DEV Community

David G. Simmons
David G. Simmons

Posted on • Originally published at davidgs.com on

Adventures in Golang

29437996I’m not a Golang developer. Let’s just get that out of the way up front. I’ve developed a few things in Go, but a Go developer I’m not. I sort of need to be, but it hasn’t been essential. I decided that it was really time to take the plunge and get serious about Go. Seriously, there’s only so much you can learn by reading the internet.

To that end, I have taken 2 actions:

  1. I’m going to Gophercon in Denver next week
  2. I ported a library from C to Go

It’s #2 that I’ll write about here today and not because I think I did an exceptionally good job of it but because it may be useful to others, and just to record what I’ve done, in case I want to refer to it later.

Read on if you’re interested!

Background

I’ve been working on a little IoT project (duh) that is using a Raspberry Pi. It also uses a Bosch BME280 breakout board from Adafruit. Which would be super easy to deal with if I was running it on an Arduino. But I’m not. And yes, I’m aware that there are ways to just run Arduino sketches on Raspberry Pi but I really am not such a fan of Arduino sketches, so I decided to do it another way.

The sensor is I2C, of course, so there was that. It’s easy to make the I2C buss accessible on Raspberry Pi (just run raspi-config and Bob’s your Uncle), but dealing with I2C devices is a little harder. I tried a couple of C-based I2C libraries but most of them gave … unexpected results. The one I found that was the closest was by a GitHub user called “BitBank2” (https://github.com/bitbank2/bme280) so I decided to use his. I was able to compile it and run the example program with at least reasonable results. But then I still had to call it from some user-space program in order to get the results. I should have smelled a rathole coming, but of course I didn’t.

I’ll just port it to Go! Sounded reasonable at the time.

Porting to Go

It was actually a lot easier than I thought it would be. First, there’s a great Go I2C library from @rakyll that works great. I had used it to access a SenseAir K30 CO2 sensor, so I thought I’d start there.

Since the library I was starting from worked, I figured the easiest thing to do would be to just do a semi-straight translation. I’d copy in a few lines of the C code, and then make it Go. There were, of course, some things that just wouldn’t work well. For instance, the I2C library wants to deal in bytes and byte slices, so I couldn’t very well just use the ints that the C library used. Also, the C library used a slew of static global variables, and that was also not going to work well in go. So I made adjustments:

static int calT1,calT2,calT3;
static int calP1, calP2, calP3, calP4, calP5, calP6, calP7, calP8, calP9;
static int calH1, calH2, calH3, calH4, calH5, calH6;
Enter fullscreen mode Exit fullscreen mode

became:

type BME280 struct {
 Dev *i2c.Device
 tConfig []int
 pConfig []int
 hConfig []int
}
Enter fullscreen mode Exit fullscreen mode

and

device.tConfig = make([]int, 3)
device.pConfig = make([]int, 9)
device.hConfig = make([]int, 6)
Enter fullscreen mode Exit fullscreen mode

Pretty much the rest of it was a simple translation of turning a C language construct into a Golang construct.

// Prepare temperature calibration data
calT1 = ucCal[0] + (ucCal[1] << 8);
calT2 = ucCal[2] + (ucCal[3] << 8);
if (calT2 > 32767) calT2 -= 65536; // negative value
calT3 = ucCal[4] + (ucCal[5] << 8);
if (calT3 > 32767) calT3 -= 65536;
Enter fullscreen mode Exit fullscreen mode

Turned into:

// time to set up the calibration
 device.tConfig[0] = int(ucCal[0]) + (int(ucCal[1]) << 8)
 device.tConfig[1] = int(ucCal[2]) + (int(ucCal[3]) << 8)
 if device.tConfig[1] > 32767 {
     device.tConfig[1] -= 65536
 }
 device.tConfig[2] = int(ucCal[4]) + (int(ucCal[5]) << 8)
 if device.tConfig[2] > 32767 {
     device.tConfig[2] -= 65536
 }
Enter fullscreen mode Exit fullscreen mode

And so on.

Now any Go program can simply do the following:

package main
import (
  "fmt"
  "github.com/davidgs/bme280_go"
  "time"
)
func main() {
  dev := "/dev/i2c-1"
  bme := bme280_go.BME280{}
  r := bme.BME280Init(dev)
  if r < 0 {
    fmt.Println("Error")
  }
  rets := bme.BME280ReadValues()
  f := 0.00
  f = float64(rets[0]) / 100.00
  fmt.Println("Temp: ", f)
  f = float64(rets[2]) / 1024.00
  fmt.Println("Humidity: ", f)
  bme.Dev.Close()
}
Enter fullscreen mode Exit fullscreen mode

because a call to BME280ReadValues returns a simple slice of ints as Temperature, Pressure, and Humidity, in that order. Note : The pressure calculation is currently broken, so I don’t suggest using it.

As I said, it was surprisingly easy to get it all working! I now have a motley-fully functioning library for the Adafruit ZBME280 Breakout Board in GoLang!

Next up is to write a similar library for the SenseAir K30 sensor. I’ve got the sensor working just fine, I just have to turn the code into a library.

If you’re interested in using this library, it’s freely available on my GitHub.

The post Adventures in Golang appeared first on David G. Simmons.

Top comments (1)

Collapse
 
arhuman profile image
arhuman

First let me correct you ;-)
You write some Go code, you're a Go developer!
You might be a learning developer, but guess what, we all are!
Don't let anybody fool you into thinking otherwise.

That being said, it's a great article, thanks for sharing, fellow Gopher!

I hope you enjoyed GopherCon...