From 58a6fc6375f5f3a54ee5864e6c06ee80919b2929 Mon Sep 17 00:00:00 2001 From: F5OEO Date: Tue, 24 Jan 2023 12:20:34 +0100 Subject: [PATCH] Fix multi frequencies issue --- wspr.cpp | 1009 ++++++++++++++++++++++++++++++------------------------ 1 file changed, 562 insertions(+), 447 deletions(-) diff --git a/wspr.cpp b/wspr.cpp index ca23ce5..32658cc 100644 --- a/wspr.cpp +++ b/wspr.cpp @@ -17,6 +17,7 @@ // ha7ilm: added RPi2 support based on a patch to PiFmRds by Cristophe // Jacquet and Richard Hirst: http://git.io/vn7O9 +// F5OEO : adapt to librpitx for cleaner spectrum #include #include @@ -46,40 +47,42 @@ #include #include "librpitx/src/librpitx.h" - -clkgpio *clk=NULL; -ngfmdmasync *ngfmtest=NULL; - +clkgpio *clk = NULL; +ngfmdmasync *ngfmtest = NULL; #define ABORT(a) exit(a) // Used for debugging #define MARK std::cout << "Currently in file: " << __FILE__ << " line: " << __LINE__ << std::endl -typedef enum {WSPR,TONE} mode_type; +typedef enum +{ + WSPR, + TONE +} mode_type; // WSRP nominal symbol time -#define WSPR_SYMTIME (8192.0/12000.0) +#define WSPR_SYMTIME (8192.0 / 12000.0) // How much random frequency offset should be added to WSPR transmissions // if the --offset option has been turned on. #define WSPR_RAND_OFFSET 80 #define WSPR15_RAND_OFFSET 8 // Disable the PWM clock and wait for it to become 'not busy'. -void disable_clock() { - +void disable_clock() +{ } // Turn on TX -void txon() { - - //ACCESS_BUS_ADDR(PADS_GPIO_0_27_BUS) = 0x5a000018 + 7; //16mA +10.6dBm +void txon() +{ + + // ACCESS_BUS_ADDR(PADS_GPIO_0_27_BUS) = 0x5a000018 + 7; //16mA +10.6dBm disable_clock(); - - } // Turn transmitter on -void txoff() { +void txoff() +{ disable_clock(); } @@ -90,40 +93,39 @@ void txoff() { // do not know which DMA table entry is being processed by the DMA engine. #define PWM_CLOCKS_PER_ITER_NOMINAL 1000 void txSym( - const int & sym_num, - const double & center_freq, - const double & tone_spacing, - const double & tsym, - const std::vector & dma_table_freq, - const double & f_pwm_clk, - struct PageInfo instrs[], - struct PageInfo & constPage, - int & bufPtr -) { - + const int &sym_num, + const double ¢er_freq, + const double &tone_spacing, + const double &tsym, + const std::vector &dma_table_freq, + const double &f_pwm_clk, + struct PageInfo instrs[], + struct PageInfo &constPage, + int &bufPtr) +{ } // Turn off (reset) DMA engine -void unSetupDMA(){ - +void unSetupDMA() +{ + txoff(); } // Truncate at bit lsb. i.e. set all bits less than lsb to zero. double bit_trunc( - const double & d, - const int & lsb -) { - return floor(d/pow(2.0,lsb))*pow(2.0,lsb); + const double &d, + const int &lsb) +{ + return floor(d / pow(2.0, lsb)) * pow(2.0, lsb); } - - // Convert string to uppercase void to_upper( - char *str -) { - while(*str) { + char *str) +{ + while (*str) + { *str = toupper(*str); str++; } @@ -131,133 +133,157 @@ void to_upper( // Encode call, locator, and dBm into WSPR codeblock. void wspr( - const char* call, - const char* l_pre, - const char* dbm, - unsigned char* symbols -) { + const char *call, + const char *l_pre, + const char *dbm, + unsigned char *symbols) +{ // pack prefix in nadd, call in n1, grid, dbm in n2 - char* c, buf[16]; + char *c, buf[16]; strncpy(buf, call, 16); - c=buf; + c = buf; to_upper(c); - unsigned long ng,nadd=0; + unsigned long ng, nadd = 0; - if(strchr(c, '/')){ //prefix-suffix - nadd=2; - int i=strchr(c, '/')-c; //stroke position - int n=strlen(c)-i-1; //suffix len, prefix-call len - c[i]='\0'; - if(n==1) ng=60000-32768+(c[i+1]>='0'&&c[i+1]<='9'?c[i+1]-'0':c[i+1]==' '?38:c[i+1]-'A'+10); // suffix /A to /Z, /0 to /9 - if(n==2) ng=60000+26+10*(c[i+1]-'0')+(c[i+2]-'0'); // suffix /10 to /99 - if(n>2){ // prefix EA8/, right align - ng=(i<3?36:c[i-3]>='0'&&c[i-3]<='9'?c[i-3]-'0':c[i-3]-'A'+10); - ng=37*ng+(i<2?36:c[i-2]>='0'&&c[i-2]<='9'?c[i-2]-'0':c[i-2]-'A'+10); - ng=37*ng+(i<1?36:c[i-1]>='0'&&c[i-1]<='9'?c[i-1]-'0':c[i-1]-'A'+10); - if(ng<32768) nadd=1; else ng=ng-32768; - c=c+i+1; + if (strchr(c, '/')) + { // prefix-suffix + nadd = 2; + int i = strchr(c, '/') - c; // stroke position + int n = strlen(c) - i - 1; // suffix len, prefix-call len + c[i] = '\0'; + if (n == 1) + ng = 60000 - 32768 + (c[i + 1] >= '0' && c[i + 1] <= '9' ? c[i + 1] - '0' : c[i + 1] == ' ' ? 38 + : c[i + 1] - 'A' + 10); // suffix /A to /Z, /0 to /9 + if (n == 2) + ng = 60000 + 26 + 10 * (c[i + 1] - '0') + (c[i + 2] - '0'); // suffix /10 to /99 + if (n > 2) + { // prefix EA8/, right align + ng = (i < 3 ? 36 : c[i - 3] >= '0' && c[i - 3] <= '9' ? c[i - 3] - '0' + : c[i - 3] - 'A' + 10); + ng = 37 * ng + (i < 2 ? 36 : c[i - 2] >= '0' && c[i - 2] <= '9' ? c[i - 2] - '0' + : c[i - 2] - 'A' + 10); + ng = 37 * ng + (i < 1 ? 36 : c[i - 1] >= '0' && c[i - 1] <= '9' ? c[i - 1] - '0' + : c[i - 1] - 'A' + 10); + if (ng < 32768) + nadd = 1; + else + ng = ng - 32768; + c = c + i + 1; } } - int i=(isdigit(c[2])?2:isdigit(c[1])?1:0); //last prefix digit of de-suffixed/de-prefixed callsign - int n=strlen(c)-i-1; //2nd part of call len + int i = (isdigit(c[2]) ? 2 : isdigit(c[1]) ? 1 + : 0); // last prefix digit of de-suffixed/de-prefixed callsign + int n = strlen(c) - i - 1; // 2nd part of call len unsigned long n1; - n1=(i<2?36:c[i-2]>='0'&&c[i-2]<='9'?c[i-2]-'0':c[i-2]-'A'+10); - n1=36*n1+(i<1?36:c[i-1]>='0'&&c[i-1]<='9'?c[i-1]-'0':c[i-1]-'A'+10); - n1=10*n1+c[i]-'0'; - n1=27*n1+(n<1?26:c[i+1]-'A'); - n1=27*n1+(n<2?26:c[i+2]-'A'); - n1=27*n1+(n<3?26:c[i+3]-'A'); + n1 = (i < 2 ? 36 : c[i - 2] >= '0' && c[i - 2] <= '9' ? c[i - 2] - '0' + : c[i - 2] - 'A' + 10); + n1 = 36 * n1 + (i < 1 ? 36 : c[i - 1] >= '0' && c[i - 1] <= '9' ? c[i - 1] - '0' + : c[i - 1] - 'A' + 10); + n1 = 10 * n1 + c[i] - '0'; + n1 = 27 * n1 + (n < 1 ? 26 : c[i + 1] - 'A'); + n1 = 27 * n1 + (n < 2 ? 26 : c[i + 2] - 'A'); + n1 = 27 * n1 + (n < 3 ? 26 : c[i + 3] - 'A'); - //if(rand() % 2) nadd=0; - if(!nadd){ + // if(rand() % 2) nadd=0; + if (!nadd) + { // Copy locator locally since it is declared const and we cannot modify // its contents in-place. char l[4]; strncpy(l, l_pre, 4); - to_upper(l); //grid square Maidenhead locator (uppercase) - ng=180*(179-10*(l[0]-'A')-(l[2]-'0'))+10*(l[1]-'A')+(l[3]-'0'); + to_upper(l); // grid square Maidenhead locator (uppercase) + ng = 180 * (179 - 10 * (l[0] - 'A') - (l[2] - '0')) + 10 * (l[1] - 'A') + (l[3] - '0'); } - int p = atoi(dbm); //EIRP in dBm={0,3,7,10,13,17,20,23,27,30,33,37,40,43,47,50,53,57,60} - int corr[]={0,-1,1,0,-1,2,1,0,-1,1}; - p=p>60?60:p<0?0:p+corr[p%10]; - unsigned long n2=(ng<<7)|(p+64+nadd); + int p = atoi(dbm); // EIRP in dBm={0,3,7,10,13,17,20,23,27,30,33,37,40,43,47,50,53,57,60} + int corr[] = {0, -1, 1, 0, -1, 2, 1, 0, -1, 1}; + p = p > 60 ? 60 : p < 0 ? 0 + : p + corr[p % 10]; + unsigned long n2 = (ng << 7) | (p + 64 + nadd); // pack n1,n2,zero-tail into 50 bits char packed[11] = { - static_cast(n1>>20), - static_cast(n1>>12), - static_cast(n1>>4), - static_cast(((n1&0x0f)<<4)|((n2>>18)&0x0f)), - static_cast(n2>>10), - static_cast(n2>>2), - static_cast((n2&0x03)<<6), - 0, - 0, - 0, - 0 - }; + static_cast(n1 >> 20), + static_cast(n1 >> 12), + static_cast(n1 >> 4), + static_cast(((n1 & 0x0f) << 4) | ((n2 >> 18) & 0x0f)), + static_cast(n2 >> 10), + static_cast(n2 >> 2), + static_cast((n2 & 0x03) << 6), + 0, + 0, + 0, + 0}; // convolutional encoding K=32, r=1/2, Layland-Lushbaugh polynomials int k = 0; - int j,s; + int j, s; int nstate = 0; unsigned char symbol[176]; - for(j=0;j!=sizeof(packed);j++){ - for(i=7;i>=0;i--){ - unsigned long poly[2] = { 0xf2d05351L, 0xe4613c47L }; - nstate = (nstate<<1) | ((packed[j]>>i)&1); - for(s=0;s!=2;s++){ //convolve - unsigned long n = nstate & poly[s]; - int even = 0; // even := parity(n) - while(n){ - even = 1 - even; - n = n & (n - 1); - } - symbol[k] = even; - k++; + for (j = 0; j != sizeof(packed); j++) + { + for (i = 7; i >= 0; i--) + { + unsigned long poly[2] = {0xf2d05351L, 0xe4613c47L}; + nstate = (nstate << 1) | ((packed[j] >> i) & 1); + for (s = 0; s != 2; s++) + { // convolve + unsigned long n = nstate & poly[s]; + int even = 0; // even := parity(n) + while (n) + { + even = 1 - even; + n = n & (n - 1); } - } + symbol[k] = even; + k++; + } + } } // interleave symbols const unsigned char npr3[162] = { - 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,0,0,0,0,0,1,0,1,1,0,0,1,1,0,1,0,0,0,1,1,0,1,0, - 0,0,0,1,1,0,1,0,1,0,1,0,1,0,0,1,0,0,1,0,1,1,0,0,0,1,1,0,1,0,1,0, - 0,0,1,0,0,0,0,0,1,0,0,1,0,0,1,1,1,0,1,1,0,0,1,1,0,1,0,0,0,1,1,1, - 0,0,0,0,0,1,0,1,0,0,1,1,0,0,0,0,0,0,0,1,1,0,1,0,1,1,0,0,0,1,1,0, - 0,0 }; - for(i=0;i!=162;i++){ - // j0 := bit reversed_values_smaller_than_161[i] - unsigned char j0; - p=-1; - for(k=0;p!=i;k++){ - for(j=0;j!=8;j++) // j0:=bit_reverse(k) - j0 = ((k>>j)&1)|(j0<<1); - if(j0<162) - p++; - } - symbols[j0]=npr3[j0]|symbol[i]<<1; //interleave and add sync std::vector + 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, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, + 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, + 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 1, 1, + 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, + 0, 0}; + for (i = 0; i != 162; i++) + { + // j0 := bit reversed_values_smaller_than_161[i] + unsigned char j0; + p = -1; + for (k = 0; p != i; k++) + { + for (j = 0; j != 8; j++) // j0:=bit_reverse(k) + j0 = ((k >> j) & 1) | (j0 << 1); + if (j0 < 162) + p++; + } + symbols[j0] = npr3[j0] | symbol[i] << 1; // interleave and add sync std::vector } } // Wait for the system clock's minute to reach one second past 'minute' void wait_every( - int minute -) { + int minute) +{ time_t t; - struct tm* ptm; - for(;;){ + struct tm *ptm; + for (;;) + { time(&t); ptm = gmtime(&t); - if((ptm->tm_min % minute) == 0 && ptm->tm_sec == 0) break; + if ((ptm->tm_min % minute) == 0 && ptm->tm_sec == 0) + break; usleep(1000); } usleep(1000000); // wait another second } -void print_usage() { +void print_usage() +{ std::cout << "Usage:" << std::endl; std::cout << " wspr [options] callsign locator tx_pwr_dBm f1 ..." << std::endl; std::cout << " OR" << std::endl; @@ -298,181 +324,229 @@ void print_usage() { } void parse_commandline( - // Inputs - const int & argc, - char * const argv[], - // Outputs - std::string & callsign, - std::string & locator, - std::string & tx_power, - std::vector & center_freq_set, - double & ppm, - bool & self_cal, - bool & repeat, - bool & random_offset, - double & test_tone, - bool & no_delay, - mode_type & mode, - int & terminate -) { + // Inputs + const int &argc, + char *const argv[], + // Outputs + std::string &callsign, + std::string &locator, + std::string &tx_power, + std::vector ¢er_freq_set, + double &ppm, + bool &self_cal, + bool &repeat, + bool &random_offset, + double &test_tone, + bool &no_delay, + mode_type &mode, + int &terminate) +{ // Default values - ppm=0; - self_cal=true; - repeat=false; - random_offset=false; - test_tone=NAN; - no_delay=false; - mode=WSPR; - terminate=-1; + ppm = 0; + self_cal = true; + repeat = false; + random_offset = false; + test_tone = NAN; + no_delay = false; + mode = WSPR; + terminate = -1; static struct option long_options[] = { - {"help", no_argument, 0, 'h'}, - {"ppm", required_argument, 0, 'p'}, - {"self-calibration", no_argument, 0, 's'}, - {"free-running", no_argument, 0, 'f'}, - {"repeat", no_argument, 0, 'r'}, - {"terminate", required_argument, 0, 'x'}, - {"offset", no_argument, 0, 'o'}, - {"test-tone", required_argument, 0, 't'}, - {"no-delay", no_argument, 0, 'n'}, - {0, 0, 0, 0} - }; + {"help", no_argument, 0, 'h'}, + {"ppm", required_argument, 0, 'p'}, + {"self-calibration", no_argument, 0, 's'}, + {"free-running", no_argument, 0, 'f'}, + {"repeat", no_argument, 0, 'r'}, + {"terminate", required_argument, 0, 'x'}, + {"offset", no_argument, 0, 'o'}, + {"test-tone", required_argument, 0, 't'}, + {"no-delay", no_argument, 0, 'n'}, + {0, 0, 0, 0}}; - while (true) { + while (true) + { /* getopt_long stores the option index here. */ int option_index = 0; - int c = getopt_long (argc, argv, "hp:sfrx:ot:n", - long_options, &option_index); + int c = getopt_long(argc, argv, "hp:sfrx:ot:n", + long_options, &option_index); if (c == -1) break; - switch (c) { - char * endp; - case 0: - // Code should only get here if a long option was given a non-null - // flag value. - std::cout << "Check code!" << std::endl; + switch (c) + { + char *endp; + case 0: + // Code should only get here if a long option was given a non-null + // flag value. + std::cout << "Check code!" << std::endl; + ABORT(-1); + break; + case 'h': + print_usage(); + ABORT(-1); + break; + case 'p': + ppm = strtod(optarg, &endp); + if ((optarg == endp) || (*endp != '\0')) + { + std::cerr << "Error: could not parse ppm value" << std::endl; ABORT(-1); - break; - case 'h': - print_usage(); + } + break; + case 's': + self_cal = true; + break; + case 'f': + self_cal = false; + break; + case 'r': + repeat = true; + break; + case 'x': + terminate = strtol(optarg, &endp, 10); + if ((optarg == endp) || (*endp != '\0')) + { + std::cerr << "Error: could not parse termination argument" << std::endl; ABORT(-1); - break; - case 'p': - ppm=strtod(optarg,&endp); - if ((optarg==endp)||(*endp!='\0')) { - std::cerr << "Error: could not parse ppm value" << std::endl; - ABORT(-1); - } - break; - case 's': - self_cal=true; - break; - case 'f': - self_cal=false; - break; - case 'r': - repeat=true; - break; - case 'x': - terminate=strtol(optarg,&endp,10); - if ((optarg==endp)||(*endp!='\0')) { - std::cerr << "Error: could not parse termination argument" << std::endl; - ABORT(-1); - } - if (terminate<1) { - std::cerr << "Error: termination parameter must be >= 1" << std::endl; - ABORT(-1); - } - break; - case 'o': - random_offset=true; - break; - case 't': - test_tone=strtod(optarg,&endp); - mode=TONE; - if ((optarg==endp)||(*endp!='\0')) { - std::cerr << "Error: could not parse test tone frequency" << std::endl; - ABORT(-1); - } - break; - case 'n': - no_delay=true; - break; - case '?': - /* getopt_long already printed an error message. */ + } + if (terminate < 1) + { + std::cerr << "Error: termination parameter must be >= 1" << std::endl; ABORT(-1); - default: + } + break; + case 'o': + random_offset = true; + break; + case 't': + test_tone = strtod(optarg, &endp); + mode = TONE; + if ((optarg == endp) || (*endp != '\0')) + { + std::cerr << "Error: could not parse test tone frequency" << std::endl; ABORT(-1); + } + break; + case 'n': + no_delay = true; + break; + case '?': + /* getopt_long already printed an error message. */ + ABORT(-1); + default: + ABORT(-1); } - } // Parse the non-option parameters - unsigned int n_free_args=0; - while (optind0) { + if (terminate > 0) + { temp << " TX will stop after " << terminate << " transmissions." << std::endl; - } else if (repeat) { + } + else if (repeat) + { temp << " Transmissions will continue forever until stopped with CTRL-C" << std::endl; } - if (random_offset) { + if (random_offset) + { temp << " A small random frequency offset will be added to all transmissions" << std::endl; } - if (temp.str().length()) { + if (temp.str().length()) + { std::cout << "Extra options:" << std::endl; std::cout << temp.str(); } std::cout << std::endl; - } else { + } + else + { std::stringstream temp; - temp << std::setprecision(6) << std::fixed << "A test tone will be generated at frequency " << test_tone/1e6 << " MHz" << std::endl; + temp << std::setprecision(6) << std::fixed << "A test tone will be generated at frequency " << test_tone / 1e6 << " MHz" << std::endl; std::cout << temp.str(); - if (self_cal) { + if (self_cal) + { std::cout << "NTP will be used to calibrate the tone frequency" << std::endl; - } else if (ppm) { + } + else if (ppm) + { std::cout << "PPM value to be used to generate the tone: " << ppm << std::endl; } std::cout << std::endl; @@ -554,8 +650,8 @@ void parse_commandline( // Call ntp_adjtime() to obtain the latest calibration coefficient. void update_ppm( - double & ppm -) { + double &ppm) +{ struct timex ntx; int status; double ppm_new; @@ -563,63 +659,79 @@ void update_ppm( ntx.modes = 0; /* only read */ status = ntp_adjtime(&ntx); - if (status != TIME_OK) { - //cerr << "Error: clock not synchronized" << std::endl; - //return; + if (status != TIME_OK) + { + // cerr << "Error: clock not synchronized" << std::endl; + // return; } - ppm_new = (double)ntx.freq/(double)(1 << 16); /* frequency scale */ - if (abs(ppm_new)>200) { + ppm_new = (double)ntx.freq / (double)(1 << 16); /* frequency scale */ + if (abs(ppm_new) > 200) + { std::cerr << "Warning: absolute ppm value is greater than 200 and is being ignored!" << std::endl; - } else { - if (ppm!=ppm_new) { + } + else + { + if (ppm != ppm_new) + { std::cout << " Obtained new ppm value: " << ppm_new << std::endl; } - ppm=ppm_new; + ppm = ppm_new; } } /* Return 1 if the difference is negative, otherwise 0. */ // From StackOverflow: // http://stackoverflow.com/questions/1468596/c-programming-calculate-elapsed-time-in-milliseconds-unix -int timeval_subtract(struct timeval *result, struct timeval *t2, struct timeval *t1) { - long int diff = (t2->tv_usec + 1000000 * t2->tv_sec) - (t1->tv_usec + 1000000 * t1->tv_sec); - result->tv_sec = diff / 1000000; - result->tv_usec = diff % 1000000; +int timeval_subtract(struct timeval *result, struct timeval *t2, struct timeval *t1) +{ + long int diff = (t2->tv_usec + 1000000 * t2->tv_sec) - (t1->tv_usec + 1000000 * t1->tv_sec); + result->tv_sec = diff / 1000000; + result->tv_usec = diff % 1000000; - return (diff<0); + return (diff < 0); } -void timeval_print(struct timeval *tv) { - char buffer[30]; - time_t curtime; +void timeval_print(struct timeval *tv) +{ + char buffer[30]; + time_t curtime; - //printf("%ld.%06ld", tv->tv_sec, tv->tv_usec); - curtime = tv->tv_sec; - //strftime(buffer, 30, "%m-%d-%Y %T", localtime(&curtime)); - strftime(buffer, 30, "UTC %Y-%m-%d %T", gmtime(&curtime)); - printf("%s.%03ld", buffer, (tv->tv_usec+500)/1000); + // printf("%ld.%06ld", tv->tv_sec, tv->tv_usec); + curtime = tv->tv_sec; + // strftime(buffer, 30, "%m-%d-%Y %T", localtime(&curtime)); + strftime(buffer, 30, "UTC %Y-%m-%d %T", gmtime(&curtime)); + printf("%s.%03ld", buffer, (tv->tv_usec + 500) / 1000); } - // Called when exiting or when a signal is received. -void cleanup() { - if(clk!=NULL) {delete clk;clk=NULL;} - if(ngfmtest!=NULL) {delete ngfmtest;ngfmtest=NULL;} +void cleanup() +{ + if (clk != NULL) + { + delete clk; + clk = NULL; + } + if (ngfmtest != NULL) + { + delete ngfmtest; + ngfmtest = NULL; + } } // Called when a signal is received. Automatically calls cleanup(). -void cleanupAndExit(int sig) { +void cleanupAndExit(int sig) +{ std::cerr << "Exiting with error; caught signal: " << sig << std::endl; cleanup(); ABORT(-1); } - - -int main(const int argc, char * const argv[]) { - //catch all signals (like ctrl+c, ctrl+z, ...) to ensure DMA is disabled - for (int i = 0; i < 64; i++) { +int main(const int argc, char *const argv[]) +{ + // catch all signals (like ctrl+c, ctrl+z, ...) to ensure DMA is disabled + for (int i = 0; i < 64; i++) + { struct sigaction sa; memset(&sa, 0, sizeof(sa)); sa.sa_handler = cleanupAndExit; @@ -627,9 +739,6 @@ int main(const int argc, char * const argv[]) { } atexit(cleanup); - - - // Initialize the RNG srand(time(NULL)); @@ -637,7 +746,7 @@ int main(const int argc, char * const argv[]) { std::string callsign; std::string locator; std::string tx_power; - std::vector center_freq_set; + std::vector center_freq_set; double ppm; bool self_cal; bool repeat; @@ -647,53 +756,52 @@ int main(const int argc, char * const argv[]) { mode_type mode; int terminate; parse_commandline( - argc, - argv, - callsign, - locator, - tx_power, - center_freq_set, - ppm, - self_cal, - repeat, - random_offset, - test_tone, - no_delay, - mode, - terminate - ); - int nbands=center_freq_set.size(); + argc, + argv, + callsign, + locator, + tx_power, + center_freq_set, + ppm, + self_cal, + repeat, + random_offset, + test_tone, + no_delay, + mode, + terminate); + int nbands = center_freq_set.size(); - - - - if (mode==TONE) { - if(clk==NULL) - clk=new clkgpio; - clk->SetAdvancedPllMode(true); + if (mode == TONE) + { + if (clk == NULL) + clk = new clkgpio; + clk->SetAdvancedPllMode(true); // Test tone mode... double wspr_symtime = WSPR_SYMTIME; - double tone_spacing=1.0/wspr_symtime; + double tone_spacing = 1.0 / wspr_symtime; std::stringstream temp; - temp << std::setprecision(6) << std::fixed << "Transmitting test tone on frequency " << test_tone/1.0e6 << " MHz" << std::endl; + temp << std::setprecision(6) << std::fixed << "Transmitting test tone on frequency " << test_tone / 1.0e6 << " MHz" << std::endl; std::cout << temp.str(); std::cout << "Press CTRL-C to exit!" << std::endl; txon(); - int bufPtr=0; - - // Set to non-zero value to ensure setupDMATab is called at least once. - double ppm_prev=123456; - double center_freq_actual; - //SetTone - clk->SetCenterFrequency(test_tone,100); - clk->enableclk(4); - clk->SetFrequency(000); - while(true) usleep(1000000); - // Should never get here... + int bufPtr = 0; - } else { + // Set to non-zero value to ensure setupDMATab is called at least once. + double ppm_prev = 123456; + double center_freq_actual; + // SetTone + clk->SetCenterFrequency(test_tone, 100); + clk->enableclk(4); + clk->SetFrequency(000); + while (true) + usleep(1000000); + // Should never get here... + } + else + { // WSPR mode // Create WSPR symbols @@ -711,56 +819,65 @@ int main(const int argc, char * const argv[]) { */ std::cout << "Ready to transmit (setup complete)..." << std::endl; - int band=0; - int n_tx=0; - for(;;) { + int band = 0; + int n_tx = 0; + for (;;) + { // Calculate WSPR parameters for this transmission double center_freq_desired; center_freq_desired = center_freq_set[band]; bool wspr15 = - (center_freq_desired > 137600 && center_freq_desired < 137625) || \ - (center_freq_desired > 475800 && center_freq_desired < 475825) || \ - (center_freq_desired > 1838200 && center_freq_desired < 1838225); + (center_freq_desired > 137600 && center_freq_desired < 137625) || + (center_freq_desired > 475800 && center_freq_desired < 475825) || + (center_freq_desired > 1838200 && center_freq_desired < 1838225); double wspr_symtime = (wspr15) ? 8.0 * WSPR_SYMTIME : WSPR_SYMTIME; - double tone_spacing=1.0/wspr_symtime; + double tone_spacing = 1.0 / wspr_symtime; // Add random offset - if ((center_freq_desired!=0)&&random_offset) { - center_freq_desired+=(2.0*rand()/((double)RAND_MAX+1.0)-1.0)*(wspr15?WSPR15_RAND_OFFSET:WSPR_RAND_OFFSET); + if ((center_freq_desired != 0) && random_offset) + { + center_freq_desired += (2.0 * rand() / ((double)RAND_MAX + 1.0) - 1.0) * (wspr15 ? WSPR15_RAND_OFFSET : WSPR_RAND_OFFSET); } // Status message before transmission std::stringstream temp; temp << std::setprecision(6) << std::fixed; - temp << "Desired center frequency for " << (wspr15?"WSPR-15":"WSPR") << " transmission: "<< center_freq_desired/1e6 << " MHz" << std::endl; + temp << "Desired center frequency for " << (wspr15 ? "WSPR-15" : "WSPR") << " transmission: " << center_freq_desired / 1e6 << " MHz" << std::endl; std::cout << temp.str(); // Wait for WSPR transmission window to arrive. - if (no_delay) { + if (no_delay) + { std::cout << " Transmitting immediately (not waiting for WSPR window)" << std::endl; - } else { + } + else + { std::cout << " Waiting for next WSPR transmission window..." << std::endl; wait_every((wspr15) ? 15 : 2); } // Update crystal calibration information - if (self_cal) { + if (self_cal) + { update_ppm(ppm); } // Create the DMA table for this center frequency - std::vector dma_table_freq; + std::vector dma_table_freq; double center_freq_actual; - if (center_freq_desired) { - center_freq_actual=center_freq_desired; - - } else { - center_freq_actual=center_freq_desired; + if (center_freq_desired) + { + center_freq_actual = center_freq_desired; + } + else + { + center_freq_actual = center_freq_desired; } // Send the message! - //std::cout << "TX started!" << std::endl; - if (center_freq_actual){ + // std::cout << "TX started!" << std::endl; + if (center_freq_actual) + { // Print a status message right before transmission begins. struct timeval tvBegin, tvEnd, tvDiff; gettimeofday(&tvBegin, NULL); @@ -770,88 +887,86 @@ int main(const int argc, char * const argv[]) { struct timeval sym_start; struct timeval diff; - int bufPtr=0; - int Upsample=10000; - int SR=Upsample*1/wspr_symtime; - int FifoSize=40000; - bool usePWMSample=false; - static float *FreqPWM=NULL; - if(ngfmtest==NULL) - { - ngfmtest=new ngfmdmasync(center_freq_actual,SR,14,FifoSize,true); - FreqPWM=(float*)malloc(Upsample*sizeof(float)); - } - else - ngfmtest->enableclk(4); - double FreqResolution=ngfmtest->GetFrequencyResolution(); - - double RealFreq=ngfmtest->GetRealFrequency(0); - if(FreqResolution>tone_spacing) - { - fprintf(stderr,"Freq resolution=%f - Tone spacing =%f Erreur tuning=%f\n",FreqResolution,tone_spacing,RealFreq); - usePWMSample=true; - - } - + int bufPtr = 0; + int Upsample = 10000; + int SR = Upsample * 1 / wspr_symtime; + int FifoSize = 40000; + bool usePWMSample = false; + static float *FreqPWM = NULL; + + //New modulator and tx on + ngfmtest = new ngfmdmasync(center_freq_actual, SR, 14, FifoSize, true); + FreqPWM = (float *)malloc(Upsample * sizeof(float)); + + double FreqResolution = ngfmtest->GetFrequencyResolution(); + + double RealFreq = ngfmtest->GetRealFrequency(0); + if (FreqResolution > tone_spacing) + { + fprintf(stderr, "Freq resolution=%f - Tone spacing =%f Erreur tuning=%f\n", FreqResolution, tone_spacing, RealFreq); + usePWMSample = true; + } + for (int i = 0; i < 162; i++) - { - double tone_freq=-1.5*tone_spacing+symbols[i]*tone_spacing-RealFreq; - int Nbtx=0; - int f1=0; - int Frac=ngfmtest->GetMasterFrac(0); - int IntFreq=floor(tone_freq/FreqResolution); - double ToneFreqInf=tone_freq-IntFreq; - int Step=ToneFreqInf*Upsample/FreqResolution; - - if(!usePWMSample) - { - for(int j=0;jSetFrequencySamples(FreqPWM,Upsample); - - } + { + double tone_freq = -1.5 * tone_spacing + symbols[i] * tone_spacing - RealFreq; + int Nbtx = 0; + int f1 = 0; + int Frac = ngfmtest->GetMasterFrac(0); + int IntFreq = floor(tone_freq / FreqResolution); + double ToneFreqInf = tone_freq - IntFreq; + int Step = ToneFreqInf * Upsample / FreqResolution; + + if (!usePWMSample) + { + for (int j = 0; j < Upsample; j++) + { + FreqPWM[j] = tone_freq; + } + } + else + { + // Todo : Implement PWMFrequency to obtain better frequency resolution + for (int j = 0; j < Upsample; j++) + { + FreqPWM[j] = tone_freq; + } + } + ngfmtest->SetFrequencySamples(FreqPWM, Upsample); + } n_tx++; // Turn transmitter off ngfmtest->disableclk(4); - + delete ngfmtest; + ngfmtest = NULL; + free(FreqPWM); // End timestamp gettimeofday(&tvEnd, NULL); std::cout << " TX ended at: "; timeval_print(&tvEnd); timeval_subtract(&tvDiff, &tvEnd, &tvBegin); - printf(" (%ld.%03ld s)\n", tvDiff.tv_sec, (tvDiff.tv_usec+500)/1000); - - } else { + printf(" (%ld.%03ld s)\n", tvDiff.tv_sec, (tvDiff.tv_usec + 500) / 1000); + } + else + { std::cout << " Skipping transmission" << std::endl; usleep(1000000); } // Advance to next band - band=(band+1)%nbands; - if ((band==0)&&!repeat) { - break; - } - if ((terminate>0)&&(n_tx>=terminate)) { - + band = (band + 1) % nbands; + if ((band == 0) && !repeat) + { break; } + if ((terminate > 0) && (n_tx >= terminate)) + { + break; + } } } return 0; } -