
1. 개요 이 문서는 시리얼 모듈을 루아에서 동작 시키기 위한 기능 중에서
2. Serial com 모듈 serial com 객체는 다음과 같은 기능을 제공한다.
2.1 Serial com 객체 생성
시리얼 통신을 하기 위해서는 시리얼 장치를 다루기 위한
2.2 통신 환경 설정 시리얼 통신을 하기 위해서는 통신 환경을 설정해야 한다. 보통 통신 속도 , 데이터 크기, 패리티 비트 , 스톱 비트 수 를 지정하는데 serial com 은 통신 속도 , 데이터 크기, 패리티 비트 만 지원한다. 스톱비트는 거의 대부분 1 비트를 사용하기 때문에 일단 지원하지 않기로 결정했다. 통신 환경 설정은 open() 함수를 호출하기 전에 설정해야 하며 재 설정이 필요하다면 close() 함수를 호출하고 통신 포트 환경을 설정 후 open() 를 사용해야 적용된다.
시리얼 포트를 열기 위해서는 open() 함수를 사용하고
2.4 시리얼 포트 쓰기 시리얼 포트에 데이터를 쓰기 위해서는 write() 함수를 사용한다.
다음은 사용예이다.
2.5 시리얼 포트 읽기 시리얼 포트에서 데이터를 읽기 위해서는 read() 함수를 사용한다.
2.6 시험용 루아 데모 소스 #!/mnt/nfs/lua/lua printf = function(s,...) return io.write(s:format(...)) end; m = require "serial"; printf( ">> serial port list\n" ); spl = m.port_list(); printf( " total = %d\n", spl.count ); printf( " list = " ); print( spl ); for i = 1, spl.count do spl.select = i; printf( " " ); printf( "select = %d ", spl.select ); printf( "device name = %s ", spl.name ); printf( "major = %d ", spl.major ); printf( "minor = %s ", spl.minor ); printf( "\n" ); end; spl.make_device_file(); printf( ">> com create\n" ); com = m.create(); com.port = "/dev/ttyS1"; com.baud = 115200; com.data = 8; com.parity = "none"; printf( " port = %s\n", com.port ); printf( " baud = %d\n", com.baud ); printf( " data = %d\n", com.data ); printf( " parity = %s\n", com.parity ); com.open(); printf( " fd = %d\n", com.fd ); printf( ">> com write\n" ); w_size = com.write( "com write test - 1234 ABCD abcd !\r\n" ); printf( " write result = %d\n", w_size ); printf( ">> com read\n" ); while true do rxsize, rxdata = com.read(); if rxsize > 0 then printf( " read size = %d [%s]\n", rxsize, rxdata ); end; end; com.close(); m = nil; 3. 구현 소스 목록 2 항에서 설명한 내용을 구현하기 위한 소스 구성은 다음과 같다
4. serial.c 소스 #include <stdarg.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #define LUA_LIB #include <lua.h> #include <lauxlib.h> #include <serial_port_list.h> #include <serial_com.h> #define SERIAL_MODULE "SERIAL" static const struct luaL_Reg sm[] = { { "port_list" , serial_port_list }, { "create" , serial_com_create }, { NULL, NULL } }; LUALIB_API int luaopen_serial( lua_State *L ) { int top; luaL_register(L, SERIAL_MODULE, sm ); serial_port_list_new_metatable(L); serial_com_new_metatable(L); return 1; }
5. serial_port_list.h 헤더 파일 소스 // serial_port_list.h #define SERIAL_PORT_LIST "SERIAL_PORT_LIST" #define MAX_SERIAL_PORT 256 typedef struct { char device_name[128]; int major; int minor; } serial_port_info_t; typedef struct { int count; int select; serial_port_info_t ports[MAX_SERIAL_PORT]; } serial_port_list_t; extern int serial_port_list( lua_State *L ); extern int serial_port_list_new_metatable(lua_State *L ); 6. serial_port_list.c 파일 소스
#include <stdarg.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <fcntl.h> #include <sys/stat.h> #include <sys/ioctl.h> #include <linux/limits.h> #define LUA_LIB #include <lua.h> #include <lauxlib.h> #include <serial_port_list.h> static serial_port_list_t *call_func_spl = NULL; static serial_port_list_t *spl_new_userdata(lua_State *L) { serial_port_list_t *spl = (serial_port_list_t *) lua_newuserdata(L, sizeof(serial_port_list_t)); luaL_getmetatable(L, SERIAL_PORT_LIST); lua_setmetatable(L, -2); return spl; } static serial_port_list_t * spl_get_data(lua_State *L, int index) { serial_port_list_t *spl = (serial_port_list_t *) lua_touserdata(L, index); if (spl == NULL) luaL_typerror(L, index, SERIAL_PORT_LIST); return spl; } int serial_port_list( lua_State *L ) { FILE *fp; int ret; char linebuff [128]; char device_name [128]; char device_file_name[128]; char minor_name [128]; char type_name [128]; int major; int minor_start; int minor_end; serial_port_list_t *spl; serial_port_info_t *port_info; int lp; spl = spl_new_userdata(L); spl->count = 0; spl->select = 0; fp = fopen("/proc/tty/drivers", "r"); if(fp == NULL) return 1; while(1) { if( fgets (linebuff, sizeof(linebuff) , fp ) == NULL ) break; ret = sscanf(linebuff, "%s %s %d %s %s", device_name, device_file_name, &major, minor_name, type_name ); if( ret != 5 ) continue; if( strcmp( type_name, "serial" ) ) continue; if( strchr( minor_name, '-' ) == NULL ) { ret = sscanf( minor_name, "%d", &minor_start ); minor_end = minor_start; } else { ret = sscanf( minor_name, "%d-%d", &minor_start, &minor_end ); } spl->count = 0; for( lp = minor_start; lp <= minor_end; lp++ ) { port_info = (serial_port_info_t *) &(spl->ports[lp-minor_start]); sprintf( port_info->device_name, "/dev/ttyS%d", spl->count ); port_info->major = major; port_info->minor = lp; spl->count++; } } fclose( fp ); return 1; } static int spl_newindex( lua_State *L ) { serial_port_list_t *spl; char *var_str; int select; if( lua_type(L, 2) == LUA_TSTRING ) { spl = spl_get_data ( L, 1 ); var_str = (char * ) lua_tostring ( L, 2 ); select = lua_tointeger( L, 3 ); if( !strcmp( var_str, "select" ) ) { if( ( select > 0 ) && ( select <= spl->count ) ) { spl->select = select; } } } return 0; } static int spl_index( lua_State *L ) { serial_port_list_t *spl; serial_port_info_t *port_info; char *var_str; if( lua_type(L, 2) == LUA_TSTRING ) { spl = spl_get_data( L, 1 ); port_info = (serial_port_info_t *) &(spl->ports[spl->select - 1]); var_str = (char *) lua_tostring( L, 2 ); if( !strcmp( var_str, "count" ) ) { lua_pushinteger( L, spl->count ); return 1; } if( !strcmp( var_str, "select" ) ) { lua_pushinteger( L, spl->select ); return 1; } if( !strcmp( var_str, "name" ) ) { lua_pushstring ( L, port_info->device_name); return 1; } if( !strcmp( var_str, "major" ) ) { lua_pushinteger( L, port_info->major ); return 1; } if( !strcmp( var_str, "minor" ) ) { lua_pushinteger( L, port_info->minor ); return 1; } if( !strcmp( var_str, "make_device_file" ) ) { call_func_spl = spl; } lua_getmetatable(L, 1); lua_replace(L, 1); lua_rawget(L, 1); return 1; } return 0; } static int spl_tostring (lua_State *L) { serial_port_list_t *spl; serial_port_info_t *port_info; luaL_Buffer b; int lp; spl = spl_get_data( L, 1 ); luaL_buffinit(L, &b); for( lp = 0; lp < spl->count; lp++ ) { port_info = (serial_port_info_t *) &(spl->ports[lp]); luaL_addstring(&b,port_info->device_name ); if( lp != (spl->count-1) ) luaL_addchar (&b, ' '); } luaL_pushresult(&b); return 1; } static int spl_gc (lua_State *L) { return 0; } static int spl_make_device_file(lua_State *L) { serial_port_list_t *spl; serial_port_info_t *port_info; int lp; spl = call_func_spl; if( spl != NULL ) { for( lp = 0; lp < spl->count; lp++ ) { port_info = (serial_port_info_t *) &(spl->ports[lp]); remove(port_info->device_name); mknod (port_info->device_name, (S_IRWXU|S_IRWXG|S_IFCHR), (port_info->major<<8) + port_info->minor ); } } call_func_spl = NULL; return 0; } static const luaL_reg serial_port_list_meta[] = { {"__newindex" , spl_newindex }, {"__index" , spl_index }, {"__tostring" , spl_tostring }, {"__gc" , spl_gc }, {"make_device_file" , spl_make_device_file }, {0, 0} }; int serial_port_list_new_metatable(lua_State *L ) { int top; top = lua_gettop(L); luaL_newmetatable(L, SERIAL_PORT_LIST ); lua_pushvalue(L, -1); lua_setfield(L, -2, "__index"); luaL_register(L, NULL, serial_port_list_meta ); lua_settop(L, top); return 1; }
7. serial_com.h 헤더 파일 소스 // serial_com.h #define SERIAL_COM "SERIAL_COM" 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; extern int serial_com_create( lua_State *L ); extern int serial_com_new_metatable(lua_State *L ); 8. serial_com.c 파일 소스
#include <stdarg.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <fcntl.h> #include <sys/stat.h> #include <sys/ioctl.h> #include <linux/limits.h> #include <unistd.h> #include <sys/types.h> #include <termios.h> #include <fcntl.h> #define LUA_LIB #include <lua.h> #include <lauxlib.h> #include <serial_com.h> static serial_com_t *call_func_com = NULL; static serial_com_t *sc_new_userdata(lua_State *L) { serial_com_t *com = (serial_com_t *) lua_newuserdata(L, sizeof(serial_com_t)); luaL_getmetatable(L, SERIAL_COM); lua_setmetatable(L, -2); return com; } static serial_com_t * sc_get_data(lua_State *L, int index) { serial_com_t *com = (serial_com_t *) lua_touserdata(L, index); if (com == NULL) luaL_typerror(L, index, SERIAL_COM); return com; } int serial_com_create( lua_State *L ) { serial_com_t *com; com = sc_new_userdata(L); com->fd = -1; strcpy( com->port,"/dev/ttyS1" ); com->baud = 115200; com->data = 8; strcpy( com->parity,"none" ); return 1; } static int sc_set_port( lua_State *L, serial_com_t *com ) { char *var_str; var_str = (char * ) lua_tostring ( L, 3 ); strcpy( com->port, var_str ); return 0; } static int sc_set_baud( lua_State *L, serial_com_t *com ) { int var_int; var_int = lua_tointeger( L, 3 ); com->baud = var_int; return 0; } static int sc_set_data( lua_State *L, serial_com_t *com ) { int var_int; var_int = lua_tointeger( L, 3 ); com->data = var_int; return 0; } static int sc_set_parity( lua_State *L, serial_com_t *com ) { char *var_str; var_str = (char * ) lua_tostring ( L, 3 ); strcpy( com->parity, var_str ); return 0; } static int sc_newindex( lua_State *L ) { serial_com_t *com; char *var_str; if( lua_type(L, 2) == LUA_TSTRING ) { com = sc_get_data ( L, 1 ); var_str = (char * ) lua_tostring ( L, 2 ); if( !strcmp( var_str, "port" ) ) { return sc_set_port(L,com); } if( !strcmp( var_str, "baud" ) ) { return sc_set_baud(L,com); } if( !strcmp( var_str, "data" ) ) { return sc_set_data(L,com); } if( !strcmp( var_str, "parity" ) ) { return sc_set_parity(L,com); } } return 0; } static int sc_index( lua_State *L ) { serial_com_t *com; char *var_str; if( lua_type(L, 2) == LUA_TSTRING ) { com = sc_get_data( L, 1 ); var_str = (char *) lua_tostring( L, 2 ); if ( !strcmp( var_str, "read" ) ) { call_func_com = com; } else if( !strcmp( var_str, "write" ) ) { call_func_com = com; } else if( !strcmp( var_str, "open" ) ) { call_func_com = com; } else if( !strcmp( var_str, "close" ) ) { call_func_com = com; } else { if( !strcmp( var_str, "fd" ) ) { lua_pushinteger( L, com->fd ); return 1; } if( !strcmp( var_str, "port" ) ) { lua_pushstring ( L, com->port ); return 1; } if( !strcmp( var_str, "baud" ) ) { lua_pushinteger( L, com->baud ); return 1; } if( !strcmp( var_str, "data" ) ) { lua_pushinteger( L, com->data ); return 1; } if( !strcmp( var_str, "parity" ) ) { lua_pushstring ( L, com->parity ); return 1; } } lua_getmetatable(L, 1); lua_replace(L, 1); lua_rawget(L, 1); return 1; } return 0; } static int sc_tostring (lua_State *L) { serial_com_t *com; com = sc_get_data( L, 1 ); lua_pushstring ( L, com->port ); return 1; } static int sc_gc(lua_State *L) { serial_com_t *com; com = sc_get_data( L, 1 ); if( com->fd >= 0 ) { tcdrain(com->fd); tcsetattr(com->fd, TCSANOW, &(com->old_tio) ); close( com->fd ); com->fd = -1; } return 0; } static int sc_open(lua_State *L) { serial_com_t *com; int baud; struct termios new_tio; com = call_func_com; if( com != NULL ) { if( com->fd >= 0 ) { tcdrain(com->fd); close( com->fd ); } com->fd = open( com->port, O_RDWR | O_NOCTTY | O_NONBLOCK ); if( com->fd >= 0 ) { tcgetattr( com->fd, &(com->old_tio) ); memset( &new_tio, 0, sizeof(new_tio) ); switch( com->baud ) { case 1200 : baud = B1200 ; break; case 2400 : baud = B2400 ; break; case 4800 : baud = B4800 ; break; case 9600 : baud = B9600 ; break; case 19200 : baud = B19200 ; break; case 38400 : baud = B38400 ; break; case 57600 : baud = B57600 ; break; case 115200 : baud = B115200 ; break; case 230400 : baud = B230400 ; break; case 460800 : baud = B460800 ; break; case 500000 : baud = B500000 ; break; case 576000 : baud = B576000 ; break; case 921600 : baud = B921600 ; break; case 1000000 : baud = B1000000 ; break; default : baud = B115200 ; break; } cfsetispeed(&new_tio, baud); cfsetospeed(&new_tio, baud); new_tio.c_cflag = baud; switch( com->data ) { case 5 : new_tio.c_cflag |= CS5 ; break; case 6 : new_tio.c_cflag |= CS6 ; break; case 7 : new_tio.c_cflag |= CS7 ; break; case 8 : default : new_tio.c_cflag |= CS8 ; break; } if ( !strcmp( com->parity,"even" ) ) new_tio.c_cflag |= ( PARENB ); else if ( !strcmp( com->parity,"odd" ) ) new_tio.c_cflag |= ( PARENB |PARODD ); else { // none parity } new_tio.c_cflag |= CLOCAL; // 외부 모뎀을 사용하지 않고 내부 통신 포트 사용 new_tio.c_cflag |= CREAD; // 쓰기는 기본, 읽기도 가능하게 new_tio.c_iflag = 0; new_tio.c_oflag = 0; new_tio.c_lflag = 0; new_tio.c_cc[VTIME] = 0; new_tio.c_cc[VMIN] = 1; memset( &new_tio, 0, sizeof(new_tio) ); new_tio.c_cflag = B115200; // 통신 속도 115200 new_tio.c_cflag |= CS8; // 데이터 비트가 8bit new_tio.c_cflag |= CLOCAL; // 외부 모뎀을 사용하지 않고 내부 통신 포트 사용 new_tio.c_cflag |= CREAD; // 쓰기는 기본, 읽기도 가능하게 new_tio.c_iflag = 0; // parity 비트는 없음 new_tio.c_oflag = 0; new_tio.c_lflag = 0; new_tio.c_cc[VTIME] = 0; new_tio.c_cc[VMIN] = 1; tcflush (com->fd, TCIFLUSH ); tcsetattr(com->fd, TCSANOW, &new_tio ); } } call_func_com = NULL; return 0; } static int sc_close(lua_State *L) { serial_com_t *com; com = call_func_com; if( com != NULL ) { if( com->fd >= 0 ) { tcdrain(com->fd); tcsetattr(com->fd, TCSANOW, &(com->old_tio) ); close( com->fd ); com->fd = -1; } } call_func_com = NULL; return 0; } static int sc_read(lua_State *L) { serial_com_t *com; ssize_t ret; ret = -1; com = call_func_com; if( com != NULL ) { if( com->fd >= 0 ) { ret = read( com->fd, com->r_data, sizeof( com->r_data ) ); } } call_func_com = NULL; lua_pushinteger( L, ret ); if( ret > 0 ) { lua_pushlstring( L, (const char *) com->r_data, ret ); } else { lua_pushnil( L ); } return 2; } static int sc_write(lua_State *L) { serial_com_t *com; ssize_t ret; unsigned char *var_str; ssize_t w_size; ret = -1; com = call_func_com; if( com != NULL ) { if( com->fd >= 0 ) { var_str = (unsigned char *) lua_tolstring( L, 1 , &w_size ); if( var_str != NULL ) { ret = write( com->fd, var_str, w_size ); } } } call_func_com = NULL; lua_pushinteger( L, ret ); return 1; } static const luaL_reg serial_com_meta[] = { {"__newindex" , sc_newindex }, {"__index" , sc_index }, {"__tostring" , sc_tostring }, {"__gc" , sc_gc }, {"open" , sc_open }, {"close" , sc_close }, {"read" , sc_read }, {"write" , sc_write }, {0, 0} }; int serial_com_new_metatable(lua_State *L ) { int top; top = lua_gettop(L); luaL_newmetatable(L, SERIAL_COM ); lua_pushvalue(L, -1); lua_setfield(L, -2, "__index"); luaL_register(L, NULL, serial_com_meta ); lua_settop(L, top); return 1; }
9. Makefile 모듈 컴파일을 위한 메이크 파일이다.
CROSS_PREFIX = arm-linux LUA_MODULE = serial.so TARGET = $(LUA_MODULE) TARGET_NFS = /nfs/lua LIB_LUA_A = liblua.a C_SRCS = LUA_SRCS = LUA_LIBS_SRCS = C_SRCS += serial.c C_SRCS += serial_port_list.c C_SRCS += serial_com.c LUA_SRCS += run.lua # LUA Support -- CORE LUA_LIBS_SRCS = LUA_LIBS_SRCS += ../../lua_lib/lapi.c LUA_LIBS_SRCS += ../../lua_lib/lcode.c LUA_LIBS_SRCS += ../../lua_lib/ldebug.c LUA_LIBS_SRCS += ../../lua_lib/ldo.c LUA_LIBS_SRCS += ../../lua_lib/ldump.c LUA_LIBS_SRCS += ../../lua_lib/lfunc.c LUA_LIBS_SRCS += ../../lua_lib/lgc.c LUA_LIBS_SRCS += ../../lua_lib/llex.c LUA_LIBS_SRCS += ../../lua_lib/lmem.c LUA_LIBS_SRCS += ../../lua_lib/lobject.c LUA_LIBS_SRCS += ../../lua_lib/lopcodes.c LUA_LIBS_SRCS += ../../lua_lib/lparser.c LUA_LIBS_SRCS += ../../lua_lib/lstate.c LUA_LIBS_SRCS += ../../lua_lib/lstring.c LUA_LIBS_SRCS += ../../lua_lib/ltable.c LUA_LIBS_SRCS += ../../lua_lib/ltm.c LUA_LIBS_SRCS += ../../lua_lib/lundump.c LUA_LIBS_SRCS += ../../lua_lib/lvm.c LUA_LIBS_SRCS += ../../lua_lib/lzio.c # LUA Support -- LIB LUA_LIBS_SRCS += ../../lua_lib/lauxlib.c LUA_LIBS_SRCS += ../../lua_lib/lbaselib.c LUA_LIBS_SRCS += ../../lua_lib/ldblib.c LUA_LIBS_SRCS += ../../lua_lib/liolib.c LUA_LIBS_SRCS += ../../lua_lib/lmathlib.c LUA_LIBS_SRCS += ../../lua_lib/loslib.c LUA_LIBS_SRCS += ../../lua_lib/ltablib.c LUA_LIBS_SRCS += ../../lua_lib/lstrlib.c LUA_LIBS_SRCS += ../../lua_lib/loadlib.c LUA_LIBS_SRCS += ../../lua_lib/linit.c INCLUDES += -I. INCLUDES += -I/usr/local/include INCLUDES += -I/usr/$(CROSS_PREFIX)/include INCLUDES += -I../include INCLUDES += -I../../lua_include LDFLAGS += -L./ LDFLAGS += -L../../lua_lib/ LDFLAGS += -L/usr/$(CROSS_PREFIX)/lib LIBS = -lm -ldl -llua CFLAGS += $(INCLUDES) CFLAGS += -Wall -O2 -g -DLUA_USE_LINUX CPPFLAGS += $(DEFINES) ARFLAGS = rs #--------------------------------------------------------------------- CC = $(CROSS_PREFIX)-gcc CXX = $(CROSS_PREFIX)-g++ AR = $(CROSS_PREFIX)-ar rcu AR2 = $(CROSS_PREFIX)-ranlib RANLIB = $(CROSS_PREFIX)-ranlib LD = $(CROSS_PREFIX)-ld NM = $(CROSS_PREFIX)-nm STRIP = $(CROSS_PREFIX)-strip OBJCOPY = $(CROSS_PREFIX)-objcopy CP = cp MV = mv #-------------------------------------------------------------------- C_OBJS = $(C_SRCS:%.c=%.o) LUA_LIBS_OBJS = $(LUA_LIBS_SRCS:%.c=%.o) # # Compilation target for C files # %.o:%.c @echo "Compiling $< ..." $(CC) -c $(CFLAGS) -o $@ $< %.o:%.cc @echo "Compiling $< ..." $(CXX) -c $(CPPFLAGS) $(CFLAGS) -o $@ $< # # Compilation target for C++ files # %.o:%.cc @echo "C++ compiling $< ..." $(CXX) -c $(CFLAGS) $(CXXFLAGS) -o $@ $< all : $(LIB_LUA_A) $(LIB_GXLIB_A) $(TARGET) cp -a $(LUA_MODULE) $(TARGET_NFS) cp $(LUA_SRCS) $(TARGET_NFS) $(LIB_LUA_A) : $(LUA_LIBS_OBJS) $(AR) $@ $? $(RANLIB) $@ $(TARGET) : $(C_OBJS) $(CC) $(LDFLAGS) -shared -Wl,-soname,$(TARGET) $(C_OBJS) -o $@ $(LIBS) dep : $(CC) -M $(INCLUDES) $(C_SRCS) > .depend clean: rm -f *.bak rm -f *.map rm -f *.o rm -f *.so rm -f $(C_OBJS) rm -f $(LUA_LIBS_OBJS) rm -f $(LIB_LUA_A) rm -f $(TARGET) core distclean: clean rm -rf .depend ifeq (.depend,$(wildcard .depend)) include .depend endif ![]() |