kopia lustrzana https://github.com/F5OEO/WsprryPi
Fix multi frequencies issue
rodzic
bc4a1e3f97
commit
58a6fc6375
427
wspr.cpp
427
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 <stdio.h>
|
||||
#include <string.h>
|
||||
|
@ -46,15 +47,17 @@
|
|||
#include <sys/timex.h>
|
||||
#include "librpitx/src/librpitx.h"
|
||||
|
||||
|
||||
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)
|
||||
|
@ -64,22 +67,22 @@ typedef enum {WSPR,TONE} mode_type;
|
|||
#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() {
|
||||
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();
|
||||
}
|
||||
|
||||
|
@ -98,13 +101,13 @@ void txSym(
|
|||
const double &f_pwm_clk,
|
||||
struct PageInfo instrs[],
|
||||
struct PageInfo &constPage,
|
||||
int & bufPtr
|
||||
) {
|
||||
|
||||
int &bufPtr)
|
||||
{
|
||||
}
|
||||
|
||||
// Turn off (reset) DMA engine
|
||||
void unSetupDMA(){
|
||||
void unSetupDMA()
|
||||
{
|
||||
|
||||
txoff();
|
||||
}
|
||||
|
@ -112,18 +115,17 @@ void unSetupDMA(){
|
|||
// Truncate at bit lsb. i.e. set all bits less than lsb to zero.
|
||||
double bit_trunc(
|
||||
const double &d,
|
||||
const int & lsb
|
||||
) {
|
||||
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++;
|
||||
}
|
||||
|
@ -134,8 +136,8 @@ void wspr(
|
|||
const char *call,
|
||||
const char *l_pre,
|
||||
const char *dbm,
|
||||
unsigned char* symbols
|
||||
) {
|
||||
unsigned char *symbols)
|
||||
{
|
||||
// pack prefix in nadd, call in n1, grid, dbm in n2
|
||||
char *c, buf[16];
|
||||
strncpy(buf, call, 16);
|
||||
|
@ -143,34 +145,49 @@ void wspr(
|
|||
to_upper(c);
|
||||
unsigned long ng, nadd = 0;
|
||||
|
||||
if(strchr(c, '/')){ //prefix-suffix
|
||||
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;
|
||||
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 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 = (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 (!nadd)
|
||||
{
|
||||
// Copy locator locally since it is declared const and we cannot modify
|
||||
// its contents in-place.
|
||||
char l[4];
|
||||
|
@ -180,7 +197,8 @@ void wspr(
|
|||
}
|
||||
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];
|
||||
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
|
||||
|
@ -195,22 +213,25 @@ void wspr(
|
|||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
};
|
||||
0};
|
||||
|
||||
// convolutional encoding K=32, r=1/2, Layland-Lushbaugh polynomials
|
||||
int k = 0;
|
||||
int j, s;
|
||||
int nstate = 0;
|
||||
unsigned char symbol[176];
|
||||
for(j=0;j!=sizeof(packed);j++){
|
||||
for(i=7;i>=0;i--){
|
||||
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
|
||||
for (s = 0; s != 2; s++)
|
||||
{ // convolve
|
||||
unsigned long n = nstate & poly[s];
|
||||
int even = 0; // even := parity(n)
|
||||
while(n){
|
||||
while (n)
|
||||
{
|
||||
even = 1 - even;
|
||||
n = n & (n - 1);
|
||||
}
|
||||
|
@ -228,11 +249,13 @@ void wspr(
|
|||
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++){
|
||||
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 (k = 0; p != i; k++)
|
||||
{
|
||||
for (j = 0; j != 8; j++) // j0:=bit_reverse(k)
|
||||
j0 = ((k >> j) & 1) | (j0 << 1);
|
||||
if (j0 < 162)
|
||||
|
@ -244,20 +267,23 @@ void wspr(
|
|||
|
||||
// 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(;;){
|
||||
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 <f2> <f3> ..." << std::endl;
|
||||
std::cout << " OR" << std::endl;
|
||||
|
@ -313,8 +339,8 @@ void parse_commandline(
|
|||
double &test_tone,
|
||||
bool &no_delay,
|
||||
mode_type &mode,
|
||||
int & terminate
|
||||
) {
|
||||
int &terminate)
|
||||
{
|
||||
// Default values
|
||||
ppm = 0;
|
||||
self_cal = true;
|
||||
|
@ -335,10 +361,10 @@ void parse_commandline(
|
|||
{"offset", no_argument, 0, 'o'},
|
||||
{"test-tone", required_argument, 0, 't'},
|
||||
{"no-delay", no_argument, 0, 'n'},
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
{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",
|
||||
|
@ -346,7 +372,8 @@ void parse_commandline(
|
|||
if (c == -1)
|
||||
break;
|
||||
|
||||
switch (c) {
|
||||
switch (c)
|
||||
{
|
||||
char *endp;
|
||||
case 0:
|
||||
// Code should only get here if a long option was given a non-null
|
||||
|
@ -360,7 +387,8 @@ void parse_commandline(
|
|||
break;
|
||||
case 'p':
|
||||
ppm = strtod(optarg, &endp);
|
||||
if ((optarg==endp)||(*endp!='\0')) {
|
||||
if ((optarg == endp) || (*endp != '\0'))
|
||||
{
|
||||
std::cerr << "Error: could not parse ppm value" << std::endl;
|
||||
ABORT(-1);
|
||||
}
|
||||
|
@ -376,11 +404,13 @@ void parse_commandline(
|
|||
break;
|
||||
case 'x':
|
||||
terminate = strtol(optarg, &endp, 10);
|
||||
if ((optarg==endp)||(*endp!='\0')) {
|
||||
if ((optarg == endp) || (*endp != '\0'))
|
||||
{
|
||||
std::cerr << "Error: could not parse termination argument" << std::endl;
|
||||
ABORT(-1);
|
||||
}
|
||||
if (terminate<1) {
|
||||
if (terminate < 1)
|
||||
{
|
||||
std::cerr << "Error: termination parameter must be >= 1" << std::endl;
|
||||
ABORT(-1);
|
||||
}
|
||||
|
@ -391,7 +421,8 @@ void parse_commandline(
|
|||
case 't':
|
||||
test_tone = strtod(optarg, &endp);
|
||||
mode = TONE;
|
||||
if ((optarg==endp)||(*endp!='\0')) {
|
||||
if ((optarg == endp) || (*endp != '\0'))
|
||||
{
|
||||
std::cerr << "Error: could not parse test tone frequency" << std::endl;
|
||||
ABORT(-1);
|
||||
}
|
||||
|
@ -405,24 +436,27 @@ void parse_commandline(
|
|||
default:
|
||||
ABORT(-1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Parse the non-option parameters
|
||||
unsigned int n_free_args = 0;
|
||||
while (optind<argc) {
|
||||
while (optind < argc)
|
||||
{
|
||||
// Check for callsign, locator, tx_power
|
||||
if (n_free_args==0) {
|
||||
if (n_free_args == 0)
|
||||
{
|
||||
callsign = argv[optind++];
|
||||
n_free_args++;
|
||||
continue;
|
||||
}
|
||||
if (n_free_args==1) {
|
||||
if (n_free_args == 1)
|
||||
{
|
||||
locator = argv[optind++];
|
||||
n_free_args++;
|
||||
continue;
|
||||
}
|
||||
if (n_free_args==2) {
|
||||
if (n_free_args == 2)
|
||||
{
|
||||
tx_power = argv[optind++];
|
||||
n_free_args++;
|
||||
continue;
|
||||
|
@ -430,49 +464,89 @@ void parse_commandline(
|
|||
// Must be a frequency
|
||||
// First see if it is a string.
|
||||
double parsed_freq;
|
||||
if (!strcasecmp(argv[optind],"LF")) {
|
||||
if (!strcasecmp(argv[optind], "LF"))
|
||||
{
|
||||
parsed_freq = 137500.0;
|
||||
} else if (!strcasecmp(argv[optind],"LF-15")) {
|
||||
}
|
||||
else if (!strcasecmp(argv[optind], "LF-15"))
|
||||
{
|
||||
parsed_freq = 137612.5;
|
||||
} else if (!strcasecmp(argv[optind],"MF")) {
|
||||
}
|
||||
else if (!strcasecmp(argv[optind], "MF"))
|
||||
{
|
||||
parsed_freq = 475700.0;
|
||||
} else if (!strcasecmp(argv[optind],"MF-15")) {
|
||||
}
|
||||
else if (!strcasecmp(argv[optind], "MF-15"))
|
||||
{
|
||||
parsed_freq = 475812.5;
|
||||
} else if (!strcasecmp(argv[optind],"160m")) {
|
||||
}
|
||||
else if (!strcasecmp(argv[optind], "160m"))
|
||||
{
|
||||
parsed_freq = 1838100.0;
|
||||
} else if (!strcasecmp(argv[optind],"160m-15")) {
|
||||
}
|
||||
else if (!strcasecmp(argv[optind], "160m-15"))
|
||||
{
|
||||
parsed_freq = 1838212.5;
|
||||
} else if (!strcasecmp(argv[optind],"80m")) {
|
||||
}
|
||||
else if (!strcasecmp(argv[optind], "80m"))
|
||||
{
|
||||
parsed_freq = 3594100.0;
|
||||
} else if (!strcasecmp(argv[optind],"60m")) {
|
||||
}
|
||||
else if (!strcasecmp(argv[optind], "60m"))
|
||||
{
|
||||
parsed_freq = 5288700.0;
|
||||
} else if (!strcasecmp(argv[optind],"40m")) {
|
||||
}
|
||||
else if (!strcasecmp(argv[optind], "40m"))
|
||||
{
|
||||
parsed_freq = 7040100.0;
|
||||
} else if (!strcasecmp(argv[optind],"30m")) {
|
||||
}
|
||||
else if (!strcasecmp(argv[optind], "30m"))
|
||||
{
|
||||
parsed_freq = 10140200.0;
|
||||
} else if (!strcasecmp(argv[optind],"20m")) {
|
||||
}
|
||||
else if (!strcasecmp(argv[optind], "20m"))
|
||||
{
|
||||
parsed_freq = 14097100.0;
|
||||
} else if (!strcasecmp(argv[optind],"17m")) {
|
||||
}
|
||||
else if (!strcasecmp(argv[optind], "17m"))
|
||||
{
|
||||
parsed_freq = 18106100.0;
|
||||
} else if (!strcasecmp(argv[optind],"15m")) {
|
||||
}
|
||||
else if (!strcasecmp(argv[optind], "15m"))
|
||||
{
|
||||
parsed_freq = 21096100.0;
|
||||
} else if (!strcasecmp(argv[optind],"12m")) {
|
||||
}
|
||||
else if (!strcasecmp(argv[optind], "12m"))
|
||||
{
|
||||
parsed_freq = 24926100.0;
|
||||
} else if (!strcasecmp(argv[optind],"10m")) {
|
||||
}
|
||||
else if (!strcasecmp(argv[optind], "10m"))
|
||||
{
|
||||
parsed_freq = 28126100.0;
|
||||
} else if (!strcasecmp(argv[optind],"6m")) {
|
||||
}
|
||||
else if (!strcasecmp(argv[optind], "6m"))
|
||||
{
|
||||
parsed_freq = 50294500.0;
|
||||
} else if (!strcasecmp(argv[optind],"4m")) {
|
||||
}
|
||||
else if (!strcasecmp(argv[optind], "4m"))
|
||||
{
|
||||
parsed_freq = 70092500.0;
|
||||
} else if (!strcasecmp(argv[optind],"2m")) {
|
||||
}
|
||||
else if (!strcasecmp(argv[optind], "2m"))
|
||||
{
|
||||
parsed_freq = 144490500.0;
|
||||
} else if (!strcasecmp(argv[optind],"70cm")) {
|
||||
}
|
||||
else if (!strcasecmp(argv[optind], "70cm"))
|
||||
{
|
||||
parsed_freq = 432300500.0;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
// Not a string. See if it can be parsed as a double.
|
||||
char *endp;
|
||||
parsed_freq = strtod(argv[optind], &endp);
|
||||
if ((optarg==endp)||(*endp!='\0')) {
|
||||
if ((optarg == endp) || (*endp != '\0'))
|
||||
{
|
||||
std::cerr << "Error: could not parse transmit frequency: " << argv[optind] << std::endl;
|
||||
ABORT(-1);
|
||||
}
|
||||
|
@ -486,21 +560,28 @@ void parse_commandline(
|
|||
transform(locator.begin(), locator.end(), locator.begin(), ::toupper);
|
||||
|
||||
// Check consistency among command line options.
|
||||
if (ppm&&self_cal) {
|
||||
if (ppm && self_cal)
|
||||
{
|
||||
std::cout << "Warning: ppm value is being ignored!" << std::endl;
|
||||
ppm = 0.0;
|
||||
}
|
||||
if (mode==TONE) {
|
||||
if ((callsign!="")||(locator!="")||(tx_power!="")||(center_freq_set.size()!=0)||random_offset) {
|
||||
if (mode == TONE)
|
||||
{
|
||||
if ((callsign != "") || (locator != "") || (tx_power != "") || (center_freq_set.size() != 0) || random_offset)
|
||||
{
|
||||
std::cerr << "Warning: callsign, locator, etc. are ignored when generating test tone" << std::endl;
|
||||
}
|
||||
random_offset = 0;
|
||||
if (test_tone<=0) {
|
||||
if (test_tone <= 0)
|
||||
{
|
||||
std::cerr << "Error: test tone frequency must be positive" << std::endl;
|
||||
ABORT(-1);
|
||||
}
|
||||
} else {
|
||||
if ((callsign=="")||(locator=="")||(tx_power=="")||(center_freq_set.size()==0)) {
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((callsign == "") || (locator == "") || (tx_power == "") || (center_freq_set.size() == 0))
|
||||
{
|
||||
std::cerr << "Error: must specify callsign, locator, dBm, and at least one frequency" << std::endl;
|
||||
std::cerr << "Try: wspr --help" << std::endl;
|
||||
ABORT(-1);
|
||||
|
@ -508,44 +589,59 @@ void parse_commandline(
|
|||
}
|
||||
|
||||
// Print a summary of the parsed options
|
||||
if (mode==WSPR) {
|
||||
if (mode == WSPR)
|
||||
{
|
||||
std::cout << "WSPR packet contents:" << std::endl;
|
||||
std::cout << " Callsign: " << callsign << std::endl;
|
||||
std::cout << " Locator: " << locator << std::endl;
|
||||
std::cout << " Power: " << tx_power << " dBm" << std::endl;
|
||||
std::cout << "Requested TX frequencies:" << std::endl;
|
||||
std::stringstream temp;
|
||||
for (unsigned int t=0;t<center_freq_set.size();t++) {
|
||||
for (unsigned int t = 0; t < center_freq_set.size(); t++)
|
||||
{
|
||||
temp << std::setprecision(6) << std::fixed;
|
||||
temp << " " << center_freq_set[t] / 1e6 << " MHz" << std::endl;
|
||||
}
|
||||
std::cout << temp.str();
|
||||
temp.str("");
|
||||
if (self_cal) {
|
||||
if (self_cal)
|
||||
{
|
||||
temp << " NTP will be used to periodically calibrate the transmission frequency" << std::endl;
|
||||
} else if (ppm) {
|
||||
}
|
||||
else if (ppm)
|
||||
{
|
||||
temp << " PPM value to be used for all transmissions: " << ppm << std::endl;
|
||||
}
|
||||
if (terminate>0) {
|
||||
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;
|
||||
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,16 +659,21 @@ void update_ppm(
|
|||
ntx.modes = 0; /* only read */
|
||||
status = ntp_adjtime(&ntx);
|
||||
|
||||
if (status != TIME_OK) {
|
||||
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) {
|
||||
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;
|
||||
|
@ -582,7 +683,8 @@ void update_ppm(
|
|||
/* 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) {
|
||||
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;
|
||||
|
@ -590,7 +692,8 @@ int timeval_subtract(struct timeval *result, struct timeval *t2, struct timeval
|
|||
return (diff < 0);
|
||||
}
|
||||
|
||||
void timeval_print(struct timeval *tv) {
|
||||
void timeval_print(struct timeval *tv)
|
||||
{
|
||||
char buffer[30];
|
||||
time_t curtime;
|
||||
|
||||
|
@ -601,25 +704,34 @@ void timeval_print(struct timeval *tv) {
|
|||
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[]) {
|
||||
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++) {
|
||||
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));
|
||||
|
||||
|
@ -660,14 +769,11 @@ int main(const int argc, char * const argv[]) {
|
|||
test_tone,
|
||||
no_delay,
|
||||
mode,
|
||||
terminate
|
||||
);
|
||||
terminate);
|
||||
int nbands = center_freq_set.size();
|
||||
|
||||
|
||||
|
||||
|
||||
if (mode==TONE) {
|
||||
if (mode == TONE)
|
||||
{
|
||||
if (clk == NULL)
|
||||
clk = new clkgpio;
|
||||
clk->SetAdvancedPllMode(true);
|
||||
|
@ -690,10 +796,12 @@ int main(const int argc, char * const argv[]) {
|
|||
clk->SetCenterFrequency(test_tone, 100);
|
||||
clk->enableclk(4);
|
||||
clk->SetFrequency(000);
|
||||
while(true) usleep(1000000);
|
||||
while (true)
|
||||
usleep(1000000);
|
||||
// Should never get here...
|
||||
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
// WSPR mode
|
||||
|
||||
// Create WSPR symbols
|
||||
|
@ -713,19 +821,21 @@ 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(;;) {
|
||||
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 > 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;
|
||||
|
||||
// Add random offset
|
||||
if ((center_freq_desired!=0)&&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);
|
||||
}
|
||||
|
||||
|
@ -736,31 +846,38 @@ int main(const int argc, char * const argv[]) {
|
|||
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<double> dma_table_freq;
|
||||
double center_freq_actual;
|
||||
if (center_freq_desired) {
|
||||
if (center_freq_desired)
|
||||
{
|
||||
center_freq_actual = center_freq_desired;
|
||||
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
center_freq_actual = center_freq_desired;
|
||||
}
|
||||
|
||||
// Send the message!
|
||||
// std::cout << "TX started!" << std::endl;
|
||||
if (center_freq_actual){
|
||||
if (center_freq_actual)
|
||||
{
|
||||
// Print a status message right before transmission begins.
|
||||
struct timeval tvBegin, tvEnd, tvDiff;
|
||||
gettimeofday(&tvBegin, NULL);
|
||||
|
@ -776,13 +893,11 @@ int main(const int argc, char * const argv[]) {
|
|||
int FifoSize = 40000;
|
||||
bool usePWMSample = false;
|
||||
static float *FreqPWM = NULL;
|
||||
if(ngfmtest==NULL)
|
||||
{
|
||||
|
||||
//New modulator and tx on
|
||||
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);
|
||||
|
@ -790,7 +905,6 @@ int main(const int argc, char * const argv[]) {
|
|||
{
|
||||
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++)
|
||||
|
@ -817,41 +931,42 @@ int main(const int argc, char * const argv[]) {
|
|||
{
|
||||
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 {
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << " Skipping transmission" << std::endl;
|
||||
usleep(1000000);
|
||||
}
|
||||
|
||||
// Advance to next band
|
||||
band = (band + 1) % nbands;
|
||||
if ((band==0)&&!repeat) {
|
||||
if ((band == 0) && !repeat)
|
||||
{
|
||||
break;
|
||||
}
|
||||
if ((terminate>0)&&(n_tx>=terminate)) {
|
||||
if ((terminate > 0) && (n_tx >= terminate))
|
||||
{
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
Ładowanie…
Reference in New Issue