# This is a combination of 2 commits.

# The first commit's message is:

Updated RDS transmitter: flags, PI and date/time

Merging baseband audio tone generators

Merging DTMF baseband with "tones" baseband

Added stealth transmit mode

App flash section bumped to 512k
RX and TX LEDs are now used
Play dead should work again, added login option
Morse frame gen. for letters and fox hunt codes
Merged EPAR with Xylos
Made EPAR use encoders for frame gen.
Moved OOK encoders data in encoders.hpp
Simplified about screen, ui_about_demo.* files are still there

BHT city DB, keywords removed

BHT cities DB, keywords removed

Update README.md

RDS radiotext and time group generators

# This is the 2nd commit message:

Update README.md
This commit is contained in:
furrtek
2016-12-09 18:21:47 +01:00
parent 0b13283d5d
commit 6bcb7dc1b1
91 changed files with 3867 additions and 2535 deletions

View File

@@ -375,19 +375,12 @@ DeclareTargets(PAFS afsk)
#)
#DeclareTargets(PEPR epar)
### Xylos
### Tones
set(MODE_CPPSRC
proc_xylos.cpp
proc_tones.cpp
)
DeclareTargets(PXYL xylos)
### DTMF TX
set(MODE_CPPSRC
proc_dtmf_tx.cpp
)
DeclareTargets(PDTX dtmf_tx)
DeclareTargets(PTON tones)
### RDS

View File

@@ -31,6 +31,12 @@
#include <cstddef>
#include <array>
void AudioOutput::configure(
const bool do_proc
) {
do_processing = do_proc;
}
void AudioOutput::configure(
const iir_biquad_config_t& hpf_config,
const iir_biquad_config_t& deemph_config,
@@ -69,20 +75,25 @@ void AudioOutput::write(
void AudioOutput::on_block(
const buffer_f32_t& audio
) {
const auto audio_present_now = squelch.execute(audio);
hpf.execute_in_place(audio);
deemph.execute_in_place(audio);
audio_present_history = (audio_present_history << 1) | (audio_present_now ? 1 : 0);
const bool audio_present = (audio_present_history != 0);
bool audio_present;
if( !audio_present ) {
for(size_t i=0; i<audio.count; i++) {
audio.p[i] = 0;
}
}
if (do_processing) {
const auto audio_present_now = squelch.execute(audio);
hpf.execute_in_place(audio);
deemph.execute_in_place(audio);
audio_present_history = (audio_present_history << 1) | (audio_present_now ? 1 : 0);
audio_present = (audio_present_history != 0);
if( !audio_present ) {
for(size_t i=0; i<audio.count; i++) {
audio.p[i] = 0;
}
}
} else
audio_present = true;
fill_audio_buffer(audio, audio_present);
}

View File

@@ -36,6 +36,10 @@
class AudioOutput {
public:
void configure(
const bool do_proc
);
void configure(
const iir_biquad_config_t& hpf_config,
const iir_biquad_config_t& deemph_config = iir_config_passthrough,
@@ -64,6 +68,8 @@ private:
AudioStatsCollector audio_stats;
uint64_t audio_present_history = 0;
bool do_processing = true;
void on_block(const buffer_f32_t& audio);
void fill_audio_buffer(const buffer_f32_t& audio, const bool send_to_fifo);

Binary file not shown.

Binary file not shown.

View File

@@ -50,7 +50,7 @@ void ADSBTXProcessor::execute(const buffer_c8_t& buffer) {
if (!bit_part) {
if (bit_pos >= 112) {
// Stop
message.n = 200;
message.progress = 200;
shared_memory.application_queue.push(message);
configured = false;
cur_bit = 0;

View File

@@ -41,8 +41,8 @@ void AFSKProcessor::execute(const buffer_c8_t& buffer) {
if (sample_count >= afsk_samples_per_bit) {
if (configured) {
cur_byte = shared_memory.tx_data[byte_pos];
ext_byte = shared_memory.tx_data[byte_pos + 1];
cur_byte = shared_memory.bb_data.data[byte_pos];
ext_byte = shared_memory.bb_data.data[byte_pos + 1];
if (!(cur_byte | ext_byte)) {
// End of data
@@ -50,16 +50,16 @@ void AFSKProcessor::execute(const buffer_c8_t& buffer) {
// Repeat
bit_pos = 0;
byte_pos = 0;
cur_byte = shared_memory.tx_data[0];
ext_byte = shared_memory.tx_data[1];
message.n = repeat_counter + 1;
cur_byte = shared_memory.bb_data.data[0];
ext_byte = shared_memory.bb_data.data[1];
message.progress = repeat_counter + 1;
shared_memory.application_queue.push(message);
repeat_counter++;
} else {
// Stop
cur_byte = 0;
ext_byte = 0;
message.n = 0;
message.progress = 0;
shared_memory.application_queue.push(message);
configured = false;
}

View File

@@ -48,15 +48,15 @@ void DTMFTXProcessor::execute(const buffer_c8_t& buffer) {
tone = true;
timer = tone_length;
tone_code = shared_memory.tx_data[tone_idx];
tone_code = shared_memory.bb_data.data[tone_idx];
if (tone_code == 0xFF) {
txdone_message.n = 0xFF; // End of list
txdone_message.done = true; // End of list
shared_memory.application_queue.push(txdone_message);
configured = false;
tone = false;
} else {
txdone_message.n = tone_idx; // New tone (progress)
txdone_message.progress = tone_idx; // New tone
shared_memory.application_queue.push(txdone_message);
tone_idx++;
}
@@ -99,7 +99,7 @@ void DTMFTXProcessor::on_message(const Message* const msg) {
if (message.id == Message::ID::DTMFTXConfig) {
// Translate DTMF message to index in DTMF frequencies table
tone_ptr = &shared_memory.tx_data[0];
tone_ptr = &shared_memory.bb_data.data[0];
for (;;) {
tone_code = *tone_ptr;
if (tone_code == 0xFF)
@@ -132,6 +132,8 @@ void DTMFTXProcessor::on_message(const Message* const msg) {
tone_length = message.tone_length * 154; // 153.6
pause_length = message.pause_length * 154; // 153.6
as = 0;
txdone_message.progress = 0;
txdone_message.done = false;
tone = false;
timer = 0;
tone_idx = 0;

View File

@@ -87,7 +87,7 @@ void JammerProcessor::execute(const buffer_c8_t& buffer) {
void JammerProcessor::on_message(const Message* const msg) {
jammer_ranges = (JammerRange*)shared_memory.tx_data;
jammer_ranges = (JammerRange*)shared_memory.bb_data.data;
/*const auto message = *reinterpret_cast<const DTMFTXConfigMessage*>(msg);

View File

@@ -49,15 +49,15 @@ void OOKProcessor::execute(const buffer_c8_t& buffer) {
if (repeat_counter < repeat) {
// Repeat
bit_pos = 0;
cur_bit = shared_memory.tx_data[0] & 0x80;
message.n = repeat_counter + 1;
shared_memory.application_queue.push(message);
cur_bit = shared_memory.bb_data.data[0] & 0x80;
txdone_message.progress = repeat_counter + 1;
shared_memory.application_queue.push(txdone_message);
repeat_counter++;
} else {
// Stop
cur_bit = 0;
message.n = 0;
shared_memory.application_queue.push(message);
txdone_message.done = true;
shared_memory.application_queue.push(txdone_message);
configured = false;
}
pause_counter = 0;
@@ -65,7 +65,7 @@ void OOKProcessor::execute(const buffer_c8_t& buffer) {
pause_counter--;
}
} else {
cur_bit = (shared_memory.tx_data[bit_pos >> 3] << (bit_pos & 7)) & 0x80;
cur_bit = (shared_memory.bb_data.data[bit_pos >> 3] << (bit_pos & 7)) & 0x80;
bit_pos++;
}
}
@@ -108,6 +108,8 @@ void OOKProcessor::on_message(const Message* const p) {
repeat_counter = 0;
bit_pos = 0;
cur_bit = 0;
txdone_message.progress = 0;
txdone_message.done = false;
configured = true;
}
}

View File

@@ -52,7 +52,7 @@ private:
uint32_t tone_phase, phase, sphase;
int32_t tone_sample, sig, frq;
TXDoneMessage message;
TXDoneMessage txdone_message;
};
#endif

View File

@@ -98,7 +98,7 @@ void RDSProcessor::execute(const buffer_c8_t& buffer) {
void RDSProcessor::on_message(const Message* const msg) {
if (msg->id == Message::ID::RDSConfigure) {
const auto message = *reinterpret_cast<const RDSConfigureMessage*>(msg);
rdsdata = (uint32_t*)shared_memory.tx_data;
rdsdata = (uint32_t*)shared_memory.bb_data.data;
message_length = message.length;
configured = true;
}

View File

@@ -0,0 +1,152 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2016 Furrtek
*
* This file is part of PortaPack.
*
* 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, 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; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "proc_tones.hpp"
#include "sine_table_int8.hpp"
#include "event_m4.hpp"
#include <cstdint>
// This is called at 1536000/2048 = 750Hz
void TonesProcessor::execute(const buffer_c8_t& buffer) {
if (!configured) return;
ai = 0;
for (size_t i = 0; i < buffer.count; i++) {
// Tone generation at full samplerate
if (silence_count) {
// Just occupy channel with carrier
silence_count--;
if (!silence_count) {
sample_count = 0;
tone_a_phase = 0;
tone_b_phase = 0;
}
tone_sample = 0;
re = 0;
im = 0;
} else {
if (!sample_count) {
digit = shared_memory.bb_data.tones_data.message[digit_pos++];
if (digit_pos >= message_length) {
configured = false;
txdone_message.done = true;
shared_memory.application_queue.push(txdone_message);
} else {
txdone_message.progress = digit_pos; // Inform UI about progress
shared_memory.application_queue.push(txdone_message);
}
if ((digit >= 32) || (tone_deltas[digit] == 0)) {
silence_count = shared_memory.bb_data.tones_data.silence;
} else {
if (!dual_tone) {
tone_a_delta = tone_deltas[digit];
} else {
tone_a_delta = tone_deltas[digit << 1];
tone_b_delta = tone_deltas[(digit << 1) + 1];
}
sample_count = tone_durations[digit];
}
} else {
sample_count--;
}
// Ugly
if (digit >= 32) {
tone_sample = 0;
re = 0;
im = 0;
} else {
if (!dual_tone) {
tone_sample = (sine_table_i8[(tone_a_phase & 0x03FC0000) >> 18]);
tone_a_phase += tone_a_delta;
} else {
tone_sample = sine_table_i8[(tone_a_phase & 0x03FC0000) >> 18] >> 1;
tone_sample += sine_table_i8[(tone_b_phase & 0x03FC0000) >> 18] >> 1;
tone_a_phase += tone_a_delta;
tone_b_phase += tone_b_delta;
}
// FM
delta = tone_sample * fm_delta;
phase += delta;
sphase = phase + (64 << 18);
re = (sine_table_i8[(sphase & 0x03FC0000) >> 18]);
im = (sine_table_i8[(phase & 0x03FC0000) >> 18]);
}
}
// Headphone output sample generation: 1536000/24000 = 64
if (audio_out) {
if (!as) {
as = 64; // 63 ?
audio_buffer.p[ai++] = tone_sample * 128;
} else {
as--;
}
}
buffer.p[i] = {(int8_t)re, (int8_t)im};
}
if (audio_out) audio_output.write(audio_buffer);
}
void TonesProcessor::on_message(const Message* const p) {
const auto message = *reinterpret_cast<const TonesConfigureMessage*>(p);
if (message.id == Message::ID::TonesConfigure) {
silence_count = message.pre_silence; // In samples
for (uint8_t c = 0; c < 32; c++) {
tone_deltas[c] = shared_memory.bb_data.tones_data.tone_defs[c].delta;
tone_durations[c] = shared_memory.bb_data.tones_data.tone_defs[c].duration;
}
message_length = message.tone_count;
fm_delta = message.fm_delta;
audio_out = message.audio_out;
dual_tone = message.dual_tone;
if (audio_out) audio_output.configure(false);
txdone_message.done = false;
txdone_message.progress = 0;
digit_pos = 0;
tone_a_phase = 0;
tone_b_phase = 0;
as = 0;
configured = true;
}
}
int main() {
EventDispatcher event_dispatcher { std::make_unique<TonesProcessor>() };
event_dispatcher.run();
return 0;
}

View File

@@ -20,18 +20,15 @@
* Boston, MA 02110-1301, USA.
*/
#ifndef __PROC_XYLOS_H__
#define __PROC_XYLOS_H__
#ifndef __PROC_TONES_H__
#define __PROC_TONES_H__
#include "portapack_shared_memory.hpp"
#include "baseband_processor.hpp"
#include "baseband_thread.hpp"
#include "audio_output.hpp"
//#include "audio_output.hpp"
#define CCIR_PHASEINC (436.91/2) // (65536*1024)/1536000*10
#define CCIR_SILENCE (122880)-1 // 400ms
class XylosProcessor : public BasebandProcessor {
class TonesProcessor : public BasebandProcessor {
public:
void execute(const buffer_c8_t& buffer) override;
@@ -42,37 +39,31 @@ private:
BasebandThread baseband_thread { 1536000, this, NORMALPRIO + 20, baseband::Direction::Transmit };
const uint32_t ccir_phases[16] = {
(uint32_t)(1981*CCIR_PHASEINC),
(uint32_t)(1124*CCIR_PHASEINC),
(uint32_t)(1197*CCIR_PHASEINC),
(uint32_t)(1275*CCIR_PHASEINC),
(uint32_t)(1358*CCIR_PHASEINC),
(uint32_t)(1446*CCIR_PHASEINC),
(uint32_t)(1540*CCIR_PHASEINC),
(uint32_t)(1640*CCIR_PHASEINC),
(uint32_t)(1747*CCIR_PHASEINC),
(uint32_t)(1860*CCIR_PHASEINC),
(uint32_t)(2400*CCIR_PHASEINC),
(uint32_t)(930*CCIR_PHASEINC),
(uint32_t)(2247*CCIR_PHASEINC),
(uint32_t)(991*CCIR_PHASEINC),
(uint32_t)(2110*CCIR_PHASEINC),
(uint32_t)(1055*CCIR_PHASEINC)
};
std::array<int16_t, 32> audio; // 2048/64
const buffer_s16_t audio_buffer {
(int16_t*)audio.data(),
sizeof(audio) / sizeof(int16_t)
};
uint32_t samples_per_tone;
int8_t re, im;
uint8_t s, as = 0, ai;
uint8_t byte_pos = 0;
uint8_t digit = 0;
uint32_t sample_count = 0;
uint32_t tone_phase, phase, sphase;
int32_t tone_sample, delta;
bool silence = true;
TXDoneMessage message;
uint32_t tone_deltas[32];
uint32_t tone_durations[32];
//AudioOutput audio_output;
bool audio_out;
bool dual_tone;
uint32_t fm_delta;
uint32_t tone_a_phase, tone_b_phase;
uint32_t tone_a_delta, tone_b_delta;
uint8_t digit_pos;
uint8_t digit;
uint32_t silence_count, sample_count;
uint32_t message_length;
uint32_t phase, sphase;
int32_t tone_sample, delta;
int8_t re, im;
uint8_t as, ai;
TXDoneMessage txdone_message;
AudioOutput audio_output;
};
#endif

View File

@@ -1,122 +0,0 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2016 Furrtek
*
* This file is part of PortaPack.
*
* 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, 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; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "proc_xylos.hpp"
#include "portapack_shared_memory.hpp"
#include "sine_table_int8.hpp"
#include "event_m4.hpp"
#include <cstdint>
void XylosProcessor::execute(const buffer_c8_t& buffer) {
// This is called at 1536000/2048 = 750Hz
if (!configured) return;
for (size_t i = 0; i<buffer.count; i++) {
// Tone generation at 1536000/5 = 307.2kHz
if (s >= (5 - 1)) {
s = 0;
if (silence) {
// Just occupy channel with carrier
if (sample_count >= CCIR_SILENCE) {
silence = false;
sample_count = samples_per_tone;
} else {
sample_count++;
}
} else {
if (sample_count >= samples_per_tone) {
digit = shared_memory.tx_data[byte_pos++];
if ((digit == 0xFF) || (byte_pos >= 21)) {
configured = false;
message.n = 25; // End of message code
shared_memory.application_queue.push(message);
} else {
message.n = byte_pos; // Inform UI about progress (just as eye candy)
shared_memory.application_queue.push(message);
}
sample_count = 0;
} else {
sample_count++;
}
tone_phase += ccir_phases[digit];
}
} else {
s++;
}
if (silence) {
re = 0;
im = 0;
} else {
tone_sample = (sine_table_i8[(tone_phase & 0x03FC0000) >> 18]);
// Audio preview sample generation: 1536000/48000 = 32
/*if (as >= 31) {
as = 0;
audio[ai++] = sample * 128;
} else {
as++;
}*/
// FM
// 1<<18 = 262144
// m = (262144 * BW) / 1536000 / 2
delta = tone_sample * 853; // 10kHz BW
phase += delta;
sphase = phase + (64 << 18);
re = (sine_table_i8[(sphase & 0x03FC0000) >> 18]);
im = (sine_table_i8[(phase & 0x03FC0000) >> 18]);
}
buffer.p[i] = {(int8_t)re, (int8_t)im};
}
//audio_output.write(audio_buffer);
}
void XylosProcessor::on_message(const Message* const p) {
const auto message = *reinterpret_cast<const CCIRConfigureMessage*>(p);
if (message.id == Message::ID::CCIRConfigure) {
byte_pos = 0;
digit = 0;
samples_per_tone = message.samples_per_tone;
sample_count = samples_per_tone;
as = 0;
silence = true;
configured = true;
}
}
int main() {
EventDispatcher event_dispatcher { std::make_unique<XylosProcessor>() };
event_dispatcher.run();
return 0;
}