tarm / serial

BSD 3-Clause "New" or "Revised" License
1.61k stars 452 forks source link

Provide API for reading/writing to serial port via channels #11

Closed tiziano88 closed 8 years ago

tiziano88 commented 10 years ago

I suggest adding a new method

func OpenPortChan(c *Config) (chan<- []byte, <-chan []byte, error)

that returns a pair of channels that can be used to read and write to the serial port directly, by spawning a couple of goroutines redirecting input/output from/to the port. I have a pull request almost ready, will send it for discussion soon.

tarm commented 9 years ago

Hi @tiziano88,

I often end up wrapping the serial port in channel code like that as well, so it is likely a common need.

I think an API like that would be interesting and I'd be happy to review/merge a new API. Please send it when you have a chance.

wichert commented 8 years ago

@tiziano88 Have you made any progress on this?

tiziano88 commented 8 years ago

No, sorry, haven't worked on this for a long time, feel free to pick it up

tarm commented 8 years ago

I've been thinking about it more and I don't think it's the right API.

It's certainly convenient initially, but if you want to have timeouts, handle error, and do retries then a channel API does not work as well.

Here's a quick example: https://play.golang.org/p/zk_03P071w

I annotated that example with comments about some of the issues. By the time you add bidirectional communication (errors, closing of connections, reusing of buffers), then a blocking Read()/Write() api often ends up being simpler.

I recently refactored a bunch of my code to STOP using a pattern like that because I wanted better error handling.

The pattern I am moving towards is having a dedicated goroutine (or 2 if needed) per device. That goroutine does blocking Read()s, handles errors and retries, and then there is a higher level API to communicate with the device. The way I have it, a single goroutine does not handle bytes from multiple devices so no select or channels are needed.