출처: http://fastironex.blogspot.com/2010/02/1588-ecn-asia.html


대부분의 엔지니어들은 원격지의 정확한 동기화 이벤트를 위해 이더넷 통신 기반의 장비를 이용할 수 없다는 것을 알고 있다. 이러한 문제를 해결하기 위해 IEEE는 일부 산업 제어 업체들과 장비 벤더들이 채택한 타임 동기화 표준을 발표했다. IEEE 1588(2002)이라고 불리는 이 표준은 디바이스가 네트워크상에서 가장 정밀하고 정확한 클럭을 활용할 수 있는 프로토콜을 제공한다. 네트워크상에서 타이밍을 동기화해야 하는 임베디드 시스템 개발자들도 이 표준의 혜택을 누릴 수 있다.


장비 내 각각의 부분별로 별도의 정확한 클럭이 존재하지만 ns에서 μs 사이에 발생하는 회로의 변화나 작은 차이도 금방 누적된다. 또한 네트워크 연결로 인해 레이턴시 지연, 즉 ‘지터(Jitter)’ 또한 발생한다. 장비 제조업체들이 제품에 1588 기능을 탑재하거나 제품에 1588 기능을 추가함으로써 엔지니어들은 이러한 타이밍 문제를 해결할 수 있다. 네트워크 구성과 장비에 따라 동기화된 클럭은 수십ns~수μs 내에 추적이 가능하다.


다음 단계들은 일반적으로 1588 PTP(Precision Time Protocol)가 IEEE 1588 호환 디바이스와 어떻게 동작하는지 설명하고 있다.

* 네트워크에 추가될 때 디바이스는 클럭 정보를 전송하고 네트워크의 다른 클럭 정보를 수신하는 BMC(Best Master Clock) 알고리즘을 실행한다. 최적의 클럭이 마스터가 되고 다른 모든 디바이스들은 슬레이브로 동작한다.


* 마스터가 동기화 메시지를 모든 슬레이브에 보내고 내부 전송 타임 스탬프를 생성한다.(그림 1) 슬레이브가 동기화 메시지를 수신할 때 슬레이브는 자체 도착 타임 스탬프를 생성한다. 마스터 클럭은 전송 타임 스탬프 데이터를 포함한 메시지를 뒤따라 전송한다. 이 때 각 슬레이브는 마스터가 동기화 메시지를 보낸 때와 도착한 때를 알게 된다. 이 시간 차로 각 슬레이브는 내부 클럭을 마스터 클럭과 동기화 한다. 타임 스탬프 차이에는 네트워크 전파 지연이 포함된다는 사실에 주의해야 한다.


* 네트워크 지연을 정하기 위해 슬레이브는 지연 요청 메시지를 마스터에 전송하고 타임 스탬프를 생성한다. 마스터는 지연 요청 메시지의 도착 시간을 기록하고 이 정보를 지연 응답 메시지를 통해 슬레이브로 보낸다. 두 타임 스탬프의 시간 차가 네트워크 전파 지연을 나타낸다. 이제 슬레이브는 지연을 고려하여 내부 클럭을 미세 조정한다. 이 방법이 제대로 되려면 네트워크는 마스터와 각 슬레이브 간에 대칭적 지연을 제공해야 한다.


* 일정한 시간 간격(디폴트는 2초)을 두고 마스터는 클럭 동기화를 유지하기 위한 후속 메시지와 새로운 동기화 메시지를 전송한다. 제품에 IEEE 1588을 구현할 계획이라면 여러 제조업체들로부터 도움을 얻을 수 있다. 예컨대 IXXAT는 OS와 상관없이 동작하는 PTP 프로토콜 소프트웨어를 공급하고 있으며, 이 소프트웨어는 이더넷 스택의 UDP(User Datagram Protocol) 소켓에 연결된다. 이 소프트웨어는 클럭 인터페이스와 타임 스탬프 유닛을 제공한다. 유저가 좀더 빨리 시작할 수 있도록 IXXAT 패키지에는 프리스케일 PowerQUICC MPC8360 프로세서용 구현 샘플이 함께 제공된다. 이 칩에는 타임 유닛과 시스템 클럭, PTP 기반 타이머가 통합되어 있으며, 이를 통해 설계자들은 20ns의 정확한 타임 베이스를 구현할 수 있다.(www.ixxat.com)

실시간 시스템의 경우에도 마스터와 슬레이브 클럭을 구현하는 소프트웨어를 공급하고 있다. RTS 프로토콜 스택은 지속적으로 타이밍 메시지를 교환하는 방법으로 가장 정확한 클럭을 자동으로 정하고 RTC를 조절한다. 이 소프트웨어는 통계 기술을 사용하여 잔여 클럭 편차를 더욱 낮춘다. RTS IEEE 1588 프로토콜 스택은 핫 스와핑 디바이스용으로 공급되므로 언제든지 네트워크에 ‘연결’하거나 네트워크에서 ‘분리’시킬 수 있다. 이 업체는 PTP 네트워크를 모니터링하고 조정, 분석하는데 사용되는 오픈 소스 툴을 제공한다. 엔지니어들은 이 스택의 소스 코드를 구할 수 있다. 또한 이 업체는 IEEE 1588 프로토콜의 하드웨어 구현을 제공한다.(www.real-time-systems.com)


하드웨어의 경우 내쇼날 인스트루먼트는 마스터 또는 슬레이브로 동작이 가능하고 PCI 버스로 동작하는 하드웨어 타임 스탬프 유닛을 구현한 PCI-1588 카드를 판매하고 있다. 많은 분산형 제어, 계측 및 데이터 수집 시스템이 호스트 컨트롤러에 의존하고 있기 때문에 이 카드는 PC에 쉽게 실장이 가능하며, 마스터 카드로서 역할을 한다. 이 카드는 3가지 범용 출력을 통해 IEEE 1588 프로토콜과 호환되지 않는 클럭을 동기화할 수 있다. 내쇼날 인스트루먼트는 NI-Sync 드라이버 소프트웨어(www.ni.com)를 제공한다.


만약 프로토콜 테스트 셋업을 완료하고 즉각적으로 동작시키길 원한다면 Hirschmann Automation and Control의 산업용 이더넷 스위치와 Meinberg의 GrandMaster 클럭을 모두 포함하고 있는 Meinberg의 3가지의 스타터 키트를 고려할만 한다. 1588 지원 장비를 테스트하거나 혹은 1588 기반 네트워크용 소프트웨어를 개발하거나 기존 장비에 1588을 통합하는 등 각각의 엔지니어 요구 조건에 맞게 키트를 고르면 된다.(ptp-starterkit.meinberg.de)


Illustrations:

Figure 1


참고자료

1. “IEEE 1588 Protocol Stack Product Documentation,” Real Time Systems. www.real-time-systems.com/ieee_1588_documentation.html.
2. “Introduction to Distributed Clock Synchronization and the IEEE 1588 Precision Time Protocol,” National Instruments. www.ni.com. Search Developer Zone for “1588.”
3. Eidson, John C., and Dan Pleasant, “Time Scales and IEEE 1588,” Part 2, LXIConnexion, July 2006, www.lxiconnexion.com.
4. Mohl, Dirk, “IEEE 1588: Running Real-Time on Ethernet,” Industrial Networking. www.industrial-networking.com.
저작자 표시 비영리 변경 금지
신고
블로그 이미지

꽃중년

불만있으면 떠나라...

SDH, PDH

전송 2010.06.07 12:45
출처: http://www.cable04.co.kr/BBDays/comms/knowhow.asp?job=view&mnu=&brd=110600&seq_no=582&req_flag=0&que_page=2&ans_page=21


개요 

 디지털화 된 음성신호의 고속전송을 위해서 PDH가 제안되었지만, 동기화의 문제와 다단계 다중화에 따른 망 운영의 비효율성 때문에 새로운 방식의 디지털 계위 필요성으로 기존의 디지털 전송구조의 단점을 보완하여 일단계 다중화로 표준화한 것이 SDH이다. 동기식 디지털 계위에는 155.520Mbps 비트율의 신호를 n개 바이트 교직 다중화(BIM : Byte Interleaved Multiplexing) 시킨 형태를 갖는 STM(Synchronous Transport Module) 신호 STM-n이 있다. SDH는 PDH에 비해 외형상 지극히 단순한 구조를 지니고 기존 PDH의 DS1∼DS4계위 신호들을 STM-n 신호로 매핑 시키는 동기식 다중화 과정은 매우 복잡하다. 

SDH 프레임 구조

  SDHD의 기본 전송단위는 STM-1이며 기본속도는 155.52Mbps이다. STM-1 Frame은 ,그림 8-2>에서 보듯이 신호프레임의 반복주기가 9행 * 270 Byte이고, Over Head와 Payload로 구성되어 있다. 기본속도 155.52Mbps는 8,000Frame/sec*9*270*8bit이다.

( 그림 8-2 ) STM-1의 구조 

Over Head는 정보신호의 감시 및 망운용 정보를 전송하며 구간 오버헤드(SOH:Section Over Head)와 경로 오버헤드(POH: Path Over Head)로 구성되어 있다. SOH는 재생기간의 전송의 신뢰성을 높이는데 사용되는 3 byte의 재생기 SOH(Regenerator SOH)와 다중화기간에 필요한 정보를 상호 전달하는데 사용되는 5 byte의 다중화기 SOH가 있다. 반면 POH는 VC에 대하여 Data에러를 감시하고, VC 신호가 구성될 때마다 삽입된다. 상위 POH는 VC-4, VC-3이고, 하위 POH는 VC-11, VC-12, VC-2가 있다. 

 동기식 다중화 구조 

 동기식 다중화구조를 구성하는 계위 신호들을 북미식, 유럽식 계위 신호 모두이다. 따라서 모든 신호들이 PDH, SDH 절차를 동하여 STM-n 신호에 다중화될 수 있음을 나타내고 있다. 동기식 신호를 구성하는 단위들은 아래와 같다. 

(1) C(Container) : 동기식 다중화 구조를 구성하는 기본신호 단위로 Palyload에 들어갈 최소 정보단위이다.
     PHD신호를 수용하기 위한 콘테이너는 C11, C12, C2, C3, C4가 있고 ATM Cell들은 C4에 매핑된 후  동기식 다중화된다. 
(2) VC(Virtual container) : POH와 Payload로 구성된다. VC1, VC2는 저위 VC이고 VC3, VC4는 고위 VC이다. 
(3) TU(Tributary Unit) : 저위 VC를 고위 VC로 다중화할 때 사용하며 Payload 와 TU포인터로 구성된다.  
(4) TUG : TU 한 개 이상 결합한 것으로 Byte Interleaving방식으로 다중화한다. Interleaving이란 brusty한 에러를 분산시켜 robust한다. 
(5) AU(Administrative Unit) : 고차 VC를 전송하는 단위로 Payload와 AU Pointer로 구성된다.  
(6) AUG : AU 신호들이 한 개 이상 결합한것  
(7) STM-n : 동기식 다중화 구조의 최종신호 단위로서 실제 동기식 전송망에 전송되는 신호이다. STM-n은 AUG를 n개 바이트 교직 다중화(BIM) 시킨 후 SOH를 더하여 만들어진다.  

 각종 계위 시노들은 STM-n 신호로 다중화 시키는 과정을 동기식 다중화라고 하며, C, VC로의 매핑, TU, AU로의 정열, TUG AUG로의 다중화, 포인터 처리를 통하여 이루어진다. 

(1) 매핑(Mapping) :  PDH계 Data를 해당 VC에 싣는 과정으로 비동기식 신호를 동기식 구조로 맞추는 일이다.  
(2) 정렬(Aligning) : 프레임 어긋남(Frame Offset)에 관한 정보를 반영하면서 VC를 TU 또는 AU에 싣는 과정 
(3) 포인터 처리 : VC를 TU 또는 AU에 정렬시키면서 프레임 어슷남 정보를 포인터에 기록하는 것 
(4) 다중화 : TU가 TUG로, AU가 AUG로 적응되는 과정

다음 <그림 8-3>은 동기식 다중화 절차를 나타내고 있다. 

 ( 그림 8-3 ) 동기식 다중화 절차 

지금까지 논의된  PDH와 SDH의 주요 특징을 비교하면 <표 8-2>와 같다.  

<표 8-2> PDH 와 SDH의 비교
PDH SDH
다단계(N-STEP) 다중화 일단계 다중화
비트 스터핑에 의한 동기화 포인터에 의한 동기화
고위 신호상에서 저위 신호가 가시적이지 않음 STM-1내에서 단위 신호가 가시적임
Point To Point 환경에 적합 망 환경에 적합
세계 표준이 없음 세계 표준임
매 단계 새로운 오버헤드 추가 오버헤드 추가 없음
PSTN에 적합 BISDN에 적합

동기식 전송 방식의 특징

(1) 125μsec Frame : Frame 구조가 125μsec 단위로 구성되어 모든 Data처리
(2) 디지털 계층의 통합 : 북미식, 유럽식, 디지털 신호 모두 수용
(3) 계층화 구조 : Frame 구조에서 오버헤드를 SOH, POH로 구분
(4) 오버헤드의 체계적 활용 : SOH, POH, 포인터 등을 이용한 통신망 운용 관리 및 보수가 원할
(5) 포인터에 의한 동기화
(6) 일단계 다중화



저작자 표시 비영리 변경 금지
신고
블로그 이미지

꽃중년

불만있으면 떠나라...

Tag sdh

1. Subversion Server 프로그램 다운로드
http://subversion.tigris.org/servlets/ProjectDocumentList?folderID=8100 에서 "Setup-Subversion-x.x.x.msi" 다운로드 (http://subversion.apache.org/)

2. Subversion Client 프로그램 다운로드
http://tortoisesvn.net/downloads

3. 저장소(repository) 만들기
  • 임의의 장소에 "루트" 폴더 생성 ==> "D:\SVN_ROOT"
  • command 창에 G:\SVN_root> svnadmin create sample ==> sample 저장소 생성
  • 또는 sample 폴더를 만들어 놓은 후 마우스 우클릭 "TortoiseSVN >> Create repository here..."
4. 저장소\conf\ 폴더내의 config 파일 수정

[svnserve.conf ]

...
anon-access = read          // 비인증 사용자는 읽기만 가능하다. [none/read/write]
auth-access = write          // 인증 사용자는 쓰기도 가능하다
...
password-db = passwd     // 패쓰워드 관련 파일은 passwd 파일을 참조한다.
authz-db = authz               // 인증 관련 파일은 authz 파일을 참조한다.
...

[passwd]

[users]
user_name = password

[authz]

[groups]
manager = user_name

[/]
user_name = rw


5. SVN server 윈도우즈 서비스 등록하여 실행하기
command 창에서 아래 명령 실행 ("=" 뒤에는 반드시 공백, 관리자 모드로 실행)

prompt> sc \\컴퓨터명 create svnserve binPath= "C:\Program Files\Subversion\bin\svnserve.exe --service -r D:\svn_root" DisplayName= "Subversion svnserve"

"제어판\시스템 및 보안\관리 도구 >> 서비스" 에서 시작/중지/자동/수동 선택

6. SVN 기본 에디터 등록
svn 명령 사용전 기본 에디터 등록.
윈도우즈 (시스템)환경변수에 SVN_EDITOR를 만들고, 에디터의 실행 파일 경로를 설정

7. 하위 폴더 만들기
prompt> svn mkdir svn://127.0.0.1/sample/trunk
commit 메시지가 나오면 적절히 로깅 후 종료하면 commit 성공

8. Repository Browser
SVN_ROOT 마우스 우클릭 >> TortoiseSVN >> Repository Browser
URL 입력창에 "svn://127.0.0.1/sample" 입력


저작자 표시 비영리 변경 금지
신고
블로그 이미지

꽃중년

불만있으면 떠나라...


출처: http://alan.keum.org/183


Microsoft Visual Studio 2008 설치 제거시 
A problem has been encountered while loading the setup components.
 Canceling setup
이라는 메시지만 출력하고 제거가 안되는 경우.


- 영문 Visual Studio 2008 HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Installer\Products\DCC60C0870D76BD368DC5BB7F360418D\Patches\
Patches(REG_MULTI_SZ) 항목을 제거하고 다시 설치제거 시도.

- 한글 Visual Studio 2008
HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Installer\Products\2F5B0C81B134C6130A6B87589A22B84A\Patches\
Patches(REG_MULTI_SZ) 항목을 제거하고 다시 설치제거 시도.

저작자 표시 비영리 변경 금지
신고
블로그 이미지

꽃중년

불만있으면 떠나라...

yum 명령어

잡다구리 2009.07.21 11:53


출처 : 한국 LUG

 


1. 업데이트할 목록을 보려면?

# yum list updates

2. 업데이트 목록을 다운로드하고, 업데이트를 설치하려면?

# yum update -y

3. 설치된 rpm 패키지 목록을 보려면?

# rpm -qa
# yum list installed

4. gcc 패키지가 설치되어 있는지 확인 하려면?

# rpm -qa | grep gcc
# yum list installed gcc

5. gcc 패키지를 설치하려면?

# yum install gcc

6. gcc 패키지를 업데이트 하려면?

# yum update gcc

7. 패키지 이름으로 검색하려면?

# yum list 패키지명
# yum list 정규식
# yum list gcc
# yum list gcc*

8. 여러개의 패키지를 설치하려면?

# yum install gcc gcc-c++

9. 패키지를 삭제하려면?

# yum remove gcc gcc-c++

10. 설치가 가능한 모든 패키지를 보려면?

# yum list all

11. 패키지 그룹을 보려면?

# yum grouplist

12. 그룹 패키지를 모두 설치하려면?

# yum groupinstall "Development Tools"

13. 그룹 패키지를 업데이트 하려면?

# yum groupupdate "Development Tools"

14. 그룹 패키지를 삭제하려면?

# yum groupremove "Development Tools"

15. 아키텍처를 지정하여 설치하려면?

# yum install mysql.i386

16. 파일을 가지고 있는 패키지명을 알려면?

# rpm -qf /etc/passwd
# yum whatprovides /etc/passwd

17. 맨페이지를 보려면?

# man yum


저작자 표시 비영리 변경 금지
신고
블로그 이미지

꽃중년

불만있으면 떠나라...

Tag yum

apt-get 명령어

잡다구리 2009.07.21 11:35

출처: http://blog.outsider.ne.kr/346


패키지 인덱스 인덱스 정보를 업데이트 : apt-get은 인덱스를 가지고 있는데 이 인덱스는 /etc/apt/sources.list에 있습니다. 이곳에 저장된 저장소에서 사용할 패키지의 정보를 얻습니다.
apt-get update

설치된 패키지 업그래이드 : 설치되어 있는 패키지를 모두 새버전으로 업그래이드 합니다.
apt-get upgrade
의존성검사하며 설치하기
apt-get dist-upgrade

패키지 설치
apt-get install 패키지이름

패키지 재설치
apt-get --reinstall install 패키지이름

패키지 삭제 : 설정파일은 지우지 않음
apt-get remove 패키지이름
설정파일까지 모두 지움
apt-get --purge remove 패키지이름

패키지 소스코드 다운로드
apt-get source 패키지이름

위에서 받은 소스코드를 의존성있게 빌드
apt-get build-dep 패키지이름

패키지 검색
apt-cache  serach 패키지이름

패키지 정보 보기
apt-cache show 패키지이름

apt를 이용해서 설치된 deb패키지는 /var/cache/apt/archive/ 에 설치가 됩니다.

저작자 표시 비영리 변경 금지
신고
블로그 이미지

꽃중년

불만있으면 떠나라...

Tag apt-get

플래시는 UI 측면에서 강력한  디스플레이 객체 중의 하나입니다.

플래시와 어플 웹 브라우저의 통신 방법으로 주로 이용되는 방법이 fscommand 입니다.

최근에는 external interface 라는 새로운 방법이 추가되기도 하였지만 여전히 상당수가 사용하는 방법이 fscommand 입니다.

 플래시에서 어플리케이션에 어떤 명령을 요청하는 경우 fscommand 의 command 와 argument 를 이용하며 어플리케이션에서 플래시를 호출할 경우는 명령어와 xml 경로를 전달해 주는 방식을 주로 사용합니다.

 플래시의 제작사인 Adobe 에서도 관련하여 많은 샘플코드를 제공하고는 있지만 주로 브라우저 즉 웹 어플리케이션 연동이나 C# 쪽 예제 중심이지 Visual C++ 용 예제는 별로 제공이 되지 않습니다.

 제 경험을 토대로 Visual C++ 과 Flash 의 연동방법에 대해 정리해 보았습니다.

 다이얼로그 베이스 프로그램에 플래시 오브젝트를 추가하여 연동하는 방법입니다.

 

1> 플래시 오브젝트를  불러옵니다.

Tools -> Choose ToolBox Items 메뉴를 선택합니다. (로딩되는데 시간이 좀 걸립니다)

Com Components Tab 으로 이동 후 Shockwave Flash Object 를 선택하고 OK 버튼을 클릭합니다,

 

 

2>다이얼로그에 플래시 오브젝트를 올립니다.

이름은 IDC_FLASH_MAIN 로 합니다.

 

3>플래시 wrapper Class 용 파일(flash_main.cpp, flash_main.h)을 프로젝트에 추가합니다.

 

4>fscommand 연동 관련 작업을 진행합니다.

 

*참고로 저는 CMobileShellDlg  라는 다이얼로그를 만들어 작업을 했습니다.

 

다이얼로그 헤더 파일에  아래와 같이 추가해줍니다.

#include "UI/flash_main.h"

#pragma once


// CMobileShellDlg dialog
class CMobileShellDlg : public CDialog
{
// Construction
public:
    CMobileShellDlg(CWnd* pParent = NULL); // standard constructor
    virtual ~CMobileShellDlg();

// Dialog Data
    enum { IDD = IDD_MOBILESHELL_DIALOG };

protected:
    virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support


// Implementation
protected:
// Generated message map functions
    virtual BOOL OnInitDialog();
DECLARE_MESSAGE_MAP()


public:
    CFlash_main m_Flash_Main; //플래시 오브젝트
    CStringArray m_CommandArray; //플래시와 통신하기 위해 명령어들이 저장되는 Array

public: // Flash
DECLARE_EVENTSINK_MAP()
    void FSCommandFlashMain(LPCTSTR command, LPCTSTR args); //플래시에서 쉘로 보내는 명령

    void Send_FlashFunction(); //쉘에서 플래시로 명령을 보내는 부분

public:
    virtual BOOL DestroyWindow();
};

 

다이얼로그 cpp 파일을 아래와 같이 작업해 줍니다.

 

// MobileShellDlg.cpp : implementation file
//

#include "stdafx.h"
#include "MobileShell.h"
#include "MobileShellDlg.h"
#include <afxmt.h>

CCriticalSection g_csFlashCallFunction;

#ifdef _DEBUG
#define new DEBUG_NEW
#endif


// CAboutDlg dialog used for App About

class CAboutDlg : public CDialog
{
public:
 CAboutDlg();

// Dialog Data
 enum { IDD = IDD_ABOUTBOX };

 protected:
 virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support

// Implementation
protected:
 DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
 CDialog::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
END_MESSAGE_MAP()


// CMobileShellDlg dialog

 


CMobileShellDlg::CMobileShellDlg(CWnd* pParent /*=NULL*/)
 : CDialog(CMobileShellDlg::IDD, pParent)
 , m_bLoadMainFlash(false)
{
 m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
 m_bLoadMainFlash = FALSE;
}

CMobileShellDlg::~CMobileShellDlg()
{
 m_CommandArray.RemoveAll();
}

void CMobileShellDlg::DoDataExchange(CDataExchange* pDX)
{
 CDialog::DoDataExchange(pDX);
 DDX_Control(pDX, IDC_FLASH_MAIN, m_Flash_Main); //IDC_FLASH_MAIN 와 m_Flash_Main 을 연결

BEGIN_MESSAGE_MAP(CMobileShellDlg, CDialog)
 ON_WM_SYSCOMMAND()
 ON_WM_PAINT()
 ON_WM_QUERYDRAGICON()
 //}}AFX_MSG_MAP
END_MESSAGE_MAP()


// CMobileShellDlg message handlers

//플래시 메시지 핸들러 부분
BEGIN_EVENTSINK_MAP(CMobileShellDlg, CDialog)
 ON_EVENT(CMobileShellDlg, IDC_FLASH_MAIN, 150, CMobileShellDlg::FSCommandFlashMain, VTS_BSTR VTS_BSTR)
END_EVENTSINK_MAP()


BOOL CMobileShellDlg::OnInitDialog()
{
 CDialog::OnInitDialog();

 // Add "About..." menu item to system menu.

 // IDM_ABOUTBOX must be in the system command range.
 ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
 ASSERT(IDM_ABOUTBOX < 0xF000);

 

 //메인 플래시 파일을 로딩하는 부분
 
TCHAR Buffer[BUFSIZE];
 GetCurrentDirectory(BUFSIZE, Buffer);
 
 wcscat_s(Buffer,BUFSIZE,_T("\\sample.swf"));
 m_Flash_Main.LoadMovie(0, Buffer); //현재 디렉토리에 있는 sample.swf 파일을 로딩합니다

 return TRUE;  // return TRUE  unless you set the focus to a control
}

 

//실제 플래시에서 쉘로 보내는 메시지를 받는 부분입니다
void CMobileShellDlg::FSCommandFlashMain(LPCTSTR command, LPCTSTR args)

{
 

 CString sCmd, sArgs; //fscommand 로 날라오는 command 와 argument
 sCmd.Format(_T("%s"), command);
 sArgs.Format(_T("%s"), args);
 
 CString sFilePath;
 TCHAR Buffer[BUFSIZE];
 GetCurrentDirectory(BUFSIZE, Buffer);


 if( sCmd.CompareNoCase(_T("command1")) == 0 ) //command 명이 command1 일때 아래 코드를 실행합니다. 
 { 
  sFilePath.Format(_T("%s"),Buffer);
  sFilePath =  sFilePath + _T("\\test.xml");

 

 CString sRequest; //실제 플래시에 있는 명령을 호출하기 위해 작업하는 부분입니다.
 sRequest.Format(_T("<invoke name=\"responseall\"><arguments><string><![CDATA[%s]]></string></arguments></invoke>"), sFilePath);

//어플리케이션에서 호출할 플래시함수명이 responseall 이며 참조할 xml 파일이 test.xml 이라는 의미입니다.

//플래시에 responseall 이라는 외부함수가 존재하지 않는다면  exception에 의해 memory leak  이 발생합니다.

 

//플래시에 리턴할 명령을 commandArray 객체에 넣습니다.

 m_CommandArray.Add(sRequest);

Send_FlashFunction(); //실제 플래시메 명령을 전송합니다.

 }
}

 

//실제로 플래시에 명령을 보내는 부분

void CMobileShellDlg::Send_FlashFunction()
{
  CString sReturn;
  sReturn.Empty();
  try
  {
   if( m_Flash_Main.GetSafeHwnd() != NULL )
    sReturn = m_Flash_Main.CallFunction(sRrequest);

    //실제로 플래시에 명령을 보내는 부분입니다.

    //flash_main.h 파일의 callFunction 부분을 참조하시면 됩니다                

   }
  catch(...) //호출하는 함수명이 플래시내부에 존재하지 않는 경우 이부분에서 예외가 발생합니다
  {
  }

 }
 while(FALSE);
}

 

대략적인 방법을 설명드렸습니다.

완전한 소스 원하시는 분들은 메일 주시면 보내 드리겠습니다.


fscommand 에 대해 좀더 자세히 아시고 싶으신 분들은 아래 URL 을 참조하시기 바랍니다.

http://livedocs.adobe.com/flex/3/html/help.html?content=19_External_Interface_01.html





저작자 표시 비영리 변경 금지
신고
블로그 이미지

꽃중년

불만있으면 떠나라...

Tag mfc
출처: http://blog.naver.com/yi002910?Redirect=Log&logNo=60028589432


[강좌 / 고급] MFC + Flash 연동

야웅커뮤니티에 올린 본인의 강좌입니다.

이 강좌는 VC++6.0에서 MFC 어플리케이션과 Flash와의 상호 연동을 위한 것입니다.
따라서 MFC에 대한 지식을 동시에 요구합니다.

MFC 와 Flash를 서로 상호 연동한다는 것은 두 프로그램간의 변수를 서로 주고 받는 다는 것을 의미합니다. Flash에서는 어떤 작업이 완료 되었으니 다음 작업지시를 해달라고 MFC쪽에 변수를 하나 날리는겁니다. 그럼 MFC에서는 알았다고 다음 작업지시를 다시 Flash로 내려줍니다.
이때 MFC와 Flash간에 사용될 변수들은 미리 정의되어 있어져야 합니다.

일단 작업은 두 파트로 나누어 진행합니다.
MFC파트와 Flash 파트 둘로 말이죠....

<1: Flash Part>
플래시에서 해주어야 할 것은 MFC쪽에서 주는 변수를 받을때 사용할 변수가 하나 선언되어 있어야 합니다.
그러면 MFC에서 데이터를 Flash쪽으로 날려줄때 해당 변수로 값이 들어가게 됩니다.
그러면 플래시에서는 이 값을 받은 즉시 어떤 작업을 하기 위해서 onEnterFrame 으로 잡아내던지
watch 함수를 이용해서 잡아내던지 하면 되는 것입니다.

<2: MFC Part>
꼭 MFC를 고집하는 이유가 있습니다. 쉽기 때문이죠. MFC가 싫다고 하시면 C++ API로 MFC 다이얼로그를 직접 구현해서 ActiveX를 띄워야 합니다. 불가능 한건 아니지만 정말 어렵습니다. 플래시 자체가 원래 MFC로 만들어진 것이기 때문에 MFC를 빼고서는 서로 얘기가 되지 않는 것입니다.
그래서 다들 MFC나 C#을 사용할 것을 권하는 것입니다.

일단 MFC 어플리케이션 응용프로그램에서 ActiveX를 붙이면 됩니다. 아주 간단합니다.
File -> New 메뉴에서 MFC Application (EXE) 를 선택한뒤에 MFC응용프로그램 프로젝트를 만듭니다.
VC++6 을 기준으로 Project -> Add To Project -> Components and Controls 를 선택해서
"Shockwave Flash Object" 를 선택합니다.
Class Wizard 가 정상적으로 작동하는 프로젝트라면 CShockwaveFlash 라는 클래스를 생성하는 창이 뜰것입니다. 이 창이 뜨지 않으면 안됍니다.

그러면 ShockwaveFlash 클래스를 생성하고 나면 리소스 편집기에서 도구상자에서 맨 아래에 빨간색 X자 표시가 되어 있는 문서모양의 아이콘이 보일것입니다. 이것이 플래시를 보여주기 위한 것입니다.
그리고 다이얼로그박스에 이 플래시를 넣어줍니다.

그리고 Member Variables 를 추가해주기 위해 Class Wizard 를 띄웁니다.
Member Variables 탭으로 이동한뒤 보시면 Control ID에 IDC_SHOCKWAVEFLASH 라는 상수가 있을겁니다. 이것을 선택하고 옆의 Add Variables 버튼을 클릭하면 이제 Member Variable 을 추가하는 창이 뜹니다.
m_ 하고 옆에다가 이름을 적으면 됩니다. 여기에 적은 이름은 나중에 이 플래시를 컨트롤 하는 인스턴스네임으로 쓰여집니다.

자... 이제 준비는 다 끝났습니다.
이제 코딩만 남았습니다.
플래시를 띄울 다이얼로그의 사이즈와 플래시의 사이즈를 조절하기 위해 다이얼로그 클래스(기본적으로 Dlg 라는 글자가 포함되어 있습니다.)의 OnInitDialog() 함수로 이동하시기 바랍니다.
다이얼로그 초기화가 이루어질때 호출되는 함수입니다.
그리고 아래처럼 코딩을 합니다.

RECT rc;
rc.left = 0;
rc.top = 0;
rc.right = 640+4;
rc.bottom = 480+23;
MoveWindow(rc.left,rc.top,rc.right,rc.bottom);
ShowWindow(SW_SHOW);

다이얼로그의 크기를 조정하는 것입니다.
높이부분인 bottom 에 23을 더한 이유는 타이틀바가 크기가 23픽셀이기 때문이고 마찬가지로 좌우 4픽셀씩 더 나오기 때문입니다.
다이얼로그의 크기를 조절했으면 이제 플래시의 크기를 조절할 때입니다.

RECT rc2;
rc2.left = 0;
rc2.top = 0;
rc2.right = 640;
rc2.bottom = 480;
m_flash.MoveWindow(&rc2);

아래처럼 MoveWindow 함수를 씁니다.
플래시의 경우는 저렇게 해주면 됩니다.
m_flash는 플래시의 멤버변수입니다. 아까 말했죠? 인스턴스네임처럼 쓴다구요.
자 이제 플래시 컨텐츠를 넣을 시간입니다.

char buffer[_MAX_PATH];
char filename[] = "\\bmsp.dat";
_getcwd( buffer, _MAX_PATH );
strcat(buffer,filename);
m_flash.SetMovie(buffer);

_getcwd 함수로 현재 경로를 얻어와서 같은 폴더내에 있는 플래시파일을 실행하는 것입니다.
SetMovie 가 플래시 컨텐츠를 넣는 함수인데 이게 절대경로만 먹힙니다.
따라서 상대경로를 쓰려면 위에처럼 현재 디렉토리의 경로명을 _getcwd 함수로 받아온 다음에 strcat 함수로 끝에다 플래시파일명을 갖다 붙여서 넣어야 합니다.
\ 이문자는 경로구분으로 쓸때는 반드시 두개를 붙여야 합니다. 위에처럼 말이죠....

그럼 플래시가 작동되는 모습을 보실수 있을겁니다.
그럼 이제 연동을 구현할 시간입니다.

먼저 다시 Class Wizard 를 띄웁니다.
Message Maps 탭에서
IDC_SHOCKWAVEFLASH 라는 Object ID가 보일겁니다.
옆에 Message란에 보시면 FSCommand 라는것이 보입니다. 이 FSCommand 를 추가합니다.
이것은 플래시에서 fscommand로 넘어오는 값들을 catch 하는 함수입니다.
자동으로 값이 넘어오면 호출되는 콜백함수이므로 실시간으로 메세지를 캐치하도록 따로 구현할 필요는 없습니다. 수동으로 넣으신다면 당연히 구현해야 하지만 Class Wizard 를 통해서 넣으면 그런 과정까지 다 되어집니다.
그럼 아래와 같은 함수가 다이얼로그멤버에 추가됩니다.

void CBmspDlg::OnFSCommandShockwaveflash(LPCTSTR command, LPCTSTR args)
{
getmsg = command;
MessageBox(getmsg);
MessageBox(args);
m_flash.SetVariable("msg_variable","send from mfc");
}

플래시에서 fscommand 로 넘어오는 값을 체크할땐 이 함수를 통해서 체크를 합니다.
다만 command로 넘어오는 앞자리 변수는 if 구문으로 비교가 안됍니다.
따라서 미리 변수를 만들어 놓은 다음에 여기에 들어있는 값과 서로 비교해서 맞는지 여부를 체크해야 합니다.
다시 플래시로 값을 넘길때는 위의 예제처럼 SetVariable 함수를 사용합니다.
앞자리가 변수명이고 뒷자리가 변수에 들어갈 값입니다.
반대로도 가능한데 플래시에서 쓰이는 변수를 가져올때는 GetVariable 을 사용하시면 됩니다.

이것으로 강좌를 마치겠습니다.
 

저작자 표시 비영리 변경 금지
신고
블로그 이미지

꽃중년

불만있으면 떠나라...

Tag mfc
vga=xxx

 Colours   640x480 800x600 1024x768 1280x1024 1600x1200
 --------+---------------------------------------------
 256     |   769     771      773      775      796
 32,768  |   784     787      790      793      797
 65,536  |   785     788      791      794      798
 16.8M   |   786     789      792      795      799
 
저작자 표시 비영리 변경 금지
신고
블로그 이미지

꽃중년

불만있으면 떠나라...

1. DC얻기

  CClientDC dc(this);



2. Client 영역 구하기

  GetClientRect(&rect);

  WM_SIZE 메시지발생후 cx,cy 사용



3. 문자열 사각형안에 그리기

  pDC->DrawText(문자열,사각형,Style);

  Style: DT_BOTTOM - 문자열을 사각형 맨아래줄에배열 반드시 DT_SINGLELINE과 함께사용

        DT_CENTER - 문자열을 가로중앙에 배치

        DT_VCENTER - 문자열을 세로중앙에 배치

        DT_LEFT,RIGHT - 문자열을 좌,우로 배치

        DT_SINGLELINE - 문자열을 한줄로만 쓴다



4. Brush 사용법

  CBrush brushname(RGB(red,green,blue)); //브러쉬 생성

  CBrush *oldBrush=pDC->SelectObject(&brushname); //이전Brush 저장, 새로운 Brush 선택

  pDC->SelectObject(oldBrush); //원래의 브러쉬로 반환



5. Pen사용법

  CPen pen(Pen Style,RGB(red,green,blue)); //브러쉬생성

//Style: PS_SOLID,PS_DASH,PS_DOT,PS_DASHDOT,PS_GEOMETRIC,PS_COSMETRIC - 펜종류

        PS_ENDCAP_ROUND,PS_ENDCAP_SQUARE - 펜끝을 둥글게,각지게 설정

  CPen *oldPen=pDC->SelectObject(&pen); //이전Pen저장, 새로운 Pen설정

  pDC->SelectObject(oldPen); //펜반환



6. 화면다시그리기

  View Class에서 - Invalidate(TRUE) : 화면을 지우고다시그린다

                    Invalidate(FALSE) : 화면을 덮어씌운다

  UpdateAllViews(NULL);  // Doc Class에서 View 의 OnDraw 호출

  RedrawWindow();



7. 메시지,함수 수동으로 넣기 (EX)버튼클릭함수넣기

  헤더파일의 AFX_MSG_MAP 부분에 함수를 정의

  EX) afx_msg void funcName();

  .cpp파일의 AFX_MSG 부분에 메시지를 추가한다

  EX) ON_BN_CLICKED(ID_NAME,funcName)...

  ID 등록:  View 메뉴의 Resource Symbol 에 들어가서 메뉴 ID 를 등록해준다..

  .cpp파일의 맨아래에서 함수를 정의한다

  EX) void CClass::funcName() { ... }



8. 마우스커서 바꾸기

  리소스탭에서 커서를 그리고 저장한뒤 ID값은 준다음

  SetCapture(); //커서의입력을 클라이언트영역을 벗어나더라도 받아낸다

  SetCursor(AfxGetApp()->LoadCursor(nIDResource));

  //APP클래스의 LoadCursor View의 SetCursor 사용

  ReleaseCapture(); //SetCursor()상태를 해제한다



9. 색상표 사용하기

  CColorDialog dlg;

  if(dlg.DoModal()==IDOK) //Dialog 를 띄운후 OK버튼을누르면 실행할부분

  MemberFunc: GetColor() //선택된 색상을 받아온다 return 형은 COLORREF 형



10. 팝업메뉴 만들기

  CMenu menu; //메뉴 객체생성

  CMenu *pmenu; //메뉴 포인터생성

  menu.LoadMenu(IDR_MAINFRAME); //메뉴를 불러온다

  pmenu=menu.GetSubMenu(3); //메뉴의 3번째 메뉴를 가져온다

  menu.CheckMenuItem(ID_MENU,m_kind==ID_MENU ? MF_CHECKED : MF_UNCHECKED);

  //메뉴 체크하기 (메뉴 ID, ID 체크조건)

  pmenu->TrackPopupMenu(TPM_LEFTALIGN,point.x,point.y,this)  //(TMP_Style,x좌표,y좌표,hWnd) 메뉴 띄우기



  *주의사항*

    [안내]태그제한으로등록되지않습니다-OnContextMenu(CWnd* pWnd, CPoint point)  //여기서 point 는 스크린 기준이고,

    OnRButtonDown(UINT nFlags, CPoint point)  //여기서 point 는 클라이언트 기준이다!



11. 클라이언트 포인터를 스크린 포인터로 변경

  ClientToScreen(&point);



12. 그림판기능

         if(m_flag==FALSE)  return;   //m_falg=그리기 기능 참,거짓설정  그리기 아니면 빠져나간다

        CClientDC dc(this);

        CPen myPen(PS_SOLID,m_width,m_color);

        CPen *pOldPen=dc.SelectObject(&myPen);

        switch(m_shape)

        {

        case ID_FREELINE: //자유선그리기

                dc.MoveTo(m_oldpt.x,m_oldpt.y); //지난포인터부터

                dc.LineTo(point.x,point.y); //새포인터까지 그린다

                break;

        case ID_RECT: //사각형그리기

                dc.SetROP2(R2_NOTXORPEN);

                dc.Rectangle(m_spt.x,m_spt.y,m_oldpt.x,m_oldpt.y);  //지워지는 효과

                dc.Rectangle(m_spt.x,m_spt.y,point.x,point.y); //그려지는 효과

                break;

        case ID_ELLIPSE: //원그리기

                dc.SetROP2(R2_NOTXORPEN);

                dc.Ellipse(m_spt.x,m_spt.y,m_oldpt.x,m_oldpt.y);  //지워지는 효과

                dc.Ellipse(m_spt.x,m_spt.y,point.x,point.y); //그려지는 효과

                break;

        case ID_LINE: //선그리기

                dc.SetROP2(R2_NOTXORPEN);

                dc.MoveTo(m_spt.x,m_spt.y); //시작점부터

                dc.LineTo(m_oldpt.x,m_oldpt.y); //지난점까지 그은선을 지운다

                dc.MoveTo(m_spt.x,m_spt.y); //시작점부터

                dc.LineTo(point.x,point.y); //새로운점까지 그린다

                break;

        }

        m_oldpt=point;  //바로이전값 보관

        dc.SelectObject(pOldPen); //펜 반환


13. MessageBox

  AfxMessageBox() -> 전역함수를 이용하영 메세지 박스를 출력한다.   //어디서든지 사용할수 잇다

  int CWnd::MessageBox("메세지","창제목","아이콘|버튼(상수값)");   //View클래스에서 사용한다

  아이콘 상수값  MB_IC[안내]태그제한으로등록되지않습니다-xxONERROR, MB_ICONWARNING, MB_ICONQUESTION,MB_ICONINFOMATION

                MB_SYSTEMMODAL //시스템모달 대화창 닫기전에 다른작업 못함

                MB_APPLMODAL //응용모달

  버튼 상수값    MB_OK, MB_OKCANCEL, MB_YESNO



14. OS 컨트롤

        ExitWindowEx(EWX_SHUTDOWN,NULL); //Shut Down

        ExitWindowsEx(EWX_FORCE,0); //강제종료

        ExitWindowsEx(EWX_LOGOFF,0); //로그오프

        ExitWindowsEx(EWX_POWEROFF,0); //Shut Down -> Turn Off

        ExitWindowsEx(EWX_REBOOT); //Shut Down -> Reboot



15. DialogBox 메시지 교환

        UpdateData(FALSE); // 컨트롤에 멤버변수의 내용을 표시해준다

        UpdateData(TRUE);  // 컨트롤 내용을 다이얼로그 클래스의 멤버변수로 저장



16. 자료변환

        atoi,itoa - int <=> ASCII(char) 변환

        str.Format(" %d %d",x,y); // int형을 문자열로 변환

        atol,ltoa - ASCII <=> long 변환

        atof - ACSII => float 변환

        fcvt,gcvt  - 실수를 text로 변환

        LPtoDP, DPtoLP - 장치좌표 <=> 논리좌표 변환



17. CEdit Class 사용하기

  CEdit e_str.SetSel(int StartChae, int EndChar); //처음문자부터 마지막까지 블록 지정

  CEdit e_str.GetSel(int SChar,int EChar); //블럭 지정한 처음문자와 마지막문자 받기

  CString str=m_str.Mid(SChar,EChar-SChar); //블럭지정한 부분을 가져온다


18. 컨트롤과 자료교환

  SetDlgItemText(컨트롤 ID,문자열) //컨트롤에 문자열을 넣는다

  GetDlgItemText(컨트롤 ID,문자열) //컨트롤의 내용을 문자열에 넣는다

  GetDlgItem(컨트롤 ID); //컨트롤의 주소를 가져온다


19. 상태바조작

  CMainFrame 생성자 위에

  static UINT indicators[] = //이안에 새로운 ID를 넣고 그 ID의 갱신핸들러를 만든다음 코딩

  pCmdUI->SetText("표시할내용“);



20. 수동으로 Bitmap 컨트롤 사용하기

  CStatic bitmap; //bitmap 컨트롤변수

  bitmap.SetBitmap(CBitmap m_bitmap); //컨트롤에 비트맵지정

  GetDlgItem(IDC_BITMAP)->ShowWindow(SW_SHOW,HIDE);  // 그림을 보이거나 숨긴다.

  

21. 응용프로그램 실행하기

  WinExec("프로그램경로“,SW_SHOW,HIDE); //응용프로그램실행,경로는 \\로 구분한다



22. Bitmap 사용하기

  CBitmap bitmap.LoadBitmap(IDC_BITMAP); //비트맵객체에 비트맵지정

  CDC memDC; //그림그릴 메모리DC생성

  MemDC.CreateCompatibleDC(pDC); //화면 DC와 메모리 DC 호환 생성

  CBitmap *pOldBitmap=MemDC.SelectObject(&m_bitmap); //메모리에 그림을그린다.

  pDC->BitBlt(int x, int y,int Width, int Height, CDC* pSrcDC, int xSrc, int ySrc, DWORD dwRop);

//BitBlt(그림x좌표,그림y좌표,그림넓이,그림높이,그림그려진메모리DC,그림시작x좌표,그림시작y좌표,스타일);

  pDC->StretchBlt( int x, int y, int nWidth, int nHeight, CDC* pSrcDC, int xSrc, int ySrc, int nSrcWidth, int nSrcHeight, DWORD dwRop )

//StretchBlt(그림x좌표,그림y좌표,그림넓이,그림높이,그림그려진메모리DC,그림x좌표,그림y좌표,메모리그림넓이,메모리그림높이,스타일);

MemDC.SelectObject(pOldBitmap); // 메모리DC반환



23. Font 바꾸기

  CFontDialog dlg; //폰트다이얼로그 생성

  LOGFONT m_logFont; //폰트받을변수선언

  if(dlg.DoModal()==IDOK) //폰트다이얼로그표시

  {dlg.GetCurrentFont(&m_logFont)} //선택된 폰트받기

  OnDraw()

   CFont newFont,*pOldFont; //폰트 객체 만들기

   newFont.CreateFontIndirect(&m_logFont); //폰트 생성

   pOldFont=(CFont *)pDC->SelectObject(&newFont); //폰트 선택

   OnCreate()

   CClientDC dc(this); //DC 생성

   CFont *pFont=dc.GetCurrentFont();        //클라이언트 영역의 폰트를

   pFont->GetLogFont(&m_logFont); //로그폰트 멤버값으로 지정



24. Font 만들기

         LOGFONT logfont; //폰트를 만든다

        logfont.lfHeight=50;               //문자열 높이

        logfont.lfWidth=0;                 //너비

        logfont.lfEscapement=0;            //문자열기울기

        logfont.lfOrientation=0;             //문자개별각도

        logfont.lfWeight=FW_NORMAL;     //굵기

        logfont.lfItalic=TRUE;             //이탤릭

        logfont.lfUnderline=TRUE;  //밑줄

        logfont.lfStrikeOut=FALSE; //취소선

        logfont.lfCharSet=HANGUL_CHARSET; //필수

        logfont.lfOutPrecision=OUT_DEFAULT_PRECIS;               

        logfont.lfClipPrecision=CLIP_DEFAULT_PRECIS;      //가변폭폰트 고정폭폰트

        logfont.lfPitchAndFamily=DEFAULT_PITCH|FF_SWISS; //글꼴이름

        strcpy(logfont.lfFaceName,"궁서체");

        CClientDC dc(this);

        CFont newFont; //폰트객체생성

        newFont.CreateFontIndirect(&logfont); //폰트지정

        CFont *pOldFont=dc.SelectObject(&newFont); //폰트선택

        dc.TextOut(100,100,m_text);

        dc.SelectObject(pOldFont); //폰트반환



25. Font 만들기 2

  CFont newFont;

  newFont.CreateFont( int nHeight, int nWidth, int nEscapement, int nOrientation, int nWeight, BYTE bItalic, BYTE bUnderline, BYTE cStrikeOut, BYTE nCharSet, BYTE nOutPrecision, BYTE nClipPrecision, BYTE nQuality, BYTE nPitchAndFamily, LPCTSTR lpszFacename );

 CFont *pOldFont=dc.SelectObject(&newFont);



26. ComboBox 사용하기

  CComboBox combo; //콤보박스 선언

  combo.Create( DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID );

  //Style - WS_CHILD|WS_VISIBLE

  int n=combo.GetCurSel(); //선택된 아이템의 index를 가져온다

  combo.AddString("문자열“); //문자열을 추가한다

  combo.GetLBText(n,str); //n번째 아이템을 str에 저장



27. Spin 사용하기

  Spin은 바로앞의 Tab Order에 따라 붙는다

  m_spinr.SetRange(1900,3000); //스핀 범위 지정

  m_spinr.SetPos(m_nYear); //스핀 위치 지정



28. CTime사용하기

  CTime time; //시간객체생성

  time=CTime::GetCurrentTime(); //현재시간을 저장

  time.GetYear(),time.GetMonth();,time.GetDay(),time.GetHour(),time.GetMinute(),time.GetSecond()



29. CListBox 메소드

  AddString("문자열");             //리스트에 문자열 추가

  DeleteString(index);             //리스트에서 항목 삭제

  GetCount()                     //전체 항목 갯수를 얻는다.

  GetSelcount()                   //선택된 항목 갯수 리턴

  GetSel()                       //선택된 것인지 아닌지를 리턴한다 -> 양수 = TRUE , 음수 => FALSE

  GetText(int index,문자열변수)     //index 번째 문자열을 문자열 변수에 넣는다

  FindStringExact(문자열)          //지정 문자열의 index 값 리턴 -> 없으면 리턴값 LB_ERR 반환

  FindString("a")                 //"a"로 시작하는 항목을 모두 찾는다.

  ResetCountent()                 //모든 내용을 지운다.



30. 파일입출력

 프로젝트생성시 Step4 => Advanced => 저장파일확장자지정

 .h 파일에       DECLARE_SERIAL(CSawon) //이 클래스를 저장,로드가능한 클래스로 쓰겟다는 선언

 .cpp 파일에     IMPLEMENT_SERIAL(CSawon,CObject,1) //이거를 해야 저장이 가능하다

void CFileioDoc::Serialize(CArchive& ar)

        if (ar.IsStoring())  //저장하기

        {ar<

        else    //열기

        {ar>>m_shape; //불러올걸 쓴다. 읽을때도순서대로읽어야한다}



31. MicroSoft FlexGrid 사용하기!

        CMSFlexGrid m_Grid; //FlexGrid 컨트롤 변수

        CString strTitle[]={"고객코드","고객성명","고객포인트","신장","몸무게","고객등급","BMT지수","판정결과"};

        // Grid 의 제목에 넣을문자배열

        int Width[]={900,900,1100,800,800,900,1000,900};

        // Grid 의 열넓이 지정할 배열

        m_Grid.SetRows(m_cnt+2); //전체행수 지정

        m_Grid.SetCols(8); //전체열수 지정

        m_Grid.Clear(); //지우기

        m_Grid.SetFixedCols(0); //고정열은 없다.

        m_Grid.SetRow(0); // 행선택

        for(int i=0;i<=7;i++)

        {

                m_Grid.SetColWidth(i,Width[i]); //열 넓이 설정

                m_Grid.SetCol(i); //열 선택

                m_Grid.SetText(strTitle[i]); // 선택된행, 선택된열에 Text 를 넣는다

        }



32. 4대 Class간 참조

//각각 헤더파일 include

#include "MainFrm.h" //메인프레임 헤더파일

#include "ClassDoc.h"   //Doc클래스 헤더파일

#include "ClassView.h" //View를 include 할때는 반드시 Doc 헤더파일이 위에잇어야한다

#include "Class.h" //APP Class 의 헤더파일



void CClassView::OnMenuView() //뷰클래스

        CClassApp *pApp=(CClassApp *)AfxGetApp();   //View -> App
        CMainFrame *pMain=(CMainFrame *)AfxGetMainWnd();  //View -> MainFrm

        CClassDoc *pDoc=(CClassDoc *)pMain->GetActiveDocument(); //View -> MainFrm -> Doc

        CClassDoc *pDoc=(CClassDoc *)GetDocument();                     //View -> Doc



 //MainFrame 클래스

        CClassView *pView=(CClassView *)GetActiveView();  //MainFrm -> View

        CClassDoc *pDoc=(CClassDoc *)GetActiveDocument();  //MainFrm -> Doc

        CClassApp *pApp=(CClassApp *)AfxGetApp(); //MainFrm -> App



//Doc 클래스

        CClassApp *pApp=(CClassApp *)AfxGetApp(); //Doc -> App

        CMainFrame *pMain=(CMainFrame *)AfxGetMainWnd(); //Doc -> MainFrm

        CClassView *pView=(CClassView *)pMain->GetActiveView(); // Doc -> MainFrm -> View

        CClassView *pView=(CClassView *)m_viewList.GetHead();      // Doc -> View



//App 클래스

        CMainFrame *pMain=(CMainFrame *)AfxGetMainWnd(); //App -> MainFrm

        CClassView *pView=(CClassView *)pMain->GetActiveView(); //App -> MainFrm -> View

        CClassDoc *pDoc=(CClassDoc *)pMain->GetActiveDocument(); //App -> MainFrm -> Doc



33. ToolBar 추가하기

  CMainFrame 으로 가서 멤버변수 추가

        CToolBar m_wndToolBar1;

  OnCreate 로 가서 다음 내용을 추가해준다 (위의 toolbar 부분을 복사하고 이름만 바꾸면 된다.3군데..)

  if (!m_wndToolBar1.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP

                | CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC) ||

                !m_wndToolBar1.LoadToolBar(IDR_TOOLBAR1))

        {

                TRACE0("Failed to create toolbar\n");

                return -1;      // fail to create

        }



  그 함수내에서 //TODO 아래에 내용추가..역시..복사해서 이름만 바꾸면 된다.

        m_wndToolBar1.EnableDocking(CBRS_ALIGN_TOP|CBRS_ALIGN_BOTTOM);

        //DockControlBar(&m_wndToolBar1);   <= 이부분 대신..

        이거를 넣는다..

        CRect toolRect; //툴바 영역을 얻을 사각형

        this->RecalcLayout(); //현상태의 Client 영역을 구해서 저장한다

        m_wndToolBar.GetWindowRect(&toolRect); //툴바영역을 저장한다

        toolRect.left+=1; //사각형의 왼쪽을 1Pixel 줄인다

        DockControlBar(&m_wndToolBar1,AFX_IDW_DOCKBAR_TOP,&toolRect); //ToolRect에 툴바를 붙인다

        return 0;



34. ToolBar에 ComboBox붙이기

        CComboBox m_combo; //객체생성

        ID 등록 => view 메뉴 => resource symbol => new => ID_COMBO

  oncreate 에 내용 추가 (콤보를 만들고 표시하는 내용)

        m_wndToolBar.SetButtonInfo(10,IDC_COMBO,TBBS_SEPARATOR,150); 

        //툴바의 10번째버튼을 편집한다

        CRect itemRect; //콤보를넣을 사각형을 만든다

        m_wndToolBar.GetItemRect(10,&itemRect); //툴바의 10번째 버튼을 사각형에 넣는다
        itemRect.left+=5; //앞여백

        itemRect.right+=5; //뒤여백

        itemRect.bottom+=100; //콤보가열릴 공간확보

        m_combo.Create(WS_CHILD|WS_VISIBLE|CBS_DROPDOWN,itemRect,&m_wndToolBar,IDC_COMBO);

        //콤보박스를 툴바에 붙여준다

        m_combo.AddString("이름"); //내용추가

        m_combo.SetCurSel(0); //셀 선택



35.  Toolbar에 수동으로넣은 ComboBox 사용하기

  afx_msg void [안내]태그제한으로등록되지않습니다-xxOnSelectCombo(); //원형

  ON_CBN_SELCHANGE(IDC_COMBO,[안내]태그제한으로등록되지않습니다-xxOnSelectCombo) //메세지맵에 추가

        CMainFrame *pMain=(CMainFrame *)GetParent(); //메인프레임 주소참조

        CComboBox *pCom=(CComboBox *)(pMain->m_wndToolBar.GetDlgItem(IDC_COMBO));

        //콤보박스의 주소를 가져온다, 접근할 때 메인프레임 -> 툴바 -> 콤보박스 의 순서로 가야한다

        int n=pCom->GetCurSel(); //현재선택된 셀의 인덱스를 가져온다

        if(n==CB_ERR) return; //선택된셀이 없으면 중지한다

        CString str;

        pMain->m_combo.GetLBText(n,str); //선택된셀의 Text를 가져온다



36. UPDATE_COMMAND 사용하기

        pCmdUI->Enable(TRUE); //버튼 활성화

        pCmdUI->SetText((bAdd)?"취소":"신규"); //버튼의 text 설정

        pCmdUI->SetCheck(TRUE); //버튼 체크



37. 프로그램정보저장

  CWinApp::GetProfileString(섹션명,항목명,기본값); // 함수를 사용한다. (문자열)

  CWinApp::GetProfileInt(섹션명,항목명,기본값);  //불러올때사용 (숫자) 

  CWinApp::WriteProfileString(섹션명,항목명,값); //저장할때 사용 (문자열)

  CWinApp::WriteProfileInt(섹션명,항목명,값); //저장할때 사용 (숫자)

  //불러올때 사용할함수

  void CMainFrame::ActivateFrame(int nCmdShow)  //프로그램 실행후 프레임생성될때 실행

  //저장할 때 WM_DESTROY 메시지 사용



38. 컨트롤바 표시하기

        CMainFrame *pMain=(CMainFrame *)GetParent(); //MainFrame 주소가져오기

        pMain->ShowControlBar(&pMain->m_wndToolBar,bTool1,FALSE); //툴바를 bTool2 에따라 보이고 감춘다



39. Window 창크기,위치정보 저장하기

MainFrame 의 WM_DESTROY 에

        WINDOWPLACEMENT w;

        this->GetWindowPlacement(&w); //윈도우의 정보를 저장한다.

        CString strRect;

        strRect.Format("%04d,%04d,%04d,%04d", //04d 는 4자리 확보하고 남은건 0으로 채워라

                w.rcNormalPosition.left,w.rcNormalPosition.top,

                w.rcNormalPosition.right,w.rcNormalPosition.bottom); //윈도우의 위치,크기 확보..

        

        BOOL bMax,bMin; //윈도우의 상태를 저장하기위한 변수

        //w.falg 는 이전상태의 정보를 가지고 잇다!!

        if(w.showCmd==SW_SHOWMINIMIZED)           //최소화 상태

        {

                bMin=TRUE;

                if(w.flags==0) //falg 값이 0 이면 이전 상태가 보통상태이다!!

                        bMax=FALSE;

                else    //이전상태가 최대화 상태

                        bMax=TRUE;

        }

        else                            

        {

                if(w.showCmd==SW_SHOWMAXIMIZED) //최대화상태

                {

                        bMax=TRUE;

                        bMin=FALSE;

                }

                else  //보통 상태

                {

                        bMax=FALSE;

                        bMin=FALSE;

                }

        }

        AfxGetApp()->WriteProfileString("WinStatus","Rect",strRect);

        AfxGetApp()->WriteProfileInt("WinStatus","Max",bMax);

        AfxGetApp()->WriteProfileInt("WinStatus","Min",bMin);



//읽어올차례..

ActivateFrame 함수로 가서

        WINDOWPLACEMENT w;  //윈도우의 상태를 저장하는 구조체..

        BOOL bMax,bMin;               //최대,최소상태를 저장할 변수

        CString strRect; //창크기를 받아올 변수

        strRect=AfxGetApp()->GetProfileString("WinStatus","Rect","0000,0000,0500,0700");

        bMin=AfxGetApp()->GetProfileInt("WinStatus","Min",FALSE);

        bMax=AfxGetApp()->GetProfileInt("WinStatus","Max",FALSE);

        int a=atoi(strRect.Left(4)); //문자열을 int 로 바꿔준다.

        int b=atoi(strRect.Mid(5,4));     //atoi 아스키 값을 int형으로 바꿔준다..

        int c=atoi(strRect.Mid(10,4));

        int d=atoi(strRect.Mid(15,4));

        w.rcNormalPosition=CRect(a,b,c,d);

        if(bMin)

        {

                w.showCmd=SW_SHOWMINIMIZED;

                if(bMax)

                {

                        w.flags=WPF_RESTORETOMAXIMIZED  ;

                }

                else

                {

                        w.flags=0;

                }

        }

        else

        {

                if(bMax)

                {

                        w.showCmd=SW_SHOWMAXIMIZED;

                }

                else

                {

                        w.showCmd=SW_SHOWNORMAL;

                }

        }

        this->SetWindowPlacement(&w); //설정된 값으로 윈도우를 그리게 한다..

        

        //CFrameWnd::ActivateFrame(nCmdShow); //이건 반드시 주석처리한다..



40. progress Bar 쓰기



        m_progress.SetRange(m_first,m_last); //Progress 범위설정하기

        m_progress.SetStep(m_step); //Progress Step설정하기

        //m_progress.StepIt(); //스텝만큼 움직이기

        //또는 다음을 사용한다

        for(int a=m_first;a<=m_last;a+=m_step) //a가 처음부터 끝까지

        {

                m_progress.SetPos(a); // 위치를 a에 맞춘다

                Sleep(50); //천천히 움직이게한다

        }



41. 파일대화상자 FileDialog 사용하기

void CConDlg1::OnFileopen()  //파일열기 버튼

{

        CFileDialog *fdlg; //파일대화상자 객체 생성 // 포인터로 만든다..

        static char BASED_CODE szFilter[] = "Animate Video Files (*.avi)|*.avi|All Files (*.*)|*.*||";

        //필터를 만들어 준다..이건 할줄 모름..

        fdlg =new CFileDialog(TRUE, ".avi", NULL, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,szFilter);

        //대화상자 만들기..이렇게 해야댄다..

        if(fdlg->DoModal()==IDOK) //이제..대화상자를 띠우고..    

        {                               //OK 누르면 실행될 부분..

                m_filename=fdlg->GetPathName();        //대화상자에서 경로를 받아서 저장.

                UpdateData(FALSE);    

        }

}

선생님이 해준거 //파일 다이얼로그 만들기

CFileDialog fdlg(TRUE,"avi",".avi",OFN_OEVRWRITEPROMPT,"Vidoe Files(*.avi)|*.avi|All Files(*.*)|*.*||");



42. Animate Control 사용하기

        m_animate.Open(m_filename); //파일을 연다

        m_animate.Play(0,-1,1);  //(처음프레임,마지막프레임,반복횟수)

        m_animate.Stop(); //정지시키기

        m_ani.SetAutoStart(TRUE); //자동으로 시작한다

43. Control 의 Style 바꿔주기

        Control.ModyfyStyle(제거할스타일,추가할스타일); //스타일은 MSDN내용 참조



44. 시스템 날자바꾸기 버튼

//SetSystemTime(),GetSystemTime() //GMT 표준시를 가져온다.

//GetLocalTime(),SetLocalTime()  //현재 지역시간을 가져온다.



        SYSTEMTIME st;

        GetLocalTime(&st); //현재 시간, 날자를 넣는다.

        st.wYear=m_date2.GetYear();

        st.wMonth=m_date2.GetMonth();

        st.wDay=m_date2.GetDay();

        SetSystemTime(&st);



45. 시스템 시간 바꾸기 버튼

        UpdateData(TRUE);

        SYSTEMTIME st;

        GetLocalTime(&st);

        st.wHour=m_time.GetHour();

        st.wMinute=m_time.GetMinute();

        st.wSecond=m_time.GetSecond();

        SetLocalTime(&st);



46.시스템의 드라이브 문자 얻기



        char temp[50];

        GetLogicalDriveStrings(sizeof(temp),temp);

        CString str,str1;

        int n=0;

        while(*(temp+n)!=NULL)

        {

                str=temp+n;

                str1+= " "+str.Left(2);

                n+=4;

        }



47. 현재 작업경로 얻기

        char temp[MAX_PATH]; //MAX_PATH 는 경로길이의 최대를 define 해놓은것.

        GetCurrentDirectory(sizeof(temp),temp);  // 현작업하는 경로를 얻어온다.(경로 길이,문자형);



48. Tree Control 사용하기

        HTREEITEM hmov,hmus; //핸들을받을 변수 이게 잇어야 하위 디렉토리 생성가능

        hmov=m_tree.InsertItem("영화",TVI_ROOT,TVI_LAST); //,TVI_ROOT,TVI_LAST는 default

        hm1=m_tree.InsertItem("외화",hmov);  //hmov 아래 “외화”트리 생성

        CImageList m_image; //그림을 사용하기 위한 클래스다!! 알아두자..

        m_tree.SetImageList(&m_image,TVSIL_NORMAL); //Tree View Style Image List => TVSIL

        hmov=m_tree.InsertItem("영화",0,1,TVI_ROOT,TVI_LAST); //,TVI_ROOT,TVI_LAST는 default

        hmus=m_tree.InsertItem("가요",1,2); //("문자열",처음그림번호,선택시그림)

        hm1=m_tree.InsertItem("외화",2,3,hmov); //그림 번호는 default 로 0이 들어간다..



49. List Control 사용하기

        m_list.ModifyStyle(LVS_TYPEMASK, LVS_ICON); //리스트를 큰아이콘형태로 보인다

        m_list.ModifyStyle(LVS_TYPEMASK, LVS_SMALLICON);  //리스트를 작은아이콘형태로 보인다

        m_list.ModifyStyle(LVS_TYPEMASK, LVS_LIST); //리스트를 리스트형태로 보인다

        m_list.ModifyStyle(LVS_TYPEMASK, LVS_REPORT); //리스트를 자세히형태로 보인다



        CImageList m_treeimage; //이미지리스트

        CImageList m_small, m_large;

        m_large.Create(IDB_LARGE,32,0,RGB(255,255,255)); //이거는 클래스에서 추가해준거다

        m_small.Create(IDB_SMALL,16,0,RGB(255,255,255)); (bmp ID값,

        m_list.SetImageList(&m_large,LVSIL_NORMAL);

        m_list.SetImageList(&m_small,LVSIL_SMALL);

        CString name[]={"홍길동","진달래","한국남","개나리"};

        CString tel[]={"400-3759","304-7714","505-9058","700-9898"};

        CString born[]={"1980-1-1","1981-12-20","1980-05-15","1981-08-31"};

        CString sex[]={"남자","여자","남자","여자"};

        

        m_list.InsertColumn(0,"이름",LVCFMT_LEFT,70);

        m_list.InsertColumn(1,"전화번호",LVCFMT_LEFT,80);

        m_list.InsertColumn(2,"생일",LVCFMT_LEFT,90);

        m_list.InsertColumn(3,"성별",LVCFMT_LEFT,50);

        LVITEM it; //리스트 구조체

        char temp[100];

        for(int a=0;a<4;a++)

        {       

                int n=(sex[a]=="남자")?0:1;

                m_list.InsertItem(a,name[a],n); //insert item 은 행을 만들고..

                it.mask=LVIF_TEXT|LVIF_IMAGE; //마스크 설정

                it.iItem=a;

                it.iSubItem=1; //열 설정

                strcpy(temp,tel[a]); //이거 모하는거냐..

                it.pszText=temp;

                m_list.SetItem(&it);                      // setitem 열에 정보를 넣는다.



                it.iSubItem=2; //열 설정

                strcpy(temp,born[a]); //이거 모하는거냐..

                it.pszText=temp;

                m_list.SetItem(&it);                      // setitem 열에 정보를 넣는다.



                it.iSubItem=3; //열 설정

                strcpy(temp,sex[a]); //이거 모하는거냐..

                it.pszText=temp;

                m_list.SetItem(&it);                      // setitem 열에 정보를 넣는다.




50. Bitmap Button 사용하기

  CBitmapButton 을 사용한다! CButton 에서 상속 받는클래스임..

        m_button1.Create(NULL,

                WS_CHILD|WS_VISIBLE|BS_OWNERDRAW,CRect(310,20,370,50),

                this,IDC_MYBUTTON); //버튼만들기

        m_button1.LoadBitmaps(IDB_UP,IDB_DOWN,IDB_FOCUS,IDB_DISABLE); //버튼의 그림설정

        m_button1.SizeToContent(); //버튼을 그림 크기로 맞춰 준다!!



 그냥 버튼을 비트맵버튼으로 바꾸기 -> 버튼을 만든다 속성에서 OWNERDRA 속성에 체크!!

        m_button2.LoadBitmaps(IDB_UP,IDB_DOWN,IDB_FOCUS,IDB_DISABLE); //버튼의 그림설정

        m_button2.SizeToContent(); //버튼을 그림 크기로 맞춰 준다!!



51. 중복없는 난수발생하기

        int su; //발생된 난수저장

        int a,b;

        BOOL bDasi; //숫자가중복될경우 다시하기위한 변수

        for(a=0;a<9;a++)  //난수 9개 발생

        {

                bDasi=TRUE;

                while(bDasi)

                {

                        bDasi=FALSE;

                        su=rand()%10; //난수발생

                        for(b=0;b

                        {

                                if(temp[b]==su)  //중복이면

                                {

                                        bDasi=TRUE; //중복이 잇으면 다시while 문을 실행한다

                                        break;

                                }//if

                        }//for

                }//while

                temp[a]=su; //중복이 아니면 대입한다



52. 메뉴 범위로 사용하기

  ON_COMMAND_RANGE(ID_LEVEL3,ID_LEVEL9,OnLevel); //범위메세지 발생

  //메뉴 ID의 값이 연속된 숫자일 경우 범위로 지정해서 사용할수잇다



53. 한,영 전환함수

void CCustView::SetHangul(BOOL bCheck) //T:한글 F:영문 이건 외우자..

{

        HIMC hm=ImmGetContext(this->GetSafeHwnd()); //뷰클래스의 윈도우 핸들포인터를 얻는다.

        if(bCheck)

        {

                ::ImmSetConversionStatus(hm,1,0); //1은 한글 0은 영문

        }

        else

        {

                ::ImmSetConversionStatus(hm,0,0); //영문으로 바꿔준다

        }

        ::ImmReleaseContext(this->GetSafeHwnd(),hm); //장치를 풀어준다

}

#include "imm.h" //헤더 반드시 추가하고

imm32.lib (라이브러리 파일)를 반드시 링크해주어야 한다!

**** 라이브러리 추가하기

프로젝트메뉴 -> 셋팅 -> 링크탭



54. DLL함수정의하기

임포트함수 :  extern "C"  __declspec(dllimport)   리터형  함수명(매개변수,...) ;

  - 메인프로그램에서 DLL에 있는 함수를 호출할때 사용한다.



엑스포트함수 :  extern "C"  __declspec(dllexport)   리터형  함수명(매개변수,...)

                      {

                             내용;

                      }

출처 : Tong - navy9370님의 MFC통

신고
블로그 이미지

꽃중년

불만있으면 떠나라...

Tag mfc

원문출처: http://monac.egloos.com/1936134

autocomplpop.vim : Automatically open the popup menu for completion
http://www.vim.org/scripts/script.php?script_id=1879

2007년 5월에 등장한 플러그인입니다.
autocomplpop.vim 파일을 자신의 홈 ~/.vim/plugin 디렉터리에 복사합니다. 그러면 끝입니다.

C 언어를 쓰거나, 파이썬을 쓰거나, 루비를 쓰거나 잘 동작합니다. 루비라면 apt-get install vim-ruby를 설치하면 잘 동작합니다.

엔터키를 입력하면 완성되지만 비주얼 스튜디오를 쓰던 손맛이 있어서 탭키가 익숙합니다. 그래서 ~/.vimrc에 다음을 추가합니다.

function! InsertTabWrapper()
  let col = col('.') - 1
  if !col || getline('.')[col-1]!~'\k'
    return "\<TAB>"
  else
    if pumvisible()
      return "\<C-N>"
    else
      return "\<C-N>\<C-P>"
    end
  endif
endfunction

inoremap <tab> <c-r>=InsertTabWrapper()<cr>

이 스크립트는 http://blog.blueblack.net/item_164에서 가져왔습니다. ^^;

그런데 조금 문제가 있습니다. 엔터키를 입력해도 항상 코드가 자동 완성됩니다. printf가 아니라 print만 입력하고 싶어도 자꾸 printf만 되죠. 그래서 위 코드를 다시 아래처럼 바꿉니다.

function! InsertTabWrapper()
  let col = col('.') - 1
  if !col || getline('.')[col-1]!~'\k'
    return "\<TAB>"
  else
    if pumvisible()
      return "\<C-P>"
    else
      return "\<C-N>\<C-P>"
    end
  endif
endfunction

inoremap <tab> <c-r>=InsertTabWrapper()<cr>
inoremap <expr> <CR> pumvisible() ? "<C-Y><CR>" : "<CR>"

이렇게하면 코드 완성은 탭키로만하고 엔터키를 누르면 자동 완성은 하지 않고 줄바꿈을 할 수 있습니다.

이 플러그인은 현재까지 다운로드 수가 3257밖에 안 되었습니다. 이런 건 좀 널리 써줘야 해요~

팝업창의 색상 설정은 .vimrc에 다음과 같이 하면 됩니다.

hi Pmenu guibg=#666666
hi PmenuSel guibg=#8cd0d3 guifg=#666666
hi PmenuSbar guibg=#333333

autocomplpop.vim
taglist.vim

신고
블로그 이미지

꽃중년

불만있으면 떠나라...


1. doxygen 설치 (v1.5.6)
 http://www.stack.nl/~dimitri/doxygen/download.html#latestsrc

2. graphivz 설치 (V1.28)
http://www.graphviz.org/Download..php

3. mscgen 압축 풀어 적당한 폴더로 이동 (V0.12)
http://www.mcternan.me.uk/mscgen/

4. doxywizard 실행
5. Wizard 버튼 눌러 대충 설정
6. Expert 버튼 눌러 DOT 탭으로 이동
7. DOT_PATH에 graphviz 경로 지정
8. MCSGEN_PATH에 mscgen 경로 설정
9. Save... 그리고 Start...
신고
블로그 이미지

꽃중년

불만있으면 떠나라...

"=============================================================================
" default (gvim v7.1)
"=============================================================================
set nocompatible
source $VIMRUNTIME/vimrc_example.vim
source $VIMRUNTIME/mswin.vim
behave mswin

set diffexpr=MyDiff()
function MyDiff()
  let opt = '-a --binary '
  if &diffopt =~ 'icase' | let opt = opt . '-i ' | endif
  if &diffopt =~ 'iwhite' | let opt = opt . '-b ' | endif
  let arg1 = v:fname_in
  if arg1 =~ ' ' | let arg1 = '"' . arg1 . '"' | endif
  let arg2 = v:fname_new
  if arg2 =~ ' ' | let arg2 = '"' . arg2 . '"' | endif
  let arg3 = v:fname_out
  if arg3 =~ ' ' | let arg3 = '"' . arg3 . '"' | endif
  let eq = ''
  if $VIMRUNTIME =~ ' '
    if &sh =~ '\<cmd'
      let cmd = '""' . $VIMRUNTIME . '\diff"'
      let eq = '"'
    else
      let cmd = substitute($VIMRUNTIME, ' ', '" ', '') . '\diff"'
    endif
  else
    let cmd = $VIMRUNTIME . '\diff'
  endif
  silent execute '!' . cmd . ' ' . opt . arg1 . ' ' . arg2 . ' > ' . arg3 . eq
endfunction

"=============================================================================
" set
"=============================================================================
set tabstop=4
set shiftwidth=4
"set expandtab "탭을 스페이스로 바꾸어줌

filetype on  " 파일의 종류를 자동으로 인식
syntax on "문법 색상 강조

"set backup  "백업 파일 만들기
set nobackup "백업 파일 생성하지 않음
"set nowrap "자동줄바꿈 사용 안함

set ruler "커서가 위치한 열과 행을 표시
set showmode "삽입모드, 명령모드, 블럭모드등의 현재 모드 표시
set ignorecase "검색시 대소문자 구별 하지 않음
set hlsearch "검색어 색상 강조
set autoindent "자동 들여쓰기 설정

"set guifont=굴림체:h12:cHANGEUL "폰트 설정
"set guifont=ProFontWindows:h12 "폰트 설정
set guifont=Bitstream_Vera_Sans_Mono:h10

set lines=65 columns=85 "창크기 설정
set title "제목표시줄에 파일명 표시

set cmdheight=2 "command line의 줄수를 지정한다.
set exrc "현재 디렉토리의 vimrc 파일을 실행할 수 있게...

set showmatch "괄호 닫기 할 때 열었던 괄호와 매칭 확인
set mousehide "타이핑시 마우스 커서 감추기
set visualbell "경고소리를 깜빡임으로 대치
"set history=50 "파일 편집 시 undo 할 수 있는 최대 회수 설정

"한영 입력 상태에 따라 커서 색깔을 다르게...
if has('multi_byte_ime')
 highlight Cursor guibg=black guifg=NONE
 highlight CursorIM guibg=blue guifg=NONE
endif

"set backupdir=%VIM/backup
"set dir=%VIM/tmp

set nu
set wmnu "Tab 자동 완성시 가능한 목록을 보여
colorscheme desert "colorscheme을 elfload로 세팅

"=============================================================================
" Tags
"=============================================================================
set tags=./tags,C:\Projects\DME\Software\TCU_V1\tags


"=============================================================================
" Key Mapping
"=============================================================================
map <F5> :20vs ./<CR>
map <F6> O

"Ctrl+e를 누르면 현재 오픈한 파일의 디렉토리에 대한 탐색기를 띄운다
map <C-e> :silent !explorer %:p:h:gs?\/?\\\\\\?<CR>

" Directory Explorer를 위한 키맵핑
":nnoremap <silent> <F5> :TagExplorer


신고
블로그 이미지

꽃중년

불만있으면 떠나라...

Tag gVim, gvimrc, vi, vim

project -> Setting ->C/C++ 텝에서 Debug info 에서 None를 Program Database 선택

project -> Setting -> Link 텝에서 Generate debug info 체크

이렇게 하시면 릴리즈에서 디버깅이 가능합니다.



신고
블로그 이미지

꽃중년

불만있으면 떠나라...


HKEY_LOCAL_MACHINE / SOFTWARE / Microsoft / Windows NT / CurrentVersion
 
이곳에서 오른쪽에 있는 Registered OwnerRegistered Organization값을 각각 원하는 사용자명과 조직명으로 바꾸세요.
신고
블로그 이미지

꽃중년

불만있으면 떠나라...


HKEY_LOCAL_MACHINE -> SOFTWARE -> Microsoft -> Windows -> CurrentVersion -> Run

으로 이동하시면 우측에 자동으로 실행되는 프로그램 목록이 나타난다.
여기서 자신에게 필요없는 프로그램이나 실행 파일을 삭제해주면 시작프로그램에서 제거됩니다 .
신고
블로그 이미지

꽃중년

불만있으면 떠나라...


javascript:function r(d){d.oncontextmenu=null;d.onselectstart=null;d.ondragstart=null;d.onkeydown=null;d.onmousedown=null; d.body.oncontextmenu=null;d.body.onselectstart=null;d.body.ondragstart=null;d.body.onkeydown=null; d.body.onmousedown=null;}var tb=document.all.tags('BODY');if(tb.length==0) {for(var i=0;i< top.frames.length;i++){r(top.frames[i].document);}}else{r(document);}
신고
블로그 이미지

꽃중년

불만있으면 떠나라...



void WarmBoot(void)
{

    unsigned far *pBootFlag = (unsigned far *)0x00400072;
    void (far *pReboot) (void);

    *pBootFlag = 0x1234;
    pReboot = (void(far *)(void))0xffff0000;

    (*pReboot)();
}

신고
블로그 이미지

꽃중년

불만있으면 떠나라...

Tag reboot
출처: http://cafe.naver.com/devctrl.cafe?iframe_url=/ArticleRead.nhn%3Farticleid=197


http://www.vim.org                 -> gvim64.exe (Version 6.4)
http://ctags.sourceforge.net    -> ec56w32.zip (Version 5.6)

1. GViM 설치
7.0이 아닌 6.4를 설치하는 이유는 창을 파일 익스플로러로 나누었을 때 다른 창에 새로운 파일의 내용을 표시할 수 있기 때문이다.

2. ctags.exe를 GViM이 설치된 곳인 C:\Program Files\Vim\vim64\에 복사

3. 환경변수 PATH 설정
[내 컴퓨터 -> 속성 -> 고급 -> 환경변수 -> 시스템 변수 -> Path - 편집]의 맨 끝에 GViM이 설치된 경로를 추가
예) ;C:\Program Files\Vim\vim64\

4. GViM 환경 설정
C:\Program Files\Vim\_vimrc 파일을 수정 (줄에서 "로 시작하면 이후부터 그 줄의 끝까지 주석으로 인식)

syntax on "언어에 따른 자동 문법, 구문 강조 기능 사용
filetype on "파일의 종류를 자동으로 인식
colorscheme torte "색상 테마 변경

set nocp "오리지널 VI와의 호환성을 없애고, VIM 만의 기능들을 쓸 수 있게 함. (compatible)
set ru "화면 우측 하단에 현재 커서의 위치(줄, 칸)를 표시 (ruler)
set sc "완성 중인 명령을 표시
set nu "라인 번호를 표시
set vb "키를 잘못눌렀을 때 삑 소리를 내는 대신 번쩍임 (visualbell)
set hls "검색어 강조 기능 사용 (hlsearch)
set ci "C 형태의 들여쓰기 (cindent)
set ai "자동 들여쓰기 (autoindent)
set si "좀더 똑똑한 들여쓰기 (smartindent)
set sw=4 "자동 들여쓰기를 4칸으로 설정 (shift width)
set ts=4 "tab 간격을 4칸으로 설정 (tab stop)
set bs=2 "삽입 모드에서 백스페이스를 계속 허용 (backspace)
set hi=50 "명령어 기록을 남길 개수 지정 (history)
set bs=eol,start,indent "줄의 끝, 시작, 들여쓰기에서 백스페이스를 사용하면 이전 줄과 연결됨
set sm "(), {}에서 닫는 괄호를 입력할 때 일치하는 괄호를 보여줌 (showmatch)


다음 라인들은 필요시 선택적으로 추가
set nobackup "백업 파일을 생성하지 않음

set title "타이틀 바에 현재 편집 중인 파일 표시
set expandtab "탭 문자를 공백 문자로 변환
set incsearch "키워드 전진 검색 사용
set background=dark "어두누 배경색 사용, 터미널 모드에서는 영향 없음
set ignorecase "검색, 편집, 친환시에 대소문자 구분하지 않음
set textwidth=76 "76번째 칸을 넘어가면 자동으로 줄 바꿈
set nowrapscan "찾기에서 파일의 맨 끝에 이르면 계속하여 찾지 않음
set nowrap "줄을 Wrap 하지 않음
set backupdir=C:\Backup "백업 파일을 저장할 디렉토리를 설정
set sol "여러 가지 이동 동작시 줄의 시작으로 자동 이동
set ch=1 "맨 아래 보이는 명령줄의 높이를 설정, 기본 값은 1
set sel=exclusive "비주얼 모드에서의 동작 설정
set scs "똑똑한 대소문자 구별 기능 사용
set sts=0
set nows "검색시 파일 끝에서 처음으로 되돌리기 안함

set enc=cp949 "인코딩을 설정, cp949, euc-kr ... (encoding)
set fenc=utf-8
set fenc=unicode
set exrc

"GUI 이면, 시작시 크기 설정
if has("gui_running")
    set lines=89
    set co=114
endif

5. 분석할 소스 트리의 루트로 이동하여 tags 파일 생성
예) test_src 소스를 c:\test_src>에 있다고 가정
소스의 루트 디렉토리에 vi.bat 파일을 만들고 메모장으로 열어서 다음과 같이 입력
ctags -R . ------------------------ ① -R과 .(dot) 사이에 스페이스 있음
gvim -S Session.vim ---------------- ②
① 소스의 루트 디렉토리에 tags라는 파일 생성
    - vi.bat를 실행할 때 마다 매 번 tags 파일 갱신
    - 소스의 내용이 변경되지 않는다면  ① 번 라인을 제거
    - 소스의 내용이 변경되어 tags 파일을 갱신하고자 할 때 GViM에서 [도구 - 꼬리표 만들기]로 tags 파일을 새로 생성
② 소스의 루트 디렉토리에 Session.vim 파일을 읽음
    - Session.vim 파일은 GViM의 분할된 화면 상태 등을 저장하고 있음
    - GViM에서 [창 - 파일 익스플러로 나누기], [창 - #으로 나누기], [창 - 세로로 나누기] 등으로 화면을 분할한 후 세션을 저장

6. VI에서 ctags 활용
현재 cursor를 찾고 싶은 keyword에 놓은 상태에서
g] : 키워드의 정의 목록 확인
g^] : 키워드의 정의 목록이 둘 이상이면 보여주고 한 곳이면 바로 이동
^] : 키워드가 정의된 곳으로 이동
^T : 정의된 곳으로 갔다가 다시 돌아옴
[i : 함수 및 변수의 원형 확인

현재 cursor 위치와 상관없이
:tj keyword
:ta keyword

같은 keyword가 여러 곳에서 선언된 경우에는 "tag 1 of 2 or more"와 같은 메시지가 보인다.
그 keyword 위에서 g]를 입력하면 GViM은 tag list를 나열한 후 선택할 수 있도록 해 준다.
:tn Next tag search
:tp Previous tag search

7. 태그 파일 위치 지정
여러 tag 파일들을 동시에 참조를 할 수 있으며 keyword를 아래 tags 파일에서 순서대로 search
set tags=./tags,../tags,../include/tags,/usr/include/tags
작업할 directory에 _vimrc 파일을 만들어 위의 line을 넣고 vim을 실행시키면 home의 _vimrc를 읽은 후에 현재 directory의 _vimrc를 읽는다.
만약 vim이 현재 directory의 _vimrc를 읽지 않는 것 같다면 :set all 해서 noexrc가 설정되어 있는 지 확인한다.
exrc이어야 local 디렉토리의 _vimrc를 읽는다.
만일 noexrc라면 C:\Vim/_vimrc에 set exrc를 추가한다.

좀더 자세한 사항을 알고 싶으면?
:help tags
:help g]
:help :tjump
:help :sts
:help :tn

반드시 :help tags의 내용을 대충이라도 읽어보기 바란다. 많은 유용한 명령들이 있다.

gd를 누르면 열려있는 file에서 커서 위의 단어가 정의되어 있는지 확인하여 있으면 가고 없으면 현재 자리에 그대로 있는다.
그 상태에서 n을 누르면 아래로 이동하고 N을 누르면 위로 이동한다. 그리고 gd를 눌러서 해당 단어의 선언이나 정의만 보고 다시 제자리로 오고 싶으면 '(엔터옆 따옴표)를 두 번 누른다.

파일이 탭으로 작성되었는지 확인 하기
:set list

중복된 여러 개 선언이 있을 때, 예를 들어서 i386/arm/mips/alpha 등 모든 플랫폼에서 선언하였을 때 tag 이동은 올바로 가는 경우가 거의 없다.
그럴 때는 g + ctrl + ]로 리스트를 뽑아서 이동

Usage: ctags [options] [file(s)]
-f <name> Write tags to specified file. Value of "-" writes tags to stdout ["tags"; or "TAGS" when -e supplied].
-h <list> Specify list of file extensions to be treated as include files. [".h.H.hh.hpp.hxx.h++"]
-R Equivalent to --recurse.

Usage: vim [arguments] [file ..]

리눅스에서 모든 .c와 .h파일에 대해 tag 생성
# ctags *.[ch]

# cd /usr/src/linux-2.4.18-3/include/linux
# find . -name '*.[chCH]' -print | ctags -R -L-

# cd /usr/include
# find . -name '*.[chCH]' -print | ctags -R -L-

set tags=./tags,tags,../tags,/usr/tags   " 자신의 디렉토리 및 상위 디렉토리 경로
set tags+=/usr/src/linux-2.4.18-3/include/linux/tags    " kernel의 경로 추가
set tags+=/usr/include/tags    " include 의 경로 추가
신고
블로그 이미지

꽃중년

불만있으면 떠나라...

Tag ctags, editor, gVim

1903년 12월 17일 윌버 라이트(Wilbur Wright: 1867-1912)와 오빌 라이트(Orville Wright: 1871-1948) 형제가 동력 비행기 플라이어(Flyer)호를 개발하여 노스캐롤라니나주 키티호크(Kitty Hawk)에서 인류 최초 동력비행에 성공한 이래, 인류의 하늘에 대한 도전은 100년 간 지속되어 왔다. 그 당시 59초, 260m 라는 비행기록으로부터 오늘에 이르러서는 거의 무제한 날 수 있게 되었지만 현재의 인류의 꿈은 비행시간이나 거리가 아닌 "어떠한 기상조건 하에서도 안전하게 뜨고 내리는" 쪽으로 달리고 있다.



즉 컴퓨터의 힘을 빌려 전천후자동이착륙을 가능케 하는 것이다. 이러한 꿈의 실현을 위해 사자(使者)들은 그 실현 과정을 I∼ III단계로 나누어 집요하게 추구해 나가고 있다. 시계착륙을 I단계로 보고 최종단계, 즉 한치 앞을 볼 수 없는 상태에서도 안전하게 착륙이 가능한 Almighty를 제III단계에 설정해놓고 있다. 물론 이것은 ILS라고 불리는 계기착륙장치라는 것이 갖추어짐으로써 이러한 목표설정이 가시적인 것이 되었다.



현재 모든 공항은 항공기의 안전한 자동이착륙을 위하여 이러한 계기착륙장치(ILS)를 갖추고 있는데 이는 계기착륙장치, 자동조종장치, 자동추력조정장치(Autothrottle System), 전파고도계 등이 밀접하게 관련되어 작동하므로써 가능한 것이다. 물론 이러한 장치는 활주로에 설치되어 있으나 당연히 항공기에도 이와 연계 가능한 계기가 갖추어져 있어야 하고 조종사도 아울러 훈련이 되어 있어야 함은 물론이다.



- 방위각 시설(LLZ : Localizer) : 활주로 중심선 방향 정보 제공

- 활공각장비(GP : Glide Path) : 착륙각도 정보 제공

- 마커장비(IM, MM, OM) : 항공기가 착륙하는 진입로상의 특정지점에 대한 위치정보 제공



ICAO에서는 전천후착륙장치(All Weather Landing System)개발을 단계적으로 추진하기 위해 5가지 카테고리(CAT)를 설정하여 기준을 정하고 있는데 이는 RVR(Runway Visual Range, 활주로가시거리)및 시정거리와 밀접한 관련이 있다.



①I 등급(CAT I) : 전천후 착륙프로그램 제1단계, RVR 550m 이상 또는 시정거리 800m이상, 결심고도 60m 이상


②Ⅱ등급(CAT II) : 전천후 착륙프로그램 제2단계, RVR 350m 이상 또는 시정거리 400m 이상, 결심고도 30m 이상


③Ⅲa등급(이하 CAT III) : 전천후 착륙프로그램 제3단계,RVR 200m이상, 결심고도 15m 이상


④Ⅲb등급: 전천후 착륙프로그램 제4단계, RVR 50m이상, 결심고도 15m 미만이 확보되면 안전한 이착륙이 가능


⑤Ⅲc등급: 전천후착륙 프로그램 최종단계, 활주로 시정거리 0m에서도 착륙 및 지상활주가 가능



여기서 RVR(활주로가시거리)란 활주로에 설치된 장비에 의해 측정한 거리며, "시정"이란 RVR 측정장비가 없어 기상대에서 육안으로 측정한 가시거리를 말한다.



이와 같이 공항의 계기착륙시설의 운영기준 등급은 시정거리를 얼마 나 확보하느냐에 따라 달라지게 되는데 이는 공항의 기상조건에 따라 제약을 받게된다. 인천공항은 현재 200m이상의 시정거리만 확보되면 되는 Ⅲa등급으로 계기착륙시설을 운영하고 있는데 월드컵 개최를 계기로 특히 안개로 시정거리가 짧을 때 회항률을 줄이기 위해 항공사에 대한 카테고리Ⅲa 운항승인과 조종사 기능증명 취득을 권고했다. 이륙 최저 시정치도 종전 200m에서 175m로 낮추어 운영중이다.



현재 김포공항(GMP)은 카테고리Ⅱ등급으로 운용중이고 일본의 대표적인 공항인 나리타공항(TYO-NRT) 및 칸사이공항(OSA-KIX)은 현재 카테고리 Ⅲa등급으로 운영 중이다. 그러나 인천공항은 ICAO와의 사전협의에 따라 개항 2년 후인 2003년도 하반기를 목표로 시정거리 50m∼100m에서도 항공기 이착륙이 가능한 카테고리Ⅲb등급으로 격상시킬 계획이며 이에 대한 시설은 이미 갖추어져 있다. 전 세계적으로 통용되는 시정거리 등급은 Ⅰ(최저 550m), Ⅱ(350∼500m), Ⅲa(200∼350m), Ⅲb(50∼200m), Ⅲ(0m) 등 5단계로 나눠져 있다. Ⅲ-C 등급에 해당하는 공항은 지구상에 아직 존재하지 않는다.



인천공항은 현재 건설교통부에 활주로 시정거리 등급을 Ⅲa에서 1단계 높은 Ⅲb로 승격신청을 해 놓은 상태로 건설교통부 항공운항안전본부는 항공기 유도, 지상 감시장치 등 인천공항의 시설과 관제절차 등에 대해 부문별로 종합심사와 현장실사를 하고 있으며 상반기 중 등급과 관련된 모든 절차를 매듭짓고 승격, 2003년 하반기부터 최저 시정거리를 100m까지 완화할 수 있게 된다. 인천공항은 개항시 등급 승격에 필요한 모든 시설을 미리 갖춰두었기 때문에 운영 측면에서 별다른 문제가 없을 것으로 보인다.



ILS 카테고리 Ⅲb는 전 세계적으로도 미국 덴버공항과 영국 런던 히드로, 프랑스 드골공항 등 55개이다. 2002년도의 경우 인천공항에서 짙은 안개로 인해 시정거리가 100m 이하였던 경우는 한 건도 없었기 때문에 등급이 승격되면 인천공항에서는 비행기 지연 이륙이나 회항 등의 사태는 거의 사라질 것으로 보인다.



◇ILS Category IIIb 설치 공항 현황 (2003.7.1현재)

▲미국(33개 공항) : ANC(Anchorage), ATL(Atlanta), AUS(Austin), BWI(Baltimore), CAE(Columbia), CLT(Charllote), CLE(Cleveland), ORD(Chicago), CVG
(Cincinnati),DFW(Dallas),DEN(Denver),IAH(Houston),IND(Indianapolis),MCI(Kansas City),LAX(Los Angeles),SDF(Louisville Standfo rd),MEM(Memphis),MKE(Milwaukee),BNA(Nashville),MSY(new Orleans),JFK(New York-JFK),EWR(Newyork-Newark),OAK(Oakland),MCO(Orlando),PHL(Philadelphia),PIT(Pitsburgh),PDX(Portland),SMF(Sacramento),SLC(Salt Lake City),SEA(Seattle),TPA(Tampa),FAT(Yosemite),IAD(Washington DC



▲독일(10) : TXL(Berlin Tegal-Otto),SXF(Berlin-Schonefeld),CGN(Bonn),DUS(Duesseldorf),FRA(Frankfurt), HAM(Hamburg),HAJ(Hanover)
LEJ(Leipzig Halle) MUC(Munich),STR(Stuttgart)



▲영국(6) : BFS(Belfast),BRS(Bristol),LHR(London-Heathro),EDI(Edinburgh),EMA(East Midland),MAN(Manchester)



▲유럽(5) : CPH(Copenhagen), CDG(Paris), PRG(Prague), VCE(Venice),VIE(Vienna)



▲아프리카(1) : CPT(Capetown Int'l Airport)



▲2003년도 중 준비중인 공항(4) : ICN(Incheon In'tl), AUH(Abu Dhabi), BEG(Belgrade),AMS(Schiphol)
※현재 전세계 55개 공항이 카테고리 IIIb를 운영중에 있으며 금년중으로 인천공항을 비롯 3개공항이 인증을 서두르고 있다. 아시아권에서는 아직까지 Ⅲb 인증을 받은 공항이 없으며 인천공항은 최초의 Ⅲb 인증을 받은 공항이 될 것이다.



그러나 시정거리 등급이 높아지더라도 곧바로 시행에 옮길 수 있는 것은 아니다. 계기착륙시설과 등화시설 등 공항시설을 비롯해 인천공항에 이 착륙할 항공기와 조종사들도 카테고리 Ⅲb 조건에 맞는 요건을 갖춰야 허용되는 것이다. 현재 인천공항에 취항하는 53개 항공사 중 유나이티드, 에어프랑스 등 15개 항공사가 이 요건을 갖추고 있으며 대한항공과 아시아나항공도 자격 취득을 서두르고 있다. 따라서 2003년 하반기부터 시작하여 본격적으로 카테고리 Ⅲb가 운영되는 것은 2004년경부터가 될 것으로 보인다.



건교부는 착륙이 가능한 가시거리 기준을 우선 100m이상으로 적용한 후, 항공사들이 준비가 되는대로 단계적으로 75m이상 수준으로 조정한다는 방침이다.



영종도 일대에서 발생하는 안개, 특히 해무와 안개 발생시의 시정거리와 지속시간 등이 궁금하지 않을 수 없다. 인천국제공항의 활주로지역 일대가 원래는 바다, 그것도 주로 개펄이었고 당연히 북에서 남으로 또는 남에서 북으로 해류가 흐르고 있었던 만큼 그것을 인위적으로 남측, 북측 방조제로 막아버린 이상 어떤 형태로든 어느 정도의 기상변화는 각오해야할 것이다. 또한 그 결과에 따라서는 항공기의 결항률에 직접 간접적으로 영향을 미칠 것이 불가피한 요소이기도 하다.



영종도 및 용유도 일대에 대한 과거의 기상 데이타는 1994년 10월말 남북 양측 방조제 물막이공사가 끝나고 해류가 차단된 시점에서 일단 시효가 만료되었고 이 때부터 새로운 데이타의 적치가 시작되었다고 보아야 한다. 만일 인천국제공항에 계기착륙시설이 운용되지 않는다면 가을하늘처럼 가시거리가 약 5,000m이상이고 구름의 높이가 450m이상일 경우에만 시계비행으로 착륙이 가능하고, 약한 비나 옅은 안개에 의해서도 수시로 결항이 될 수밖에 없어 국제공항으로서의 제 기능을 갖추지 못할 것이다.

출처 :
www.airport114.com
www.whel.de/Aerospace/airport_rwy_info_1.html

www.navaid.co.kr/n_nav/NAV_MAIN.htm
신고
블로그 이미지

꽃중년

불만있으면 떠나라...

Tag Cat, ILS



 

현대의 항공기는 시계(視界)에 의존하던 초창기에 비해 첨단 운항기기들로 인해 전천후 착륙이 가능한 비약적인 발전을 이루어냈습니다. 따라서 안개 혹은 구름이 낀 날씨나 야간 착륙시에도 공항의 항공기 착륙 유도 장치의 구비 여건에 따라 계기착륙이 가능하게 된 것이지요.

현재 대부분의 공항에서 항공기의 항행, 특히 착륙을 위해 사용되는 시설로는 정밀 진입용 시설인 계기 착륙 장치(ILS:Instru-ment Landing System)와 비정밀 진입용 시설인 초단파 전방향식 무선표지(VOR), 거리 측정 장치(DME), 전술 항법장치(TACAN), 무지향성 무선표지(NDB) 등이 있습니다.

이중 계기 착륙 장치(ILS)는 기상조건이 나쁠 때 전파를 이용하여 항공기의 진입방향과 강하의 경로를 지시하여 안전하게 착륙시키는 시설입니다. 국제민간항공기구(ICAO:International Civil Aviation Organization)에서는 무선 착륙 지원 시설의 국제표준을 설정하고 있는데, 그 성능에 따라 공항을 ‘카테고리 1’에서 ‘카테고리 3’까지 세 가지로 구분하고 있습니다. ‘카테고리 3’의 경우 항공기가 활주로면까지 육안에 의지하지 않고 계기 착륙하는 것이 가능합니다. 현재 우리 나라에서는 인천국제공항만이 카테고리 3의 자동착륙 성능을 갖추고 있습니다. 그러나 대다수 국내 일부 지방공항들은 시설이 구비되어 있지 않아 기준에 못 미치는 곳도 많습니다.

조종사는 ILS 수신장치로 지상의 ILS 시설이 발사하는 전파를 수신하여 항공기의 진입 방향과 강하, 착륙 코스를 지시받고 그에 따라 항공기를 조종, 강하하면 정확하게 활주로에 착륙할 수 있게 됩니다.

ILS의 지상 설비로는 진입 방향을 지시하기 위한 로컬라이저(Localizer), 강하 경로를 지시하기 위한 글라이드 패스(Glide Pass), 진입 코스상의 특정지점 상공을 지시하기 위한 마커(Marker) 등이 있습니다.

로컬라이저는 진입 중의 항공기에 대해 활주로의 방향을 지시하는 전파를 발사하게 됩니다. 이 전파는 두 개의 다른 주파수로 변조되어 코스의 중심 선상에서는 양 주파수의 크기가 대등해집니다. 이 때 조종석에서 수신되는 신호가 좌측이 강하면 좌측으로, 우측이 강하면 우측으로 치우쳐 있음을 알게되는 것이지요.

로컬라이저 외에 항공기 진입시 활주로에 대한 강하 각도가 적정한지를 지시하는 전파를 발사하는 글라이드 패스도 있습니다. 마커는 활주로 끝으로부터 1천여 미터 지점에 설치되어 있는 내측 표시, 3천500미터와 7천 미터에 설치되어 있는 외측 무선 위치표시, 세 개로 구성되어 있습니다.

이 시설들에서는 지상으로부터 마커 비컨(Marker Beacon)이라는 전파를 진입 코스의 수직방향으로 발사시켜 항공기의 수신기가 이를 수신하면 램프가 켜지고 동시에 전파의 변조음을 들을 수 있게 되어 있습니다. 따라서 항공기가 진입 코스의 어느 지점을 통과했는지를 알수 있는 것이지요.

대한항공은 이러한 항행 시설들이 미비한 일부 지방공항에 대하여 보다 강화된 엄격한 운항기준을 적용, 필요한 경우 운항 자체를 포기하는 안전 최우선의 운항규정을 준수하고 있습니다.

신고
블로그 이미지

꽃중년

불만있으면 떠나라...

I2C Bus

Hardware 관련/BUS 2008.03.16 15:38

http://www.hayanmail.com/jsy/index.html?board=cizblog_zboard3&ln_mode=news_view&id=5&ct_sel=2

I2C Bus


Inter-IC Bus (= TWI: Two-wire Serial Interface)

Philips에서 제안한 IC간 통신 방식으로 클럭(SCL)과 데이터(SDA)의 2라인을 사용하는 동기 양방향 2선식 Bus이다. 버스에 연결된 각 디바이스는 고유의 어드레스를 갖으며 필요에 따라 receiver와 transmitter로 동작한다. 전송속도는 standard mode에서 100kbps까지 이고 fast mode에서는 400kbps까지 가능하다.

transmitter: 버스에 데이타를 보내는 장치
receiver:     버스로부터 데이타를 받는 장치
master:       전송을 개시하는 장치로 클럭 펄스를 만들고, 전송을 종료하는 일을 한다.
slave:          master가 어드레싱한 장치

master가 start condition을 만들면 버스에 연결된 슬레이브 장치들이 이후의 데이터를 기다린다. master가 slave 어드레스를 보내면 각 칩은 자신의 고유 어드레스와 비교를 한다. 어드레스가 일치하는 칩은 이어지는 acknowledge 신호 구간에서 데이터를 low로 유지해 응답을 보낸다. 그러면 master는 데이터를 읽거나 쓰기를 할 수 있다. 모든 작업이 끝나면 master는 stop condition을 발생하고 버스를 release한다.

SDA H -\      /---\     /---\          /---\         /---\      /---
    L   \----/     \---/     \--------/     \-------/     \----/

SCL H ----\     /-\       /-\     /-\    /-\    /-\    /-\    /------
    L      \---/   \-----/   \---/   \--/   \--/   \--/   \--/


   | START   |   1    |    1    |   0  |  1   |  0   |   1   | STOP

* start condition
클럭과 데이터가 모두 high인 일반 상태에서 데이타 라인이 low로 떨어지는 상태.

SDA H ------\
    L        \-------
SCL H ---------\
    L           \----

* stop condition
클럭이 high인 동안에 데이타 라인이 low에서 high로 바뀌는 상태.

SDA H           /----
    L ---------/
SCL H        /-------
    L ------/

* 일반 데이터 전송에서는 클럭이 low일 때만 데이타의 상태를 바꿀 수 있다. 따라서 클럭이 high인 구간에만 유효한 데이타이다. master는 먼저 데이타 라인을 적당한 데이타로 바꾸고 클럭 라인을 일정시간 high로 하고 다음 SDA 라인의 상태를 바꾸기 전에 클럭을 low로 만든다. 데이타는 8bit이고 MSB가 먼저 전송된다. start 와 stop condition 사이에 전송되는 데이타의 수는 제한이 없다.

SDA H       /----------\
    L -----/\----------/\-------
SCL H          /----\
    L --------/      \----------

* acknowledge 조건
master든 slave든 transmitter는 8 bit 전송을 마치고 버스선을 high로 한다. 9번째 사이클 동안 receiver는 데이타 선을 low로 유지하여 acknowledge 를 표시한다.

write시

한 byte write시

S

slave address

A

data write

A

P

여러 byte write시

S

slave address

A

data write

A

data write

A

...

data write

A

P

Note : S = start condition
          A = Wait for Acknowledge (master <-- slave)
          P = stop condition

read시

slave address를 보낸후 SDA를 놓아주면 slave가 8bit 데이터를 보내고 master는 ack신호를 slave에게 보내준다.

한 byte reading

S

slave address

WA

read byte

GNA

P


여러 byte reading

S

slave address

WA

read byte

GA

...

read byte

GNA

P

Note: WA = Wait for Acknowledge (master <-- slave)
          GA = Give Acknowledge (master --> slave)
GNA = Give Acknowledge with NACK (master --> slave) : end of reading

I2C software driver pseudo code

#define SDA_HIGH()	  { ... your code here ... } // SDA pin high
#define SDA_LOW()	  { ... your code here ... } // SDA pin low
#define SCL_HIGH()	  { ... your code here ... } // SCL pin high
#define SCL_LOW()	  { ... your code here ... } // SCL pin low
#define SDA_OUPUT() { ... your code here ... } // SDA pin output mode
#define SDA_INPUT() { ... your code here ... } // SDA pin input mode
#define SDA_READ()	  { ... your code here ... } // SDA pin read

#define i2c_delay()  delay_us(5)	// delay time for 100khz clock
#define i2c_clock() \
{ i2c_delay(); SCL_HIGH(); i2c_delay(); SCL_LOW(); } #define i2c_start() \
{ SDA_HIGH(); SCL_HIGH(); i2c_delay(); SDA_LOW(); i2c_delay(); SCL_LOW(); } #define i2c_stop() \
{ SCL_LOW(); SDA_LOW(); i2c_delay(); SCL_HIGH(); i2c_delay(); SDA_HIGH(); i2c_delay(); } unsigned char i2c_write(unsigned char data) { unsigned char i; for(i=0; i<8; i++) { // MSB first if(data & 0x80) SDA_HIGH(); else SDA_LOW(); i2c_clock(); data = data << 1; } // read ACK SDA_HIGH(); // leave SDA HI SDA_INPUT(); // change direction to input on SDA line i2c_delay(); SCL_HIGH(); // clock back up i2c_delay(); i = SDA_READ(); // get the ACK bit SCL_LOW(); SDA_OUPUT(); // change direction back to output return i; } unsigned char i2c_read(void) { unsigned char i, data; SDA_HIGH(); // leave SDA HI SDA_INPUT(); // change direction to input on SDA line data = 0; for(i=0; i<8; i++) { // MSB first data = data << 1; SCL_HIGH(); // clock HI i2c_delay(); if(SDA_READ()) // get the Data bit data |= 1; SCL_LOW(); // clock LO i2c_delay(); } SDA_OUPUT(); // change direction back to output // send ACK SDA_LOW(); i2c_clock(); SDA_HIGH(); // leave with SDA HI return data; } unsigned char i2c_read_nack(void) { unsigned char i, data; SDA_HIGH(); // leave SDA HI SDA_INPUT(); // change direction to input on SDA line data = 0; for(i=0; i<8; i++) { // MSB first data = data << 1; SCL_HIGH(); // clock HI i2c_delay(); if(SDA_READ()) // get the Data bit data |= 1; SCL_LOW(); // clock LO i2c_delay(); } SDA_OUPUT(); // change direction back to output // send NACK SDA_HIGH(); i2c_clock(); SDA_HIGH(); // leave with SDA HI return data; }















EEPROM read/write sample (AT24C32)

#define EEP_SLAVE_ADR	0xA0
#define TWI_WRITE		0x00
#define TWI_READ		0x01
#define TWI_ACK		0
#define TWI_NACK		1
#define TWI_ERROR		TWI_NACK

void eep_write(unsigned short addr, unsigned char data)
{
	i2c_start();
	i2c_write(EEP_SLAVE_ADR|TWI_WRITE);  // slave address
	i2c_write(addr>>8);		// word address high
	i2c_write(addr & 0xFF);		// word address low

	i2c_write(data);
	i2c_stop();

	delay_ms(6);		// 5ms EEPROM write cycle time
}


unsigned char eep_read(unsigned short addr)
{
	unsigned char	data;

	i2c_start();
	i2c_write(EEP_SLAVE_ADR|TWI_WRITE);	// slave address
	i2c_write(addr>>8);		// word address high
	i2c_write(addr & 0xFF);		// word address low

	i2c_start();
	i2c_write(EEP_SLAVE_ADR|TWI_READ);	// slave address with READ
	data = i2c_read_nack();
	i2c_stop();

	return data;
}
신고
블로그 이미지

꽃중년

불만있으면 떠나라...

Tag I2C Bus

http://www.hayanmail.com/jsy/index.html?board=cizblog_zboard3&ln_mode=news_view&id=14&ct_sel=2

스레드를 사용하는 프로그램 디버그시 OS가 멈추는 현상

XP에서 스레드를 사용하는 프로그램을 디버깅하다 보면 자주 OS가 멈춰버려서 리부팅까지 해야 되는 상황이 자주 발생합니다. 이 때문에 98이나 2000 에서 디버깅을 하기도 했는데 VC++ 6.0과 XP가 충돌하는 것으로도 의심을 했었지만 VC++2005 에서도 동일한 문제가 생긴다고 합니다.
그래서 검색을 해보니 원인은 IME 쪽 버그라고 합니다.
해결방법은 제어판 --> 국가 및 언어 옵션 --> 언어 탭 --> 자세히... --> 고급 --> 고급 텍스트 서비스 사용 안 함 을 체크하고 리부팅을 합니다.


VC++의 메모리 누수 (Memory Leak) 탐지 기능 사용하기

보통 디버깅을 하다보면 메모리 릭이 발생했다는 메시지가 출력되지만 어디에서 현상이 발생했는지는 표시해 주지 않습니다. 다른 유틸리티를 사용해 보기도 했지만 가끔 프로그램에 충돌이 생겨 디버깅을 할 수 없었습니다.

이런 경우에 VC++에 내장된 메모리 누수 탐지 기능을 사용해서 현상이 발생된 소스 파일의 위치를 표시하도록 할 수 있습니다. 원리는 new 나 malloc 등의 함수를 새로 정의해 메모리를 할당할 때 소스 파일의 위치를 기억해 두었다가 프로그램 종료시 해제되지 않은 메모리의 위치를 표시하도록 하는 것입니다.
소스 파일명을 나타내는 마크로 __FILE__와 라인 번호를 나타내는 마크로 __LINE__ 가 사용됩니다.

(1) MFC를 사용하는 경우

먼저 stdafx.h 파일에서 다른 include 문 보다 제일 상위에 다음 선언문을 추가 합니다.

#ifdef _DEBUG
#define _CRTDBG_MAP_ALLOC // include Microsoft memory leak detection procedures
#define _INC_MALLOC      // exclude standard memory alloc procedures
#endif

_CRTDBG_MAP_ALLOC 은 crtdbg.h 파일에서 new 등을 새로 정의하도록 사용됩니다.

그리고 프로그램 초기에 아래 함수를 추가합니다.

#ifdef _DEBUG
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF|_CRTDBG_LEAK_CHECK_DF);
#endif

stdafx.h 파일을 사용하지 않는 소스 파일의 경우 (Pre compiled header 기능을 사용하지 않는 경우)는 기존 메모리 할당 함수를 사용하게 되므로 이 기능이 지원되지 않게 됩니다.

(2) MFC를 사용하지 않는 경우

crtdbg.h 파일이 자동으로 추가 되지 않으므로 소스 파일에 crtdbg.h 를 추가해야 합니다.

#ifdef _DEBUG
#define _CRTDBG_MAP_ALLOC
#include [crtdbg.h] <-- 수정 필요 :-)
#endif

마찬가지로 프로그램 초기에 아래 함수를 추가 합니다.

#ifdef _DEBUG
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF|_CRTDBG_LEAK_CHECK_DF);
#endif

(3) 링크에러가 발생하는 경우

nafxcwd.lib(afxmem.obj) : error LNK2005: "void * __cdecl operator new(unsigned int)" (??2@YAPAXI@Z) already defined in StdAfx.obj

위와 같은 링크 에러가 발생하게 되면 임시 방편으로 아래와 같이 강제로 링크하도록 합니다.

Project Settings --> Link --> Customize --> Force file output 항목 체크
(* 주: 이것은 항구적인 해결책은 아닙니다. 다른 링크에러도 무시되므로... )

이는 Project options에 /FORCE 플래그를 추가 하는 것과 동일 합니다.

static 라이브러리 작성시 주의사항

static 라이브러리를 작성해 application에 링크하려다 보면 LIBCD.lib 등의 링크 에러가 발생합니다. 이것은 static library 위저드와 application 위저드가 Code Generation 옵션을 서로 다르게 생성하기 때문입니다.

해결 방법은 Project Settings --> C/C++ --> Code Generation --> Use run-time library --> Debug Multithreaded XXX 식으로 application에 사용된 속성과 맞춰줘야 합니다.

디버그시 변수값 보기

사용자 지정 구조체등의 값이 표시되지 않을 때나 크기가 아주 큰 변수의 경우 메모리 뷰를 띄워서 볼 수도 있지만 불편하다. 이 경우 변수, 10 (앞의 10 바이트만 표시) 형식으로 입력하면 된다.

원하는 데이터 형으로 보고 싶은 경우에는 (형변환자)변수 형식으로 입력한다.

텍스트를 컬럼으로 선택하기

- 텍스트를 라인으로 선택하지 않고 컬럼으로 선택하려면 ALT + 마우스 드래그, 또는 ALT+SHIFT+방향키를 사용한다.
칸을 맞춰놓은 경우 중간에 불필요한 것을 삭제하거나 끼워 넣을 경우 일일히 타이핑하지 않아도 되므로 편리하다.

무료 윈도우 컴파일러 사용하기

- 코드프로젝트의 다음 기사를 참고하여 VC++ 2005 Express 버전을 설치하고 MFC대신에 WTL을 개발 프레임워크로 사용한다.
Using WTL with Visual C++ 2005 Express Edition
- 무료 리소스 편집기로는 아직 버그가 많지만 간단한 리소스의 경우 ResEdit 을 추천한다.
- VC++ 2005 Express에 리소스편집기 등록 방법: RC파일을 선택하고 팝업메뉴에서 Open With...를 클릭한다. [Add...] 버튼으로 리소스 편집 프로그램을 등록 후 [Set as Default]를 클릭한다.

들여쓰기 자동 정렬하기

- 입수한 소스가 들여쓰기가 제대로 안돼 있어서 읽기 불편한 경우 다음과 같은 방법으로 자동정렬 할 수 있다.
우선 정렬할 부분을 선택하고 SHIFT + TAB 키를 몇 번 눌러 불필요한 불필요한 공백 문자를 제거한다.
그리고 ALT+F8 을 누르면 자동으로 들여쓰기를 맞춰준다.

추가된 클래스가 클래스위저드에서 보이지 않을 때

보통은 클래스위저드 파일(.clw)을 삭제하고 갱신해 준다.
이렇게 해도 클래스가 보이지 않으면 다음 내용이 소스파일에 있는지 확인하고 없으면 추가해 준다.
헤더 파일에는 다음 내용이 들어 있어야 한다.

// ClassWizard generated virtual function overrides
	//{{AFX_VIRTUAL(CMyWnd)
	//}}AFX_VIRTUAL

	// Generated message map functions
protected:
	//{{AFX_MSG(CMyWnd)
	//}}AFX_MSG
	DECLARE_MESSAGE_MAP()
그리고 소스 파일에는 다음 내용이 있어야 한다.
BEGIN_MESSAGE_MAP(CMyWnd, CWnd)
	//{{AFX_MSG_MAP(CMyWnd)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()
신고
블로그 이미지

꽃중년

불만있으면 떠나라...

Tag vc++
http://www.hayanmail.com/jsy/index.html?board=cizblog_zboard3&ln_mode=news_view&id=13&ct_sel=2


AT91SAM7S256

그래픽 처리등으로 많은 메모리와 좀더 빠른 처리시간이 요구 되면서 새로운 MCU가 필요했는데 ATmel에서 아주 유용한 놈이 나왔습니다. 보통 ARM은 CPU로 외부에 RAM과 ROM을 추가로 붙여야 하지만 이 녀석은 마이크로컨트롤러 식으로 RAM과 ROM이 내장된 방식이고 패키지도 LQFP 입니다. OS를 올릴 정도는 안되고 AVR로는 좀 부족한 중급 레벨의 시스템을 구성할 때 좋겠습니다.
드디어 32비트의 세계로 발을 들이게 되었는데 많이 낯설고 레지스터 한 개가 32 비트씩이니까 어지럽군요@.@
48메가로 돌리니까 AVR에 비해 붕붕~ 날아 다닙니다. 예전 486 급의 클럭 스피드니까요. 단순 수치상으로는 3배가 빠르지만 수 백번 반복 연산의 경우 전체 절약시간은 [수 백 x 단위 절약시간] 이 되어 3초 걸리는 일을 1초에 끝내는 것은 2초 절약으로 별 차이가 아니지만 3시간 걸리는 일을 1시간 만에 한다는 것은 2시간이 절약되어 체감상으로 큰 차이입니다.

특징

  • 내장 64KB 램, 256KB 플래시 롬
  • 12Mbps USB 내장
  • 3개의 UART 사용가능
  • 1개의 I/O 포트가 있어 32개의 입출력 핀 사용가능 (5V tolerance I/O)
  • 내장 PLL회로로 55MHz 까지 구동 (누군가는 105 MHz까지 오버클럭 해봤다는 군요^.^)
  • 내부 패리패럴 장치를 위한 13 채널의 DMA 컨트롤러
  • MHz당 0.9MIPS
  • SAM-BA 부트로더가 내부 마스크 롬에 내장
  • 64핀 LQFP 패키지

* 8비트 마이컴과의 차이점

  • 기동시 PLL 로 동작 주파수를 설정함
  • ARM의 전원관리 기능 때문에 사용하려는 내부 장치의 전원(클럭)을 먼저 살려줘야 함
  • set용 레지스터와 clear 용 레지스터가 분리돼 있음
  • 포트를 예전처럼 사용하려면 해당 핀을 direct drive 모드로 설정해야 함
  • int 형이 16비트에서 32비트로 바뀜
  • 구조체의 sizeof() 연산자 사용시 크기가 바뀔수 있음을 주의
    (gcc의 경우는 __attribute__ ((packed)), 일반적으로는 #pragma pack(1) ~ #pragma pack() 사용)

* 아트웍시 주의사항: TST, JTAGSEL, ERASE 핀은 사용하지 않을 시 GND에 연결하는 것이 좋음
외부 노이즈에 의한 HIGH 유입시 증상: TST 및 ERASE(부팅시 프로그램 지워짐), JTAGSEL(프로그램 정지)


WinARM GCC 컴파일러

AVR의 WinAVR 식으로 나온 것입니다.
홈페이지는
http://gandalf.arubi.uni-kl.de/avr_projects/arm_projects/index.html
역시 경로에 C:\WinARM\bin;C:\WinARM\utils\bin 을 추가해야 합니다.
WinAVR이 설치된 경우는 C:\WinARM\utils\bin 부분이 필요 없습니다.

SAM-BA 를 통한 ISP 지원

별도 롬에 내장된 부트로더로 USB 또는 RS232 포트(DBGU)로 인 시스템 프로그래밍(ISP)을 지원 합니다. PC측 프로그램은 Atmel 사이트에서 다운 받을 수 있습니다. SAM-BA는 플래시 롬에 있을 때 실행되며 사용자 프로그램을 라이팅하게 되면 플래시를 덮어쓰게 되므로 이 부트로더는 지워지게 됩니다. 지워졌을 경우는 System Recovery 과정을 통해 내장된 별도 롬에서 플래시 롬으로 다시 복사할 수 있습니다. 최초에는 플래시 롬이 비여있는 상태이므로 SAM-BA를 복사해야 합니다.
실제 사용에는 불편하여 별도 부트로더를 작성해 사용하게 됩니다. SAM-BA는 단지 부트로더를 처음 write할 때 사용합니다.

WinARM용 부트로더(bootloader)

SAM-BA의 불편함과 불합리한 점 때문에 다른 프로그램을 참고로 WinARM용 부트로더를 만들어 봤습니다.
사용자 프로그램에 통합된 형태이고 시리얼 포트를 이용합니다. 다른 컴파일러에서도 조금 수정하면 사용가능할 것입니다.
자세한 사항은 readme.txt 파일을 참고하세요.
sam7flash.zip ver 1.0.4 (134KB)

ARM은 RAM 에서 코드 실행이 가능합니다. makefile에서 RUN_MODE를 RAM_RUN으로 설정하면 RAM에서 실행되도록 컴파일 할 수 있습니다.
sam7flash 부트로더에서 사용 가능한 RAM 실행 데모 입니다.
ramdemo.zip (53KB)

위 부트로더를 롬 이미지로 만든 버전입니다. 평소에는 RAM을 소비하지 않습니다.
u_boot.zip (130KB)

JTAG 장비

단순 인터페이스 인데 가격이 좀 비싸군요. USB 패킷을 잡아보면 호환 제품을 자작하는 것도 가능할 것입니다.

WIGGLER는 패러랠 포트를 사용하는 초저가 형입니다.
DTC114 블럭은 디지털 TR로 단순 인버터 기능이므로 74HC14로 구성해도 됩니다.

Simple JTAG interface circuit.
==============================

25 pin Male parallel                                              20 pin JTAG header

    17-25 <--------------+-------------------------+--+-----------<  4,6,8,
              GND        |                         |  |              10,12,14,
                         |    AC244          200nF =  = 4.7uF        16,18,20 (GND)
                         | +------------+  Vcc     |  |
         TDI          0v +-| 1       20 |-+--------+--+-----------<  1,2 (VCC)
    5  >-------------------| 2       19 |-+
         TMS               | 3       18 |-----XXXX---------------->  5 (TDI)
    3  >-------------------| 4       17 |     51R     
         TCLK              | 5       16 |-----XXXX---------------->  7 (TMS)
    4  >-------------------| 6       15 |     51R
                           | 7       14 |-----XXXX---------------->  9 (TCK)
                      +----| 8       13 |     51R
                      |    | 9       12 |-----XXXX---+
                      |  +-| 10      11 |     51R    |
                      |  | +------------+            |
                      |  V 0v                        |
                      +------------------------------------------<   13 (TDO)
         TDO                                         |
    11 <---------------------------------------------+


                            DTC114   /-------xxxx----------------<   15 (nRST)
         RST            10k       | /        51R
    2  >----------------XXXX--+---|<
                              |   | \
                              X      V
                         47k  X      |  
                              X      |
                              |      |
                              V 0v   V

usbjtag USB포트를 사용하는 자작 JTAG 에뮬레이터
J-Link 수 백만원 대의 Multi-ICE 보다 저렴한 JTAG 에뮬레이터
AT91SAM-ICE J-Link의 ATmel 버전 (22만원) : 타 ARM CPU에 사용하려면 별도 라이센스를 구매해야 함

AT91SAM7X256

SAM7S 시리즈가 핀수가 적어 더 많은 제어핀이 필요한 경우 SAM7X 시리즈를 사용할 수 있습니다.
- 포트B 가 추가되어 31핀을 더 사용할 수 있음
- SPI 1채널 추가. Ethernet MAC 추가
- SAM-BA 를 호출하는 방식이 편리하게 바뀜.
즉, ERASE핀에 220ms 이상 high 신호를 입력해 주면 플래시가 지워지고 NVM 플래그가 초기화되어 내장 부트롬(SAM-BA)으로 부팅하도록 됨. SAM-BA로 라이팅후 다시 NVM 플래그를 설정해야 플래시로 부팅가능하여 사용자 프로그램이 실행되게 됨.
초기 출하상태는 내장 부트롬(SMA-BA)으로 부팅 가능한 상태임.
- USB 엔드포인트 2개 추가로 총 6개의 엔드포인트 지원.

AT91SAM7SE256

EBI 인터페이스가 있어서 DRAM 등을 추가로 장착할 수 있는 버전입니다.

openocd 사용법 (JTAG을 이용한 디버깅 방법)

1. openocd 설치

일단, JTAGSEL 핀은 사용하지 않습니다. 오픈 상태로 두거나 GND로 처리해야 합니다.
디버그에 필요한 파일은 WinARM 패키지에 모두 들어있습니다.
OpenOCD 홈페이지(http://openocd.berlios.de/web)에서는 현재 최신버전을 Yagarto(http://www.yagarto.de/)에서 제공한다고 돼있습니다.
최신 버전을 설치하고 사용하는 JTAG 장비의 PC인터페이스에 맞는 config 파일을 준비해야 합니다.
패러랠 포트나 FT2232를 사용한 USB포트를 지원하고 있습니다.
사용자 환경에 맞춰 OpenOCD를 실행합니다.

예) openocd-ftd2xx.exe -f arm7_ft2232.cfg (USB 포트의 경우)
openocd-pp.exe -f arm7_wig.cfg (Wiggler의 경우)

실행이 되어 JTAG 장비와 연결에 성공하면 아래와 같은 메시지가 출력됩니다.

Info: openocd.c:84 main(): Open On-Chip Debugger (2007-01-31 12:00 CET)
Warning: arm7_9_common.c:683 arm7_9_assert_reset(): srst resets test logic, too

여기까지만 성공하면 절반은 성공입니다.

2. openocd 사용법 I - 텔넷을 통한 연결

openocd 자체로는 아무것도 할 수 없습니다. 단지 드라이버를 통해 JTAG장비와 연결해주고 클라이언트 S/W와의 통신을 지원하는 디버그 서버의 역할만 합니다.

openocd는 telnet과 gdb 연결을 지원합니다. telnet은 4444 포트를, gdb는 3333 포트를 사용합니다.
이제 도스창에서 telnet을 실행해서 JTAG이 제대로 동작하는지 확인해 봅니다.

telnet localhost 4444

연결되면 아래와 같은 메시지가 출력됩니다.
Open On-Chip Debugger
]

플래시 메모리 정보를 보기 위해 다음 명령을 입력합니다.
] flash info 0

그러면 아래와 같은 메시지가 출력됩니다.

#1: at91sam7 at 0x00100000, size 0x00020000, buswidth 4, chipwidth 0

at91sam7 information: Chip is AT91SAM7X128
cidr: 0x275a0740, arch: 0x0075, eproc: ARM7TDMI, version:0x000, flashsize: 0x00020000
master clock(estimated): 52369kHz
pagesize: 256, lockbits: 8 0x0000, pages in lock region: 64
securitybit: 0, nvmbits: 0x4
]

플래시에 프로그램을 라이팅하기위해 아래의 명령을 사용해 lockbits을 해제합니다.
초기 상태는 lockbits이 해제된 상태입니다.

flash protect 0 0 15 off -- AT91SAM7S256의 경우 lockbits 해제
flash protect 0 0 7 off -- AT91SAM7X128의 경우 lockbits 해제

플래시에 프로그램을 기록하려면 아래의 명령을 사용합니다.

flash write 0 main.bin 0
여기서 main.bin 은 openocd가 실행된 폴더에 있어야만 가능합니다.

또는 경로를 지정하여 다음과 같이 입력합니다.

flash write 0 c:\test\main.bin 0

기타 명령으로는,
reg: 레지스터 정보를 출력합니다.
exit: 텔넷을 종료 합니다.
shutdown: openocd를 종료합니다.
help: 도움말을 출력합니다.

3. openocd 사용법 II - Insight를 통한 디버깅

먼저 플래시메모리에 디버깅할 프로그램을 굽고 시작합니다.

(1) WinARM/utils/insight/bin (또는 WinARM/bin) 폴더에서 arm-elf-insight.exe 를 실행합니다.
(2) File -- Open... 에서 디버깅하려는 elf 파일을 선택합니다.
(3) File -- Target settings..에서
Target은 Remote/TCP로, Hostname은 localhist로, 포트는 3333으로 설정합니다.
브레이크 포인트는 Set breakpoint at 'main' 만 선택합니다.
Run Method는 Continue from Last Stop을 선택합니다.
More options에서 Command to issue after attaching:에서 아래 내용을 입력하고 OK버튼을 누릅니다.
monitor arm7_9 force_hw_bkpts enable
(4) Run -- Connect Target을 실행합니다.
(5) Run -- Download를 실행합니다.
(6) Run -- Run 을 실행합니다.

그러면 main()에서 브레이크가 걸리게 됩니다.
원하는 라인의 왼쪽을 클릭하면 브레이크포인트가 설정됩니다.

여기서 주의사항은 소프트웨어브레이크 포인트는 2개만 지원합니다.
그 이상을 설정하고 진행하려 하면 openocd창에 아래와 같은 메시지가 출력됩니다.
Info: breakpoints.c:65 breakpoint_add(): can't add software breakpoint, resource not available
그러면 브레이크 포인트를 해제해야 진행이 가능합니다.
(Only two software breakpoints are supported. So, you have to remove some breakpoints to continue.)

링크

AT91SAM7S C-Startup Sequence
Procyon ARMlib
AT91 ARM Forum
WinARM User Forum
Philips ARM Design Contest 2005
FreeRTOS
TNKernel
OpenOCD Quick Reference

 

* 참고

Philips 의 LPC2101은 이와 유사한 마이크로콘트롤러이며 70MHz에 가격은 3,500원 대입니다.

신고
블로그 이미지

꽃중년

불만있으면 떠나라...


FAT 파일 시스템(File System)

원문 :  http://kkamagui.springnote.com/pages/345737


들어가기 전에...


1.FAT 파일 시스템 개요

 FAT 파일 시스템은 전통적으로 DOS 시절부터 사용되어 왔다. FAT 파일 시스템이 다른 파일 시스템과 구별되는 점은 파일 내용을 클러스터 단위로 구성하고 이것을 링크드 리스트(Linked List)의 형태로 보관하는 것이다.

 말로 하면 어려우므로, 일단 아래 그림을 보도록 하자.

사용자 삽입 이미지

<FAT의 간략한 구조>


 위 그림과 같이 파일은 고정된 크기의 클러스터(Cluster) 단위로 나누어져 있으며, 그 클러스터들은 클러스터 풀(Cluster Pool)에 존재하는 클러스터를 연결한 클러스터 채인(Cluster Chain)으로 되어있다. 실제 FAT 파일 시스템에서 클러스터 풀은 FAT(File Allocation Table)이라는 용어를 사용한다.

 클러스터(Cluster)란 별개 아니고 여러개의 섹터를 모아서 하나의 블럭 단위로 보는 것이다. 윈도우 포맷 프로그램을 이용해서 포맷을 하면 일반적으로 클러스터의 크기를 4Kbyte로 잡는데, 이 말은 한 섹터(Sector)의 크기가 512byte 이므로 8개의 섹터를 하나의 블럭으로 설정한다고 보면 된다.

 그럼 왜 클러스터라는 말을 쓰는 것일까? 그것은 섹터를 블럭으로 관리하면 얻는 이득이 있기때문이다. 아까 잠시 클러스터 풀에 대한 이야기를 했는데, 고용량일수록 클러스터 풀(FAT 영역)이 커지게 된다. 이것이 커질수록 파일을 읽고 쓸때 관리해야 하는 양이 늘어나게되고, 또한 디스크의 비어있는 공간이 줄어들게 된다. 이것을 블럭으로 관리하게 되면 이런 문제가 해결되며, 또한 블럭 단위로 읽기 쓰기를 수행함으로 얻는 효율로 인해 성능이 좋아지게 되는 것이다.

 특히 요즘처럼 파일의 크기가 큰 상황에서는 클러스터의 크기가 큰 것이 성능 향상에 도움이 된다. 하지만 클러스터의 크기가 무조건 크다고 좋은 것은 아니다. 아까 이야기 했듯이 클러스터의 단위로 작업을 하기 때문에, 작은 파일 같은 경우는 클러스터 하나를 할당받아서 대부분의 영역을 낭비하는 경우도 있으니 적당히 조절해야 한다.


 자 그럼 FAT 파일 시스템의 큰 특징을 알아봤으니 세부적인 내용을 알아보자

 FAT 파일 시스템은 총 3가지의 타입이 있다.

  • FAT12 : 클러스터의 개수가 1 ~ 0xFFF 까지를 가지는 타입. 플로피 디스크에서 주로 사용됨
  • FAT16 : 클러스터의 개수가 0xFFF ~  0xFFFF 까지를 가지는 타입. 소용량에 주로 사용됨
  • FAT32 : 클러스터의 개수가 0xFFFF ~ 0xFFFFFFFF 까지를 가지는 타입. 대용량에 주로 사용됨

 세가지 타입 모두 내부 포맷은 비슷하며, 차이점은 클러스터 개수라고 볼 수 있다.(물론 그것만 차이나는 것은 아니다. ㅡ,.ㅡ;;; 오해하지 말자.). 클러스터의 개수에 따라 FAT 타입을 분류한다고 했는데, 이 클러스터 개수는 어떻게 구하는 것일까? 실제 데이터 영역을 구성하는 크기를 가지고 계산하는 것일까?


 실제 타입 구분에 사용되는 클러스터의 크기는 디스크 전체 크기를 범위로 한다. 즉 아래의 공식으로 클러스터의 크기를 구하고 그것으로 타입을 유추하는 것이다.

클러스터의 개수 = 파티션 또는 디스크의 크기 / 클러스터의 크기

 이렇게 구한 클러스터의 개수는 실제로 사용가능한 데이터 영역의 클러스터의 개수와 비교하면 당연히 큰값을 가진다. 왜냐하면 디스크 또는 파티션 영역에 데이터만 들어가는 것이 아니고 FAT 파일 시스템을 관리하기위한 파일 시스템 메타 데이터(Meta Data)를 포함하기 때문이다.

 이제 파티션과 메타 데이터에 대해서 알아보자.


2.파티션(Partition)

 파티션에 대해서 익히 알고있고 들어봤을 것이다. 디스크 전체를 하나로 사용하는 것이 아니라 그 안에 C: D:와 같이 영역을 분할하여 사용하는 것이 파티션이다. 파티션을 나누면 디스크를 효율적으로 관리할 수 있는 장점 때문에 약간의 디스크 공간을 낭비하더라도 파티션을 해서 많이 사용한다(아래와 같이 나눌 수도 있다).

사용자 삽입 이미지


 그럼 어떻게해서 파티션이 나누어지는 것일까? 파티션을 나누게 되면 그 파티션에 대한 정보가 MBR(Master Boot Record)란 영역에 삽입되게 된다. MBR이란 디스크의 첫번째 섹터로 부트 코드와 여러가지를 정보를 포함하고 있다. MBR의 존재는 맨 마지막 510째부터 0x55 0xAA가 있는지 확인하여 이것이 있으면 MBR이 존재한다고 보면 된다(사실 다 있다. ㅡ_ㅡ;;; OS를 깔아 쓰면 저것 말고도 여러 정보가 MBR에 들어가 있다.)

 MBR의 세부구조를 한번 알아보자.

사용자 삽입 이미지

 헥사 에디터 프로그램으로 4개의 파티션으로 나누어진 USB 메모리의 MBR을  캡쳐한 화면이다. 좌측 상단에 0xEB 0x3C 0x90의 3Byte가 있는데, 이부분은 부트 코드의 시작으로 jmp 하라는 어셈블리어 명령이다. 굳이 필요한 것은 아니나 윈도우에서 MBR 인식을 위해서는 이 부분이 꼭 필요하다( 이부분이 0x00으로 비어져있는 경우에 윈도우가 MBR로 인식하지 못하는 것을 발견했다).

 우측 하단에 0x55 0xAA의 매직넘버가 보이고 그위에 붉은 색 줄이 쳐져있는 16byte의 라인이 보인다. 이부분이 파티션 데이터의 시작으로 그 앞부분은 모두 Boot Code의 용도로 사용되거나 아니면 사용되지 않는다. 파티션 정보는 16Byte씩 4개로 총 64Byte로 되어있으며 각 항목은 아래와 같은 구조체로 되어있다.

  1. /**
        Partition에 대한 정보를 포함하는 구조체
    */
    typedef struct partitionStruct
    {
        BYTE bBootIndicator;
        BYTE bStartingHeader;
        WORD wStartingSectorAndCylinder;
        BYTE bSystemID;
        BYTE bEndingHeader;
        WORD wEndingSectorAndCylinder;
        DWORD dwRelativeSector;
        DWORD dwTotalSector;
    } PARTITION, * PPARTITION;

  여기서 중요하게 봐야할 부분은 위에서 파란색으로 표시된 부분인데, 그 외 부분들은 옛날 도스 시절에나 사용된 필드기 때문에 무시해도 된다. 각 필드는 아래와 같은 의미를 가진다.

  • Boot Indicator : 부팅 가능한 파티션이면 0x80을 가짐. 그렇지 않으면 0x00
  • System ID : 파일 시스템의 ID. 일반적으로 윈도우에서 사용하는 값은 0x0B. 그 외의 값도 많으나 잘 쓰이지 않음
  • Relative Sector : 파티션이 시작되는 섹터.
  • Total Sector : 총 파티션의 크기

  위 정도값만 제대로 설정하면 윈도우에서 정상적으로 파티션 된 것으로 인식한다. MBR에 파티션 필드는 총 4개가 있으므로 파티션은 최대 4개까지 만들 수 있다. 그럼 도스 시절에는 파티션이 4개 이상이 가능했는데, 이것은 어떻게 한 것일까? 옛날 도스에서는 확장 파티션(Extension Partition)이라는 기능을 사용했다. 즉 MBR 파티션에는 확장 파티션 영역을 표시해 놓고, 확장 파티션 영역의 첫번째 섹터로 이동하면 그 첫번째 섹터에 다시 파티션 정보 + 확장 파티션 정보를 기입하는 식으로 체인으로 연결했던 것이다(이렇게 하면 디스크 용량이 허락하는 한 거의 무한대의 파티션을 생성할 수 있다. ㅡ,.ㅡ;;;;). 도스 이후에는 별로 사용하지 않으므로 일단 넘어가자. 궁금한 사람은 http://www.nondot.org/sabre/os/articles에 가서 Partition 쪽을 보면 된다.



3.파일 시스템 메타 데이터(File System Meta Data)

 

사용자 삽입 이미지

 FAT 파일 시스템을 구성하는 메타 데이터는 위와 같은 순서로 구성된다. 각 항목에 대한 설명은 아래와 같다.

  • PBR : 파티션 부트 레코드(Partition Boot Record)의 약자로서 파티션에 대한 전반적인 정보를 저장하고 있음. 핵심적인 부분
  • Reserved : 특수한 용도(Root Directory의 시작위치를 조절하거나 특수한 데이터를 저장할 용도)로 사용되는 공간. 존재하지 않을 수도 있음
  • FAT1/2 : 클러스터 풀로써 클러스터 체인을 구성하는 부분. 뒤에오는 Data Cluster의 개수에 따라 가변적인 크기를 가짐. FAT1은 FAT2은 동일한 데이터를 가지며 FAT는 1만 존재할 수도 있음
  • Root Directory : 파일시스템의 최상위 디렉토리. FAT12/16의 경우 섹터단위로 설정할 수 있고, FAT32의 경우 클러스터 체인으로 구성함.
  • FSInfo : FAT32에만 존제하는 영역으로 FAT32에 속하는 기타 정보를 포함하는 영역
  • Backup Area : FAT32에만 존재하는 영역으로 PBR부터 FSInfo까지를 백업하는 영역. 완전히 복사하여 파일 시스템에 문제가 생기면 Backup 영역에서 데이터를 다시 복사하여 복원하는 역할

3.1 PBR(Partition Boot Record), BPB(BIOS Parmeter Block)

 PBR은 여러 이름으로 불리는데 다른 이름으로는 BPB라고도 한다. 옛날 도스 시절에 BIOS 콜을 통해 파티션에 대한 정보를 얻어오고 처리하고 했는데, 그 기본 정보가 되는 블럭이라서 저런 이름이 붙은 것 같다. 일단 여기서는 PBR이라고 하겠다.

 PBR과 MBR의 차이는 무엇일까? MBR은 하나만 존재하며 섹터 0에만 있고, PBR은 각 파티션의 시작에 존재하며 FAT에 대한 정보를 포함하고 있다는 것이 다르다. PBR에는 어떤 정보가 포함되어있을까? FAT Type에 따라 다르므로 각각 살펴보도록 하자.


 FAT16/32의 PBR에 포함된 데이터는 아래와 같다.

  1. /**
        FAT16에 대한 구조체
    */
    typedef struct fat16Struct
    {
        BYTE vbJumpCode[ 3 ];
        char vcCreatingSystemIdentifier[ 8 ];
        WORD wSectorSize;
        BYTE bSectorsPerCluster;
        WORD wReservedSectorCount;
        BYTE bNumberOfFATs;
        WORD wNumberOfRootDirectoryEntries;
        WORD wTotalSectors;
        BYTE bMediumIdentifer;
        WORD wSectorsPerFAT;
        WORD wSectorsPerTrack;
        WORD wNumberOfSides;
        DWORD dwNumberOfHiddenSectors;
        DWORD dwTotalSectors;
  2.     // 여기 위까지는 FAT16/32 공통
        BYTE bPhysicalDiskNumber;
        BYTE bReserved;
        BYTE bExtendedBootRecordSignature;
        char vcVolumeIDNumber[ 4 ];
        char vcVolumeLabel[ 11 ];
        char vcFileSystemType[ 8 ];
        BYTE vbReservedForSystemUse[ 448 ];
        BYTE vbSignatureWord[ 2 ];
    } FAT16, * PFAT16;
  3. /**
        FAT32에 대한 구조체
    */
    typedef struct fat32Struct
    {
        BYTE vbJumpCode[ 3 ];
        char vcCreatingSystemIdentifier[ 8 ];
        WORD wSectorSize;
        BYTE bSectorsPerCluster;
        WORD wReservedSectorCount;
        BYTE bNumberOfFATs;
        WORD wNumberOfRootDirectoryEntries;
        WORD wTotalSectors;
        BYTE bMediumIdentifer;
        WORD wSectorsPerFAT;
        WORD wSectorsPerTrack;
        WORD wNumberOfSides;
        DWORD dwNumberOfHiddenSectors;
        DWORD dwTotalSectors;
  4.     // 여기 위까지는 FAT16/32 공통
        DWORD dwSectorsPerFAT32;
        WORD wExtensionFlag;
        WORD wFSVersion;
        DWORD dwRootCluster;
        WORD wFSInfo;
        WORD wBackupBootSector;
        BYTE vbReserved[ 12 ];
        BYTE bPhysicalDiskNumber;
        BYTE bReserved;
        BYTE bExtendedBootRecordSignature;
        char vcVolumeIDNumber[ 4 ];
        char vcVolumeLabel[ 11 ];
        char vcFileSystemType[ 8 ];
        BYTE vbReservedForSystemUse[ 420 ];
        BYTE vbSignatureWord[ 2 ];
    } FAT32, * PFAT32;

 상당히 많은 데이터를 포함하고 있는데, 일단 FAT16/32에 공통인 부분부터 살펴보자.

  • BYTE vbJumpCode[ 3 ] : Jump Code. 0xEB 0x?? 0x90 또는 0xE9 0x?? 0x??으로 구성되어야 함(이 부분을 제대로 넣지 않을 경우 윈도우에서 파티션 인식이 제대로 안됨)
  • char vcCreatingSystemIdentifier[ 8 ] : Format을 수행한 OS의 이름. 대충 집어넣으면 됨. "MSWIN4.1"와 같은 값.
  • WORD wSectorSize : 섹터 하나의 크기. 보통 512byte
  • BYTE bSectorsPerCluster : 클러스터를 구성하는 섹터의 수. 1Byte이므로 최대 255개까지 클러스터로 설정가능하나 1, 2, 4, 8, 16, 32, 64, 128이 일반적으로 유효한 값.
  • WORD wReservedSectorCount : 파티션 시작 영역부터 FAT 1영역이 시작되기 전에 존재하는 섹터의 수(위 그림 참조). FAT12/16에서는 1, FAT32에서는 32로 권장. 하지만 0xFFFF까지 값을 가질 수 있음. 이 값을 이용하면 Root Cluster의 시작을 적당한 위치로 설정할 수 있음
  • BYTE bNumberOfFATs : File Allocation Table(FAT)의 개수. 1개 또는 2개가 설정 가능하나 일반적으로 2의 값을 가짐.
  • WORD wNumberOfRootDirectoryEntries : Root Directory의 Entry의 개수. FAT12/16에서 사용하며 FAT16에서는 512 권장. FAT32에서는 0.
  • WORD wTotalSectors : 파티션의 크기가 0xFFFF 섹터 이하이면 이 필드 사용. FAT32에서는 0.
  • BYTE bMediumIdentifer : Media의 Type. 일반적으로 0xF8 사용.
  • WORD wSectorsPerFAT : FAT12/16에서 사용되는 값. FAT32에서는 0.
  • WORD wSectorsPerTrack : Track에 포함된 섹터의 수.
  • WORD wNumberOfSides : Size의 개수. 일반적으로 Cylinder의 수.
  • DWORD dwNumberOfHiddenSectors : 파티션 시작 이전에 존재하는 섹터의 수.
  • DWORD dwTotalSectors : 파티션의 크기가 0xFFFF 초과일때 사용되는 필드. FAT32에서는 반드시 이 필드 사용.
  •  BYTE bExtendedBootRecordSignature :  0x29 값으로 설정.
  • char vcVolumeIDNumber[ 4 ] : Volume ID. 일반적으로 일자/시간을 섞어서 만듬. 대충 만들어도 됨.
  • char vcVolumeLabel[ 11 ] : Volume Label. 볼륨 이름.
  • char vcFileSystemType[ 8 ] : "FAT12", "FAT16", "FAT", "FAT32" 같은 문자열.
  • BYTE vbSignatureWord[ 2 ] : 0x55 0xAA

 공통인 부분들에 대해 살펴봤으니, 이제 FAT32에 특화된 부분을 보자

  • DWORD dwSectorsPerFAT32 : FAT32용 FAT 영역 크기를 설정하는 부분
  • WORD wExtensionFlag : FAT1/2 영역이 존재할때, 하나만 사용할 것인지 아니면 둘다 동기화 해서 사용할 것인지 설정하는 플래그. 일반적으로 0으로 설정하여 둘다 동기화 하여 사용하는 것으로 설정.
  • WORD wFSVersion : File System Version. High Byte는 Major, Low Byte는 Minor를 나타냄. 일반적으로 0x00 0x00으로 설정.
  • DWORD dwRootCluster : Root Cluster의 번호. 일반적으로 2로 설정(클러스터 0과 1번은 Signature 같은 용도로 사용).
  • WORD wFSInfo : FSInfo가 위치하는 Sector Offset. 일반적으로 PBR 바로 뒤에 위치하므로 1의 값을 가짐.
  • WORD wBackupBootSector : Backup 영역이 존재하는 Sector Offset. 일반적으로 6의 값을 가짐.
  • BYTE vbReserved[ 12 ] : 예약된 영역. 무조건 0으로 설정.
  • BYTE bPhysicalDiskNumber : Drive Number. 일반적으로 0x80을 가짐.
  • BYTE bReserved : 예약된 영역. 무조건 0으로 설정.

  위의 필드 값을 FAT Type에 따라 PBR에 설정해 주면 반은 끝난 것이다. 약간 주의할 점은 Reserved Sector에 값을 설정했다면 파티션의 시작부터 Reserved Sector에 설정된 값만큼을 0으로 초기화해야한다(적극 권장). 위의 설명에도 나와있듯이 Reserved Sector의 값은 파티션의 시작부터 FAT1/2 이전까지의 섹터 수이므로, 절대 0이 될 수 없다. 왜? PBR이 있기 때문에 @0@)/~!!! 아무리 작아도 1 이상의 값을 가진다.

 이제 다음 메타 데이터를 살펴보자.


3.2File Allocation Table(FAT) 1/2 영역

 FAT 1/2 영역은 클러스터의 개수에 따라서 영역의 크기가 달라진다고 이야기 했다. 여기에서 말하는 클러스터의 개수는 실제 사용가능한 클러스터의 개수를 이야기하는데, 이 크기 이상만 된다면 얼마든지 좀 크게 잡아도 상관없다.

 FAT12의 경우 FAT를 구성하는 클러스터 링크의 비트수가 12bit가 이고, FAT16의 경우  16bit, FAT32의 경우 32bit이다. 따라서 한 섹터를 기준으로 FAT Type에 따라서 포함할 수 있는 클러스터 링크의 개수는 아래와 같이 된다.

  • FAT12 : 512Byte * 8 / 12 = 341.3333 개
  • FAT16 : 512Byte * 8 / 16 = 256 개
  • FAT32 : 512Byte * 8 / 32 = 128 개

 위에서 보는 것과 같이 FAT32로 갈수록 한 섹터에 담을 수 있는 클러스터 링크의 개수가 작아진다. 이것은 동일한 클러스터의 크기를 사용한다면 대용량일수록 FAT의 크기가 커진다는 것을 의미하고 FAT가 커지면 커질수록 실제로 사용가능한 클러스터의 크기가 줄어들게된다. 클러스터의 크기를 적당히 조절하여 FAT 크기를 너무 크지않게 하는 것이 좋다.

 FAT의 0번째 클러스터 링크와 1번째 클러스터 링크는 Signature의 용도 비슷하게 사용되는데, FAT Type에 따라 아래와 같이 설정해 준다.

  • FAT12 : 0xFF8, 0xFFF
  • FAT16 : 0xFFF8, 0xFFFF
  • FAT32 : 0xFFFFFFF8, 0xFFFFFFFF

 자 그럼 이제 FAT의 실제 크기를 한번 계산해 보자. 가장 간단하게 계산할 수 있는 방법은 파티션 전체의 크기를 클러스터의 크기로 나누어 구하는 방법이다. 실제로 이렇게 구하면 PBR + Rerserved Area + FAT1/2 영역의 크기도 사용가능한 것으로 인식하여 계산하기 때문에 낭비가 좀 있지만 계산은 편리하다. 특히 Root Directory의 시작 위치를 맞추거나 할때는 이렇게 계산하여 FAT의 크기를 구하고 여기에 Reserved Area의 값을 조절하여 맞출 수 있어 편리하다.

 또다른 방법은 전체 크기에서 PBR과 Reserved 영역을 제외하고 구하는 방법이다. 낭비가 좀 줄어들긴 한데, 식이 복잡해 진다. 아래는 그 계산 식이다(511은 올림을 위해 넣었다)

FAT의 크기(섹터) = [ ( 전체 파티션 크기(섹터) - PBR(1섹터) - Reserved Sector(?섹터)  )  / 클러스터의 크기(섹터) * 클러스터 링크의 크기 + 511 ] / 512

 이렇게 계산된 크기를 PBR에 wSectorsPerFAT나 dwSectorsPerFAT32 영역에 넣어주면 된다. 만약 wNumberOfFAT의 값을 2로 설정했으면 FAT1/2 영역을 연속해서 만들어줘야 하며 위의 FAT의 크기 * 2 만큼의 영역을 할당해 줘야 한다.



3.3 Root Directory Sector or Cluster 영역

  FAT16/32의 경우 위의 순서대로 PBR, FAT1/2 를 만들고 Root Directory Sector만 생성해 주면 정상적으로 윈도우에서 인식이 가능하다. 만약 Volume Label을 "NO NAME"으로 입력한 경우 Root Directory는 0으로 초기화 해주는 것으로 충분하다. 하지만 Volume Label을 사용한다면 Directory Entry Structure를 생성해서 Volume Label을 삽입해야 한다.


 Directory Entry Structure는 아래와 같이 구성되어있다.

  1. typedef struct directoryStruct
    {
        char vcNameAndExtension[ 11 ];
        BYTE bAttribute;
        BYTE bReservedForNT;
        BYTE bCreatedTimeTenth;
        WORD wCreatedTime;
        WORD wCreatedDate;
        WORD wLastAccessDate;
        WORD wStartingClusterNumberHigh;
        WORD wTimeRecorded;
        WORD wDateRecorded;
        WORD wStartingClusterNumberLow;
        DWORD dwFileLength;
    } DIRECTORY, * PDIRECTORY;

 각 항목은 아래와 같은 의미를 가진다.

  • char vcNameAndExtension[ 11 ] : 파일 이름과 확장자 또는 Volume Label 저장. 0번째 값이 0x00 or 0xE5이면 Free Entry.
  • BYTE bAttribute : Entry의 속성을 표시. 여러가지가 있음(타입은 아래 참조)
  • BYTE bReservedForNT : NT를 위해 사용되는 필드. 0의 값으로 설정.
  • BYTE bCreatedTimeTenth : 생성된 초. 1/10초 단위까지 저장.
  • WORD wCreatedTime : 생성된 시간(포맷은 아래 참조)
  • WORD wCreatedDate : 생성된 날짜(포맷은 아래 참조)
  • WORD wLastAccessDate : 마지막으로 접근한 날짜(포맷은 아래 참조)
  • WORD wStartingClusterNumberHigh : 클러스터의 상위 16bit 번호
  • WORD wTimeRecorded : 마지막으로 쓴 시간(포맷은 아래 참조)
  • WORD wDateRecorded : 마지막으로 쓴 날짜(포맷은 아래 참조)
  • WORD wStartingClusterNumberLow : 클러스터의 하위 16bit 번호
  • DWORD dwFileLength : 파일의 크기

 조금 복잡한데, 일단 Attribute 부터 보면 아래와 같이 나와있다(첨부 항목에 White Paper 참조).

사용자 삽입 이미지

 일단 포맷 후에 Volume Label을 생성해야 하므로 ATTR_VOLUME_ID를 생성하면 된다. 이때 주의할 것은 Volume Label을 설정하는 Directory Entry의 경우 Name과 Attribute를 제외한 나머지는 모두 0으로 설정해야한다.

 위를 보면 낯 익은 값들도 있을 것이다. 만약 윈도우가 FAT Filesystem으로 포맷되어있다면 위의 항목들이 설정된 Directory Entry 구조체가 여기저기 널려있을 것이다. Hex Editor와 같은 프로그램을 이용해서 하드디스크를 열어서 확인해 보자 @0@)/~~!!!!. 각 항목에 대한 자세한 설명은 White Paper를 참조하자.


 Time과 Date 부분은 공통적인 포맷을 사용하는데, White Paper에 아래와 같이 나와있다(간단한 비트 연산으로 만들 수 있다).

사용자 삽입 이미지

 파일 시스템 분석을 하는 경우라면 ClusterNumber와 Name, 그리고 Attribute를 유심히 봐두는 것이 도움이 될 것이다. 다른 파일 시스템이 그러하듯이 Root Directory로부터 Sub Directory가 생성되고 트리 형태로 관리되기 때문에 Root Directory를 찾은 다음 Entry 구조만 안다면 전체를 Travel 하는 것은 어렵지 않으니까...


3.4 FSInfo

  FSInfo 영역은 FAT32에만 존재하는 영역이다. 역시 한 섹터 크기정도로 되어있고 별다른 정보를 포함하지 않는다. 단지 FAT32에 참고할만한 정보만 가지고 있다.

  1. typedef struct fsInfoStruct
    {
        BYTE vbLeadSignature[ 4 ];
        BYTE vbReserved1[ 480 ];
        BYTE vbStructureSignature[ 4 ];
        DWORD dwFreeClusterCount;
        DWORD dwNextFreeCluster;
        BYTE vbReserved2[ 12 ];
        BYTE vbTrailSignature[ 4 ];
    } FSINFO, * PFSINFO;

  각 항목은 아래와 같은 의미를 가진다.

  • BYTE vbLeadSignature[ 4 ] : 0x52 0x52 0x61 0x41 설정
  • BYTE vbReserved1[ 480 ] : 예약된 영역. 0으로 설정.
  • BYTE vbStructureSignature[ 4 ] : 0x72 0x72 0x41 0x61 설정
  • DWORD dwFreeClusterCount : Free한 클러스터의 개수 저장. 알 수 없을 경우 0xFFFFFFFF. 권장 값이므로 100% 신용하면 안됨.
  • DWORD dwNextFreeCluster : Free한 클러스터의 첫번째 번호. 알 수 없을 경우 0xFFFFFFFF. 권장 값이므로 100% 신용하면 안됨.
  • BYTE vbReserved2[ 12 ] : 예약된 영역. 0으로 설정.
  • BYTE vbTrailSignature[ 4 ] : 0x00 0x00 0x55 0xAA 설정

 위에서 보는 것과 같이 FAT32의 부가적인 정보가 포함된 영역이고 특히 클러스터 관련 필드는 권장값이므로 절대 100% 믿으면 안된다.


4.마치며...

 여기까지 간단하게 FAT Filesystem에 대해서 알아보았다. 원래 훨씬 일찍 마무리 되었어야 하는데... 과제하느라 정신이 조금 없어서 찔끔 찔끔 정리하다보니 이제야 마무리를... ㅜ_ㅜ... 다소 부족한 감이 있지만 Formatter를 개발하면서 알아낸 정보를 기반으로 작성하였다.

 다음에는 위 정보를 기반으로 실제 FAT Filesystem을 분석해 보도록 하자.


5.첨부


신고
블로그 이미지

꽃중년

불만있으면 떠나라...

SD card

Hardware 관련/Memory 2008.03.13 16:12


 

간략하게 SDHC드에 대해 설명하면 아래와 같습니다.


SDHC 메모리 카드는 성능 등급 및 용량을 재정의하는 SD Card Association가 제정한 새로운 표준입니다.  이러한 표준에 입각하여 SDHC 카드는 오늘날 SD 카드의 2GB 임계값을 뛰어넘는 용량을 가집니다.

SD카드와 SDHC카드는 크기가 똑같다.

SDHC(Secure Digital High Capacity)카드는 SD카드의 상위 버전이다.
SD카드의 한계를 극복하기 위해 나온 새로운 버전이다.

 SD카드와 SDHC카드의 가장 큰 차이점은 파일시스템이다.
SD카드는 구식인 FAT16 파일시스템을 사용하고, SDHC카드는 신식인 FAT32 파일 시스템을 사용한다.

SD카드는 FAT16이기때문에 2GB 이상의 파일을 인식하지 못한다.

그러나 SDHC는 FAT32를 사용하기 때문에 2GB 이상의 고용량을 지원한다.

SDHC에는 대용량의 디지털 비디오 녹화를 위해 최소로 유지되는 전송 속도를
보장하는 세 가지 속도 등급(Class 2, 4 및 6)이 있다. 클래스2는 2MB/s, 클래스4는 4MB/s,
클래스6은 6MB/s 전송속도를 보장한다는 뜻이다.

 SDHC 카드는 겉면에는 몇클래스 제품인지 써져 있다.


--------------------------

au1200 cpu를 사용하는 EVM 보드에서 sd card를 테스트 중입니다.
(kernel 2.6.11)

목표는 4G 이상 시판 되는 SD card를 사용하는 것입니다.

sd card spec에는 >=2GB 는 sdhc spec으로 사용 가능하다고 되어 있더군요.

그런데 시판되는 SD card 중에는 4G, 8G도 있습니다. 물론 sdhc로 별도 표기 되지 않은 제품입니다.

혹자는 sd card의 2G용량 한계가 fat16에 따른 것이라고 하는데 정확한지도 잘 모르겠네요.

어쨌든 리눅스 상에서 sd card를 4G 이상 쓰려면 어떤 방법이 있는지 알고 싶습니다.

또는 sd card를 사용하는데서 kernel version 상의 차이가 있다면 어떤 것이 있는지도 알려주시면 고맙겠습니다.



---

전용 SD 컨트롤러가 아니라면 사용하시는 SD카드리더에 더 영향을 많이 받습니다.
제가 파악하기론, 국내에서 애용되는 칩셋은 SDHC 를 검증을 받지 못했습니다. 언젠가 웹사이트를 돌아다니다 칩셋별로 테스트 결과를 적어놓은 것을 보긴 했는데... 기억이 나질 않네요.
다만, 중요한 것은, SDHC 를 지원하지 않는 칩셋을 사용한 SD카드리더라 해도 2G SD 카드를 읽고 쓰는덴 지장이 없다는 점입니다.

애석한 점은, 이것이 긍정적인 측면이 아니라 부정적인 측면의 중요한 점이라는 겁니다.
2G SD 는 tansfer block size 가 1024 byte 입니다.
4G SD 는 2048 byte 겠지요(없어서 확인 못했습니다)
FAT 에서 따지는 hard block size 즉 device sector size 가 됩니다.
removable media 는 파티션을 나누지 않는 것이 MS windows 의 관례이나 불가능한 것도 아닙니다.
파티션 테이블에는 각 파티션의 시작위치와 크기 정보가 담기게 되는데, 이는 전적으로 hard block size 로 계산된 block address 여야만 합니다.
왜냐하면 media 의 파티션 테이블을 분석하는 시점에서 OS 는 전적으로 h/w 가 보고하는 정보에만 의존해야 하기 때문입니다.
SDHC 를 지원하지 않는 칩셋을 사용한 카드리더들은 실제 media 가 제공하는 정보를 사용하지 않고 일률적으로 512byte 로 보고합니다.
이렇게 잘못된 정보를 기반으로 작성된 파티션 정보가 기록된 media 를 제대로 된 카드리더나 컨트롤러를 가지는 기기에 접속할 경우 파티션정보가 제대로 전달되지 않습니다.
더욱 더 불행한 것은, 이렇게 잘못된 카드리더가 이미 널리 퍼져있기 때문에... 그것들에 의해 사용된 카드를 제대로 읽어내기 위해 리눅스 커널 드라이버에서도 h/w 정보를 무시하고 hard block size 를 512 byte 로 고정시켜야 한다는 점이지요.
때문에, 현재 2.6 커널에 들어가 있는 몇몇 컨트롤러(주로 MPU 에 내장된)에 대한 드라이버(drivers/mmc/) 들은 2G 이상의 SD 카드를 사용하는데 애로사항이 많습니다. 드라이버가 원칙대로 작성되어 있기 때문입니다.

FAT16 의 한계가 있긴 하지만....
FAT 은 media 의 hard block size 말고 logical sector 를 따로 가져가며,
이보다도 sectors per cluser 라는 것을 통해 용량을 극복합니다.
FAT16 이라는 것은 관리할 수 있는 cluster 의 갯수가 최대 2^16-1 개라는 뜻입니다. 65535 개입니다.
리눅스의 mkdosfs 옵션을 살펴보시면 포맷 옵션에 sectors per cluser 갯수를 설정할 수 있는 옵션을 보실 수 있습니다.
기억이 정확지는 않지만 최대 127개까지 가능했던 것 같습니다.
logical sector size 가 512byte 라 해도 최대 512*127*65535=4261347840 까지 FAT16 으로 감당이 됩니다. 다만, 1byte 짜리 파일을 만들어도 단순 데이타만을 저장하기 위해 512*127=65024 byte 가 낭비된다는 단점이 있습니다.

간추리면, 카드리더를 사용하실 것이라면 카드리더에 사용된 칩셋을 알아보고 그 칩셋이 검증을 받은 칩셋인지 미리 확인해보는 겁니다. 사실상... 직접 확인하시기가 거의 불가능에 가깝겠습니다. 주변의 소문이나 이름난 전문 커뮤니티(디지털카메라등...)를 뒤져보면 혹시 정보가 있을지도 모르겠습니다.

전용 컨트롤러를 선택해야 하신다면,
컨트롤러의 스펙도 보세요. 제가 직업이 직업인지라 경험이 일천합니다만,
인기있는 MPU 들 중에서 SD 컨트롤러를 내장한 예를 들면 PXA25x 는 최대 transfer block size 가 1024byte 이고, PXA27x 는 2048byte 까지입니다.
윗 글에서 말씀드린 여자저차한 이유로 이리저리 꼼수를 부려 512 로 사용해야 하지만, 스펙은 스펙이죠.

사실상 SDHC 스펙은 용량보다는 속도 향상에 그 가치가 있습니다.

---

제가 사용중인 cpu에 sd 컨트롤러가 내장되어 있습니다.

따로 card reader를 사용하지 않지요.

그렇다면 내장 sd 컨트롤러의 transfer block size가 sd card의 block size를 지원한다면 mmc 이하의 드라이버를 수정해서 4G까지도 사용할 수 있다는 것으로 보아도 될는지요?

sd 관련 linux-mips 쪽의 메일링 리스트에 이것에 관한 간단 패치가 올랐다가 native directory 쪽의 강한 반대에 부딛힌듯 하던데...

가능한지 어떤지 모르겠습니다. 가능하기만 하다면 mmc 디렉토리를 손봐서라도 써야 하겠는데 말입니다.

--

커널 drivers/mmc/ 는 MMC protocol 을 사용하여 구현되어 있습니다.

read/write 커맨드의 아규먼트로 address 를 넘겨줘야 합니다.
행인지 불행인지 애매하지만,
이 address 는 tansfer block size 와는 상관없는 media offset 이며 단위(unit) 은 byte 입니다.
unsigned 32bit 이므로 4G 까지입니다.

2G 까지는 SD protocol 과 꼼수를 사용하여 PXA27x 에서 사용했는데 4G 는 잘 모르겠습니다.
실제로 해보기 전에는 누구도 뭐라 못 할 것 같네요.

8G SD 카드가 있다면, 아마도 SD memory 가 아니라 SDIO 로 만들어진 놈이 아닐까 조심스레 추측해봅니다.
하여간, 가난해서... 4G 8G 카드는 구경도 못 해봤습니다.

신고
블로그 이미지

꽃중년

불만있으면 떠나라...

Tag SD 카드


client.c
----------
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <sys/un.h>
#include <unistd.h>

int main()
{
 int sockfd;
 int len;
 struct sockaddr_un address;
 int result;
 char ch = 'A';
 
 sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
 address.sun_family = AF_UNIX;
 strcpy(address.sun_path, "server_socket");
 len = sizeof(address);
 
 result = connect(sockfd, (struct sockaddr *)&address, len);
 
 if (result == -1)
 {
  perror("oops: client1");
  exit(1);
 }
 
 write(sockfd, &ch, 1);
 read(sockfd, &ch, 1);
 printf("char from server = %c\n", ch);
 close(sockfd);
 
 return 0;
}



server.c
--------------
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <sys/un.h>
#include <unistd.h>

int main()
{
 int server_sockfd, client_sockfd;
 int server_len, client_len;
 struct sockaddr_un server_address;
 struct sockaddr_un client_address;
 
 unlink("server_socket");
 server_sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
 
 server_address.sun_family = AF_UNIX;
 strcpy(server_address.sun_path, "server_socket");
 server_len = sizeof(server_address);
 
 bind(server_sockfd, 5);
 while (1)
 {
  char ch;
  printf("server waiting\n");
 
  client_len = sizeof(client_address);
  client_sockfd = accept(server_sockfd, (struct sockaddr *)&client_address, &client_len);
 
  read(client_sockfd, &ch, 1);
  ch++;
  write(client_sockfd, &ch, 1);
  close(client_sockfd);
 }
 
 return 0;
}

신고
블로그 이미지

꽃중년

불만있으면 떠나라...


신고
블로그 이미지

꽃중년

불만있으면 떠나라...

Tag 68K

I2C

Hardware 관련/BUS 2008.03.09 20:44

신고
블로그 이미지

꽃중년

불만있으면 떠나라...

Tag I2C

디바이스 드라이버
 
 
http://blog.naver.com/iamlow/90006359729



변수

 

1. 지역변수와 전역변수의 선택

- 디바이스 드라이버 소스에 정의된 지역변수와 전역변수는 모두 커널 메모리공간에 배치

- 가급적 제진입 가능함수로 만들것(지역변수 사용할것)

 

2. 중복 함수명과 변수명방지

- 중복 우려 static 키워드 사용하여 해당 파일 소스에서만 참조하도록

- 지역 변수에서는 사용하지 말것

  지역변수에 static선언하면 전역 변수와 같이 종료시에도 값이 유지

  차이점은 외부 심볼 참조가 되지 않는점

 

3. 이식성과 데이터형

- 이식성 문제는 대부분 사용하는 변수의 데이터형을 명확히 하면 해결된다.

- 변수의 프로세서 의존성을 피하기 우해 리눅스 커널에서 제공하는 데이터형을 사용하라

  #include <asm/types.h>에 선언되어있다.

- 구조체에서 보통 int형 크기의 배수로 선언되므로 정확한 데이터크기를 위해

  packed키워드 사용할것 (강추~!)

  typedef struct

  {

         u16 index;

         u16 data;

         u8  data;

  } __attribute__ ((packed)) testctl_t;

- 바이트 순서(Big,Little Endian)

  바이트 순서를 정확하게 처리하도록 도와주는 헤더파일은 모두 include/linux/byteorder에있다.

  실제로 디바이스 드라이버에는 #include <asm/byteorder.h>를 포함시킨다.

 

4.I/O 메모리 접근 변수 처리

- volatile 사용~ 책참조~!

 

동적 메모리

 

일반 프로그램에서의 동적메모리와 디바이스 드라이버에서 사용되는 동적메모리는 차이가있다

알아보자~!!

- 커널과 프로세스의 메모리 공간은 서로 다른구조다

     - 사용자 메모리공간에서 메모리를 할당하는경우에는 커널의 메모리관리 루틴과 glibc의 메모

       리 할당 루틴에의해 할당받는다.

     - 디바이스 드라이버가 동작하는 메모리의 공간은 커널 메모리공간이다.

     - 특히 커널은 시스템 전체의 물리메모리에 접근할수 있고 자체적으로 관리하기때문에 MMU를

       고려한 처리가 필요하다.

- PAGE_SIZE 단위로 할당하는 특성

     - 메모르리를 특정단위로 할당(리눅스에서는 PAGE_SIZE,PAGE_SHIFT에의해 관리)

     - 특히 PAGE_SIZE값은 MMU가 관리하는 단위에 영향(보통 4KByte)

- 시스템에 가용 메모리가 없는 상황

     - malloc()은 실패가능성 거의없다(가상메모리 사용하기때문에...)

     - 커널 메모리는 가상메모리의 페이징 기능을 이용하지않는다.

- 가상 메모리 기법에 의해 접근하고자 하는 메모리가 보조 장치에 존재하는 상황

- DMA같은 디바이스가 사용하는 연속된 물리 메모리 주소가 필요한 상황

     - 디바이스 드라이버가 다루는 디바이스중에는 고속의 데이터전송을 수행하기위해 DMA이용

     - DMA의 경우에는 물리적으로 연속될 필요가 있어 이를 처리하기위한 메모리관리루틴 필요

- 인터럽트 상태에서 메모리를 할당하는 상황

 

1.kmalloc(),kfree()

- 할당속도가 빠르고 사용법 간단하여 디바이스 드라이버에서 가장 많이 사용

- 단 kmalloc()함수를 사용할때 할당 가능한 크기가 32 * PAGE_SIZE(131,072Byte)

- ex) char * buff;

        buff = kmalloc(1024, GFP_KERNEL);

        ...

        kfree(buff);

- kmalloc()함수의 옵션

     - GFP_KERNEL : 동적 메모리 할당이 항상 성공하도록...

                              메모리 부족할때는 할당가능할때까지 대기~

                              그래서 인터럽트 서비스에 사용할때는 이 값사용하면 안된다.

     - GFP_ATOMIC : 메모리있으면 무조건 할당 없으면 즉시 리턴(NULL)

                              프로세스가 잠들문제는 없지만 NULL일경우 대비하여 프로그래밍해야...

     - GFP_DMA : 연속된 물리 메모리를 할당받을때 사용

                         DMA컨트롤러 사용시..

2.vmalloc(),vfree()

- malloc과 가장 유사

- kmalloc()은 크기가 제한(32*PAGE_SIZE)되어있지만 vmalloc()함수는 가상 공간이 허용하는

  한 크기 제한없이 사용가능

- 그래서 큰 메모리공간을 할당할때 주로 사용

- 가상 메모리 관리루틴이 수행되기때문에 kmalloc()함수보다 속도가 매우느리다

- 옵션이 없어서(GFP_ATOMIC같은..) 인터럽트 서비스 함수 안에서 사용할수 없다.
신고
블로그 이미지

꽃중년

불만있으면 떠나라...

티스토리 툴바