kopia lustrzana https://github.com/JamesP6000/PiCW
Mostly compiling :)
rodzic
cf110cb7f0
commit
6035b10e12
116
PiCW.cpp
116
PiCW.cpp
|
@ -18,6 +18,14 @@ License:
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <deque>
|
||||||
|
#include <thread>
|
||||||
|
#include <mutex>
|
||||||
|
#include <condition_variable>
|
||||||
|
#include <chrono>
|
||||||
|
#include <random>
|
||||||
|
#include <atomic>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
@ -196,7 +204,7 @@ void txSym(
|
||||||
std::atomic <bool> & terminate,
|
std::atomic <bool> & terminate,
|
||||||
const double & tone_freq,
|
const double & tone_freq,
|
||||||
const double & tsym,
|
const double & tsym,
|
||||||
const vector <double> & dma_table_freq,
|
const std::vector <double> & dma_table_freq,
|
||||||
const double & f_pwm_clk,
|
const double & f_pwm_clk,
|
||||||
struct PageInfo instrs[],
|
struct PageInfo instrs[],
|
||||||
struct PageInfo & constPage,
|
struct PageInfo & constPage,
|
||||||
|
@ -282,7 +290,7 @@ double bit_trunc(
|
||||||
void setupDMATab(
|
void setupDMATab(
|
||||||
const double & tone_freq,
|
const double & tone_freq,
|
||||||
const double & plld_actual_freq,
|
const double & plld_actual_freq,
|
||||||
vector <double> & dma_table_freq,
|
std::vector <double> & dma_table_freq,
|
||||||
struct PageInfo & constPage
|
struct PageInfo & constPage
|
||||||
){
|
){
|
||||||
// Make sure that the tone can be produced solely by
|
// Make sure that the tone can be produced solely by
|
||||||
|
@ -305,7 +313,7 @@ void setupDMATab(
|
||||||
// while the clock generator is enabled. Check to see that it is also safe
|
// while the clock generator is enabled. Check to see that it is also safe
|
||||||
// to change the integer part. If it is not safe to change the integer part,
|
// to change the integer part. If it is not safe to change the integer part,
|
||||||
// then there will be some frequencies which are not synthesizeable.
|
// then there will be some frequencies which are not synthesizeable.
|
||||||
vector <long int> tuning_word(1024);
|
std::vector <long int> tuning_word(1024);
|
||||||
double div=bit_trunc(plld_actual_freq/tone_freq,-12)+pow(2.0,-12);
|
double div=bit_trunc(plld_actual_freq/tone_freq,-12)+pow(2.0,-12);
|
||||||
tuning_word[0]=((int)(div*pow(2.0,12)));
|
tuning_word[0]=((int)(div*pow(2.0,12)));
|
||||||
div-=pow(2.0,-12);
|
div-=pow(2.0,-12);
|
||||||
|
@ -693,7 +701,7 @@ void parse_commandline(
|
||||||
ABORT(-1);
|
ABORT(-1);
|
||||||
break;
|
break;
|
||||||
case 'f':
|
case 'f':
|
||||||
freq=strtod(optarg,&endp);
|
tone_freq=strtod(optarg,&endp);
|
||||||
if ((optarg==endp)||(*endp!='\0')) {
|
if ((optarg==endp)||(*endp!='\0')) {
|
||||||
std::cerr << "Error: could not parse frequency" << std::endl;
|
std::cerr << "Error: could not parse frequency" << std::endl;
|
||||||
ABORT(-1);
|
ABORT(-1);
|
||||||
|
@ -726,7 +734,6 @@ void parse_commandline(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse the non-option parameters
|
// Parse the non-option parameters
|
||||||
unsigned int n_free_args=0;
|
|
||||||
while (optind<argc) {
|
while (optind<argc) {
|
||||||
if (!str.empty()) {
|
if (!str.empty()) {
|
||||||
str+=" ";
|
str+=" ";
|
||||||
|
@ -743,8 +750,8 @@ void parse_commandline(
|
||||||
// Print a summary of the parsed options
|
// Print a summary of the parsed options
|
||||||
std::cout << "PiCW parsed command line options:" << std::endl;
|
std::cout << "PiCW parsed command line options:" << std::endl;
|
||||||
std::stringstream temp;
|
std::stringstream temp;
|
||||||
temp << setprecision(6) << fixed;
|
temp << std::setprecision(6) << std::fixed;
|
||||||
temp << freq/1e6 << " MHz";
|
temp << tone_freq/1e6 << " MHz";
|
||||||
std::cout << " TX frequency: " << temp.str() << std::endl;
|
std::cout << " TX frequency: " << temp.str() << std::endl;
|
||||||
temp.str("");
|
temp.str("");
|
||||||
std::cout << " WPM: " << wpm << std::endl;
|
std::cout << " WPM: " << wpm << std::endl;
|
||||||
|
@ -827,7 +834,7 @@ void tone_main(
|
||||||
}
|
}
|
||||||
double ppm_old=ppm;
|
double ppm_old=ppm;
|
||||||
double freq_old=freq;
|
double freq_old=freq;
|
||||||
vector <double> & dma_table_freq,
|
std::vector <double> dma_table_freq;
|
||||||
setupDMATab(freq_old,F_PLLD_CLK*(1-ppm_old/1e6),dma_table_freq,constPage);
|
setupDMATab(freq_old,F_PLLD_CLK*(1-ppm_old/1e6),dma_table_freq,constPage);
|
||||||
int bufPtr=0;
|
int bufPtr=0;
|
||||||
|
|
||||||
|
@ -866,7 +873,7 @@ void tone_main(
|
||||||
|
|
||||||
class time_value {
|
class time_value {
|
||||||
public:
|
public:
|
||||||
double time;
|
std::chrono::duration <double> time;
|
||||||
unsigned int value;
|
unsigned int value;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -900,7 +907,7 @@ void raised_cosine(
|
||||||
{
|
{
|
||||||
time_value rec;
|
time_value rec;
|
||||||
rec.value=0;
|
rec.value=0;
|
||||||
rec.time=0;
|
rec.time=std::chrono::duration <double> (0);
|
||||||
rise.push_back(rec);
|
rise.push_back(rec);
|
||||||
rec.value=8;
|
rec.value=8;
|
||||||
fall.push_back(rec);
|
fall.push_back(rec);
|
||||||
|
@ -908,19 +915,19 @@ void raised_cosine(
|
||||||
for (double y=0.5/8.0;y<1;y+=1.0/8.0) {
|
for (double y=0.5/8.0;y<1;y+=1.0/8.0) {
|
||||||
time_value rec;
|
time_value rec;
|
||||||
rec.value=round(y*8.0+0.5);
|
rec.value=round(y*8.0+0.5);
|
||||||
rec.time=acos(1-2*y)/M_PI*width_secs;
|
rec.time=std::chrono::duration <double> (acos(1-2*y)/M_PI*width_secs);
|
||||||
rise.push_back(rec);
|
rise.push_back(rec);
|
||||||
}
|
}
|
||||||
for (double y=7.5/8.0;y>0;y-=1.0/8.0) {
|
for (double y=7.5/8.0;y>0;y-=1.0/8.0) {
|
||||||
time_value rec;
|
time_value rec;
|
||||||
rec.value=round(y*8.0-0.5);
|
rec.value=round(y*8.0-0.5);
|
||||||
rec.time=acos(2*y-1)/M_PI*width_secs;
|
rec.time=std::chrono::duration <double> (acos(2*y-1)/M_PI*width_secs);
|
||||||
fall.push_back(rec);
|
fall.push_back(rec);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
time_value rec;
|
time_value rec;
|
||||||
rec.value=8;
|
rec.value=8;
|
||||||
rec.time=width_secs;
|
rec.time=std::chrono::duration <double> (width_secs);
|
||||||
rise.push_back(rec);
|
rise.push_back(rec);
|
||||||
rec.value=0;
|
rec.value=0;
|
||||||
fall.push_back(rec);
|
fall.push_back(rec);
|
||||||
|
@ -935,10 +942,12 @@ void set_current(
|
||||||
value=8;
|
value=8;
|
||||||
}
|
}
|
||||||
if (value==0) {
|
if (value==0) {
|
||||||
|
MARK;
|
||||||
struct GPCTL setupword = {6/*SRC*/, 0, 0, 0, 0, 1,0x5a};
|
struct GPCTL setupword = {6/*SRC*/, 0, 0, 0, 0, 1,0x5a};
|
||||||
ACCESS(CM_GP0CTL) = *((int*)&setupword);
|
ACCESS(CM_GP0CTL) = *((int*)&setupword);
|
||||||
} else {
|
} else {
|
||||||
ACCESS(PADS_GPIO_0_27) = 0x5a000018 + value - 1;
|
ACCESS(PADS_GPIO_0_27) = 0x5a000018 + ((value - 1)&0x7);
|
||||||
|
MARK;
|
||||||
struct GPCTL setupword = {6/*SRC*/, 1, 0, 0, 0, 3,0x5a};
|
struct GPCTL setupword = {6/*SRC*/, 1, 0, 0, 0, 3,0x5a};
|
||||||
ACCESS(CM_GP0CTL) = *((int*)&setupword);
|
ACCESS(CM_GP0CTL) = *((int*)&setupword);
|
||||||
}
|
}
|
||||||
|
@ -955,23 +964,23 @@ void send_dit_dah(
|
||||||
// of 1.0 will produce a dit that has a ramp going up, a ramp going down,
|
// of 1.0 will produce a dit that has a ramp going up, a ramp going down,
|
||||||
// and no flat portion.
|
// and no flat portion.
|
||||||
const double ramp_excess=0.3;
|
const double ramp_excess=0.3;
|
||||||
const double ramp_time=dot_duration_sec*ramp_excess;
|
const std::chrono::duration <double> ramp_time(dot_duration_sec*ramp_excess);
|
||||||
const flat_time=dot_duration_sec*(1-ramp_excess)+((sym=='-')?(2*dot_duration_sec):(0));
|
const std::chrono::duration <double> flat_time(dot_duration_sec*(1-ramp_excess)+((sym=='-')?(2*dot_duration_sec):(0)));
|
||||||
// Jitter adjusts the timing of the rising and falling ramp. This serves
|
// Jitter adjusts the timing of the rising and falling ramp. This serves
|
||||||
// to spread out the harmonics that are created.
|
// to spread out the harmonics that are created.
|
||||||
const double jitter_factor=0.1;
|
const double jitter_factor=0.1;
|
||||||
std::uniform_real_distribution<> dis(0,jitter_factor*dot_duration_sec);
|
std::uniform_real_distribution<> dis(0,jitter_factor*dot_duration_sec);
|
||||||
const double jitter_rise=dis(gen);
|
const std::chrono::duration <double> jitter_rise(dis(gen));
|
||||||
const double jitter_fall=dis(gen);
|
const std::chrono::duration <double> jitter_fall(dis(gen));
|
||||||
|
|
||||||
// Calculate the rise and fall ramps.
|
// Calculate the rise and fall ramps.
|
||||||
static bool initialized=false;
|
static bool initialized=false;
|
||||||
static double ramp_time_prev=0;
|
static std::chrono::duration <double> ramp_time_prev(0);
|
||||||
static std::vector <time_value> rise;
|
static std::vector <time_value> rise;
|
||||||
static std::vector <time_value> fall;
|
static std::vector <time_value> fall;
|
||||||
if ((!initialized)||(ramp_time_prev!=ramp_time)) {
|
if ((!initialized)||(ramp_time_prev!=ramp_time)) {
|
||||||
raised_cosine(
|
raised_cosine(
|
||||||
ramp_time,
|
ramp_time.count(),
|
||||||
rise,
|
rise,
|
||||||
fall
|
fall
|
||||||
);
|
);
|
||||||
|
@ -982,13 +991,14 @@ void send_dit_dah(
|
||||||
std::chrono::high_resolution_clock::time_point ref=std::chrono::high_resolution_clock::now();
|
std::chrono::high_resolution_clock::time_point ref=std::chrono::high_resolution_clock::now();
|
||||||
|
|
||||||
// Delay the rising ramp.
|
// Delay the rising ramp.
|
||||||
|
//std::chrono::duration <double> jitter_rise_duration(jitter_rise);
|
||||||
std::this_thread::sleep_until(ref+jitter_rise);
|
std::this_thread::sleep_until(ref+jitter_rise);
|
||||||
if (terminate) {
|
if (terminate) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Rising ramp.
|
// Rising ramp.
|
||||||
for (auto & tv:rise) {
|
for (auto & tv:rise) {
|
||||||
std::this_thread::sleep_until(ref+jitter_rise1+tv.time);
|
std::this_thread::sleep_until(ref+jitter_rise+tv.time);
|
||||||
if (terminate) {
|
if (terminate) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1017,12 +1027,12 @@ void am_main(
|
||||||
std::deque <char> & queue,
|
std::deque <char> & queue,
|
||||||
std::mutex & queue_mutex,
|
std::mutex & queue_mutex,
|
||||||
std::condition_variable & queue_signal,
|
std::condition_variable & queue_signal,
|
||||||
const std::map <char,std::string> & morse_table,
|
std::map <char,std::string> & morse_table,
|
||||||
std::atomic <double> & wpm
|
std::atomic <double> & wpm,
|
||||||
std::atomic <bool> & busy;
|
std::atomic <bool> & busy
|
||||||
) {
|
) {
|
||||||
bool prev_char_whitespace=true;
|
bool prev_char_whitespace=true;
|
||||||
std::chrono::high_resolution_clock::time_point earliest_tx_time=std::chrono::high_resolution_clock::now();
|
std::chrono::time_point <std::chrono::high_resolution_clock,std::chrono::duration <double>> earliest_tx_time=std::chrono::high_resolution_clock::now();
|
||||||
|
|
||||||
std::random_device rd;
|
std::random_device rd;
|
||||||
std::mt19937 gen(rd());
|
std::mt19937 gen(rd());
|
||||||
|
@ -1057,7 +1067,7 @@ void am_main(
|
||||||
// Ignore multiple whitespaces.
|
// Ignore multiple whitespaces.
|
||||||
continue;
|
continue;
|
||||||
} else {
|
} else {
|
||||||
earliest_tx_time+=std::chrono::nanoseconds(4*dot_duration*1e6);
|
earliest_tx_time=earliest_tx_time+std::chrono::duration <double> (4*dot_duration_sec);
|
||||||
prev_char_whitespace=true;
|
prev_char_whitespace=true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -1077,21 +1087,21 @@ void am_main(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send the dits and dahs
|
// Send the dits and dahs
|
||||||
const std::string tx_pattern=morse_table[tx_char];
|
std::string tx_pattern=morse_table[tx_char];
|
||||||
for (unsigned int t=0;t<tx_pattern.length();t++) {
|
for (unsigned int t=0;t<tx_pattern.length();t++) {
|
||||||
std::this_thread::sleep_until(earliest_tx_time);
|
std::this_thread::sleep_until(earliest_tx_time);
|
||||||
if (terminate) {
|
if (terminate) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const char sym=tx_pattern[t];
|
const char sym=tx_pattern[t];
|
||||||
send_dit_dah(sym,dot_duration_sec,gen);
|
send_dit_dah(terminate,sym,dot_duration_sec,gen);
|
||||||
if (sym=='.') {
|
if (sym=='.') {
|
||||||
earliest_tx_time+=std::chrono::nanoseconds(2*dot_duration*1e6);
|
earliest_tx_time+=std::chrono::duration <double> (2*dot_duration_sec);
|
||||||
} else {
|
} else {
|
||||||
earliest_tx_time+=std::chrono::nanoseconds(4*dot_duration*1e6);
|
earliest_tx_time+=std::chrono::duration <double> (4*dot_duration_sec);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
earliest_tx_time+=std::chrono::nanoseconds(3*dot_duration*1e6);
|
earliest_tx_time+=std::chrono::duration <double> (3*dot_duration_sec);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1140,7 +1150,7 @@ void morse_table_init(
|
||||||
morse_table[',']="−−..−−";
|
morse_table[',']="−−..−−";
|
||||||
morse_table[':']="−−−...";
|
morse_table[':']="−−−...";
|
||||||
morse_table['?']="..−−..";
|
morse_table['?']="..−−..";
|
||||||
morse_table[''']=".−−−−.";
|
morse_table['\'']=".−−−−.";
|
||||||
morse_table['-']="−....−";
|
morse_table['-']="−....−";
|
||||||
morse_table['/']="−..−.";
|
morse_table['/']="−..−.";
|
||||||
morse_table['(']="−.−−.";
|
morse_table['(']="−.−−.";
|
||||||
|
@ -1198,7 +1208,7 @@ int main(const int argc, char * const argv[]) {
|
||||||
txoff();
|
txoff();
|
||||||
|
|
||||||
// Morse code table.
|
// Morse code table.
|
||||||
std::map <char,std::string> & morse_table;
|
std::map <char,std::string> morse_table;
|
||||||
morse_table_init(morse_table);
|
morse_table_init(morse_table);
|
||||||
|
|
||||||
// Atomics used for IPC
|
// Atomics used for IPC
|
||||||
|
@ -1210,35 +1220,31 @@ int main(const int argc, char * const argv[]) {
|
||||||
// Start tone thread.
|
// Start tone thread.
|
||||||
std::atomic <bool> terminate_tone_thread;
|
std::atomic <bool> terminate_tone_thread;
|
||||||
terminate_tone_thread=false;
|
terminate_tone_thread=false;
|
||||||
std::thread tone_thread(
|
std::thread tone_thread(tone_main,
|
||||||
tone_main(
|
std::ref(terminate_tone_thread),
|
||||||
terminate_tone_thread,
|
std::ref(self_cal),
|
||||||
self_cal,
|
std::ref(ppm_init),
|
||||||
ppm_init,
|
std::ref(tone_freq),
|
||||||
tone_freq,
|
instrs,
|
||||||
instrs,
|
std::ref(constPage)
|
||||||
constPage
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// Start AM thread
|
// Start AM thread
|
||||||
std::atomic <bool> terminate_am_thread;
|
std::atomic <bool> terminate_am_thread;
|
||||||
terminate_am_thread=false;
|
terminate_am_thread=false;
|
||||||
std::deque <char> & queue;
|
std::deque <char> queue;
|
||||||
std::mutex & queue_mutex;
|
std::mutex queue_mutex;
|
||||||
std::condition_variable & queue_signal;
|
std::condition_variable queue_signal;
|
||||||
std::atomic <bool> am_thread_busy;
|
std::atomic <bool> am_thread_busy;
|
||||||
am_thread_busy=false;
|
am_thread_busy=false;
|
||||||
std::thread am_thread(
|
std::thread am_thread(am_main,
|
||||||
am_main(
|
std::ref(terminate_am_thread),
|
||||||
terminate_am_thread,
|
std::ref(queue),
|
||||||
queue,
|
std::ref(queue_mutex),
|
||||||
queue_mutex,
|
std::ref(queue_signal),
|
||||||
queue_signal,
|
std::ref(morse_table),
|
||||||
morse_table,
|
std::ref(wpm),
|
||||||
wpm,
|
std::ref(am_thread_busy)
|
||||||
am_thread_busy
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// Push text into AM thread
|
// Push text into AM thread
|
||||||
|
|
2
makefile
2
makefile
|
@ -3,7 +3,7 @@ prefix=/usr/local
|
||||||
all: PiCW
|
all: PiCW
|
||||||
|
|
||||||
PiCW: PiCW.cpp
|
PiCW: PiCW.cpp
|
||||||
g++ -std=c++11 -Wall -Werror -lm PiCW.cpp -oPiCW
|
g++-4.7 -std=c++11 -Wall -Werror -fmax-errors=5 -lm PiCW.cpp -oPiCW
|
||||||
|
|
||||||
#.PHONY: install
|
#.PHONY: install
|
||||||
#install: wspr
|
#install: wspr
|
||||||
|
|
Ładowanie…
Reference in New Issue