sgslib 1.5.0 → 1.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/exe/sgs_otto +0 -0
- data/lib/sgs/alarm.rb +21 -11
- data/lib/sgs/bearing.rb +32 -3
- data/lib/sgs/config.rb +0 -1
- data/lib/sgs/course.rb +18 -5
- data/lib/sgs/diagnostics.rb +2 -1
- data/lib/sgs/gps.rb +35 -2
- data/lib/sgs/location.rb +115 -59
- data/lib/sgs/logger.rb +1 -8
- data/lib/sgs/mission.rb +61 -184
- data/lib/sgs/mission_status.rb +20 -9
- data/lib/sgs/navigate.rb +206 -63
- data/lib/sgs/nmea.rb +3 -2
- data/lib/sgs/otto.rb +317 -45
- data/lib/sgs/redis_base.rb +9 -9
- data/lib/sgs/report.rb +6 -1
- data/lib/sgs/rpc.rb +5 -6
- data/lib/sgs/version.rb +1 -1
- data/lib/sgs/waypoint.rb +2 -2
- data/lib/sgslib.rb +1 -4
- data/sgslib.gemspec +7 -5
- metadata +52 -12
- data/exe/sgs_nav +0 -43
data/lib/sgs/nmea.rb
CHANGED
@@ -87,7 +87,7 @@ module SGS
|
|
87
87
|
if @args.count < 12 or @args.count > 13
|
88
88
|
return nil
|
89
89
|
end
|
90
|
-
gps =
|
90
|
+
gps = GPS.new
|
91
91
|
gps.is_valid if @args[2] == "A"
|
92
92
|
hh = @args[1][0..1].to_i
|
93
93
|
mm = @args[1][2..3].to_i
|
@@ -100,7 +100,8 @@ module SGS
|
|
100
100
|
gps.time = Time.gm(yy, mn, dd, hh, mm, ss, us)
|
101
101
|
pos = {"latitude" => ll_nmea(@args[3,4]),
|
102
102
|
"longitude" => ll_nmea(@args[5,6])}
|
103
|
-
gps.location = Location.
|
103
|
+
gps.location = Location.new
|
104
|
+
gps.location.parse_hash(pos)
|
104
105
|
gps.sog = @args[7].to_f
|
105
106
|
gps.cmg = Bearing.dtor @args[8].to_f
|
106
107
|
gps
|
data/lib/sgs/otto.rb
CHANGED
@@ -31,125 +31,397 @@
|
|
31
31
|
# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
32
32
|
#
|
33
33
|
# ABSTRACT
|
34
|
+
# This daemon handles all serial I/O with the low-level board (Otto). Otto
|
35
|
+
# publishes various status messages at regular intervals, and has a series
|
36
|
+
# of registers which can be used to alter the low-level operational state.
|
37
|
+
# This daemon code has two threads. One thread listens for RPCs to update
|
38
|
+
# Otto register state, and the other listens for status messages from Otto.
|
39
|
+
# The class also has helper functions for converting between Otto data
|
40
|
+
# formats (usually 8bit) and internal formats (usually floating point).
|
34
41
|
#
|
42
|
+
require 'serialport'
|
43
|
+
require 'msgpack'
|
35
44
|
|
36
45
|
##
|
37
46
|
# Routines for interfacing with the low-level microcontroller.
|
38
47
|
#
|
39
48
|
module SGS
|
40
49
|
class Otto < RedisBase
|
41
|
-
attr_accessor :
|
42
|
-
attr_accessor :mode, :rudder_m, :rudder_c, :sail_m, :sail_c
|
50
|
+
attr_accessor :mode, :serial_port
|
43
51
|
attr_accessor :bv_m, :bv_c, :bi_m, :bi_c, :bt_m, :bt_c, :sv_m, :sv_c
|
52
|
+
attr_reader :alarm_status
|
53
|
+
attr_reader :actual_rudder, :actual_sail
|
54
|
+
attr_reader :otto_mode, :otto_timestamp, :telemetry
|
44
55
|
|
56
|
+
#
|
57
|
+
# Updates to Otto are done by setting an 8bit register value, as below.
|
58
|
+
ALARM_CLEAR_REGISTER = 0
|
59
|
+
MISSION_CONTROL_REGISTER = 1
|
60
|
+
MODE_REGISTER = 2
|
61
|
+
BUZZER_REGISTER = 3
|
62
|
+
RUDDER_ANGLE_REGISTER = 4
|
63
|
+
SAIL_ANGLE_REGISTER = 5
|
64
|
+
COMPASS_HEADING_REGISTER = 6
|
65
|
+
MIN_COMPASS_REGISTER = 7
|
66
|
+
MAX_COMPASS_REGISTER =8
|
67
|
+
AWA_HEADING_REGISTER = 9
|
68
|
+
MIN_AWA_REGISTER = 10
|
69
|
+
MAX_AWA_REGISTER = 11
|
70
|
+
WAKE_DURATION_REGISTER = 12
|
71
|
+
NEXT_WAKEUP_REGISTER = 13
|
72
|
+
MAX_REGISTER = 14
|
73
|
+
|
74
|
+
#
|
75
|
+
# This is different from mission mode. This mode defines how Otto should
|
76
|
+
# operate. Inert means "do nothing". Diagnostic mode is for the low-level
|
77
|
+
# code to run self-checks and calibrations. Manual means that the upper
|
78
|
+
# level system controls the rudder and sail angle without any higher-level
|
79
|
+
# PID controller. Track compass means that the boat will try to keep the
|
80
|
+
# actual compass reading within certain parameters, and track AWA will
|
81
|
+
# try to maintain a specific "apparent wind angle".
|
45
82
|
MODE_INERT = 0
|
46
|
-
|
83
|
+
MODE_DIAG = 1
|
47
84
|
MODE_MANUAL = 2
|
48
|
-
|
49
|
-
|
85
|
+
MODE_REMOTE = 3
|
86
|
+
MODE_TRACK_COMPASS = 4
|
87
|
+
MODE_TRACK_AWA = 5
|
50
88
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
89
|
+
#
|
90
|
+
# Define some tweaks for rudder and sail setting. Rudder goes from
|
91
|
+
# +/-40 degrees, with zero indicating a straight rudder. On Otto, this
|
92
|
+
# translates to 0 (for -40.0), 128 (for the zero position) and 255 (for
|
93
|
+
# +40 degrees of rudder). A fully trimmed-in sail is zero and a fully
|
94
|
+
# extended sail is 255 (0->100 from a function perspective).
|
95
|
+
RUDDER_MAX = 40.0
|
96
|
+
RUDDER_MIN = -40.0
|
97
|
+
RUDDER_M = 3.175
|
98
|
+
RUDDER_C = 128.0
|
99
|
+
SAIL_MAX = 100.0
|
100
|
+
SAIL_MIN = 0.0
|
101
|
+
SAIL_M = 2.55
|
102
|
+
SAIL_C = 0.0
|
55
103
|
|
56
104
|
#
|
57
|
-
# Set up some useful defaults. We assume rudder goes from 0 to
|
58
|
-
# the sail angle.
|
105
|
+
# Set up some useful defaults. We assume rudder goes from 0 to 255 as does
|
106
|
+
# the sail angle.
|
59
107
|
def initialize
|
108
|
+
serial_port = nil
|
60
109
|
#
|
61
|
-
|
62
|
-
|
63
|
-
@
|
64
|
-
|
65
|
-
|
110
|
+
# Set some defaults for the read-back parameters
|
111
|
+
# The following five parameters are reported back by Otto with a status
|
112
|
+
# message, and are read-only. @alarm_status is 16 bits while the other
|
113
|
+
# four are 8-bit values. The helper methods convert these 8-bit values
|
114
|
+
# into radians, etc. The telemetry parameters are used to capture
|
115
|
+
# telemetry data from Otto.
|
116
|
+
@alarm_status = 0
|
117
|
+
@actual_rudder = @actual_sail = @actual_awa = @actual_compass = 0
|
118
|
+
@telemetry = Array.new(16)
|
66
119
|
#
|
67
|
-
#
|
68
|
-
|
69
|
-
|
120
|
+
# Mode is used by Otto to decide how to steer the boat and trim the
|
121
|
+
# sails.
|
122
|
+
@otto_mode = MODE_INERT
|
123
|
+
@otto_timestamp = 1000
|
70
124
|
#
|
71
125
|
# Set up some basic parameters for battery/solar readings
|
72
126
|
@bv_m = @bi_m = @bt_m = @sv_m = 1.0
|
73
127
|
@bv_c = @bi_c = @bt_c = @sv_c = 0.0
|
128
|
+
#
|
129
|
+
# RPC client / server
|
130
|
+
@rpc_client = @rpc_server = nil
|
74
131
|
super
|
75
132
|
end
|
76
133
|
|
77
134
|
#
|
78
|
-
# Main daemon function (called from executable)
|
135
|
+
# Main daemon function (called from executable). The job of
|
136
|
+
# this daemon is to accept commands from the Redis pub/sub
|
137
|
+
# stream and send them to the low-level device, recording the
|
138
|
+
# response and sending it back to the caller. Note that we need
|
139
|
+
# to do an initial sync with the device as it will ignore the
|
140
|
+
# usual serial console boot-up gumph awaiting our sync message.
|
79
141
|
def self.daemon
|
80
|
-
|
81
|
-
|
142
|
+
puts "Low-level (Otto) communication subsystem starting up..."
|
143
|
+
otto = new
|
144
|
+
config = Config.load
|
145
|
+
otto.serial_port = SerialPort.new config.otto_device, config.otto_speed
|
146
|
+
otto.serial_port.read_timeout = 10000
|
147
|
+
#
|
148
|
+
# Start by getting a sync message from Otto.
|
149
|
+
otto.synchronize()
|
150
|
+
#
|
151
|
+
# Run the communications service with Otto. Two threads are used, one for
|
152
|
+
# reading and one for writing. Don't let the command stack get too big.
|
153
|
+
t1 = Thread.new { otto.reader_thread }
|
154
|
+
t2 = Thread.new { otto.writer_thread }
|
155
|
+
t1.join
|
156
|
+
t2.join
|
157
|
+
end
|
158
|
+
|
159
|
+
#
|
160
|
+
# Build a C include file based on the current register definitions
|
161
|
+
def self.build_include(fname)
|
162
|
+
otto = new
|
163
|
+
File.open(fname, "w") do |f|
|
164
|
+
f.puts "/*\n * Autogenerated by #{__FILE__}.\n * DO NOT HAND-EDIT!\n */"
|
165
|
+
constants.sort.each do |c|
|
166
|
+
if c.to_s =~ /REGISTER$/
|
167
|
+
cval = Otto.const_get(c)
|
168
|
+
str = "#define SGS_#{c.to_s}"
|
169
|
+
str += "\t" if str.length < 32
|
170
|
+
str += "\t#{cval}"
|
171
|
+
f.puts str
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
#
|
178
|
+
# Synchronize with the low-level board by sending CQ messages until
|
179
|
+
# they respond. When Mother boots up, the serial console is shared with
|
180
|
+
# Otto so a lot of rubbish is sent to the low-level board. To notify
|
181
|
+
# Otto that we are now talking sense, we send @@CQ! and Otto responds
|
182
|
+
# with +CQOK. Note that this function, which is always called before any
|
183
|
+
# of the threads, is bidirectional in terms of serial I/O.
|
184
|
+
def synchronize
|
185
|
+
index = 0
|
186
|
+
backoffs = [1, 1, 1, 1, 2, 2, 3, 5, 10, 10, 20, 30, 60]
|
187
|
+
puts "Attempting to synchronize with Otto..."
|
188
|
+
while true do
|
189
|
+
begin
|
190
|
+
@serial_port.puts "@@CQ!"
|
191
|
+
resp = read_data
|
192
|
+
break if resp =~ /^\+CQOK/ or resp =~ /^\+OK/
|
193
|
+
sleep backoffs[index]
|
194
|
+
index += 1 if index < (backoffs.count - 1)
|
195
|
+
end
|
196
|
+
end
|
197
|
+
puts "Synchronization complete!"
|
198
|
+
end
|
199
|
+
|
200
|
+
#
|
201
|
+
# Thread to read status messages from Otto and handle them
|
202
|
+
def reader_thread
|
203
|
+
puts "Starting OTTO reader thread..."
|
204
|
+
while true
|
205
|
+
data = read_data
|
206
|
+
next if data.nil? or data.length == 0
|
207
|
+
case data[0]
|
208
|
+
when '$'
|
209
|
+
#
|
210
|
+
# Status message (every second)
|
211
|
+
parse_status(data[1..])
|
212
|
+
when '@'
|
213
|
+
#
|
214
|
+
# Otto elapsed time (every four seconds)
|
215
|
+
parse_tstamp(data[1..])
|
216
|
+
when '!'
|
217
|
+
#
|
218
|
+
# Otto mode state (every four seconds)
|
219
|
+
parse_mode(data[1..])
|
220
|
+
when '>'
|
221
|
+
#
|
222
|
+
# Telemetry data (every two seconds)
|
223
|
+
parse_telemetry(data[1..])
|
224
|
+
when '*'
|
225
|
+
#
|
226
|
+
# Message for the debug log
|
227
|
+
parse_debug(data[1..])
|
228
|
+
end
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
#
|
233
|
+
# Thread to write commands direct to Otto.
|
234
|
+
def writer_thread
|
235
|
+
puts "Starting OTTO writer thread..."
|
236
|
+
#
|
237
|
+
# Now listen for Redis PUB/SUB requests and act on each one.
|
238
|
+
myredis = Redis.new
|
239
|
+
while true
|
240
|
+
channel, request = myredis.brpop("otto")
|
241
|
+
request = MessagePack.unpack(request)
|
242
|
+
puts "Req:[#{request.inspect}]"
|
243
|
+
params = request['params']
|
244
|
+
next if request['method'] != "set_local_register"
|
245
|
+
puts "PARAMS: #{params}"
|
246
|
+
cmd = "R%d=%X\r\n" % params
|
247
|
+
puts "Command: #{cmd}"
|
248
|
+
@serial_port.write cmd
|
249
|
+
puts "> Sending command: #{str}"
|
250
|
+
@serial_port.puts "#{str}"
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
254
|
+
#
|
255
|
+
# Read data from the serial port
|
256
|
+
def read_data
|
257
|
+
begin
|
258
|
+
data = @serial_port.readline.chomp
|
259
|
+
rescue EOFError => error
|
260
|
+
puts "Otto Read Timeout!"
|
261
|
+
data = nil
|
262
|
+
end
|
263
|
+
data
|
264
|
+
end
|
265
|
+
|
266
|
+
#
|
267
|
+
# Parse a status message from Otto. In the form:
|
268
|
+
# 0001:C000:0000
|
269
|
+
def parse_status(status)
|
270
|
+
puts "OTTO PARSE: #{status}"
|
271
|
+
args = status.split /:/
|
272
|
+
@alarm_status = args[0].to_i(16)
|
273
|
+
wc = args[1].to_i(16)
|
274
|
+
rs = args[2].to_i(16)
|
275
|
+
@actual_awa = (wc >> 8) & 0xff
|
276
|
+
@actual_compass = (wc & 0xff)
|
277
|
+
@actual_rudder = (rs >> 8) & 0xff
|
278
|
+
@actual_sail = (rs & 0xff)
|
279
|
+
p self
|
280
|
+
self.save_and_publish
|
281
|
+
end
|
282
|
+
|
283
|
+
#
|
284
|
+
# Parse a timestamp message from Otto. In the form: "000FE2" 24 bits
|
285
|
+
# representing the elapsed seconds since Otto restarted.
|
286
|
+
def parse_tstamp(tstamp)
|
287
|
+
newval = tstamp.to_i(16)
|
288
|
+
if newval < @otto_timestamp
|
289
|
+
puts "ALARM! Otto rebooted (or something)..."
|
82
290
|
end
|
291
|
+
@otto_timestamp = newval
|
292
|
+
end
|
293
|
+
|
294
|
+
#
|
295
|
+
# Parse a mode state message from Otto. In the form: "00". An eight bit
|
296
|
+
# quantity.
|
297
|
+
def parse_mode(mode)
|
298
|
+
@otto_mode = mode.to_i(16)
|
299
|
+
end
|
300
|
+
|
301
|
+
#
|
302
|
+
# Parse a telemetry message from Otto. In the form: "7327" where the first
|
303
|
+
# character is the channel (0->9) and the remaining 12 bits are the value.
|
304
|
+
def parse_telemetry(telemetry)
|
305
|
+
data = telemetry.to_i(16)
|
306
|
+
chan = (data >> 12) & 0xf
|
307
|
+
@telemetry[chan] = data & 0xfff
|
308
|
+
end
|
309
|
+
|
310
|
+
#
|
311
|
+
# Parse a debug message from the low-level code. Basically just append it
|
312
|
+
# to a log file.
|
313
|
+
def parse_debug(debug_data)
|
314
|
+
puts "DEBUG: [#{debug_data}].\n"
|
315
|
+
end
|
316
|
+
|
317
|
+
#
|
318
|
+
# Clear an alarm setting
|
319
|
+
def alarm_clear(alarm)
|
320
|
+
set_register(ALARM_CLEAR_REGISTER, alarm)
|
321
|
+
end
|
322
|
+
|
323
|
+
#
|
324
|
+
# Set the Otto mode
|
325
|
+
def mode=(val)
|
326
|
+
set_register(MODE_REGISTER, val) if @otto_mode != val
|
83
327
|
end
|
84
328
|
|
85
329
|
#
|
86
330
|
# Set the required rudder angle. Input values range from +/- 40.0 degrees
|
87
331
|
def rudder=(val)
|
88
|
-
val =
|
89
|
-
val =
|
90
|
-
|
332
|
+
val = RUDDER_MIN if val < RUDDER_MIN
|
333
|
+
val = RUDDER_MAX if val > RUDDER_MAX
|
334
|
+
val = (RUDDER_M * val.to_f + RUDDER_C).to_i
|
335
|
+
if val != @actual_rudder
|
336
|
+
@actual_rudder = val
|
337
|
+
set_register(RUDDER_ANGLE_REGISTER, val)
|
338
|
+
end
|
339
|
+
mode = MODE_MANUAL
|
91
340
|
end
|
92
341
|
|
93
342
|
#
|
94
343
|
# Return the rudder angle in degrees
|
95
344
|
def rudder
|
96
|
-
(@
|
345
|
+
(@actual_rudder.to_f - RUDDER_C) / RUDDER_M
|
97
346
|
end
|
98
347
|
|
99
348
|
#
|
100
|
-
# Set the required sail angle. Input values range from 0 ->
|
349
|
+
# Set the required sail angle. Input values range from 0 -> 100.
|
101
350
|
def sail=(val)
|
102
|
-
val =
|
103
|
-
val =
|
104
|
-
|
351
|
+
val = SAIL_MIN if val < SAIL_MIN
|
352
|
+
val = SAIL_MAX if val > SAIL_MAX
|
353
|
+
val = (SAIL_M * val.to_f + SAIL_C).to_i
|
354
|
+
if val != @actual_sail
|
355
|
+
@actual_sail = val
|
356
|
+
set_register(SAIL_ANGLE_REGISTER, val)
|
357
|
+
end
|
358
|
+
mode = MODE_MANUAL
|
105
359
|
end
|
106
360
|
|
107
361
|
#
|
108
362
|
# Return the sail setting (0.0 -> 100.0)
|
109
363
|
def sail
|
110
|
-
(@
|
364
|
+
(@actual_sail.to_f - SAIL_C) / SAIL_M
|
111
365
|
end
|
112
366
|
|
113
367
|
#
|
114
368
|
# Return the compass angle (in radians)
|
115
369
|
def compass
|
116
|
-
@
|
370
|
+
Bearing.xtor(@actual_compass)
|
117
371
|
end
|
118
372
|
|
119
373
|
#
|
120
374
|
# Return the apparent wind angle (in radians)
|
121
375
|
def awa
|
122
|
-
@
|
376
|
+
@actual_awa -= 256 if @actual_awa > 128
|
377
|
+
Bearing.xtor(@actual_awa)
|
123
378
|
end
|
124
379
|
|
125
380
|
#
|
126
|
-
#
|
381
|
+
# Return the actual wind direction (in radians)
|
382
|
+
def wind
|
383
|
+
Bearing.xtor(@actual_compass + @actual_awa)
|
384
|
+
end
|
385
|
+
|
386
|
+
#
|
387
|
+
# Set the required compass reading (in radians)
|
127
388
|
def track_compass=(val)
|
128
|
-
|
129
|
-
|
389
|
+
val = Bearing.rtox(val)
|
390
|
+
if @track_compass.nil? or @track_compass != val
|
391
|
+
@track_compass = val
|
392
|
+
set_register(COMPASS_HEADING_REGISTER, val)
|
130
393
|
end
|
131
|
-
|
132
|
-
@raw_tc = (val.to_f * 128.0 / Math::PI).to_i
|
394
|
+
mode = MODE_TRACK_COMPASS
|
133
395
|
end
|
134
396
|
|
135
397
|
#
|
136
398
|
# Return the compass value for tracking.
|
137
399
|
def track_compass
|
138
|
-
@
|
400
|
+
Bearing.xtor(@track_compass)
|
139
401
|
end
|
140
402
|
|
141
403
|
#
|
142
|
-
# Set the required AWA for tracking.
|
404
|
+
# Set the required AWA for tracking (in radians).
|
143
405
|
def track_awa=(val)
|
144
|
-
val =
|
145
|
-
|
146
|
-
|
406
|
+
val = Bearing.rtox(val)
|
407
|
+
if @track_awa.nil? or @track_awa != val
|
408
|
+
@track_awa = val
|
409
|
+
set_register(AWA_HEADING_REGISTER, val)
|
410
|
+
end
|
411
|
+
mode = MODE_TRACK_AWA
|
147
412
|
end
|
148
413
|
|
149
414
|
#
|
150
|
-
# Return the current tracking AWA.
|
415
|
+
# Return the current tracking AWA (in radians).
|
151
416
|
def track_awa
|
152
|
-
@
|
417
|
+
Bearing.xtor(@track_awa)
|
418
|
+
end
|
419
|
+
|
420
|
+
#
|
421
|
+
# RPC client call to set register - sent to writer function above
|
422
|
+
def set_register(regno, value)
|
423
|
+
@rpc_client = RPCClient.new("otto") unless @rpc_client
|
424
|
+
@rpc_client.set_local_register(regno, value)
|
153
425
|
end
|
154
426
|
end
|
155
427
|
end
|
data/lib/sgs/redis_base.rb
CHANGED
@@ -75,7 +75,7 @@ module SGS
|
|
75
75
|
# Initialize a Redis variable.
|
76
76
|
def self.var_init(var, val, idx = nil)
|
77
77
|
cls = new
|
78
|
-
|
78
|
+
RedisBase.redis.setnx cls.make_redis_name(var, :idx => idx), self.to_redis(var, val, idx)
|
79
79
|
end
|
80
80
|
|
81
81
|
#
|
@@ -96,8 +96,8 @@ module SGS
|
|
96
96
|
# It's an array - iterate and read the values.
|
97
97
|
lval.size.times do |idx|
|
98
98
|
idx_val = lval[idx]
|
99
|
-
lval[idx] = redis_read_var var, idx_val.class, :idx => idx
|
100
|
-
|
99
|
+
lval[idx] = redis_read_var var, idx_val.class, :idx => idx
|
100
|
+
end
|
101
101
|
elsif lval.kind_of? Location
|
102
102
|
#
|
103
103
|
# ::FIXME:: Yes. this is a hack.
|
@@ -141,7 +141,7 @@ module SGS
|
|
141
141
|
#
|
142
142
|
# Inside a multi-block, set all the variables and increment
|
143
143
|
# the count.
|
144
|
-
|
144
|
+
RedisBase.redis.multi do |pipeline|
|
145
145
|
var_list.each do |key, value|
|
146
146
|
pipeline.set key, value
|
147
147
|
end
|
@@ -157,7 +157,7 @@ module SGS
|
|
157
157
|
# class name), you can remember the last received count and decide if
|
158
158
|
# there is fresh data. Or, you can just act anyway.
|
159
159
|
def publish
|
160
|
-
|
160
|
+
RedisBase.redis.publish self.class.redis_handle, count.to_s
|
161
161
|
end
|
162
162
|
|
163
163
|
#
|
@@ -182,7 +182,7 @@ module SGS
|
|
182
182
|
#
|
183
183
|
# Retrieve the count
|
184
184
|
def count
|
185
|
-
|
185
|
+
RedisBase.redis.get count_name
|
186
186
|
end
|
187
187
|
|
188
188
|
#
|
@@ -195,7 +195,7 @@ module SGS
|
|
195
195
|
# Get an instance variable value from a Redis value.
|
196
196
|
def redis_read_var(var, klass, opts = {})
|
197
197
|
redis_name = make_redis_name var, opts
|
198
|
-
redis_val =
|
198
|
+
redis_val = RedisBase.redis.get redis_name
|
199
199
|
redis_val = nil if redis_val == ""
|
200
200
|
if redis_val
|
201
201
|
if not klass or klass == NilClass
|
@@ -211,9 +211,9 @@ module SGS
|
|
211
211
|
when klass == Float
|
212
212
|
redis_val = redis_val.to_f
|
213
213
|
when klass == FalseClass
|
214
|
-
redis_val =
|
214
|
+
redis_val = (redis_val == "true" or redis_val == "TRUE")
|
215
215
|
when klass == TrueClass
|
216
|
-
redis_val = true
|
216
|
+
redis_val = (redis_val == "true" or redis_val == "TRUE")
|
217
217
|
end
|
218
218
|
end
|
219
219
|
redis_val
|
data/lib/sgs/report.rb
CHANGED
@@ -32,15 +32,20 @@
|
|
32
32
|
#
|
33
33
|
# ABSTRACT
|
34
34
|
#
|
35
|
+
require 'serialport'
|
35
36
|
|
36
37
|
##
|
37
38
|
# Routines for handling sailboat navigation and route planning.
|
38
39
|
#
|
39
40
|
module SGS
|
40
|
-
class Report
|
41
|
+
class Report
|
41
42
|
#
|
42
43
|
# Main daemon function (called from executable)
|
43
44
|
def self.daemon
|
45
|
+
puts "Reporting subsystem starting up..."
|
46
|
+
config = Config.load
|
47
|
+
sp = SerialPort.new config.comm_device, config.comm_speed
|
48
|
+
sp.read_timeout = 10000
|
44
49
|
loop do
|
45
50
|
sleep 300
|
46
51
|
end
|
data/lib/sgs/rpc.rb
CHANGED
@@ -55,9 +55,8 @@ module SGS
|
|
55
55
|
'method' => name,
|
56
56
|
'params' => args
|
57
57
|
}
|
58
|
-
|
59
|
-
|
60
|
-
MessagePack.unpack(response)['result']
|
58
|
+
puts "RPC CLIENT SENDING MESSAGE! request: #{request.inspect}, channel: #{@channel}"
|
59
|
+
RedisBase.redis.lpush(@channel, request.to_msgpack)
|
61
60
|
end
|
62
61
|
end
|
63
62
|
|
@@ -70,7 +69,7 @@ module SGS
|
|
70
69
|
def start
|
71
70
|
puts "Starting RPC server for #{@channel}"
|
72
71
|
loop do
|
73
|
-
channel, request =
|
72
|
+
channel, request = RedisBase.redis.brpop(@channel)
|
74
73
|
request = MessagePack.unpack(request)
|
75
74
|
|
76
75
|
puts "Working on request: #{request['id']}"
|
@@ -84,8 +83,8 @@ module SGS
|
|
84
83
|
'id' => request['id']
|
85
84
|
}
|
86
85
|
|
87
|
-
|
88
|
-
|
86
|
+
RedisBase.redis.rpush(request['id'], MessagePack.pack(reply))
|
87
|
+
RedisBase.redis.expire(request['id'], 30)
|
89
88
|
end
|
90
89
|
end
|
91
90
|
end
|
data/lib/sgs/version.rb
CHANGED
data/lib/sgs/waypoint.rb
CHANGED
@@ -39,7 +39,7 @@
|
|
39
39
|
module SGS
|
40
40
|
#
|
41
41
|
# Waypoint, Attractor, and Repellor definitions
|
42
|
-
class Waypoint
|
42
|
+
class Waypoint
|
43
43
|
attr_accessor :location, :normal, :range, :name, :attractor
|
44
44
|
attr_reader :bearing, :distance
|
45
45
|
|
@@ -58,7 +58,7 @@ module SGS
|
|
58
58
|
def parse(data)
|
59
59
|
@@count += 1
|
60
60
|
@name = data["name"] || "Waypoint ##{@@count}"
|
61
|
-
@location =
|
61
|
+
@location = Location.parse(data)
|
62
62
|
@normal = data["normal"] || 0.0
|
63
63
|
@range = data["range"] || 0.1
|
64
64
|
end
|
data/lib/sgslib.rb
CHANGED
@@ -31,13 +31,10 @@
|
|
31
31
|
# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
32
32
|
#
|
33
33
|
# ABSTRACT
|
34
|
-
#
|
34
|
+
# Include all of the various components.
|
35
35
|
|
36
36
|
##
|
37
37
|
#
|
38
|
-
require 'date'
|
39
|
-
require 'logger'
|
40
|
-
|
41
38
|
require "sgs/version"
|
42
39
|
require 'sgs/redis_base'
|
43
40
|
require 'sgs/config'
|
data/sgslib.gemspec
CHANGED
@@ -34,14 +34,16 @@ Gem::Specification.new do |spec|
|
|
34
34
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
35
35
|
spec.require_paths = ["lib"]
|
36
36
|
|
37
|
-
spec.required_ruby_version = '>=
|
37
|
+
spec.required_ruby_version = '>= 2.7.6'
|
38
38
|
|
39
39
|
spec.add_development_dependency "bundler", "~> 2.2"
|
40
40
|
spec.add_development_dependency "rake", ">= 12.3.3"
|
41
41
|
spec.add_development_dependency "rspec", "~> 3.0"
|
42
42
|
|
43
|
-
spec.add_runtime_dependency "
|
44
|
-
spec.add_runtime_dependency "
|
45
|
-
|
46
|
-
spec.
|
43
|
+
spec.add_runtime_dependency "redis", "~> 5.0"
|
44
|
+
spec.add_runtime_dependency "serialport", "~> 1.3"
|
45
|
+
spec.add_runtime_dependency "msgpack", "~> 1.6"
|
46
|
+
spec.add_runtime_dependency "json"
|
47
|
+
spec.add_runtime_dependency "securerandom"
|
48
|
+
spec.add_runtime_dependency "yaml"
|
47
49
|
end
|