(make-buffer-repository smallest-pwr largest-pwr)
A procedure in module (buffer repository).
Make a buffer repository instance. Parameters refer to the sizes of buffers
stored in the repository. The smallest size is 2 to the smallest-pwr, the
largest is 2 to the largest-pwr.
(checkout-buffer! requested-bytes (buffer-repository) (#:spawn))
A procedure in module (buffer repository).
Checkout a buffer (bytevector) from the buffer-repository. If
buffer-repository is not specified, parameter %buffer-repository is
used. The default action, if a buffer is not available from the
appropriate size bucket, is to generate a new buffer. If #:spawn #f is
passed, checkout-buffer! will throw the 'empty-bucket exception
instead. The buffer returned might be larger than the number of bytes
requested. A 'no-match exception will be thrown if the size-requested
is not in the range of buffer sizes stored by the buffer-repository.
(checkin-buffer! buffer (buffer-repository))
A procedure in module (buffer repository).
Return a buffer (bytevector) to the buffer-repository. If
buffer-repository is not specified, parameter %buffer-repository is
used. It is the responsibility of the calling code not to use the
buffer after it has been checked in. Technically the buffer does not
have to be one that was originally checked-out from the
buffer-repository, but checkin-buffer will throw exceptions if the
buffer is not the proper size to fit in a repository bucket.
I coded a circular-bytevector-copy! function which handles the logic to copy from one vector to another, wrapping around the source and destination vectors as much as necessary.
I coded also a <consumable-buffer> class which implements a FIFO buffer of fix memory size, but implemented with circular reads and writes for efficiency.
I want to play around with the 8sync framework, but the project is unfortunately lacking an API reference. So, I am writing example code to help me learn each of the modules, and thought I might as well share. Here is some example code for the(8sync agenda) module.
This illustrates how an Agenda can be used to interweave the execution of computations, by yielding to other computations during your loop:
scheme@(guile-user)> ,use (8sync agenda examples)
scheme@(guile-user)> (make-stuff)
Making widget
Making thingamabob
Making sprocket
Making widget
Making thingamabob
Making sprocket
Making widget
Making thingamabob
Making sprocket
Making widget
Making thingamabob
Making sprocket
Making widget
Making thingamabob
Making sprocket
Making widget
Making widget
Making widget
Making widget
Making widget
$2 = done
I wanted to move on quickly from completing the FFT interface, on to FM demodulation. However, I realized that if the rest of the project was going to practical and modular, I would need some kind of block style I/O buffer management system, like GnuRadio has. And as I started to pursue that, I realized that I would need to properly modularize my code.
Up until now, all the functions were either being dumped into the default module by the C code, or loaded from one Scheme file in the source directory. I took all the external C code and organized it in sensible module divisions, and then took all the C-based Scheme primitives and put them in two modules ((sdr primitives) and (sdr hackrf primitives)). Those two modules are created and loaded when HackRF Shell is launched, while the other modules can be compiled independently.
That all required taking the time to actually learn how the module system works, as well as understanding how to create and fill-out modules through the C interfaces. So, not much amazing progress to the outside observer, but I learned a lot. The FFT demo function is still working:
One neat thing about programming in Guile is that you can jump into various modules at any time, to play around in them or see what variables are defined in them (private and public):
christopher@nightshade:~/Repos/hackrf-shell$ ./hackrf-shell
HackRF Shell, copyright 2019 Christopher Howard
Initializing primitive functions.
Entering the Scheme shell.
GNU Guile 2.2.3
Copyright (C) 1995-2017 Free Software Foundation, Inc.
Guile comes with ABSOLUTELY NO WARRANTY; for details type `,show w'.
This program is free software, and you are welcome to redistribute it
under certain conditions; type `,show c' for details.
Enter `,help' for help.
scheme@(guile-user)> (set! %load-path (cons "/home/christopher.qlfiles.net/Repos/hackrf-shell" %load-path))
scheme@(guile-user)> ,m (sdr hackrf util)
scheme@(sdr hackrf util)> ,b
hackrf-sensible-defaults #<variable 56314e6aaac0 value: #<procedure hackrf-sensible-defaults (d)>>
filename #<variable 56314e6aa940 value: #<undefined>>
timed-read #<variable 56314e6aa8a0 value: #<procedure timed-read (d file-path start-h start-m end-h end-m)>>
hackrf-cb-rx-to-file #<variable 56314e6aa990 value: #<procedure hackrf-cb-rx-to-file (filename)>>
out #<variable 56314e6aa9e0 value: #<undefined>>
when-hour-min #<variable 56314e6bd660 value: #<procedure when-hour-min (h m l)>>
hackrf-cb-rx-to-stream #<variable 56314e6aaa30 value: #<procedure hackrf-cb-rx-to-stream (out)>>
cb-fft-to-gnuplot #<variable 56314e6aa8f0 value: #<procedure cb-fft-to-gnuplot (center-freq samp-rate averaging-alpha)>>
scheme@(sdr hackrf util)> hackrf-
hackrf-cb-rx-to-file hackrf-open hackrf-set-sample-rate
hackrf-cb-rx-to-stream hackrf-sensible-defaults hackrf-set-vga-gain
hackrf-close hackrf-set-baseband-filter-bandwidth hackrf-start-rx
hackrf-disable-amp hackrf-set-freq hackrf-stop-rx
hackrf-enable-amp hackrf-set-lna-gain
scheme@(sdr hackrf util)> ,m (sdr util)
scheme@(sdr util)> ,b
bv-complex-to-mag #<variable 56314e6b4700 value: #<procedure bv-complex-to-mag (complex-float-bv n_complex_nums dest-bv)>>
freq-shifter #<variable 56314e6b4670 value: #<procedure freq-shifter (freq samprate)>>
The next step in my project will be to work out my block-style I/O buffer management system, which will require me to re-learn GOOPS, Guile’s object oriented programming extension, so that will likely still take a while.
I’m not quite sure I have all the bugs worked out yet, but I implemented simple averaging, as well and the frequency display. The latter required implementing fft-shift to move center frequency to the center. The above plot shows FM stations at 101.1, 102.5, 103.9, and 104.7 Mhz, matching local stations I know about.
These simple things took quite a while, mainly because of the busyness of other life responsibilities; but also because the process of implementation led to fixing some bugs, which led to cleaning up some code, which led to learning new things about Guile scheme and C.
In Guile scheme, I learned how to implement a procedure to auto-close unreachable ports: