func setTermSettingsCtsRts(enable bool, settings *syscall.Termios) { if enable { settings.Cflag |= termiosMask(tcCRTSCTS) } else { settings.Cflag &= ^termiosMask(tcCRTSCTS) } }
// Configure configures f as a 8N1 serial port with the specified baudrate. func Configure(f fder, baudrate uint32) error { var termios syscall.Termios if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, uintptr(f.Fd()), uintptr(syscall.TCGETS), uintptr(unsafe.Pointer(&termios))); err != 0 { return err } termios.Ispeed = baudrate termios.Ospeed = baudrate termios.Cflag &^= CBAUD termios.Cflag &^= CBAUDEX termios.Cflag |= baudrate // set 8N1 termios.Cflag &^= syscall.PARENB termios.Cflag &^= syscall.CSTOPB termios.Cflag &^= syscall.CSIZE termios.Cflag |= syscall.CS8 // Local connection, no modem control termios.Cflag |= (syscall.CLOCAL | syscall.CREAD) // Disable hardware flow control termios.Cflag &^= CRTSCTS // Block on a zero read (instead of returning EOF) termios.Cc[syscall.VMIN] = 1 if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, uintptr(f.Fd()), syscall.TCSETS, uintptr(unsafe.Pointer(&termios))); err != 0 { return err } return nil }
func (l *lflagSetter) Set(pty *os.File, termios *syscall.Termios, value uint32) error { if value == 0 { termios.Lflag &^= l.Flag } else { termios.Lflag |= l.Flag } return SetAttr(pty, termios) }
func (i *iflagSetter) Set(pty *os.File, termios *syscall.Termios, value uint32) error { if value == 0 { termios.Iflag &^= i.Flag } else { termios.Iflag |= i.Flag } return TcSetAttr(pty, termios) }
func setTermSettingsDataBits(bits int, settings *syscall.Termios) error { databits, ok := databitsMap[bits] if !ok { return &SerialPortError{code: ERROR_INVALID_PORT_DATA_BITS} } settings.Cflag &= ^termiosMask(syscall.CSIZE) settings.Cflag |= termiosMask(databits) return nil }
// Cfmakeraw modifies attr for raw mode. func Cfmakeraw(attr *syscall.Termios) { attr.Iflag &^= syscall.BRKINT | syscall.ICRNL | syscall.INPCK | syscall.ISTRIP | syscall.IXON attr.Oflag &^= syscall.OPOST attr.Cflag &^= syscall.CSIZE | syscall.PARENB attr.Cflag |= syscall.CS8 attr.Lflag &^= syscall.ECHO | syscall.ICANON | syscall.IEXTEN | syscall.ISIG attr.Cc[syscall.VMIN] = 1 attr.Cc[syscall.VTIME] = 0 }
func setTermSettingsDataBits(bits int, settings *syscall.Termios) error { databits, ok := databitsMap[bits] if !ok { return &PortError{code: InvalidDataBits} } settings.Cflag &= ^termiosMask(syscall.CSIZE) settings.Cflag |= termiosMask(databits) return nil }
// returns non-canonical mode term for keybind func rawModeTerm(term syscall.Termios) syscall.Termios { term.Iflag &= syscall.IGNCR // ignore received CR term.Lflag ^= syscall.ICANON // disable canonical mode term.Lflag ^= syscall.ECHO // disable echo of input term.Lflag ^= syscall.ISIG // disable signal term.Cc[syscall.VMIN] = 1 // number of bytes to read() term.Cc[syscall.VTIME] = 0 // timeout of read() return term }
func setTermSettingsStopBits(bits StopBits, settings *syscall.Termios) error { switch bits { case OneStopBit: settings.Cflag &= ^termiosMask(syscall.CSTOPB) case OnePointFiveStopBits, TwoStopBits: settings.Cflag |= termiosMask(syscall.CSTOPB) } return nil }
func setTermSettingsStopBits(bits StopBits, settings *syscall.Termios) error { switch bits { case STOPBITS_ONE: settings.Cflag &= ^termiosMask(syscall.CSTOPB) case STOPBITS_ONEPOINTFIVE, STOPBITS_TWO: settings.Cflag |= termiosMask(syscall.CSTOPB) } return nil }
// disableEcho disables terminal echoing, which simplifies parsing by // not having our inputs mixed into it. func (b *Bash) disableEcho() error { var termios syscall.Termios _, _, errno := syscall.Syscall(syscall.SYS_IOCTL, b.pty.Fd(), uintptr(syscall.TCGETS), uintptr(unsafe.Pointer(&termios))) if errno != 0 { return errno } termios.Lflag &^= syscall.ECHO _, _, errno = syscall.Syscall(syscall.SYS_IOCTL, b.pty.Fd(), uintptr(syscall.TCSETS), uintptr(unsafe.Pointer(&termios))) if errno != 0 { return errno } return nil }
func (c *cflagSetter) Set(pty *os.File, termios *syscall.Termios, value uint32) error { switch c.Flag { // CSIZE is a field case syscall.CS7, syscall.CS8: termios.Cflag &^= syscall.CSIZE termios.Cflag |= c.Flag default: if value == 0 { termios.Cflag &^= c.Flag } else { termios.Cflag |= c.Flag } } return SetAttr(pty, termios) }
func setRawMode(settings *syscall.Termios) { // Set local mode settings.Cflag |= termiosMask(syscall.CREAD | syscall.CLOCAL) // Set raw mode settings.Lflag &= ^termiosMask(syscall.ICANON | syscall.ECHO | syscall.ECHOE | syscall.ECHOK | syscall.ECHONL | syscall.ECHOCTL | syscall.ECHOPRT | syscall.ECHOKE | syscall.ISIG | syscall.IEXTEN) settings.Iflag &= ^termiosMask(syscall.IXON | syscall.IXOFF | syscall.IXANY | syscall.INPCK | syscall.IGNPAR | syscall.PARMRK | syscall.ISTRIP | syscall.IGNBRK | syscall.BRKINT | syscall.INLCR | syscall.IGNCR | syscall.ICRNL | tcIUCLC) settings.Oflag &= ^termiosMask(syscall.OPOST) // Block reads until at least one char is available (no timeout) settings.Cc[syscall.VMIN] = 1 settings.Cc[syscall.VTIME] = 0 }
func setTermSettingsBaudrate(speed int, settings *syscall.Termios) error { baudrate, ok := baudrateMap[speed] if !ok { return &PortError{code: InvalidSpeed} } // revert old baudrate var BAUDMASK uint for _, rate := range baudrateMap { BAUDMASK |= rate } settings.Cflag &= ^termiosMask(BAUDMASK) // set new baudrate settings.Cflag |= termiosMask(baudrate) settings.Ispeed = termiosMask(baudrate) settings.Ospeed = termiosMask(baudrate) return nil }
// saneTerminal sets the necessary tty_ioctl(4)s to ensure that a pty pair // created by us acts normally. In particular, a not-very-well-known default of // Linux unix98 ptys is that they have +onlcr by default. While this isn't a // problem for terminal emulators, because we relay data from the terminal we // also relay that funky line discipline. func saneTerminal(terminal *os.File) error { // Go doesn't have a wrapper for any of the termios ioctls. var termios syscall.Termios if err := ioctl(terminal.Fd(), syscall.TCGETS, uintptr(unsafe.Pointer(&termios))); err != nil { return fmt.Errorf("ioctl(tty, tcgets): %s", err.Error()) } // Set -onlcr so we don't have to deal with \r. termios.Oflag &^= syscall.ONLCR if err := ioctl(terminal.Fd(), syscall.TCSETS, uintptr(unsafe.Pointer(&termios))); err != nil { return fmt.Errorf("ioctl(tty, tcsets): %s", err.Error()) } return nil }
func setTermSettingsBaudrate(speed int, settings *syscall.Termios) error { baudrate, ok := baudrateMap[speed] if !ok { return &SerialPortError{code: ERROR_INVALID_PORT_SPEED} } // revert old baudrate BAUDMASK := 0 for _, rate := range baudrateMap { BAUDMASK |= rate } settings.Cflag &= ^termiosMask(BAUDMASK) // set new baudrate settings.Cflag |= termiosMask(baudrate) settings.Ispeed = termiosMask(baudrate) settings.Ospeed = termiosMask(baudrate) return nil }
func ReadPassword(fd uintptr) (string, error) { var termios, oldState syscall.Termios if _, _, e := syscall.Syscall6(syscall.SYS_IOCTL, fd, TCGETS, uintptr(unsafe.Pointer(&termios)), 0, 0, 0); e == 0 { oldState = termios termios.Lflag &^= syscall.ECHO if _, _, e := syscall.Syscall6(syscall.SYS_IOCTL, fd, TCSETS, uintptr(unsafe.Pointer(&termios)), 0, 0, 0); e == 0 { } // Restoring after reading the password defer syscall.Syscall6(syscall.SYS_IOCTL, fd, TCSETS, uintptr(unsafe.Pointer(&oldState)), 0, 0, 0) // Restoring on SIGINT sigChan := make(chan os.Signal, 1) go func(c chan os.Signal, t syscall.Termios, fd uintptr) { if _, ok := <-c; ok { syscall.Syscall6(syscall.SYS_IOCTL, fd, TCSETS, uintptr(unsafe.Pointer(&oldState)), 0, 0, 0) os.Exit(1) } }(sigChan, oldState, fd) defer close(sigChan) signal.Notify(sigChan, syscall.SIGINT) } var buf [16]byte var pass []byte for { n, err := syscall.Read(int(fd), buf[:]) if n == 0 { break } if err != nil { return "", err } for n > 0 && (buf[n-1] == '\n' || buf[n-1] == '\r') { n-- } pass = append(pass, buf[:n]...) if n < len(buf) { break } } return string(pass), nil }
func setRawMode(settings *syscall.Termios, mode *Mode) { // Set local mode settings.Cflag |= termiosMask(syscall.CREAD | syscall.CLOCAL) // Set raw mode settings.Lflag &= ^termiosMask(syscall.ICANON | syscall.ECHO | syscall.ECHOE | syscall.ECHOK | syscall.ECHONL | syscall.ECHOCTL | syscall.ECHOPRT | syscall.ECHOKE | syscall.ISIG | syscall.IEXTEN) settings.Iflag &= ^termiosMask(syscall.IXON | syscall.IXOFF | syscall.IXANY | syscall.INPCK | syscall.IGNPAR | syscall.PARMRK | syscall.ISTRIP | syscall.IGNBRK | syscall.BRKINT | syscall.INLCR | syscall.IGNCR | syscall.ICRNL | tc_IUCLC) settings.Oflag &= ^termiosMask(syscall.OPOST) if mode.Vmin == 0 && mode.Vtimeout == 0 { // Switch to default mode // Block reads until at least one char is available (no timeout) mode.Vmin = 1 } settings.Cc[syscall.VMIN] = mode.Vmin settings.Cc[syscall.VTIME] = mode.Vtimeout }
func (s *Screen) Init() error { var err error ttyIn, err = os.OpenFile("/dev/tty", os.O_RDWR, 0666) if err != nil { return err } ttyOut, err = os.OpenFile("/dev/tty", os.O_RDONLY, 0666) if err != nil { return err } orig = new(syscall.Termios) err = tcgetattr(ttyIn.Fd(), orig) if err != nil { return err } tios := new(syscall.Termios) *tios = *orig tios.Iflag &= ^uint32(syscall.ECHO | syscall.ICANON | syscall.IEXTEN | syscall.ISIG) tios.Iflag &= ^uint32(syscall.BRKINT | syscall.ICRNL | syscall.ISTRIP | syscall.IXON) tios.Cflag &= ^uint32(syscall.CSIZE | syscall.PARENB) tios.Cflag |= syscall.CS8 tios.Oflag &= ^uint32(syscall.OPOST) tios.Cc[syscall.VMIN] = 1 tios.Cc[syscall.VTIME] = 0 err = tcsetattr(ttyIn.Fd(), tios) if err != nil { return err } s.HideCursor() s.Clear() return nil }
func OpenSerial(device string, baud uint) (s *serial, err error) { myBaud := getBaud(baud) if myBaud == 0 { err = errInvalidBaud return } fd, err := syscall.Open( device, os.O_RDWR|syscall.O_RDWR|syscall.O_NOCTTY|syscall.O_NDELAY|syscall.O_NONBLOCK, 0666) if err != nil { return } defer func() { if err != nil { syscall.Close(fd) } }() term := syscall.Termios{} if err = sys.Ioctl(uintptr(fd), syscall.TCGETS, uintptr(unsafe.Pointer(&term))); err != nil { return } term.Ispeed = myBaud term.Ospeed = myBaud term.Cflag |= (syscall.CLOCAL | syscall.CREAD) term.Cflag = uint32(int32(term.Cflag) & ^syscall.PARENB & ^syscall.CSTOPB & ^syscall.CSIZE) term.Cflag |= syscall.CS8 term.Lflag = uint32(int32(term.Lflag) & ^(syscall.ICANON | syscall.ECHO | syscall.ECHOE | syscall.ISIG)) term.Oflag = uint32(int32(term.Oflag) & ^syscall.OPOST) term.Cc[syscall.VMIN] = 0 term.Cc[syscall.VTIME] = 100 if err = sys.Ioctl(uintptr(fd), syscall.TCSETS, uintptr(unsafe.Pointer(&term))); err != nil { return } status := 0 if err = sys.Ioctl(uintptr(fd), syscall.TIOCMGET, uintptr(unsafe.Pointer(&status))); err != nil { return } status |= syscall.TIOCM_DTR | syscall.TIOCM_RTS if err = sys.Ioctl(uintptr(fd), syscall.TIOCMSET, uintptr(unsafe.Pointer(&status))); err != nil { return } s = &serial{uintptr(fd)} runtime.SetFinalizer(s, func(this *serial) { this.Close() }) return }
// Open a connection with a read timeout. func (connection *Connection) Open(timeout uint8) error { var err error // The serial port is basically a file we are writing to and reading from. // O_RDWR allows the program to read and write the file. // O_NOCTTY prevents the device from controlling the terminal. // O_NONBLOCK prevents the system from blocking for a long time. connection.f, err = os.OpenFile(connection.Port, syscall.O_RDWR|syscall.O_NOCTTY|syscall.O_NONBLOCK, 0666) if err != nil { return err } // Close the file on error occurrence. defer func() { if err != nil && connection.f != nil { connection.f.Close() } }() // Create a plain termios, which allows the program to execute // input/output operations. termios := syscall.Termios{} // Setup the baud rate in the termios structure. baudrate := baudrates[connection.Baud] termios.Cflag |= baudrate termios.Ispeed = baudrate termios.Ospeed = baudrate // Setup stop bits in the termios structure. switch connection.StopBit { case StopBit1: termios.Cflag &^= syscall.CSTOPB // CSTOPB = 0x40 case StopBit2: termios.Cflag |= syscall.CSTOPB default: return errStopBit } // Setup data bits in the termios structure. databit := databits[connection.DataBit] termios.Cflag |= databit // Setup parity in the termios structure. switch connection.Parity { case ParityNone: termios.Cflag &^= syscall.PARENB // PARENB = 0x100 case ParityEven: termios.Cflag |= syscall.PARENB case ParityOdd: termios.Cflag |= syscall.PARENB termios.Cflag |= syscall.PARODD // PARODD = 0x200 default: return errParity } // // set blocking / non-blocking read vmin := uint8(0) if timeout == 0 { vmin = 1 } // Attach min bytes and timeout to the termios structure. termios.Cc = [32]uint8{ syscall.VMIN: vmin, // min bytes per transfer syscall.VTIME: timeout, // actual read timeout in deciseconds } // Execute IOCTL with the modified termios structure to apply the changes. if _, _, errno := syscall.Syscall6( // device-specific input/output operations syscall.SYS_IOCTL, // open file descriptor uintptr(connection.f.Fd()), // a request code number to set the current serial port settings uintptr(syscall.TCSETS), //TODO: it looks like syscall.TCSETS is not available under // freebsd and darwin. Is this a bug? uintptr(unsafe.Pointer(&termios)), // a pointer to the termios structure 0, 0, 0, ); errno != 0 { return errno } connection.isOpen = true return nil }
// Cfmakecbreak modifies attr for cbreak mode. func Cfmakecbreak(attr *syscall.Termios) { attr.Lflag &^= syscall.ECHO | syscall.ICANON attr.Cc[syscall.VMIN] = 1 attr.Cc[syscall.VTIME] = 0 }
func setTermSettingsParity(parity Parity, settings *syscall.Termios) error { switch parity { case PARITY_NONE: settings.Cflag &= ^termiosMask(syscall.PARENB | syscall.PARODD | tc_CMSPAR) settings.Iflag &= ^termiosMask(syscall.INPCK) case PARITY_ODD: settings.Cflag |= termiosMask(syscall.PARENB | syscall.PARODD) settings.Cflag &= ^termiosMask(tc_CMSPAR) settings.Iflag |= termiosMask(syscall.INPCK) case PARITY_EVEN: settings.Cflag &= ^termiosMask(syscall.PARODD | tc_CMSPAR) settings.Cflag |= termiosMask(syscall.PARENB) settings.Iflag |= termiosMask(syscall.INPCK) case PARITY_MARK: settings.Cflag |= termiosMask(syscall.PARENB | syscall.PARODD | tc_CMSPAR) settings.Iflag |= termiosMask(syscall.INPCK) case PARITY_SPACE: settings.Cflag &= ^termiosMask(syscall.PARODD) settings.Cflag |= termiosMask(syscall.PARENB | tc_CMSPAR) settings.Iflag |= termiosMask(syscall.INPCK) } return nil }
func setTermSettingsParity(parity Parity, settings *syscall.Termios) error { switch parity { case NoParity: settings.Cflag &= ^termiosMask(syscall.PARENB | syscall.PARODD | tcCMSPAR) settings.Iflag &= ^termiosMask(syscall.INPCK) case OddParity: settings.Cflag |= termiosMask(syscall.PARENB | syscall.PARODD) settings.Cflag &= ^termiosMask(tcCMSPAR) settings.Iflag |= termiosMask(syscall.INPCK) case EvenParity: settings.Cflag &= ^termiosMask(syscall.PARODD | tcCMSPAR) settings.Cflag |= termiosMask(syscall.PARENB) settings.Iflag |= termiosMask(syscall.INPCK) case MarkParity: settings.Cflag |= termiosMask(syscall.PARENB | syscall.PARODD | tcCMSPAR) settings.Iflag |= termiosMask(syscall.INPCK) case SpaceParity: settings.Cflag &= ^termiosMask(syscall.PARODD) settings.Cflag |= termiosMask(syscall.PARENB | tcCMSPAR) settings.Iflag |= termiosMask(syscall.INPCK) } return nil }