turtleshell 1.0.4
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 +7 -0
- data/.gitignore +6 -0
- data/CHANGELOG.md +5 -0
- data/Gemfile +10 -0
- data/LICENSE +20 -0
- data/README.md +46 -0
- data/Rakefile +25 -0
- data/examples/async_read_from_device.rb +29 -0
- data/examples/listing_devices.rb +11 -0
- data/examples/simple_read_from_device.rb +29 -0
- data/ext/librtlsdr/Makefile +217 -0
- data/ext/librtlsdr/extconf.rb +8 -0
- data/ext/librtlsdr/librtlsdr.c +233 -0
- data/lib/turtleshell.rb +22 -0
- data/lib/turtleshell/device.rb +104 -0
- data/spec/device_spec.rb +184 -0
- data/spec/turtleshell_spec.rb +22 -0
- data/turtleshell.gemspec +28 -0
- metadata +105 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 0020ab1903bd5ebd8bf3338fbf008ed6c8496411
|
4
|
+
data.tar.gz: 1243d95e4ae08009ff350e827fd03876d1f93a93
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 7ff72851c7c4aac05e27ae19a2ae84872d454e9342565a63c084449b87b2d0cf0f8f53ffe7e9ff5c380fd364616bf67f069ab9109e965f74b156723849f47df0
|
7
|
+
data.tar.gz: c2ebcfd7eb0001075f1645f87e2a16e5c0a2952a738c1dcd2b2cc175223ade07feefd047d8be95d7774fa420285c3f2bd89227a0ea08e7c7ed37a3b27f21b49e
|
data/.gitignore
ADDED
data/CHANGELOG.md
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2013 Tim Jarratt
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
6
|
+
this software and associated documentation files (the "Software"), to deal in
|
7
|
+
the Software without restriction, including without limitation the rights to
|
8
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
9
|
+
the Software, and to permit persons to whom the Software is furnished to do so,
|
10
|
+
subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
17
|
+
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
18
|
+
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
19
|
+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
20
|
+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
[](https://travis-ci.org/tjarratt/turtleshell) turRTLshell
|
2
|
+
============
|
3
|
+
|
4
|
+
Overview
|
5
|
+
--------
|
6
|
+
Turtleshell is a ruby wrapper around librtlsdr, a C library for interfacing with Realtek RTL2832 DVB USB devices. More information about librtlsdr can be found [on their website](http://sdr.osmocom.org/trac/wiki/rtl-sdr).
|
7
|
+
|
8
|
+
Usage
|
9
|
+
-----
|
10
|
+
Turtleshell is available on rubygems. You can install it with `gem install turtleshell` or by adding it to your `Gemfile`.
|
11
|
+
|
12
|
+
Most of the key functions in librtlsdr are available, more will be added as development continues.
|
13
|
+
|
14
|
+
Examples
|
15
|
+
--------
|
16
|
+
Getting a reference to a device and reading from it could not be easier
|
17
|
+
```ruby
|
18
|
+
require 'turtleshell'
|
19
|
+
sdr = TurtleShell::Device.new
|
20
|
+
|
21
|
+
# configure device properties
|
22
|
+
sdr.sample_rate = 2.4e6
|
23
|
+
sdr.center_frequency = 100e6
|
24
|
+
sdr.gain = 10
|
25
|
+
|
26
|
+
# read samples from the device
|
27
|
+
samples = sdr.read_samples
|
28
|
+
puts "signal mean: #{samples.inject(:+)/samples.length}"
|
29
|
+
```
|
30
|
+
|
31
|
+
More examples are available in the [examples directory](https://github.com/tjarratt/turtleshell/tree/master/examples).
|
32
|
+
|
33
|
+
Dependencies
|
34
|
+
------------
|
35
|
+
* ruby (version 1.9.2 or later)
|
36
|
+
* librtlsdr
|
37
|
+
|
38
|
+
License
|
39
|
+
-------
|
40
|
+
Turtleshell is released under the permissive MIT license.
|
41
|
+
|
42
|
+
Credit
|
43
|
+
------
|
44
|
+
The idea for this project came to me when I was watching [@0xabad1dea's](https://github.com/0xabad1dea) talk at Defcon 21. Without that initial idea and inspiration, this wouldn't exist!
|
45
|
+
|
46
|
+
Credit is due to [@roger-](https://github.com/roger-) for writing pyrtlsdr, which provided a great reference when working on Turtleshell.
|
data/Rakefile
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'bundler/setup'
|
2
|
+
require 'rspec/core/rake_task'
|
3
|
+
require 'rake/extensiontask'
|
4
|
+
|
5
|
+
task :default => 'compile:librtlsdr'
|
6
|
+
task :default => :spec
|
7
|
+
task :spec => 'spec:progress'
|
8
|
+
|
9
|
+
Rake::ExtensionTask.new(:librtlsdr) do |ext|
|
10
|
+
ext.lib_dir = "lib/librtlsdr"
|
11
|
+
end
|
12
|
+
|
13
|
+
namespace :spec do
|
14
|
+
desc 'Run all specs in spec directory (format=progress)'
|
15
|
+
RSpec::Core::RakeTask.new(:progress) do |t|
|
16
|
+
t.pattern = 'spec/**/*_spec.rb'
|
17
|
+
t.rspec_opts = %w{ --color --format=progress }
|
18
|
+
end
|
19
|
+
|
20
|
+
desc 'Run all specs in spec directory (format=documentation)'
|
21
|
+
RSpec::Core::RakeTask.new(:documentation) do |t|
|
22
|
+
t.pattern = 'spec/**/*_spec.rb'
|
23
|
+
t.rspec_opts = %w{ --color --format=documentation }
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
lib = File.expand_path('../../lib', __FILE__)
|
3
|
+
$:.unshift lib unless $:.include? lib
|
4
|
+
|
5
|
+
require 'turtleshell'
|
6
|
+
|
7
|
+
begin
|
8
|
+
sdr = TurtleShell::Device.new
|
9
|
+
rescue TurtleShell::DeviceNotFoundError
|
10
|
+
puts 'No compatible devices found. bailing!'
|
11
|
+
exit 1
|
12
|
+
end
|
13
|
+
|
14
|
+
|
15
|
+
sdr.sample_rate = 2.4e6
|
16
|
+
sdr.center_frequency = 100e6
|
17
|
+
sdr.gain = 8
|
18
|
+
|
19
|
+
count = 0
|
20
|
+
puts "\n\nTesting async callbacks..."
|
21
|
+
sdr.read_samples_async(512) do |buffer|
|
22
|
+
count += 1
|
23
|
+
puts "\t in async callback with buffer of length #{buffer.length}"
|
24
|
+
puts "\t signal mean: #{buffer.inject(:+)/buffer.length}"
|
25
|
+
|
26
|
+
count == 3 # exit when this has been called three times
|
27
|
+
end
|
28
|
+
|
29
|
+
sdr.close_device
|
@@ -0,0 +1,11 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
lib = File.expand_path('../../lib', __FILE__)
|
3
|
+
$:.unshift lib unless $:.include? lib
|
4
|
+
|
5
|
+
require 'turtleshell'
|
6
|
+
|
7
|
+
puts "Found #{TurtleShell.count_of_devices} devices connected"
|
8
|
+
|
9
|
+
TurtleShell.all_devices.each_with_index do |device_name, index|
|
10
|
+
puts "#{index} : #{device_name}"
|
11
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
lib = File.expand_path('../../lib', __FILE__)
|
3
|
+
$:.unshift lib unless $:.include? lib
|
4
|
+
|
5
|
+
require 'turtleshell'
|
6
|
+
|
7
|
+
begin
|
8
|
+
sdr = TurtleShell::Device.new
|
9
|
+
rescue TurtleShell::DeviceNotFoundError
|
10
|
+
puts 'No compatible devices found. bailing!'
|
11
|
+
exit 1
|
12
|
+
end
|
13
|
+
|
14
|
+
puts "\n\nConfiguring SDR device\n"
|
15
|
+
|
16
|
+
sdr.sample_rate = 2.4e6
|
17
|
+
sdr.center_frequency = 100e6
|
18
|
+
sdr.gain = 10
|
19
|
+
|
20
|
+
puts "\t sample rate: #{sdr.sample_rate / 1e6} MHz"
|
21
|
+
puts "\t center frequency: #{sdr.center_frequency / 1e6} MHz"
|
22
|
+
puts "\t gain: #{sdr.gain} dB"
|
23
|
+
|
24
|
+
puts "\n\n"
|
25
|
+
puts "Reading Samples..."
|
26
|
+
samples = sdr.read_samples(1024)
|
27
|
+
print "\t signal mean: #{samples.inject(:+)/samples.length}"
|
28
|
+
|
29
|
+
sdr.close_device
|
@@ -0,0 +1,217 @@
|
|
1
|
+
|
2
|
+
SHELL = /bin/sh
|
3
|
+
|
4
|
+
# V=0 quiet, V=1 verbose. other values don't work.
|
5
|
+
V = 0
|
6
|
+
Q1 = $(V:1=)
|
7
|
+
Q = $(Q1:0=@)
|
8
|
+
n=$(NULLCMD)
|
9
|
+
ECHO1 = $(V:1=@$n)
|
10
|
+
ECHO = $(ECHO1:0=@echo)
|
11
|
+
|
12
|
+
#### Start of system configuration section. ####
|
13
|
+
|
14
|
+
srcdir = .
|
15
|
+
topdir = /Users/tjarratt/.rvm/rubies/ruby-1.9.3-p327/include/ruby-1.9.1
|
16
|
+
hdrdir = /Users/tjarratt/.rvm/rubies/ruby-1.9.3-p327/include/ruby-1.9.1
|
17
|
+
arch_hdrdir = /Users/tjarratt/.rvm/rubies/ruby-1.9.3-p327/include/ruby-1.9.1/$(arch)
|
18
|
+
VPATH = $(srcdir):$(arch_hdrdir)/ruby:$(hdrdir)/ruby
|
19
|
+
prefix = $(DESTDIR)/Users/tjarratt/.rvm/rubies/ruby-1.9.3-p327
|
20
|
+
rubylibprefix = $(libdir)/$(RUBY_BASE_NAME)
|
21
|
+
exec_prefix = $(prefix)
|
22
|
+
vendorhdrdir = $(rubyhdrdir)/vendor_ruby
|
23
|
+
sitehdrdir = $(rubyhdrdir)/site_ruby
|
24
|
+
rubyhdrdir = $(includedir)/$(RUBY_BASE_NAME)-$(ruby_version)
|
25
|
+
vendordir = $(rubylibprefix)/vendor_ruby
|
26
|
+
sitedir = $(rubylibprefix)/site_ruby
|
27
|
+
ridir = $(datarootdir)/$(RI_BASE_NAME)
|
28
|
+
mandir = $(datarootdir)/man
|
29
|
+
localedir = $(datarootdir)/locale
|
30
|
+
libdir = $(exec_prefix)/lib
|
31
|
+
psdir = $(docdir)
|
32
|
+
pdfdir = $(docdir)
|
33
|
+
dvidir = $(docdir)
|
34
|
+
htmldir = $(docdir)
|
35
|
+
infodir = $(datarootdir)/info
|
36
|
+
docdir = $(datarootdir)/doc/$(PACKAGE)
|
37
|
+
oldincludedir = $(DESTDIR)/usr/include
|
38
|
+
includedir = $(prefix)/include
|
39
|
+
localstatedir = $(prefix)/var
|
40
|
+
sharedstatedir = $(prefix)/com
|
41
|
+
sysconfdir = $(DESTDIR)/etc
|
42
|
+
datadir = $(datarootdir)
|
43
|
+
datarootdir = $(prefix)/share
|
44
|
+
libexecdir = $(exec_prefix)/libexec
|
45
|
+
sbindir = $(exec_prefix)/sbin
|
46
|
+
bindir = $(exec_prefix)/bin
|
47
|
+
rubylibdir = $(rubylibprefix)/$(ruby_version)
|
48
|
+
archdir = $(rubylibdir)/$(arch)
|
49
|
+
sitelibdir = $(sitedir)/$(ruby_version)
|
50
|
+
sitearchdir = $(sitelibdir)/$(sitearch)
|
51
|
+
vendorlibdir = $(vendordir)/$(ruby_version)
|
52
|
+
vendorarchdir = $(vendorlibdir)/$(sitearch)
|
53
|
+
|
54
|
+
NULLCMD = :
|
55
|
+
|
56
|
+
CC = /usr/bin/gcc-4.2
|
57
|
+
CXX = g++
|
58
|
+
LIBRUBY = $(LIBRUBY_A)
|
59
|
+
LIBRUBY_A = lib$(RUBY_SO_NAME)-static.a
|
60
|
+
LIBRUBYARG_SHARED =
|
61
|
+
LIBRUBYARG_STATIC = -l$(RUBY_SO_NAME)-static
|
62
|
+
empty =
|
63
|
+
OUTFLAG = -o $(empty)
|
64
|
+
COUTFLAG = -o $(empty)
|
65
|
+
|
66
|
+
RUBY_EXTCONF_H =
|
67
|
+
cflags = $(optflags) $(debugflags) $(warnflags)
|
68
|
+
optflags = -O3
|
69
|
+
debugflags = -ggdb
|
70
|
+
warnflags = -Wall -Wextra -Wno-unused-parameter -Wno-parentheses -Wno-long-long -Wno-missing-field-initializers -Wpointer-arith -Wwrite-strings -Wdeclaration-after-statement -Wshorten-64-to-32 -Wimplicit-function-declaration
|
71
|
+
CFLAGS = -fno-common -I/Users/mpapis/.sm/pkg/active/include -pipe $(ARCH_FLAG)
|
72
|
+
INCFLAGS = -I. -I$(arch_hdrdir) -I$(hdrdir)/ruby/backward -I$(hdrdir) -I$(srcdir)
|
73
|
+
DEFS =
|
74
|
+
CPPFLAGS = -D_XOPEN_SOURCE -D_DARWIN_C_SOURCE $(DEFS) $(cppflags)
|
75
|
+
CXXFLAGS = $(CFLAGS) $(cxxflags)
|
76
|
+
ldflags = -L. -Bstatic -L/Users/mpapis/.sm/pkg/active/lib
|
77
|
+
dldflags = -Wl,-undefined,dynamic_lookup -Wl,-multiply_defined,suppress -Wl,-flat_namespace
|
78
|
+
ARCH_FLAG = -arch x86_64
|
79
|
+
DLDFLAGS = $(ldflags) $(dldflags) $(ARCH_FLAG)
|
80
|
+
LDSHARED = $(CC) -dynamic -bundle
|
81
|
+
LDSHAREDXX = $(CXX) -dynamic -bundle
|
82
|
+
AR = ar
|
83
|
+
EXEEXT =
|
84
|
+
|
85
|
+
RUBY_BASE_NAME = ruby
|
86
|
+
RUBY_INSTALL_NAME = ruby
|
87
|
+
RUBY_SO_NAME = ruby
|
88
|
+
arch = x86_64-darwin12.2.0
|
89
|
+
sitearch = $(arch)
|
90
|
+
ruby_version = 1.9.1
|
91
|
+
ruby = /Users/tjarratt/.rvm/rubies/ruby-1.9.3-p327/bin/ruby
|
92
|
+
RUBY = $(ruby)
|
93
|
+
RM = rm -f
|
94
|
+
RM_RF = $(RUBY) -run -e rm -- -rf
|
95
|
+
RMDIRS = rmdir -p
|
96
|
+
MAKEDIRS = mkdir -p
|
97
|
+
INSTALL = /usr/bin/install -c
|
98
|
+
INSTALL_PROG = $(INSTALL) -m 0755
|
99
|
+
INSTALL_DATA = $(INSTALL) -m 644
|
100
|
+
COPY = cp
|
101
|
+
TOUCH = exit >
|
102
|
+
|
103
|
+
#### End of system configuration section. ####
|
104
|
+
|
105
|
+
preload =
|
106
|
+
|
107
|
+
libpath = . $(libdir)
|
108
|
+
LIBPATH = -L. -L$(libdir)
|
109
|
+
DEFFILE =
|
110
|
+
|
111
|
+
CLEANFILES = mkmf.log
|
112
|
+
DISTCLEANFILES =
|
113
|
+
DISTCLEANDIRS =
|
114
|
+
|
115
|
+
extout =
|
116
|
+
extout_prefix =
|
117
|
+
target_prefix =
|
118
|
+
LOCAL_LIBS =
|
119
|
+
LIBS = -lpthread -ldl -lobjc
|
120
|
+
SRCS = librtlsdr.c
|
121
|
+
OBJS = librtlsdr.o
|
122
|
+
TARGET = librtlsdr
|
123
|
+
DLLIB = $(TARGET).bundle
|
124
|
+
EXTSTATIC =
|
125
|
+
STATIC_LIB =
|
126
|
+
|
127
|
+
BINDIR = $(bindir)
|
128
|
+
RUBYCOMMONDIR = $(sitedir)$(target_prefix)
|
129
|
+
RUBYLIBDIR = $(sitelibdir)$(target_prefix)
|
130
|
+
RUBYARCHDIR = $(sitearchdir)$(target_prefix)
|
131
|
+
HDRDIR = $(rubyhdrdir)/ruby$(target_prefix)
|
132
|
+
ARCHHDRDIR = $(rubyhdrdir)/$(arch)/ruby$(target_prefix)
|
133
|
+
|
134
|
+
TARGET_SO = $(DLLIB)
|
135
|
+
CLEANLIBS = $(TARGET).bundle
|
136
|
+
CLEANOBJS = *.o *.bak
|
137
|
+
|
138
|
+
all: $(DLLIB)
|
139
|
+
static: $(STATIC_LIB)
|
140
|
+
.PHONY: all install static install-so install-rb
|
141
|
+
.PHONY: clean clean-so clean-rb
|
142
|
+
|
143
|
+
clean-rb-default::
|
144
|
+
clean-rb::
|
145
|
+
clean-so::
|
146
|
+
clean: clean-so clean-rb-default clean-rb
|
147
|
+
@-$(RM) $(CLEANLIBS) $(CLEANOBJS) $(CLEANFILES)
|
148
|
+
|
149
|
+
distclean-rb-default::
|
150
|
+
distclean-rb::
|
151
|
+
distclean-so::
|
152
|
+
distclean: clean distclean-so distclean-rb-default distclean-rb
|
153
|
+
@-$(RM) Makefile $(RUBY_EXTCONF_H) conftest.* mkmf.log
|
154
|
+
@-$(RM) core ruby$(EXEEXT) *~ $(DISTCLEANFILES)
|
155
|
+
@-$(RMDIRS) $(DISTCLEANDIRS) 2> /dev/null || true
|
156
|
+
|
157
|
+
realclean: distclean
|
158
|
+
install: install-so install-rb
|
159
|
+
|
160
|
+
install-so: $(RUBYARCHDIR)/$(DLLIB)
|
161
|
+
$(RUBYARCHDIR)/$(DLLIB): $(DLLIB)
|
162
|
+
-$(Q)$(MAKEDIRS) $(@D)
|
163
|
+
$(INSTALL_PROG) $(DLLIB) $(@D)
|
164
|
+
clean-static::
|
165
|
+
-$(Q)$(RM) $(STATIC_LIB)
|
166
|
+
install-rb: pre-install-rb install-rb-default
|
167
|
+
install-rb-default: pre-install-rb-default
|
168
|
+
pre-install-rb: Makefile
|
169
|
+
pre-install-rb-default: Makefile
|
170
|
+
pre-install-rb-default:
|
171
|
+
$(ECHO) installing default librtlsdr libraries
|
172
|
+
./.RUBYARCHDIR.time:
|
173
|
+
$(Q) $(MAKEDIRS) $(RUBYARCHDIR)
|
174
|
+
$(Q) $(TOUCH) $@
|
175
|
+
|
176
|
+
site-install: site-install-so site-install-rb
|
177
|
+
site-install-so: install-so
|
178
|
+
site-install-rb: install-rb
|
179
|
+
|
180
|
+
.SUFFIXES: .c .m .cc .mm .cxx .cpp .C .o
|
181
|
+
|
182
|
+
.cc.o:
|
183
|
+
$(ECHO) compiling $(<)
|
184
|
+
$(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $<
|
185
|
+
|
186
|
+
.mm.o:
|
187
|
+
$(ECHO) compiling $(<)
|
188
|
+
$(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $<
|
189
|
+
|
190
|
+
.cxx.o:
|
191
|
+
$(ECHO) compiling $(<)
|
192
|
+
$(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $<
|
193
|
+
|
194
|
+
.cpp.o:
|
195
|
+
$(ECHO) compiling $(<)
|
196
|
+
$(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $<
|
197
|
+
|
198
|
+
.C.o:
|
199
|
+
$(ECHO) compiling $(<)
|
200
|
+
$(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $<
|
201
|
+
|
202
|
+
.c.o:
|
203
|
+
$(ECHO) compiling $(<)
|
204
|
+
$(Q) $(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) $(COUTFLAG)$@ -c $<
|
205
|
+
|
206
|
+
.m.o:
|
207
|
+
$(ECHO) compiling $(<)
|
208
|
+
$(Q) $(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) $(COUTFLAG)$@ -c $<
|
209
|
+
|
210
|
+
$(DLLIB): $(OBJS) Makefile
|
211
|
+
$(ECHO) linking shared-object $(DLLIB)
|
212
|
+
-$(Q)$(RM) $(@)
|
213
|
+
$(Q) $(LDSHARED) -o $@ $(OBJS) $(LIBPATH) $(DLDFLAGS) $(LOCAL_LIBS) $(LIBS)
|
214
|
+
|
215
|
+
|
216
|
+
|
217
|
+
$(OBJS): $(hdrdir)/ruby.h $(hdrdir)/ruby/defines.h $(arch_hdrdir)/ruby/config.h
|
@@ -0,0 +1,233 @@
|
|
1
|
+
#include "ruby.h"
|
2
|
+
#include "rtl-sdr.h"
|
3
|
+
|
4
|
+
VALUE m_turtleshell = Qnil;
|
5
|
+
VALUE c_device;
|
6
|
+
static VALUE m_rtlsdr;
|
7
|
+
|
8
|
+
static VALUE turtleshell_count() {
|
9
|
+
return INT2NUM(rtlsdr_get_device_count());
|
10
|
+
}
|
11
|
+
|
12
|
+
static VALUE turtleshell_first_device() {
|
13
|
+
rtlsdr_dev_t *device = NULL;
|
14
|
+
VALUE wrapped_device;
|
15
|
+
VALUE hash;
|
16
|
+
int count = rtlsdr_get_device_count();
|
17
|
+
|
18
|
+
// ensure we have at least one device
|
19
|
+
if (!count) { return Qnil; }
|
20
|
+
|
21
|
+
rtlsdr_open(&device, 0);
|
22
|
+
wrapped_device = Data_Wrap_Struct(c_device, NULL, NULL, device);
|
23
|
+
|
24
|
+
hash = rb_hash_new();
|
25
|
+
rb_hash_aset(hash, rb_str_new2("name"), rb_str_new2(rtlsdr_get_device_name(0)));
|
26
|
+
rb_hash_aset(hash, rb_str_new2("device_handle"), wrapped_device);
|
27
|
+
|
28
|
+
return hash;
|
29
|
+
}
|
30
|
+
|
31
|
+
static VALUE turtleshell_all_devices() {
|
32
|
+
int i, count;
|
33
|
+
VALUE devices_array = rb_ary_new();
|
34
|
+
count = rtlsdr_get_device_count();
|
35
|
+
|
36
|
+
for (i = 0; i < count; ++i) {
|
37
|
+
rb_ary_push(devices_array, rb_str_new2(rtlsdr_get_device_name(i)));
|
38
|
+
}
|
39
|
+
|
40
|
+
return devices_array;
|
41
|
+
}
|
42
|
+
|
43
|
+
static VALUE turtleshell_nth_device(VALUE self, VALUE n) {
|
44
|
+
int open_success;
|
45
|
+
uint32_t int_n = NUM2UINT(n);
|
46
|
+
rtlsdr_dev_t *device = NULL;
|
47
|
+
VALUE wrapped_device, hash = rb_hash_new();
|
48
|
+
uint32_t device_count = (uint32_t)rtlsdr_get_device_count();
|
49
|
+
|
50
|
+
if (int_n >= device_count) { return Qnil; }
|
51
|
+
|
52
|
+
open_success = rtlsdr_open(&device, int_n);
|
53
|
+
if (open_success != 0) {
|
54
|
+
return Qnil;
|
55
|
+
}
|
56
|
+
|
57
|
+
wrapped_device = Data_Wrap_Struct(c_device, NULL, NULL, device);
|
58
|
+
|
59
|
+
rb_hash_aset(hash, ID2SYM(rb_intern("name")), rb_str_new2(rtlsdr_get_device_name(0)));
|
60
|
+
rb_hash_aset(hash, ID2SYM(rb_intern("device")), wrapped_device);
|
61
|
+
|
62
|
+
return hash;
|
63
|
+
}
|
64
|
+
|
65
|
+
static VALUE turtleshell_close(VALUE self, VALUE device) {
|
66
|
+
rtlsdr_dev_t *dev = NULL;
|
67
|
+
Data_Get_Struct(device, rtlsdr_dev_t, dev);
|
68
|
+
rtlsdr_close(dev);
|
69
|
+
return Qnil;
|
70
|
+
}
|
71
|
+
|
72
|
+
static VALUE turtleshell_read_synchronous(VALUE self,
|
73
|
+
VALUE device,
|
74
|
+
VALUE bytes_to_read) {
|
75
|
+
int success, i;
|
76
|
+
int bytes_read;
|
77
|
+
VALUE buffer = rb_ary_new();
|
78
|
+
int length = NUM2INT(bytes_to_read);
|
79
|
+
uint8_t *p_buffer = malloc(sizeof(uint8_t) * bytes_to_read);
|
80
|
+
rtlsdr_dev_t *p_device;
|
81
|
+
|
82
|
+
Data_Get_Struct(device, rtlsdr_dev_t, p_device);
|
83
|
+
|
84
|
+
rtlsdr_reset_buffer(p_device);
|
85
|
+
success = rtlsdr_read_sync(p_device, p_buffer, length, &bytes_read);
|
86
|
+
if (success != 0) {
|
87
|
+
printf("error reading bytes. read_sync returned %d\n", success);
|
88
|
+
free(p_buffer);
|
89
|
+
return buffer;
|
90
|
+
}
|
91
|
+
|
92
|
+
for (i = 0; i < bytes_read; ++i) {
|
93
|
+
rb_ary_push(buffer, UINT2NUM((uint8_t)p_buffer[i]));
|
94
|
+
}
|
95
|
+
|
96
|
+
free(p_buffer);
|
97
|
+
return buffer;
|
98
|
+
}
|
99
|
+
|
100
|
+
struct turtleshell_context {
|
101
|
+
VALUE callback;
|
102
|
+
rtlsdr_dev_t *device;
|
103
|
+
};
|
104
|
+
|
105
|
+
typedef struct turtleshell_context turtleshell_context;
|
106
|
+
|
107
|
+
static void turtleshell_callback(unsigned char *buffer, uint32_t length, void *context) {
|
108
|
+
uint32_t i;
|
109
|
+
rtlsdr_dev_t *device;
|
110
|
+
VALUE buffer_array, callback, bool_value;
|
111
|
+
struct turtleshell_context unwrapped_context;
|
112
|
+
|
113
|
+
unwrapped_context = *(struct turtleshell_context *)context;
|
114
|
+
|
115
|
+
if (!unwrapped_context.callback || !unwrapped_context.device) {
|
116
|
+
printf("unexpected error: could not read callback / device from unwrapped context\n");
|
117
|
+
exit(1);
|
118
|
+
}
|
119
|
+
|
120
|
+
device = unwrapped_context.device;
|
121
|
+
callback = unwrapped_context.callback;
|
122
|
+
|
123
|
+
buffer_array = rb_ary_new();
|
124
|
+
for (i = 0; i < length; ++i) {
|
125
|
+
rb_ary_push(buffer_array, UINT2NUM((uint8_t)buffer[i]));
|
126
|
+
}
|
127
|
+
|
128
|
+
// TODO: do we need to free(buffer) or context ?
|
129
|
+
bool_value = RTEST(rb_funcall(callback, rb_intern("call"), 1, buffer_array));
|
130
|
+
|
131
|
+
if (!bool_value) {
|
132
|
+
rtlsdr_cancel_async(device);
|
133
|
+
}
|
134
|
+
}
|
135
|
+
|
136
|
+
static VALUE turtleshell_read_asynchronous(VALUE self,
|
137
|
+
VALUE device,
|
138
|
+
VALUE bytes_to_read,
|
139
|
+
VALUE callback) {
|
140
|
+
int success, length = NUM2INT(bytes_to_read);
|
141
|
+
rtlsdr_dev_t *p_device;
|
142
|
+
struct turtleshell_context context;
|
143
|
+
void *wrapped_context;
|
144
|
+
|
145
|
+
Data_Get_Struct(device, rtlsdr_dev_t, p_device);
|
146
|
+
|
147
|
+
context.device = p_device;
|
148
|
+
context.callback = callback;
|
149
|
+
wrapped_context = (void *)&context;
|
150
|
+
|
151
|
+
rtlsdr_reset_buffer(p_device);
|
152
|
+
success = rtlsdr_read_async(p_device, turtleshell_callback, wrapped_context, 0, length);
|
153
|
+
|
154
|
+
if (success != 0) {
|
155
|
+
printf("error reading async: return code %d\n", success);
|
156
|
+
}
|
157
|
+
|
158
|
+
return Qnil;
|
159
|
+
}
|
160
|
+
|
161
|
+
static VALUE turtleshell_get_sample_rate(VALUE self, VALUE wrapped_device) {
|
162
|
+
rtlsdr_dev_t *device;
|
163
|
+
Data_Get_Struct(wrapped_device, rtlsdr_dev_t, device);
|
164
|
+
return UINT2NUM(rtlsdr_get_sample_rate(device));
|
165
|
+
}
|
166
|
+
|
167
|
+
static VALUE turtleshell_set_sample_rate(VALUE self,
|
168
|
+
VALUE wrapped_device,
|
169
|
+
VALUE value) {
|
170
|
+
uint32_t rate = NUM2UINT(value);
|
171
|
+
rtlsdr_dev_t *device;
|
172
|
+
Data_Get_Struct(wrapped_device, rtlsdr_dev_t, device);
|
173
|
+
rtlsdr_set_sample_rate(device, rate);
|
174
|
+
|
175
|
+
return Qnil;
|
176
|
+
}
|
177
|
+
|
178
|
+
static VALUE turtleshell_get_center_frequency(VALUE self, VALUE wrapped_device) {
|
179
|
+
rtlsdr_dev_t *device;
|
180
|
+
Data_Get_Struct(wrapped_device, rtlsdr_dev_t, device);
|
181
|
+
return UINT2NUM(rtlsdr_get_center_freq(device));
|
182
|
+
}
|
183
|
+
|
184
|
+
static VALUE turtleshell_set_center_frequency(VALUE self,
|
185
|
+
VALUE wrapped_device,
|
186
|
+
VALUE value) {
|
187
|
+
uint32_t freq = NUM2UINT(value);
|
188
|
+
rtlsdr_dev_t *device;
|
189
|
+
Data_Get_Struct(wrapped_device, rtlsdr_dev_t, device);
|
190
|
+
rtlsdr_set_center_freq(device, freq);
|
191
|
+
return Qnil;
|
192
|
+
}
|
193
|
+
|
194
|
+
static VALUE turtleshell_get_gain(VALUE self, VALUE wrapped_device) {
|
195
|
+
rtlsdr_dev_t *device;
|
196
|
+
Data_Get_Struct(wrapped_device, rtlsdr_dev_t, device);
|
197
|
+
return INT2NUM(rtlsdr_get_tuner_gain(device));
|
198
|
+
}
|
199
|
+
|
200
|
+
static VALUE turtleshell_set_gain(VALUE self, VALUE wrapped_device, VALUE value) {
|
201
|
+
int gain = NUM2INT(value);
|
202
|
+
rtlsdr_dev_t *device;
|
203
|
+
Data_Get_Struct(wrapped_device, rtlsdr_dev_t, device);
|
204
|
+
rtlsdr_set_tuner_gain(device, gain);
|
205
|
+
return Qnil;
|
206
|
+
}
|
207
|
+
|
208
|
+
void Init_librtlsdr() {
|
209
|
+
m_turtleshell = rb_define_module("TurtleShell");
|
210
|
+
m_rtlsdr = rb_define_module_under(m_turtleshell, "RTLSDR");
|
211
|
+
c_device = rb_define_class_under(m_rtlsdr, "Device", rb_cObject);
|
212
|
+
|
213
|
+
// count of devices
|
214
|
+
rb_define_module_function(m_rtlsdr, "count", turtleshell_count, 0);
|
215
|
+
|
216
|
+
// life cycle of devices
|
217
|
+
rb_define_module_function(m_rtlsdr, "first_device", turtleshell_first_device, 0);
|
218
|
+
rb_define_module_function(m_rtlsdr, "all_devices", turtleshell_all_devices, 0);
|
219
|
+
rb_define_module_function(m_rtlsdr, "nth_device", turtleshell_nth_device, 1);
|
220
|
+
rb_define_module_function(m_rtlsdr, "close_device", turtleshell_close, 1);
|
221
|
+
|
222
|
+
// reading bytes
|
223
|
+
rb_define_module_function(m_rtlsdr, "read_sync", turtleshell_read_synchronous, 2);
|
224
|
+
rb_define_module_function(m_rtlsdr, "read_async", turtleshell_read_asynchronous, 3);
|
225
|
+
|
226
|
+
// getters and setters
|
227
|
+
rb_define_module_function(m_rtlsdr, "get_sample_rate", turtleshell_get_sample_rate, 1);
|
228
|
+
rb_define_module_function(m_rtlsdr, "set_sample_rate", turtleshell_set_sample_rate, 2);
|
229
|
+
rb_define_module_function(m_rtlsdr, "get_center_freq", turtleshell_get_center_frequency, 1);
|
230
|
+
rb_define_module_function(m_rtlsdr, "set_center_freq", turtleshell_set_center_frequency, 2);
|
231
|
+
rb_define_module_function(m_rtlsdr, "get_gain", turtleshell_get_gain, 1);
|
232
|
+
rb_define_module_function(m_rtlsdr, "set_gain", turtleshell_set_gain, 2);
|
233
|
+
}
|
data/lib/turtleshell.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
module TurtleShell
|
2
|
+
end
|
3
|
+
|
4
|
+
Dir.entries(Dir.pwd).select do |f|
|
5
|
+
File.directory?(f) && f[0] != '.'
|
6
|
+
end.each do |dir|
|
7
|
+
lib = File.expand_path("../#{dir}", __FILE__)
|
8
|
+
$:.unshift lib unless $:.include? lib
|
9
|
+
end
|
10
|
+
|
11
|
+
require 'librtlsdr/librtlsdr'
|
12
|
+
require 'turtleshell/device'
|
13
|
+
|
14
|
+
module TurtleShell
|
15
|
+
def self.all_devices
|
16
|
+
TurtleShell::RTLSDR.all_devices
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.count_of_devices
|
20
|
+
TurtleShell::RTLSDR.count
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
module TurtleShell
|
2
|
+
|
3
|
+
class DeviceNotFoundError < Exception; end
|
4
|
+
|
5
|
+
class Device
|
6
|
+
attr_reader :name
|
7
|
+
|
8
|
+
def initialize(n = 0)
|
9
|
+
raise ArgumentError.new('TurtleShell::Device.new expects a number') unless n.is_a? Fixnum
|
10
|
+
|
11
|
+
unless raw_device_attrs = TurtleShell::RTLSDR.nth_device(n)
|
12
|
+
raise TurtleShell::DeviceNotFoundError
|
13
|
+
end
|
14
|
+
|
15
|
+
@name = raw_device_attrs[:name]
|
16
|
+
@device = raw_device_attrs[:device]
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.device_with_name(name)
|
20
|
+
unless index = TurtleShell.all_devices.index(name)
|
21
|
+
raise ArgumentError.new('No device with that name')
|
22
|
+
end
|
23
|
+
|
24
|
+
new(index)
|
25
|
+
end
|
26
|
+
|
27
|
+
def sample_rate
|
28
|
+
TurtleShell::RTLSDR.get_sample_rate(@device)
|
29
|
+
end
|
30
|
+
|
31
|
+
def sample_rate=(rate)
|
32
|
+
TurtleShell::RTLSDR.set_sample_rate(@device, rate)
|
33
|
+
end
|
34
|
+
|
35
|
+
def center_frequency
|
36
|
+
TurtleShell::RTLSDR.get_center_freq(@device)
|
37
|
+
end
|
38
|
+
|
39
|
+
def center_frequency=(freq)
|
40
|
+
TurtleShell::RTLSDR.set_center_freq(@device, freq)
|
41
|
+
end
|
42
|
+
|
43
|
+
def gain
|
44
|
+
TurtleShell::RTLSDR.get_gain(@device)
|
45
|
+
end
|
46
|
+
|
47
|
+
def gain=(gain)
|
48
|
+
TurtleShell::RTLSDR.set_gain(@device, gain)
|
49
|
+
end
|
50
|
+
|
51
|
+
# read specified number of complex samples from tuner
|
52
|
+
# real and imaginary parts are normalized between [-1, 1]
|
53
|
+
def read_samples(number_of_samples = 1024)
|
54
|
+
number_of_bytes = 2 * number_of_samples
|
55
|
+
raw_data = read_bytes(number_of_bytes)
|
56
|
+
packed_bytes_to_complex(raw_data)
|
57
|
+
end
|
58
|
+
|
59
|
+
# read specified number of complex samples from tuner into a block
|
60
|
+
# real and imaginary parts are normalized between [-1, 1]
|
61
|
+
def read_samples_async(number_of_samples = 1024, &block)
|
62
|
+
block = proc { } unless block_given?
|
63
|
+
wrapped_block = proc do |raw_data|
|
64
|
+
block.call(packed_bytes_to_complex(raw_data))
|
65
|
+
end
|
66
|
+
|
67
|
+
number_of_bytes_to_read = 2 * number_of_samples
|
68
|
+
|
69
|
+
begin
|
70
|
+
TurtleShell::RTLSDR.read_async(@device, number_of_bytes_to_read, wrapped_block)
|
71
|
+
rescue SignalException => e
|
72
|
+
puts 'Caught signal, cancelling async callback.'
|
73
|
+
TurtleShell::RTLSDR.end_async(@device)
|
74
|
+
raise e
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def close_device
|
79
|
+
unless @device.nil?
|
80
|
+
TurtleShell::RTLSDR.close_device(@device)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
private
|
85
|
+
def read_bytes(bytes_to_read)
|
86
|
+
buffer = TurtleShell::RTLSDR.read_sync(@device, bytes_to_read)
|
87
|
+
|
88
|
+
if buffer.size != bytes_to_read
|
89
|
+
close_device
|
90
|
+
raise IOError.new("Error reading from device. Requested #{bytes_to_read} but got #{buffer.size} back")
|
91
|
+
end
|
92
|
+
|
93
|
+
buffer
|
94
|
+
end
|
95
|
+
|
96
|
+
# converts an array of bytes to a list of complex numbers
|
97
|
+
# and normalizes them within the range [-1, 1]
|
98
|
+
def packed_bytes_to_complex(bytes)
|
99
|
+
bytes.each_slice(2).map do |i, r|
|
100
|
+
Complex(i / 127.5 - 1, r / 127.5 - 1)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
data/spec/device_spec.rb
ADDED
@@ -0,0 +1,184 @@
|
|
1
|
+
require 'turtleshell'
|
2
|
+
|
3
|
+
describe 'TurtleShell:Device behavior' do
|
4
|
+
it 'should return the name' do
|
5
|
+
TurtleShell::RTLSDR.
|
6
|
+
should_receive(:nth_device).
|
7
|
+
and_return({:name => 'slippery-slope'})
|
8
|
+
|
9
|
+
expect(TurtleShell::Device.new.name).to eq('slippery-slope')
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
describe 'creating devices' do
|
14
|
+
describe 'finding a device by index' do
|
15
|
+
it 'should create a new device' do
|
16
|
+
TurtleShell::RTLSDR.
|
17
|
+
should_receive(:nth_device).
|
18
|
+
with(750).
|
19
|
+
and_return({:name => 'ill-sorted-limbic-system'})
|
20
|
+
|
21
|
+
expect(TurtleShell::Device.new(750)).to be_an_instance_of TurtleShell::Device
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
describe 'finding a device by name' do
|
26
|
+
before do
|
27
|
+
TurtleShell.
|
28
|
+
should_receive(:all_devices).
|
29
|
+
and_return(['electro-positive-self-activity', 'dry-shod-leze-majesty'])
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'should create a new device' do
|
33
|
+
TurtleShell::RTLSDR.
|
34
|
+
should_receive(:nth_device).
|
35
|
+
with(1).
|
36
|
+
and_return({:name => 'dry-shod-leze-majesty'})
|
37
|
+
|
38
|
+
expect(TurtleShell::Device.device_with_name('dry-shod-leze-majesty')).
|
39
|
+
to be_an_instance_of TurtleShell::Device
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'should raise an ArgumentError when there is matching device' do
|
43
|
+
expect { TurtleShell::Device.device_with_name('clincher-built-parity-check') }.
|
44
|
+
to raise_error(ArgumentError, 'No device with that name')
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
describe 'creating a new device' do
|
49
|
+
it 'should create a new device' do
|
50
|
+
TurtleShell::RTLSDR.
|
51
|
+
should_receive(:nth_device).
|
52
|
+
with(437).
|
53
|
+
and_return({:name => 'self-applying-cat-silver'})
|
54
|
+
|
55
|
+
expect(TurtleShell::Device.new(437)).to be_an_instance_of TurtleShell::Device
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'should raise an error if the first argument is not an integer' do
|
59
|
+
expect { TurtleShell::Device.new('a') }.
|
60
|
+
to raise_error ArgumentError, 'TurtleShell::Device.new expects a number'
|
61
|
+
|
62
|
+
expect { TurtleShell::Device.new(nil) }.
|
63
|
+
to raise_error ArgumentError, 'TurtleShell::Device.new expects a number'
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def create_mock_device
|
69
|
+
TurtleShell::RTLSDR.
|
70
|
+
should_receive(:nth_device).
|
71
|
+
with(0).
|
72
|
+
and_return({
|
73
|
+
:name => 'self-applying-cat-silver',
|
74
|
+
:sample_rate => 666,
|
75
|
+
:center_frequency => 70e6,
|
76
|
+
:gain => :auto,
|
77
|
+
})
|
78
|
+
|
79
|
+
TurtleShell::Device.new(0)
|
80
|
+
end
|
81
|
+
|
82
|
+
describe 'device attribues' do
|
83
|
+
describe 'getting and setting the sample rate' do
|
84
|
+
describe 'getting the value' do
|
85
|
+
before do
|
86
|
+
@device = create_mock_device
|
87
|
+
TurtleShell::RTLSDR.
|
88
|
+
should_receive(:get_sample_rate).
|
89
|
+
and_return(666)
|
90
|
+
end
|
91
|
+
|
92
|
+
it 'gets the value' do
|
93
|
+
expect(@device.sample_rate).to eq(666)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
describe 'setting the value' do
|
98
|
+
before do
|
99
|
+
@device = create_mock_device
|
100
|
+
TurtleShell::RTLSDR.
|
101
|
+
should_receive(:set_sample_rate)
|
102
|
+
.with(nil, 12) ### mocked out device struct
|
103
|
+
|
104
|
+
TurtleShell::RTLSDR.
|
105
|
+
should_receive(:get_sample_rate)
|
106
|
+
.and_return(12)
|
107
|
+
end
|
108
|
+
|
109
|
+
it 'sets the value' do
|
110
|
+
@device.sample_rate = 12
|
111
|
+
expect(@device.sample_rate).to eq(12)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
describe 'getting and setting the center frequency' do
|
117
|
+
describe 'getting the value' do
|
118
|
+
before do
|
119
|
+
@device = create_mock_device
|
120
|
+
|
121
|
+
TurtleShell::RTLSDR.
|
122
|
+
should_receive(:get_center_freq)
|
123
|
+
.and_return(70e6)
|
124
|
+
|
125
|
+
it 'gets the value' do
|
126
|
+
expect(@device.center_frequency).to eq(70e6)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
describe 'setting the value' do
|
132
|
+
before do
|
133
|
+
@device = create_mock_device
|
134
|
+
|
135
|
+
TurtleShell::RTLSDR.
|
136
|
+
should_receive(:set_center_freq).
|
137
|
+
with(nil, 12e12)
|
138
|
+
|
139
|
+
TurtleShell::RTLSDR.
|
140
|
+
should_receive(:get_center_freq).
|
141
|
+
and_return(12e12)
|
142
|
+
end
|
143
|
+
|
144
|
+
it 'sets the value' do
|
145
|
+
@device.center_frequency = 12e12
|
146
|
+
expect(@device.center_frequency).to eq(12e12)
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
describe 'getting and setting the gain' do
|
152
|
+
describe 'getting the value' do
|
153
|
+
before do
|
154
|
+
@device = create_mock_device
|
155
|
+
TurtleShell::RTLSDR.
|
156
|
+
should_receive(:get_gain).
|
157
|
+
and_return(:auto)
|
158
|
+
end
|
159
|
+
|
160
|
+
it 'gets the gain' do
|
161
|
+
expect(@device.gain).to eq(:auto)
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
describe 'setting the value' do
|
166
|
+
before do
|
167
|
+
@device = create_mock_device
|
168
|
+
|
169
|
+
TurtleShell::RTLSDR.
|
170
|
+
should_receive(:set_gain).
|
171
|
+
with(nil, 4) # xxx mocked out device
|
172
|
+
|
173
|
+
TurtleShell::RTLSDR.
|
174
|
+
should_receive(:get_gain).
|
175
|
+
and_return(4)
|
176
|
+
end
|
177
|
+
|
178
|
+
it 'sets the value' do
|
179
|
+
@device.gain = 4
|
180
|
+
expect(@device.gain).to eq(4)
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'turtleshell'
|
2
|
+
|
3
|
+
describe 'TurtleShell' do
|
4
|
+
it 'tells you how many devices are connected' do
|
5
|
+
TurtleShell::RTLSDR.
|
6
|
+
should_receive(:count).
|
7
|
+
and_return(886)
|
8
|
+
|
9
|
+
expect(TurtleShell.count_of_devices).to eq(886)
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'tells you which devices are at which index' do
|
13
|
+
TurtleShell::RTLSDR.
|
14
|
+
should_receive(:all_devices).
|
15
|
+
and_return(['guilt-ridden-humpback-whale', 'four-ply-self-repellency', 'lute-backed-cross-stone'])
|
16
|
+
|
17
|
+
names = TurtleShell.all_devices
|
18
|
+
expect(names[0]).to eq('guilt-ridden-humpback-whale')
|
19
|
+
expect(names[1]).to eq('four-ply-self-repellency')
|
20
|
+
expect(names[2]).to eq('lute-backed-cross-stone')
|
21
|
+
end
|
22
|
+
end
|
data/turtleshell.gemspec
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = 'turtleshell'
|
3
|
+
s.version = '1.0.4'
|
4
|
+
s.date = '2013-11-05'
|
5
|
+
s.summary = 'A ruby wrapper for librtlsdr'
|
6
|
+
s.description = 'turtleshell is an interface for realtek USB software defined radio devices'
|
7
|
+
s.authors = ['Tim Jarratt']
|
8
|
+
s.email = 'tjarratt@gmail.com'
|
9
|
+
s.files = ['lib/turtleshell.rb']
|
10
|
+
s.homepage = 'http://github.com/tjarratt/turtleshell'
|
11
|
+
s.license = 'MIT'
|
12
|
+
s.require_path = 'lib'
|
13
|
+
|
14
|
+
s.extensions = ['ext/librtlsdr/extconf.rb']
|
15
|
+
|
16
|
+
s.add_dependency 'rake', '~> 10.1'
|
17
|
+
s.add_dependency 'rake-compiler', '~> 0.9'
|
18
|
+
s.add_development_dependency 'rspec', '~> 2.14'
|
19
|
+
|
20
|
+
ignores = File.readlines('.gitignore').grep(/\S+/).map(&:chomp)
|
21
|
+
dotfiles = %w[.gitignore]
|
22
|
+
|
23
|
+
all_files_without_ignores = Dir['**/*'].reject { |f|
|
24
|
+
File.directory?(f) || ignores.any? { |i| File.fnmatch(i, f) }
|
25
|
+
}
|
26
|
+
|
27
|
+
s.files = (all_files_without_ignores + dotfiles).sort
|
28
|
+
end
|
metadata
ADDED
@@ -0,0 +1,105 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: turtleshell
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.4
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Tim Jarratt
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2013-11-05 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rake
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '10.1'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '10.1'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake-compiler
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ~>
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0.9'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ~>
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0.9'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ~>
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '2.14'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ~>
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '2.14'
|
55
|
+
description: turtleshell is an interface for realtek USB software defined radio devices
|
56
|
+
email: tjarratt@gmail.com
|
57
|
+
executables: []
|
58
|
+
extensions:
|
59
|
+
- ext/librtlsdr/extconf.rb
|
60
|
+
extra_rdoc_files: []
|
61
|
+
files:
|
62
|
+
- .gitignore
|
63
|
+
- CHANGELOG.md
|
64
|
+
- Gemfile
|
65
|
+
- LICENSE
|
66
|
+
- README.md
|
67
|
+
- Rakefile
|
68
|
+
- examples/async_read_from_device.rb
|
69
|
+
- examples/listing_devices.rb
|
70
|
+
- examples/simple_read_from_device.rb
|
71
|
+
- ext/librtlsdr/Makefile
|
72
|
+
- ext/librtlsdr/extconf.rb
|
73
|
+
- ext/librtlsdr/librtlsdr.c
|
74
|
+
- lib/turtleshell.rb
|
75
|
+
- lib/turtleshell/device.rb
|
76
|
+
- spec/device_spec.rb
|
77
|
+
- spec/turtleshell_spec.rb
|
78
|
+
- tmp/x86_64-darwin13.0.0/librtlsdr/2.0.0/Makefile
|
79
|
+
- tmp/x86_64-darwin13.0.0/librtlsdr/2.0.0/mkmf.log
|
80
|
+
- turtleshell.gemspec
|
81
|
+
homepage: http://github.com/tjarratt/turtleshell
|
82
|
+
licenses:
|
83
|
+
- MIT
|
84
|
+
metadata: {}
|
85
|
+
post_install_message:
|
86
|
+
rdoc_options: []
|
87
|
+
require_paths:
|
88
|
+
- lib
|
89
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
90
|
+
requirements:
|
91
|
+
- - '>='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0'
|
94
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
95
|
+
requirements:
|
96
|
+
- - '>='
|
97
|
+
- !ruby/object:Gem::Version
|
98
|
+
version: '0'
|
99
|
+
requirements: []
|
100
|
+
rubyforge_project:
|
101
|
+
rubygems_version: 2.1.11
|
102
|
+
signing_key:
|
103
|
+
specification_version: 4
|
104
|
+
summary: A ruby wrapper for librtlsdr
|
105
|
+
test_files: []
|