Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SetDeadline implementation #117

Open
maitredede opened this issue Aug 24, 2021 · 5 comments
Open

SetDeadline implementation #117

maitredede opened this issue Aug 24, 2021 · 5 comments
Labels
2.0 Breaking changes scheduled for v2.0 release enhancement

Comments

@maitredede
Copy link

Hello,

Thanks for PR #109 (timeouts).

I am using your lib (go 1.16.7 on linux/amd64) to drive Ingenico payement hardware that has timeouts defined in its communication protocol. But the timeouts are not the same between protocol states. For example : when I write a ENQ byte, there is a response timeout of 2s; when I ended sending something, I have to listen 2s before I can start sending a new item; when there is a communication conflict, the timeout is 5s before retry...

My first driving implementation was based on your lib, and did not fully respected all the timeouts. My second implementation use directly the /dev/ttyACM0 file (using *os.File), and respects the timeouts, using the *os.File.SetDeadline func.

So I would like if it is possible to add a SetDeadline implementation that can be called when needed, and that may have the same behavior that the *os.File. 🙂

@maitredede
Copy link
Author

A quick and dirty implementation may be :

func (port *unixPort) SetDeadline(t time.Time) error {
	return port.SetReadTimeout(time.Until(t))
}

but it would be also interesting to have timeouts/deadlines on .Write() 🙂

@cmaglie cmaglie added 2.0 Breaking changes scheduled for v2.0 release enhancement labels Sep 6, 2021
@maitredede
Copy link
Author

Hello,
More precisions about my use case, I need to communicate with devices that respects some timouts, when both reading and writing.

Either the native timeout or the context approach can be used in my case, but I need both read and write timeouts 😃

@quite
Copy link
Contributor

quite commented Jan 23, 2023

I need this as well. I would like to use io.ReadFull on the go-serial reader/Port interface. But since go-serial's SetReadTimeout() only causes go-serial's Read() implementation to do return 0, nil, the ReadFull gets stuck. My workaround might end up using SetReadTimeout(), and the doing my own Read-loop, reading 1 byte at a time into my buffer and interpreting n, nil as the timeout. related #148

@kmpm
Copy link

kmpm commented May 17, 2023

How about the same interface as net.conn?

SetDeadline(t time.Time) error
SetReadDeadline(t time.Time) error
SetWriteDeadline(t time.Time) error

which could be set using for example port.SetReadDeadline(time.Now().Add(time.Second)).

If implementing the same interface as net.Conn one could keep much code between networked and serial connections without much change.
As long as one of the existing interfaces from either from this or os.File is used then I'm happy.

@dschmidt
Copy link

How about the same interface as net.conn?

SetDeadline(t time.Time) error
SetReadDeadline(t time.Time) error
SetWriteDeadline(t time.Time) error

which could be set using for example port.SetReadDeadline(time.Now().Add(time.Second)).

If implementing the same interface as net.Conn one could keep much code between networked and serial connections without much change. As long as one of the existing interfaces from either from this or os.File is used then I'm happy.

I second this! I had to implement serial port handling in software that was already using net.Conn, so having the deadline functions would have made Port basically a drop in replacement. It would be nice to have it in the long run, but for the time being this is what I've come up with:

type portWithDeadline struct {
	serial.Port

	writeDeadline *time.Time
}

func (p portWithDeadline) SetDeadline(t time.Time) error {
	p.SetWriteDeadline(t)
	return p.SetReadDeadline(t)
}

func (p portWithDeadline) SetReadDeadline(t time.Time) error {
	return p.SetReadTimeout(time.Until(t))
}

func (p portWithDeadline) SetWriteDeadline(t time.Time) error {
	p.writeDeadline = &t
	return nil
}

func (p portWithDeadline) Write(b []byte) (n int, err error) {
	if p.writeDeadline == nil || p.writeDeadline.IsZero() {
		return p.Port.Write(b)
	}

	finishedCh := make(chan struct{})
	timeoutCh := time.After(time.Until(*p.writeDeadline))
	go func() {
		defer close(finishedCh)
		n, err = p.Port.Write(b)
	}()

	select {
	case <-timeoutCh:
		return 0, errors.New("write operation timed out")
	case <-finishedCh:
		return n, err
	}
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
2.0 Breaking changes scheduled for v2.0 release enhancement
Projects
None yet
Development

No branches or pull requests

5 participants