Go – Parsed serial port input using goroutines not printing

Issue

I am taking input through the serial port (using an Arduino) and I want to parse the data. Here is what I have so far:

package main

import (
    "log"
    "github.com/tarm/serial"
    "bufio"
    "sync"
    "fmt"
)


func readFirstLine(data []string, wg *sync.WaitGroup){
    defer wg.Done()

    fmt.Printf("This is the sensor data:\n%q\n%q", data[0], data[1])

}

func readSecondLine(data []string, wg *sync.WaitGroup){
    defer wg.Done()

    fmt.Printf("This is the actuator data:\n%q", data[2])
}

func main() {
    usbRead := &serial.Config{Name: "COM5", Baud: 9600, ReadTimeout: 0}
    port, err := serial.OpenPort(usbRead)
    var wg sync.WaitGroup
    wg.Add(2)


    if err != nil {
        log.Fatal(err)
    }
    data := []string{}
    scanner := bufio.NewScanner(port)


    for scanner.Scan() {
        data = append(data, scanner.Text())
    }


    for {

    go readFirstLine(data, &wg)
    go readSecondLine(data, &wg)
    wg.Wait()

    }
}   

The serial port currently prints this (looped):

{"temperature":[27.7],"humidity":[46.9],"sensor":"DHT22"}
{"temperature":[25.41545],"sensor":"LM35DZ"}
{"blink":["true"],"actuator":"arduinoLED"}

I am trying to use goroutines to parse the data, and print this (should be looped as well):

This is the sensor data: 
{"temperature":[27.7],"humidity":[46.9],"sensor":"DHT22"}
{"temperature":[25.41545],"sensor":"LM35DZ"}
This is the actuator data: 
{"blink":["true"],"actuator":"arduinoLED"}

However, I am not getting an output. The program simply isn’t printing. I think it has to do with the way I am saving the data. Does anyone know how to fix this? And if it’s fixed, whether this use of goroutines is the correct method to achieving what I want?

Thank you so much.

Solution

The obvious problem with your code is invalid use of the waitgroup – you init it with 2 and then wait for it in infinite loop… also, your code never reaches to the part where it calls readFirstLine and readSecondLine, it is stuck in the scanner loop

I think the basic structure youre after would be something like following:

func main() {
    // create channels for data
    sensor := make(chan string)
    actuator := make(chan string)
    // launch goroutines which process the data
    var wg, pg sync.WaitGroup
    pg.Add(2)
    go func() {
       defer pg.Done()
       processSensorData(sensor)
    }()
    go func() {
       defer pg.Done()
       processActuatorData(actuator)
    }()
    // read from the data source
    usbRead := &serial.Config{Name: "COM5", Baud: 9600, ReadTimeout: 0}
    port, err := serial.OpenPort(usbRead)
    if err != nil {
        log.Fatal(err)
    }
    scanner := bufio.NewScanner(port)

    for scanner.Scan() {
        data := scanner.Text()
        wg.Add(1)
        go func(data string) {
           defer wg.Done()
           // figure out data packet type and
           // send it into approprioate channel
           if strings.Contains(data, `"sensor"`) {
              sensor <- data
           } else {
              actuator <- data
           }
        }(data)
    }
    // wait for all data to be sent for processing
    wg.Wait()
    // close the channels so goroutines terminate
    close(sensor)
    close(actuator)
    // wait for all data to be processed
    pg.Wait()
}

And the goroutines which process the data would be like:

func processSensorData(data chan string) {
   for d := range data {
      // do something with data
   }
}

Answered By – ain

Answer Checked By – Mary Flores (GoLangFix Volunteer)

Leave a Reply

Your email address will not be published.