-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathgpio_mmap_collection.go
147 lines (131 loc) · 5.48 KB
/
gpio_mmap_collection.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
/// Author: Bernhard Tittelbach, btittelbach@github (c) 2015
package bbhw
import "sync"
// Uses the memory mapped IO to directly interface with AM335x registers.
// Same as MMappedGPIO, but part of a collection of GPIOs you can set all at once using database-like transactions.
type MMappedGPIOInCollection struct {
MMappedGPIO
collection *MMappedGPIOCollectionFactory
}
// Collection of GPIOs. Records SetState() calls after BeginTransactionRecordSetStates() has been called and delays their effect until EndTransactionApplySetStates() is called.
// Use it to toggle many GPIOs in the very same instant.
type MMappedGPIOCollectionFactory struct {
//4 32bit arrays to be copied to register
gpios_to_set []uint32
gpios_to_clear []uint32
record_changes bool
lock sync.Mutex
}
/// ---------- MMappedGPIOCollectionFactory ---------------
// Create a collection of GPIOs.
// Doubles as factory for the MMappedGPIOInCollection type.
func NewMMappedGPIOCollectionFactory() (gpiocf *MMappedGPIOCollectionFactory) {
mmapreg := getgpiommap()
gpiocf = new(MMappedGPIOCollectionFactory)
gpiocf.gpios_to_set = make([]uint32, len(mmapreg.memgpiochipreg32))
gpiocf.gpios_to_clear = make([]uint32, len(mmapreg.memgpiochipreg32))
return gpiocf
}
// Quickly and concurrently (i.e. faster than GPIOChips can react) applies new state
// by writing a 32 bit value to the corresponding CLEARDATA and SETDATA registers for each
// of the four gpio chips.
//
// Note that at LEAST one gpio for each gpiochip has to be exported in sysfs
// in order to active the corresponding gpiochip
// otherwise clocksource of gpiochip remains gated and we hang on receiving SIGBUS immediately after trying to write that register
// see: https://groups.google.com/forum/#!msg/beagleboard/OYFp4EXawiI/Mq6s3sg14HoJ
func (gpiocf *MMappedGPIOCollectionFactory) EndTransactionApplySetStates() {
mmapreg := getgpiommap()
gpiocf.lock.Lock()
defer gpiocf.lock.Unlock()
for i, _ := range gpiocf.gpios_to_clear {
if gpiocf.gpios_to_set[i] > 0 || gpiocf.gpios_to_clear[i] > 0 {
// only set registers which are known to be enabled (i.e. have been set by our code thus have had NewMMappedGPIO called, thus have been exported in sysfs and thus are provided with a clk by the CPU/Linux)
mmapreg.memgpiochipreg32[i][intgpio_cleardataout_o32_] = gpiocf.gpios_to_clear[i]
mmapreg.memgpiochipreg32[i][intgpio_setdataout_o32_] = gpiocf.gpios_to_set[i]
}
gpiocf.gpios_to_set[i] = 0
gpiocf.gpios_to_clear[i] = 0
}
gpiocf.record_changes = false
}
// Begin recording calls to SetState for later
func (gpiocf *MMappedGPIOCollectionFactory) BeginTransactionRecordSetStates() {
gpiocf.lock.Lock()
defer gpiocf.lock.Unlock()
gpiocf.record_changes = true
}
// Same as NewMMappedGPIO but part of a MMappedGPIOCollectionFactory
func (gpiocf *MMappedGPIOCollectionFactory) NewMMappedGPIO(number uint, direction int) (gpio *MMappedGPIOInCollection) {
NewSysfsGPIOOrPanic(number, direction).Close()
gpio = new(MMappedGPIOInCollection)
gpio.chipid, gpio.gpioid = calcGPIOAddrFromLinuxGPIONum(number)
gpio.collection = gpiocf
return gpio
}
func (gpiocf *MMappedGPIOCollectionFactory) NewGPIO(number uint, direction int) GPIOControllablePinInCollection {
return gpiocf.NewMMappedGPIO(number, direction)
}
/// ------------- MMappedGPIOInCollection Methods -------------------
func (gpio *MMappedGPIOInCollection) SetStateNow(state bool) error {
return gpio.MMappedGPIO.SetState(state)
}
func (gpio *MMappedGPIOInCollection) SetFutureState(state bool) error {
gpio.collection.lock.Lock()
defer gpio.collection.lock.Unlock()
if gpio.activelow != state {
gpio.collection.gpios_to_set[gpio.chipid] |= uint32(1 << gpio.gpioid)
gpio.collection.gpios_to_clear[gpio.chipid] &= ^uint32(1 << gpio.gpioid)
} else {
gpio.collection.gpios_to_clear[gpio.chipid] |= uint32(1 << gpio.gpioid)
gpio.collection.gpios_to_set[gpio.chipid] &= ^uint32(1 << gpio.gpioid)
}
return nil
}
/// Checks if State was Set during a transaction but not yet applied
/// state_known returns true if state was set (i.e. either a corresponding bit is set in either clear- or set-register)
/// state returns the future state (i.e. which bit was set)
/// SetActiveLow inverts state but obviously not state_known
/// err returns nil
func (gpio *MMappedGPIOInCollection) GetFutureState() (state_known, state bool, err error) {
gpio.collection.lock.Lock()
defer gpio.collection.lock.Unlock()
state = gpio.collection.gpios_to_set[gpio.chipid]&uint32(1<<gpio.gpioid) > 0
state_known = state
if !state_known {
state_known = gpio.collection.gpios_to_clear[gpio.chipid]&uint32(1<<gpio.gpioid) > 0
}
state = state != gpio.activelow
return
}
func (gpio *MMappedGPIOInCollection) SetState(state bool) error {
if gpio.collection.record_changes {
return gpio.SetFutureState(state)
} else {
return gpio.SetStateNow(state)
}
}
//this inverts the meaning of 0 and 1
//just like in SysFS, this has an immediate effect on the physical output
//unless BeginTransactionRecordSetStates() was called beforehand in which case its effect is delayed until EndTransactionApplySetStates()
func (gpio *MMappedGPIOInCollection) SetActiveLow(activelow bool) (err error) {
if gpio == nil {
panic("gpio == nil")
}
state_known := false
prev_state := false
if gpio.collection.record_changes {
state_known, prev_state, err = gpio.GetFutureState()
if err != nil {
return
}
}
if state_known == false {
prev_state, err = gpio.GetState()
if err != nil {
return
}
}
gpio.activelow = activelow
return gpio.SetState(prev_state)
}