Esempio n. 1
0
// 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
}
Esempio n. 2
0
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
}
Esempio n. 3
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
}
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
}
Esempio n. 5
0
// 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
}