diff --git a/wspr b/wspr deleted file mode 100755 index 1383d47..0000000 Binary files a/wspr and /dev/null differ diff --git a/wspr.c b/wspr.c deleted file mode 100644 index f094c1a..0000000 --- a/wspr.c +++ /dev/null @@ -1,689 +0,0 @@ -/* - - Raspberry Pi bareback LF/MF/HF/VHF WSPR transmitter - - Makes a very simple WSPR beacon from your RasberryPi by connecting GPIO - port to Antanna (and LPF), operates on LF, MF, HF and VHF bands from - 0 to 250 MHz. - -License: - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -Credits: - Credits goes to Oliver Mattos and Oskar Weigl who implemented PiFM [1] - based on the idea of exploiting RPi DPLL as FM transmitter. Dan MD1CLV - combined this effort with WSPR encoding algorithm from F8CHK, resulting - in WsprryPi a WSPR beacon for LF and MF bands. Guido PE1NNZ extended - this effort with DMA based PWM modulation of fractional divider that was - part of PiFM, allowing to operate the WSPR beacon also on HF and VHF bands. - In addition time-synchronisation and double amount of power output was - implemented. - - [1] PiFM code from http://www.icrobotics.co.uk/wiki/index.php/Turning_the_Raspberry_Pi_Into_an_FM_Transmitter - -To use: - In order to transmit legally, a HAM Radio License is REQUIRED for running - this experiment. The output is a square wave so a low pass filter is REQUIRED. - Connect a low-pass filter (via decoupling C) to GPIO4 (GPCLK0) and Ground pin - of your Raspberry Pi, connect an antenna to the LPF. The GPIO4 and GND pins - are found on header P1 pin 7 and 9 respectively, the pin closest to P1 label - is pin 1 and its 3rd and 4th neighbour is pin 7 and 9 respectively, see this - link for pin layout: http://elinux.org/RPi_Low-level_peripherals Examples of - low-pass filters can be found here: http://www.gqrp.com/harmonic_filters.pdf - The expected power output is 10mW (+10dBm) in a 50 Ohm load. This looks - neglible, but when connected to a simple dipole antenna this may result in - reception reports ranging up to several thousands of kilometers. - Example of low-pass filters here: http://www.gqrp.com/harmonic_filters.pdf - As the Raspberry Pi does not attenuate ripple and noise components from the - 5V USB power supply, it is RECOMMENDED to use a regulated supply that has - sufficient ripple supression. Supply ripple might be seen as mixing products - products centered around the transmit carrier typically at 100/120Hz. - - This software is using system time to determine the start of a WSPR - transmissions, so keep the system time synchronised within 1sec precision, - i.e. use NTP network time synchronisation or set time manually with date - command. A WSPR broadcast starts on even minute and takes 2 minutes for WSPR-2 - or starts at :00,:15,:30,:45 and takes 15 minutes for WSPR-15. It contains - a callsign, 4-digit Maidenhead square locator and transmission power. - Reception reports can be viewed on Weak Signal Propagation Reporter Network - at: http://wsprnet.org/drupal/wsprnet/spots - - Frequency calibration is REQUIRED to ensure that the WSPR-2 transmission occurs - within the 200 Hz narrow band. The reference crystal on your RPi might have - an frequency error (which in addition is temp. dependent -1.3Hz/degC @10MHz). - To calibrate, the frequency might be manually corrected on the command line - or by changing the F_XTAL value in the code. A practical way to calibrate - is to tune the transmitter on the same frequency of a medium wave AM broadcast - station; keep tuning until zero beat (the constant audio tone disappears when - the transmitter is exactly on the same frequency as the broadcast station), - and determine the frequency difference with the broadcast station. This is - the frequency error that can be applied for correction while tuning on a WSPR - frequency. - - DO NOT expose GPIO4 to voltages or currents that are above the specified - Absolute Maximum limits. GPIO4 outputs a digital clock in 3V3 logic, with a - maximum current of 16mA. As there is no current protection available and - a DC component of 1.6V, DO NOT short-circuit or place a resistive (dummy) load - straight on the GPIO4 pin, as it may draw too much current. Instead, use a - decoupling capacitor to remove DC component when connecting the output - dummy loads, transformers, antennas, etc. DO NOT expose GPIO4 to electro- - static voltages or voltages exceeding the 0 to 3.3V logic range; connecting an - antenna directly to GPIO4 may damage your RPi due to transient voltages such as - lightning or static buildup as well as RF from other transmitters operating into - nearby antennas. Therefore it is RECOMMENDED to add some form of isolation, e.g. - by using a RF transformer, a simple buffer/driver/PA stage, two schottky small - signal diodes back to back. - -Installation / update: - Open a terminal and execute the following commands: - sudo apt-get install git - rm -rf WsprryPi - git clone https://github.com/threeme3/WsprryPi.git - cd WsprryPi - -Usage: - sudo ./wspr <[prefix]/callsign[/suffix]> [ ...] - e.g.: sudo ./wspr PA/K1JT JO21 10 7040074 0 0 10140174 0 0 - where 0 frequency represents a interval for which TX is disabled, - wspr-2 or wspr-15 mode selection based on specified frequency. - - WSPR is used on the following frequencies (local restriction may apply): - LF 137400 - 137600 - 137600 - 137625 (WSPR-15) - MF 475600 - 475800 - 475800 - 475825 (WSPR-15) - 160m 1838000 - 1838200 - 1838200 - 1838225 (WSPR-15) - 80m 3594000 - 3594200 - 60m 5288600 - 5288800 - 40m 7040000 - 7040200 - 30m 10140100 - 10140300 - 20m 14097000 - 14097200 - 17m 18106000 - 18106200 - 15m 21096000 - 21096200 - 12m 24926000 - 24926200 - 10m 28126000 - 28126200 - 6m 50294400 - 50294600 - 4m 70092400 - 70092600 - 2m 144490400 -144490600 - -Compile: - sudo apt-get install gcc - gcc -lm wspr.c -owspr - -Reference documentation: - http://www.raspberrypi.org/wp-content/uploads/2012/02/BCM2835-ARM-Peripherals.pdf - http://www.scribd.com/doc/127599939/BCM2835-Audio-clocks - http://www.scribd.com/doc/101830961/GPIO-Pads-Control2 - https://github.com/mgottschlag/vctools/blob/master/vcdb/cm.yaml - https://www.kernel.org/doc/Documentation/vm/pagemap.txt - -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define F_XTAL (19229581.050215044276577479844352) // calibrated 19.2MHz XTAL frequency -#define F_PLLD_CLK (26.0 * F_XTAL) // 500MHz PLLD reference clock - -#define N_ITER 1400 // number of PWM operations per symbol; larger values gives less spurs at the cost of frequency resolution; e.g. use 22500 for HF usage up to 30MHz, 12000 up to 50MHz, 1600 for VHF usage up to 144 Mhz, F_PWM_CLK needs to be adjusted when changing N_ITER -//#define F_PWM_CLK (31500000.0) // 31.5MHz PWM clock use with N_ITER=22500 -#define F_PWM_CLK (33970588.235294117647058823529413) // 31.5MHz calibrated PWM clock use with N_ITER=1400 - -#define WSPR_SYMTIME (8192.0/12000.0) // symbol time - -#define POLYNOM_1 0xf2d05351 // polynoms for -#define POLYNOM_2 0xe4613c47 // parity generator - -/* RF code: */ - -#define BCM2708_PERI_BASE 0x20000000 -#define GPIO_BASE (BCM2708_PERI_BASE + 0x200000) /* GPIO controller */ -#define PAGE_SIZE (4*1024) -#define BLOCK_SIZE (4*1024) - -int mem_fd; -char *gpio_mem, *gpio_map; -char *spi0_mem, *spi0_map; - - -// I/O access -volatile unsigned *gpio = NULL; -volatile unsigned *allof7e = NULL; - -// GPIO setup macros. Always use INP_GPIO(x) before using OUT_GPIO(x) or SET_GPIO_ALT(x,y) -#define INP_GPIO(g) *(gpio+((g)/10)) &= ~(7<<(((g)%10)*3)) -#define OUT_GPIO(g) *(gpio+((g)/10)) |= (1<<(((g)%10)*3)) -#define SET_GPIO_ALT(g,a) *(gpio+(((g)/10))) |= (((a)<=3?(a)+4:(a)==4?3:2)<<(((g)%10)*3)) - -#define GPIO_SET *(gpio+7) // sets bits which are 1 ignores bits which are 0 -#define GPIO_CLR *(gpio+10) // clears bits which are 1 ignores bits which are 0 -#define GPIO_GET *(gpio+13) // sets bits which are 1 ignores bits which are 0 - -#define ACCESS(base) *(volatile int*)((int)allof7e+base-0x7e000000) -#define SETBIT(base, bit) ACCESS(base) |= 1<SOURCE_AD = (int)constPage.p + (i-1)*4; - - bufPtr++; - while( ACCESS(DMABASE + 0x04 /* CurBlock*/) == (int)(instrs[bufPtr].p)) usleep(100); - ((struct CB*)(instrs[bufPtr].v))->TXFR_LEN = clocksPerIter-fracval; - - bufPtr++; - while( ACCESS(DMABASE + 0x04 /* CurBlock*/) == (int)(instrs[bufPtr].p)) usleep(100); - ((struct CB*)(instrs[bufPtr].v))->SOURCE_AD = (int)constPage.p + (i+1)*4; - - bufPtr=(bufPtr+1) % (1024); - while( ACCESS(DMABASE + 0x04 /* CurBlock*/) == (int)(instrs[bufPtr].p)) usleep(100); - ((struct CB*)(instrs[bufPtr].v))->TXFR_LEN = fracval; - } -} - -void unSetupDMA(){ - printf("exiting\n"); - struct DMAregs* DMA0 = (struct DMAregs*)&(ACCESS(DMABASE)); - DMA0->CS =1<<31; // reset dma controller - txoff(); -} - -void handSig() { - exit(0); -} -void setupDMATab( float centerFreq, double symOffset, double tsym, int nsym ){ - // make data page contents - it's essientially 1024 different commands for the - // DMA controller to send to the clock module at the correct time. - int i; - for(i=1; i<1023; i+=3){ - double freq = centerFreq + ((double)(-511 + i))*symOffset/3.0; - double divisor = F_PLLD_CLK/freq; - unsigned long integer_part = (unsigned long) divisor; - unsigned long fractional_part = (divisor - integer_part) * (1 << 12); - unsigned long tuning_word = (0x5a << 24) + integer_part * (1 << 12) + fractional_part; - if(fractional_part == 0 || fractional_part == 1023){ - if((-511 + i) >= 0 && (-511 + i) <= (nsym * 3)) - printf("warning: symbol %u unusable because fractional divider is out of range, try near frequency.\n", i/3); - } - ((int*)(constPage.v))[i-1] = tuning_word - 1; - ((int*)(constPage.v))[i] = tuning_word; - ((int*)(constPage.v))[i+1] = tuning_word + 1; - double actual_freq = F_PLLD_CLK/((double)integer_part + (double)fractional_part/(double)(1<<12)); - double freq_corr = freq - actual_freq; - double delta = F_PLLD_CLK/((double)integer_part + (double)fractional_part/(double)(1<<12)) - F_PLLD_CLK/((double)integer_part + ((double)fractional_part+1.0)/(double)(1<<12)); - int clocksPerIter = (int)((F_PWM_CLK/((double)N_ITER)) * tsym); - double resolution = 2.0 * delta / ((double)clocksPerIter); - if(resolution > symOffset ){ - printf("warning: PWM/PLL fractional divider has not enough resolution: %fHz while %fHz is required, try lower frequency or decrease N_ITER in code to achieve more resolution.\n", resolution, symOffset); - exit(0); - } - fracs[i] = freq_corr/delta; - //printf("i=%u f=%f fa=%f corr=%f delta=%f percfrac=%f int=%u frac=%u tuning_word=%u resolution=%fmHz\n", i, freq, actual_freq, freq_corr, delta, fracs[i], integer_part, fractional_part, tuning_word, resolution *1000); - } -} - -void setupDMA(){ - atexit(unSetupDMA); - signal (SIGINT, handSig); - signal (SIGTERM, handSig); - signal (SIGHUP, handSig); - signal (SIGQUIT, handSig); - - // allocate a few pages of ram - getRealMemPage(&constPage.v, &constPage.p); - - int instrCnt = 0; - - while (instrCnt<1024) { - getRealMemPage(&instrPage.v, &instrPage.p); - - // make copy instructions - struct CB* instr0= (struct CB*)instrPage.v; - int i; - for (i=0; i<4096/sizeof(struct CB); i++) { - instrs[instrCnt].v = (void*)((int)instrPage.v + sizeof(struct CB)*i); - instrs[instrCnt].p = (void*)((int)instrPage.p + sizeof(struct CB)*i); - instr0->SOURCE_AD = (unsigned int)constPage.p+2048; - instr0->DEST_AD = PWMBASE+0x18 /* FIF1 */; - instr0->TXFR_LEN = 4; - instr0->STRIDE = 0; - //instr0->NEXTCONBK = (int)instrPage.p + sizeof(struct CB)*(i+1); - instr0->TI = (1/* DREQ */<<6) | (5 /* PWM */<<16) | (1<<26/* no wide*/) ; - instr0->RES1 = 0; - instr0->RES2 = 0; - - if (i%2) { - instr0->DEST_AD = CM_GP0DIV; - instr0->STRIDE = 4; - instr0->TI = (1<<26/* no wide*/) ; - } - - if (instrCnt!=0) ((struct CB*)(instrs[instrCnt-1].v))->NEXTCONBK = (int)instrs[instrCnt].p; - instr0++; - instrCnt++; - } - } - ((struct CB*)(instrs[1023].v))->NEXTCONBK = (int)instrs[0].p; - - // set up a clock for the PWM - ACCESS(CLKBASE + 40*4 /*PWMCLK_CNTL*/) = 0x5A000026; // Source=PLLD and disable - usleep(1000); -// ACCESS(CLKBASE + 41*4 /*PWMCLK_DIV*/) = 0x5A002800; - ACCESS(CLKBASE + 41*4 /*PWMCLK_DIV*/) = 0x5A002000; // set PWM div to 2, for 250MHz - ACCESS(CLKBASE + 40*4 /*PWMCLK_CNTL*/) = 0x5A000016; // Source=PLLD and enable - usleep(1000); - - // set up pwm - ACCESS(PWMBASE + 0x0 /* CTRL*/) = 0; - usleep(1000); - ACCESS(PWMBASE + 0x4 /* status*/) = -1; // clear errors - usleep(1000); - ACCESS(PWMBASE + 0x0 /* CTRL*/) = -1; //(1<<13 /* Use fifo */) | (1<<10 /* repeat */) | (1<<9 /* serializer */) | (1<<8 /* enable ch */) ; - usleep(1000); - ACCESS(PWMBASE + 0x8 /* DMAC*/) = (1<<31 /* DMA enable */) | 0x0707; - - //activate dma - struct DMAregs* DMA0 = (struct DMAregs*)&(ACCESS(DMABASE)); - DMA0->CS =1<<31; // reset - DMA0->CONBLK_AD=0; - DMA0->TI=0; - DMA0->CONBLK_AD = (unsigned int)(instrPage.p); - DMA0->CS =(1<<0)|(255 <<16); // enable bit = 0, clear end flag = 1, prio=19-16 -} - - -// -// Set up a memory regions to access GPIO -// -void setup_io() -{ - /* open /dev/mem */ - if ((mem_fd = open("/dev/mem", O_RDWR|O_SYNC) ) < 0) { - printf("can't open /dev/mem \n"); - exit (-1); - } - - /* mmap GPIO */ - - // Allocate MAP block - if ((gpio_mem = malloc(BLOCK_SIZE + (PAGE_SIZE-1))) == NULL) { - printf("allocation error \n"); - exit (-1); - } - - // Make sure pointer is on 4K boundary - if ((unsigned long)gpio_mem % PAGE_SIZE) - gpio_mem += PAGE_SIZE - ((unsigned long)gpio_mem % PAGE_SIZE); - - // Now map it - gpio_map = (unsigned char *)mmap( - gpio_mem, - BLOCK_SIZE, - PROT_READ|PROT_WRITE, - MAP_SHARED|MAP_FIXED, - mem_fd, - GPIO_BASE - ); - - if ((long)gpio_map < 0) { - printf("mmap error %d\n", (int)gpio_map); - exit (-1); - } - - // Always use volatile pointer! - gpio = (volatile unsigned *)gpio_map; - - -} - -void setup_gpios() -{ - int g; - // Switch GPIO 7..11 to output mode - - /************************************************************************\ - * You are about to change the GPIO settings of your computer. * - * Mess this up and it will stop working! * - * It might be a good idea to 'sync' before running this program * - * so at least you still have your code changes written to the SD-card! * - \************************************************************************/ - - // Set GPIO pins 7-11 to output - for (g=7; g<=11; g++) { - INP_GPIO(g); // must use INP_GPIO before we can use OUT_GPIO - //OUT_GPIO(g); - } - -} - -void strupr(char *str) -{ while(*str) - { - *str = toupper(*str); - str++; - } -} - -void wspr(char* call, char* l, char* dbm, unsigned char* symbols) -{ - // pack prefix in nadd, call in n1, grid, dbm in n2 - char* c, buf[16]; - strncpy(buf, call, 16); - c=buf; - strupr(c); - 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; - } - } - - 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'); - - //if(rand() % 2) nadd=0; - if(!nadd){ - strupr(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); - - // pack n1,n2,zero-tail into 50 bits - char packed[11] = {n1>>20, n1>>12, n1>>4, ((n1&0x0f)<<4)|((n2>>18)&0x0f), -n2>>10, n2>>2, (n2&0x03)<<6, 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--){ - 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 vector - } -} - -void wait_every(int minute) -{ - time_t t; - struct tm* ptm; - for(;;){ - time(&t); - ptm = gmtime(&t); - if((ptm->tm_min % minute) == 0 && ptm->tm_sec == 0) break; - usleep(1000); - } - usleep(1000000); // wait another second -} - -int main(int argc, char *argv[]) -{ - unsigned char symbols[162]; - int i; - double centre_freq; - int wspr15; - double wspr_symtime; - int nbands = argc - 4; - int band = 0; - - if(argc < 5){ - printf("Usage: wspr <[prefix/]callsign[/A-Z,/0-9,/00-99]> [ ...]\n"); - printf("\te.g.: sudo ./wspr K1JT/P JO21 10 7040074 0 0 10140174 0 0\n"); - printf("\tchoose freq in range +/-100 Hz around one of center frequencies: 137500, 475700, 1838100, 3594100, 5288700, 7040100, 10140200, 14097100, 18106100, 21096100, 24926100, 28126100, 50294500, 70092500, 144490500 Hz (WSPR-2), or in range +/-12 Hz around 137612, 475812, 1838212 Hz (WSPR-15).\n"); - return 1; - } - // argv[1]=callsign, argv[2]=locator, argv[3]=power(dBm) - wspr(argv[1], argv[2], argv[3], symbols); - printf("Symbols: "); - for (i = 0; i < sizeof(symbols)/sizeof(*symbols); i++) - printf("%d,", symbols[i]); - printf("\n"); - setup_io(); - setup_gpios(); - txon(); - setupDMA(); - printf("Ready for transmit...\n"); - - for(;;) - { - txoff(); - centre_freq = atof(argv[band + 4]); - wspr15 = (centre_freq > 137600 && centre_freq < 137625) || \ - (centre_freq > 475800 && centre_freq < 475825) || \ - (centre_freq > 1838200 && centre_freq < 1838225); - wspr_symtime = (wspr15) ? 8.0 * WSPR_SYMTIME : WSPR_SYMTIME; - band++; - if(band >= nbands) - band = 0; - if(centre_freq) setupDMATab(centre_freq, 1.0/wspr_symtime, wspr_symtime, 4); - wait_every((wspr15) ? 15 : 2); - time_t t; - time(&t); - char buf[256]; - strcpy(buf,ctime(&t)); - buf[strlen(buf)-1]='\0'; - printf("%s - %s@%f\n", buf, (wspr15)?"wspr-15":"wspr-2", centre_freq); - if(centre_freq){ - txon(); - for (i = 0; i < 162; i++) { - txSym(symbols[i], wspr_symtime); - //txSym(atoi(argv[5]), wspr_symtime); - } - } - } - return 0; -}