Sign in Join
Wiki copytemporary

Hardware Access/ko: what changed

Revision 0 to 1. Removed lines have a minus sign; added lines have a plus sign.

Title: Hardware Access/ko

OldNewLine
1+## 개관
2+
3+이 페이지는 라자루스상에서 하드웨어 장치(디바이스)에 접근하기위한 튜토리얼의 시작입니다. 이 장치들은 ISA, PCI, USB, parallel port, serial port 등을 포함하지만 이것들에 제한된것은 아닙니다. 완전한 멀티 플랫폼상에서 하드웨어에 접근하는 것은 프리파스칼 라이브러리나 LCL에의해 구현되지는 않았으므로 이 튜토리얼은 다른 플랫폼상에서의 기초적인 하드웨어 접근 방법을 다룰 것 입니다. 조건적인 컴파일에 의해 다른 플랫폼에서 컴파일된 코드는 다음과 같을 것이다:
4+
5+``` pascal
6+ uses
7+ Classes, SysUtils, LResources, Forms, Controls, Graphics, Dialogs, ExtCtrls,
8+ {$IFDEF WIN32}
9+ Windows;
10+ {$ENDIF}
11+ {$IFDEF Unix}
12+ ports;
13+ {$ENDIF}
14+```
15+
16+이 시점에서 Mac OX/x86이 HW 접근을 허용하는지는 아직 확실치는 않다. 이 경우에서는 내가 가정하듯이 위의 방법이 허용되지 않을 수 있지만 곧 io.dll같은 드라이버가 나타날 것이다.
17+
18+## 패러랠과 시리얼 의 비교
19+
20+ISA카드, PCI 카드 및 패러랠 포트는 **parallel** 프로토콜에 의해 컴퓨터와 통신을 한다. 시리얼 포트와 USB장치는 **serial** 프로토콜로 통신한다. 프로세서와 프로그래밍 언어는 모두 데이터에 패러랠한 접근을 통해 작업을 수행하기 때문에 이런 종류의 프로토콜에 대한 접근은 소프트웨어 측면에서 보면 구현하기가 더 쉽다.예를 들어, Integer 변수에 접근할 때, 단일 명령으로 그 값에 접근할 수가 있다. 그러나 시리얼 포트 프로토콜에서는 동시에 한개의 비트만을 알 수 밖에 없으며 데이터를 이해하기 위해서는 그 비트 조각들을 붙여 놓을 필요가 있다.
21+
22+시리얼 툥신은 직접적으로 구현하기가 어렵지만, 미리 만들어 놓은(pre-made) 컴포넌트를 사용한다면 매우 쉽게 구현할 수가 있다.이는 하드웨어 측면에서도 역시 어려운건 마찬가지이기 때문에 많은 장치들은 그것을 구현하기 위해 특별한 통합 써킷이나 마이크로 컨트롤러를 사용한다.
23+
24+이제 다음에 하드웨어 접근 프로토콜에 대한 간략한 비교가 있다:
25+
26+| | 속도 | 하드웨어 구현의 난이도 |
27+|-------------|-------------------------|------------------------|
28+| 시리얼 포트 | 매우 느림 (\< E5 bit/s) | 중간 |
29+| 패러랠 포트 | 느림 (~ E6 bit/s) | 쉬움 |
30+| ISA 카드 | 중간(~ E7 bit/s) | 중간 |
31+| USB | 중간(~ E7 bit/s) | 어려움 |
32+| PCI 카드 | 매우 빠름 (\> E9 bit/s) | 매우 어려움 |
33+
34+## 패러랠 통신
35+
36+### 윈도우에서 inpout32.dll의 이용
37+
38+윈도우즈는 9x시리즈와 NT시리즈에서 하드웨어 접근에 있어서 다른 방법을 취하고 있다. 9x 시리즈(95, 98, Me)에서 프로그램은 DOS상에서 했듯이 하드웨어에 직접 접근 할 수가 있었다. 그러나 NT 시리즈(Windows NT and XP)에서는 이런 접근방법을 허용하고 있지 않다. 이 구조에서 하드웨어 포트와의 모든 통신은 디바이스 드라이버를 통해 이루어진다. 이것은 보안 메커니즘이지만, 작은 프로젝트에서도 드라이버 개발에 시간과 비용 등 많은 댓가를 추가하게 된다.
39+
40+행복하게도 이 문제를 해결할 수 있는 라이브러리가 있다. 만약 Windows NT가 탐지 된다면, HWInterface.sys 커널 디바이스 드라이버의 압축을 해제하고 설치를 한다. 만약 Windows 9x가 탐지된다면 하드웨어 접근은 단순히 어셈블러 opcode를 이용한다.
41+
42+그렇지만 이 라이브러리를 어떻게 사용할까요? 간단합니다! 이것은 Inp32 와 Out32 등의 단지 두개의 함수만이 있으므로 사용법은 매우 직관적이다
43+
44+라이브러리를 동적으로 로드하므로, 먼저 두개의 함수를 정의해 보자:
45+
46+``` pascal
47+ type
48+ TInp32 = function(Address: SmallInt): SmallInt; stdcall;
49+ TOut32 = procedure(Address: SmallInt; Data: SmallInt); stdcall;
50+```
51+
52+- Address는 접근하려는 포트의 어드레스를 표시한다
53+- Out32는 지정한 Address의 포트로 Data를 전송한다
54+- Inp32는 지정한 포트로부터 한개의 byte를 되돌려 준다
55+
56+이제 라이브러리를 로드한다. 이것은 작성한 프로그램의 메인폼의 OnCreate 메소드같은 곳에서 구현할 수가 있다:
57+
58+``` pascal
59+ type
60+ TMyForm = class(TForm)
61+ .........
62+ private
63+ { private declarations }
64+ Inpout32: THandle;
65+ Inp32: TInp32;
66+ Out32: TOut32;
67+ .........
68+ implementation
69+ .........
70+ procedure TMyForm.FormCreate(Sender: TObject);
71+ begin
72+ {$IFDEF WIN32}
73+ Inpout32 := LoadLibrary('inpout32.dll');
74+ if (Inpout32 <> 0) then
75+ begin
76+ // needs overtyping, plain Delphi's @Inp32 = GetProc... leads to compile errors
77+ Inp32 := TInp32(GetProcAddress(Inpout32, 'Inp32'));
78+ if (@Inp32 = nil) then Caption := 'Error';
79+ Out32 := TOut32(GetProcAddress(Inpout32, 'Out32'));
80+ if (@Out32 = nil) then Caption := 'Error';
81+ end
82+ else Caption := 'Error';
83+ {$ENDIF}
84+ end;
85+```
86+
87+OnCreate 에서 라이브러리를 로드했으면 OnDestroy에서 언로드하는 것을 잊으면 안된다:
88+
89+``` pascal
90+ procedure TMyForm.FormDestroy(Sender: TObject);
91+ begin
92+ {$IFDEF WIN32}
93+ FreeLibrary(Inpout32);
94+ {$ENDIF}
95+ end;
96+```
97+
98+다음에 Inp32 함수를 이용하는 방법에 관한 단순한 예제가 있다:
99+
100+``` pascal
101+ {$IFDEF WIN32}
102+ myLabel.Caption := IntToStr(Inp32($0220));
103+ {$ENDIF}
104+```
105+
106+이 코드는 Windows XP상의 포트 \$0220에 있는 커스텀 ISA카드에서 Lazarus 0.9.10으로 터스트하였다. 물론 이코드를 실행하기 위해서는 uses 절에 Windows를 넣어야 한다. 개발을 위해 할 일은 작성하는 응용프로그램과 같은 디렉토리에 있는"inpout32.dll"를 인클루드(include)하기만 하면 된다.
107+
108+이 라이브러리에 관한 홈페이지는 다음과 같다: [www.logix4u.net/inpout32.htm](http://www.logix4u.net/inpout32.htm) *토론을 보세요*
109+
110+### Windows 9x에서 어셈블러 사용
111+
112+Windows 9x에서 역시 어셈블러 코드를 사용할 수 있다. \$CC를 \$320 포트에 쓰고싶다고 가정해보자. 다음 코드가 그렇게 해줄 것이다:
113+
114+``` pascal
115+ {$ASMMODE ATT}
116+ ...
117+ asm
118+ movl $0x320, %edx
119+ movb $0xCC, %al
120+ outb %al, %dx
121+ end ['EAX','EDX'];
122+```
123+
124+### Windows상에서 문제 해결
125+
126+Windows상에서 플럭앤플레이를 지원하지 않는 패러랠 하드웨어를 사용할 때 문제를 일으키는 가능한 한가지는 당신의 하드웨어에 의해 사용되고 있는 포트를 다른 하드웨어에 할당할 때 일어난다. Windows가 당신의 디바이스 주소에 플럭앤플레이 디바이스를 할당하지 못하도록 하는 방법을 아래 URL에서 그에 대해 설명된 것을 찾을 수 있을 것이다:
127+
128+<http://support.microsoft.com/kb/135168>
129+
130+### 리눅스상에서 포트 접근을 위해서는 ioperm을 사용
131+
132+리눅스에서 하드웨어에 접근하는 가장 좋은 방법은 디바이스 드라이버를 통해 하는 것이지만 드라이버를 만드는 작업이 너무 복잡함으로 인해 가끔은 빠른 방법이 매우 유용하다.
133+
134+리눅스에서 "[[doc:rtl/ports|ports]]" unit를 이용하기 위해서는 프로그램은 root로 실행해야만 하며 포트접근을 위한 적절한 퍼미션 설정을 위해 IOPerm을 콜해야 한다. "[[doc:rtl/ports|ports]]" 유닛에 관한 문서는 다음에서 찾을 수 있다. [이곳](http://www.freepascal.org/docs-html/rtl/ports/index.html).
135+
136+첫번째 할 일은 (g)libc를 링크하고 IOPerm을 콜하는 것이다. 유닛과 연결된 완전한 (g)libc가 프리파스칼에 존재하지만 이 유닛은 어플리케이션이 직접 사용할 때 문제를 야기하고, 또한 이것을 완전한 (g)libc 라이브러리에 정적으로 연결하는 것은 호환되지 않은 방법으로 버전이 변화하기 때문에 좋은 생각은 아니다. 그러나 ioperm같은 함수는 변하지 않을 것 같다.
137+
138+``` pascal
139+ {$IFDEF Linux}
140+ function ioperm(from: Cardinal; num: Cardinal; turn_on: Integer): Integer; cdecl; external 'libc';
141+ {$ENDIF}
142+```
143+
144+- "from" 은 접근할 수 있는 첫번째 포트를 표시한다.
145+- "num" 은 첫번째 접근한 다음의 포트 수이므로 ioperm(&220, 8, 1)은 프로그램에게 \$220과 \$227를 포함한 그 사이의 모든 포트를 접근하게 할 것이다.
146+
147+IOPerm에 링크 한 후 포트에 접근하기 위해 port\[\<Address\>\]를 사용할 수 있다.
148+
149+``` pascal
150+ {$IFDEF Linux}
151+ i := ioperm($220, 8, 1);
152+ port[$220] := $00;
153+ myLabel.Caption := 'ioperm: ' + IntToStr(i);
154+ i := Integer(port[$220]);
155+ myOtherLabel.Caption := 'response: ' + IntToStr(i);
156+ {$ENDIF}
157+```
158+
159+이 코드는 커스텀 ISA 카드의 포트 \$0220에서 테스트 하였으며, Mandriva Linux 2005 와 Damn Small Linux 1.5상에서 Lazarus 0.9.10을 사용하였다.
160+
161+### 일반적인 유닉스 하드웨어 접근
162+
163+``` pascal
164+{$IFDEF Unix}
165+Uses Clib; // libc 라이브러리 이름을 가져옴.
166+{$ENDIF}
167+
168+{$IFDEF Unix}
169+function ioperm(from: Cardinal; num: Cardinal; turn_on: Integer): Integer; cdecl; external clib;
170+{$ENDIF}
171+```
172+
173+**Note 1** :FPC는 "fpioperm"이라 불리는 ioperm에 대한 추상화를 [[doc:rtl/x86/index.html|unit x86에서]] 제공하며 또한 out과 inport 함수를 제공한다. 이 함수들은 현재 Linux/x86 과 FreeBSD/x86에서도 구현되어 있다.
174+
175+배포와 이동성 기능 때문에 반드시 필요한 것이 아니라면 libc에 링크하는 것은 추천하지 않는다. 또한 위에서 한 것처럼 수동으로 libc에 링크(다른 곳에 필요한 함수 때문에 특별히 libc 임포트를 선언하여)하는 것도 추천되지 않는다.(예, 위의 libc 임포트(import) 라인은 표준(standard) C lib가 BeOS상의 libroot나 비표준 C심볼을 가진 플랫폼같이 libc에 의해 콜되지 않으면 실패하게 된다.
176+
177+**Note 2** _unit_ libc를 사용하는 것 역시 Kylix 호환을 제외한 어떤 환경하에서도 추천되지 않는다. 이것은 유닛은 상대적으로 이동성이 떨어지며(구조체와 다른 private 심볼의 과도한 노출(excessive exposure)) Kylix와 호환이 되지 않는 것에서는 가능한 적은 수정만이 필요하기 때문이다.
178+
179+## 시리얼 통신
180+
181+시리얼 통신 소프트웨어를 빌드하는 것은 [Synaser library](http://synapse.ararat.cz/doku.php)를 이용하면 매우 쉽다. [Synaser 문서](http://synapse.ararat.cz/doc/help/synaser.html)와 함께 사용한 예는 이해하기가 쉬워야 한다. 가장 중요한 부분은 속도(초당 bits)와 데이터 비트, 패리티 비트, 스톱 비트 및 핸드쉐이크 프로토콜 등을 조정하는 TBlockSerial.Config이다. 다음의 코드는 COM 1에 연결된 시리얼 마우스에서 테스트 하였다.
182+
183+``` pascal
184+program comm;
185+
186+{$apptype console}
187+
188+uses
189+ Classes, SysUtils, Synaser;
190+
191+var
192+ ser: TBlockSerial;
193+begin
194+ ser:=TBlockSerial.Create;
195+ try
196+ ser.Connect('COM1');
197+ ser.config(1200, 7, 'N', SB1, False, False);
198+ while True do
199+ Write(IntToHex(ser.RecvByte(10000), 2), ' ');
200+ finally
201+ ser.free;
202+ end;
203+end.
204+```
205+
206+다음의 코드-에제는 상기에 있는 예제의 또 다른 버전이다. 위에 보인 예는, 정확히 말하자면 메인 컨셉에서 결정적으로 잘못된 것이 있어 보인다. 이 부분은 "while true do..."이다. 테스트에서 시스템(Asus A6T 랩탑으로 Digitus USB가 RS232 어댑터에 연결되어 있으며 Ubuntu 8.04.1를 사용한다)에서 이 부분은 다음과 같은 에러를 일으켰다: 어플리케이션은 세션당 단 한번 만 성공적으로 실행이 되었고, 어플리케이션을 다시 시작하면, 어프리케이션은 시리얼 포트에 연결할 수가 없었다. 그러므로 사용자가 어플리케이션을 다시 시작할 때마다 리부트가 필요했으므로, 이는 정말 불쾌한 버그인 것이다.
207+
208+이유를 이해하는 것은 어렵지 않다: 어플리케이션은 while true do 루프에 있게 되면, 그것은 정확히 말하면 무한 루프이다. 중단할 방법이 없기 때문에 어플리케이션을 중단시킬 유일한 방법은 터미널을 닫거나 CTRL-C를 누르는 것 뿐이다. 그러나 어플리케이션을 이런 방법으로 종료한다면, 시리얼 포트를 해제하는 "ser.free"의 중요한 부분이 콜되지 않는다. 이 문제는 다음의 독일의 라자루스 포럼\[<http://www.lazarusforum.de/viewtopic.php?f=10&t=2082> <http://www.lazarusforum.de/viewtopic.php?f=10&t=2082%5D에> 설명되어 있다.
209+
210+각 사용자가 CTRL-C를 누르지 않고 클리어하기 위한 메인 어플리케이션에서의 코드는 약간 만 필요하다. /dev/ttyUSB0를 com-포트를 위해 사용하는 것에 대해 걱정하는 사람은 테스트 시스템상의 USB-시리얼 어댑터(Digitus) 때문이다.만약 ㅅ스템에 내장된 시리얼 포트를 가지고 있다면 'Com0'를 사용하는 것이 좋다.- 위의 예와 같이 코드와 같이 선언해서.
211+
212+``` pascal
213+
214+program serialtest;
215+
216+{$mode objfpc}{$H+}
217+
218+uses
219+ {$IFDEF UNIX}{$IFDEF UseCThreads}
220+ cthreads,
221+ {$ENDIF}{$ENDIF}
222+ Classes,SysUtils,Synaser,Crt
223+ { you can add units after this };
224+
225+ var l:boolean;
226+
227+ function check_affirmation():boolean;
228+ var k:string;
229+ begin
230+ Writeln('To quit the application please do NOT use CTRL-C! Instead, please press any key to quit the application! '+
231+ 'Please confirm this notification before the application continues! '+
232+ '[0]=Quit, [1]=Confirm, please continue! ');
233+ Writeln('Your decision: ');
234+ Read(k);
235+ if StrtoInt(k) = 1 then
236+ begin
237+ check_affirmation:=true;
238+ Writeln('OK, application continues ...');
239+ end
240+ else
241+ begin
242+ check_affirmation:=false;
243+ Writeln('Abort');
244+ end
245+ end;
246+
247+ procedure RS232_connect;
248+ var
249+ ser: TBlockSerial;
250+ begin
251+ ser:=TBlockSerial.Create;
252+ try
253+ ser.Connect('/dev/ttyUSB0'); //ComPort
254+ Sleep(1000);
255+ ser.config(1200, 7, 'N', SB1, False, False);
256+ Write('Device: ' + ser.Device + ' Status: ' + ser.LastErrorDesc +' '+
257+ Inttostr(ser.LastError));
258+ Sleep(1000);
259+ repeat
260+ Write(IntToHex(ser.RecvByte(10000), 2), ' ');
261+ until keypressed; //Important!!!
262+ finally
263+ Writeln('Serial Port will be freed...');
264+ ser.free;
265+ Writeln('Serial Port was freed successfully!');
266+ end;
267+ end;
268+
269+ begin
270+ l:=check_affirmation();
271+ if l=true then
272+ RS232_connect()
273+ else
274+ Writeln('Program quit! ');
275+ end.
276+```
277+
278+또한,[[Hardware Access|외부 링크]] 섹션에 유닉스와 윈도우즈 시리얼 포트 튜토리얼이 있다.
279+
280+## USB
281+
282+### libusb
283+
284+[libusb](http://libusb.sourceforge.net/) 는 Linux, BSDs 및 Mac OS X 등의 크로스 플랫폼을 지원합니다.
285+
286+헤더를 구할 수 있는 링크는 다음과 같습니다. <http://www.freepascal.org/contrib/db.php3?category=Miscellaneous> :
287+
288+| 이름 | 제작자 | 버전 | 일자 | 링크 | 비고 |
289+|----|----|----|----|----|----|
290+| libusb.pp | nowrap \| Uwe Zimmermann | 0.1.12 | nowrap \| 2006-06-29 | <http://www.sciencetronics.com/download/fpc_libusb.tgz> | |
291+| libusb.pas | Johann Glaser | | nowrap \| 2005-01-14 | <https://github.com/hansiglaser/pas-libusb> | OOP 래퍼를 포함하며, LibUSB 1.0는 곧 나온다 |
292+| fpcusb | Joe Jared | 0.11-14 | nowrap \| 2006-02-02 | <http://relays.osirusoft.com/fpcusb.tgz> | nowrap \| 다운로드 링크 깨짐 |
293+| libusb.pp | Marko Medic | 1.0 | nowrap \| 2010-12-14 | <http://www.lazarus.freepascal.org/index.php/topic,11435.0.html> | |
294+
295+### FTDI
296+
297+만약 [FTDI](http://www.ftdichip.com/)의 칩 중의 하나를 사용한다면, 칩을 위한 dll 인터페이스용 파스칼 헤더를 사용할 수 있다.
298+
299+## 추가적으로 볼 것
300+
301+- [[Target NativeNT|타겟 네이티브NT]]
302+- [[Networking/ko|네트워킹]]
303+
304+## 외부 링크
305+
306+통신 프로토콜 속도 비교:
307+
308+1. <http://en.wikipedia.org/wiki/Serial_port#Speed>
309+2. <http://www.lvr.com/jansfaq.htm> - Jan Axelson의 패러랠 포트 FAQ
310+3. <http://en.wikipedia.org/wiki/USB#Transfer_Speed>
311+4. <http://en.wikipedia.org/wiki/PCI#Conventional_PCI_bus_specifications>
312+
313+시리얼 통신 링크:
314+
315+1. UNIX에서: [1](http://www.easysw.com/~mike/serial/serial.html)
316+2. Windows에서: <http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnfiles/html/msdn_serial.asp>
317+3. Synaser 콤포넌트: <http://synapse.ararat.cz/>
318+4. Comport 델파이 패키지e: <http://sourceforge.net/projects/comport/>
319+
320+ISA 디지탈 오실로 스코프- 하드웨어 접근에 대한 완전 소스가 포함된 예제:
321+
322+[2](http://eletronicalivre.incubadora.fapesp.br/portal/english/oscilloscope/)
323+
324+------------------------------------------------------------------------
325+
326+[[네트워킹]]
327+
328+---
329+*From the Free Pascal wiki, page "Hardware Access/ko", as it stood on 2020-02-16 after a change by Trev, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).*

Back to history