Golang Setup

Ensure you have MATRIX CORE installed, before moving on.

Installing Golang

This setup will go through how to install Golang and the dependencies needed to create a Go application that can communicate with MATRIX CORE. Run the following on your Raspberry Pi.

Before downloading Go, you'll need to make sure you have git installed.

sudo apt-get install git

Download and install Go v1.11.2.

wget https://dl.google.com/go/go1.11.2.linux-armv6l.tar.gz
sudo tar -C /usr/local -xvzf go1.11.2.linux-armv6l.tar.gz
rm go1.11.2.linux-armv6l.tar.gz

Setup the GOPATH directory and environment variables.

mkdir -p ~/go/{bin,src,pkg}
echo -e "\n##Golang Environment Variables##" | sudo tee -a /etc/profile
echo 'export PATH=$PATH:/usr/local/go/bin' | sudo tee -a /etc/profile
echo 'export GOPATH=$HOME/go' | sudo tee -a /etc/profile
echo 'export PATH=$PATH:$GOPATH/bin' | sudo tee -a /etc/profile
source /etc/profile

Make sure Go is properly installed. The command below should output go version go1.11 linux/arm.

go version


Installing ZMQ Dependency

Although ZMQ has already been installed, Go requires an extra dependency.

sudo apt-get install libsodium-dev


Creating A Go Application

Making Your Project Directory

Use the following commands to initialize a Go project folder, in the home directory ~/ of your MATRIX device.
cd ~/
mkdir go-matrix-core-app
cd go-matrix-core-app
go mod init go-matrix-core-app

Installing Go Packages for ZMQ and Protocol Buffers

While inside your project folder, use the commands below to install the required dependencies for interacting with MATRIX CORE.

go get github.com/pebbe/zmq4
go get github.com/matrix-io/matrix-protos-go


Check If Everything Works

Creating main.go

To ensure your installation has succeeded, create a file named main.go and paste the code below.

package main

import (
    "fmt"
    "math/rand"
    "time"

    "github.com/golang/protobuf/proto"
    core "github.com/matrix-io/matrix-protos-go/matrix_io/malos/v1"
    zmq "github.com/pebbe/zmq4"
)

// Global Vars
var portStatus = make(chan string, 4) // Channel To Ensure Port Goroutines Are Called
var everloop = core.EverloopImage{}   // State Of All MATRIX LEDs

func main() {
    fmt.Println("Starting MATRIX CORE Everloop")

    // Asynchronously Start MATRIX CORE Ports
    go keepAlivePort()  // Ping Once
    go errorPort()      // Report Any Errors
    go dataUpdatePort() // Receive # Of Leds & Starts basePort()

    // Wait For Each Port Connection (ensures each goroutine is able to run)
    for portStatus := range portStatus {
        fmt.Println("received", portStatus)
    }
}

// BASE PORT \\ (port where configurations are sent)
func basePort() {
    // Connect ZMQ Socket To MATRIX CORE
    pusher, _ := zmq.NewSocket(zmq.PUSH)    // Create A Pusher Socket
    pusher.Connect("tcp://127.0.0.1:20021") // Connect Pusher To Base Port

    // Notify That Port Is Ready
    portStatus <- "Base Port: CONNECTED"

    // Keep Sending Everloop Image
    for {
        // Create (x) Amount Of Randomly Colored LEDs
        for i := int32(0); i < everloop.EverloopLength; i++ {
            led := core.LedValue{
                Red:   (uint32)(rand.Int31n(200) + 1),
                Green: (uint32)(rand.Int31n(255) + 1),
                Blue:  (uint32)(rand.Int31n(50) + 1),
                White: 0,
            }
            // Add New LED to Everloop LED Array
            everloop.Led = append(everloop.Led, &led)
        }

        // Create Everloop Driver Configuration Protocol
        configuration := core.DriverConfig{
            Image: &everloop,
        }
        //Encode Protocol Buffer
        var encodedConfiguration, _ = proto.Marshal(&configuration)
        // Send Protocol Buffer
        pusher.Send(string((encodedConfiguration)), 1)

        // Reset Everloop Array
        everloop.Led = []*core.LedValue{}
        // Loop delay
        time.Sleep(50 * time.Millisecond)
    }
}

// KEEP-ALIVE PORT \\ (port where pings are sent)
func keepAlivePort() {
    // Connect ZMQ Socket To MATRIX CORE
    pusher, _ := zmq.NewSocket(zmq.PUSH)    // Create A Pusher Socket
    pusher.Connect("tcp://127.0.0.1:20022") // Connect Pusher To Keep-Alive Port

    // Notify That Port Is Ready
    portStatus <- "Keep-Alive Port: CONNECTED"

    // Send Keep Alive Message
    pusher.Send("", 1)
}

// ERROR PORT \\ (port where errors are received)
func errorPort() {
    // Connect ZMQ Socket To MATRIX CORE
    subscriber, _ := zmq.NewSocket(zmq.SUB)     // Create A Subscriber Socket
    subscriber.Connect("tcp://127.0.0.1:20023") // Connect Subscriber To Data Update Port
    subscriber.SetSubscribe("")                 // Subscribe To Error Port Messages

    // Notify That Port Is Ready
    portStatus <- "Error Port: CONNECTED"

    // Wait For Error
    for {
        // On Error
        message, _ := subscriber.Recv(2)
        // Print Error
        fmt.Println("ERROR:", message)
    }
}

// DATA UPDATE PORT \\ (port where updates are received)
func dataUpdatePort() {
    // Connect ZMQ Socket To MATRIX CORE
    subscriber, _ := zmq.NewSocket(zmq.SUB)     // Create A Subscriber Socket
    subscriber.Connect("tcp://127.0.0.1:20024") // Connect Subscriber To Data Update Port
    subscriber.SetSubscribe("")                 // Subscribe To Data Update Port Messages

    // Notify That Port Is Ready
    portStatus <- "Data Update Port: CONNECTED"

    // Wait For Data
    for {
        // On Data
        message, _ := subscriber.Recv(2)
        // Decode Protocol Buffer & Update everloop Struct LED Count
        proto.Unmarshal([]byte(message), &everloop)
        // Print Data
        fmt.Print("\nEverloop Length: ", everloop.EverloopLength, "\n\n")

        // Start Base Port
        go basePort() // Send Configuration Message

        // Close Data Update Port
        return
    }
}

Running main.go

Once you have main.go ready, use the following command to run a simple hello world app.

go run main.go

Result

Next Steps

Now that everything is properly installed, learn more about the Everloop and other Driver Protocols MATRIX Core has to offer. Go examples coming soon!