sgslib 1.5.0 → 1.5.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a7ecb05d8a8096186dd2d79b8126cc50e501e71d5b7c80a58f7b8bcc9a0f7ec0
4
- data.tar.gz: c4d5073036b612bc4333ad2e176e58c6dae5c262d748a981eb55992526c0a29e
3
+ metadata.gz: b5dffcc970035c48e2b6026c72884b6ab97cc14ac43ba255cb4386244b46287c
4
+ data.tar.gz: 347c958575c0e9510047c75b997426083d4e3abf8ee479ff9b407c3395bbe118
5
5
  SHA512:
6
- metadata.gz: 891aa77f6714876a1c2ec5432b760aeab2a7a9421c2e97713dac0ad618f068961142d06020a24eec586222f3ddc4762e1e549461152fa3ab32d18b93b1f046b9
7
- data.tar.gz: 03d3070b475d819e0f1f855ba6a83fb83596b4c2900a4bb201348570ca9b2e7e5769ab5c9a7f00a3d71c1b31cac12023d362224dd190af01a46695b20df43f7d
6
+ metadata.gz: bdee04756fe59509497bc455f7874e9c05ecca6c9031f55133460a28ea987d9a0dd788588e2b449b9fe0630f734f23b6c968722361153b9130fa0362c354b67c
7
+ data.tar.gz: de267f01e59622938cfb1ad3ebbcb7c08c72bb02a625f1de72c93255b5e3be868cae29a1625383890c4c4aa57292b27942d735adb0abb4f36763dd481ca62893
data/exe/sgs_otto CHANGED
File without changes
data/lib/sgs/alarm.rb CHANGED
@@ -44,7 +44,9 @@ module SGS
44
44
  class Alarm < RedisBase
45
45
  attr_accessor :last_report, :time
46
46
 
47
- OTTO_RESTART = 0
47
+ #
48
+ # Alarms generated by Otto.
49
+ MISSION_SWITCH = 0
48
50
  RUDDSRV_FAULT = 1
49
51
  SAILSRV_FAULT = 2
50
52
  VBATT_CRITICAL = 3
@@ -60,16 +62,18 @@ module SGS
60
62
  RUDDER_NOZERO = 13
61
63
  SAIL_NOZERO = 14
62
64
  MOTHER_UNRESP = 15
63
-
64
- MISSION_COMMENCE = 16
65
- MISSION_COMPLETE = 17
66
- MISSION_ABORT = 18
67
- WAYPOINT_REACHED = 19
68
- CROSS_TRACK_ERROR = 20
69
- INSIDE_FENCE = 21
65
+ #
66
+ # Alarms generated by Mother.
67
+ OTTO_RESTART = 16
68
+ MISSION_COMMENCE = 17
69
+ MISSION_COMPLETE = 18
70
+ MISSION_ABORT = 19
71
+ WAYPOINT_REACHED = 20
72
+ CROSS_TRACK_ERROR = 21
73
+ INSIDE_FENCE = 22
70
74
 
71
75
  ALARM_NAMES = [
72
- "OTTO Restarted",
76
+ "Mission Activation Switch",
73
77
  "Rudder Servo Fault",
74
78
  "Sail Servo Fault",
75
79
  "Battery voltage is critically low",
@@ -85,6 +89,7 @@ module SGS
85
89
  "Cannot zero the rudder position",
86
90
  "Cannot zero the sail position",
87
91
  "Mother is unresponsive",
92
+ "OTTO Restarted",
88
93
  "Mission has commenced",
89
94
  "Mission is completed",
90
95
  "*** MISSION ABORT ***",
@@ -103,8 +108,13 @@ module SGS
103
108
  #
104
109
  # Main daemon function (called from executable)
105
110
  def self.daemon
111
+ puts "Alarm daemon starting up..."
112
+ otto = SGS::RPCClient.new(:otto)
106
113
  loop do
107
- sleep 300
114
+ #puts "Check for any alarms..."
115
+ #resp = otto.command "A?"
116
+ #puts "Response: #{resp}"
117
+ sleep 30
108
118
  end
109
119
  end
110
120
 
data/lib/sgs/bearing.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  #
2
+ #
2
3
  # Copyright (c) 2013-2023, Kalopa Robotics Limited. All rights
3
4
  # reserved.
4
5
  #
@@ -41,6 +41,7 @@ module SGS
41
41
  #
42
42
  # Main daemon function (called from executable)
43
43
  def self.daemon
44
+ puts "Diagnostics subsystem starting up..."
44
45
  loop do
45
46
  sleep 300
46
47
  end
data/lib/sgs/gps.rb CHANGED
@@ -32,6 +32,8 @@
32
32
  #
33
33
  # ABSTRACT
34
34
  #
35
+ require 'serialport'
36
+
35
37
  module SGS
36
38
  class GPS < RedisBase
37
39
  attr_accessor :time, :location, :sog, :cmg, :magvar
@@ -49,8 +51,19 @@ module SGS
49
51
  #
50
52
  # Main daemon function (called from executable)
51
53
  def self.daemon
54
+ puts "GPS reader starting up..."
55
+ config = SGS::Config.load
56
+
57
+ sp = SerialPort.new config.gps_device, config.gps_speed
58
+ sp.read_timeout = 10000
59
+
52
60
  loop do
53
- sleep 300
61
+ nmea = SGS::NMEA.parse sp.readline
62
+ if nmea.is_gprmc?
63
+ gps = nmea.parse_gprmc
64
+ p gps
65
+ gps.save_and_publish if gps and gps.valid?
66
+ end
54
67
  end
55
68
  end
56
69
 
data/lib/sgs/logger.rb CHANGED
@@ -38,12 +38,5 @@
38
38
  #
39
39
  module SGS
40
40
  class Logger < RedisBase
41
- #
42
- # Main daemon function (called from executable)
43
- def self.daemon
44
- loop do
45
- sleep 300
46
- end
47
- end
48
41
  end
49
42
  end
data/lib/sgs/mission.rb CHANGED
@@ -51,6 +51,7 @@ module SGS
51
51
  #
52
52
  # Main daemon function (called from executable)
53
53
  def self.daemon
54
+ puts "Mission management system starting up..."
54
55
  loop do
55
56
  sleep 300
56
57
  end
@@ -73,7 +73,6 @@ module SGS
73
73
  @state = STATE_AWAITING
74
74
  @current_waypoint = 0
75
75
  @start_time = @end_time = nil
76
- @logger = Logger.new(STDOUT)
77
76
  end
78
77
 
79
78
  #
@@ -91,7 +90,7 @@ module SGS
91
90
  #
92
91
  # Commence a mission...
93
92
  def start_test!(time = nil)
94
- @logger.warn "***** Starting test phase *****"
93
+ puts "***** Starting test phase *****"
95
94
  @start_time = time || Time.now
96
95
  @state = STATE_START_TEST
97
96
  @current_waypoint = 0
@@ -104,7 +103,7 @@ module SGS
104
103
  @end_time = time || Time.now
105
104
  @state = STATE_COMPLETE
106
105
  save_and_publish
107
- @logger.warn "***** Mission completed! *****"
106
+ puts "***** Mission completed! *****"
108
107
  end
109
108
 
110
109
  #
@@ -113,7 +112,7 @@ module SGS
113
112
  @end_time = time || Time.now
114
113
  @state = STATE_TERMINATED
115
114
  save_and_publish
116
- @logger.warn "***** Mission terminated! *****"
115
+ puts "***** Mission terminated! *****"
117
116
  end
118
117
 
119
118
  #
@@ -122,7 +121,7 @@ module SGS
122
121
  @end_time = time || Time.now
123
122
  @state = STATE_FAILURE
124
123
  save_and_publish
125
- @logger.warn "***** Mission failure! *****"
124
+ puts "***** Mission failure! *****"
126
125
  end
127
126
  end
128
127
  end
data/lib/sgs/navigate.rb CHANGED
@@ -71,8 +71,27 @@ module SGS
71
71
  #
72
72
  # Main daemon function (called from executable)
73
73
  def self.daemon
74
- loop do
75
- sleep 300
74
+ puts "Navigation system starting up..."
75
+ #
76
+ # Load the mission data from Redis and augment it with the
77
+ # contents of the mission file.
78
+ config = SGS::Config.load
79
+ mission = SGS::Mission.file_load config.mission_file
80
+ #
81
+ # Now listen for GPS data...
82
+ SGS::GPS.subscribe do |count|
83
+ puts "Received new GPS count: #{count}"
84
+ case SGS::MissionStatus.state
85
+ when STATE_COMPASS_FOLLOW
86
+ when STATE_WIND_FOLLOW
87
+ mission.navigate
88
+ when STATE_COMPLETE
89
+ when STATE_TERMINATED
90
+ when STATE_FAILURE
91
+ mission.hold_station
92
+ end
93
+ gps = SGS::GPS.load
94
+ p gps
76
95
  end
77
96
  end
78
97
 
data/lib/sgs/otto.rb CHANGED
@@ -32,6 +32,8 @@
32
32
  #
33
33
  # ABSTRACT
34
34
  #
35
+ require 'serialport'
36
+ require 'msgpack'
35
37
 
36
38
  ##
37
39
  # Routines for interfacing with the low-level microcontroller.
@@ -41,6 +43,9 @@ module SGS
41
43
  attr_accessor :raw_rudder, :raw_sail, :raw_compass, :raw_awa, :raw_tc, :raw_ta
42
44
  attr_accessor :mode, :rudder_m, :rudder_c, :sail_m, :sail_c
43
45
  attr_accessor :bv_m, :bv_c, :bi_m, :bi_c, :bt_m, :bt_c, :sv_m, :sv_c
46
+ attr_accessor :serial_port
47
+ attr_reader :alarm_status, :wind, :compass, :actual_rudder, :actual_sail
48
+ attr_reader :otto_mode, :otto_timestamp, :telemetry
44
49
 
45
50
  MODE_INERT = 0
46
51
  MODE_DIAGNOSTICS = 1
@@ -57,8 +62,9 @@ module SGS
57
62
  # Set up some useful defaults. We assume rudder goes from 0 to 200 as does
58
63
  # the sail angle.
59
64
  def initialize
65
+ serial_port = nil
60
66
  #
61
- # Configure the Mx + C values for sail and rudder
67
+ # Configure the Mx + C values for sail and rudder
62
68
  @rudder_m = 2.5
63
69
  @rudder_c = 100.0
64
70
  @sail_m = 2.0
@@ -68,6 +74,12 @@ module SGS
68
74
  rudder = 0.0
69
75
  sail = 0.0
70
76
  #
77
+ # Set some defaults for the read-back parameters
78
+ @alarm_status = @wind = @compass = @actual_rudder = @actual_sail = 0
79
+ @otto_mode = 0
80
+ @otto_timestamp = 1000
81
+ @telemetry = Array.new(16)
82
+ #
71
83
  # Set up some basic parameters for battery/solar readings
72
84
  @bv_m = @bi_m = @bt_m = @sv_m = 1.0
73
85
  @bv_c = @bi_c = @bt_c = @sv_c = 0.0
@@ -75,13 +87,170 @@ module SGS
75
87
  end
76
88
 
77
89
  #
78
- # Main daemon function (called from executable)
90
+ # Main daemon function (called from executable). The job of
91
+ # this daemon is to accept commands from the Redis pub/sub
92
+ # stream and send them to the low-level device, recording the
93
+ # response and sending it back to the caller. Note that we need
94
+ # to do an initial sync with the device as it will ignore the
95
+ # usual serial console boot-up gumph awaiting our sync message.
79
96
  def self.daemon
80
- loop do
81
- sleep 300
97
+ puts "Low-level (Otto) communication subsystem starting up..."
98
+ otto = new
99
+ config = SGS::Config.load
100
+ otto.serial_port = SerialPort.new config.otto_device, config.otto_speed
101
+ otto.serial_port.read_timeout = 10000
102
+ #
103
+ # Start by getting a sync message from Otto.
104
+ otto.synchronize()
105
+ #
106
+ # Run the communications service with Otto. Two threads are used, one for
107
+ # reading and one for writing. Don't let the command stack get too big.
108
+ t1 = Thread.new { otto.reader_thread }
109
+ t2 = Thread.new { otto.writer_thread }
110
+ t1.join
111
+ t2.join
112
+ end
113
+
114
+ #
115
+ # Synchronize with the low-level board by sending CQ messages until
116
+ # they respond.
117
+ def synchronize
118
+ index = 0
119
+ backoffs = [1, 1, 1, 1, 2, 2, 3, 5, 10, 10, 20, 30, 60]
120
+ puts "Attempting to synchronize with Otto..."
121
+ while true do
122
+ begin
123
+ @serial_port.puts "@@CQ!"
124
+ resp = read_data
125
+ break if resp =~ /^\+CQOK/ or resp =~ /^\+OK/
126
+ sleep backoffs[index]
127
+ index += 1 if index < (backoffs.count - 1)
128
+ end
129
+ end
130
+ puts "Synchronization complete!"
131
+ end
132
+
133
+ #
134
+ # Thread to read status messages from Otto and handle them
135
+ def reader_thread
136
+ puts "Starting OTTO reader thread..."
137
+ while true
138
+ data = read_data
139
+ next if data.nil? or data.length == 0
140
+ case data[0]
141
+ when '$'
142
+ #
143
+ # Status message (every second)
144
+ parse_status(data[1..])
145
+ when '@'
146
+ #
147
+ # Otto elapsed time (every four seconds)
148
+ parse_tstamp(data[1..])
149
+ when '!'
150
+ #
151
+ # Otto mode state (every four seconds)
152
+ parse_mode(data[1..])
153
+ when '>'
154
+ #
155
+ # Telemetry data (every two seconds)
156
+ parse_telemetry(data[1..])
157
+ end
158
+ end
159
+ end
160
+
161
+ #
162
+ # Thread to write commands direct to Otto.
163
+ def writer_thread
164
+ puts "Starting OTTO writer thread..."
165
+ #
166
+ # Now listen for Redis PUB/SUB requests and act on each one.
167
+ while true
168
+ channel, request = SGS::RedisBase.redis.brpop("otto")
169
+ request = MessagePack.unpack(request)
170
+ puts "Req:[#{request.inspect}]"
171
+ cmd = {
172
+ id: request['id'],
173
+ args: request['params'].unshift(request['method'])
174
+ }
175
+ puts "CMD:#{cmd.inspect}"
176
+ #
177
+ # Don't let the command stack get too big.
178
+ while @command_stack.length > 5
179
+ sleep 5
180
+ end
181
+
182
+ puts "> Sending command: #{str}"
183
+ @serial_port.puts "#{str}"
184
+
185
+ reply = {
186
+ 'id' => id,
187
+ 'jsonrpc' => '2.0',
188
+ 'result' => result
189
+ }
190
+ SGS::RedisBase.redis.rpush(id, MessagePack.pack(reply))
191
+ SGS::RedisBase.redis.expire(id, 30)
82
192
  end
83
193
  end
84
194
 
195
+ #
196
+ # Read data from the serial port
197
+ def read_data
198
+ begin
199
+ data = @serial_port.readline.chomp
200
+ rescue EOFError => error
201
+ puts "Otto Read Timeout!"
202
+ data = nil
203
+ end
204
+ data
205
+ end
206
+
207
+ #
208
+ # Parse a status message from Otto. In the form:
209
+ # 0001:C000:0000
210
+ def parse_status(status)
211
+ puts "Parse status: #{status}"
212
+ args = status.split /:/
213
+ @alarm_status = args[0].to_i(16)
214
+ wc = args[1].to_i(16)
215
+ rs = args[2].to_i(16)
216
+ @wind = (wc >> 8) & 0xff
217
+ @compass = (wc & 0xff)
218
+ @actual_rudder = (rs >> 8) & 0xff
219
+ @actual_sail = (rs & 0xff)
220
+ p self
221
+ self.save_and_publish
222
+ end
223
+
224
+ #
225
+ # Parse a timestamp message from Otto. In the form: "000FE2" 24 bits
226
+ # representing the elapsed seconds since Otto restarted.
227
+ def parse_tstamp(tstamp)
228
+ puts "Parse timestamp: #{tstamp}"
229
+ newval = tstamp.to_i(16)
230
+ if newval < @otto_timestamp
231
+ puts "ALARM! Otto rebooted (or something)..."
232
+ end
233
+ @otto_timestamp = newval
234
+ end
235
+
236
+ #
237
+ # Parse a mode state message from Otto. In the form: "00". An eight bit
238
+ # quantity.
239
+ def parse_mode(mode)
240
+ puts "Parse Otto Mode State: #{mode}"
241
+ @otto_mode = mode.to_i(16)
242
+ end
243
+
244
+ #
245
+ # Parse a telemetry message from Otto. In the form: "7327" where the first
246
+ # character is the channel (0->9) and the remaining 12 bits are the value.
247
+ def parse_telemetry(telemetry)
248
+ puts "Parse Otto Telemetry Data: #{telemetry}"
249
+ data = telemetry.to_i(16)
250
+ chan = (data >> 12) & 0xf
251
+ @telemetry[chan] = data & 0xff
252
+ end
253
+
85
254
  #
86
255
  # Set the required rudder angle. Input values range from +/- 40.0 degrees
87
256
  def rudder=(val)
data/lib/sgs/report.rb CHANGED
@@ -32,6 +32,7 @@
32
32
  #
33
33
  # ABSTRACT
34
34
  #
35
+ require 'serialport'
35
36
 
36
37
  ##
37
38
  # Routines for handling sailboat navigation and route planning.
@@ -41,6 +42,10 @@ module SGS
41
42
  #
42
43
  # Main daemon function (called from executable)
43
44
  def self.daemon
45
+ puts "Reporting subsystem starting up..."
46
+ config = SGS::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/version.rb CHANGED
@@ -33,5 +33,5 @@
33
33
  # ABSTRACT
34
34
  #
35
35
  module SGS
36
- VERSION = "1.5.0"
36
+ VERSION = "1.5.1"
37
37
  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
@@ -40,8 +40,10 @@ Gem::Specification.new do |spec|
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"
43
+ spec.add_runtime_dependency "redis", "~> 4.7"
44
+ spec.add_runtime_dependency "serialport", "~> 1.3"
44
45
  spec.add_runtime_dependency "msgpack", "~> 1.3"
45
-
46
- spec.add_dependency "redis", "~> 4.7"
46
+ spec.add_runtime_dependency "json"
47
+ spec.add_runtime_dependency "securerandom"
48
+ spec.add_runtime_dependency "yaml"
47
49
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sgslib
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.5.0
4
+ version: 1.5.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dermot Tynan
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-01-08 00:00:00.000000000 Z
11
+ date: 2023-01-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -53,21 +53,21 @@ dependencies:
53
53
  - !ruby/object:Gem::Version
54
54
  version: '3.0'
55
55
  - !ruby/object:Gem::Dependency
56
- name: logger
56
+ name: redis
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: '1.4'
61
+ version: '4.7'
62
62
  type: :runtime
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: '1.4'
68
+ version: '4.7'
69
69
  - !ruby/object:Gem::Dependency
70
- name: msgpack
70
+ name: serialport
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
73
  - - "~>"
@@ -81,19 +81,61 @@ dependencies:
81
81
  - !ruby/object:Gem::Version
82
82
  version: '1.3'
83
83
  - !ruby/object:Gem::Dependency
84
- name: redis
84
+ name: msgpack
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
87
  - - "~>"
88
88
  - !ruby/object:Gem::Version
89
- version: '4.7'
89
+ version: '1.3'
90
90
  type: :runtime
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
94
  - - "~>"
95
95
  - !ruby/object:Gem::Version
96
- version: '4.7'
96
+ version: '1.3'
97
+ - !ruby/object:Gem::Dependency
98
+ name: json
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: securerandom
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :runtime
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: yaml
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :runtime
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
97
139
  description: Sailboat Guidance System - an autonomous navigation and control system
98
140
  for robotic sailboats.
99
141
  email:
@@ -164,7 +206,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
164
206
  - !ruby/object:Gem::Version
165
207
  version: '0'
166
208
  requirements: []
167
- rubygems_version: 3.0.3.1
209
+ rubygems_version: 3.1.6
168
210
  signing_key:
169
211
  specification_version: 4
170
212
  summary: Sailboat Guidance System