forked from hybridgroup/gobot
-
Notifications
You must be signed in to change notification settings - Fork 0
/
robot.go
186 lines (164 loc) · 4.49 KB
/
robot.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
package gobot
import (
"errors"
"fmt"
"log"
)
// JSONRobot a JSON representation of a robot.
type JSONRobot struct {
Name string `json:"name"`
Commands []string `json:"commands"`
Connections []*JSONConnection `json:"connections"`
Devices []*JSONDevice `json:"devices"`
}
// Robot software representation of a physical board. A robot is a named
// entitity that manages multiple IO devices using a set of adaptors. Additionally
// a user can specificy custom commands to control a robot remotely.
type Robot struct {
Name string
Work func()
connections *connections
devices *devices
Commander
Eventer
}
type robots []*Robot
// Len counts the robots associated with this instance.
func (r *robots) Len() int {
return len(*r)
}
// Start initialises the event loop. All robots that were added will
// be automtically started as a result of this call.
func (r *robots) Start() (errs []error) {
for _, robot := range *r {
if errs = robot.Start(); len(errs) > 0 {
for i, err := range errs {
errs[i] = errors.New(fmt.Sprintf("Robot %q: %v", robot.Name, err))
}
return
}
}
return
}
// Each enumerates thru the robots and calls specified function
func (r *robots) Each(f func(*Robot)) {
for _, robot := range *r {
f(robot)
}
}
// NewRobot constructs a new named robot. Though a robot's name will be generated,
// we recommend that user take care of naming a robot for later access.
func NewRobot(name string, v ...interface{}) *Robot {
if name == "" {
name = fmt.Sprintf("%X", Rand(int(^uint(0)>>1)))
}
r := &Robot{
Name: name,
connections: &connections{},
devices: &devices{},
Work: nil,
Eventer: NewEventer(),
Commander: NewCommander(),
}
log.Println("Initializing Robot", r.Name, "...")
for i := range v {
switch v[i].(type) {
case []Connection:
log.Println("Initializing connections...")
for _, connection := range v[i].([]Connection) {
c := r.AddConnection(connection)
log.Println("Initializing connection", c.Name(), "...")
}
case []Device:
log.Println("Initializing devices...")
for _, device := range v[i].([]Device) {
d := r.AddDevice(device)
log.Println("Initializing device", d.Name(), "...")
}
case func():
r.Work = v[i].(func())
default:
log.Println("Unknown argument passed to NewRobot")
}
}
return r
}
// Start a robot instance and runs it's work function if any. You should not
// need to manually start a robot if already part of a Gobot application as the
// robot will be automatically started for you.
func (r *Robot) Start() (errs []error) {
log.Println("Starting Robot", r.Name, "...")
if cerrs := r.Connections().Start(); len(cerrs) > 0 {
errs = append(errs, cerrs...)
return
}
if derrs := r.Devices().Start(); len(derrs) > 0 {
errs = append(errs, derrs...)
return
}
if r.Work != nil {
log.Println("Starting work...")
r.Work()
}
return
}
// Devices retrieves all devices associated with this robot.
func (r *Robot) Devices() *devices {
return r.devices
}
// AddDevice adds a new device on this robot.
func (r *Robot) AddDevice(d Device) Device {
*r.devices = append(*r.Devices(), d)
return d
}
// Device finds a device by name.
func (r *Robot) Device(name string) Device {
if r == nil {
return nil
}
for _, device := range *r.devices {
if device.Name() == name {
return device
}
}
return nil
}
// Connections retrieves all connections on this robot.
func (r *Robot) Connections() *connections {
return r.connections
}
// AddConnection add a new connection on this robot.
func (r *Robot) AddConnection(c Connection) Connection {
*r.connections = append(*r.Connections(), c)
return c
}
// Connection finds a connection by name.
func (r *Robot) Connection(name string) Connection {
if r == nil {
return nil
}
for _, connection := range *r.connections {
if connection.Name() == name {
return connection
}
}
return nil
}
// ToJSON returns a JSON representation of the master robot.
func (r *Robot) ToJSON() *JSONRobot {
jsonRobot := &JSONRobot{
Name: r.Name,
Commands: []string{},
Connections: []*JSONConnection{},
Devices: []*JSONDevice{},
}
for command := range r.Commands() {
jsonRobot.Commands = append(jsonRobot.Commands, command)
}
r.Devices().Each(func(device Device) {
jsonDevice := device.ToJSON()
jsonRobot.Connections = append(jsonRobot.Connections, r.Connection(jsonDevice.Connection).ToJSON())
jsonRobot.Devices = append(jsonRobot.Devices, jsonDevice)
})
return jsonRobot
}