serframe

package module
v0.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 8, 2025 License: MIT Imports: 4 Imported by: 2

README

GoDoc

serframe

This package provides a mechanism to read byte frames from a serial stream.

It is currently used to implement binary protocols like Modbus (UART, TCP, CAN) or HSLI (high-speed lighting interface, UARToverCAN, as used in the TLD7002-16es LED driver).

Another use case is reading frames from a text-based command-line interface.

Documentation

Index

Constants

This section is empty.

Variables

View Source
var ErrOverflow = Error("receive buffer overflow")
View Source
var ErrTimeout = Error("timeout")
View Source
var ErrUnexpectedReply = Error("unexpected reply")

Functions

This section is empty.

Types

type Error

type Error string

func (Error) Error

func (e Error) Error() string

type FrameInterceptor

type FrameInterceptor func(curFrame, newPart []byte) (FrameStatus, error)

A FrameInterceptor is called every time new bytes have been received and appended to the current frame. The interceptor may infer from the content of curFrame, whether it can be considered complete or not, and return an corresponding frame status, and, if appropriate, an error. NewPart might be used, for example, to calculate a hash in parallel.

type FrameStatus

type FrameStatus int
const (
	None FrameStatus = iota
	Complete
	CompleteSkipTimeout
)

type LocalEchoMismatchError added in v0.2.0

type LocalEchoMismatchError struct {
	Want, Got []byte
}

func (*LocalEchoMismatchError) Error added in v0.2.0

func (e *LocalEchoMismatchError) Error() string

type Option

type Option func(*Stream)

func ForwardUnsolicited

func ForwardUnsolicited(w io.Writer) Option

ForwardUnsolicited configures the stream to forward bytes received without a prior call to StartReception to the given io.Writer.

func WithInternalBufSize

func WithInternalBufSize(n int) Option

WithInternalBufSize sets the size of the internal buffer used to read from the underlying io.Reader. The default is 64 bytes.

func WithInternalReadBytesFunc

func WithInternalReadBytesFunc(readBytes func() ([]byte, error)) Option

WithInternalReadBytesFunc specifies that bytes should not be read from the io.Reader provided as argument to NewStream, but rather be read from the given function. This is useful when the instance providing bytes does not implement an io.Reader interface.

func WithReceptionOptions

func WithReceptionOptions(opts ...ReceptionOption) Option

WithReceptionOptions allows to specifiy ReceptionOptions globally when creating the Stream object. These settings may be overridden later.

type ReceptionOption

type ReceptionOption func(*receptionParams)

func ExpectNoReply

func ExpectNoReply() ReceptionOption

ExpectNoReply configures the reception to expect no reply, as it might be the case for broadcast requests. ReadFrame will return after the configured initial timeout, if no bytes have been received, otherwise it will return ErrUnexpectedReply.

func SkipInitialEchoNullBytes

func SkipInitialEchoNullBytes() ReceptionOption

SkipInitialEchoNullBytes skips null bytes received prior an echo of sent data. These null bytes may occur when, as part of a protocol, a short break condition, slightly larger than a zero byte, gets issued on the bus to initiate a request. In case this break condition is misinterpeted as a zero byte it will show up at the start of the received data just before the echoed request. If WithLocalEcho is used, this option enables detecting and removing these zero bytes; protocols not based on per-request break conditions won't need it.

func WithExtInterByteTimeout

func WithExtInterByteTimeout(t time.Duration) ReceptionOption

WithExtInterByteTimeout extends the duration of the normal inter-byte timeout to the specified value, in case a FrameInterceptor has been configured. A frame will be considered complete, after both at least the normal inter-byte timeout has elapsed, and the interceptor signals Complete.

func WithFrameInterceptor

func WithFrameInterceptor(f FrameInterceptor) ReceptionOption

func WithInitialTimeout

func WithInitialTimeout(t time.Duration) ReceptionOption

WithInitialTimeout configures the timeout that is active before the first byte of a frame has been received. A value of zero deactivates the timeout, which is also the default.

func WithInterByteTimeout

func WithInterByteTimeout(t time.Duration) ReceptionOption

The InterByteTimeout is the time that is allowed to elapse after a byte has been received before a frame is considered complete.

On a pc system there may be the case that this timeout elapsed but the goroutine reading bytes from the stream didn't have a chance to know about new bytes waiting to be read -- as a result, frames may appear truncated. To work around this problem, while allowing to keep the inter byte timeout short, a combination of an extended inter-byte timeout and a frame interceptor may be used; see options WithExtInterByteTimeout and WithFrameInterceptor.

func WithLocalEcho

func WithLocalEcho(expectedEcho []byte) ReceptionOption

WithLocalEcho sets the data that is expected to be received first -- because of an activated local echo mechanism --, before receiving an actual frame. ReadFrame will detect, then skip this echo data.

type Stream

type Stream struct {
	ExitC <-chan error
	// contains filtered or unexported fields
}

Stream is an object byte frames can be read from.

func NewStream

func NewStream(r io.Reader, opts ...Option) *Stream

NewStream creates a new Stream from the given io.Reader.

func (*Stream) CancelReception

func (s *Stream) CancelReception()

CancelReception reverts a previous call to StartReception. It should be called in case ReadFrame won't be called for some reason.

func (*Stream) ExpectEcho added in v0.2.0

func (s *Stream) ExpectEcho(ctx context.Context) error

ExpectEcho waits until the byte sequence specified via WithLocalEcho in the preceding call to Stream.StartReception has been received. If no echo data was specified, ExpectEcho returns immediately. A typical use case is to wait until a sync preamble has been fully transmitted, allowing actions such as parity switching to be performed afterward.

func (*Stream) ReadFrame

func (s *Stream) ReadFrame(ctx context.Context, opts ...ReceptionOption) ([]byte, error)

ReadFrame reads the next frame from the stream. On success, it returns the frame content as a byte slice, otherwise an error will be returned. The returned slice's underlying buffer is the one passed to StartReception.

func (*Stream) StartReception

func (s *Stream) StartReception(buf []byte, opts ...ReceptionOption) error

StartReception starts the handling of another data frame, that will be stored in buf; a byte received after calling this function is regarded the first byte of the new frame. The actual reception of the frame will be done in the following call to ReadFrame. Bytes received before StartReception gets called are considered unsolicited.

When implementing a request/response scheme, e.g. when communicating to a device, StartReception should be called just before Writing the request. If calling it after the Write it could happen that the call to Write has not returned yet, but the first bytes of the device's response frame have already been received by the host system; subsequently, ReadFrame could miss the first bytes of the response frame.

If the underlying io.Reader returned an io.EOF previously, StartReception returns io.EOF.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL