-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathemogo.go
194 lines (173 loc) · 4.82 KB
/
emogo.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
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
/*
The emogo package provides go bindings for emokit
(https://github.com/openyou/emokit).
*/
package emogo
import (
"errors"
"unsafe"
)
// #include <emokit/emokit.h>
// #include <stdint.h>
// #cgo LDFLAGS: -lemokit
import "C"
// These are defined in emokit.h and reproduced here as cgo isn't
// linking them in for some reason.
const (
EMOKIT_VID int = 0x21a1
EMOKIT_PID = 0x0001
EmokitPacketSize = 32
)
// HeadsetType is one of (DeveloperHeadset,ConsumerHeadset) - this is a
// kludge around different device identifiers.
//
// FIXME: do this properly in emokit
type HeadsetType uint
const (
DeveloperHeadset HeadsetType = 0
ConsumerHeadset HeadsetType = 1
)
// EmokitContext represents a connection to an EPOC device.
type EmokitContext struct {
eeg *C.struct_emokit_device
}
// NewEmokitContext initializes the Emokit context. Call Shutdown on the
// context when done.
func NewEmokitContext(t HeadsetType) (*EmokitContext, error) {
e := new(EmokitContext)
e.eeg = C.emokit_create()
ret := C.emokit_open(e.eeg, C.int(EMOKIT_VID), C.int(EMOKIT_PID), C.uint(t))
if ret != 0 {
return nil, errors.New("Cannot access device.")
}
return e, nil
}
// Shutdown closes the connection to the EPOC and frees associated
// memory.
func (c *EmokitContext) Shutdown() {
C.emokit_close(c.eeg)
C.emokit_delete(c.eeg)
}
// EmokitSensor represents the state of one sensor/electrode. It
// consists of both the value reading and the contact quality.
type EmokitSensor struct {
Value int
Quality int
}
type EmokitFrame struct {
raw []byte
rendered C.struct_emokit_frame
F3 EmokitSensor
FC6 EmokitSensor
P7 EmokitSensor
T8 EmokitSensor
F7 EmokitSensor
F8 EmokitSensor
T7 EmokitSensor
P8 EmokitSensor
AF4 EmokitSensor
F4 EmokitSensor
AF3 EmokitSensor
O2 EmokitSensor
O1 EmokitSensor
FC5 EmokitSensor
}
func NewEmokitFrame() *EmokitFrame {
f := new(EmokitFrame)
f.raw = make([]byte, EmokitPacketSize)
return f
}
// parseSensors populates the EmokitSensor elements of the frame from
// the C struct.
func (f *EmokitFrame) parseSensors() {
f.F3.Value = int(f.rendered.F3)
f.F3.Quality = int(f.rendered.cq.F3)
f.FC6.Value = int(f.rendered.FC6)
f.FC6.Quality = int(f.rendered.cq.FC6)
f.P7.Value = int(f.rendered.P7)
f.P7.Quality = int(f.rendered.cq.P7)
f.T8.Value = int(f.rendered.T8)
f.T8.Quality = int(f.rendered.cq.T8)
f.F7.Value = int(f.rendered.F7)
f.F7.Quality = int(f.rendered.cq.F7)
f.F8.Value = int(f.rendered.F8)
f.F8.Quality = int(f.rendered.cq.F8)
f.T7.Value = int(f.rendered.T7)
f.T7.Quality = int(f.rendered.cq.T7)
f.P8.Value = int(f.rendered.P8)
f.P8.Quality = int(f.rendered.cq.P8)
f.AF4.Value = int(f.rendered.AF4)
f.AF4.Quality = int(f.rendered.cq.AF4)
f.F4.Value = int(f.rendered.F4)
f.F4.Quality = int(f.rendered.cq.F4)
f.AF3.Value = int(f.rendered.AF3)
f.AF3.Quality = int(f.rendered.cq.AF3)
f.O2.Value = int(f.rendered.O2)
f.O2.Quality = int(f.rendered.cq.O2)
f.O1.Value = int(f.rendered.O1)
f.O1.Quality = int(f.rendered.cq.O1)
f.FC5.Value = int(f.rendered.FC5)
f.FC5.Quality = int(f.rendered.cq.FC5)
}
// readData reads data from the EPOC dongle and returns 0 on success, <0
// on error.
func (e *EmokitContext) readData() error {
n := C.emokit_read_data(e.eeg)
if n >= 0 {
return nil
}
return errors.New("emokit_read_data failed")
}
func (e *EmokitContext) getNextFrame() (*EmokitFrame, error) {
f := NewEmokitFrame()
f.rendered = C.emokit_get_next_frame(e.eeg)
if f.rendered.counter == 0 {
return nil, errors.New("Could not read raw packet.")
}
C.emokit_get_raw_frame(e.eeg, (*C.uchar)(unsafe.Pointer(&f.raw[0])))
f.parseSensors()
return f, nil
}
// GetFrame returns the next available EPOC frame. If there is no frame
// to be read, the error value will be EAGAIN.
func (e *EmokitContext) GetFrame() (*EmokitFrame, error) {
err := e.readData()
if err == nil {
f, err := e.getNextFrame()
if err != nil {
return nil, err
}
return f, nil
}
return nil, err
}
// Count returns the number of EPOC devices connected.
func (e *EmokitContext) Count() int {
n := C.emokit_get_count(e.eeg, C.int(EMOKIT_VID), C.int(EMOKIT_PID))
return int(n)
}
// Raw returns the (unencrypted) raw EPOC frame.
func (f *EmokitFrame) Raw() []byte {
return f.raw
}
// Gyro returns the current (x,y) of the frame's Gyro value.
func (f *EmokitFrame) Gyro() (int,int) {
return int(f.rendered.gyroX), int(f.rendered.gyroY)
}
// BatteryFrame returns true if the frame contains a battery-level
// value, otherwise false.
func (f *EmokitFrame) BatteryFrame() bool {
if f.Counter() == 128 {
return true
}
return false
}
// Battery returns the current battery level of the device. May be 0 if
// the battery level has not yet been read.
func (f *EmokitFrame) Battery() uint {
return uint(f.rendered.battery)
}
// Counter returns the counter value of the frame (0-127).
func (f *EmokitFrame) Counter() uint {
return uint(f.rendered.counter)
}