commit 6bad484a354ed430735733a969df3aa663e2c0b0
parent 5a718f4e0005fd215cf4362025175a187e26cdaa
Author: Matsuda Kenji <info@mtkn.jp>
Date:   Mon, 25 Aug 2025 08:53:32 +0900
add cons written in go
Diffstat:
3 files changed, 125 insertions(+), 0 deletions(-)
diff --git a/consgo/go.mod b/consgo/go.mod
@@ -0,0 +1,5 @@
+module cons
+
+go 1.24.1
+
+require golang.org/x/sys v0.35.0
diff --git a/consgo/go.sum b/consgo/go.sum
@@ -0,0 +1,2 @@
+golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=
+golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
diff --git a/consgo/main.go b/consgo/main.go
@@ -0,0 +1,118 @@
+package main
+
+import (
+	"fmt"
+	"io"
+	"log"
+
+	"golang.org/x/sys/unix"
+)
+
+const ttyFile = "/dev/ttyU0"
+
+func main() {
+	fd, err := device_open(ttyFile)
+	if err != nil {
+		log.Fatal(err)
+	}
+	defer unix.Close(fd)
+	if err = setparms(fd, 115200); err != nil {
+		log.Fatal(err)
+	}
+	if err = flush(fd); err != nil {
+		log.Fatal(err)
+	}
+
+	go reader(fd)
+	writer(fd)
+}
+
+func reader(fd int) {
+	buf := make([]byte, 64)
+	for {
+		n, err := unix.Read(fd, buf)
+		if err == io.EOF {
+			break
+		} else if err != nil {
+			log.Printf("read from tty: %v", err)
+			break
+		}
+		log.Printf("read from tty: %q", buf[:n])
+		_, err = unix.Write(unix.Stdout, buf[:n])
+		if err != nil {
+			log.Printf("write to stdout: %v", err)
+			break
+		}
+	}
+}
+
+func writer(fd int) {
+	buf := make([]byte, 64)
+	for {
+		n, err := unix.Read(unix.Stdin, buf)
+		if n == 0 || err == io.EOF {
+			break
+		} else if err != nil {
+			log.Printf("read from stdin: %v", err)
+			break
+		}
+		log.Printf("from terminal: %q", buf[:n])
+		_, err = unix.Write(fd, buf[:n])
+		if err != nil {
+			log.Printf("write to tty: %v", err)
+			break
+		}
+	}
+}
+
+func device_open(path string) (fd int, err error) {
+	fd, err = unix.Open(path, unix.O_RDWR|unix.O_NDELAY|unix.O_NOCTTY, 0)
+	if err != nil {
+		return 0, fmt.Errorf("open: %w", err)
+	}
+	defer func() {
+		if err != nil {
+			unix.Close(fd)
+		}
+	}()
+	n, err := unix.FcntlInt(uintptr(fd), unix.F_GETFL, 0)
+	if err != nil {
+		return 0, fmt.Errorf("getfl: %w", err)
+	}
+	_, err = unix.FcntlInt(uintptr(fd), unix.F_SETFL, n&^unix.O_NDELAY)
+	if err != nil {
+		return 0, fmt.Errorf("setfl: %w", err)
+	}
+	return fd, nil
+}
+
+func setparms(fd int, baud int32) error {
+	tty, err := unix.IoctlGetTermios(fd, unix.TIOCGETA)
+	if err != nil {
+		return fmt.Errorf("gettermios: %w", err)
+	}
+	tty.Iflag = unix.IGNBRK
+	tty.Iflag &= ^(uint32(unix.IXON) | uint32(unix.IXOFF) | uint32(unix.IXANY))
+	tty.Oflag = 0
+	tty.Cflag = (tty.Cflag &^ unix.CSIZE) | unix.CS8
+	tty.Cflag |= unix.CLOCAL | unix.CREAD
+	tty.Cflag &= ^uint32(unix.CSTOPB)
+	tty.Lflag = 0
+	tty.Cc[unix.VMIN] = 1
+	tty.Cc[unix.VTIME] = 5
+	tty.Ispeed = baud
+	tty.Ospeed = baud
+	err = unix.IoctlSetTermios(fd, unix.TIOCSETA, tty)
+	if err != nil {
+		return fmt.Errorf("settermios: %w", err)
+	}
+	return nil
+}
+
+func flush(fd int) error {
+	_, err := unix.IoctlGetInt(fd, unix.TIOCFLUSH)
+	if err != nil {
+		return fmt.Errorf("tiocflush: %w", err)
+	}
+	return nil
+}