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.
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 = SGS::GPS.new
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.parse pos
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 :raw_rudder, :raw_sail, :raw_compass, :raw_awa, :raw_tc, :raw_ta
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
- MODE_DIAGNOSTICS = 1
83
+ MODE_DIAG = 1
47
84
  MODE_MANUAL = 2
48
- MODE_TRACK_COMPASS = 3
49
- MODE_TRACK_AWA = 4
85
+ MODE_REMOTE = 3
86
+ MODE_TRACK_COMPASS = 4
87
+ MODE_TRACK_AWA = 5
50
88
 
51
- MODE_NAMES = [
52
- "Inert Mode", "Diagnostics Mode", "Manual Control Mode",
53
- "Compass-Tracking Mode", "AWA-Tracking Mode"
54
- ].freeze
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 200 as does
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
- # Configure the Mx + C values for sail and rudder
62
- @rudder_m = 2.5
63
- @rudder_c = 100.0
64
- @sail_m = 2.0
65
- @sail_c = 0.0
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
- # Now set the rudder and sail to default positions (rudder is centered)
68
- rudder = 0.0
69
- sail = 0.0
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
- loop do
81
- sleep 300
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 = -40.0 if val < -40.0
89
- val = 40.0 if val > 40.0
90
- @raw_rudder = (@rudder_m * val.to_f + @rudder_c).to_i
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
- (@raw_rudder.to_f - @rudder_c) / @rudder_m
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 -> 90 degrees.
349
+ # Set the required sail angle. Input values range from 0 -> 100.
101
350
  def sail=(val)
102
- val = 0.0 if val < 0.0
103
- val = 100.0 if val > 100.0
104
- @raw_sail = (@sail_m * val.to_f + @sail_c).to_i
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
- (@raw_sail.to_f - @sail_c) / @sail_m
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
- @raw_compass.to_f * Math::PI / 128.0
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
- @raw_awa.to_f * Math::PI / 128.0
376
+ @actual_awa -= 256 if @actual_awa > 128
377
+ Bearing.xtor(@actual_awa)
123
378
  end
124
379
 
125
380
  #
126
- # Set the required compass reading. Input values range from 0 -> 359 degrees
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
- while val < 0.0
129
- val += 360.0
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
- val %= 360.0
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
- @raw_tc.to_f * Math::PI / 128.0
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 = -180.0 if val < -180.0
145
- val = 180.0 if val > 180.0
146
- @raw_ta = (val.to_f * 128.0 / Math::PI).to_i
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
- @raw_ta.to_f * Math::PI / 128.0
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
@@ -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
- SGS::RedisBase.redis.setnx cls.make_redis_name(var, :idx => idx), self.to_redis(var, val, idx)
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
- end
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
- SGS::RedisBase.redis.multi do |pipeline|
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
- SGS::RedisBase.redis.publish self.class.redis_handle, count.to_s
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
- SGS::RedisBase.redis.get count_name
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 = SGS::RedisBase.redis.get redis_name
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 = false
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 < RedisBase
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
- SGS::RedisBase.redis.lpush(@channel, request.to_msgpack)
59
- channel, response = SGS::RedisBase.redis.brpop(uuid, timeout=60)
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 = SGS::RedisBase.redis.brpop(@channel)
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
- SGS::RedisBase.redis.rpush(request['id'], MessagePack.pack(reply))
88
- SGS::RedisBase.redis.expire(request['id'], 30)
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
@@ -33,5 +33,5 @@
33
33
  # ABSTRACT
34
34
  #
35
35
  module SGS
36
- VERSION = "1.5.0"
36
+ VERSION = "1.6.0"
37
37
  end
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 < RedisBase
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 = SGS::Location.parse(data)
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 = '>= 1.9.2'
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 "logger", "~> 1.4"
44
- spec.add_runtime_dependency "msgpack", "~> 1.3"
45
-
46
- spec.add_dependency "redis", "~> 4.7"
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