diff options
Diffstat (limited to 'binding/radio_impl_rtlsdr.c')
-rw-r--r-- | binding/radio_impl_rtlsdr.c | 507 |
1 files changed, 0 insertions, 507 deletions
diff --git a/binding/radio_impl_rtlsdr.c b/binding/radio_impl_rtlsdr.c deleted file mode 100644 index 2087d10..0000000 --- a/binding/radio_impl_rtlsdr.c +++ /dev/null @@ -1,507 +0,0 @@ -/* - * Copyright (C) 2017,2018,2020 Konsulko Group - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <stdio.h> -#include <stdlib.h> -#include <stdint.h> -#include <stdbool.h> -#include <string.h> -#include <unistd.h> -#include <pthread.h> -#include <sys/stat.h> -#include <errno.h> -#include <glib.h> -#include <afb/afb-binding.h> - -#include "radio_impl.h" - -#define HELPER_NAME "rtl_fm_helper" -#define HELPER_MAX PATH_MAX + 64 - -#define HELPER_CMD_MAXLEN 64 -#define HELPER_RSP_MAXLEN 128 - -// Structure to describe FM band plans, all values in Hz. -typedef struct { - char *name; - uint32_t min; - uint32_t max; - uint32_t step; -} fm_band_plan_t; - -static fm_band_plan_t known_fm_band_plans[5] = { - { .name = "US", .min = 87900000, .max = 107900000, .step = 200000 }, - { .name = "JP", .min = 76000000, .max = 95000000, .step = 100000 }, - { .name = "EU", .min = 87500000, .max = 108000000, .step = 50000 }, - { .name = "ITU-1", .min = 87500000, .max = 108000000, .step = 50000 }, - { .name = "ITU-2", .min = 87900000, .max = 107900000, .step = 50000 } -}; - -static unsigned int bandplan; -static char *helper_output; -static pid_t helper_pid; -static int helper_in; -static int helper_out; -static pthread_mutex_t helper_mutex = PTHREAD_MUTEX_INITIALIZER; -static bool present; -static bool initialized; -static bool active; -static bool scanning; -static uint32_t current_frequency; -static radio_freq_callback_t freq_callback; -static void *freq_callback_data; - -static uint32_t rtlsdr_get_min_frequency(radio_band_t band); -static void rtlsdr_set_frequency(uint32_t frequency); -static void rtlsdr_scan_stop(void); - -/* - * Bi-directional popen implementation - * Based on one of the versions given in: - * - * https://stackoverflow.com/questions/12778672/killing-process-that-has-been-created-with-popen2 - */ -static pid_t popen2(char *command, int *in_fd, int *out_fd) -{ - int pin[2], pout[2]; - pid_t pid; - - if(out_fd != NULL) { - if(pipe(pin) != 0) - return -1; - } - if(in_fd != NULL) { - if (pipe(pout) != 0) { - if(out_fd != NULL) { - close(pin[0]); - close(pin[1]); - } - return -1; - } - } - - pid = fork(); - if(pid < 0) { - if(out_fd != NULL) { - close(pin[0]); - close(pin[1]); - } - if(in_fd != NULL) { - close(pout[0]); - close(pout[1]); - } - return pid; - } - if(pid == 0) { - if(out_fd != NULL) { - close(pin[1]); - dup2(pin[0], 0); - } - if(in_fd != NULL) { - close(pout[0]); - dup2(pout[1], 1); - } - execlp(command, command, NULL); - perror("Error:"); - exit(1); - } - if(in_fd != NULL) { - close(pout[1]); - *in_fd = pout[0]; - } - if(out_fd != NULL) { - close(pin[0]); - *out_fd = pin[1]; - } - return pid; -} - -static int rtlsdr_probe(void) -{ - char *rootdir; - char *helper_path; - - if(present) - return 0; - - rootdir = getenv("AFM_APP_INSTALL_DIR"); - if(!rootdir) - return -1; - - // Run helper to detect adapter - helper_path = malloc(HELPER_MAX); - if(!helper_path) - return -ENOMEM; - if(snprintf(helper_path, HELPER_MAX, "%s/bin/%s --detect", rootdir, HELPER_NAME) == HELPER_MAX) { - AFB_API_ERROR(afbBindingV3root, "Could not create command for \"%s --detect\"", HELPER_NAME); - return -EINVAL; - } - if(system(helper_path) != 0) { - free(helper_path); - return -1; - } - - present = true; - return 0; -} - -static int rtlsdr_start_helper(void) -{ - char *rootdir; - char *helper_path; - static bool helper_started = false; - - if(!present || initialized) - return -1; - - if(helper_started) - return 0; - - rootdir = getenv("AFM_APP_INSTALL_DIR"); - if(!rootdir) - return -1; - - if(helper_output) { - // Indicate desired output to helper - AFB_API_INFO(afbBindingV3root, "Setting RADIO_OUTPUT=%s", helper_output); - setenv("RADIO_OUTPUT", helper_output, 1); - } - - // Run helper - helper_path = malloc(HELPER_MAX); - if(!helper_path) - return -ENOMEM; - if(snprintf(helper_path, PATH_MAX, "%s/bin/%s", rootdir, HELPER_NAME) == PATH_MAX) { - AFB_API_ERROR(afbBindingV3root, "Could not create path to %s", HELPER_NAME); - return -EINVAL; - } - helper_pid = popen2(helper_path, &helper_out, &helper_in); - if(helper_pid < 0) { - AFB_API_ERROR(afbBindingV3root, "Could not run %s!", HELPER_NAME); - return -1; - } - AFB_API_DEBUG(afbBindingV3root, "%s started", HELPER_NAME); - helper_started = true; - free(helper_path); - - return 0; -} - -static int rtlsdr_init(void) -{ - GKeyFile *conf_file; - char *value_str; - int rc; - - if(!present) - return -1; - - if(initialized) - return 0; - - // Load settings from configuration file if it exists - conf_file = g_key_file_new(); - if(conf_file && - g_key_file_load_from_dirs(conf_file, - "AGL.conf", - (const gchar**) g_get_system_config_dirs(), - NULL, - G_KEY_FILE_KEEP_COMMENTS, - NULL) == TRUE) { - - // Set band plan if it is specified - value_str = g_key_file_get_string(conf_file, - "radio", - "fmbandplan", - NULL); - if(value_str) { - unsigned int i; - for(i = 0; - i < sizeof(known_fm_band_plans) / sizeof(fm_band_plan_t); - i++) { - if(!strcasecmp(value_str, known_fm_band_plans[i].name)) { - bandplan = i; - break; - } - } - } - } - - // Start off with minimum bandplan frequency - current_frequency = rtlsdr_get_min_frequency(BAND_FM); - rc = rtlsdr_start_helper(); - if(rc != 0) { - return rc; - } - - initialized = true; - rtlsdr_set_frequency(current_frequency); - - return 0; -} - -static void rtlsdr_set_output(const char *output) -{ - // Save output for later use - free(helper_output); - helper_output = output ? strdup(output) : NULL; -} - -static uint32_t rtlsdr_get_frequency(void) -{ - return current_frequency; -} - -static void rtlsdr_set_frequency(uint32_t frequency) -{ - char cmd[HELPER_CMD_MAXLEN]; - char output[HELPER_RSP_MAXLEN]; - bool found = false; - ssize_t rc; - uint32_t n; - - if(!initialized) - return; - - if(frequency < known_fm_band_plans[bandplan].min || - frequency > known_fm_band_plans[bandplan].max) - return; - - if(scanning) - rtlsdr_scan_stop(); - - current_frequency = frequency; - snprintf(cmd, sizeof(cmd), "F=%u\n", frequency); - pthread_mutex_lock(&helper_mutex); - rc = write(helper_in, cmd, strlen(cmd)); - if(rc < 0) { - pthread_mutex_unlock(&helper_mutex); - return; - } - while(!found) { - rc = read(helper_out, output, sizeof(output)-1); - if(rc <= 0) - break; - output[rc] = '\0'; - if(output[0] == 'F') { - if(sscanf(output, "F=%u\n", &n) == 1) { - if(freq_callback) - freq_callback(n, freq_callback_data); - found = true; - } - } - } - pthread_mutex_unlock(&helper_mutex); -} - -static void rtlsdr_set_frequency_callback(radio_freq_callback_t callback, - void *data) -{ - freq_callback = callback; - freq_callback_data = data; -} - -static radio_band_t rtlsdr_get_band(void) -{ - // We only support FM - return BAND_FM; -} - -static void rtlsdr_set_band(radio_band_t band) -{ - // We only support FM, so do nothing -} - -static int rtlsdr_band_supported(radio_band_t band) -{ - if(band == BAND_FM) - return 1; - return 0; -} - -static uint32_t rtlsdr_get_min_frequency(radio_band_t band) -{ - return known_fm_band_plans[bandplan].min; -} - -static uint32_t rtlsdr_get_max_frequency(radio_band_t band) -{ - return known_fm_band_plans[bandplan].max; -} - -static uint32_t rtlsdr_get_frequency_step(radio_band_t band) -{ - uint32_t ret = 0; - - switch (band) { - case BAND_AM: - ret = 1000; // 1 kHz - break; - case BAND_FM: - ret = known_fm_band_plans[bandplan].step; - break; - default: - break; - } - return ret; -} - -static void rtlsdr_start(void) -{ - ssize_t rc; - char cmd[HELPER_CMD_MAXLEN]; - - if(!initialized) - return; - - if(active) - return; - - snprintf(cmd, sizeof(cmd), "START\n"); - pthread_mutex_lock(&helper_mutex); - rc = write(helper_in, cmd, strlen(cmd)); - pthread_mutex_unlock(&helper_mutex); - if (rc < 0) { - AFB_API_ERROR(afbBindingV3root, "Failed to ask \"%s\" to start", HELPER_NAME); - return; - } - active = true; -} - -static void rtlsdr_stop(void) -{ - ssize_t rc; - if(!initialized) - return; - - if (!active) - return; - - char cmd[HELPER_CMD_MAXLEN]; - - snprintf(cmd, sizeof(cmd), "STOP\n"); - pthread_mutex_lock(&helper_mutex); - rc = write(helper_in, cmd, strlen(cmd)); - pthread_mutex_unlock(&helper_mutex); - if (rc < 0) { - AFB_API_ERROR(afbBindingV3root, "Failed to ask \"%s\" to stop", HELPER_NAME); - return; - } - active = false; -} - -static void rtlsdr_scan_start(radio_scan_direction_t direction, - radio_scan_callback_t callback, - void *data) -{ - ssize_t rc; - char cmd[HELPER_CMD_MAXLEN]; - char output[HELPER_RSP_MAXLEN]; - bool found = false; - uint32_t n; - - if(!active || scanning) - return; - - scanning = true; - snprintf(cmd, - sizeof(cmd), - "S=%s\n", direction == SCAN_FORWARD ? "UP" : "DOWN"); - pthread_mutex_lock(&helper_mutex); - if(!scanning) { - pthread_mutex_unlock(&helper_mutex); - return; - } - rc = write(helper_in, cmd, strlen(cmd)); - pthread_mutex_unlock(&helper_mutex); - if(rc < 0) - return; - while(!found) { - pthread_mutex_lock(&helper_mutex); - if(!scanning) { - pthread_mutex_unlock(&helper_mutex); - break; - } - rc = read(helper_out, output, sizeof(output)-1); - pthread_mutex_unlock(&helper_mutex); - if(rc <= 0) - break; - - output[rc] = '\0'; - if(output[0] == 'F') { - if(sscanf(output, "F=%u\n", &n) == 1) { - current_frequency = n; - if(freq_callback) - freq_callback(n, freq_callback_data); - } - } - if(output[0] == 'S') { - if(sscanf(output, "S=%u\n", &n) == 1) { - if(callback) - callback(n, data); - found = true; - scanning = false; - } - } - } -} - -static void rtlsdr_scan_stop(void) -{ - char cmd[HELPER_CMD_MAXLEN]; - ssize_t rc; - - snprintf(cmd, sizeof(cmd), "S=STOP\n"); - pthread_mutex_lock(&helper_mutex); - scanning = false; - rc = write(helper_in, cmd, strlen(cmd)); - pthread_mutex_unlock(&helper_mutex); - if (rc < 0) - AFB_API_ERROR(afbBindingV3root, "Failed to ask \"%s\" to stop scan", HELPER_NAME); -} - -static radio_stereo_mode_t rtlsdr_get_stereo_mode(void) -{ - // We only support stereo - return STEREO; -} - -static void rtlsdr_set_stereo_mode(radio_stereo_mode_t mode) -{ - // We only support stereo, so do nothing -} - -radio_impl_ops_t rtlsdr_impl_ops = { - .name = "RTL-SDR USB adapter", - .probe = rtlsdr_probe, - .init = rtlsdr_init, - .set_output = rtlsdr_set_output, - .get_frequency = rtlsdr_get_frequency, - .set_frequency = rtlsdr_set_frequency, - .set_frequency_callback = rtlsdr_set_frequency_callback, - .get_band = rtlsdr_get_band, - .set_band = rtlsdr_set_band, - .band_supported = rtlsdr_band_supported, - .get_min_frequency = rtlsdr_get_min_frequency, - .get_max_frequency = rtlsdr_get_max_frequency, - .get_frequency_step = rtlsdr_get_frequency_step, - .start = rtlsdr_start, - .stop = rtlsdr_stop, - .scan_start = rtlsdr_scan_start, - .scan_stop = rtlsdr_scan_stop, - .get_stereo_mode = rtlsdr_get_stereo_mode, - .set_stereo_mode = rtlsdr_set_stereo_mode -}; |