kopia lustrzana https://github.com/rpp0/gr-lora
Support for SNR calculation and LoRaTAP headers (Wireshark)
rodzic
2f28b1ba9e
commit
01fde5be3d
|
@ -1,6 +1,6 @@
|
||||||
# Test suite: 'decode_long_hackrf'
|
# Test suite: 'decode_long_hackrf'
|
||||||
|
|
||||||
*Results on 2017-09-20 07:54:45.563359*
|
*Results on 2017-10-06 15:51:09.045468*
|
||||||
|
|
||||||
### 868.1 MHz, SF 7, CR 4/8, BW 125 kHz, prlen 8, crc on, implicit off
|
### 868.1 MHz, SF 7, CR 4/8, BW 125 kHz, prlen 8, crc on, implicit off
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# Test suite: 'decode_long_rtl-sdr'
|
# Test suite: 'decode_long_rtl-sdr'
|
||||||
|
|
||||||
*Results on 2017-09-20 07:53:29.656650*
|
*Results on 2017-10-06 15:49:53.109400*
|
||||||
|
|
||||||
### 868.1 MHz, SF 7, CR 4/8, BW 125 kHz, prlen 8, crc on, implicit off
|
### 868.1 MHz, SF 7, CR 4/8, BW 125 kHz, prlen 8, crc on, implicit off
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# Test suite: 'decode_long_usrp'
|
# Test suite: 'decode_long_usrp'
|
||||||
|
|
||||||
*Results on 2017-09-20 07:54:06.220649*
|
*Results on 2017-10-06 15:50:29.701072*
|
||||||
|
|
||||||
### 868.1 MHz, SF 7, CR 4/8, BW 125 kHz, prlen 8, crc on, implicit off
|
### 868.1 MHz, SF 7, CR 4/8, BW 125 kHz, prlen 8, crc on, implicit off
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# Test suite: 'short_hackrf'
|
# Test suite: 'short_hackrf'
|
||||||
|
|
||||||
*Results on 2017-09-20 08:04:02.415820*
|
*Results on 2017-10-06 16:00:25.768653*
|
||||||
|
|
||||||
### 868.1 MHz, SF 7, CR 4/8, BW 125 kHz, prlen 8, crc on, implicit off
|
### 868.1 MHz, SF 7, CR 4/8, BW 125 kHz, prlen 8, crc on, implicit off
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# Test suite: 'short_rtl-sdr'
|
# Test suite: 'short_rtl-sdr'
|
||||||
|
|
||||||
*Results on 2017-09-20 07:55:22.913194*
|
*Results on 2017-10-06 15:51:46.369561*
|
||||||
|
|
||||||
### 868.1 MHz, SF 7, CR 4/8, BW 125 kHz, prlen 8, crc on, implicit off
|
### 868.1 MHz, SF 7, CR 4/8, BW 125 kHz, prlen 8, crc on, implicit off
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# Test suite: 'short_usrp'
|
# Test suite: 'short_usrp'
|
||||||
|
|
||||||
*Results on 2017-09-20 07:59:26.311889*
|
*Results on 2017-10-06 15:55:49.743840*
|
||||||
|
|
||||||
### 868.1 MHz, SF 7, CR 4/8, BW 125 kHz, prlen 8, crc on, implicit off
|
### 868.1 MHz, SF 7, CR 4/8, BW 125 kHz, prlen 8, crc on, implicit off
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
<key>lora_message_socket_sink</key>
|
<key>lora_message_socket_sink</key>
|
||||||
<category>[LoRa]</category>
|
<category>[LoRa]</category>
|
||||||
<import>import lora</import>
|
<import>import lora</import>
|
||||||
<make>lora.message_socket_sink($ip, $port, $loratap, $loraphy)</make>
|
<make>lora.message_socket_sink($ip, $port, $layer)</make>
|
||||||
|
|
||||||
<param>
|
<param>
|
||||||
<name>IP</name>
|
<name>IP</name>
|
||||||
|
@ -21,17 +21,21 @@
|
||||||
</param>
|
</param>
|
||||||
|
|
||||||
<param>
|
<param>
|
||||||
<name>Append LoRaTap</name>
|
<name>Layer</name>
|
||||||
<key>loratap</key>
|
<key>layer</key>
|
||||||
<value>False</value>
|
<type>enum</type>
|
||||||
<type>bool</type>
|
<option>
|
||||||
</param>
|
<name>LoRa TAP</name>
|
||||||
|
<key>0</key>
|
||||||
<param>
|
</option>
|
||||||
<name>Append LoRaPHY</name>
|
<option>
|
||||||
<key>loraphy</key>
|
<name>LoRa PHY</name>
|
||||||
<value>False</value>
|
<key>1</key>
|
||||||
<type>bool</type>
|
</option>
|
||||||
|
<option>
|
||||||
|
<name>LoRa MAC</name>
|
||||||
|
<key>2</key>
|
||||||
|
</option>
|
||||||
</param>
|
</param>
|
||||||
|
|
||||||
<sink>
|
<sink>
|
||||||
|
|
|
@ -692,6 +692,7 @@ namespace gr {
|
||||||
class LORA_API message_socket_sink : virtual public gr::block {
|
class LORA_API message_socket_sink : virtual public gr::block {
|
||||||
public:
|
public:
|
||||||
typedef boost::shared_ptr<message_socket_sink> sptr;
|
typedef boost::shared_ptr<message_socket_sink> sptr;
|
||||||
|
enum lora_layer { LORATAP = 0, LORAPHY, LORAMAC };
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Return a shared_ptr to a new instance of lora::message_socket_sink.
|
* \brief Return a shared_ptr to a new instance of lora::message_socket_sink.
|
||||||
|
@ -701,7 +702,7 @@ namespace gr {
|
||||||
* class. lora::message_socket_sink::make is the public interface for
|
* class. lora::message_socket_sink::make is the public interface for
|
||||||
* creating new instances.
|
* creating new instances.
|
||||||
*/
|
*/
|
||||||
static sptr make(std::string ip, int port, bool loratap, bool loraphy);
|
static sptr make(std::string ip, int port, enum lora_layer layer);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace lora
|
} // namespace lora
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
|
|
||||||
#define REV_BITS
|
#define REV_BITS
|
||||||
#define MAC_CRC_SIZE 2u
|
#define MAC_CRC_SIZE 2u
|
||||||
|
#define MAX_PWR_QUEUE_SIZE 4
|
||||||
#define SM(value, shift, mask) (((value) << (shift)) & (mask))
|
#define SM(value, shift, mask) (((value) << (shift)) & (mask))
|
||||||
#define MS(value, mask, shift) (((value) & (mask)) >> (shift))
|
#define MS(value, mask, shift) (((value) & (mask)) >> (shift))
|
||||||
|
|
||||||
|
|
|
@ -48,7 +48,8 @@ namespace gr {
|
||||||
decoder_impl::decoder_impl(float samp_rate, uint8_t sf, bool implicit, uint8_t cr, bool crc)
|
decoder_impl::decoder_impl(float samp_rate, uint8_t sf, bool implicit, uint8_t cr, bool crc)
|
||||||
: gr::sync_block("decoder",
|
: gr::sync_block("decoder",
|
||||||
gr::io_signature::make(1, -1, sizeof(gr_complex)),
|
gr::io_signature::make(1, -1, sizeof(gr_complex)),
|
||||||
gr::io_signature::make(0, 0, 0)) {
|
gr::io_signature::make(0, 0, 0)),
|
||||||
|
d_pwr_queue(MAX_PWR_QUEUE_SIZE) {
|
||||||
// Radio config
|
// Radio config
|
||||||
d_state = gr::lora::DecoderState::DETECT;
|
d_state = gr::lora::DecoderState::DETECT;
|
||||||
|
|
||||||
|
@ -330,8 +331,14 @@ namespace gr {
|
||||||
volk_32f_accumulator_s32f(&energy_chirp1, magsq_chirp1, window);
|
volk_32f_accumulator_s32f(&energy_chirp1, magsq_chirp1, window);
|
||||||
volk_32f_accumulator_s32f(&energy_chirp2, magsq_chirp2, window);
|
volk_32f_accumulator_s32f(&energy_chirp2, magsq_chirp2, window);
|
||||||
|
|
||||||
|
// When using implicit mode, stop when energy is halved.
|
||||||
|
d_energy_threshold = energy_chirp2 / 2.0f;
|
||||||
|
|
||||||
|
// For calculating the SNR later on
|
||||||
|
d_pwr_queue.push_back(energy_chirp1 / d_samples_per_symbol);
|
||||||
|
|
||||||
|
// Autocorr value
|
||||||
autocorr = abs(dot_product / gr_complex(sqrt(energy_chirp1 * energy_chirp2), 0));
|
autocorr = abs(dot_product / gr_complex(sqrt(energy_chirp1 * energy_chirp2), 0));
|
||||||
d_energy_threshold = energy_chirp2 / 2.0f; // When using implicit mode, stop when energy is halved.
|
|
||||||
|
|
||||||
return autocorr;
|
return autocorr;
|
||||||
}
|
}
|
||||||
|
@ -345,6 +352,14 @@ namespace gr {
|
||||||
return energy_chirp;
|
return energy_chirp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void decoder_impl::determine_snr() {
|
||||||
|
if(d_pwr_queue.size() >= 2) {
|
||||||
|
float pwr_noise = d_pwr_queue[0];
|
||||||
|
float pwr_signal = d_pwr_queue[d_pwr_queue.size()-1];
|
||||||
|
d_snr = pwr_signal / pwr_noise;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
float decoder_impl::detect_downchirp(const gr_complex *samples, const uint32_t window) {
|
float decoder_impl::detect_downchirp(const gr_complex *samples, const uint32_t window) {
|
||||||
float samples_ifreq[window];
|
float samples_ifreq[window];
|
||||||
instantaneous_frequency(samples, samples_ifreq, window);
|
instantaneous_frequency(samples, samples_ifreq, window);
|
||||||
|
@ -554,6 +569,8 @@ namespace gr {
|
||||||
memset(buffer, 0, sizeof(uint8_t) * len);
|
memset(buffer, 0, sizeof(uint8_t) * len);
|
||||||
memset(&loratap_header, 0, sizeof(loratap_header));
|
memset(&loratap_header, 0, sizeof(loratap_header));
|
||||||
|
|
||||||
|
loratap_header.rssi.snr = (uint8_t)(10.0f * log10(d_snr) + 0.5);
|
||||||
|
|
||||||
offset = gr::lora::build_packet(buffer, offset, &loratap_header, sizeof(loratap_header_t));
|
offset = gr::lora::build_packet(buffer, offset, &loratap_header, sizeof(loratap_header_t));
|
||||||
offset = gr::lora::build_packet(buffer, offset, &d_phdr, sizeof(loraphy_header_t));
|
offset = gr::lora::build_packet(buffer, offset, &d_phdr, sizeof(loraphy_header_t));
|
||||||
offset = gr::lora::build_packet(buffer, offset, &d_decoded[0], d_payload_length);
|
offset = gr::lora::build_packet(buffer, offset, &d_decoded[0], d_payload_length);
|
||||||
|
@ -717,6 +734,7 @@ namespace gr {
|
||||||
float correlation = detect_preamble_autocorr(input, d_samples_per_symbol);
|
float correlation = detect_preamble_autocorr(input, d_samples_per_symbol);
|
||||||
|
|
||||||
if (correlation >= 0.90f) {
|
if (correlation >= 0.90f) {
|
||||||
|
determine_snr();
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
d_debug << "Ca: " << correlation << std::endl;
|
d_debug << "Ca: " << correlation << std::endl;
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
#include <lora/debugger.h>
|
#include <lora/debugger.h>
|
||||||
#include <volk/volk.h>
|
#include <volk/volk.h>
|
||||||
#include <lora/loraphy.h>
|
#include <lora/loraphy.h>
|
||||||
|
#include <boost/circular_buffer.hpp>
|
||||||
|
|
||||||
namespace gr {
|
namespace gr {
|
||||||
namespace lora {
|
namespace lora {
|
||||||
|
@ -99,6 +100,8 @@ namespace gr {
|
||||||
uint32_t d_corr_fails; ///< Indicates how many times the correlation failed. After some tries, the state will revert to `DecoderState::DETECT`.
|
uint32_t d_corr_fails; ///< Indicates how many times the correlation failed. After some tries, the state will revert to `DecoderState::DETECT`.
|
||||||
float d_energy_threshold; ///< The absolute threshold to distinguish signal from noise.
|
float d_energy_threshold; ///< The absolute threshold to distinguish signal from noise.
|
||||||
const uint8_t* d_whitening_sequence; ///< A pointer to the whitening sequence to be used in decoding. Determined by the SF in the ctor.
|
const uint8_t* d_whitening_sequence; ///< A pointer to the whitening sequence to be used in decoding. Determined by the SF in the ctor.
|
||||||
|
float d_snr; ///< Signal to noise ratio
|
||||||
|
boost::circular_buffer<float> d_pwr_queue; ///< Queue holding symbol power values
|
||||||
|
|
||||||
std::vector<uint32_t> d_words; ///< Vector containing the demodulated words.
|
std::vector<uint32_t> d_words; ///< Vector containing the demodulated words.
|
||||||
std::vector<uint8_t> d_demodulated; ///< Vector containing the words after deinterleaving.
|
std::vector<uint8_t> d_demodulated; ///< Vector containing the words after deinterleaving.
|
||||||
|
@ -271,6 +274,11 @@ namespace gr {
|
||||||
*/
|
*/
|
||||||
float determine_energy(const gr_complex *samples);
|
float determine_energy(const gr_complex *samples);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Determine the SNR
|
||||||
|
*/
|
||||||
|
void determine_snr();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Returns the index of the bin containing the frequency change.
|
* \brief Returns the index of the bin containing the frequency change.
|
||||||
*
|
*
|
||||||
|
|
|
@ -31,8 +31,8 @@
|
||||||
namespace gr {
|
namespace gr {
|
||||||
namespace lora {
|
namespace lora {
|
||||||
|
|
||||||
message_socket_sink::sptr message_socket_sink::make(std::string ip, int port, bool loratap, bool loraphy) {
|
message_socket_sink::sptr message_socket_sink::make(std::string ip, int port, enum lora_layer layer) {
|
||||||
return gnuradio::get_initial_sptr(new message_socket_sink_impl(ip, port, loratap, loraphy));
|
return gnuradio::get_initial_sptr(new message_socket_sink_impl(ip, port, layer));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -40,12 +40,11 @@ namespace gr {
|
||||||
*
|
*
|
||||||
* Create a UDP socket connection to send the data through.
|
* Create a UDP socket connection to send the data through.
|
||||||
*/
|
*/
|
||||||
message_socket_sink_impl::message_socket_sink_impl(std::string ip, int port, bool loratap, bool loraphy)
|
message_socket_sink_impl::message_socket_sink_impl(std::string ip, int port, enum lora_layer layer)
|
||||||
: gr::block("message_socket_sink", gr::io_signature::make(0, 0, 0), gr::io_signature::make(0, 0, 0)),
|
: gr::block("message_socket_sink", gr::io_signature::make(0, 0, 0), gr::io_signature::make(0, 0, 0)),
|
||||||
d_ip(ip),
|
d_ip(ip),
|
||||||
d_port(port),
|
d_port(port),
|
||||||
d_loratap(loratap),
|
d_layer(layer) {
|
||||||
d_loraphy(loraphy) {
|
|
||||||
|
|
||||||
message_port_register_in(pmt::mp("in"));
|
message_port_register_in(pmt::mp("in"));
|
||||||
set_msg_handler(pmt::mp("in"), boost::bind(&message_socket_sink_impl::handle, this, _1));
|
set_msg_handler(pmt::mp("in"), boost::bind(&message_socket_sink_impl::handle, this, _1));
|
||||||
|
@ -85,44 +84,38 @@ namespace gr {
|
||||||
*/
|
*/
|
||||||
void message_socket_sink_impl::handle(pmt::pmt_t msg) {
|
void message_socket_sink_impl::handle(pmt::pmt_t msg) {
|
||||||
uint8_t* data = (uint8_t*)pmt::blob_data(msg);
|
uint8_t* data = (uint8_t*)pmt::blob_data(msg);
|
||||||
uint32_t offset = 0;
|
|
||||||
size_t size = pmt::blob_length(msg);
|
size_t size = pmt::blob_length(msg);
|
||||||
loratap_header_t *loratap_header;
|
|
||||||
loraphy_header_t *loraphy_header;
|
|
||||||
uint8_t *payload;
|
|
||||||
|
|
||||||
offset = gr::lora::dissect_packet((const void **)&loratap_header, sizeof(loratap_header_t), data, offset);
|
//offset = gr::lora::dissect_packet((const void **)&loratap_header, sizeof(loratap_header_t), data, offset);
|
||||||
offset = gr::lora::dissect_packet((const void **)&loraphy_header, sizeof(loraphy_header_t), data, offset);
|
msg_send_udp(data, size); // Send message over UDP socket
|
||||||
uint32_t payload_length = size - (sizeof(loratap_header_t) + sizeof(loraphy_header_t));
|
|
||||||
offset = gr::lora::dissect_packet((const void **)&payload, sizeof(uint8_t)*payload_length, data, offset);
|
|
||||||
if(offset != size) {
|
|
||||||
std::cerr << "message_socket_sink_impl::handle: invalid read: " << offset << " != " << size << std::endl;
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(d_loratap == false) {
|
|
||||||
msg_send_udp(loraphy_header, payload, payload_length); // Send message over UDP socket
|
|
||||||
} else {
|
|
||||||
//msg_send_loratap(); // Send message over raw LoRa socket
|
|
||||||
std::cerr << "message_socket_sink_impl::handle: LoRaTap is not supported yet." << std::endl;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void message_socket_sink_impl::msg_send_udp(const loraphy_header_t* loraphy_header, const uint8_t* payload, const uint32_t payload_length) {
|
void message_socket_sink_impl::msg_send_udp(const uint8_t* data, const uint32_t length) {
|
||||||
bool error = false;
|
int32_t msg_len;
|
||||||
|
const uint8_t* msg;
|
||||||
|
|
||||||
if(d_loraphy) {
|
switch(d_layer) {
|
||||||
int32_t msg_len = sizeof(loraphy_header_t) + payload_length;
|
case LORATAP:
|
||||||
if (sendto(d_socket, loraphy_header, msg_len, 0, (const struct sockaddr*)d_sock_addr, sizeof(*d_sock_addr)) != msg_len)
|
msg_len = length;
|
||||||
error = true;
|
msg = data;
|
||||||
} else {
|
break;
|
||||||
int32_t msg_len = payload_length-(MAC_CRC_SIZE * loraphy_header->has_mac_crc); // User did not request PHY header
|
case LORAPHY:
|
||||||
if (sendto(d_socket, payload, msg_len, 0, (const struct sockaddr*)d_sock_addr, sizeof(*d_sock_addr)) != msg_len)
|
msg_len = length - sizeof(loratap_header_t);
|
||||||
error = true;
|
msg = data + sizeof(loratap_header_t);
|
||||||
|
break;
|
||||||
|
case LORAMAC:
|
||||||
|
loraphy_header_t* loraphy_header;
|
||||||
|
gr::lora::dissect_packet((const void **)&loraphy_header, sizeof(loraphy_header_t), data, sizeof(loratap_header_t));
|
||||||
|
msg_len = length - sizeof(loratap_header_t) - sizeof(loraphy_header_t) - (MAC_CRC_SIZE * loraphy_header->has_mac_crc);
|
||||||
|
msg = data + sizeof(loratap_header_t) + sizeof(loraphy_header_t);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
msg_len = length;
|
||||||
|
msg = data;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(error) {
|
if (sendto(d_socket, msg, msg_len, 0, (const struct sockaddr*)d_sock_addr, sizeof(*d_sock_addr)) != msg_len) {
|
||||||
perror("message_socket_sink_impl::handle: mismatch in number of bytes sent");
|
perror("message_socket_sink_impl::handle: mismatch in number of bytes sent");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,8 +33,7 @@ namespace gr {
|
||||||
private:
|
private:
|
||||||
std::string d_ip = "127.0.0.1";
|
std::string d_ip = "127.0.0.1";
|
||||||
int d_port = 40868;
|
int d_port = 40868;
|
||||||
bool d_loratap;
|
enum lora_layer d_layer;
|
||||||
bool d_loraphy;
|
|
||||||
|
|
||||||
// socket
|
// socket
|
||||||
struct sockaddr_in *d_sock_addr;
|
struct sockaddr_in *d_sock_addr;
|
||||||
|
@ -43,11 +42,11 @@ namespace gr {
|
||||||
void handle(pmt::pmt_t msg);
|
void handle(pmt::pmt_t msg);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
message_socket_sink_impl(std::string ip, int port, bool loratap, bool loraphy);
|
message_socket_sink_impl(std::string ip, int port, enum lora_layer layer);
|
||||||
~message_socket_sink_impl();
|
~message_socket_sink_impl();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void msg_send_udp(const loraphy_header_t* loraphy_header, const uint8_t* payload, const uint32_t payload_length);
|
void msg_send_udp(const uint8_t* data, const uint32_t length);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace lora
|
} // namespace lora
|
||||||
|
|
|
@ -253,7 +253,7 @@ class qa_testsuite():
|
||||||
file_source = blocks.file_source(gr.sizeof_gr_complex, data_file, False)
|
file_source = blocks.file_source(gr.sizeof_gr_complex, data_file, False)
|
||||||
lora_receiver = lora.lora_receiver(sample_rate, capture_freq, [868100000], sf, 1000000, False, 4, True)
|
lora_receiver = lora.lora_receiver(sample_rate, capture_freq, [868100000], sf, 1000000, False, 4, True)
|
||||||
throttle = blocks.throttle(gr.sizeof_gr_complex, sample_rate, True)
|
throttle = blocks.throttle(gr.sizeof_gr_complex, sample_rate, True)
|
||||||
message_socket_sink = lora.message_socket_sink("127.0.0.1", 40868, False, False)
|
message_socket_sink = lora.message_socket_sink("127.0.0.1", 40868, 2)
|
||||||
freq_xlating_fir_filter = filter.freq_xlating_fir_filter_ccc(1, (firdes.low_pass(1, sample_rate, 200000, 100000, firdes.WIN_HAMMING, 6.67)), frequency_offset, sample_rate)
|
freq_xlating_fir_filter = filter.freq_xlating_fir_filter_ccc(1, (firdes.low_pass(1, sample_rate, 200000, 100000, firdes.WIN_HAMMING, 6.67)), frequency_offset, sample_rate)
|
||||||
|
|
||||||
# Make connections
|
# Make connections
|
||||||
|
|
Ładowanie…
Reference in New Issue