forked from google/periph
/
streams.go
134 lines (126 loc) · 3.25 KB
/
streams.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
// Copyright 2017 The Periph Authors. All rights reserved.
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.
package bcm283x
import (
"encoding/binary"
"errors"
"fmt"
"periph.io/x/periph/conn/gpio/gpiostream"
)
// uint32ToBitLSBF packs a bit offset found on slice `d` (that is actually
// uint32) back into a densely packed Bits stream.
func uint32ToBitLSBF(w []byte, d []uint8, bit uint8, skip int) {
// Little endian.
x := bit / 8
d = d[x:]
bit -= 8 * x
mask := uint8(1) << bit
for i := range w {
w[i] = ((d[0]&mask)>>bit<<0 |
(d[skip*1]&mask)>>bit<<1 |
(d[skip*2]&mask)>>bit<<2 |
(d[skip*3]&mask)>>bit<<3 |
(d[skip*4]&mask)>>bit<<4 |
(d[skip*5]&mask)>>bit<<5 |
(d[skip*6]&mask)>>bit<<6 |
(d[skip*7]&mask)>>bit<<7)
d = d[skip*8:]
}
}
func getBit(b byte, index int, msb bool) byte {
var shift uint
if msb {
shift = uint(7 - index)
} else {
shift = uint(index)
}
return (b >> shift) & 1
}
func raster32Bits(s gpiostream.Stream, skip int, clear, set []uint32, mask uint32) error {
var msb bool
var bits []byte
switch b := s.(type) {
case *gpiostream.BitStream:
msb = !b.LSBF
bits = b.Bits
default:
return fmt.Errorf("unsupported type %T", b)
}
m := len(clear) / 8
if n := len(bits); n < m {
m = n
}
index := 0
for i := 0; i < m; i++ {
for j := 0; j < 8; j++ {
if getBit(bits[i], j, msb) != 0 {
for k := 0; k < skip; k++ {
set[index] |= mask
index++
}
} else {
for k := 0; k < skip; k++ {
clear[index] |= mask
index++
}
}
}
}
return nil
}
// raster32 rasters the stream into a uint32 stream with the specified masks to
// put in the correctly slice when the bit is set and when it is clear.
//
// `s` must be one of the types in this package.
func raster32(s gpiostream.Stream, skip int, clear, set []uint32, mask uint32) error {
if mask == 0 {
return errors.New("bcm283x: mask is 0")
}
if len(clear) == 0 {
return errors.New("bcm283x: clear buffer is empty")
}
if len(set) == 0 {
return errors.New("bcm283x: set buffer is empty")
}
if len(clear) != len(set) {
return errors.New("bcm283x: clear and set buffers have different length")
}
switch x := s.(type) {
case *gpiostream.BitStream:
// TODO
return raster32Bits(x, skip, clear, set, mask)
case *gpiostream.EdgeStream:
return errors.New("bcm283x: EdgeStream is not supported yet")
case *gpiostream.Program:
return errors.New("bcm283x: Program is not supported yet")
default:
return errors.New("bcm283x: unknown stream type")
}
}
// PCM/PWM DMA buf is encoded as little-endian and MSB first.
func copyStreamToDMABuf(w gpiostream.Stream, dst []uint32) error {
switch v := w.(type) {
case *gpiostream.BitStream:
if v.LSBF {
return errors.New("TODO(simokawa): handle BitStream.LSBF")
}
// This is big-endian and MSB first.
i := 0
for ; i < len(v.Bits)/4; i++ {
dst[i] = binary.BigEndian.Uint32(v.Bits[i*4:])
}
last := uint32(0)
if mod := len(v.Bits) % 4; mod > 0 {
for j := 0; j < mod; j++ {
last |= (uint32(v.Bits[i*4+j])) << uint32(8*(3-j))
}
dst[i] = last
}
return nil
case *gpiostream.EdgeStream:
return errors.New("TODO(simokawa): handle EdgeStream")
default:
return errors.New("unsupported Stream type")
}
}