diff --git a/cmd/demo/colorphase/main.go b/cmd/demo/colorphase/main.go new file mode 100644 index 0000000..10ba491 --- /dev/null +++ b/cmd/demo/colorphase/main.go @@ -0,0 +1,13 @@ +// Copyright 2018 Dan Jacques. All rights reserved. +// Use of this source code is governed under the MIT License +// that can be found in the LICENSE file. + +package main + +import ( + "github.com/danjacques/gopushpixels/demo/colorphase" +) + +func main() { + colorphase.Main() +} diff --git a/demo/colorphase/app.go b/demo/colorphase/app.go new file mode 100644 index 0000000..d6c65ab --- /dev/null +++ b/demo/colorphase/app.go @@ -0,0 +1,120 @@ +// Copyright 2018 Dan Jacques. All rights reserved. +// Use of this source code is governed under the MIT License +// that can be found in the LICENSE file. + +package colorphase + +import ( + "context" + "flag" + "log" + "time" + + "github.com/danjacques/gopushpixels/device" + "github.com/danjacques/gopushpixels/discovery" + "github.com/danjacques/gopushpixels/pixel" +) + +var ( + fps = flag.Int("fps", 30, "FPS that colors will be cycled.") +) + +// Main is the main entry point. +func Main() { + flag.Parse() + + // Calculate sleep interval from FPS. + sleepInterval := time.Second / (time.Second * time.Duration(*fps)) + + // Start discovery. + var l discovery.Listener + conn, err := discovery.DefaultListenerConn().ListenMulticastUDP4() + if err != nil { + log.Fatalf("Couldn't listen for discovery packets: %s", err) + } + defer conn.Close() + if err := l.Start(conn); err != nil { + log.Fatalf("Couldn't start discovery listener: %s", err) + } + + var reg discovery.Registry + c := context.Background() + for { + dh, err := l.Accept(c) + if err != nil { + log.Fatalf("Error listening for discovery packets: %s", err) + } + if d, isNew := reg.Observe(dh); isNew { + go cycleColors(d, sleepInterval) + } + } +} + +func cycleColors(d device.D, sleepInterval time.Duration) { + log.Printf("Cycling on device: %s", d.ID()) + + sender, err := d.Sender() + if err != nil { + log.Printf("Could't create sender for device %q: %s", d.ID(), err) + return + } + defer sender.Close() + + // Create a mutable state for the device. + var m device.Mutable + m.Initialize(d.DiscoveryHeaders()) + + var c cycler + for { + // Cycle colors. + // + // First, shift all pixels towards the end. + next := c.Next() + for s := 0; s < m.NumStrips(); s++ { + for i := m.PixelsPerStrip() - 1; i > 0; i-- { + m.SetPixel(s, i, m.GetPixel(s, i-1)) + } + m.SetPixel(s, 0, next) + } + + // Send any update packets. + if pkt := m.SyncPacket(); pkt != nil { + if err := sender.SendPacket(pkt); err != nil { + log.Printf("Couldn't send packet to device %q: %s", d.ID(), err) + return + } + } + + time.Sleep(sleepInterval) + } +} + +type cycler struct { + r, g, b int + offset int +} + +func (c *cycler) Next() (p pixel.P) { + var v *int + var pos *byte + switch c.offset { + case 0: + v, pos = &c.r, &p.Red + case 1: + v, pos = &c.g, &p.Green + case 2: + v, pos = &c.b, &p.Blue + } + + *v++ + switch { + case *v > 0x1FF: + *v, *pos = 0, 0 + c.offset = ((c.offset + 1) % 3) + case *v > 0xFF: + *pos = 0xFF - byte(*v) + default: + *pos = byte(*v) + } + return +}