github.com/jordan-bonecutter/can-go@v0.0.0-20230901155856-d83995b18e50/pkg/socketcan/receiver.go (about)

     1  package socketcan
     2  
     3  import (
     4  	"bufio"
     5  	"io"
     6  
     7  	"go.einride.tech/can"
     8  )
     9  
    10  type ReceiverOption func(*receiverOpts)
    11  
    12  type receiverOpts struct {
    13  	frameInterceptor FrameInterceptor
    14  }
    15  
    16  type Receiver struct {
    17  	opts  receiverOpts
    18  	rc    io.ReadCloser
    19  	sc    *bufio.Scanner
    20  	frame frame
    21  }
    22  
    23  func NewReceiver(rc io.ReadCloser, opt ...ReceiverOption) *Receiver {
    24  	opts := receiverOpts{}
    25  	for _, f := range opt {
    26  		f(&opts)
    27  	}
    28  	sc := bufio.NewScanner(rc)
    29  	sc.Split(scanFrames)
    30  	return &Receiver{
    31  		rc:   rc,
    32  		opts: opts,
    33  		sc:   sc,
    34  	}
    35  }
    36  
    37  func scanFrames(data []byte, _ bool) (int, []byte, error) {
    38  	if len(data) < lengthOfFrame {
    39  		// not enough data for a full frame
    40  		return 0, nil, nil
    41  	}
    42  	return lengthOfFrame, data[0:lengthOfFrame], nil
    43  }
    44  
    45  func (r *Receiver) Receive() bool {
    46  	ok := r.sc.Scan()
    47  	r.frame = frame{}
    48  	if ok {
    49  		r.frame.unmarshalBinary(r.sc.Bytes())
    50  		if r.opts.frameInterceptor != nil {
    51  			r.opts.frameInterceptor(r.frame.decodeFrame())
    52  		}
    53  	}
    54  	return ok
    55  }
    56  
    57  func (r *Receiver) HasErrorFrame() bool {
    58  	return r.frame.isError()
    59  }
    60  
    61  func (r *Receiver) Frame() can.Frame {
    62  	return r.frame.decodeFrame()
    63  }
    64  
    65  func (r *Receiver) ErrorFrame() ErrorFrame {
    66  	return r.frame.decodeErrorFrame()
    67  }
    68  
    69  func (r *Receiver) Err() error {
    70  	return r.sc.Err()
    71  }
    72  
    73  func (r *Receiver) Close() error {
    74  	return r.rc.Close()
    75  }
    76  
    77  // ReceiverFrameInterceptor returns a ReceiverOption that sets the FrameInterceptor for the
    78  // receiver. Only one frame interceptor can be installed.
    79  func ReceiverFrameInterceptor(i FrameInterceptor) ReceiverOption {
    80  	return func(o *receiverOpts) {
    81  		o.frameInterceptor = i
    82  	}
    83  }