Skip to content

Commit

Permalink
experimental/host/sysfs: continue implementing UART support
Browse files Browse the repository at this point in the history
  • Loading branch information
maruel committed Aug 13, 2018
1 parent 5a152b4 commit 78a6876
Show file tree
Hide file tree
Showing 4 changed files with 200 additions and 22 deletions.
141 changes: 119 additions & 22 deletions experimental/host/sysfs/uart.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,11 @@ import (
"path/filepath"
"strconv"
"sync"
"syscall"

"periph.io/x/periph/conn"
"periph.io/x/periph/conn/gpio"
"periph.io/x/periph/conn/gpio/gpioreg"
"periph.io/x/periph/conn/physic"
"periph.io/x/periph/experimental/conn/uart"
)
Expand All @@ -39,21 +41,18 @@ func EnumerateUART() ([]int, error) {
}

// UART is an open serial bus via sysfs.
//
// TODO(maruel): It's not yet implemented. Should probably defer to an already
// working library like https://github.com/tarm/serial
type UART struct {
conn uartConn
}

func newUART(busNumber int) (*UART, error) {
func newUART(portNumber int) (*UART, error) {
// Use the devfs path for now.
name := fmt.Sprintf("/dev/ttyS%d", busNumber)
f, err := os.OpenFile(name, os.O_RDWR, os.ModeExclusive)
name := fmt.Sprintf("ttyS%d", portNumber)
f, err := os.OpenFile("/dev/"+name, os.O_RDWR|syscall.O_NOCTTY, os.ModeExclusive)
if err != nil {
return nil, err
}
u := &UART{uartConn{name: name, f: f, busNumber: busNumber}}
u := &UART{uartConn{name: name, f: f, portNumber: portNumber}}
return u, nil
}

Expand All @@ -64,25 +63,67 @@ func (u *UART) Close() error {
return err
}

// String implements uart.Port.
func (u *UART) String() string {
return u.conn.String()
}

// Connect implements uart.Port.
func (u *UART) Connect(f physic.Frequency, stopBit uart.Stop, parity uart.Parity, flow uart.Flow, bits int) (conn.Conn, error) {
if f > physic.GigaHertz {
return nil, fmt.Errorf("sysfs-uart: invalid speed %s; maximum supported clock is 1GHz", f)
}
if f < 50*physic.Hertz {
return nil, fmt.Errorf("sysfs-uart: invalid speed %s; minimum supported clock is 50Hz; did you forget to multiply by physic.KiloHertz?", f)
}
if bits < 5 || bits > 8 {
return nil, fmt.Errorf("sysfs-uart: invalid bits %d; must be between 5 and 8", bits)
}

// Find the closest value in acceptedBauds.
baud := uint32(f / physic.Hertz)
//var op uint32
for _, line := range acceptedBauds {
if line[0] > baud {
break
}
//op = line[1]
}

u.conn.mu.Lock()
defer u.conn.mu.Unlock()
if u.conn.f == nil {
return nil, errors.New("already closed")
return nil, errors.New("sysfs-uart: already closed")
}
if u.conn.opened {
return nil, errors.New("already connected")
if u.conn.connected {
return nil, errors.New("sysfs-uart: already connected")
}
u.conn.freqConn = f
u.conn.bitsPerWord = uint8(bits)
if flow != uart.RTSCTS {
u.conn.muPins.Lock()
u.conn.rts = gpio.INVALID
u.conn.cts = gpio.INVALID
u.conn.muPins.Unlock()
}

// TODO(maruel): ioctl with flags and op.

return &u.conn, nil
}

// LimitSpeed implements uart.PortCloser.
func (u *UART) LimitSpeed(f physic.Frequency) error {
return errors.New("sysfs-uart: not implemented")
if f > physic.GigaHertz {
return fmt.Errorf("sysfs-uart: invalid speed %s; maximum supported clock is 1GHz", f)
}
if f < 50*physic.Hertz {
return fmt.Errorf("sysfs-uart: invalid speed %s; minimum supported clock is 50Hz; did you forget to multiply by physic.KiloHertz?", f)
}
u.conn.mu.Lock()
defer u.conn.mu.Unlock()
u.conn.freqPort = f
return nil
}

// RX implements uart.Pins.
Expand All @@ -106,14 +147,27 @@ func (u *UART) CTS() gpio.PinIn {
}

type uartConn struct {
name string
f *os.File
busNumber int
// Immutable
name string
f *os.File
portNumber int

mu sync.Mutex
freqPort physic.Frequency // Frequency specified at LimitSpeed()
freqConn physic.Frequency // Frequency specified at Connect()
bitsPerWord uint8
connected bool

mu sync.Mutex
opened bool
// Use a separate lock for the pins, so that they can be queried while a
// transaction is happening.
muPins sync.Mutex
rx gpio.PinIn
tx gpio.PinOut
rts gpio.PinOut
cts gpio.PinIn
}

// String implements conn.Conn.
func (u *uartConn) String() string {
return u.name
}
Expand All @@ -123,36 +177,79 @@ func (u *uartConn) Duplex() conn.Duplex {
return conn.Full
}

// Read implements io.Reader.
func (u *uartConn) Read(b []byte) (int, error) {
return u.f.Read(b)
}

// Write implements io.Writer.
func (u *uartConn) Write(b []byte) (int, error) {
return 0, errors.New("sysfs-uart: not implemented")
return u.f.Write(b)
}

// Tx implements conn.Conn.
func (u *uartConn) Tx(w, r []byte) error {
return errors.New("sysfs-uart: not implemented")
if len(w) != 0 {
if _, err := u.f.Write(w); err != nil {
return err
}
}
if len(r) != 0 {
_, err := u.f.Read(r)
return err
}
return nil
}

// RX implements uart.Pins.
func (u *uartConn) RX() gpio.PinIn {
return gpio.INVALID
u.initPins()
return u.rx
}

// TX implements uart.Pins.
func (u *uartConn) TX() gpio.PinOut {
return gpio.INVALID
u.initPins()
return u.tx
}

// RTS implements uart.Pins.
func (u *uartConn) RTS() gpio.PinOut {
return gpio.INVALID
u.initPins()
return u.rts
}

// CTS implements uart.Pins.
func (u *uartConn) CTS() gpio.PinIn {
return gpio.INVALID
u.initPins()
return u.cts
}

func (u *uartConn) initPins() {
u.muPins.Lock()
defer u.muPins.Unlock()
if u.rx != nil {
return
}
if u.rx = gpioreg.ByName(fmt.Sprintf("UART%d_RX", u.portNumber)); u.rx == nil {
u.rx = gpio.INVALID
}
if u.tx = gpioreg.ByName(fmt.Sprintf("UART%d_TX", u.portNumber)); u.tx == nil {
u.tx = gpio.INVALID
}
// u.rts is set to INVALID if no hardware RTS/CTS flow control is used.
if u.rts == nil {
if u.rts = gpioreg.ByName(fmt.Sprintf("UART%d_RTS", u.portNumber)); u.rts == nil {
u.rts = gpio.INVALID
}
if u.cts = gpioreg.ByName(fmt.Sprintf("UART%d_CTS", u.portNumber)); u.cts == nil {
u.cts = gpio.INVALID
}
}
}

//

// driverUART implements periph.Driver.
type driverUART struct {
}
Expand Down
42 changes: 42 additions & 0 deletions experimental/host/sysfs/uart_fast.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// Copyright 2018 The Periph Authors. All rights reserved.
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.

// +build freebsd linux netbsd solaris

package sysfs

import "syscall"

var acceptedBauds = [][2]uint32{
{50, syscall.B50},
{75, syscall.B75},
{110, syscall.B110},
{134, syscall.B134},
{150, syscall.B150},
{200, syscall.B200},
{300, syscall.B300},
{600, syscall.B600},
{1200, syscall.B1200},
{1800, syscall.B1800},
{2400, syscall.B2400},
{4800, syscall.B4800},
{9600, syscall.B9600},
{19200, syscall.B19200},
{38400, syscall.B38400},
{57600, syscall.B57600},
{115200, syscall.B115200},
{230400, syscall.B230400},
{460800, syscall.B460800},
{500000, syscall.B500000},
{576000, syscall.B576000},
{921600, syscall.B921600},
{1000000, syscall.B1000000},
{1152000, syscall.B1152000},
{1500000, syscall.B1500000},
{2000000, syscall.B2000000},
{2500000, syscall.B2500000},
{3000000, syscall.B3000000},
{3500000, syscall.B3500000},
{4000000, syscall.B4000000},
}
9 changes: 9 additions & 0 deletions experimental/host/sysfs/uart_other.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// Copyright 2018 The Periph Authors. All rights reserved.
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.

// +build !freebsd,!linux,!netbsd,!solaris,!darwin,!dragonfly,!openbsd

package sysfs

var acceptedBauds [][2]uint32
30 changes: 30 additions & 0 deletions experimental/host/sysfs/uart_slow.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// Copyright 2018 The Periph Authors. All rights reserved.
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.

// +build darwin dragonfly openbsd

package sysfs

import "syscall"

var acceptedBauds = [][2]uint32{
{50, syscall.B50},
{75, syscall.B75},
{110, syscall.B110},
{134, syscall.B134},
{150, syscall.B150},
{200, syscall.B200},
{300, syscall.B300},
{600, syscall.B600},
{1200, syscall.B1200},
{1800, syscall.B1800},
{2400, syscall.B2400},
{4800, syscall.B4800},
{9600, syscall.B9600},
{19200, syscall.B19200},
{38400, syscall.B38400},
{57600, syscall.B57600},
{115200, syscall.B115200},
{230400, syscall.B230400},
}

0 comments on commit 78a6876

Please sign in to comment.