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
 |