mirror of https://github.com/drowe67/librtlsdr.git
Merge pull request #68 from hayguen/development
option '-H' to write wave Header for rtl_sdr and rtl_fmdevelopment
commit
91dbae89d7
|
@ -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")
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
@ -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.
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
blacklist dvb_usb_rtl28xxu
|
||||
blacklist dvb_usb_v2
|
||||
blacklist rtl_2830
|
||||
blacklist rtl_2832
|
||||
blacklist r820t
|
||||
blacklist rtl8xxxu
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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(>m);
|
||||
lt = mktime(<m);
|
||||
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
|
||||
|
|
|
@ -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*/
|
||||
|
|
|
@ -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
|
|
@ -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*/
|
|
@ -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
|
||||
|
|
@ -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(>m);
|
||||
lt = mktime(<m);
|
||||
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
|
|
@ -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*/
|
|
@ -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
|
|
@ -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*/
|
1535
src/librtlsdr.c
1535
src/librtlsdr.c
File diff suppressed because it is too large
Load Diff
|
@ -45,6 +45,7 @@
|
|||
|
||||
#include "rtl-sdr.h"
|
||||
#include "convenience/convenience.h"
|
||||
#include "convenience/rtl_convenience.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#define sleep Sleep
|
||||
|
|
|
@ -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
|
223
src/rtl_fm.c
223
src/rtl_fm.c
|
@ -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 */
|
||||
|
|
|
@ -49,6 +49,7 @@
|
|||
|
||||
#include "rtl-sdr.h"
|
||||
#include "convenience/convenience.h"
|
||||
#include "convenience/rtl_convenience.h"
|
||||
|
||||
static volatile int do_exit = 0;
|
||||
|
||||
|
|
|
@ -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))
|
||||
|
||||
|
|
|
@ -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 */
|
124
src/rtl_sdr.c
124
src/rtl_sdr.c
|
@ -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:
|
||||
|
|
167
src/rtl_tcp.c
167
src/rtl_tcp.c
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
136
src/rtl_udp.c
136
src/rtl_udp.c
|
@ -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();
|
||||
|
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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;
|
||||
}
|
||||
|
|
1445
src/tuner_r82xx.c
1445
src/tuner_r82xx.c
File diff suppressed because it is too large
Load Diff
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue