package main import ( "bytes" "flag" "io" "log" "os" "os/signal" "syscall" "time" "unicode" "github.com/tarm/serial" ) func readSerial(s *serial.Port, c chan []byte) { var unread bytes.Buffer buf := make([]byte, 128) for { n, err := s.Read(buf) if err != nil { log.Fatal(err) } unread.Write(buf[:n]) for { line, err := unread.ReadBytes('\n') if err == io.EOF { if _, err = unread.Write(line); err != nil { log.Println(err) } break } else if err != nil { log.Println(err) break } c <- bytes.TrimRightFunc(line, func(r rune) bool { return unicode.IsSpace(r) || unicode.IsControl(r) }) } } } func computeChecksum(area []byte) (checksum byte) { for _, c := range area { checksum += c } checksum = (checksum & 0x3F) + 0x20 return } func getHorodate(fields *[][]byte) (horodate time.Time, err error) { if len(*fields) == 4 && len((*fields)[1]) == 13 { horodate, err = time.Parse("060102150405", string((*fields)[1][1:])) if err != nil { horodate = time.Now().Truncate(time.Second).UTC() } // Handle "saison" if (*fields)[1][0] == 'E' || (*fields)[1][0] == 'e' { horodate = horodate.Add(2 * time.Hour) } else { horodate = horodate.Add(1 * time.Hour) } // Mark field as treated *fields = append((*fields)[:1], (*fields)[2:]...) } else { horodate = time.Now().Truncate(time.Second).UTC() } return } func treatLines(c chan []byte) { for { line := <-c if len(line) <= 1 { continue } if computeChecksum(line[:len(line)-1]) != line[len(line)-1] { log.Printf("BAD checksum on %s: calculated: %c\n", line, computeChecksum(line[:len(line)-1])) continue } fields := bytes.Fields(line) horodate, err := getHorodate(&fields) if err != nil { log.Println(err) continue } log.Println(horodate, fields) } } func main() { var interval = flag.Duration("interval", 5*time.Second, "Minimum time between releve") flag.Parse() log.Println(interval) if len(flag.Args()) < 1 { log.Println("missing required argument: serial device (eg. /dev/ttyUSB0)") return } config := &serial.Config{ Name: flag.Args()[0], Baud: 9600, Size: 7, Parity: serial.ParityNone, StopBits: 1, } s, err := serial.OpenPort(config) if err != nil { log.Fatal(err) } c := make(chan []byte) go readSerial(s, c) go treatLines(c) interrupt := make(chan os.Signal, 1) signal.Notify(interrupt, os.Interrupt, syscall.SIGTERM) <-interrupt }