2010년 4월 24일 토요일

유니버셜 디자인

< 유니버셜 디자인 >

 

1. 개념

  • Design for all people
  • 유니버셜 디자인은 "평생 디자인"이라고도 부르는 디자인계의 최신 주제(2010.4.)
  • 장애인, 노인, 어린이 등 약자가 사용할 수 있는 환경과 상품 창조를 만드는 디자인을 말하고, 신체적인 약함뿐 아니라 상황이나 나이에 따라 일어날 수 있는 특정 부분의 불리한 점을 보완하는 것이 "유니버셜 디자인"이다.
  • '더 편하게, 더 안전하게, 더 풍요롭게'를 외치는 소비자 중심의 생활 디자인이 지금 세계 디자이너가 추구하는 디자인의 중심이다.

 

2. 배경

  • 20세기 들어서 장애인, 고령자 등이 늘면서, 그들이 일상 생활을 자유롭게 보낼 수 있는 베리어 프리(barrier free) 개념이 등장했다.
  • 1980년 미국의 건축가이자 공업 디자이너인 론 메이스는 베리어 프리 개념을 뛰어넘는 남녀노소 누구나 사는데 불편함이 없는 디자인을 해야한다고 주장했고, 이 때 유니버셜 디자인이라는 개념이 생겨났다.
  • 유니버셜 디자인은 장애의 개념을 좀더 넓힌 디자인으로 정상인뿐 아니라 일시적 장애를 포함한 모든 장애를 어린이와 노인이 사용할 수 있는 환경과 상품창조를 추구하고, 이론적으로 생각하는 신체적 능력의 부족함만이 아니라, 상황이나 나이에 따라 모든 사람이 가지고 있는 특정부분의 취약성 모두를 장애의 개념으로 본다.

 

3. 원리

  • 기능적 자원성이 높은 디자인(Supportive Design)
    • 기능상 필요한 도움을 제공해야 하며 사용자에게 불필요한 어떤 부담도 야기시켜서는 안된다. 조명의 경우 밝기가 적절치 않으면 시각의 정확성이 떨어지며
  • 수용가능한 디자인(Adaptable Design)
    • 상품이나 환경이 상황에 따라 조절가능함으로써 다양한 요구를 충족시킬 수 있는 유통성을 지녀야 한다. 특히 오랜 시간 다양한 형태로 작업하는 사무환경에서는 인간공학적인 방법으로 이러한 특성의 디자인이 연구되어야 한다.
    • 변화 가능한 형태의 작업대나 높이조절이 가능한 책상과 스탠드, 다양한 서체와 글자의 크기조절이 가능한 컴퓨터 프로그램들이 이러한 사례이다.
    • 이러한 상품은 시각장애자와 노인들에게도 매우 유용하다.
  • 접근 가능한 디자인(Accessible Design)
    • 접근 가능성이란 장애물이 제거된 상태이다.
    • 보도블럭을 휠체어 사용자와 자전거를 타는 사람, 환자들이 편리하게 다닐 수 있도록 고려하고 아울러 시각장애자들에게도 도움이 되도록 색채와 패턴, 적절한 배치와 질감있는 재료를 사용해 시각장애로 인한 사고를 가능한 줄이는 것 등이 이러한 것들이다.
  • 안전한 디자인(Safely-oriental Design)
    • 대조적인 색채와 패턴으로 레벨차를 표시하거나 모서리를 둥글게 처리한 것 등 안전한 디자인은 보다 개성적이며 예반적이다. 또한 안전성은 심리적인 건강함, 소속감, 자기가치등을 포함한다.
    • 장애자가 정상정적인 활동을 유지할 수 있도록 고려된 공간은 개인에게 도립심을 부여함으로써 심리적인 건강을 유지시켜 준다.

 

 

< 7가지 원칙 >

  • 공평한 사용(Equitable)
    • 누구라도 차별감이나 불안감, 열등감을 느끼지 않고 공평하게 사용 가능한가?
  • 사용상의 융통성(Flexiblility in Use)
    • 서두르거나, 다양한 생활환경 조건에서도 정확하고 자유롭게 사용 가능한가?
  • 간단하고 직관적인 사용(Simple and Intutive)
    • 직감적으로 사용방법을 간단히 알 수 있도록 간결하고, 사용 시 피드백이 있는가?
  • 쉽게 인지할 수 있는 정보(Perceptive Information)
    • 정보구조가 간단하고, 복수의 전달수단을 통해 정보입수가 가능한가?
  • 오류에 대한 포용력(Tolerance for Error)
    • 사고를 방지하고, 잘못된 명령에도 원래 상태로 쉽게 복귀가 가능한가?
  • 적은 물리적 노력(Low Physical Effort)
    • 무의미한 반복동작이나, 무리한 힘을 들이지 않고 자연스런 자세로 사용이 가능한가?
  • 접근과 사용을 위한 충분한 공간(Size and Space for Approach and Use)
    • 이동이나 수납이 용이하고, 다양한 신체조건의 사용자와 도우미가 함께 사용이 가능한가?

 

 이와 같은 유니버셜 디자인은 제품이나 환경시설 외에 모든 산업을 대상으로 할 만큼 대단히 광범위하며, 근래 고령화의 급진전에 따른 고령친화산업(실버산업)의 부각은 기업에 있어서 새로운 비즈니스 창출 및 참여라는 기회를 제공하고 있습니다. 본격적인 고령사회의 도래와 와 국제화, 정보통신기술의 고도화 등에 동반하여 사회, 경제구조의 변혁, 가치관의 다양화 등이 한층 진전될 것으로 예측되는 향후 사회에 있어서 유니버셜 디자인은 더불어 사는 사회를 형성해가기 위해 필연적인 대안이라고 할 수 있습니다.

 

 

출처 : Our Blog, UDRC 유니버셜 디자인 연구센터

2010년 4월 20일 화요일

Qt4를 이용한 C++ GUI 프로그래밍-Chapter 01

(1) Hello Qt

  • 예제

1 #include <QApplication>
2 #include <QLabel>

3 int main(int argc, char *argv[])
4 {
5     QApplication app(argc, argv);
6     QLabel *label = new QLabel("Hello Qt!");
7     label->show();
8     return app.exec();
9 }

  • Qt의 모든 클래스는 자신의 이름과 똑같은 이름으로 된 헤더파일 내에 정의되어 있다.
  • 5번째 줄 : 응용 프로그램 차원의 자원을 관리하기 위해 QApplication 객체를 생성한다.
    • QApplication은 GUI 응용 프로그램 제어 흐름과 주요 설정 사항을 관리하는 클래스로서, 메인 이벤트 루프를 갖고 있으며, 응용 프로그램의 초기화와 종료화 그리고 시스템 차원의 설정사항과 응용 프로그램 차원의 설정사항을 다룬다.
    • Qt를 사용하는 GUI 응용 프로그램에는 하나의 QApplication 객체만이 존재할 수 있으며, 전역 포인터인 qApp 나 QCoreApplication::instance()를 통해 이 객체에 접근할 수 있다.(자세한 것은 Qt 어시스턴트 참조)
  • 명령행으로부터 입력되는 인자 중에서 Qt가 자체적으로 인식하는 것이 있기 때문에, QApplication을 생성할 때는 생성자에 argc와 argv를 넘겨줘야 한다.
  • 6번째 줄 : "Hello Qt"라는 문자열을 출력하는 QLabel 위젯을 생성하고 있다.
  • Qt와 유닉스에서 통용되는 위젯(Widget)이란 용어는 유저 인터페이스 상에 자리잡은 각각의 비주얼한 요소를 일컫는 말이다. '윈도우 가젯'이란 말에서 유래된 이 용어는, 윈도우에서 사용되는 용어인 '컨트롤'이나 '컨테이너'와 그 의미하는 바가 동일한데, 이를 테면 버튼, 메뉴, 스크롤 바, 프레임 등이 바로 위젯인 것이다. 하지만 Qt는 어떠한 위젯이라도 윈도우가 될 수 있다는 특징이 있다.
  • 7번째 줄 : 이 레이블이 화면에 보이게 만들고 있다. 모든 위젯은 항상 화면에 보이지 않는 상태로 생성되는데, 이러한 방침은 화면에 보이기 이전에 위젯에 필요한 모든 조치가 취해질 수 있게 하기 위한 것으로서, 이를 통해 불필요한 화면의  깜빡임을 막을 수 있게 된다.(화면 깜빡임의 다른 방법은 더블 버퍼링으로 5장에서 다룬다.)
  • 8번 줄 : 응용 프로그램의 제어를 Qt에게 넘겨주고 있다. 이렇게 되면 프로그램은 마우스 클릭이나 키보드 입력과 같은 사용자의 액션을 기다리는 일종의 대기모드인 이벤트 루프에 진입하게 된다. 사용자의 액션은 이벤트('메시지'라고도 함)를 발생시키게 되는데, 프로그램은 보통 이러한 이벤트에 대해 몇 가지 함수를 실행함으로써 반응하게 된다. 예를 들어, 사용자가 어떤 위젯을 클릭하면 '마우스 버튼의 누름'과 '마우스 버튼의 뗌'을 의미하는 이벤트가 생성된다.
  • main() 함수의 끝부분에서는 좀 더 간략함을 위해 QLabel 객체에 대한 delete 호출을 생략하고 있다. 프로그램이 종료되면 운영체제는 그 프로그램이 사용한 모든 메모리를 회수하기 때문에, 이 정도 크기의 작은 프로그램에서 발생하는 메모리 누수는 아무런 해가 되지 않는다.
  • 프로그램을 실행시키려면 먼저 컴퓨터에 Qt 4.3.2이상의 Qt 4가 설치되어 있어야 함.
  • 그리고 Qt의 bin 디렉토리가 PATH 환경변수에 설정되어 있어야 함.(부록 A 참조, 윈도우는 Qt 설치시 자동으로 등록됨.)
    • 1 # vi hello.cpp
      2 # qmake -project
      3 # qmake hello.pro
      4 # make
      5 # ./hello
    • 1 : chapter01의 hello 예제 파일 소스임.
    • 2 : 플랫폼에 독립적인 프로젝트 파일(hello.pro)이 생성됨.
    • 3 : 이전 단계에서 생성된 플랫폼 독립적인 프로젝트 파일로부터 특정 플랫폼을 위한 makefile이 생성됨.
    • 4 : 프로그램이 만들어 진다.
    • 5 : 만들어진 프로그램을 실행

 

  • ### 윈도우 비쥬얼 스튜디오 프로젝트 파일 만드는 법 ###
    • # qmake -tp vc hello.pro

 

 

(2) Signal / Slot

  • 시그널은 함수와 연결될 수 있어서, 시그널이 발생하면 그와 연결된 함수가 자동으로 실행되는데, 이처럼 시그널의 발생에 의해 자동으로 호출되는 함수를 슬롯이라고 한다.
  • SIGNAL()과 SLOT()은 시그널과 슬롯을 연결하는 데 사용하는 매크로이다.
  • ex) QObject::connect( button, SIGNAL(clicked()), &app, SLOT(quit()));

 

(3) Widget

  • QWidget은 어떤 응용프로그램의 메인 윈도우가 될 수 있다.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         

 

 

(4) Reference Document

 

 

end

2010년 4월 19일 월요일

Qt4를 이용한 C++ GUI 프로그래밍-시작하기

* Qt(큐트)

  • 소스 코드 한 벌만으로 다양한 운영체제 환경에서 실행 가능한 어플리케이션을 만들 수 있도록 해주는 크로스 플랫폼 응용프로그램 프레임워크
  • 노르웨이에 있는 트롤테크에서 처음 개발되었고, 2008년 노키아가 인수하여 현재 모바일 및 데스크톱 소프트웨어에 관한 노키아의 플랫폼 소프트웨어 전략의 핵심 역할을 하고 있음.(2008년?)
  • Write Once, Compile Anywhere : 소스 코드는 한 벌만 만들고 이를 원하는 운영체제 환경에서 컴파일하기만 하면 해당 환경에서 실행될 수 있는 이미지가 만들어진다.(윈도우, 리눅스, 맥 OS 지원, 임베디드 리눅스, 윈도우 CE 지원)
  • Qt로 만들어진 제품들 : 구글 어스, 얻도비 포토샵 앨범, 스카이프, 메스메티카,  KDE, KOffice
  • 오픈 소스로 배포되고 있음

 

* Qt 라이선스

  • 오픈 소스 에디션
    • GNU GPL 사용에 대한 요구사항이 포함됨
    • 소스를 보고, 수정하고, 배포하는 권리를 부여함.
  • 상용 에디션
    • 만든 응용 프로그램을 상용 라이선스 조건을 적용하고자 할 경우 사용
    • 자신만의 조건 하에 판매하고 배포할 수 있음.

 

* Qt 설치하기(부록 A)

  • Qt 다운로드 하기
  • 책 예제 다운 받기
  • Qt/윈도우 설치(MinGW C++ 설치 필수)
  • Qt/맥 설치(Xcode Tools 먼저 설치 필수)
  • Qt/X11 설치
    • # cd /tmp
    • # gunzip qt-x11-opensource-src-4.3.2.tar.gz
    • # tar xvf qt-x11-opensource-src-4.3.2.tar
    • # cd /tmp/qt-x11-opensource-src-4.3.2
    • # ./configure
    • # make
    • # make install or sudo make install
    • 환경 변수 설정(.profile)
      PATH=/usr/local/Trolltech/Qt-4.3.2/bin:$PATH
      export PATH

 

2010년 4월 14일 수요일

linux 2.6 device model

* 5 component for device model

  • the device model core -> defines a set of structures and functions
    • 'include/linux/device.h', 'drivers/base/*.c'
  • the generic bus drivers
    • bus / struct bus_type / bus_register(), bus_unregister()
  • the bus  controller drivers
    • device / struct device / device_register(), device_unregister()
  • the device drivers
    • driver / sturce device_driver / driver_register(), driver_unregister()
  • the class drivers
    • class / struct class / class_register(), class_unregister()

 

* Device Model Core

  • 'struct bus_type' : Represents busses(PCI, USB, I2C, etc.)
  • 'struct device' : Represents devices(Intel AC97 audio controller, Intel PRO/100 ethernet controller, a PS/2 mouse, etc.)
  • 'struct device_driver' : Represents kernel drivers that handle devices
  • 'struct class ' : Represents a class of devices(sound, input, graphics, etc.)
  • 'include/linux/device.h', 'drivers/base/*.c'

 

* device_register() : 한 device에 대해 맞는 driver들을 검색

* driver_register() : 한 driver에 대해 맞는 device들을 검색

 

* Generic Bus Drivers

  • kernel이 지원하는 모든 bus마다 generic bus driver가 있다. Generic bus driver는 sturct bus_type을 allocate하고 bus_register()를 써서 kernel의 bus type list에 register한다.
  • bus_type structure
    • name (string)
    • !klist_devices (klist)
    • !klist_driver (klist)
    • match (fp)
    • suspend (fp)
    • resume (fp)
  • klist_devices는 이 bus에 존재하는 device들의 list, Bus controller driver가 device_register()를 호출함에 의해 update 됨.
  • Bus controller driver는 system initialization 시 bus를 scan해서 어떤 device들이 있는지 check한 뒤 각 device마다 device_register()를 호출해서 klist_devices를 scan해서 맞는 driver (match() 이용)를 찾는다. 그런 뒤 device를 klist_devices에 update한다.
  • Bus controller driver는 또한 gadget이 hot plugged 되었을 때(어떤 device인지 확인한 뒤) device_register()를 호출해서 klist_drivers를 scan해서 각 device 마다 맞는 driver( match() 이용 )를 찾는다. 그런뒤 device를 klist_devices에 update 한다.
  • klist_driver는 이 bus에 존재하는 device들을 handle할 수 있는 driver들의 list, Device driver가 스스로 initialization 할 때, driver_register()를 호출하여 자신을 등록함으로써 갱신된다.
  • Device Driver가 kernel에 inserted 되면, 이 driver는 driver_register()를 호출하여 해당 bus에 대해 klist_devices를 scan하여 이 driver가 다룰 수 있는 device들을 찾는다. 그런 뒤 driver를 klist_drivers에 update 한다.
  • match()에 의해 device와 driver가 associated 되는 것을 binding이라고 한다.
  • ex) 'drivers/net/phy/mdio_bus.c'
  • struct bus_type mdio_bus_type = {
    . name = "mdio_bus",
    .match = mdio_bus_match,
    .suspend = mdio_bus_suspend,
    .resume = mdio_bus_resume,
    };

 

* '!' is internal to the device motel core and should not be touched by the bus controller driver directly.

 

* Bus Controller Drivers

  • Bus의 device driver다. 따라서, 여느 device drivers와 마찬가지로 자신을 driver_register()로 등록함. 그러나 추가적으로 자신이 다루는 bus 상에 있는 devices를 detect하여 device_register()를 이용해 등록한다. bus_type 구조체의 klist_devices list에.
  • 새로운 Linux device driver model에서 모든 device는 bus 상에 존재하므로, 결국 bus controller driver가 모든 device를 등록한다. struct device 형태로. bus_type 구조체의 klist_devices list에.
  • device
    • bus_id (string)
    • bus (bus_type)
    • parent (device)
    • !driver(device_driver)
  • 'drivers/net/gianfar_mii.c'

 

* Device Drivers

  • 모든 device driver는, driver_register()를 호출해 bus_type 구조체의 klist_driver list에 자기 자신을 등록한다. 그 다음에 device model core가 이 driver를 한 device와 binding을 시도함.
  • 한 device가 registered 되면 (이는 곧 이 device를 handle할 수 있는 drivers가 klist_drivers에 등록된다는 말이므로) 한 특정 driver에 의해 handled 될 수 있는데, 그 driver의 probe member가 하는 일이 바로 그 특정 device 하나를 위해 이 driver의 한 instance를 생성해내는 (그리고 그 device를 초기화하는) 일이다.
  • device_driver
    • bus (bus_type)
    • probe (fp)
    • remove (fp)
    • suspend (fp)
    • resume (fp)
  • bus는 이 driver가 등록될 klist_drivers를 가진 bus_type 구조체에 대한 pointer.
  • probe는, 이 driver가 지원하는 device가 detected (이는 곧 device를 지원하는 drivers를 klist_drivers에서 찾아내는 일을 한 것 즉, binded) 될 때마다 불리는 callback function. 이 함수는 driver 자신을 각 device 당 하나 씩 instantiate한 뒤 그 device를 initialize 한다.
  • remove는 이 driver를 그 device로부터 unbind하기 위해 불리는 callback function. Unbinding은 device가 physically removed 되거나 driver가 unloaded 되거나 system이 shutdown 될 때 일어난다.
  • 'drivers/net/phy/'

 

* Class Drivers

  • Class driver는 그것이 표현하는 device class들에 대해 struct class를 instantiate하여  class_register()를 통해 device model core에 등록한다.
  • Devices를 적당한 class에 추가하는 것은 각 해당 device driver의 책임이다.
  • class
    • name (string)
    • !devices (list)
  • devices는 이 class에 속한 device들의 list이다. 이 list는 device driver들에 의해 갱신된다. (그 device driver들이 자기 자신들을 각 device들에 대해 instantiate할 때).

 

* Conclusion

  • 결국 이런 data structure들이 있음으로 해서, device들이 어떻게 tree 구조를 이루고 있는지 알 수 있고, 어떤 종류의 device들이 system에 존재하는지도 알 수 있다.
  • 그 효과는 더 나은 power management, 그리고 system에 연결된 devices에 대한 더 나은 통찰.

 

출처 : 블로그

 

 

I2C

I2C(Inter-Integrated Circuit,아이 스퀘어 씨)

  • 필립스에서 개발한 직렬 컴퓨터 버스
  • 마더보드, 임베디드 시스템, 휴대전화 등에 저속의 주변 기기를 연결하기 위해 사용됨.
  • I2C는 풀업 저항이 연결된 직렬 데이터(SDA)와 직렬 클럭(SCL)이라는 두 개의 양방향 오픈 컬렉터 라인을 사용한다. 최대 전압은 +5V이며, 일반적으로 +3.3V 시스템이 사용되지만 다른 전압도 가능하다.
  • I2C 레퍼런스 디자인은 7bit의 주소 공간을 가지며, 이 중 16개는 예약되어 있으므로, 동일한 버스에 최대 112개의 노드를 연결할 수 있다. 가장 일반적으로 사용되는 I2C 버스의 모드는 표준 모드인 100kbit/s와 저속 모드인 10kbit/s가 사용된다. 최신 리비전의 I2C는 보다 빠르게 동작하며, fast mode인 400kbit/s와 고속 모드인 3.4Mbit/s를 지원한다. 최대 1008 노드까지 연결 가능한 10bit 주소 지정 등의 확장된 기능등을 지원한다.
  • 응용 영역
    • 사용자 설정값을 저장하기 위해 NVRAM에 접근하는 경우
    • 저속의 디지털-아날로그 변환 회로에 접근하는 경우
    • 저속의 아날로그-디지털 변환 회로에 접근하는 경우
    • 모니터의 명암, 대비, 색상 등을 변경하는 경우
    • 지능형 스피커의 볼륨값을 변경하는 경우
    • 휴대전화 같은 장치에 포함된 발광 다이오드를 제어하는 경우
    • 중앙 처리 장치 온도나 팬 속도와 같은 하드웨어 모니터링 정보나 진단 센서 정보를 읽는 경우
    • 실시간 클럭 값을 읽는 경우
    • 시스템 요소의 전원을 제어하는 경우
  • I2C의 장점은 특히 마이크로컨트롤러에서 단지 2개의 일반 목적 입출력 핀(GPIO)과 소프트웨어만을 이용하여 여러 장치들을 제어할 수 있다는 점이다
  • 주변장치들은 시스템이 동작 중일 때도 I2C 버스에 추가/제거될 수 있으며, 이것은 핫 스왑이 필요한 요소들을 이용하는 응용에 적합하다.
  • I2C는 엑세스 버스, VESA 디스플레이 데이터 채널 (DDC) 인터페이스, 시스템 과리 버스(SMBus), IPMI 프로토콜 중의 하나인 지능형 플랫폼 관리 버스(IPMB)의 기본 기술이다. 이러한 것들은 전압과 클럭 주파수 범위에서 차이가 있으며, 인터럽트 라인을 가질 수 있다.
  • I2C 버스의 설계상 장점 : 노이즈에 강하여 신뢰성이 높고, 매우 적은 전력을 사용하며, 다양한 온다환경에서도 잘 동작할 뿐만 아니라, 다양한 전압레벨을 지원한다.

 

* I2C에서 ACK의 역할

  • Write 시 정상 수신 신호
  • Read 시 송신 완료 신호
  • Write, Read 모두 ACK 신호는 Slave에서 발생시킴

 

* I2C의 정의

  • 1980년대 필립스에서 개발된 버스 표준안
  • 2개의 전송 라인을 이용한 양방향 통신 지원(SDA, SCL)
  • 현재 세계에서 가장 많이 쓰이는 임베디드 표준안
  • Multi-master capable bus with arbitration feature
  • Master-Slave communication supported
  • Each IC on the bus is identified by its own address code

 

* I2C의 장점

  • 단순한 하드웨어 구성
  • 단순한 프로토콜로 구성
  • 장치의 연결과 제거가 용이함
  • Simpler PCB
  • Fast enough for all "Human Interfaces" applications(Display, Switches, Keyboard)
  • Large number of I2C devices

 

* I2C Signals

 (1) Control Signal

  • SCL highdptj SDA transition으로 판정
  • Start / Stop bit
    • Start : SDA low 이동 후 SCL low 이동
    • Stop : SCL high 이동 후 SDA high 이동

 (2) Data Signal

  • SCL이 pulse 안에서 SDA 데이터의 이동으로 0/1 구분
  • SCL pulse 안에서...
    • SDA pulse 존재하면 : 1
    • SDA pulse 존재하지 않으면 : 0

 (3) ACK / NAK Signal

  • 9번째 data 신호로 판명
    • ACK : 0
    • NAK : 1

 

 

The image shows a simplified equivalent circuit diagram for an I2C connection between two devices (master or slave). It shows all factors which are relevant for I2C.

 

VCC I2C supply voltage, typically ranging from 1.2 V to 5.5 V
GND Common ground
SDA Serial data (I2C data line)
SCL Serial clock (I2C clock line)
Rp Pull-up resistance (a.k.a. I2C termination)
Rs Serial resistance
Cp Wire capacitance
Cc Cross channel capacitance

 

 

출처 : 위키 백과, 다음 블로그, 네이버 블로그, I2C bus(영문)

2010년 4월 13일 화요일

latency

latency : 지연 (또는 대기) 시간

 

1. 네트워크에서의 latency는 delay와 비슷한 말로서, 하나의 데이터 패킷을 한 지점에서 다른 지점으로 보내는데 소요되는 시간을 표현한 것이다. 그러나 일부에서는 (예를 들어 AT&T 등에서는), 패킷 하나를 보내고 그것이 송신자에게 되돌아올 때까지의 왕복에 걸리는 시간을 latency라고 부르기도 한다. latency는 한 지점에서 다른 지점 사이에 (지연시간이 전혀 없이) 데이터가 즉시 전송되어야만 하는 것으로 가정한다. 네트워크에서 latency를 일으키는 요인은 다음과 같다.

  • 전달 지연 : 이것은 단순히 하나의 패킷이 한 지점에서 다른 지점으로 광속으로 이동하는데 걸리는 시간이다.
  • 전송 지연 : (광케이블, 무선 또는 그 밖의 어떤 것이라도) 매체 그 차제에서 약간의 지연이 생긴다. 또 패킷의 크기에 따라서도 왕복하는데 지연이 생길 수 있는데, 그 이유는 패킷이 클수록 수신하고 반환하는데 시간이 더 걸리기 때문이다.
  • 라우터 및 기타 처리 지연 :  게이트웨이 노드들 시험하고, 또 어쩌면 패킷 내의 헤더를 변경 (예를 들어, TTL 필드 내에 있는  카운트의 값을 변경하는 등) 하는 데에도 시간이 걸린다.
  • 다른 컴퓨터 및 저장장치 지연 : 네트웍 내 행로 양단에서, 패킷은 스위치 브리지와 같은 중간 장비들에서 하드디스크와 같은 저장장치에 액세스하기 쉽다 (그러나백본 통계에서, 이러한 종류의 지연은 십중팔구 고려되지 않는다). 

 

2. 컴퓨터 시스템에서의 latency는 종종 응답시간을 늦추는 지연이나 대기를 의미하는데 사용된다. 컴퓨터 latency에 기여하는 명확한 요인들로는, 마이크로프로세서와 입출력장치들 간의 데이터 속도가 맞지 않거나, 데이터 버퍼링이 불충분한 것 등이 포함된다. 컴퓨터 내에서, latnecy는 prefeching이나 멀티 스레딩, 또는 다중 스레드의 실행에 걸친 병렬 처리의 사용 등

과 같은 기술에 의해 제거되거나 감추어질 수 있다.

 

3. 입체 시야와 머리 추적 장치 등이 제공되는 헬멧을 설명하는 3차원 모의실험에서, latency는 컴퓨터가 머리의 움직임을 감지하는 때부터 적절한 이미지가 나타나는데 까지 걸리는 시간을 말한다.

 

출처 : 텀즈

2010년 4월 10일 토요일

리눅스 사운드 프로그래밍

< 음악이 생겨라 (Let There Be Music) >

 

by Shuveb Hussain

한글 번역 전정호

이 글은 한글번역판을 요약한 것입니다.

 

*** 사운드 카드 프로그래밍 ***

 

 (1) 샘플링

  • 음을 녹음할 때 음질을 선택한다.
  • 음질을 결정하는 중요한 요소 중 하나가 샘플링 빈도(sampling rate)이다.
  • 음은 시간에 따라 진동수가 바뀌는 파장일 뿐이다.
  • 음을 녹음하려면 일정 간격으로 음의 진동수를 기록한다. 이 간격을 샘플링 빈도라고 한다.
  • 샘플링 빈도가 높을수록 음질이 좋아진다. 예를 들어, CD의 샘플링 빈도는 초당 44100번, 즉 44.1kHz이다.
  • PCM(Pulse Code Modulation, 펄스 코드 변조)이라고 하는 이 작업은 ADC(Analogue to Digital Converter, 아날로그-디지털 변환기)가 한다.

 

 

 (2) 비트와 채널

  • 음을 샘플링할 때, 샘플당 일정 수의 비트를 사용하고, 이런 채널을 여러 개 사용한다. 샘플링하는 자료의 비트 개수를 샘플링 정밀도(resolution)라고 한다.
  • 가장 흔한 형식은 8비트 양수 바이트 혹은 16비트이다.
  • 채널별로 자료를 분리한다. 예를 들어, CD 음악에는 왼쪽, 오른쪽(스테레오) 두 채널이 있다.
  • 8비트 정밀도로 CD음질을 녹음할 때 초당 필요한 크기를 계산해보면 :
  •        2        x       44100      =      88200 bytes
    (채널 개수) x (샘플링 빈도) = (초당 필요한 크기)

  • 이제 이론은 충분하니 실제 프로그램을 시작하자.

 

 

 (3) 사운드 카드를 프로그래밍 하기

  • 사운드 카드를 프로그래밍하는 방법이 몇가지 있다.
  •  초기 리눅스 드라이버가 만들어지던 때 두 그룹이 있었다.
    • Open Sound System(OSS)은 많은 장치 드라이버를 작성한 그룹으로 심지어 하드웨어 사양을 공개하지 않거나 비밀유지동의(non-disclusure agreement)를 하지않은 개발자에게 사양을 공개하지 않는 사운드 카드 제조사의 이진모듈도 포함하였다. 하드웨어 제조자가 개인에게 사양을 알려주려고하지 않았기 때문에 OSS는 4Front Technologies란 회사를 만들었다.
    • ALSA(Advanced Linux Sound Architecture)는 제조사가 사양을 공개한 사운드 카드 드라이버만 작성했다. ALSA는 2.6-test 커널에 포함되어 있다.
  • ALSA는 OSS 에뮬레이션 계층을 제공하기 때문에 OSS로 작성한 프로그램은 OSS와 ALSA 시스템에서 모두 동작한다. 간단하고 대다수의 시스템에 설치되어 있기 때문에 이 글은 OSS 프로그래밍을 다룰 것이다.

 

  • 유닉스/리눅스는 모든 장치 드라이버마다 (보통 /dev 디렉토리에) 파일 시스템 인터페이스가 있다. 이 장치파일을 open, read, write, lseek, close와 같은 파일관련 시스템 호출에 사용한다. 장치파일을 장치드라이버가 요청을 기다리는 파일시스템상의 훅(hook)이라고 보면 된다.예를 들어, /dev/hda1 파일은 primary master IDE 하드디스크의 첫번째 파티션에 대한 인터페이스이다. open 시스템호출을 사용하여 파일을 열면 일반파일과 같이 파일핸드(file handle)을 얻을 수 있다. 파일핸들을 읽으면 실제로 파티션의 첫번째 섹터에 있는 자료를 읽게 된다. 또, 앞으로 lseek하면 파일포인터(file pointer)를 앞으로 이동한다. 섹터를 건너뛰으려면 섹터 크기만큼 앞으로 lseek한다. 위험하므로 하드디스크 장치 파일을 수정하지는 마라. 파티션에 값을 쓰면 파티션이 망가질 수 있다. 하드웨어 장치는 보통 root만 직접 접근할 수 있다.

 (4) 코드

  • 이제 코드로 넘어가자. 이 코드는 root가 아니어도 문제없이 실행되야 한다. 파일장치를 접근하는데 문제가 있다면 root로 su하고 chmod하여 접근 권한을 푼다. 물론 리눅스에서 작동하는 사운드카드를 사용해야 한다. 직접 코드를 입력하지 않고 여기에서 다운받을 수 있다. demo.pcm 파일도 같이 다운받아야 한다.

 

/*
 * oss.c는 사운드카드에서 raw PCM 22KHz 샘플음을 낸다
 *
 * 중요 - 프로그램을 실행하기전에 현재 디렉토리에 demo.pcm 파일이 있는지 확인하라.
 */

#include < sys/types.h >
#include < sys/stat.h >
#include < sys/soundcard.h >
#include < sys/ioctl.h >
#include < unistd.h >
#include < fcntl.h >
#include < errno.h >
#include < stdlib.h >

#define SECONDS 5 //재생 시간 (초)

int main()
{
    int fd;
    int handle = -1;
    int channels = 1;         // 0=모노 1=스테레오
    int format = AFMT_U8;
    int rate = 22000;
    unsigned char* data;

   /* 사운드카드에 해당하는 파일에 쓰기위해(write) 파일을 연다(open). DSP = Digital Signal Processor */
    if ( (handle = open("/dev/dsp",O_WRONLY)) == -1 )
    {
  perror("open /dev/dsp");
  return -1;
    }

   /* 재생하려는 음이 스테레오라고 사운드카드에 알린다. 0=모노 1=스테레오 */
    if ( ioctl(handle, SNDCTL_DSP_STEREO,&channels) == -1 )
    {
  perror("ioctl stereo");
  return errno;
    }

    /* 자료 형식을 사운드카드에게 알린다 */
    if ( ioctl(handle, SNDCTL_DSP_SETFMT,&format) == -1 )
    {
  perror("ioctl format");
  return errno;
    }

    /* DSP 재생율(playback rate), 즉 raw PCM 음의 샘플링 빈도를 지정한다. */
    if (ioctl(handle, SNDCTL_DSP_SPEED,&rate) == -1 )
    {
  perror("ioctl sample rate");
  return errno;
    }

    // 빈도 * 5 초 * 두 채널
    data = malloc(rate*SECONDS*(channels+1));

    if((fd=open("demo.pcm",O_RDONLY))==-1)
    {
  perror("open file");
  exit(-1);
    }

    /* demo 파일에 저장된 정보를 읽어서 할당한 메모리에 저장한다 */
    read(fd,data,rate*SECONDS*(channels+1));
    close(fd);

    /* 읽은 내용을 사운드카드에 쓴다(write)! 그러면 재생이 된다. */
    write(handle, data, rate*SECONDS*(channels+1));

    if (ioctl(handle, SNDCTL_DSP_SYNC) == -1)
    {
  perror("ioctl sync");
  return errno;
     }

    free(data); //좋다. 마무리.
    close(handle);

    printf("===Done===\n");
    return 0;
}


 

(5) 코드 설명

  • 이 프로그램은 raw PCM, 22KHz, stereo 자료파일을 5초간 연주한다. 프로그램은 크게 3가지 작업을 한다.
    • sound 장치 열기(open)
    • 재생을 위한 파라미터 설정
    • 장치에 자료 쓰기(write)
  • open() / write() / close() 시스템 호출은 일반 파일과 동일하다.
  • ioctl()(Input/Output ConTroL) 시스템 호출을 사용하여 재생에 사용할 파라미터를 설정한다. ioctl() 시스템 호출은 입출력 장치와 통신하거나 파라미터를 설정할 때 사용한다. 또 시스템 호출의 개수를 줄이기 위한 편법으로 사용되기도 한다. 그래서 흔히 프로그래머의 다용도칼이라고 부른다. 함수의 원형
  • int ioctl( int fd, int command, ... );

    • fd : 장치의 파일 기술자(file descriptor)
    • command : 장치에 대한 요청/명령
    • ... : command에 따라 달라진다.
  • ioctl(handle, SNDCTL_DSP_SPEED, &rate)
    • DSP 재생을 설정한다. rate는 장치 드라이버로 전달되는 실제 재생율이다.
  • 예제 프로그램에는 3가지 ioctl()이 있다.
    • 재생에 사용할 채널 개수(channels)를 설정
    • PCM 형식(format)을 설정
    • 재생율(sampling rate)을 설정
  • 이것으로 장치에 필요한 정보는 충분하고, 다음은 장치파일에 PCM 자료를 직접 쓰면(write) 재생이 된다. 마지막 ioctl()은 장치를 비우고(flush), 그 다음 PCM 자료를 저장하기 위해 할당한 메모리를 해제한다. 이게 끝이다.

 

 

(6) 음악 저장 형식

  • 방금 전에 5초짜리 22KHz 음악을 재생하기 위해 raw PCM 자료 220KB가 필요했다.
    • 22,000 x  5  x   2    = 220,000 bytes
    • (샘플   x 초 x 채널 = 데이터 크기)
    • CD 음질로 1분을 재생하기 위해 필요한 크기는 :
      • 44,100 x 60 x 2 = 5292000 bytes, 약 5 MB!
  • 음악 CD는 raw PCM 형식으로 자료를 저장한다. 그러나 컴퓨터는 음악을 효율적으로 저장하고 (인터넷으로) 전송하기 위해 음악을 압축하여 크기를 줄이고 재생시 다시 압축을 푼다. 어떤 음악이던 관계없이 샘플링률은 고정되어 있다. 아무 소리가 없는 몇 초간을 샘플링 했다고 생각해 보자. 같은 시간의 시끄러운 락 음악과 동일한 크기가 필요하다.
  • raw 음악파일은 자료반복이 매우 적기 때문에 일반적인 압축방법으로는 잘 압축되지 않는다. 음악은 다른 기술을 사용하여 압축한다. 가장 일반적인 방법은 사림이 귀로 들을 수 없는 부분을 제거하거나 음악 특성에 따라 압축한다. 음악을 좋아하는 사람들에게 가장 대중적인 형식은 분명 MP3다. 현재 MP3에는 특허문제가 걸려 있기 때문에, 오픈소스 공동체에서는 Ogg Vorbis 형식을 반긴다. 두 형식 모두 크기가 비슷하게 줄어들며 음질의 손실을 최소화한다.

 

 

 (7) Ogg Vorbis 파일을 재생하는 방법

  • 사운드 카드가 어떻게 raw 음악 자료를 재생하는지 알았으니, Ogg Vorbis 파일을 재생하는 방법을 알아보자. Ogg Vorbis 파일을 재생하려면 먼저 복호화(decode), 즉 raw PCM 자료로 변환해야 한다.
  • libvorbisfile이 이 작업을 한다. 이 라이브러리는 매우 낮은 수준을 다루지만 더 세밀한 조절이 가능한 libvorbis 라이브러리보다 높은 수준에서 변환을 한다. 이제 문제가 간단해진다 : Ogg Vorbis 파일에서 읽은 자료를 라이브러리로 넘기고, 라이브러리가 변환된 raw PCM 자료를 사운드 카드로 직접 보낸다. 소스는 여기에
  • #include < sys/types.h >
    #include < sys/stat.h >
    #include < sys/soundcard.h >
    #include < sys/ioctl.h >
    #include < unistd.h >
    #include < fcntl.h >
    #include < errno.h >
    #include < stdlib.h >

    #include "vorbis/codec.h"
    #include "vorbisfile.h"

    int setup_dsp(int fd,int rate, int channels);

    char pcmout[4096]; // 변환한 PCM 자료를 저장할 4KB 버퍼
    int dev_fd;

    int main(int argc, char **argv)
    {
     OggVorbis_File vf;
     int eof=0;
     int current_section;
     FILE *infile,*outfile;

     if(argc<2)
     {
      printf("supply file arguement");
      exit(0);
     }

     if ( (dev_fd = open("/dev/dsp",O_WRONLY)) == -1 )
    {
      perror("open /dev/dsp");
      return -1;
     }

     infile=fopen(argv[1],"r");

     if(infile==NULL)
     {
      perror("fopen");
      exit(-1);
     }  

    if(ov_open(infile, &vf, NULL, 0) < 0)
    {
      fprintf(stderr,"Input does not appear to be an Ogg bitstream.");
      exit(1);
     }

     char **ptr=ov_comment(&vf,-1)->user_comments;
     vorbis_info *vi=ov_info(&vf,-1);

     while(*ptr)
     {
      fprintf(stderr,"%s",*ptr);
      ++ptr;
     }

     fprintf(stderr,"Bitstream is %d channel, %ldHz",vi->channels,vi->rate);
     fprintf(stderr,"Decoded length: %ld samples",(long)ov_pcm_total(&vf,-1));
     fprintf(stderr,"Encoded by: %s",ov_comment(&vf,-1)->vendor);

     if(setup_dsp(dev_fd,vi->rate,vi->channels-1))
     {
      printf("dsp setup error.aborting");
      exit(-1);
     }

     int count=0;

     while(!eof)
     {
          long ret=ov_read(&vf,pcmout,sizeof(pcmout),0,2,1,&current_section);
          if (ret == 0)
          {
        /* EOF */
      eof=1;
          }
          else if (ret < 0)
          {
            /* 자료에 오류가 있다.  (프로그램에) 중요하다면 보고하지만,
      이 프로그램은 하지 않는다. */
           }
          else   {
      printf("Writing %d bytes for the %d time.",ret,++count);
      write(dev_fd,pcmout,ret);
          }
     }

     ov_clear(&vf);
     fclose(infile);
     
    if (ioctl(dev_fd, SNDCTL_DSP_SYNC) == -1)
    {
          perror("ioctl sync");
      return errno;
     }

     close(dev_fd);
     fprintf(stderr,"Done.");

     return(0);
    }


    int setup_dsp(int handle,int rate, int channels)
    {
        int format;

        if ( ioctl(handle, SNDCTL_DSP_STEREO,&channels) == -1 )
        {
      perror("ioctl stereo");
      return errno;
        }

         format=AFMT_U8;

         if ( ioctl(handle, SNDCTL_DSP_SETFMT,&format) == -1 )
        {
      perror("ioctl format");
      return errno;
        }
     
        if ( ioctl(handle, SNDCTL_DSP_SPEED,&rate) == -1 )
       {
      perror("ioctl sample rate");
      return errno;
        }

         return 0;
    }

 

  • 다음과 같이 컴파일 한다.
  • gcc oggplay.c -oggplay -lvorbisfile -I/path/to/vorbis/header/files -L/path/to/vorbis/lib/files

  • 라이브러리파일과 헤더파일이 /usr/lib 이나 /usr/include 같은 일반적인 위치에 있다면 -l 과 -L 명령행 옵션이 필요없다. 모든 대중적인 배포본에 vorbisfile 라이브러리가 포함되있다. 만약 시스템에 설치가 안되있다면 여기에서 다운받을 수 있다. 또, Ogg Vorbis 사이트는 여기다. 프로그램을 컴파일하려면 (개발용) 헤더파일이 필요하다.

  • setup_dsp 함수는 dsp 장치를 열고(open), 세가지 중요한 파라미터인 채널, 형식, 재생율을 지정한다. 음악 재생을 위해 가장 중요한 세가지 파라미터를 기억하라. main 함수는 오류검사외에, 쉘 아규먼트로 준 Ogg Vorbis 파일을 열고, 파일에 저장된 설명과 파일정보를 출력한다. ov_open() 라이브러리함수가 채우는 구조체에 저장된 샘플링 빈도와 채널 정보를 setup_dsp 함수에 넘긴다. 그후 프로그램은 Ogg Vorbis 파일 내용을 변환하여 버퍼에 넣는 반복문을 실행한다. 반복문은 버퍼에 저장한 raw PCM 자료를 앞에서 설정한 dsp 장치에 쓴다. 파일이 끝날때까지 반복한 후, 마지막으로 정리하고 종료한다. 간단하지 않는가? 쉽고 직관적으로 변환해준 libvorbisfile에게 감사하다.
  • Ogg Vorbis 파일을 변환하려면 libvorbisfile을 사용하면 된다. MP3 파일을 변환하여 재생하고 싶다면 여러 라이브러리를 선택할 수 있다. 많이 사용하는 라이브러리중에 영상과 음악을 모두 변환할 수 있는 smpeg 라이브러리가 있다. 또, libmad 라이브러리도 찾았다. 나는 smpeg의 음악 변환 기능만 사용하기로 했다. 관심이 있다면 smpeg의 MPEG 영상 변환 기능도 살펴보길 바란다. 라이브러리 사용법을 설명하는 샘플 프로그램 plaympeg도 포함되있다. 영상을 보여주기위해 smpeg은 매우 사용하기 쉽고 기능이 많은 그래픽 프로그래밍 라이브러리인 SDL을 사용한다. 이외에도 MP3를 변환하는 라이브러리는 많지만, 많은 리눅스 배포본에 smpeg이 포함되있기때문에 smpeg을 선택했다. 많이 사용하는 gtv MPEG 영상플레이어도 smpeg 패키지에 포함되있다.

 

 (8) MP3 파일 연주하는 프로그램 예제

  • smpeg 라이브러리가 변환한 MP3 자료를 직접 사운드 카드로 보낸다. 직접 PCM을 다룰 필요가 없다. 소스 다운로드
  • #include < stdio.h >
    #include < stdlib.h >
    #include < string.h >
    #include < signal.h >
    #include < unistd.h >
    #include < errno.h >
    #include < sys/types.h >
    #include < sys/stat.h >
    #include < sys/ioctl.h >
    #include < sys/time.h >

    #include "smpeg.h"

    void usage(char *argv0)
    {
        printf("Hi,%s This is the normal useage.",argv0);
    }

    int main(int argc, char *argv[])
    {

        int volume;
        SMPEG *mpeg;
        SMPEG_Info info;
       
        volume = 100; //Volume level

        /* 아규먼트가 없으면 사용법만 출력한다 */
        if (argc == 1)
        {
             usage(argv[0]);
             return(0);
        }

        mpeg = SMPEG_new(argv[1], &info;, 1);

        if ( SMPEG_error(mpeg) )
        {
                fprintf(stderr, "%s: %s", argv[1], SMPEG_error(mpeg));
                SMPEG_delete(mpeg);
        }

        SMPEG_enableaudio(mpeg, 1);
       SMPEG_setvolume(mpeg, volume);

        /* 음악에 대한 정보를 출력한다 */
        if ( info.has_audio )
        {
                printf("%s: MPEG audio stream", argv[1]);
         
                if ( info.has_audio )
                    printf("Audio %s", info.audio_string);

                 if ( info.total_size )
      printf("Size: %d", info.total_size);
             

                  if ( info.total_time )
      printf("Total time: %f", info.total_time);

                   /* 재생하고 재생이 끌날때까지 기다린다 */
      SMPEG_play(mpeg);  

      while(SMPEG_status(mpeg)==SMPEG_PLAYING);

            SMPEG_delete(mpeg); //구조체 반환
       }

       return(0);
    }

  • 여기에 있는 smpeg을 설치한후 프로그램을 컴파일한다. smpeg을 설치하기위해서 미리 SDL을 설치해야 한다. 컴파일할때 헤더파일과 라이브러리파일 경로를 컴파일러에게 알려줘야 한다. 쉽게 하려고 smpeg 패키지는 smpeg-config라는 간단한 도구를 제공한다. 다음과 같이 프로그램을 컴파일한다:
  • gcc playmp3.c `smpeg-config --cflags --libs` -I/usr/include/SDL

  • smpeg-config 명령어를 감싸는 따옴표문자를 주의하라. 보통 backqoute라고 부르며, US식 키보드에서 틸데(~) 문자와 같이 있다. 쉘에서 이 문자는 안에 있는 명령어의 출력을 그 자리에 대신한다. 그냥 smpeg-config 명령만 실행해보면 내가 무슨 말을 하는지 알 것이다. -I/usr/include/SDL 명령행 옵션을 -I < 실제 SDL 경로 >로 수정하라. SDL 함수를 사용하지 않아도, smpeg.h가 내부적으로 SDL 헤더파일을 사용하므로 SDL 헤더파일 경로를 지정해야 한다. RPM 사용자는 프로그램을 컴파일하기위해 smpeg과 smpeg-devel 패키지를 설치해야 한다.
  • SMPEG_new 라이브러리함수는 필요한 내부 객체를 할당하고, MP3 파일에 대한 정보를 SMPEG_info 구조체에 채운다. 프로그램은 이 정보를 출력하고, SMPEG_play를 호출하여 재생을 시작한다. 함수는 즉시 반환되기때문에 다른 작업을 하면서 MP3를 연주하는 프로그램에 유용하다. 이 프로그램에서는 따로 할 일이 없기때문에 재생이 끝날 때까지 기다린다. SMPEG_delete는 그동안 라이브러리가 할당한 모든 메모리를 반환하고, 마친다

 

 글이 여러분의 프로그래밍 작업에 조금이나마 도움이 되길 바란다. 의견을 듣고 싶다. 잘못된 점을 알려주거나 제안을 바란다. shuveb@shuvebhussain.org로 내게 연락할 수 있다.

 

참고로 테스트를 해봤는데 PCM RAW파일로만 가능한다. ^^ 형식이 그렇네. mp3나 다른 형식의 파일을 받아서 cool edit로 변환해 주었다. 쿠울~~~ 에디터 ㄱㄱ 그리고 역시나 속도 그런거 잘 맞춰줘야 한다는 ^^

 

출처 : http://www.whiterabbitpress.com/lg/issue97tag/shuveb.html

 

출처 : 한국어 출처, 원문(영어)

2010년 4월 9일 금요일

리눅스 멀티미디어 프로그래밍

1. Linux용 멀티미디어 환경

 (1) 사운드

  •  기본적으로 리눅스에서는 커널 차원에서 사운드 드라이버를 지원한다.
  • 리눅스 지원 사운드 드라이버
    • 리눅스 커널과 함께 배포된 것(OSS/Free)
    • 상업용 드라이버 OSS
    • 무료로 배포되고 있는 ALSA
  • 커널 표준 사운드 드라이버
    • OSS/Free라고도 불리우며 4Front Technologies 사에서 OSS 개발을 하고 있는 Hanu Savolainen씨가 대부분을 개발했다. 지금도 OSS에서 무상 드라이버를 기부하여 이에 대응하는 사운드 카드는 점점 늘어가고 있다.
  • OSS(Open Sound System)
    • 미국의 4Front Technologes라는 회사가 개발하여 배포하고 있는 사운드 드라이버로 자유롭게 사용할 수 있는 것과 상업용이 있다.
  • ALSA(Advanced Linux Sound Architecture)
    • Jaroslav Kysela(체코 거주)가 메인 프로그래머로서 활동하고 있는 ALSA Project에서 제작, 배포하고 있는 자유 Linux용 사운드 드라이버, GPL에 의한 재배포가 가능함, 커널 표준 드라이버나 OSS 드라이버와의 호환성이 있어, 이들 드라이버용으로 작성된 프로그램의 대부분이 ALSA 드라이버에서 그대로 사용할 수 있다. 인스톨 과정이 좀 복잡함, 커널 2.4부터 자동으로 포함되어 있다.

  (2) 화상(Video)

  •  리눅스에서 지원하는 화상캡쳐 장치들로는 TV 수신카드와 영상 캡쳐 장치들 그리고 USB 화상 CAM 으로 나눌 수 있다.
    • Video4Linux
      • Kernel에서 지원하는 기본 모듈로 TV 수신카드를 지원하기 위해 등장.
    • Video4Linux2
      • Video4Linux 1.0 버전이 TV 수신카드를 위해 등장했기 때문에 화상 Cam에는 맞지 않기 때문에 USB Web CAM을 위해서 등장했다.
      • 화면의 확대/축소 기능 지원

2. Linux Sound 프로그래밍

 (1) 사운드 프로그래밍

  • 리눅스에서의 사운드 프로그래밍은 커널에서 제공해주는 API를 이용해서 만든다.
  • 리눅스 사운드에서 Degital Audio("/dev/dsp"), mixer("/dev/mixer"), MIDI, raw Music 그리고 synthesizer와 같은 장치들을 사용한다.
  • 기본적으로 사용되는 Device 장치들
    • /dev/dsp(Digital voice device)
      • 마이크로 사운드를 녹음하고 스피커로 사운드를 출력하기 위해 사용됨
    • /dev/mixer(mixer)
      • 사운드 볼륨을 조절할 때 사용됨, 마이크의 입력 방향 설정 가능
    • /dev/sequencer(Synthesizer)
      • 사운드로 효과를 만드는데 사용된다. 미리 녹음된 소리(악기 소리나 기타소리)를 합성해서 새로운 소리를 만든다.
    • /dev/music
      • 기본적으로는 "/dev/dsp"와 같다. 차이는 알고리즘 적으로 /dev/dsp는 8bit unsigned 선형(Linear) Encoding을 사용하고, /dev/music은 mu-law Encoding을 사용한다.
    • /dev/midi
      • MIDI 인터페이스를 이용해서 MIDI 장치들(Keyboards, synthesizers, stage props)을 연결하는데 사용된다.
  • 우리는 여기서 /dev/dsp를 이용해서 사운드를 입력 받아서 출력하는 어플을 작성

 (2) OSS API Basic

  • OSS API들은 <soundcard.h>라는 헤더파일에 정의되어 있다.
  • 위의 헤더파일은 보통 "/usr/include/sys"에 위치하고 있다.
  • OSS에서 장치의 값을 설정하고 읽어오는 방법은 ioctl() 함수를 이용한다.

 (3) Audio Programming

  • 디지털 오디오(Digital Audio)는 컴퓨터 외부로 소리를 표현하는 일반적인 방법이다.
  • 오디오 프로그래밍의 일반적인 방법
    • 오디오 장치를 open() 한다.
    • 환경을 설정한다.
    • 입출력을 위한 메모리(버퍼)를 설정한다.
    • Read/Write 작어
    • 사용이 끝난 오디오 장치를 close() 한다.
  • 우선 "/dev/dsp"를 사용하기 위해서는 open()을 이용해서 장치를 열어야 한다.

### fedora11에서는 커널에 기본적으로 /dev/dsp와 /dev/mixer가 모듈로 설치가 되어서 부팅후 모듈을 올려줘야 한다. 아래처럼 시스템 시작시 모듈로 올라가도록 해준다.

# vi /etc/rc.d/rc.local
 ...
modprobe snd-pcm-oss

 

 

 (4) 사운드 장치 열기

  • open()의 flag 값
    • O_RDONLY : 사운드 장치(보통 마이크)로부터 입력을 받을 때 사용한다.
    • O_WRONLY : 사운드 장치(뽀통 스피커)로 사운드를 출력할 때 사용한다.
    • O_RDWR : 사운드 장치에서 사운드를 입력과 출력을 동시에 할 경우 사용된다.
    • if( fd = open("/dev/dsp", O_WRONLY, 0) ) == -1 ){
          perror("OSS : error opening device\n");
          return -1;
      }

  • 사운드 장치를 사용할 수 없을 경우 -1을 반환한다. 만약 다른 프로그램에서 사운드 장치를 사용하고 있을 경우 "EBUSY"라고 에러값을 설정한다.

 

 

 (5) 샘플링 환경 설정하기

  • 사운드 장치를 open한 후에는 사운드 입출력을 하기 전에 기본적인 설정이 필요하다. 사운드 음질에 영향을 미치는 다음의 기본적인 세가지 parameter가 존재한다.
    • Sample format(number of bits)
    • Channel의 수(mono or stereo)
    • Sample Rate(spee)
  • 위의 설정은 순서대로 해야한다. 아래의 설정을 위의 설정보다 먼저하면 설정이 되지 않는다.

 

 

 (6) 오디오 포맷 설저하기

  • Sample format은 음질에 영향을 미치는 중요한 변수이다.
  • Sample format은 여러가지가 있지만 여기서 AFMF_S16_LE를 사용하겠다. AFMF_S16_LE는 Signed 16Bit Little Endian을 뜻한다. 이 포맷은 일반적인 PC의 사운드 카드에서 사용되고 있다.
  • 사운드 카드를 설정하기 위해서는 앞에서 설명한 ioctl()에 매개변수로 SNDCTL_DSP_SETFMT를 사용한다.
    format = AFMF_S16_LE;
    if( ioctl(fd, SNDCTL_DSP_SETFMT, &format) == -1 ){
        perror("SOUND_PCM_SETFMT");
        return -1;
    }

 

 

 (7) 채널의 수 설정하기

  • 현재 사용되는 대부분의 오디오 장치들은 Stereo모드를 지원한다. 기본적으로 설정되는 모드는 Mono이다.
  • ioctl()에 SNDCTL_DSP_CHANNELS을 사용해서 채널의 수를 선택할 수 있다.
  • Mono의 경우는 1이고, Stereo는 2이다.
  • stereo = 2; // 1 : mono, 2 : stereo
    if( ioctl(fd, SNDCTL_DSP_CHANNELS, &stereo) == -1 ){
        perror("SOUND_PCM_CHANNELS");
        return -1;
    }

 

 

 (8) Sampling Rate 설정하기

  • Sampleing Rate는 소리의 질을 결정하는 파라미터이다.
  • OSS API는 1Hz에서 2GHz의 대역을 지원한다. 기본적으로 지원되는 Sampling rate는 8kHz이다.
  • 전화기(음성)에서 기본적으로 사용하는 것이 8kHz이다. CD의 경우 44.1kHz, DVD의 경우 96kHz의 값을 가지고 있다.
  • 우리는 음성을 이용해서 녹음/재생할 것이므로 8kHz를 이용할 것이다.
  • ioctl()에 SNDCTL_DSP_SPEED를 이용하면 Sampling Rate를 선택할 수 있다.
  • rate = 8000;
    if( ioctl(fd, SNDCTL_DSP_SPEED, &rate) == -1 ){
        perror("SOUND_PCM_SPEED");
        return -1;
    }

 

 

 (9) Full Duplex 설정하기

  • 많은 장치들이 half duplex이다. Half duplex의 경우 Recording이나 Playing이 동시에 되지 않는다. 오직 한 번에 한 가지의 일을 할 수 있다.
  • 물론 다중 채널이 지원되는 경우 Recording과 Playing을 각각 다른 채널을 이용해서 하면 된다.
  • 단일 채널에 Full Duplex를 지원하기 위해서는 사운드 장치를 설치하기에 앞서서 Full Duplex로 설정해아 한다. 설정은 다음과 같다.
  • if( ioctl(fd, SNDCTL_DSP_SETDUPLEX, 0) == -1){
        perror("SOUND_PCM_SETDUPLEX");
        return -1;
    }

 

 

 (10) 사운드 입/출력

  • 일반적으로 리눅스에서는 장치를 파일의 개념으로 사용한다.
  • 사운드를 입력받기 위해서는 파일을 읽는 것과 마찬가지로 read()를 사용한다.
  • if( status = read(fd, buf, count) ) == -1 ){
        perror(SOUND_READ_ERROR");
        return -1;
    }

  • 마친가지로 사운드를 출력하기 위해서는 write()를 사용한다.
  • if( status = write(fd, buf, count) ) == -1 ){
        perror("SOUND_WRITE_ERROR");
        return -1;
    }

  • 더 자세한 사항을 알고 싶으면 OSS API 문서를 참조하라.

 

 

 (11) 동시에 여러가지 일하기

  • 여러가지 일을 동시에 실행시키기 위해서는 thread나 멀티  proecess를 사용해야 한다. 이것들은 설정이 복잡하다. 그래서 여기서는 기본적으로 Qt에서 제공하는 QTimer를 사용하도록 한다.(자세한 내용은 출처를 참고한다.)

 

3. Video4Linx 프로그래밍

  • Video4Linux는 리눅스에서 비디오 장치들을 제어하고 사용하기 위한 API들의 모임이다.
  • 비디오 장치들로는 튜너를 가지고 있는 비디오 카드나 PC Web CAM과 같은 장치들을 들 수 있다. 튜너를 가지고 있는 장치들을 제어해서 TV나 AM/FM 라디오, TeleText등의 방송을 시청할 수 있다.
  • Video4Linux는 커널에 기본적으로 포함되어 있으므로 따로 설치할 필요가 없다.
  • 이 Video4Linux를 이용해서 X윈도우 상에서 TV를 볼 수 있는 프로그램으로는 xawtv나 xwintv 등이 있다.
  • 이 곳에서는 Philips Web Cam을 이용해서 프로그램할 것이다. 튜너를 가지고 있는 디바이스(BT848)도 거의 같은 방식으로 동작하기 때문에 프로그램을 적용하는데 무리가 없을 것으로 생각이 든다.
  • 비디오 화면을 캡쳐하는 순서(드라이버에 따라서는 mmap 등 일부의 조작이 그 기능이 없는 경우 malloc으로 메모리 버퍼를 잡을 수도 있다.)
    • Video4Linux 장비의 정보(사양)을 얻기
      • capture 카드에 관한 정보를 얻는다. 프로그램 내에서 capture 카드를 하나로 고정하고 있다면, 하지 않아도 된다.
    • 사용 가능한 채널 얻기
      • capture 카드로 사용 가능한 채널(영상 소스)의 종류를 취득한다. 이것도 위와 마찬가지로 프로그램 내에서 capture 카드를 하나로 고정하고 있다면, 하지 않아도 된다.
    • Capture할 채널의 설정
      • 앞에서 가져온 정보를 이용해서 capture 하는 채널을 선택한다. 동시에, 영상 신호의 포맷 종류(NTSC, PAL, SECAM 등)도 선택한다.
    • 파라미터 설정
      • 밝음(Brightness), 대비(Contrast), 휴(Hue) 등의 파라미터 설정한다.
    • 메모리 공간 할당
      • malloc이나 mmap의 시스템 콜을 이용해서 캡쳐할 영상이 저장될 메모리 기억공간(buffer)을 확보한다.
    • Capture 시작하기
      • 앞에서 확보한 메모리 공간에 capture가 되도록 한다.
    • Capture 종료까지 기다리기
      • 그 밖에 하는 것이 없으면, capture 처리가 종료될 때까지 기다린다.
    • 화성처리
      • capture한 버퍼 내의 영상 데이터를 원하는 목적으로 처리한다. 이 과정에서 화면에 영상을 표시할 수 있다.
  • 더 자세한 내용은 출처를 참고한다.

 

 

출처 : 리눅스 멀티미디어 프로그래밍

전역변수에 왜 static을 사용했을까?

  • 전역변수에서의 static은 해당하는 파일 내에서만 사용한다는 의미를 가지고 있다.
  • 여러 개의 파일로 개발할 때에 유용한다.
  • a.c라는 파일과 b.c라는 파일에 똑같이 전역변수를 정의할 경우, c.c라는 파일에서 해당하는 전역변수를 사용하려 할 때 어느 쪽을 사용해야 할지 헷갈리게 된다. 아마도 링크 시에 에러가 날 것이다.
  • 전역변수를 static으로 정의하면 그 파일 내에서만 사용할 수 있으므로 외부에서는 변수에 접근을 못한다. 이로 인해 디버깅의 노력을 줄일 수 있다.
  • 완전히 외부 모듈에 공개할 것만 일반적인 전역변수로 잡고 나머지 모듈 내에서 사용할 것은 모두 static으로 선언하면 static 변수를 누가 바꿨는지 추적하기 위해 모든 소스를 뒤질 필요가 없다.

출처 : 네이버 지식in

inline 함수

< inline 함수 >

- 매크로 함수와 그냥 함수의 중간적인 성격을 띈 함수이다.

 

* 사용 이유

  • 일반적인 함수를 사용하면 필요할 때마다 호출하여 사용하므로 실행파일의 크기를 줄일 수 있으나 제어권의 이동이 심하므로 실행 속도가 느려진다.
  • 매크로 함수는 컴파일시 전개되어 치환되므로 제어권 이동이 발생하지 않으므로 속도가 빠르지만 데이터형 지정을 할 수가 없고 실행파일의 용량이 커지게 된다.
  • 인라인 함수는 컴파일시 통째로 매크로처럼 전개되어 속도면에서 큰 이득을 얻는다. 그리고 데이터형 체크를 할 수 있다. 용량이 커지는 단점이 있긴 하지만 간단한 작업을 하는 함수의 경우에 이용하면 매우 편리하다.

* 장점

  • function call이 생략되는 형태로 실행되기 때문에 function call에 의한 여러가지 오버헤드(CPU register 백업, stack 관리 등)를 생략하기 때문에 간단하면서 자주 사용되는 함수에는 더 빠른 효율성을 갖게 된다.

*단점

  • 지나친 inline 함수의 사용은 실행파일이 커지게 하고, 이 때문에 페이지 폴트를 야기하는 원인이 되어 퍼포먼스가 떨어지게 되기도 한다.

* 매크로 함수와 인라인 함수의 차이점

  • 안정성 측면에서 inline 함수가 앞선다.

* inline 함수의 제약조건

  • inline 함수 내에서는 루프문(do while, while, for), switch, goto문을 사용할 수 없다.
  • inline 함수 호출시 호출되기 전에 먼저 inline 함수가 정의되어 있어야 한다.
  • inline 함수 내에서 재귀호출을 할 수 없다.
  • inline 함수는 한 수식 내에서 두 번이상 호출될 수 없다.
  • 함수 포인터로 inline 함수의 주소를 취할 수 없다.
  • inline 함수는 호출방식이 아니라 치환전개방식이기 때문이다.

 

출처

2010년 4월 3일 토요일

pthread 사용하기

< pthread 사용하기 >

1. 기본 쓰레드 함수

(1) pthreard_create
  • 쓰레드 생성을 위해 사용(pthread_t)
  • 첫번째 인자는 쓰레드 식별자
  • 세번째 인자는 쓰레드 실행시 호출되는 함수
  • 네번째 인자는 그 함수의 인자
  • 리턴값은 쓰레드 ID
  • 실행된 쓰레드에 대해서는 pthread_join 등의 함수를 이용해서 쓰레드 종료 때까지 기다려줘야 한다. pthread_join은 일종의 fork의 wait와 비슷하게 동작하며, 쓰레드 자원을 해제시켜 준다.
  • ex) thr_id = pthread_create(&p_thread[1], NULL, t_function, (void *)&a);
(2) pthread_join
  • 첫번째 인자는 기다릴(join)할 쓰레드 식별자
  • 두번째 인자는 쓰레드의 return값
  • 두번째 인자가 NULL이 아닐 경우 해당 포인터로 쓰레드 return값을 받아올 수 있다.
  • ex) pthread_join(p_thread, (void *)&status);

(3) pthread_detach
  • detach는 "떼어내다"라는 뜻을 가지며, main 쓰레드에서 pthread_create를 이용해 생성된 쓰레드를 분리시킨다.
  • 이 함수는 식별번호(첫번째 인자)인 쓰레드를 detach시키는데, detach 되었을 경우, 해당(detach)된 쓰레드가 종료될 경우 pthread_join을 호출하지 않더라도 즉시 모든 자원이 해제(free) 된다.
  • detach를 하지 않을 경우, 쓰레드 함수가 종료되더라도 자원이 해제되지 않는다.
  • pthread_create 호출 후 detach할 수 도 있고, pthread_create 호출시에 쓰레드가 detach 되도록 할 수도 있다.(pthread_attr_setdetachstate 참조)
  • ex) pthread_detach(p_thread);

(4) pthread_exit
  • 현재 실행 중인 쓰레드를 종료시키고자 할 때 사용한다.
  • pthread_cleanup_push가 정의되어 있다면, pthread_exit가 호출될 경우 cleanup handler가 호출된다. 보통 이 cleanup handler는 메모리를 정리하는 등의 일을 하게 된다.
  • ex) pthread_exit(0);

(5) pthread_cleanup_push
  • cleanup handler를 인스톨하기 위해서 사용된다.
  • pthread_exit가 호출되어서 쓰레드가 종료될 때 pthread_cleanup_push에 의해서 인스톨된 함수가 호출된다.
  • 첫번째 인자가 쓰레드가 종료될 때 호출되는 함수이다.
  • 두번째 인자는 이 때의 아규먼트이다.
  • cleanup handler는 주로 자원을 돌려주거나, mutex 잠금등의 해제를 위한 용도로 사용된다. 만약 mutex 영역에서 pthread_exit가 호출되어 버릴 경우, 다른 쓰레드에서 영원히 block 될 수 있기 때문이다.
  • 또, malloc 으로 할당받은 메모리, 열린 파일지정자를 닫기 위해서도 사용한다.
  • ex) phread_cleanup_push(cleanup, (void *)&a);

(6) pthread_cleanup_pop
  • pthread_cleanup_push와 함께 사용되며, cleanup handler를 제거하기 위해서 사용된다.
  • pthread_cleanup_push와 pthread_cleanup_pop은 반드시 같은 함수 내의 같은 레벨의 블럭에서 한 쌍으로 사용해야 한다.

(7) pthread_self
  • pthread_self를 호출하는 현재 쓰레드의 쓰레드 식별자를 리턴한다.
  • ex) ptread_t id;        id = pthread_self();

2. 쓰레드 동기화 함수

(1) pthread_mutex_init
(2) pthread_mutex_distroy
(3) pthread_mutex_lock
(4) pthread_mutex_unlock
(5) pthread_cond_init
(6) pthread_cond_signal
(7) pthread_cond_boradcast
(8) pthread_cond_wait
(9) pthread_cond_timewait
(10) pthread_cond_destroy
(11) 예제 코드

3. Thread Attribute 함수

(1) pthread_attr_init
(2) pthread_attr_distroy
(3) pthread_attr_getscope
(4) pthread_attr_setscope

4. 쓰레드 시그널 관련

(1) pthread_sigmask
(2) pthread_kill
(3) sigwait

5. 쓰레드 취소
(1) pthread_cancel
(2) pthread_setcancelstate
(3) pthread_getcancelstate



getch(), getchar(), getche() 가 필요한 이유

< getch(), getchar(), getche() 가 필요한 이유 >

* 공통 기능
  • 키보드로부터 문자 하나를 입력 받아 리턴한다.
  • 키보드에서 문자가 눌러질 때까지 무한대로 대기한다.
  • 키보드 입력시까지 대기시키는 목적으로 많이 사용된다.
* getch()
  • 에코 기능이 없다.
  • 입력받은 문자를 리턴한다.
  • 확장키 코드가 입력되었을 때는 0을 리턴한다. 이 경우 getch를 한번 더 호출하면 확장키 코드를 얻을 수 있다.
* getchar()
  • getch() 함수와 비슷하다. 유닉스에서 사용가능
* getche()
  • getch() 함수와 같되 에코 기능이 있다.

### int fflush(FILE * stream);
  • 스트림에 할당되어 있는 버퍼를 비운다.
  • 버퍼를 비운다는 의미는 입력, 출력에 따라 의미가 다르다.
    • 출력시 : 출력 대기중에 임시적으로 버퍼에 있던 데이터들이 파일에 기록된다.
    • 입력시 : 버퍼에 있던 데이터를 모두 지운다. 그리고 다시 새로운 데이터를 입력 받게 된다.
  • 버퍼를 비운다는 말은 버퍼에 들어있는 데이터를 없앤다는 의미이다.
  • fflush 실행 후에도 스트림은 여전히 개방된 상태로 남는다.
  • 성공시 0을 리턴, 에러 발생시 EOF 리턴

### linux에는 getch() 함수가 없기 때문에 함수를 만들어 사용해야 한다.

#include <termios.h>
#include <unistd.h>

int mygetch(void)
{
    struct termios oldt, newt;
    int ch;

    tcgetattr( STDIN_FILENO, &oldt );

    newt = oldt;
    newt.c_lflag &= ~( ICANON | ECHO );
    tcsetattr( STDIN_FILENO, TCSANOW, &newt );

    ch = getchar();
    tcsetattr( STDIN_FILENO, TCSANOW, &oldt );

    return ch;
}





2010년 4월 2일 금요일

NFS 설정

< Mini2440 NFS 설정 >

1. NSF setting
#get /etc/exports
/opt/FriendlyARM/MINI2440/root_qtopia *(rw,sync,no_root_squash)


2. firewall disable
# lokkit => disabled


3. start and stop nfs server
# /etc/init.d/nfs start
#mount -t nfs localhost:/opt/FriendlyARM/MINI2440/root_qtopia /mnt/
# /etc/init.d/nfs stop


3.1 in nfs server in gui
# serviceconf
 nfs => enable


4. booting system via nfs
 1) Nand flash로 모드 전환
 2) 전원 케이블, 시리얼 케이블 네트워크 케이블 연결
 3) 터미널 오픈
 4) 타겟 보드 power on
 5) vivi shell에서
   Supervivi> param set linux_cmd_line "console=ttySAC0 root=/dev/nfs nfsroot=192.168.1.70:192.168.1.111:192.168.1.111:255.255.255.0:MINI2440.arm9.net:eth0:off"

 6) vivi shell에서 boot 타이핑