From ffe46a0f4b7d6c811fad6648748295d92b6411bc Mon Sep 17 00:00:00 2001 From: Giovanni Harting <539@idlegandalf.com> Date: Tue, 12 Dec 2017 19:18:31 +0100 Subject: [PATCH] inital commit of PCA9685 backend in go --- .gitignore | 99 ++++++++++++++++++++++++++++++++++ .gitmodules | 3 ++ config.yaml | 9 ++++ main.go | 149 ++++++++++++++++++++++++++++++++++++++++++++++++++++ proto | 1 + 5 files changed, 261 insertions(+) create mode 100644 .gitignore create mode 100644 .gitmodules create mode 100644 config.yaml create mode 100644 main.go create mode 160000 proto diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e92ca14 --- /dev/null +++ b/.gitignore @@ -0,0 +1,99 @@ +# Created by https://www.gitignore.io/api/go,linux,intellij+all + +### Go ### +# Binaries for programs and plugins +*.exe +*.dll +*.so +*.dylib + +# Test binary, build with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736 +.glide/ + +### Intellij+all ### +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff: +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/dictionaries + +# Sensitive or high-churn files: +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.xml +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml + +# Gradle: +.idea/**/gradle.xml +.idea/**/libraries + +# CMake +cmake-build-debug/ + +# Mongo Explorer plugin: +.idea/**/mongoSettings.xml + +## File-based project format: +*.iws + +## Plugin-specific files: + +# IntelliJ +/out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# Ruby plugin and RubyMine +/.rakeTasks + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +### Intellij+all Patch ### +# Ignores the whole idea folder +# See https://github.com/joeblau/gitignore.io/issues/186 and https://github.com/joeblau/gitignore.io/issues/360 + +.idea/ + +### Linux ### +*~ + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* + +# End of https://www.gitignore.io/api/go,linux,intellij+all + +bin/ +pkg/ +src/ + diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..d36f1e9 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "proto"] + path = proto + url = git@github.com:LED-Freaks/LedD-protobuf.git diff --git a/config.yaml b/config.yaml new file mode 100644 index 0000000..2cfc30a --- /dev/null +++ b/config.yaml @@ -0,0 +1,9 @@ +name: PCA9685 +ledd: + host: "127.0.0.1" + port: 5640 +pca9685: + device: "dev/i2c-2" + address: 0x40 + minpulse: 0 + maxpulse: 1000 diff --git a/main.go b/main.go new file mode 100644 index 0000000..d3104dd --- /dev/null +++ b/main.go @@ -0,0 +1,149 @@ +package main + +import ( + "github.com/op/go-logging" + "golang.org/x/exp/io/i2c" + "gopkg.in/yaml.v2" + "os" + "os/signal" + "syscall" + "io/ioutil" + "net" + "encoding/binary" + "gen/ledd" + "github.com/golang/protobuf/proto" + "github.com/sergiorb/pca9685-golang/device" + "fmt" +) + +// CONSTANTS + +const VERSION = "0.1" +const RESOLUTION = 4096 +const CHANNEL = 16 + +// STRUCTS + +type config struct { + Name string + Ledd struct { + Host string + Port int + } + Pca9685 struct { + Device string + Address int + MinPulse int + MaxPulse int + } +} + +type LedD struct { + name string + socket net.Conn + data chan []byte +} + +var log = logging.MustGetLogger("LedD") +var ledDaemon = &LedD{} +var pca9685 = device.PCA9685{} + + +func check(e error) { + if e != nil { + panic(e) + } +} + +func (ledd *LedD) receive() { + for { + message := make([]byte, 4096) + length, err := ledd.socket.Read(message) + if err != nil { + ledd.socket.Close() + break + } + if length > 0 { + msgLen := binary.BigEndian.Uint32(message[0:3]) + + log.Debugf("[%s] Read %d bytes, first protobuf is %d long", ledd.name, length, msgLen) + + backendMsg := &ledd.BackendWrapperMessage{} + err = proto.Unmarshal(message[4:msgLen], backendMsg) + if err != nil { + log.Warningf("[%s] Couldn't decode protobuf msg!", backend.niceName()) + continue + } + + switch msg := backendMsg.Msg.(type) { + case *ledd.BackendWrapperMessage_MLedd: + ledd.name = msg.MLedd.Name + log.Infof("Connection with LedD (%s) etablished and registered", msg.MLedd.Name) + } + } + } +} + +func (ledd *LedD) send() { + defer ledd.socket.Close() + for { + select { + case message, ok := <-ledd.data: + if !ok { + return + } + ledd.socket.Write(message) + } + } +} + +func main() { + killSignals := make(chan os.Signal, 1) + signal.Notify(killSignals, syscall.SIGINT, syscall.SIGTERM) + + log.Info("LedD", VERSION) + config := config{} + + content, err := ioutil.ReadFile("config.yaml") + check(err) + + err = yaml.Unmarshal(content, &config) + check(err) + + i2cDevice, err := i2c.Open(&i2c.Devfs{Dev: config.Pca9685.Device}, config.Pca9685.Address) + check(err) + defer i2cDevice.Close() + + pca9685 := device.NewPCA9685(i2cDevice, "PWM Controller", config.Pca9685.MinPulse, config.Pca9685.MaxPulse, log) + pca9685.Init() + + conn, err := net.Dial("tcp4", fmt.Sprintf("%s:%d", config.Ledd.Host, config.Ledd.Port)) + check(err) + + ledDaemon = &LedD{ + socket:conn, + data: make (chan []byte), + } + + go ledDaemon.send() + go ledDaemon.receive() + + wrapperMsg := &ledd.BackendWrapperMessage{ + Msg: &ledd.BackendWrapperMessage_MBackend{ + MBackend: &ledd.Backend{ + Name: config.Name, + Channel: CHANNEL, + Type: "PCA9685", + Resolution: RESOLUTION, + Version: VERSION, + }, + }, + } + + data, err := proto.Marshal(wrapperMsg) + check(err) + + ledDaemon.data <- data + + <-killSignals +} diff --git a/proto b/proto new file mode 160000 index 0000000..c0b46db --- /dev/null +++ b/proto @@ -0,0 +1 @@ +Subproject commit c0b46db0cf38cfd192d6a787c0328cbff8db42fb