2016-08-11 11:37:40 +00:00
/* -*- c++ -*- */
/*
2017-04-19 19:43:06 +00:00
* Copyright 2017 Pieter Robyns , William Thenaers .
2016-08-11 11:37:40 +00:00
*
* This 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 3 , or ( at your option )
* any later version .
*
* This software 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 software ; see the file COPYING . If not , write to
* the Free Software Foundation , Inc . , 51 Franklin Street ,
* Boston , MA 02110 - 1301 , USA .
*/
# ifdef HAVE_CONFIG_H
2017-02-23 20:12:40 +00:00
# include "config.h"
2016-08-11 11:37:40 +00:00
# endif
# include <gnuradio/io_signature.h>
# include <gnuradio/expj.h>
# include <liquid/liquid.h>
2016-09-13 14:43:41 +00:00
# include <numeric>
2017-03-17 15:51:40 +00:00
# include <algorithm>
2016-08-11 11:37:40 +00:00
# include "decoder_impl.h"
# include "tables.h"
# include "utilities.h"
2017-03-17 15:51:40 +00:00
# include "dbugr.hpp"
2016-08-11 11:37:40 +00:00
2017-02-23 20:12:40 +00:00
namespace gr {
namespace lora {
decoder : : sptr decoder : : make ( float samp_rate , int sf ) {
return gnuradio : : get_initial_sptr
( new decoder_impl ( samp_rate , sf ) ) ;
}
/**
* The private constructor
*/
decoder_impl : : decoder_impl ( float samp_rate , uint8_t sf )
: gr : : sync_block ( " decoder " ,
gr : : io_signature : : make ( 1 , - 1 , sizeof ( gr_complex ) ) ,
2017-08-29 18:18:53 +00:00
gr : : io_signature : : make ( 0 , 0 , 0 ) ) {
// Radio config
2017-08-31 13:02:15 +00:00
d_state = gr : : lora : : DecoderState : : DETECT ;
2017-02-23 20:12:40 +00:00
if ( sf < 6 | | sf > 13 ) {
2017-03-17 15:51:40 +00:00
std : : cerr < < " [LoRa Decoder] ERROR : Spreading factor should be between 6 and 12 (inclusive)! " < < std : : endl
< < " Other values are currently not supported. " < < std : : endl ;
2017-02-23 20:12:40 +00:00
exit ( 1 ) ;
2017-03-31 14:48:32 +00:00
}
2017-08-29 18:18:53 +00:00
# ifdef DEBUG
2017-08-31 13:02:15 +00:00
d_debug_samples . open ( " /tmp/grlora_debug " , std : : ios : : out | std : : ios : : binary ) ;
d_debug . open ( " /tmp/grlora_debug_txt " , std : : ios : : out ) ;
2017-08-25 10:38:00 +00:00
d_dbg . attach ( ) ;
# endif
2017-08-31 13:02:15 +00:00
d_bw = 125000u ;
d_cr = 4 ;
d_samples_per_second = samp_rate ;
d_payload_symbols = 0 ;
d_cfo_estimation = 0.0f ;
d_dt = 1.0f / d_samples_per_second ;
d_sf = sf ;
2017-09-06 13:57:44 +00:00
d_bits_per_second = ( double ) d_sf * ( double ) ( 4.0 / ( 4.0 + d_cr ) ) / ( 1u < < d_sf ) * d_bw ;
2017-08-31 13:02:15 +00:00
d_symbols_per_second = ( double ) d_bw / ( 1u < < d_sf ) ;
d_period = 1.0f / ( double ) d_symbols_per_second ;
d_bits_per_symbol = ( uint32_t ) ( d_bits_per_second / d_symbols_per_second ) ;
d_samples_per_symbol = ( uint32_t ) ( d_samples_per_second / d_symbols_per_second ) ;
d_delay_after_sync = d_samples_per_symbol / 4u ;
d_number_of_bins = ( uint32_t ) ( 1u < < d_sf ) ;
d_decim_factor = d_samples_per_symbol / d_number_of_bins ;
d_energy_threshold = 0.01f ;
d_whitening_sequence = gr : : lora : : prng_payload ;
d_fine_sync = 0 ;
set_output_multiple ( 2 * d_samples_per_symbol ) ;
2017-09-06 13:57:44 +00:00
std : : cout < < " Bits (nominal) per symbol: \t " < < d_bits_per_symbol < < std : : endl ;
2017-08-31 13:02:15 +00:00
std : : cout < < " Bins per symbol: \t " < < d_number_of_bins < < std : : endl ;
std : : cout < < " Samples per symbol: \t " < < d_samples_per_symbol < < std : : endl ;
std : : cout < < " Decimation: \t \t " < < d_decim_factor < < std : : endl ;
2017-02-23 20:12:40 +00:00
2017-08-29 18:18:53 +00:00
// Locally generated chirps
2017-08-31 13:02:15 +00:00
build_ideal_chirps ( ) ;
2017-02-23 20:12:40 +00:00
2017-08-29 18:18:53 +00:00
// FFT decoding preparations
2017-08-31 13:02:15 +00:00
d_fft . resize ( d_samples_per_symbol ) ;
d_mult_hf . resize ( d_samples_per_symbol ) ;
d_tmp . resize ( d_number_of_bins ) ;
d_q = fft_create_plan ( d_samples_per_symbol , & d_mult_hf [ 0 ] , & d_fft [ 0 ] , LIQUID_FFT_FORWARD , 0 ) ;
d_qr = fft_create_plan ( d_number_of_bins , & d_tmp [ 0 ] , & d_mult_hf [ 0 ] , LIQUID_FFT_BACKWARD , 0 ) ;
2017-06-02 13:53:43 +00:00
2017-02-23 20:12:40 +00:00
// Register gnuradio ports
2017-08-31 13:02:15 +00:00
message_port_register_out ( pmt : : mp ( " frames " ) ) ;
message_port_register_out ( pmt : : mp ( " control " ) ) ;
2017-02-23 20:12:40 +00:00
}
/**
* Our virtual destructor .
*/
decoder_impl : : ~ decoder_impl ( ) {
2017-08-29 18:18:53 +00:00
# ifdef DEBUG
2017-08-31 13:02:15 +00:00
if ( d_debug_samples . is_open ( ) )
d_debug_samples . close ( ) ;
2017-02-23 20:12:40 +00:00
2017-08-31 13:02:15 +00:00
if ( d_debug . is_open ( ) )
d_debug . close ( ) ;
2017-02-23 20:12:40 +00:00
# endif
2017-08-31 13:02:15 +00:00
fft_destroy_plan ( d_q ) ;
fft_destroy_plan ( d_qr ) ;
2017-02-23 20:12:40 +00:00
}
void decoder_impl : : build_ideal_chirps ( void ) {
2017-08-31 13:02:15 +00:00
d_downchirp . resize ( d_samples_per_symbol ) ;
d_upchirp . resize ( d_samples_per_symbol ) ;
d_downchirp_ifreq . resize ( d_samples_per_symbol ) ;
d_upchirp_ifreq . resize ( d_samples_per_symbol ) ;
d_upchirp_ifreq_v . resize ( d_samples_per_symbol * 3 ) ;
gr_complex tmp [ d_samples_per_symbol * 3 ] ;
const double T = - 0.5 * d_bw * d_symbols_per_second ;
const double f0 = ( d_bw / 2.0 ) ;
2017-05-17 15:33:15 +00:00
const double pre_dir = 2.0 * M_PI ;
2017-02-23 20:12:40 +00:00
double t ;
gr_complex cmx = gr_complex ( 1.0f , 1.0f ) ;
2017-08-31 13:02:15 +00:00
for ( uint32_t i = 0u ; i < d_samples_per_symbol ; i + + ) {
2017-02-23 20:12:40 +00:00
// Width in number of samples = samples_per_symbol
// See https://en.wikipedia.org/wiki/Chirp#Linear
2017-08-31 13:02:15 +00:00
t = d_dt * i ;
d_downchirp [ i ] = cmx * gr_expj ( pre_dir * t * ( f0 + T * t ) ) ;
d_upchirp [ i ] = cmx * gr_expj ( pre_dir * t * ( f0 + T * t ) * - 1.0f ) ;
2017-02-23 20:12:40 +00:00
}
2016-08-11 11:37:40 +00:00
2017-08-29 18:18:53 +00:00
// Store instantaneous frequency
2017-08-31 13:02:15 +00:00
instantaneous_frequency ( & d_downchirp [ 0 ] , & d_downchirp_ifreq [ 0 ] , d_samples_per_symbol ) ;
instantaneous_frequency ( & d_upchirp [ 0 ] , & d_upchirp_ifreq [ 0 ] , d_samples_per_symbol ) ;
2017-03-17 15:51:40 +00:00
2017-08-31 13:02:15 +00:00
samples_to_file ( " /tmp/downchirp " , & d_downchirp [ 0 ] , d_downchirp . size ( ) , sizeof ( gr_complex ) ) ;
samples_to_file ( " /tmp/upchirp " , & d_upchirp [ 0 ] , d_upchirp . size ( ) , sizeof ( gr_complex ) ) ;
2017-08-23 15:20:42 +00:00
2017-08-29 18:18:53 +00:00
// Upchirp sequence
2017-08-31 13:02:15 +00:00
memcpy ( tmp , & d_upchirp [ 0 ] , sizeof ( gr_complex ) * d_samples_per_symbol ) ;
memcpy ( tmp + d_samples_per_symbol , & d_upchirp [ 0 ] , sizeof ( gr_complex ) * d_samples_per_symbol ) ;
memcpy ( tmp + d_samples_per_symbol * 2 , & d_upchirp [ 0 ] , sizeof ( gr_complex ) * d_samples_per_symbol ) ;
instantaneous_frequency ( tmp , & d_upchirp_ifreq_v [ 0 ] , d_samples_per_symbol * 3 ) ;
2016-08-11 11:37:40 +00:00
}
2017-06-02 13:53:43 +00:00
void decoder_impl : : values_to_file ( const std : : string path , const unsigned char * v , const uint32_t length , const uint32_t ppm ) {
std : : ofstream out_file ;
out_file . open ( path . c_str ( ) , std : : ios : : out | std : : ios : : app ) ;
for ( uint32_t i = 0u ; i < length ; i + + ) {
std : : string tmp = gr : : lora : : to_bin ( v [ i ] , ppm ) ;
out_file . write ( tmp . c_str ( ) , tmp . length ( ) ) ;
2017-08-03 12:41:47 +00:00
out_file . write ( " " , 1 ) ;
2017-06-02 13:53:43 +00:00
}
out_file . write ( " \n " , 1 ) ;
out_file . close ( ) ;
}
2017-04-26 11:56:45 +00:00
void decoder_impl : : samples_to_file ( const std : : string path , const gr_complex * v , const uint32_t length , const uint32_t elem_size ) {
2017-08-29 18:18:53 +00:00
# ifdef DEBUG
2017-02-23 20:12:40 +00:00
std : : ofstream out_file ;
out_file . open ( path . c_str ( ) , std : : ios : : out | std : : ios : : binary ) ;
2016-08-11 11:37:40 +00:00
2017-02-23 20:12:40 +00:00
//for(std::vector<gr_complex>::const_iterator it = v.begin(); it != v.end(); ++it) {
2017-03-21 17:03:44 +00:00
for ( uint32_t i = 0u ; i < length ; i + + ) {
2017-02-23 20:12:40 +00:00
out_file . write ( reinterpret_cast < const char * > ( & v [ i ] ) , elem_size ) ;
}
2016-09-14 14:03:15 +00:00
2017-02-23 20:12:40 +00:00
out_file . close ( ) ;
# else
( void ) path ;
( void ) v ;
( void ) length ;
( void ) elem_size ;
# endif
}
2016-08-11 11:37:40 +00:00
2017-04-26 11:56:45 +00:00
void decoder_impl : : samples_debug ( const gr_complex * v , const uint32_t length ) {
2017-08-29 18:18:53 +00:00
# ifdef DEBUG
2017-02-23 20:12:40 +00:00
gr_complex start_indicator ( 0.0f , 32.0f ) ;
2017-08-31 13:02:15 +00:00
d_debug_samples . write ( reinterpret_cast < const char * > ( & start_indicator ) , sizeof ( gr_complex ) ) ;
2016-08-11 11:37:40 +00:00
2017-04-26 11:56:45 +00:00
for ( uint32_t i = 1u ; i < length ; i + + ) {
2017-08-31 13:02:15 +00:00
d_debug_samples . write ( reinterpret_cast < const char * > ( & v [ i ] ) , sizeof ( gr_complex ) ) ;
2017-02-23 20:12:40 +00:00
}
# else
( void ) v ;
( void ) length ;
# endif
2016-08-11 11:37:40 +00:00
}
2017-04-26 11:56:45 +00:00
inline void decoder_impl : : instantaneous_frequency ( const gr_complex * in_samples , float * out_ifreq , const uint32_t window ) {
if ( window < 2u ) {
2017-03-29 11:04:04 +00:00
std : : cerr < < " [LoRa Decoder] WARNING : window size < 2 ! " < < std : : endl ;
2017-02-23 20:12:40 +00:00
return ;
}
2016-09-14 14:03:15 +00:00
2017-03-17 15:51:40 +00:00
/* instantaneous_phase */
2017-04-26 11:56:45 +00:00
for ( uint32_t i = 1u ; i < window ; i + + ) {
2017-03-29 11:04:04 +00:00
const float iphase_1 = std : : arg ( in_samples [ i - 1 ] ) ;
float iphase_2 = std : : arg ( in_samples [ i ] ) ;
2017-03-17 15:51:40 +00:00
// Unwrapped loops from liquid_unwrap_phase
2017-03-21 17:03:44 +00:00
while ( ( iphase_2 - iphase_1 ) > M_PI ) iphase_2 - = 2.0f * M_PI ;
while ( ( iphase_2 - iphase_1 ) < - M_PI ) iphase_2 + = 2.0f * M_PI ;
2017-03-17 15:51:40 +00:00
out_ifreq [ i - 1 ] = iphase_2 - iphase_1 ;
2017-02-23 20:12:40 +00:00
}
2016-09-12 12:23:25 +00:00
2017-02-23 20:12:40 +00:00
// Make sure there is no strong gradient if this value is accessed by mistake
out_ifreq [ window - 1 ] = out_ifreq [ window - 2 ] ;
2016-09-12 12:23:25 +00:00
}
2017-04-26 11:56:45 +00:00
inline void decoder_impl : : instantaneous_phase ( const gr_complex * in_samples , float * out_iphase , const uint32_t window ) {
2017-03-17 15:51:40 +00:00
out_iphase [ 0 ] = std : : arg ( in_samples [ 0 ] ) ;
2017-04-26 11:56:45 +00:00
for ( uint32_t i = 1u ; i < window ; i + + ) {
2017-03-17 15:51:40 +00:00
out_iphase [ i ] = std : : arg ( in_samples [ i ] ) ;
2017-02-23 20:12:40 +00:00
// = the same as atan2(imag(in_samples[i]),real(in_samples[i]));
2016-09-12 12:23:25 +00:00
2017-03-17 15:51:40 +00:00
// Unwrapped loops from liquid_unwrap_phase
2017-03-21 17:03:44 +00:00
while ( ( out_iphase [ i ] - out_iphase [ i - 1 ] ) > M_PI ) out_iphase [ i ] - = 2.0f * M_PI ;
while ( ( out_iphase [ i ] - out_iphase [ i - 1 ] ) < - M_PI ) out_iphase [ i ] + = 2.0f * M_PI ;
2017-03-17 15:51:40 +00:00
}
2017-02-23 20:12:40 +00:00
}
2016-08-11 11:37:40 +00:00
2017-08-23 15:20:42 +00:00
float decoder_impl : : cross_correlate_ifreq_fast ( const float * samples_ifreq , const float * ideal_chirp , const uint32_t window ) {
float result = 0 ;
volk_32f_x2_dot_prod_32f ( & result , samples_ifreq , ideal_chirp , window ) ;
return result ;
}
2017-08-25 10:38:00 +00:00
float decoder_impl : : cross_correlate_fast ( const gr_complex * samples , const gr_complex * ideal_chirp , const uint32_t window ) {
gr_complex result = 0 ;
volk_32fc_x2_conjugate_dot_prod_32fc ( & result , samples , ideal_chirp , window ) ;
return abs ( result ) ;
}
2017-04-26 11:56:45 +00:00
float decoder_impl : : cross_correlate ( const gr_complex * samples_1 , const gr_complex * samples_2 , const uint32_t window ) {
2017-02-23 20:12:40 +00:00
float result = 0.0f ;
2016-08-11 11:37:40 +00:00
2017-03-21 17:03:44 +00:00
for ( uint32_t i = 0u ; i < window ; i + + ) {
2017-03-17 15:51:40 +00:00
result + = std : : real ( samples_1 [ i ] * std : : conj ( samples_2 [ i ] ) ) ;
2017-02-23 20:12:40 +00:00
}
2016-08-11 11:37:40 +00:00
2017-02-23 20:12:40 +00:00
result / = ( float ) window ;
2016-09-13 14:43:41 +00:00
2017-02-23 20:12:40 +00:00
return result ;
2016-08-11 11:37:40 +00:00
}
2016-09-14 14:03:15 +00:00
2017-06-02 13:53:43 +00:00
float decoder_impl : : cross_correlate_ifreq ( const float * samples_ifreq , const std : : vector < float > & ideal_chirp , const uint32_t to_idx ) {
2016-09-14 14:03:15 +00:00
float result = 0.0f ;
2016-09-13 13:21:23 +00:00
2017-06-02 13:53:43 +00:00
const float average = std : : accumulate ( samples_ifreq , samples_ifreq + to_idx , 0.0f ) / ( float ) ( to_idx ) ;
const float chirp_avg = std : : accumulate ( & ideal_chirp [ 0 ] , & ideal_chirp [ to_idx ] , 0.0f ) / ( float ) ( to_idx ) ;
2017-08-31 13:02:15 +00:00
const float sd = stddev ( samples_ifreq , to_idx , average )
* stddev ( & ideal_chirp [ 0 ] , to_idx , chirp_avg ) ;
2016-09-13 14:43:41 +00:00
2017-06-02 13:53:43 +00:00
for ( uint32_t i = 0u ; i < to_idx ; i + + ) {
2017-04-27 16:33:07 +00:00
result + = ( samples_ifreq [ i ] - average ) * ( ideal_chirp [ i ] - chirp_avg ) / sd ;
2017-02-23 20:12:40 +00:00
}
2016-09-14 14:03:15 +00:00
2017-08-23 15:20:42 +00:00
result / = ( float ) ( to_idx ) ;
2016-09-14 14:03:15 +00:00
2017-02-23 20:12:40 +00:00
return result ;
2016-09-13 13:21:23 +00:00
}
2017-08-25 10:38:00 +00:00
void decoder_impl : : fine_sync ( const gr_complex * in_samples , uint32_t bin_idx , int32_t search_space ) {
2017-08-31 13:02:15 +00:00
int32_t shift_ref = ( bin_idx + 1 ) * d_decim_factor ;
2017-08-23 15:20:42 +00:00
float samples_ifreq [ d_samples_per_symbol ] ;
float max_correlation = 0.0f ;
int32_t lag = 0 ;
2017-08-31 13:02:15 +00:00
instantaneous_frequency ( in_samples , samples_ifreq , d_samples_per_symbol ) ;
2017-08-23 15:20:42 +00:00
2017-08-24 10:06:14 +00:00
for ( int32_t i = - search_space + 1 ; i < search_space ; i + + ) {
2017-08-29 18:18:53 +00:00
//float c = cross_correlate_fast(in_samples, &d_upchirp_v[shift_ref+i+d_samples_per_symbol], d_samples_per_symbol);
2017-08-25 10:38:00 +00:00
float c = cross_correlate_ifreq_fast ( samples_ifreq , & d_upchirp_ifreq_v [ shift_ref + i + d_samples_per_symbol ] , d_samples_per_symbol ) ;
2017-08-23 15:20:42 +00:00
if ( c > max_correlation ) {
max_correlation = c ;
lag = i ;
}
}
2017-08-29 18:18:53 +00:00
# ifdef DEBUG
2017-08-29 12:44:47 +00:00
//d_debug << "FINE: " << -lag << std::endl;
2017-08-29 10:57:17 +00:00
# endif
2017-08-23 15:20:42 +00:00
2017-08-31 13:02:15 +00:00
d_fine_sync = - lag ;
2017-08-25 10:38:00 +00:00
//if(abs(d_fine_sync) >= d_decim_factor / 2)
// d_fine_sync = 0;
//d_fine_sync = 0;
2017-08-23 15:20:42 +00:00
}
2017-08-23 15:53:00 +00:00
float decoder_impl : : detect_preamble_autocorr ( const gr_complex * samples , const uint32_t window ) {
const gr_complex * chirp1 = samples ;
const gr_complex * chirp2 = samples + d_samples_per_symbol ;
float magsq_chirp1 [ window ] ;
float magsq_chirp2 [ window ] ;
float energy_chirp1 = 0 ;
float energy_chirp2 = 0 ;
float autocorr = 0 ;
gr_complex dot_product ;
volk_32fc_x2_conjugate_dot_prod_32fc ( & dot_product , chirp1 , chirp2 , window ) ;
volk_32fc_magnitude_squared_32f ( magsq_chirp1 , chirp1 , window ) ;
volk_32fc_magnitude_squared_32f ( magsq_chirp2 , chirp2 , window ) ;
volk_32f_accumulator_s32f ( & energy_chirp1 , magsq_chirp1 , window ) ;
volk_32f_accumulator_s32f ( & energy_chirp2 , magsq_chirp2 , window ) ;
autocorr = abs ( dot_product / gr_complex ( sqrt ( energy_chirp1 * energy_chirp2 ) , 0 ) ) ;
2017-08-29 10:57:17 +00:00
if ( energy_chirp1 < 0.05f )
autocorr = 0 ; // TODO: fixme
2017-08-23 15:53:00 +00:00
return autocorr ;
}
2017-04-26 11:56:45 +00:00
float decoder_impl : : detect_downchirp ( const gr_complex * samples , const uint32_t window ) {
2017-03-29 11:04:04 +00:00
float samples_ifreq [ window ] ;
2017-08-31 13:02:15 +00:00
instantaneous_frequency ( samples , samples_ifreq , window ) ;
2017-06-02 13:53:43 +00:00
2017-08-31 13:02:15 +00:00
return cross_correlate_ifreq ( samples_ifreq , d_downchirp_ifreq , window - 1u ) ;
2017-03-29 11:04:04 +00:00
}
2017-08-29 18:18:53 +00:00
float decoder_impl : : detect_upchirp ( const gr_complex * samples , const uint32_t window , int32_t * index ) {
float samples_ifreq [ window * 2 ] ;
2017-08-31 13:02:15 +00:00
instantaneous_frequency ( samples , samples_ifreq , window * 2 ) ;
2017-08-29 18:18:53 +00:00
2017-08-31 13:02:15 +00:00
return sliding_norm_cross_correlate_upchirp ( samples_ifreq , window , index ) ;
2017-08-29 18:18:53 +00:00
}
float decoder_impl : : sliding_norm_cross_correlate_upchirp ( const float * samples_ifreq , const uint32_t window , int32_t * index ) {
2017-08-23 15:53:00 +00:00
float max_correlation = 0 ;
2017-03-17 15:51:40 +00:00
2017-08-23 15:53:00 +00:00
// Cross correlate
for ( uint32_t i = 0 ; i < window ; i + + ) {
2017-08-31 13:02:15 +00:00
const float max_corr = cross_correlate_ifreq_fast ( samples_ifreq + i , & d_upchirp_ifreq [ 0 ] , window - 1u ) ;
2017-06-02 13:53:43 +00:00
2017-08-23 15:53:00 +00:00
if ( max_corr > max_correlation ) {
* index = i ;
max_correlation = max_corr ;
}
}
2017-04-26 11:56:45 +00:00
2017-08-23 15:53:00 +00:00
return max_correlation ;
}
2017-03-17 15:51:40 +00:00
2017-04-26 11:56:45 +00:00
float decoder_impl : : stddev ( const float * values , const uint32_t len , const float mean ) {
2017-03-31 14:48:32 +00:00
float variance = 0.0f ;
2016-09-09 15:32:15 +00:00
2017-03-21 17:03:44 +00:00
for ( uint32_t i = 0u ; i < len ; i + + ) {
2017-03-31 14:48:32 +00:00
const float temp = values [ i ] - mean ;
2017-02-23 20:12:40 +00:00
variance + = temp * temp ;
}
2016-08-11 11:37:40 +00:00
2017-02-23 20:12:40 +00:00
variance / = ( float ) len ;
return std : : sqrt ( variance ) ;
2016-08-11 11:37:40 +00:00
}
2017-03-29 11:04:04 +00:00
/**
2017-06-02 13:53:43 +00:00
* Currently unstable due to center frequency offset .
2017-03-29 11:04:04 +00:00
*/
2017-05-04 12:33:16 +00:00
uint32_t decoder_impl : : get_shift_fft ( const gr_complex * samples ) {
2017-08-31 13:02:15 +00:00
float fft_mag [ d_number_of_bins ] ;
2017-04-26 11:56:45 +00:00
2017-08-31 13:02:15 +00:00
samples_to_file ( " /tmp/data " , & samples [ 0 ] , d_samples_per_symbol , sizeof ( gr_complex ) ) ;
2016-08-11 11:37:40 +00:00
2017-02-23 20:12:40 +00:00
// Multiply with ideal downchirp
2017-08-31 13:02:15 +00:00
for ( uint32_t i = 0u ; i < d_samples_per_symbol ; i + + ) {
d_mult_hf [ i ] = samples [ i ] * d_downchirp [ i ] ;
2017-02-23 20:12:40 +00:00
}
2016-08-11 11:37:40 +00:00
2017-08-31 13:02:15 +00:00
samples_to_file ( " /tmp/mult " , & d_mult_hf [ 0 ] , d_samples_per_symbol , sizeof ( gr_complex ) ) ;
2016-08-11 11:37:40 +00:00
2017-02-23 20:12:40 +00:00
// Perform FFT
2017-08-31 13:02:15 +00:00
fft_execute ( d_q ) ;
2016-08-11 11:37:40 +00:00
2017-06-02 13:53:43 +00:00
// Decimate. Note: assumes fft size is multiple of decimation factor and number of bins is even
2017-08-29 18:18:53 +00:00
// This decimation should be identical to numpy's approach
2017-08-31 13:02:15 +00:00
const uint32_t N = d_number_of_bins ;
memcpy ( & d_tmp [ 0 ] , & d_fft [ 0 ] , ( N + 1u ) / 2u * sizeof ( gr_complex ) ) ;
memcpy ( & d_tmp [ ( N + 1u ) / 2u ] , & d_fft [ d_samples_per_symbol - ( N / 2u ) ] , N / 2u * sizeof ( gr_complex ) ) ;
d_tmp [ N / 2u ] + = d_fft [ N / 2u ] ;
2017-06-02 13:53:43 +00:00
2017-02-23 20:12:40 +00:00
// Get magnitude
2017-08-31 13:02:15 +00:00
for ( uint32_t i = 0u ; i < d_number_of_bins ; i + + ) {
fft_mag [ i ] = std : : abs ( d_tmp [ i ] ) ;
2016-08-11 11:37:40 +00:00
}
2017-08-31 13:02:15 +00:00
samples_to_file ( " /tmp/fft " , & d_tmp [ 0 ] , d_number_of_bins , sizeof ( gr_complex ) ) ;
2017-06-02 13:53:43 +00:00
2017-08-31 13:02:15 +00:00
fft_execute ( d_qr ) ; // For debugging
samples_to_file ( " /tmp/resampled " , & d_mult_hf [ 0 ] , d_number_of_bins , sizeof ( gr_complex ) ) ;
2017-02-23 20:12:40 +00:00
// Return argmax here
2017-08-31 13:02:15 +00:00
return ( std : : max_element ( fft_mag , fft_mag + d_number_of_bins ) - fft_mag ) ;
2016-08-11 11:37:40 +00:00
}
2017-08-29 18:18:53 +00:00
uint32_t decoder_impl : : max_frequency_gradient_idx ( const gr_complex * samples ) {
2017-08-31 13:02:15 +00:00
float samples_ifreq [ d_samples_per_symbol ] ;
float samples_ifreq_avg [ d_number_of_bins ] ;
2016-08-11 11:37:40 +00:00
2017-08-31 13:02:15 +00:00
samples_to_file ( " /tmp/data " , & samples [ 0 ] , d_samples_per_symbol , sizeof ( gr_complex ) ) ;
2016-08-11 11:37:40 +00:00
2017-08-31 13:02:15 +00:00
instantaneous_frequency ( samples , samples_ifreq , d_samples_per_symbol ) ;
2016-08-11 11:37:40 +00:00
2017-08-25 10:38:00 +00:00
for ( uint32_t i = 0 ; i < d_number_of_bins ; i + + ) {
volk_32f_accumulator_s32f ( & samples_ifreq_avg [ i ] , & samples_ifreq [ i * d_decim_factor ] , d_decim_factor ) ;
samples_ifreq_avg [ i ] / = d_decim_factor ;
}
2017-08-29 10:57:17 +00:00
float max_gradient = 0.1f ;
2017-08-03 13:05:33 +00:00
float gradient = 0.0f ;
uint32_t max_index = 0 ;
2017-08-31 13:02:15 +00:00
for ( uint32_t i = 1u ; i < d_number_of_bins ; i + + ) {
2017-08-25 10:38:00 +00:00
gradient = samples_ifreq_avg [ i - 1 ] - samples_ifreq_avg [ i ] ;
2017-08-03 13:05:33 +00:00
if ( gradient > max_gradient ) {
max_gradient = gradient ;
2017-08-24 10:06:14 +00:00
max_index = i ;
2016-08-11 11:37:40 +00:00
}
}
2017-08-25 10:38:00 +00:00
max_index + = 1 ;
2017-08-31 13:02:15 +00:00
return ( d_number_of_bins - max_index ) % d_number_of_bins ;
2016-08-11 11:37:40 +00:00
}
2017-04-26 11:56:45 +00:00
bool decoder_impl : : demodulate ( const gr_complex * samples , const bool is_header ) {
2017-08-29 18:18:53 +00:00
// DBGR_TIME_MEASUREMENT_TO_FILE("SFxx_method");
2017-05-17 15:33:15 +00:00
2017-08-29 18:18:53 +00:00
// DBGR_START_TIME_MEASUREMENT(false, "only");
2017-05-17 15:33:15 +00:00
2017-08-31 13:02:15 +00:00
uint32_t bin_idx = max_frequency_gradient_idx ( samples ) ;
//uint32_t bin_idx = get_shift_fft(samples);
2017-08-29 10:57:17 +00:00
fine_sync ( samples , bin_idx , std : : max ( d_decim_factor / 4u , 2u ) ) ;
2017-03-29 11:04:04 +00:00
2017-08-29 18:18:53 +00:00
// DBGR_INTERMEDIATE_TIME_MEASUREMENT();
2017-05-17 15:33:15 +00:00
2017-02-23 20:12:40 +00:00
// Header has additional redundancy
2017-08-29 10:57:17 +00:00
if ( is_header | | d_sf > 10 ) {
2017-04-26 11:56:45 +00:00
bin_idx / = 4u ;
2017-02-23 20:12:40 +00:00
}
// Decode (actually gray encode) the bin to get the symbol value
2017-04-26 11:56:45 +00:00
const uint32_t word = bin_idx ^ ( bin_idx > > 1u ) ;
2017-08-29 18:18:53 +00:00
# ifdef DEBUG
2017-08-31 13:02:15 +00:00
d_debug < < gr : : lora : : to_bin ( word , is_header ? d_sf - 2u : d_sf ) < < " " < < bin_idx < < std : : endl ;
2017-02-23 20:12:40 +00:00
# endif
2017-08-31 13:02:15 +00:00
d_words . push_back ( word ) ;
2017-02-23 20:12:40 +00:00
// Look for 4+cr symbols and stop
2017-08-31 13:02:15 +00:00
if ( d_words . size ( ) = = ( 4u + d_cr ) ) {
2017-02-23 20:12:40 +00:00
// Deinterleave
2017-08-31 13:02:15 +00:00
deinterleave ( ( is_header | | d_sf > 10 ) ? d_sf - 2u : d_sf ) ;
2017-02-23 20:12:40 +00:00
return true ; // Signal that a block is ready for decoding
}
return false ; // We need more words in order to decode a block
2016-08-11 11:37:40 +00:00
}
2017-05-17 15:33:15 +00:00
/**
* Correct the interleaving by extracting each column of bits after rotating to the left .
2017-08-29 18:18:53 +00:00
* < br / > ( The words were interleaved diagonally , by rotating we make them straight into columns . )
2017-05-17 15:33:15 +00:00
*/
2017-04-26 11:56:45 +00:00
void decoder_impl : : deinterleave ( const uint32_t ppm ) {
2017-08-31 13:02:15 +00:00
const uint32_t bits_per_word = d_words . size ( ) ;
2017-06-02 13:53:43 +00:00
const uint32_t offset_start = ppm - 1u ;
2017-05-04 12:33:16 +00:00
std : : vector < uint8_t > words_deinterleaved ( ppm , 0u ) ;
2016-08-11 11:37:40 +00:00
2017-03-21 17:03:44 +00:00
if ( bits_per_word > 8u ) {
2017-02-23 20:12:40 +00:00
// Not sure if this can ever occur. It would imply coding rate high than 4/8 e.g. 4/9.
2017-03-29 11:04:04 +00:00
std : : cerr < < " [LoRa Decoder] WARNING : Deinterleaver: More than 8 bits per word. uint8_t will not be sufficient! \n Bytes need to be stored in intermediate array and then packed into words_deinterleaved! " < < std : : endl ;
2017-08-29 18:18:53 +00:00
exit ( 1 ) ;
2017-02-23 20:12:40 +00:00
}
2016-08-11 11:37:40 +00:00
2017-05-04 12:33:16 +00:00
for ( uint32_t i = 0u ; i < bits_per_word ; i + + ) {
2017-08-31 13:02:15 +00:00
const uint32_t word = gr : : lora : : rotl ( d_words [ i ] , i , ppm ) ;
2016-09-29 15:19:21 +00:00
2017-05-04 12:33:16 +00:00
for ( uint32_t j = ( 1u < < offset_start ) , x = offset_start ; j ; j > > = 1u , x - - ) {
words_deinterleaved [ x ] | = ! ! ( word & j ) < < i ;
2016-08-11 11:37:40 +00:00
}
2017-02-23 20:12:40 +00:00
}
2016-08-11 11:37:40 +00:00
2017-08-29 18:18:53 +00:00
# ifdef DEBUG
2017-08-31 13:02:15 +00:00
print_vector ( d_debug , words_deinterleaved , " D " , sizeof ( uint8_t ) * 8u ) ;
//print_interleave_matrix(d_debug, d_words, ppm);
2017-02-23 20:12:40 +00:00
# endif
2016-08-11 11:37:40 +00:00
2017-02-23 20:12:40 +00:00
// Add to demodulated data
2017-08-31 13:02:15 +00:00
d_demodulated . insert ( d_demodulated . end ( ) , words_deinterleaved . begin ( ) , words_deinterleaved . end ( ) ) ;
2016-08-11 11:37:40 +00:00
2017-02-23 20:12:40 +00:00
// Cleanup
2017-08-31 13:02:15 +00:00
d_words . clear ( ) ;
2016-08-11 11:37:40 +00:00
}
2017-05-17 15:33:15 +00:00
void decoder_impl : : decode ( uint8_t * out_data , const bool is_header ) {
2017-08-03 12:41:47 +00:00
static const uint8_t shuffle_pattern [ ] = { 5 , 0 , 1 , 2 , 4 , 3 , 6 , 7 } ;
2016-08-11 11:37:40 +00:00
2017-08-29 18:18:53 +00:00
// For determining shuffle pattern
//if (!is_header)
2017-08-31 13:02:15 +00:00
// values_to_file("/tmp/before_deshuffle", &d_demodulated[0], d_demodulated.size(), 8);
2017-08-25 10:38:00 +00:00
2017-08-31 13:02:15 +00:00
deshuffle ( shuffle_pattern , is_header ) ;
2017-06-02 13:53:43 +00:00
2017-06-08 14:08:17 +00:00
// For determining whitening sequence
2017-08-29 18:18:53 +00:00
//if (!is_header)
2017-08-31 13:02:15 +00:00
// values_to_file("/tmp/after_deshuffle", &d_words_deshuffled[0], d_words_deshuffled.size(), 8);
2017-06-02 13:53:43 +00:00
2017-08-31 13:02:15 +00:00
dewhiten ( is_header ? gr : : lora : : prng_header : d_whitening_sequence ) ;
hamming_decode ( out_data ) ;
2016-08-11 11:37:40 +00:00
2017-02-23 20:12:40 +00:00
// Print result
std : : stringstream result ;
2016-09-29 12:46:03 +00:00
2017-08-31 13:02:15 +00:00
for ( uint32_t i = 0u ; i < d_payload_length ; i + + ) {
2017-02-23 20:12:40 +00:00
result < < " " < < std : : hex < < std : : setw ( 2 ) < < std : : setfill ( ' 0 ' ) < < ( int ) out_data [ i ] ;
}
2016-08-11 11:37:40 +00:00
2017-02-23 20:12:40 +00:00
if ( ! is_header ) {
2017-08-31 13:02:15 +00:00
d_data . insert ( d_data . end ( ) , out_data , out_data + d_payload_length ) ;
2017-02-23 20:12:40 +00:00
std : : cout < < result . str ( ) < < std : : endl ;
2016-08-11 11:37:40 +00:00
2017-08-31 13:02:15 +00:00
pmt : : pmt_t payload_blob = pmt : : make_blob ( & d_data [ 0 ] ,
sizeof ( uint8_t ) * ( d_payload_length + 3u ) ) ;
message_port_pub ( pmt : : mp ( " frames " ) , payload_blob ) ;
2017-02-23 20:12:40 +00:00
} else {
2017-08-31 13:02:15 +00:00
d_data . insert ( d_data . end ( ) , out_data , out_data + 3u ) ;
2017-02-23 20:12:40 +00:00
std : : cout < < result . str ( ) ;
}
2016-08-11 11:37:40 +00:00
}
2017-04-26 11:56:45 +00:00
void decoder_impl : : deshuffle ( const uint8_t * shuffle_pattern , const bool is_header ) {
2017-08-31 13:02:15 +00:00
const uint32_t to_decode = is_header ? 5u : d_demodulated . size ( ) ;
2017-02-23 20:12:40 +00:00
const uint32_t len = sizeof ( shuffle_pattern ) / sizeof ( uint8_t ) ;
2017-06-02 13:53:43 +00:00
uint8_t result ;
2016-09-09 15:32:15 +00:00
2017-03-21 17:03:44 +00:00
for ( uint32_t i = 0u ; i < to_decode ; i + + ) {
2017-06-02 13:53:43 +00:00
result = 0u ;
2016-09-09 15:32:15 +00:00
2017-03-21 17:03:44 +00:00
for ( uint32_t j = 0u ; j < len ; j + + ) {
2017-08-31 13:02:15 +00:00
result | = ! ! ( d_demodulated [ i ] & ( 1u < < shuffle_pattern [ j ] ) ) < < j ;
2017-02-23 20:12:40 +00:00
}
2016-09-09 15:32:15 +00:00
2017-08-31 13:02:15 +00:00
d_words_deshuffled . push_back ( result ) ;
2017-02-23 20:16:27 +00:00
}
2017-08-29 18:18:53 +00:00
# ifdef DEBUG
2017-02-23 20:12:40 +00:00
//print_vector(d_debug, d_words_deshuffled, "S", sizeof(uint8_t)*8);
2017-08-31 13:02:15 +00:00
print_vector_raw ( d_debug , d_words_deshuffled , sizeof ( uint8_t ) * 8u ) ;
d_debug < < std : : endl ;
2017-02-23 20:12:40 +00:00
# endif
// We're done with these words
if ( is_header ) {
2017-08-31 13:02:15 +00:00
d_demodulated . erase ( d_demodulated . begin ( ) , d_demodulated . begin ( ) + 5u ) ;
2017-02-23 20:16:27 +00:00
} else {
2017-08-31 13:02:15 +00:00
d_demodulated . clear ( ) ;
2017-02-23 20:12:40 +00:00
}
2016-09-09 15:32:15 +00:00
}
2017-02-23 20:12:40 +00:00
void decoder_impl : : dewhiten ( const uint8_t * prng ) {
2017-08-31 13:02:15 +00:00
const uint32_t len = d_words_deshuffled . size ( ) ;
2016-09-12 12:23:25 +00:00
2017-04-26 11:56:45 +00:00
for ( uint32_t i = 0u ; i < len ; i + + ) {
2017-08-31 13:02:15 +00:00
uint8_t xor_b = d_words_deshuffled [ i ] ^ prng [ i ] ;
d_words_dewhitened . push_back ( xor_b ) ;
2017-02-23 20:16:27 +00:00
}
2017-08-29 18:18:53 +00:00
# ifdef DEBUG
2017-08-31 13:02:15 +00:00
print_vector ( d_debug , d_words_dewhitened , " W " , sizeof ( uint8_t ) * 8 ) ;
2017-02-23 20:16:27 +00:00
# endif
2016-09-09 15:32:15 +00:00
2017-08-31 13:02:15 +00:00
d_words_deshuffled . clear ( ) ;
2016-09-09 15:32:15 +00:00
}
2017-02-23 20:12:40 +00:00
void decoder_impl : : hamming_decode ( uint8_t * out_data ) {
2017-05-17 15:33:15 +00:00
static const uint8_t data_indices [ 4 ] = { 1 , 2 , 3 , 5 } ;
2017-02-23 20:12:40 +00:00
2017-08-31 13:02:15 +00:00
switch ( d_cr ) {
2017-05-17 15:33:15 +00:00
case 4 : case 3 : // Hamming(8,4) or Hamming(7,4)
2017-08-31 13:02:15 +00:00
gr : : lora : : hamming_decode_soft ( & d_words_dewhitened [ 0 ] , d_words_dewhitened . size ( ) , out_data ) ;
2017-02-23 20:12:40 +00:00
break ;
2017-05-17 15:33:15 +00:00
case 2 : case 1 : // Hamming(6,4) or Hamming(5,4)
// TODO: Report parity error to the user
2017-08-31 13:02:15 +00:00
gr : : lora : : fec_extract_data_only ( & d_words_dewhitened [ 0 ] , d_words_dewhitened . size ( ) , data_indices , 4u , out_data ) ;
2017-02-23 20:12:40 +00:00
break ;
2016-09-09 15:32:15 +00:00
}
2017-08-31 13:02:15 +00:00
d_words_dewhitened . clear ( ) ;
2016-09-09 15:32:15 +00:00
2017-02-23 20:12:40 +00:00
/*
fec_scheme fs = LIQUID_FEC_HAMMING84 ;
2017-08-31 13:02:15 +00:00
unsigned int n = ceil ( d_words_dewhitened . size ( ) * 4.0f / ( 4.0f + d_cr ) ) ;
2016-09-13 13:21:23 +00:00
2017-02-23 20:12:40 +00:00
unsigned int k = fec_get_enc_msg_length ( fs , n ) ;
fec hamming = fec_create ( fs , NULL ) ;
2016-09-16 15:07:28 +00:00
2017-02-23 20:12:40 +00:00
fec_decode ( hamming , n , & d_words_dewhitened [ 0 ] , out_data ) ;
2016-09-13 13:21:23 +00:00
2017-02-23 20:12:40 +00:00
d_words_dewhitened . clear ( ) ;
fec_destroy ( hamming ) ; */
2016-09-13 13:21:23 +00:00
}
2017-04-26 11:56:45 +00:00
void decoder_impl : : nibble_reverse ( uint8_t * out_data , const uint32_t len ) {
2017-03-21 17:03:44 +00:00
for ( uint32_t i = 0u ; i < len ; i + + ) {
2017-04-26 11:56:45 +00:00
out_data [ i ] = ( ( out_data [ i ] & 0x0f ) < < 4u ) | ( ( out_data [ i ] & 0xf0 ) > > 4u ) ;
2016-09-09 15:32:15 +00:00
}
}
2017-03-29 11:04:04 +00:00
/**
2017-08-29 18:18:53 +00:00
* Old method to determine CFO . Currently unused .
2017-03-29 11:04:04 +00:00
*/
2017-02-23 20:12:40 +00:00
void decoder_impl : : determine_cfo ( const gr_complex * samples ) {
2017-08-31 13:02:15 +00:00
float iphase [ d_samples_per_symbol ] ;
const float div = ( float ) d_samples_per_second / ( 2.0f * M_PI ) ;
2016-09-09 15:32:15 +00:00
2017-02-23 20:12:40 +00:00
// Determine instant phase
2017-08-31 13:02:15 +00:00
instantaneous_phase ( samples , iphase , d_samples_per_symbol ) ;
2017-02-23 20:12:40 +00:00
float sum = 0.0f ;
2017-08-31 13:02:15 +00:00
for ( uint32_t i = 1u ; i < d_samples_per_symbol ; i + + ) {
sum + = ( float ) ( ( iphase [ i ] - iphase [ i - 1u ] ) * div ) ;
2016-09-16 15:07:28 +00:00
}
2017-02-23 20:12:40 +00:00
2017-08-31 13:02:15 +00:00
d_cfo_estimation = sum / ( float ) ( d_samples_per_symbol - 1u ) ;
2017-02-23 20:12:40 +00:00
}
2017-08-29 18:18:53 +00:00
/**
* New method to determine CFO .
*/
2017-08-25 12:21:41 +00:00
float decoder_impl : : experimental_determine_cfo ( const gr_complex * samples , uint32_t window ) {
gr_complex mult [ window ] ;
float mult_ifreq [ window ] ;
volk_32fc_x2_multiply_32fc ( mult , samples , & d_downchirp [ 0 ] , window ) ;
instantaneous_frequency ( mult , mult_ifreq , window ) ;
return mult_ifreq [ 256 ] / ( 2.0 * M_PI ) * d_samples_per_second ;
}
2017-04-26 11:56:45 +00:00
uint8_t decoder_impl : : lookup_cr ( const uint8_t bytevalue ) {
2017-02-23 20:16:27 +00:00
switch ( bytevalue & 0x0f ) {
2017-08-03 12:41:47 +00:00
case 0x09 : return 4 ;
case 0x07 : return 3 ;
case 0x05 : return 2 ;
case 0x03 : return 1 ;
2017-02-23 20:16:27 +00:00
default : return 4 ;
}
}
2017-02-23 20:12:40 +00:00
int decoder_impl : : work ( int noutput_items ,
gr_vector_const_void_star & input_items ,
gr_vector_void_star & output_items ) {
( void ) noutput_items ;
( void ) output_items ;
2017-04-26 11:56:45 +00:00
const gr_complex * input = ( gr_complex * ) input_items [ 0 ] ;
2017-08-29 18:18:53 +00:00
//const gr_complex *raw_input = (gr_complex *) input_items[1]; // Input bypassed by low pass filter
2017-02-23 20:12:40 +00:00
2017-08-29 18:18:53 +00:00
d_fine_sync = 0 ; // Always reset fine sync
2017-05-17 15:33:15 +00:00
2017-08-29 18:18:53 +00:00
// DBGR_TIME_MEASUREMENT_TO_FILE("SF7_fft_idx");
2017-08-31 13:02:15 +00:00
// DBGR_START_TIME_MEASUREMENT(false, gr::lora::DecoderStateToString(d_state));
2017-04-27 16:33:07 +00:00
2017-08-31 13:02:15 +00:00
switch ( d_state ) {
2017-02-23 20:12:40 +00:00
case gr : : lora : : DecoderState : : DETECT : {
2017-08-23 15:53:00 +00:00
float correlation = detect_preamble_autocorr ( input , d_samples_per_symbol ) ;
2017-08-29 10:57:17 +00:00
if ( correlation > = 0.90f ) {
2017-08-29 18:18:53 +00:00
# ifdef DEBUG
2017-08-31 13:02:15 +00:00
d_debug < < " Ca: " < < correlation < < std : : endl ;
2017-08-29 10:57:17 +00:00
# endif
2017-08-31 13:02:15 +00:00
d_corr_fails = 0u ;
d_state = gr : : lora : : DecoderState : : SYNC ;
2017-08-23 15:53:00 +00:00
break ;
2016-08-11 11:37:40 +00:00
}
2017-08-23 15:53:00 +00:00
2017-08-31 13:02:15 +00:00
consume_each ( d_samples_per_symbol ) ;
2017-08-23 15:53:00 +00:00
2017-02-23 20:12:40 +00:00
break ;
2016-08-11 11:37:40 +00:00
}
2017-02-23 20:12:40 +00:00
case gr : : lora : : DecoderState : : SYNC : {
2017-08-23 15:53:00 +00:00
int i = 0 ;
2017-08-29 18:18:53 +00:00
detect_upchirp ( input , d_samples_per_symbol , & i ) ;
2017-08-23 15:53:00 +00:00
2017-08-29 10:57:17 +00:00
//float cfo = experimental_determine_cfo(&input[i], d_samples_per_symbol);
//pmt::pmt_t kv = pmt::cons(pmt::intern(std::string("cfo")), pmt::from_double(cfo));
2017-08-31 13:02:15 +00:00
//message_port_pub(pmt::mp("control"), kv);
2017-08-25 12:21:41 +00:00
2017-08-31 13:02:15 +00:00
samples_to_file ( " /tmp/detect " , & input [ i ] , d_samples_per_symbol , sizeof ( gr_complex ) ) ;
2017-08-25 10:38:00 +00:00
2017-08-31 13:02:15 +00:00
consume_each ( i ) ;
d_state = gr : : lora : : DecoderState : : FIND_SFD ;
2017-08-23 15:53:00 +00:00
break ;
}
case gr : : lora : : DecoderState : : FIND_SFD : {
2017-08-31 13:02:15 +00:00
const float c = detect_downchirp ( input , d_samples_per_symbol ) ;
2017-04-27 16:33:07 +00:00
2017-08-29 18:18:53 +00:00
# ifdef DEBUG
2017-08-31 13:02:15 +00:00
d_debug < < " Cd: " < < c < < std : : endl ;
2017-02-23 20:12:40 +00:00
# endif
2017-08-29 10:57:17 +00:00
if ( c > 0.96f ) {
2017-08-29 18:18:53 +00:00
# ifdef DEBUG
2017-08-31 13:02:15 +00:00
d_debug < < " SYNC: " < < c < < std : : endl ;
2017-02-23 20:12:40 +00:00
# endif
// Debug stuff
2017-08-31 13:02:15 +00:00
samples_to_file ( " /tmp/sync " , input , d_samples_per_symbol , sizeof ( gr_complex ) ) ;
2017-03-17 15:51:40 +00:00
2017-08-31 13:02:15 +00:00
d_state = gr : : lora : : DecoderState : : PAUSE ;
2017-02-23 20:12:40 +00:00
} else {
2017-08-29 18:18:53 +00:00
if ( c < - 0.97f ) {
2017-08-29 10:57:17 +00:00
fine_sync ( input , d_number_of_bins - 1 , d_decim_factor * 4 ) ;
2017-08-24 10:06:14 +00:00
} else {
2017-08-31 13:02:15 +00:00
d_corr_fails + + ;
2017-08-24 10:06:14 +00:00
}
2017-02-23 20:12:40 +00:00
2017-08-31 13:02:15 +00:00
if ( d_corr_fails > 4u ) {
d_state = gr : : lora : : DecoderState : : DETECT ;
2017-08-29 18:18:53 +00:00
# ifdef DEBUG
2017-08-31 13:02:15 +00:00
d_debug < < " Lost sync " < < std : : endl ;
2017-02-23 20:12:40 +00:00
# endif
}
2016-08-11 11:37:40 +00:00
}
2017-02-23 20:12:40 +00:00
2017-08-31 13:02:15 +00:00
consume_each ( ( int32_t ) d_samples_per_symbol + d_fine_sync ) ;
2017-02-23 20:12:40 +00:00
break ;
2016-08-11 11:37:40 +00:00
}
2017-02-23 20:12:40 +00:00
case gr : : lora : : DecoderState : : PAUSE : {
2017-08-31 13:02:15 +00:00
d_state = gr : : lora : : DecoderState : : DECODE_HEADER ;
consume_each ( d_samples_per_symbol + d_delay_after_sync ) ;
2017-02-23 20:12:40 +00:00
break ;
}
case gr : : lora : : DecoderState : : DECODE_HEADER : {
2017-08-31 13:02:15 +00:00
d_cr = 4u ;
2017-02-23 20:12:40 +00:00
2017-08-31 13:02:15 +00:00
if ( demodulate ( input , true ) ) {
2017-02-23 20:12:40 +00:00
uint8_t decoded [ 3 ] ;
// TODO: A bit messy. I think it's better to make an internal decoded std::vector
2017-08-31 13:02:15 +00:00
d_payload_length = 3u ;
2016-08-11 11:37:40 +00:00
2017-08-31 13:02:15 +00:00
decode ( decoded , true ) ;
2016-08-11 11:37:40 +00:00
2017-08-31 13:02:15 +00:00
nibble_reverse ( decoded , 1u ) ; // TODO: Why? Endianness?
d_payload_length = decoded [ 0 ] ;
d_cr = lookup_cr ( decoded [ 1 ] ) ;
2016-08-11 11:37:40 +00:00
2017-08-29 18:18:53 +00:00
// Calculate number of payload symbols needed
2017-08-29 10:57:17 +00:00
uint8_t redundancy = ( d_sf > 10 ? 2 : 0 ) ;
2017-08-31 13:02:15 +00:00
const int symbols_per_block = d_cr + 4u ;
const float bits_needed = float ( d_payload_length ) * 8.0f + 16.0f ;
const float symbols_needed = bits_needed * ( symbols_per_block / 4.0f ) / float ( d_sf - redundancy ) ;
2017-03-21 17:03:44 +00:00
const int blocks_needed = ( int ) std : : ceil ( symbols_needed / symbols_per_block ) ;
2017-08-31 13:02:15 +00:00
d_payload_symbols = blocks_needed * symbols_per_block ;
2016-08-11 11:37:40 +00:00
2017-08-29 18:18:53 +00:00
# ifdef DEBUG
2017-08-31 13:02:15 +00:00
d_debug < < " LEN: " < < d_payload_length < < " ( " < < d_payload_symbols < < " symbols) " < < std : : endl ;
2017-02-23 20:12:40 +00:00
# endif
2017-08-31 13:02:15 +00:00
d_state = gr : : lora : : DecoderState : : DECODE_PAYLOAD ;
2017-02-23 20:12:40 +00:00
}
2017-04-26 11:56:45 +00:00
2017-08-31 13:02:15 +00:00
consume_each ( ( int32_t ) d_samples_per_symbol + d_fine_sync ) ;
2017-02-23 20:12:40 +00:00
break ;
2016-08-11 11:37:40 +00:00
}
2017-02-23 20:12:40 +00:00
case gr : : lora : : DecoderState : : DECODE_PAYLOAD : {
2017-03-29 11:04:04 +00:00
//**************************************************************************
// Failsafe if decoding length reaches end of actual data == noise reached?
2017-04-26 11:56:45 +00:00
// Could be replaced be rejecting packets with CRC mismatch...
2017-08-31 13:02:15 +00:00
if ( std : : abs ( input [ 0 ] ) < d_energy_threshold ) {
2017-04-27 16:33:07 +00:00
//printf("\n*** Decode payload reached end of data! (payload length in HDR is wrong)\n");
2017-08-31 13:02:15 +00:00
d_payload_symbols = 0 ;
2017-03-29 11:04:04 +00:00
}
//**************************************************************************
2017-08-31 13:02:15 +00:00
if ( demodulate ( input , false ) ) {
d_payload_symbols - = ( 4u + d_cr ) ;
2017-02-23 20:12:40 +00:00
2017-08-31 13:02:15 +00:00
if ( d_payload_symbols < = 0 ) {
uint8_t decoded [ d_payload_length ] ;
memset ( decoded , 0u , d_payload_length * sizeof ( uint8_t ) ) ;
2016-08-11 11:37:40 +00:00
2017-08-31 13:02:15 +00:00
decode ( decoded , false ) ;
2016-08-11 11:37:40 +00:00
2017-08-31 13:02:15 +00:00
d_state = gr : : lora : : DecoderState : : DETECT ;
d_data . clear ( ) ;
2017-04-27 16:33:07 +00:00
2017-08-29 18:18:53 +00:00
// DBGR_STOP_TIME_MEASUREMENT(true);
// DBGR_PAUSE();
2017-02-23 20:12:40 +00:00
}
2016-08-11 11:37:40 +00:00
}
2017-02-23 20:12:40 +00:00
2017-08-31 13:02:15 +00:00
consume_each ( ( int32_t ) d_samples_per_symbol + d_fine_sync ) ;
2017-04-27 16:33:07 +00:00
2017-02-23 20:12:40 +00:00
break ;
2016-08-11 11:37:40 +00:00
}
2017-02-23 20:12:40 +00:00
case gr : : lora : : DecoderState : : STOP : {
2017-08-31 13:02:15 +00:00
consume_each ( d_samples_per_symbol ) ;
2017-02-23 20:12:40 +00:00
break ;
}
default : {
2017-03-29 11:04:04 +00:00
std : : cerr < < " [LoRa Decoder] WARNING : No state! Shouldn't happen \n " ;
2017-02-23 20:12:40 +00:00
break ;
}
2016-08-11 11:37:40 +00:00
}
2017-08-29 18:18:53 +00:00
// DBGR_INTERMEDIATE_TIME_MEASUREMENT();
2017-04-27 16:33:07 +00:00
2017-02-23 20:12:40 +00:00
// Tell runtime system how many output items we produced.
return 0 ;
}
2016-08-11 11:37:40 +00:00
2017-04-26 11:56:45 +00:00
void decoder_impl : : set_sf ( const uint8_t sf ) {
2017-02-23 20:12:40 +00:00
( void ) sf ;
std : : cerr < < " [LoRa Decoder] WARNING : Setting the spreading factor during execution is currently not supported. " < < std : : endl
2017-08-31 13:02:15 +00:00
< < " Nothing set, kept SF of " < < d_sf < < " . " < < std : : endl ;
2017-02-23 20:12:40 +00:00
}
2016-08-11 11:37:40 +00:00
2017-04-26 11:56:45 +00:00
void decoder_impl : : set_samp_rate ( const float samp_rate ) {
2017-02-23 20:12:40 +00:00
( void ) samp_rate ;
std : : cerr < < " [LoRa Decoder] WARNING : Setting the sample rate during execution is currently not supported. " < < std : : endl
2017-08-31 13:02:15 +00:00
< < " Nothing set, kept SR of " < < d_samples_per_second < < " . " < < std : : endl ;
2017-02-23 20:12:40 +00:00
}
2016-11-24 09:56:59 +00:00
2017-04-26 11:56:45 +00:00
void decoder_impl : : set_abs_threshold ( const float threshold ) {
2017-08-31 13:02:15 +00:00
d_energy_threshold = gr : : lora : : clamp ( threshold , 0.0f , 20.0f ) ;
2017-03-29 11:04:04 +00:00
}
2017-02-23 20:12:40 +00:00
} /* namespace lora */
2016-08-11 11:37:40 +00:00
} /* namespace gr */