lua-users home
lua-l archive

RE: Serial I/O Support

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


> I need to do serial I/O in LUA.
> Should I use Serial I/O from LUASYS or http://lua-users.org/wiki/SerialCommunication.
> In either case, how do I build and install LUASYS on a Windows XP machine?
> I am currently using LUA 5.1
I have written my own library. There is no documentation except for "clean" code. I have attached my library.
CONFIDENTIALITY NOTICE: This e-mail message, including any attachments, is for the sole use of the intended recipient(s) and may contain information that is confidential or proprietary to K&L Microwave, Inc. Any unauthorized review, use, disclosure or distribution is prohibited. If you are not the intended recipient, immediately contact the sender by reply e-mail and destroy all copies of the original message.
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#define LUA_LIB
#include <lua.h>
#include <lauxlib.h>
#include <stdlib.h>
#define LUA_SERIALLIBNAME "serialcom"
#define LUA_HANDLE "HANDLE*"
typedef int (*bsearch_cmp_t)(const void*, const void*);
#define tsearch(k,s) bsearch((const void*)k, (const void*)s, sizeof(s)/sizeof(s[0]), sizeof(struct tsear), (bsearch_cmp_t)compare )
struct tsear {
 const char* const s;
 const int v;
};
int compare ( char **arg1, char **arg2 ) {
 return strcmp(*arg1,*arg2);
}
HANDLE to_handle (lua_State *L) {
 HANDLE* ph = (HANDLE*)luaL_checkudata(L, 1, LUA_HANDLE);
 if (*ph == NULL)
 luaL_error(L, "attempt to use a closed port");
 return *ph;
}
static int return_error (lua_State *L, const char* fmt, ...){
 va_list ap;
 va_start(ap, fmt);
 lua_pushnil(L);
 lua_pushvfstring(L, fmt, ap);
 return 2;
}
static int return_typerror (lua_State *L, int narg, const char *tname, const char* var) {
 return return_error(L, "%s: %s expected, got %s",
 var, tname, luaL_typename(L, narg));
}
static int return_win32_error (lua_State *L) {
 LPVOID lpMsgBuf;
 DWORD dw = GetLastError(); 
 FormatMessage(
 FORMAT_MESSAGE_ALLOCATE_BUFFER |
 FORMAT_MESSAGE_FROM_SYSTEM,
 NULL,
 dw,
 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
 (LPTSTR) &lpMsgBuf,
 0, NULL );
 
 lua_pushnil(L);
 lua_pushstring(L, lpMsgBuf);
 LocalFree(lpMsgBuf);
 return 2;
}
static int ser_open (lua_State *L) {
 const char* port;
 HANDLE* ph;
 
 luaL_checktype(L, 1, LUA_TSTRING);
 lua_pushstring(L, "\\\\.\\");
 lua_insert(L, 1); 
 lua_concat(L, 2);
 port = lua_tostring(L,-1);
 
 ph = (HANDLE*)lua_newuserdata(L, sizeof(HANDLE));
 *ph = CreateFile(port,
 GENERIC_READ | GENERIC_WRITE,
 0, /* dwShareMode must be 0 */
 0,
 OPEN_EXISTING, /* dwCreationDisposition must be OPEN_EXISTING */
 FILE_ATTRIBUTE_NORMAL,
 0); /* hTemplateFile must be 0 */
 if (*ph == INVALID_HANDLE_VALUE)
 return return_win32_error(L);
 luaL_getmetatable(L, LUA_HANDLE);
 lua_setmetatable(L, -2);
 return 1;
}
static int ser_close (lua_State *L) {
 HANDLE h = to_handle(L);
 CloseHandle(h);
 return 0;
}
static int ser_purge (lua_State *L) {
 static const char* lst[] = {"rx","tx","both",NULL};
 HANDLE h = to_handle(L);
 switch (luaL_checkoption(L, 2, NULL, lst)) {
 case 0:
 if (!PurgeComm(h, PURGE_RXCLEAR))
 return return_win32_error(L);
 break;
 case 1:
 if (!PurgeComm(h, PURGE_TXCLEAR))
 return return_win32_error(L);
 break;
 case 2:
 if (!PurgeComm(h, PURGE_RXCLEAR | PURGE_TXCLEAR))
 return return_win32_error(L);
 break;
 }
 return 0;
}
static int ser_flush (lua_State *L) {
 HANDLE h = to_handle(L);
 if (!FlushFileBuffers(h))
 return return_win32_error(L);
 return 0;
}
static int ser_read (lua_State *L) {
 HANDLE h;
 DWORD read;
 char* buff;
 luaL_Buffer b;
 h = to_handle(L);
 read = luaL_checkint(L,2);
 luaL_argcheck(L, read >= 0, 2, "expected a positive number"); 
 if (read>LUAL_BUFFERSIZE)
 read = LUAL_BUFFERSIZE;
 luaL_buffinit(L, &b); 
 buff = luaL_prepbuffer(&b);
 if (!ReadFile(h, buff, read, &read, NULL)) {
 luaL_pushresult(&b);
 return return_win32_error(L);
 }
 luaL_addsize(&b, read);
 luaL_pushresult(&b);
 return 1;
}
static int ser_write (lua_State *L) {
 HANDLE h;
 DWORD read;
 const char* buff;
 h = to_handle(L);
 buff = luaL_checkstring(L, 2);
 read = lua_objlen(L, 2);
 if (!WriteFile(h,buff,read,&read,NULL))
 return return_win32_error(L);
 lua_pushinteger(L,read);
 return 1;
}
static int str_to_values (lua_State *L, const char* i) {
 const char* j;
 int n = 0;
 for (;;) {
 for(;*i && !isdigit(*i);i++) {}
 if (!(*i)) break;
 if ((j=strchr(i, ' ')) == NULL)
 j=i+strlen(i);
 lua_pushlstring(L, i, j-i);
 lua_tointeger(L, -1);
 n++;
 i=j;
 }
 return n;
}
static int ser_configure (lua_State *L) {
 static const struct tsear t[] = {
 "baud_rate",1, "byte_size",2, "dsr_sensitivity",3,
 "dtr_control",4, "parity",5, "parity_error",6,
 "parity_error_char",7, "rts_control",8, "stop_bits",9,
 "timeouts",10};
 static const struct tsear dtr[] = {
 "disable",DTR_CONTROL_DISABLE,
 "enable",DTR_CONTROL_ENABLE,
 "handshake",DTR_CONTROL_HANDSHAKE};
 static const struct tsear rts[] = {
 "disable",RTS_CONTROL_DISABLE,
 "enable",RTS_CONTROL_ENABLE,
 "handshake",RTS_CONTROL_HANDSHAKE};
 static const struct tsear parity[] = {
 "even",EVENPARITY, "mark",MARKPARITY, "none",NOPARITY,
 "odd",ODDPARITY, "space",SPACEPARITY};
 static const struct tsear parity_error[] = {
 "error",1, "ignore",2, "replace",3};
 static const struct tsear stop_bits[] = {
 "1",ONESTOPBIT, "1.5",ONE5STOPBITS, "2",TWOSTOPBITS};
 HANDLE h = to_handle(L);
 DCB dcb;
 COMMTIMEOUTS times;
 struct tsear* p;
 char* tmp;
/*
In a future version, the following fields will be modifiable
fTXContinueOnXoff
fOutxCtsFlow
fOutxDsrFlow
fOutX
fInX
XonChar
XoffChar
XonLim
XoffLim
*/
 if (!GetCommState(h,&dcb))
 return return_win32_error(L);
 dcb.fNull = FALSE;
 dcb.fOutX = FALSE;
 dcb.fInX = FALSE;
 lua_pushnil(L);
 while (lua_next(L, -2) != 0) {
 tmp = (char*)lua_tostring(L, -2);
 p = tsearch(&tmp, t);
 if (!p) continue;
 switch (p->v) {
 case 1: /* baud_rate */
 if (!lua_isnumber(L, -1))
 return return_typerror(L, -1, "number", p->s);
 dcb.BaudRate = lua_tonumber(L,-1);
 break;
 case 2: /* byte_size */
 if (!lua_isnumber(L, -1))
 return return_typerror(L, -1, "number", p->s);
 dcb.ByteSize = lua_tonumber(L,-1);
 break;
 case 3: /* dsr_sensitivity */
 if (!lua_isboolean(L, -1))
 return return_typerror(L, -1, "boolean", p->s);
 dcb.fDsrSensitivity = lua_toboolean(L,-1);
 break;
 case 4: /* dtr_control */
 if (!lua_isstring(L, -1))
 return return_typerror(L, -1, "string", p->s);
 tmp = (char*)lua_tostring(L, -1);
 p = tsearch(&tmp, dtr);
 if (p)
 dcb.fDtrControl = p->v;
 else
 return return_error(L, LUA_QL("dtr_control") " is set incorrectly");
 break;
 case 5: /* parity */
 if (!lua_isstring(L, -1))
 return return_typerror(L, -1, "string", p->s);
 tmp = (char*)lua_tostring(L, -1);
 p = tsearch(&tmp, parity);
 if (p)
 dcb.Parity = p->v;
 else
 return return_error(L, LUA_QL("parity") " is set incorrectly");
 break;
 case 6: /* parity_error */
 if (!lua_isstring(L, -1))
 return return_typerror(L, -1, "string", p->s);
 tmp = (char*)lua_tostring(L, -1);
 p = tsearch(&tmp, parity_error);
 if (!p)
 return return_error(L, LUA_QL("parity_error") " is set incorrectly");
 switch (p->v) {
 case 1: /* error */
 dcb.fParity = TRUE;
 dcb.fAbortOnError = TRUE;
 dcb.fErrorChar = FALSE;
 break;
 case 2: /* ignore */
 dcb.fParity = FALSE;
 /* TODO: does fAbortOnError need to be set? */
 break;
 case 3: /* replace */
 dcb.fParity = TRUE;
 dcb.fErrorChar = TRUE;
 break;
 }
 break;
 case 7: /* parity_error_char */
 if (!lua_isstring(L, -1))
 return return_typerror(L, -1, "string", p->s);
 if (!lua_objlen(L, -1))
 return return_error(L, "%s should have a length of 1", p->s);
 dcb.ErrorChar = lua_tostring(L, -1)[0];
 break;
 case 8: /* rts_control */
 if (!lua_isstring(L, -1))
 return return_typerror(L, -1, "string", p->s);
 tmp = (char*)lua_tostring(L, -1);
 p = tsearch(&tmp, rts);
 if (p)
 dcb.fRtsControl = p->v;
 else
 return return_error(L, LUA_QL("rts_control") " is set incorrectly");
 break;
 case 9: /* stop_bits */
 if (!lua_isstring(L, -1))
 return return_typerror(L, -1, "string", p->s);
 tmp = (char*)lua_tostring(L, -1);
 p = tsearch(&tmp, stop_bits);
 if (p)
 dcb.StopBits = p->v;
 else
 return return_error(L, LUA_QL("stop_bits") " is set incorrectly");
 break;
 case 10: /* timeouts */
 if (!lua_isstring(L, -1))
 return return_typerror(L, -1, "string", p->s);
 if (!GetCommTimeouts(h,&times))
 return return_win32_error(L);
 if (str_to_values(L, lua_tostring(L, -1)) != 5)
 return return_error(L,"%s is set incorrectly", p->s);
 times.ReadIntervalTimeout = lua_tointeger(L, -5);
 times.ReadTotalTimeoutMultiplier = lua_tointeger(L, -4);
 times.ReadTotalTimeoutConstant = lua_tointeger(L, -3);
 times.WriteTotalTimeoutMultiplier = lua_tointeger(L, -2);
 times.WriteTotalTimeoutConstant = lua_tointeger(L, -1);
 lua_pop(L, 5);
 if (!SetCommTimeouts(h, &times))
 return return_win32_error(L);
 break;
 }
 lua_pop(L, 1);
 }
 SetCommState(h, &dcb);
 return 0;
}
static int ser_status (lua_State *L) {
 DWORD ModemStat;
 HANDLE h = to_handle(L);
 if (lua_istable(L, 2))
 {
 lua_getfield(L, 2, "DTR");
 if (lua_isboolean(L, -1))
 EscapeCommFunction(h, lua_toboolean(L, -1) ? SETDTR : CLRDTR);
 lua_pop(L, 1);
 lua_getfield(L, 2, "RTS");
 if (lua_isboolean(L, -1))
 EscapeCommFunction(h, lua_toboolean(L, -1) ? SETRTS : CLRRTS);
 return 0;
 }
 else
 {
 if (!GetCommModemStatus(h,&ModemStat))
 return return_win32_error(L);
 lua_pushboolean(L, ModemStat & MS_CTS_ON);
 lua_pushboolean(L, ModemStat & MS_DSR_ON);
 lua_pushboolean(L, ModemStat & MS_RING_ON);
 lua_pushboolean(L, ModemStat & MS_RLSD_ON);
 return 4;
 }
}
static const luaL_Reg serlib[] = {
 {"open", ser_open},
 {"close", ser_close},
 {"purge", ser_purge},
 {"flush", ser_flush},
 {"read", ser_read},
 {"write", ser_write},
 {"configure", ser_configure},
 {"status", ser_status},
 {NULL, NULL}
};
LUALIB_API int luaopen_serialcom (lua_State *L) {
 luaL_newmetatable(L, LUA_HANDLE);
 lua_pushvalue(L, -1); /* push metatable */
 lua_setfield(L, -2, "__index"); /* metatable.__index = metatable */
 luaL_register(L, NULL, serlib);
 luaL_register(L, LUA_SERIALLIBNAME, serlib);
 return 1;
}

AltStyle によって変換されたページ (->オリジナル) /