CraftDuino v2.0
  • - это CraftDuino - наш вариант полностью Arduino-совместимой платы.
  • CraftDuino - настоящий конструктор, для очень быстрого прототипирования и реализации идей.
  • Любая возможность автоматизировать что-то с лёгкостью реализуется с CraftDuino!
Просто добавьте CraftDuino!

Lua - модуль для работы с последовательным портом



Напишем модуль Lua для работы с последовательным портом:

Возьмём за основу старый исходник для проброса последовательного порта в сокет — suart. Почитаем про магию метатаблиц Lua и получим простой тестовый модуль.

myserial.c

//
// serial library for use in Lua
//
// compile:
// $(CC) -shared -fPIC -I./lua-5.2.1/src -o myserial.so myserial.c
//
// mips-openwrt-linux-gcc myserial.c -shared -fpic -I./lua-5.2.1/src -o myserial.so
//

#include <stdio.h>
#include <stdlib.h>

#include <unistd.h> 	// UNIX standard function definitions
#include <fcntl.h> 		// File control definitions
#include <errno.h> 		// Error number definitions
#include <termios.h> 	// POSIX terminal control definitions

# include <sys/select.h>
# include <sys/ioctl.h>

#ifdef __cplusplus
extern "C" {
#endif

#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"

#ifdef __cplusplus
}
#endif

#define LUA_MYSERIAL          "myserial"

typedef struct luaL_Serial {
    int fd;                 // serial port file descriptor
    char port_name[32]; 	// serial port name
    speed_t baudrate;       // serial port Baudrate
    int rate;
    struct termios options;

} luaL_Serial;

typedef luaL_Serial LSerial;

#define tomyserial(L)	((LSerial *)luaL_checkudata(L, 1, LUA_MYSERIAL))
//#define tomyserial(L)	((LSerial *)lua_touserdata(L, 1))

// open serial port
static int myserial_open(LSerial *s)
{

    if(!s)
        return -1;

    if(s->rate==9600) {
        s->baudrate=B9600;
    }
    else if(s->rate==19200) {
        s->baudrate=B19200;
    }
    else if(s->rate==38400) {
        s->baudrate=B38400;
    }
    else if(s->rate==57600) {
        s->baudrate=B57600;
    }
    else if(s->rate==115200) {
        s->baudrate=B115200;
    }
    else {
        printf("[!] Error: bad baudrate: %d!\n", s->rate);
        return -1;
    }

    printf("[i] open: %s %d!\n", s->port_name, s->rate);
    s->fd = open(s->port_name, O_RDWR | O_NOCTTY | O_NONBLOCK);
    if (s->fd == -1) {
        printf("[!] Error: Unable to open serial port: %s\n", s->port_name);
        return -1;
    }
    else {
        fcntl(s->fd, F_SETFL, 0);

        tcgetattr(s->fd, &(s->options));
        memset(&(s->options), 0, sizeof(s->options)); //cfmakeraw(&options);

        //----------------------------------------------------------------------------------------------------------------
        // c_cflag
        s->options.c_cflag |= CS8;
        s->options.c_cflag &= ~PARENB;
        s->options.c_cflag &= ~CSTOPB;
        s->options.c_cflag |= CREAD; // Enable Receiver
        s->options.c_cflag |= CLOCAL; // Ignore modem control lines.

        //cfsetispeed(&options, baudrate);
        //cfsetospeed(&options, baudrate);
        s->options.c_cflag&=(~CBAUD);
        s->options.c_cflag |= s->baudrate;
        //options.c_ispeed = baudrate;
        //options.c_ospeed = baudrate;

        tcsetattr(s->fd, TCSAFLUSH, &(s->options));
        //tcflush(tty_fd, TCIOFLUSH);
    }

    return 0;
}

// create serial object by open port
static int ser_open(lua_State *L)
{
    printf("[i] ser_open()\n");
    const char *filename = luaL_checkstring(L, 1);  // first param - dev name
    int rate = (int)luaL_checknumber(L, 2);         // second param - baudrate

    LSerial *s = (LSerial *)lua_newuserdata(L, sizeof(LSerial));

    luaL_getmetatable(L, LUA_MYSERIAL);
    lua_setmetatable(L, -2);

    if(s) {
        s->fd = -1;
        s->rate = rate;
    }
    if(filename) {
        strncpy(s->port_name, filename, sizeof(s->port_name));
        myserial_open(s);
    }

    return 1;  // new userdatum is already on the stack
}

// open method for myserial object
static int serial_open(lua_State *L)
{
    printf("[i] serial_open()\n");
    LSerial *s = tomyserial(L);                     // object
    const char *filename = luaL_checkstring(L, 2);  // first param - dev name
    int rate = (int)luaL_checknumber(L, 3);         // second param - baudrate

    int res = -1;

    if( filename && s) {
        s->rate = rate;
        strncpy(s->port_name, filename, sizeof(s->port_name));
        res = myserial_open(s);
    }

    lua_pushinteger(L, res);
    return 1;
}

// close method for myserial object
static int serial_close(lua_State *L)
{
    printf("[i] serial_close()\n");
    LSerial *s = tomyserial(L); // object
    if(s) {
        if(s->fd>0) {
            close(s->fd);
            s->fd = -1;
        }
    }
    return 0;
}

static int serial_write(lua_State *L)
{
    printf("[i] serial_write()\n");

    LSerial *s = tomyserial(L); // object
    int res = 0; // number of bytes sent

    if(s && s->fd>0) {
        if(lua_isstring(L, 2)) {
            size_t dlen;
            char *data = (char *)lua_tolstring(L, 2, &dlen);
            if (dlen > 0) {
                res = write(s->fd, data, dlen);
            }
        }
        else if(lua_isnumber(L, 2)) {
            char data = (char)luaL_checknumber(L, 2);
            res = write(s->fd, &data, sizeof(data));
        }
    }
    lua_pushinteger(L, res);
    return 1;
}

static int serial_read(lua_State *L)
{
    printf("[i] serial_read()\n");

    LSerial *s = tomyserial(L); // object
    int size = (int)luaL_checknumber(L, 2);
    int res = 0;

    char *data = NULL;
    if(s && s->fd>0 && size>0) {
        data = malloc(size);
        if(data) {
            res = read(s->fd, data, size);
        }
        else {
            printf("[!] Error: cant allocate memory!\n");
        }
    }
    lua_pushlstring(L, data, res);
    // free allocated buffer
    if (data)
        free(data);
    return 1;
}

static int serial_wait(lua_State *L)
{
    LSerial *s = tomyserial(L); // object
    int msec = (int)luaL_checknumber(L, 2);

    int res = 0;

    if(s && s->fd>0) {

        fd_set rfds;
        struct timeval tv;
        tv.tv_sec = msec / 1000;
        tv.tv_usec = (msec % 1000) * 1000;

        if( tv.tv_usec > 1000000 ){
            tv.tv_sec++;
            tv.tv_usec -= 1000000;
        }

        FD_ZERO(&rfds);
        FD_SET(s->fd, &rfds);
        res = select(s->fd+1, &rfds, NULL, NULL, &tv);
    }

    lua_pushinteger(L, res);
    return 1;
}

static int serial_available(lua_State *L)
{
    printf("[i] serial_available()\n");
    LSerial *s = tomyserial(L); // object
    int res = 0;

    if(s && s->fd>0) {
         ioctl(s->fd, FIONREAD, &res);
    }

    lua_pushinteger(L, res);
    return 1;
}

// special methods for metatable
static int ser_gc (lua_State *L) {
    printf("[i] serial GC!\n");
    return serial_close(L);
}

static int ser_tostring (lua_State *L) {
  LSerial *s = tomyserial(L); // object
  if(s) {
    if (s->fd>0)
        lua_pushfstring(L, "serial (%s %d)", s->port_name, s->rate);
    else
        lua_pushliteral(L, "serial (closed)");
  }
  return 1;
}

// functions for 'myserial' library
static const struct luaL_Reg myseriallib_m[] =
{
    {"open", serial_open},
    {"close", serial_close},
    {"write", serial_write},
    {"read", serial_read},
    {"wait", serial_wait},
    {"available", serial_available},
    {"__gc", ser_gc},
    {"__tostring", ser_tostring},
    {NULL, NULL}
};

// methods
static const struct luaL_Reg myseriallib_f[] = {
    {"open", ser_open},
    {NULL, NULL}
};

LUAMOD_API int luaopen_myserial (lua_State *L)
{
    //luaL_openlib(L, "myserial", myseriallib, 0);
#if 0
    luaL_newlib(L, myseriallib_m);  // new module
    // createmeta
    luaL_newmetatable(L, LUA_MYSERIAL);  // create metatable for file handles
    lua_pushvalue(L, -1);  // push metatable
    lua_setfield(L, -2, "__index");  // metatable.__index = metatable
    luaL_setfuncs(L, myseriallib_f, 0);  // add file methods to new metatable
    lua_pop(L, 1);  // pop new metatable
#else

    luaL_newmetatable(L, LUA_MYSERIAL);

    lua_pushstring(L, "__index");
    lua_pushvalue(L, -2);  /* pushes the metatable */
    lua_settable(L, -3);  /* metatable.__index = metatable */

    luaL_openlib(L, NULL, myseriallib_m, 0);

    luaL_openlib(L, LUA_MYSERIAL, myseriallib_f, 0);

#endif
    return 1;
}


собираем
mips-openwrt-linux-gcc myserial.c -shared -fpic -I./lua-5.2.1/src -o myserial.so

заливаем
scp myserial.so root@192.168.217.1:/root/

пишем тестовый скрипт

callmyserial.lua

-- test myserial

print("start lua...");

require('myserial');

serial = myserial.open("/dev/ttyATH0", 9600);
print(serial);

res = serial:write('A');
print(res);

serial:close();
print(serial);
print(serial.open);

res = serial:open("/dev/ttyUSB0", 9600);
print(res);

res = serial:write('A');
print(res);

while 1 do
	if serial:wait(100000) > 0 then
		res = serial:available();
		print(res);
		data = serial:read(res);
		print(data);
	end
end

print("end lua...");


scp callmyserial.lua root@192.168.217.1:/root/

тестируем, нажимая в терминале клавишу q

# ./lua ./callmyserial.lua
start lua...
[i] ser_open()
[i] open: /dev/ttyATH0 9600!
serial (/dev/ttyATH0 9600)
[i] serial_write()
1
[i] serial_close()
serial (closed)
function: 0x76f42230
[i] serial_open()
[i] open: /dev/ttyUSB0 9600!
0
[i] serial_write()
1
[i] serial_available()
1
[i] serial_read()
q
^C./lua: ./callmyserial.lua:24: interrupted!
stack traceback:
        [C]: in function 'wait'
        ./callmyserial.lua:24: in main chunk
        [C]: in ?
[i] serial GC!
[i] serial_close()


Супер! Теперь этот модуль можно взять за основу для Lua-изации своих роботов и прочих автоматов :)

Ссылки:
www.lua.org

По теме:
Использование Lua в робототехнике
Исследование Wi-Fi-роутера TP-LINK TL-MR3020
Кросс-компиляция Lua для TP-LINK TL-MR3020
Превращаем ADSL-модем в Ethernet-шилд для Arduino/CraftDuino
  • 0
  • 5 января 2013, 13:38
  • noonv

Комментарии (0)

RSS свернуть / развернуть

Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.