Skip to content

Instantly share code, notes, and snippets.

@Sasszem
Created December 18, 2022 09:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Sasszem/08f3c470e0b7a078011578757b6063b7 to your computer and use it in GitHub Desktop.
Save Sasszem/08f3c470e0b7a078011578757b6063b7 to your computer and use it in GitHub Desktop.
Transmit a 440Hz triangle wave through FM using the libhackrf API
#include <libhackrf/hackrf.h>
#include <math.h>
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <complex.h>
#include <stdint.h>
const double f_mod = 440;
const uint64_t sample_rate = 10000000;
double triangle() {
/*
* Generate an f_mod frequency triangle wave in the -1 - 1 region
* each call to this function generates a single sample
*/
static double state;
static uint64_t samples_generated;
const uint64_t period_in_samples = sample_rate / f_mod;
const double step = 4.0 / period_in_samples; // we need to go from -1 to 1 in half the period
if (samples_generated < period_in_samples / 2 )
state += step;
else
state -= step;
// this way we don't need to modulo it
if (samples_generated ++ == period_in_samples)
samples_generated = 0;
return state - 1.0;
}
volatile double complex phasor = 1.0;
int xfered_samples = 0;
int samples_to_xfer = 5*sample_rate;
volatile int should_stop = 0;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
int transfer_callback(hackrf_transfer *transfer) {
int8_t *signed_buffer = (int8_t*)transfer->buffer;
for (int i = 0; i<transfer->buffer_length; i+=2) {
phasor *= cexp(I*6.28*3000 / sample_rate*triangle());
// any IQ samples can be written here, now I'm doing FM modulation with a triangle wave
signed_buffer[i] = 128 * creal(phasor);
signed_buffer[i+1] = 128 * cimag(phasor);
}
transfer->valid_length = transfer->buffer_length;
xfered_samples += transfer->buffer_length;
if (xfered_samples >= samples_to_xfer) {
return 1;
}
return 0;
}
void flush_callback(hackrf_transfer *transfer) {
pthread_mutex_lock(&mutex);
pthread_cond_broadcast(&cond);
pthread_mutex_unlock(&mutex);
}
int main() {
hackrf_init();
hackrf_device *device = NULL;
hackrf_open(&device);
hackrf_set_freq(device, 144500000);
hackrf_set_sample_rate(device, 10000000);
hackrf_set_amp_enable(device, 1);
hackrf_set_txvga_gain(device, 20);
// hackrf_set_tx_underrun_limit(device, 100000);
hackrf_enable_tx_flush(device, flush_callback, NULL);
hackrf_start_tx(device, transfer_callback, NULL);
pthread_mutex_lock(&mutex);
pthread_cond_wait(&cond, &mutex);
hackrf_stop_tx(device);
hackrf_close(device);
hackrf_exit();
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment