Merge pull request #68 from hayguen/development

option '-H' to write wave Header for rtl_sdr and rtl_fm
development
hayati ayguen 2020-08-01 08:11:08 +00:00 committed by GitHub
commit 91dbae89d7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
37 changed files with 5805 additions and 1119 deletions

View File

@ -39,6 +39,9 @@ endif()
OPTION(LINK_RTLTOOLS_AGAINST_STATIC_LIB "Link rtl-tools statically against librtlsdr" OFF)
OPTION(PROVIDE_UDP_SERVER "Provide UDP server for tests" OFF)
OPTION(WITH_RPC "RPC for non-Windows" OFF)
# Set the version information here
set(VERSION_INFO_MAJOR_VERSION 0) # increment major on api compatibility changes
@ -46,6 +49,10 @@ set(VERSION_INFO_MINOR_VERSION 7) # increment minor on feature-level changes
set(VERSION_INFO_PATCH_VERSION git) # increment patch for bug fixes and docs
include(Version) # setup version info
if(PROVIDE_UDP_SERVER AND WIN32)
add_definitions(-DWITH_UDP_SERVER)
endif()
########################################################################
# Compiler specific setup
########################################################################
@ -70,7 +77,7 @@ if(RTL_STATIC_BUILD)
# Special MINGW stuff here
# see https://cmake.org/pipermail/cmake/2012-September/051970.html
# see http://stackoverflow.com/questions/13768515/how-to-do-static-linking-of-libwinpthread-1-dll-in-mingw
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -static-libgcc")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -static-libgcc -static")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static-libgcc -static-libstdc++")
set(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "${CMAKE_SHARED_LIBRARY_LINK_C_FLAGS} -static-libgcc -s")
set(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "${CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS} -static-libgcc -static-libstdc++ -s")

View File

@ -19,6 +19,8 @@ https://osmocom.org/projects/rtl-sdr/wiki
thus can be used without blacklisting dvb_usb_rtl28xxu below /etc/modprobe.d/
- this allows to use a second RTL dongle for use with DVB in parallel
- the IDs can be programmed with 'rtl_eeprom -n' or 'rtl_eeprom -g realtek_sdr'
- for permanent blacklisting you might check/call following from the clone git directory
* ./install-blacklist.sh
# Contributing

View File

@ -0,0 +1,43 @@
/*
* rtl-sdr, turns your Realtek RTL2832 based DVB dongle into a SDR receiver
* Copyright (C) 2019 <>
*
* 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_CONTROL_THREAD_H
#define __RTL_CONTROL_THREAD_H
#ifdef __cplusplus
extern "C" {
#endif
typedef struct
{
rtlsdr_dev_t *dev;
int port;
int wait;
int report_i2c;
char *addr;
int* pDoExit;
}
ctrl_thread_data_t;
void *ctrl_thread_fn(void *arg);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -24,15 +24,17 @@
extern "C" {
#endif
#ifndef WIN32
#define _ENABLE_RPC
#endif
#include <stdint.h>
#include <stddef.h>
#include <rtl-sdr_export.h>
#define RTLSDRLIB_VER_MAJOR 0
#define RTLSDRLIB_VER_MINOR 7
#define RTLSDRLIB_VER_ID "github.com/hayguen"
typedef struct rtlsdr_dev rtlsdr_dev_t;
RTLSDR_API uint32_t rtlsdr_get_device_count(void);
@ -241,6 +243,24 @@ RTLSDR_API int rtlsdr_set_and_get_tuner_bandwidth(rtlsdr_dev_t *dev, uint32_t bw
RTLSDR_API int rtlsdr_set_tuner_bandwidth(rtlsdr_dev_t *dev, uint32_t bw );
/*!
* Sets the center of the filtered tuner band(width)
*
* \param dev the device handle given by rtlsdr_open()
* \param if_band_center_freq in Hz. Zero means, that band center shall be at zero (=default).
* set if_band_center_freq = +samplerate/4 to have the filtered band centered at output's right half.
* \return 0 on success
*/
RTLSDR_API int rtlsdr_set_tuner_band_center(rtlsdr_dev_t *dev, int32_t if_band_center_freq );
/*!
* Set the mixer sideband for the device.
*
* \param dev the device handle given by rtlsdr_open()
* \param sideband mixer sideband 0 means lower sideband, 1 means upper sideband.
* \return 0 on success
*/
RTLSDR_API int rtlsdr_set_tuner_sideband(rtlsdr_dev_t *dev, int sideband);
/*!
* Get actual gain the device is configured to.
@ -254,9 +274,10 @@ RTLSDR_API int rtlsdr_get_tuner_gain(rtlsdr_dev_t *dev);
* Set LNA / Mixer / VGA Device Gain for R820T device is configured to.
*
* \param dev the device handle given by rtlsdr_open()
* \param lna_gain in tenths of a dB, -30 means -3.0 dB.
* \param mixer_gain in tenths of a dB, -30 means -3.0 dB.
* \param vga_gain in tenths of a dB, -30 means -3.0 dB.
* \param lna_gain index in 0 .. 15: 0 == min; see tuner_r82xx.c table r82xx_lna_gain_steps[]
* \param mixer_gain index in 0 .. 15: 0 == min; see tuner_r82xx.c table r82xx_mixer_gain_steps[]
* \param vga_gain index in 0 .. 15: 0 == -12 dB; 15 == 40.5 dB; => 3.5 dB/step;
* see tuner_r82xx.c table r82xx_vga_gain_steps[]
* \return 0 on success
*/
RTLSDR_API int rtlsdr_set_tuner_gain_ext(rtlsdr_dev_t *dev, int lna_gain, int mixer_gain, int vga_gain);
@ -281,6 +302,26 @@ RTLSDR_API int rtlsdr_set_tuner_if_gain(rtlsdr_dev_t *dev, int stage, int gain);
*/
RTLSDR_API int rtlsdr_set_tuner_gain_mode(rtlsdr_dev_t *dev, int manual);
/*!
* Set the agc_variant for automatic gain mode for the device.
* Automatic gain mode must be enabled for the gain setter function to work.
*
* \param dev the device handle given by rtlsdr_open()
* \param if_mode:
* 0 for automatic VGA
* -5000 .. +5000 value range - except 0 - for fixed IF gain in tenths of a dB, 115 means 11.5 dB.
* use -1 or +1 in case you neither want attenuation nor gain.
* this equals the VGA gain for R820T/2 tuner.
* accepted values are in range -47 .. 408 in tenth of a dB == -4.7 .. +40.8 dB.
* the exact values may slightly change with better measured values.
* 10008 for fixed VGA (=default)
* 10000 .. 10015: IF gain == VGA index from parameter if_mode
* set if_mode by index: index := VGA_idx +10000
*
* \return 0 on success
*/
RTLSDR_API int rtlsdr_set_tuner_if_mode(rtlsdr_dev_t *dev, int if_mode);
/*!
* Set the sample rate for the device, also selects the baseband filters
* according to the requested sample rate for tuners where this is possible.
@ -475,6 +516,52 @@ RTLSDR_API int rtlsdr_set_bias_tee(rtlsdr_dev_t *dev, int on);
*/
RTLSDR_API int rtlsdr_set_opt_string(rtlsdr_dev_t *dev, const char *opts, int verbose);
RTLSDR_API const char * rtlsdr_get_opt_help(int longInfo);
/*!
* Exposes/permits hacking of Tuner-specific I2C registers: set register once
*
* \param dev the device handle given by rtlsdr_open()
* \param i2c_register register address
* \param mask 8-bit bitmask, indicating which bits shall be set
* \param data 8-bit data, which shall be set
* \return -1 if device is not initialized. 0 otherwise.
*/
RTLSDR_API int rtlsdr_set_tuner_i2c_register(rtlsdr_dev_t *dev, unsigned i2c_register, unsigned mask, unsigned data);
/* TODO: uint8_t */
RTLSDR_API int rtlsdr_get_tuner_i2c_register(rtlsdr_dev_t *dev, unsigned char* data, int len);
/*!
* Exposes/permits hacking of Tuner-specific I2C registers: set and keep register for future
*
* \param dev the device handle given by rtlsdr_open()
* \param i2c_register register address
* \param mask 8-bit bitmask, indicating which bits shall be set
* \param data 8-bit data, which shall be set; data in 0 .. 255 sets override; data > 255 clears override
* \return -1 if device is not initialized. 0 otherwise.
*/
RTLSDR_API int rtlsdr_set_tuner_i2c_override(rtlsdr_dev_t *dev, unsigned i2c_register, unsigned mask, unsigned data);
/*!
* request version id string to identify source of library
*
* \return pointer to C string, e.g. "github.com/librtlsdr" or "github.com/hayguen" or .. with build date
* string keeps owned by library
*/
RTLSDR_API const char * rtlsdr_get_ver_id();
/*!
* request version numbers of library
*
* \return major version in upper 16 bit, minor revision in lower 16 bit
*/
RTLSDR_API uint32_t rtlsdr_get_version();
#ifdef __cplusplus
}
#endif

View File

@ -26,6 +26,9 @@ extern "C" {
/*!
* This enum defines the possible commands in rtl_tcp
* commands 0x01..0x0E are compatible to osmocom's rtlsdr
* see https://github.com/osmocom/rtl-sdr/blob/master/src/rtl_tcp.c
* commands >= 0x40 are extensions
*/
enum RTL_TCP_COMMANDS {
SET_FREQUENCY = 0x01,
@ -41,10 +44,30 @@ enum RTL_TCP_COMMANDS {
SET_RTL_CRYSTAL = 0x0B,
SET_TUNER_CRYSTAL = 0x0C,
SET_TUNER_GAIN_BY_INDEX = 0x0D,
#if 1
/* development branch since 2018-10-03 */
SET_BIAS_TEE = 0x0E,
SET_TUNER_BANDWIDTH = 0x40,
#else
/* prev code - used in ExtIO - to build compatible rtl_tcp.exe */
SET_TUNER_BANDWIDTH = 0x0E,
SET_BIAS_TEE = 0x0F
#endif
UDP_ESTABLISH = 0x41,
UDP_TERMINATE = 0x42
UDP_TERMINATE = 0x42,
SET_I2C_TUNER_REGISTER = 0x43, /* for experiments: 32 bit data word:
* 31 .. 20: register (12 bits)
* 19 .. 12: mask (8 bits)
* 11 .. 0: data (12 bits) */
SET_I2C_TUNER_OVERRIDE = 0x44, /* encoding as with SET_I2C_TUNER_REGISTER
* data (bits 11 .. 0) > 255 removes override */
SET_TUNER_BW_IF_CENTER = 0x45, /* freq from SET_FREQUENCY stays in center;
* the bandwidth (from SET_TUNER_BANDWIDTH)
* is set to be centered at given IF frequency */
SET_TUNER_IF_MODE = 0x46, /* set tuner IF mode - or gain */
SET_SIDEBAND = 0x47, /* Mixer Sideband for R820T */
REPORT_I2C_REGS = 0x48, /* perodically report I2C registers
* - if reverse channel is enabled */
};
#ifdef __cplusplus

View File

@ -32,5 +32,7 @@
int fc0012_init(void *dev);
int fc0012_set_params(void *dev, uint32_t freq, uint32_t bandwidth);
int fc0012_set_gain(void *dev, int gain);
int fc0012_set_i2c_register(void *dev, unsigned i2c_register, unsigned data);
int fc0012_get_i2c_register(void *dev, unsigned char* data, int len);
#endif

View File

@ -35,12 +35,14 @@
#define R82XX_IF_FREQ 3570000
#define REG_SHADOW_START 5
#define NUM_REGS 30
#define NUM_REGS 32
#define NUM_IMR 5
#define IMR_TRIAL 9
#define VER_NUM 49
#define USE_R82XX_ENV_VARS 1
enum r82xx_chip {
CHIP_R820T,
CHIP_R620D,
@ -77,19 +79,47 @@ struct r82xx_priv {
uint8_t regs[NUM_REGS];
uint8_t buf[NUM_REGS + 1];
uint8_t override_data[NUM_REGS];
uint8_t override_mask[NUM_REGS];
enum r82xx_xtal_cap_value xtal_cap_sel;
uint16_t pll; /* kHz */
uint32_t int_freq;
int32_t if_band_center_freq;
uint8_t fil_cal_code;
uint8_t input;
int has_lock;
int init_done;
int sideband;
/* Store current mode */
uint32_t delsys;
enum r82xx_tuner_type type;
uint32_t bw; /* in MHz */
void *rtl_dev;
int last_if_mode;
int last_manual_gain;
int last_extended_mode;
int last_LNA_value;
int last_Mixer_value;
int last_VGA_value;
#if USE_R82XX_ENV_VARS
/* store some environment variables */
int printI2C;
unsigned int filterCenter;
unsigned int haveR9, valR9;
unsigned int haveR10L, valR10L;
unsigned int haveR10H, valR10H;
unsigned int haveR11L, valR11L;
unsigned int haveR11H, valR11H;
unsigned int haveR13L, valR13L;
unsigned int haveR13H, valR13H;
unsigned int haveR14L, valR14L;
unsigned int haveR14H, valR14H;
unsigned int haveR30H, valR30H;
unsigned int haveR30L, valR30L;
#endif
};
struct r82xx_freq_range {
@ -112,9 +142,21 @@ enum r82xx_delivery_system {
int r82xx_standby(struct r82xx_priv *priv);
int r82xx_init(struct r82xx_priv *priv);
int r82xx_set_freq(struct r82xx_priv *priv, uint32_t freq);
//int r82xx_set_gain(struct r82xx_priv *priv, int set_manual_gain, int gain);
int r82xx_set_gain(struct r82xx_priv *priv, int set_manual_gain, int gain, int extended_mode, int lna_gain, int mixer_gain, int vga_gain);
int r82xx_set_gain(struct r82xx_priv *priv, int set_manual_gain, int gain, int extended_mode, int lna_gain, int mixer_gain, int vga_gain, int *rtl_vga_control);
int r82xx_set_if_mode(struct r82xx_priv *priv, int if_mode, int *rtl_vga_control);
int r82xx_set_i2c_register(struct r82xx_priv *priv, unsigned i2c_register, unsigned data, unsigned mask);
int r82xx_get_i2c_register(struct r82xx_priv *priv, unsigned char* data, int len);
int r82xx_set_i2c_override(struct r82xx_priv *priv, unsigned i2c_register, unsigned data, unsigned mask);
int r82xx_set_bandwidth(struct r82xx_priv *priv, int bandwidth, uint32_t rate, uint32_t * applied_bw, int apply);
int r82xx_set_bw_center(struct r82xx_priv *priv, int32_t if_band_center_freq);
/* Mixer Sideband: 0: lower, 1: upper */
int r82xx_set_sideband(struct r82xx_priv *priv, int sideband);
int r82xx_read_cache_reg(struct r82xx_priv *priv, int reg);
int r82xx_write_reg_mask(struct r82xx_priv *priv, uint8_t reg, uint8_t val,uint8_t bit_mask);
int r82xx_write_reg_mask_ext(struct r82xx_priv *priv, uint8_t reg, uint8_t val, uint8_t bit_mask, const char * func_name);
#endif

View File

@ -0,0 +1,26 @@
#!/bin/bash
BLACKLIST_FN=""
if [ -f /etc/modprobe.d/rtlsdr-blacklist.conf ]; then
BLACKLIST_FN="rtlsdr-blacklist.conf"
echo "found /etc/modprobe.d/${BLACKLIST_FN}"
elif [ -f /etc/modprobe.d/blacklist-rtl8xxxu.conf ]; then
BLACKLIST_FN="blacklist-rtl8xxxu.conf"
echo "found /etc/modprobe.d/${BLACKLIST_FN}"
elif [ -f /etc/modprobe.d/raspi-blacklist.conf ]; then
BLACKLIST_FN="raspi-blacklist.conf"
echo "found /etc/modprobe.d/${BLACKLIST_FN}"
else
BLACKLIST_FN="rtlsdr-blacklist.conf"
echo "could not find existing blacklist. will use /etc/modprobe.d/${BLACKLIST_FN}"
fi
if [ -f /etc/modprobe.d/${BLACKLIST_FN} ]; then
cat /etc/modprobe.d/${BLACKLIST_FN} rtlsdr-blacklist.conf | sort | uniq >/dev/shm/${BLACKLIST_FN}
cp /dev/shm/${BLACKLIST_FN} /etc/modprobe.d/${BLACKLIST_FN}
echo "updated /etc/modprobe.d/${BLACKLIST_FN} ; reboot to apply"
else
cp rtlsdr-blacklist.conf /etc/modprobe.d/${BLACKLIST_FN}
echo "created /etc/modprobe.d/${BLACKLIST_FN} ; reboot to apply"
fi

View File

@ -0,0 +1,81 @@
The command protocol of rtl_tcp is on port 1234 (by default):
=============================================================
Commands are directed from a client application towards rtl_tcp.
Each command consists of 2 fields:
1- command_id: value of enum RTL_TCP_COMMANDS, defined in rtl_tcp.h.
This element is an unsigned character, starting at offset 0
with length: 1 byte.
2- parameter: depends on the command id,
e.g. is a frequency for SET_FREQUENCY.
This element is a (signed or unsigned) 32 bit integer,
starting at offset 1 with length: 4 bytes.
Both fields are in Network Byte Order (Big Endian).
Size of one command is 3 bytes, without padding.
Reverse direction on command connection:
========================================
With accepting a connection, rtl_tcp initially transmits some dongle_info.
The dongle_info consists of 3 fields:
1- magic string: identifies the rtl_tcp protocol. The value is "RTL0".
This element is a fixed size string, starting at offset 0
with length 4 bytes.
2- tuner type: identifies the tuner chip built in the controlled RTL-SDR model,
e.g. E4000 or R820T.
This element is an unsigned 32 bit integer, starting at offset 4
with length: 4 bytes.
3- tuner gain count: reports the number of available gain values,
necessary for the command SET_TUNER_GAIN_BY_INDEX.
This element is an unsigned 32 bit integer, starting at offset 8
with length: 4 bytes.
Both fields are in Network Byte Order (Big Endian).
Size of one dongle_info is 12 bytes, without padding.
After that initial dongle_info, from offset 12 byte, just raw I/Q data is transferred.
For each I/Q frame, in the commanded samplerate, I and Q values are transferred,
each as unsigned 8 bit sample. Thus one I/Q-frame is 2 bytes, each frame 1 byte.
Response channel:
=================
The command channel does not allow specific response on commands.
This is why an additional response channel got necessary.
rtl_tcp now offers an additional tcp server "response" channel,
by default, on the next port as the command protocol.
Thus, by default on port 1235.
Each response from rtl_tcp to the client consists of 3 fields:
1- command_id: references the command, which generated this response.
It's value is also the enum RTL_TCP_COMMANDS, defined in rtl_tcp.h.
This element is an unsigned character, starting at offset 0
with length: 1 byte.
2- length_of_content: defines the number of bytes following this field at offset 3.
The length is necessary to allow responses with different lengths.
This element is an unsigned 16 bit integer, starting at offset 1
with length: 2 bytes. 0 is interpreted as 65536!
It is strongly recommended to limit the response to 32768 bytes in total.
3- content: the content is command specific and might contain up to 65536 bytes.
The content starts at offset 3.
All fields are in Network Byte Order (Big Endian).
Size of one response is (3 + length_of_content), without padding.

View File

@ -0,0 +1,6 @@
blacklist dvb_usb_rtl28xxu
blacklist dvb_usb_v2
blacklist rtl_2830
blacklist rtl_2832
blacklist r820t
blacklist rtl8xxxu

View File

@ -21,18 +21,6 @@ MACRO(RTLSDR_APPEND_SRCS)
LIST(APPEND rtlsdr_srcs ${ARGV})
ENDMACRO(RTLSDR_APPEND_SRCS)
if(NOT WIN32)
RTLSDR_APPEND_SRCS(
librtlsdr.c
tuner_e4k.c
tuner_fc0012.c
tuner_fc0013.c
tuner_fc2580.c
tuner_r82xx.c
rtlsdr_rpc.c
rtlsdr_rpc_msg.c
)
else()
RTLSDR_APPEND_SRCS(
librtlsdr.c
tuner_e4k.c
@ -41,6 +29,11 @@ RTLSDR_APPEND_SRCS(
tuner_fc2580.c
tuner_r82xx.c
)
if(WITH_RPC)
RTLSDR_APPEND_SRCS(
rtlsdr_rpc.c
rtlsdr_rpc_msg.c
)
endif()
########################################################################
@ -61,7 +54,15 @@ ENDIF(MSVC)
# Setup shared library variant
########################################################################
add_library(rtlsdr_shared SHARED ${rtlsdr_srcs})
target_link_libraries(rtlsdr_shared ${LIBUSB_LIBRARIES})
if(NOT WIN32)
target_link_libraries(rtlsdr_shared ${LIBUSB_LIBRARIES})
else()
target_link_libraries(rtlsdr_shared ws2_32 ${LIBUSB_LIBRARIES})
endif()
if (WITH_RPC)
target_compile_definitions(rtlsdr_shared PUBLIC _ENABLE_RPC)
endif()
set_target_properties(rtlsdr_shared PROPERTIES DEFINE_SYMBOL "rtlsdr_EXPORTS")
set_target_properties(rtlsdr_shared PROPERTIES OUTPUT_NAME rtlsdr)
set_target_properties(rtlsdr_shared PROPERTIES SOVERSION ${MAJOR_VERSION})
@ -71,11 +72,20 @@ set_target_properties(rtlsdr_shared PROPERTIES VERSION ${LIBVER})
# Setup static library variant
########################################################################
add_library(rtlsdr_static STATIC ${rtlsdr_srcs})
target_link_libraries(rtlsdr_static ${LIBUSB_LIBRARIES})
if(NOT WIN32)
target_link_libraries(rtlsdr_static ${LIBUSB_LIBRARIES})
else()
target_link_libraries(rtlsdr_static ws2_32 ${LIBUSB_LIBRARIES})
endif()
if (WITH_RPC)
target_compile_definitions(rtlsdr_static PUBLIC _ENABLE_RPC)
endif()
set_property(TARGET rtlsdr_static APPEND PROPERTY COMPILE_DEFINITIONS "rtlsdr_STATIC" )
if(NOT WIN32)
# Force same library filename for static and shared variants of the library
set_target_properties(rtlsdr_static PROPERTIES OUTPUT_NAME rtlsdr)
# Force same library filename for static and shared variants of the library
set_target_properties(rtlsdr_static PROPERTIES OUTPUT_NAME rtlsdr)
endif()
@ -84,16 +94,16 @@ endif()
########################################################################
if(LINK_RTLTOOLS_AGAINST_STATIC_LIB)
set(RTLSDR_TOOL_LIB rtlsdr_static)
set(RTLSDR_TOOL_LIB rtlsdr_static)
else()
set(RTLSDR_TOOL_LIB rtlsdr_shared)
set(RTLSDR_TOOL_LIB rtlsdr_shared)
endif()
########################################################################
# Setup libraries used in executables
########################################################################
add_library(convenience_static STATIC
convenience/convenience.c
convenience/rtl_convenience.c convenience/convenience.c convenience/wavewrite.c
)
if(WIN32)
@ -109,7 +119,7 @@ endif()
# Build utility
########################################################################
add_executable(rtl_sdr rtl_sdr.c)
add_executable(rtl_tcp rtl_tcp.c)
add_executable(rtl_tcp rtl_tcp.c controlThread.c)
add_executable(rtl_udp rtl_udp.c)
add_executable(rtl_test rtl_test.c)
add_executable(rtl_fm rtl_fm.c)
@ -117,11 +127,15 @@ add_executable(rtl_ir rtl_ir.c)
add_executable(rtl_eeprom rtl_eeprom.c)
add_executable(rtl_adsb rtl_adsb.c)
add_executable(rtl_power rtl_power.c)
if (NOT WIN32)
add_executable(rtl_raw2wav rtl_raw2wav.c convenience/convenience.c convenience/wavewrite.c)
add_executable(rtl_wavestat rtl_wavestat.c convenience/convenience.c convenience/waveread.c)
add_executable(rtl_wavestream rtl_wavestream.c convenience/convenience.c convenience/waveread.c)
if (WITH_RPC)
add_executable(rtl_rpcd rtl_rpcd.c rtlsdr_rpc_msg.c)
set(INSTALL_TARGETS rtlsdr_shared rtlsdr_static rtl_sdr rtl_tcp rtl_udp rtl_test rtl_fm rtl_ir rtl_eeprom rtl_adsb rtl_power rtl_rpcd)
set(INSTALL_TARGETS rtlsdr_shared rtlsdr_static rtl_sdr rtl_tcp rtl_udp rtl_test rtl_fm rtl_ir rtl_eeprom rtl_adsb rtl_power rtl_raw2wav rtl_wavestat rtl_wavestream rtl_rpcd)
else()
set(INSTALL_TARGETS rtlsdr_shared rtlsdr_static rtl_sdr rtl_tcp rtl_udp rtl_test rtl_fm rtl_ir rtl_eeprom rtl_adsb rtl_power)
set(INSTALL_TARGETS rtlsdr_shared rtlsdr_static rtl_sdr rtl_tcp rtl_udp rtl_test rtl_fm rtl_ir rtl_eeprom rtl_adsb rtl_power rtl_raw2wav rtl_wavestat rtl_wavestream)
endif()
target_link_libraries(rtl_sdr ${RTLSDR_TOOL_LIB} convenience_static
@ -160,46 +174,57 @@ target_link_libraries(rtl_power ${RTLSDR_TOOL_LIB} convenience_static
${LIBUSB_LIBRARIES}
${CMAKE_THREAD_LIBS_INIT}
)
if(NOT WIN32)
target_link_libraries(rtl_rpcd ${RTLSDR_TOOL_LIB} convenience_static
${LIBUSB_LIBRARIES}
${CMAKE_THREAD_LIBS_INIT}
)
if(WITH_RPC)
target_link_libraries(rtl_rpcd ${RTLSDR_TOOL_LIB} convenience_static
${LIBUSB_LIBRARIES}
${CMAKE_THREAD_LIBS_INIT}
)
endif()
if(UNIX)
target_link_libraries(rtl_fm m)
target_link_libraries(rtl_ir m)
target_link_libraries(rtl_adsb m)
target_link_libraries(rtl_power m)
if(APPLE)
target_link_libraries(rtl_test m)
else()
target_link_libraries(rtl_test m rt)
endif()
target_link_libraries(rtl_fm m)
target_link_libraries(rtl_ir m)
target_link_libraries(rtl_adsb m)
target_link_libraries(rtl_power m)
target_link_libraries(rtl_raw2wav m)
target_link_libraries(rtl_wavestat m)
target_link_libraries(rtl_wavestream m)
if(APPLE)
target_link_libraries(rtl_test m)
else()
target_link_libraries(rtl_test m rt)
endif()
endif()
if(WIN32)
target_link_libraries(rtl_sdr libgetopt_static)
target_link_libraries(rtl_tcp ws2_32 libgetopt_static)
target_link_libraries(rtl_udp ws2_32 libgetopt_static)
target_link_libraries(rtl_test libgetopt_static)
target_link_libraries(rtl_fm libgetopt_static)
target_link_libraries(rtl_ir libgetopt_static)
target_link_libraries(rtl_eeprom libgetopt_static)
target_link_libraries(rtl_adsb libgetopt_static)
target_link_libraries(rtl_power libgetopt_static)
#target_link_libraries(rtl_rpcd ws2_32 libgetopt_static)
set_property(TARGET rtl_sdr APPEND PROPERTY COMPILE_DEFINITIONS "rtlsdr_STATIC" )
set_property(TARGET rtl_tcp APPEND PROPERTY COMPILE_DEFINITIONS "rtlsdr_STATIC" )
set_property(TARGET rtl_udp APPEND PROPERTY COMPILE_DEFINITIONS "rtlsdr_STATIC" )
set_property(TARGET rtl_test APPEND PROPERTY COMPILE_DEFINITIONS "rtlsdr_STATIC" )
set_property(TARGET rtl_fm APPEND PROPERTY COMPILE_DEFINITIONS "rtlsdr_STATIC" )
set_property(TARGET rtl_ir APPEND PROPERTY COMPILE_DEFINITIONS "rtlsdr_STATIC" )
set_property(TARGET rtl_eeprom APPEND PROPERTY COMPILE_DEFINITIONS "rtlsdr_STATIC" )
set_property(TARGET rtl_adsb APPEND PROPERTY COMPILE_DEFINITIONS "rtlsdr_STATIC" )
set_property(TARGET rtl_power APPEND PROPERTY COMPILE_DEFINITIONS "rtlsdr_STATIC" )
#set_property(TARGET rtl_rpcd APPEND PROPERTY COMPILE_DEFINITIONS "rtlsdr_STATIC" )
target_link_libraries(rtl_sdr libgetopt_static)
target_link_libraries(rtl_tcp ws2_32 libgetopt_static)
target_link_libraries(rtl_udp ws2_32 libgetopt_static)
target_link_libraries(rtl_test libgetopt_static)
target_link_libraries(rtl_fm libgetopt_static)
target_link_libraries(rtl_ir libgetopt_static)
target_link_libraries(rtl_eeprom libgetopt_static)
target_link_libraries(rtl_adsb libgetopt_static)
target_link_libraries(rtl_power libgetopt_static)
target_link_libraries(rtl_raw2wav libgetopt_static m)
target_link_libraries(rtl_wavestat libgetopt_static m)
target_link_libraries(rtl_wavestream libgetopt_static m)
set_property(TARGET rtl_sdr APPEND PROPERTY COMPILE_DEFINITIONS "rtlsdr_STATIC" )
set_property(TARGET rtl_tcp APPEND PROPERTY COMPILE_DEFINITIONS "rtlsdr_STATIC" )
set_property(TARGET rtl_udp APPEND PROPERTY COMPILE_DEFINITIONS "rtlsdr_STATIC" )
set_property(TARGET rtl_test APPEND PROPERTY COMPILE_DEFINITIONS "rtlsdr_STATIC" )
set_property(TARGET rtl_fm APPEND PROPERTY COMPILE_DEFINITIONS "rtlsdr_STATIC" )
set_property(TARGET rtl_ir APPEND PROPERTY COMPILE_DEFINITIONS "rtlsdr_STATIC" )
set_property(TARGET rtl_eeprom APPEND PROPERTY COMPILE_DEFINITIONS "rtlsdr_STATIC" )
set_property(TARGET rtl_adsb APPEND PROPERTY COMPILE_DEFINITIONS "rtlsdr_STATIC" )
set_property(TARGET rtl_power APPEND PROPERTY COMPILE_DEFINITIONS "rtlsdr_STATIC" )
set_property(TARGET rtl_raw2wav APPEND PROPERTY COMPILE_DEFINITIONS "rtlsdr_STATIC" )
set_property(TARGET rtl_wavestat APPEND PROPERTY COMPILE_DEFINITIONS "rtlsdr_STATIC" )
set_property(TARGET rtl_wavestream APPEND PROPERTY COMPILE_DEFINITIONS "rtlsdr_STATIC" )
if (WITH_RPC)
target_link_libraries(rtl_rpcd ws2_32 libgetopt_static)
set_property(TARGET rtl_rpcd APPEND PROPERTY COMPILE_DEFINITIONS "rtlsdr_STATIC" )
endif()
endif()
########################################################################
# Install built library files & utilities

231
src/controlThread.c 100644
View File

@ -0,0 +1,231 @@
/*
* 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-2013 by Hoernchen <la@tfc-server.de>
*
* 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/>.
*/
#include <errno.h>
#include <signal.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#ifndef _WIN32
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <fcntl.h>
#else
#include <winsock2.h>
#include "getopt/getopt.h"
#define usleep(x) Sleep(x/1000)
#endif
#ifdef NEED_PTHREADS_WORKARROUND
#define HAVE_STRUCT_TIMESPEC
#endif
#include <pthread.h>
#include "rtl-sdr.h"
#include "rtl_tcp.h"
#include "controlThread.h"
#include "convenience/convenience.h"
#include "convenience/rtl_convenience.h"
#include "tuner_r82xx.h"
#ifdef _WIN32
#pragma comment(lib, "ws2_32.lib")
typedef int socklen_t;
#else
#define closesocket close
#define SOCKADDR struct sockaddr
#define SOCKET int
#define SOCKET_ERROR -1
#endif
/* we need a message id in the protocol: 1st 2 byte (little endian) == message id */
#define USE_MSGID_IN_PROTOCOL 1
#define NUM_I2C_REGISTERS 32
#define TX_BUF_LEN (NUM_I2C_REGISTERS +4) //2 len, 1 head, 1 tail
ctrl_thread_data_t ctrl_thread_data;
void *ctrl_thread_fn(void *arg)
{
unsigned char reg_values [NUM_I2C_REGISTERS];
#if USE_MSGID_IN_PROTOCOL
unsigned char txbuf [2+2 +1+NUM_I2C_REGISTERS+1]; //2 type, 2 length, 1 head, 1 tail
#else
unsigned char txbuf [NUM_I2C_REGISTERS+4]; //2 length, 1 head, 1 tail
#endif
int r = 1;
struct timeval tv = { 1,0 };
struct linger ling = { 1,0 };
SOCKET listensocket;
SOCKET controlSocket;
int haveControlSocket = 0;
struct sockaddr_in local, remote;
socklen_t rlen;
int error = 0;
int ret = 0, len, result;
fd_set connfds;
fd_set writefds;
int bytesleft, bytessent, index;
ctrl_thread_data_t *data = (ctrl_thread_data_t *)arg;
rtlsdr_dev_t *dev = data->dev;
int port = data->port;
int wait = data->wait;
int report_i2c = data->report_i2c;
char *addr = data->addr;
int* do_exit = data->pDoExit;
u_long blockmode = 1;
int retval;
memset(reg_values, 0, NUM_I2C_REGISTERS);
memset(&local, 0, sizeof(local));
local.sin_family = AF_INET;
local.sin_port = htons(port);
local.sin_addr.s_addr = inet_addr(addr);
listensocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
setsockopt(listensocket, SOL_SOCKET, SO_REUSEADDR, (char *)&r, sizeof(int));
setsockopt(listensocket, SOL_SOCKET, SO_LINGER, (char *)&ling, sizeof(ling));
retval = bind(listensocket, (struct sockaddr *)&local, sizeof(local));
if (retval == SOCKET_ERROR)
error = 1;
#ifdef _WIN32
ioctlsocket(listensocket, FIONBIO, &blockmode);
#else
r = fcntl(listensocket, F_GETFL, 0);
r = fcntl(listensocket, F_SETFL, r | O_NONBLOCK);
#endif
while (1) {
printf("listening on Control port %d...\n", port);
retval = listen(listensocket, 1);
if (retval == SOCKET_ERROR)
error = 1;
while (1) {
FD_ZERO(&connfds);
FD_SET(listensocket, &connfds);
tv.tv_sec = 1;
tv.tv_usec = 0;
r = select(listensocket + 1, &connfds, NULL, NULL, &tv);
if (*do_exit) {
goto close;
}
else if (r) {
rlen = sizeof(remote);
controlSocket = accept(listensocket, (struct sockaddr *)&remote, &rlen);
haveControlSocket = 1;
break;
}
}
setsockopt(controlSocket, SOL_SOCKET, SO_LINGER, (char *)&ling, sizeof(ling));
printf("Control client accepted!\n");
usleep(5000000);
while (1) {
/* check if i2c reporting is to be (de)activated */
if ( report_i2c && !data->report_i2c )
report_i2c = 0;
else if ( !report_i2c && data->report_i2c )
report_i2c = 1;
/* @TODO: check if something else has to be transmitted */
if ( !report_i2c )
goto sleep;
result = rtlsdr_get_tuner_i2c_register(dev, reg_values, NUM_I2C_REGISTERS);
/* printf("rtlsdr_get_tuner_i2c_register\n"); */
memset(txbuf, 0, TX_BUF_LEN);
if (result)
goto sleep;
/* Little Endian */
len = 0;
/* we need some message id: use enum RTL_TCP_COMMANDS */
#if USE_MSGID_IN_PROTOCOL
txbuf[len++] = REPORT_I2C_REGS & 0x0FF;
txbuf[len++] = (REPORT_I2C_REGS >> 8) & 0x0FF;
/* following message length in Little Endian */
txbuf[len++] = TX_BUF_LEN - 2 - 2; /* sub message id and length field */
#else
txbuf[len++] = TX_BUF_LEN - 2; /* sub message id and length field */
#endif
txbuf[len++] = 0;
/* now the message contents */
txbuf[len++] = 0x55; /* @CS: do we need this? */
memcpy(&txbuf[len], reg_values, NUM_I2C_REGISTERS);
txbuf[TX_BUF_LEN - 1] = 0xaa; /* @CS: do we need this? */
len = sizeof(txbuf);
/* now start (possibly blocking) transmission */
bytessent = 0;
bytesleft = len;
index = 0;
while (bytesleft > 0) {
FD_ZERO(&writefds);
FD_SET(controlSocket, &writefds);
tv.tv_sec = 1;
tv.tv_usec = 0;
r = select(controlSocket + 1, NULL, &writefds, NULL, &tv);
if (r) {
bytessent = send(controlSocket, &txbuf[index], bytesleft, 0);
bytesleft -= bytessent;
index += bytessent;
}
if (bytessent == SOCKET_ERROR || *do_exit) {
goto close;
}
}
sleep:
usleep(wait);
}
close:
if (haveControlSocket)
closesocket(controlSocket);
if (*do_exit)
{
closesocket(listensocket);
printf("Control Thread terminates\n");
break;
}
}
return 0;
}

341
src/convenience/convenience.c 100755 → 100644
View File

@ -23,9 +23,12 @@
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <time.h>
#include <assert.h>
#ifndef _WIN32
#include <unistd.h>
#include <sys/time.h>
#else
#include <windows.h>
#include <fcntl.h>
@ -36,7 +39,6 @@
#include <math.h>
#include "rtl-sdr.h"
double atofs(char *s)
/* standard suffixes */
@ -117,221 +119,141 @@ double atofp(char *s)
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;
static struct tm * str_to_tm( const char * str, struct tm * t, double * fraction ) {
char b[16];
int k, v;
/* 0 1 2 */
/* 01234567890123456789012 */
/* 2019-09-15T01:53:20.234 - mostly ISO 8601 */
*fraction = 0.0;
t->tm_sec = 0;
t->tm_min = 0;
t->tm_hour = 0;
t->tm_mday = 1;
t->tm_mon = 0;
t->tm_year = 0;
t->tm_wday = 0;
t->tm_yday = 0;
t->tm_isdst = -1;
/* date */
if ( (str[4] == '-' || str[4] == '/') && str[4] == str[7] ) {
/* year */
b[4] = 0; for ( k = 0; k < 4; ++k ) b[k] = str[k];
v = atoi(b);
t->tm_year = v - 1900;
/* month */
b[2] = 0; for ( k = 0; k < 2; ++k ) b[k] = str[5+k];
v = atoi(b);
if (v < 1 || v > 12)
return NULL;
t->tm_mon = v - 1;
/* day */
b[2] = 0; for ( k = 0; k < 2; ++k ) b[k] = str[8+k];
v = atoi(b);
if (v < 1 || v > 31)
return NULL;
t->tm_mday = v;
} else
return NULL;
if (str[10] == 0 )
return t;
/* time */
if ( str[10] != 'T' && str[10] != ' ' && str[10] != '_' )
return NULL;
if ( (str[13] == ':' || str[13] == '/') && str[13] == str[16] ) {
/* hour */
b[2] = 0; for ( k = 0; k < 2; ++k ) b[k] = str[11+k];
v = atoi(b);
if (v < 0 || v > 23)
return NULL;
t->tm_hour = v;
/* minute */
b[2] = 0; for ( k = 0; k < 2; ++k ) b[k] = str[14+k];
v = atoi(b);
if (v < 0 || v > 59)
return NULL;
t->tm_min = v;
/* second */
b[2] = 0; for ( k = 0; k < 2; ++k ) b[k] = str[17+k];
v = atoi(b);
if (v < 0 || v > 61)
return NULL;
t->tm_sec = v;
} else
return NULL;
if (str[19] == 0 )
return t;
/* fraction */
if ( str[19] == '.' && str[19] == ',' ) {
for ( k = 0; k < 16; ++k ) b[k] = 0;
strcpy(b, "0.");
strncpy(&b[2], &str[20], 12);
*fraction = atof(b);
return t;
}
count = rtlsdr_get_tuner_gains(dev, NULL);
if (count <= 0) {
/* return t anyway .. without fraction */
return t;
}
time_t utctimestr_to_time(const char * str, double * fraction) {
struct tm t;
struct tm *p;
#ifdef _WIN32
struct tm gtm;
struct tm ltm;
time_t nt;
time_t gt;
time_t lt;
#endif
p = str_to_tm( str, &t, fraction );
if (!p)
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;
p->tm_isdst = 0;
#ifndef _WIN32
return timegm(p);
#else
#ifdef _MSC_VER
return _mkgmtime(p);
#else
/* workaround missing mkgmtime on mingw */
nt = mktime(p);
gtm = *gmtime(&nt);
ltm = *localtime(&nt);
gt = mktime(&gtm);
lt = mktime(&ltm);
assert( nt == gt );
nt += ( lt - gt );
return nt;
#endif
#endif
}
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;
time_t localtimestr_to_time(const char * str, double * fraction) {
struct tm t;
struct tm *p;
p = str_to_tm( str, &t, fraction );
if (!p)
return 0;
#ifndef _WIN32
return timelocal(p);
#else
return mktime(p);
#endif
}
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_set_bandwidth(rtlsdr_dev_t *dev, uint32_t bandwidth)
{
int r;
uint32_t applied_bw = 0;
/* r = rtlsdr_set_tuner_bandwidth(dev, bandwidth); */
r = rtlsdr_set_and_get_tuner_bandwidth(dev, bandwidth, &applied_bw, 1 /* =apply_bw */);
if (r < 0) {
fprintf(stderr, "WARNING: Failed to set bandwidth.\n");
} else if (bandwidth > 0) {
if (applied_bw)
fprintf(stderr, "Bandwidth parameter %u Hz resulted in %u Hz.\n", bandwidth, applied_bw);
else
fprintf(stderr, "Set bandwidth parameter %u Hz.\n", bandwidth);
} else {
fprintf(stderr, "Bandwidth set to automatic resulted in %u Hz.\n", applied_bw);
}
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) {
if ( r == -2 )
fprintf(stderr, "WARNING: Failed to set offset tuning: tuner doesn't support offset tuning!\n");
else if ( r == -3 )
fprintf(stderr, "WARNING: Failed to set offset tuning: direct sampling not combinable with offset tuning!\n");
else
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, 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;
}
#ifndef _WIN32
@ -397,4 +319,5 @@ void executeInBackground( char * file, char * args, char * searchStr[], char * r
#endif
// vim: tabstop=8:softtabstop=8:shiftwidth=8:noexpandtab

View File

@ -17,6 +17,13 @@
#ifndef __CONVENIENCE_H
#define __CONVENIENCE_H
#include <stdint.h>
#include <stdio.h>
#include <time.h>
#ifdef __cplusplus
extern "C" {
#endif
/* a collection of user friendly tools */
@ -47,114 +54,16 @@ double atoft(char *s);
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);
/*!
* Set device bandwidth 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_bandwidth(rtlsdr_dev_t *dev, uint32_t bandwidth);
/*!
* 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);
time_t utctimestr_to_time(const char * str, double * fraction);
time_t localtimestr_to_time(const char * str, double * fraction);
void executeInBackground( char * file, char * args, char * searchStr[], char * replaceStr[] );
#ifdef __cplusplus
}
#endif
#endif /*__CONVENIENCE_H*/

View File

@ -0,0 +1,261 @@
/*
* 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>
#include <ctype.h>
#include <time.h>
#include <assert.h>
#ifndef _WIN32
#include <unistd.h>
#include <sys/time.h>
#else
#include <windows.h>
#include <fcntl.h>
#include <io.h>
#define _USE_MATH_DEFINES
#endif
#include <math.h>
#include "rtl-sdr.h"
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_set_bandwidth(rtlsdr_dev_t *dev, uint32_t bandwidth)
{
int r;
uint32_t applied_bw = 0;
/* r = rtlsdr_set_tuner_bandwidth(dev, bandwidth); */
r = rtlsdr_set_and_get_tuner_bandwidth(dev, bandwidth, &applied_bw, 1 /* =apply_bw */);
if (r < 0) {
fprintf(stderr, "WARNING: Failed to set bandwidth.\n");
} else if (bandwidth > 0) {
if (applied_bw)
fprintf(stderr, "Bandwidth parameter %u Hz resulted in %u Hz.\n", bandwidth, applied_bw);
else
fprintf(stderr, "Set bandwidth parameter %u Hz.\n", bandwidth);
} else {
fprintf(stderr, "Bandwidth set to automatic resulted in %u Hz.\n", applied_bw);
}
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) {
if ( r == -2 )
fprintf(stderr, "WARNING: Failed to set offset tuning: tuner doesn't support offset tuning!\n");
else if ( r == -3 )
fprintf(stderr, "WARNING: Failed to set offset tuning: direct sampling not combinable with offset tuning!\n");
else
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, 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

View File

@ -0,0 +1,141 @@
/*
* 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/>.
*/
#ifndef __RTL_CONVENIENCE_H
#define __RTL_CONVENIENCE_H
#include <stdint.h>
#include <stdio.h>
#ifdef __cplusplus
extern "C" {
#endif
/* a collection of user friendly tools */
/*!
* 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);
/*!
* Set device bandwidth 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_bandwidth(rtlsdr_dev_t *dev, uint32_t bandwidth);
/*!
* 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);
#ifdef __cplusplus
}
#endif
#endif /*__RTL_CONVENIENCE_H*/

View File

@ -0,0 +1,102 @@
/*
* Copyright (C) 2019 by Hayati Ayguen <h_ayguen@web.de>
*
* 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 __WAVEHDR_H
#define __WAVEHDR_H
#include <stdint.h>
#include <stdio.h>
#include <time.h>
#pragma pack(push)
#pragma pack(1)
typedef struct
{
char ID[4];
uint32_t size;
} chunk_hdr;
typedef struct
{
uint16_t wYear; /* 1601 through 30827 */
uint16_t wMonth; /* 1..12 */
uint16_t wDayOfWeek; /* 0 .. 6: 0 == Sunday, .., 6 == Saturday */
uint16_t wDay; /* 1 .. 31 */
uint16_t wHour; /* 0 .. 23 */
uint16_t wMinute; /* 0 .. 59 */
uint16_t wSecond; /* 0 .. 59 */
uint16_t wMilliseconds; /* 0 .. 999 */
} Wind_SystemTime;
typedef struct
{
/* RIFF header */
chunk_hdr hdr; /* ID == "RIFF" string, size == full filesize - 8 bytes (maybe with some byte missing...) */
char waveID[4]; /* "WAVE" string */
} riff_chunk;
typedef struct
{
/* FMT header */
chunk_hdr hdr; /* ID == "fmt " */
int16_t wFormatTag;
int16_t nChannels;
int32_t nSamplesPerSec;
int32_t nAvgBytesPerSec;
int16_t nBlockAlign;
int16_t nBitsPerSample;
} fmt_chunk;
typedef struct
{
/* auxi header - used by SpectraVue / rfspace / HDSDR / ELAD FDM .. */
chunk_hdr hdr; /* ="auxi" (chunk rfspace) */
Wind_SystemTime StartTime;
Wind_SystemTime StopTime;
uint32_t centerFreq; /* receiver center frequency */
uint32_t ADsamplerate; /* A/D sample frequency before downsampling */
uint32_t IFFrequency; /* IF freq if an external down converter is used */
uint32_t Bandwidth; /* displayable BW if you want to limit the display to less than Nyquist band */
int32_t IQOffset; /* DC offset of the I and Q channels in 1/1000's of a count */
int32_t Unused2;
int32_t Unused3;
int32_t Unused4;
int32_t Unused5;
} auxi_chunk;
typedef struct
{
/* DATA header */
chunk_hdr hdr; /* ="data" */
} data_chunk;
typedef struct
{
riff_chunk r;
fmt_chunk f;
auxi_chunk a;
data_chunk d;
} waveFileHeader;
#pragma pack(pop)
#endif /* __WAVEHDR_H */
// vim: tabstop=8:softtabstop=8:shiftwidth=8:noexpandtab

View File

@ -0,0 +1,285 @@
/*
* Copyright (C) 2019 by Hayati Ayguen <h_ayguen@web.de>
*
* 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/>.
*/
#include "waveread.h"
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <assert.h>
#ifndef _WIN32
#include <unistd.h>
#include <sys/time.h>
#else
#include <windows.h>
#include <fcntl.h>
#include <io.h>
#include <process.h>
#define _USE_MATH_DEFINES
#endif
#include <math.h>
#include "wavehdr.h"
#define PRINT_DEBUG_OUTPUTS 0
static waveFileHeader waveHdr;
static uint32_t waveDataSize = 0;
static void waveGetTimeInt(const Wind_SystemTime *p, time_t *tim, double *fraction)
{
struct tm t;
#ifdef _WIN32
struct tm gtm, ltm;
time_t nt, gt, lt;
#endif
/* fprintf(stderr, "waveGetTimeInt( Wind_SystemTime = %04d-%02d-%02d T %02d:%02d:%02d %f )\n"
, (int)(p->wYear), (int)(p->wMonth), (int)(p->wDay)
, (int)(p->wHour), (int)(p->wMinute), (int)(p->wSecond)
, (float)(p->wMilliseconds / 1000.0) );
*/
t.tm_year = p->wYear - 1900; /* 1601 through 30827 */
t.tm_mon = p->wMonth -1; /* 1..12 */
t.tm_wday = p->wDayOfWeek; /* 0 .. 6: 0 == Sunday, .., 6 == Saturday */
t.tm_mday = p->wDay; /* 1 .. 31 */
t.tm_hour = p->wHour; /* 0 .. 23 */
t.tm_min = p->wMinute; /* 0 .. 59 */
t.tm_sec = p->wSecond; /* 0 .. 59 */
t.tm_wday = 0;
t.tm_yday = 0;
t.tm_isdst = 0;
*fraction = p->wMilliseconds / 1000.0;
#ifndef _WIN32
*tim = timegm( &t );
/* fprintf(stderr, " using timegm()\n"); */
#else
#ifdef _MSC_VER
*tim = _mkgmtime(&t);
/* fprintf(stderr, " using _mkgmtime()\n"); */
#else
/* workaround missing mkgmtime on mingw */
nt = mktime(&t);
gtm = *gmtime(&nt);
ltm = *localtime(&nt);
gt = mktime(&gtm);
lt = mktime(&ltm);
assert( nt == gt );
nt += ( lt - gt );
*tim = nt;
/* fprintf(stderr, " using mktime(), gmtime() and localtime() difference\n"); */
#endif
#endif
}
void waveGetStartTime(time_t *tim, double *fraction)
{
waveGetTimeInt(&waveHdr.a.StartTime, tim, fraction);
}
void waveGetStopTime(time_t *tim, double *fraction)
{
waveGetTimeInt(&waveHdr.a.StopTime, tim, fraction);
}
int waveReadHeader(FILE * f, uint32_t *srate, uint32_t *freq, int *bitsPerSample, int *numChannels
, uint32_t *nFrames, int16_t *formatTag, int verbosity)
{
uint8_t buf[32768];
size_t rd, smpSize;
int readAuxiHdr = 0;
int readDataHdr = 0;
int rv = 0;
#if PRINT_DEBUG_OUTPUTS
fprintf(stderr, "waveReadHeader(.., verbosity = %d)\n", verbosity);
#endif
rd = fread( &waveHdr.r, sizeof(riff_chunk), 1, f );
if ( rd != 1 )
return 10;
if ( memcmp(waveHdr.r.hdr.ID, "RIFF", 4) )
return 11;
if ( memcmp(waveHdr.r.waveID, "WAVE", 4 ) )
return 12;
rd = fread( &waveHdr.f, sizeof(fmt_chunk), 1, f );
#if PRINT_DEBUG_OUTPUTS
fprintf(stderr, "read %d chunk '%c%c%c%c' size %u = 0x%X\n", (int)rd
, waveHdr.f.hdr.ID[0], waveHdr.f.hdr.ID[1], waveHdr.f.hdr.ID[2], waveHdr.f.hdr.ID[3]
, (unsigned)waveHdr.f.hdr.size, (unsigned)waveHdr.f.hdr.size );
#endif
if ( rd != 1 )
return 20;
if ( memcmp(waveHdr.f.hdr.ID, "fmt ", 4 ) )
return 21;
if ( waveHdr.f.hdr.size != 16 )
return 22;
*bitsPerSample = waveHdr.f.nBitsPerSample;
*numChannels = waveHdr.f.nChannels;
*srate = waveHdr.f.nSamplesPerSec;
*formatTag = waveHdr.f.wFormatTag;
rd = fread( &waveHdr.a.hdr, sizeof(chunk_hdr), 1, f );
while ( !readDataHdr )
{
if ( rd != 1 )
return 30;
#if PRINT_DEBUG_OUTPUTS
fprintf(stderr, "read %d chunk '%c%c%c%c' size %u = 0x%X\n", (int)rd
, waveHdr.a.hdr.ID[0], waveHdr.a.hdr.ID[1], waveHdr.a.hdr.ID[2], waveHdr.a.hdr.ID[3]
, (unsigned)waveHdr.a.hdr.size, (unsigned)waveHdr.a.hdr.size );
#endif
if ( !memcmp(waveHdr.a.hdr.ID, "auxi", 4 ) )
{
if ( verbosity )
fprintf(stderr, "read chunk 'auxi' .. continue searching for 'data'-chunk ..\n");
if ( waveHdr.a.hdr.size > sizeof(buf) )
return 32;
if ( waveHdr.a.hdr.size < (sizeof(auxi_chunk) - sizeof(chunk_hdr)) )
return 33;
rd = fread( buf, waveHdr.a.hdr.size, 1, f );
if ( rd != 1 )
return 34;
memcpy( &waveHdr.a.StartTime, buf, sizeof(auxi_chunk) - sizeof(chunk_hdr));
*freq = waveHdr.a.centerFreq;
readAuxiHdr = 1;
}
else if ( !memcmp(waveHdr.a.hdr.ID, "data", 4 ) )
{
if ( verbosity )
fprintf(stderr, "read chunk 'data' .. going to process - %s 'auxi'-chunk ..\n", readAuxiHdr ? "with" : "without" );
waveHdr.d.hdr = waveHdr.a.hdr;
if (!readAuxiHdr) {
memset(&waveHdr.a, 0, sizeof(auxi_chunk));
waveHdr.a.StartTime.wYear = 1970;
waveHdr.a.StartTime.wMonth = 1;
waveHdr.a.StartTime.wDay = 1;
*freq = 100UL * 1000 * 1000; /* set frequency to 100 MHz */
}
readDataHdr = 1;
break;
}
else
{
if ( verbosity )
fprintf(stderr, "read chunk '%c%c%c%c' while expecting 'auxi' or 'data'. going to next chunk ..\n"
, waveHdr.a.hdr.ID[0], waveHdr.a.hdr.ID[1], waveHdr.a.hdr.ID[2], waveHdr.a.hdr.ID[3] );
if ( waveHdr.a.hdr.size > sizeof(buf) )
return 32;
rd = fread( buf, waveHdr.a.hdr.size, 1, f );
if ( rd != 1 )
return 34;
}
/* read next chunk's header */
rd = fread( &waveHdr.a.hdr, sizeof(chunk_hdr), 1, f );
}
if ( !readDataHdr )
{
rd = fread( &waveHdr.d.hdr, sizeof(chunk_hdr), 1, f );
#if PRINT_DEBUG_OUTPUTS
fprintf(stderr, "read %d chunk '%c%c%c%c' size %u = 0x%X\n", (int)rd
, waveHdr.d.hdr.ID[0], waveHdr.d.hdr.ID[1], waveHdr.d.hdr.ID[2], waveHdr.d.hdr.ID[3]
, (unsigned)waveHdr.d.hdr.size, (unsigned)waveHdr.d.hdr.size );
#endif
}
else
rd = 1;
if ( rd != 1 )
return 40;
if ( memcmp(waveHdr.d.hdr.ID, "data", 4 ) )
return 41;
smpSize = (*bitsPerSample + 7) / 8; /* round up to next byte */
smpSize *= *numChannels;
*nFrames = waveHdr.d.hdr.size / smpSize;
if ( verbosity >= 2 )
{
fprintf(stderr, "riffSize = %lu\n", (unsigned long)waveHdr.r.hdr.size );
fprintf(stderr, "dataSize = %lu\n", (unsigned long)waveHdr.d.hdr.size);
fprintf(stderr, "nBlockAlign = %d\n", (int)waveHdr.f.nBlockAlign);
fprintf(stderr, "smpSize = %d\n", (int)smpSize);
fprintf(stderr, "*nFrames = %lu\n", (unsigned long)(*nFrames) );
}
return rv;
}
int waveReadSamples(FILE* f, void * vpData, size_t numSamples, int needCleanData, size_t *numRead)
{
size_t nw;
switch (waveHdr.f.nBitsPerSample)
{
case 0:
default:
return 1;
case 8:
/* no endian conversion needed for single bytes */
nw = fread(vpData, sizeof(uint8_t), numSamples, f);
*numRead = nw;
return (nw == numSamples) ? 0 : 1;
case 16:
/* TODO: endian conversion needed */
nw = fread(vpData, sizeof(int16_t), numSamples, f);
if ( needCleanData )
{
/* TODO: convert back endianness */
}
*numRead = nw;
return (nw == numSamples) ? 0 : 1;
}
}
int waveReadFrames(FILE* f, void * vpData, size_t numFrames, int needCleanData, size_t *numRead)
{
size_t nw;
switch (waveHdr.f.nBitsPerSample)
{
case 0:
default:
return 1;
case 8:
/* no endian conversion needed for single bytes */
nw = fread(vpData, waveHdr.f.nChannels * sizeof(uint8_t), numFrames, f);
*numRead = nw;
return (nw == numFrames) ? 0 : 1;
case 16:
/* TODO: endian conversion needed */
nw = fread(vpData, waveHdr.f.nChannels * sizeof(int16_t), numFrames, f);
if ( needCleanData )
{
/* TODO: convert back endianness */
}
*numRead = nw;
return (nw == numFrames) ? 0 : 1;
}
}
// vim: tabstop=8:softtabstop=8:shiftwidth=8:noexpandtab

View File

@ -0,0 +1,40 @@
/*
* Copyright (C) 2019 by Hayati Ayguen <h_ayguen@web.de>
*
* 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 __WAVEREAD_H
#define __WAVEREAD_H
#include <stdint.h>
#include <stdio.h>
#include <time.h>
#ifdef __cplusplus
extern "C" {
#endif
int waveReadHeader(FILE * f, uint32_t *samplerate, uint32_t *freq, int *bitsPerSample, int *numChannels
, uint32_t *nFrames, int16_t *formatTag, int verbosity);
int waveReadFrames(FILE* f, void * vpData, size_t numFrames, int needCleanData, size_t *numRead);
int waveReadSamples(FILE* f, void * vpData, size_t numSamples, int needCleanData, size_t *numRead); /* returns 0, when no errors occured */
void waveGetStartTime(time_t *tim, double *fraction);
void waveGetStopTime(time_t *tim, double *fraction);
#ifdef __cplusplus
}
#endif
#endif /*__WAVEREAD_H*/

View File

@ -0,0 +1,209 @@
/*
* Copyright (C) 2019 by Hayati Ayguen <h_ayguen@web.de>
*
* 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/>.
*/
#include "wavewrite.h"
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <assert.h>
#ifndef _WIN32
#include <unistd.h>
#include <sys/time.h>
#else
#include <windows.h>
#include <fcntl.h>
#include <io.h>
#include <process.h>
#define _USE_MATH_DEFINES
#endif
#include <math.h>
#include "wavehdr.h"
static waveFileHeader waveHdr;
static uint32_t waveDataSize = 0;
int waveHdrStarted = 0;
static void waveSetCurrTime(Wind_SystemTime *p)
{
struct timeval tv;
struct tm t;
gettimeofday(&tv, NULL);
p->wMilliseconds = tv.tv_usec / 1000;
#ifdef _WIN32
t = *gmtime(&tv.tv_sec);
#else
gmtime_r(&tv.tv_sec, &t);
#endif
p->wYear = t.tm_year + 1900; /* 1601 through 30827 */
p->wMonth = t.tm_mon + 1; /* 1..12 */
p->wDayOfWeek = t.tm_wday; /* 0 .. 6: 0 == Sunday, .., 6 == Saturday */
p->wDay = t.tm_mday; /* 1 .. 31 */
p->wHour = t.tm_hour; /* 0 .. 23 */
p->wMinute = t.tm_min; /* 0 .. 59 */
p->wSecond = t.tm_sec; /* 0 .. 59 */
}
static void waveSetStartTimeInt(time_t tim, double fraction, Wind_SystemTime *p)
{
struct tm t = *gmtime( &tim );
p->wYear = t.tm_year + 1900; /* 1601 through 30827 */
p->wMonth = t.tm_mon + 1; /* 1..12 */
p->wDayOfWeek = t.tm_wday; /* 0 .. 6: 0 == Sunday, .., 6 == Saturday */
p->wDay = t.tm_mday; /* 1 .. 31 */
p->wHour = t.tm_hour; /* 0 .. 23 */
p->wMinute = t.tm_min; /* 0 .. 59 */
p->wSecond = t.tm_sec; /* 0 .. 59 */
p->wMilliseconds = (int)( fraction * 1000.0 );
if (p->wMilliseconds >= 1000)
p->wMilliseconds = 999;
}
void waveSetStartTime(time_t tim, double fraction)
{
waveSetStartTimeInt(tim, fraction, &waveHdr.a.StartTime );
waveHdr.a.StopTime = waveHdr.a.StartTime; /* to fix */
}
void wavePrepareHeader(unsigned samplerate, unsigned freq, int bitsPerSample, int numChannels)
{
int bytesPerSample = bitsPerSample / 8;
int bytesPerFrame = bytesPerSample * numChannels;
strncpy( waveHdr.r.hdr.ID, "RIFF", 4 );
waveHdr.r.hdr.size = sizeof(waveFileHeader) - 8; /* to fix */
strncpy( waveHdr.r.waveID, "WAVE", 4 );
strncpy( waveHdr.f.hdr.ID, "fmt ", 4 );
waveHdr.f.hdr.size = 16;
waveHdr.f.wFormatTag = 1; /* PCM */
waveHdr.f.nChannels = numChannels; /* I and Q channels */
waveHdr.f.nSamplesPerSec = samplerate;
waveHdr.f.nAvgBytesPerSec = samplerate * bytesPerFrame;
waveHdr.f.nBlockAlign = waveHdr.f.nChannels;
waveHdr.f.nBitsPerSample = bitsPerSample;
strncpy( waveHdr.a.hdr.ID, "auxi", 4 );
waveHdr.a.hdr.size = 2 * sizeof(Wind_SystemTime) + 9 * sizeof(int32_t); /* = 2 * 16 + 9 * 4 = 68 */
waveSetCurrTime( &waveHdr.a.StartTime );
waveHdr.a.StopTime = waveHdr.a.StartTime; /* to fix */
waveHdr.a.centerFreq = freq;
waveHdr.a.ADsamplerate = samplerate;
waveHdr.a.IFFrequency = 0;
waveHdr.a.Bandwidth = 0;
waveHdr.a.IQOffset = 0;
waveHdr.a.Unused2 = 0;
waveHdr.a.Unused3 = 0;
waveHdr.a.Unused4 = 0;
waveHdr.a.Unused5 = 0;
strncpy( waveHdr.d.hdr.ID, "data", 4 );
waveHdr.d.hdr.size = 0; /* to fix later */
waveDataSize = 0;
}
void waveWriteHeader(unsigned samplerate, unsigned freq, int bitsPerSample, int numChannels, FILE * f)
{
if (f != stdout) {
assert( !waveHdrStarted );
wavePrepareHeader(samplerate, freq, bitsPerSample, numChannels);
fwrite(&waveHdr, sizeof(waveFileHeader), 1, f);
waveHdrStarted = 1;
}
}
int waveWriteSamples(FILE* f, void * vpData, size_t numSamples, int needCleanData)
{
size_t nw;
switch (waveHdr.f.nBitsPerSample)
{
case 0:
default:
return 1;
case 8:
/* no endian conversion needed for single bytes */
nw = fwrite(vpData, sizeof(uint8_t), numSamples, f);
waveDataSize += sizeof(uint8_t) * numSamples;
return (nw == numSamples) ? 0 : 1;
case 16:
/* TODO: endian conversion needed */
nw = fwrite(vpData, sizeof(int16_t), numSamples, f);
waveDataSize += sizeof(int16_t) * numSamples;
if ( needCleanData )
{
/* TODO: convert back endianness */
}
return (nw == numSamples) ? 0 : 1;
}
}
int waveWriteFrames(FILE* f, void * vpData, size_t numFrames, int needCleanData)
{
size_t nw;
switch (waveHdr.f.nBitsPerSample)
{
case 0:
default:
return 1;
case 8:
/* no endian conversion needed for single bytes */
nw = fwrite(vpData, waveHdr.f.nChannels * sizeof(uint8_t), numFrames, f);
waveDataSize += waveHdr.f.nChannels * sizeof(uint8_t) * numFrames;
return (nw == numFrames) ? 0 : 1;
case 16:
/* TODO: endian conversion needed */
nw = fwrite(vpData, waveHdr.f.nChannels * sizeof(int16_t), numFrames, f);
waveDataSize += waveHdr.f.nChannels * sizeof(int16_t) * numFrames;
if ( needCleanData )
{
/* TODO: convert back endianness */
}
return (nw == numFrames) ? 0 : 1;
}
}
int waveFinalizeHeader(FILE * f)
{
if (f != stdout) {
assert( waveHdrStarted );
waveSetCurrTime( &waveHdr.a.StopTime );
waveHdr.d.hdr.size = waveDataSize;
waveHdr.r.hdr.size += waveDataSize;
/* fprintf(stderr, "waveFinalizeHeader(): datasize = %d\n", waveHdr.dataSize); */
waveHdrStarted = 0;
if ( fseek(f, 0, SEEK_SET) )
return 1;
if ( 1 != fwrite(&waveHdr, sizeof(waveFileHeader), 1, f) )
return 1;
/* fprintf(stderr, "waveFinalizeHeader(): success writing header\n"); */
return 0;
}
return 1;
}
// vim: tabstop=8:softtabstop=8:shiftwidth=8:noexpandtab

View File

@ -0,0 +1,55 @@
/*
* Copyright (C) 2019 by Hayati Ayguen <h_ayguen@web.de>
*
* 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 __WAVEWRITE_H
#define __WAVEWRITE_H
#include <stdint.h>
#include <stdio.h>
#include <time.h>
#ifdef __cplusplus
extern "C" {
#endif
int waveHdrStarted;
/*!
* helper functions to write and finalize wave headers
* with compatibility to some SDR programs - showing frequency:
* raw sample data still have to be written by caller to FILE*.
* call waveWriteHeader() before writing anything to to file
* and call waveFinalizeHeader() afterwards,
* stdout/stderr can't be used, because seek to begin isn't possible.
*
*/
void waveWriteHeader(unsigned samplerate, unsigned freq, int bitsPerSample, int numChannels, FILE * f);
/* waveWriteFrames() writes (numFrames * numChannels) samples
* waveWriteSamples()
* both return 0, when no errors occured
*/
int waveWriteFrames(FILE* f, void * vpData, size_t numFrames, int needCleanData);
int waveWriteSamples(FILE* f, void * vpData, size_t numSamples, int needCleanData); /* returns 0, when no errors occured */
void waveSetStartTime(time_t t, double fraction);
int waveFinalizeHeader(FILE * f); /* returns 0, when no errors occured */
#ifdef __cplusplus
}
#endif
#endif /*__WAVEWRITE_H*/

File diff suppressed because it is too large Load Diff

View File

@ -45,6 +45,7 @@
#include "rtl-sdr.h"
#include "convenience/convenience.h"
#include "convenience/rtl_convenience.h"
#ifdef _WIN32
#define sleep Sleep

View File

@ -0,0 +1,8 @@
#ifndef __RTL_APP_VER_H
#define __RTL_APP_VER_H
#define APP_VER_MAJOR 0
#define APP_VER_MINOR 7
#define APP_VER_ID "github.com/hayguen"
#endif

View File

@ -83,6 +83,10 @@
#include "rtl-sdr.h"
#include "convenience/convenience.h"
#include "convenience/rtl_convenience.h"
#include "convenience/wavewrite.h"
#include "rtl_app_ver.h"
#define DEFAULT_SAMPLE_RATE 24000
#define DEFAULT_BUF_LENGTH (1 * 16384)
@ -111,6 +115,8 @@ static int printLevelNo = 1;
static int levelMax = 0;
static int levelMaxMax = 0;
static double levelSum = 0.0;
static int32_t prev_if_band_center_freq = 0;
enum trigExpr { crit_IN =0, crit_OUT, crit_LT, crit_GT };
char * aCritStr[] = { "in", "out", "<", ">" };
@ -156,6 +162,7 @@ struct dongle_state
uint32_t freq;
uint32_t rate;
uint32_t bandwidth;
int bccorner; /* -1 for low band corner, 0 for band center, +1 for high band corner */
int gain;
int16_t buf16[MAXIMUM_BUF_LENGTH];
uint32_t buf_len;
@ -213,6 +220,7 @@ struct output_state
pthread_t thread;
FILE *file;
char *filename;
char *tempfilename;
int16_t result[MAXIMUM_BUF_LENGTH];
int result_len;
int rate;
@ -235,7 +243,7 @@ struct controller_state
struct cmd_state *cmd;
};
// multiple of these, eventually
/* multiple of these, eventually */
struct dongle_state dongle;
struct demod_state demod;
struct output_state output;
@ -245,8 +253,17 @@ struct cmd_state cmd;
void usage(void)
{
fprintf(stderr, "rtl_fm, a simple narrow band FM demodulator for RTL2832 based receivers\n");
fprintf(stderr, "rtl_fm version %u.%u %s (%s)\n",
APP_VER_MAJOR, APP_VER_MINOR,
APP_VER_ID, __DATE__ );
fprintf(stderr, "librtlsdr version %u.%u %s\n\n",
(unsigned)(rtlsdr_get_version() >> 16),
(unsigned)(rtlsdr_get_version() & 0xFFFFU),
rtlsdr_get_ver_id()
);
fprintf(stderr,
"rtl_fm, a simple narrow band FM demodulator for RTL2832 based DVB-T receivers\n\n"
"Use:\trtl_fm -f freq [-options] [filename]\n"
"\t-f frequency_to_tune_to [Hz]\n"
"\t use multiple -f for scanning (requires squelch)\n"
@ -274,7 +291,9 @@ void usage(void)
"\t output are comma separated values (csv):\n"
"\t avg rms since last output, max rms since last output, overall max rms, squelch (paramed), rms, rms level, avg rms level\n"
"\t[-c de-emphasis_time_constant in us for wbfm. 'us' or 'eu' for 75/50 us (default: us)]\n"
//"\t for fm squelch is inverted\n"
#if 0
"\t for fm squelch is inverted\n"
#endif
"\t[-o oversampling (default: 1, 4 recommended)]\n"
"\t[-p ppm_error (default: 0)]\n"
"\t[-E enable_option (default: none)]\n"
@ -288,11 +307,14 @@ void usage(void)
"\t deemp: enable de-emphasis filter\n"
"\t direct: enable direct sampling (bypasses tuner, uses rtl2832 xtal)\n"
"\t offset: enable offset tuning (only e4000 tuner)\n"
"\t[-O set RTL options string seperated with ':' ]\n"
"\t f=<freqHz>:bw=<bw_in_kHz>:agc=<tuner_gain_mode>:gain=<tenth_dB>\n"
"\t dagc=<rtl_agc>:ds=<direct_sampling_mode>:T=<bias_tee>\n"
"\t bcc: use tuner bandwidths center as band center (default)\n"
"\t bclo: use tuner bandwidths low corner as band center\n"
"\t bchi: use tuner bandwidths high corner as band center\n"
"%s"
"\t[-q dc_avg_factor for option rdc (default: 9)]\n"
"\t[-n disables demodulation output to stdout/file]\n"
"\t[-H write wave Header to file (default: off)]\n"
"\t limitation: only 1st tuned frequency will be written into the header!\n"
"\tfilename ('-' means stdout)\n"
"\t omitting the filename also uses stdout\n\n"
"Experimental options:\n"
@ -303,17 +325,20 @@ void usage(void)
"\t enables low-leakage downsample filter\n"
"\t size can be 0 or 9. 0 has bad roll off\n"
"\t[-A std/fast/lut choose atan math (default: std)]\n"
//"\t[-C clip_path (default: off)\n"
//"\t (create time stamped raw clips, requires squelch)\n"
//"\t (path must have '\%s' and will expand to date_time_freq)\n"
//"\t[-H hop_fifo (default: off)\n"
//"\t (fifo will contain the active frequency)\n"
#if 0
"\t[-C clip_path (default: off)\n"
"\t (create time stamped raw clips, requires squelch)\n"
"\t (path must have '\%s' and will expand to date_time_freq)\n"
"\t[-H hop_fifo (default: off)\n"
"\t (fifo will contain the active frequency)\n"
#endif
"\n"
"Produces signed 16 bit ints, use Sox or aplay to hear them.\n"
"\trtl_fm ... | play -t raw -r 24k -es -b 16 -c 1 -V1 -\n"
"\t | aplay -r 24k -f S16_LE -t raw -c 1\n"
"\t -M wbfm | play -r 32k ... \n"
"\t -s 22050 | multimon -t raw /dev/stdin\n\n");
"\t -s 22050 | multimon -t raw /dev/stdin\n\n"
, rtlsdr_get_opt_help(1) );
exit(1);
}
@ -463,8 +488,8 @@ void low_pass(struct demod_state *d)
if (d->prev_index < d->downsample) {
continue;
}
d->lowpassed[i2] = d->now_r; // * d->output_scale;
d->lowpassed[i2+1] = d->now_j; // * d->output_scale;
d->lowpassed[i2] = d->now_r; /* * d->output_scale; */
d->lowpassed[i2+1] = d->now_j; /* * d->output_scale; */
d->prev_index = 0;
d->now_r = 0;
d->now_j = 0;
@ -730,7 +755,7 @@ static void checkTriggerCommand(struct cmd_state *c, unsigned char adcSampleMax,
int low_pass_simple(int16_t *signal2, int len, int step)
// no wrap around, length must be multiple of step
/* no wrap around, length must be multiple of step */
{
int i, i2, sum;
for(i=0; i < len; i+=step) {
@ -738,7 +763,7 @@ int low_pass_simple(int16_t *signal2, int len, int step)
for(i2=0; i2<step; i2++) {
sum += (int)signal2[i + i2];
}
//signal2[i/step] = (int16_t)(sum / step);
/* signal2[i/step] = (int16_t)(sum / step); */
signal2[i/step] = (int16_t)(sum);
}
signal2[i/step + 1] = signal2[i/step];
@ -747,7 +772,7 @@ int low_pass_simple(int16_t *signal2, int len, int step)
void low_pass_real(struct demod_state *s)
/* simple square window FIR */
// add support for upsampling?
/* add support for upsampling? */
{
int i=0, i2=0;
int fast = (int)s->rate_out;
@ -845,7 +870,7 @@ 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
int pi4=(1<<12), pi34=3*(1<<12); /* note pi = 1<<14 */
if (x==0 && y==0) {
return 0;
}
@ -952,20 +977,21 @@ void fm_demod(struct demod_state *fm)
}
void am_demod(struct demod_state *fm)
// todo, fix this extreme laziness
/* 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]);
/* 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)sqrt(pcm) * fm->output_scale;
}
fm->result_len = fm->lp_len/2;
// lowpass? (3khz) highpass? (dc)
/* lowpass? (3khz) highpass? (dc) */
}
void usb_demod(struct demod_state *fm)
@ -1003,10 +1029,11 @@ void raw_demod(struct demod_state *fm)
void deemph_filter(struct demod_state *fm)
{
static int avg; // cheating...
static int avg; /* cheating... */
int i, d;
// de-emph IIR
// avg = avg * (1 - alpha) + sample * alpha;
/* 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) {
@ -1110,7 +1137,7 @@ void arbitrary_upsample(int16_t *buf1, int16_t *buf2, int len1, int len2)
int i = 1;
int j = 0;
int tick = 0;
double frac; // use integers...
double frac; /* use integers... */
while (j < len2) {
frac = (double)tick / (double)len2;
buf2[j] = (int16_t)(buf1[i-1]*(1-frac) + buf1[i]*frac);
@ -1134,7 +1161,7 @@ void arbitrary_downsample(int16_t *buf1, int16_t *buf2, int len1, int len2)
int j = 0;
int tick = 0;
double remainder = 0;
double frac; // use integers...
double frac; /* use integers... */
buf2[0] = 0;
while (j < len2) {
frac = 1.0;
@ -1251,7 +1278,7 @@ void full_demod(struct demod_state *d)
return;
}
/* todo, fm noise squelch */
// use nicer filter here too?
/* 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) {
@ -1260,7 +1287,7 @@ void full_demod(struct demod_state *d)
dc_block_audio_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);
/* arbitrary_resample(d->result, d->result, d->result_len, d->result_len * d->rate_out2 / d->rate_out); */
}
}
@ -1303,7 +1330,7 @@ static void rtlsdr_callback(unsigned char *buf, uint32_t len, void *ctx)
s->sampleMax = sampleMax;
}
if (c->checkADCrms ) {
while ( len >= 16384 * step )
while ( (int)len >= 16384 * step )
step += 2;
for (i=0; i<(int)len; i+= step) {
sampleP = ( (int)buf[i] -127 ) * ( (int)buf[i] -127 ); /* I^2 */
@ -1385,20 +1412,32 @@ static void *demod_thread_fn(void *arg)
static void *output_thread_fn(void *arg)
{
struct output_state *s = arg;
while (!do_exit) {
// use timedwait and pad out under runs
safe_cond_wait(&s->ready, &s->ready_m);
pthread_rwlock_rdlock(&s->rw);
fwrite(s->result, 2, s->result_len, s->file);
pthread_rwlock_unlock(&s->rw);
if (!waveHdrStarted) {
while (!do_exit) {
/* use timedwait and pad out under runs */
safe_cond_wait(&s->ready, &s->ready_m);
pthread_rwlock_rdlock(&s->rw);
fwrite(s->result, 2, s->result_len, s->file);
pthread_rwlock_unlock(&s->rw);
}
} else {
while (!do_exit) {
/* use timedwait and pad out under runs */
safe_cond_wait(&s->ready, &s->ready_m);
pthread_rwlock_rdlock(&s->rw);
/* distinguish for endianness: wave requires little endian */
waveWriteSamples(s->file, s->result, s->result_len, 0);
pthread_rwlock_unlock(&s->rw);
}
}
return 0;
}
static void optimal_settings(uint32_t freq, uint32_t rate)
{
// giant ball of hacks
// seems unable to do a single pass, 2:1
/* giant ball of hacks
* seems unable to do a single pass, 2:1
*/
uint32_t capture_freq, capture_rate;
struct dongle_state *d = &dongle;
struct demod_state *dm = &demod;
@ -1437,9 +1476,11 @@ static void optimal_settings(uint32_t freq, uint32_t rate)
static void *controller_thread_fn(void *arg)
{
// thoughts for multiple dongles
// might be no good using a controller thread if retune/rate blocks
/* thoughts for multiple dongles
* might be no good using a controller thread if retune/rate blocks
*/
int i, r, execWaitHop = 1;
int32_t if_band_center_freq = 0;
struct controller_state *s = arg;
struct cmd_state *c = s->cmd;
@ -1483,6 +1524,25 @@ static void *controller_thread_fn(void *arg)
verbose_set_sample_rate(dongle.dev, dongle.rate);
fprintf(stderr, "Output at %u Hz.\n", demod.rate_in/demod.post_downsample);
if ( dongle.bandwidth ) {
if_band_center_freq = dongle.userFreq - dongle.freq;
if (dongle.bccorner < 0)
if_band_center_freq += ( dongle.bandwidth - demod.rate_out ) / 2;
else if (dongle.bccorner > 0)
if_band_center_freq -= ( dongle.bandwidth - demod.rate_out ) / 2;
if ( prev_if_band_center_freq != if_band_center_freq ) {
r = rtlsdr_set_tuner_band_center(dongle.dev, if_band_center_freq );
if (r)
fprintf(stderr, "WARNING: Failed to set band center.\n");
else {
prev_if_band_center_freq = if_band_center_freq;
if (verbosity)
fprintf(stderr, "rtlsdr_set_tuner_band_center(%.0f Hz) successful\n", (double)if_band_center_freq);
}
}
}
while (!do_exit) {
if (execWaitHop)
safe_cond_wait(&s->hop, &s->hop_m);
@ -1495,9 +1555,22 @@ static void *controller_thread_fn(void *arg)
s->freq_now = (s->freq_now + 1) % s->freq_len;
optimal_settings(s->freqs[s->freq_now], demod.rate_in);
rtlsdr_set_center_freq(dongle.dev, dongle.freq);
if ( dongle.bandwidth ) {
if_band_center_freq = dongle.userFreq - dongle.freq;
if ( prev_if_band_center_freq != if_band_center_freq ) {
r = rtlsdr_set_tuner_band_center(dongle.dev, if_band_center_freq );
if (r)
fprintf(stderr, "WARNING: Failed to set band center.\n");
else {
prev_if_band_center_freq = if_band_center_freq;
if (verbosity)
fprintf(stderr, "rtlsdr_set_tuner_band_center(%.0f Hz) successful\n", (double)if_band_center_freq);
}
}
}
dongle.mute = DEFAULT_BUFFER_DUMP;
} else {
dongle.mute = 2 * 3200000; /* over a second - until parametrized the dongle */
dongle.mute = 2 * dongle.rate; /* over a second - until parametrized the dongle */
c->numSummed = 0;
toNextCmdLine(c);
@ -1536,7 +1609,21 @@ static void *controller_thread_fn(void *arg)
if (r < 0)
fprintf(stderr, "WARNING: Failed to set bandwidth.\n");
else
c->prevBandwidth != dongle.bandwidth;
c->prevBandwidth = dongle.bandwidth;
}
/* */
if ( dongle.bandwidth ) {
if_band_center_freq = dongle.userFreq - dongle.freq;
if ( prev_if_band_center_freq != if_band_center_freq ) {
r = rtlsdr_set_tuner_band_center(dongle.dev, if_band_center_freq );
if (r)
fprintf(stderr, "WARNING: Failed to set band center.\n");
else {
prev_if_band_center_freq = if_band_center_freq;
if (verbosity)
fprintf(stderr, "rtlsdr_set_tuner_band_center(%.0f Hz) successful\n", (double)if_band_center_freq);
}
}
}
/* 4- Set ADC samplerate *
r = rtlsdr_set_sample_rate(dongle.dev, dongle.rate);
@ -1593,6 +1680,7 @@ void dongle_init(struct dongle_state *s)
s->samplePowCount = 0;
s->sampleMax = 0;
s->bandwidth = 0;
s->bccorner = 0;
s->buf_len = 32 * 512; /* see rtl_tcp */
}
@ -1695,6 +1783,7 @@ int main(int argc, char **argv)
#endif
int r, opt;
int dev_given = 0;
int writeWav = 0;
int custom_ppm = 0;
int enable_biastee = 0;
const char * rtlOpts = NULL;
@ -1708,7 +1797,7 @@ int main(int argc, char **argv)
controller_init(&controller);
cmd_init(&cmd);
while ((opt = getopt(argc, argv, "d:f:g:s:b:l:o:t:r:p:E:O:F:A:M:hTC:B:m:L:q:c:w:W:D:nv")) != -1) {
while ((opt = getopt(argc, argv, "d:f:g:s:b:l:o:t:r:p:E:O:F:A:M:hTC:B:m:L:q:c:w:W:D:nHv")) != -1) {
switch (opt) {
case 'd':
dongle.dev_index = verbose_device_search(optarg);
@ -1787,6 +1876,12 @@ int main(int argc, char **argv)
dongle.offset_tuning = 1;}
if (strcmp("rtlagc", optarg) == 0 || strcmp("agc", optarg) == 0) {
rtlagc = 1;}
if (strcmp("bclo", optarg) == 0 || strcmp("bcL", optarg) == 0 || strcmp("bcl", optarg) == 0) {
dongle.bccorner = -1; }
if (strcmp("bcc", optarg) == 0 || strcmp("bcC", optarg) == 0) {
dongle.bccorner = 0; }
if (strcmp("bchi", optarg) == 0 || strcmp("bcH", optarg) == 0 || strcmp("bch", optarg) == 0) {
dongle.bccorner = 1; }
break;
case 'O':
rtlOpts = optarg;
@ -1847,6 +1942,9 @@ int main(int argc, char **argv)
else
ds_threshold = ds_temp;
break;
case 'H':
writeWav = 1;
break;
case 'v':
++verbosity;
break;
@ -1966,13 +2064,28 @@ int main(int argc, char **argv)
_setmode(_fileno(output.file), _O_BINARY);
#endif
} else {
output.file = fopen(output.filename, "wb");
const char * filename_to_open = output.filename;
if (writeWav) {
output.tempfilename = malloc( strlen(output.filename)+8 );
strcpy(output.tempfilename, output.filename);
strcat(output.tempfilename, ".tmp");
filename_to_open = output.tempfilename;
}
output.file = fopen(filename_to_open, "wb");
if (!output.file) {
fprintf(stderr, "Failed to open %s\n", output.filename);
fprintf(stderr, "Failed to open %s\n", filename_to_open);
exit(1);
}
else
fprintf(stderr, "Open %s for write\n", output.filename);
{
fprintf(stderr, "Open %s for write\n", filename_to_open);
if (writeWav) {
int nChan = (demod.mode_demod == &raw_demod) ? 2 : 1;
int srate = (demod.rate_out2 > 0) ? demod.rate_out2 : demod.rate_out;
uint32_t f = controller.freqs[0]; /* only 1st frequency!!! */
waveWriteHeader(srate, f, 16, nChan, output.file);
}
}
}
//r = rtlsdr_set_testmode(dongle.dev, 1);
@ -2004,7 +2117,7 @@ int main(int argc, char **argv)
safe_cond_signal(&controller.hop, &controller.hop_m);
pthread_join(controller.thread, NULL);
//dongle_cleanup(&dongle);
/* dongle_cleanup(&dongle); */
demod_cleanup(&demod);
output_cleanup(&output);
controller_cleanup(&controller);
@ -2019,10 +2132,22 @@ int main(int argc, char **argv)
}
if (output.file != stdout) {
fclose(output.file);}
if (writeWav) {
int r;
waveFinalizeHeader(output.file);
fclose(output.file);
remove(output.filename); /* delete, in case file already exists */
r = rename( output.tempfilename, output.filename ); /* #include <stdio.h> */
if ( r )
fprintf( stderr, "%s: error %d '%s' renaming'%s' to '%s'\n"
, argv[0], errno, strerror(errno), output.tempfilename, output.filename );
} else {
fclose(output.file);
}
}
rtlsdr_close(dongle.dev);
return r >= 0 ? r : -r;
}
// vim: tabstop=8:softtabstop=8:shiftwidth=8:noexpandtab
/* vim: tabstop=8:softtabstop=8:shiftwidth=8:noexpandtab */

View File

@ -49,6 +49,7 @@
#include "rtl-sdr.h"
#include "convenience/convenience.h"
#include "convenience/rtl_convenience.h"
static volatile int do_exit = 0;

View File

@ -68,6 +68,7 @@
#include "rtl-sdr.h"
#include "convenience/convenience.h"
#include "convenience/rtl_convenience.h"
#define MAX(x, y) (((x) > (y)) ? (x) : (y))

312
src/rtl_raw2wav.c 100644
View File

@ -0,0 +1,312 @@
/*
* rtl-raw2wav, converts binary/raw data into wave files - including frequency
* Copyright (C) 2019 by Hayati Ayguen <h_ayguen@web.de>
*
* 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/>.
*/
#include <errno.h>
#include <signal.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#ifndef _WIN32
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#else
#include <windows.h>
#include <fcntl.h>
#include <io.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "getopt/getopt.h"
#if defined(_MSC_VER) && (_MSC_VER < 1900)
#define snprintf _snprintf
#endif
#endif
#include "convenience/convenience.h"
#include "convenience/wavewrite.h"
#include "rtl_app_ver.h"
static volatile int do_exit = 0;
static int verbosity = 0;
void usage(void)
{
fprintf(stderr, "rtl_raw2wav, a raw (binary sampledata) to wave file converter\n");
fprintf(stderr, "rtl_raw2wav version %u.%u %s (%s)\n",
APP_VER_MAJOR, APP_VER_MINOR,
APP_VER_ID, __DATE__ );
fprintf(stderr,
"Use:\trtl_raw2wav -w <output_wave_filename> [-options] [input_raw_filename]\n"
"\t-w filename output filename\n"
"\t-f frequency frequency, to write into output filename\n"
"\t-s samplerate samplerate, of raw input\n"
"\t-c #channels number of channels, default: 2 - for I and Q\n"
"\t-b #bits number of bits per sample, default: 8 - 8 or 16 allowed\n"
"\t-u time set start time in UTC: 'yyy-mm-ddThh:mm:dd.zzz'\n"
"\t-t time set start time in localtime: 'yyy-mm-ddThh:mm:dd.zzz'\n"
"\t-v verbose output\n"
"\t-r filename input filename for raw samples, default: - for stdin\n\n" );
}
#ifdef _WIN32
BOOL WINAPI
sighandler(int signum)
{
if (CTRL_C_EVENT == signum) {
fprintf(stderr, "Signal caught, exiting!\n");
do_exit = 1;
return TRUE;
}
return FALSE;
}
#else
static void sighandler(int signum)
{
fprintf(stderr, "Signal caught, exiting!\n");
do_exit = 1;
}
#endif
int main(int argc, char **argv)
{
#ifndef _WIN32
struct sigaction sigact;
#endif
int r, opt;
const char * rawfilename = NULL;
const char * wavfilename = NULL;
char *tempfilename = NULL;
FILE * outfile = NULL;
FILE * inpfile = NULL;
uint32_t freq = 0;
uint32_t srate = 0;
int nChan = 2;
int nBits = 8;
char acBuf[ 65536 * sizeof(int16_t) * 2 ]; /* 64 K frames with 2 channels and 16 Bit */
size_t smpSize;
size_t nRead;
time_t tim = 0;
double fraction = 0.0;
int haveTime = 0;
while ((opt = getopt(argc, argv, "f:s:c:b:r:u:t:w:vh")) != -1) {
switch (opt) {
case 'f': freq = (uint32_t)atofs(optarg); break;
case 's': srate = (uint32_t)atofs(optarg); break;
case 'c': nChan = atoi(optarg); break;
case 'b': nBits = atoi(optarg);
if (nBits <= 4) /* assume intention was: bytes per sample */
nBits *= 8;
break;
case 'v': ++verbosity; break;
case 'r': rawfilename = optarg; break;
case 'u': tim = utctimestr_to_time(optarg, &fraction);
if (tim) haveTime = 1;
break;
case 't': tim = localtimestr_to_time(optarg, &fraction);
if (tim) haveTime = 1;
break;
case 'w': wavfilename = optarg; break;
case 'h':
case '?':
default:
usage();
exit(1);
break;
}
}
if (verbosity)
fprintf(stderr, "verbosity set to %d\n", verbosity);
if (optind < argc) {
rawfilename = argv[optind];
}
while (!wavfilename) {
if (rawfilename) {
int slen = strlen(rawfilename);
const char * rawEnd = rawfilename + slen;
if (slen > 4 && (!strcmp(rawEnd - 4, ".bin") || !strcmp(rawEnd - 4, ".raw"))) {
char * wfn = strdup(rawfilename);
strcpy(wfn+slen-4, ".wav");
wavfilename = wfn;
if (verbosity)
fprintf(stderr, "Warning: deduced .wav filename '%s' from rawfilename '%s'\n", wavfilename, rawfilename);
break; /* the while() */
}
}
usage();
fprintf(stderr, "Error: missing output wave filename!\n");
exit(1);
}
if (nChan < 1 || nChan > 2) {
usage();
fprintf(stderr, "Error: number of channels must be 1 or 2!\n");
exit(1);
}
if (nBits != 8 && nBits != 16) {
usage();
fprintf(stderr, "Error: number of bits per sample must be 8 or 16!\n");
exit(1);
}
#ifndef _WIN32
sigact.sa_handler = sighandler;
sigemptyset(&sigact.sa_mask);
sigact.sa_flags = 0;
sigaction(SIGINT, &sigact, NULL);
sigaction(SIGTERM, &sigact, NULL);
sigaction(SIGQUIT, &sigact, NULL);
sigaction(SIGPIPE, &sigact, NULL);
#else
SetConsoleCtrlHandler( (PHANDLER_ROUTINE) sighandler, TRUE );
#endif
smpSize = nChan * ( nBits == 16 ? sizeof(int16_t) : sizeof(uint8_t) );
if (verbosity >= 2)
fprintf(stderr, "Frame size = %d channels * %d bits = %d bytes\n", nChan, nBits, (int)smpSize);
if (!rawfilename || !strcmp(rawfilename, "-")) {
#ifdef _WIN32
_setmode(_fileno(stdin), _O_BINARY);
#endif
inpfile = stdin;
if (verbosity)
fprintf(stderr, "Using stdin as input\n");
} else {
if (verbosity >= 2)
fprintf(stderr, "Opening input '%s'\n", rawfilename);
inpfile = fopen(rawfilename, "rb");
if (!inpfile) {
fprintf(stderr, "Error: Failed to open input %s\n", rawfilename);
exit(1);
}
if (verbosity)
fprintf(stderr, "Opened '%s' for input\n", rawfilename);
if (!haveTime) {
int gotmodtim = 0;
#ifdef _WIN32
struct _stat attr;
if (!_stat(rawfilename, &attr)) {
tim = attr.st_mtime;
fraction = 0.0;
gotmodtim = 1;
}
#else
struct stat attr;
if (!stat(rawfilename, &attr)) {
tim = attr.st_mtime;
fraction = attr.st_mtim.tv_nsec / 1E9;
gotmodtim = 1;
}
#endif
if (gotmodtim) {
long fs = 0;
if (verbosity >= 2)
fprintf(stderr, "Got 'last modified' from input file '%s'\n", rawfilename);
if (!fseek(inpfile, 0, SEEK_END)) {
fs = ftell(inpfile);
if (fs > 0) {
double dur = (double)(fs) / ( (double)srate * smpSize );
double di = floor(dur);
double df = dur - di;
tim -= (time_t)di;
fraction -= df;
if (fraction < 0.0) {
fraction += 1.0;
tim -= 1;
}
if (verbosity)
fprintf(stderr, "Set output's timestamp from input files 'last modified' minus duration of %f seconds\n", dur);
haveTime = 1;
}
}
fseek(inpfile, 0, SEEK_SET);
}
}
}
tempfilename = malloc( strlen(wavfilename)+8 );
strcpy(tempfilename, wavfilename);
strcat(tempfilename, ".tmp");
if (verbosity >= 2)
fprintf(stderr, "Opening output '%s'\n", tempfilename);
outfile = fopen(tempfilename, "wb");
if (!outfile) {
fprintf(stderr, "Error: Failed to open output '%s'\n", tempfilename);
exit(1);
} else {
if (verbosity)
fprintf(stderr, "Opened '%s' for output\n", tempfilename);
waveWriteHeader(srate, freq, nBits, nChan, outfile);
if (haveTime) {
if (verbosity >= 2)
fprintf(stderr, "Setting start time of output file\n");
waveSetStartTime(tim, fraction);
}
}
while ( !feof(inpfile) ) {
if (do_exit) {
fprintf(stderr, "\nUser cancel, exiting...\n");
break;
}
nRead = fread(acBuf, smpSize, 65536, inpfile);
if (nRead > 0)
waveWriteFrames(outfile, acBuf, nRead, 0);
if (verbosity >= 2)
fprintf(stderr, ".");
}
if (verbosity >= 2)
fprintf(stderr, "\nWriting output header\n");
waveFinalizeHeader(outfile);
fclose(outfile);
if (verbosity)
fprintf(stderr, "Closed output file.\n");
if (verbosity >= 2)
fprintf(stderr, "Deleting '%s' - in case it exists\n", wavfilename);
remove(wavfilename); /* delete, in case file already exists */
if (verbosity >= 2)
fprintf(stderr, "Renaming '%s' into '%s'\n", tempfilename, wavfilename);
r = rename( tempfilename, wavfilename ); /* #include <stdio.h> */
if ( r )
fprintf( stderr, "%s: Error %d '%s' renaming'%s' to '%s'\n"
, argv[0], errno, strerror(errno), tempfilename, wavfilename );
else if (verbosity)
fprintf( stderr, "Renamed output file into '%s'\n", wavfilename );
if (inpfile != stdin)
fclose(inpfile);
return 0;
}
/* vim: tabstop=8:softtabstop=8:shiftwidth=8:noexpandtab */

View File

@ -33,6 +33,10 @@
#include "rtl-sdr.h"
#include "convenience/convenience.h"
#include "convenience/rtl_convenience.h"
#include "convenience/wavewrite.h"
#include "rtl_app_ver.h"
#define DEFAULT_SAMPLE_RATE 2048000
#define DEFAULT_BANDWIDTH 0 /* automatic bandwidth */
@ -40,27 +44,37 @@
#define MINIMAL_BUF_LENGTH 512
#define MAXIMAL_BUF_LENGTH (256 * 16384)
static int do_exit = 0;
static uint32_t bytes_to_read = 0;
static uint32_t iq_frames_to_read = 0;
static rtlsdr_dev_t *dev = NULL;
void usage(void)
{
fprintf(stderr, "rtl_sdr, an I/Q recorder for RTL2832 based receivers\n");
fprintf(stderr, "rtl_sdr version %u.%u %s (%s)\n",
APP_VER_MAJOR, APP_VER_MINOR,
APP_VER_ID, __DATE__ );
fprintf(stderr, "librtlsdr version %u.%u %s\n\n",
(unsigned)(rtlsdr_get_version() >> 16),
(unsigned)(rtlsdr_get_version() & 0xFFFFU),
rtlsdr_get_ver_id()
);
fprintf(stderr,
"rtl_sdr, an I/Q recorder for RTL2832 based DVB-T receivers\n\n"
"Usage:\t -f frequency_to_tune_to [Hz]\n"
"\t[-s samplerate (default: 2048000 Hz)]\n"
"\t[-w tuner_bandwidth (default: automatic)]\n"
"\t[-d device_index or serial (default: 0)]\n"
"\t[-g gain (default: 0 for auto)]\n"
"\t[-p ppm_error (default: 0)]\n"
"\t[-O set RTL options string seperated with ':' ]\n"
"\t f=<freqHz>:bw=<bw_in_kHz>:agc=<tuner_gain_mode>:gain=<tenth_dB>\n"
"\t dagc=<rtl_agc>:ds=<direct_sampling_mode>:T=<bias_tee>\n"
"%s"
"\t[-b output_block_size (default: 16 * 16384)]\n"
"\t[-n number of samples to read (default: 0, infinite)]\n"
"\t[-S force sync output (default: async)]\n"
"\tfilename (a '-' dumps samples to stdout)\n\n");
"\t[-H write wave Header to file (default: off)]\n"
"\tfilename (a '-' dumps samples to stdout)\n\n"
, rtlsdr_get_opt_help(1) );
exit(1);
}
@ -91,19 +105,35 @@ static void rtlsdr_callback(unsigned char *buf, uint32_t len, void *ctx)
if (do_exit)
return;
if ((bytes_to_read > 0) && (bytes_to_read < len)) {
len = bytes_to_read;
if ((iq_frames_to_read) && (iq_frames_to_read < len/2)) {
len = 2U * iq_frames_to_read;
iq_frames_to_read = 0;
do_exit = 1;
rtlsdr_cancel_async(dev);
}
if (fwrite(buf, 1, len, (FILE*)ctx) != len) {
fprintf(stderr, "Short write, samples lost, exiting!\n");
rtlsdr_cancel_async(dev);
if (!waveHdrStarted) {
size_t wr = fwrite(buf, 1, len, (FILE*)ctx);
if ( wr != len) {
fprintf(stderr, "Short write (wrote %ld of %ld bytes), samples lost, exiting!\n"
, (long)wr, (long)len );
rtlsdr_cancel_async(dev);
}
} else {
if ( waveWriteFrames((FILE*)ctx, buf, len/2, 0) ) {
fprintf(stderr, "Short write, samples lost, exiting!\n");
rtlsdr_cancel_async(dev);
}
}
if (bytes_to_read > 0)
bytes_to_read -= len;
if (iq_frames_to_read) {
if (iq_frames_to_read > len/2)
iq_frames_to_read -= len/2;
else {
do_exit = 1;
rtlsdr_cancel_async(dev);
}
}
}
}
@ -113,6 +143,7 @@ int main(int argc, char **argv)
struct sigaction sigact;
#endif
char *filename = NULL;
char *tempfilename = NULL;
int n_read;
int r, opt;
int gain = 0;
@ -123,13 +154,14 @@ int main(int argc, char **argv)
const char * rtlOpts = NULL;
int dev_index = 0;
int dev_given = 0;
int writeWav = 0;
uint32_t frequency = 100000000;
uint32_t bandwidth = DEFAULT_BANDWIDTH;
uint32_t samp_rate = DEFAULT_SAMPLE_RATE;
uint32_t out_block_size = DEFAULT_BUF_LENGTH;
int verbosity = 0;
while ((opt = getopt(argc, argv, "d:f:g:s:w:b:n:p:O:Sv")) != -1) {
while ((opt = getopt(argc, argv, "d:f:g:s:w:b:n:p:O:SHv")) != -1) {
switch (opt) {
case 'd':
dev_index = verbose_device_search(optarg);
@ -157,11 +189,14 @@ int main(int argc, char **argv)
out_block_size = (uint32_t)atof(optarg);
break;
case 'n':
bytes_to_read = (uint32_t)atof(optarg) * 2;
iq_frames_to_read = (uint32_t)atof(optarg);
break;
case 'S':
sync_mode = 1;
break;
case 'H':
writeWav = 1;
break;
case 'v':
++verbosity;
break;
@ -244,11 +279,21 @@ int main(int argc, char **argv)
_setmode(_fileno(stdin), _O_BINARY);
#endif
} else {
file = fopen(filename, "wb");
const char * filename_to_open = filename;
if (writeWav) {
tempfilename = malloc( strlen(filename)+8 );
strcpy(tempfilename, filename);
strcat(tempfilename, ".tmp");
filename_to_open = tempfilename;
}
file = fopen(filename_to_open, "wb");
if (!file) {
fprintf(stderr, "Failed to open %s\n", filename);
fprintf(stderr, "Failed to open %s\n", filename_to_open);
goto out;
}
if (writeWav) {
waveWriteHeader(samp_rate, frequency, 8, 2, file);
}
}
/* Reset endpoint before we start reading from it (mandatory) */
@ -263,14 +308,23 @@ int main(int argc, char **argv)
break;
}
if ((bytes_to_read > 0) && (bytes_to_read < (uint32_t)n_read)) {
n_read = bytes_to_read;
if ((iq_frames_to_read) && (iq_frames_to_read < ((uint32_t)n_read /2))) {
n_read = 2U * iq_frames_to_read;
do_exit = 1;
}
if (fwrite(buffer, 1, n_read, file) != (size_t)n_read) {
fprintf(stderr, "Short write, samples lost, exiting!\n");
break;
if (!waveHdrStarted) {
size_t wr = fwrite(buffer, 1, n_read, file);
if (wr != (size_t)n_read) {
fprintf(stderr, "Short write (wrote %ld of %ld bytes), samples lost, exiting!\n"
, (long)wr, (long)n_read );
break;
}
} else {
if ( waveWriteSamples(file, buffer, n_read/2, 0) ) {
fprintf(stderr, "Short write, samples lost, exiting!\n");
break;
}
}
if ((uint32_t)n_read < out_block_size) {
@ -278,8 +332,12 @@ int main(int argc, char **argv)
break;
}
if (bytes_to_read > 0)
bytes_to_read -= n_read;
if (iq_frames_to_read) {
if (iq_frames_to_read > ((uint32_t)n_read /2))
iq_frames_to_read -= n_read/2;
else
do_exit = 1;
}
}
} else {
fprintf(stderr, "Reading samples in async mode...\n");
@ -287,14 +345,26 @@ int main(int argc, char **argv)
0, out_block_size);
}
if (file != stdout) {
if (writeWav) {
waveFinalizeHeader(file);
fclose(file);
remove(filename); /* delete, in case file already exists */
r = rename( tempfilename, filename ); /* #include <stdio.h> */
if ( r )
fprintf( stderr, "%s: error %d '%s' renaming'%s' to '%s'\n"
, argv[0], errno, strerror(errno), tempfilename, filename );
} else {
fclose(file);
}
}
if (do_exit)
fprintf(stderr, "\nUser cancel, exiting...\n");
else
fprintf(stderr, "\nLibrary error %d, exiting...\n", r);
if (file != stdout)
fclose(file);
rtlsdr_close(dev);
free (buffer);
out:

View File

@ -46,6 +46,9 @@
#include "rtl-sdr.h"
#include "rtl_tcp.h"
#include "convenience/convenience.h"
#include "convenience/rtl_convenience.h"
#include "rtl_app_ver.h"
#ifdef _WIN32
#pragma comment(lib, "ws2_32.lib")
@ -59,6 +62,10 @@ typedef int socklen_t;
#define SOCKET_ERROR -1
#endif
#include "controlThread.h"
static ctrl_thread_data_t ctrldata;
static SOCKET s;
static pthread_t tcp_worker_thread;
@ -95,9 +102,19 @@ static volatile int do_exit = 0;
void usage(void)
{
printf("rtl_tcp, an I/Q spectrum server for RTL2832 based DVB-T receivers\n\n"
"Usage:\t[-a listen address]\n"
"\t[-p listen port (default: 1234)]\n"
fprintf(stderr, "rtl_tcp, an I/Q spectrum server for RTL2832 based receivers\n");
fprintf(stderr, "rtl_tcp version %u.%u %s (%s)\n",
APP_VER_MAJOR, APP_VER_MINOR,
APP_VER_ID, __DATE__ );
fprintf(stderr, "librtlsdr version %u.%u %s\n\n",
(unsigned)(rtlsdr_get_version() >> 16),
(unsigned)(rtlsdr_get_version() & 0xFFFFU),
rtlsdr_get_ver_id()
);
fprintf(stderr, "Usage:\t[-a listen address]\n"
"\t[-p control listen port (default: 1234)]\n"
"\t[-r response listen port: 0 = off; 1 (=default) for On at control listen port +1; or port]\n"
"\t[-I infrared sensor listen port (default: 0=none)]\n"
"\t[-W infrared sensor query wait interval usec (default: 10000)]\n"
"\t[-f frequency to tune to [Hz]]\n"
@ -109,11 +126,13 @@ void usage(void)
"\t[-w rtlsdr tuner bandwidth [Hz] (for R820T and E4000 tuners)]\n"
"\t[-d device index or serial (default: 0)]\n"
"\t[-P ppm_error (default: 0)]\n"
"%s"
"\t[-T enable bias-T on GPIO PIN 0 (works for rtl-sdr.com v3 dongles)]\n"
"\t[-D direct_sampling_mode (default: 0, 1 = I, 2 = Q, 3 = I below threshold, 4 = Q below threshold)]\n"
"\t[-D direct_sampling_threshold_frequency (default: 0 use tuner specific frequency threshold for 3 and 4)]\n"
"\t[-v increase verbosity (default: 0)]\n");
"\t[-v increase verbosity (default: 0)]\n"
, rtlsdr_get_opt_help(1) );
exit(1);
}
@ -305,6 +324,8 @@ static void *command_worker(void *arg)
struct timeval tv= {1, 0};
int r = 0;
uint32_t tmp;
int32_t itmp;
int32_t if_band_center_freq;
while(1) {
left=sizeof(cmd);
@ -326,25 +347,30 @@ static void *command_worker(void *arg)
}
switch(cmd.cmd) {
case SET_FREQUENCY:
printf("set freq %d\n", ntohl(cmd.param));
rtlsdr_set_center_freq(dev,ntohl(cmd.param));
tmp = ntohl(cmd.param);
printf("set freq %u\n", tmp);
rtlsdr_set_center_freq(dev, tmp);
break;
case SET_SAMPLE_RATE:
printf("set sample rate %d\n", ntohl(cmd.param));
rtlsdr_set_sample_rate(dev, ntohl(cmd.param));
tmp = ntohl(cmd.param);
printf("set sample rate %u\n", tmp);
rtlsdr_set_sample_rate(dev, tmp);
/*verbose_set_bandwidth(dev, bandwidth);*/
break;
case SET_GAIN_MODE:
printf("set gain mode %d\n", ntohl(cmd.param));
rtlsdr_set_tuner_gain_mode(dev, ntohl(cmd.param));
tmp = ntohl(cmd.param);
printf("set gain mode %u\n", tmp);
rtlsdr_set_tuner_gain_mode(dev, tmp);
break;
case SET_GAIN:
printf("set gain %d\n", ntohl(cmd.param));
rtlsdr_set_tuner_gain(dev, ntohl(cmd.param));
tmp = ntohl(cmd.param);
printf("set gain %u\n", tmp);
rtlsdr_set_tuner_gain(dev, tmp);
break;
case SET_FREQUENCY_CORRECTION:
printf("set freq correction %d\n", ntohl(cmd.param));
rtlsdr_set_freq_correction(dev, ntohl(cmd.param));
itmp = ntohl(cmd.param);
printf("set freq correction %d\n", itmp);
rtlsdr_set_freq_correction(dev, itmp);
break;
case SET_IF_STAGE:
tmp = ntohl(cmd.param);
@ -352,20 +378,24 @@ static void *command_worker(void *arg)
rtlsdr_set_tuner_if_gain(dev, tmp >> 16, (short)(tmp & 0xffff));
break;
case SET_TEST_MODE:
printf("set test mode %d\n", ntohl(cmd.param));
rtlsdr_set_testmode(dev, ntohl(cmd.param));
tmp = ntohl(cmd.param);
printf("set test mode %d\n", tmp);
rtlsdr_set_testmode(dev, tmp);
break;
case SET_AGC_MODE:
printf("set agc mode %d\n", ntohl(cmd.param));
rtlsdr_set_agc_mode(dev, ntohl(cmd.param));
tmp = ntohl(cmd.param);
printf("set agc mode %d\n", tmp);
rtlsdr_set_agc_mode(dev, tmp);
break;
case SET_DIRECT_SAMPLING:
printf("set direct sampling %d\n", ntohl(cmd.param));
rtlsdr_set_direct_sampling(dev, ntohl(cmd.param));
tmp = ntohl(cmd.param);
printf("set direct sampling %u\n", tmp);
rtlsdr_set_direct_sampling(dev, tmp);
break;
case SET_OFFSET_TUNING:
printf("set offset tuning %d\n", ntohl(cmd.param));
rtlsdr_set_offset_tuning(dev, ntohl(cmd.param));
itmp = ntohl(cmd.param);
printf("set offset tuning %d\n", itmp);
rtlsdr_set_offset_tuning(dev, itmp);
break;
case SET_RTL_CRYSTAL:
printf("set rtl xtal %d\n", ntohl(cmd.param));
@ -376,18 +406,53 @@ static void *command_worker(void *arg)
rtlsdr_set_xtal_freq(dev, 0, ntohl(cmd.param));
break;
case SET_TUNER_GAIN_BY_INDEX:
printf("set tuner gain by index %d\n", ntohl(cmd.param));
set_gain_by_index(dev, ntohl(cmd.param));
tmp = ntohl(cmd.param);
printf("set tuner gain by index %u\n", tmp);
set_gain_by_index(dev, tmp);
break;
case SET_BIAS_TEE:
printf("set bias tee %d\n", ntohl(cmd.param));
rtlsdr_set_bias_tee(dev, (int)ntohl(cmd.param));
tmp = ntohl(cmd.param);
printf("set bias tee %u\n", tmp);
rtlsdr_set_bias_tee(dev, tmp);
break;
case SET_TUNER_BANDWIDTH:
bandwidth = ntohl(cmd.param);
printf("set tuner bandwidth to %i Hz\n", bandwidth);
verbose_set_bandwidth(dev, bandwidth);
break;
case SET_I2C_TUNER_REGISTER:
tmp = ntohl(cmd.param);
printf("set i2c register x%03X to x%03X with mask x%02X\n", (tmp >> 20) & 0xfff, tmp & 0xfff, (tmp >> 12) & 0xff );
rtlsdr_set_tuner_i2c_register(dev, (tmp >> 20) & 0xfff, (tmp >> 12) & 0xff, tmp & 0xfff);
break;
case SET_I2C_TUNER_OVERRIDE:
tmp = ntohl(cmd.param);
printf("set i2c override register x%03X to x%03X with mask x%02X\n", (tmp >> 20) & 0xfff, tmp & 0xfff, (tmp >> 12) & 0xff );
rtlsdr_set_tuner_i2c_override(dev, (tmp >> 20) & 0xfff, (tmp >> 12) & 0xff, tmp & 0xfff);
break;
case SET_TUNER_BW_IF_CENTER:
if_band_center_freq = ntohl(cmd.param);
printf("set tuner band to IF frequency %i Hz from center\n", if_band_center_freq);
rtlsdr_set_tuner_band_center(dev, if_band_center_freq );
break;
case SET_TUNER_IF_MODE:
itmp = ntohl(cmd.param);
printf("set tuner IF mode to %i\n", itmp);
rtlsdr_set_tuner_if_mode(dev, itmp);
break;
case SET_SIDEBAND:
tmp = ntohl(cmd.param);
if(tmp)
tmp = 1;
printf("set to %s sideband\n", (tmp ? "upper" : "lower") );
rtlsdr_set_tuner_sideband(dev, tmp);
break;
case REPORT_I2C_REGS:
tmp = ntohl(cmd.param);
if(tmp)
tmp = 1;
ctrldata.report_i2c = tmp; /* (de)activate reporting */
break;
default:
break;
}
@ -398,7 +463,7 @@ static void *command_worker(void *arg)
struct ir_thread_data
{
rtlsdr_dev_t *dev;
SOCKET port;
int port;
int wait;
char *addr;
};
@ -475,6 +540,11 @@ int main(int argc, char **argv)
int port_ir = 0;
int wait_ir = 10000;
pthread_t thread_ir;
pthread_t thread_ctrl; /* -cs- for periodically reading the register values */
int port_resp = 1;
int report_i2c = 0;
int do_exit_thrd_ctrl = 0;
uint32_t frequency = 100000000, samp_rate = 2048000;
enum rtlsdr_ds_mode ds_mode = RTLSDR_DS_IQ;
uint32_t ds_temp, ds_threshold = 0;
@ -492,6 +562,7 @@ int main(int argc, char **argv)
* 512 samples @ 8 kHz = 64 ms
*/
uint32_t buf_len = 32 * 512;
const char * rtlOpts = NULL;
int dev_index = 0;
int dev_given = 0;
int gain = 0;
@ -507,6 +578,7 @@ int main(int argc, char **argv)
u_long blockmode = 1;
dongle_info_t dongle_info;
int gains[100];
const char * opt_str = NULL;
#ifdef _WIN32
WSADATA wsd;
i = WSAStartup(MAKEWORD(2,2), &wsd);
@ -514,7 +586,8 @@ int main(int argc, char **argv)
struct sigaction sigact, sigign;
#endif
while ((opt = getopt(argc, argv, "a:p:f:g:s:b:n:d:P:TI:W:l:w:D:v")) != -1) {
opt_str = "a:p:f:g:s:b:n:d:P:O:TI:W:l:w:D:vr:";
while ((opt = getopt(argc, argv, opt_str)) != -1) {
switch (opt) {
case 'd':
dev_index = verbose_device_search(optarg);
@ -535,6 +608,10 @@ int main(int argc, char **argv)
case 'p':
port = atoi(optarg);
break;
case 'r':
port_resp = atoi(optarg);
report_i2c = 0;
break;
case 'I':
port_ir = atoi(optarg);
break;
@ -553,6 +630,9 @@ int main(int argc, char **argv)
case 'P':
ppm_error = atoi(optarg);
break;
case 'O':
rtlOpts = optarg;
break;
case 'T':
enable_biastee = 1;
break;
@ -616,6 +696,10 @@ int main(int argc, char **argv)
if (r < 0)
fprintf(stderr, "WARNING: Failed to set sample rate.\n");
if (rtlOpts) {
rtlsdr_set_opt_string(dev, rtlOpts, verbosity);
}
/* Set direct sampling with threshold */
rtlsdr_set_ds_mode(dev, ds_mode, ds_threshold);
@ -644,7 +728,6 @@ int main(int argc, char **argv)
else
fprintf(stderr, "Tuner gain set to %f dB.\n", gain/10.0);
}
verbose_set_bandwidth(dev, bandwidth);
rtlsdr_set_bias_tee(dev, enable_biastee);
@ -668,6 +751,24 @@ int main(int argc, char **argv)
pthread_create(&thread_ir, NULL, &ir_thread_fn, (void *)(&data));
}
#if 0
fprintf(stderr, "enabling Response channel with I2C reporting\n");
port_resp = 1;
report_i2c = 1;
#endif
if ( port_resp == 1 )
port_resp = port + 1;
ctrldata.port = port_resp;
ctrldata.dev = dev;
ctrldata.addr = addr;
ctrldata.wait = 500000; /* = 0.5 sec */
ctrldata.report_i2c = report_i2c;
ctrldata.pDoExit = &do_exit_thrd_ctrl;
if ( port_resp ) {
fprintf(stderr, "activating Response channel on port %d with %s I2C reporting\n"
, port_resp, (report_i2c ? "active" : "inactive") );
pthread_create(&thread_ctrl, NULL, &ctrl_thread_fn, &ctrldata);
}
memset(&local,0,sizeof(local));
local.sin_family = AF_INET;
@ -768,7 +869,13 @@ int main(int argc, char **argv)
out:
rtlsdr_close(dev);
closesocket(listensocket);
//if (port_ir) pthread_join(thread_ir, &status);
/* if (port_ir) pthread_join(thread_ir, &status); */
if ( port_resp ) {
do_exit_thrd_ctrl = 1;
pthread_join(thread_ctrl, &status);
}
closesocket(s);
#ifdef _WIN32
WSACleanup();

View File

@ -42,6 +42,7 @@
#include "rtl-sdr.h"
#include "convenience/convenience.h"
#include "convenience/rtl_convenience.h"
#define DEFAULT_SAMPLE_RATE 2048000
#define DEFAULT_BUF_LENGTH (16 * 16384)
@ -91,15 +92,14 @@ void usage(void)
"Usage:\n"
"\t[-s samplerate (default: 2048000 Hz)]\n"
"\t[-d device_index or serial (default: 0)]\n"
"\t[-O set RTL options string seperated with ':' ]\n"
"\t f=<freqHz>:bw=<bw_in_kHz>:agc=<tuner_gain_mode>:gain=<tenth_dB>\n"
"\t dagc=<rtl_agc>:ds=<direct_sampling_mode>:T=<bias_tee>\n"
"%s"
"\t[-t enable Elonics E4000 tuner benchmark]\n"
#ifndef _WIN32
"\t[-p[seconds] enable PPM error measurement (default: 10 seconds)]\n"
#endif
"\t[-b output_block_size (default: 16 * 16384)]\n"
"\t[-S force sync output (default: async)]\n");
"\t[-S force sync output (default: async)]\n"
, rtlsdr_get_opt_help(1) );
exit(1);
}

View File

@ -35,6 +35,7 @@
#else
#include <winsock2.h>
#include "getopt/getopt.h"
#define usleep(x) Sleep(x/1000)
#endif
#ifdef NEED_PTHREADS_WORKARROUND
@ -45,6 +46,9 @@
#include "rtl-sdr.h"
#include "rtl_tcp.h"
#include "convenience/convenience.h"
#include "convenience/rtl_convenience.h"
#include "rtl_app_ver.h"
#ifdef _WIN32
#pragma comment(lib, "ws2_32.lib")
@ -84,8 +88,9 @@ typedef struct { /* structure size must be multiple of 2 bytes */
static rtlsdr_dev_t *dev = NULL;
static int verbosity = 0;
static int enable_biastee = 0;
static uint32_t bandwidth = 0;
static int enable_biastee = 0;
static int global_numq = 0;
static struct llist *ll_buffers = 0;
static int llbuf_num = 500;
@ -94,8 +99,17 @@ static volatile int do_exit = 0;
void usage(void)
{
printf("rtl_tcp, an I/Q spectrum server for RTL2832 based DVB-T receivers\n\n"
"Usage:\t[-a listen address]\n"
fprintf(stderr, "rtl_udp, an I/Q spectrum server for RTL2832 based receivers\n");
fprintf(stderr, "rtl_udp version %u.%u %s (%s)\n",
APP_VER_MAJOR, APP_VER_MINOR,
APP_VER_ID, __DATE__ );
fprintf(stderr, "librtlsdr version %u.%u %s\n\n",
(unsigned)(rtlsdr_get_version() >> 16),
(unsigned)(rtlsdr_get_version() & 0xFFFFU),
rtlsdr_get_ver_id()
);
fprintf(stderr, "Usage:\t[-a listen address]\n"
"\t[-p listen port (default: 1234)]\n"
"\t[-I infrared sensor listen port (default: 0=none)]\n"
"\t[-W infrared sensor query wait interval usec (default: 10000)]\n"
@ -106,12 +120,15 @@ void usage(void)
"\t[-l length of single buffer in units of 512 samples (default: 32 was 256)]\n"
"\t[-n max number of linked list buffers to keep (default: 500)]\n"
"\t[-w rtlsdr tuner bandwidth [Hz] (for R820T and E4000 tuners)]\n"
"\t[-d device index (default: 0)]\n"
"\t[-d device index or serial (default: 0)]\n"
"\t[-P ppm_error (default: 0)]\n"
"%s"
"\t[-T enable bias-T on GPIO PIN 0 (works for rtl-sdr.com v3 dongles)]\n"
"\t[-D direct_sampling_mode (default: 0, 1 = I, 2 = Q, 3 = I below threshold, 4 = Q below threshold)]\n"
"\t[-D direct_sampling_threshold_frequency (default: 0 use tuner specific frequency threshold for 3 and 4)]\n"
"\t[-v increase verbosity (default: 0)]\n");
"\t[-v increase verbosity (default: 0)]\n"
, rtlsdr_get_opt_help(1) );
exit(1);
}
@ -303,6 +320,8 @@ static void *command_worker(void *arg)
struct timeval tv= {1, 0};
int r = 0;
uint32_t tmp;
int32_t itmp;
int32_t if_band_center_freq;
while(1) {
left=sizeof(cmd);
@ -324,25 +343,30 @@ static void *command_worker(void *arg)
}
switch(cmd.cmd) {
case SET_FREQUENCY:
printf("set freq %d\n", ntohl(cmd.param));
rtlsdr_set_center_freq(dev,ntohl(cmd.param));
tmp = ntohl(cmd.param);
printf("set freq %u\n", tmp);
rtlsdr_set_center_freq(dev, tmp);
break;
case SET_SAMPLE_RATE:
printf("set sample rate %d\n", ntohl(cmd.param));
rtlsdr_set_sample_rate(dev, ntohl(cmd.param));
tmp = ntohl(cmd.param);
printf("set sample rate %u\n", tmp);
rtlsdr_set_sample_rate(dev, tmp);
/*verbose_set_bandwidth(dev, bandwidth);*/
break;
case SET_GAIN_MODE:
printf("set gain mode %d\n", ntohl(cmd.param));
rtlsdr_set_tuner_gain_mode(dev, ntohl(cmd.param));
tmp = ntohl(cmd.param);
printf("set gain mode %u\n", tmp);
rtlsdr_set_tuner_gain_mode(dev, tmp);
break;
case SET_GAIN:
printf("set gain %d\n", ntohl(cmd.param));
rtlsdr_set_tuner_gain(dev, ntohl(cmd.param));
tmp = ntohl(cmd.param);
printf("set gain %u\n", tmp);
rtlsdr_set_tuner_gain(dev, tmp);
break;
case SET_FREQUENCY_CORRECTION:
printf("set freq correction %d\n", ntohl(cmd.param));
rtlsdr_set_freq_correction(dev, ntohl(cmd.param));
itmp = ntohl(cmd.param);
printf("set freq correction %d\n", itmp);
rtlsdr_set_freq_correction(dev, itmp);
break;
case SET_IF_STAGE:
tmp = ntohl(cmd.param);
@ -350,20 +374,24 @@ static void *command_worker(void *arg)
rtlsdr_set_tuner_if_gain(dev, tmp >> 16, (short)(tmp & 0xffff));
break;
case SET_TEST_MODE:
printf("set test mode %d\n", ntohl(cmd.param));
rtlsdr_set_testmode(dev, ntohl(cmd.param));
tmp = ntohl(cmd.param);
printf("set test mode %d\n", tmp);
rtlsdr_set_testmode(dev, tmp);
break;
case SET_AGC_MODE:
printf("set agc mode %d\n", ntohl(cmd.param));
rtlsdr_set_agc_mode(dev, ntohl(cmd.param));
tmp = ntohl(cmd.param);
printf("set agc mode %d\n", tmp);
rtlsdr_set_agc_mode(dev, tmp);
break;
case SET_DIRECT_SAMPLING:
printf("set direct sampling %d\n", ntohl(cmd.param));
rtlsdr_set_direct_sampling(dev, ntohl(cmd.param));
tmp = ntohl(cmd.param);
printf("set direct sampling %u\n", tmp);
rtlsdr_set_direct_sampling(dev, tmp);
break;
case SET_OFFSET_TUNING:
printf("set offset tuning %d\n", ntohl(cmd.param));
rtlsdr_set_offset_tuning(dev, ntohl(cmd.param));
itmp = ntohl(cmd.param);
printf("set offset tuning %d\n", itmp);
rtlsdr_set_offset_tuning(dev, itmp);
break;
case SET_RTL_CRYSTAL:
printf("set rtl xtal %d\n", ntohl(cmd.param));
@ -374,23 +402,54 @@ static void *command_worker(void *arg)
rtlsdr_set_xtal_freq(dev, 0, ntohl(cmd.param));
break;
case SET_TUNER_GAIN_BY_INDEX:
printf("set tuner gain by index %d\n", ntohl(cmd.param));
set_gain_by_index(dev, ntohl(cmd.param));
tmp = ntohl(cmd.param);
printf("set tuner gain by index %u\n", tmp);
set_gain_by_index(dev, tmp);
break;
case SET_BIAS_TEE:
tmp = ntohl(cmd.param);
printf("set bias tee %u\n", tmp);
rtlsdr_set_bias_tee(dev, tmp);
break;
case SET_TUNER_BANDWIDTH:
bandwidth = ntohl(cmd.param);
printf("set tuner bandwidth to %i Hz\n", bandwidth);
verbose_set_bandwidth(dev, bandwidth);
break;
case SET_BIAS_TEE:
printf("setting bias-t to %d\n", ntohl(cmd.param));
rtlsdr_set_bias_tee(dev, ntohl(cmd.param));
case SET_I2C_TUNER_REGISTER:
tmp = ntohl(cmd.param);
printf("set i2c register x%03X to x%03X with mask x%02X\n", (tmp >> 20) & 0xfff, tmp & 0xfff, (tmp >> 12) & 0xff );
rtlsdr_set_tuner_i2c_register(dev, (tmp >> 20) & 0xfff, (tmp >> 12) & 0xff, tmp & 0xfff);
break;
case SET_I2C_TUNER_OVERRIDE:
tmp = ntohl(cmd.param);
printf("set i2c override register x%03X to x%03X with mask x%02X\n", (tmp >> 20) & 0xfff, tmp & 0xfff, (tmp >> 12) & 0xff );
rtlsdr_set_tuner_i2c_override(dev, (tmp >> 20) & 0xfff, (tmp >> 12) & 0xff, tmp & 0xfff);
break;
case UDP_TERMINATE:
printf("comm recv bye\n");
sighandler(0);
pthread_exit(NULL);
break;
case SET_TUNER_BW_IF_CENTER:
if_band_center_freq = ntohl(cmd.param);
printf("set tuner band to IF frequency %i Hz from center\n", if_band_center_freq);
rtlsdr_set_tuner_band_center(dev, if_band_center_freq );
break;
case SET_TUNER_IF_MODE:
itmp = ntohl(cmd.param);
printf("set tuner IF mode to %i\n", itmp);
rtlsdr_set_tuner_if_mode(dev, itmp);
break;
case SET_SIDEBAND:
tmp = ntohl(cmd.param);
if(tmp) {
tmp = 1;
printf("set to upper sideband\n");
} else
printf("set to lower sideband\n");
rtlsdr_set_tuner_sideband(dev, tmp);
break;
default:
break;
}
@ -478,7 +537,7 @@ int main(int argc, char **argv)
int port_ir = 0;
int wait_ir = 10000;
pthread_t thread_ir;
uint32_t frequency = 100000000, samp_rate = 2097152;
uint32_t frequency = 100000000, samp_rate = 2048000;
enum rtlsdr_ds_mode ds_mode = RTLSDR_DS_IQ;
uint32_t ds_temp, ds_threshold = 0;
struct sockaddr_in local;
@ -495,6 +554,7 @@ int main(int argc, char **argv)
* 512 samples @ 8 kHz = 64 ms
*/
uint32_t buf_len = 32 * 512;
const char * rtlOpts = NULL;
int dev_index = 0;
int dev_given = 0;
int gain = 0;
@ -517,7 +577,7 @@ int main(int argc, char **argv)
struct sigaction sigact, sigign;
#endif
while ((opt = getopt(argc, argv, "a:p:I:W:f:g:s:b:l:n:d:P:w:D:vT")) != -1) {
while ((opt = getopt(argc, argv, "a:p:I:W:f:g:s:b:l:n:d:P:uw:D:vT")) != -1) {
switch (opt) {
case 'd':
dev_index = verbose_device_search(optarg);
@ -556,15 +616,18 @@ int main(int argc, char **argv)
case 'P':
ppm_error = atoi(optarg);
break;
case 'O':
rtlOpts = optarg;
break;
case 'T':
enable_biastee = 1;
break;
case 'w':
bandwidth = (uint32_t)atofs(optarg);
break;
case 'v':
++verbosity;
break;
case 'T':
enable_biastee = 1;
break;
case 'D':
ds_temp = (uint32_t)( atofs(optarg) + 0.5 );
if (ds_temp <= RTLSDR_DS_Q_BELOW)
@ -611,6 +674,10 @@ int main(int argc, char **argv)
SetConsoleCtrlHandler( (PHANDLER_ROUTINE) sighandler, TRUE );
#endif
if (rtlOpts) {
rtlsdr_set_opt_string(dev, rtlOpts, verbosity);
}
/* Set the tuner error */
verbose_ppm_set(dev, ppm_error);
@ -647,7 +714,6 @@ int main(int argc, char **argv)
else
fprintf(stderr, "Tuner gain set to %f dB.\n", gain/10.0);
}
verbose_set_bandwidth(dev, bandwidth);
rtlsdr_set_bias_tee(dev, enable_biastee);
@ -766,7 +832,7 @@ int main(int argc, char **argv)
out:
rtlsdr_close(dev);
//if (port_ir) pthread_join(thread_ir, &status);
/* if (port_ir) pthread_join(thread_ir, &status); */
closesocket(s);
#ifdef _WIN32
WSACleanup();

283
src/rtl_wavestat.c 100644
View File

@ -0,0 +1,283 @@
/*
* rtl-wavestat, display wave file meta information
* Copyright (C) 2019 by Hayati Ayguen <h_ayguen@web.de>
*
* 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/>.
*/
#include <errno.h>
#include <signal.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#ifndef _WIN32
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#else
#include <windows.h>
#include <fcntl.h>
#include <io.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "getopt/getopt.h"
#if defined(_MSC_VER) && (_MSC_VER < 1900)
#define snprintf _snprintf
#endif
#endif
#include "convenience/convenience.h"
#include "convenience/waveread.h"
#include "rtl_app_ver.h"
static volatile int do_exit = 0;
static int verbosity = 0;
void usage(void)
{
fprintf(stderr, "rtl_wavestat, display wave file meta information\n");
fprintf(stderr, "rtl_wavestat version %u.%u %s (%s)\n",
APP_VER_MAJOR, APP_VER_MINOR,
APP_VER_ID, __DATE__ );
fprintf(stderr,
"Use:\trtl_wavestat [-options] <input_wave_filename>\n"
"\t-a print all information\n"
"\t-r print without field name\n"
"\t-f print center frequency in Hz\n"
"\t-s print samplerate in Hz\n"
"\t-c print number of channels\n"
"\t-b print number of bits per sample\n"
"\t-F print sample Format\n"
"\t-u print start time in UTC: 'yyy-mm-ddThh:mm:dd.zzz'\n"
"\t-t print start time in localtime: 'yyy-mm-ddThh:mm:dd.zzz'\n"
"\t-z print start time in seconds since 1970-01-01T00:00:00.000\n"
"\t-d print file duration in frames (= num samples per channel)\n"
"\t-D print file duration in seconds\n"
"\t-w input file\n"
"\t-v verbose output\n" );
}
#ifdef _WIN32
BOOL WINAPI
sighandler(int signum)
{
if (CTRL_C_EVENT == signum) {
fprintf(stderr, "Signal caught, exiting!\n");
do_exit = 1;
return TRUE;
}
return FALSE;
}
#else
static void sighandler(int signum)
{
fprintf(stderr, "Signal caught, exiting!\n");
do_exit = 1;
}
#endif
int main(int argc, char **argv)
{
#ifndef _WIN32
struct sigaction sigact;
#endif
int r, opt;
const char * wavfilename = NULL;
FILE * inpfile = stdin;
uint32_t freq = 0;
uint32_t srate = 0;
int nChan = 0;
int nBits = 0;
int16_t formatTag;
uint32_t numFrames;
time_t tim = 0;
double fraction = 0.0;
struct tm *ptm = NULL;
int printAll = 0;
int printFieldName = 1;
int printFreq = 0;
int printSRate = 0;
int printNchan = 0;
int printNbits = 0;
int printSmpFmt = 0;
int printStartZ = 0;
int printStartL = 0;
int printStartUnix = 0;
int printDurationSmp = 0;
int printDurationTim = 0;
while ((opt = getopt(argc, argv, "arfscbFutzdDvhw:")) != -1) {
switch (opt) {
case 'a': printAll = 1; break;
case 'r': printFieldName = 0; break;
case 'f': printFreq = 1; break;
case 's': printSRate = 1; break;
case 'c': printNchan = 1; break;
case 'b': printNbits = 1; break;
case 'F': printSmpFmt = 1; break;
case 'u': printStartZ = 1; break;
case 't': printStartL = 1; break;
case 'z': printStartUnix = 1; break;
case 'd': printDurationSmp = 1; break;
case 'D': printDurationTim = 1; break;
case 'w': wavfilename = optarg; break;
case 'v': ++verbosity; break;
case 'h':
case '?':
default:
usage();
exit(1);
break;
}
}
if (verbosity)
fprintf(stderr, "verbosity set to %d\n", verbosity);
if (optind < argc) {
wavfilename = argv[optind];
}
#ifndef _WIN32
sigact.sa_handler = sighandler;
sigemptyset(&sigact.sa_mask);
sigact.sa_flags = 0;
sigaction(SIGINT, &sigact, NULL);
sigaction(SIGTERM, &sigact, NULL);
sigaction(SIGQUIT, &sigact, NULL);
sigaction(SIGPIPE, &sigact, NULL);
#else
SetConsoleCtrlHandler( (PHANDLER_ROUTINE) sighandler, TRUE );
#endif
if (!wavfilename || !strcmp(wavfilename, "-")) {
#ifdef _WIN32
_setmode(_fileno(stdin), _O_BINARY);
#endif
inpfile = stdin;
if (verbosity)
fprintf(stderr, "Using stdin as input\n");
} else {
if (verbosity >= 2)
fprintf(stderr, "Opening input '%s'\n", wavfilename);
inpfile = fopen(wavfilename, "rb");
if (!inpfile) {
fprintf(stderr, "Error: Failed to open input %s\n", wavfilename);
exit(1);
}
if (verbosity)
fprintf(stderr, "Opened '%s' for input\n", wavfilename);
}
r = waveReadHeader(inpfile, &srate, &freq, &nBits, &nChan, &numFrames, &formatTag, verbosity);
if ( r >= 10 ) {
fprintf(stderr, "Error %d reading/evaluating wave file header\n", r);
exit(1);
} else if ( verbosity >= 2 ) {
fprintf(stderr, "Success reading/evaluating wave file header\n");
}
if ( !printFreq && !printSRate && !printNchan && !printNbits && !printSmpFmt && !printStartZ && !printStartL
&& !printDurationSmp && !printDurationTim ) {
printAll = 1;
}
if ( printAll || printFreq ) {
if ( printFieldName )
fprintf(stdout, "frequency/Hz:\t");
fprintf(stdout, "%lu\n", (unsigned long)freq);
}
if ( printAll || printSRate ) {
if ( printFieldName )
fprintf(stdout, "samplerate/Hz:\t");
fprintf(stdout, "%lu\n", (unsigned long)srate);
}
if ( printAll || printNchan ) {
if ( printFieldName )
fprintf(stdout, "num_channels:\t");
fprintf(stdout, "%d\n", nChan);
}
if ( printAll || printNbits ) {
if ( printFieldName )
fprintf(stdout, "bits_per_sample:\t");
fprintf(stdout, "%d\n", nBits);
}
if ( printAll || printSmpFmt ) {
if ( printFieldName )
fprintf(stdout, "sample_format:\t");
if (formatTag == 0x0001)
fprintf(stdout, "0x%04X\tPCM\n", (unsigned)formatTag);
else if (formatTag == 0x0003)
fprintf(stdout, "0x%04X\tIEEE_FLOAT\n", (unsigned)formatTag);
else
fprintf(stdout, "0x%04X\n", (unsigned)formatTag);
}
if ( printAll || printStartZ ) {
waveGetStartTime(&tim, &fraction);
ptm = gmtime(&tim);
if (ptm) {
if ( printFieldName )
fprintf(stdout, "time_start/Z:\t");
fprintf(stdout, "%04d-%02d-%02dT%02d:%02d:%02d.%03d\n"
, ptm->tm_year+1900, ptm->tm_mon+1, ptm->tm_mday
, ptm->tm_hour, ptm->tm_min, ptm->tm_sec, (int)(fraction*1000.0) );
}
}
if ( printAll || printStartL ) {
waveGetStartTime(&tim, &fraction);
ptm = localtime(&tim);
if (ptm) {
if ( printFieldName )
fprintf(stdout, "time_start/L:\t");
fprintf(stdout, "%04d-%02d-%02dT%02d:%02d:%02d.%03d\n"
, ptm->tm_year+1900, ptm->tm_mon+1, ptm->tm_mday
, ptm->tm_hour, ptm->tm_min, ptm->tm_sec, (int)(fraction*1000.0) );
}
}
if ( printAll || printStartUnix ) {
tim = 0;
fraction = 0;
waveGetStartTime(&tim, &fraction);
if ( printFieldName )
fprintf(stdout, "time_start/secs (unix):\t");
fraction += (double)tim;
fprintf(stdout, "%f\n", fraction );
}
if ( printAll || printDurationSmp ) {
if ( printFieldName )
fprintf(stdout, "duration/frames:\t");
fprintf(stdout, "%lu\n", (unsigned long)numFrames);
}
if ( printAll || printDurationTim ) {
if ( printFieldName )
fprintf(stdout, "duration/secs:\t");
fprintf(stdout, "%f\n", (double)numFrames/(double)srate);
}
if (inpfile != stdin)
fclose(inpfile);
return 0;
}
/* vim: tabstop=8:softtabstop=8:shiftwidth=8:noexpandtab */

View File

@ -0,0 +1,314 @@
/*
* rtl-wavestream, stream raw data (in specified sample format)
* Copyright (C) 2019 by Hayati Ayguen <h_ayguen@web.de>
*
* 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/>.
*/
#include <errno.h>
#include <signal.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#ifndef _WIN32
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#else
#include <windows.h>
#include <fcntl.h>
#include <io.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "getopt/getopt.h"
#if defined(_MSC_VER) && (_MSC_VER < 1900)
#define snprintf _snprintf
#endif
#endif
#include "convenience/convenience.h"
#include "convenience/waveread.h"
#include "rtl_app_ver.h"
static volatile int do_exit = 0;
static int verbosity = 0;
#define BLOCKLEN 65536
/* read up to 64K samples */
static uint8_t inpBuffer[BLOCKLEN * sizeof(int32_t)];
/* output is max 4 times bigger: uint8_t -> int32_t */
static uint8_t outBuffer[BLOCKLEN * sizeof(int32_t) * sizeof(int32_t)];
void usage(void)
{
fprintf(stderr, "rtl_wavestream, stream raw data (in specified format)\n");
fprintf(stderr, "rtl_wavestream version %u.%u %s (%s)\n",
APP_VER_MAJOR, APP_VER_MINOR,
APP_VER_ID, __DATE__ );
fprintf(stderr,
"Use:\trtl_wavestream [-options] <input_wave_filename>\n"
"\t-f <fmt> sample format for output. default = input format\n"
"\t supported formats: 'PCM16'/'PCM' or 'FLOAT32'/'FLOAT'\n"
"\t-w input file\n"
"\t-v verbose output\n" );
}
#ifdef _WIN32
BOOL WINAPI
sighandler(int signum)
{
if (CTRL_C_EVENT == signum) {
fprintf(stderr, "Signal caught, exiting!\n");
do_exit = 1;
return TRUE;
}
return FALSE;
}
#else
static void sighandler(int signum)
{
fprintf(stderr, "Signal caught, exiting!\n");
do_exit = 1;
}
#endif
int main(int argc, char **argv)
{
#ifndef _WIN32
struct sigaction sigact;
#endif
int r, opt;
const char * wavfilename = NULL;
const char * targetFmtStr = "pcm16";
FILE * inpfile = NULL;
uint32_t freq = 0;
uint32_t srate = 0;
int nChan = 0;
int nBits = 0;
int targetFmt = 0; /* PCM16 = 0, FLOAT32 = 1 */
int inputFmt = 0; /* PCM16 = 0, FLOAT32 = 1 */
int16_t formatTag;
uint32_t numFrames;
time_t tim = 0;
double fraction = 0.0;
struct tm *ptm = NULL;
while ((opt = getopt(argc, argv, "f:w:vh")) != -1) {
switch (opt) {
case 'f': targetFmtStr = optarg; break;
case 'w': wavfilename = optarg; break;
case 'v': ++verbosity; break;
case 'h':
case '?':
default:
usage();
exit(1);
break;
}
}
if (verbosity)
fprintf(stderr, "verbosity set to %d\n", verbosity);
if (optind < argc) {
wavfilename = argv[optind];
}
if ( !strcmp(targetFmtStr, "pcm") || !strcmp(targetFmtStr, "pcm16")
|| !strcmp(targetFmtStr, "PCM") || !strcmp(targetFmtStr, "PCM16") )
{
targetFmt = 0; /* PCM16 = 0, FLOAT32 = 1 */
if (verbosity)
fprintf(stderr, "target sample format: PCM16\n");
}
else if ( !strcmp(targetFmtStr, "flt32") || !strcmp(targetFmtStr, "float32") || !strcmp(targetFmtStr, "float")
|| !strcmp(targetFmtStr, "FLT32") || !strcmp(targetFmtStr, "FLOAT32") || !strcmp(targetFmtStr, "FLOAT") )
{
targetFmt = 1; /* PCM16 = 0, FLOAT32 = 1 */
if (verbosity)
fprintf(stderr, "target sample format: FLOAT32\n");
}
else
{
fprintf(stderr, "Error: unsupported target format. accepting 'PCM16'/'PCM' or 'FLOAT32'/'FLOAT'\n");
exit(1);
}
#ifndef _WIN32
sigact.sa_handler = sighandler;
sigemptyset(&sigact.sa_mask);
sigact.sa_flags = 0;
sigaction(SIGINT, &sigact, NULL);
sigaction(SIGTERM, &sigact, NULL);
sigaction(SIGQUIT, &sigact, NULL);
sigaction(SIGPIPE, &sigact, NULL);
#else
SetConsoleCtrlHandler( (PHANDLER_ROUTINE) sighandler, TRUE );
#endif
#ifdef _WIN32
_setmode(_fileno(stdout), _O_BINARY);
#endif
if (!wavfilename) {
fprintf(stderr, "Error: No input file specified!\n");
exit(1);
} else {
if (verbosity >= 2)
fprintf(stderr, "Opening input '%s'\n", wavfilename);
inpfile = fopen(wavfilename, "rb");
if (!inpfile) {
fprintf(stderr, "Error: Failed to open input %s\n", wavfilename);
exit(1);
}
if (verbosity)
fprintf(stderr, "Opened '%s' for input\n", wavfilename);
}
r = waveReadHeader(inpfile, &srate, &freq, &nBits, &nChan, &numFrames, &formatTag, verbosity);
if ( r >= 10 ) {
fprintf(stderr, "Error %d reading/evaluating wave file header\n", r);
} else if ( verbosity >= 2 ) {
fprintf(stderr, "Success reading/evaluating wave file header\n");
}
if ( verbosity ) {
fprintf(stderr, "frequency/Hz:\t%lu\n", (unsigned long)freq);
fprintf(stderr, "samplerate/Hz:\t%lu\n", (unsigned long)srate);
fprintf(stderr, "num_channels:\t%d\n", nChan);
fprintf(stderr, "bits_per_sample:\t%d\n", nBits);
if (formatTag == 0x0001)
fprintf(stderr, "sample_format:\t0x%04X\tPCM\n", (unsigned)formatTag);
else if (formatTag == 0x0003)
fprintf(stderr, "sample_format:\t0x%04X\tIEEE_FLOAT\n", (unsigned)formatTag);
else
fprintf(stderr, "sample_format:\t0x%04X\n", (unsigned)formatTag);
fprintf(stderr, "duration/frames:\t%lu\t0x%lX\n", (unsigned long)numFrames, (unsigned long)numFrames);
fprintf(stderr, "duration/secs:\t%f\n", (double)numFrames/(double)srate);
}
if ( formatTag == 0x0001 && nBits == 16 ) {
inputFmt = 0;
if (verbosity)
fprintf(stderr, "input sample format: PCM16\n");
}
else if ( formatTag == 0x0003 && nBits == 32 ) {
inputFmt = 1;
if (verbosity)
fprintf(stderr, "input sample format: FLOAT32\n");
}
else
{
fprintf(stderr, "Error: unsupported input format. only 'PCM16' and 'FLOAT32' supported.\n");
exit(1);
}
{
void * pvInp = &inpBuffer[0];
void * pvOut = &outBuffer[0];
const size_t numFramesPerRead = BLOCKLEN / nChan;
const size_t numSmpPerRead = numFramesPerRead * nChan;
const size_t inpSmpSize = (inputFmt == 0) ? sizeof(int16_t) : sizeof(float);
const size_t outSmpSize = (targetFmt == 0) ? sizeof(int16_t) : sizeof(float);
size_t numSamples = numFrames * nChan;
size_t readTotal = 0;
size_t numRead;
if ( verbosity )
{
fprintf(stderr, "input sample size = %u\n", (unsigned)inpSmpSize);
fprintf(stderr, "output sample size = %u\n", (unsigned)outSmpSize);
fprintf(stderr, "samples per read = %u smp\n", (unsigned)numSmpPerRead);
}
while ( !do_exit )
{
const size_t numToRead = numSmpPerRead;
const size_t readErr = waveReadSamples(inpfile, pvInp, numToRead, 0, &numRead);
if ( numRead != numToRead )
fprintf(stderr, "Error: reading %lu delivered %lu smp after %lu smp - left %lu frames\n"
, (unsigned long)numToRead, (unsigned long)numRead
, (unsigned long)readTotal, (unsigned long)(numSamples / nChan) );
if ( readErr )
{
fprintf(stderr, "Error reading samples after %lu smp - left %lu frames\n"
, (unsigned long)readTotal, (unsigned long)(numSamples / nChan) );
}
else if ( verbosity >= 2 )
fprintf(stderr, "read %lu samples: left frames: %lu\n"
, (unsigned long)numToRead, (unsigned long)numSamples);
if ( !numRead )
break;
if ( inputFmt == targetFmt ) {
size_t w = fwrite(pvInp, inpSmpSize, numRead, stdout);
if ( w != numRead ) {
fprintf(stderr, "Error writing read samples after %lu smp - left %lu frames\n"
, (unsigned long)readTotal, (unsigned long)(numSamples / nChan) );
break;
}
}
else if ( inputFmt == 0 && targetFmt == 1 ) {
const int16_t *ai = (const int16_t*)pvInp;
float * ao = (float*)pvOut;
size_t w;
for ( size_t k = 0; k < numRead; ++k )
ao[k] = ai[k] * (1.0F / 32768.0F);
w = fwrite(pvOut, outSmpSize, numRead, stdout);
if ( w != numRead ) {
fprintf(stderr, "Error writing converted samples after %lu smp - left %lu frames\n"
, (unsigned long)readTotal, (unsigned long)(numSamples / nChan) );
break;
}
}
else if ( inputFmt == 1 && targetFmt == 0 ) {
const float *ai = (const float*)pvInp;
int16_t * ao = (int16_t*)pvOut;
size_t w;
for ( size_t k = 0; k < numRead; ++k )
ao[k] = (int16_t)( ai[k] * 32768.0F );
w = fwrite(pvOut, outSmpSize, numRead, stdout);
if ( w != numRead ) {
fprintf(stderr, "Error writing converted samples after %lu smp - left %lu frames\n"
, (unsigned long)readTotal, (unsigned long)(numSamples / nChan) );
break;
}
}
numSamples -= numRead;
readTotal += numRead;
}
if ( verbosity )
{
fprintf(stderr, "Written %lu samples in total - left %lu of %lu frames\n"
, (unsigned long)readTotal, (unsigned long)(numSamples / nChan), (unsigned long)(numFrames * nChan) );
}
}
fclose(inpfile);
return 0;
}
/* vim: tabstop=8:softtabstop=8:shiftwidth=8:noexpandtab */

View File

@ -54,38 +54,92 @@ static int fc0012_readreg(void *dev, uint8_t reg, uint8_t *val)
return 0;
}
/* expose/permit tuner specific i2c register hacking! */
int fc0012_set_i2c_register(void *dev, unsigned i2c_register, unsigned data)
{
uint8_t reg = i2c_register & 0xFF;
uint8_t reg_val = data & 0xFF;
return fc0012_writereg(dev, reg, reg_val);
}
int fc0012_get_i2c_register(void *dev, unsigned char* data, int len)
{
int len1;
data[0] = 0;
/* The lower 16 I2C registers can be read with the normal read fct,
* the upper ones are read from the cache */
if(len < 16)
len1 = len;
else
len1 = 16;
if (rtlsdr_i2c_write_fn(dev, FC0012_I2C_ADDR, data, 1) < 0)
return -1;
if (rtlsdr_i2c_read_fn(dev, FC0012_I2C_ADDR, data, len1) < 0)
return -1;
if(len > 16)
{
len1 = len - 16;
data[16] = 16;
if (rtlsdr_i2c_write_fn(dev, FC0012_I2C_ADDR, data+16, 1) < 0)
return -1;
if (rtlsdr_i2c_read_fn(dev, FC0012_I2C_ADDR, data+16, len1) < 0)
return -1;
}
return 0;
}
static int print_registers(void *dev)
{
uint8_t data[32];
unsigned int i;
if (fc0012_get_i2c_register(dev, data, 32) < 0)
return -1;
for(i=0; i<16; i++)
printf("%02x ", data[i]);
printf("\n");
for(i=16; i<32; i++)
printf("%02x ", data[i]);
printf("\n");
return 0;
}
/* Incomplete list of register settings:
*
* Name Reg Bits Desc
* CHIP_ID 0x00 0-7 Chip ID (constant 0xA1)
* RF_A 0x01 0-3 Number of count-to-9 cycles in RF
* divider (suggested: 2..9)
* RF_M 0x02 0-7 Total number of cycles (to-8 and to-9)
* in RF divider
* Name Reg BitsDesc
* CHIP_ID 0x00 0-7 Chip ID (constant 0xA1)
* RF_A 0x01 0-3 Number of count-to-9 cycles in RF
* divider (suggested: 2..9)
* RF_M 0x02 0-7 Total number of cycles (to-8 and to-9)
* in RF divider
* RF_K_HIGH 0x03 0-6 Bits 8..14 of fractional divider
* RF_K_LOW 0x04 0-7 Bits 0..7 of fractional RF divider
* RF_K_LOW 0x04 0-7 Bits 0..7 of fractional RF divider
* RF_OUTDIV_A 0x05 3-7 Power of two required?
* LNA_POWER_DOWN 0x06 0 Set to 1 to switch off low noise amp
* RF_OUTDIV_B 0x06 1 Set to select 3 instead of 2 for the
* RF output divider
* RF output divider
* VCO_SPEED 0x06 3 Select tuning range of VCO:
* 0 = Low range, (ca. 1.1 - 1.5GHz)
* 1 = High range (ca. 1.4 - 1.8GHz)
* 0 = Low range, (ca. 1.1 - 1.5GHz)
* 1 = High range (ca. 1.4 - 1.8GHz)
* BANDWIDTH 0x06 6-7 Set bandwidth. 6MHz = 0x80, 7MHz=0x40
* 8MHz=0x00
* 8MHz=0x00
* XTAL_SPEED 0x07 5 Set to 1 for 28.8MHz Crystal input
* or 0 for 36MHz
* or 0 for 36MHz
* <agc params> 0x08 0-7
* EN_CAL_RSSI 0x09 4 Enable calibrate RSSI
* (Receive Signal Strength Indicator)
* (Receive Signal Strength Indicator)
* LNA_FORCE 0x0d 0
* AGC_FORCE 0x0d ?
* LNA_GAIN 0x13 3-4 Low noise amp gain
* LNA_COMPS 0x15 3 ?
* VCO_CALIB 0x0e 7 Set high then low to calibrate VCO
* (fast lock?)
* (fast lock?)
* VCO_VOLTAGE 0x0e 0-6 Read Control voltage of VCO
* (big value -> low freq)
* (big value -> low freq)
* LNA_GAIN 0x13 3-4 Low noise amp gain
* LNA_COMPS 0x15 3 ?
*/
int fc0012_init(void *dev)
@ -112,8 +166,8 @@ int fc0012_init(void *dev)
0x00, /* reg. 0x0e */
0x00, /* reg. 0x0f */
0x00, /* reg. 0x10: may also be 0x0d */
0x00, /* reg. 0x11 */
0x1f, /* reg. 0x12: Set to maximum gain */
0x0a, /* reg. 0x11 */
0x51, /* reg. 0x12: Set to maximum gain */
0x08, /* reg. 0x13: Set to Middle Gain: 0x08,
Low Gain: 0x00, High Gain: 0x10, enable IX2: 0x80 */
0x00, /* reg. 0x14 */
@ -133,7 +187,7 @@ int fc0012_init(void *dev)
#endif
reg[0x07] |= 0x20;
// if (priv->dual_master)
/* if (priv->dual_master) */
reg[0x0c] |= 0x02;
for (i = 1; i < sizeof(reg); i++) {
@ -278,7 +332,7 @@ int fc0012_set_params(void *dev, uint32_t freq, uint32_t bandwidth)
ret = fc0012_writereg(dev, 0x0e, 0x00);
if (!ret) {
// msleep(10);
/* msleep(10); */
ret = fc0012_readreg(dev, 0x0e, &tmp);
}
if (ret)
@ -340,6 +394,6 @@ int fc0012_set_gain(void *dev, int gain)
}
ret = fc0012_writereg(dev, 0x13, tmp);
/* print_registers(dev); */
return ret;
}

File diff suppressed because it is too large Load Diff

View File

@ -50,6 +50,8 @@ SET( RTLLIBFILES
../src/convenience/convenience.c
../src/convenience/convenience.h
../src/convenience/wavewrite.c
../src/convenience/wavewrite.h
../src/getopt/getopt.c
../src/getopt/getopt.h