From f2436f8aa565aec619b5d0d9f08677e74ffb741e Mon Sep 17 00:00:00 2001 From: sam <30084950+lunaboards-dev@users.noreply.github.com> Date: Sat, 29 May 2021 17:18:55 -0400 Subject: [PATCH] Drives and serial. --- src/c/blkdev.c | 155 ++++++++++++++++++++++++++++++++++++ src/c/init.c | 1 + src/c/modules.c | 2 + src/c/run.c | 2 + src/c/serial.c | 159 +++++++++++++++++++++++++++++++++++++ src/lua/core/component.lua | 2 +- src/lua/core/drive.lua | 59 ++++++++++++++ src/lua/core/init.lua | 9 ++- src/lua/core/serial.lua | 32 ++++++++ 9 files changed, 419 insertions(+), 2 deletions(-) create mode 100644 src/c/blkdev.c create mode 100644 src/c/serial.c create mode 100644 src/lua/core/drive.lua create mode 100644 src/lua/core/serial.lua diff --git a/src/c/blkdev.c b/src/c/blkdev.c new file mode 100644 index 0000000..1a50054 --- /dev/null +++ b/src/c/blkdev.c @@ -0,0 +1,155 @@ +#include "lupi.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct blkdev { + int fd; + int secsize; + int platters; + size_t size; + char * buffer; +}; + +int blk_open(lua_State * L) { + char * path = luaL_checkstring(L, 1); + char rpath[255]; + sprintf(rpath, "/dev/%s", path); + int fd = open(rpath, O_RDWR | O_DSYNC); + if (fd == -1) { + luaL_error(L, "Failed to open %s: %s", rpath, strerror(errno)); + } + struct blkdev * dev = lua_newuserdata(L, sizeof(struct blkdev)); + dev->fd = fd; + struct hd_driveid driveid; + if (ioctl(fd, HDIO_GET_IDENTITY, &driveid) < 0) { + //luaL_error("Failed to get identity for %s", rpath); + dev->platters = 3; + // Use another ioctl call to get sector size. + if (!ioctl(fd, BLKSSZGET, &dev->secsize)) { + // Fuck it, i guess it's 512 bytes. + dev->secsize = 512; + // Maybe a warning here? + } + dev->size = lseek(fd, 0, SEEK_END); + lseek(fd, 0, SEEK_SET); + } else { + dev->size = driveid.lba_capacity_2*driveid.sector_bytes; + dev->platters = driveid.cur_heads/2; + dev->secsize = driveid.sector_bytes; + if (dev->size == 0) { + dev->size = lseek(fd, 0, SEEK_END); + lseek(fd, 0, SEEK_SET); + } + if (dev->platters == 0) { + dev->platters = 3; + } + if (dev->secsize == 0) { + if (!ioctl(fd, BLKSSZGET, &dev->secsize)) { + // Fuck it, i guess it's 512 bytes. + dev->secsize = 512; + // Maybe a warning here too? + } + } + } + dev->buffer = malloc(dev->secsize); + return 1; +} + +int blk_readbyte(lua_State * L) { + struct blkdev * dev = lua_touserdata(L, 1); + off_t offset = luaL_checkinteger(L, 2); + lseek(dev->fd, offset-1, SEEK_SET); + uint8_t c = 0; + size_t ioc = 0; + if ((ioc = read(dev->fd, &c, 1)) != 1) { + luaL_error(L, "io error! %llu != %llu", ioc, 1); + } + lua_pushinteger(L, c); + return 1; +} + +int blk_writebyte(lua_State * L) { + struct blkdev * dev = lua_touserdata(L, 1); + off_t offset = luaL_checkinteger(L, 2); + long byte = luaL_checkinteger(L, 3); + if (byte > 255 || byte < 0) + luaL_error(L, "%lld is out of range (should be between 0 and 255)", byte); + uint8_t i = byte & 0xFF; + lseek(dev->fd, offset-1, SEEK_SET); + size_t ioc = 0; + if ((ioc = write(dev->fd, &i, 1)) != 1) { + luaL_error(L, "io error! %llu != %llu", ioc, 1); + } + return 0; +} + +int blk_readsector(lua_State * L) { + struct blkdev * dev = lua_touserdata(L, 1); + off_t offset = luaL_checkinteger(L, 2); + lseek(dev->fd, (offset-1)*dev->secsize, SEEK_SET); + size_t ioc = 0; + if ((ioc = read(dev->fd, dev->buffer, dev->secsize)) != dev->secsize) { + luaL_error(L, "io error! %llu != %llu", ioc, dev->secsize); + } + lua_pushlstring(L, dev->buffer, dev->secsize); + return 1; +} + +int blk_writesector(lua_State * L) { + struct blkdev * dev = lua_touserdata(L, 1); + off_t offset = luaL_checkinteger(L, 2); + size_t len = 0; + char * sec = luaL_checklstring(L, 3, &len); + lseek(dev->fd, (offset-1)*dev->secsize, SEEK_SET); + if (len > dev->secsize) { + len = dev->secsize; + } + size_t ioc = 0; + if ((ioc = write(dev->fd, sec, len)) != len) { + luaL_error(L, "io error! %llu != %llu", ioc, dev->secsize); + } + return 0; +} + +int blk_getsecsize(lua_State * L) { + struct blkdev * dev = lua_touserdata(L, 1); + lua_pushinteger(L, dev->secsize); + return 1; +} + +int blk_getsize(lua_State * L) { + struct blkdev * dev = lua_touserdata(L, 1); + lua_pushinteger(L, dev->size); + return 1; +} + +int blk_getplatcount(lua_State * L) { + struct blkdev * dev = lua_touserdata(L, 1); + lua_pushinteger(L, dev->platters); + return 1; +} + +void blk_start(lua_State * L) { + struct luaL_Reg blklib[] = { + {"open", blk_open}, + {"readbyte", blk_readbyte}, + {"writebyte", blk_writebyte}, + {"readsector", blk_readsector}, + {"writesector", blk_writesector}, + {"secsize", blk_getsecsize}, + {"size", blk_getsize}, + {"platcount", blk_getplatcount}, + {NULL, NULL} + }; + luaL_openlib(L, "blk", blklib, 0); +} \ No newline at end of file diff --git a/src/c/init.c b/src/c/init.c index facacd0..6d8bff8 100644 --- a/src/c/init.c +++ b/src/c/init.c @@ -12,6 +12,7 @@ void lupi_init() { mount(NULL, "/sys", "sysfs", 0, NULL); mount(NULL, "/proc", "procfs", 0, NULL); mount(NULL, "/tmp", "tmpfs", 0, NULL); + mount(NULL, "/dev", "devtmpfs", 0, NULL); } struct statvfs fsstat; diff --git a/src/c/modules.c b/src/c/modules.c index 7ca75ea..841fa1f 100644 --- a/src/c/modules.c +++ b/src/c/modules.c @@ -14,12 +14,14 @@ void setup_modules(lua_State *L) { pushstuple(L, "component", lua_component); pushstuple(L, "computer", lua_computer); pushstuple(L, "debug", lua_debug); + pushstuple(L, "drive", lua_drive); pushstuple(L, "eeprom", lua_eeprom); pushstuple(L, "filesystem", lua_filesystem); pushstuple(L, "gpio", lua_gpio); pushstuple(L, "gpudetect", lua_gpudetect); pushstuple(L, "internet", lua_internet); pushstuple(L, "sandbox", lua_sandbox); + pushstuple(L, "serial", lua_serial); pushstuple(L, "textgpu", lua_textgpu); pushstuple(L, "fbgpu", lua_fbgpu); pushstuple(L, "winapigpu", lua_winapigpu); diff --git a/src/c/run.c b/src/c/run.c index 4b91ee2..711099b 100644 --- a/src/c/run.c +++ b/src/c/run.c @@ -31,6 +31,8 @@ void run_init(int argc, char **argv) { #endif fb_start (L); termutils_start (L); + serial_start (L); + blk_start (L); event_prepare(); int status = luaL_loadbuffer(L, lua_init, strlen(lua_init), "=INIT"); diff --git a/src/c/serial.c b/src/c/serial.c new file mode 100644 index 0000000..4ab5a1f --- /dev/null +++ b/src/c/serial.c @@ -0,0 +1,159 @@ +#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); +} \ No newline at end of file diff --git a/src/lua/core/component.lua b/src/lua/core/component.lua index 655f7be..b9eef60 100644 --- a/src/lua/core/component.lua +++ b/src/lua/core/component.lua @@ -109,7 +109,7 @@ function api.invoke(address, method, ...) local msg = tostring((native.uptime() - start) / 1000) .. " [+" .. native.uptime() - last .. "] " .. caller.short_src .. ":".. caller.currentline .. " > c.invoke(" .. address .. "): " .. components[address].type .. "." .. method .. "(" .. table.concat(t, ", ") .. ")" - native.log(msg) + --native.log(msg) end return components[address].rawproxy[method](...) end diff --git a/src/lua/core/drive.lua b/src/lua/core/drive.lua new file mode 100644 index 0000000..f2e6668 --- /dev/null +++ b/src/lua/core/drive.lua @@ -0,0 +1,59 @@ +local drive = {} + +function drive.register() + local list = native.fs_list("/sys/block") + for _, ent in ipairs(list) do + -- Match hard drives. floppy drives, an rewindable tape drives + if (ent:match("sd%a%d*") or ent:match("hd%a%d*") or ent:match("fd%d+") or ent:match("n?st%d+[lma]?") or ent:match("n?ht%d+[lma]?")) then + --if true then + lprint("Attempting to open: "..ent) + local ok, disk = pcall(blk.open, ent) + if ok then + local component = {} + + function component.readByte(offset) + return blk.readbyte(disk, offset) + end + + function component.writeByte(offset, value) + return blk.writebyte(disk, offset, value) + end + + function component.getLabel() + return ent + end + + function component.setLabel(str) + -- stub + return ent + end + + function component.readSector(sec) + return blk.readsector(disk, sec) + end + + function component.writeSector(sec, val) + return blk.writesector(disk, sec, val) + end + + function component.getPlatterCount() + return blk.platcount(disk) + end + + function component.getSectorSize() + return blk.secsize(disk) + end + + function component.getCapacity() + return blk.size(disk) + end + + modules.component.api.register("Block:"..ent, "drive", component) + else + lprint("Can't open blkdev: "..ent..": "..disk) + end + end + end +end + +return drive \ No newline at end of file diff --git a/src/lua/core/init.lua b/src/lua/core/init.lua index 31f0f0a..faba5ba 100644 --- a/src/lua/core/init.lua +++ b/src/lua/core/init.lua @@ -44,6 +44,10 @@ lprint = function (...) end lprint("LuPI L1 INIT") +local ports = serial.list() +for i=1, #ports do + lprint(ports[i]) +end modules = {} deadhooks = {} @@ -90,6 +94,8 @@ function main() loadModule("gpudetect") loadModule("filesystem") loadModule("internet") + loadModule("serial") + loadModule("drive") --Userspace loadModule("sandbox") @@ -99,7 +105,8 @@ function main() modules.component.prepare() modules.computer.prepare() _G.pushEvent = modules.computer.api.pushSignal - + modules.serial.register() + modules.drive.register() modules.eeprom.register() modules.gpio.register() modules.internet.start() diff --git a/src/lua/core/serial.lua b/src/lua/core/serial.lua new file mode 100644 index 0000000..d26552c --- /dev/null +++ b/src/lua/core/serial.lua @@ -0,0 +1,32 @@ +local com = {} + +function com.register() + local ports = serial.list() + for i=1, #ports do + lprint("Serial port: "..ports[i]) + local component = {} + local ok, dev = pcall(serial.open, ports[i]) + if not dev then lprint("Can't open port: "..ports[i]..": "..dev) goto continue end + --lprint(dev) + function component.setBaudRate(baud) + return serial.setbaud(dev, baud) + end + + function component.getBaudRate() + return serial.getbaud(dev) + end + + function component.write(s) + return serial.write(dev, s) + end + + function component.read(amt) + return serial.read(dev, amt) + end + + modules.component.api.register("Serial:"..ports[i], "serial", component) + ::continue:: + end +end + +return com \ No newline at end of file