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 }