blob: 1196a9957c5e9e46494b30f0f182f3643addab25 [file] [log] [blame]
// Copyright 2021 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package serial
import (
"context"
"github.com/tarm/serial"
"chromiumos/tast/errors"
)
// ConnectedPort implements Port, delegates to tarm/serial.
type ConnectedPort struct {
port *serial.Port
}
// Read reads bytes into provided buffer, returns number of bytes read.
// Bytes already written to the port shall be moved into buf, up to its size.
// In blocking mode (port opened without ReadTimeout), it blocks until at least
// one byte is read. In non-blocking mode, it may return an error with zero
// bytes read if ReadTimeout is exceeded, however this is not guaranteed on all
// platforms and so a context deadline exceeded error may be returned even
// though the deadline is greater than the ReadTimeout.
func (p *ConnectedPort) Read(ctx context.Context, buf []byte) (n int, err error) {
done := make(chan struct{}, 1)
go func() {
if p.port == nil {
err = errors.New("port already closed")
} else {
n, err = p.port.Read(buf)
}
done <- struct{}{}
}()
select {
case <-ctx.Done():
return 0, ctx.Err()
case <-done:
return n, err
}
}
// Write writes bytes from provided buffer, returns number of bytes written.
// It returns a non-nil error when n != len(b), nil otherwise.
func (p *ConnectedPort) Write(ctx context.Context, buf []byte) (n int, err error) {
done := make(chan struct{}, 1)
go func() {
if p.port == nil {
err = errors.New("port already closed")
} else {
n, err = p.port.Write(buf)
}
done <- struct{}{}
}()
select {
case <-ctx.Done():
return 0, ctx.Err()
case <-done:
return n, err
}
}
// Flush flushes un-read/written content from the port.
func (p *ConnectedPort) Flush(ctx context.Context) error {
var err error
done := make(chan struct{}, 1)
go func() {
if p.port == nil {
err = errors.New("port already closed")
} else {
err = p.port.Flush()
}
done <- struct{}{}
}()
select {
case <-ctx.Done():
return ctx.Err()
case <-done:
return err
}
}
// Close closes the port.
func (p *ConnectedPort) Close(ctx context.Context) error {
var err error
done := make(chan struct{}, 1)
go func() {
if p.port == nil {
err = nil
done <- struct{}{}
return
}
err = p.port.Close()
if err == nil {
p.port = nil
}
done <- struct{}{}
}()
select {
case <-ctx.Done():
return ctx.Err()
case <-done:
return err
}
}