201 lines
		
	
	
		
			6.6 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
		
		
			
		
	
	
			201 lines
		
	
	
		
			6.6 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
|  | /*=========================================================================*\
 | ||
|  | * Serial stream | ||
|  | * LuaSocket toolkit | ||
|  | \*=========================================================================*/ | ||
|  | #include <string.h> 
 | ||
|  | 
 | ||
|  | #include "lua.h"
 | ||
|  | #include "lauxlib.h"
 | ||
|  | #include "luasocket.h"
 | ||
|  | 
 | ||
|  | #include "auxiliar.h"
 | ||
|  | #include "socket.h"
 | ||
|  | #include "options.h"
 | ||
|  | #include "unix.h"
 | ||
|  | 
 | ||
|  | #ifndef _WIN32
 | ||
|  | #include <sys/un.h> 
 | ||
|  | #endif
 | ||
|  | 
 | ||
|  | /*
 | ||
|  | Reuses userdata definition from unix.h, since it is useful for all | ||
|  | stream-like objects. | ||
|  | 
 | ||
|  | If we stored the serial path for use in error messages or userdata | ||
|  | printing, we might need our own userdata definition. | ||
|  | 
 | ||
|  | Group usage is semi-inherited from unix.c, but unnecessary since we | ||
|  | have only one object type. | ||
|  | */ | ||
|  | 
 | ||
|  | namespace NS_SLUA {     | ||
|  | 
 | ||
|  | /*=========================================================================*\
 | ||
|  | * Internal function prototypes | ||
|  | \*=========================================================================*/ | ||
|  | static int serial_global_create(lua_State *L); | ||
|  | static int serial_meth_send(lua_State *L); | ||
|  | static int serial_meth_receive(lua_State *L); | ||
|  | static int serial_meth_close(lua_State *L); | ||
|  | static int serial_meth_settimeout(lua_State *L); | ||
|  | static int serial_meth_getfd(lua_State *L); | ||
|  | static int serial_meth_setfd(lua_State *L); | ||
|  | static int serial_meth_dirty(lua_State *L); | ||
|  | static int serial_meth_getstats(lua_State *L); | ||
|  | static int serial_meth_setstats(lua_State *L); | ||
|  | 
 | ||
|  | /* serial object methods */ | ||
|  | static luaL_Reg serial_methods[] = { | ||
|  |     {"__gc",        serial_meth_close}, | ||
|  |     {"__tostring",  auxiliar_tostring}, | ||
|  |     {"close",       serial_meth_close}, | ||
|  |     {"dirty",       serial_meth_dirty}, | ||
|  |     {"getfd",       serial_meth_getfd}, | ||
|  |     {"getstats",    serial_meth_getstats}, | ||
|  |     {"setstats",    serial_meth_setstats}, | ||
|  |     {"receive",     serial_meth_receive}, | ||
|  |     {"send",        serial_meth_send}, | ||
|  |     {"setfd",       serial_meth_setfd}, | ||
|  |     {"settimeout",  serial_meth_settimeout}, | ||
|  |     {NULL,          NULL} | ||
|  | }; | ||
|  | 
 | ||
|  | /* our socket creation function */ | ||
|  | /* this is an ad-hoc module that returns a single function 
 | ||
|  |  * as such, do not include other functions in this array. */ | ||
|  | static luaL_Reg serial_func[] = { | ||
|  |     {"serial", serial_global_create}, | ||
|  |     {NULL,          NULL} | ||
|  | }; | ||
|  | 
 | ||
|  | 
 | ||
|  | /*-------------------------------------------------------------------------*\
 | ||
|  | * Initializes module | ||
|  | \*-------------------------------------------------------------------------*/ | ||
|  | LUASOCKET_API int luaopen_socket_serial(lua_State *L) { | ||
|  |     /* create classes */ | ||
|  |     auxiliar_newclass(L, "serial{client}", serial_methods); | ||
|  |     /* create class groups */ | ||
|  |     auxiliar_add2group(L, "serial{client}", "serial{any}"); | ||
|  | #if LUA_VERSION_NUM > 501 && !defined(LUA_COMPAT_MODULE)
 | ||
|  |     lua_pushcfunction(L, serial_global_create); | ||
|  |     (void)serial_func; | ||
|  | #else
 | ||
|  |     /* set function into socket namespace */ | ||
|  |     luaL_openlib(L, "socket", serial_func, 0); | ||
|  |     lua_pushcfunction(L, serial_global_create); | ||
|  | #endif
 | ||
|  |     return 1; | ||
|  | } | ||
|  | 
 | ||
|  | /*=========================================================================*\
 | ||
|  | * Lua methods | ||
|  | \*=========================================================================*/ | ||
|  | /*-------------------------------------------------------------------------*\
 | ||
|  | * Just call buffered IO methods | ||
|  | \*-------------------------------------------------------------------------*/ | ||
|  | static int serial_meth_send(lua_State *L) { | ||
|  |     p_unix un = (p_unix) auxiliar_checkclass(L, "serial{client}", 1); | ||
|  |     return buffer_meth_send(L, &un->buf); | ||
|  | } | ||
|  | 
 | ||
|  | static int serial_meth_receive(lua_State *L) { | ||
|  |     p_unix un = (p_unix) auxiliar_checkclass(L, "serial{client}", 1); | ||
|  |     return buffer_meth_receive(L, &un->buf); | ||
|  | } | ||
|  | 
 | ||
|  | static int serial_meth_getstats(lua_State *L) { | ||
|  |     p_unix un = (p_unix) auxiliar_checkclass(L, "serial{client}", 1); | ||
|  |     return buffer_meth_getstats(L, &un->buf); | ||
|  | } | ||
|  | 
 | ||
|  | static int serial_meth_setstats(lua_State *L) { | ||
|  |     p_unix un = (p_unix) auxiliar_checkclass(L, "serial{client}", 1); | ||
|  |     return buffer_meth_setstats(L, &un->buf); | ||
|  | } | ||
|  | 
 | ||
|  | /*-------------------------------------------------------------------------*\
 | ||
|  | * Select support methods | ||
|  | \*-------------------------------------------------------------------------*/ | ||
|  | static int serial_meth_getfd(lua_State *L) { | ||
|  |     p_unix un = (p_unix) auxiliar_checkgroup(L, "serial{any}", 1); | ||
|  |     lua_pushnumber(L, (int) un->sock); | ||
|  |     return 1; | ||
|  | } | ||
|  | 
 | ||
|  | /* this is very dangerous, but can be handy for those that are brave enough */ | ||
|  | static int serial_meth_setfd(lua_State *L) { | ||
|  |     p_unix un = (p_unix) auxiliar_checkgroup(L, "serial{any}", 1); | ||
|  |     un->sock = (t_socket) luaL_checknumber(L, 2);  | ||
|  |     return 0; | ||
|  | } | ||
|  | 
 | ||
|  | static int serial_meth_dirty(lua_State *L) { | ||
|  |     p_unix un = (p_unix) auxiliar_checkgroup(L, "serial{any}", 1); | ||
|  |     lua_pushboolean(L, !buffer_isempty(&un->buf)); | ||
|  |     return 1; | ||
|  | } | ||
|  | 
 | ||
|  | /*-------------------------------------------------------------------------*\
 | ||
|  | * Closes socket used by object  | ||
|  | \*-------------------------------------------------------------------------*/ | ||
|  | static int serial_meth_close(lua_State *L) | ||
|  | { | ||
|  |     p_unix un = (p_unix) auxiliar_checkgroup(L, "serial{any}", 1); | ||
|  |     socket_destroy(&un->sock); | ||
|  |     lua_pushnumber(L, 1); | ||
|  |     return 1; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | /*-------------------------------------------------------------------------*\
 | ||
|  | * Just call tm methods | ||
|  | \*-------------------------------------------------------------------------*/ | ||
|  | static int serial_meth_settimeout(lua_State *L) { | ||
|  |     p_unix un = (p_unix) auxiliar_checkgroup(L, "serial{any}", 1); | ||
|  |     return timeout_meth_settimeout(L, &un->tm); | ||
|  | } | ||
|  | 
 | ||
|  | /*=========================================================================*\
 | ||
|  | * Library functions | ||
|  | \*=========================================================================*/ | ||
|  | 
 | ||
|  | 
 | ||
|  | /*-------------------------------------------------------------------------*\
 | ||
|  | * Creates a serial object  | ||
|  | \*-------------------------------------------------------------------------*/ | ||
|  | static int serial_global_create(lua_State *L) { | ||
|  | #ifndef _WIN32
 | ||
|  |     const char* path = luaL_checkstring(L, 1); | ||
|  | 
 | ||
|  |     /* allocate unix object */ | ||
|  |     p_unix un = (p_unix) lua_newuserdata(L, sizeof(t_unix)); | ||
|  | 
 | ||
|  |     /* open serial device */ | ||
|  |     t_socket sock = open(path, O_NOCTTY|O_RDWR); | ||
|  | 
 | ||
|  |     /*printf("open %s on %d\n", path, sock);*/ | ||
|  | 
 | ||
|  |     if (sock < 0)  { | ||
|  |         lua_pushnil(L); | ||
|  |         lua_pushstring(L, socket_strerror(errno)); | ||
|  |         lua_pushnumber(L, errno); | ||
|  |         return 3; | ||
|  |     } | ||
|  |     /* set its type as client object */ | ||
|  |     auxiliar_setclass(L, "serial{client}", -1); | ||
|  |     /* initialize remaining structure fields */ | ||
|  |     socket_setnonblocking(&sock); | ||
|  |     un->sock = sock; | ||
|  |     io_init(&un->io, (p_send) socket_write, (p_recv) socket_read,  | ||
|  |             (p_error) socket_ioerror, &un->sock); | ||
|  |     timeout_init(&un->tm, -1, -1); | ||
|  |     buffer_init(&un->buf, &un->io, &un->tm); | ||
|  |     return 1; | ||
|  | #else
 | ||
|  | 	return -1; | ||
|  | #endif
 | ||
|  | } | ||
|  | 
 | ||
|  | } // end NS_SLUA
 |