summaryrefslogtreecommitdiffstats
path: root/binding
diff options
context:
space:
mode:
Diffstat (limited to 'binding')
-rw-r--r--binding/CMakeLists.txt73
-rw-r--r--binding/convenience/convenience.c309
-rw-r--r--binding/convenience/convenience.h142
-rw-r--r--binding/radio-binding.c752
-rw-r--r--binding/radio_impl.h125
-rw-r--r--binding/radio_impl_kingfisher.c526
-rw-r--r--binding/radio_impl_kingfisher.h25
-rw-r--r--binding/radio_impl_null.c281
-rw-r--r--binding/radio_impl_null.h25
-rw-r--r--binding/radio_impl_rtlsdr.c507
-rw-r--r--binding/radio_impl_rtlsdr.h25
-rw-r--r--binding/radio_impl_tef665x.c2405
-rw-r--r--binding/radio_impl_tef665x.h23
-rw-r--r--binding/radio_output.h31
-rw-r--r--binding/radio_output_gstreamer.c231
-rw-r--r--binding/rtl_fm.c1275
-rw-r--r--binding/rtl_fm.h70
-rw-r--r--binding/rtl_fm_helper.c243
-rw-r--r--binding/tef665x.h397
19 files changed, 0 insertions, 7465 deletions
diff --git a/binding/CMakeLists.txt b/binding/CMakeLists.txt
deleted file mode 100644
index 560dcaf..0000000
--- a/binding/CMakeLists.txt
+++ /dev/null
@@ -1,73 +0,0 @@
-###########################################################################
-# Copyright 2015, 2016, 2017 IoT.bzh
-# Copyright (C) 2018, 2019 Konsulko Group
-#
-# author: Fulup Ar Foll <fulup@iot.bzh>
-# contrib: Romain Forlot <romain.forlot@iot.bzh>
-#
-# 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.
-###########################################################################
-
-# Add target to project dependency list
-PROJECT_TARGET_ADD(radio-binding)
-
- add_definitions(-DAFB_BINDING_VERSION=3)
-
- # Define project Targets
- set(radio_SOURCES
- radio-binding.c
- radio_impl_kingfisher.c
- radio_impl_null.c
- radio_impl_rtlsdr.c
- radio_impl_tef665x.c)
-
- PKG_CHECK_MODULES(SOUND REQUIRED gstreamer-1.0)
-
- add_library(${TARGET_NAME} MODULE ${radio_SOURCES})
-
- # Binder exposes a unique public entry point
- SET_TARGET_PROPERTIES(${TARGET_NAME} PROPERTIES
- PREFIX "libafm-"
- LABELS "BINDING"
- LINK_FLAGS ${BINDINGS_LINK_FLAG}
- OUTPUT_NAME ${TARGET_NAME}
- )
-
- # Library dependencies (include updates automatically)
- TARGET_COMPILE_OPTIONS(${TARGET_NAME} PUBLIC ${SOUND_CFLAGS})
- TARGET_LINK_LIBRARIES(${TARGET_NAME} ${SOUND_LIBRARIES} ${link_libraries})
-
-# Add helper program target
-PROJECT_TARGET_ADD(rtl_fm_helper)
-
- # Define project targets
- set(helper_SOURCES
- ${TARGET_NAME}.c
- radio_output_gstreamer.c
- rtl_fm.c
- convenience/convenience.c)
-
- PKG_CHECK_MODULES(helper_SOUND REQUIRED gstreamer-1.0)
- PKG_CHECK_MODULES(helper_RTLSDR REQUIRED librtlsdr)
- PKG_CHECK_MODULES(helper_LIBUSB REQUIRED libusb-1.0)
-
- add_executable(${TARGET_NAME} ${helper_SOURCES})
-
- SET_TARGET_PROPERTIES(${TARGET_NAME} PROPERTIES
- LABELS "EXECUTABLE"
- OUTPUT_NAME ${TARGET_NAME}
- )
-
- TARGET_COMPILE_OPTIONS(${TARGET_NAME} PUBLIC ${helper_SOUND_CFLAGS})
- TARGET_LINK_LIBRARIES(${TARGET_NAME}
- ${helper_RTLSDR_LIBRARIES} ${helper_LIBUSB_LIBRARIES} ${helper_SOUND_LIBRARIES} ${link_libraries} m)
diff --git a/binding/convenience/convenience.c b/binding/convenience/convenience.c
deleted file mode 100644
index ae1e24b..0000000
--- a/binding/convenience/convenience.c
+++ /dev/null
@@ -1,309 +0,0 @@
-/*
- * Copyright (C) 2014 by Kyle Keen <keenerd@gmail.com>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/* a collection of user friendly tools
- * todo: use strtol for more flexible int parsing
- * */
-
-#include <string.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-#ifndef _WIN32
-#include <unistd.h>
-#else
-#include <windows.h>
-#include <fcntl.h>
-#include <io.h>
-#define _USE_MATH_DEFINES
-#endif
-
-#include <math.h>
-
-#include "rtl-sdr.h"
-
-double atofs(char *s)
-/* standard suffixes */
-{
- char last;
- size_t len;
- double suff = 1.0;
- len = strlen(s);
- last = s[len-1];
- s[len-1] = '\0';
- switch (last) {
- case 'g':
- case 'G':
- suff *= 1e3;
- /*@fallthrough@*/
- case 'm':
- case 'M':
- suff *= 1e3;
- /*@fallthrough@*/
- case 'k':
- case 'K':
- suff *= 1e3;
- suff *= atof(s);
- s[len-1] = last;
- return suff;
- }
- s[len-1] = last;
- return atof(s);
-}
-
-double atoft(char *s)
-/* time suffixes, returns seconds */
-{
- char last;
- size_t len;
- double suff = 1.0;
- len = strlen(s);
- last = s[len-1];
- s[len-1] = '\0';
- switch (last) {
- case 'h':
- case 'H':
- suff *= 60;
- /*@fallthrough@*/
- case 'm':
- case 'M':
- suff *= 60;
- /*@fallthrough@*/
- case 's':
- case 'S':
- suff *= atof(s);
- s[len-1] = last;
- return suff;
- }
- s[len-1] = last;
- return atof(s);
-}
-
-double atofp(char *s)
-/* percent suffixes */
-{
- char last;
- size_t len;
- double suff = 1.0;
- len = strlen(s);
- last = s[len-1];
- s[len-1] = '\0';
- switch (last) {
- case '%':
- suff *= 0.01;
- suff *= atof(s);
- s[len-1] = last;
- return suff;
- }
- s[len-1] = last;
- return atof(s);
-}
-
-int nearest_gain(rtlsdr_dev_t *dev, int target_gain)
-{
- int i, r, err1, err2, count, nearest;
- int* gains;
- r = rtlsdr_set_tuner_gain_mode(dev, 1);
- if (r < 0) {
- fprintf(stderr, "WARNING: Failed to enable manual gain.\n");
- return r;
- }
- count = rtlsdr_get_tuner_gains(dev, NULL);
- if (count <= 0) {
- return 0;
- }
- gains = malloc(sizeof(int) * count);
- count = rtlsdr_get_tuner_gains(dev, gains);
- nearest = gains[0];
- for (i=0; i<count; i++) {
- err1 = abs(target_gain - nearest);
- err2 = abs(target_gain - gains[i]);
- if (err2 < err1) {
- nearest = gains[i];
- }
- }
- free(gains);
- return nearest;
-}
-
-int verbose_set_frequency(rtlsdr_dev_t *dev, uint32_t frequency)
-{
- int r;
- r = rtlsdr_set_center_freq(dev, frequency);
- if (r < 0) {
- fprintf(stderr, "WARNING: Failed to set center freq.\n");
- } else {
- fprintf(stderr, "Tuned to %u Hz.\n", frequency);
- }
- return r;
-}
-
-int verbose_set_sample_rate(rtlsdr_dev_t *dev, uint32_t samp_rate)
-{
- int r;
- r = rtlsdr_set_sample_rate(dev, samp_rate);
- if (r < 0) {
- fprintf(stderr, "WARNING: Failed to set sample rate.\n");
- } else {
- fprintf(stderr, "Sampling at %u S/s.\n", samp_rate);
- }
- return r;
-}
-
-int verbose_direct_sampling(rtlsdr_dev_t *dev, int on)
-{
- int r;
- r = rtlsdr_set_direct_sampling(dev, on);
- if (r != 0) {
- fprintf(stderr, "WARNING: Failed to set direct sampling mode.\n");
- return r;
- }
- if (on == 0) {
- fprintf(stderr, "Direct sampling mode disabled.\n");}
- if (on == 1) {
- fprintf(stderr, "Enabled direct sampling mode, input 1/I.\n");}
- if (on == 2) {
- fprintf(stderr, "Enabled direct sampling mode, input 2/Q.\n");}
- return r;
-}
-
-int verbose_offset_tuning(rtlsdr_dev_t *dev)
-{
- int r;
- r = rtlsdr_set_offset_tuning(dev, 1);
- if (r != 0) {
- fprintf(stderr, "WARNING: Failed to set offset tuning.\n");
- } else {
- fprintf(stderr, "Offset tuning mode enabled.\n");
- }
- return r;
-}
-
-int verbose_auto_gain(rtlsdr_dev_t *dev)
-{
- int r;
- r = rtlsdr_set_tuner_gain_mode(dev, 0);
- if (r != 0) {
- fprintf(stderr, "WARNING: Failed to set tuner gain.\n");
- } else {
- fprintf(stderr, "Tuner gain set to automatic.\n");
- }
- return r;
-}
-
-int verbose_gain_set(rtlsdr_dev_t *dev, int gain)
-{
- int r;
- r = rtlsdr_set_tuner_gain_mode(dev, 1);
- if (r < 0) {
- fprintf(stderr, "WARNING: Failed to enable manual gain.\n");
- return r;
- }
- r = rtlsdr_set_tuner_gain(dev, gain);
- if (r != 0) {
- fprintf(stderr, "WARNING: Failed to set tuner gain.\n");
- } else {
- fprintf(stderr, "Tuner gain set to %0.2f dB.\n", gain/10.0);
- }
- return r;
-}
-
-int verbose_ppm_set(rtlsdr_dev_t *dev, int ppm_error)
-{
- int r;
- if (ppm_error == 0) {
- return 0;}
- r = rtlsdr_set_freq_correction(dev, ppm_error);
- if (r < 0) {
- fprintf(stderr, "WARNING: Failed to set ppm error.\n");
- } else {
- fprintf(stderr, "Tuner error set to %i ppm.\n", ppm_error);
- }
- return r;
-}
-
-int verbose_reset_buffer(rtlsdr_dev_t *dev)
-{
- int r;
- r = rtlsdr_reset_buffer(dev);
- if (r < 0) {
- fprintf(stderr, "WARNING: Failed to reset buffers.\n");}
- return r;
-}
-
-int verbose_device_search(char *s)
-{
- int i, device_count, device;
- ssize_t offset;
- char *s2;
- char vendor[256], product[256], serial[256];
- device_count = rtlsdr_get_device_count();
- if (!device_count) {
- fprintf(stderr, "No supported devices found.\n");
- return -1;
- }
- fprintf(stderr, "Found %d device(s):\n", device_count);
- for (i = 0; i < device_count; i++) {
- rtlsdr_get_device_usb_strings(i, vendor, product, serial);
- fprintf(stderr, " %d: %s, %s, SN: %s\n", i, vendor, product, serial);
- }
- fprintf(stderr, "\n");
- /* does string look like raw id number */
- device = (int)strtol(s, &s2, 0);
- if (s2[0] == '\0' && device >= 0 && device < device_count) {
- fprintf(stderr, "Using device %d: %s\n",
- device, rtlsdr_get_device_name((uint32_t)device));
- return device;
- }
- /* does string exact match a serial */
- for (i = 0; i < device_count; i++) {
- rtlsdr_get_device_usb_strings(i, vendor, product, serial);
- if (strcmp(s, serial) != 0) {
- continue;}
- device = i;
- fprintf(stderr, "Using device %d: %s\n",
- device, rtlsdr_get_device_name((uint32_t)device));
- return device;
- }
- /* does string prefix match a serial */
- for (i = 0; i < device_count; i++) {
- rtlsdr_get_device_usb_strings(i, vendor, product, serial);
- if (strncmp(s, serial, strlen(s)) != 0) {
- continue;}
- device = i;
- fprintf(stderr, "Using device %d: %s\n",
- device, rtlsdr_get_device_name((uint32_t)device));
- return device;
- }
- /* does string suffix match a serial */
- for (i = 0; i < device_count; i++) {
- rtlsdr_get_device_usb_strings(i, vendor, product, serial);
- offset = strlen(serial) - strlen(s);
- if (offset < 0) {
- continue;}
- if (strncmp(s, serial+offset, strlen(s)) != 0) {
- continue;}
- device = i;
- fprintf(stderr, "Using device %d: %s\n",
- device, rtlsdr_get_device_name((uint32_t)device));
- return device;
- }
- fprintf(stderr, "No matching devices found.\n");
- return -1;
-}
-
-// vim: tabstop=8:softtabstop=8:shiftwidth=8:noexpandtab
diff --git a/binding/convenience/convenience.h b/binding/convenience/convenience.h
deleted file mode 100644
index 1faa2af..0000000
--- a/binding/convenience/convenience.h
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * Copyright (C) 2014 by Kyle Keen <keenerd@gmail.com>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/* a collection of user friendly tools */
-
-/*!
- * Convert standard suffixes (k, M, G) to double
- *
- * \param s a string to be parsed
- * \return double
- */
-
-double atofs(char *s);
-
-/*!
- * Convert time suffixes (s, m, h) to double
- *
- * \param s a string to be parsed
- * \return seconds as double
- */
-
-double atoft(char *s);
-
-/*!
- * Convert percent suffixe (%) to double
- *
- * \param s a string to be parsed
- * \return double
- */
-
-double atofp(char *s);
-
-/*!
- * Find nearest supported gain
- *
- * \param dev the device handle given by rtlsdr_open()
- * \param target_gain in tenths of a dB
- * \return 0 on success
- */
-
-int nearest_gain(rtlsdr_dev_t *dev, int target_gain);
-
-/*!
- * Set device frequency and report status on stderr
- *
- * \param dev the device handle given by rtlsdr_open()
- * \param frequency in Hz
- * \return 0 on success
- */
-
-int verbose_set_frequency(rtlsdr_dev_t *dev, uint32_t frequency);
-
-/*!
- * Set device sample rate and report status on stderr
- *
- * \param dev the device handle given by rtlsdr_open()
- * \param samp_rate in samples/second
- * \return 0 on success
- */
-
-int verbose_set_sample_rate(rtlsdr_dev_t *dev, uint32_t samp_rate);
-
-/*!
- * Enable or disable the direct sampling mode and report status on stderr
- *
- * \param dev the device handle given by rtlsdr_open()
- * \param on 0 means disabled, 1 I-ADC input enabled, 2 Q-ADC input enabled
- * \return 0 on success
- */
-
-int verbose_direct_sampling(rtlsdr_dev_t *dev, int on);
-
-/*!
- * Enable offset tuning and report status on stderr
- *
- * \param dev the device handle given by rtlsdr_open()
- * \return 0 on success
- */
-
-int verbose_offset_tuning(rtlsdr_dev_t *dev);
-
-/*!
- * Enable auto gain and report status on stderr
- *
- * \param dev the device handle given by rtlsdr_open()
- * \return 0 on success
- */
-
-int verbose_auto_gain(rtlsdr_dev_t *dev);
-
-/*!
- * Set tuner gain and report status on stderr
- *
- * \param dev the device handle given by rtlsdr_open()
- * \param gain in tenths of a dB
- * \return 0 on success
- */
-
-int verbose_gain_set(rtlsdr_dev_t *dev, int gain);
-
-/*!
- * Set the frequency correction value for the device and report status on stderr.
- *
- * \param dev the device handle given by rtlsdr_open()
- * \param ppm_error correction value in parts per million (ppm)
- * \return 0 on success
- */
-
-int verbose_ppm_set(rtlsdr_dev_t *dev, int ppm_error);
-
-/*!
- * Reset buffer
- *
- * \param dev the device handle given by rtlsdr_open()
- * \return 0 on success
- */
-
-int verbose_reset_buffer(rtlsdr_dev_t *dev);
-
-/*!
- * Find the closest matching device.
- *
- * \param s a string to be parsed
- * \return dev_index int, -1 on error
- */
-
-int verbose_device_search(char *s);
-
diff --git a/binding/radio-binding.c b/binding/radio-binding.c
deleted file mode 100644
index 8b5559c..0000000
--- a/binding/radio-binding.c
+++ /dev/null
@@ -1,752 +0,0 @@
-/*
- * Copyright (C) 2017, 2019 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.
- */
-
-#define _GNU_SOURCE
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdint.h>
-#include <stdbool.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <json-c/json.h>
-#include <afb/afb-binding.h>
-
-#include "radio_impl.h"
-#include "radio_impl_null.h"
-#include "radio_impl_rtlsdr.h"
-#include "radio_impl_kingfisher.h"
-#include "radio_impl_tef665x.h"
-
-static radio_impl_ops_t *radio_impl_ops;
-
-static afb_event_t freq_event;
-static afb_event_t scan_event;
-static afb_event_t status_event;
-static afb_event_t rds_event;
-
-static bool playing;
-
-static const char *signalcomposer_events[] = {
- "event.media.next",
- "event.media.previous",
- "event.media.mode",
- NULL,
-};
-
-static void freq_callback(uint32_t frequency, void *data)
-{
- json_object *jresp = json_object_new_object();
- json_object *value = json_object_new_int((int) frequency);
-
- json_object_object_add(jresp, "value", value);
- afb_event_push(freq_event, json_object_get(jresp));
-}
-
-static void scan_callback(uint32_t frequency, void *data)
-{
- json_object *jresp = json_object_new_object();
- json_object *value = json_object_new_int((int) frequency);
-
- json_object_object_add(jresp, "value", value);
- afb_event_push(scan_event, json_object_get(jresp));
-}
-
-static void rds_callback(void *rds_data)
-{
- //rds_data is a json object
- afb_event_push(rds_event, json_object_get(rds_data));
-}
-
-/*
- * Binding verb handlers
- */
-
-/*
- * @brief Get (and optionally set) frequency
- *
- * @param afb_req_t : an afb request structure
- *
- */
-static void frequency(afb_req_t request)
-{
- json_object *ret_json;
- const char *value = afb_req_value(request, "value");
- uint32_t frequency;
-
- if(value) {
- char *p;
- radio_band_t band;
- uint32_t min_frequency;
- uint32_t max_frequency;
- uint32_t step;
-
- frequency = (uint32_t) strtoul(value, &p, 10);
- if(frequency && *p == '\0') {
- band = radio_impl_ops->get_band();
- min_frequency = radio_impl_ops->get_min_frequency(band);
- max_frequency = radio_impl_ops->get_max_frequency(band);
- step = radio_impl_ops->get_frequency_step(band);
- if(frequency < min_frequency ||
- frequency > max_frequency ||
- (frequency - min_frequency) % step) {
- afb_req_reply(request, NULL, "failed", "Invalid frequency");
- return;
- }
- radio_impl_ops->set_frequency(frequency);
- } else {
- afb_req_reply(request, NULL, "failed", "Invalid frequency");
- return;
- }
- }
- ret_json = json_object_new_object();
- frequency = radio_impl_ops->get_frequency();
- json_object_object_add(ret_json, "frequency", json_object_new_int((int32_t) frequency));
- afb_req_reply(request, ret_json, NULL, NULL);
-}
-
-/*
- * @brief Get RDS information
- *
- * @param afb_req_t : an afb request structure
- *
- */
-static void rds(afb_req_t request)
-{
- json_object *ret_json;
- char * rds;
-
- if (radio_impl_ops->get_rds_info == NULL) {
- afb_req_reply(request, NULL, "failed", "not supported");
- return;
- }
-
- ret_json = json_object_new_object();
- rds = radio_impl_ops->get_rds_info();
- json_object_object_add(ret_json, "rds", json_object_new_string(rds?rds:""));
- free(rds);
-
- afb_req_reply(request, ret_json, NULL, NULL);
-}
-
-/* @brief Get quality information
- *
- * @param afb_req_t : an afb request structure
- *
- */
-static void quality(afb_req_t request)
-{
- json_object *ret_json;
- station_quality_t *quality_data;
-
- if (radio_impl_ops->get_quality_info == NULL) {
- afb_req_reply(request, NULL, "failed", "Not supported");
- return;
- }
-
- quality_data = radio_impl_ops->get_quality_info();
- ret_json=json_object_new_object();
- if(quality_data->af_update)
- {
- json_object_object_add(ret_json, "af_update", json_object_new_int((int) quality_data->af_update));
- }
- if(quality_data->time_stamp){
- json_object_object_add(ret_json, "timestamp", json_object_new_int((int) quality_data->time_stamp));
- }
- if(quality_data->rssi)
- {
- json_object_object_add(ret_json, "rssi", json_object_new_int((int) quality_data->rssi));
- }
- if(quality_data->usn)
- {
- json_object_object_add(ret_json, "usn", json_object_new_int((int) quality_data->usn));
- }
- if(quality_data->bandw)
- {
- json_object_object_add(ret_json, "bandwidth", json_object_new_int((int) quality_data->bandw));
- }
- afb_req_reply(request, ret_json, NULL, NULL);
- return;
-}
-
-/* @brief Check alternative frequency
- *
- * @param afb_req_t : an afb request structure
- *
- */
-static void alternative_frequency(afb_req_t request)
-{
- json_object *ret_json;
- uint32_t alternative;
- const char *value;
-
- if (radio_impl_ops->set_alternative_frequency == NULL) {
- afb_req_reply(request, NULL, "failed", "Not supported");
- return;
- }
-
- value = afb_req_value(request, "value");
- if(value) {
- char *p;
- radio_band_t band;
- uint32_t min_frequency;
- uint32_t max_frequency;
- uint32_t step;
-
- alternative = (uint32_t) strtoul(value, &p, 10);
- if(alternative && *p == '\0') {
- band = radio_impl_ops->get_band();
- min_frequency = radio_impl_ops->get_min_frequency(band);
- max_frequency = radio_impl_ops->get_max_frequency(band);
- step = radio_impl_ops->get_frequency_step(band);
- if(alternative < min_frequency ||
- alternative > max_frequency ||
- (alternative - min_frequency) % step) {
- afb_req_reply(request, NULL, "failed", "Invalid alternative frequency");
- return;
- }
- radio_impl_ops->set_alternative_frequency(alternative);
- ret_json = json_object_new_object();
- json_object_object_add(ret_json, "alternative", json_object_new_int((int32_t) alternative));
- afb_req_reply(request, ret_json, NULL, NULL);
- } else {
- afb_req_reply(request, NULL, "failed", "Invalid alternative frequency");
- return;
- }
- }
- else {
- afb_req_reply(request, NULL, "failed", "Invalid alternative frequency");
- return;
- }
-}
-
-/*
- * @brief Get (and optionally set) frequency band
- *
- * @param afb_req_t : an afb request structure
- *
- */
-static void band(afb_req_t request)
-{
- json_object *ret_json;
- const char *value = afb_req_value(request, "value");
- int valid = 0;
- radio_band_t band;
- char band_name[4];
-
- if(value) {
- if(!strcasecmp(value, "AM")) {
- band = BAND_AM;
- valid = 1;
- } else if(!strcasecmp(value, "FM")) {
- band = BAND_FM;
- valid = 1;
- } else {
- char *p;
- band = strtoul(value, &p, 10);
- if(p != value && *p == '\0') {
- switch(band) {
- case BAND_AM:
- case BAND_FM:
- valid = 1;
- break;
- default:
- break;
- }
- }
- }
- if(valid) {
- radio_impl_ops->set_band(band);
- } else {
- afb_req_reply(request, NULL, "failed", "Invalid band");
- return;
- }
- }
- ret_json = json_object_new_object();
- band = radio_impl_ops->get_band();
- sprintf(band_name, "%s", band == BAND_AM ? "AM" : "FM");
- json_object_object_add(ret_json, "band", json_object_new_string(band_name));
- afb_req_reply(request, ret_json, NULL, NULL);
-}
-
-/*
- * @brief Check if band is supported
- *
- * @param afb_req_t : an afb request structure
- *
- */
-static void band_supported(afb_req_t request)
-{
- json_object *ret_json;
- const char *value = afb_req_value(request, "band");
- int valid = 0;
- radio_band_t band;
-
- if(value) {
- if(!strcasecmp(value, "AM")) {
- band = BAND_AM;
- valid = 1;
- } else if(!strcasecmp(value, "FM")) {
- band = BAND_FM;
- valid = 1;
- } else {
- char *p;
- band = strtoul(value, &p, 10);
- if(p != value && *p == '\0') {
- switch(band) {
- case BAND_AM:
- case BAND_FM:
- valid = 1;
- break;
- default:
- break;
- }
- }
- }
- }
- if(!valid) {
- afb_req_reply(request, NULL, "failed", "Invalid band");
- return;
- }
- ret_json = json_object_new_object();
- json_object_object_add(ret_json,
- "supported",
- json_object_new_int(radio_impl_ops->band_supported(band)));
- afb_req_reply(request, ret_json, NULL, NULL);
-}
-
-/*
- * @brief Get frequency range for a band
- *
- * @param afb_req_t : an afb request structure
- *
- */
-static void frequency_range(afb_req_t request)
-{
- json_object *ret_json;
- const char *value = afb_req_value(request, "band");
- int valid = 0;
- radio_band_t band;
- uint32_t min_frequency;
- uint32_t max_frequency;
-
- if(value) {
- if(!strcasecmp(value, "AM")) {
- band = BAND_AM;
- valid = 1;
- } else if(!strcasecmp(value, "FM")) {
- band = BAND_FM;
- valid = 1;
- } else {
- char *p;
- band = strtoul(value, &p, 10);
- if(p != value && *p == '\0') {
- switch(band) {
- case BAND_AM:
- case BAND_FM:
- valid = 1;
- break;
- default:
- break;
- }
- }
- }
- }
- if(!valid) {
- afb_req_reply(request, NULL, "failed", "Invalid band");
- return;
- }
- ret_json = json_object_new_object();
- min_frequency = radio_impl_ops->get_min_frequency(band);
- max_frequency = radio_impl_ops->get_max_frequency(band);
- json_object_object_add(ret_json, "min", json_object_new_int((int32_t) min_frequency));
- json_object_object_add(ret_json, "max", json_object_new_int((int32_t) max_frequency));
- afb_req_reply(request, ret_json, NULL, NULL);
-}
-
-/*
- * @brief Get frequency step size (Hz) for a band
- *
- * @param afb_req_t : an afb request structure
- *
- */
-static void frequency_step(afb_req_t request)
-{
- json_object *ret_json;
- const char *value = afb_req_value(request, "band");
- int valid = 0;
- radio_band_t band;
- uint32_t step;
-
- if(value) {
- if(!strcasecmp(value, "AM")) {
- band = BAND_AM;
- valid = 1;
- } else if(!strcasecmp(value, "FM")) {
- band = BAND_FM;
- valid = 1;
- } else {
- char *p;
- band = strtoul(value, &p, 10);
- if(p != value && *p == '\0') {
- switch(band) {
- case BAND_AM:
- case BAND_FM:
- valid = 1;
- break;
- default:
- break;
- }
- }
- }
- }
- if(!valid) {
- afb_req_reply(request, NULL, "failed", "Invalid band");
- return;
- }
- ret_json = json_object_new_object();
- step = radio_impl_ops->get_frequency_step(band);
- json_object_object_add(ret_json, "step", json_object_new_int((int32_t) step));
- afb_req_reply(request, ret_json, NULL, NULL);
-}
-
-/*
- * @brief Start radio playback
- *
- * @param afb_req_t : an afb request structure
- *
- */
-static void start(afb_req_t request)
-{
- radio_impl_ops->set_output(NULL);
- radio_impl_ops->start();
- playing = true;
- afb_req_reply(request, NULL, NULL, NULL);
-
- json_object *jresp = json_object_new_object();
- json_object *value = json_object_new_string("playing");
- json_object_object_add(jresp, "value", value);
- afb_event_push(status_event, json_object_get(jresp));
-}
-
-/*
- * @brief Stop radio playback
- *
- * @param afb_req_t : an afb request structure
- *
- */
-static void stop(afb_req_t request)
-{
- radio_impl_ops->stop();
- playing = false;
- afb_req_reply(request, NULL, NULL, NULL);
-
- json_object *jresp = json_object_new_object();
- json_object *value = json_object_new_string("stopped");
- json_object_object_add(jresp, "value", value);
- afb_event_push(status_event, json_object_get(jresp));
-}
-
-/*
- * @brief Scan for a station in the specified direction
- *
- * @param afb_req_t : an afb request structure
- *
- */
-static void scan_start(afb_req_t request)
-{
- const char *value = afb_req_value(request, "direction");
- int valid = 0;
- radio_scan_direction_t direction;
-
- if(value) {
- if(!strcasecmp(value, "forward")) {
- direction = SCAN_FORWARD;
- valid = 1;
- } else if(!strcasecmp(value, "backward")) {
- direction = SCAN_BACKWARD;
- valid = 1;
- } else {
- char *p;
- direction = strtoul(value, &p, 10);
- if(p != value && *p == '\0') {
- switch(direction) {
- case SCAN_FORWARD:
- case SCAN_BACKWARD:
- valid = 1;
- break;
- default:
- break;
- }
- }
- }
- }
- if(!valid) {
- afb_req_reply(request, NULL, "failed", "Invalid direction");
- return;
- }
- radio_impl_ops->scan_start(direction, scan_callback, NULL);
- afb_req_reply(request, NULL, NULL, NULL);
-}
-
-/*
- * @brief Stop station scan
- *
- * @param afb_req_t : an afb request structure
- *
- */
-static void scan_stop(afb_req_t request)
-{
- radio_impl_ops->scan_stop();
- afb_req_reply(request, NULL, NULL, NULL);
-}
-
-/*
- * @brief Get (and optionally set) stereo mode
- *
- * @param afb_req_t : an afb request structure
- *
- */
-static void stereo_mode(afb_req_t request)
-{
- json_object *ret_json;
- const char *value = afb_req_value(request, "value");
- int valid = 0;
- radio_stereo_mode_t mode;
-
- if(value) {
- if(!strcasecmp(value, "mono")) {
- mode = MONO;
- valid = 1;
- } else if(!strcasecmp(value, "stereo")) {
- mode = STEREO;
- valid = 1;
- } else {
- char *p;
- mode = strtoul(value, &p, 10);
- if(p != value && *p == '\0') {
- switch(mode) {
- case MONO:
- case STEREO:
- valid = 1;
- break;
- default:
- break;
- }
- }
- }
- if(valid) {
- radio_impl_ops->set_stereo_mode(mode);
- } else {
- afb_req_reply(request, NULL, "failed", "Invalid mode");
- return;
- }
- }
- ret_json = json_object_new_object();
- mode = radio_impl_ops->get_stereo_mode();
-
- json_object_object_add(ret_json, "mode", json_object_new_string(mode == MONO ? "mono" : "stereo"));
- afb_req_reply(request, ret_json, NULL, NULL);
-}
-
-/*
- * @brief Subscribe for an event
- *
- * @param afb_req_t : an afb request structure
- *
- */
-static void subscribe(afb_req_t request)
-{
- const char *value = afb_req_value(request, "value");
- if(value) {
- if(!strcasecmp(value, "frequency")) {
- afb_req_subscribe(request, freq_event);
- } else if(!strcasecmp(value, "station_found")) {
- afb_req_subscribe(request, scan_event);
- } else if(!strcasecmp(value, "status")) {
- afb_req_subscribe(request, status_event);
- } else if(!strcasecmp(value, "rds")) {
- afb_req_subscribe(request, rds_event);
- }
- else {
- afb_req_reply(request, NULL, "failed", "Invalid event");
- return;
- }
- }
- afb_req_reply(request, NULL, NULL, NULL);
-}
-
-/*
- * @brief Unsubscribe for an event
- *
- * @param afb_req_t : an afb request structure
- *
- */
-static void unsubscribe(afb_req_t request)
-{
- const char *value = afb_req_value(request, "value");
- if(value) {
- if(!strcasecmp(value, "frequency")) {
- afb_req_unsubscribe(request, freq_event);
- } else if(!strcasecmp(value, "station_found")) {
- afb_req_unsubscribe(request, scan_event);
- } else if(!strcasecmp(value, "status")) {
- afb_req_unsubscribe(request, status_event);
-
- } else if(!strcasecmp(value, "rds")) {
- afb_req_unsubscribe(request, rds_event);
-
- } else {
- afb_req_reply(request, NULL, "failed", "Invalid event");
- return;
- }
- }
- afb_req_reply(request, NULL, NULL, NULL);
-}
-
-static const afb_verb_t verbs[]= {
- { .verb = "frequency", .session = AFB_SESSION_NONE, .callback = frequency, .info = "Get/Set frequency" },
- { .verb = "band", .session = AFB_SESSION_NONE, .callback = band, .info = "Get/Set band" },
- { .verb = "rds", .session = AFB_SESSION_NONE, .callback = rds, .info = "Get RDS information" },
- { .verb = "quality", .session = AFB_SESSION_NONE, .callback = quality, .info = "Get station quality information" },
- { .verb = "alternative_frequency", .session = AFB_SESSION_NONE, .callback = alternative_frequency, .info = "Check an alternative frequency" },
- { .verb = "band_supported", .session = AFB_SESSION_NONE, .callback = band_supported, .info = "Check band support" },
- { .verb = "frequency_range", .session = AFB_SESSION_NONE, .callback = frequency_range, .info = "Get frequency range" },
- { .verb = "frequency_step", .session = AFB_SESSION_NONE, .callback = frequency_step, .info = "Get frequency step" },
- { .verb = "start", .session = AFB_SESSION_NONE, .callback = start, .info = "Start radio playback" },
- { .verb = "stop", .session = AFB_SESSION_NONE, .callback = stop, .info = "Stop radio playback" },
- { .verb = "scan_start", .session = AFB_SESSION_NONE, .callback = scan_start, .info = "Start station scan" },
- { .verb = "scan_stop", .session = AFB_SESSION_NONE, .callback = scan_stop, .info = "Stop station scan" },
- { .verb = "stereo_mode", .session = AFB_SESSION_NONE, .callback = stereo_mode, .info = "Get/Set stereo_mode" },
- { .verb = "subscribe", .session = AFB_SESSION_NONE, .callback = subscribe, .info = "Subscribe for an event" },
- { .verb = "unsubscribe", .session = AFB_SESSION_NONE, .callback = unsubscribe, .info = "Unsubscribe for an event" },
- { }
-};
-
-static void onevent(afb_api_t api, const char *event, struct json_object *object)
-{
- json_object *tmp = NULL;
- const char *uid;
- const char *value;
-
- json_object_object_get_ex(object, "uid", &tmp);
- if (tmp == NULL)
- return;
-
- uid = json_object_get_string(tmp);
- if (strncmp(uid, "event.media.", 12))
- return;
-
- if (!playing ||
- (radio_impl_ops->get_corking_state &&
- radio_impl_ops->get_corking_state())) {
- return;
- }
-
- json_object_object_get_ex(object, "value", &tmp);
- if (tmp == NULL)
- return;
-
- value = json_object_get_string(tmp);
- if (strncmp(value, "true", 4))
- return;
-
- if (!strcmp(uid, "event.media.next")) {
- radio_impl_ops->scan_start(SCAN_FORWARD, scan_callback, NULL);
- } else if (!strcmp(uid, "event.media.previous")) {
- radio_impl_ops->scan_start(SCAN_BACKWARD, scan_callback, NULL);
- } else if (!strcmp(uid, "event.media.mode")) {
- // Do nothing ATM
- } else {
- AFB_WARNING("Unhandled signal-composer uid '%s'", uid);
- }
-}
-
-static int init(afb_api_t api)
-{
- // Probe for radio backends
- radio_impl_ops = &rtlsdr_impl_ops;
- int rc = radio_impl_ops->probe();
- if(rc != 0) {
- // Look for Kingfisher Si4689
- radio_impl_ops = &kf_impl_ops;
- rc = radio_impl_ops->probe();
- }
- if(rc != 0) {
- radio_impl_ops = &tef665x_impl_ops;
- rc = radio_impl_ops->probe();
- }
- if (rc != 0) {
- radio_impl_ops = &null_impl_ops;
- rc = radio_impl_ops->probe();
- }
- if (rc != 0) {
- // We don't expect the null implementation to fail probe, but just in case...
- AFB_API_ERROR(afbBindingV3root, "No radio device found, exiting");
- return rc;
- }
- // Try to initialize detected backend
- rc = radio_impl_ops->init();
- if(rc < 0) {
- AFB_API_ERROR(afbBindingV3root,
- "%s initialization failed\n",
- radio_impl_ops->name);
- return rc;
- }
- AFB_API_NOTICE(afbBindingV3root, "%s found\n", radio_impl_ops->name);
- radio_impl_ops->set_frequency_callback(freq_callback, NULL);
- radio_impl_ops->set_frequency_callback(freq_callback, NULL);
- if(radio_impl_ops->set_rds_callback) {
- radio_impl_ops->set_rds_callback(rds_callback);
- }
-
- rc = afb_daemon_require_api("signal-composer", 1);
- if (rc) {
- AFB_WARNING("unable to initialize signal-composer binding");
- } else {
- const char **tmp = signalcomposer_events;
- json_object *args = json_object_new_object();
- json_object *signals = json_object_new_array();
-
- while (*tmp) {
- json_object_array_add(signals, json_object_new_string(*tmp++));
- }
- json_object_object_add(args, "signal", signals);
- if(json_object_array_length(signals)) {
- afb_api_call_sync(api, "signal-composer", "subscribe",
- args, NULL, NULL, NULL);
- } else {
- json_object_put(args);
- }
- }
-
- // Initialize event structures
- freq_event = afb_daemon_make_event("frequency");
- scan_event = afb_daemon_make_event("station_found");
- status_event = afb_daemon_make_event("status");
- rds_event = afb_daemon_make_event("rds");
- return 0;
-}
-
-const afb_binding_t afbBindingExport = {
- .info = "radio service",
- .api = "radio",
- .specification = "Radio API",
- .verbs = verbs,
- .onevent = onevent,
- .init = init,
-};
diff --git a/binding/radio_impl.h b/binding/radio_impl.h
deleted file mode 100644
index 3e549ac..0000000
--- a/binding/radio_impl.h
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * Copyright (C) 2017 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.
- */
-
-#ifndef _RADIO_IMPL_H
-#define _RADIO_IMPL_H
-
-#include <stdint.h>
-
-typedef enum {
- BAND_AM = 0,
- BAND_FM
-} radio_band_t;
-
-typedef enum {
- SCAN_FORWARD = 0,
- SCAN_BACKWARD
-} radio_scan_direction_t;
-
-typedef void (*radio_scan_callback_t)(uint32_t frequency, void *data);
-
-typedef void (*radio_freq_callback_t)(uint32_t frequency, void *data);
-
-typedef void (*radio_rds_callback_t)(void *rds_data);
-
-typedef enum {
- MONO = 0,
- STEREO
-} radio_stereo_mode_t;
-
-/*
- * AF_update
- * true if quality belongs to an alternative frequency
- *
- * time_stamp
- * if time_stamp is zero, quality data won't be valid
- * reliability depending on time stamp
- * it takes some time after tuning to get valid quality data
- *
- * rssi
- * (signed)
- * level detector result(RF input level)
- *
- * usn
- * FM ultrasonic noise detector (relative usn detector result)
- *
- * bandwidth
- * IF bandwidth
- */
-typedef struct
-{
- bool af_update;
- uint16_t time_stamp;
- int16_t rssi;
- uint16_t usn;
- uint16_t bandw;
-} station_quality_t;
-
-typedef struct {
- char *name;
-
- int (*probe)(void);
-
- /* NOTE: init should return -1 if called before probe has been called and returned success */
- int (*init)(void);
-
- void (*set_output)(const char *output);
-
- uint32_t (*get_frequency)(void);
-
- void (*set_frequency)(uint32_t frequency);
-
- void (*set_frequency_callback)(radio_freq_callback_t callback,
- void *data);
-
- void (*set_rds_callback)(radio_rds_callback_t callback);
-
- radio_band_t (*get_band)(void);
-
- void (*set_band)(radio_band_t band);
-
- int (*band_supported)(radio_band_t band);
-
- uint32_t (*get_min_frequency)(radio_band_t band);
-
- uint32_t (*get_max_frequency)(radio_band_t band);
-
- uint32_t (*get_frequency_step)(radio_band_t band);
-
- bool (*get_corking_state)(void);
-
- void (*start)(void);
-
- void (*stop)(void);
-
- void (*scan_start)(radio_scan_direction_t direction,
- radio_scan_callback_t callback,
- void *data);
-
- void (*scan_stop)(void);
-
- radio_stereo_mode_t (*get_stereo_mode)(void);
-
- void (*set_stereo_mode)(radio_stereo_mode_t mode);
-
- char * (*get_rds_info)(void);
-
- station_quality_t * (*get_quality_info)(void);
-
- void (*set_alternative_frequency)(uint32_t frequency);
-} radio_impl_ops_t;
-
-#endif /* _RADIO_IMPL_H */
diff --git a/binding/radio_impl_kingfisher.c b/binding/radio_impl_kingfisher.c
deleted file mode 100644
index e906140..0000000
--- a/binding/radio_impl_kingfisher.c
+++ /dev/null
@@ -1,526 +0,0 @@
-/*
- * Copyright (C) 2017-2019 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 <glib.h>
-#include <fcntl.h>
-#include <sys/stat.h>
-#include <json-c/json.h>
-#include <gst/gst.h>
-
-#include <afb/afb-binding.h>
-
-#include "radio_impl.h"
-
-#define SI_NODE "/sys/firmware/devicetree/base/si468x@0/compatible"
-#define SI_CTL "/usr/bin/si_ctl"
-#define SI_CTL_CMDLINE_MAXLEN 128
-#define SI_CTL_OUTPUT_MAXLEN 128
-
-#define GST_PIPELINE_LEN 256
-
-// Flag to enable using GST_STATE_READY instead of GST_STATE_PAUSED to trigger
-// Wireplumber policy mechanism. Hopefully temporary.
-#define WIREPLUMBER_WORKAROUND
-
-// 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 = 0;
-static bool corking;
-static bool present;
-static bool initialized;
-static uint32_t current_frequency;
-static int scan_valid_snr_threshold = 128;
-static int scan_valid_rssi_threshold = 128;
-static bool scanning;
-
-// stream state
-static GstElement *pipeline;
-static bool running;
-
-static void (*freq_callback)(uint32_t, void*);
-static void *freq_callback_data;
-
-static uint32_t kf_get_min_frequency(radio_band_t band);
-static void kf_scan_stop(void);
-
-static gboolean handle_message(GstBus *bus, GstMessage *msg, __attribute__((unused)) void *ptr)
-{
- GstState state;
-
- if (GST_MESSAGE_TYPE(msg) == GST_MESSAGE_REQUEST_STATE) {
- gst_message_parse_request_state(msg, &state);
-
- if (state == GST_STATE_PAUSED) {
- corking = true;
-
- // NOTE: Explicitly using PAUSED here, this case currently
- // is separate from the general PAUSED/READY issue wrt
- // Wireplumber policy.
- gst_element_set_state(pipeline, GST_STATE_PAUSED);
- } else if (state == GST_STATE_PLAYING) {
- corking = false;
-
- gst_element_set_state(pipeline, GST_STATE_PLAYING);
- }
- }
-
- return TRUE;
-}
-
-static void *gstreamer_loop_thread(void *ptr)
-{
- g_main_loop_run(g_main_loop_new(NULL, FALSE));
- return NULL;
-}
-
-static int kf_probe(void)
-{
- struct stat statbuf;
-
- if(present)
- return 0;
-
- // Check for Kingfisher SI468x devicetree node
- if(stat(SI_NODE, &statbuf) != 0)
- return -1;
-
- // Check for Cogent's si_ctl utility
- if(stat(SI_CTL, &statbuf) != 0)
- return -1;
-
- present = true;
- return 0;
-}
-
-static int kf_init(void)
-{
- GKeyFile* conf_file;
- bool conf_file_present = false;
- char *value_str;
- char cmd[SI_CTL_CMDLINE_MAXLEN];
- int rc;
- char gst_pipeline_str[GST_PIPELINE_LEN];
- pthread_t thread_id;
-
- 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) {
- conf_file_present = 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;
- }
- }
- }
- }
-
- if(conf_file_present) {
- GError *error = NULL;
- int n;
-
- // Allow over-riding scanning parameters just in case a demo
- // setup needs to do so to work reliably.
- n = g_key_file_get_integer(conf_file,
- "radio",
- "scan_valid_snr_threshold",
- &error);
- if(!error) {
- AFB_API_INFO(afbBindingV3root, "Scan valid SNR level set to %d", n);
- scan_valid_snr_threshold = n;
- }
-
- error = NULL;
- n = g_key_file_get_integer(conf_file,
- "radio",
- "scan_valid_rssi_threshold",
- &error);
- if(!error) {
- AFB_API_INFO(afbBindingV3root, "Scan valid SNR level set to %d", n);
- scan_valid_rssi_threshold = n;
- }
-
- g_key_file_free(conf_file);
- }
-
- AFB_API_INFO(afbBindingV3root, "Using FM Bandplan: %s", known_fm_band_plans[bandplan].name);
- current_frequency = kf_get_min_frequency(BAND_FM);
- snprintf(cmd,
- sizeof(cmd),
- "%s /dev/i2c-12 0x65 -b fm -p %s -t %d -u %d -c %d",
- SI_CTL,
- known_fm_band_plans[bandplan].name,
- scan_valid_snr_threshold,
- scan_valid_rssi_threshold,
- current_frequency / 1000);
- rc = system(cmd);
- if(rc != 0) {
- AFB_API_ERROR(afbBindingV3root, "%s failed, rc = %d", SI_CTL, rc);
- return -1;
- }
-
- // Initialize GStreamer
- gst_init(NULL, NULL);
-
- // Use PipeWire output
- rc = snprintf(gst_pipeline_str,
- GST_PIPELINE_LEN,
- "pipewiresrc stream-properties=\"p,node.target=alsa:pcm:radio:0:capture\" ! "
- "audio/x-raw,format=F32LE,channels=2 ! "
- "pipewiresink stream-properties=\"p,media.role=Multimedia\"");
- if(rc >= GST_PIPELINE_LEN) {
- AFB_API_ERROR(afbBindingV3root, "pipeline string too long");
- return -1;
- }
- pipeline = gst_parse_launch(gst_pipeline_str, NULL);
- if(!pipeline) {
- AFB_API_ERROR(afbBindingV3root, "pipeline construction failed!");
- return -1;
- }
-
- // Start pipeline in paused state
-#ifdef WIREPLUMBER_WORKAROUND
- gst_element_set_state(pipeline, GST_STATE_READY);
-#else
- gst_element_set_state(pipeline, GST_STATE_PAUSED);
-#endif
-
- gst_bus_add_watch(gst_element_get_bus(pipeline), (GstBusFunc) handle_message, NULL);
-
- rc = pthread_create(&thread_id, NULL, gstreamer_loop_thread, NULL);
- if(rc != 0)
- return rc;
-
- initialized = true;
- return 0;
-}
-
-static void kf_set_output(const char *output)
-{
-}
-
-static uint32_t kf_get_frequency(void)
-{
- return current_frequency;
-}
-
-static void kf_set_frequency(uint32_t frequency)
-{
- char cmd[SI_CTL_CMDLINE_MAXLEN];
- int rc;
-
- if(!initialized)
- return;
-
- if(scanning)
- return;
-
- if(frequency < known_fm_band_plans[bandplan].min ||
- frequency > known_fm_band_plans[bandplan].max)
- return;
-
- kf_scan_stop();
- snprintf(cmd, sizeof(cmd), "%s /dev/i2c-12 0x65 -c %d", SI_CTL, frequency / 1000);
- rc = system(cmd);
- if(rc == 0)
- current_frequency = frequency;
-
- if(freq_callback)
- freq_callback(current_frequency, freq_callback_data);
-}
-
-static void kf_set_frequency_callback(radio_freq_callback_t callback,
- void *data)
-{
- freq_callback = callback;
- freq_callback_data = data;
-}
-
-static char * kf_get_rds_info(void) {
- char cmd[SI_CTL_CMDLINE_MAXLEN];
- char line[SI_CTL_OUTPUT_MAXLEN];
- char * rds = NULL;
- FILE *fp;
-
- if (scanning)
- goto done;
-
- snprintf(cmd, sizeof(cmd), "%s /dev/i2c-12 0x65 -m", SI_CTL);
- fp = popen(cmd, "r");
- if(fp == NULL) {
- fprintf(stderr, "Could not run: %s!\n", cmd);
- goto done;
- }
- /* Look for "Name:" in output */
- while (fgets(line, sizeof(line), fp) != NULL) {
-
- char* nS = strstr(line, "Name:");
- char * end;
- if (!nS)
- continue;
-
- end = nS+strlen("Name:");
- /* remove the trailing '\n' */
- end[strlen(end)-1] = '\0';
-
- rds = strdup(end);
- break;
- }
-
- /* Make sure si_ctl has finished */
- pclose(fp);
-
-done:
- return rds;
-}
-
-static radio_band_t kf_get_band(void)
-{
- return BAND_FM;
-}
-
-static void kf_set_band(radio_band_t band)
-{
- // We only support FM, so do nothing
-}
-
-static int kf_band_supported(radio_band_t band)
-{
- if(band == BAND_FM)
- return 1;
- return 0;
-}
-
-static uint32_t kf_get_min_frequency(radio_band_t band)
-{
- return known_fm_band_plans[bandplan].min;
-}
-
-static uint32_t kf_get_max_frequency(radio_band_t band)
-{
- return known_fm_band_plans[bandplan].max;
-}
-
-static uint32_t kf_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 bool kf_get_corking_state(void)
-{
- return corking;
-}
-
-static void kf_start(void)
-{
- if(!initialized)
- return;
-
- if(!running || corking) {
- // Start pipeline
- gst_element_set_state(pipeline, GST_STATE_PLAYING);
- running = true;
- corking = false;
- }
-}
-
-static void kf_stop(void)
-{
- GstEvent *event;
-
- if(initialized && running) {
- // Stop pipeline
- running = false;
-
-#ifdef WIREPLUMBER_WORKAROUND
- // NOTE: Using NULL here instead of READY, as it seems to trigger
- // some odd behavior in the pipeline; alsasrc does not seem to
- // stop, and things get hung up on restart as there are a bunch
- // of "old" samples that seemingly confuse pipewiresink. Going
- // to NULL state seems to tear down things enough to avoid
- // whatever happens.
- gst_element_set_state(pipeline, GST_STATE_NULL);
-#else
- gst_element_set_state(pipeline, GST_STATE_PAUSED);
-#endif
- corking = false;
-
-#ifndef WIREPLUMBER_WORKAROUND
- // Flush pipeline
- // This seems required to avoid stutters on starts after a stop
- event = gst_event_new_flush_start();
- gst_element_send_event(GST_ELEMENT(pipeline), event);
- event = gst_event_new_flush_stop(TRUE);
- gst_element_send_event(GST_ELEMENT(pipeline), event);
-#endif
- }
-}
-
-static void kf_scan_start(radio_scan_direction_t direction,
- radio_scan_callback_t callback,
- void *data)
-{
- int rc;
- char cmd[SI_CTL_CMDLINE_MAXLEN];
- char line[SI_CTL_OUTPUT_MAXLEN];
- uint32_t new_frequency = 0;
- FILE *fp;
-
- if(!initialized)
- return;
-
- if(!running || scanning)
- return;
-
- scanning = true;
- snprintf(cmd,
- SI_CTL_CMDLINE_MAXLEN,
- "%s /dev/i2c-12 0x65 -l %s",
- SI_CTL, direction == SCAN_FORWARD ? "up" : "down");
- fp = popen(cmd, "r");
- if(fp == NULL) {
- AFB_API_ERROR(afbBindingV3root, "Could not run: %s!", cmd);
- return;
- }
- // Look for "Frequency:" in output
- while(fgets(line, SI_CTL_OUTPUT_MAXLEN, fp) != NULL) {
- if(strncmp("Frequency:", line, 10) == 0) {
- new_frequency = atoi(line + 10);
- //AFB_API_DEBUG(afbBindingV3root, "%s: got new_frequency = %d", __FUNCTION__, new_frequency);
- break;
- }
- }
-
- // Make sure si_ctl has finished
- rc = pclose(fp);
- if(rc != 0) {
- // Make sure we reset to original frequency, the Si4689 seems
- // to auto-mute sometimes on failed scans, this hopefully works
- // around that.
- new_frequency = 0;
- }
-
- if(new_frequency) {
- current_frequency = new_frequency * 1000;
-
- // Push up the new frequency
- // This is more efficient than calling kf_set_frequency and calling
- // out to si_ctl again.
- if(freq_callback)
- freq_callback(current_frequency, freq_callback_data);
- } else {
- // Assume no station found, go back to starting frequency
- kf_set_frequency(current_frequency);
- }
-
- // Push up scan state
- if(callback)
- callback(current_frequency, data);
-
- scanning = false;
-}
-
-static void kf_scan_stop(void)
-{
- // ATM, it's not straightforward to stop a scan since we're using the si_ctl utility...
-}
-
-static radio_stereo_mode_t kf_get_stereo_mode(void)
-{
- return STEREO;
-}
-
-static void kf_set_stereo_mode(radio_stereo_mode_t mode)
-{
- // We only support stereo, so do nothing
-}
-
-radio_impl_ops_t kf_impl_ops = {
- .name = "Kingfisher Si4689",
- .probe = kf_probe,
- .init = kf_init,
- .set_output = kf_set_output,
- .get_frequency = kf_get_frequency,
- .set_frequency = kf_set_frequency,
- .set_frequency_callback = kf_set_frequency_callback,
- .get_band = kf_get_band,
- .set_band = kf_set_band,
- .band_supported = kf_band_supported,
- .get_min_frequency = kf_get_min_frequency,
- .get_max_frequency = kf_get_max_frequency,
- .get_frequency_step = kf_get_frequency_step,
- .get_corking_state = kf_get_corking_state,
- .start = kf_start,
- .stop = kf_stop,
- .scan_start = kf_scan_start,
- .scan_stop = kf_scan_stop,
- .get_stereo_mode = kf_get_stereo_mode,
- .set_stereo_mode = kf_set_stereo_mode,
- .get_rds_info = kf_get_rds_info
-};
diff --git a/binding/radio_impl_kingfisher.h b/binding/radio_impl_kingfisher.h
deleted file mode 100644
index 5d4f064..0000000
--- a/binding/radio_impl_kingfisher.h
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright (C) 2017 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.
- */
-
-#ifndef _RADIO_IMPL_KINGFISHER_H
-#define _RADIO_IMPL_KINGFISHER_H
-
-#include "radio_impl.h"
-
-extern radio_impl_ops_t kf_impl_ops;
-
-#endif /* _RADIO_IMPL_KINGFISHER_H */
-
diff --git a/binding/radio_impl_null.c b/binding/radio_impl_null.c
deleted file mode 100644
index b66c025..0000000
--- a/binding/radio_impl_null.c
+++ /dev/null
@@ -1,281 +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.
- */
-
-/*
- * NOTE: Some locking around frequency and scanning state may be
- * required if this null implementation ever needs to be used
- * beyond basic functionality testing.
- */
-
-#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"
-
-// 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 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 null_get_min_frequency(radio_band_t band);
-static void null_set_frequency(uint32_t frequency);
-
-static int null_probe(void)
-{
- present = true;
- return 0;
-}
-
-static int null_init(void)
-{
- GKeyFile *conf_file;
- char *value_str;
- char *rootdir;
- char *helper_path;
-
- 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 = null_get_min_frequency(BAND_FM);
-
- initialized = true;
- null_set_frequency(current_frequency);
-
- return 0;
-}
-
-static void null_set_output(const char *output)
-{
-}
-
-static uint32_t null_get_frequency(void)
-{
- return current_frequency;
-}
-
-static void null_set_frequency(uint32_t frequency)
-{
- if(frequency < known_fm_band_plans[bandplan].min ||
- frequency > known_fm_band_plans[bandplan].max)
- return;
-
- current_frequency = frequency;
-
- if(freq_callback)
- freq_callback(current_frequency, freq_callback_data);
-}
-
-static void null_set_frequency_callback(radio_freq_callback_t callback,
- void *data)
-{
- freq_callback = callback;
- freq_callback_data = data;
-}
-
-static radio_band_t null_get_band(void)
-{
- // We only support FM
- return BAND_FM;
-}
-
-static void null_set_band(radio_band_t band)
-{
- // We only support FM, so do nothing
-}
-
-static int null_band_supported(radio_band_t band)
-{
- if(band == BAND_FM)
- return 1;
- return 0;
-}
-
-static uint32_t null_get_min_frequency(radio_band_t band)
-{
- return known_fm_band_plans[bandplan].min;
-}
-
-static uint32_t null_get_max_frequency(radio_band_t band)
-{
- return known_fm_band_plans[bandplan].max;
-}
-
-static uint32_t null_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 null_start(void)
-{
- if(!initialized)
- return;
-
- if(active)
- return;
-
- active = true;
-}
-
-static void null_stop(void)
-{
- if(!initialized)
- return;
-
- if (!active)
- return;
-
- active = false;
-}
-
-static void null_scan_start(radio_scan_direction_t direction,
- radio_scan_callback_t callback,
- void *data)
-{
- int frequency;
-
- if(!active || scanning)
- return;
-
- scanning = true;
-
- // Just go to the next frequency step up or down
- frequency = current_frequency;
- if(direction == SCAN_FORWARD) {
- frequency += known_fm_band_plans[bandplan].step;
- } else {
- frequency -= known_fm_band_plans[bandplan].step;
- }
- if(frequency < known_fm_band_plans[bandplan].min)
- frequency = known_fm_band_plans[bandplan].max;
- else if(frequency > known_fm_band_plans[bandplan].max)
- frequency = known_fm_band_plans[bandplan].min;
-
- scanning = false;
- null_set_frequency(frequency);
- if(callback)
- callback(frequency, data);
-}
-
-static void null_scan_stop(void)
-{
- scanning = false;
-}
-
-static radio_stereo_mode_t null_get_stereo_mode(void)
-{
- // We only support stereo
- return STEREO;
-}
-
-static void null_set_stereo_mode(radio_stereo_mode_t mode)
-{
- // We only support stereo, so do nothing
-}
-
-radio_impl_ops_t null_impl_ops = {
- .name = "null/mock radio",
- .probe = null_probe,
- .init = null_init,
- .set_output = null_set_output,
- .get_frequency = null_get_frequency,
- .set_frequency = null_set_frequency,
- .set_frequency_callback = null_set_frequency_callback,
- .get_band = null_get_band,
- .set_band = null_set_band,
- .band_supported = null_band_supported,
- .get_min_frequency = null_get_min_frequency,
- .get_max_frequency = null_get_max_frequency,
- .get_frequency_step = null_get_frequency_step,
- .start = null_start,
- .stop = null_stop,
- .scan_start = null_scan_start,
- .scan_stop = null_scan_stop,
- .get_stereo_mode = null_get_stereo_mode,
- .set_stereo_mode = null_set_stereo_mode
-};
diff --git a/binding/radio_impl_null.h b/binding/radio_impl_null.h
deleted file mode 100644
index 16bd5e6..0000000
--- a/binding/radio_impl_null.h
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright (C) 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.
- */
-
-#ifndef _RADIO_IMPL_NULL_H
-#define _RADIO_IMPL_NULL_H
-
-#include "radio_impl.h"
-
-extern radio_impl_ops_t null_impl_ops;
-
-#endif /* _RADIO_IMPL_NULL_H */
-
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
-};
diff --git a/binding/radio_impl_rtlsdr.h b/binding/radio_impl_rtlsdr.h
deleted file mode 100644
index 6c83338..0000000
--- a/binding/radio_impl_rtlsdr.h
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright (C) 2017 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.
- */
-
-#ifndef _RADIO_IMPL_RTLSDR_H
-#define _RADIO_IMPL_RTLSDR_H
-
-#include "radio_impl.h"
-
-extern radio_impl_ops_t rtlsdr_impl_ops;
-
-#endif /* _RADIO_IMPL_RTLSDR_H */
-
diff --git a/binding/radio_impl_tef665x.c b/binding/radio_impl_tef665x.c
deleted file mode 100644
index 3abcc00..0000000
--- a/binding/radio_impl_tef665x.c
+++ /dev/null
@@ -1,2405 +0,0 @@
-/*
- * 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.
- */
-/*
- TODO:
- at this point:
- - complete the set stereo_mode verb.
- - find a way to tell the service which i2c chanel is used.
- - separate the functions of driver from the verbs by creating new c file.
- - find a way of monitoring the quality of tuning and correct it time by time.
- - use Interupt for getting RDS data
-*/
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include <stdbool.h>
-#include <string.h>
-#include <unistd.h>
-#include <glib.h>
-#include <fcntl.h>
-#include <sys/stat.h>
-#include <sys/ioctl.h>
-#include <linux/i2c-dev.h>
-#include <linux/i2c.h>
-#include <stdarg.h>
-#include <error.h>
-#include <gst/gst.h>
-#include <time.h>
-//#include <json-c/json.h>
-//#include <gst/gst.h>
-
-#include <afb/afb-binding.h>
-
-#include <pthread.h>
-#include "radio_impl.h"
-#include "tef665x.h"
-
-
-#define I2C_ADDRESS 0x64
-#define I2C_DEV "/dev/i2c-3"
-#define VERSION "0.1"
-
-#define TEF665x_CMD_LEN_MAX 20
-#define SET_SUCCESS 1
-#define TEF665X_SPLIT_SIZE 24
-
-#define TEF665x_REF_CLK 9216000 //reference clock frequency
-#define TEF665x_IS_CRYSTAL_CLK 0 //crstal
-#define TEF665x_IS_EXT_CLK 1 //external clock input
-
-#define High_16bto8b(a) ((uint8_t)((a) >> 8))
-#define Low_16bto8b(a) ((uint8_t)(a))
-#define Convert8bto16b(a) ((uint16_t)(((uint16_t)(*(a))) << 8 |((uint16_t)(*(a+1)))))
-
-#define GST_PIPELINE_LEN 256
-
-const uint8_t tef665x_patch_cmdTab1[] = {3, 0x1c,0x00,0x00};
-const uint8_t tef665x_patch_cmdTab2[] = {3, 0x1c,0x00,0x74};
-const uint8_t tef665x_patch_cmdTab3[] = {3, 0x1c,0x00,0x75};
-
-
-typedef struct {
- char *name;
- uint32_t min;
- uint32_t max;
- uint32_t step;
-} band_plan_t;
-
-typedef struct{
- radio_scan_callback_t callback;
- radio_scan_direction_t direction;
- void* data;
-}scan_data_t;
-typedef struct rds_data
-{
- bool Text_Changed;
- bool TrafficAnnouncement;
- bool TrafficProgram;
- bool Music_Speech;
-
- uint32_t Alternative_Freq[25];
- uint8_t Alternative_Freq_Counter;
- uint8_t Num_AlterFreq;
-
- uint16_t PICode;
- uint8_t DI_Seg;
- uint8_t PTY_Code;
-
- uint8_t Year;
- uint8_t Month;
- uint8_t Day;
- uint8_t Hour;
- uint8_t Min;
-
- uint8_t PTYN_Size;
- uint8_t raw_data[12];
-
- char PS_Name[16];
- char RT[128];
- char PTYN[16];
-} rds_data_t;
-
-//thread for handling RDS and Mutex
-pthread_t rds_thread;
-rds_data_t RDS_Message;
-pthread_mutex_t RDS_Mutex;
-
-station_quality_t quality;
-
-//Threads for handling Scan
-pthread_t scan_thread;
-
-pthread_mutex_t scan_mutex;
-
-char _Temp[64]={0};
-
-static 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 band_plan_t known_am_band_plans[1] = {
- { .name = "W-ASIA", .min = 522000, .max = 1620000, .step = 9000 }
-};
-
-static unsigned int fm_bandplan = 2;
-static unsigned int am_bandplan = 0;
-static bool corking;
-static bool present;
-static bool initialized;
-static bool scanning;
-
-// stream state
-static GstElement *pipeline;
-static bool running;
-
-
-uint32_t AlterFreqOffset=0;
-
-static void (*freq_callback)(uint32_t, void*);
-static void (*rds_callback) (void*);
-static void *freq_callback_data;
-
-int tef665x_set_rds (uint32_t i2c_file_desc);
-#define DEBUG 0
-
-#if DEBUG == 1
-#define _debug(x, y) printf("function: %s, %s : %d\n", __FUNCTION__, #x, y)
-#else
-#define _debug(x, y)
-#endif
-
-static uint32_t file_desc;
-
-static radio_band_t current_band;
-static uint32_t current_am_frequency;
-static uint32_t current_fm_frequency;
-
-static void tef665x_scan_stop (void);
-static void tef665x_set_frequency (uint32_t);
-static void tef665x_search_frequency (uint32_t);
-
-static uint32_t tef665x_get_min_frequency (radio_band_t);
-static uint32_t tef665x_get_max_frequency (radio_band_t);
-static uint32_t tef665x_get_frequency_step (radio_band_t);
-
-static station_quality_t *tef665x_get_quality_info (void);
-
-static gboolean handle_message(GstBus *bus, GstMessage *msg, __attribute__((unused)) void *ptr)
-{
- GstState state;
-
- if (GST_MESSAGE_TYPE(msg) == GST_MESSAGE_REQUEST_STATE) {
-
- gst_message_parse_request_state(msg, &state);
-
- if (state == GST_STATE_PAUSED)
- corking = true;
- else if (state == GST_STATE_PLAYING)
- corking = false;
-
- }
-
- return TRUE;
-}
-
-static int tef665x_set_cmd(int i2c_file_desc, TEF665x_MODULE module, uint8_t cmd, int len, ...)
-{
- int i, ret;
- uint8_t buf[TEF665x_CMD_LEN_MAX];
- uint16_t temp;
- va_list vArgs;
-
- va_start(vArgs, len);
-
- buf[0] = module; //module, FM/AM/APP
- buf[1] = cmd; //cmd, 1,2,10,...
- buf[2] = 0x01; //index, always 1
-
- for(i = 3; i < len; i++)
- {
- temp = va_arg(vArgs,int);
-
- buf[i++] = High_16bto8b(temp);
- buf[i] = Low_16bto8b(temp);
- }
-
- va_end(vArgs);
-
- ret = write(i2c_file_desc, buf, len);
-
- temp = (ret == len) ? 1 : 0;
- _debug("return value", temp);
- return temp;
-}
-
-static int tef665x_get_cmd(int i2c_file_desc, TEF665x_MODULE module, uint8_t cmd, uint8_t *receive, int len)
-{
- uint8_t temp;
- uint8_t buf[3];
- int ret;
-
- buf[0]= module; //module, FM/AM/APP
- buf[1]= cmd; //cmd, 1,2,10,...
- buf[2]= 1; //index, always 1
-
- write(i2c_file_desc, buf, 3);
-
- ret = read(i2c_file_desc, receive, len);
- temp = (ret == len) ? 1 : 0;
- _debug("return value", temp);
- if(temp==0)
- AFB_ERROR("Error Number: %d: %s",errno,strerror(errno));
- return temp;
-}
-
-/*
-module 64 APPL
-cmd 128 Get_Operation_Status | status
-index
-1 status
- Device operation status
- 0 = boot state; no command support
- 1 = idle state
- 2 = active state; radio standby
- 3 = active state; FM
- 4 = active state; AM
-*/
-static int appl_get_operation_status(int i2c_file_desc ,uint8_t *status)
-{
- uint8_t buf[2];
- int ret;
-
- ret = tef665x_get_cmd(i2c_file_desc, TEF665X_MODULE_APPL,
- TEF665X_Cmd_Get_Operation_Status,
- buf, sizeof(buf));
-
- if(ret == SET_SUCCESS)
- {
- *status = Convert8bto16b(buf);
- _debug("return value", 1);
- return 1;
- }
- _debug("return value", 0);
- return 0;
-}
-
-static int get_operation_status(int i2c_file_desc, TEF665x_STATE *status)
-{
- TEF665x_STATE data;
- int ret;
- if(SET_SUCCESS ==(ret = appl_get_operation_status(i2c_file_desc, &data)))
- {
- //printk( "appl_get_operation_status1 data= %d \n",data);
- _debug("got status", ret);
- switch(data)
- {
- case 0:
- _debug("status: boot", ret);
- *status = eDevTEF665x_Boot_state;
- break;
- case 1:
- _debug("status: idle", ret);
- *status = eDevTEF665x_Idle_state;
- break;
- default:
- _debug("status: active", ret);
- *status = eDevTEF665x_Active_state;
- break;
- }
- }
- return ret;
-}
-
-static int tef665x_power_on(int i2c_file_desc)
-{
- int ret;
- TEF665x_STATE status;
- usleep(5000);
- if(SET_SUCCESS == (ret = get_operation_status(i2c_file_desc, &status))) //[ w 40 80 01 [ r 0000 ]
- {
- _debug("Powered ON", ret);
- }
- else
- {
- _debug("Powered ON FAILED!", ret);
- }
-
- return ret;
-}
-
-static int tef665x_writeTab(int i2c_file_desc,const uint8_t *tab)
-{
- int ret;
- ret = write(i2c_file_desc, tab + 1, tab[0]);
- return (ret != tab[0]) ? 0 : 1;
-}
-
-static int tef665x_patch_load(int i2c_file_desc, const uint8_t *bytes, uint16_t size)
-{
- uint8_t buf[25]; //the size which we break the data into, is 24 bytes.
- int ret, i;
-
- uint16_t num = size / 24;
- uint16_t rem = size % 24;
-
- buf[0] = 0x1b;
-
- usleep(10000);
-
- for(i = 0; i < num; i++)
- {
- memcpy(buf + 1, bytes + (24 * i), 24);
-
- ret = write(i2c_file_desc, buf, 25);
-
- if(ret != 25)
- {
- _debug("FAILED, send patch error! in pack no", i);
- return false;
- }
- usleep(50);
- }
-
- memcpy(buf + 1, bytes + (num * 24), rem);
-
- ret = write(i2c_file_desc, buf, rem);
- if(ret != rem)
- {
- _debug("FAILED, send patch error at the end!", 0);
- return false;
- }
- usleep(50);
-
- _debug("return value", 1);
- return true;
-}
-
-static int tef665x_patch_init(int i2c_file_desc)
-{
- int ret = 0;
- ret = tef665x_writeTab(i2c_file_desc, tef665x_patch_cmdTab1); //[ w 1C 0000 ]
- if(!ret)
- {
- _debug("1- tab1 load FAILED", ret);
- return ret;
- }
-
- ret = tef665x_writeTab(i2c_file_desc, tef665x_patch_cmdTab2); //[ w 1C 0074 ]
- if(!ret)
- {
- _debug("2- tab2 load FAILED", ret);
- return ret;
- }
-
- ret = tef665x_patch_load(i2c_file_desc, pPatchBytes, patchSize); //table1
- if(!ret)
- {
- _debug("3- pPatchBytes load FAILED", ret);
- return ret;
- }
-
- ret = tef665x_writeTab(i2c_file_desc, tef665x_patch_cmdTab1); //[ w 1C 0000 ]
- if(!ret)
- {
- _debug("4- tab1 load FAILED", ret);
- return ret;
- }
-
- ret = tef665x_writeTab(i2c_file_desc, tef665x_patch_cmdTab3); //[ w 1C 0075 ]
- if(!ret)
- {
- _debug("5- tab3 load FAILED", ret);
- return ret;
- }
-
- ret = tef665x_patch_load(i2c_file_desc, pLutBytes, lutSize); //table2
- if(!ret)
- {
- _debug("6- pLutBytes load FAILED", ret);
- return ret;
- }
-
- ret = tef665x_writeTab(i2c_file_desc, tef665x_patch_cmdTab1); //[ w 1C 0000 ]
- if(!ret)
- {
- _debug("7- tab1 load FAILED", ret);
- return ret;
- }
- _debug("patch loaded", ret);
- return ret;
-}
-
-//Command start will bring the device into? idle state�: [ w 14 0001 ]
-static int tef665x_start_cmd(int i2c_file_desc)
-{
-
- int ret;
- unsigned char buf[3];
-
- buf[0] = 0x14;
- buf[1] = 0;
- buf[2] = 1;
-
- ret = write(i2c_file_desc, buf, 3);
-
- if (ret != 3)
- {
- _debug("start cmd FAILED", 0);
- return 0;
- }
- _debug("return true", 1);
- return 1;
-}
-
-static int tef665x_boot_state(int i2c_file_desc)
-{
- int ret=0;
- if(1 == tef665x_patch_init(i2c_file_desc))
- {
- _debug("return true", 1);
- }
- else
- {
- _debug("return value", 0);
- return 0;
- }
-
- usleep(50000);
-
- if(1 == tef665x_start_cmd(i2c_file_desc))
- {
- _debug("'start cmd'return true", 1);
- }
- else
- {
- _debug("return value", 0);
- return 0;
- }
-
- usleep(50000);
-
- return ret;
-}
-
-/*
-module 64 APPL
-cmd 4 Set_ReferenceClock frequency
-
-index
-1 frequency_high
- [ 15:0 ]
- MSB part of the reference clock frequency
- [ 31:16 ]
-2 frequency_low
- [ 15:0 ]
- LSB part of the reference clock frequency
- [ 15:0 ]
- frequency [*1 Hz] (default = 9216000)
-3 type
- [ 15:0 ]
- clock type
- 0 = crystal oscillator operation (default)
- 1 = external clock input operation
-*/
-static int tef665x_appl_set_referenceClock(uint32_t i2c_file_desc, uint16_t frequency_high, uint16_t frequency_low, uint16_t type)
-{
- return tef665x_set_cmd(i2c_file_desc, TEF665X_MODULE_APPL,
- TEF665X_Cmd_Set_ReferenceClock,
- 9,
- frequency_high, frequency_low, type);
-}
-
-static int appl_set_referenceClock(uint32_t i2c_file_desc, uint32_t frequency, bool is_ext_clk) //0x3d 0x900
-{
- return tef665x_appl_set_referenceClock(i2c_file_desc,(uint16_t)(frequency >> 16), (uint16_t)frequency, is_ext_clk);
-}
-
-/*
-module 64 APPL
-cmd 5 Activate mode
-
-index
-1 mode
- [ 15:0 ]
- 1 = goto �active� state with operation mode of �radio standby�
-*/
-static int tef665x_appl_activate(uint32_t i2c_file_desc ,uint16_t mode)
-{
- return tef665x_set_cmd(i2c_file_desc, TEF665X_MODULE_APPL,
- TEF665X_Cmd_Activate,
- 5,
- mode);
-}
-
-static int appl_activate(uint32_t i2c_file_desc)
-{
- return tef665x_appl_activate(i2c_file_desc, 1);
-}
-/*
-module 48 AUDIO
-cmd 22 set_dig_io signal, format, operation, samplerate
-
-index
-1 signal
-[ 15:0 ]
- digital audio input / output
- 32 = I²S digital audio IIS_SD_0 (input)
- 33 = I²S digital audio IIS_SD_1 (output)
-(2) mode
- 0 = off (default)
- 1 = input (only available for signal = 32)
- 2 = output (only available for signal = 33)
-(3) format
- [ 15:0 ]
- digital audio format select
- 16 = I²S 16 bits (fIIS_BCK = 32 * samplerate)
- 32 = I²S 32 bits (fIIS_BCK = 64 * samplerate) (default)
- 272 = lsb aligned 16 bit (fIIS_BCK = 64 * samplerate)
- 274 = lsb aligned 18 bit (fIIS_BCK = 64 * samplerate)
- 276 = lsb aligned 20 bit (fIIS_BCK = 64 * samplerate)
- 280 = lsb aligned 24 bit (fIIS_BCK = 64 * samplerate)
-(4) operation
- [ 15:0 ]
- operation mode
- 0 = slave mode; IIS_BCK and IIS_WS input defined by source (default)
- 256 = master mode; IIS_BCK and IIS_WS output defined by device
-(5) samplerate
- [ 15:0 ] 3200 = 32.0 kHz
- 4410 = 44.1 kHz (default)
- 4800 = 48.0 kHz
-*/
-static int tef665x_audio_set_dig_io(uint8_t i2c_file_desc, uint16_t signal, uint16_t mode, uint16_t format, uint16_t operation, uint16_t samplerate)
-{
- int ret = tef665x_set_cmd(i2c_file_desc, TEF665X_MODULE_AUDIO,
- TEF665X_Cmd_Set_Dig_IO,
- 13,
- signal, mode, format, operation, samplerate);
- if(ret)
- {
- _debug("Digital In/Out is set ", signal);
- }
- else
- {
- _debug("FAILED, return", 0);
- return 0;
- }
- return 1;
-}
-
-/*
-module 32 / 33 FM / AM
-cmd 85 Set_Specials ana_out, dig_out
-
-index
-1 signal
- [ 15:0 ]
- analog audio output
- 128 = DAC L/R output
-2 mode
- [ 15:0 ]
- output mode
- 0 = off (power down)
- 1 = output enabled (default)
-*/
-
-static int tef665x_audio_set_ana_out(uint32_t i2c_file_desc, uint16_t signal,uint16_t mode)
-{
- int ret = tef665x_set_cmd(i2c_file_desc, TEF665X_MODULE_AUDIO,
- TEF665X_Cmd_Set_Ana_Out,
- 7,
- signal, mode);
- if(ret)
- {
- _debug("analog output is set to ", mode);
- }
- else
- {
- _debug("FAILED, return", 0);
- return 0;
- }
- return 1;
-
-}
-
-/*
-module 48 AUDIO
-cmd 13 Set_Output_Source
-
-index
-1 signal
- [ 15:0 ]
- audio output
- 33 = I2S Digital audio
- 128 = DAC L/R output (default)
-2 source
- [ 15:0 ]
- source
- 4 = analog radio
- 32 = i2s digital audio input
- 224 = audio processor (default)
- 240 = sin wave generator
-*/
-static int tef665x_set_output_src(uint32_t i2c_file_desc, uint8_t signal, uint8_t src)
-{
- int ret = tef665x_set_cmd(i2c_file_desc, TEF665X_MODULE_AUDIO,
- TEF665X_Cmd_Set_Output_Source,
- 7,
- signal, src);
- if(ret)
- {
- _debug("Output is set ", signal);
- }
- else
- {
- _debug("FAILED, return", 0);
- return 0;
- }
- return 1;
-}
-
-static int tef665x_idle_state(int i2c_file_desc)
-{
- TEF665x_STATE status;
-
- //mdelay(50);
-
- if(SET_SUCCESS == get_operation_status(i2c_file_desc, &status))
- {
- _debug("got operation status", 1);
- if(status != eDevTEF665x_Boot_state)
- {
- _debug("not in boot status", 1);
-
- if(SET_SUCCESS == appl_set_referenceClock(i2c_file_desc, TEF665x_REF_CLK, TEF665x_IS_CRYSTAL_CLK)) //TEF665x_IS_EXT_CLK
- {
- _debug("set the clock", TEF665x_REF_CLK);
- if(SET_SUCCESS == appl_activate(i2c_file_desc))// APPL_Activate mode = 1.[ w 40 05 01 0001 ]
- {
- //usleep(100000); //Wait 100 ms
- _debug("activate succeed", 1);
- return 1;
- }
- else
- {
- _debug("activate FAILED", 1);
- }
- }
- else
- {
- _debug("set the clock FAILED", TEF665x_REF_CLK);
- }
-
- }
- else
- {
- _debug("did not get operation status", 0);
- }
-
- }
- _debug("return value", 0);
- return 0;
-}
-
-static int tef665x_para_load(uint32_t i2c_file_desc)
-{
- int i;
- int r;
- const uint8_t *p = init_para;
-
- for(i = 0; i < sizeof(init_para); i += (p[i]+1))
- {
- if(SET_SUCCESS != (r = tef665x_writeTab(i2c_file_desc, p + i)))
- {
- break;
- }
- }
-
- //Initiate RDS
- tef665x_set_rds(i2c_file_desc);
-
- _debug("return value", r);
- return r;
-}
-
-/*
-module 32 / 33 FM / AM
-cmd 1 Tune_To mode, frequency
-
-index
-1 mode
- [ 15:0 ]
- tuning actions
- 0 = no action (radio mode does not change as function of module band)
- 1 = Preset Tune to new program with short mute time
- 2 = Search Tune to new program and stay muted
- FM 3 = AF-Update Tune to alternative frequency, store quality
- and tune back with inaudible mute
- 4 = Jump Tune to alternative frequency with short
- inaudible mute
- 5 = Check Tune to alternative frequency and stay
- muted
- AM 3 � 5 = reserved
- 6 = reserved
- 7 = End Release the mute of a Search or Check action
- (frequency is not required and ignored)
-2 frequency
-[ 15:0 ]
- tuning frequency
- FM 6500 � 10800 65.00 � 108.00 MHz / 10 kHz step size
- AM LW 144 � 288 144 � 288 kHz / 1 kHz step size
- MW 522 � 1710 522 � 1710 kHz / 1 kHz step size
- SW 2300 � 27000 2.3 � 27 MHz / 1 kHz step size
-*/
-static int tef665x_radio_tune_to (uint32_t i2c_file_desc, bool fm, uint16_t mode,uint16_t frequency )
-{
- return tef665x_set_cmd(i2c_file_desc, fm ? TEF665X_MODULE_FM: TEF665X_MODULE_AM,
- TEF665X_Cmd_Tune_To,
- ( mode <= 5 ) ? 7 : 5,
- mode, frequency);
-}
-
-static int FM_tune_to(uint32_t i2c_file_desc, AR_TuningAction_t mode, uint16_t frequency)
-{
- int ret = tef665x_radio_tune_to(i2c_file_desc, 1, (uint16_t)mode, frequency);
- _debug("return value", ret);
- return ret;
-}
-
-static int AM_tune_to(uint32_t i2c_file_desc, AR_TuningAction_t mode,uint16_t frequency)
-{
- int ret = tef665x_radio_tune_to(i2c_file_desc, 0, (uint16_t)mode, frequency);
- _debug("return value", ret);
- return ret;
-}
-
-/*
-module 48 AUDIO
-cmd 11 Set_Mute mode
-
-index
-1 mode
- [ 15:0 ]
- audio mute
- 0 = mute disabled
- 1 = mute active (default)
-*/
-int tef665x_audio_set_mute(uint32_t i2c_file_desc, uint16_t mode)
-{
- int ret = tef665x_set_cmd(i2c_file_desc, TEF665X_MODULE_AUDIO,
- TEF665X_Cmd_Set_Mute,
- 5,
- mode);
- if(ret)
- {
- _debug("mute state changed , mode", mode);
- }
- else
- {
- _debug("FAILED, return", 0);
- return 0;
- }
- return 1;
-}
-
-/*
-module 48 AUDIO
-cmd 10 Set_Volume volume
-
-index
-1 volume
- [ 15:0 ] (signed)
- audio volume
- -599 � +240 = -60 � +24 dB volume
- 0 = 0 dB (default)f665x_patch_init function: "3"t,int16_t volume)
-*/
-static int tef665x_audio_set_volume(uint32_t i2c_file_desc, uint16_t volume)
-{
- return tef665x_set_cmd(i2c_file_desc, TEF665X_MODULE_AUDIO,
- TEF665X_Cmd_Set_Volume,
- 5,
- volume*10);
-}
-/*
-module 64 APPL
-cmd 130 Get_Identification
-index
-1 device
-2 hw_version
-3 sw_version
-*/
-int appl_get_identification(int i2c_file_desc)
-{
- uint8_t buf[6];
- int ret;
-
- ret = tef665x_get_cmd(i2c_file_desc, TEF665X_MODULE_APPL,
- TEF665X_Cmd_Get_Identification,
- buf, sizeof(buf));
-// should be completed for further use
-// extracting chip versions ...
- if(ret == SET_SUCCESS)
- {
- for(int i = 0; i<6;i++)
- printf("buf[%i] = %x\n", i, buf[i]);
- return 1;
- }
- _debug("return value", 0);
- return 0;
-}
-
-
-//mute=1, unmute=0
-int audio_set_mute(uint32_t i2c_file_desc, bool mute)
-{
- return tef665x_audio_set_mute(i2c_file_desc, mute);//AUDIO_Set_Mute mode = 0 : disable mute
-}
-
-//-60 � +24 dB volume
-int audio_set_volume(uint32_t i2c_file_desc, int vol)
-{
- return tef665x_audio_set_volume(i2c_file_desc, (uint16_t)vol);
-}
-
-/*
-module 64 APPL
-cmd 1 Set_OperationMode mode
-
-index
-1 mode
- [ 15:0 ]
- device operation mode
- 0 = normal operation
- 1 = radio standby mode (low-power mode without radio functionality)
- (default)
-*/
-
-static int tef665x_audio_set_operationMode(uint32_t i2c_file_desc, uint16_t mode)
-{
- _debug("normal: 0 standby: 1 requested", 1);
- int ret = tef665x_set_cmd(i2c_file_desc, TEF665X_MODULE_APPL,
- TEF665X_Cmd_Set_OperationMode,
- 5,
- mode);
- if(ret)
- {
- _debug("was able to set the mode", ret);
- }
- else
- {
- _debug("FAILED, return", 0);
- return 0;
- }
- return 1;
-}
-
-
-
-//TRUE = ON;
-//FALSE = OFF
-static void radio_powerSwitch(uint32_t i2c_file_desc, bool OnOff)
-{
- tef665x_audio_set_operationMode(i2c_file_desc, OnOff? 0 : 1);//standby mode = 1
-}
-
-static void radio_modeSwitch(uint32_t i2c_file_desc, bool mode_switch, AR_TuningAction_t mode, uint16_t frequency)
-{
-
- if(mode_switch) //FM
- {
- FM_tune_to(i2c_file_desc, mode, frequency);
- }
- else //AM
- {
- AM_tune_to(i2c_file_desc, mode, frequency);
- }
-}
-
-/*
-module 32 FM
-cmd 81 Set_RDS
-
-index
-1 mode
- [ 15:0 ]
- RDS operation mode
- 0 = OFF
- 1 = decoder mode (default), output of RDS groupe data (Block A, B, C, D)
- from get_rds_status, get_rds_data FM cmd 130/131
-
-2 restart
- [ 15:0 ]
- RDS decoder restart
- 0 = no control
- 1 = manual restart, starlooking for new RDS data immidiately
- 2 = automatic restart after tuning (default)
- 3 = flush, empty RDS output buffer.
-
-3 interface
- [ 15:0 ]
- 0 = no pin interface.
- 2 = data available status output; active low (GPIO feature 'DAVN')
- 4 = legecy 2-wire demodulator data and clock output ('RDDA' and 'RDCL')
-*/
-int tef665x_set_rds(uint32_t i2c_file_desc)
-{
- return tef665x_set_cmd(i2c_file_desc, TEF665X_MODULE_FM,
- TEF665X_Cmd_Set_RDS,
- 9,//Total Bytes to be sent
- TEF665X_Cmd_Set_RDS_mode, // default
- TEF665X_Cmd_Set_RDS_autorestart, // restart after tune
- 0x002 // no interface
- );
-}
-
-
-/*
- * @brief Adding Alternative Frequencies to RDS Data Structure
- *
- * @param uint8_t* : raw data of alternative frequency (Group 0A of RDS)
- * @param rds_data_t* : Pointer to RDS Data Structure
- * @return void
- */
-void Extract_Alt_Freqs(uint8_t* buf,rds_data_t *Rds_STU)
-{
- for(int Buffer_Index=6;Buffer_Index<8;Buffer_Index++)
- {
- if(buf[Buffer_Index]>204){
- if(250>buf[Buffer_Index]&&buf[Buffer_Index]>224)
- {
- Rds_STU->Num_AlterFreq=buf[Buffer_Index]-224;
-
- if(Rds_STU->Alternative_Freq_Counter == Rds_STU->Num_AlterFreq)
- {
- Rds_STU->Alternative_Freq_Counter = 0;
- }
- AlterFreqOffset=87500000;
- }
- else if(buf[Buffer_Index]==205)
- {
- AFB_ERROR("Filler Code");
- }
- else if(buf[Buffer_Index]==224)
- {
- AFB_ERROR("No AF Exists");
- }
- else if(buf[Buffer_Index]==250)
- {
- AFB_ERROR("An LF/MF Frequency Follows");
- AlterFreqOffset=144000;
- }
- else if(buf[Buffer_Index]>250)
- {
- AFB_WARNING("Alternative Frequency Not Assigned");
- }
- }
- else if(buf[Buffer_Index]>0)
- {
- if(AlterFreqOffset == 87500000)
- {
- Rds_STU->Alternative_Freq[Rds_STU->Alternative_Freq_Counter]=
- buf[Buffer_Index] * 100000 + AlterFreqOffset;
-
- Rds_STU->Alternative_Freq_Counter++;
-
- if(Rds_STU->Alternative_Freq_Counter == Rds_STU->Num_AlterFreq)
- {
- Rds_STU->Alternative_Freq_Counter = 0;
- }
- }
- else if(AlterFreqOffset == 144000)
- {
- Rds_STU->Alternative_Freq[Rds_STU->Alternative_Freq_Counter]=
- ((uint32_t)buf[Buffer_Index]) * 9000 + AlterFreqOffset;
-
- Rds_STU->Alternative_Freq_Counter++;
-
- if(Rds_STU->Alternative_Freq_Counter == Rds_STU->Num_AlterFreq)
- {
- Rds_STU->Alternative_Freq_Counter = 0;
- }
- }
- else
- {
- AFB_WARNING("Alternative Frequency is not defined");
- }
- }
- else
- {
- AFB_ERROR("Alternative Frequency- Not to be used");
- }
- }
-}
-
-/*
- * @brief Checking rds error code (determined by decoder)
- *
- * 0 : no error; block data was received with matching data and syndrome
- * 1 : small error; possible 1 bit reception error detected; data is corrected
- * 2 : large error; theoretical correctable error detected; data is corrected
- * 3 : uncorrectable error; no data correction possible
- *
- * @param Errors : Error Code of blocks A,B,C and D of RDS
- * @return void
- */
-void Check_RDS_Error(uint8_t Errors[])
-{
- for (int i=0;i<4;i++){
- if(Errors[i]==1){
- AFB_WARNING("RDS Block %d Reception Error; small error; possible 1 bit reception error detected; data is corrected",i+1);
- }
- else if(Errors[i]==2){
- AFB_WARNING("RDS Block %d Reception Error; large error; theoretical correctable error detected; data is corrected",i+1);
- }
- else if(Errors[i]==3){
- AFB_ERROR("RDS Block %d Reception Error; uncorrectable error; no data correction possible",i+1);
- }
- }
-}
-
-/*
- * @brief Getting rds_data_t and Process its raw_data
- *
- * @param rds_data_t * : Pointer to latest RDS Data Structure
- */
-void *Process_RDS_Words(void* rds_words){
- pthread_detach(pthread_self());
-
- rds_data_t *Rds_STU = rds_words;
- uint8_t *raw_data = Rds_STU->raw_data;
- int8_t group_Ver = -1;
- uint8_t GType0 = 0;
- bool DI_Seg = 0;
- bool M_S = 0;
- bool TA = 0;
-
- //Parse 1st Section
- bool DataAvailable = (raw_data[0] >> 7) & 1;
- bool DataLoss = (raw_data[0] >> 6) & 1 == 1;
- bool DataAvailType = (raw_data[0] >> 5) & 1 == 0;
- bool GroupType = (raw_data[0] >> 4) & 1;
- bool SyncStatus = (raw_data[0] >> 1) & 1;
-
- //Parse Last Section(Error Codes)
- uint8_t Error_A = raw_data[10] >> 6;
- uint8_t Error_B = raw_data[10] >> 4 & 3;
- uint8_t Error_C = raw_data[10] >> 2 & 3;
- uint8_t Error_D = raw_data[10] & 3;
- uint8_t Errors[]={Error_A,Error_B,Error_C,Error_D};
-
- //Inform user about Error Blocks Status Codes
- Check_RDS_Error(Errors);
-
- if(Error_A==0){
- //Bytes 2 and 3 are inside Block A
- //raw_data[2]and raw_data[3] Contains PI Code
- Rds_STU->PICode=Convert8bto16b(&raw_data[2]);
- }
- else{
- AFB_ERROR("Error_A=%d",Error_A);
- }
-
- bool GTypeVer=GType0;
- uint16_t GType=raw_data[4]>>4;
- //Bytes 4 and 5 are inside Block B
- if(Error_B==0){
- GTypeVer=raw_data[4]>>3 & 1;
- GType=raw_data[4]>>4;
- Rds_STU->TrafficProgram=raw_data[4]>>2&1;
- Rds_STU->PTY_Code= (raw_data[4] & 3) << 3 | raw_data[5] >> 5;
- }
-
- //Position Of Character
- uint8_t CharPos=0;
-
- //Extract Data based on Group Type values
- switch (GType)
- {
- case 0:
- {
- if(Error_B==0)
- {
- CharPos = raw_data[5] & 3;
-
- Rds_STU->TrafficAnnouncement = raw_data[5] >> 4 & 1;
- Rds_STU->Music_Speech = raw_data[5] >> 3 & 1;
- Rds_STU->DI_Seg = (raw_data[5] >> 2 & 1) * (2 ^ (3 - CharPos));
- }
-
- if(Error_C==0)
- {
- //Group Type 0A
- if (GType==0)
- {
- Extract_Alt_Freqs(raw_data,Rds_STU);
- }
-
- //Group Type 0B
- else
- {
- Rds_STU->PICode=Convert8bto16b(&raw_data[6]);
- }
- }
-
- if(Error_D == 0 && Error_B == 0)
- {
- if(raw_data[8] != 0x7f)
- {
- Rds_STU->PS_Name[CharPos*2] = raw_data[8];
- }
- else
- {
- Rds_STU->PS_Name[CharPos*2] = (char)'\0';
- }
- if(raw_data[9] != 0x7f)
- {
- Rds_STU->PS_Name[CharPos*2+1] = raw_data[9];
- }
- else
- {
- Rds_STU->PS_Name[CharPos*2+1] = (char)'\0';
- }
- }
- }
- break;
- case 1:
- {
- //Group Type 1A
- if(GTypeVer == 0)
- {
- if(Error_D == 0)
- {
- Rds_STU->Day = raw_data[8] >> 3;
- Rds_STU->Hour = raw_data[8] >> 3;
- Rds_STU->Min = ((raw_data[8] & 7) << 2) | (raw_data[9] >> 6) ;
- }
- }
- }
- break;
- case 2:
- {
- //Group Type 2A:
- if(GTypeVer == 0)
- {
- uint8_t Text_pos = raw_data[5] & 15;
-
- if(Error_B == 0 && Error_C == 0)
- {
-
- if(raw_data[6] !=0x7f && raw_data[6] != '\n')
- {
- Rds_STU->RT[Text_pos*4] = raw_data[6];
- }
- else{
- Rds_STU->RT[Text_pos*4] = (char)'\0';
- }
- if(raw_data[7]!=0x7f&&raw_data[7]!='\n')
- {
- Rds_STU->RT[Text_pos*4+1] = raw_data[7];
- }
- else
- {
- Rds_STU->RT[Text_pos*4+1] = (char)'\0';
- }
- }
- if(Error_B == 0 && Error_D == 0)
- {
- if(raw_data[8] != 0x7f && raw_data[8] != '\n')
- {
- Rds_STU->RT[Text_pos*4+2] = raw_data[8];
- }
- else{
- Rds_STU->RT[Text_pos*4+2] = (char)'\0';
- }
- if(raw_data[9] != 0x7f && raw_data[9] != '\n')
- {
- Rds_STU->RT[Text_pos*4+3] = raw_data[9];
- }
- else
- {
- Rds_STU->RT[Text_pos*4+3] = (char)'\0';
- }
- }
- }
-
- //Group Type 2B:
- else{
- if(Error_B==0 && Error_D==0)
- {
- //Clear All Radio Text if flag was changed
- if(raw_data[5] >> 4 & 1 != Rds_STU->Text_Changed)
- {
- memcpy(Rds_STU->RT, _Temp , 64);
- }
-
- uint8_t Text_pos = raw_data[5] & 15;
- if(raw_data[8] != 0x7f && raw_data[8] != '\n')
- {
-
- Rds_STU->RT[Text_pos*2] = raw_data[8];
- }
- else{
- Rds_STU->RT[Text_pos*2] = (char)'\0';
- }
- if(raw_data[9] != 0x7f && raw_data[9] != '\n')
- {
- Rds_STU->RT[Text_pos*2+1] = raw_data[9];
- }
- else
- {
- Rds_STU->RT[Text_pos*2+1] = (char)'\0';
- }
- }
- }
- }
- break;
- case 4:
- {
- //Group Type 4A
- if(GTypeVer == 0)
- {
- if(Error_B == 0 && Error_C == 0 && Error_D == 0)
- {
- //Following caclulations are based on RDS Standard
- uint32_t Modified_Julian_Day = ((raw_data[5] & 3) << 15) | (raw_data[6] << 7) | (raw_data[7]>>1);
- int y2 = (int)((((double)Modified_Julian_Day)-15078.2)/365.25);
- int m2 = (int)((((double)Modified_Julian_Day)-14956.1-((double)y2*365.25))/30.6001);
- int d2 = (double)Modified_Julian_Day-14956-(int)(y2*365.25)-(int)(m2*30.6001);
- int k = 0;
-
- if(m2 == 14 || m2 == 15)
- {
- k = 1;
- }
-
- Rds_STU->Day = d2;
- Rds_STU->Month = m2 - 1 + k * 12;
- Rds_STU->Year = y2 + k;
-
- uint8_t UTCHour = ((raw_data[7] & 1) << 4) | (raw_data[8] >> 4);
- uint8_t UTCMinute = ((raw_data[8] & 15) << 2) | (raw_data[9] >> 6);
-
- //Check Negative Offset
- bool NegOff = raw_data[9] & 32;
- uint8_t LocTimeOff = raw_data[9] & 31;
-
- if(!NegOff)
- {
- Rds_STU->Min = UTCMinute + LocTimeOff % 2;
- while(UTCMinute > 60)
- {
- UTCHour++;
- UTCMinute = UTCMinute - 60;
- }
-
- Rds_STU->Hour = UTCHour + LocTimeOff / 2;
- while(Rds_STU->Hour > 24){
- Rds_STU->Hour = Rds_STU->Hour - 24;
- }
-
-
- }
- else{
- Rds_STU->Min = UTCMinute + LocTimeOff % 2;
- while(UTCMinute < 0)
- {
- UTCHour--;
- UTCMinute = UTCMinute + 60;
- }
- Rds_STU->Hour = UTCHour + LocTimeOff / 2;
- while(Rds_STU->Hour<0)
- {
- Rds_STU->Hour = Rds_STU->Hour + 24;
-
- }
- }
- }
- }
- //Group Type 4B
- else
- {
- AFB_WARNING("Groupe Type 4B are not supported yet");
- }
- }
- case 8:
- {
- AFB_WARNING("Groupe Type 8A and 8B are not supported yet");
-
- }
- case 10:
- {
- AFB_WARNING("Groupe Type 10A and 10B are not supported yet");
- /*
- if(Error_B == 0){
- uint8_t pos = 0;
- pos=(raw_data[5] & 1) * 4;
-
- if(Error_C == 0){
- Rds_STU->PTYN[pos] = raw_data[6];
- Rds_STU->PTYN[pos+1] = raw_data[7];
- Rds_STU->PTYN_Size = pos + 2;
- }
- if(Error_D == 0){
- Rds_STU->PTYN[pos+2] = raw_data[8];
- Rds_STU->PTYN[pos+3] = raw_data[9];
- Rds_STU->PTYN_Size = pos + 4;
- }
- }
- /**/
- }
- break;
- default:
- AFB_ERROR("Unsupported Group %d",GType);
- break;
- }
-
- if(!DataAvailable)
- {
- AFB_ERROR("RDS Data is not available");
- }
-
- if(DataLoss)
- {
- AFB_ERROR("previous data was not read, replaced by newer data");
- }
-
- if(GroupType == 0)
- {
- group_Ver = 0;
- }
- else
- {
- group_Ver = 1;
- }
-
- if(!SyncStatus)
- {
- AFB_ERROR(" RDS decoder not synchronized; no RDS data found");
- }
-
- if(GroupType != GTypeVer)
- {
- AFB_ERROR("Version is not Correct?");
- }
-}
-
-/*
-module 32 FM
-cmd 131 get RDS data
-
-index
-1 status
- [ 15:0 ]
- FM RDS reception status.
- [15] = dta availableflag
- 0 = no data
- 1 = data available
- [14] = data loss flag
- 0 = no data loss
- 1 = previose data not read, replaced by newer data.
- [13] = data available type
- 0 = group data; continuos operation.
- 1 = first PI data;data with PI code following decoder sync.
- [12] = groupe type.
- 0 = type A; A-B-C-D group (with PI code in the block A)
- 1 = type B; A-B-C'-D group (with PI code in the block A and C')
- [ 8:0 ] reserved
-
-2 A_Block
- [ 15:0 ] = A block data
-
-3 B_Block
- [ 15:0 ] = B block data
-
-4 C_Block
- [ 15:0 ] = C block data
-
-5 D_Block
- [ 15:0 ] = D block data
-
-6 dec error
- [ 15:0 ]
- error code determined by decoder
- [ 15:14 ] = A block error
- [ 13:12 ] = B block error
- [ 11:10 ] = C block error
- [ 9:8 ] = D block error
- 0 = no error found
- 1 = small error, correctable. data is corrected.
- 2 = larg error, correctable. data is corrected.
- 3 = uncorrectable error.
- [ 7:0 ] = reserved.
-*/
-/*
- * @brief Get RDS Data fron Tef-665
- *
- * Getting RDS Data From I2C and Calling a thread to process raw data
- *
- * @param i2c_file_desc : I2C File Descriptor
- * @param Rds_STU : RDS Data Structure
- *
- */
-int tef665x_get_rds_data(uint32_t i2c_file_desc, rds_data_t *Rds_STU)
-{
-
- int ret;
- uint8_t buf[12];
-
- ret = tef665x_get_cmd(i2c_file_desc, TEF665X_MODULE_FM,
- TEF665X_Cmd_Get_RDS_Data,
- buf, sizeof(buf));
-
- if(ret == 1) {
- memcpy(Rds_STU->raw_data,buf,12);
- pthread_t t0;
- pthread_create(&t0, NULL,Process_RDS_Words ,(void *) (Rds_STU));
- }
- return ret;
-}
-
-void Clear_RDS_Data(rds_data_t *Rds_STU){
-
- Rds_STU-> Text_Changed=0;
- Rds_STU-> TrafficAnnouncement=0;
- Rds_STU-> TrafficProgram=0;
- Rds_STU-> Music_Speech=0;
-
- Rds_STU-> DI_Seg=0;
- Rds_STU-> PTY_Code=0;
- Rds_STU-> Num_AlterFreq=0;
- Rds_STU->PTYN_Size=0;
-
- Rds_STU-> Day=0;
- Rds_STU-> Month=0;
- Rds_STU-> Year=0;
-
- Rds_STU-> Hour=0;
- Rds_STU-> Min=0;
-
- /*memcpy(Rds_STU->Alternative_Freq,_Temp,25);/**/
- for(uint8_t i=0;i<25;i++){
- Rds_STU->Alternative_Freq[i]=0;
- }
- memcpy(Rds_STU-> PS_Name,_Temp,8);
- Rds_STU-> PS_Name[0]='\0';
- memcpy(Rds_STU-> RT,_Temp,64);
- Rds_STU-> RT[0]='\0';
- memcpy(Rds_STU-> PTYN,_Temp,8);
- Rds_STU-> PTYN[0]='\0';
-
- Rds_STU-> PICode=0;
- Rds_STU->Alternative_Freq_Counter=0;
- Rds_STU->PTYN_Size=0;
-}
-
-//Check if RDS is available
-int tef665x_get_rds_status(uint32_t i2c_file_desc, uint16_t *status)
-{
- int ret = 0;
- uint8_t buf[2];
-
- ret = tef665x_get_cmd(i2c_file_desc, TEF665X_MODULE_FM,
- TEF665X_Cmd_Get_RDS_Status,
- buf, sizeof(buf));
-
- if(ret == 1){
- status[0] =buf[0];
- status[1] =buf[1];
- }
-
- return ret;
-}
-
-static int tef665x_wait_active(uint32_t i2c_file_desc)
-{
- TEF665x_STATE status;
- //usleep(50000);
- if(SET_SUCCESS == appl_get_operation_status(i2c_file_desc, &status))
- {
- AFB_INFO("got status", 1);
- if((status != eDevTEF665x_Boot_state) && (status != eDevTEF665x_Idle_state))
- {
- AFB_INFO("active status", 1);
-
- if(SET_SUCCESS == tef665x_para_load(i2c_file_desc))
- {
- _debug("parameters loaded", 1);
- }
- else
- {
- _debug("parameters not loaded", 0);
- return 0;
- }
-
- if(current_band == BAND_FM){
- FM_tune_to(i2c_file_desc, eAR_TuningAction_Preset, current_fm_frequency / 10000);// tune to min
- } else {
- AM_tune_to(i2c_file_desc, eAR_TuningAction_Preset, current_am_frequency / 1000);// tune to min
- }
-
- if(SET_SUCCESS == audio_set_mute(i2c_file_desc, 1))//unmute=0
- {
- _debug("muted", 1);
- }
- else
- {
- _debug("not muted", 0);
- return 0;
- }
-
- // //if(SET_SUCCESS == audio_set_volume(i2c_file_desc, 35))//set to -10db
- // {
- // _debug("set vol to", 25);
- // }
-
- // else
- // {
- // _debug("vol not set", 0);
- // return 0;
- // }
- return 1;
- }
- }
-
- return 0;
-}
-
-static void tef665x_chip_init(int i2c_file_desc)
-{
- if(1 == tef665x_power_on(i2c_file_desc)) _debug("tef665x_power_on", 1);
- usleep(50000);
- if(1 == tef665x_boot_state(i2c_file_desc)) _debug("tef665x_boot_state", 1);
- usleep(100000);
- if(1 == tef665x_idle_state(i2c_file_desc)) _debug("tef665x_idle_state", 1);
- usleep(200000);
- if(1 == tef665x_wait_active(i2c_file_desc)) _debug("tef665x_wait_active", 1);
- //if you want to use analog output comment below command, or pass 1 to it.
- if(SET_SUCCESS != tef665x_audio_set_ana_out(i2c_file_desc, TEF665X_Cmd_Set_Output_signal_dac, 0))
- {
- _debug("Set DAC to OFF failed", 0);
- //return 0;
- }
-
- if(SET_SUCCESS != tef665x_set_output_src(i2c_file_desc, TEF665X_Cmd_Set_Output_signal_i2s,
- TEF665X_Cmd_Set_Output_source_aProcessor))
- {
- _debug("Set output failed", 0);
- //return 0;
- }
- //this is needed to use digital output
- if(SET_SUCCESS != tef665x_audio_set_dig_io(i2c_file_desc, TEF665X_AUDIO_CMD_22_SIGNAL_i2s1,
- TEF665X_AUDIO_CMD_22_MODE_voltage,
- TEF665X_AUDIO_CMD_22_FORMAT_16,
- TEF665X_AUDIO_CMD_22_OPERATION_slave,
- TEF665X_AUDIO_CMD_22_SAMPLERATE_48K))
- {
- _debug("Setup i2s failed", 0);
- //return 0;
- }
-
-
-}
-
-
-static int i2c_init(const char *i2c, int state, uint32_t *i2c_file_desc)
-{
- int fd = 0, t;
-
- if(state == _open)
- {
- fd = open(i2c, O_RDWR);
-
- if(fd < 0)
- {
- _debug("could not open %s", i2c);
- return fd;
- }
-
- t = ioctl(fd, I2C_SLAVE, I2C_ADDRESS);
- if (t < 0)
- {
- _debug("could not set up slave ", 0);
- return t;
- }
- *i2c_file_desc = fd;
- }
- else
- {
- close(*i2c_file_desc);
- }
-
- return 0;
-}
-
-static void tef665x_start(void)
-{
- int ret;
-
- if(!initialized)
- return;
-
- _debug("file_desc ", file_desc);
-
- audio_set_mute(file_desc, 0);
-
- if(!running) {
-
- // Start pipeline
- ret = gst_element_set_state(pipeline, GST_STATE_PLAYING);
- _debug("gst_element_set_state to play", ret);
- running = true;
- }
- }
-
-/*
- * @brief Send_Rds_Result to rds subscribers
- *
- * @param rds_data_t : a rds message structure
- * @return The JsonObject of rds info
- */
-void *Send_Rds_Result(rds_data_t* RDS_Message){
- //Kill the thread when it was over
- pthread_detach(pthread_self());
-
- json_object *ret_json;
- json_object *Alternative_Freqs;
-
-
- ret_json = json_object_new_object();
- Alternative_Freqs=json_object_new_array();
-
-
-
- for(uint8_t af=0 ; af<25 ; af++)
- {
- if(RDS_Message->Alternative_Freq[af]!=NULL&&RDS_Message->Alternative_Freq[af]!=0)
- {
- json_object_array_add(Alternative_Freqs,json_object_new_int(RDS_Message->Alternative_Freq[af]));
- }
- }
-
- //Prepare JSon Object
- json_object_object_add(ret_json, "name" , json_object_new_string(RDS_Message->PS_Name));
- json_object_object_add(ret_json, "radiotext" , json_object_new_string(RDS_Message->RT));
- json_object_object_add(ret_json, "alternatives" , (Alternative_Freqs));
- json_object_object_add(ret_json, "minute" , json_object_new_int (RDS_Message->Min));
- json_object_object_add(ret_json, "hour" , json_object_new_int (RDS_Message->Hour));
- json_object_object_add(ret_json, "day" , json_object_new_int (RDS_Message->Day));
- json_object_object_add(ret_json, "month" , json_object_new_int (RDS_Message->Month));
- json_object_object_add(ret_json, "year" , json_object_new_int (RDS_Message->Year));
- json_object_object_add(ret_json, "pi" , json_object_new_int (RDS_Message->PICode));
- json_object_object_add(ret_json, "pty" , json_object_new_int (RDS_Message->PTY_Code));
- json_object_object_add(ret_json, "ta" , json_object_new_int (RDS_Message->TrafficAnnouncement));
- json_object_object_add(ret_json, "tp" , json_object_new_int (RDS_Message->TrafficProgram));
- json_object_object_add(ret_json, "ms" , json_object_new_int (RDS_Message->Music_Speech));
-
- //Send JsonObject to rds Subscribers
- if(rds_callback){
- rds_callback(ret_json);
- }
-
- return ret_json;
-}
-
-/*
- * @brief Create an infinit Loop to get RDS Packets and Send them to subscribers
- *
- * RDS data will be available every 85 ms;
- * Currently availability of RDS is checkes by tef665x_get_rds_status function
- *
- * @param rds_data_t : a rds message structure
- * @return The JsonObject of latest rds info
- */
-void *Get_RDS_Packets(rds_data_t *StuRDS){
- pthread_detach(pthread_self());
- uint32_t fd = 0;
-
- int ret = i2c_init(I2C_DEV, _open, &fd);
- uint8_t status[2];
-
- ret=tef665x_get_rds_status(fd, status);
-
- if(ret==1){
- if(status[0]>7){
- //RDS must update all the time, except the times we are scanning or changing frequency
- //when scanning or changing frequncy, we unlock RDS_Mutex and it will end this thread
- for (int ref_cnt=0; pthread_mutex_trylock(&RDS_Mutex) != 0;ref_cnt++){
- //Get New RDS Data
- tef665x_get_rds_data(fd,StuRDS);
-
- //Send RDS Data after rexeiving 22 Packets
- if(ref_cnt%22==0){
- pthread_t t0;
- pthread_create(&t0, NULL,Send_Rds_Result ,(void *) (&RDS_Message));
- }
-
- //Wait for 85ms before reading available rds data
- usleep(85000);
- }
- pthread_mutex_unlock (&RDS_Mutex);
- }
-
- else{
- AFB_ERROR("RDS is Not Valid0");
- }
- }
-
- else{
- AFB_ERROR("RDS is Not Valid1");
- }
- i2c_init(I2C_DEV, _close, &fd);
-}
-
-/*
- * @brief Free Allocated Memory for Scan Thread and Unlock Scan Mutex
- *
- * @param scan_data : scan_data_t contains direction of search and callback
- * for station_found event
- */
-static void scan_cleanup_handler(void *scan_data)
-{
- pthread_mutex_unlock(&scan_mutex);
- free(scan_data);
- scanning=false;
-}
-
-/*
- * @brief Create a loop to scan from current frequency to find a valid frequency
- *
- * If found a valid frequency, send station_found to subscribers and break the loop;
- * If the direction was forward and reach the maximum frequency, Search Must continue
- * from minimum frequency
- * If the direction was backward and reach the minimum frequency, Search Must continue
- * from maximum frequency
- * If no valid frequency found, scan will stop at the begining point
- * If stop_scan called, scan_mutex will be unlocked and thread must be stopped
- *
- * @param scan_data : scan_data_t contains direction of search and callback
- * for station_found event
- */
-void *scan_frequencies(scan_data_t* scan_data){
- pthread_cleanup_push(scan_cleanup_handler, (void *)scan_data);
-
- //Kill the thread when it was over
- pthread_detach(pthread_self());
-
- //Set Scan Flag
- scanning=true;
-
- //"Unlock Mutex" Flag
- bool unlck_mtx = false;
- uint32_t new_freq = 0;
- uint32_t init_freq = 0;
-
- init_freq = current_band == BAND_FM ? current_fm_frequency : current_am_frequency;
-
- //First Mute Current Frequency
- tef665x_search_frequency(init_freq);
-
- //freq_step will be negative if direction was backward and positive if direction was forward
- uint32_t freq_step = tef665x_get_frequency_step(current_band) * (scan_data->direction==SCAN_FORWARD?1:-1);
-
- //Continue loop until reaching the initial frequency
- while(init_freq != new_freq)
- {
- //Check Status of scan_mutex
- unlck_mtx = pthread_mutex_trylock(&scan_mutex)==0;
-
- //break the loop if scan_mutex was unlocked
- if(unlck_mtx)
- {
- break;
- }
-
- if(current_band==BAND_FM)
- {
- new_freq = current_fm_frequency + freq_step;
-
- //Searching Step is 100 KHz
- //If frequency reached to initial point, the search must stop
- while (((new_freq/10000)%10)!=0 && init_freq != new_freq){
- new_freq = new_freq+freq_step;
- }
- }
- else
- {
- new_freq = current_am_frequency + freq_step;
- }
-
- //Set Freq to min when it was more than Max Value
- if(new_freq>tef665x_get_max_frequency(current_band))
- {
- new_freq=tef665x_get_min_frequency(current_band);
- }
-
- //Set Freq to max when it was less than Min Value
- if(new_freq<tef665x_get_min_frequency(current_band))
- {
- new_freq=tef665x_get_max_frequency(current_band);
- }
-
- //Tune to new frequency
- tef665x_search_frequency(new_freq);
-
- //wait 30 ms to make sure quality data is available
- for(int i=0;i<40;i++)
- {
- usleep(1000);
-
- //Check scan_mutex lock for handling stop_scan
- unlck_mtx=pthread_mutex_trylock(&scan_mutex)==0;
- if(unlck_mtx)
- {
- break;
- }
- }
- if(unlck_mtx)
- {
- break;
- }
-
- //Get Quality of tuned frequeency
- tef665x_get_quality_info();//Get_quality_status();
-
- if((quality.rssi >260 /*&& ->.usn<100/**/) || quality.bandw>1200)
- {
- //Send frequency value
- if(scan_data->callback)
- {
- scan_data->callback(new_freq,NULL);
- }
-
- break;
- }
- usleep(100);
- }
-
- //Calling last pthread_cleanup_push
- pthread_cleanup_pop(1);
-}
-
-/*
- * @brief Get latest RDS Info and send rds jsonObject as response
- *
- * @return: cast rds_json(json_object) to (char *) and return result as response
- */
-static char *tef665x_get_rds_info(void)
-{
- //If Getting RDS Result wasn't already started, Start it now
- if(pthread_mutex_trylock(&RDS_Mutex) == 0)
- {
- AFB_DEBUG("Create the thread.");
- pthread_create(&rds_thread, NULL,Get_RDS_Packets ,(void *) (&RDS_Message));
- }
-
- //Send latest available rds data
- json_object *rds_json=(json_object *)Send_Rds_Result(&RDS_Message);
-
- //Convert json_object to char* and send it as response
- return (char *)json_object_to_json_string(rds_json);
-}
-
-/*
- * @brief Get latest quality Info and send quality parameters as response
- *
- * module 32/33 FM/AM
- * cmd 129 Get_Quality_Data
- *
- * index
- * 1 status
- * [ 15:0 ]
- * quality detector status
- * [15] = AF_update flag
- * 0 = continuous quality data with time stamp
- * 1 = AF_Update sampled data
- * [14:10] = reserved
- * 0 = no data loss
- * 1 = previose data not read, replaced by newer data.
- * [9:0] = quality time stamp
- * 0 = tuning is in progress, no quality data available
- * 1 … 320 (* 0.1 ms) = 0.1 … 32 ms after tuning,
- * quality data available, reliability depending on time stamp
- * 1000 = > 32 ms after tuning
- * quality data continuously updated
- *
- * 2 level
- * [ 15:0 ] (signed)
- * level detector result
- * -200 … 1200 (0.1 * dBuV) = -20 … 120 dBuV RF input level
- * actual range and accuracy is limited by noise and agc
- *
- * 3 usn
- * [ 15:0 ] = noise detector
- * FM ultrasonic noise detector
- * 0 … 1000 (*0.1 %) = 0 … 100% relative usn detector result
- *
- * 4 wam
- * [ 15:0 ] = radio frequency offset
- * FM ‘wideband-AM’ multipath detector
- * 0 … 1000 (*0.1 %) = 0 … 100% relative wam detector result
- *
- * 5 offset
- * [ 15:0 ] (signed) = radio frequency offset
- * -1200 … 1200 (*0.1 kHz) = -120 kHz … 120 kHz radio frequency error
- * actual range and accuracy is limited by noise and bandwidth
- *
- * 6 bandwidth
- * [ 15:0 ] = IF bandwidth
- * FM 560 … 3110 [*0.1 kHz] = IF bandwidth 56 … 311 kHz; narrow … wide
- * AM 30 … 80 [*0.1 kHz] = IF bandwidth 3 … 8 kHz; narrow … wide
- *
- * 7 modulation
- * [ 15:0 ] = modulation detector
- * FM 0 … 1000 [*0.1 %] = 0 … 100% modulation = 0 … 75 kHz FM dev.
- *
- * @return: cast station_quality_t pointer as response
- *
- */
-
-static station_quality_t *tef665x_get_quality_info(void)
-{
- uint32_t i2c_file_desc=0;
- uint8_t data[14];
-
- int ret = i2c_init(I2C_DEV, _open, &i2c_file_desc);
- if(current_band==BAND_FM)
- {
- ret = tef665x_get_cmd(i2c_file_desc, TEF665X_MODULE_FM,
- TEF665X_Cmd_Get_Quality_Data,
- data, sizeof(data));
- }
- else
- {
- ret = tef665x_get_cmd(i2c_file_desc, TEF665X_MODULE_AM,
- TEF665X_Cmd_Get_Quality_Data,
- data, sizeof(data));
- }
- i2c_init(I2C_DEV, _close, &i2c_file_desc);
-
- quality.af_update = data[0]&0b10000000;
- quality.time_stamp = ((data[0]&0b00000011)<<8 | data[1]);
- quality.rssi = (data[2] << 8 | data[3] );
- quality.usn = (data[4] << 8 | data[5] );
- quality.bandw = (data[10]<< 8 | data[11]);
-
- return &quality;
-}
-
-/*
- * @brief Start Scan
- *
- * @param radio_scan_direction_t direction which is the scan direction and can be
- * SCAN_FORWARD or SCAN_BACKWARD
- * @param radio_scan_callback_t callback which is the callback for sending result of search to
- * station_found ecent subscribers
- * @return void
- */
-static void tef665x_scan_start(radio_scan_direction_t direction,
- radio_scan_callback_t callback,
- void *data)
-{
- //Stop RDS if enabled
- pthread_mutex_unlock (&RDS_Mutex);
-
- //Stop current scan:
- if(scanning)
- {
- tef665x_scan_stop();
- }
-
- scan_data_t *inputs;
-
- //Clean RDS Message since frequency will change
- Clear_RDS_Data(&RDS_Message);
- usleep(10000);
-
- AFB_DEBUG("check Mutex Condition");
-
- //check if is there any activated search
- if(pthread_mutex_trylock(&scan_mutex)==0&&!scanning)
- {
- AFB_DEBUG("Start Scanning...");
-
- inputs=malloc(sizeof(*inputs));
- if(!inputs)
- return -ENOMEM;
-
- inputs->direction= direction;
- inputs->callback= callback;
- inputs->data=data;
-
- pthread_create(&scan_thread, NULL,scan_frequencies ,(void *) inputs);
- }
-}
-
-/*
- * @brief Stop Scan
- *
- * By unlocking scan_mutex, Scan thread will be stopped safely and update scanning flag
- *
- * @return void
- */
-static void tef665x_scan_stop(void)
-{
- pthread_mutex_unlock(&scan_mutex);
- while(scanning)
- {
- usleep(100);
- AFB_DEBUG(" Wait for unlocking scan Thread");
- }
-}
-
-/*
-module 32 / 33 FM / AM
-cmd 133 Get_Signal_Status | status
-index
-1 status
- [ 15:0 ] = Radio signal information
- [15] = 0 : mono signal
- [15] = 1 : FM stereo signal (stereo pilot detected)
-
- [14] = 0 : analog signal
- [14] = 1 : digital signal (blend input activated by digital processor or control)
- (TEF6659 only)
-*/
-radio_stereo_mode_t tef665x_get_stereo_mode(void)
-{
- uint32_t i2c_file_desc = 0;
- int ret = i2c_init(I2C_DEV, _open, &i2c_file_desc);
- uint8_t data[2];
- if(current_band==BAND_FM){
- ret = tef665x_get_cmd(i2c_file_desc, TEF665X_MODULE_FM,
- TEF665X_Cmd_Get_Signal_Status,
- data, sizeof(data));
- }
- else{
- ret = tef665x_get_cmd(i2c_file_desc, TEF665X_MODULE_AM,
- TEF665X_Cmd_Get_Signal_Status,
- data, sizeof(data));
- }
- i2c_init(I2C_DEV, _close, &i2c_file_desc);
- return data[0]>>7 ==1 ? STEREO:MONO;
-}
-
-static void tef665x_stop(void)
-{
- int ret;
- GstEvent *event;
- audio_set_mute(file_desc, 1);
-
- if(initialized && running) {
- // Stop pipeline
- running = false;
- ret = gst_element_set_state(pipeline, GST_STATE_PAUSED);
- _debug("gst_element_set_state to pause", ret);
-
- // Flush pipeline
- // This seems required to avoidstatic stutters on starts after a stop
- event = gst_event_new_flush_start();
- gst_element_send_event(GST_ELEMENT(pipeline), event);
- event = gst_event_new_flush_stop(TRUE);
- gst_element_send_event(GST_ELEMENT(pipeline), event);
- }
-}
-
-static int tef665x_probe()
-{
- int rc;
-
- if(present)
- return 0;
-
- rc = i2c_init(I2C_DEV, _open, &file_desc);
- if(rc < 0) {
- AFB_NOTICE("tef665x not present");
- return -1;
- }
- _debug("file_desc= ", file_desc);
-
- rc = appl_get_identification(file_desc);
- if(rc != 1){
- AFB_ERROR("no tef665x!");
- return -1;
- }
-
- present = true;
- return 0;
-}
-
-static int tef665x_init()
-{
- char gst_pipeline_str[GST_PIPELINE_LEN];
- int rc;
-
- if(!present)
- return -1;
-
- if(initialized)
- return 0;
-
- current_am_frequency = known_am_band_plans[am_bandplan].min;
- current_fm_frequency = known_fm_band_plans[fm_bandplan].min;
-
- current_band = BAND_AM;
-
- radio_powerSwitch(file_desc, 1);
-
- tef665x_chip_init(file_desc);
-
- // Initialize GStreamer
- gst_init(NULL, NULL);
-
- // Use PipeWire output
- // This pipeline is working on imx6solo, the important thing, up to now, is that it gets xrun error every few seconds.
- // I believe it's related to wireplumber on imx6.
- rc = snprintf(gst_pipeline_str,
- GST_PIPELINE_LEN,
- "alsasrc device=hw:1,0 ! audioconvert ! audioresample ! audio/x-raw, rate=48000, channels=2 \
- ! pipewiresink stream-properties=\"p,media.role=Multimedia\"");
-
- if(rc >= GST_PIPELINE_LEN) {
- AFB_ERROR("pipeline string too long");
- return -1;
- }
- printf("pipeline: , %s\n", gst_pipeline_str);
-
- pipeline = gst_parse_launch(gst_pipeline_str, NULL);
- if(!pipeline) {
- AFB_ERROR("pipeline construction failed!");
- return -1;
- }
-
- // Start pipeline in paused state
- rc = gst_element_set_state(pipeline, GST_STATE_PAUSED);
- _debug("gst_element_set_state to pause (at the begining)", rc);
-
- rc = gst_bus_add_watch(gst_element_get_bus(pipeline), (GstBusFunc) handle_message, NULL);
- _debug("gst_bus_add_watch rc", rc);
-
- //Initialize Mutex Lock for Scan and RDS
- pthread_mutex_init(&scan_mutex, NULL);
- pthread_mutex_init (&RDS_Mutex, NULL);
-
- initialized = true;
-
- tef665x_start();
- return 0;
-}
-
-static void tef665x_set_frequency_callback(radio_freq_callback_t callback,
- void *data)
-{
- freq_callback = callback;
- freq_callback_data = data;
-}
-static void tef665x_set_rds_callback(radio_rds_callback_t callback)
-{
- rds_callback = callback;
-
-}
-static void tef665x_set_output(const char *output)
-{
-}
-
-static radio_band_t tef665x_get_band(void)
-{
- _debug("band", current_band);
- return current_band;
-}
-
-static void tef665x_set_band(radio_band_t band)
-{
- uint32_t fd = 0;
- int ret = i2c_init(I2C_DEV, _open, &fd);
-
- _debug("i2c_init ret value", ret);
-
- if(band == BAND_FM){
- current_band = band;
- FM_tune_to(fd, eAR_TuningAction_Preset, current_fm_frequency / 10000);
- } else {
- current_band = band;
- AM_tune_to(fd, eAR_TuningAction_Preset, current_am_frequency / 1000);
- }
-
- i2c_init(I2C_DEV, _close, &fd);
-
- _debug("band", current_band);
-}
-
-static uint32_t tef665x_get_frequency(void)
-{
- if(current_band == BAND_FM){
- return current_fm_frequency;
- } else {
- return current_am_frequency;
- }
-}
-
-static void tef665x_set_alternative_frequency(uint32_t frequency)
-{
- uint32_t fd = 0;
- int ret = i2c_init(I2C_DEV, _open, &fd);
-
- if(current_band == BAND_FM)
- {
- FM_tune_to(fd, eAR_TuningAction_AF_Update, frequency / 10000);
- }
-
- i2c_init(I2C_DEV, _close, &fd);
-}
-
-static void tef665x_set_frequency(uint32_t frequency)
-{
- uint32_t fd = 0;
-
- if(!initialized)
- return;
-
- if(scanning)
- return;
-
- if(current_band == BAND_FM) {
- if(frequency < known_fm_band_plans[fm_bandplan].min ||
- frequency > known_fm_band_plans[fm_bandplan].max ) {
- _debug("invalid FM frequency", frequency);
- return;
- }
- } else {
- if(frequency < known_am_band_plans[am_bandplan].min ||
- frequency > known_am_band_plans[am_bandplan].max ) {
- _debug("invalid AM frequency", frequency);
- return;
- }
- }
-
- int ret = i2c_init(I2C_DEV, _open, &fd);
-
- if(current_band == BAND_FM){
- current_fm_frequency = frequency;
- _debug("frequency set to FM :", frequency);
- FM_tune_to(fd, eAR_TuningAction_Preset, frequency / 10000);
- } else {
- current_am_frequency = frequency;
- _debug("frequency set to AM :", frequency);
- AM_tune_to(fd, eAR_TuningAction_Preset, frequency / 1000);
- }
- i2c_init(I2C_DEV, _close, &fd);
-
- //Send Frequency data to subscribers
- if(freq_callback)
- {
- freq_callback(frequency, freq_callback_data);
- }
-
- //Start RDS if the band was FM
- if(current_band==BAND_FM){
- //Unlock Mutex
- pthread_mutex_unlock (&RDS_Mutex);
-
- //Clean RDS Message
- Clear_RDS_Data(&RDS_Message);
-
- //Wait to make sure rds thread is finished
- usleep(300000);
-
- //Restart RDS
- tef665x_get_rds_info();
- }
-}
-
-/*
- * @brief Tune to a frequency in search mode
- *
- * Tune to new program and stay muted
- * Sending new frequency to subscribers
- *
- * @param uint32_t which is the frequecy to be tuned
- * @return void
- */
-static void tef665x_search_frequency(uint32_t frequency)
-{
- uint32_t fd = 0;
- int ret = i2c_init(I2C_DEV, _open, &fd);
- if(current_band == BAND_FM)
- {
- current_fm_frequency = frequency;
- _debug("frequency set to FM :", frequency);
- FM_tune_to(fd, eAR_TuningAction_Search, frequency / 10000);
-
- }
- else
- {
- current_am_frequency = frequency;
- _debug("frequency set to AM :", frequency);
- AM_tune_to(fd, eAR_TuningAction_Search, frequency / 1000);
- }
- i2c_init(I2C_DEV, _close, &fd);
-
- //Send Frequency data to subscribers
- if(freq_callback)
- {
- freq_callback(frequency, freq_callback_data);
- }
-}
-
-static int tef665x_band_supported(radio_band_t band)
-{
- if(band == BAND_FM || band == BAND_AM)
- return 1;
- return 0;
-}
-
-static uint32_t tef665x_get_min_frequency(radio_band_t band)
-{
- if(band == BAND_FM) {
- return known_fm_band_plans[fm_bandplan].min;
- } else {
- return known_am_band_plans[am_bandplan].min;
- }
-}
-
-static uint32_t tef665x_get_max_frequency(radio_band_t band)
-{
- if(band == BAND_FM) {
- return known_fm_band_plans[fm_bandplan].max;
- } else {
- return known_am_band_plans[am_bandplan].max;
- }
-}
-
-static uint32_t tef665x_get_frequency_step(radio_band_t band)
-{
- uint32_t ret = 0;
-
- switch (band) {
- case BAND_AM:
- ret = known_am_band_plans[am_bandplan].step;
- break;
- case BAND_FM:
- ret = known_fm_band_plans[fm_bandplan].step;
- break;
- default:
- break;
- }
- return ret;
-}
-
-radio_impl_ops_t tef665x_impl_ops = {
- .name = "TEF665x",
- .probe = tef665x_probe,
- .init = tef665x_init,
- .start = tef665x_start,
- .stop = tef665x_stop,
- .set_output = tef665x_set_output,
- .get_frequency = tef665x_get_frequency,
- .set_frequency = tef665x_set_frequency,
- .set_frequency_callback = tef665x_set_frequency_callback,
- .set_rds_callback=tef665x_set_rds_callback,
- .get_band = tef665x_get_band,
- .set_band = tef665x_set_band,
- .band_supported = tef665x_band_supported,
- .get_min_frequency = tef665x_get_min_frequency,
- .get_max_frequency = tef665x_get_max_frequency,
- .get_frequency_step = tef665x_get_frequency_step,
- .scan_start = tef665x_scan_start,
- .scan_stop = tef665x_scan_stop,
- .get_stereo_mode = tef665x_get_stereo_mode,
- //.set_stereo_mode = tef665x_set_stereo_mode,*/
- .get_rds_info = tef665x_get_rds_info,
- .get_quality_info = tef665x_get_quality_info,
- .set_alternative_frequency = tef665x_set_alternative_frequency
-};
diff --git a/binding/radio_impl_tef665x.h b/binding/radio_impl_tef665x.h
deleted file mode 100644
index a95fd99..0000000
--- a/binding/radio_impl_tef665x.h
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * 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.
- */
-#ifndef _RADIO_IMPL_TEF665X_H
-#define _RADIO_IMPL_TEF665X_H
-
-#include "radio_impl.h"
-
-extern radio_impl_ops_t tef665x_impl_ops;
-
-
-#endif /* _RADIO_IMPL_TEF665X_H */
-
diff --git a/binding/radio_output.h b/binding/radio_output.h
deleted file mode 100644
index bfa13cd..0000000
--- a/binding/radio_output.h
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (C) 2017 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.
- */
-
-#ifndef _RADIO_OUTPUT_H
-#define _RADIO_OUTPUT_H
-
-int radio_output_open(void);
-
-int radio_output_start(void);
-
-void radio_output_stop(void);
-
-void radio_output_close(void);
-
-ssize_t radio_output_write(void *buf, int len);
-
-#endif /* _RADIO_OUTPUT_H */
-
diff --git a/binding/radio_output_gstreamer.c b/binding/radio_output_gstreamer.c
deleted file mode 100644
index e098d2d..0000000
--- a/binding/radio_output_gstreamer.c
+++ /dev/null
@@ -1,231 +0,0 @@
-/*
- * Copyright (C) 2018, 2019 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 <stdbool.h>
-#include <string.h>
-#include <errno.h>
-#include <gst/gst.h>
-
-#include "radio_output.h"
-#include "rtl_fm.h"
-
-// Flag to enable using GST_STATE_READY instead of GST_STATE_PAUSED to trigger
-// Wireplumber policy mechanism. Hopefully temporary.
-#define WIREPLUMBER_WORKAROUND
-
-// Output buffer
-static unsigned int extra;
-static int16_t extra_buf[1];
-static unsigned char *output_buf;
-
-// GStreamer state
-static GstElement *pipeline, *appsrc;
-static bool running;
-
-int radio_output_open()
-{
- unsigned int rate = 24000;
- GstElement *queue, *convert, *sink, *resample;
- char *p;
-
- if(pipeline)
- return 0;
-
- // Initialize GStreamer
-#ifdef DEBUG
- unsigned int argc = 2;
- char **argv = malloc(2 * sizeof(char*));
- argv[0] = strdup("test");
- argv[1] = strdup("--gst-debug-level=5");
- gst_init(&argc, &argv);
-#else
- gst_init(NULL, NULL);
-#endif
-
- // Setup pipeline
- // NOTE: With our use of the simple buffer pushing mode, there seems to
- // be no need for a mainloop, so currently not instantiating one.
- pipeline = gst_pipeline_new("pipeline");
- appsrc = gst_element_factory_make("appsrc", "source");
- queue = gst_element_factory_make("queue", "queue");
- convert = gst_element_factory_make("audioconvert", "convert");
- resample = gst_element_factory_make("audioresample", "resample");
- sink = gst_element_factory_make("pipewiresink", "sink");
- if(!(pipeline && appsrc && queue && convert && resample && sink)) {
- fprintf(stderr, "pipeline element construction failed!\n");
- }
- g_object_set(G_OBJECT(appsrc), "caps",
- gst_caps_new_simple("audio/x-raw",
- "format", G_TYPE_STRING, "S16LE",
- "rate", G_TYPE_INT, rate,
- "channels", G_TYPE_INT, 2,
- "layout", G_TYPE_STRING, "interleaved",
- "channel-mask", G_TYPE_UINT64, 3,
- NULL), NULL);
- gst_util_set_object_arg(sink, "stream-properties", "p,media.role=Multimedia");
-
- if((p = getenv("RADIO_OUTPUT"))) {
- fprintf(stderr, "Using output device %s\n", p);
- g_object_set(sink, "device", p, NULL);
- }
- gst_bin_add_many(GST_BIN(pipeline), appsrc, queue, convert, resample, sink, NULL);
- gst_element_link_many(appsrc, queue, convert, resample, sink, NULL);
- //gst_bin_add_many(GST_BIN(pipeline), appsrc, convert, resample, sink, NULL);
- //gst_element_link_many(appsrc, convert, resample, sink, NULL);
-
- // Set up appsrc
- // NOTE: Radio seems like it matches the use case the "is-live" property
- // is for, but setting it seems to require a lot more work with
- // respect to latency settings to make the pipeline work smoothly.
- // For now, leave it unset since the result seems to work
- // reasonably well.
- g_object_set(G_OBJECT(appsrc),
- "stream-type", 0,
- "format", GST_FORMAT_TIME,
- NULL);
-
- // Start pipeline in paused state
-#ifdef WIREPLUMBER_WORKAROUND
- gst_element_set_state(pipeline, GST_STATE_READY);
-#else
- gst_element_set_state(pipeline, GST_STATE_PAUSED);
-#endif
-
- // Set up output buffer
- extra = 0;
- output_buf = malloc(sizeof(unsigned char) * RTL_FM_MAXIMUM_BUF_LENGTH);
-
- return 0;
-}
-
-int radio_output_start(void)
-{
- int rc = 0;
-
- if(!pipeline) {
- rc = radio_output_open();
- if(rc)
- return rc;
- }
-
- // Start pipeline
- running = true;
- gst_element_set_state(pipeline, GST_STATE_PLAYING);
-
- return rc;
-}
-
-void radio_output_stop(void)
-{
- GstEvent *event;
-
- if(pipeline && running) {
- // Stop pipeline
- running = false;
-#ifdef WIREPLUMBER_WORKAROUND
- gst_element_set_state(pipeline, GST_STATE_READY);
-#else
- gst_element_set_state(pipeline, GST_STATE_PAUSED);
-#endif
-
- // Flush pipeline
- // This seems required to avoid stutters on starts after a stop
- event = gst_event_new_flush_start();
- gst_element_send_event(GST_ELEMENT(pipeline), event);
- event = gst_event_new_flush_stop(TRUE);
- gst_element_send_event(GST_ELEMENT(pipeline), event);
- }
-}
-
-void radio_output_suspend(int state)
-{
- // Placeholder
-}
-
-void radio_output_close(void)
-{
- radio_output_stop();
-
- if(pipeline) {
- // Tear down pipeline
- gst_element_set_state(pipeline, GST_STATE_NULL);
- gst_object_unref(GST_OBJECT(pipeline));
- pipeline = NULL;
- running = false;
- }
-
- free(output_buf);
- output_buf = NULL;
-}
-
-ssize_t radio_output_write(void *buf, int len)
-{
- ssize_t rc = -EINVAL;
- size_t n = len;
- int samples = len / 2;
- unsigned char *p;
- GstBuffer *buffer;
- GstFlowReturn ret;
-
- if(!(pipeline && buf)) {
- return rc;
- }
-
- // Don't bother pushing samples if output hasn't started
- if(!running)
- return 0;
-
- /*
- * Handle the rtl_fm code giving us an odd number of samples.
- * This extra buffer copying approach is not particularly efficient,
- * but works for now. It looks feasible to hack in something in the
- * demod and output thread routines in rtl_fm.c to handle it there
- * if more performance is required.
- */
- p = output_buf;
- if(extra) {
- memcpy(output_buf, extra_buf, sizeof(int16_t));
- if((extra + samples) % 2) {
- // We still have an extra sample, n remains the same, store the extra
- memcpy(output_buf + sizeof(int16_t), buf, n - 2);
- memcpy(extra_buf, ((unsigned char*) buf) + n - 2, sizeof(int16_t));
- } else {
- // We have an even number of samples, no extra
- memcpy(output_buf + sizeof(int16_t), buf, n);
- n += 2;
- extra = 0;
- }
- } else if(samples % 2) {
- // We have an extra sample, store it, and decrease n
- n -= 2;
- memcpy(output_buf + sizeof(int16_t), buf, n);
- memcpy(extra_buf, ((unsigned char*) buf) + n, sizeof(int16_t));
- extra = 1;
- } else {
- p = buf;
- }
-
- // Push buffer into pipeline
- buffer = gst_buffer_new_allocate(NULL, n, NULL);
- gst_buffer_fill(buffer, 0, p, n);
- g_signal_emit_by_name(appsrc, "push-buffer", buffer, &ret);
- gst_buffer_unref(buffer);
- rc = n;
-
- return rc;
-}
diff --git a/binding/rtl_fm.c b/binding/rtl_fm.c
deleted file mode 100644
index cfbd487..0000000
--- a/binding/rtl_fm.c
+++ /dev/null
@@ -1,1275 +0,0 @@
-/*
- * rtl-sdr, turns your Realtek RTL2832 based DVB dongle into a SDR receiver
- * Copyright (C) 2012 by Steve Markgraf <steve@steve-m.de>
- * Copyright (C) 2012 by Hoernchen <la@tfc-server.de>
- * Copyright (C) 2012 by Kyle Keen <keenerd@gmail.com>
- * Copyright (C) 2013 by Elias Oenal <EliasOenal@gmail.com>
- * Copyright (C) 2016, 2017 Konsulko Group
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/*
- * Note that this version replaces the standalone main() with separate
- * init/start/stop API calls to allow building into another application.
- * Other than removing the separate controller thread and adding an output
- * function callback, other changes have been kept to a minimum to
- * potentially allow using other rtl_fm features by modifying rtl_fm_init.
- *
- * December 2016, Scott Murray <scott.murray@konsulko.com>
- */
-
-/*
- * written because people could not do real time
- * FM demod on Atom hardware with GNU radio
- * based on rtl_sdr.c and rtl_tcp.c
- *
- * lots of locks, but that is okay
- * (no many-to-many locks)
- *
- * todo:
- * sanity checks
- * scale squelch to other input parameters
- * test all the demodulations
- * pad output on hop
- * frequency ranges could be stored better
- * scaled AM demod amplification
- * auto-hop after time limit
- * peak detector to tune onto stronger signals
- * fifo for active hop frequency
- * clips
- * noise squelch
- * merge stereo patch
- * merge soft agc patch
- * merge udp patch
- * testmode to detect overruns
- * watchdog to reset bad dongle
- * fix oversampling
- */
-
-#include <errno.h>
-#include <signal.h>
-#include <string.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <math.h>
-#include <pthread.h>
-
-#include "rtl-sdr.h"
-#include "rtl_fm.h"
-#include "convenience/convenience.h"
-
-#define DEFAULT_SAMPLE_RATE 24000
-#define DEFAULT_BUF_LENGTH RTL_FM_DEFAULT_BUF_LENGTH
-#define MAXIMUM_OVERSAMPLE RTL_FM_MAXIMUM_OVERSAMPLE
-#define MAXIMUM_BUF_LENGTH RTL_FM_MAXIMUM_BUF_LENGTH
-#define AUTO_GAIN -100
-#define BUFFER_DUMP 4096
-
-#define FREQUENCIES_LIMIT 1000
-
-#define DEFAULT_SQUELCH_LEVEL 140
-#define DEFAULT_CONSEQ_SQUELCH 10
-
-static volatile int do_exit = 0;
-static int lcm_post[17] = {1,1,1,3,1,5,3,7,1,9,5,11,3,13,7,15,1};
-static int ACTUAL_BUF_LENGTH;
-
-static int *atan_lut = NULL;
-static int atan_lut_size = 131072; /* 512 KB */
-static int atan_lut_coef = 8;
-
-struct dongle_state
-{
- int exit_flag;
- pthread_t thread;
- rtlsdr_dev_t *dev;
- int dev_index;
- uint32_t freq;
- uint32_t rate;
- int gain;
- uint16_t buf16[MAXIMUM_BUF_LENGTH];
- uint32_t buf_len;
- int ppm_error;
- int offset_tuning;
- int direct_sampling;
- int mute;
- struct demod_state *demod_target;
-};
-
-struct demod_state
-{
- int exit_flag;
- pthread_t thread;
- int16_t lowpassed[MAXIMUM_BUF_LENGTH];
- int lp_len;
- int16_t lp_i_hist[10][6];
- int16_t lp_q_hist[10][6];
- int16_t result[MAXIMUM_BUF_LENGTH];
- int16_t droop_i_hist[9];
- int16_t droop_q_hist[9];
- int result_len;
- int rate_in;
- int rate_out;
- int rate_out2;
- int now_r, now_j;
- int pre_r, pre_j;
- int prev_index;
- int downsample; /* min 1, max 256 */
- int post_downsample;
- int output_scale;
- int squelch_level, conseq_squelch, squelch_hits, terminate_on_squelch;
- int downsample_passes;
- int comp_fir_size;
- int custom_atan;
- int deemph, deemph_a;
- int now_lpr;
- int prev_lpr_index;
- int dc_block, dc_avg;
- void (*mode_demod)(struct demod_state*);
- pthread_rwlock_t rw;
- pthread_cond_t ready;
- pthread_mutex_t ready_m;
- struct output_state *output_target;
-};
-
-struct output_state
-{
- int exit_flag;
- pthread_t thread;
- rtl_fm_output_fn_t output_fn;
- void *output_fn_data;
- int16_t result[MAXIMUM_BUF_LENGTH];
- int result_len;
- int rate;
- pthread_rwlock_t rw;
- pthread_cond_t ready;
- pthread_mutex_t ready_m;
-};
-
-struct controller_state
-{
- int exit_flag;
- pthread_t thread;
- uint32_t freqs[FREQUENCIES_LIMIT];
- int freq_len;
- int freq_now;
- int edge;
- int wb_mode;
- pthread_cond_t hop;
- pthread_mutex_t hop_m;
-
- void (*freq_callback)(uint32_t, void*);
- void *freq_callback_data;
-
- int scanning;
- int scan_direction;
- void (*scan_callback)(uint32_t, void*);
- void *scan_callback_data;
- uint32_t scan_step;
- uint32_t scan_min;
- uint32_t scan_max;
- int scan_squelch_level;
- int scan_squelch_count;
-};
-
-// multiple of these, eventually
-struct dongle_state dongle;
-struct demod_state demod;
-struct output_state output;
-struct controller_state controller;
-
-#if 0
-static void sighandler(int signum)
-{
- fprintf(stderr, "Signal caught, exiting!\n");
- do_exit = 1;
- rtlsdr_cancel_async(dongle.dev);
-}
-#endif
-
-/* more cond dumbness */
-#define safe_cond_signal(n, m) pthread_mutex_lock(m); pthread_cond_signal(n); pthread_mutex_unlock(m)
-#define safe_cond_wait(n, m) pthread_mutex_lock(m); pthread_cond_wait(n, m); pthread_mutex_unlock(m)
-
-/* {length, coef, coef, coef} and scaled by 2^15
- for now, only length 9, optimal way to get +85% bandwidth */
-#define CIC_TABLE_MAX 10
-int cic_9_tables[][10] = {
- {0,},
- {9, -156, -97, 2798, -15489, 61019, -15489, 2798, -97, -156},
- {9, -128, -568, 5593, -24125, 74126, -24125, 5593, -568, -128},
- {9, -129, -639, 6187, -26281, 77511, -26281, 6187, -639, -129},
- {9, -122, -612, 6082, -26353, 77818, -26353, 6082, -612, -122},
- {9, -120, -602, 6015, -26269, 77757, -26269, 6015, -602, -120},
- {9, -120, -582, 5951, -26128, 77542, -26128, 5951, -582, -120},
- {9, -119, -580, 5931, -26094, 77505, -26094, 5931, -580, -119},
- {9, -119, -578, 5921, -26077, 77484, -26077, 5921, -578, -119},
- {9, -119, -577, 5917, -26067, 77473, -26067, 5917, -577, -119},
- {9, -199, -362, 5303, -25505, 77489, -25505, 5303, -362, -199},
-};
-
-void rotate_90(unsigned char *buf, uint32_t len)
-/* 90 rotation is 1+0j, 0+1j, -1+0j, 0-1j
- or [0, 1, -3, 2, -4, -5, 7, -6] */
-{
- uint32_t i;
- uint8_t tmp;
-
- for (i=0; i<len; i+=8) {
- /* uint8_t negation = 255 - x */
- tmp = (uint8_t)(255 - buf[i+3]);
- buf[i+3] = buf[i+2];
- buf[i+2] = tmp;
-
- buf[i+4] = (uint8_t)(255 - buf[i+4]);
- buf[i+5] = (uint8_t)(255 - buf[i+5]);
-
- tmp = (uint8_t)(255 - buf[i+6]);
- buf[i+6] = buf[i+7];
- buf[i+7] = tmp;
- }
-}
-
-void low_pass(struct demod_state *d)
-/* simple square window FIR */
-{
- int i=0, i2=0;
- while (i < d->lp_len) {
- d->now_r += d->lowpassed[i];
- d->now_j += d->lowpassed[i+1];
- i += 2;
- d->prev_index++;
- if (d->prev_index < d->downsample) {
- continue;
- }
- d->lowpassed[i2] = (int16_t)d->now_r; // * d->output_scale;
- d->lowpassed[i2+1] = (int16_t)d->now_j; // * d->output_scale;
- d->prev_index = 0;
- d->now_r = 0;
- d->now_j = 0;
- i2 += 2;
- }
- d->lp_len = i2;
-}
-
-int low_pass_simple(int16_t *signal2, int len, int step)
-// no wrap around, length must be multiple of step
-{
- int i, i2, sum;
- for(i=0; i < len; i+=step) {
- sum = 0;
- for(i2=0; i2<step; i2++) {
- sum += (int)signal2[i + i2];
- }
- //signal2[i/step] = (int16_t)(sum / step);
- signal2[i/step] = (int16_t)(sum);
- }
- signal2[i/step + 1] = signal2[i/step];
- return len / step;
-}
-
-void low_pass_real(struct demod_state *s)
-/* simple square window FIR */
-// add support for upsampling?
-{
- int i=0, i2=0;
- int fast = (int)s->rate_out;
- int slow = s->rate_out2;
- while (i < s->result_len) {
- s->now_lpr += s->result[i];
- i++;
- s->prev_lpr_index += slow;
- if (s->prev_lpr_index < fast) {
- continue;
- }
- s->result[i2] = (int16_t)(s->now_lpr / (fast/slow));
- s->prev_lpr_index -= fast;
- s->now_lpr = 0;
- i2 += 1;
- }
- s->result_len = i2;
-}
-
-void fifth_order(int16_t *data, int length, int16_t *hist)
-/* for half of interleaved data */
-{
- int i;
- int16_t a, b, c, d, e, f;
- a = hist[1];
- b = hist[2];
- c = hist[3];
- d = hist[4];
- e = hist[5];
- f = data[0];
- /* a downsample should improve resolution, so don't fully shift */
- data[0] = (int16_t) ((a + (b+e)*5 + (c+d)*10 + f) >> 4);
- for (i=4; i<length; i+=4) {
- a = c;
- b = d;
- c = e;
- d = f;
- e = data[i-2];
- f = data[i];
- data[i/2] = (int16_t) ((a + (b+e)*5 + (c+d)*10 + f) >> 4);
- }
- /* archive */
- hist[0] = a;
- hist[1] = b;
- hist[2] = c;
- hist[3] = d;
- hist[4] = e;
- hist[5] = f;
-}
-
-void generic_fir(int16_t *data, int length, int *fir, int16_t *hist)
-/* Okay, not at all generic. Assumes length 9, fix that eventually. */
-{
- int16_t temp;
- int sum;
- int d;
- for (d=0; d<length; d+=2) {
- temp = data[d];
- sum = 0;
- sum += (hist[0] + hist[8]) * fir[1];
- sum += (hist[1] + hist[7]) * fir[2];
- sum += (hist[2] + hist[6]) * fir[3];
- sum += (hist[3] + hist[5]) * fir[4];
- sum += hist[4] * fir[5];
- data[d] = (int16_t) (sum >> 15);
- hist[0] = hist[1];
- hist[1] = hist[2];
- hist[2] = hist[3];
- hist[3] = hist[4];
- hist[4] = hist[5];
- hist[5] = hist[6];
- hist[6] = hist[7];
- hist[7] = hist[8];
- hist[8] = temp;
- }
-}
-
-/* define our own complex math ops
- because ARMv5 has no hardware float */
-
-void multiply(int ar, int aj, int br, int bj, int *cr, int *cj)
-{
- *cr = ar*br - aj*bj;
- *cj = aj*br + ar*bj;
-}
-
-int polar_discriminant(int ar, int aj, int br, int bj)
-{
- int cr, cj;
- double angle;
- multiply(ar, aj, br, -bj, &cr, &cj);
- angle = atan2((double)cj, (double)cr);
- return (int)(angle / 3.14159 * (1<<14));
-}
-
-int fast_atan2(int y, int x)
-/* pre scaled for int16 */
-{
- int yabs, angle;
- int pi4=(1<<12), pi34=3*(1<<12); // note pi = 1<<14
- if (x==0 && y==0) {
- return 0;
- }
- yabs = y;
- if (yabs < 0) {
- yabs = -yabs;
- }
- if (x >= 0) {
- angle = pi4 - pi4 * (x-yabs) / (x+yabs);
- } else {
- angle = pi34 - pi4 * (x+yabs) / (yabs-x);
- }
- if (y < 0) {
- return -angle;
- }
- return angle;
-}
-
-int polar_disc_fast(int ar, int aj, int br, int bj)
-{
- int cr, cj;
- multiply(ar, aj, br, -bj, &cr, &cj);
- return fast_atan2(cj, cr);
-}
-
-int atan_lut_init(void)
-{
- int i = 0;
-
- atan_lut = malloc(atan_lut_size * sizeof(int));
-
- for (i = 0; i < atan_lut_size; i++) {
- atan_lut[i] = (int) (atan((double) i / (1<<atan_lut_coef)) / 3.14159 * (1<<14));
- }
-
- return 0;
-}
-
-int polar_disc_lut(int ar, int aj, int br, int bj)
-{
- int cr, cj, x, x_abs;
-
- multiply(ar, aj, br, -bj, &cr, &cj);
-
- /* special cases */
- if (cr == 0 || cj == 0) {
- if (cr == 0 && cj == 0)
- {return 0;}
- if (cr == 0 && cj > 0)
- {return 1 << 13;}
- if (cr == 0 && cj < 0)
- {return -(1 << 13);}
- if (cj == 0 && cr > 0)
- {return 0;}
- if (cj == 0 && cr < 0)
- {return 1 << 14;}
- }
-
- /* real range -32768 - 32768 use 64x range -> absolute maximum: 2097152 */
- x = (cj << atan_lut_coef) / cr;
- x_abs = abs(x);
-
- if (x_abs >= atan_lut_size) {
- /* we can use linear range, but it is not necessary */
- const int ret = 1<<13;
- return (cj > 0) ? ret : -ret;
- }
-
- if (x > 0) {
- return (cj > 0) ? atan_lut[x] : atan_lut[x] - (1<<14);
- } else {
- return (cj > 0) ? (1<<14) - atan_lut[-x] : -atan_lut[-x];
- }
-
- return 0;
-}
-
-void fm_demod(struct demod_state *fm)
-{
- int i, pcm;
- int16_t *lp = fm->lowpassed;
- pcm = polar_discriminant(lp[0], lp[1],
- fm->pre_r, fm->pre_j);
- fm->result[0] = (int16_t)pcm;
- for (i = 2; i < (fm->lp_len-1); i += 2) {
- switch (fm->custom_atan) {
- case 0:
- pcm = polar_discriminant(lp[i], lp[i+1],
- lp[i-2], lp[i-1]);
- break;
- case 1:
- pcm = polar_disc_fast(lp[i], lp[i+1],
- lp[i-2], lp[i-1]);
- break;
- case 2:
- pcm = polar_disc_lut(lp[i], lp[i+1],
- lp[i-2], lp[i-1]);
- break;
- }
- fm->result[i/2] = (int16_t)pcm;
- }
- fm->pre_r = lp[fm->lp_len - 2];
- fm->pre_j = lp[fm->lp_len - 1];
- fm->result_len = fm->lp_len/2;
-}
-
-void am_demod(struct demod_state *fm)
-// todo, fix this extreme laziness
-{
- int i, pcm;
- int16_t *lp = fm->lowpassed;
- int16_t *r = fm->result;
- for (i = 0; i < fm->lp_len; i += 2) {
- // hypot uses floats but won't overflow
- //r[i/2] = (int16_t)hypot(lp[i], lp[i+1]);
- pcm = lp[i] * lp[i];
- pcm += lp[i+1] * lp[i+1];
- r[i/2] = (int16_t) ((int16_t)sqrt(pcm) * fm->output_scale);
- }
- fm->result_len = fm->lp_len/2;
- // lowpass? (3khz) highpass? (dc)
-}
-
-void usb_demod(struct demod_state *fm)
-{
- int i, pcm;
- int16_t *lp = fm->lowpassed;
- int16_t *r = fm->result;
- for (i = 0; i < fm->lp_len; i += 2) {
- pcm = lp[i] + lp[i+1];
- r[i/2] = (int16_t)((int16_t)pcm * fm->output_scale);
- }
- fm->result_len = fm->lp_len/2;
-}
-
-void lsb_demod(struct demod_state *fm)
-{
- int i, pcm;
- int16_t *lp = fm->lowpassed;
- int16_t *r = fm->result;
- for (i = 0; i < fm->lp_len; i += 2) {
- pcm = lp[i] - lp[i+1];
- r[i/2] = (int16_t)((int16_t)pcm * fm->output_scale);
- }
- fm->result_len = fm->lp_len/2;
-}
-
-void raw_demod(struct demod_state *fm)
-{
- int i;
- for (i = 0; i < fm->lp_len; i++) {
- fm->result[i] = (int16_t)fm->lowpassed[i];
- }
- fm->result_len = fm->lp_len;
-}
-
-void deemph_filter(struct demod_state *fm)
-{
- static int avg; // cheating...
- int i, d;
- // de-emph IIR
- // avg = avg * (1 - alpha) + sample * alpha;
- for (i = 0; i < fm->result_len; i++) {
- d = fm->result[i] - avg;
- if (d > 0) {
- avg += (d + fm->deemph_a/2) / fm->deemph_a;
- } else {
- avg += (d - fm->deemph_a/2) / fm->deemph_a;
- }
- fm->result[i] = (int16_t)avg;
- }
-}
-
-void dc_block_filter(struct demod_state *fm)
-{
- int i, avg;
- int64_t sum = 0;
- for (i=0; i < fm->result_len; i++) {
- sum += fm->result[i];
- }
- avg = (int)(sum / fm->result_len);
- avg = (avg + fm->dc_avg * 9) / 10;
- for (i=0; i < fm->result_len; i++) {
- fm->result[i] = (int16_t)(fm->result[i] - avg);
- }
- fm->dc_avg = avg;
-}
-
-int mad(int16_t *samples, int len, int step)
-/* mean average deviation */
-{
- int i=0, sum=0, ave=0;
- if (len == 0)
- {return 0;}
- for (i=0; i<len; i+=step) {
- sum += samples[i];
- }
- ave = sum / (len * step);
- sum = 0;
- for (i=0; i<len; i+=step) {
- sum += abs(samples[i] - ave);
- }
- return sum / (len / step);
-}
-
-int rms(int16_t *samples, int len, int step)
-/* largely lifted from rtl_power */
-{
- int i;
- double p, t, s;
- double dc, err;
-
- p = t = 0L;
- for (i=0; i<len; i+=step) {
- s = (long)samples[i];
- t += s;
- p += s * s;
- }
- /* correct for dc offset in squares */
- dc = (double)(t*step) / (double)len;
- err = t * 2 * dc - dc * dc * len;
-
- return (int)sqrt((p-err) / len);
-}
-
-void arbitrary_upsample(int16_t *buf1, int16_t *buf2, int len1, int len2)
-/* linear interpolation, len1 < len2 */
-{
- int i = 1;
- int j = 0;
- int tick = 0;
- double frac; // use integers...
- while (j < len2) {
- frac = (double)tick / (double)len2;
- buf2[j] = (int16_t)(buf1[i-1]*(1-frac) + buf1[i]*frac);
- j++;
- tick += len1;
- if (tick > len2) {
- tick -= len2;
- i++;
- }
- if (i >= len1) {
- i = len1 - 1;
- tick = len2;
- }
- }
-}
-
-void arbitrary_downsample(int16_t *buf1, int16_t *buf2, int len1, int len2)
-/* fractional boxcar lowpass, len1 > len2 */
-{
- int i = 1;
- int j = 0;
- int tick = 0;
- double remainder = 0;
- double frac; // use integers...
- buf2[0] = 0;
- while (j < len2) {
- frac = 1.0;
- if ((tick + len2) > len1) {
- frac = (double)(len1 - tick) / (double)len2;}
- buf2[j] = (int16_t)(buf2[j] + (double)buf1[i] * frac + remainder);
- remainder = (double)buf1[i] * (1.0-frac);
- tick += len2;
- i++;
- if (tick > len1) {
- j++;
- buf2[j] = 0;
- tick -= len1;
- }
- if (i >= len1) {
- i = len1 - 1;
- tick = len1;
- }
- }
- for (j=0; j<len2; j++) {
- buf2[j] = (int16_t) (buf2[j] * len2 / len1);
- }
-}
-
-void arbitrary_resample(int16_t *buf1, int16_t *buf2, int len1, int len2)
-/* up to you to calculate lengths and make sure it does not go OOB
- * okay for buffers to overlap, if you are downsampling */
-{
- if (len1 < len2) {
- arbitrary_upsample(buf1, buf2, len1, len2);
- } else {
- arbitrary_downsample(buf1, buf2, len1, len2);
- }
-}
-
-void full_demod(struct demod_state *d)
-{
- int i, ds_p;
- int sr = 0;
- ds_p = d->downsample_passes;
- if (ds_p) {
- for (i=0; i < ds_p; i++) {
- fifth_order(d->lowpassed, (d->lp_len >> i), d->lp_i_hist[i]);
- fifth_order(d->lowpassed+1, (d->lp_len >> i) - 1, d->lp_q_hist[i]);
- }
- d->lp_len = d->lp_len >> ds_p;
- /* droop compensation */
- if (d->comp_fir_size == 9 && ds_p <= CIC_TABLE_MAX) {
- generic_fir(d->lowpassed, d->lp_len,
- cic_9_tables[ds_p], d->droop_i_hist);
- generic_fir(d->lowpassed+1, d->lp_len-1,
- cic_9_tables[ds_p], d->droop_q_hist);
- }
- } else {
- low_pass(d);
- }
- /* power squelch */
- if (d->squelch_level) {
- sr = rms(d->lowpassed, d->lp_len, 1);
- if (sr < d->squelch_level) {
- d->squelch_hits++;
- for (i=0; i< d->lp_len; i++) {
- d->lowpassed[i] = 0;
- }
- } else {
- d->squelch_hits = 0;
- }
- }
- d->mode_demod(d); /* lowpassed -> result */
- if (d->mode_demod == &raw_demod) {
- return;
- }
- /* todo, fm noise squelch */
- // use nicer filter here too?
- if (d->post_downsample > 1) {
- d->result_len = low_pass_simple(d->result, d->result_len, d->post_downsample);}
- if (d->deemph) {
- deemph_filter(d);}
- if (d->dc_block) {
- dc_block_filter(d);}
- if (d->rate_out2 > 0) {
- low_pass_real(d);
- //arbitrary_resample(d->result, d->result, d->result_len, d->result_len * d->rate_out2 / d->rate_out);
- }
-}
-
-static void rtlsdr_callback(unsigned char *buf, uint32_t len, void *ctx)
-{
- int i;
- struct dongle_state *s = ctx;
- struct demod_state *d = s->demod_target;
-
- if (do_exit) {
- return;}
- if (!ctx) {
- return;}
- if (s->mute) {
- for (i=0; i<s->mute; i++) {
- buf[i] = 127;}
- s->mute = 0;
- }
- if (!s->offset_tuning) {
- rotate_90(buf, len);}
- for (i=0; i<(int)len; i++) {
- s->buf16[i] = (int16_t)(buf[i] - 127);
- }
- pthread_rwlock_wrlock(&d->rw);
- memcpy(d->lowpassed, s->buf16, 2*len);
- d->lp_len = len;
- pthread_rwlock_unlock(&d->rw);
- safe_cond_signal(&d->ready, &d->ready_m);
-}
-
-static void *dongle_thread_fn(void *arg)
-{
- struct dongle_state *s = arg;
- fprintf(stderr, "dongle_thread_fn running\n");
- rtlsdr_read_async(s->dev, rtlsdr_callback, s, 0, s->buf_len);
- fprintf(stderr, "dongle_thread_fn exited!\n");
- return 0;
-}
-
-static void rtl_fm_scan_callback(void)
-{
- struct controller_state *s = &controller;
- uint32_t frequency = rtl_fm_get_freq();
-
- if(!s->scanning)
- return;
-
- if(!s->scan_direction) {
- frequency += s->scan_step;
- if(frequency > s->scan_max)
- frequency = s->scan_min;
- } else {
- frequency -= s->scan_step;
- if(frequency < s->scan_min)
- frequency = s->scan_max;
- }
-
- rtl_fm_set_freq(frequency);
-}
-
-static void rtl_fm_scan_end_callback(void)
-{
- struct controller_state *s = &controller;
-
- if(!s->scanning)
- return;
-
- rtl_fm_scan_stop();
-
- if(s->scan_callback)
- s->scan_callback(rtl_fm_get_freq(), s->scan_callback_data);
-}
-
-static void *demod_thread_fn(void *arg)
-{
- struct demod_state *d = arg;
- struct output_state *o = d->output_target;
- fprintf(stderr, "demod_thread_fn running\n");
- while (!do_exit) {
- safe_cond_wait(&d->ready, &d->ready_m);
- pthread_rwlock_wrlock(&d->rw);
- full_demod(d);
- pthread_rwlock_unlock(&d->rw);
- if (d->exit_flag) {
- do_exit = 1;
- }
- if (d->squelch_level) {
- if(d->squelch_hits > d->conseq_squelch) {
- d->squelch_hits = d->conseq_squelch + 1; /* hair trigger */
- //safe_cond_signal(&controller.hop, &controller.hop_m);
- rtl_fm_scan_callback();
- continue;
- } else if(!d->squelch_hits) {
- rtl_fm_scan_end_callback();
- }
- }
- pthread_rwlock_wrlock(&o->rw);
- memcpy(o->result, d->result, 2*d->result_len);
- o->result_len = d->result_len;
- pthread_rwlock_unlock(&o->rw);
- safe_cond_signal(&o->ready, &o->ready_m);
- }
- fprintf(stderr, "demod_thread_fn exited!\n");
- return 0;
-}
-
-static void *output_thread_fn(void *arg)
-{
- struct output_state *s = arg;
- fprintf(stderr, "output_thread_fn running\n");
- while (!do_exit) {
- // use timedwait and pad out under runs
- safe_cond_wait(&s->ready, &s->ready_m);
- pthread_rwlock_rdlock(&s->rw);
- if(s->output_fn) {
- s->output_fn(s->result, s->result_len, s->output_fn_data);
- }
- pthread_rwlock_unlock(&s->rw);
- }
- fprintf(stderr, "output_thread_fn exited!\n");
- return 0;
-}
-
-static void optimal_settings(int freq, int rate)
-{
- // giant ball of hacks
- // seems unable to do a single pass, 2:1
- int capture_freq, capture_rate;
- struct dongle_state *d = &dongle;
- struct demod_state *dm = &demod;
- struct controller_state *cs = &controller;
- dm->downsample = (1000000 / dm->rate_in) + 1;
- if (dm->downsample_passes) {
- dm->downsample_passes = (int)log2(dm->downsample) + 1;
- dm->downsample = 1 << dm->downsample_passes;
- }
- capture_freq = freq;
- capture_rate = dm->downsample * dm->rate_in;
- if (!d->offset_tuning) {
- capture_freq = freq + capture_rate/4;}
- capture_freq += cs->edge * dm->rate_in / 2;
- dm->output_scale = (1<<15) / (128 * dm->downsample);
- if (dm->output_scale < 1) {
- dm->output_scale = 1;}
- if (dm->mode_demod == &fm_demod) {
- dm->output_scale = 1;}
- d->freq = (uint32_t)capture_freq;
- d->rate = (uint32_t)capture_rate;
-}
-
-
-void frequency_range(struct controller_state *s, char *arg)
-{
- char *start, *stop, *step;
- int i;
- start = arg;
- stop = strchr(start, ':') + 1;
- stop[-1] = '\0';
- step = strchr(stop, ':') + 1;
- step[-1] = '\0';
- for(i=(int)atofs(start); i<=(int)atofs(stop); i+=(int)atofs(step))
- {
- s->freqs[s->freq_len] = (uint32_t)i;
- s->freq_len++;
- if (s->freq_len >= FREQUENCIES_LIMIT) {
- break;}
- }
- stop[-1] = ':';
- step[-1] = ':';
-}
-
-void dongle_init(struct dongle_state *s)
-{
- s->rate = DEFAULT_SAMPLE_RATE;
- s->gain = AUTO_GAIN; // tenths of a dB
- s->mute = 0;
- s->direct_sampling = 0;
- s->offset_tuning = 0;
- s->demod_target = &demod;
-}
-
-void demod_init(struct demod_state *s)
-{
- s->rate_in = DEFAULT_SAMPLE_RATE;
- s->rate_out = DEFAULT_SAMPLE_RATE;
- s->squelch_level = 0;
- s->conseq_squelch = DEFAULT_CONSEQ_SQUELCH;
- s->terminate_on_squelch = 0;
- s->squelch_hits = DEFAULT_CONSEQ_SQUELCH + 1;
- s->downsample_passes = 0;
- s->comp_fir_size = 0;
- s->prev_index = 0;
- s->post_downsample = 1; // once this works, default = 4
- s->custom_atan = 0;
- s->deemph = 0;
- s->rate_out2 = -1; // flag for disabled
- s->mode_demod = &fm_demod;
- s->pre_j = s->pre_r = s->now_r = s->now_j = 0;
- s->prev_lpr_index = 0;
- s->deemph_a = 0;
- s->now_lpr = 0;
- s->dc_block = 0;
- s->dc_avg = 0;
- pthread_rwlock_init(&s->rw, NULL);
- pthread_cond_init(&s->ready, NULL);
- pthread_mutex_init(&s->ready_m, NULL);
- s->output_target = &output;
-}
-
-void demod_cleanup(struct demod_state *s)
-{
- pthread_rwlock_destroy(&s->rw);
- pthread_cond_destroy(&s->ready);
- pthread_mutex_destroy(&s->ready_m);
-}
-
-void output_init(struct output_state *s)
-{
- s->rate = DEFAULT_SAMPLE_RATE;
- s->output_fn = NULL;
- s->output_fn_data = NULL;
- pthread_rwlock_init(&s->rw, NULL);
- pthread_cond_init(&s->ready, NULL);
- pthread_mutex_init(&s->ready_m, NULL);
-}
-
-void output_cleanup(struct output_state *s)
-{
- pthread_rwlock_destroy(&s->rw);
- pthread_cond_destroy(&s->ready);
- pthread_mutex_destroy(&s->ready_m);
-}
-
-void controller_init(struct controller_state *s)
-{
- s->freqs[0] = 100000000;
- s->freq_len = 0;
- s->edge = 0;
- s->wb_mode = 0;
- pthread_cond_init(&s->hop, NULL);
- pthread_mutex_init(&s->hop_m, NULL);
-}
-
-void controller_cleanup(struct controller_state *s)
-{
- pthread_cond_destroy(&s->hop);
- pthread_mutex_destroy(&s->hop_m);
-}
-
-int sanity_checks(void)
-{
- int r = 1;
- if (controller.freq_len == 0) {
- fprintf(stderr, "Please specify a frequency.\n");
- r = 0;
- }
-
- if (controller.freq_len >= FREQUENCIES_LIMIT) {
- fprintf(stderr, "Too many channels, maximum %i.\n", FREQUENCIES_LIMIT);
- r = 0;
- }
-
- if (controller.freq_len > 1 && demod.squelch_level == 0) {
- fprintf(stderr, "Please specify a squelch level. Required for scanning multiple frequencies.\n");
- r = 0;
- }
- return r;
-}
-
-int rtl_fm_init(uint32_t freq,
- uint32_t sample_rate,
- uint32_t resample_rate,
- rtl_fm_output_fn_t output_fn,
- void *output_fn_data)
-{
- int r = 0;
-
- dongle_init(&dongle);
- demod_init(&demod);
- output_init(&output);
- controller_init(&controller);
-
- /*
- * Simulate the effects of command line arguments:
- *
- * -W wbfm -s <sample rate> -r <resample rate>
- */
-
- /* Set initial frequency */
- controller.freqs[0] = freq;
- controller.freq_len++;
-
- /* Set mode to wbfm */
- controller.wb_mode = 1;
- demod.mode_demod = &fm_demod;
- demod.rate_in = 170000;
- demod.rate_out = 170000;
- demod.rate_out2 = 32000;
- demod.custom_atan = 1;
- //demod.post_downsample = 4;
- demod.deemph = 1;
- controller.scan_squelch_count = DEFAULT_CONSEQ_SQUELCH;
- controller.scan_squelch_level = DEFAULT_SQUELCH_LEVEL;
- demod.squelch_level = 0;
-
- /* Adjust frequency for wb mode */
- controller.freqs[0] += 16000;
-
- /* Set sample rate */
- demod.rate_in = sample_rate;
- demod.rate_out = sample_rate;
-
- /* Set resample rate */
- output.rate = (int) resample_rate;
- demod.rate_out2 = (int) resample_rate;
-
- /* Set output function pointer */
- if(output_fn) {
- output.output_fn = output_fn;
- output.output_fn_data = output_fn_data;
- }
-
- /* quadruple sample_rate to limit to Δθ to ±π/2 */
- demod.rate_in *= demod.post_downsample;
-
- if (!output.rate) {
- output.rate = demod.rate_out;
- }
-
- if (!sanity_checks())
- return -1;
-
- if (controller.freq_len > 1) {
- demod.terminate_on_squelch = 0;
- }
-
- ACTUAL_BUF_LENGTH = lcm_post[demod.post_downsample] * DEFAULT_BUF_LENGTH;
-
- dongle.dev_index = verbose_device_search("0");
- if (dongle.dev_index < 0) {
- return -1;
- }
-
- r = rtlsdr_open(&dongle.dev, (uint32_t)dongle.dev_index);
- if (r < 0) {
- fprintf(stderr, "Failed to open rtlsdr device #%d.\n", dongle.dev_index);
- return r;
- }
-
- if (demod.deemph) {
- demod.deemph_a = (int)round(1.0/((1.0-exp(-1.0/(demod.rate_out * 75e-6)))));
- }
-
- /* Set the tuner gain */
- if (dongle.gain == AUTO_GAIN) {
- verbose_auto_gain(dongle.dev);
- } else {
- dongle.gain = nearest_gain(dongle.dev, dongle.gain);
- verbose_gain_set(dongle.dev, dongle.gain);
- }
-
- verbose_ppm_set(dongle.dev, dongle.ppm_error);
-
- //r = rtlsdr_set_testmode(dongle.dev, 1);
-
- return r;
-}
-
-void rtl_fm_start(void)
-{
- struct controller_state *s = &controller;
-
- /*
- * A bunch of the following is pulled from the controller_thread_fn,
- * which has been removed.
- */
-
- /* Reset endpoint before we start reading from it (mandatory) */
- verbose_reset_buffer(dongle.dev);
-
- /* set up primary channel */
- optimal_settings(s->freqs[0], demod.rate_in);
- if (dongle.direct_sampling) {
- verbose_direct_sampling(dongle.dev, 1);}
- if (dongle.offset_tuning) {
- verbose_offset_tuning(dongle.dev);}
-
- /* Set the frequency */
- verbose_set_frequency(dongle.dev, dongle.freq);
- fprintf(stderr, "Oversampling input by: %ix.\n", demod.downsample);
- fprintf(stderr, "Oversampling output by: %ix.\n", demod.post_downsample);
- fprintf(stderr, "Buffer size: %0.2fms\n",
- 1000 * 0.5 * (float)ACTUAL_BUF_LENGTH / (float)dongle.rate);
-
- /* Set the sample rate */
- verbose_set_sample_rate(dongle.dev, dongle.rate);
- fprintf(stderr, "Output at %u Hz.\n", demod.rate_in/demod.post_downsample);
- usleep(100000);
-
- rtl_fm_scan_stop();
-
- do_exit = 0;
- pthread_create(&output.thread, NULL, output_thread_fn, (void *)(&output));
- pthread_create(&demod.thread, NULL, demod_thread_fn, (void *)(&demod));
- pthread_create(&dongle.thread, NULL, dongle_thread_fn, (void *)(&dongle));
-}
-
-void rtl_fm_set_freq(uint32_t freq)
-{
- struct controller_state *s = &controller;
-
- if(s->freqs[0] == freq)
- return;
-
- s->freqs[0] = freq;
- s->freq_len = 1;
-
- if (s->wb_mode) {
- s->freqs[0] += 16000;
- }
-
- optimal_settings(s->freqs[0], demod.rate_in);
- if (dongle.offset_tuning) {
- verbose_offset_tuning(dongle.dev);
- }
- rtlsdr_set_center_freq(dongle.dev, dongle.freq);
-
- // It does not look like refreshing the sample rate is desirable
- // (e.g. the scanning code in the removed controller thread function
- // did not do it), and behavior seemed a bit less robust with it
- // present. However, I am leaving this here as a reminder to revisit
- // via some more testing.
- //rtlsdr_set_sample_rate(dongle.dev, dongle.rate);
-
- // This triggers a mute during the frequency change
- dongle.mute = BUFFER_DUMP;
-
- if(s->freq_callback)
- s->freq_callback(freq, s->freq_callback_data);
-}
-
-void rtl_fm_set_freq_callback(void (*callback)(uint32_t, void *),
- void *data)
-{
- struct controller_state *s = &controller;
-
- s->freq_callback = callback;
- s->freq_callback_data = data;
-}
-
-uint32_t rtl_fm_get_freq(void)
-{
- struct controller_state *s = &controller;
- uint32_t frequency = s->freqs[0];
-
- if (s->wb_mode)
- frequency -= 16000;
-
- return frequency;
-}
-
-void rtl_fm_stop(void)
-{
- rtl_fm_scan_stop();
-
- rtlsdr_cancel_async(dongle.dev);
- do_exit = 1;
- pthread_join(dongle.thread, NULL);
- safe_cond_signal(&demod.ready, &demod.ready_m);
- pthread_join(demod.thread, NULL);
- safe_cond_signal(&output.ready, &output.ready_m);
- pthread_join(output.thread, NULL);
-}
-
-void rtl_fm_scan_start(int direction,
- void (*callback)(uint32_t, void *),
- void *data,
- uint32_t step,
- uint32_t min,
- uint32_t max)
-{
- struct controller_state *s = &controller;
- struct demod_state *dm = &demod;
- uint32_t frequency = rtl_fm_get_freq();
-
- if(s->scanning && s->scan_direction == direction)
- return;
-
- s->scanning = 1;
- s->scan_direction = direction;
- s->scan_callback = callback;
- s->scan_callback_data = data;
- s->scan_step = step;
- s->scan_min = min;
- s->scan_max = max;
-
- /* Start scan by stepping in the desired direction */
- if(!direction) {
- frequency += s->scan_step;
- if(frequency > s->scan_max)
- frequency = s->scan_min;
- } else {
- frequency -= s->scan_step;
- if(frequency < s->scan_min)
- frequency = s->scan_max;
- }
-
- rtl_fm_set_freq(frequency);
-
- dm->conseq_squelch = s->scan_squelch_count;
- dm->squelch_hits = s->scan_squelch_count + 1;
- dm->squelch_level = s->scan_squelch_level;
-}
-
-void rtl_fm_scan_stop(void)
-{
- struct controller_state *s = &controller;
- struct demod_state *dm = &demod;
-
- s->scanning = 0;
-
- dm->squelch_hits = s->scan_squelch_count + 1;
- dm->squelch_level = 0;
-}
-
-void rtl_fm_scan_set_squelch_level(int level)
-{
- struct controller_state *s = &controller;
-
- s->scan_squelch_level = level;
-}
-
-void rtl_fm_scan_set_squelch_limit(int count)
-{
- struct controller_state *s = &controller;
-
- s->scan_squelch_count = count;
-}
-
-void rtl_fm_cleanup(void)
-{
- //dongle_cleanup(&dongle);
- demod_cleanup(&demod);
- output_cleanup(&output);
- controller_cleanup(&controller);
-
- rtlsdr_close(dongle.dev);
-}
-
-// vim: tabstop=8:softtabstop=8:shiftwidth=8:noexpandtab
diff --git a/binding/rtl_fm.h b/binding/rtl_fm.h
deleted file mode 100644
index f5b2a86..0000000
--- a/binding/rtl_fm.h
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * rtl-sdr, turns your Realtek RTL2832 based DVB dongle into a SDR receiver
- * Copyright (C) 2016, 2017 Konsulko Group
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef RTL_FM_H
-#define RTL_FM_H
-
-#include <stdint.h>
-
-#define RTL_FM_DEFAULT_BUF_LENGTH (1 * 16384)
-#define RTL_FM_MAXIMUM_OVERSAMPLE 16
-#define RTL_FM_MAXIMUM_BUF_LENGTH (RTL_FM_MAXIMUM_OVERSAMPLE * RTL_FM_DEFAULT_BUF_LENGTH)
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef void (*rtl_fm_output_fn_t)(int16_t *result, int result_len, void *data);
-
-int rtl_fm_init(uint32_t freq,
- uint32_t sample_rate,
- uint32_t resample_rate,
- rtl_fm_output_fn_t output_fn,
- void *output_fn_data);
-
-void rtl_fm_start(void);
-
-void rtl_fm_set_freq(uint32_t freq);
-
-void rtl_fm_set_freq_callback(void (*callback)(uint32_t, void *),
- void *data);
-
-uint32_t rtl_fm_get_freq(void);
-
-void rtl_fm_stop(void);
-
-void rtl_fm_scan_start(int direction,
- void (*callback)(uint32_t, void *),
- void *data,
- uint32_t step,
- uint32_t min,
- uint32_t max);
-
-void rtl_fm_scan_stop(void);
-
-void rtl_fm_scan_set_squelch_level(int level);
-
-void rtl_fm_scan_set_squelch_limit(int count);
-
-void rtl_fm_cleanup(void);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* RTL_FM_H */
diff --git a/binding/rtl_fm_helper.c b/binding/rtl_fm_helper.c
deleted file mode 100644
index c7df4b9..0000000
--- a/binding/rtl_fm_helper.c
+++ /dev/null
@@ -1,243 +0,0 @@
-/*
- * Copyright (C) 2018 Konsulko Group
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include <stdbool.h>
-#include <string.h>
-#include <glib.h>
-
-#include "rtl_fm.h"
-#include "radio_output.h"
-
-#ifdef DEBUG
-#define LOG_FILE "/tmp/helper.log"
-FILE *_log;
-#define LOG(...) \
- do { \
- if(!_log) _log = fopen(LOG_FILE, "w"); \
- fprintf(_log, __VA_ARGS__); \
- fflush(_log); \
- } while(0)
-#else
-#define LOG(...) do { } while(0)
-#endif
-
-// Structure to describe FM band plans, all values in Hz.
-typedef struct {
- const 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 line[64];
-
-static void rtl_output_callback(int16_t *result, int result_len, void *ctx)
-{
- radio_output_write((char*) result, result_len * 2);
-}
-
-static void rtl_freq_callback(uint32_t freq, void *ctx)
-{
- // Note, need to flush output to ensure parent sees it
- printf("F=%u\n", freq);
- fflush(stdout);
- LOG("F=%u\n", freq);
-}
-
-static void rtl_scan_callback(uint32_t freq, void *ctx)
-{
- // Note, need to flush output to ensure parent sees it
- printf("S=%u\n", freq);
- fflush(stdout);
- LOG("S=%u\n", freq);
-}
-
-static void read_config(void)
-{
- GKeyFile* conf_file;
- int conf_file_present = 0;
- char *value_str;
-
- // 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) {
- conf_file_present = 1;
-
- // 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;
- }
- }
- }
- }
- fprintf(stderr, "Using FM Bandplan: %s\n", known_fm_band_plans[bandplan].name);
-
- if(conf_file_present) {
- GError *error = NULL;
- int n;
-
- // Allow over-riding scanning parameters just in case a demo
- // setup needs to do so to work reliably.
- n = g_key_file_get_integer(conf_file,
- "radio",
- "scan_squelch_level",
- &error);
- if(!error) {
- fprintf(stderr, "Scanning squelch level set to %d\n", n);
- rtl_fm_scan_set_squelch_level(n);
- }
-
- error = NULL;
- n = g_key_file_get_integer(conf_file,
- "radio",
- "scan_squelch_limit",
- &error);
- if(!error) {
- fprintf(stderr, "Scanning squelch limit set to %d\n", n);
- rtl_fm_scan_set_squelch_limit(n);
- }
-
- g_key_file_free(conf_file);
- }
-}
-
-int main(int argc, char *argv[])
-{
- int rc;
- bool detect = false;
- bool done = false;
- bool started = false;
- uint32_t frequency;
-
- LOG("started\n");
-
- read_config();
- frequency = known_fm_band_plans[bandplan].min;
-
- if(argc == 2 && strcmp(argv[1], "--detect") == 0) {
- detect = true;
- }
-
- rc = rtl_fm_init(frequency, 200000, 48000, rtl_output_callback, NULL);
- if(rc < 0) {
- fprintf(stderr, "No RTL USB adapter?\n");
- exit(1);
- }
- if(detect) {
- rtl_fm_cleanup();
- exit(0);
- }
-
- rtl_fm_set_freq_callback(rtl_freq_callback, NULL);
-
- while(!done) {
- LOG("Reading command\n");
- if (fgets(line, sizeof(line), stdin) == NULL)
- break;
- if(line[0] == '\0' || line[0] == '\n')
- continue;
- if(strcmp(line, "START\n") == 0) {
- LOG("START received\n");
- if(!started) {
- LOG("Starting\n");
- radio_output_start();
- rtl_fm_start();
- started = true;
- }
- } else if(strcmp(line, "STOP\n") == 0) {
- LOG("STOP received\n");
- if(started) {
- LOG("Stopping\n");
- radio_output_stop();
- rtl_fm_stop();
- started = false;
- }
- } else if(strncmp(line, "F=", 2) == 0) {
- uint32_t n;
- if(sscanf(line, "F=%u\n", &n) == 1) {
- LOG("F=%d received\n", n);
- rtl_fm_scan_stop();
- rtl_fm_set_freq(n);
- }
- } else if(strcmp(line, "S=UP\n") == 0) {
- LOG("S=UP received\n");
- if(!started)
- continue;
- LOG("Calling rtl_fm_scan_start\n");
- rtl_fm_scan_start(0,
- rtl_scan_callback,
- NULL,
- known_fm_band_plans[bandplan].step,
- known_fm_band_plans[bandplan].min,
- known_fm_band_plans[bandplan].max);
- } else if(strcmp(line, "S=DOWN\n") == 0) {
- LOG("S=DOWN received\n");
- if(!started)
- continue;
- LOG("Calling rtl_fm_scan_start\n");
- rtl_fm_scan_start(1,
- rtl_scan_callback,
- NULL,
- known_fm_band_plans[bandplan].step,
- known_fm_band_plans[bandplan].min,
- known_fm_band_plans[bandplan].max);
- } else if(strcmp(line, "S=STOP\n") == 0) {
- LOG("S=STOP received\n");
- if(started) {
- LOG("Calling rtl_fm_scan_stop\n");
- rtl_fm_scan_stop();
- }
- } else if(line[0] == 'q' || line[0] == 'Q')
- break;
- }
- if(started) {
- radio_output_stop();
- rtl_fm_stop();
- }
- rtl_fm_cleanup();
- LOG("done");
- return 0;
-}
diff --git a/binding/tef665x.h b/binding/tef665x.h
deleted file mode 100644
index 10874e8..0000000
--- a/binding/tef665x.h
+++ /dev/null
@@ -1,397 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef TEF665X_H
-#define TEF665X_H
-
-typedef uint8_t u8;
-typedef uint16_t ushort;
-typedef uint32_t uint;
-
-typedef enum
-{
-_close = 0,
-_open
-} I2C_STATE;
-
-typedef enum
-{
- TEF665X_MODULE_FM = 0x20, //32
- TEF665X_MODULE_AM = 0x21, //31
- TEF665X_MODULE_AUDIO = 0x30, //48
- TEF665X_MODULE_APPL = 0x40 //64
-} TEF665x_MODULE;
-
-enum {
- TEF6657_CMD_tune = 0,
- TEF6657_CMD_open = 1,
- TEF6657_CMD_close = 2,
- TEF6657_CMD_am = 3,
- TEF6657_CMD_fm = 4,
- TEF6657_CMD_GETamSTAUS = 5,
- TEF6657_CMD_GETfmSTAUS = 6,
- TEF6657_CMD_GEToirtSTAUS
-};
-
-enum
-{
- RADIO_BOOT_STATE = 0,
- RADIO_IDLE_STATE,
- RADIO_STANBDY_STATE,
- RADIO_FM_STATE,
- RADIO_AM_STATE
-
-};
-
-typedef enum
-{
- TEF665X_Cmd_Set_OperationMode = 0x01,
- TEF665X_Cmd_Set_GPIO = 0x03,
- TEF665X_Cmd_Set_ReferenceClock = 0x04,
- TEF665X_Cmd_Activate = 0x05,
-
- TEF665X_Cmd_Get_Operation_Status = 0x80, //128,
- TEF665X_Cmd_Get_GPIO_Status = 0x81, //129,
- TEF665X_Cmd_Get_Identification = 0x82, //130,
- TEF665X_Cmd_Get_LastWrite = 0x83, //131
-} TEF665x_APPL_COMMAND;
-
-typedef enum
-{
- TEF665X_Cmd_Set_RDS_mode = 0x01, // default
- TEF665X_Cmd_Set_RDS_autorestart= 0x02, // restart after tune
- TEF665X_Cmd_Set_RDS_interface = 0, // no interface
-} TEF665x_FM_COMMAND;
-
-typedef enum
-{
- TEF665X_Cmd_Tune_To = 0x01,
- TEF665X_Cmd_Set_Tune_Options =0x02,
- TEF665X_Cmd_Set_Bandwidth =0x0A, //10,
- TEF665X_Cmd_Set_RFAGC =0x0B, //11,
- TEF665X_Cmd_Set_Antenna =0x0C, //12,
-
- TEF665X_Cmd_Set_MphSuppression =0x14, //20,
- TEF665X_Cmd_Set_NoiseBlanker =0x17, //23,
- TEF665X_Cmd_Set_NoiseBlanker_Audio =0x18, //24,
-
- TEF665X_Cmd_Set_DigitalRadio =0x1E, //30,
- TEF665X_Cmd_Set_Deemphasis =0x1F, //31,
-
- TEF665X_Cmd_Set_LevelStep = 0x26, //38,
- TEF665X_Cmd_Set_LevelOffset = 0x27, //39,
-
- TEF665X_Cmd_Set_Softmute_Time =0x28, //40,
- TEF665X_Cmd_Set_Softmute_Mod = 0x29, //41,
- TEF665X_Cmd_Set_Softmute_Level =0x2A, //42,
- TEF665X_Cmd_Set_Softmute_Noise =0x2B, //43,
- TEF665X_Cmd_Set_Softmute_Mph =0x2C, //44,
- TEF665X_Cmd_Set_Softmute_Max =0x2D, //45,
-
- TEF665X_Cmd_Set_Highcut_Time =0x32, //50,
- TEF665X_Cmd_Set_Highcut_Mod = 0x33, //51,
- TEF665X_Cmd_Set_Highcut_Level =0x34, //52,
- TEF665X_Cmd_Set_Highcut_Noise = 0x35, //53,
- TEF665X_Cmd_Set_Highcut_Mph =0x36, //54,
- TEF665X_Cmd_Set_Highcut_Max =0x37, //55,
- TEF665X_Cmd_Set_Highcut_Min =0x38, //56,
- TEF665X_Cmd_Set_Lowcut_Min =0x3A, //58,
-
- TEF665X_Cmd_Set_Stereo_Time =0x3C, //60,
- TEF665X_Cmd_Set_Stereo_Mod =0x3D, //61,
- TEF665X_Cmd_Set_Stereo_Level =0x3E, //62,
- TEF665X_Cmd_Set_Stereo_Noise = 0x3F, //63,
- TEF665X_Cmd_Set_Stereo_Mph =0x40, //64,
- TEF665X_Cmd_Set_Stereo_Max = 0x41, //65,
- TEF665X_Cmd_Set_Stereo_Min = 0x42, //66,
-
- TEF665X_Cmd_Set_Scaler = 0x50, //80,
- TEF665X_Cmd_Set_RDS = 0x51, //81,
- TEF665X_Cmd_Set_QualityStatus = 0x52, //82,
- TEF665X_Cmd_Set_DR_Blend = 0x53, //83,
- TEF665X_Cmd_Set_DR_Options = 0x54, //84,
- TEF665X_Cmd_Set_Specials = 0x55, //85,
-
- TEF665X_Cmd_Get_Quality_Status = 0x80, //128,
- TEF665X_Cmd_Get_Quality_Data = 0x81, //129,
- TEF665X_Cmd_Get_RDS_Status = 0x82, //130,
- TEF665X_Cmd_Get_RDS_Data = 0x83, //131,
- TEF665X_Cmd_Get_AGC = 0x84, //132,
- TEF665X_Cmd_Get_Signal_Status = 0x85, //133,
- TEF665X_Cmd_Get_Processing_Status = 0x86, //134,
- TEF665X_Cmd_Get_Interface_Status = 0x87, //135,
-
- TEF665X_Cmd_Set_Output_signal_i2s = 0x21, //33,
- TEF665X_Cmd_Set_Output_signal_dac = 0x80, //128,
- TEF665X_Cmd_Set_Output_source_aRadio = 0x04, //4,
- TEF665X_Cmd_Set_Output_source_dInput = 0x20, //32,
- TEF665X_Cmd_Set_Output_source_aProcessor = 0xe0, //224,
- TEF665X_Cmd_Set_Output_source_SinWave = 0xf0, //240,
- } TEF665x_RADIO_COMMAND;
-
-typedef enum
-{
- TEF665X_Cmd_Set_Volume = 0x0A, //10,
- TEF665X_Cmd_Set_Mute = 0x0B, //11,
- TEF665X_Cmd_Set_Input = 0x0C, //12,
- TEF665X_Cmd_Set_Output_Source = 0x0D, //13,
-
- TEF665X_Cmd_Set_Ana_Out = 0x15, //21,
- TEF665X_Cmd_Set_Dig_IO = 0x16, //22,
- TEF665X_Cmd_Set_Input_Scaler = 0x17, //23,
- TEF665X_Cmd_Set_WaveGen = 0x18, //24
-} TEF665x_AUDIO_COMMAND;
-
-typedef enum
-{
- TEF665X_AUDIO_CMD_22_SIGNAL_i2s1 = 0x21, //33,
- TEF665X_AUDIO_CMD_22_MODE_voltage = 0x02, //2,
- TEF665X_AUDIO_CMD_22_FORMAT_16 = 0x10, //16,
- TEF665X_AUDIO_CMD_22_FORMAT_32 = 0x20, //32,
- TEF665X_AUDIO_CMD_22_OPERATION_slave = 0, //0,
- TEF665X_AUDIO_CMD_22_OPERATION_master = 0x0100,//256,
- TEF665X_AUDIO_CMD_22_SAMPLERATE_48K = 0x12c0 //4800
-} TEF665x_AUDIO_CMD_22;
-
-typedef enum{
- eDevTEF665x_Boot_state ,
- eDevTEF665x_Idle_state,
- eDevTEF665x_Wait_Active,
- eDevTEF665x_Active_state,
-
- eDevTEF665x_Power_on,
-
- eDevTEF665x_Not_Exist,
-
- eDevTEF665x_Last
-}TEF665x_STATE;
-
-const u8 patchByteValues[]=
-{
- 0xF0, 0x00, 0x38, 0x16, 0xD0, 0x80, 0x43, 0xB2, 0x38, 0x1D, 0xD0, 0x80, 0xF0, 0x00, 0x70, 0x00, 0xC2, 0xF7, 0xF0, 0x00, 0x38, 0x4E, 0xD0, 0x80,
- 0xF0, 0x00, 0x38, 0xF1, 0xD0, 0x80, 0xC4, 0xA2, 0x02, 0x0C, 0x60, 0x04, 0x90, 0x01, 0x39, 0x07, 0xD0, 0x80, 0xF0, 0x00, 0x38, 0xD3, 0xD0, 0x80,
- 0xF0, 0x00, 0x39, 0x0E, 0xD2, 0x80, 0xF0, 0x00, 0x39, 0x12, 0xD0, 0x80, 0x40, 0x20, 0x39, 0x1E, 0xD0, 0x80, 0x9E, 0x30, 0x18, 0xF9, 0xD2, 0x80,
- 0xF0, 0x00, 0x39, 0x20, 0xD0, 0x80, 0xF0, 0x00, 0x39, 0x23, 0xD0, 0x80, 0xF0, 0x00, 0x39, 0x38, 0xD0, 0x80, 0xF0, 0x00, 0x39, 0x3B, 0xD0, 0x80,
- 0x00, 0x43, 0x39, 0x43, 0xD9, 0x80, 0xF0, 0x00, 0x39, 0x46, 0xD0, 0x80, 0xF0, 0x00, 0x39, 0x60, 0xD0, 0x80, 0xF0, 0x00, 0x39, 0x71, 0xD0, 0x80,
- 0xF0, 0x00, 0x39, 0x7F, 0xD0, 0x80, 0xF0, 0x00, 0x39, 0x82, 0xD0, 0x80, 0xF0, 0x00, 0x70, 0x00, 0xA0, 0x14, 0xF0, 0x00, 0x70, 0x00, 0xA0, 0xD4,
- 0xF0, 0x00, 0x70, 0x00, 0xA0, 0xDB, 0xF0, 0x00, 0x70, 0x00, 0xA1, 0x0C, 0xF0, 0x00, 0x70, 0x00, 0xA1, 0x12, 0xF0, 0x00, 0x70, 0x00, 0xA1, 0x2D,
- 0xF0, 0x00, 0x20, 0x31, 0xD0, 0x80, 0x00, 0x7F, 0x60, 0x02, 0xE2, 0x00, 0xF0, 0x00, 0x0E, 0x22, 0x60, 0x0A, 0xF0, 0x00, 0x00, 0xFF, 0x60, 0x03,
- 0xF0, 0x00, 0x01, 0x42, 0xD2, 0x80, 0x90, 0x03, 0x40, 0x02, 0xF0, 0x00, 0x90, 0x43, 0x01, 0x70, 0xD1, 0x80, 0xF0, 0x00, 0x01, 0x69, 0xD0, 0x80,
- 0x0E, 0x69, 0x60, 0x0A, 0xA1, 0x60, 0x20, 0x23, 0x00, 0x01, 0x60, 0x01, 0xF0, 0x00, 0x70, 0x00, 0xF0, 0x00, 0xC4, 0xCB, 0x70, 0x00, 0xF0, 0x00,
- 0xCA, 0x09, 0x30, 0x23, 0xF0, 0x00, 0xC2, 0xCB, 0x70, 0x00, 0xF0, 0x00, 0xF0, 0x00, 0x30, 0x23, 0xD0, 0x08, 0x82, 0x00, 0x0D, 0x50, 0x60, 0x08,
- 0xF0, 0x00, 0x0D, 0x51, 0x60, 0x09, 0x30, 0x00, 0x21, 0x80, 0x60, 0x01, 0xF0, 0x00, 0x40, 0x32, 0xF0, 0x00, 0x30, 0x11, 0x45, 0xF3, 0xF0, 0x00,
- 0x30, 0x92, 0x2D, 0x30, 0x60, 0x04, 0x31, 0x13, 0x2D, 0x40, 0x60, 0x05, 0x31, 0x94, 0x7F, 0xFF, 0x60, 0x06, 0x32, 0x15, 0x0D, 0x61, 0x60, 0x0A,
- 0x32, 0x96, 0x0D, 0x6B, 0x60, 0x0B, 0x33, 0x10, 0x0D, 0x50, 0x60, 0x01, 0x33, 0x90, 0x0D, 0x5C, 0x60, 0x02, 0x30, 0x21, 0x0D, 0x63, 0x60, 0x03,
- 0x30, 0x31, 0x0D, 0x75, 0x60, 0x0C, 0x30, 0xA2, 0x8D, 0x00, 0x60, 0x01, 0x30, 0xB3, 0x01, 0x73, 0x60, 0x02, 0x30, 0x41, 0x00, 0x25, 0x60, 0x03,
- 0x30, 0xC2, 0x40, 0x44, 0xF0, 0x00, 0x31, 0x43, 0x40, 0x35, 0xF0, 0x00, 0x31, 0xC4, 0x64, 0x00, 0x60, 0x06, 0x32, 0x45, 0x1F, 0x40, 0x60, 0x07,
- 0x32, 0xC6, 0x70, 0x00, 0xF0, 0x00, 0x33, 0x47, 0x1E, 0xBC, 0x60, 0x0D, 0x33, 0xC0, 0x01, 0x22, 0x60, 0x01, 0x34, 0x40, 0xFD, 0xEE, 0x60, 0x02,
- 0x30, 0x51, 0x7B, 0x8F, 0x60, 0x03, 0x30, 0xD2, 0xC4, 0x29, 0x60, 0x04, 0x31, 0x51, 0x1E, 0xC2, 0x60, 0x0E, 0x32, 0x53, 0xFF, 0x0D, 0x60, 0x02,
- 0x32, 0xD4, 0x7D, 0x2E, 0x60, 0x03, 0x30, 0x61, 0xC1, 0x9A, 0x60, 0x04, 0x30, 0xE2, 0x70, 0x00, 0xF0, 0x00, 0x31, 0x61, 0x70, 0x00, 0xF0, 0x00,
- 0x32, 0x63, 0x70, 0x00, 0xF0, 0x00, 0x32, 0xE4, 0x70, 0x00, 0xD0, 0x08, 0xF0, 0x00, 0x03, 0x70, 0xD2, 0x80, 0xF0, 0x00, 0x70, 0x00, 0xA0, 0x02,
- 0xF0, 0x00, 0x70, 0x00, 0xA0, 0x59, 0xF0, 0x00, 0x02, 0x15, 0xD0, 0x80, 0xF0, 0x00, 0x0D, 0x51, 0x60, 0x0F, 0xF0, 0x00, 0x05, 0x17, 0x60, 0x0E,
- 0x23, 0xF6, 0x70, 0x00, 0xF0, 0x00, 0xF0, 0x00, 0x21, 0x63, 0x41, 0xF5, 0x91, 0x8F, 0x21, 0xF8, 0x40, 0x74, 0xC3, 0xEF, 0x21, 0xE0, 0xF0, 0x00,
- 0xC3, 0xA4, 0x33, 0xF7, 0xF0, 0x00, 0xD8, 0x5B, 0x70, 0x00, 0xF0, 0x00, 0x82, 0x18, 0x70, 0x00, 0xF0, 0x00, 0x9F, 0xAF, 0x18, 0x00, 0xF0, 0x00,
- 0x9F, 0x0F, 0x31, 0xF8, 0x90, 0x02, 0xF0, 0x00, 0x70, 0x00, 0x90, 0x28, 0xF0, 0x00, 0x70, 0x00, 0xD0, 0x08, 0xF0, 0x00, 0x22, 0x78, 0xF0, 0x00,
- 0x16, 0xD3, 0x60, 0x09, 0xA0, 0x7F, 0x35, 0xF0, 0x1E, 0xBC, 0x60, 0x0D, 0xF0, 0x00, 0x0D, 0x61, 0x60, 0x08, 0xF0, 0x00, 0x03, 0xA5, 0xD2, 0x80,
- 0xF0, 0x00, 0x1E, 0xC2, 0x60, 0x0D, 0xF0, 0x00, 0x0D, 0x6B, 0x60, 0x08, 0xF0, 0x00, 0x03, 0xA5, 0xD2, 0x80, 0xF0, 0x00, 0x21, 0x00, 0xF0, 0x00,
- 0x83, 0x6D, 0x22, 0xF1, 0xF0, 0x00, 0xF0, 0x00, 0x23, 0x77, 0xF0, 0x00, 0x90, 0x41, 0x36, 0x70, 0xF0, 0x00, 0x9E, 0x79, 0x70, 0x00, 0x90, 0x01,
- 0xF0, 0x00, 0x32, 0xF1, 0xD0, 0x08, 0x91, 0xC7, 0x33, 0x75, 0xF0, 0x00, 0xF0, 0x00, 0x34, 0x70, 0xE6, 0x00, 0xF0, 0x00, 0x34, 0xF0, 0xE6, 0x00,
- 0xF0, 0x00, 0x24, 0x74, 0xF0, 0x00, 0xF0, 0x00, 0x24, 0xF3, 0xF0, 0x00, 0x8C, 0x24, 0x26, 0xF2, 0x40, 0x16, 0x8A, 0x1B, 0x34, 0x74, 0x4F, 0xF5,
- 0x82, 0xB7, 0x34, 0xF3, 0xF0, 0x00, 0xF0, 0x00, 0x20, 0x71, 0x90, 0x05, 0x83, 0x04, 0x70, 0x00, 0xF0, 0x00, 0x8E, 0x67, 0x70, 0x00, 0xF0, 0x00,
- 0xF0, 0x00, 0x70, 0x00, 0x90, 0x02, 0xF0, 0x00, 0x36, 0xF6, 0xF0, 0x00, 0xF0, 0x00, 0x34, 0xF0, 0x80, 0x06, 0x82, 0xAF, 0x70, 0x00, 0xF0, 0x00,
- 0x82, 0x1B, 0x70, 0x00, 0xD0, 0x09, 0x8E, 0x5F, 0x70, 0x00, 0xF0, 0x00, 0xF0, 0x00, 0x70, 0x00, 0xD0, 0x09, 0xF0, 0x00, 0x36, 0xF5, 0xF0, 0x00,
- 0xF0, 0x00, 0x34, 0x70, 0xF0, 0x00, 0x40, 0x11, 0x27, 0x72, 0xA1, 0x03, 0x90, 0x8A, 0x20, 0xF3, 0xA1, 0x02, 0x8E, 0xD7, 0x37, 0x72, 0xF0, 0x00,
- 0xF0, 0x00, 0x37, 0xF1, 0xE6, 0x00, 0xF0, 0x00, 0x70, 0x00, 0xD0, 0x08, 0xF0, 0x00, 0x22, 0x7A, 0xF0, 0x00, 0x16, 0xC3, 0x60, 0x09, 0xA0, 0x58,
- 0xF0, 0x00, 0x18, 0x20, 0xF0, 0x00, 0xF0, 0x00, 0x35, 0x70, 0xF0, 0x00, 0xF0, 0x00, 0x32, 0x7A, 0xD0, 0x08, 0x82, 0x00, 0x0D, 0x51, 0x60, 0x08,
- 0x40, 0x03, 0x70, 0x00, 0xF0, 0x00, 0x33, 0x80, 0x70, 0x00, 0xF0, 0x00, 0x21, 0x06, 0x70, 0x00, 0xF0, 0x00, 0x37, 0x00, 0x70, 0x00, 0xF0, 0x00,
- 0x37, 0x80, 0x40, 0x15, 0xF0, 0x00, 0x36, 0x83, 0x70, 0x00, 0xF0, 0x00, 0x33, 0x05, 0x0D, 0x61, 0x60, 0x09, 0x32, 0x86, 0x0D, 0x6B, 0x60, 0x0A,
- 0x32, 0x10, 0x70, 0x00, 0xF0, 0x00, 0x32, 0x90, 0x70, 0x00, 0xF0, 0x00, 0x33, 0x10, 0x70, 0x00, 0xF0, 0x00, 0x33, 0x90, 0x70, 0x00, 0xF0, 0x00,
- 0x34, 0x10, 0x70, 0x00, 0xF0, 0x00, 0x34, 0x90, 0x70, 0x00, 0xF0, 0x00, 0x31, 0x10, 0x70, 0x00, 0xF0, 0x00, 0x31, 0x90, 0x70, 0x00, 0xF0, 0x00,
- 0x32, 0x20, 0x70, 0x00, 0xF0, 0x00, 0x32, 0xA0, 0x70, 0x00, 0xF0, 0x00, 0x33, 0x20, 0x70, 0x00, 0xF0, 0x00, 0x33, 0xA0, 0x70, 0x00, 0xF0, 0x00,
- 0x34, 0x20, 0x70, 0x00, 0xF0, 0x00, 0x34, 0xA0, 0x70, 0x00, 0xF0, 0x00, 0x31, 0x20, 0x70, 0x00, 0xF0, 0x00, 0x31, 0xA0, 0x70, 0x00, 0xF0, 0x00,
- 0x82, 0x00, 0x0D, 0x30, 0x60, 0x0A, 0x0D, 0x40, 0x60, 0x0B, 0xC0, 0x10, 0xF0, 0x00, 0x10, 0x20, 0xF0, 0x00, 0x0D, 0x51, 0x60, 0x0C, 0xC0, 0x10,
- 0xF0, 0x00, 0x10, 0x30, 0xF0, 0x00, 0xF0, 0x00, 0x35, 0xC0, 0xD0, 0x08, 0xF0, 0x00, 0x0D, 0x75, 0x60, 0x0F, 0xF0, 0x00, 0x05, 0x63, 0x60, 0x0E,
- 0x24, 0xF7, 0x05, 0x1D, 0x60, 0x0D, 0x25, 0x76, 0x70, 0x00, 0xF0, 0x00, 0x91, 0xC7, 0x20, 0xE8, 0x40, 0x15, 0x91, 0x8F, 0x21, 0xE9, 0xD4, 0x09,
- 0xC3, 0xEF, 0x20, 0x00, 0x40, 0x12, 0x9F, 0xBE, 0x20, 0x11, 0x58, 0x03, 0xA0, 0x80, 0x35, 0x77, 0x90, 0x01, 0xF0, 0x00, 0x70, 0x00, 0xD0, 0x08,
- 0xF0, 0x00, 0x21, 0xF5, 0xF0, 0x00, 0xA0, 0xCA, 0x22, 0x54, 0xF0, 0x00, 0xCC, 0x09, 0x05, 0x17, 0x60, 0x0C, 0x83, 0x2C, 0x70, 0x00, 0xF0, 0x00,
- 0x8A, 0x61, 0x70, 0x00, 0xF0, 0x00, 0xAE, 0x48, 0x22, 0x45, 0xA0, 0xCB, 0xA2, 0x28, 0x20, 0x78, 0xF0, 0x00, 0xF0, 0x00, 0x35, 0xF0, 0xF0, 0x00,
- 0xF0, 0x00, 0x18, 0x00, 0xF0, 0x00, 0xF0, 0x00, 0x30, 0x78, 0xF0, 0x00, 0x16, 0xE3, 0x60, 0x09, 0xA0, 0x27, 0x89, 0x01, 0x23, 0xF4, 0xF0, 0x00,
- 0xF0, 0x00, 0x20, 0xF2, 0xF0, 0x00, 0x82, 0x61, 0x21, 0x73, 0xF0, 0x00, 0xA0, 0x50, 0x36, 0x70, 0xF0, 0x00, 0xA0, 0x58, 0x23, 0x72, 0xE1, 0x40,
- 0xA8, 0x01, 0x22, 0xF3, 0xF0, 0x00, 0x90, 0x49, 0x22, 0x75, 0xE0, 0x40, 0x80, 0x61, 0x70, 0x00, 0xF0, 0x00, 0x8A, 0x51, 0x33, 0xF1, 0xF0, 0x00,
- 0xA0, 0x58, 0x70, 0x00, 0xF0, 0x00, 0xAF, 0x48, 0x70, 0x00, 0xF0, 0x00, 0xF0, 0x00, 0x34, 0x70, 0xD0, 0x08, 0x82, 0x00, 0x0D, 0x75, 0x60, 0x08,
- 0x90, 0x09, 0x0D, 0x00, 0x60, 0x09, 0xF0, 0x00, 0x35, 0x00, 0xF0, 0x00, 0xF0, 0x00, 0x33, 0x80, 0xC0, 0x28, 0xF0, 0x00, 0x10, 0x10, 0xF0, 0x00,
- 0xF0, 0x00, 0x34, 0x81, 0xD0, 0x08, 0x82, 0x49, 0x0D, 0x75, 0x60, 0x08, 0xF0, 0x00, 0x70, 0x00, 0x8F, 0xFD, 0x04, 0x00, 0x60, 0x00, 0xA0, 0xB1,
- 0x8E, 0xC0, 0x40, 0x00, 0x60, 0x05, 0x60, 0x00, 0x60, 0x05, 0xE6, 0x00, 0xC8, 0x1B, 0x70, 0x00, 0xF0, 0x00, 0xD8, 0xDB, 0x0D, 0x51, 0x60, 0x08,
- 0x83, 0x5B, 0x70, 0x00, 0xF0, 0x00, 0x9E, 0xBA, 0x30, 0x03, 0xF0, 0x00, 0xF0, 0x00, 0x30, 0x84, 0xD4, 0x09, 0xF0, 0x00, 0x70, 0x00, 0x8F, 0xAF,
- 0xF0, 0x00, 0x0D, 0x75, 0x60, 0x08, 0xF0, 0x00, 0x0D, 0x51, 0x60, 0x09, 0xF0, 0x00, 0x24, 0x03, 0xF0, 0x00, 0xF0, 0x00, 0x27, 0x94, 0xD0, 0x08,
- 0xA0, 0x03, 0x70, 0x00, 0xF0, 0x00, 0x00, 0x11, 0x08, 0x00, 0xF0, 0x00, 0x00, 0x11, 0x08, 0x00, 0xC0, 0x0E, 0xA0, 0x09, 0x00, 0x11, 0x08, 0x00,
- 0xA0, 0x09, 0x70, 0x00, 0xF0, 0x00, 0xA4, 0x08, 0x70, 0x00, 0xD0, 0x08, 0xA0, 0x03, 0x70, 0x00, 0xF0, 0x00, 0x00, 0x11, 0x08, 0x00, 0xF0, 0x00,
- 0x00, 0x11, 0x08, 0x00, 0xC0, 0x26, 0xA0, 0x09, 0x00, 0x11, 0x08, 0x00, 0xA0, 0x09, 0x70, 0x00, 0xF0, 0x00, 0xA4, 0x08, 0x70, 0x00, 0xD0, 0x08,
- 0xF0, 0x00, 0x1D, 0x01, 0x60, 0x08, 0xF0, 0x00, 0x0A, 0x2C, 0x60, 0x00, 0xF0, 0x00, 0x01, 0x1A, 0x60, 0x01, 0x31, 0x00, 0x70, 0x00, 0xF0, 0x00,
- 0x31, 0x81, 0x70, 0x00, 0xD0, 0x08, 0x10, 0x00, 0x60, 0x03, 0xA0, 0x93, 0x30, 0x23, 0x07, 0x73, 0xD2, 0x80, 0xF0, 0x00, 0x07, 0xC6, 0xD0, 0x80,
- 0x40, 0xE0, 0x00, 0x1F, 0x60, 0x01, 0x13, 0xD5, 0x60, 0x07, 0xA0, 0x06, 0x13, 0xFB, 0x60, 0x06, 0xF0, 0x00, 0x90, 0x40, 0x0D, 0x28, 0xD2, 0x80,
- 0x14, 0x05, 0x60, 0x06, 0xF0, 0x00, 0xF0, 0x00, 0x0D, 0x28, 0xD2, 0x80, 0x14, 0x0F, 0x60, 0x06, 0xF0, 0x00, 0xF0, 0x00, 0x0D, 0x28, 0xD0, 0x80,
- 0xD7, 0xCA, 0x00, 0xFF, 0x60, 0x04, 0x81, 0xD7, 0x0C, 0xF7, 0x60, 0x09, 0xD0, 0x56, 0x70, 0x00, 0xF0, 0x00, 0x82, 0x76, 0x30, 0x17, 0xF0, 0x00,
- 0xD0, 0xF6, 0x40, 0x83, 0xF0, 0x00, 0xC1, 0xA4, 0x20, 0x19, 0xF0, 0x00, 0x82, 0xF6, 0x70, 0x00, 0xF0, 0x00, 0xC1, 0x80, 0x20, 0x17, 0xA0, 0x81,
- 0xC3, 0xE7, 0x70, 0x00, 0xF0, 0x00, 0xC5, 0xC7, 0x70, 0x00, 0xF0, 0x00, 0xF0, 0x00, 0x10, 0xB1, 0xD0, 0x80, 0x40, 0x00, 0x70, 0x00, 0xAF, 0xF0,
- 0x41, 0xF1, 0x40, 0x40, 0xF0, 0x00, 0xF0, 0x00, 0x10, 0xB2, 0xD0, 0x80, 0x40, 0x71, 0x10, 0xB2, 0xD2, 0x80, 0xF0, 0x00, 0x10, 0x81, 0xD0, 0x80,
- 0xF0, 0x00, 0x0B, 0xC9, 0x60, 0x08, 0xF0, 0x00, 0x1D, 0x8D, 0xD2, 0x80, 0xF0, 0x00, 0x16, 0xD5, 0xD0, 0x80, 0xF0, 0x00, 0x0B, 0xC9, 0x60, 0x08,
- 0xF0, 0x00, 0x1D, 0x8F, 0xD2, 0x80, 0xF0, 0x00, 0x16, 0xDA, 0xD0, 0x80, 0xF0, 0x00, 0x0B, 0x60, 0x60, 0x0E, 0xF0, 0x00, 0x00, 0x04, 0x60, 0x03,
- 0xF0, 0x00, 0x3F, 0xFC, 0x60, 0x04, 0x32, 0x63, 0x80, 0x08, 0x60, 0x05, 0x32, 0xE4, 0x19, 0x9A, 0x60, 0x06, 0x33, 0x65, 0x70, 0x00, 0xF0, 0x00,
- 0x31, 0xE6, 0x70, 0x00, 0xD0, 0x08, 0x83, 0x6D, 0x0C, 0x35, 0x60, 0x08, 0x40, 0x60, 0x39, 0x36, 0x60, 0x01, 0x41, 0xE2, 0x21, 0x96, 0x60, 0x03,
- 0x33, 0x00, 0x41, 0x44, 0xF0, 0x00, 0x33, 0x81, 0x70, 0x00, 0xF0, 0x00, 0x34, 0x02, 0x70, 0x00, 0xF0, 0x00, 0x34, 0x83, 0x70, 0x00, 0xF0, 0x00,
- 0x35, 0x04, 0x70, 0x00, 0xF0, 0x00, 0x35, 0x85, 0x70, 0x00, 0xD0, 0x08, 0xF0, 0x00, 0x70, 0x00, 0xAF, 0x54, 0xF0, 0x00, 0x70, 0x00, 0x8F, 0x99,
- 0xF0, 0x00, 0x70, 0x00, 0xAF, 0x92, 0xF0, 0x00, 0x0C, 0x51, 0xD2, 0x80, 0xF0, 0x00, 0x21, 0xA0, 0xD0, 0x80, 0xF0, 0x00, 0x05, 0x2E, 0xD2, 0x80,
- 0xF0, 0x00, 0x70, 0x00, 0xA0, 0x01, 0xF0, 0x00, 0x21, 0xB7, 0xD0, 0x80, 0xF0, 0x00, 0x20, 0xF0, 0xD2, 0x80, 0x90, 0x02, 0x27, 0xDF, 0xD2, 0x80,
- 0x9E, 0x69, 0x70, 0x00, 0xF0, 0x00, 0xF0, 0x00, 0x07, 0x00, 0xD1, 0x80, 0xF0, 0x00, 0x23, 0x20, 0xD0, 0x80, 0x17, 0x0B, 0x60, 0x0C, 0xA0, 0x41,
- 0x00, 0x40, 0x40, 0x05, 0xF0, 0x00, 0x00, 0x41, 0x24, 0x3F, 0xD0, 0x80, 0xF0, 0x00, 0x70, 0x00, 0xAE, 0xDD, 0xF0, 0x00, 0x0C, 0x8D, 0x60, 0x08,
- 0xF0, 0x00, 0x26, 0x0A, 0xD0, 0x80, 0x83, 0xFF, 0x0D, 0x83, 0x60, 0x08, 0xF0, 0x00, 0x01, 0xF4, 0x60, 0x00, 0xF0, 0x00, 0x03, 0xB1, 0x60, 0x01,
- 0x10, 0x00, 0x03, 0xB2, 0x60, 0x02, 0x10, 0x01, 0x04, 0x0E, 0x60, 0x00, 0x10, 0x02, 0x04, 0x0F, 0x60, 0x01, 0x10, 0x00, 0x04, 0x5C, 0x60, 0x02,
- 0x10, 0x01, 0x04, 0x5D, 0x60, 0x00, 0x10, 0x02, 0x13, 0x80, 0x60, 0x01, 0x10, 0x00, 0x0D, 0x8E, 0x60, 0x09, 0x10, 0x01, 0x02, 0xEE, 0x60, 0x00,
- 0x10, 0x07, 0x43, 0x06, 0x60, 0x01, 0x10, 0x10, 0x04, 0x69, 0x60, 0x02, 0x10, 0x11, 0x44, 0x87, 0x60, 0x00, 0x10, 0x12, 0x05, 0xE3, 0x60, 0x01,
- 0x10, 0x10, 0x46, 0x08, 0x60, 0x02, 0x10, 0x11, 0x06, 0xAE, 0x60, 0x00, 0x10, 0x12, 0x0D, 0x8C, 0x60, 0x08, 0x10, 0x10, 0x9E, 0x3C, 0x60, 0x00,
- 0x10, 0x17, 0x0D, 0x82, 0x60, 0x09, 0x10, 0x00, 0x70, 0x00, 0xF0, 0x00, 0x10, 0x07, 0x70, 0x00, 0xF0, 0x00, 0x10, 0x17, 0x70, 0x00, 0xD0, 0x08,
- 0x0D, 0x83, 0x60, 0x08, 0xA0, 0x24, 0xF0, 0x00, 0x00, 0x02, 0xA0, 0x23, 0x90, 0x82, 0x70, 0x00, 0xF0, 0x00, 0x82, 0x8A, 0x70, 0x00, 0x90, 0x03,
- 0x90, 0x8A, 0x70, 0x00, 0x90, 0x01, 0xF0, 0x00, 0x70, 0x00, 0x8F, 0xFB, 0x82, 0xBF, 0x70, 0x00, 0xF0, 0x00, 0xF0, 0x00, 0x01, 0x99, 0xD2, 0x80,
- 0xF0, 0x00, 0x0D, 0x82, 0x60, 0x08, 0xF0, 0x00, 0x26, 0xC1, 0xF0, 0x00, 0xF0, 0x00, 0x00, 0x02, 0xA0, 0x1A, 0x90, 0x82, 0x70, 0x00, 0xF0, 0x00,
- 0x82, 0x8A, 0x70, 0x00, 0x90, 0x03, 0x90, 0x8A, 0x70, 0x00, 0x90, 0x01, 0xF0, 0x00, 0x70, 0x00, 0x8F, 0xFB, 0x82, 0x80, 0x70, 0x00, 0xF0, 0x00,
- 0xF0, 0x00, 0x70, 0x00, 0xD0, 0x08, 0xF0, 0x00, 0x0D, 0x8E, 0x60, 0x0D, 0xF0, 0x00, 0x3F, 0xFF, 0x60, 0x02, 0xF0, 0x00, 0x00, 0x51, 0xA0, 0x11,
- 0xC2, 0x53, 0x70, 0x00, 0xF0, 0x00, 0x8E, 0xC4, 0x70, 0x00, 0x90, 0x01, 0xF0, 0x00, 0x70, 0x00, 0x97, 0xFC, 0xD4, 0x8F, 0x01, 0x99, 0xD2, 0x80,
- 0x40, 0x05, 0x0D, 0x8C, 0x60, 0x0D, 0x40, 0x17, 0x3F, 0xFF, 0x60, 0x02, 0x9F, 0x7D, 0x00, 0x51, 0xA0, 0x0A, 0xC2, 0x53, 0x70, 0x00, 0xF0, 0x00,
- 0x82, 0xC4, 0x27, 0x1C, 0xD1, 0x80, 0xF0, 0x00, 0x70, 0x00, 0x97, 0xFC, 0x91, 0x46, 0x27, 0x20, 0xD0, 0x80, 0xF0, 0x00, 0x29, 0x15, 0xD2, 0x80,
- 0xF0, 0x00, 0x39, 0x86, 0xD2, 0x80, 0xF0, 0x00, 0x28, 0x88, 0xD0, 0x80, 0x01, 0x52, 0x60, 0x00, 0xF0, 0x00, 0xF0, 0x00, 0x28, 0xDC, 0xD2, 0x80,
- 0xF0, 0x00, 0x28, 0xD5, 0xD0, 0x80, 0xF0, 0x00, 0x70, 0x00, 0xD0, 0x08, 0xF0, 0x00, 0x16, 0xC3, 0x60, 0x08, 0xF0, 0x00, 0x00, 0x9A, 0x60, 0x00,
- 0xF0, 0x00, 0x02, 0xE3, 0x60, 0x00, 0x10, 0x00, 0x04, 0xF4, 0x60, 0x00, 0x10, 0x00, 0x06, 0xFF, 0x60, 0x00, 0x10, 0x00, 0x09, 0x07, 0x60, 0x00,
- 0x10, 0x00, 0x0B, 0x10, 0x60, 0x00, 0x10, 0x00, 0x0D, 0x1F, 0x60, 0x00, 0x10, 0x00, 0x0F, 0x65, 0x60, 0x00, 0x10, 0x00, 0x0F, 0x65, 0x60, 0x00,
- 0x10, 0x00, 0x0D, 0x1F, 0x60, 0x00, 0x10, 0x00, 0x0B, 0x10, 0x60, 0x00, 0x10, 0x00, 0x09, 0x07, 0x60, 0x00, 0x10, 0x00, 0x06, 0xFF, 0x60, 0x00,
- 0x10, 0x00, 0x04, 0xF4, 0x60, 0x00, 0x10, 0x00, 0x02, 0xE3, 0x60, 0x00, 0x10, 0x00, 0x00, 0x9A, 0x60, 0x00, 0xF0, 0x00, 0x10, 0x00, 0xF0, 0x00,
- 0xF0, 0x00, 0x10, 0x00, 0xF0, 0x00, 0xF0, 0x00, 0x16, 0xD3, 0x60, 0x08, 0xF0, 0x00, 0xFF, 0x93, 0x60, 0x00, 0xF0, 0x00, 0xFE, 0x37, 0x60, 0x00,
- 0x10, 0x00, 0xFD, 0xD9, 0x60, 0x00, 0x10, 0x00, 0xFE, 0x9F, 0x60, 0x00, 0x10, 0x00, 0x03, 0x85, 0x60, 0x00, 0x10, 0x00, 0x0D, 0x6B, 0x60, 0x00,
- 0x10, 0x00, 0x16, 0x84, 0x60, 0x00, 0x10, 0x00, 0x1E, 0x49, 0x60, 0x00, 0x10, 0x00, 0x1E, 0x49, 0x60, 0x00, 0x10, 0x00, 0x16, 0x84, 0x60, 0x00,
- 0x10, 0x00, 0x0D, 0x6B, 0x60, 0x00, 0x10, 0x00, 0x03, 0x85, 0x60, 0x00, 0x10, 0x00, 0xFE, 0x9F, 0x60, 0x00, 0x10, 0x00, 0xFD, 0xD9, 0x60, 0x00,
- 0x10, 0x00, 0xFE, 0x37, 0x60, 0x00, 0x10, 0x00, 0xFF, 0x93, 0x60, 0x00, 0xF0, 0x00, 0x10, 0x00, 0xF0, 0x00, 0xF0, 0x00, 0x10, 0x00, 0xF0, 0x00,
- 0xF0, 0x00, 0x16, 0xE3, 0x60, 0x08, 0xF0, 0x00, 0x00, 0x64, 0x60, 0x00, 0xF0, 0x00, 0xFF, 0xA8, 0x60, 0x00, 0x10, 0x00, 0xFF, 0xA6, 0x60, 0x00,
- 0x10, 0x00, 0xFF, 0xDF, 0x60, 0x00, 0x10, 0x00, 0x00, 0x01, 0x60, 0x00, 0x10, 0x00, 0x01, 0x28, 0x60, 0x00, 0x10, 0x00, 0x01, 0x2F, 0x60, 0x00,
- 0x10, 0x00, 0xFD, 0x23, 0x60, 0x00, 0x10, 0x00, 0xFD, 0xA1, 0x60, 0x00, 0x10, 0x00, 0x03, 0x89, 0x60, 0x00, 0x10, 0x00, 0x02, 0x54, 0x60, 0x00,
- 0x10, 0x00, 0x0E, 0xA2, 0x60, 0x00, 0x10, 0x00, 0x0C, 0x47, 0x60, 0x00, 0x10, 0x00, 0xF9, 0x42, 0x60, 0x00, 0x10, 0x00, 0xFB, 0xE1, 0x60, 0x00,
- 0x10, 0x00, 0x00, 0x8C, 0x60, 0x00, 0x10, 0x00, 0xFE, 0x7D, 0x60, 0x00, 0x10, 0x00, 0x02, 0x54, 0x60, 0x00, 0x10, 0x00, 0x03, 0x89, 0x60, 0x00,
- 0x10, 0x00, 0xFD, 0xA1, 0x60, 0x00, 0x10, 0x00, 0xFD, 0x23, 0x60, 0x00, 0x10, 0x00, 0x01, 0x2F, 0x60, 0x00, 0x10, 0x00, 0x01, 0x28, 0x60, 0x00,
- 0x10, 0x00, 0x00, 0x01, 0x60, 0x00, 0x10, 0x00, 0xFF, 0xDF, 0x60, 0x00, 0x10, 0x00, 0xFF, 0xA6, 0x60, 0x00, 0x10, 0x00, 0xFF, 0xA8, 0x60, 0x00,
- 0x10, 0x00, 0x00, 0x64, 0x60, 0x00, 0xF0, 0x00, 0x10, 0x00, 0xF0, 0x00, 0xF0, 0x00, 0x10, 0x00, 0xF0, 0x00, 0xF0, 0x00, 0x17, 0x0B, 0x60, 0x08,
- 0xF0, 0x00, 0x00, 0x03, 0x60, 0x00, 0xF0, 0x00, 0x54, 0xC0, 0x60, 0x00, 0x10, 0x00, 0x00, 0x05, 0x60, 0x00, 0x10, 0x00, 0x00, 0x05, 0x60, 0x00,
- 0x10, 0x00, 0x00, 0x0F, 0x60, 0x00, 0x10, 0x00, 0x00, 0x0F, 0x60, 0x00, 0x10, 0x00, 0x09, 0xC0, 0x60, 0x00, 0x10, 0x00, 0x0A, 0x20, 0x60, 0x00,
- 0x10, 0x00, 0x1D, 0x40, 0x60, 0x00, 0x10, 0x00, 0x1E, 0x60, 0x60, 0x00, 0xF0, 0x00, 0x10, 0x00, 0xF0, 0x00, 0xF0, 0x00, 0x10, 0x00, 0xF0, 0x00,
- 0xF0, 0x00, 0x70, 0x00, 0xD0, 0x08
-};
-
-unsigned char lutByteValues[]=
-{
- /*
- 0x40, 0x13, 0x41, 0x68, 0x41, 0xC1, 0x42, 0x14,
- 0x47, 0xC5, 0x4D, 0x83, 0x4E, 0x49, 0x4E, 0x53,
- 0x4F, 0x92, 0x4F, 0xEA, 0x50, 0x80, 0x56, 0x60,
- 0x56, 0xD4, 0x56, 0xD9, 0x61, 0x9F, 0x61, 0xB6,
- 0x64, 0x3B, 0x66, 0x09, 0x67, 0x0B, 0x67, 0x1A,
- 0x68, 0x87, 0x68, 0xD4
- */
- 0x80, 0x17, 0x80, 0x45, 0x80, 0x96, 0x81, 0x5B,
- 0x82, 0xD6, 0x88, 0x0B, 0x88, 0x10, 0x88, 0xDB,
- 0x89, 0x48, 0x8B, 0x0A, 0x8B, 0x12, 0x8B, 0x13,
- 0x8B, 0x21, 0x8B, 0x26, 0x8C, 0x6F, 0x94, 0xD0,
- 0x95, 0x20, 0x95, 0x33, 0x95, 0x6F, 0x95, 0xA8,
- 0x95, 0xAC, 0x95, 0xC3, 0x95, 0xE1, 0x97, 0xC9,
- 0x97, 0xF6, 0x98, 0x8D, 0x99, 0x00, 0x9A, 0x00,
- 0x9E, 0x73, 0xA0, 0x12, 0xA1, 0x03, 0xA2, 0xF0,
- 0xA3, 0x0D, 0xA3, 0x4C, 0xA3, 0x52, 0xA3, 0xED,
- 0xA8, 0x31, 0xAB, 0x01, 0xAB, 0x1F, 0xAB, 0x4C,
- 0xAC, 0x76, 0xAC, 0x88, 0xAD, 0xB0, 0xAD, 0xB7,
- 0xB0, 0xE2, 0xB1, 0x01, 0xB1, 0x0B, 0xB1, 0x35,
- 0xB1, 0x3B, 0xB1, 0x97, 0xB3, 0x03
-};
-
-const uint32_t patchSize = sizeof(patchByteValues);
-const uint8_t *pPatchBytes = &patchByteValues[0];
-
-const uint32_t lutSize = sizeof(lutByteValues);
-const uint8_t *pLutBytes = &lutByteValues[0];
-
-static const u8 init_para[] = {
-//Set the Band related API settings...
-11, 0x20, 0x0A, 0x01, 0x00, 0x01, 0x09, 0x38, 0x05, 0xDC, 0x05, 0xDC, //FM_BandWidth Auto, FM_Set_Bandwidth (1, 1, 2360, 1500, 1200)
-5, 0x20, 0x14, 0x01, 0x00, 0x01, //FM_MphSuppression, FM_Set_MphSuppression (1, 1)
-//5, 0x20, 0x16, 0x01, 0x00, 0x01,
-7, 0x20, 0x17, 0x01, 0x00, 0x01, 0x05, 0xDC, //FM_NoiseBlanker, FM_Set_NoiseBlanker (1, 1, 1200)
-
-//Set all Weaksignal API settings (LevelOffset)...
-//Set the SoftMute API settings...
-9, 0x20, 0x2A, 0x01, 0x00, 0x03, 0x00, 0x64, 0x00, 0xFA, //FM_SmlMode, FM_Set_SoftMute_Level (1, 3, 100, 250)
-11, 0x20, 0x28, 0x01, 0x00, 0x3C, 0x00, 0x78, 0x00, 0x0A, 0x00, 0x14, //FM_SmSlowAttack,FM_Set_SoftMute_Time (1, 60, 120, 10, 20)
-9, 0x20, 0x2C, 0x01, 0x00, 0x03, 0x01, 0x90, 0x03, 0xE8, //FM_Smm,FM_Set_SoftMute_Mph (1, 3, 400, 1000)
-9, 0x20, 0x2B, 0x01, 0x00, 0x03, 0x01, 0x90, 0x03, 0xE8, //FM_Smn,FM_Set_SoftMute_Noise (1, 3, 400, 1000)
-7, 0x20, 0x2D, 0x01, 0x00, 0x01, 0x00, 0x64, //FM_SmMaximum,FM_Set_SoftMute_Max (1, 1, 100)
-
-//Set the HighCut API settings...
-9, 0x20, 0x34, 0x01, 0x00, 0x01, 0x01, 0xF4, 0x00, 0xC8, //FM_HclMode,FM_Set_HighCut_Level (1, 1, 500, 200)
-11, 0x20, 0x32, 0x01, 0x00, 0x3C, 0x00, 0x78, 0x00, 0x14, 0x00, 0x14, //FM_HcSlowAttack,FM_Set_HighCut_Time (1, 60, 120, 20, 20)
-11, 0x20, 0x33, 0x01, 0x00, 0x01, 0x01, 0x90, 0x00, 0xC8, 0x03, 0x20, //FM_Hco,FM_Set_HighCut_Mod (1, 1, 400, 200, 800)
-9, 0x20, 0x36, 0x01, 0x00, 0x01, 0x00, 0x64, 0x00, 0x64, //FM_Hcm,FM_Set_HighCut_Mph (1, 1, 100, 100)
-9, 0x20, 0x35, 0x01, 0x00, 0x01, 0x00, 0x64, 0x00, 0x64, //FM_Hcn,FM_Set_HighCut_Noise (1, 1, 100, 100)
-7, 0x20, 0x38, 0x01, 0x00, 0x01, 0x3A, 0x98, //FM_HcMinimum,FM_Set_HighCut_Min (1, 1, 15000)
-7, 0x20, 0x3A, 0x01, 0x00, 0x01, 0x00, 0x0A, //FM_HcLowCutMinimum,FM_Set_LowCut_Min (1, 1, 100)
-7, 0x20, 0x37, 0x01, 0x00, 0x01, 0x05, 0xDC, //FM_HcMaximum,FM_Set_HighCut_Max (1, 1, 1500)
-
-//Set the Stereo API settings...
-9, 0x20, 0x3E, 0x01, 0x00, 0x01, 0x01, 0xF4, 0x00, 0xFA, //FM_StlMode,FM_Set_Stereo_Level (1, 1, 500, 250)
-11, 0x20, 0x3C, 0x01, 0x00, 0x3C, 0x00, 0x78, 0x00, 0x0A, 0x00, 0x14, //FM_StSlowAttack,FM_Set_Stereo_Time (1, 60, 120, 10, 20)
-11, 0x20, 0x3D, 0x01, 0x00, 0x01, 0x00, 0xC8, 0x00, 0xC8, 0x03, 0xE8, //FM_Sto,FM_Set_Stereo_Mod (1, 1, 200, 200, 1000)
-9, 0x20, 0x40, 0x01, 0x00, 0x01, 0x00, 0x64, 0x00, 0x64, //FM_Stm,FM_Set_Stereo_Mph (1, 1, 100, 100)
-9, 0x20, 0x3F, 0x01, 0x00, 0x01, 0x00, 0x64, 0x00, 0x64, //FM_Stn,FM_Set_Stereo_Noise (1, 1, 100, 100)
-7, 0x20, 0x39, 0x01, 0x00, 0x01, 0x00, 0x50,
-9, 0x20, 0x4A, 0x01, 0x00, 0x03, 0x00, 0x50, 0x00, 0x80,
-9, 0x20, 0x49, 0x01, 0x00, 0x03, 0x00, 0x50, 0x00, 0x80,
-
-//Set_Deemphasis
-5, 0x20, 0x1F, 0x01, 0x02, 0xEE,
-
-//Set RDS
-9, 0x20, 0x51, 0x01, 0x00, 0x01, 0x00, 0x02, 0x00, 0x02,
-
-//Set the Audio and Application related API settings...
-9, 0x40, 0x03, 0x01, 0x00, 0x00, 0x00, 0x21, 0x00, 0x03, //AM_GPIO 0 Feature
-9, 0x40, 0x03, 0x01, 0x00, 0x01, 0x00, 0x21, 0x00, 0x00, //AM_GPIO 1 Feature
-9, 0x40, 0x03, 0x01, 0x00, 0x02, 0x00, 0x21, 0x00, 0x00, //AM_GPIO 2 Feature
-9, 0x40, 0x03, 0x01, 0x00, 0x00, 0x00, 0x20, 0x01, 0x01, //FM_GPIO 0 Feature set for RDS
-9, 0x40, 0x03, 0x01, 0x00, 0x01, 0x00, 0x20, 0x00, 0x00, //FM_GPIO 1 Feature
-9, 0x40, 0x03, 0x01, 0x00, 0x02, 0x00, 0x20, 0x00, 0x00, //FM_GPIO 2 Feature
-
-5, 0x20, 0x1E, 0x01, 0x00, 0x01 ,
-5, 0x20, 0x54, 0x01, 0x00, 0x00 ,
-7, 0x20, 0x0B, 0x01, 0x03, 0x7A, 0x00, 0x00
-//13, 0x30, 0x16, 0x01, 0x00, 0x21, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x11, 0x3A, //Dig_IO_IIS_SD_1 Mode
-//5, 0x30, 0x0B, 0x01, 0x00, 0x00, //Mute
-//5, 0x30, 0x0A, 0x01, 0xFF, 0xf0, //Volume
-//7, 0x30, 0x0D, 0x01, 0x00, 0x80, 0x00, 0xE0,//Audio Output Source DAC L/R
-};
-
-typedef enum
-{
- eAR_TuningAction_Standby = 0,
- eAR_TuningAction_Preset = 1, /*!< Tune to new program with short mute time */
- eAR_TuningAction_Search = 2, /*!< Tune to new program and stay muted */
- eAR_TuningAction_AF_Update = 3, /*!< Tune to alternative frequency, store quality and tune back with inaudible mute */
- eAR_TuningAction_Jump = 4, /*!< Tune to alternative frequency with short inaudible mute */
- eAR_TuningAction_Check = 5, /*!< Tune to alternative frequency and stay muted */
- eAR_TuningAction_End = 7 /*!< Release the mute of a Search/Check action (frequency is ignored) */
-} AR_TuningAction_t, *pAR_TuningAction_t;
-#endif