Portapack应用开发教程(十七)nrf24l01发射

以前用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

https://github.com/jamesshao8/BTLE

制作最廉价的BLE Beacon

"Bit-Banging" Bluetooth Low Energy - Dmitry.GR

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值