rfbeam 0.5.0 → 0.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 +4 -4
- data/.streerc +1 -0
- data/.streerc~1f4cd14e3c0a9afdf972aa5f3982d36a89869b72 +2 -0
- data/.tool-versions +1 -1
- data/CHANGELOG.md +8 -0
- data/Gemfile.lock +2 -1
- data/Rakefile +8 -3
- data/cog.toml +24 -0
- data/lib/rfbeam/cli.rb +58 -9
- data/lib/rfbeam/kld7/cli_output.rb +1 -1
- data/lib/rfbeam/kld7/constants.rb +61 -134
- data/lib/rfbeam/kld7/radar_messages.rb +46 -29
- data/lib/rfbeam/kld7/radar_parameters.rb +94 -50
- data/lib/rfbeam/kld7/streamer.rb +82 -0
- data/lib/rfbeam/version.rb +1 -1
- data/rfbeam.gemspec +3 -3
- data/streamer2.rb +55 -0
- data/streaming.rb +71 -0
- metadata +15 -10
- data/.streerc +0 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 641d32533a354fa54db2906e234d7243899286dd85ab72a51d8a477b27f327cd
|
4
|
+
data.tar.gz: a1d94a25fee763ada51a4dc5fd6687f7bb4e1bc67a56adae257dd67efa6ded79
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 66d1d5f9e22d1adce03395cb153cebbc5eff4336b3cf3ade2a73d77548a7ff233ebe7d45b9ce09a23479c9c60382b0e81052c7da20f584792c8eb642b758a317
|
7
|
+
data.tar.gz: '094f688f3e86604632a1fa5fd05c3ff377e9b848deb6ed56eb024991e7ad8288641d3d29dc16f538cd4b1d564e5ac6f6b6dcaf77862048f3ffa9de351eab7932'
|
data/.streerc
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
/Users/rob/.streerc
|
data/.tool-versions
CHANGED
@@ -1 +1 @@
|
|
1
|
-
ruby 3.1.
|
1
|
+
ruby 3.1.3
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,11 @@
|
|
1
|
+
- - -
|
2
|
+
## [v0.5.1](https://github.com/robcarruthers/rfbeam/compare/v0.5.0..v0.5.1) - 2023-05-09
|
3
|
+
#### Documentation
|
4
|
+
- **(cog)** Setup changelog generator - ([23dd6d8](https://github.com/robcarruthers/rfbeam/commit/23dd6d8407edaf6d4c29472fa60775a5aea87daa)) - [@robcarruthers](https://github.com/robcarruthers)
|
5
|
+
- **(readme)** Updated - ([14bb58e](https://github.com/robcarruthers/rfbeam/commit/14bb58ecaa6f55166532151425fa24269b515937)) - [@robcarruthers](https://github.com/robcarruthers)
|
6
|
+
|
7
|
+
- - -
|
8
|
+
|
1
9
|
## [0.5.0] - 2023-11-4
|
2
10
|
|
3
11
|
- Refactored CLI, refined help and options
|
data/Gemfile.lock
CHANGED
@@ -9,7 +9,7 @@ GIT
|
|
9
9
|
PATH
|
10
10
|
remote: .
|
11
11
|
specs:
|
12
|
-
rfbeam (0.5.
|
12
|
+
rfbeam (0.5.1)
|
13
13
|
activesupport (~> 6.1.0)
|
14
14
|
rubyserial (~> 0.6.0)
|
15
15
|
thor (~> 1.2.1)
|
@@ -89,6 +89,7 @@ GEM
|
|
89
89
|
PLATFORMS
|
90
90
|
aarch64-linux
|
91
91
|
arm64-darwin-21
|
92
|
+
arm64-darwin-22
|
92
93
|
|
93
94
|
DEPENDENCIES
|
94
95
|
minitest (~> 5.0)
|
data/Rakefile
CHANGED
@@ -2,14 +2,19 @@
|
|
2
2
|
|
3
3
|
require 'bundler/gem_tasks'
|
4
4
|
require 'rake/testtask'
|
5
|
+
require 'rubocop/rake_task'
|
5
6
|
|
6
|
-
Rake::TestTask.new(:
|
7
|
+
Rake::TestTask.new(:local_test) do |t|
|
7
8
|
t.libs << 'test'
|
8
9
|
t.libs << 'lib'
|
9
|
-
t.test_files = FileList['test
|
10
|
+
t.test_files = FileList['test/local_tests/test_*.rb']
|
10
11
|
end
|
11
12
|
|
12
|
-
|
13
|
+
Rake::TestTask.new(:test) do |t|
|
14
|
+
t.libs << 'test'
|
15
|
+
t.libs << 'lib'
|
16
|
+
t.test_files = FileList['test/**/test_*.rb'].exclude('test/local_tests/**/*')
|
17
|
+
end
|
13
18
|
|
14
19
|
RuboCop::RakeTask.new
|
15
20
|
|
data/cog.toml
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
from_latest_tag = false
|
2
|
+
ignore_merge_commits = false
|
3
|
+
branch_whitelist = []
|
4
|
+
pre_bump_hooks = [ "bump set {{version}} -p 'chore(version):' -m 'v{{version}}'" ]
|
5
|
+
post_bump_hooks = [ "rake release" ]
|
6
|
+
pre_package_bump_hooks = []
|
7
|
+
post_package_bump_hooks = []
|
8
|
+
tag_prefix = "v"
|
9
|
+
|
10
|
+
[commit_types]
|
11
|
+
|
12
|
+
[changelog]
|
13
|
+
path = "CHANGELOG.md"
|
14
|
+
template = "remote"
|
15
|
+
remote = "github.com"
|
16
|
+
repository = "rfbeam"
|
17
|
+
owner = "robcarruthers"
|
18
|
+
authors = [
|
19
|
+
{ signature = "Rob Carruthers", username = "robcarruthers" }
|
20
|
+
]
|
21
|
+
|
22
|
+
[bump_profiles]
|
23
|
+
|
24
|
+
[packages]
|
data/lib/rfbeam/cli.rb
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'thor'
|
4
|
-
require 'rfbeam'
|
5
4
|
require 'tty-table'
|
6
5
|
require 'tty-logger'
|
7
6
|
require 'tty-spinner'
|
@@ -10,7 +9,7 @@ require 'unicode_plot'
|
|
10
9
|
|
11
10
|
module RfBeam
|
12
11
|
class CLI < Thor
|
13
|
-
attr_accessor :logger
|
12
|
+
attr_accessor :radar, :logger
|
14
13
|
|
15
14
|
desc 'list', 'List available radar modules'
|
16
15
|
def list
|
@@ -43,12 +42,25 @@ module RfBeam
|
|
43
42
|
@logger.success r.formatted_parameter(param.to_sym)
|
44
43
|
end
|
45
44
|
|
46
|
-
desc 'ddat
|
47
|
-
option :stream, type: :boolean, aliases: '-s', desc: 'Stream the data from the device
|
48
|
-
option :raw, type: :boolean, aliases: '-r', desc: 'Display raw data'
|
45
|
+
desc 'ddat <radar_id>', 'stream any valid detections, stop stream with q and enter'
|
46
|
+
option :stream, type: :boolean, aliases: '-s', desc: 'Stream the data from the device'
|
49
47
|
def ddat(radar_id)
|
50
|
-
|
51
|
-
|
48
|
+
init_radar radar_id
|
49
|
+
|
50
|
+
if options[:stream]
|
51
|
+
Thread.new { monitor_keypress }
|
52
|
+
spinner = TTY::Spinner.new('[:spinner] :title ', format: :bouncing_ball)
|
53
|
+
loop do
|
54
|
+
break if @stop_streaming
|
55
|
+
spinner.spin
|
56
|
+
data = @radar.ddat
|
57
|
+
spinner.update title: "Searching... #{data[:detection_str]}"
|
58
|
+
@logger.success "#{@radar.tdat}" if data[:detection]
|
59
|
+
end
|
60
|
+
puts "\nTask Quit."
|
61
|
+
else
|
62
|
+
puts "\n#{@radar.ddat}"
|
63
|
+
end
|
52
64
|
end
|
53
65
|
|
54
66
|
desc 'tdat [RADAR_ID]', 'Display tracked target data'
|
@@ -64,7 +76,7 @@ module RfBeam
|
|
64
76
|
cli.display(:pdat, options)
|
65
77
|
end
|
66
78
|
|
67
|
-
desc 'rfft
|
79
|
+
desc 'rfft <radar_id>', 'Display the dopplar radar data as a plot'
|
68
80
|
option :stream, type: :boolean, aliases: '-s', desc: 'Stream the data from the device'
|
69
81
|
option :raw, type: :boolean, aliases: '-r', desc: 'Display raw data'
|
70
82
|
def rfft(radar_id)
|
@@ -83,7 +95,44 @@ module RfBeam
|
|
83
95
|
@logger = TTY::Logger.new
|
84
96
|
return @logger.warning 'No Radar modules found.' unless devices.count.positive?
|
85
97
|
|
86
|
-
RfBeam::
|
98
|
+
@radar = RfBeam::K_ld7.new(devices[id.to_i])
|
99
|
+
end
|
100
|
+
|
101
|
+
def plot_data(data)
|
102
|
+
{ x: Array(-128...128), series1: data.shift(256).map { |value| value / 100 }, series2: data.shift(256).map { |value| value.to_i / 100 } }
|
103
|
+
end
|
104
|
+
|
105
|
+
def monitor_keypress
|
106
|
+
@stop_streaming = false
|
107
|
+
loop do
|
108
|
+
key = STDIN.getch
|
109
|
+
if key.downcase == 'q'
|
110
|
+
@stop_streaming = true
|
111
|
+
break
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
def rfft_plot(radar)
|
117
|
+
speed = radar.max_speed
|
118
|
+
speed_label = radar.formatted_parameter(:max_speed)
|
119
|
+
xlim = [speed - speed * 2, speed]
|
120
|
+
data = plot_data(radar.rfft)
|
121
|
+
plot =
|
122
|
+
UnicodePlot.lineplot(
|
123
|
+
data[:x],
|
124
|
+
data[:series1],
|
125
|
+
name: 'IF1/2 Averaged',
|
126
|
+
title: 'Raw FFT',
|
127
|
+
height: 25,
|
128
|
+
width: 120,
|
129
|
+
xlabel: "Speed (km/h), #{speed_label}",
|
130
|
+
ylabel: 'Signal (db)',
|
131
|
+
xlim: [-128, 128],
|
132
|
+
ylim: [0, 100]
|
133
|
+
)
|
134
|
+
UnicodePlot.lineplot!(plot, data[:x], data[:series2], name: 'Threshold')
|
135
|
+
plot
|
87
136
|
end
|
88
137
|
end
|
89
138
|
end
|
@@ -33,231 +33,158 @@ module RfBeam
|
|
33
33
|
speed: %w[Low High]
|
34
34
|
}.freeze
|
35
35
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
@grps_index = grps_index
|
42
|
-
@description = options.fetch(:description, nil)
|
43
|
-
@default = options.fetch(:default, nil)
|
44
|
-
@units = options.fetch(:units, nil)
|
45
|
-
@str_values = options.fetch(:str_values, [])
|
36
|
+
Param =
|
37
|
+
Data.define(:name, :grps_index, :description, :default, :units, :values) do |_param|
|
38
|
+
def initialize(name:, grps_index:, description: nil, default: nil, units: nil, values: [])
|
39
|
+
super(name:, grps_index:, description:, default:, units:, values:)
|
40
|
+
end
|
46
41
|
end
|
47
|
-
end
|
48
42
|
|
49
43
|
RADAR_PARAMETERS = {
|
50
|
-
sw_version: Param.new(name: 'Software Version', grps_index: 2,
|
44
|
+
sw_version: Param.new(name: 'Software Version', grps_index: 2, default: 'K-LD7_APP-RFB-XXXX'),
|
51
45
|
base_frequency:
|
52
46
|
Param.new(
|
53
47
|
name: 'Base Frequency',
|
54
48
|
grps_index: 3,
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
str_values: %w[Low Middle High]
|
59
|
-
}
|
49
|
+
description: '0 = Low, 1 = Middle, 2 = High',
|
50
|
+
default: 1,
|
51
|
+
values: %w[Low Middle High]
|
60
52
|
),
|
61
53
|
max_speed:
|
62
54
|
Param.new(
|
63
55
|
name: 'Maximum Speed',
|
64
56
|
grps_index: 4,
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
str_values: %w[12.5 25 50 100]
|
70
|
-
}
|
57
|
+
description: '0 = 12km/h, 1 = 25km/h, 2 = 50km/h, 3 = 100km/h',
|
58
|
+
default: 1,
|
59
|
+
units: 'km/h',
|
60
|
+
values: %w[12.5 25 50 100]
|
71
61
|
),
|
72
62
|
max_range:
|
73
63
|
Param.new(
|
74
64
|
name: 'Maximum Range',
|
75
65
|
grps_index: 5,
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
str_values: %w[5m 10m 30m 100m]
|
80
|
-
}
|
66
|
+
description: '0 = 5m, 1 = 10m, 2 = 30m, 3 = 100m',
|
67
|
+
default: 1,
|
68
|
+
values: %w[5m 10m 30m 100m]
|
81
69
|
),
|
82
70
|
threshold_offset:
|
83
|
-
Param.new(
|
84
|
-
name: 'Threshold Offset',
|
85
|
-
grps_index: 6,
|
86
|
-
options: {
|
87
|
-
description: '10db - 60db',
|
88
|
-
default: 30,
|
89
|
-
units: 'db'
|
90
|
-
}
|
91
|
-
),
|
71
|
+
Param.new(name: 'Threshold Offset', grps_index: 6, description: '10db - 60db', default: 30, units: 'db'),
|
92
72
|
tracking_filter:
|
93
73
|
Param.new(
|
94
74
|
name: 'Tracking Filter Type',
|
95
75
|
grps_index: 7,
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
str_values: ['standard', 'Fast Detection', 'Long Visibility']
|
100
|
-
}
|
76
|
+
description: '0 = Standard, 2 = Fast Detection, 3 = Long Visibility',
|
77
|
+
default: 0,
|
78
|
+
values: ['standard', 'Fast Detection', 'Long Visibility']
|
101
79
|
),
|
102
80
|
vibration_suppression:
|
103
81
|
Param.new(
|
104
82
|
name: 'Vibration Suppression',
|
105
83
|
grps_index: 8,
|
106
|
-
|
107
|
-
|
108
|
-
default: 2
|
109
|
-
}
|
84
|
+
description: '0-16, 0 = No Suppression, 16 = High Suppression',
|
85
|
+
default: 2
|
110
86
|
),
|
111
87
|
min_detection_distance:
|
112
88
|
Param.new(
|
113
89
|
name: 'Minimum Detection Distance',
|
114
90
|
grps_index: 9,
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
units: '%'
|
119
|
-
}
|
91
|
+
description: '0 - 100% of range setting',
|
92
|
+
default: 0,
|
93
|
+
units: '%'
|
120
94
|
),
|
121
95
|
max_detection_distance:
|
122
96
|
Param.new(
|
123
97
|
name: 'Maximum Detection Distance',
|
124
98
|
grps_index: 10,
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
units: '%'
|
129
|
-
}
|
99
|
+
description: '0 - 100% of range setting',
|
100
|
+
default: 50,
|
101
|
+
units: '%'
|
130
102
|
),
|
131
103
|
min_detection_angle:
|
132
|
-
Param.new(
|
133
|
-
name: 'Minimum Detection Angle',
|
134
|
-
grps_index: 11,
|
135
|
-
options: {
|
136
|
-
description: '-90° - 90°',
|
137
|
-
default: -90,
|
138
|
-
units: '°'
|
139
|
-
}
|
140
|
-
),
|
104
|
+
Param.new(name: 'Minimum Detection Angle', grps_index: 11, description: '-90° - 90°', default: -90, units: '°'),
|
141
105
|
max_detection_angle:
|
142
|
-
Param.new(
|
143
|
-
name: 'Maximum Detection Angle',
|
144
|
-
grps_index: 12,
|
145
|
-
options: {
|
146
|
-
description: '-90° - 90°',
|
147
|
-
default: 90,
|
148
|
-
units: '°'
|
149
|
-
}
|
150
|
-
),
|
106
|
+
Param.new(name: 'Maximum Detection Angle', grps_index: 12, description: '-90° - 90°', default: 90, units: '°'),
|
151
107
|
min_detection_speed:
|
152
108
|
Param.new(
|
153
109
|
name: 'Minimum Detection Speed',
|
154
110
|
grps_index: 13,
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
units: '%'
|
159
|
-
}
|
111
|
+
description: '0 - 100% of speed setting',
|
112
|
+
default: 0,
|
113
|
+
units: '%'
|
160
114
|
),
|
161
115
|
max_detection_speed:
|
162
116
|
Param.new(
|
163
117
|
name: 'Maximum Detection Speed',
|
164
118
|
grps_index: 14,
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
units: '%'
|
169
|
-
}
|
119
|
+
description: '0 - 100% of speed setting',
|
120
|
+
default: 100,
|
121
|
+
units: '%'
|
170
122
|
),
|
171
123
|
detection_direction:
|
172
124
|
Param.new(
|
173
125
|
name: 'Detection Direction',
|
174
126
|
grps_index: 15,
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
str_values: %w[Receding Approaching Both]
|
179
|
-
}
|
127
|
+
description: '0 = Receding, 1 = Approaching, 2 = Both',
|
128
|
+
default: 2,
|
129
|
+
values: %w[Receding Approaching Both]
|
180
130
|
),
|
181
131
|
range_threshold:
|
182
132
|
Param.new(
|
183
133
|
name: 'Range Threshold',
|
184
134
|
grps_index: 16,
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
units: '%'
|
189
|
-
}
|
135
|
+
description: '0 - 100% of range setting',
|
136
|
+
default: 10,
|
137
|
+
units: '%'
|
190
138
|
),
|
191
139
|
angle_threshold:
|
192
|
-
Param.new(
|
193
|
-
name: 'Angle Threshold',
|
194
|
-
grps_index: 17,
|
195
|
-
options: {
|
196
|
-
description: '-90° - 90°',
|
197
|
-
default: 0,
|
198
|
-
units: '°'
|
199
|
-
}
|
200
|
-
),
|
140
|
+
Param.new(name: 'Angle Threshold', grps_index: 17, description: '-90° - 90°', default: 0, units: '°'),
|
201
141
|
speed_threshold:
|
202
142
|
Param.new(
|
203
143
|
name: 'Speed Threshold',
|
204
144
|
grps_index: 18,
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
units: '%'
|
209
|
-
}
|
145
|
+
description: '0 - 100% of speed setting',
|
146
|
+
default: 50,
|
147
|
+
units: '%'
|
210
148
|
),
|
211
149
|
digital_output1:
|
212
150
|
Param.new(
|
213
151
|
name: 'Digital Output 1',
|
214
152
|
grps_index: 19,
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
str_values: %w[Direction Angle Range Speed Micro]
|
219
|
-
}
|
153
|
+
description: '0 = Direction, 1 = Angle, 2 = Range, 3 = Speed, 4 = Micro Detection',
|
154
|
+
default: 0,
|
155
|
+
values: %w[Direction Angle Range Speed Micro]
|
220
156
|
),
|
221
157
|
digital_output2:
|
222
158
|
Param.new(
|
223
159
|
name: 'Digital Output 2',
|
224
160
|
grps_index: 20,
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
str_values: %w[Direction Angle Range Speed Micro]
|
229
|
-
}
|
161
|
+
description: '0 = Direction, 1 = Angle, 2 = Range, 3 = Speed, 4 = Micro Detection',
|
162
|
+
default: 1,
|
163
|
+
values: %w[Direction Angle Range Speed Micro]
|
230
164
|
),
|
231
165
|
digital_output3:
|
232
166
|
Param.new(
|
233
167
|
name: 'Digital Output 3',
|
234
168
|
grps_index: 21,
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
str_values: %w[Direction Angle Range Speed Micro]
|
239
|
-
}
|
169
|
+
description: '0 = Direction, 1 = Angle, 2 = Range, 3 = Speed, 4 = Micro Detection',
|
170
|
+
default: 2,
|
171
|
+
values: %w[Direction Angle Range Speed Micro]
|
240
172
|
),
|
241
|
-
hold_time:
|
242
|
-
Param.new(name: 'Hold Time', grps_index: 22, options: { description: '1 - 7200s', default: 1, units: 's' }),
|
173
|
+
hold_time: Param.new(name: 'Hold Time', grps_index: 22, description: '1 - 7200s', default: 1, units: 's'),
|
243
174
|
micro_detection_retrigger:
|
244
175
|
Param.new(
|
245
176
|
name: 'Micro Detection Trigger',
|
246
177
|
grps_index: 23,
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
str_values: %w[Off Retrigger]
|
251
|
-
}
|
178
|
+
description: '0 = Off, 1 = Retrigger',
|
179
|
+
default: 0,
|
180
|
+
values: %w[Off Retrigger]
|
252
181
|
),
|
253
182
|
micro_detection_sensativity:
|
254
183
|
Param.new(
|
255
184
|
name: 'Micro Detection Sensativity',
|
256
185
|
grps_index: 24,
|
257
|
-
|
258
|
-
|
259
|
-
default: 4
|
260
|
-
}
|
186
|
+
description: '0 - 9, 0 = Min, 9 = Max',
|
187
|
+
default: 4
|
261
188
|
)
|
262
189
|
}.freeze
|
263
190
|
end
|
@@ -1,6 +1,4 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require 'csv'
|
1
|
+
require "csv"
|
4
2
|
|
5
3
|
module RfBeam
|
6
4
|
module Kld7
|
@@ -12,26 +10,26 @@ module RfBeam
|
|
12
10
|
def rfft
|
13
11
|
request_frame_data(:rfft)
|
14
12
|
sleep MEASUREMENT_DELAY
|
15
|
-
data = read(1032).unpack(
|
13
|
+
data = read(1032).unpack("a4LS256S256")
|
16
14
|
header, length = data.shift(2)
|
17
|
-
|
15
|
+
unless header == "RFFT"
|
16
|
+
raise Error, "RFFT header response, header=#{header}"
|
17
|
+
end
|
18
18
|
raise Error, "RFFT payload length, length=#{length}" unless length == 1024
|
19
19
|
|
20
20
|
data
|
21
21
|
end
|
22
22
|
|
23
23
|
def reset
|
24
|
-
command = [
|
25
|
-
write command.pack(
|
24
|
+
command = ["RFSE", 0]
|
25
|
+
write command.pack("a4L")
|
26
26
|
check_response
|
27
27
|
end
|
28
28
|
alias rfse reset
|
29
29
|
|
30
30
|
def pdat(formatted: false)
|
31
31
|
request_frame_data(:pdat)
|
32
|
-
resp = read(102).unpack(
|
33
|
-
raise Error, "PDAT response = #{resp[0]}" unless resp[0] == 'PDAT'
|
34
|
-
|
32
|
+
resp = read(102).unpack("a4LSssSSssSSssSSssSSssSSssSSssSSssSSssSSssS")
|
35
33
|
return resp unless formatted
|
36
34
|
|
37
35
|
target_count = resp[1].to_i / 8
|
@@ -40,7 +38,9 @@ module RfBeam
|
|
40
38
|
resp.shift 2
|
41
39
|
resp.compact
|
42
40
|
detected_raw_targets = []
|
43
|
-
target_count.times
|
41
|
+
target_count.times do
|
42
|
+
detected_raw_targets << format_raw_target_data(resp.shift(4))
|
43
|
+
end
|
44
44
|
detected_raw_targets
|
45
45
|
end
|
46
46
|
|
@@ -48,34 +48,46 @@ module RfBeam
|
|
48
48
|
request_frame_data(:tdat)
|
49
49
|
sleep MEASUREMENT_DELAY
|
50
50
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
51
|
+
sleep 0.1
|
52
|
+
resp = read(16).unpack("a4LSssS")
|
53
|
+
unless resp[1].zero?
|
54
|
+
return { dist: resp[2], speed: resp[3], angle: resp[4], mag: resp[5] }
|
55
|
+
end
|
55
56
|
end
|
56
57
|
|
57
58
|
def ddat
|
58
59
|
request_frame_data(:ddat)
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
60
|
+
flags = %w[Low High]
|
61
|
+
array = read(14).unpack("a4LC6")
|
62
|
+
{
|
63
|
+
label: array[0],
|
64
|
+
detection: array[2] == 1,
|
65
|
+
detection_str: DETECTION_FLAGS[:detection][array[2]],
|
66
|
+
micro_detection: DETECTION_FLAGS[:micro_detection][array[3]],
|
67
|
+
angle: DETECTION_FLAGS[:angle][array[4]],
|
68
|
+
direction: DETECTION_FLAGS[:direction][array[5]],
|
69
|
+
range: DETECTION_FLAGS[:range][array[6]],
|
70
|
+
speed: DETECTION_FLAGS[:speed][array[7]]
|
71
|
+
}
|
65
72
|
end
|
66
73
|
|
67
74
|
# Get the radar parameter structure
|
68
75
|
def grps
|
69
|
-
command = [
|
70
|
-
write command.pack(
|
76
|
+
command = ["GRPS", 0]
|
77
|
+
write command.pack("a4L")
|
71
78
|
check_response
|
72
|
-
read(50).unpack(
|
79
|
+
read(50).unpack("a4LA19C8c2C4cCCCCSCC")
|
73
80
|
end
|
74
81
|
|
75
82
|
def config
|
76
83
|
data = grps
|
77
|
-
output =
|
78
|
-
RADAR_PARAMETERS.
|
84
|
+
output = "\n"
|
85
|
+
RADAR_PARAMETERS.keys.each do |key|
|
86
|
+
output << formatted_parameter(
|
87
|
+
key,
|
88
|
+
data[RADAR_PARAMETERS[key].grps_index]
|
89
|
+
)
|
90
|
+
end
|
79
91
|
output
|
80
92
|
end
|
81
93
|
|
@@ -92,12 +104,17 @@ module RfBeam
|
|
92
104
|
private
|
93
105
|
|
94
106
|
def format_raw_target_data(array)
|
95
|
-
{
|
107
|
+
{
|
108
|
+
dist: array.shift,
|
109
|
+
speed: array.shift,
|
110
|
+
angle: array.shift,
|
111
|
+
mag: array.shift
|
112
|
+
}
|
96
113
|
end
|
97
114
|
|
98
115
|
def request_frame_data(type)
|
99
|
-
command = [
|
100
|
-
write command.pack(
|
116
|
+
command = ["GNFD", 4, FRAME_DATA_TYPES[type]]
|
117
|
+
write command.pack("a4LL")
|
101
118
|
check_response
|
102
119
|
end
|
103
120
|
end
|
@@ -1,7 +1,5 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
1
|
module RfBeam
|
4
|
-
module
|
2
|
+
module KLD7
|
5
3
|
# -----------------
|
6
4
|
# Software Version, 'K-LD7_APP-RFB-XXXX'
|
7
5
|
# -----------------
|
@@ -20,11 +18,11 @@ module RfBeam
|
|
20
18
|
def base_frequency=(frequency = 1)
|
21
19
|
value =
|
22
20
|
case frequency
|
23
|
-
when 0, :low,
|
21
|
+
when 0, :low, "low"
|
24
22
|
0
|
25
|
-
when 1, :middle,
|
23
|
+
when 1, :middle, "middle"
|
26
24
|
1
|
27
|
-
when 2, :high,
|
25
|
+
when 2, :high, "high"
|
28
26
|
2
|
29
27
|
else
|
30
28
|
raise ArgumentError, "Invalid arg: '#{frequency}'"
|
@@ -43,8 +41,10 @@ module RfBeam
|
|
43
41
|
end
|
44
42
|
|
45
43
|
def max_speed=(speed = 1)
|
46
|
-
|
47
|
-
|
44
|
+
unless (0..3).include?(speed)
|
45
|
+
raise ArgumentError, "Invalid arg: '#{speed}'"
|
46
|
+
end
|
47
|
+
raise ArgumentError, "Expected an Integer" unless speed.is_a?(Integer)
|
48
48
|
|
49
49
|
set_parameter :rspi, speed, :uint32
|
50
50
|
end
|
@@ -60,8 +60,10 @@ module RfBeam
|
|
60
60
|
end
|
61
61
|
|
62
62
|
def max_range=(range = 1)
|
63
|
-
|
64
|
-
|
63
|
+
unless (0..3).include?(range)
|
64
|
+
raise ArgumentError, "Invalid arg: '#{range}'"
|
65
|
+
end
|
66
|
+
raise ArgumentError, "Expected an Integer" unless range.is_a?(Integer)
|
65
67
|
|
66
68
|
set_parameter :rrai, range, :uint32
|
67
69
|
end
|
@@ -77,8 +79,10 @@ module RfBeam
|
|
77
79
|
end
|
78
80
|
|
79
81
|
def threshold_offset=(offset = 30)
|
80
|
-
|
81
|
-
|
82
|
+
unless (10..60).include?(offset)
|
83
|
+
raise ArgumentError, "Invalid arg: '#{offset}'"
|
84
|
+
end
|
85
|
+
raise ArgumentError, "Expected an Integer" unless offset.is_a?(Integer)
|
82
86
|
|
83
87
|
set_parameter :thof, offset, :uint32
|
84
88
|
end
|
@@ -95,7 +99,7 @@ module RfBeam
|
|
95
99
|
|
96
100
|
def tracking_filter=(type = 0)
|
97
101
|
raise ArgumentError, "Invalid arg: '#{type}'" unless (0..2).include?(type)
|
98
|
-
raise ArgumentError,
|
102
|
+
raise ArgumentError, "Expected an Integer" unless type.is_a?(Integer)
|
99
103
|
|
100
104
|
set_parameter :trft, type, :uint32
|
101
105
|
end
|
@@ -110,8 +114,10 @@ module RfBeam
|
|
110
114
|
end
|
111
115
|
|
112
116
|
def vibration_suppression=(value = 2)
|
113
|
-
|
114
|
-
|
117
|
+
unless (0..16).include?(value)
|
118
|
+
raise ArgumentError, "Invalid arg: '#{value}'"
|
119
|
+
end
|
120
|
+
raise ArgumentError, "Expected an Integer" unless value.is_a?(Integer)
|
115
121
|
|
116
122
|
set_parameter :visu, value, :uint32
|
117
123
|
end
|
@@ -126,8 +132,10 @@ module RfBeam
|
|
126
132
|
end
|
127
133
|
|
128
134
|
def min_detection_distance=(value = 0)
|
129
|
-
|
130
|
-
|
135
|
+
unless (0..100).include?(value)
|
136
|
+
raise ArgumentError, "Invalid arg: '#{value}'"
|
137
|
+
end
|
138
|
+
raise ArgumentError, "Expected an Integer" unless value.is_a?(Integer)
|
131
139
|
|
132
140
|
set_parameter :mira, value, :uint32
|
133
141
|
end
|
@@ -142,8 +150,10 @@ module RfBeam
|
|
142
150
|
end
|
143
151
|
|
144
152
|
def max_detection_distance=(value = 50)
|
145
|
-
|
146
|
-
|
153
|
+
unless (0..100).include?(value)
|
154
|
+
raise ArgumentError, "Invalid arg: '#{value}'"
|
155
|
+
end
|
156
|
+
raise ArgumentError, "Expected an Integer" unless value.is_a?(Integer)
|
147
157
|
|
148
158
|
set_parameter :mara, value, :uint32
|
149
159
|
end
|
@@ -158,8 +168,10 @@ module RfBeam
|
|
158
168
|
end
|
159
169
|
|
160
170
|
def min_detection_angle=(angle = -90)
|
161
|
-
|
162
|
-
|
171
|
+
unless (-90..90).include?(angle)
|
172
|
+
raise ArgumentError, "Invalid arg: '#{angle}'"
|
173
|
+
end
|
174
|
+
raise ArgumentError, "Expected an Integer" unless angle.is_a?(Integer)
|
163
175
|
|
164
176
|
set_parameter :mian, angle, :int32
|
165
177
|
end
|
@@ -174,8 +186,10 @@ module RfBeam
|
|
174
186
|
end
|
175
187
|
|
176
188
|
def max_detection_angle=(angle = 90)
|
177
|
-
|
178
|
-
|
189
|
+
unless (-90..90).include?(angle)
|
190
|
+
raise ArgumentError, "Invalid arg: '#{angle}'"
|
191
|
+
end
|
192
|
+
raise ArgumentError, "Expected an Integer" unless angle.is_a?(Integer)
|
179
193
|
|
180
194
|
set_parameter :maan, angle, :int32
|
181
195
|
end
|
@@ -190,8 +204,10 @@ module RfBeam
|
|
190
204
|
end
|
191
205
|
|
192
206
|
def min_detection_speed=(speed = 0)
|
193
|
-
|
194
|
-
|
207
|
+
unless (0..100).include?(speed)
|
208
|
+
raise ArgumentError, "Invalid arg: '#{speed}'"
|
209
|
+
end
|
210
|
+
raise ArgumentError, "Expected an Integer" unless speed.is_a?(Integer)
|
195
211
|
|
196
212
|
set_parameter :misp, speed, :uint32
|
197
213
|
end
|
@@ -206,8 +222,10 @@ module RfBeam
|
|
206
222
|
end
|
207
223
|
|
208
224
|
def max_detection_speed=(speed = 100)
|
209
|
-
|
210
|
-
|
225
|
+
unless (0..100).include?(speed)
|
226
|
+
raise ArgumentError, "Invalid arg: '#{speed}'"
|
227
|
+
end
|
228
|
+
raise ArgumentError, "Expected an Integer" unless speed.is_a?(Integer)
|
211
229
|
|
212
230
|
set_parameter :masp, speed, :uint32
|
213
231
|
end
|
@@ -222,8 +240,10 @@ module RfBeam
|
|
222
240
|
end
|
223
241
|
|
224
242
|
def detection_direction=(direction = 2)
|
225
|
-
|
226
|
-
|
243
|
+
unless (0..2).include?(direction)
|
244
|
+
raise ArgumentError, "Invalid arg: '#{direction}'"
|
245
|
+
end
|
246
|
+
raise ArgumentError, "Expected an Integer" unless direction.is_a?(Integer)
|
227
247
|
|
228
248
|
set_parameter :dedi, direction, :uint32
|
229
249
|
end
|
@@ -238,8 +258,10 @@ module RfBeam
|
|
238
258
|
end
|
239
259
|
|
240
260
|
def range_threshold=(value = 10)
|
241
|
-
|
242
|
-
|
261
|
+
unless (0..100).include?(value)
|
262
|
+
raise ArgumentError, "Invalid arg: '#{value}'"
|
263
|
+
end
|
264
|
+
raise ArgumentError, "Expected an Integer" unless value.is_a?(Integer)
|
243
265
|
|
244
266
|
set_parameter :rath, value, :uint32
|
245
267
|
end
|
@@ -254,8 +276,10 @@ module RfBeam
|
|
254
276
|
end
|
255
277
|
|
256
278
|
def angle_threshold=(value = 0)
|
257
|
-
|
258
|
-
|
279
|
+
unless (-90..90).include?(value)
|
280
|
+
raise ArgumentError, "Invalid arg: '#{value}'"
|
281
|
+
end
|
282
|
+
raise ArgumentError, "Expected an Integer" unless value.is_a?(Integer)
|
259
283
|
|
260
284
|
set_parameter :anth, value, :int32
|
261
285
|
end
|
@@ -270,8 +294,10 @@ module RfBeam
|
|
270
294
|
end
|
271
295
|
|
272
296
|
def speed_threshold=(value = 50)
|
273
|
-
|
274
|
-
|
297
|
+
unless (0..100).include?(value)
|
298
|
+
raise ArgumentError, "Invalid arg: '#{value}'"
|
299
|
+
end
|
300
|
+
raise ArgumentError, "Expected an Integer" unless value.is_a?(Integer)
|
275
301
|
|
276
302
|
set_parameter :spth, value, :uint32
|
277
303
|
end
|
@@ -286,8 +312,10 @@ module RfBeam
|
|
286
312
|
end
|
287
313
|
|
288
314
|
def digital_output1=(value = 0)
|
289
|
-
|
290
|
-
|
315
|
+
unless (0..4).include?(value)
|
316
|
+
raise ArgumentError, "Invalid arg: '#{value}'"
|
317
|
+
end
|
318
|
+
raise ArgumentError, "Expected an Integer" unless value.is_a?(Integer)
|
291
319
|
|
292
320
|
set_parameter :dig1, value, :uint32
|
293
321
|
end
|
@@ -302,8 +330,10 @@ module RfBeam
|
|
302
330
|
end
|
303
331
|
|
304
332
|
def digital_output2=(value = 1)
|
305
|
-
|
306
|
-
|
333
|
+
unless (0..4).include?(value)
|
334
|
+
raise ArgumentError, "Invalid arg: '#{value}'"
|
335
|
+
end
|
336
|
+
raise ArgumentError, "Expected an Integer" unless value.is_a?(Integer)
|
307
337
|
|
308
338
|
set_parameter :dig2, value, :uint32
|
309
339
|
end
|
@@ -318,8 +348,10 @@ module RfBeam
|
|
318
348
|
end
|
319
349
|
|
320
350
|
def digital_output3=(value = 2)
|
321
|
-
|
322
|
-
|
351
|
+
unless (0..4).include?(value)
|
352
|
+
raise ArgumentError, "Invalid arg: '#{value}'"
|
353
|
+
end
|
354
|
+
raise ArgumentError, "Expected an Integer" unless value.is_a?(Integer)
|
323
355
|
|
324
356
|
set_parameter :dig3, value, :uint32
|
325
357
|
end
|
@@ -334,8 +366,10 @@ module RfBeam
|
|
334
366
|
end
|
335
367
|
|
336
368
|
def hold_time=(time = 1)
|
337
|
-
|
338
|
-
|
369
|
+
unless (1..7200).include?(time)
|
370
|
+
raise ArgumentError, "Invalid arg: '#{time}'"
|
371
|
+
end
|
372
|
+
raise ArgumentError, "Expected an Integer" unless time.is_a?(Integer)
|
339
373
|
|
340
374
|
set_parameter :hold, time, :uint32
|
341
375
|
end
|
@@ -346,12 +380,16 @@ module RfBeam
|
|
346
380
|
# Micro Detection retrigger, 0 = Off (default), 1 = Retrigger
|
347
381
|
# -----------------
|
348
382
|
def micro_detection_retrigger
|
349
|
-
query_parameter RADAR_PARAMETERS[
|
383
|
+
query_parameter RADAR_PARAMETERS[
|
384
|
+
:set_micro_detection_retrigger
|
385
|
+
].grps_index
|
350
386
|
end
|
351
387
|
|
352
388
|
def micro_detection_retrigger=(value = 0)
|
353
|
-
|
354
|
-
|
389
|
+
unless (0..1).include?(value)
|
390
|
+
raise ArgumentError, "Invalid arg: '#{value}'"
|
391
|
+
end
|
392
|
+
raise ArgumentError, "Expected an Integer" unless value.is_a?(Integer)
|
355
393
|
|
356
394
|
set_parameter :mide, value, :uint32
|
357
395
|
end
|
@@ -366,8 +404,10 @@ module RfBeam
|
|
366
404
|
end
|
367
405
|
|
368
406
|
def micro_detection_sensitivity=(value = 4)
|
369
|
-
|
370
|
-
|
407
|
+
unless (0..9).include?(value)
|
408
|
+
raise ArgumentError, "Invalid arg: '#{value}'"
|
409
|
+
end
|
410
|
+
raise ArgumentError, "Expected an Integer" unless value.is_a?(Integer)
|
371
411
|
|
372
412
|
set_parameter :mids, value, :uint32
|
373
413
|
end
|
@@ -384,10 +424,14 @@ module RfBeam
|
|
384
424
|
def set_parameter(header, value, return_type = :uint32)
|
385
425
|
return_type =
|
386
426
|
case return_type
|
427
|
+
when :uint32
|
428
|
+
"L"
|
387
429
|
when :int32
|
388
|
-
|
430
|
+
"l"
|
431
|
+
when :uint32
|
432
|
+
"S"
|
389
433
|
else
|
390
|
-
|
434
|
+
"L"
|
391
435
|
end
|
392
436
|
command = [header.upcase.to_s, 4, value]
|
393
437
|
write command.pack("a4L#{return_type}")
|
@@ -0,0 +1,82 @@
|
|
1
|
+
# rubocop:disable all
|
2
|
+
require "unicode_plot"
|
3
|
+
require "io/console"
|
4
|
+
require "stringio"
|
5
|
+
require "tty-screen"
|
6
|
+
|
7
|
+
module RfBeam
|
8
|
+
module KLD7
|
9
|
+
class Streamer
|
10
|
+
attr_accessor :radar
|
11
|
+
|
12
|
+
def initialize(radar)
|
13
|
+
@radar = radar
|
14
|
+
end
|
15
|
+
|
16
|
+
def monitor_keypress
|
17
|
+
loop do
|
18
|
+
key = STDIN.getch
|
19
|
+
if key.downcase == "q"
|
20
|
+
@stop_streaming = true
|
21
|
+
break
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def rfft
|
27
|
+
out = StringIO.new
|
28
|
+
def out.tty?
|
29
|
+
true
|
30
|
+
end
|
31
|
+
|
32
|
+
Thread.new { monitor_keypress }
|
33
|
+
|
34
|
+
loop do
|
35
|
+
out.truncate(0)
|
36
|
+
|
37
|
+
plot = rfft_plot(@radar)
|
38
|
+
plot.render(out)
|
39
|
+
|
40
|
+
lines = out.string.lines
|
41
|
+
lines.each { |line| $stdout.print "\r#{line}" }
|
42
|
+
$stdout.print "\e[0J"
|
43
|
+
$stdout.flush
|
44
|
+
break if @stop_streaming
|
45
|
+
|
46
|
+
n = lines.count
|
47
|
+
$stdout.print "\e[#{n}F"
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def plot_data(data)
|
54
|
+
{
|
55
|
+
x: Array(-128...128),
|
56
|
+
series1: data.shift(256).map { |value| value / 100 },
|
57
|
+
series2: data.shift(256).map { |value| value.to_i / 100 }
|
58
|
+
}
|
59
|
+
end
|
60
|
+
|
61
|
+
def rfft_plot(radar)
|
62
|
+
width = TTY::Screen.width * 0.65
|
63
|
+
data = plot_data(radar.rfft)
|
64
|
+
plot =
|
65
|
+
UnicodePlot.lineplot(
|
66
|
+
data[:x],
|
67
|
+
data[:series1],
|
68
|
+
name: "IF1/2 Averaged",
|
69
|
+
title: "Raw FFT",
|
70
|
+
height: 25,
|
71
|
+
width: width,
|
72
|
+
xlabel: "Speed (km/h)",
|
73
|
+
ylabel: "Signal (db)",
|
74
|
+
xlim: [-128, 128],
|
75
|
+
ylim: [0, 100]
|
76
|
+
)
|
77
|
+
UnicodePlot.lineplot!(plot, data[:x], data[:series2], name: "Threshold")
|
78
|
+
plot
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
data/lib/rfbeam/version.rb
CHANGED
data/rfbeam.gemspec
CHANGED
@@ -10,15 +10,15 @@ Gem::Specification.new do |spec|
|
|
10
10
|
|
11
11
|
spec.summary = 'Ruby API and CLI for RFBeam doplar radar modules'
|
12
12
|
spec.description = 'Currently only tested with K-LD7 on MacOS & Raspian (bullseye)'
|
13
|
-
spec.homepage = 'https://
|
13
|
+
spec.homepage = 'https://github.com/robcarruthers/rfbeam'
|
14
14
|
spec.license = 'MIT'
|
15
15
|
spec.required_ruby_version = '>= 3.1.2'
|
16
16
|
|
17
17
|
# spec.metadata["allowed_push_host"] = "TODO: Set to your gem server 'https://example.com'"
|
18
18
|
|
19
19
|
spec.metadata['homepage_uri'] = spec.homepage
|
20
|
-
spec.metadata['source_code_uri'] = 'https://
|
21
|
-
spec.metadata['changelog_uri'] = 'https://
|
20
|
+
spec.metadata['source_code_uri'] = 'https://github.com/robcarruthers/rfbeam'
|
21
|
+
spec.metadata['changelog_uri'] = 'https://github.com/robcarruthers/rfbeam/CHANGELOG.md'
|
22
22
|
|
23
23
|
# Specify which files should be added to the gem when it is released.
|
24
24
|
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
data/streamer2.rb
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
require "unicode_plot"
|
2
|
+
require "stringio"
|
3
|
+
require "io/console"
|
4
|
+
|
5
|
+
N = 1000
|
6
|
+
M = 50
|
7
|
+
|
8
|
+
def generate_random_data(n)
|
9
|
+
Array.new(n) { rand(-10.0..10.0) }
|
10
|
+
end
|
11
|
+
|
12
|
+
def monitor_keypress
|
13
|
+
loop do
|
14
|
+
key = STDIN.getch
|
15
|
+
if key.downcase == "q"
|
16
|
+
@stop_streaming = true
|
17
|
+
break
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
out = StringIO.new
|
23
|
+
def out.tty?
|
24
|
+
true
|
25
|
+
end
|
26
|
+
|
27
|
+
Thread.new { monitor_keypress }
|
28
|
+
|
29
|
+
loop do
|
30
|
+
out.truncate(0)
|
31
|
+
|
32
|
+
plot =
|
33
|
+
UnicodePlot.lineplot(
|
34
|
+
generate_random_data(40),
|
35
|
+
name: "Series 0",
|
36
|
+
width: 120,
|
37
|
+
height: 30
|
38
|
+
)
|
39
|
+
UnicodePlot.lineplot!(
|
40
|
+
plot,
|
41
|
+
generate_random_data(40),
|
42
|
+
name: "Series 1",
|
43
|
+
color: :red
|
44
|
+
)
|
45
|
+
plot.render(out)
|
46
|
+
|
47
|
+
lines = out.string.lines
|
48
|
+
lines.each { |line| $stdout.print "\r#{line}" }
|
49
|
+
$stdout.print "\e[0J"
|
50
|
+
$stdout.flush
|
51
|
+
break if @stop_streaming
|
52
|
+
|
53
|
+
n = lines.count
|
54
|
+
$stdout.print "\e[#{n}F"
|
55
|
+
end
|
data/streaming.rb
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
# rubocop:disable all
|
2
|
+
require "unicode_plot"
|
3
|
+
require "io/console"
|
4
|
+
|
5
|
+
def generate_random_data(n)
|
6
|
+
Array.new(n) { rand(-10.0..10.0) }
|
7
|
+
end
|
8
|
+
|
9
|
+
def update_data(plot, series1, series2)
|
10
|
+
plot.series_list[0].data.y = series1
|
11
|
+
plot.series_list[1].data.y = series2
|
12
|
+
plot.auto_calc_ylim
|
13
|
+
end
|
14
|
+
|
15
|
+
def start
|
16
|
+
Thread.new { monitor_keypress }
|
17
|
+
loop do
|
18
|
+
break if @stop_streaming
|
19
|
+
display_plot
|
20
|
+
sleep period
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def monitor_keypress
|
25
|
+
loop do
|
26
|
+
key = STDIN.getch
|
27
|
+
if key.downcase == "q"
|
28
|
+
@stop_streaming = true
|
29
|
+
break
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def plot_demo
|
35
|
+
out = StringIO.new
|
36
|
+
out.truncate(0)
|
37
|
+
plot =
|
38
|
+
UnicodePlot.lineplot(
|
39
|
+
generate_random_data(40),
|
40
|
+
name: "Series 0",
|
41
|
+
width: 40,
|
42
|
+
height: 10
|
43
|
+
)
|
44
|
+
|
45
|
+
UnicodePlot.lineplot!(
|
46
|
+
plot,
|
47
|
+
generate_random_data(40),
|
48
|
+
name: "Series 1",
|
49
|
+
color: :red
|
50
|
+
)
|
51
|
+
UnicodePlot.lineplot!(
|
52
|
+
plot,
|
53
|
+
generate_random_data(40),
|
54
|
+
name: "Series 2",
|
55
|
+
color: :blue
|
56
|
+
)
|
57
|
+
puts plot.render(out)
|
58
|
+
|
59
|
+
Thread.new { monitor_keypress }
|
60
|
+
|
61
|
+
loop do
|
62
|
+
break if @stop_streaming
|
63
|
+
|
64
|
+
lines = out.string.lines
|
65
|
+
lines.each { |line| $stdout.print "\r#{line}" }
|
66
|
+
$stdout.print "\e[0J"
|
67
|
+
$stdout.flush
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
plot_demo
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rfbeam
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.5.
|
4
|
+
version: 0.5.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Rob Carruthers
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-
|
11
|
+
date: 2023-05-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -133,6 +133,7 @@ files:
|
|
133
133
|
- ".DS_Store"
|
134
134
|
- ".rubocop.yml"
|
135
135
|
- ".streerc"
|
136
|
+
- ".streerc~1f4cd14e3c0a9afdf972aa5f3982d36a89869b72"
|
136
137
|
- ".tool-versions"
|
137
138
|
- CHANGELOG.md
|
138
139
|
- Gemfile
|
@@ -140,6 +141,7 @@ files:
|
|
140
141
|
- LICENSE.txt
|
141
142
|
- README.md
|
142
143
|
- Rakefile
|
144
|
+
- cog.toml
|
143
145
|
- exe/rfbeam
|
144
146
|
- lib/rfbeam.rb
|
145
147
|
- lib/rfbeam/cli.rb
|
@@ -149,6 +151,7 @@ files:
|
|
149
151
|
- lib/rfbeam/kld7/radar_messages.rb
|
150
152
|
- lib/rfbeam/kld7/radar_parameters.rb
|
151
153
|
- lib/rfbeam/kld7/serial_connection.rb
|
154
|
+
- lib/rfbeam/kld7/streamer.rb
|
152
155
|
- lib/rfbeam/version.rb
|
153
156
|
- node_modules/.bin/prettier
|
154
157
|
- node_modules/.yarn-integrity
|
@@ -238,16 +241,18 @@ files:
|
|
238
241
|
- package.json
|
239
242
|
- rfbeam.gemspec
|
240
243
|
- sig/rfbeam.rbs
|
244
|
+
- streamer2.rb
|
245
|
+
- streaming.rb
|
241
246
|
- yarn.lock
|
242
|
-
homepage: https://
|
247
|
+
homepage: https://github.com/robcarruthers/rfbeam
|
243
248
|
licenses:
|
244
249
|
- MIT
|
245
250
|
metadata:
|
246
|
-
homepage_uri: https://
|
247
|
-
source_code_uri: https://
|
248
|
-
changelog_uri: https://
|
251
|
+
homepage_uri: https://github.com/robcarruthers/rfbeam
|
252
|
+
source_code_uri: https://github.com/robcarruthers/rfbeam
|
253
|
+
changelog_uri: https://github.com/robcarruthers/rfbeam/CHANGELOG.md
|
249
254
|
rubygems_mfa_required: 'true'
|
250
|
-
post_install_message:
|
255
|
+
post_install_message:
|
251
256
|
rdoc_options: []
|
252
257
|
require_paths:
|
253
258
|
- lib
|
@@ -262,8 +267,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
262
267
|
- !ruby/object:Gem::Version
|
263
268
|
version: '0'
|
264
269
|
requirements: []
|
265
|
-
rubygems_version: 3.3.
|
266
|
-
signing_key:
|
270
|
+
rubygems_version: 3.3.26
|
271
|
+
signing_key:
|
267
272
|
specification_version: 4
|
268
273
|
summary: Ruby API and CLI for RFBeam doplar radar modules
|
269
274
|
test_files: []
|
data/.streerc
DELETED