rp2040

RP2040 Programming without SDK
Log | Files | Refs

main.go (2373B)


      1 package main
      2 
      3 import (
      4 	"fmt"
      5 	"io"
      6 	"log"
      7 
      8 	"golang.org/x/sys/unix"
      9 )
     10 
     11 const ttyFile = "/dev/ttyU0"
     12 
     13 func main() {
     14 	fd, err := device_open(ttyFile)
     15 	if err != nil {
     16 		log.Fatal(err)
     17 	}
     18 	defer unix.Close(fd)
     19 	if err = setparms(fd, 115200); err != nil {
     20 		log.Fatal(err)
     21 	}
     22 	if err = flush(fd); err != nil {
     23 		log.Fatal(err)
     24 	}
     25 
     26 	go reader(fd)
     27 	writer(fd)
     28 }
     29 
     30 func reader(fd int) {
     31 	buf := make([]byte, 64)
     32 	for {
     33 		n, err := unix.Read(fd, buf)
     34 		if err == io.EOF {
     35 			break
     36 		} else if err != nil {
     37 			log.Printf("read from tty: %v", err)
     38 			break
     39 		}
     40 		log.Printf("read from tty: %q", buf[:n])
     41 		_, err = unix.Write(unix.Stdout, buf[:n])
     42 		if err != nil {
     43 			log.Printf("write to stdout: %v", err)
     44 			break
     45 		}
     46 	}
     47 }
     48 
     49 func writer(fd int) {
     50 	buf := make([]byte, 64)
     51 	for {
     52 		n, err := unix.Read(unix.Stdin, buf)
     53 		if n == 0 || err == io.EOF {
     54 			break
     55 		} else if err != nil {
     56 			log.Printf("read from stdin: %v", err)
     57 			break
     58 		}
     59 		log.Printf("from terminal: %q", buf[:n])
     60 		_, err = unix.Write(fd, buf[:n])
     61 		if err != nil {
     62 			log.Printf("write to tty: %v", err)
     63 			break
     64 		}
     65 	}
     66 }
     67 
     68 func device_open(path string) (fd int, err error) {
     69 	fd, err = unix.Open(path, unix.O_RDWR|unix.O_NDELAY|unix.O_NOCTTY, 0)
     70 	if err != nil {
     71 		return 0, fmt.Errorf("open: %w", err)
     72 	}
     73 	defer func() {
     74 		if err != nil {
     75 			unix.Close(fd)
     76 		}
     77 	}()
     78 	n, err := unix.FcntlInt(uintptr(fd), unix.F_GETFL, 0)
     79 	if err != nil {
     80 		return 0, fmt.Errorf("getfl: %w", err)
     81 	}
     82 	_, err = unix.FcntlInt(uintptr(fd), unix.F_SETFL, n&^unix.O_NDELAY)
     83 	if err != nil {
     84 		return 0, fmt.Errorf("setfl: %w", err)
     85 	}
     86 	return fd, nil
     87 }
     88 
     89 func setparms(fd int, baud int32) error {
     90 	tty, err := unix.IoctlGetTermios(fd, unix.TIOCGETA)
     91 	if err != nil {
     92 		return fmt.Errorf("gettermios: %w", err)
     93 	}
     94 	tty.Iflag = unix.IGNBRK
     95 	tty.Iflag &= ^(uint32(unix.IXON) | uint32(unix.IXOFF) | uint32(unix.IXANY))
     96 	tty.Oflag = 0
     97 	tty.Cflag = (tty.Cflag &^ unix.CSIZE) | unix.CS8
     98 	tty.Cflag |= unix.CLOCAL | unix.CREAD
     99 	tty.Cflag &= ^uint32(unix.CSTOPB)
    100 	tty.Lflag = 0
    101 	tty.Cc[unix.VMIN] = 1
    102 	tty.Cc[unix.VTIME] = 5
    103 	tty.Ispeed = baud
    104 	tty.Ospeed = baud
    105 	err = unix.IoctlSetTermios(fd, unix.TIOCSETA, tty)
    106 	if err != nil {
    107 		return fmt.Errorf("settermios: %w", err)
    108 	}
    109 	return nil
    110 }
    111 
    112 func flush(fd int) error {
    113 	_, err := unix.IoctlGetInt(fd, unix.TIOCFLUSH)
    114 	if err != nil {
    115 		return fmt.Errorf("tiocflush: %w", err)
    116 	}
    117 	return nil
    118 }