rfbeam 0.3.4 → 0.4.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 698385739f70574b698a117af8c749a21ebd75d9c3b0abaa39447ebd869324ef
4
- data.tar.gz: 11f47d264d76f5a5b968c8f7cb49152602359383e8a0cf20a16564a2b2e808f3
3
+ metadata.gz: 19f39170dee64099fe6806a345393beff434035df70fe525fa31b361468cac9e
4
+ data.tar.gz: 622aba1c5ab9f85fdb8cadf90f10339344306db39ab9299b2ef8b437d228d82d
5
5
  SHA512:
6
- metadata.gz: 58b01ae8497458e6e4f238afcc64a38cd925312e7893b4e65a854407f34694493b002e5721a9980129d586370cc51abfca5e5cd238a51cf33dfb890f40992479
7
- data.tar.gz: 48934f301cb4eb9ac2cdb695d08dfd544cc9e6ea16f130ab6b30b182c35ee1630d5ad2574c4bab081656f51ce4208857c92a2dfd6d2925639c303a3c66c0d1ae
6
+ metadata.gz: 57bd136ef560a32dab06e08c841b44e6e1b192525d9d3d44db1a88885c0b30b9b9b28ab28b1f408d628e191195373a012d31405ae24372fa4efd76ecbb3af46c
7
+ data.tar.gz: 5dc08c9c71c511e210a4c30599248bb5be53f1ccd7373af73edeb1ff35043dc76b90235bf46de93b9b755123af598225d6b96f06f6c0c5ab89bf4d1bc2e81d57
data/.rubocop.yml CHANGED
@@ -2,10 +2,16 @@ inherit_from:
2
2
  - node_modules/@prettier/plugin-ruby/rubocop.yml
3
3
 
4
4
  AllCops:
5
- TargetRubyVersion: 2.6
5
+ TargetRubyVersion: 3.2
6
6
 
7
7
  Layout/LineLength:
8
8
  Max: 120
9
9
 
10
+ Metrics/ModuleLength:
11
+ Enabled: false
12
+
13
+ Metrics/MethodLength:
14
+ Max: 20
15
+
10
16
  Documentation:
11
17
  Enabled: false
data/CHANGELOG.md CHANGED
@@ -1,6 +1,16 @@
1
+ ## [0.4.0] - 2023-4-4
2
+
3
+ - rough CLI implementation
4
+ - Streaming rfft data, with plot output
5
+
6
+ ## [0.3.5] - 2023-4-1
7
+
8
+ - Updated Radar parameter accessors
9
+ - Added parameter setter arg validation and errors
10
+
1
11
  ## [0.3.4] - 2023-3-28
2
12
 
3
- - Added a formatted option to pdat
13
+ - Added a formatted option to pdat
4
14
 
5
15
  ## [0.3.2] - 2023-3-28
6
16
 
data/Gemfile CHANGED
@@ -10,3 +10,13 @@ gem "rake", "~> 13.0"
10
10
  gem "minitest", "~> 5.0"
11
11
 
12
12
  gem "rubocop", "~> 1.21"
13
+
14
+ gem "tty-table", "~> 0.12.0"
15
+
16
+ gem "tty-spinner", "~> 0.9.3"
17
+
18
+ gem "unicode_plot", "~> 0.0.5"
19
+
20
+ gem "tty-logger", "~> 0.6.0"
21
+
22
+ gem "tty-screen", "~> 0.8.1"
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- rfbeam (0.3.4)
4
+ rfbeam (0.4.0)
5
5
  activesupport (~> 6.1.0)
6
6
  rubyserial (~> 0.6.0)
7
7
  thor (~> 1.2.1)
@@ -17,6 +17,7 @@ GEM
17
17
  zeitwerk (~> 2.3)
18
18
  ast (2.4.2)
19
19
  concurrent-ruby (1.1.10)
20
+ enumerable-statistics (2.0.7)
20
21
  ffi (1.15.5)
21
22
  i18n (1.12.0)
22
23
  concurrent-ruby (~> 1.0)
@@ -25,6 +26,8 @@ GEM
25
26
  parallel (1.22.1)
26
27
  parser (3.1.3.0)
27
28
  ast (~> 2.4.1)
29
+ pastel (0.8.0)
30
+ tty-color (~> 0.5)
28
31
  rainbow (3.1.1)
29
32
  rake (13.0.6)
30
33
  regexp_parser (2.6.1)
@@ -44,10 +47,29 @@ GEM
44
47
  ruby-progressbar (1.11.0)
45
48
  rubyserial (0.6.0)
46
49
  ffi (~> 1.9, >= 1.9.3)
50
+ strings (0.2.1)
51
+ strings-ansi (~> 0.2)
52
+ unicode-display_width (>= 1.5, < 3.0)
53
+ unicode_utils (~> 1.4)
54
+ strings-ansi (0.2.0)
47
55
  thor (1.2.1)
56
+ tty-color (0.6.0)
57
+ tty-cursor (0.7.1)
58
+ tty-logger (0.6.0)
59
+ pastel (~> 0.8)
60
+ tty-screen (0.8.1)
61
+ tty-spinner (0.9.3)
62
+ tty-cursor (~> 0.7)
63
+ tty-table (0.12.0)
64
+ pastel (~> 0.8)
65
+ strings (~> 0.2.0)
66
+ tty-screen (~> 0.8)
48
67
  tzinfo (2.0.5)
49
68
  concurrent-ruby (~> 1.0)
50
69
  unicode-display_width (2.3.0)
70
+ unicode_plot (0.0.5)
71
+ enumerable-statistics (>= 2.0.1)
72
+ unicode_utils (1.4.0)
51
73
  zeitwerk (2.6.6)
52
74
 
53
75
  PLATFORMS
@@ -59,6 +81,11 @@ DEPENDENCIES
59
81
  rake (~> 13.0)
60
82
  rfbeam!
61
83
  rubocop (~> 1.21)
84
+ tty-logger (~> 0.6.0)
85
+ tty-screen (~> 0.8.1)
86
+ tty-spinner (~> 0.9.3)
87
+ tty-table (~> 0.12.0)
88
+ unicode_plot (~> 0.0.5)
62
89
 
63
90
  BUNDLED WITH
64
91
  2.4.10
data/README.md CHANGED
@@ -1,7 +1,11 @@
1
1
  # Rfbeam
2
2
 
3
- RfBeam is a simple, high-level interface to the RFBeam radar modules.
4
- The user can read and set the radar parameters and fetch raw or processed data frames from the sensor.
3
+ ![Gem](https://img.shields.io/gem/v/rfbeam?color=green&label=version)
4
+ ![Ruby](https://img.shields.io/static/v1?message=Ruby&color=red&logo=Ruby&logoColor=FFFFFF&label=v3.2.1)
5
+ ![Ruby](https://img.shields.io/gitlab/license/robcarruthers/rfbeam?color=orange)
6
+
7
+ RfBeam is a simple, high-level interface for the RFBeam radar modules.
8
+ The user can query process and raw detection data and set the radar parameters for the sensor.
5
9
 
6
10
  At this stage it only works on Linux and Mac with the K-LD7 module.
7
11
 
@@ -63,28 +67,29 @@ Returns a formatted String of all parameter settings. The only way to read param
63
67
 
64
68
  radar.config
65
69
 
66
- Software Version: K-LD7_APP-RFB-0103
67
- Base Frequency: Middle
68
- Max Speed: 25km/h
69
- Max Range: 10m
70
- Threshold offset: 30db
71
- Tracking Filter Type: standard
72
- Vibration Suppression: 2 , (0-16, 0 = No Suppression, 16 = High Suppression)
73
- Minimum Detection Distance: 0 , (0 - 100% of range setting)
74
- Maximum Detection Distance: 50 , (0 - 100% of range setting)
75
- Minimum Detection Angle: -90° , (-90° - 90°)
76
- Maximum Detection Angle: 90° , (0 - 100% of range setting)
77
- Maximum Detection Speed: 0 , (0 - 100% of speed setting)
78
- Maximum Detection Speed: 100 , (0 - 100% of speed setting)
79
- Detection Direction: 2Range Threshold: 10%, (0 - 100% of range setting)
80
- Angle Threshold: 0°, (-90° - 90°)
81
- Speed Threshold: 50%, (0 - 100% of speed setting)
82
- Digital output 1: Direction
83
- Digital output 2: Angle
84
- Digital output 3: Range
85
- Hold time: 1sec
86
- Micro Detection Retrigger: Off
87
- Micro Detection Sensitivity: 4 (0 - 9, 0 = Min, 9 = Max)
70
+ Software Version: K-LD7_APP-RFB-0103
71
+ Base Frequency: Low
72
+ Maximum Speed: 100km/h
73
+ Maximum Range: 100m
74
+ Threshold Offset: 30db
75
+ Tracking Filter Type: Long Visibility
76
+ Vibration Suppression: 16
77
+ Minimum Detection Distance: 0%
78
+ Maximum Detection Distance: 100%
79
+ Minimum Detection Angle: -10°
80
+ Maximum Detection Angle: 90°
81
+ Minimum Detection Speed: 0%
82
+ Maximum Detection Speed: 100%
83
+ Detection Direction: Both
84
+ Range Threshold: 10%
85
+ Angle Threshold: 0°
86
+ Speed Threshold: 50%
87
+ Digital Output 1: Direction
88
+ Digital Output 2: Angle
89
+ Digital Output 3: Range
90
+ Hold Time: 1s
91
+ Micro Detection Trigger: Off
92
+ Micro Detection Sensativity: 4
88
93
 
89
94
  ## Parameter setters
90
95
 
data/exe/rfbeam ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rfbeam'
4
+
5
+ RfBeam::CLI.start(ARGV)
data/lib/rfbeam/cli.rb ADDED
@@ -0,0 +1,130 @@
1
+ # rubocop:disable all
2
+ require 'thor'
3
+ require 'rfbeam'
4
+ require 'tty-table'
5
+ require 'tty-logger'
6
+ require 'tty-spinner'
7
+ require 'io/console'
8
+ require 'unicode_plot'
9
+
10
+ module RfBeam
11
+ class CLI < Thor
12
+
13
+ attr_accessor :radar, :logger
14
+
15
+ desc 'list', 'List available radar modules'
16
+ def list
17
+ devices = RfBeam.connected
18
+ @logger.warning 'No Radar modules found.' unless devices.count.positive?
19
+
20
+ table = TTY::Table.new( header: ['id', 'Path', 'Version'])
21
+
22
+ devices.each.with_index do |path, index|
23
+ table << ["R#{index}", path, @radar.sw_version]
24
+ end
25
+ puts table.render(:ascii)
26
+ end
27
+
28
+ desc 'config <radar_id>', 'Shows the parameter setting for the Radar module'
29
+ def config(radar_id)
30
+ init_radar(radar_id)
31
+ puts @radar.config
32
+ end
33
+
34
+ desc 'set_param <radar_id> <key> <value>', 'Set radar parameters, see readme for keys'
35
+ def set_param(radar_id, param, value)
36
+ return logger.warning("Invalid param: '#{param}'") unless RfBeam::K_ld7::RADAR_PARAMETERS.include?(param.to_sym)
37
+
38
+ init_radar radar_id
39
+ @radar.send("#{param}=", value.to_i)
40
+ logger.success "Set #{@radar.formatted_parameter(param.to_sym)}"
41
+ end
42
+
43
+ desc 'ddat <radar_id>', 'stream any valid detections, stop stream with q and enter'
44
+ option :stream, type: :boolean, aliases: '-s', desc: "Stream the data from the device"
45
+ def ddat(radar_id)
46
+ init_radar radar_id
47
+
48
+ if options[:stream]
49
+ Thread.new { monitor_keypress }
50
+ spinner = TTY::Spinner.new("[:spinner] :title ", format: :bouncing_ball)
51
+ loop do
52
+ break if @stop_streaming
53
+ spinner.spin
54
+ data = @radar.ddat
55
+ spinner.update title: "Searching... #{data}"
56
+ spinner.success @radar.tdat if data[2] == 1
57
+ end
58
+ spinner.stop
59
+ puts "\nTask Quit."
60
+ else
61
+ puts "\n#{@radar.ddat}"
62
+ end
63
+
64
+ end
65
+
66
+ desc 'pdat <radar_id>', 'Display Tracked Targets'
67
+ def pdat(radar_id)
68
+ init_radar radar_id
69
+ puts @radar.pdat
70
+ end
71
+
72
+ desc "rfft <radar_id>", "Display the dopplar radar data as a plot"
73
+ option :stream, type: :boolean, aliases: '-s', desc: "Stream the data from the device"
74
+ option :period, type: :numeric, aliases: '-p', default: 0.5, desc: "Update period (in seconds) for the streaming data"
75
+ def rfft(radar_id)
76
+ init_radar(radar_id)
77
+
78
+ if options[:stream]
79
+ streamer = RfBeam::KLD7::Streamer.new(@radar)
80
+ streamer.rfft
81
+ else
82
+ plot = rfft_plot(@radar)
83
+ p plot.render
84
+ end
85
+ end
86
+
87
+ private
88
+
89
+ def init_radar(id)
90
+ devices = RfBeam.connected
91
+ @logger = TTY::Logger.new
92
+ return @logger.warning 'No Radar modules found.' unless devices.count.positive?
93
+
94
+ @radar = RfBeam::K_ld7.new(devices[id.to_i])
95
+ end
96
+
97
+ def plot_data(data)
98
+ { x: Array(-128...128), series1: data.shift(256).map { |value| value / 100 }, series2: data.shift(256).map { |value| value.to_i / 100 } }
99
+ end
100
+
101
+ def monitor_keypress
102
+ loop do
103
+ key = STDIN.getch
104
+ if key.downcase == 'q'
105
+ @stop_streaming = true
106
+ break
107
+ end
108
+ end
109
+ end
110
+
111
+ def rfft_plot(radar)
112
+ speed = radar.max_speed
113
+ speed_label = radar.formatted_parameter(:max_speed)
114
+ xlim = [speed - speed * 2, speed]
115
+ data = plot_data(radar.rfft)
116
+ plot = UnicodePlot.lineplot(
117
+ data[:x],
118
+ data[:series1],
119
+ name: 'IF1/2 Averaged',
120
+ title: 'Raw FFT',
121
+ height: 25,
122
+ width: 120,
123
+ xlabel: "Speed (km/h), #{speed_label}",
124
+ ylabel: 'Signal (db)', xlim: [-128, 128],
125
+ ylim: [0, 100])
126
+ UnicodePlot.lineplot!(plot, data[:x], data[:series2], name: "Threshold")
127
+ plot
128
+ end
129
+ end
130
+ end
@@ -11,7 +11,7 @@ module RfBeam
11
11
  3 => 'Invalid RPST version',
12
12
  4 => 'Uart error (parity, framing, noise)',
13
13
  5 => 'Sensor busy',
14
- 6 => 'Timeout error',
14
+ 6 => 'Timeout error'
15
15
  }.freeze
16
16
 
17
17
  # The response delay was determined empirically and may need adjusting with baude rate
@@ -27,59 +27,39 @@ module RfBeam
27
27
  angle: %w[Left Right],
28
28
  direction: %w[Receding Approaching],
29
29
  range: %w[Far Near],
30
- speed: %w[Low High],
31
- }.freeze
32
-
33
- # GRPS - Parameter structure, used to map return values to readable strings
34
- PARAMETER_STRUCTURE = {
35
- base_frequency: ['Low', 'Middle', 'High'],
36
- max_speed: ['12.5km/h', '25km/h', '50km/h', '100km/h'],
37
- max_range: %w[5m 10m 30m 100m],
38
- threshold_offset: '10db - 60db',
39
- tracking_filter_type: ['standard', 'Fast Detection', 'Long Visibility'],
40
- vibration_suppression: '0-16, 0 = No Suppression, 16 = High Suppression',
41
- min_detection_distance: '0 - 100% of range setting',
42
- max_detection_distance: '0 - 100% of range setting',
43
- min_detection_angle: '-90° - 90°',
44
- max_detection_angle: '-90° - 90°',
45
- min_detection_speed: '0 - 100% of speed setting',
46
- max_detection_speed: '0 - 100% of speed setting',
47
- detection_direction: %w[receding approaching both],
48
- range_threshold: '0 - 100% of range setting',
49
- angle_threshold: '-90° - 90°',
50
- speed_threshold: '0 - 100% of speed setting',
51
- digital_output_1: %w[Direction Angle Range Speed Micro],
52
- digital_output_2: %w[Direction Angle Range Speed Micro],
53
- digital_output_3: %w[Direction Angle Range Speed Micro],
54
- hold_time: '1 - 7200s',
55
- micro_detection_trigger: %w[Off Retrigger],
56
- micro_detection_sensitivity: '0 - 9, 0 = Min, 9 = Max'
30
+ speed: %w[Low High]
31
+ }.freeze
32
+
33
+ Param = Data.define(:name, :grps_index, :description, :default, :units, :values) do |_param|
34
+ def initialize(name:, grps_index:, description: nil, default: nil, units: nil, values: [])
35
+ super(name:, grps_index:, description:, default:, units:, values:)
36
+ end
37
+ end
38
+
39
+ RADAR_PARAMETERS = {
40
+ sw_version: Param.new(name: 'Software Version', grps_index: 2, default: 'K-LD7_APP-RFB-XXXX'),
41
+ base_frequency: Param.new( name: 'Base Frequency', grps_index: 3, description: '0 = Low, 1 = Middle, 2 = High', default: 1, values: ['Low', 'Middle', 'High'] ),
42
+ max_speed: Param.new( name: 'Maximum Speed', grps_index: 4, description: '0 = 12km/h, 1 = 25km/h, 2 = 50km/h, 3 = 100km/h', default: 1, units: 'km/h', values: ['12.5', '25', '50', '100'] ),
43
+ max_range: Param.new( name: 'Maximum Range', grps_index: 5, description: '0 = 5m, 1 = 10m, 2 = 30m, 3 = 100m', default: 1, values: %w[5m 10m 30m 100m] ),
44
+ threshold_offset: Param.new( name: 'Threshold Offset', grps_index: 6, description: '10db - 60db', default: 30, units: 'db' ),
45
+ tracking_filter: Param.new( name: 'Tracking Filter Type', grps_index: 7, description: '0 = Standard, 2 = Fast Detection, 3 = Long Visibility', default: 0, values: ['standard', 'Fast Detection', 'Long Visibility'] ),
46
+ vibration_suppression: Param.new( name: 'Vibration Suppression', grps_index: 8, description: '0-16, 0 = No Suppression, 16 = High Suppression', default: 2 ),
47
+ min_detection_distance: Param.new( name: 'Minimum Detection Distance', grps_index: 9, description: '0 - 100% of range setting', default: 0, units: '%' ),
48
+ max_detection_distance: Param.new( name: 'Maximum Detection Distance', grps_index: 10, description: '0 - 100% of range setting', default: 50, units: '%' ),
49
+ min_detection_angle: Param.new( name: 'Minimum Detection Angle', grps_index: 11, description: '-90° - 90°', default: -90, units: '°' ),
50
+ max_detection_angle: Param.new( name: 'Maximum Detection Angle', grps_index: 12, description: '-90° - 90°', default: 90, units: '°' ),
51
+ min_detection_speed: Param.new( name: 'Minimum Detection Speed', grps_index: 13, description: '0 - 100% of speed setting', default: 0, units: '%' ),
52
+ max_detection_speed: Param.new( name: 'Maximum Detection Speed', grps_index: 14, description: '0 - 100% of speed setting', default: 100, units: '%' ),
53
+ detection_direction: Param.new( name: 'Detection Direction', grps_index: 15, description: '0 = Receding, 1 = Approaching, 2 = Both', default: 2, values: %w[Receding Approaching Both] ),
54
+ range_threshold: Param.new( name: 'Range Threshold', grps_index: 16, description: '0 - 100% of range setting', default: 10, units: '%' ),
55
+ angle_threshold: Param.new( name: 'Angle Threshold', grps_index: 17, description: '-90° - 90°', default: 0, units: '°' ),
56
+ speed_threshold: Param.new( name: 'Speed Threshold', grps_index: 18, description: '0 - 100% of speed setting', default: 50, units: '%' ),
57
+ digital_output1: Param.new( name: 'Digital Output 1', grps_index: 19, description: '0 = Direction, 1 = Angle, 2 = Range, 3 = Speed, 4 = Micro Detection', default: 0, values: %w[Direction Angle Range Speed Micro] ),
58
+ digital_output2: Param.new( name: 'Digital Output 2', grps_index: 20, description: '0 = Direction, 1 = Angle, 2 = Range, 3 = Speed, 4 = Micro Detection', default: 1, values: %w[Direction Angle Range Speed Micro] ),
59
+ digital_output3: Param.new( name: 'Digital Output 3', grps_index: 21, description: '0 = Direction, 1 = Angle, 2 = Range, 3 = Speed, 4 = Micro Detection', default: 2, values: %w[Direction Angle Range Speed Micro] ),
60
+ hold_time: Param.new( name: 'Hold Time', grps_index: 22, description: '1 - 7200s', default: 1, units: 's' ),
61
+ micro_detection_retrigger: Param.new( name: 'Micro Detection Trigger', grps_index: 23, description: '0 = Off, 1 = Retrigger', default: 0, values: %w[Off Retrigger] ),
62
+ micro_detection_sensativity: Param.new( name: 'Micro Detection Sensativity', grps_index: 24, description: '0 - 9, 0 = Min, 9 = Max', default: 4 )
57
63
  }.freeze
58
-
59
- # PARAMETERS = {
60
- # sw_version: { grps_index: 2, default: 'K-LD7_APP-RFB-XXXX' },
61
- # base_frequency: { grps_index: 3, description: '0 = Low, 1 = Middle, 2 = High', default: '1 - Middle', values: ['Low', 'Middle', 'High'] },
62
- # max_speed: { grps_index: 4, description: '0 = 12km/h, 1 = 25km/h, 2 = 50km/h, 3 = 100km/h, default: 1', values: ['12.5km/h', '25km/h', '50km/h', '100km/h'] },
63
- # max_range: { grps_index: 5, description: '0 = 5m, 1 = 10m, 2 = 30m, 3 = 100m, default: 1', values: %w[5m 10m 30m 100m] },
64
- # threshold_offset: { grps_index: 6, description: '10db - 60db, default: 30', values: '10db - 60db' },
65
- # tracking_filter_type: { grps_index: 7, description: '0 = Standard, 2 = Fast Detection, 3 = Long Visibility, default: 0', values: ['standard', 'Fast Detection', 'Long Visibility'] },
66
- # vibration_suppression: { grps_index: 8, description: '0-16, 0 = No Suppression, 16 = High Suppression, default: 2' },
67
- # min_detection_distance: { grps_index: 3, description: '0 - 100% of range setting, default: 0' },
68
- # max_detection_distance: { grps_index: 10, description: '0 - 100% of range setting, default: 50' },
69
- # min_detection_angle: { grps_index: 11, description: '-90° - 90°, default: -90' },
70
- # max_detection_angle: { grps_index: 12, description: '-90° - 90°, default: 90' },
71
- # min_detection_speed: { grps_index: 13, description: '0 - 100% of speed setting, default: 0' },
72
- # max_detection_speed: { grps_index: 14, description: '0 - 100% of speed setting, default: 100' },
73
- # detection_direction: { grps_index: 15, description: '0 = Receding, 1 = Approaching, 2 = Both, default: 2', values: %w[receding approaching both] },
74
- # range_threshold: { grps_index: 16, description: '0 - 100% of range setting, default: 10', values: '0 - 100% of range setting' },
75
- # angle_threshold: { grps_index: 17, description: '-90° - 90°, default: 0' },
76
- # speed_threshold: { grps_index: 18, description: '0 - 100% of speed setting, default: 50' },
77
- # digital_output_1: { grps_index: 19, description: '0 = Direction, 1 = Angle, 2 = Range, 3 = Speed, 4 = Micro Detection, default: 0', values: %w[Direction Angle Range Speed Micro] },
78
- # digital_output_2: { grps_index: 20, description: '0 = Direction, 1 = Angle, 2 = Range, 3 = Speed, 4 = Micro Detection, default: 1', values: %w[Direction Angle Range Speed Micro] },
79
- # digital_output_3: { grps_index: 21, description: '0 = Direction, 1 = Angle, 2 = Range, 3 = Speed, 4 = Micro Detection, default: 2', values: %w[Direction Angle Range Speed Micro] },
80
- # hold_time: { grps_index: 22, description: '1 - 7200s, default: 1', values: '1 - 7200s' },
81
- # micro_detection_trigger: { grps_index: 23, description: '0 = Off, 1 = Retrigger, default: 0' },
82
- # micro_detection_sensitivity: { grps_index: 24, description: '0 - 9, 0 = Min, 9 = Max, default: 4' }'
83
- # }
84
64
  end
85
65
  end
@@ -0,0 +1,94 @@
1
+ require 'csv'
2
+
3
+ module RfBeam
4
+ module KLD7
5
+ def detection?
6
+ data = ddat
7
+ (data[2] == 1)
8
+ end
9
+
10
+ def rfft
11
+ request_frame_data(:rfft)
12
+
13
+ resp = read(1032).unpack('a4LS256S256')
14
+ resp.shift 2
15
+ resp
16
+ end
17
+
18
+ def pdat(formatted: false)
19
+ request_frame_data(:pdat)
20
+ resp = read(102).unpack('a4LSssSSssSSssSSssSSssSSssSSssSSssSSssSSssS')
21
+ return resp unless formatted
22
+
23
+ target_count = resp[1].to_i / 8
24
+ return [] unless target_count > 0
25
+
26
+ resp.shift 2
27
+ resp.compact
28
+ detected_raw_targets = []
29
+ target_count.times { detected_raw_targets << format_raw_target_data(resp.shift(4)) }
30
+ detected_raw_targets
31
+ end
32
+
33
+ def tdat
34
+ request_frame_data(:tdat)
35
+
36
+ sleep 0.1
37
+ resp = read(16).unpack('a4LSssS')
38
+ return { dist: resp[2], speed: resp[3], angle: resp[4], mag: resp[5] } unless resp[1].zero?
39
+ end
40
+
41
+ def ddat
42
+ request_frame_data(:ddat)
43
+ flags = %w[Low High]
44
+ array = read(14).unpack('a4LC6')
45
+ { label: array[0],
46
+ detection: DETECTION_FLAGS[:detection][array[2]],
47
+ micro_detection: DETECTION_FLAGS[:micro_detection][array[3]],
48
+ angle: DETECTION_FLAGS[:angle][array[4]],
49
+ direction: DETECTION_FLAGS[:direction][array[5]],
50
+ range: DETECTION_FLAGS[:range][array[6]],
51
+ speed: DETECTION_FLAGS[:speed][array[7]]
52
+ }
53
+ end
54
+
55
+ # Get the radar parameter structure
56
+ def grps
57
+ command = ['GRPS', 0]
58
+ write command.pack('a4L')
59
+ check_response
60
+ read(50).unpack('a4LA19C8c2C4cCCCCSCC')
61
+ end
62
+
63
+ def config
64
+ data = grps
65
+ output = "\n"
66
+ RADAR_PARAMETERS.keys.each do |key|
67
+ output << formatted_parameter(key, data[RADAR_PARAMETERS[key].grps_index])
68
+ end
69
+ output
70
+ end
71
+
72
+ def formatted_parameter(param, value = nil)
73
+ param = RADAR_PARAMETERS[param]
74
+ if value.nil?
75
+ data = grps
76
+ value = data[param.grps_index]
77
+ end
78
+ param_str_value = param.values.empty? ? value.to_s : param.values[value]
79
+ "#{param.name}: #{param_str_value}#{param.units}\n"
80
+ end
81
+
82
+ private
83
+
84
+ def format_raw_target_data(array)
85
+ { dist: array.shift, speed: array.shift, angle: array.shift, mag: array.shift }
86
+ end
87
+
88
+ def request_frame_data(type)
89
+ command = ['GNFD', 4, FRAME_DATA_TYPES[type]]
90
+ write command.pack('a4LL')
91
+ check_response
92
+ end
93
+ end
94
+ end