以前用portapack实现过nrf24l01的接收,接下去想试试发射功能。
我在ymfc-mini-drone week6_future_experiment_哔哩哔哩_bilibili里面讲过gr-nordic也可以接收,但是发射流图跑不起来,电脑性能不够。所以我打算分析一下它的代码,把核心部分重新用c++来实现一遍,看看性能能否提升一下。
下面3个文件就是接收和发射的核心。
gr-nordic/enhanced_shockburst_packet.cc at master · BastilleResearch/gr-nordic · GitHub
gr-nordic/nordic_rx_impl.cc at master · BastilleResearch/gr-nordic · GitHub
gr-nordic/nordic_tx_impl.cc at master · BastilleResearch/gr-nordic · GitHub
接下来,我打算自己用c++写编码程序,发给之前已经写好的解码程序。
nrf24-encoder.cpp
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <iostream>
#include <time.h>
#include <sys/time.h>
using namespace std;
int16_t result_demod[210];
int result_demod_len;
FILE *file;
int main(int argc, char **argv)
{
file = stdout;
//preamble 10101010
result_demod[0] = 1;
result_demod[1] = 0;
result_demod[2] = 1;
result_demod[3] = 0;
result_demod[4] = 1;
result_demod[5] = 0;
result_demod[6] = 1;
result_demod[7] = 0;
//address 11100111
for (int i = 0; i < 5; i++)
{
result_demod[8 + i*8] = 1;
result_demod[9 + i*8] = 1;
result_demod[10 + i*8] = 1;
result_demod[11 + i*8] = 0;
result_demod[12 + i*8] = 0;
result_demod[13 + i*8] = 1;
result_demod[14 + i*8] = 1;
result_demod[15 + i*8] = 1;
}
//pcf 000101000
result_demod[48] = 0;
result_demod[49] = 0;
result_demod[50] = 0;
result_demod[51] = 1;
result_demod[52] = 0;
result_demod[53] = 1;
result_demod[54] = 0;
result_demod[55] = 0;
result_demod[56] = 0;
//payload 00000000 00000001 00000010 00000011 00000100
result_demod[57] = 0;
result_demod[58] = 0;
result_demod[59] = 0;
result_demod[60] = 0;
result_demod[61] = 0;
result_demod[62] = 0;
result_demod[63] = 0;
result_demod[64] = 0;
result_demod[65] = 0;
result_demod[66] = 0;
result_demod[67] = 0;
result_demod[68] = 0;
result_demod[69] = 0;
result_demod[70] = 0;
result_demod[71] = 0;
result_demod[72] = 1;
result_demod[73] = 0;
result_demod[74] = 0;
result_demod[75] = 0;
result_demod[76] = 0;
result_demod[77] = 0;
result_demod[78] = 0;
result_demod[79] = 1;
result_demod[80] = 0;
result_demod[81] = 0;
result_demod[82] = 0;
result_demod[83] = 0;
result_demod[84] = 0;
result_demod[85] = 0;
result_demod[86] = 0;
result_demod[87] = 1;
result_demod[88] = 1;
result_demod[89] = 0;
result_demod[90] = 0;
result_demod[91] = 0;
result_demod[92] = 0;
result_demod[93] = 0;
result_demod[94] = 1;
result_demod[95] = 0;
result_demod[96] = 0;
//CRC 11100110 11100001
result_demod[97] = 1;
result_demod[98] = 1;
result_demod[99] = 1;
result_demod[100] = 0;
result_demod[101] = 0;
result_demod[102] = 1;
result_demod[103] = 1;
result_demod[104] = 0;
result_demod[105] = 1;
result_demod[106] = 1;
result_demod[107] = 1;
result_demod[108] = 0;
result_demod[109] = 0;
result_demod[110] = 0;
result_demod[111] = 0;
result_demod[112] = 1;
result_demod[113] = 0;
result_demod[114] = 0;
result_demod[115] = 0;
result_demod[116] = 0;
result_demod[117] = 0;
result_demod[118] = 0;
result_demod[119] = 0;
result_demod[120] = 0;
result_demod[121] = 0;
result_demod[122] = 0;
result_demod[123] = 0;
result_demod[124] = 0;
result_demod[125] = 0;
result_demod[126] = 0;
result_demod[127] = 0;
result_demod[128] = 0;
result_demod[129] = 0;
result_demod[130] = 0;
result_demod[131] = 0;
result_demod[132] = 0;
result_demod[133] = 0;
result_demod[134] = 0;
result_demod[135] = 0;
result_demod[136] = 0;
result_demod[137] = 0;
result_demod[138] = 0;
result_demod[139] = 0;
result_demod[140] = 0;
result_demod[141] = 0;
result_demod[142] = 0;
result_demod[143] = 0;
result_demod[144] = 0;
result_demod[145] = 0;
result_demod[146] = 0;
result_demod[147] = 0;
result_demod[148] = 0;
result_demod[149] = 0;
result_demod_len = 150;
fwrite(result_demod, 2, result_demod_len, file);
fwrite(result_demod, 2, result_demod_len, file);
fwrite(result_demod, 2, result_demod_len, file);
fwrite(result_demod, 2, result_demod_len, file);
fwrite(result_demod, 2, result_demod_len, file);
fwrite(result_demod, 2, result_demod_len, file);
fwrite(result_demod, 2, result_demod_len, file);
fwrite(result_demod, 2, result_demod_len, file);
fwrite(result_demod, 2, result_demod_len, file);
fwrite(result_demod, 2, result_demod_len, file);
return 0;
}
下面是经过少许修改的解码程序,必须这么改,才能获得有效的结果,一个是改了Q(9)为Q(8),是原来代码确实有的bug。但是另一个地方,preamble检测到后多了一组10,必须向后跳过2个bit才能解出正确的包,我有点没完全搞懂。
nrf24-decoder.cpp
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <time.h>
#include <sys/time.h>
#include <math.h>
#include <stdbool.h>
#include <inttypes.h>
#include <stdlib.h> // For exit function
#include <unistd.h> /* for getopt */
/* Global variables */
int32_t g_threshold; // Quantization threshold
int g_srate; // sample rate downconvert ratio
/* Ring Buffer */
#define RB_SIZE 1000
int rb_head=-1;
int16_t *rb_buf;
/* Init Ring Buffer */
void RB_init(void){
rb_buf = (int16_t *)malloc(RB_SIZE*2);
}
/* increment Ring Buffer Head */
void RB_inc(void){
rb_head++;
rb_head=(rb_head)%RB_SIZE;
}
/* Access Ring Buffer location l */
#define RB(l) rb_buf[(rb_head+(l))%RB_SIZE]
/* end Ring Buffer */
/* helper functions */
/* Quantize sample at location l by checking whether it's over the threshold */
/* Important - takes into account the sample rate downconversion ratio */
inline bool Quantize(int16_t l){
return RB(l*g_srate) > g_threshold;
}
#define Q(l) Quantize(l)
/* Calcualte CRC16-CCITT for the NRF packets.
* using custom start value to compensate for non byte aligned message (due to 9 bit PCF)
*/
uint32_t NRFCrc(const uint8_t* data, size_t data_len)
{
uint8_t i;
bool bit;
uint8_t c;
uint_fast16_t crc=0x3C18;
while (data_len--) {
c = *data++;
for (i = 0x80; i > 0; i >>= 1) {
bit = crc & 0x8000;
if (c & i) {
bit = !bit;
}
crc <<= 1;
if (bit) {
crc ^= 0x1021;
}
}
crc &= 0xffff;
}
return (uint16_t)(crc & 0xffff);
}
/* Extract quantization threshold from preamble sequence */
int32_t ExtractThreshold(void){
int32_t threshold=0;
int c;
for (c=0;c<8*g_srate;c++){
threshold+=(int32_t)RB(c);
}
return (int32_t)threshold/(8*g_srate);
}
/* Identify preamble sequence */
bool DetectPreamble(void){
int transitions=0;
int c;
int value = false;
/* preamble sequence is based on the 9th symbol (either 0x55 or 0xAA) */
if (Q(8)){//orignally Q(9)
for (c=0;c<8;c++){
transitions += Q(c)>Q(c+1);
}
} else {
for (c=0;c<8;c++){
transitions += Q(c)<Q(c+1);
}
}
if (transitions == 4)
{
printf("\npreamble:");
for (int i=0; i < 150; i++)
{
printf("%d", Q(i));
}
printf("\n");
value = true;
}
return value;
}
/* Extract byte from ring buffer starting location l */
uint8_t inline ExtractByte(int l){
uint8_t byte=0;
int c;
for (c=0;c<8;c++) byte |= Q(l+c)<<(7-c);
return byte;
}
/* Extract count bytes from ring buffer starting location l into buffer*/
void inline ExtractBytes(int l, uint8_t* buffer, int count){
int t;
for (t=0;t<count;t++){
buffer[t]=ExtractByte(l+t*8);
}
}
/* Prepare packed bit stream for CRC calculation */
void PackPacket(uint64_t packet_addr_l, uint16_t pcf, uint8_t* packet_data, int packet_length, uint8_t* packet_packed){
int c;
uint64_t packet_header=packet_addr_l;
packet_header<<=9;
packet_header|=pcf;
for (c=0;c<7;c++){
packet_packed[c]=(packet_header>>((6-c)*8))&0xFF;
}
for (c=0;c<packet_length;c++){
packet_packed[c+7]=packet_data[c];
}
}
bool DecodeNRFPacket(int32_t sample, int srate, int packet_length){
int c,t;
struct timeval tv;
uint8_t tmp_buf[10];
uint8_t packet_data[500];
uint8_t packet_packed[50];
uint16_t pcf;
uint32_t packet_crc;
uint32_t calced_crc;
uint64_t packet_addr_l;
g_srate=srate;
/* extract address */
packet_addr_l=0;
ExtractBytes(1*8, tmp_buf, 5);
for (t=0;t<5;t++) packet_addr_l|=((uint64_t)tmp_buf[t])<<(4-t)*8;
/* extract pcf */
ExtractBytes(6*8, tmp_buf, 2);
pcf = tmp_buf[0]<<8 | tmp_buf[1];
pcf >>=7;
/* extract packet length, avoid excessive length packets */
if(packet_length == 0)
packet_length=(int)pcf>>3;
/* extract data */
ExtractBytes(6*8+9, packet_data, packet_length);
/* Prepare packed bit stream for CRC calculation */
PackPacket(packet_addr_l, pcf, packet_data, packet_length, packet_packed);
/* calculate packet crc */
calced_crc=NRFCrc(packet_packed, 7+packet_length);
/* extract crc */
ExtractBytes((6+packet_length)*8+9, tmp_buf, 2);
packet_crc = tmp_buf[0]<<8 | tmp_buf[1];
/* NRF24L01+ packet found, dump information */
if (packet_crc==calced_crc){
gettimeofday(&tv, NULL);
printf("%ld.%06ld ", (long)tv.tv_sec, tv.tv_usec);
printf("NRF24 Packet start sample %"PRId32", Threshold:%"PRId32", Address: 0x%08"PRIX64" ",sample,g_threshold,packet_addr_l);
printf("length:%d, pid:%d, no_ack:%d, CRC:0x%04X data:",packet_length,(pcf&0b110)>>1,pcf&0b1,packet_crc);
for (c=0;c<packet_length;c++) printf("%02X ",packet_data[c]);
printf("\n");
return true;
} else return false;
}
bool DecodePacket(int decode_type, int32_t sample, int srate, int packet_length){
bool packet_detected=false;
g_srate=srate;
g_threshold = ExtractThreshold();
if (DetectPreamble()){
RB_inc(); //need to be removed, it's caused by 10101010 10
RB_inc();
packet_detected = DecodeNRFPacket(sample, srate, packet_length);
}
return packet_detected;
}
int main (int argc, char**argv){
int16_t cursamp;
int32_t samples=0;
int skipSamples;
int opt;
/* 1 for nrf, 2 for btle */
int decode_type=1;
int srate=1;
int packet_len = 0;
RB_init();
g_threshold = 0;
skipSamples=1000;
time_t start_time = time(NULL);
while(!feof(stdin) ) {
cursamp = (int16_t) ( fgetc(stdin) | fgetc(stdin)<<8);
RB_inc();
RB(0)=(int)cursamp;
if (--skipSamples<1)
{
if (DecodePacket(decode_type, ++samples, srate, packet_len))
{
skipSamples=20;
}
else
{
}
}
}
printf("%"PRId32" samples received in %d seconds \n",samples,(int)(time(NULL)-start_time));
return 0;
}
这是运行方法和结果:
./nrf24-encoder | ./nrf24-decoder
preamble:101010101011100111111001111110011111100111111001110001010000000000000000001000000100000001100000100111001101110000100000000000000000000000000000000000
1613012483.013818 NRF24 Packet start sample 150, Threshold:0, Address: 0xE7E7E7E7E7 length:5, pid:0, no_ack:0, CRC:0xE6E1 data:00 01 02 03 04
preamble:101010101110011111100111111001111110011111100111000101000000000000000000100000010000000110000010011100110111000010000000000000000000000000000000000000
preamble:101010101011100111111001111110011111100111111001110001010000000000000000001000000100000001100000100111001101110000100000000000000000000000000000000000
1613012483.013995 NRF24 Packet start sample 427, Threshold:0, Address: 0xE7E7E7E7E7 length:5, pid:0, no_ack:0, CRC:0xE6E1 data:00 01 02 03 04
464 samples received in 0 seconds
可以看到preamble:后面10101010 10,一共有10bit,照道理应该只有8个bit,我跳过了2位后才能解出正确的数据 。
接下来我想用gnuradio把编码与调制和hackrf对接起来。
我先尝试了下面file_source直接接file_sink。
然后编码程序从stdout改为保存到文件。发现结果还行,虽然没解码成功,但是肉眼看了preamble以及后续bit,看着都差不多是对的。
然后我试了流图上方被隐藏的部分,也就是加入了调制解调的部分,就完全不对了。我接下去不打算在gnuradio里实现调制了。打算直接在portapack里做。
因为nrf24l01的解调和sstv一样,我都用hackrf_fm实现过,那么我判断它们可以用相同的代码来实现调制,而sstv的调制在portapack里有现成代码,我可以以此为基础实现nrf24l01的调制。
下面是我写的portapack程序,它可以实现1和0的交替发射,我参考了sstv发射:
proc_nrftx.cpp
void NRFTXProcessor::execute(const buffer_c8_t& buffer) {
if (!configured) return;
for (size_t i = 0; i < buffer.count; i++) {
if (!sample_count)
{
sample_count = (uint32_t)(80);
if (tone_sample == 127)
{
tone_sample = -127;
}
else
{
tone_sample = 127;
}
}
else
{
sample_count--;
}
// FM
delta = tone_sample * fm_delta * 4;
phase += delta;
sphase = phase + (64 << 24);
re = (sine_table_i8[(sphase & 0xFF000000U) >> 24]);
im = (sine_table_i8[(phase & 0xFF000000U) >> 24]);
buffer.p[i] = {re, im};
}
}
ui_nrf_tx.cpp
void NRFTXView::start_tx() {
scanline_counter = 0;
//prepare_scanline();
//transmitter_model.set_sampling_rate(3072000U);
transmitter_model.set_sampling_rate(8000000U);
transmitter_model.set_rf_amp(true);
//transmitter_model.set_baseband_bandwidth(1750000);
transmitter_model.set_baseband_bandwidth(2000000);
transmitter_model.enable();
baseband::set_sstv_data(
tx_sstv_mode->vis_code,
tx_sstv_mode->samples_per_pixel
);
options_bitmaps.set_focusable(false);
tx_view.focus();
}
hackrf_decode_costerp.cpp
#include <signal.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <math.h>
#include <pthread.h>
#include <libhackrf/hackrf.h>
#include <iostream>
#include <stdint.h>
#include <time.h>
#include <sys/time.h>
#include <math.h>
#include <stdbool.h>
#include <inttypes.h>
#define MAXIMUM_BUF_LENGTH (16 * 16384)
/* Global variables */
int32_t g_threshold; // Quantization threshold
int g_srate; // sample rate downconvert ratio
int skipSamples;
int32_t samples=0;
/* Ring Buffer */
#define RB_SIZE 1000
int rb_head=-1;
int16_t *rb_buf;
using namespace std;
static volatile bool do_exit = false;
hackrf_device *device;
uint32_t freq;
uint32_t hardware_sample_rate;
uint16_t buf16[MAXIMUM_BUF_LENGTH];
int16_t lowpassed[MAXIMUM_BUF_LENGTH];
int lp_len;
int rate_in;
int rate_out;
int rate_out2;
int16_t result_demod[MAXIMUM_BUF_LENGTH];
int result_demod_len;
int now_r, now_j;
int pre_r, pre_j;
int prev_index;
int now_lpr;
int prev_lpr_index;
FILE *file;
int downsample;
/* Init Ring Buffer */
void RB_init(void){
rb_buf = (int16_t *)malloc(RB_SIZE*2);
}
/* increment Ring Buffer Head */
void RB_inc(void){
rb_head++;
rb_head=(rb_head)%RB_SIZE;
}
/* Access Ring Buffer location l */
#define RB(l) rb_buf[(rb_head+(l))%RB_SIZE]
/* end Ring Buffer */
/* helper functions */
/* Quantize sample at location l by checking whether it's over the threshold */
/* Important - takes into account the sample rate downconversion ratio */
inline bool Quantize(int16_t l){
return RB(l*g_srate) > g_threshold;
}
#define Q(l) Quantize(l)
/* Calcualte CRC16-CCITT for the NRF packets.
* using custom start value to compensate for non byte aligned message (due to 9 bit PCF)
*/
uint32_t NRFCrc(const uint8_t* data, size_t data_len)
{
uint8_t i;
bool bit;
uint8_t c;
uint_fast16_t crc=0x3C18;
while (data_len--) {
c = *data++;
for (i = 0x80; i > 0; i >>= 1) {
bit = crc & 0x8000;
if (c & i) {
bit = !bit;
}
crc <<= 1;
if (bit) {
crc ^= 0x1021;
}
}
crc &= 0xffff;
}
return (uint16_t)(crc & 0xffff);
}
/* Extract quantization threshold from preamble sequence */
int32_t ExtractThreshold(void){
int32_t threshold=0;
int c;
for (c=0;c<8*g_srate;c++){
threshold+=(int32_t)RB(c);
}
return (int32_t)threshold/(8*g_srate);
}
/* Identify preamble sequence */
bool DetectPreamble(void){
int transitions=0;
int c;
int value = false;
/* preamble sequence is based on the 9th symbol (either 0x55 or 0xAA) */
if (Q(8)){//orignally Q(9)
for (c=0;c<8;c++){
transitions += Q(c)>Q(c+1);
}
} else {
for (c=0;c<8;c++){
transitions += Q(c)<Q(c+1);
}
}
if (Q(0) > 0)
{
printf("1");
}
else
{
printf("0");
}
if (transitions == 4)
{
value = true;
}
return value && abs(g_threshold)<15500;
}
/* Extract byte from ring buffer starting location l */
uint8_t inline ExtractByte(int l){
uint8_t byte=0;
int c;
for (c=0;c<8;c++) byte |= Q(l+c)<<(7-c);
return byte;
}
/* Extract count bytes from ring buffer starting location l into buffer*/
void inline ExtractBytes(int l, uint8_t* buffer, int count){
int t;
for (t=0;t<count;t++){
buffer[t]=ExtractByte(l+t*8);
}
}
/* Prepare packed bit stream for CRC calculation */
void PackPacket(uint64_t packet_addr_l, uint16_t pcf, uint8_t* packet_data, int packet_length, uint8_t* packet_packed){
int c;
uint64_t packet_header=packet_addr_l;
packet_header<<=9;
packet_header|=pcf;
for (c=0;c<7;c++){
packet_packed[c]=(packet_header>>((6-c)*8))&0xFF;
}
for (c=0;c<packet_length;c++){
packet_packed[c+7]=packet_data[c];
}
}
bool DecodeNRFPacket(int32_t sample, int srate, int packet_length){
int c,t;
struct timeval tv;
uint8_t tmp_buf[10];
uint8_t packet_data[500];
uint8_t packet_packed[50];
uint16_t pcf;
uint32_t packet_crc;
uint32_t calced_crc;
uint64_t packet_addr_l;
g_srate=srate;
/* extract address */
packet_addr_l=0;
ExtractBytes(1*8, tmp_buf, 5);
for (t=0;t<5;t++) packet_addr_l|=((uint64_t)tmp_buf[t])<<(4-t)*8;
/* extract pcf */
ExtractBytes(6*8, tmp_buf, 2);
pcf = tmp_buf[0]<<8 | tmp_buf[1];
pcf >>=7;
/* extract packet length, avoid excessive length packets */
if(packet_length == 0)
packet_length=(int)pcf>>3;
if (packet_length>32) return false;
/* extract data */
ExtractBytes(6*8+9, packet_data, packet_length);
/* Prepare packed bit stream for CRC calculation */
PackPacket(packet_addr_l, pcf, packet_data, packet_length, packet_packed);
/* calculate packet crc */
calced_crc=NRFCrc(packet_packed, 7+packet_length);
/* extract crc */
ExtractBytes((6+packet_length)*8+9, tmp_buf, 2);
packet_crc = tmp_buf[0]<<8 | tmp_buf[1];
if ( (((packet_addr_l>>8) & 0xFF) == 231) && ((packet_addr_l & 0xFF) == 231) )
{
gettimeofday(&tv, NULL);
printf("%ld.%06ld ", (long)tv.tv_sec, tv.tv_usec);
printf("NRF24 Packet start sample %"PRId32", Threshold:%"PRId32", Address: 0x%08"PRIX64" ",sample,g_threshold,packet_addr_l);
printf("length:%d, pid:%d, no_ack:%d, CRC:0x%04X data:",packet_length,(pcf&0b110)>>1,pcf&0b1,packet_crc);
for (c=0;c<packet_length;c++) printf("%02X ",packet_data[c]);
printf("\n");
}
/* NRF24L01+ packet found, dump information */
if (packet_crc==calced_crc){
gettimeofday(&tv, NULL);
printf("%ld.%06ld ", (long)tv.tv_sec, tv.tv_usec);
printf("NRF24 Packet start sample %"PRId32", Threshold:%"PRId32", Address: 0x%08"PRIX64" ",sample,g_threshold,packet_addr_l);
printf("length:%d, pid:%d, no_ack:%d, CRC:0x%04X data:",packet_length,(pcf&0b110)>>1,pcf&0b1,packet_crc);
for (c=0;c<packet_length;c++) printf("%02X ",packet_data[c]);
printf("\n");
return true;
} else return false;
}
bool DecodePacket(int decode_type, int32_t sample, int srate, int packet_length){
bool packet_detected=false;
g_srate=srate;
g_threshold = ExtractThreshold();
//g_threshold = 0;
if (DetectPreamble()){
RB_inc();
RB_inc();
packet_detected = DecodeNRFPacket(sample, srate, packet_length);
}
return packet_detected;
}
void sigint_callback_handler(int signum)
{
cout << "Caught signal" << endl;
do_exit = true;
}
void multiply(int ar, int aj, int br, int bj, int *cr, int *cj)
{
*cr = ar*br - aj*bj;
*cj = aj*br + ar*bj;
}
int polar_discriminant(int ar, int aj, int br, int bj)
{
int cr, cj;
double angle;
multiply(ar, aj, br, -bj, &cr, &cj);
angle = atan2((double)cj, (double)cr);
return (int)(angle / 3.14159 * (1<<14));
}
int rx_callback(hackrf_transfer* transfer)
{
for (int i = 0; i < transfer->valid_length; i++)
{
double sample = (int8_t)(transfer->buffer[i]) + 1;
buf16[i] = (int16_t)sample; //s->buf16[i] = (int16_t)buf[i] - 127; s->buf16[i] -127~128 uint16_t, unsigned for negative?
}
memcpy(lowpassed, buf16, 2*transfer->valid_length);
lp_len = transfer->valid_length;
//low pass //rate = hardware_sample_rate = 4*250K
int i=0, i2=0;
while (i < lp_len)
{
now_r += lowpassed[i];
now_j += lowpassed[i+1];
i += 2;
prev_index++;
if (prev_index < downsample)
{
continue;
}
lowpassed[i2] = now_r;
lowpassed[i2+1] = now_j;
prev_index = 0;
now_r = 0;
now_j = 0;
i2 += 2;
}
lp_len = i2;
//fm demod //rate = rate_in = 250K
int i3, pcm;
pcm = polar_discriminant(lowpassed[0], lowpassed[1], pre_r, pre_j);
result_demod[0] = (int16_t)pcm;
for (i3 = 2; i3 < (lp_len-1); i3 += 2)
{
pcm = polar_discriminant(lowpassed[i3], lowpassed[i3+1], lowpassed[i3-2], lowpassed[i3-1]);
result_demod[i3/2] = (int16_t)pcm;
}
pre_r = lowpassed[lp_len - 2];
pre_j = lowpassed[lp_len - 1];
result_demod_len = lp_len/2;
// low pass real //rate = rate_out = 250K
//fwrite(result_demod, 2, result_demod_len, file);
//printf("%d\n",result_demod[0]);
for (int s = 0; s < result_demod_len; s++)
{
int16_t cursamp = (int16_t) (result_demod[s]);
/*if (cursamp > 0)
{
printf("1");
}
else
{
printf("0");
}*/
RB_inc();
rb_buf[(rb_head + 0)%RB_SIZE] = (int)cursamp;
if (--skipSamples<1)
{
if (DecodePacket(1, ++samples, 1, 0))
{
skipSamples=20;
}
}
}
return 0;
}
int main(int argc, char **argv)
{
signal(SIGINT, &sigint_callback_handler);
int result;
RB_init();
g_threshold = 0;
skipSamples = 1000;
freq = 2480e6;
rate_in = 1000000;
//rate_in = 250000;
rate_out = 1000000;
//rate_out = 250000;
//file = stdout;
downsample = 4;
hardware_sample_rate = (uint32_t)(downsample * rate_in);
result = hackrf_init();
if( result != HACKRF_SUCCESS )
{
cout << "hackrf_init() failed" << endl;
return EXIT_FAILURE;
}
result = hackrf_open(&device);
if( result != HACKRF_SUCCESS )
{
cout << "hackrf_open() failed" << endl;
return EXIT_FAILURE;
}
result = hackrf_set_lna_gain(device, 40);
if( result != HACKRF_SUCCESS )
{
cout << "hackrf_set_lna_gain() failed" << endl;
return EXIT_FAILURE;
}
result = hackrf_set_vga_gain(device, 26);
if( result != HACKRF_SUCCESS )
{
cout << "hackrf_set_vga_gain() failed" << endl;
return EXIT_FAILURE;
}
/* Set the frequency */
result = hackrf_set_freq(device, freq);
if( result != HACKRF_SUCCESS )
{
cout << "hackrf_set_freq() failed" << endl;
return EXIT_FAILURE;
}
fprintf(stderr, "Oversampling input by: %ix.\n", downsample);
/* Set the sample rate */
result = hackrf_set_sample_rate(device, hardware_sample_rate);
if( result != HACKRF_SUCCESS )
{
cout << "hackrf_set_sample_rate() failed" << endl;
return EXIT_FAILURE;
}
result = hackrf_set_baseband_filter_bandwidth(device, hardware_sample_rate);
if( result != HACKRF_SUCCESS )
{
cout << "hackrf_baseband_filter_bandwidth_set() failed" << endl;
return EXIT_FAILURE;
}
fprintf(stderr, "Output at %u Hz.\n", rate_in);
usleep(100000);
result = hackrf_start_rx(device, rx_callback, NULL);
while ((hackrf_is_streaming(device) == HACKRF_TRUE) && (do_exit == false))
{
usleep(100000);
}
if (do_exit)
{
fprintf(stderr, "\nUser cancel, exiting...\n");
}
else
{
fprintf(stderr, "\nLibrary error, exiting...\n");
}
result = hackrf_close(device);
if(result != HACKRF_SUCCESS)
{
cout << "hackrf_close() failed" << endl;
}
else
{
cout << "hackrf_close() done" << endl;
}
hackrf_exit();
cout << "hackrf_exit() done" << endl;
return 0;
}
g++ hackrf_decode_costerp.cpp -o hackrf_decode_costerp -lhackrf -pthread -lm
我目前碰到的问题是发射的比特率不能太高。上面电脑的接收程序是1Mbps,发射程序是8MHz/80=100kbps,理论上应该出现10个1,10个0:
实际你可以看到除了正常的1111111111和0000000000以外,还夹杂着很多随机的101001110之类的不正常数据,只有10个1和10个0能代表1个正常的bit。我数了一下正确的一连串数据大概等于30个bit,也就是说一次性只能正确发30bit超过30bit(2个多byte)就不行了,而一个nrf24l01的包大概得有100多个byte,所以每个包都过不了crc。
还有一点,我现在做到100kbps就那么多错误,要达到nrf24l01最低的250kbps,错误会更多。所以我暂时放弃了。
其它还可以参考ui_coasterp.cpp proc_fsk.cpp这个程序,也是fsk,但是速率要慢不少。
这是欧洲饭店里发通知用的,另外pocsag也是fsk也可以参考一下,但是portapack中多数fsk都是1200bps,跟250kbps比,差了两百倍了。
低速率的时候1111和0000看着就比较正常,这是低速率传输的视频演示:
portapack发射nrf24l01信号 (fsk初步尝试)_哔哩哔哩_bilibili
我又试了一下之前的方法,还是不太行,生成编码再解码就有bug,然后用正确的编码和自己做的发射调制也不行。所以打算换个思路。
下面的BTLE项目,可以用电脑+HackRF收发低功耗蓝牙数据包,也是GFSK调制,是唯一一个可以用SDR成功发射GFSK信号并用电脑或手机接收的项目。现在需要把它改为发NRF格式的编码就行。
另外还有个nrf24-ble项目,可以用arduino uno+nrf24l01发低功耗蓝牙数据包。我需要另外找一套arduino+nrf24l01来收这个包,然后再用上面BTLE项目发包给他,这样就实现了电脑+SDR发给nrf24l01了。
Good Reference:
https://github.com/jamesshao8/nrf24-ble