/***************************** C SOURCE FILE *********************************
**
** Project: Firmware - LUA interface for serial communication
** Filename: SERIALLUAIF.C
** Version: 1.05
** Date: (pk)
**
*****************************************************************************/
// z:\rtcu_arm7\src\vcom\makefile to compile..
// about stack read in refman5.pdf p. 24
#define DEBMSG_ENABLE 1
#include <armx.h>
#include <string.h>
#include <errno.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
// #define serlib_c
#define LUA_LIB
// this is not a name of struct, and will be printed within *.lua code
#define cfMetaTab "lio.ser.serdev"
#define SERSTAT_INFRAME 0x01
#define SERSTAT_STUFF 0x02
#include <lua.h>
#include <lauxlib.h>
#if defined(TRG_ARM002)
#define SERPORT_MAX 1
#elif defined(TRG_ARM004)
#define SERPORT_MAX 2
#elif defined(TRG_ARM005)
#define SERPORT_MAX 0
#elif defined(TRG_ARM006)
#define SERPORT_MAX 0
#elif defined(TRG_ARM009)
#define SERPORT_MAX 2
#elif defined(TRG_ARM022)
#define SERPORT_MAX 2
#elif defined(TRG_ARM092)
#define SERPORT_MAX 2
#else
#error NO TARGET or UNSUPPORTED TARGET!
#endif
#define READ_BUFFER_SIZE 512 // define how much it can read data at a time
typedef struct port_data {
int8 handle;
int32 baud;
int8 bit;
int8 parity;
int8 stop;
int8 handshake;
int8 rs485;
} port_data;
typedef struct {
// Var:
int16 nextin;
int8 status;
// Input:
int8 port;
int8 enable;
#ifdef TRG_ARM7
int8 alignment;
#endif
uint8* frame;
int16 maxsize;
uint8 sof;
uint8 eof;
uint8 stuffch;
// Output:
int8 ready;
int16 size;
}ALIGN_ATTR tdefserframereceiver;
static port_data* check_serdev(lua_State *L, int i) {
return (port_data*) luaL_checkudata(L, i, cfMetaTab);
}
static int getInt32FromTable(lua_State *L, int index, const char * key,
int32 * val) {
lua_getfield(L, index, key);
if (lua_isnil(L, -1)) {
lua_pop(L, 1);
return 0;
}
*val = lua_tointeger(L, -1);
lua_pop(L, 1);
return 0;
}
static int getInt8FromTable(lua_State *L, int index, const char * key,
int8 * val) {
lua_getfield(L, index, key);
if (lua_isnil(L, -1)) {
lua_pop(L, 1);
return 0;
}
*val = lua_tointeger(L, -1);
lua_pop(L, 1);
return 0;
}
static const char * getStringFromTable(lua_State *L, int index,
const char * key) {
lua_getfield(L, index, key);
if (lua_isnil(L, -1)) {
lua_pop(L, 1);
return 0;
}
const char *rtn;
rtn = lua_tostring(L, -1); // if error then returns NULL
lua_pop(L, 1);
return rtn;
}
static int getBooleanFromTable(lua_State *L, int index, const char * key,
int8 * val) {
lua_getfield(L, index, key);
if (lua_isnil(L, -1)) {
lua_pop(L, 1);
return 0;
}
*val = lua_toboolean(L, -1);
lua_pop(L, 1);
return 0;
}
// Fill out the config-table with parameters from table.
// Used by luaSerConfigure() and luaSerOpen()
// Input parameters:
// L: stack, pos: position on stack
// Return values: always 0
static int32 setConfig(lua_State *L, port_data* port) {
const char *fcArray[3] = { "none", "rtscts", "xon/xoff" };
const char *pArray[3] = { "none", "even", "odd" };
int const tabOnStack = -1;
int i;
// this is a table, but we have userdata not a simple table!
getInt32FromTable(L, tabOnStack, "baudRate", &port->baud);
getInt8FromTable(L, tabOnStack, "numDataBits", &port->bit);
getInt8FromTable(L, tabOnStack, "numStopBits", &port->stop);
getBooleanFromTable(L, tabOnStack, "rs485", &port->rs485);
const char* handshake = getStringFromTable(L, tabOnStack, "flowControl");
for (i = 0; i < 3; i++) {
if (stricmp(handshake, fcArray[i]) == 0) {
port->handshake = i;
break;
}
}
const char* parity = getStringFromTable(L, tabOnStack, "parity");
for (i = 0; i < 3; i++) {
if (stricmp(parity, pArray[i]) == 0) {
port->parity = i;
break;
}
}
return 0;
}
static int luaSerSetConfigTable(lua_State *L) {
port_data* port = check_serdev(L, 1);
int status;
if (lua_gettop(L) > 1) { //Additional parameter
luaL_checktype(L, 2, LUA_TTABLE);
if ((status = setConfig(L, port)) != 0) {
return status;
}
}
lua_pushstring(L, "ok");
return 1;
}
// in LUA: serial.open(port, config)
// Parameters
// #integer port :
// #config config : An optional #config table.
// Return value: #serdev: Serial device - userdata with functions etc.
static int luaSerOpen(lua_State *L) {
int port;
struct port_data* port_data;
int use_config = 0;
deb_printf("LUA", "luaSerOpen()");
// displayStack(L);
// This function allocates a new block of memory with the given size,
// pushes onto the stack a new full userdata with the block address,
// and returns this address.
// luaL_checkint does not change the stack
port_data = lua_newuserdata(L, sizeof(struct port_data));
port = luaL_checkint(L, 1); // take the first parameter and save it
if (lua_gettop(L) > 1) { //Additional parameter
luaL_checktype(L, 2, LUA_TTABLE);
use_config = 1;
}
deb_printf("luaSerOpen()", "Opening a connection on port: %d", port);
port_data->baud = 9600;
port_data->bit = 8;
port_data->parity = 0;
port_data->stop = 1;
port_data->rs485 = 0;
port_data->handshake = 0;
if (use_config) {
int status;
lua_pushvalue(L, 2); // make a copy of the config
if ((status = setConfig(L, port_data)) != 0) {
return status;
}
lua_pop(L, 1); // pop the copy of the config
} else {
deb_printf("luaSerOpen()",
"Second parameter is not a table. Default values will be used.");
}
deb_printf("LUA", "Open: %d, %d, %d", port, port_data->baud,
port_data->bit);
port_data->handle = vcomOpen(port, port_data->baud, port_data->bit,
port_data->parity, port_data->stop, port_data->rs485, NULL);
if (port_data->handle < 0) {
lua_pushnil(L);
lua_pushnumber(L, port_data->handle);
return 2;
}
luaL_getmetatable(L, cfMetaTab);
// Pushes onto the stack the metatable "configMetatable"
// displayStack():3 LUA_TTABLE -1
// displayStack():2 LUA_TUSERDATA -2
// returns this userdata
// displayStack():1 LUA_TNUMBER -3 1
lua_setmetatable(L, -2);
// Pops a table from the stack and sets it as the new metatable
// for the value at the given index.
// displayStack():2 LUA_TUSERDATA -1
// displayStack():1 LUA_TNUMBER -2 1
return 1;
}
static int luaSerClose(lua_State *L) {
struct port_data * port = check_serdev(L, 1);
int8 rc;
// Close device
rc = vcomClose(port->handle);
// 0: - Success // -1: - Client not found.
if (rc != 0) {
deb_printf("Error: luaSerClose()", "vcomClose():rc: %d \r\n", rc);
lua_pushnil(L);
lua_pushnumber(L, rc); /* push result */
return 2;
}
// Completed
lua_pushliteral(L, "ok");
return 1;
}
#if 0
static int luaSerSendChar(lua_State *L) {
deb_printf("luaSerSendChar()", " my stack: ");
// displayStack(L);
int8 serport;
const char * mychar = lua_tostring(L, 1);
char ch = mychar[0];
configPtr cfPtr = serialPtrGet(L, 1);
// Var
int32 rc;
serport = cfPtr->port;// just added
// Validate
if (serport < 0 || serport > SERPORT_MAX) {
deb_printf("Error: luaSerSendChar()",
"serport out of range: %d \r\n", serport);
lua_pushnumber(L, 0); /* push result */
return 1;
}
// Write char
rc = vcomWrite(serport, (unsigned char*) &ch, 1);
// Return: 0 - Success. // -1 - Client not found.
if (rc != 0) {
deb_printf("Error: luaSerSendChar()", "vcomWrite():rc: %d \r\n", rc);
lua_pushnil(L);
lua_pushnumber(L, rc); /* push result */
return 2;
}
// Completed
lua_pushliteral( L, "ok");
return 1;
}
#endif
static int luaSerWrite(lua_State *L) {
deb_printf("luaSerWrite()", " my stack: ");
// displayStack(L);
size_t len;
port_data* cfPtr = check_serdev(L, 1);
const char * Data = luaL_tolstring(L, 2, &len);
int32 rc;
// Validate
int8 serport = cfPtr->handle;
if (serport < 0 || serport > SERPORT_MAX) {
deb_printf("Error: luaSerWrite()", "serport out of range: %d \r\n",
serport);
lua_pushnumber(L, serport); /* push result */
return 1;
}
deb_printf("LUA", "Write string (%d), %s", len, Data);
// Write string
// when serport + 1 write() returns nil, when serport - 1 also nil
rc = vcomWrite(serport, (unsigned char*) Data, len);
if (rc != 0) {
deb_printf("Error: luaSerWrite()", "vcomWrite():rc: %d \r\n", rc);
lua_pushnil(L);
lua_pushnumber(L, rc); /* push result */
return 2;
}
// Completed
lua_pushliteral(L, "ok");
return 1;
}
// Flushes pending data
// to check the flush command I need first the size of the buffer
static int luaSerFlush(lua_State *L) {
struct port_data* cfPtr = check_serdev(L, 1);
int8 serport = cfPtr->handle;
if (serport < 0 || serport > SERPORT_MAX) {
lua_pushnil(L);
lua_pushstring(L, "Error: luaSerFlush(). Illegal serial device.");
return 2; // Validate
}
// Var
int32 rc;
// Flush receive buffer
rc = vcomSetRegister(serport, VCOM_REG_RCVBUF, 0);
if (rc != 0) {
deb_printf("Error: luaSerFlush()", "vcomSetRegister():rc: %d \r\n", rc);
lua_pushnil(L);
lua_pushnumber(L, rc); /* push result */
return 2;
}
// Completed
lua_pushliteral(L, "ok");
return 1;
}
// Return values
// 1.#boolean: state
// 2.#nil: Illegal #serdev
// the RTS and CTS are turned off and on from alternate ends to control data flow,
// for instance when a buffer is almost full.
static int luaSerGetCTS(lua_State *L) {
int32 rc;
struct port_data* cfPtr = check_serdev(L, 1);
// SerGetCTS
int8 serport = cfPtr->handle;
if (serport < 0 || serport > SERPORT_MAX) {
lua_pushnil(L);
lua_pushstring(L, "Error: luaSerGetCTS(). Illegal serial device.");
return 2; // Validate
}
rc = vcomGetRegister(serport, VCOM_REG_UART_CTS);
lua_pushnumber(L, rc); /* push result */
return 1;
}
// serialvplif.c line: 440
// serdev:setRTS(state)
// Parameter
// #boolean state :
// Return values
// 1.#integer: 0 for ok
// 2.#nil: Illegal #serdev
static int luaSerSetRTS(lua_State *L) {
int32 rc;
struct port_data* cfPtr = check_serdev(L, 1);
int state = lua_toboolean(L, 2);
// SerSetRTS
int8 serport = cfPtr->handle;
if (serport < 0 || serport > SERPORT_MAX) {
lua_pushnil(L);
lua_pushstring(L, "Error: luaSerSetRTS(). Illegal serial device.");
return 2;
}
// bool myState = lua_toboolean(L, 1);
//cfPtr->state = lua_toboolean(L, 1);
rc = vcomSetRegister(serport, VCOM_REG_UART_RTS, state);
lua_pushnumber(L, 0); /* push result */
return 1;
}
static int luaSerGC(lua_State *L) {
struct port_data* cfPtr = check_serdev(L, 1);
vcomClose(cfPtr->handle);
return 0;
}
static int luaSerToString(lua_State *L) {
struct port_data* port_data;
port_data = check_serdev(L, 1); // get the address of userdata
lua_pushfstring(L,
cfMetaTab " (%d, %d, %d, %d, %d, %d, %d)", port_data->handle,
port_data->baud, port_data->handshake, port_data->bit,
port_data->stop, port_data->parity, port_data->rs485);
return 1;
}
// luaL_Reg to struct z dwoma polami: const char *name i lua_CFunction func;
// https://github.com/brimworks/lua-ev
// http://stackoverflow.com/questions/12058186/how-do-i-extend-lua-with-a-static-c-library
LUALIB_API int luaopen_serlib(lua_State *L) {
// metamethods
static const luaL_Reg MetaMap[] =
{
{ "__tostring", luaSerToString },
{ "__gc", luaSerGC },
{ "bufferLevel", NULL },
{ "close", luaSerClose },
{ "configure", luaSerSetConfigTable },
{ "flush", luaSerFlush },
{ "frameConfig", NULL },
{ "getCTS", luaSerGetCTS },
{ "read", NULL },
{ "setRTS", luaSerSetRTS },
{ "write", luaSerWrite },
{ NULL, NULL }
};
static const luaL_Reg Map[] = { { "open", luaSerOpen }, { NULL, NULL } };
lua_pop(L, 1);
luaL_newlib(L, Map);
luaL_newmetatable(L, cfMetaTab); // Stack: MyLib meta
lua_pushvalue(L, -1); // Push copy of metatable
lua_setfield(L, -2, "__index"); // Stack: MyLib meta
luaL_setfuncs(L, MetaMap, 0);
lua_pop(L, 1);
/* remove _PRELOAD table */
return 1;
}