금일 수업내용과 간간한 팁들입니다.
마지막에 참고자료는
윈도우 시리얼 통시에 관한 전반적인 내용인데
한번씩 읽어보는것도 좋아보입니다.
* PFID
기본적으로 이런 흐름입니다.
우리는 Host 입니다. PC로 프로그래밍을 하고 RS232통신으로 RFID와 통신을 합니다.
원하는 정보를 얻어내기 위해 Reader로 정보를 보내주고
Reader기에서 읽어온 정보를 다시 출력해보며 현재 상태가 어떠한지를 파악해주는 겁니다.
* Set Output (5.8. [0x71] Set Output P. 48)
보드로 출력을 테스트 해봅니다.
스펙에 의하면 소리, LED 그리고 지속시간을 정할 수 있습니다.
우선 RFID와 통신할때는
Host -> Reader 와 Read -> Host 간에 통신에서 바이트가 얼마나 이동하는지
각 바이트가 무었을 뜻하는지를 스펙을 통해 알아내고 시작하면 됩니다.
#include <stdio.h>
#include <windows.h>
unsigned short Emb_Crc(void *);
int main()
{
HANDLE hComm;
int iCnt;
char caString[] = "HI";
unsigned char msg[] = {0x0D,0x00,0x71,0x00,0x1F,0x00,0x00,
0x00,0x01,0x00,0x00,0xFF,0xFF}; <-1
DWORD dwWrite;
DWORD dwRead;
DCB sPS; //시리얼 포트 삭제 및 저장 :: PORT STATUS이다.
COMMTIMEOUTS cTime;
unsigned char uc;
hComm = CreateFile("COM1", GENERIC_READ | GENERIC_WRITE, 0, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
//COM3 쓰면 포트가 열린다. OPEN 존재하는가, FILE 일반적으로 연다)
//COM포트에 관한 정보가 리턴되서 hComm에 저장된다.
if(INVALID_HANDLE_VALUE == hComm) //잘못 된 입력값
{
printf("PORT OPEN ERROR!!\n");
return 0;
}
if(0 == SetupComm(hComm, 4096, 4096)) //버퍼 설정
{
printf("BUFFER CONTROL ERROR!!\n");
CloseHandle(hComm);
return 0;
}
if(0 == PurgeComm(hComm, PURGE_TXABORT | PURGE_TXCLEAR)) //포트 초기화
{
printf("PORT INIT FAIL!!\n");
CloseHandle(hComm);
return 0;
}
sPS.DCBlength = sizeof(sPS); //sPS안에 구조체 값 세팅
if(0 == GetCommState(hComm, &sPS)) //COM1의 정보 변경
{
printf("PORT STATUS READING FAIL!!\n");
CloseHandle(hComm);
return 0;
}
/* 통신 설정 해준다. 38400, 8bit, 짝수패리티, 정지비트 1, 흐름제어 없음 */
sPS.BaudRate = CBR_38400;
sPS.ByteSize = 8;
sPS.Parity = EVENPARITY;
sPS.StopBits = ONESTOPBIT;
/* 변경한 값으로 세팅한다. (검사까지) */
if(0 == SetCommState(hComm, &sPS))
{
printf("PORT STATUS WRITING FAIL!!\n");
CloseHandle(hComm);
return 0;
}
/* CRC값 */
*((unsigned short *)(msg + 11)) = Emb_Crc(msg);
/* 파일에 기록한다. (핸들, 주소, 사이즈) */
WriteFile(hComm, msg, sizeof(msg), &dwWrite, 0);
printf("%d\n", dwWrite);
/* 파일핸들, 데스테네이션, 사이즈 */
ReadFile(hComm, msg, 1, &dwRead, 0); <- 2
if(sizeof(msg) < msg[0])
{
msg[0] = sizeof(msg) - 1;
}
ReadFile(hComm, msg+1, msg[0]-1, &dwRead, 0);
/* msg의 가장 앞에 전체 길이가 들어가 있다 */
for(iCnt=0;iCnt<msg[0];++iCnt)
{
printf("%02X ", msg[iCnt]);
}
putchar('\n');
CloseHandle(hComm);
return 0;
}
unsigned short Emb_Crc(void *arg)
{
unsigned short i;
unsigned short j;
unsigned short cnt;
unsigned short crc=0xFFFF;
unsigned short temp;
unsigned char *buf = arg;
cnt = (*buf) - 2; //CRC 계산하기 위해서 -2를 해준다.
for(i=0 ; i < cnt ; ++i)
{
crc^= *(buf + i);
for(j=0 ; j < 8 ; ++j)
{
if(0 != (crc&0x0001))
{
crc=(crc>>1)^0x8408;
}
else
{
crc=(crc>>1);
}
}
}
return crc;
}
1 우선 소스코딩은 ISO 15693 스펙을 따라가도록 하겠습니다.
우선 RFID에 13byte의 정보를 씁니다.
이정보에 따라 출력을 합니다. (소리 종류, 반짝임, 지속시간)
이정보에 따라 RFID가 출력을 한뒤,
다시 Host쪽으로 정보를 리턴해줍니다. (6byte)
(자세한 사항은 스펙 참조 p.48)
-읽기
2 리턴정보는 스펙에 의하면 제일 처음 부분에 총 전송된 길이가 나옵니다.
그래서 처음 한 바이트를 읽고,
이후에 이 정보에 따라 나머지 길이를 알아내고 읽어 옵니다.
* Get Software Version (5.4.[0x65] Get Software Version P.44)
이번에는 RFID의 정보를 한번 읽어 보도록 합니다.
#include <stdio.h> |
RFID의 소프트웨어에 대한 정보를 가져 옵니다.
근데 여기서는 배열을 일단 크게 잡아줍니다. (128로 잡았습니다.)
스펙에서 보면
Host -> Reader 는 5바이트가 가는데,
Reader -> Host 로는 13바이트가 오게 됩니다.
최초 배열을 5바이트로 설정하면 후에 Raed로 읽어 올때 오버플로우가 발생하게 되겠지요.
우선 총량을 어떻게 알아낼 것인지는 앞의 소스와 같습니다.
(배열의 0번 index에는 크기가 적혀있습니다.)
1. STATUS를 검사하여 잘 읽어 왔는지를 체크 합니다. (0 이면 된다)
2. STATUS가 0이라면 이제 뒤에 추가적인 정보를 출력해 줍니다.
순서데로 펌웨어, 개발펌웨어, 하드웨어타입, 소프트웨어타입, 사용가능한 태그
순서대로 출력해주는 코드입니다.
3. printf문에 3항연산자가 나옵니다. A ? B : C 인데
A의 조건이 참일 경우 B를 수행하고
A의 조건이 거짓일 경우 C를 수행합니다.
* Host Comands
1) inventory
여기서 부터 진행하는 코딩은
호스트 커맨드 입니다. 카드로부터 정보를 읽어오는 작업입니다.
첫번째로 Inventory검사 인데, 안테나 필드에 올라온 태그의 정보를 가져 옵니다.
CRC함수는 중복되니 지우도록 하겠습니다.
#include <stdio.h> |
우선 P.52 에는 Host Commands에 대한 기본형식이 나와있습니다.
인벤토리에 가보면 4, 5번 바이트를 어떻게 세팅해야 하는지 나옵니다.
4번 바이트는 Invenroty임을 정해줘야 합니다. (0x01)
5번 바이트는 Mode에 대한 설명인데
0x00을 넣을경우 계속해서 새로운 카드에 입력을 받겟다는 뜻이고
(new Inventory requested)
0x01을 넣을경우 하나의 카드에서 정보를 계속 더 읽겟다는 뜻입니다.
(more data requested)
우리는 0x00으로 세팅을 했습니다.
이렇게 세팅된 배열 5byte를 RFID로 날려주면
카드의 정보가 날아오게 됩니다.
우선 아까와 마찬가지로 STATUS를 검사하여 카드정보를
제대로 읽었는지를 검사 합니다.
3가지 케이스를 준비하였는데, standard, I-Code EPC 그리고 I-Code UID 입니다.
각 케이스는 전송되어진 양에따라 분류 됩니다. (P.53 참고)
이제 TR-TYPE 을 알아보겠습니다. 배열의 6번째 [5] byte에 잇는 정보입니다.
스펙에서 6,7번 비트는 RF_TEC 에 대한 정보를 0,1,2,3번 비트는 TYPE_NO에 대한 정보를 나타낸다고 명시했습니다.
RF_TECH : RFID가 어떤 기술로 송수신을 하는지에 대한 정보입니다.
b00: 13,56 MHz Transponder
b10: UHF Transponder
두가지가 있습니다.
TYPE_NO : Transponder의 타입입니다.
스펙의 103페이지에 나와있습니다. 어떤 회사의 기술인지를 명시하는 비트입니다.
* Tip
-ISO15693 : Hostcommand
-커넥터와 동글
커넥터 : 선만이어준다
동글 : 선을 이어주면서 안에 칩도 있다.
-통신 세대
1G : 보이스
2G : 메세지
3G : 동영상
4G : 속도 상승
* 참고
-윈도우 시리얼 프로그래밍
직렬포트 열기
CreateFile(szDevice, fdwAccess, fdwShareMode, lpsa,fdwCreate, fdwAttrAndFlags, hTemplateFile);
szDevice : COM1,COM2와 같이 열리는 직력 포트의 논리적 이름이다,
fdwAccess : 포트의 엑세스 타입을 지정.
fdwAccess = GENERIC_READ | GENERIC_WRITE
fdwShareMode : 포트의 공유속성을 지정, 직력 포트에서는 0으로 설정되어야 한다.
lpsa : 포트 핸들이 포트를 연 응용 프로그램이 자식에 의해 상속되는 방법 등과 같은 속성을 정의하는 안전
속성 구조체를 참조한다.
이 파라미터를 NULL로 설정하면
포트에 디폴트 안전 속성을 할당한다.
자식 응용 프로그램에 의한 상속에서는 포트가 상속될 수 없다는 것이 디폴트 설정이다.
fdwCreate
: CreateFile이 기존의 파일에서 호출될 경우의 작동을 지정한다.
직렬 포트가 이미존재하기 때문에 이 값은 OPEN_EXISTING로 설정되어야 한다.
fdwAttrsAndFlag
: 포트의 여러 가지 속성을 설명한다. 직렬 포트에 있어서의 유일한 설정 내용은
FILE_FLAG_OVERLAPPED이다.
이 설정으로 지정하면 포트의 I/O는 배경에서 처리된다.
hTemplateFile : 템플릿 파일에 대한 핸들을 지정하는데, 포트를 열 때는 사용되지 않는다. 따라서 NULL로 설정되어야 한다.
포트 설정의 변경
현재의 포트에 대한 DCB 설정을 읽기 위해서 GetCommState를 호출한다. 이 함수는 열린 포트에 대한 핸들과 정보가 반환되는 DCB 구조체에 대한 포인터를 수용한다. GetCommState를 보완하는 것이 SetCommState인데, 이것 역시 DCB 구조체에 대한 포인터와 포트 핸들을 필요로 한다. SetCommState는 DCB 구조체의 내용을 포트 설정 사항으로 기록한다. 이들 두개의 함수는 다음과 같은 식으로 호출한다.
BOOL GetCommState( hComm, &dcb) ;
BOOL SetCommState( hComm, &dcb);
포트 설정 내용을 변경하는 것은 GetCommState로 읽는 것처럼 간단하지는 않다. 선택된 설정 내용을 변경하고 설정 내용을 SetCommState를 사용해서 다시 기록한다.
하나의 추가 단계가 필요하다. 즉, 포트에 대한 허용 가능한 설정 내용과 새로운 설정 내용을 비교하는 것이다. 허용 가능한 설정 내용은 COMMPROP 구조체에 존재한다. 새로운 설정이 지원 가능한 것이면 이들은 DCB에 저장되고 SetCommState를 사용해서 기록된다. 다음 예는 baud rate를 19.4kbps로 변경한 것이다.
GetCommProperties ( hComm, &commprop);
GetCommState( hComm, &dcb);
//19.2kbps가 지원되면 설정하고, 그렇지 않으면 변경하지 않는다.
if( commprop.dwSettableBaud & BAUD_19200)
dcb.dwBaudRate = 19200;
SetCommState( hComm, &dcb);
핸드쉐이킹과 흐름 조정
DTR을 ON시키는 것은 포트가 바이트를 수신할 준비가 되었음을 모뎀에 알리는 것이다. DTR은 사용 가능 신호로 작동해서 DTR이 OFF되면, 모뎀은 포트로의 바이트 송신을 중단한다. 따라서 포트 드라이버는 수신 버퍼가 가득 차서 닫힐 때 DTR을 OFF시키고, 수신 버퍼가 작동될 때까지 수신을 정지한다. 포트에 대한 바이트의 송신과 수신을 조정하기 위해 fDtrControl은 fOutxDsrFlow와 함께 사용될 수 있다. 아래에 코드에 따른 전송 흐름을 예시한다.
fOutxDsrFlow = TRUE;
fDtrControl = DTR_CONTROL_HANDSHAKE;
port1 port2
DTR ON DSR ON
TX
DTR OFF DSR OFF
DSR ON DTR ON
TX
DTR 핸드쉐이킹이 사용되면, fDsrSensitivity는 TRUE로 설정되어야 한다. 이런 식으로 DSR이 OFF일 때 수신된 바이트는 무시된다.
일반 설정의 변경
DCB에서 가장 일반적으로 변경되는 설정 내용은 baud rate, parity type, stop bit의 수이다. 이들 설정을 위해 사용하기 편리한 함수는 BuildCommDCB이다.
BuildCommDCB( szSettings, &DCB);
BuildCommDCB의 파라미터는 새로운 설정을 포함하는 문자열과 설정 내용이 적용되는 DCB 구조체에 대한 포인터이다. 문자열은 MS-DOS나 Microsoft Windows NT의 Mode 명령 문자열과 동등한 포맷을 갖는다. 다음은 그 예이다.
“baud=12 parity=N data=8 stop=1” //baud=12는 1200bps를 의미
함수는 포트 설정을 실제로 변경하지 않는다. 따라서 포트는 확인할 필요가 없다. 대신에 새로운 설정 내용들이 제공된 DCB 구조체로 복사될 뿐이다. 새로운 설정 사항을 활성화하기 위해 SetCommState를 사용한다. Mode 명령의 Retry 파라미터는 Windows 95에서는 의미가 없고, 문자열에서 빼야 한다는 점에 주의한다. 또한 문자열에서의 위치에 따라 설정 내용을 전달하기 때문에 문자열로부터 파라미터 식별자를 생략할 수도 있다. 위의 예제는 따라서 다음과 같이 줄여 쓸 수 있다. “12,N,8,1”
BuildCommDCB와 SetCommState로 변경을 시도하기 전에 직렬 포트가 설정 내용을 지원하는지를 확인하기 위해 COMMPROP를 체크해야 한다. baud rate 설정의 단축 형식은 도스 Mode 명령에서 사용 가능한 것으로 제한된다. 19200bps 이상으로 baud rate를 지정하기 위해서는 긴 형식을 사용해야 한다. 예를 들어 , baud rate를 38400bps로 지정하려면, baud=38이 아니라 baud=38400으로 해야 한다. BuildCommDCB가 단축 형식 중 하나로 지정된 baud rate를 인식하지 못하면 리터럴 값을 DCB의 baud rate 필드로 복사한다. baud=38은 38bps로 baud rate를 설정하는 것과 같다.
Baud(단축형) |
Parity(대소문자 구별) |
Data bits |
Stop bits |
11 or 110 = 110bps 15 or 150 = 150bps 30 or 300 = 300bps 60 or 600 = 600bps 12 or 1200 = 1200bps 24 or 2400 = 2400bps 48 or 4800 = 4800bps 96 or 9600 = 9600bps 19 or 19200 = 19200bps |
n = none e = even o = odd m = mark s = space
|
5 6 7 8 |
1 1. 5 2 |
COMMCONFIG 구조체
COMMCONFIG는 모든 면에서 GetCommState에 의해 반환되는 것과 동일한 DCB 구조체를 포함한다. COMMCONFIG는 포트를 초기화하기 위한 CommConfigDialog라는 간편한 함수를 갖고 있다 . 이 함수는 baud rate, 데이터 비트, 패리티 방식, 정지 비트, 포트의 흐름 조정 등을 변경하기 위한 대화상자를 표시한다. 이것은 또한 디폴트 설정을 복구하기 위한 버튼도 포함한다. 선택된 설정들은 함수가 반환될 때 COMMCONFIG의 dcb 멤버로 반환된다. CommConfigDialog의 전형적인 호출 방식은 다음과 같다.
CommConfigDialog(lpszCommName, hWnd, &cc)
'코스웨어 > 12년 내장형하드웨어' 카테고리의 다른 글
[리눅스 커널] 2.4.32 와 2.6.14 소스 (0) | 2012.10.12 |
---|---|
[RFID]스팩위주 설명 보완중 -김동기 (4) | 2012.10.11 |
[공유기]DNS 서버가 응답하지 않습니다.란 메세지 뜰시 (2) | 2012.10.11 |
제안 한가지 하겠습니다. (9) | 2012.10.11 |
[RFID]10월 11 일 수업 (5) | 2012.10.11 |
Visual Studio 에서 사용 팁. 나름 유용하니 애용하시오. (4) | 2012.10.11 |
[RFID] - 정철 (0) | 2012.10.11 |
10월 10일 - 리눅스 커널 프로그래밍 chater[3] -(4), 공유폴더에 kernel 옮기기 (8) | 2012.10.11 |