kopia lustrzana https://github.com/Guenael/rtlsdr-wsprd
commit
9c514dc425
|
@ -1,4 +1,5 @@
|
||||||
*.o
|
*.o
|
||||||
|
*.iq
|
||||||
rtlsdr_wsprd
|
rtlsdr_wsprd
|
||||||
wspr_wisdom.dat
|
fftw_wisdom.dat
|
||||||
hashtable.txt
|
hashtable.txt
|
4
Makefile
4
Makefile
|
@ -1,6 +1,6 @@
|
||||||
CC = clang
|
CC = clang
|
||||||
CFLAGS= -O3 -std=gnu17 -Wall # -fsanitize=address
|
CFLAGS= -O3 -std=gnu17 -Wall # -fsanitize=address
|
||||||
LIBS = -lusb-1.0 -lrtlsdr -lpthread -lfftw3f -lcurl -lm
|
LIBS = -lusb-1.0 -lrtlsdr -lpthread -lfftw3f -lcurl -lm # -fsanitize=address
|
||||||
|
|
||||||
OBJS = rtlsdr_wsprd.o wsprd/wsprd.o wsprd/wsprsim_utils.o wsprd/wsprd_utils.o wsprd/tab.o wsprd/fano.o wsprd/nhash.o
|
OBJS = rtlsdr_wsprd.o wsprd/wsprd.o wsprd/wsprsim_utils.o wsprd/wsprd_utils.o wsprd/tab.o wsprd/fano.o wsprd/nhash.o
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@ rtlsdr_wsprd: $(OBJS)
|
||||||
$(CC) -o $@ $^ $(LIBS)
|
$(CC) -o $@ $^ $(LIBS)
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f *.o wsprd/*.o $(TARGETS) wspr_wisdom.dat hashtable.txt
|
rm -f *.o wsprd/*.o $(TARGETS) fftw_wisdom.dat hashtable.txt selftest.iq
|
||||||
|
|
||||||
install:
|
install:
|
||||||
install rtlsdr_wsprd /usr/local/lib/rtlsdr_wsprd
|
install rtlsdr_wsprd /usr/local/lib/rtlsdr_wsprd
|
||||||
|
|
|
@ -52,7 +52,7 @@
|
||||||
// #pragma GCC diagnostic ignored "-Wformat-truncation" // Was used with GCC
|
// #pragma GCC diagnostic ignored "-Wformat-truncation" // Was used with GCC
|
||||||
|
|
||||||
/* Sampling definition for RTL devices */
|
/* Sampling definition for RTL devices */
|
||||||
#define SIGNAL_LENGHT 116 // FIXME, why not 119?
|
#define SIGNAL_LENGHT 116 // EVAL, why not 119?
|
||||||
#define SIGNAL_LENGHT_MAX 120
|
#define SIGNAL_LENGHT_MAX 120
|
||||||
#define SIGNAL_SAMPLE_RATE 375
|
#define SIGNAL_SAMPLE_RATE 375
|
||||||
#define SAMPLING_RATE 2400000
|
#define SAMPLING_RATE 2400000
|
||||||
|
@ -62,12 +62,12 @@
|
||||||
|
|
||||||
|
|
||||||
/* Global declaration for states & options */
|
/* Global declaration for states & options */
|
||||||
static struct receiver_state rx_state; // FIXME - Implicit static... (DBG only)
|
struct receiver_state rx_state;
|
||||||
static struct receiver_options rx_options;
|
struct receiver_options rx_options;
|
||||||
static struct decoder_options dec_options;
|
struct decoder_options dec_options;
|
||||||
static struct decoder_results dec_results[50];
|
struct decoder_results dec_results[50];
|
||||||
static rtlsdr_dev_t *rtl_device = NULL;
|
rtlsdr_dev_t *rtl_device = NULL;
|
||||||
// +++ n_results
|
|
||||||
|
|
||||||
/* Thread stuff for side decoding */
|
/* Thread stuff for side decoding */
|
||||||
struct decoder_state {
|
struct decoder_state {
|
||||||
|
@ -78,7 +78,7 @@ struct decoder_state {
|
||||||
pthread_cond_t ready_cond;
|
pthread_cond_t ready_cond;
|
||||||
pthread_mutex_t ready_mutex;
|
pthread_mutex_t ready_mutex;
|
||||||
};
|
};
|
||||||
struct decoder_state dec;
|
struct decoder_state dec_state;
|
||||||
|
|
||||||
|
|
||||||
/* Thread stuff for separate RX (blocking function) */
|
/* Thread stuff for separate RX (blocking function) */
|
||||||
|
@ -159,7 +159,8 @@ static void rtlsdr_callback(unsigned char *samples, uint32_t samples_count, void
|
||||||
*/
|
*/
|
||||||
for (int32_t i = 0; i < samples_count / 2; i++) {
|
for (int32_t i = 0; i < samples_count / 2; i++) {
|
||||||
/* Integrator stages (N=2) */
|
/* Integrator stages (N=2) */
|
||||||
Ix1 += (int32_t)sigIn[i * 2]; // FIXME: move sigIn in float here ?
|
// EVAL: option to move sigIn in float here
|
||||||
|
Ix1 += (int32_t)sigIn[i * 2];
|
||||||
Qx1 += (int32_t)sigIn[i * 2 + 1];
|
Qx1 += (int32_t)sigIn[i * 2 + 1];
|
||||||
Ix2 += Ix1;
|
Ix2 += Ix1;
|
||||||
Qx2 += Qx1;
|
Qx2 += Qx1;
|
||||||
|
@ -170,7 +171,7 @@ static void rtlsdr_callback(unsigned char *samples, uint32_t samples_count, void
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME/TODO : some optimization here
|
// EVAL possible optimization here
|
||||||
/* 1st Comb */
|
/* 1st Comb */
|
||||||
Iy1 = Ix2 - It1z;
|
Iy1 = Ix2 - It1z;
|
||||||
It1z = It1y;
|
It1z = It1y;
|
||||||
|
@ -187,7 +188,6 @@ static void rtlsdr_callback(unsigned char *samples, uint32_t samples_count, void
|
||||||
Qt2z = Qt2y;
|
Qt2z = Qt2y;
|
||||||
Qt2y = Qy1;
|
Qt2y = Qy1;
|
||||||
|
|
||||||
// FIXME/TODO : could be made with int32_t (8 bits, 20 bits)
|
|
||||||
/* FIR compensation filter */
|
/* FIR compensation filter */
|
||||||
float Isum = 0.0, Qsum = 0.0;
|
float Isum = 0.0, Qsum = 0.0;
|
||||||
for (uint32_t j = 0; j < 32; j++) {
|
for (uint32_t j = 0; j < 32; j++) {
|
||||||
|
@ -206,17 +206,17 @@ static void rtlsdr_callback(unsigned char *samples, uint32_t samples_count, void
|
||||||
/* Save the result in the buffer */
|
/* Save the result in the buffer */
|
||||||
if (rx_state.iqIndex < (SIGNAL_LENGHT * SIGNAL_SAMPLE_RATE)) {
|
if (rx_state.iqIndex < (SIGNAL_LENGHT * SIGNAL_SAMPLE_RATE)) {
|
||||||
/* Lock the buffer during writing */
|
/* Lock the buffer during writing */
|
||||||
pthread_rwlock_wrlock(&dec.rw);
|
pthread_rwlock_wrlock(&dec_state.rw);
|
||||||
rx_state.iSamples[rx_state.iqIndex] = Isum / (8192.0 * DOWNSAMPLING);
|
rx_state.iSamples[rx_state.iqIndex] = Isum / (8192.0 * DOWNSAMPLING);
|
||||||
rx_state.qSamples[rx_state.iqIndex] = Qsum / (8192.0 * DOWNSAMPLING);
|
rx_state.qSamples[rx_state.iqIndex] = Qsum / (8192.0 * DOWNSAMPLING);
|
||||||
pthread_rwlock_unlock(&dec.rw);
|
pthread_rwlock_unlock(&dec_state.rw);
|
||||||
rx_state.iqIndex++;
|
rx_state.iqIndex++;
|
||||||
} else {
|
} else {
|
||||||
if (rx_state.decode_flag == false) {
|
if (rx_state.decode_flag == false) {
|
||||||
/* Send a signal to the other thread to start the decoding */
|
/* Send a signal to the other thread to start the decoding */
|
||||||
pthread_mutex_lock(&dec.ready_mutex);
|
pthread_mutex_lock(&dec_state.ready_mutex);
|
||||||
pthread_cond_signal(&dec.ready_cond);
|
pthread_cond_signal(&dec_state.ready_cond);
|
||||||
pthread_mutex_unlock(&dec.ready_mutex);
|
pthread_mutex_unlock(&dec_state.ready_mutex);
|
||||||
rx_state.decode_flag = true;
|
rx_state.decode_flag = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -341,19 +341,19 @@ static void *wsprDecoder(void *arg) {
|
||||||
int32_t n_results = 0;
|
int32_t n_results = 0;
|
||||||
|
|
||||||
while (!rx_state.exit_flag) {
|
while (!rx_state.exit_flag) {
|
||||||
pthread_mutex_lock(&dec.ready_mutex);
|
pthread_mutex_lock(&dec_state.ready_mutex);
|
||||||
pthread_cond_wait(&dec.ready_cond, &dec.ready_mutex);
|
pthread_cond_wait(&dec_state.ready_cond, &dec_state.ready_mutex);
|
||||||
pthread_mutex_unlock(&dec.ready_mutex);
|
pthread_mutex_unlock(&dec_state.ready_mutex);
|
||||||
|
|
||||||
if (rx_state.exit_flag)
|
if (rx_state.exit_flag)
|
||||||
break; /* Abort case, final sig */
|
break; /* Abort case, final sig */
|
||||||
|
|
||||||
/* Lock the buffer access and make a local copy */
|
/* Lock the buffer access and make a local copy */
|
||||||
pthread_rwlock_wrlock(&dec.rw);
|
pthread_rwlock_wrlock(&dec_state.rw);
|
||||||
memcpy(iSamples, rx_state.iSamples, rx_state.iqIndex * sizeof(float));
|
memcpy(iSamples, rx_state.iSamples, rx_state.iqIndex * sizeof(float));
|
||||||
memcpy(qSamples, rx_state.qSamples, rx_state.iqIndex * sizeof(float));
|
memcpy(qSamples, rx_state.qSamples, rx_state.iqIndex * sizeof(float));
|
||||||
samples_len = rx_state.iqIndex; // Overkill ?
|
samples_len = rx_state.iqIndex; // Overkill ?
|
||||||
pthread_rwlock_unlock(&dec.rw);
|
pthread_rwlock_unlock(&dec_state.rw);
|
||||||
|
|
||||||
/* Date and time will be updated/overload during the search & decoding process
|
/* Date and time will be updated/overload during the search & decoding process
|
||||||
Make a simple copy
|
Make a simple copy
|
||||||
|
@ -584,18 +584,18 @@ int32_t decoderSelfTest() {
|
||||||
static float iSamples[SIGNAL_LENGHT_MAX * SIGNAL_SAMPLE_RATE] = {0};
|
static float iSamples[SIGNAL_LENGHT_MAX * SIGNAL_SAMPLE_RATE] = {0};
|
||||||
static float qSamples[SIGNAL_LENGHT_MAX * SIGNAL_SAMPLE_RATE] = {0};
|
static float qSamples[SIGNAL_LENGHT_MAX * SIGNAL_SAMPLE_RATE] = {0};
|
||||||
static uint32_t samples_len = SIGNAL_LENGHT_MAX * SIGNAL_SAMPLE_RATE;
|
static uint32_t samples_len = SIGNAL_LENGHT_MAX * SIGNAL_SAMPLE_RATE;
|
||||||
int32_t n_results = 0; // FIXME: put n_results as a global variable
|
int32_t n_results = 0;
|
||||||
|
|
||||||
unsigned char symbols[162];
|
unsigned char symbols[162];
|
||||||
char message[] = "K1JT FN20QI 20";
|
char message[] = "K1JT FN20QI 20";
|
||||||
char hashtab[32768*13] = {0};
|
char hashtab[32768*13] = {0};
|
||||||
//char loctab[32768*5] = {0}; // FIXME
|
//char loctab[32768*5] = {0}; // EVAL: code update from wsprd
|
||||||
|
|
||||||
// Compute sympbols from the message
|
// Compute sympbols from the message
|
||||||
get_wspr_channel_symbols(message, hashtab, symbols);
|
get_wspr_channel_symbols(message, hashtab, symbols);
|
||||||
|
|
||||||
float f0 = 50.0;
|
float f0 = 50.0;
|
||||||
float t0 = 2.0; // FIXME !! Caution, possible buffer overflow with the index calculation
|
float t0 = 2.0; // Caution!! Possible buffer overflow with the index calculation (no user input here!)
|
||||||
float amp = 1.0;
|
float amp = 1.0;
|
||||||
float wgn = 0.02;
|
float wgn = 0.02;
|
||||||
double phi = 0.0;
|
double phi = 0.0;
|
||||||
|
@ -968,20 +968,20 @@ int main(int argc, char **argv) {
|
||||||
|
|
||||||
/* Prepare a low priority param for the decoder thread */
|
/* Prepare a low priority param for the decoder thread */
|
||||||
struct sched_param param;
|
struct sched_param param;
|
||||||
pthread_attr_init(&dec.tattr);
|
pthread_attr_init(&dec_state.tattr);
|
||||||
pthread_attr_setschedpolicy(&dec.tattr, SCHED_RR);
|
pthread_attr_setschedpolicy(&dec_state.tattr, SCHED_RR);
|
||||||
pthread_attr_getschedparam(&dec.tattr, ¶m);
|
pthread_attr_getschedparam(&dec_state.tattr, ¶m);
|
||||||
param.sched_priority = 90; // = sched_get_priority_min();
|
param.sched_priority = 90; // = sched_get_priority_min();
|
||||||
pthread_attr_setschedparam(&dec.tattr, ¶m);
|
pthread_attr_setschedparam(&dec_state.tattr, ¶m);
|
||||||
|
|
||||||
/* Create a thread and stuff for separate decoding
|
/* Create a thread and stuff for separate decoding
|
||||||
Info : https://computing.llnl.gov/tutorials/pthreads/
|
Info : https://computing.llnl.gov/tutorials/pthreads/
|
||||||
*/
|
*/
|
||||||
pthread_rwlock_init(&dec.rw, NULL);
|
pthread_rwlock_init(&dec_state.rw, NULL);
|
||||||
pthread_cond_init(&dec.ready_cond, NULL);
|
pthread_cond_init(&dec_state.ready_cond, NULL);
|
||||||
pthread_mutex_init(&dec.ready_mutex, NULL);
|
pthread_mutex_init(&dec_state.ready_mutex, NULL);
|
||||||
pthread_create(&dongle.thread, NULL, rtlsdr_rx, NULL);
|
pthread_create(&dongle.thread, NULL, rtlsdr_rx, NULL);
|
||||||
pthread_create(&dec.thread, &dec.tattr, wsprDecoder, NULL);
|
pthread_create(&dec_state.thread, &dec_state.tattr, wsprDecoder, NULL);
|
||||||
|
|
||||||
/* Main loop : Wait, read, decode */
|
/* Main loop : Wait, read, decode */
|
||||||
while (!rx_state.exit_flag && !(rx_options.maxloop && (nLoop >= rx_options.maxloop))) {
|
while (!rx_state.exit_flag && !(rx_options.maxloop && (nLoop >= rx_options.maxloop))) {
|
||||||
|
@ -1017,16 +1017,16 @@ int main(int argc, char **argv) {
|
||||||
printf("Bye!\n");
|
printf("Bye!\n");
|
||||||
|
|
||||||
/* Wait the thread join (send a signal before to terminate the job) */
|
/* Wait the thread join (send a signal before to terminate the job) */
|
||||||
pthread_mutex_lock(&dec.ready_mutex);
|
pthread_mutex_lock(&dec_state.ready_mutex);
|
||||||
pthread_cond_signal(&dec.ready_cond);
|
pthread_cond_signal(&dec_state.ready_cond);
|
||||||
pthread_mutex_unlock(&dec.ready_mutex);
|
pthread_mutex_unlock(&dec_state.ready_mutex);
|
||||||
pthread_join(dec.thread, NULL);
|
pthread_join(dec_state.thread, NULL);
|
||||||
pthread_join(dongle.thread, NULL);
|
pthread_join(dongle.thread, NULL);
|
||||||
|
|
||||||
/* Destroy the lock/cond/thread */
|
/* Destroy the lock/cond/thread */
|
||||||
pthread_rwlock_destroy(&dec.rw);
|
pthread_rwlock_destroy(&dec_state.rw);
|
||||||
pthread_cond_destroy(&dec.ready_cond);
|
pthread_cond_destroy(&dec_state.ready_cond);
|
||||||
pthread_mutex_destroy(&dec.ready_mutex);
|
pthread_mutex_destroy(&dec_state.ready_mutex);
|
||||||
pthread_exit(NULL);
|
pthread_exit(NULL);
|
||||||
|
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
|
|
|
@ -62,7 +62,7 @@ fftwf_plan PLAN1,
|
||||||
PLAN3;
|
PLAN3;
|
||||||
int32_t printdata = 0;
|
int32_t printdata = 0;
|
||||||
|
|
||||||
uint8_t pr3[NSYM] = {
|
uint8_t pr3vector[NSYM] = {
|
||||||
1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0,
|
1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0,
|
||||||
0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1,
|
0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1,
|
||||||
0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1,
|
0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1,
|
||||||
|
@ -206,9 +206,9 @@ void sync_and_demodulate(float *id, float *qd, long np,
|
||||||
|
|
||||||
totp = totp + p0 + p1 + p2 + p3;
|
totp = totp + p0 + p1 + p2 + p3;
|
||||||
cmet = (p1 + p3) - (p0 + p2);
|
cmet = (p1 + p3) - (p0 + p2);
|
||||||
ss = ss + cmet * (2 * pr3[i] - 1);
|
ss = ss + cmet * (2 * pr3vector[i] - 1);
|
||||||
if (mode == 2) { // Compute soft symbols
|
if (mode == 2) { // Compute soft symbols
|
||||||
if (pr3[i]) {
|
if (pr3vector[i]) {
|
||||||
fsymb[i] = p3 - p1;
|
fsymb[i] = p3 - p1;
|
||||||
} else {
|
} else {
|
||||||
fsymb[i] = p2 - p0;
|
fsymb[i] = p2 - p0;
|
||||||
|
@ -450,7 +450,7 @@ int32_t wspr_decode(float *idat, float *qdat, uint32_t npoints,
|
||||||
fftwf_complex *fftin, *fftout;
|
fftwf_complex *fftin, *fftout;
|
||||||
|
|
||||||
FILE *fp_fftw_wisdom_file, *fhash;
|
FILE *fp_fftw_wisdom_file, *fhash;
|
||||||
if ((fp_fftw_wisdom_file = fopen("wspr_wisdom.dat", "r"))) { // Open FFTW wisdom
|
if ((fp_fftw_wisdom_file = fopen("fftw_wisdom.dat", "r"))) { // Open FFTW wisdom
|
||||||
fftwf_import_wisdom_from_file(fp_fftw_wisdom_file);
|
fftwf_import_wisdom_from_file(fp_fftw_wisdom_file);
|
||||||
fclose(fp_fftw_wisdom_file);
|
fclose(fp_fftw_wisdom_file);
|
||||||
}
|
}
|
||||||
|
@ -636,7 +636,7 @@ int32_t wspr_decode(float *idat, float *qdat, uint32_t npoints,
|
||||||
p2 = sqrtf(p2);
|
p2 = sqrtf(p2);
|
||||||
p3 = sqrtf(p3);
|
p3 = sqrtf(p3);
|
||||||
|
|
||||||
ss = ss + (2 * pr3[k] - 1) * ((p1 + p3) - (p0 + p2));
|
ss = ss + (2 * pr3vector[k] - 1) * ((p1 + p3) - (p0 + p2));
|
||||||
pow = pow + p0 + p1 + p2 + p3;
|
pow = pow + p0 + p1 + p2 + p3;
|
||||||
sync1 = ss / pow;
|
sync1 = ss / pow;
|
||||||
}
|
}
|
||||||
|
@ -811,7 +811,7 @@ int32_t wspr_decode(float *idat, float *qdat, uint32_t npoints,
|
||||||
fftwf_free(fftin);
|
fftwf_free(fftin);
|
||||||
fftwf_free(fftout);
|
fftwf_free(fftout);
|
||||||
|
|
||||||
if ((fp_fftw_wisdom_file = fopen("wspr_wisdom.dat", "w"))) {
|
if ((fp_fftw_wisdom_file = fopen("fftw_wisdom.dat", "w"))) {
|
||||||
fftwf_export_wisdom_to_file(fp_fftw_wisdom_file);
|
fftwf_export_wisdom_to_file(fp_fftw_wisdom_file);
|
||||||
fclose(fp_fftw_wisdom_file);
|
fclose(fp_fftw_wisdom_file);
|
||||||
}
|
}
|
||||||
|
|
|
@ -302,7 +302,7 @@ int unpk_(signed char *message, char *hashtab, char *call_loc_pow, char *call, c
|
||||||
strncat(call_loc_pow, cdbm, 2);
|
strncat(call_loc_pow, cdbm, 2);
|
||||||
strncat(call_loc_pow, "\0", 1);
|
strncat(call_loc_pow, "\0", 1);
|
||||||
int nu = ndbm % 10;
|
int nu = ndbm % 10;
|
||||||
if (nu == 0 || nu == 3 || nu == 7 || nu == 10) { // make sure power is OK
|
if (nu == 0 || nu == 3 || nu == 7) { // make sure power is OK
|
||||||
ihash = nhash(callsign, strlen(callsign), (uint32_t)146);
|
ihash = nhash(callsign, strlen(callsign), (uint32_t)146);
|
||||||
strcpy(hashtab + ihash * 13, callsign);
|
strcpy(hashtab + ihash * 13, callsign);
|
||||||
} else {
|
} else {
|
||||||
|
@ -324,7 +324,7 @@ int unpk_(signed char *message, char *hashtab, char *call_loc_pow, char *call, c
|
||||||
strncat(grid6, callsign + 5, 1);
|
strncat(grid6, callsign + 5, 1);
|
||||||
strncat(grid6, callsign, 5);
|
strncat(grid6, callsign, 5);
|
||||||
int nu = ndbm % 10;
|
int nu = ndbm % 10;
|
||||||
if ((nu == 0 || nu == 3 || nu == 7 || nu == 10) &&
|
if ((nu == 0 || nu == 3 || nu == 7) &&
|
||||||
(isalpha(grid6[0]) && isalpha(grid6[1]) && isdigit(grid6[2]) && isdigit(grid6[3]))) {
|
(isalpha(grid6[0]) && isalpha(grid6[1]) && isdigit(grid6[2]) && isdigit(grid6[3]))) {
|
||||||
// not testing 4'th and 5'th chars because of this case: <PA0SKT/2> JO33 40
|
// not testing 4'th and 5'th chars because of this case: <PA0SKT/2> JO33 40
|
||||||
// grid is only 4 chars even though this is a hashed callsign...
|
// grid is only 4 chars even though this is a hashed callsign...
|
||||||
|
|
Ładowanie…
Reference in New Issue