forked from alexellis/blinkt_go
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathblinkt.go
executable file
·152 lines (133 loc) · 3.41 KB
/
blinkt.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
// Package blinkt provides control over a Blinkt! LED display
package blinkt
// Blinkt provides control over a Blinkt! LED display
type Blinkt struct {
// Pixels is the number of pixels supported by the display
Pixels int
remainOnExit bool
cmdChan chan func()
closed chan struct{}
pp []pixel
apa APA102
}
// New creates a Blinkt to control the display.
func New() Blinkt {
bl := Blinkt{
Pixels: 8,
pp: make([]pixel, 8),
cmdChan: make(chan func()),
closed: make(chan struct{}),
}
bl.SetBrightness(50)
bl.apa.Open()
/* cmdLoop serialises writes to APA102 and closing */
go func() {
for {
cmd := <-bl.cmdChan
cmd()
select {
case <-bl.closed:
return
default:
}
}
}()
return bl
}
// Close the Blinkt interface.
func (bl *Blinkt) Close() {
closer := func() {
if !bl.remainOnExit {
bl.apa.WritePixels(make([]pixel, 8))
}
bl.apa.Close()
close(bl.closed)
}
select {
case bl.cmdChan <- closer:
<-bl.closed
case <-bl.closed:
}
}
// Clear sets all the pixels to off.
//
// Show must still be called to update the physical display.
func (bl *Blinkt) Clear() {
for p := range bl.pp {
bl.pp[p] &= 0xff000000
}
}
// ClearPixel sets the pixel to off.
//
// Show must still be called to update the physical display.
func (bl *Blinkt) ClearPixel(p int) {
bl.pp[p] &= 0xff000000
}
// SetClearOnExit controls the blanking of the display when the Blinkt is closed.
//
// When clearOneExit is true all pixels are turned off when Blinkt is closed.
// This is the default.
// When clearOneExit is false the display is left in its current state.
func (bl *Blinkt) SetClearOnExit(clearOnExit bool) {
bl.remainOnExit = !clearOnExit
}
// Show updates the physical dispolay with the values from Set/Clear.
func (bl *Blinkt) Show() {
pixels := append([]pixel(nil), bl.pp[:]...)
show := func() {
bl.apa.WritePixels(pixels)
}
select {
case bl.cmdChan <- show:
case <-bl.closed:
}
}
// SetAll sets all pixels to specified r, g, b colour.
//
// Show must be called to update the LEDs.
func (bl *Blinkt) SetAll(r, g, b int) {
for p := range bl.pp {
bl.SetPixel(p, r, g, b)
}
}
// SetPixel sets an individual pixel to specified r, g, b colour.
//
// Show must be called to update the LEDs.
func (bl *Blinkt) SetPixel(p, r, g, b int) {
px := bl.pp[p] & 0xff000000
px |= pixel((b << 16) | g<<8 | r)
bl.pp[p] = px
}
// SetBrightness sets the brightness of all pixels.
//
// Brightness should be in percent, i.e. 0 to 100.0.
// Greater than or equal to 100 is assumed to mean full brightness.
// Less than or equal to 0 is assumed to mean off.
func (bl *Blinkt) SetBrightness(brightness float64) {
brightnessInt := convertBrightnessToInt(brightness)
for i, px := range bl.pp {
px &^= 0xff000000
px |= pixel(brightnessInt << 24)
bl.pp[i] = px
}
}
// SetPixelBrightness sets the brightness of pixel p.
//
// Brightness should be in percent, i.e. 0 to 100.0.
// Greater than or equal to 100 is assumed to mean full brightness.
// Less than or equal to 0 is assumed to mean off.
func (bl *Blinkt) SetPixelBrightness(p int, brightness float64) {
brightnessInt := convertBrightnessToInt(brightness)
bl.pp[p] = pixel(uint(bl.pp[p])&^uint(0xff000000) | brightnessInt<<24)
}
type pixel uint
func convertBrightnessToInt(brightness float64) uint {
switch {
case brightness <= 0:
return 0
case brightness >= 100:
return 31
default:
return uint(brightness * 0.31)
}
}