Golang从连续读取

时间:2018-04-29 16:09:47

标签: go serial-port

我正在尝试从串口读取(Raspberry Pi上的GPS设备)。

按照http://www.modmypi.com/blog/raspberry-pi-gps-hat-and-python

的说明操作

我可以使用

从shell中读取
stty -F /dev/ttyAMA0 raw 9600 cs8 clocal -cstopb
cat /dev/ttyAMA0

我的格式化输出

$GNGLL,5133.35213,N,00108.27278,W,160345.00,A,A*65
$GNRMC,160346.00,A,5153.35209,N,00108.27286,W,0.237,,290418,,,A*75
$GNVTG,,T,,M,0.237,N,0.439,K,A*35
$GNGGA,160346.00,5153.35209,N,00108.27286,W,1,12,0.67,81.5,M,46.9,M,,*6C
$GNGSA,A,3,29,25,31,20,26,23,21,16,05,27,,,1.11,0.67,0.89*10
$GNGSA,A,3,68,73,83,74,84,75,85,67,,,,,1.11,0.67,0.89*1D
$GPGSV,4,1,15,04,,,34,05,14,040,21,09,07,330,,16,45,298,34*40
$GPGSV,4,2,15,20,14,127,18,21,59,154,30,23,07,295,26,25,13,123,22*74
$GPGSV,4,3,15,26,76,281,40,27,15,255,20,29,40,068,19,31,34,199,33*7C
$GPGSV,4,4,15,33,29,198,,36,23,141,,49,30,172,*4C
$GLGSV,3,1,11,66,00,325,,67,13,011,20,68,09,062,16,73,12,156,21*60
$GLGSV,3,2,11,74,62,177,20,75,53,312,36,76,08,328,,83,17,046,25*69
$GLGSV,3,3,11,84,75,032,22,85,44,233,32,,,,35*62
$GNGLL,5153.35209,N,00108.27286,W,160346.00,A,A*6C
$GNRMC,160347.00,A,5153.35205,N,00108.27292,W,0.216,,290418,,,A*7E
$GNVTG,,T,,M,0.216,N,0.401,K,A*3D
$GNGGA,160347.00,5153.35205,N,00108.27292,W,1,12,0.67,81.7,M,46.9,M,,*66
$GNGSA,A,3,29,25,31,20,26,23,21,16,05,27,,,1.11,0.67,0.89*10
$GNGSA,A,3,68,73,83,74,84,75,85,67,,,,,1.11,0.67,0.89*1D
$GPGSV,4,1,15,04,,,34,05,14,040,21,09,07,330,,16,45,298,34*40

(我已经把一些随机数据放进去了)

我正试着在Go中读到这个。目前,我有

package main

import "fmt"
import "log"
import "github.com/tarm/serial"

func main() {
        config := &serial.Config{
                Name: "/dev/ttyAMA0",
                Baud: 9600,
                ReadTimeout: 1,
                Size: 8,
        }

        stream, err := serial.OpenPort(config)
        if err != nil {
                log.Fatal(err)
        }

        buf := make([]byte, 1024)

        for {
                n, err := stream.Read(buf)
                if err != nil {
                        log.Fatal(err)
                }
                s := string(buf[:n])
                fmt.Println(s)
        }
}

但这会输出格式错误的数据。我怀疑这是由于缓冲区大小或Size结构中config的值错误,但我不确定如何从stty设置中获取这些值。

回顾过去,我认为问题在于我正在获取一个流,我希望能够迭代stty的行,而不是块。这是输出流的方式:

$GLGSV,3
,1,09,69
,10,017,
,70,43,0
69,,71,3
2,135,27
,76,23,2
32,22*6F

$GLGSV
,3,2,09,
77,35,30
0,21,78,
11,347,,
85,31,08
1,30,86,
72,355,3
6*6C
$G
LGSV,3,3
,09,87,2
4,285,30
*59
$GN
GLL,5153
.34919,N
,00108.2
7603,W,1
92901.00
,A,A*6A

3 个答案:

答案 0 :(得分:2)

serial.OpenPort()返回的结构包含一个指向打开的os.File的指针,该指针对应于打开的串行端口连接。当您Read()时,图书馆会调用Read() on the underlying os.File

documentation for this function call是:

  

读取从文件中读取最多len(b)个字节。它返回读取的字节数和遇到的任何错误。在文件末尾,Read返回0,io.EOF。

这意味着您必须跟踪读取的数据量。如果这对您来说很重要,您还必须跟踪是否有换行符。遗憾的是,基础*os.File未导出,因此您发现很难使用bufio.ReadLine()这样的技巧。可能值得修改库并发送拉取请求。

答案 1 :(得分:0)

更改

fmt.Println(s)

fmt.Print(s)

,您可能会得到想要的东西。 还是我误解了这个问题?

答案 2 :(得分:0)

我最近使用 bufio.NewScanner 构建了一个串行端口阅读器,正如 Michael Hamptom 在 his answer 的 pt.2 中所描述的那样。以下是我发现有用的两个补充:

行尾

您可能会收到不是换行分隔文本的数据。 bufio.Scanner 默认使用 ScanLines 将接收到的数据拆分为行 - 但您也可以根据默认函数的签名编写自己的行拆分器并将其设置为扫描仪:

scanner := bufio.NewScanner(stream) 
scanner.Split(ownLineSplitter) // set custom line splitter function

阅读器关闭

您可能不会收到恒定的流,而只会不时收到一些字节数据包。如果没有字节到达端口,扫描器将阻塞,您不能直接杀死它。您必须关闭流才能这样做,从而有效地引发错误。为了不阻塞任何外部循环并适当地处理错误,您可以将扫描器包装在一个接受上下文的 goroutine 中。如果上下文被取消,则忽略错误,否则转发错误。原则上,这看起来像

var errChan = make(chan error)
var dataChan = make(chan []byte)
ctx, cancelPortScanner := context.WithCancel(context.Background())

go func(ctx context.Context) {
    scanner := bufio.NewScanner(stream)
    for scanner.Scan() { // will terminate if connection is closed
        dataChan <- scanner.Bytes()
    }
    // if execution reaches this point, something went wrong or stream was closed
    select {
    case <-ctx.Done():
        return // tx was cancelled, just return without error
    default:
        errChan <- scanner.Err() // ctx wasn't cancelled, forward error
    }
}(ctx)

// handle data from dataChan, error from errChan

要停止扫描器,您需要取消上下文并关闭连接:

cancelPortScanner()
stream.Close()