--- a/gobm65.go Wed Feb 15 22:16:55 2017 +0100
+++ b/gobm65.go Sun Feb 19 00:01:09 2017 +0100
@@ -1,23 +1,26 @@
package main
import (
+ "encoding/json"
"fmt"
"io"
+ "io/ioutil"
"log"
+ flag "github.com/docker/docker/pkg/mflag"
"github.com/tarm/serial"
)
type measurement struct {
- header int
- systolic int
- diastolic int
- pulse int
- month int
- day int
- hour int
- minute int
- year int
+ Header int
+ Systolic int
+ Diastolic int
+ Pulse int
+ Month int
+ Day int
+ Hour int
+ Minute int
+ Year int
}
func getData(s io.ReadWriteCloser, buf []byte, size int) (int, error) {
@@ -35,35 +38,35 @@
return t, nil
}
-func main() {
- c := &serial.Config{Name: "/dev/ttyUSB0", Baud: 4800}
- s, err := serial.OpenPort(c)
+func fetchData(dev string) (items []measurement, err error) {
+ c := &serial.Config{Name: dev, Baud: 4800}
+
+ var s *serial.Port
+ s, err = serial.OpenPort(c)
if err != nil {
- log.Fatal(err)
- return
+ return items, err
}
+ // =================== Handshake =====================
q := []byte("\xaa")
//log.Printf("Query: %q\n", q)
log.Println("Starting handshake...")
n, err := s.Write(q)
if err != nil {
- log.Fatal(err)
- return
+ return items, err
}
buf := make([]byte, 128)
n, err = getData(s, buf, 1)
if err != nil {
- log.Fatal(err)
- return
+ return items, err
}
if n == 1 && buf[0] == '\x55' {
log.Println("Handshake successful.")
} else {
log.Printf("(%d bytes) %q\n", n, buf[:n])
s.Close()
- return
+ return items, fmt.Errorf("handshake failed")
}
// =================== Desc =====================
@@ -72,8 +75,7 @@
log.Println("Requesting device description...")
n, err = s.Write(q)
if err != nil {
- log.Fatal(err)
- return
+ return items, err
}
n, err = getData(s, buf, 32)
@@ -85,14 +87,12 @@
log.Println("Requesting data counter...")
n, err = s.Write(q)
if err != nil {
- log.Fatal(err)
- return
+ return items, err
}
n, err = getData(s, buf, 1)
if err != nil {
- log.Fatal(err)
- return
+ return items, err
}
var nRecords int
if n == 1 {
@@ -100,38 +100,158 @@
nRecords = int(buf[0])
} else {
log.Printf("(%d bytes) %q\n", n, buf[:n])
- return
+ return items, fmt.Errorf("no measurement found")
}
+ // =================== Records =====================
for i := 0; i < nRecords; i++ {
q = []byte{'\xa3', uint8(i + 1)}
//log.Printf("Query: %q\n", q)
//log.Printf("Requesting measurement %d...", i+1)
n, err = s.Write(q)
if err != nil {
- log.Fatal(err)
- return
+ return items, err
}
n, err = getData(s, buf, 9)
//log.Printf("DESC> %q\n", buf[:n])
var data measurement
- data.header = int(buf[0])
- data.systolic = int(buf[1]) + 25
- data.diastolic = int(buf[2]) + 25
- data.pulse = int(buf[3])
- data.month = int(buf[4])
- data.day = int(buf[5])
- data.hour = int(buf[6])
- data.minute = int(buf[7])
- data.year = int(buf[8]) + 2000
- fmt.Printf("%d;%x;%d-%02d-%02d %02d:%02d;%d;%d;%d\n",
- i+1, data.header,
- data.year, data.month, data.day,
- data.hour, data.minute,
- data.systolic, data.diastolic, data.pulse)
+ data.Header = int(buf[0])
+ data.Systolic = int(buf[1]) + 25
+ data.Diastolic = int(buf[2]) + 25
+ data.Pulse = int(buf[3])
+ data.Month = int(buf[4])
+ data.Day = int(buf[5])
+ data.Hour = int(buf[6])
+ data.Minute = int(buf[7])
+ data.Year = int(buf[8]) + 2000
+ items = append(items, data)
}
s.Close()
+ return items, nil
}
+
+func loadFromJSONFile(filename string) (items []measurement, err error) {
+ data, err := ioutil.ReadFile(filename)
+ if err != nil {
+ return items, err
+ }
+
+ err = json.Unmarshal(data, &items)
+ return items, err
+}
+
+func mergeItems(newItems, oldItems []measurement) []measurement {
+ var result []measurement
+ var j int
+ // TODO: Would be better to compare dates and merge chronologically...
+ for _, nItem := range newItems {
+ result = append(result, nItem)
+ if j+1 <= len(oldItems) && nItem == oldItems[j] {
+ j++
+ }
+ }
+ if j+1 <= len(oldItems) {
+ result = append(result, oldItems[j:]...)
+ }
+ return result
+}
+
+func main() {
+ inFile := flag.String([]string{"-input-file", "i"}, "", "Input JSON file")
+ outFile := flag.String([]string{"-output-file", "o"}, "", "Output JSON file")
+ limit := flag.Uint([]string{"-limit", "l"}, 0, "Limit number of items")
+ format := flag.String([]string{"-format", "f"}, "", "Output format (csv, json)")
+ avg := flag.Bool([]string{"-average", "a"}, false, "Compute average")
+ merge := flag.Bool([]string{"-merge", "m"}, false,
+ "Try to merge input JSON file with fetched data")
+ device := flag.String([]string{"-device", "d"}, "/dev/ttyUSB0", "Serial device")
+
+ flag.Parse()
+
+ switch *format {
+ case "":
+ if *outFile == "" {
+ *format = "csv"
+ }
+ break
+ case "json", "csv":
+ break
+ default:
+ log.Fatal("Unknown output format. Possible choices are csv, json.")
+ }
+
+ var err error
+ var items []measurement
+
+ if *inFile == "" {
+ // Read from device
+ if items, err = fetchData(*device); err != nil {
+ log.Fatal(err)
+ }
+ } else {
+ // Read from file
+ var fileItems []measurement
+ if fileItems, err = loadFromJSONFile(*inFile); err != nil {
+ log.Fatal(err)
+ }
+ if *merge {
+ if items, err = fetchData(*device); err != nil {
+ log.Fatal(err)
+ }
+ items = mergeItems(items, fileItems)
+ } else {
+ items = fileItems
+ }
+ }
+
+ if *limit > 0 && len(items) > int(*limit) {
+ items = items[0:*limit]
+ }
+
+ var avgMeasure measurement
+ var avgCount int
+
+ for i, data := range items {
+ if *format == "csv" {
+ fmt.Printf("%d;%x;%d-%02d-%02d %02d:%02d;%d;%d;%d\n",
+ i+1, data.Header,
+ data.Year, data.Month, data.Day,
+ data.Hour, data.Minute,
+ data.Systolic, data.Diastolic, data.Pulse)
+ }
+
+ avgMeasure.Systolic += data.Systolic
+ avgMeasure.Diastolic += data.Diastolic
+ avgMeasure.Pulse += data.Pulse
+ avgCount++
+ }
+
+ if *avg && avgCount > 0 {
+ avgMeasure.Systolic /= avgCount
+ avgMeasure.Diastolic /= avgCount
+ avgMeasure.Pulse /= avgCount
+
+ fmt.Printf("Average: %d;%d;%d\n", avgMeasure.Systolic,
+ avgMeasure.Diastolic, avgMeasure.Pulse)
+ }
+
+ if *format == "json" || *outFile != "" {
+ rawJSON, err := json.MarshalIndent(items, "", " ")
+ if err != nil {
+ log.Fatal("Error:", err)
+ }
+
+ if *format == "json" {
+ fmt.Println(string(rawJSON))
+ }
+ if *outFile != "" {
+ err = ioutil.WriteFile(*outFile, rawJSON, 0600)
+ if err != nil {
+ log.Println("Could not write output file:", err)
+ }
+ }
+ }
+}