1~8교시
☆S/W★
● Raspberry Pi
□ 라즈베리 파이 커널 빌드와 디바이스 드라이버
- 디바이스 드라이버에서 open 함수는 해당 파일에 할당된 디스크립터 번호를 반환하지만 디바이스 드라이버의 open 함수는 파일이 성공적으로 open 됐을때 반드시 0을 리턴해야한다.
- 예제를 들어보면 다음과 같이 확인 할 수 있다.
int simple_release(struct inode *inode, struct file *filp)
{
printk("Simple Driver : release\n");
return 0;
}
- 위의 내용에서 return 0라고 되어 있는 부분은 커널에 진입하게 되어 성공적으로 open 하게 되면 다른 커널로 들어갈 기반의 return 0를 반환하며, 실패 했을 경우에는 -1을 반환하게 된다.
- port mapped I/O = I/O mapped I/O => 인텔에서 체택하는 방식이며 , 어셈블리를 이용하여 레지스터를 건들게 된다.
- memory mapped I/O = I/O mapped memory => 주로 사용하는 방식이며, C와 어셈블리를 이용하여 레지스터를 제어가 가능하다.
- 대부분은 C언어로 제어가 가능하며, Assembly는 따로 할당하는 구간이 있다.
- write는 출력을 위해 사용되는 함수이며, read 함수와 마찬가지로 디바이스의 구성 방식에 따라 다르게 처리해야한다.
=> port mapped I/O 의 방식을 사용할 것이냐 또는 memory mapped I/O 방식을 사용 할 것이냐의 차이를 만든다.
- ioctl 함수의 세번째 인자인 unsigned int 는 ioctl에 요청되는 command 형식을 나타낸다.
int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long)
=> ioctl의 경우에는 read 도 되고 write도 가능하며, 다른 함수들의 제어가 가능하다. 즉 , 맥가이버 칼 과 같은 역할의 다양한 기능의 함수 역할을 한다.
- 실제로 이 필드는 2bit의 read/write , 14bit의 데이터 크기, 8bit의 인덱스 ,8bit의 매직넘버를 포함하는 값이다.
- 해당 내용을 헤더 파일로 만들어서 쉽게 이해 할 수가 있다.
#define SIMPLE_IOCTL_MAGIC 's'
#define SIMPLE_INIT _IO(SIMPLE_IOCTL_MAGIC, 0)
#define SIMPLE_READ _IOR(SIMPLE_IOCTL_MAGIC, 1, int)
#define SIMPLE_WRITE _IOW(SIMPLE_IOCTL_MAGIC, 2, int)
#define SIMPLE_RDWR _IOWR(SIMPLE_IOCTL_MAGIC,3,int)
#define SIMPLE_IOCTL_MAX 4
- 말그대로 헤더 파일을 만들어서 매직넘버를 만들어 낸다. 그렇게 되면 해당하는 숫자의 값을 불러내면 그 값에 할당하는 함수를 호출하게 된다.
- 예를 들어서 read 함수를 호출하고 싶다면 1번을 선택하면 해당 ioctl 은 read 함수가 된다는 의미가 된다.
- 8bit의 인덱스를 통해 명령을 구분하기 때문에 최대 256개의 서로 다른 연산 방법을 제공할 수 있다.
=> 256개의 casting을 통하여 명령을 써 넣을수 있다 (하지만, define 시켜두면 따로 casting을 하지 않아도 된다.)
- 마지막 인자인 unsigned long 은 ioctl함수를 통해 이뤄지는 read/write에서 추가적인 데이터 전달이 필요할 때 해당 데이터의 위치를 가리키기 위한 주소 값이다.
=> 즉 define 해둔 값의 숫자를 넘기는 것과 동시에 해당 하는 그 주소값만 넘겨주면 다른 구조체를 유연하게 사용할 수가 있다.
- poll 함수는 인터럽트의 처리와 연관되어 있는 함수이다. 리눅스 커널이 관리하는 poll 테이블에 특정 디바이스에서 감시하고자 하는 이벤트를 기술하고 해당 디바이스에서 어떤 변화가 발생하면 커널이 이를 알려주게 해서 디바이스의 이벤트를 처리할 때 사용하는 함수이다.
=> 여기서 poll 은 polling 을 의미한다. polling 방식은 감시하는 방식이며, 다른 함수들은 인터럽트 방식이지만, 커널입장에서는 인터럽트가 아닌 polling 방식으로 인식이 되어 있다.
- mach/regs_gpio.h 는 SoC (System on Chip) 수준에서 정의된 GPIO에 대한 레지스터 정보를 가진 헤더 파일이다.
=> 칩안에 시스템이 있다는 의미로써 해당하는 칩안에 제어 할 수 있는 프로그램이 들어가 있다.
- 메이저와 마이너 번호에 대한 세부 정보는 리눅스 커널소스의 Documentation 디렉토리에 있는 devices.txt파일을 통해 확인 할 수 있다.
- cd /usr/src/linux/Documentation 디렉토리 내부에 있는 devices.txt 파일 내부의 모습이다.
- 이 예제에서는 가상의 주소로 0x80000000을 사용했다. 또한 DEV_SIZE는 매핑할 영역의 크기를 가리키며, 0x8000으로 정의하고 있다.
=> 실제로 이 제품을 만들었다면 해당 주소에 대해 납땜을 해놓았을 것이다.
=> 해당 장치에 대해서 주소값을 집어넣으면 그 장치의 0번지는 0x80008000에 대한 값을 대입한 주소의 값이 된다.
ssize_t simple_read(struct file *filp, char *buf, size_t size, loff_t *pos)
{
/*memory mapped I/O */
/*readb(), reads(), readw(),...*/
/*port mapped I/O */
/*inb(), ins(), inw(),....*/
char data[] = "12345678901234567890";
printk("Simple Driver : read\n");
copy_to_user(/*to*/buf, /*from*/data, /*size*/size);
/*put_user(x, ptr)*/
return 0x11;
}
- 이 예제에서는 open, read, write,ioctl, mmap,poll,release 함수를 작성하였으며, open 함수는 MAJOR, MINOR 매크로 함수를 이용해 이 드라이버에서 사용되는 메이저 번호와 마이너 번호를 추출하고 이를 커널 메세지로 출력했다.
/*memory mapped I/O */
/*readb(), reads(), readw(),...*/
/*port mapped I/O */
/*inb(), ins(), inw(),....*/
=> 사실상 이 부분이 실제 코드이다. 이 내용을 알지 못하는 사람은 사용하기가 까다롭기 때문에 다음과 같이 주석처리 해두었다.
=> read 부분 즉 memory 부분에서는 ARM 과 AVR등 에서 사용하는 readb 함수가 각각 구현되어 있으며, 다른 read 함수도 마찬가지이다.
=> inb 함수에 해당되는 시스템은 intel에서 주로 사용하며 그에 맞는 예제가 각각 구현되어 있다.
□ Win32 API
- CmdParam : 인자들이 파라미터로 인해 인자들이 받아들일수 있는 역할을 한다.
- CmdShow : 참의 내용을 확인하여 보여준다. (프로그램 짠 사람 마음... 보여주거나 안보여주거나..)
- WNDCLASS : 구조체의 형태 (찾아보면 struct 로 표기되어 있음)
- 전역변수에 값을 넣으면 다른 프로그램에게 공유하겠다는 의미를 가지고 있다. (전역변수에 집어넣지 않으면 다른 프로그램은 알 수가 없다.)
- 현재 나와있는 WndClass 변수에다가 값을 집어넣는데, 집어넣지 않으면 쓰레기값이 나오기 때문에 초기화 해주고 있다.
- IDI_APPLICATION : 예를 들어 메모장을 열었을때 제일 왼쪽 상단 위에 있는 아이콘 표시를 의미한다.
- hInstance : 전역변수에도 적어두고 메인함수 내부에도 적어두어야한다.
- lpfn : Long Pointer Function (함수 주소를 넣는 자리)
- 예를 들어 그림판과 메모장을 동시에 띄워서 마우스를 메모장에 올려두고 우선적으로 찍힌 메모장에 마우스 커서를 그림판으로 갖다 대면 마우스가 그림판에 있다는것을 인식한다. 이것은 운영체제가 창에 대해서 메세지를 보내는 것을 의미한다. (WndProc 을 써 뒀지만 반드시 WndProc을 쓸 필요는 없다. 변수는 바꿀수 있기 때문...)
- 우리는 창에 대해서 클릭을 하는것으로 착각을 하고 있으며, 현실적으로는 OS (운영체제)가 해당 창에 대해서 메세지를 보낸다.
- 실행 중인 내용의 한 덩어리를 Class라고한다. 창에 대한 Class 를 First 라고 해두었다.
- style : 윈도우 가로 세로가 조절이 가능하다(?)
- HREDRAW , VREDRAW : 가로 크기 세로 크기의 형태
- RegisterClass : 창의 정보를 구조체로 입력한다. 그리고 변수를 선언하는 변수는 아무것도 하지 않는다. (구조체는 등록하고 나면 쓸모가 없음.. main 함수가 끝날때까지 없어지지 않는다). 이 구조체가 살아있는 이유는 Register 함수까지 가기 위해서 살아 있는 것이다.
- CreateWindow : (인자순서) -> 클래스 이름 , WS_OVERLAPPEDWINDOW, 가로 값, 세로 값 등을 나타낸 시작 좌표값 CW (1,2번째), 가로의 크기와 세로의 크기의 CW (3,4번째) [좌표는 항상 4개가 필요 원을 그릴때도 마찬가지],NULL(?), Menu 값
-WS_OVERLAPPEDWINDOW를 나타낸 표
- ShowWindow : 창을 보여줄건지 안보여줄건지 결정한다. 만약 보여주지 않으려면 USEDEFAULT를 넣으면 된다. (창을 숨길때만 사용하지 의도적으로 숨길 이유는 없다.)
- GetMessage : 해당 창에다가 메세지를 보내는 역할을 한다. (초고속으로 window 가 창에게 엄청나게 많은 양의 message를 보내고 있다.)
- 일반프로세서는 메세지를 계속 보내다가 처리를 못하게 되면 앞전에 있던 일은 버려진다. 이것을 메세지 원형큐 라고 한다. (큐는 First In First Out 구조)
- GetMessage는 원형큐에서 가장 마지막에 저장한 내용을 처리한다.
- &Message => 전달된 메시지를 놔두는 위치가 된다 (즉, 창)
- 0,0,0 =>윈도우 창에서 x를 의미 한다. x를 클릭하면 해당 OS에 Message.wParam 을 반환한다. (정상 종료인지 비정상 종료인지 확인을 해준다)
- TranslateMessage : Window 창에서 사용하는 키보드를 의미한다 (A를 지정했을때 A가 가지는 가지수가 많다)
- DispatchMessage : 쓰레기 값을 처리
- 이제 위의 내용을 Visual Studio 에서 코드를 붙여놓고 실행 시켜보면 다음과 같은 창이 실행 되어야 정상적으로 완료 된 것이다.
- 코드 부분에서 위의 이름이 한문으로 뜨게 되는데 전역변수 구간에서 First 구간 큰따옴표 왼쪽에 L을 넣게 되면 정상적으로 실행이 된다.
↑ 위와 같이 되는 이유는 내일...
'코스웨어 > 15년 스마트컨트롤러' 카테고리의 다른 글
20151112-김재홍-win32API_1일차-첫번째예제 (3) | 2015.11.13 |
---|---|
20151112 - WinAPI 첫시간 일지 엄민웅 (5) | 2015.11.13 |
20151112_박서연_WinAPI_1 (4) | 2015.11.12 |
20151112 API 수업 / 11번 남수진 (6) | 2015.11.12 |
20151111 엄민웅 업무일지 영상처리 축소 (13) | 2015.11.11 |
20151110 안향진 영상처리 대칭, 회전 (9) | 2015.11.11 |
20151109_13번_일일업무일지_박서연_영상처리(패딩, RGB컨트롤,히스토그램평활화) (10) | 2015.11.09 |
평활화 소스 (2) | 2015.11.09 |