forked from hybridgroup/gobot
-
Notifications
You must be signed in to change notification settings - Fork 0
/
robot.go
191 lines (169 loc) · 4.9 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
187
188
189
190
191
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"`
}
// NewJSONRobot returns a JSON representation of the robot.
func NewJSONRobot(robot *Robot) *JSONRobot {
jsonRobot := &JSONRobot{
Name: robot.Name,
Commands: []string{},
Connections: []*JSONConnection{},
Devices: []*JSONDevice{},
}
for command := range robot.Commands() {
jsonRobot.Commands = append(jsonRobot.Commands, command)
}
robot.Devices().Each(func(device Device) {
jsonDevice := NewJSONDevice(device)
jsonRobot.Connections = append(jsonRobot.Connections, NewJSONConnection(robot.Connection(jsonDevice.Connection)))
jsonRobot.Devices = append(jsonRobot.Devices, jsonDevice)
})
return jsonRobot
}
// Robot is a named entitity that manages a collection of connections and devices.
// It containes it's own work routine and a collection of
// custom commands to control a robot remotely via the Gobot api.
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 returns a new Robot given a name and optionally accepts:
//
// []Connection: Connections which are automatically started and stopped with the robot
// []Device: Devices which are automatically started and stopped with the robot
// func(): The work routine the robot will execute once all devices and connections have been initialized and started
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 returns all devices associated with this robot.
func (r *Robot) Devices() *devices {
return r.devices
}
// AddDevice adds a new device to the robots collection of devices. Returns the
// added device.
func (r *Robot) AddDevice(d Device) Device {
*r.devices = append(*r.Devices(), d)
return d
}
// Device returns a device given a name. Returns nil on no device.
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 returns all connections associated with this robot.
func (r *Robot) Connections() *connections {
return r.connections
}
// AddConnection adds a new connection to the robots collection of connections.
// Returns the added connection.
func (r *Robot) AddConnection(c Connection) Connection {
*r.connections = append(*r.Connections(), c)
return c
}
// Connection returns a connection given a name. Returns nil on no connection.
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
}