Drives and serial. #3
155
src/c/blkdev.c
Normal file
155
src/c/blkdev.c
Normal file
@ -0,0 +1,155 @@
|
||||
#include "lupi.h"
|
||||
#include <lua.h>
|
||||
#include <lualib.h>
|
||||
#include <lauxlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/hdreg.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
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);
|
||||
}
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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");
|
||||
|
159
src/c/serial.c
Normal file
159
src/c/serial.c
Normal file
@ -0,0 +1,159 @@
|
||||
#include "lupi.h"
|
||||
#include <lua.h>
|
||||
#include <lualib.h>
|
||||
#include <lauxlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <dirent.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <termios.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
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<sizeof(baudrates)/sizeof(struct baudrate); ++i) {
|
||||
if (baudrates[i].baud == baud) {
|
||||
return &baudrates[i];
|
||||
} else if (baudrates[i].baud > 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);
|
||||
}
|
@ -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
|
||||
|
59
src/lua/core/drive.lua
Normal file
59
src/lua/core/drive.lua
Normal file
@ -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
|
@ -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()
|
||||
|
32
src/lua/core/serial.lua
Normal file
32
src/lua/core/serial.lua
Normal file
@ -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
|
Loading…
Reference in New Issue
Block a user