github.com/simpleiot/simpleiot@v0.18.3/respreader/doc.go (about)

     1  /*
     2  Package respreader provides a convenient way to frame response data from devices
     3  that use
     4  prompt/response protocols such as Modbus, other RS485 protocols, and modem
     5  AT commands. The fundamental assumption is a device takes some variable amount of
     6  time to respond to a prompt, formats up a response, and then streams it out the
     7  serial port. Once the response data starts streaming, any significant gap in the
     8  response with
     9  no data indicates the response is complete. A Read() blocks until it detects this
    10  "gap" or the overall timeout is reached, and then returns with accumulated data.
    11  
    12  This method of framing a response has the following advantages:
    13  
    14  1) minimizes the wasted time waiting for a response to the chunkTimeout defined
    15  below. More simplistic implementations often take the worst case response time
    16  for all packets and simply wait that amount of time for the response to arrive.
    17  This works, but the bus is tied up during this worst case wait that could be used for
    18  sending the next packet.
    19  
    20  2) It is simple in that you don't have to parse the response on the fly to determine
    21  when it is complete, yet it can detect the end of a response fairly quickly.
    22  
    23  The obvious disadvantage of this method of framing is that the device may insert a
    24  significant delay in sending the response that will cause the reader to think the
    25  response is complete. As long as this delay is still significantly shorter than
    26  the overall response time, it can still work fairly well. Some experimentation may
    27  be required to optimize the chunkTimeout setting.
    28  
    29  Example using a serial port:
    30  
    31  	import (
    32  		"io"
    33  
    34  		"github.com/jacobsa/go-serial/serial"
    35  		"github.com/simpleiot/simpleiot/respreader"
    36  	)
    37  
    38  	options := serial.OpenOptions{
    39  		PortName:              "/dev/ttyUSB0",
    40  		BaudRate:              9600,
    41  		DataBits:              8,
    42  		StopBits:              1,
    43  		MinimumReadSize:       0,
    44  		// with serial ports, you just set
    45  		// InterCharacterTimeout to 100 or larger.
    46  		// Otherwise, the goroutine reading the serial
    47  		// port will never exit when you close the read
    48  		// and will still data the next time you open
    49  		// the port. Be aware it may take 100ms for this
    50  		// to close. The linux kernel only accepts timeouts
    51  		// in increments of 0.1s. When using serial ports it
    52  		// makes sense to set the chunkTimeout to 100ms as well.
    53  		// With Go files, a read is supposed to return when
    54  		// the File is closed, but this does not seem to be
    55  		// working with Linux serial devices.
    56  		InterCharacterTimeout: 100,
    57  		RTSCTSFlowControl:     true,
    58  	}
    59  
    60  	port, err := serial.Open(options)
    61  
    62  	port = respreader.NewResponseReadWriteCloser(port, time.Second,
    63  	time.Millisecond * 50)
    64  
    65  	// send out prompt
    66  	port.Write("ATAI")
    67  
    68  	// read response
    69  	data := make([]byte, 128)
    70  	count, err := port.Read(data)
    71  	data = data[0:count]
    72  
    73  	// now process response ...
    74  
    75  	// to close the reader process, you must call Close on the reader.
    76  	// This sets a flag that causes the reader goroutine to exit.
    77  	port.Close()
    78  
    79  Three types are provided for convenience that wrap io.Reader, io.ReadWriter, and io.ReadWriteCloser.
    80  */
    81  package respreader