[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: RE: Serial I/O Support
- From: "King, Mike" <MKing@...>
- Date: Tue, 5 Jan 2010 10:54:48 -0500
> 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,×))
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, ×))
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;
}