Remove \r and \n (CRLF) from serial input - go

I'm currently writing Go code which reads a sensor value through an Arduino using the serial port. Currently I am getting "\r" and "\n" in my output. I know in Python, you can do:
line = line.decode('utf-8')
to get rid of the characters. How would you do that using Golang? I'm fairly new to the language so any help would be appreciated! Here is what a snippet of the output looks like currently:
"arduinoLED\"}\r\n{\"temperature\"
Also if anyone could let me know how I can read a line in Go (similar to Python's line.readline()) that would be great.
Many thanks!

If you read a stream by lines using a default bufio.Scanner (which is the usual way) then both regular (\n) and CRLF (\r\n) line breaks will be discarded:
doc := "Hello\nWorld!\nGoodbye,\r\nnewlines!\r\n"
scanner := bufio.NewScanner(bytes.NewReader([]byte(doc)))
for scanner.Scan() {
fmt.Printf("%q\n", scanner.Text()) // Note our own newline here
}
if err := scanner.Err(); err != nil {
panic(err) // TODO: handle error properly
}
// Prints:
// "Hello,"
// "World!"
// "Goodbye,"
// "newlines!"
Of course, instead of the bytes reader in the example above you'll probably have an existing Reader but the usage should be identical otherwise.

Related

Is There a Scanner Function in Go That Separates on Length (or is Newline Agnostic)?

I have two types of files in go which can be represented by the following strings:
const nonewline := 'hello' # content but no newline
const newline := `hello\nworld' # content with newline
My goal is just to read all the content from both files (it's coming in via a stream, so I cannot use something built in like ReadAll, i'm using stdioPipe) and include newlines where they appear.
I'm using Scanner but it APPEARS that there's no way to tell if the line terminates with a newline, and if I use Scanner.Text() it auto-splits (making it impossible to tell if a line ends in a newline, or the line just terminated at the end of the file).
I've also looked at writing a custom Split function, but isn't that overkill? I just need to split on some fixed length (I assume the default buffer size - 4096), or whatever is left in the file, whichever is shorter.
I've also looking at Scanner.Split(bufio.ScanBytes) but is there a speed up by chunking the read?
Anyhow, this seems like something that should be really straightforward.
Use this loop to read a stream in fixed size chunks:
chunk := make([]byte, size) // Size is the chunk size.
for {
n, err := io.ReadFull(stream, chunk)
if n > 0 {
// Do something with the chunk of data.
process(chunk[:n])
}
if err != nil {
break
}
}

reading same input with bufio and scanf has different results

I was trying to write a simple program that reads some answers from the terminal from the user to some questions.For instance the queries are:
5+5
1+2
8+3
and the user should give the answer.My problem it that when I user bufio.ReadString and the compare the input with the real answer it doesn't work properly,how ever when I use scanf everything is fine.here is my code:
//scanner := bufio.NewReader(os.Stdin)
var correctAnswers int8 = 0
for _, pro := range problems {
fmt.Println(pro.question)
//answer,_ := scanner.ReadString('\n')
var idk string
fmt.Scanf("%s\n", &idk)
//print(answer)
println(pro.answer)
if idk == pro.answer {
fmt.Println("Correct :)")
correctAnswers++
} else {
fmt.Println("Sorry!")
}
}
fmt.Printf("You answered %d out of %d problems correctly \n", correctAnswers, len(problems))
as you can see I commented out bufio. The intersting thing is that when I print the answer that the user gave me it bufio.ReadString correctly got the input from terminal but in the if clause it doesn't work!
bufio.Reader.ReadString:
ReadString reads until the first occurrence of delim in the input, returning a string containing the data up to and including the delimiter.
The value returned from ReadString includes the \n on the end.

Getting EOF on 2nd prompt when using a file as Stdin (Golang)

I am trying to do functional testing of a cli app similar to this way.
As the command asks a few input on command prompt, I am putting them in a file and setting it as os.Stdin.
cmd := exec.Command(path.Join(dir, binaryName), "myArg")
tmpfile := setStdin("TheMasterPassword\nSecondAnswer\n12121212\n")
cmd.Stdin = tmpfile
output, err := cmd.CombinedOutput()
The setStdin just creates a tmpFile, write the string in file and returns the *os.File.
Now, I am expecting TheMasterPassword to be first input, and it's working. But for the second input always getting Critical Error: EOF.
The function I am using for asking and getting user input this :
func Ask(question string, minLen int) string {
reader := bufio.NewReader(os.Stdin)
for {
fmt.Printf("%s: ", question)
response, err := reader.ReadString('\n')
ExitIfError(err)
if len(response) >= minLen {
return strings.TrimSpace(response)
} else {
fmt.Printf("Provide at least %d character.\n", minLen)
}
}
}
Can you please help me to find out what's going wrong?
Thanks a lot!
Adding setStdin as requested
func setStdin(userInput string) *os.File {
tmpfile, err := ioutil.TempFile("", "test_stdin_")
util.ExitIfError(err)
_, err = tmpfile.Write([]byte(userInput))
util.ExitIfError(err)
_, err = tmpfile.Seek(0, 0)
util.ExitIfError(err)
return tmpfile
}
It pretty much looks like in your app your call Ask() whenever you want a single input line.
Inside Ask() you create a bufio.Reader to read from os.Stdin. Know that bufio.Reader–as its name suggests–uses buffered reading, meaning it may read more data from its source than what is returned by its methods (Reader.ReadString() in this case). Which means if you just use it to read one (or some) lines and you throw away the reader, you will throw away buffered, unread data.
So next time you call Ask() again, attempting to read from os.Stdin, you will not continue from where you left off...
To fix this issue, only create a single bufio.Reader from os.Stdin, store it in a global variable for example, and inside Ask(), always use this single reader. So buffered and unread data will not be lost between Ask() calls. Of course this solution will not be valid to call from multiple goroutines, but reading from a single os.Stdin isn't either.
For example:
var reader = bufio.NewReader(os.Stdin)
func Ask(question string, minLen int) string {
// use the global reader here...
}
Also note that using bufio.Scanner would be easier in your case. But again, bufio.Scanner may also read more data from its source than needed, so you have to use a shared bufio.Scanner here too. Also note that Reader.ReadString() returns you a string containing the delimeter (a line ending with \n in your case) which you probably have to trim, while Scanner.Text() (with the default line splitting function) will strip that first before returning the line. That's also a simplification you can take advantage of.

How to read data from serial and process it when a specific delimiter is found

I have a device, which continues to send data over a serial port.
Now I want to read this and process it.
The data send this delimiter "!" and
as soon as this delimiter appears I want to pause reading to processing the data thats already been received.
How can I do that? Is there any documentation or examples that I can read or follow.
For reading data from a serial port you can find a few packages on Github, e.g. tarm/serial.
You can use this package to read data from your serial port. In order to read until a specific delimiter is reached, you can use something like:
config := &serial.Config{Name: "/dev/ttyUSB", Baud: 9600}
s, err := serial.OpenPort(config)
if err != nil {
// stops execution
log.Fatal(err)
}
// golang reader interface
r := bufio.NewReader(s)
// reads until delimiter is reached
data, err := r.ReadBytes('\x21')
if err != nil {
// stops execution
log.Fatal(err)
}
// or use fmt.Printf() with the right verb
// https://golang.org/pkg/fmt/#hdr-Printing
fmt.Println(data)
See also: Reading from serial port with while-loop
bufio's reader unfortunately did not work for me - it kept crashing after a while. This was a no-go since I needed a stable solution for a low-performance system.
My solution was to implement this suggestion with a small tweak. As noted, if you don't use bufio, the buffer gets overwritten every time you call
n, err := s.Read(buf0)
To fix this, append the bytes from buf0 to a second buffer, buf1:
if n > 0 {
buf1 = append(buf1, buf0[:n]...)
}
Then parse the bytes stored in buf1. If you find a subset you're looking for, process it further.
make sure to clear the buffers in a suitable manner
make sure to limit the frequency the loop is running with (e.g. time.Sleep)

Read multi word string from console

I realized that the following only reads a single word string -
fmt.Scan(&sentence)
How do I read multi word string - as in, the string sentence should store a string that contains multiple words.
One can use the InputReader also to scan and print multiple words from the console.
The solution code is as follows:
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
inputReader := bufio.NewReader(os.Stdin)
input, _ := inputReader.ReadString('\n')
fmt.Println(input)
}
Console Input:
Let's Go!!!
Console Output:
Let's Go!!!
Note:
To run a GOLANG program, open the command prompt or powershell, navigate to the directory where the program file is present and type in the following command:
go run file_name.go
Your question refers to scanning space separated input. The definition of fmt.Scan https://golang.org/pkg/fmt/#Scan states:
Scan scans text read from standard input, storing successive space-
separated values into successive arguments. Newlines count as space.
It returns the number of items successfully scanned. If that is less
than the number of arguments, err will report why.
So, by definition, input is scanned up until the first space is found. To scan, let's say until you hit a \n on the command line you can use the code from the comment scanning spaces from stdin in Go:
scanner := bufio.NewScanner(os.Stdin)
for scanner.Scan() {
return scanner.Text()
}
if err := scanner.Err(); err != nil {
fmt.Fprintln(os.Stderr, "reading standard input:", err)
}
Also this thread might be useful: https://groups.google.com/forum/#!topic/golang-nuts/r6Jl4D9Juw0

Resources