#include "lupi.h" #include #include #include #include #include #include #include #include #include #include #include #include int s_listports(lua_State * L) { DIR * d = opendir("/sys/class/tty"); struct dirent * ent = NULL; struct stat statbuf; char path[255]; char linkpath[255]; lua_newtable(L); size_t index = 1; while ((ent = readdir(d)) != NULL) { sprintf(path, "/sys/class/tty/%s/device", ent->d_name); if (stat(path, &statbuf) == 0) { readlink(path, linkpath, 255); if (strstr(linkpath, "serial8250") == NULL) { // We have a serial port lua_pushinteger(L, index); lua_pushstring(L, ent->d_name); lua_settable(L, -3); } } } return 1; } struct baudrate { uint32_t baud; tcflag_t flags; }; // taken from here: https://man7.org/linux/man-pages/man3/termios.3.html struct baudrate baudrates[] = { {0, B0}, {50, B50}, {75, B75}, {110, B110}, {134, B134}, {150, B150}, {200, B200}, {300, B300}, {600, B600}, {1200, B1200}, {1800, B1800}, {2400, B2400}, {4800, B4800}, {9600, B9600}, {19200, B19200}, {38400, B38400}, {57600, B57600}, {115200, B115200}, {230400, B230400} }; struct baudrate * getbaud(uint32_t baud) { for (size_t i=0; i baud) { return &baudrates[i-1]; } } return getbaud(230400); } struct sport { uint32_t baudrate; int fd; struct termios options; }; int s_openport(lua_State * L) { char * path = luaL_checkstring(L, 1); struct sport * port = lua_newuserdata(L, sizeof(struct sport)); port->baudrate = 9600; char rpath[255]; sprintf(rpath, "/dev/%s", path); port->fd = open(rpath, O_RDWR | O_NOCTTY | O_NDELAY | O_NONBLOCK); if (port->fd == -1) luaL_error(L, "unable to open port %s: ", path, strerror(errno)); tcgetattr(port->fd, &port->options); cfsetispeed(&port->options, B9600); cfsetospeed(&port->options, B9600); tcsetattr(port->fd, TCSANOW, &port->options); return 1; } int s_setbaudrate(lua_State * L) { struct sport * port = lua_touserdata(L, 1); long raw_br = luaL_checkinteger(L, 2); struct baudrate * br = getbaud(raw_br & 0xFFFFFFFF); //port->options.c_cflag &= ~(CBAUD); //port->options.c_cflag |= br->flags; cfsetispeed(&port->options, br->flags); cfsetospeed(&port->options, br->flags); port->baudrate = br->baud; lua_pushinteger(L, br->baud); port->options.c_cflag &= ~PARENB; port->options.c_cflag &= ~CSTOPB; port->options.c_cflag &= ~CSIZE; port->options.c_cflag |= CS8; tcsetattr(port->fd, TCSANOW, &port->options); return 1; } int s_getbaudrate(lua_State * L) { struct sport * port = lua_touserdata(L, 1); lua_pushinteger(L, port->baudrate); return 1; } int s_write(lua_State * L) { struct sport * port = lua_touserdata(L, 1); size_t len = 0; char * data = luaL_checklstring(L, 2, &len); size_t ioc = 0; if ((ioc = write(port->fd, data, len)) != len) { luaL_error(L, "io error! %llu != %llu", ioc, len); } return 0; } int s_read(lua_State * L) { struct sport * port = lua_touserdata(L, 1); char buffer[2048]; // Max packet size long size = luaL_checkinteger(L, 2); size_t ioc = read(port->fd, buffer, size); if (ioc != size && ioc != 0) { luaL_error(L, "io error! %llu != %llu or 0", ioc, size); } else if (ioc != 0) { lua_pushlstring(L, buffer, size); return 1; } return 0; } void serial_start(lua_State * L) { struct luaL_Reg seriallib[] = { {"open", s_openport}, {"list", s_listports}, {"write", s_write}, {"read", s_read}, {"setbaud", s_setbaudrate}, {"getbaud", s_getbaudrate}, {NULL, NULL} }; luaL_openlib(L, "serial", seriallib, 0); }