
1. 개요 이 문서는 시리얼 모듈을 루아에서 동작 시키기 위한 기능 중에서 시리얼 통신 기능을 지원하는 시리얼 COM PORT 객체에 대한 구현 내용을 기록한 문서이다.
10. 소스 코드 10.1 시리얼 통신 객체 관리 구조체
serial_com_t 구조체는 사용자 데이터 형으로 시리얼 통신을 구현하기 위한 구조체이다. typedef struct { char port[128]; int baud; int data; char parity[16]; int fd; struct termios old_tio; ssize_t rw_size; unsigned char r_data[32*1024]; } serial_com_t; 이 구조체는 통신 디바이스 파일 정보, 설정 정보 및 프로그램 제어 정보와 내부 수신 버퍼로 이루어 진다.
디바이스 파일 정보는 다음 필드를 사용한다.
최대 128 자 까지 디바이스 파일명을 다룰 수 있도록 했다.
통신 파라메터를 설정하기 위한 필드는 다음과 같다.
baud 는 실제 통신 속도를 지정한다. 예를 들어 115200 이라면 baud = 115200 이다. data 는 통신 데이터 크기로 8비트라면 8을 지정하면 된다.
parity 는 패리티 비트를 지정하는데 다음 값 중 하나로 설정된다.
통신을 실제로 관리하기 위해서는 디바이스 파일 디스크립터 fd 를 사용하고
사용 이전 설정 사항을 내부적으로 보관하기 위해서 old_tio 를 사용한다.
LUA 스크립트에서 수신 처리를 원활하게 하려면 내부적인 수신 버퍼가 필요하다. 수신 최대 크기는 보통 32KByte 이상은 다룰 수 없으므로 최대 크기를 32 * 1024 로 잡았다.
10.2 제어 대상이 되는 시리얼 포트 객체 생성 지원 C 함수
루아에서 시리얼 객체를 사용하려면 다음과 같이 시리얼 통신 디바이스 제어용 객체를 생성해야 한다.
이 스크립트 문장은 다음과 같이 정의된 시리얼 객체 모듈 에서 등록된 함수 serial_com_create() 를 호출 하게 된다.
디폴트 값을 넣는다.
sc_new_userdata() 함수는 다음과 같이 정의되어 있다.
lua_newuserdata() 함수를 사용하여 serial_com_t 구조체를 다룰 수 있는 사용자 데이터를 할당하고 SERIAL_COM 메타테이블을 연결한다.
SERIAL_COM 메타 테이블은 다음과 같은 구성을 갖는다.
serial_com_new_metatable() 함수는 시리얼 모듈이 등록될때 호출되는 luaopen_serial() 에서 호출한다.
10.3 메타 테이블 함수가 호출될때 사용자 데이터를 얻어 오는 C 함수
메타 테이블에 지정된 함수가 호출되면 다음과 같이 serial_com_t 구조체 데이터 주소를 얻어 와야 한다.
sc_get_data() 함수는 다음과 같이 정의 되어 있다.
객체 멤버 변수가 참조되거나 함수가 호출되면 사용자 데이터는 스택 처음에 놓이기 되는데 이것을 얻어와 형변환 하여 반환한다.
10.4 객체 멤버 변수 값 설정 처리
com 객체는 통신 설정 변수로 다음과 같은 변수를 관리한다.
이 변수에 값을 설정하면 __newindex 메타 함수인 sc_newindex() 를 호출하게 된다. 이 함수는 각각의 변수명을 구별하여 해당 변수에 따라서 루아 스택에서 전달된 값을 가져와 serial_com_t 사용자 데이터에 설정한다.
다음과 같이 sc_newindex()를 구현한다.
10.5 객체 멤버 변수 값 읽기와 함수 호출 사전 처리
com 객체는 통신 설정 변수 값을 읽거나 함수를 호출하게 되면 __index 메타 함수인 sc_index() 를 호출하게 된다. sc_index() 함수는 설정 변수 이면 해당 값을 사용자 데이터에서 읽어와 스택에 탑제하거나 함수 호출이면 사용자 데이터를 전역 변수 call_func_com 에 넣어 이후에 메타 테이블에 정의된 함수가 호출되었을때 사용되도록 만든다.
sc_index() 함수는 다음과 같이 구현되어 있다 .
10.6 open() 함수 구현
com 객체는 환경 설정 변수가 설정된 상태에서 open() 함수를 호출하여 디바이스 드라이버를 실제로 연다.
이 함수는 다음과 같이 각 변수에 따라서 디바이스 파일을 열고 시리얼 통신 제어용 파라메터를 설정한다.
가장 먼저 __index 메타 함수인 sc_index()에서 call_func_com에 저장된
사용자 데이터 구조체 주소를 가져온다.
덜 쓰여진 데이터를 모두 써 놓도록 하여 디바이스 드라이버의 내부 버퍼를 비우게 한다.
tcgetattr() 함수를 이용하여 이전에 설정된 상태를 얻어와 old_tio 에 저장한다.
이후 각 설정 변수값을 이용하여 통신 환경을 new_tio 에 설정하고 tcsetattr() 를
이용하여 디바이스에 적용한다.
여기서 에러가 생긴것에 대한 처리는 하지 않았다. 사용자는 fd 값을 얻어 이 값이 0 보다 작으면 에러가 발생했음을 확인해야 한다.
10.7 close() 함수 구현
닫기 함수는 다음과 같이 매우 단순하다.
tcsetattr()함수를 이용하여 open() 함수에 적용된 이전값으로 디바이스 설정을 바꾼다. 그리고 close() 함수를 이용하여 디바이스 파일을 닫은후 fd 값을 -1 로 설정하여 더이상 열려져 있지 않음을 설정한다.
10.8 read() 함수 구현
read() 함수는 sc_read() 에서 구현하는데 다음과 같다.
read() 함수를 이용하여 r_data 버퍼에 데이터를 읽고 읽은 크기 또는 에러 상태를
를 이용하여 스택에 넣은 후 에러가 아니면
를 이용하여 문자열로 버퍼 내용을 스택에 넣는다.
를 이용하여 데이터가 없음으로 해서 스택에 넣는다.
10.9 write() 함수 구현
write() 함수는 sc_write()에서 구현하는데 다음과 같다.
sc_read() 함수와 유사하지만 써 넣어진 데이터 크기를 스택에 써 넣어 호출 루아 스크립트가 실제로 써 넣어진 데이터 크기나 에러 상태를
|