~xdavidwu/motion-control

1c5252b7b0e308fedf13550d3956b5470dcf4a2b — xdavidwu 2 years ago 40d3123
add pointer controlling over udp
5 files changed, 142 insertions(+), 2 deletions(-)

M .gitignore
M Makefile
A cmd/pointerd/main.ha
A proto/control/types.ha
A tools/pointerc/main.ha
M .gitignore => .gitignore +2 -0
@@ 1,3 1,5 @@
/evdev-dump-events
/uinput-pointer
/gy-801-dump
/pointerc
/pointerd

M Makefile => Makefile +4 -2
@@ 1,5 1,7 @@
evdev-dump-events uinput-pointer:
evdev-dump-events uinput-pointer pointerc:
	hare build -levdev -o $@ tools/$@/
gy-801-dump:
	hare build -o $@ tools/$@/
.PHONY: evdev-dump-events uinput-pointer gy-801-dump
pointerd:
	hare build -levdev -o $@ cmd/$@/
.PHONY: evdev-dump-events uinput-pointer gy-801-dump pointerd pointerc

A cmd/pointerd/main.ha => cmd/pointerd/main.ha +58 -0
@@ 0,0 1,58 @@
use evdev;
use evdev::uinput;
use fmt;
use io;
use net;
use net::ip;
use net::udp;
use proto::control;
use rt;
use time;

export fn main() void = {
	const evdev = evdev::new();
	defer evdev::destroy(evdev);
	evdev::set_name(evdev, "motion-control pointer");
	evdev::enable_event_type(evdev, evdev::EV_REL)!;
	evdev::enable_event_code(evdev, evdev::EV_REL, evdev::REL_X, null)!;
	evdev::enable_event_code(evdev, evdev::EV_REL, evdev::REL_Y, null)!;
	evdev::enable_event_type(evdev, evdev::EV_KEY)!;
	evdev::enable_event_code(evdev, evdev::EV_KEY, evdev::BTN_LEFT, null)!;
	evdev::enable_event_code(evdev, evdev::EV_KEY, evdev::BTN_MIDDLE, null)!;
	evdev::enable_event_code(evdev, evdev::EV_KEY, evdev::BTN_RIGHT, null)!;

	const uinput = match (uinput::create_from_device(evdev, uinput::OPEN_MANAGED)) {
	case let uinput: uinput::uinput =>
		yield uinput;
	case let err: rt::errno =>
		fmt::fatalf("Failed to create uinput dev: {}", rt::strerror(err));
	};
	defer uinput::destroy(uinput);

	const addr = ip::ANY_V6, port = control::DEFAULT_PORT;
	const sock = match(udp::listen(addr, port)) {
	case let sock: io::file =>
		yield sock;
	case let err: net::error =>
		fmt::fatalf("Failed to listen on {}:{}: {}",
			ip::string(addr), port, net::strerror(err));
	};
	defer io::close(sock)!;

	let buf = control::request {...};
	for (true) {
		const sz = udp::recvfrom(sock, buf.bytes, null, null)!;
		if (sz != size(control::request)) {
			fmt::errorln("Unexpected read size")!;
			continue;
		};
		switch (buf.code) {
		case control::code::RELATIVE_MOVEMENT =>
			uinput::write_event(uinput, evdev::EV_REL, evdev::REL_X, buf.x)!;
			uinput::write_event(uinput, evdev::EV_REL, evdev::REL_Y, buf.y)!;
			uinput::write_event(uinput, evdev::EV_SYN, evdev::SYN_REPORT, 0)!;
		case =>
			fmt::errorfln("Unrecognized control code: {}", buf.code)!;
		};
	};
};

A proto/control/types.ha => proto/control/types.ha +18 -0
@@ 0,0 1,18 @@
export def DEFAULT_PORT: u16	= 0x519;

export type code = enum u8 {
	RELATIVE_MOVEMENT	= 0,
};

export type request = union {
	struct {
		code: u8,
		union {
			struct {
				x: i8,
				y: i8,
			},
		},
	},
	bytes: [3]u8,
};

A tools/pointerc/main.ha => tools/pointerc/main.ha +60 -0
@@ 0,0 1,60 @@
use fmt;
use io;
use net;
use net::ip;
use net::udp;
use os;
use proto::control;
use strconv;

export fn main() int = {
	if (len(os::args) != 5) {
		fmt::fatalf("Usage: {} addr port x y", os::args[0]);
	};
	const addr = match (ip::parse(os::args[1])) {
	case let addr: ip::addr =>
		yield addr;
	case ip::invalid =>
		fmt::fatalf("Invalid address {}", os::args[1]);
	};
	const port = match (strconv::stou16(os::args[2])) {
	case let port: u16 =>
		yield port;
	case =>
		fmt::fatalf("Invalid port {}", os::args[2]);
	};
	const x = match (strconv::stoi8(os::args[3])) {
	case let n: i8 =>
		yield n;
	case =>
		fmt::fatalf("Invalid x {}", os::args[3]);
	};
	const y = match (strconv::stoi8(os::args[4])) {
	case let n: i8 =>
		yield n;
	case =>
		fmt::fatalf("Invalid y {}", os::args[4]);
	};

	const buf = control::request {
		code = control::code::RELATIVE_MOVEMENT,
		x = x,
		y = y,
	};

	const sock = match (udp::connect(addr, port)) {
	case let s: io::file =>
		yield s;
	case let err: net::error =>
		fmt::fatalf("Cannot connect() {}:{}: {}", ip::string(addr), port, net::strerror(err));
	};
	defer io::close(sock)!;

	match (udp::send(sock, buf.bytes)) {
	case let err: net::error =>
		fmt::fatalf("Cannot send(): {}", net::strerror(err));
	case size =>
		yield;
	};
	return 0;
};