Class: RTLSDR::Device
- Inherits:
-
Object
- Object
- RTLSDR::Device
- Includes:
- Enumerable
- Defined in:
- lib/rtlsdr/device.rb
Overview
High-level interface to RTL-SDR devices
The Device class provides a Ruby-idiomatic interface to RTL-SDR dongles, wrapping the low-level librtlsdr C API with convenient methods and automatic resource management. It supports both synchronous and asynchronous sample reading, comprehensive device configuration, and implements Enumerable for streaming operations.
Features:
- Automatic device lifecycle management (open/close)
- Frequency, gain, and sample rate control with validation
- Multiple gain modes (manual, automatic, AGC)
- Synchronous and asynchronous sample reading
- IQ sample conversion to Ruby Complex numbers
- EEPROM access and bias tee control
- Enumerable interface for continuous streaming
- Comprehensive error handling with custom exceptions
Instance Attribute Summary collapse
-
#handle ⇒ FFI::Pointer
readonly
Internal device handle pointer.
-
#index ⇒ Integer
readonly
Device index (0-based).
Instance Method Summary collapse
-
#agc_mode! ⇒ Boolean
Enable automatic gain control.
-
#agc_mode=(enabled) ⇒ Object
Set automatic gain control mode.
-
#auto_gain_mode! ⇒ Boolean
Enable automatic gain mode.
-
#bias_tee! ⇒ Boolean
Enable bias tee.
-
#bias_tee=(enabled) ⇒ Object
Bias tee control.
-
#cancel_async ⇒ void
Cancel asynchronous reading operation.
-
#center_freq ⇒ Integer
(also: #frequency)
Get the current center frequency.
-
#center_freq=(freq) ⇒ Object
(also: #frequency=)
Frequency control.
-
#close ⇒ void
Close the RTL-SDR device.
-
#closed? ⇒ Boolean
Check if the device is closed.
-
#configure(frequency: nil, sample_rate: nil, gain: nil, **options) ⇒ Object
Configuration shortcuts.
-
#direct_sampling ⇒ Integer?
Get current direct sampling mode.
-
#direct_sampling=(mode) ⇒ Object
Set direct sampling mode.
- #disable_bias_tee ⇒ Object
-
#dump_eeprom ⇒ String
Read the entire EEPROM contents.
-
#each(samples_per_read: 1024) ⇒ Object
Enumerable interface for reading samples.
- #enable_bias_tee ⇒ Object
-
#freq_correction ⇒ Integer
Get current frequency correction.
-
#freq_correction=(ppm) ⇒ Object
Set frequency correction in PPM.
-
#info ⇒ Object
Device info as hash.
-
#initialize(index = 0) ⇒ Device
constructor
Create a new RTL-SDR device instance.
-
#inspect ⇒ String
Return string representation of device.
-
#manual_gain_mode! ⇒ Boolean
Enable manual gain mode.
-
#name ⇒ Object
Device information.
-
#offset_tuning ⇒ Boolean?
Get current offset tuning mode.
-
#offset_tuning! ⇒ Boolean
Enable offset tuning.
-
#offset_tuning=(enabled) ⇒ Object
Set offset tuning mode.
-
#open? ⇒ Boolean
Device lifecycle.
-
#read_async(buffer_count: 15, buffer_length: 262_144) {|Array<Integer>| ... } ⇒ Thread
Read raw IQ data asynchronously.
-
#read_eeprom(offset, length) ⇒ Object
EEPROM access.
-
#read_samples(count = 1024) ⇒ Array<Complex>
Read complex samples synchronously.
-
#read_samples_async(buffer_count: 15, buffer_length: 262_144) {|Array<Complex>| ... } ⇒ Thread
Read complex samples asynchronously.
-
#read_sync(length) ⇒ Array<Integer>
Read raw IQ data synchronously.
-
#reset_buffer ⇒ Object
Streaming control.
-
#sample_rate ⇒ Integer
(also: #samp_rate)
Get current sample rate.
-
#sample_rate=(rate) ⇒ Object
(also: #samp_rate=)
Sample rate control.
-
#set_bias_tee_gpio(gpio, enabled) ⇒ Boolean
Set bias tee GPIO state.
-
#set_tuner_if_gain(stage, gain) ⇒ Integer
Set IF gain for specific stage.
-
#set_xtal_freq(rtl_freq, tuner_freq) ⇒ Object
Crystal oscillator frequencies.
-
#streaming? ⇒ Boolean
Check if asynchronous streaming is active.
-
#test_mode! ⇒ Boolean
Enable test mode.
-
#test_mode=(enabled) ⇒ Object
Mode control.
-
#tuner_bandwidth=(bw) ⇒ Object
Set tuner bandwidth.
-
#tuner_gain ⇒ Integer
(also: #gain)
Get current tuner gain.
-
#tuner_gain=(gain) ⇒ Object
(also: #gain=)
Set tuner gain in tenths of dB.
-
#tuner_gain_mode=(manual) ⇒ Object
Set gain mode (manual or automatic).
-
#tuner_gains ⇒ Object
Gain control.
-
#tuner_name ⇒ String
Get human-readable tuner name.
-
#tuner_type ⇒ Integer
Get the tuner type constant.
-
#usb_strings ⇒ Hash
Get USB device strings.
-
#write_eeprom(data, offset) ⇒ Integer
Write data to EEPROM.
-
#xtal_freq ⇒ Array<Integer>
Get crystal oscillator frequencies.
Constructor Details
#initialize(index = 0) ⇒ Device
Create a new RTL-SDR device instance
Opens the specified RTL-SDR device and prepares it for use. The device will be automatically opened during initialization.
62 63 64 65 66 67 68 69 |
# File 'lib/rtlsdr/device.rb', line 62 def initialize(index = 0) @index = index @handle = nil @streaming = false @async_thread = nil @buffer_reset_done = false open_device end |
Instance Attribute Details
#handle ⇒ FFI::Pointer (readonly)
Returns Internal device handle pointer.
49 50 51 |
# File 'lib/rtlsdr/device.rb', line 49 def handle @handle end |
#index ⇒ Integer (readonly)
Returns Device index (0-based).
47 48 49 |
# File 'lib/rtlsdr/device.rb', line 47 def index @index end |
Instance Method Details
#agc_mode! ⇒ Boolean
Enable automatic gain control
336 337 338 |
# File 'lib/rtlsdr/device.rb', line 336 def agc_mode! self.agc_mode = true end |
#agc_mode=(enabled) ⇒ Object
Set automatic gain control mode
327 328 329 330 331 |
# File 'lib/rtlsdr/device.rb', line 327 def agc_mode=(enabled) mode = enabled ? 1 : 0 result = FFI.rtlsdr_set_agc_mode(@handle, mode) check_result(result, "Failed to set AGC mode") end |
#auto_gain_mode! ⇒ Boolean
Enable automatic gain mode
267 268 269 |
# File 'lib/rtlsdr/device.rb', line 267 def auto_gain_mode! self.tuner_gain_mode = false end |
#bias_tee! ⇒ Boolean
Enable bias tee
402 403 404 |
# File 'lib/rtlsdr/device.rb', line 402 def bias_tee! enable_bias_tee end |
#bias_tee=(enabled) ⇒ Object
Bias tee control
385 386 387 388 389 |
# File 'lib/rtlsdr/device.rb', line 385 def bias_tee=(enabled) mode = enabled ? 1 : 0 result = FFI.rtlsdr_set_bias_tee(@handle, mode) check_result(result, "Failed to set bias tee") end |
#cancel_async ⇒ void
This method returns an undefined value.
Cancel asynchronous reading operation
Stops any active asynchronous reading and cleans up resources. This method is safe to call from within async callbacks.
578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 |
# File 'lib/rtlsdr/device.rb', line 578 def cancel_async return unless streaming? result = FFI.rtlsdr_cancel_async(@handle) @streaming = false # Only join if we're not calling from within the async thread itself if @async_thread && @async_thread != Thread.current @async_thread.join(1) # Wait up to 1 second for thread to finish end @async_thread = nil @async_callback = nil check_result(result, "Failed to cancel async operation") end |
#center_freq ⇒ Integer Also known as: frequency
Get the current center frequency
162 163 164 |
# File 'lib/rtlsdr/device.rb', line 162 def center_freq FFI.rtlsdr_get_center_freq(@handle) end |
#center_freq=(freq) ⇒ Object Also known as: frequency=
Frequency control
154 155 156 157 |
# File 'lib/rtlsdr/device.rb', line 154 def center_freq=(freq) result = FFI.rtlsdr_set_center_freq(@handle, freq) check_result(result, "Failed to set center frequency") end |
#close ⇒ void
This method returns an undefined value.
Close the RTL-SDR device
Closes the device handle and releases system resources. If async reading is active, it will be cancelled first. After closing, the device cannot be used until reopened.
86 87 88 89 90 91 92 93 |
# File 'lib/rtlsdr/device.rb', line 86 def close return unless open? cancel_async if streaming? result = FFI.rtlsdr_close(@handle) @handle = nil check_result(result, "Failed to close device") end |
#closed? ⇒ Boolean
Check if the device is closed
98 99 100 |
# File 'lib/rtlsdr/device.rb', line 98 def closed? !open? end |
#configure(frequency: nil, sample_rate: nil, gain: nil, **options) ⇒ Object
Configuration shortcuts
610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 |
# File 'lib/rtlsdr/device.rb', line 610 def configure(frequency: nil, sample_rate: nil, gain: nil, **) self.center_freq = frequency if frequency self.sample_rate = sample_rate if sample_rate if gain manual_gain_mode! self.tuner_gain = gain end .each do |key, value| case key when :freq_correction then self.freq_correction = value when :bandwidth then self.tuner_bandwidth = value when :agc_mode then self.agc_mode = value when :test_mode then self.test_mode = value when :bias_tee then self.bias_tee = value when :direct_sampling then self.direct_sampling = value when :offset_tuning then self.offset_tuning = value end end self end |
#direct_sampling ⇒ Integer?
Get current direct sampling mode
351 352 353 354 355 356 |
# File 'lib/rtlsdr/device.rb', line 351 def direct_sampling result = FFI.rtlsdr_get_direct_sampling(@handle) return nil if result.negative? result end |
#direct_sampling=(mode) ⇒ Object
Set direct sampling mode
343 344 345 346 |
# File 'lib/rtlsdr/device.rb', line 343 def direct_sampling=(mode) result = FFI.rtlsdr_set_direct_sampling(@handle, mode) check_result(result, "Failed to set direct sampling") end |
#disable_bias_tee ⇒ Object
395 396 397 |
# File 'lib/rtlsdr/device.rb', line 395 def disable_bias_tee self.bias_tee = false end |
#dump_eeprom ⇒ String
Read the entire EEPROM contents
Reads the complete 256-byte EEPROM data from the device and returns it as a binary string suitable for writing to a file.
447 448 449 450 |
# File 'lib/rtlsdr/device.rb', line 447 def dump_eeprom data = read_eeprom(0, 256) # RTL-SDR devices have a 256-byte EEPROM data.pack("C*") # Convert byte array to binary string end |
#each(samples_per_read: 1024) ⇒ Object
Enumerable interface for reading samples
596 597 598 599 600 601 602 603 604 605 606 607 |
# File 'lib/rtlsdr/device.rb', line 596 def each(samples_per_read: 1024) return enum_for(:each, samples_per_read: samples_per_read) unless block_given? loop do samples = read_samples(samples_per_read) yield samples rescue StandardError => e break if e.is_a?(Interrupt) raise end end |
#enable_bias_tee ⇒ Object
391 392 393 |
# File 'lib/rtlsdr/device.rb', line 391 def enable_bias_tee self.bias_tee = true end |
#freq_correction ⇒ Integer
Get current frequency correction
186 187 188 |
# File 'lib/rtlsdr/device.rb', line 186 def freq_correction FFI.rtlsdr_get_freq_correction(@handle) end |
#freq_correction=(ppm) ⇒ Object
Set frequency correction in PPM
178 179 180 181 |
# File 'lib/rtlsdr/device.rb', line 178 def freq_correction=(ppm) result = FFI.rtlsdr_set_freq_correction(@handle, ppm) check_result(result, "Failed to set frequency correction") end |
#info ⇒ Object
Device info as hash
635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 |
# File 'lib/rtlsdr/device.rb', line 635 def info { index: @index, name: name, usb_strings: usb_strings, tuner_type: tuner_type, tuner_name: tuner_name, center_freq: center_freq, sample_rate: sample_rate, tuner_gain: tuner_gain, tuner_gains: tuner_gains, freq_correction: freq_correction, direct_sampling: direct_sampling, offset_tuning: offset_tuning } end |
#inspect ⇒ String
Return string representation of device
655 656 657 658 659 660 661 |
# File 'lib/rtlsdr/device.rb', line 655 def inspect if open? "#<RTLSDR::Device:#{object_id.to_s(16)} index=#{@index} name=\"#{name}\" tuner=\"#{tuner_name}\" freq=#{center_freq}Hz rate=#{sample_rate}Hz>" # rubocop:disable Layout/LineLength else "#<RTLSDR::Device:#{object_id.to_s(16)} index=#{@index} closed>" end end |
#manual_gain_mode! ⇒ Boolean
Enable manual gain mode
260 261 262 |
# File 'lib/rtlsdr/device.rb', line 260 def manual_gain_mode! self.tuner_gain_mode = true end |
#name ⇒ Object
Device information
103 104 105 |
# File 'lib/rtlsdr/device.rb', line 103 def name RTLSDR.device_name(@index) end |
#offset_tuning ⇒ Boolean?
Get current offset tuning mode
370 371 372 373 374 375 |
# File 'lib/rtlsdr/device.rb', line 370 def offset_tuning result = FFI.rtlsdr_get_offset_tuning(@handle) return nil if result.negative? result == 1 end |
#offset_tuning! ⇒ Boolean
Enable offset tuning
380 381 382 |
# File 'lib/rtlsdr/device.rb', line 380 def offset_tuning! self.offset_tuning = true end |
#offset_tuning=(enabled) ⇒ Object
Set offset tuning mode
361 362 363 364 365 |
# File 'lib/rtlsdr/device.rb', line 361 def offset_tuning=(enabled) mode = enabled ? 1 : 0 result = FFI.rtlsdr_set_offset_tuning(@handle, mode) check_result(result, "Failed to set offset tuning") end |
#open? ⇒ Boolean
Device lifecycle
72 73 74 |
# File 'lib/rtlsdr/device.rb', line 72 def open? !@handle.nil? end |
#read_async(buffer_count: 15, buffer_length: 262_144) {|Array<Integer>| ... } ⇒ Thread
Read raw IQ data asynchronously
Starts asynchronous reading of raw 8-bit IQ data. The provided block will be called for each buffer of data received.
523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 |
# File 'lib/rtlsdr/device.rb', line 523 def read_async(buffer_count: 15, buffer_length: 262_144, &block) raise ArgumentError, "Block required for async reading" unless block_given? raise OperationFailedError, "Already streaming" if streaming? @streaming = true @async_callback = proc do |buf_ptr, len, _ctx| data = buf_ptr.read_array_of_uint8(len) block.call(data) rescue StandardError => e puts "Error in async callback: #{e.}" cancel_async end @async_thread = Thread.new do result = FFI.rtlsdr_read_async(@handle, @async_callback, nil, buffer_count, buffer_length) @streaming = false # Don't raise error for cancellation (-1) or timeout (-5) check_result(result, "Async read failed") unless [-1, -5].include?(result) end @async_thread end |
#read_eeprom(offset, length) ⇒ Object
EEPROM access
419 420 421 422 423 424 |
# File 'lib/rtlsdr/device.rb', line 419 def read_eeprom(offset, length) data_ptr = ::FFI::MemoryPointer.new(:uint8, length) result = FFI.rtlsdr_read_eeprom(@handle, data_ptr, offset, length) check_result(result, "Failed to read EEPROM") data_ptr.read_array_of_uint8(length) end |
#read_samples(count = 1024) ⇒ Array<Complex>
Read complex samples synchronously
Reads the specified number of complex samples from the device and converts them from raw 8-bit IQ data to Ruby Complex numbers.
490 491 492 493 494 495 496 497 498 499 500 501 502 503 |
# File 'lib/rtlsdr/device.rb', line 490 def read_samples(count = 1024) # RTL-SDR outputs 8-bit I/Q samples, so we need 2 bytes per complex sample data = read_sync(count * 2) # Convert to complex numbers (I + jQ) samples = [] (0...data.length).step(2) do |i| i_sample = (data[i] - 128) / 128.0 # Convert to -1.0 to 1.0 range q_sample = (data[i + 1] - 128) / 128.0 # Convert to -1.0 to 1.0 range samples << Complex(i_sample, q_sample) end samples end |
#read_samples_async(buffer_count: 15, buffer_length: 262_144) {|Array<Complex>| ... } ⇒ Thread
Read complex samples asynchronously
Starts asynchronous reading and converts raw IQ data to complex samples. The provided block will be called for each buffer of complex samples.
556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 |
# File 'lib/rtlsdr/device.rb', line 556 def read_samples_async(buffer_count: 15, buffer_length: 262_144, &block) raise ArgumentError, "Block required for async reading" unless block_given? read_async(buffer_count: buffer_count, buffer_length: buffer_length) do |data| # Convert to complex samples samples = [] (0...data.length).step(2) do |i| i_sample = (data[i] - 128) / 128.0 q_sample = (data[i + 1] - 128) / 128.0 samples << Complex(i_sample, q_sample) end block.call(samples) end end |
#read_sync(length) ⇒ Array<Integer>
Read raw IQ data synchronously
Reads raw 8-bit IQ data from the device. The buffer is automatically reset on the first read to avoid stale data.
465 466 467 468 469 470 471 472 473 474 475 476 477 478 |
# File 'lib/rtlsdr/device.rb', line 465 def read_sync(length) # Reset buffer before first read to avoid stale data reset_buffer unless @buffer_reset_done @buffer_reset_done = true buffer = ::FFI::MemoryPointer.new(:uint8, length) n_read_ptr = ::FFI::MemoryPointer.new(:int) result = FFI.rtlsdr_read_sync(@handle, buffer, length, n_read_ptr) check_result(result, "Failed to read synchronously") n_read = n_read_ptr.read_int buffer.read_array_of_uint8(n_read) end |
#reset_buffer ⇒ Object
Streaming control
453 454 455 456 |
# File 'lib/rtlsdr/device.rb', line 453 def reset_buffer result = FFI.rtlsdr_reset_buffer(@handle) check_result(result, "Failed to reset buffer") end |
#sample_rate ⇒ Integer Also known as: samp_rate
Get current sample rate
299 300 301 |
# File 'lib/rtlsdr/device.rb', line 299 def sample_rate FFI.rtlsdr_get_sample_rate(@handle) end |
#sample_rate=(rate) ⇒ Object Also known as: samp_rate=
Sample rate control
291 292 293 294 |
# File 'lib/rtlsdr/device.rb', line 291 def sample_rate=(rate) result = FFI.rtlsdr_set_sample_rate(@handle, rate) check_result(result, "Failed to set sample rate") end |
#set_bias_tee_gpio(gpio, enabled) ⇒ Boolean
Set bias tee GPIO state
411 412 413 414 415 416 |
# File 'lib/rtlsdr/device.rb', line 411 def set_bias_tee_gpio(gpio, enabled) mode = enabled ? 1 : 0 result = FFI.rtlsdr_set_bias_tee_gpio(@handle, gpio, mode) check_result(result, "Failed to set bias tee GPIO") enabled end |
#set_tuner_if_gain(stage, gain) ⇒ Integer
Set IF gain for specific stage
276 277 278 279 280 |
# File 'lib/rtlsdr/device.rb', line 276 def set_tuner_if_gain(stage, gain) result = FFI.rtlsdr_set_tuner_if_gain(@handle, stage, gain) check_result(result, "Failed to set IF gain") gain end |
#set_xtal_freq(rtl_freq, tuner_freq) ⇒ Object
Crystal oscillator frequencies
191 192 193 194 195 |
# File 'lib/rtlsdr/device.rb', line 191 def set_xtal_freq(rtl_freq, tuner_freq) result = FFI.rtlsdr_set_xtal_freq(@handle, rtl_freq, tuner_freq) check_result(result, "Failed to set crystal frequencies") [rtl_freq, tuner_freq] end |
#streaming? ⇒ Boolean
Check if asynchronous streaming is active
508 509 510 |
# File 'lib/rtlsdr/device.rb', line 508 def streaming? @streaming end |
#test_mode! ⇒ Boolean
Enable test mode
320 321 322 |
# File 'lib/rtlsdr/device.rb', line 320 def test_mode! self.test_mode = true end |
#test_mode=(enabled) ⇒ Object
Mode control
311 312 313 314 315 |
# File 'lib/rtlsdr/device.rb', line 311 def test_mode=(enabled) mode = enabled ? 1 : 0 result = FFI.rtlsdr_set_testmode(@handle, mode) check_result(result, "Failed to set test mode") end |
#tuner_bandwidth=(bw) ⇒ Object
Set tuner bandwidth
285 286 287 288 |
# File 'lib/rtlsdr/device.rb', line 285 def tuner_bandwidth=(bw) result = FFI.rtlsdr_set_tuner_bandwidth(@handle, bw) check_result(result, "Failed to set bandwidth") end |
#tuner_gain ⇒ Integer Also known as: gain
Get current tuner gain
237 238 239 |
# File 'lib/rtlsdr/device.rb', line 237 def tuner_gain FFI.rtlsdr_get_tuner_gain(@handle) end |
#tuner_gain=(gain) ⇒ Object Also known as: gain=
Set tuner gain in tenths of dB
229 230 231 232 |
# File 'lib/rtlsdr/device.rb', line 229 def tuner_gain=(gain) result = FFI.rtlsdr_set_tuner_gain(@handle, gain) check_result(result, "Failed to set tuner gain") end |
#tuner_gain_mode=(manual) ⇒ Object
Set gain mode (manual or automatic)
251 252 253 254 255 |
# File 'lib/rtlsdr/device.rb', line 251 def tuner_gain_mode=(manual) mode = manual ? 1 : 0 result = FFI.rtlsdr_set_tuner_gain_mode(@handle, mode) check_result(result, "Failed to set gain mode") end |
#tuner_gains ⇒ Object
Gain control
211 212 213 214 215 216 217 218 219 220 221 222 |
# File 'lib/rtlsdr/device.rb', line 211 def tuner_gains # First call to get count count = FFI.rtlsdr_get_tuner_gains(@handle, nil) return [] if count <= 0 # Second call to get actual gains gains_ptr = ::FFI::MemoryPointer.new(:int, count) result = FFI.rtlsdr_get_tuner_gains(@handle, gains_ptr) return [] if result <= 0 gains_ptr.read_array_of_int(result) end |
#tuner_name ⇒ String
Get human-readable tuner name
149 150 151 |
# File 'lib/rtlsdr/device.rb', line 149 def tuner_name FFI.tuner_type_name(tuner_type) end |
#tuner_type ⇒ Integer
Get the tuner type constant
Returns the tuner type as one of the RTLSDR_TUNER_* constants. The result is cached after the first call.
140 141 142 |
# File 'lib/rtlsdr/device.rb', line 140 def tuner_type @tuner_type ||= FFI.rtlsdr_get_tuner_type(@handle) end |
#usb_strings ⇒ Hash
Get USB device strings
Retrieves the USB manufacturer, product, and serial number strings for this device. Results are cached after the first call.
116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 |
# File 'lib/rtlsdr/device.rb', line 116 def usb_strings return @usb_strings if @usb_strings manufact = " " * 256 product = " " * 256 serial = " " * 256 result = FFI.rtlsdr_get_usb_strings(@handle, manufact, product, serial) check_result(result, "Failed to get USB strings") @usb_strings = { manufacturer: manufact.strip, product: product.strip, serial: serial.strip } end |
#write_eeprom(data, offset) ⇒ Integer
Write data to EEPROM
431 432 433 434 435 436 437 |
# File 'lib/rtlsdr/device.rb', line 431 def write_eeprom(data, offset) data_ptr = ::FFI::MemoryPointer.new(:uint8, data.length) data_ptr.write_array_of_uint8(data) result = FFI.rtlsdr_write_eeprom(@handle, data_ptr, offset, data.length) check_result(result, "Failed to write EEPROM") data.length end |
#xtal_freq ⇒ Array<Integer>
Get crystal oscillator frequencies
200 201 202 203 204 205 206 207 208 |
# File 'lib/rtlsdr/device.rb', line 200 def xtal_freq rtl_freq_ptr = ::FFI::MemoryPointer.new(:uint32) tuner_freq_ptr = ::FFI::MemoryPointer.new(:uint32) result = FFI.rtlsdr_get_xtal_freq(@handle, rtl_freq_ptr, tuner_freq_ptr) check_result(result, "Failed to get crystal frequencies") [rtl_freq_ptr.read_uint32, tuner_freq_ptr.read_uint32] end |