diff --git a/.gitignore b/.gitignore index ea3dd8a..ef3210c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,9 +1,14 @@ // Python things __pycache__ *.pyc +.venv +build // My devenv *.iq +*.cs16 +*.cf32 +*.cs8 *.iqhackrf *.egg-info .direnv diff --git a/README.md b/README.md index 5528e3f..9c0f6c2 100644 --- a/README.md +++ b/README.md @@ -53,7 +53,7 @@ Options: -s, --samplerate INTEGER Samplerate of the radio -l, --linetime FLOAT Time for each line to show -o, --output FILENAME File to write to (default: stdout) - --format [float|bladerf|hackrf] + --format [float|bladerf|hackrf|plutosdr] Output format of samples --help Show this message and exit. ``` @@ -61,7 +61,7 @@ Options: * Samplerate is what you will configure in your radio later. About half of that bandwidth is actually used for the image. The edges are left free since I've seen some pretty ugly bandfilter effects sometimes. * Linetime is the time in seconds that each line of your images will display. Experiment a bit here, usually a good starting value is around 0.005 - 0.01. * Output is the file to write to. Per default this is stdout. - * Format selects the output formatter. There is support for bladerf and hackrf radio formats as well as raw I/Q interleaved 32-bit float samples. + * Format selects the output formatter. There is support for bladerf, hackrf, and plutosdr radio formats as well as raw I/Q interleaved 32-bit float samples. * You can pass multiple images to the program which will all be converted and written to the output. The FFT adapts to the image size. However, I've not tried what happens for very wide or narrow images. Pictures with a horizontal resolution between about 512-2048 pixels seem to work fine, though. Only the first color channel of the image is used, so images should be black and white. diff --git a/spectrum_painter/img2iqstream.py b/spectrum_painter/img2iqstream.py index 974cb0b..242a501 100644 --- a/spectrum_painter/img2iqstream.py +++ b/spectrum_painter/img2iqstream.py @@ -1,14 +1,14 @@ import click -from spectrum_painter.radios import GenericFloat, Bladerf, Hackrf +from spectrum_painter.radios import GenericFloat, Bladerf, Hackrf, Plutosdr from spectrum_painter.spectrum_painter import SpectrumPainter -FORMATTERS = {'float': GenericFloat, 'bladerf': Bladerf, 'hackrf': Hackrf} +FORMATTERS = {'float': GenericFloat, 'bladerf': Bladerf, 'hackrf': Hackrf, 'plutosdr': Plutosdr} @click.command() @click.option('--samplerate', '-s', type=int, default=1000000, help='Samplerate of the radio') @click.option('--linetime', '-l', type=float, default=0.005, help='Time for each line to show') @click.option('--output', '-o', type=click.File('wb'), help='File to write to (default: stdout)', default='-') -@click.option('--format', type=click.Choice(['float', 'bladerf', 'hackrf']), default='float', help='Output format of samples') +@click.option('--format', type=click.Choice(['float', 'bladerf', 'hackrf', 'plutosdr']), default='float', help='Output format of samples') @click.argument('srcs', nargs=-1, type=click.Path(exists=True)) def img2iqstream(samplerate, linetime, output, format, srcs): formatter = FORMATTERS[format]() diff --git a/spectrum_painter/radios.py b/spectrum_painter/radios.py index 5cf3944..17a802f 100644 --- a/spectrum_painter/radios.py +++ b/spectrum_painter/radios.py @@ -99,4 +99,32 @@ def transmit(self, complex_iq): hackout.wait() sout = hackout.communicate() os.unlink(pipe_file) - return sout \ No newline at end of file + return sout + +class Plutosdr(Radio): + def __init__(self): + super(Plutosdr, self).__init__() + self.txvga = 0 + self.rxvga = 0 + self.rxlna = 0 + + def convert(self, complex_iq): + intlv = self._interleave(complex_iq) + clipped = self._clip(intlv) + converted = 127. * clipped + plutosdr_out = converted.astype(np.int16) + return plutosdr_out + + def transmit(self, complex_iq): + plutosdr_out = self.convert(complex_iq) + pipe_file = mktemp() + os.mkfifo(pipe_file) + plutoout = Popen(['tx_sdr', '-f', str(self.frequency), '-s', str(self.samplerate), '-B', str(self.bandwidth), + '-F', 'CS16', '-g', 70, pipe_file], stdin=PIPE, stdout=PIPE, stderr=PIPE) + pipe = open(pipe_file, 'wb') + pipe.write(plutosdr_out) + pipe.close() + plutoout.wait() + sout = plutoout.communicate() + os.unlink(pipe_file) + return sout