// 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 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 }
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 }
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 }
// 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 }