Morse TX foxhunt codes are working

This commit is contained in:
furrtek 2017-02-13 23:24:42 +00:00
parent 4e8980e5d8
commit 6c86ad1b72
8 changed files with 330 additions and 182 deletions

View File

@ -29,6 +29,7 @@
//TEST: Imperial in whipcalc
//TODO: Use transmittermodel bw setting
//TODO: Use Labels widget wherever possible
//TODO: Use TransmitterView in Morse, TEDI/LCR, Numbers, whistle, jammer...
//TODO: FreqMan: Add and rename categories

View File

@ -26,7 +26,7 @@
#include "portapack.hpp"
#define TONES_SAMPLERATE 1536000
#define TONES_DELTA_COEF ((1ULL << 32) / 1536000)
#define TONES_DELTA_COEF ((1ULL << 32) / TONES_SAMPLERATE)
#define TONES_F2D(f) (uint32_t)(f * TONES_DELTA_COEF)

View File

@ -32,19 +32,19 @@ Continuous (Fox-oring)
#include "portapack.hpp"
#include "baseband_api.hpp"
#include "portapack_persistent_memory.hpp"
#include <cstring>
#include <stdio.h>
using namespace portapack;
using namespace morse;
// TODO: Live keying mode: Dit on left key, dah on right ?
namespace ui {
void MorseView::focus() {
button_transmit.focus();
tx_view.focus();
}
MorseView::~MorseView() {
@ -56,48 +56,25 @@ void MorseView::paint(Painter& painter) {
(void)painter;
}
void MorseView::generate_message(char * text) {
char ch;
size_t i, c;
uint8_t code;
uint8_t morse_message[256];
bool MorseView::start_tx() {
size_t symbol_count;
std::string message;
ToneDef * tone_defs = shared_memory.bb_data.tones_data.tone_defs;
// TODO: OOB check on morse_message[]
i = 0;
while ((ch = (*text++))) {
if ((ch >= 'a') && (ch <= 'z')) // Make uppercase
ch -= 32;
if ((ch >= 'A') && (ch <= 'Z')) {
code = morse_ITU[ch - 'A' + 10];
for (c = 0; c < (code & 7); c++) {
morse_message[i++] = (code << c) >> 7; // Dot/dash
morse_message[i++] = 2; // Silence
}
morse_message[i - 1] = 3; // Letter silence
} else if (ch == ' ') {
morse_message[i++] = 4; // Word silence
}
if (checkbox_foxhunt.value()) {
message = foxhunt_codes[options_foxhunt.selected_index_value()];
} else {
message = "ABCDEFGHIJKLMN";
}
memcpy(shared_memory.bb_data.tones_data.message, morse_message, i);
symbol_count = morse_encode(message, field_time_unit.value(), field_tone.value());
(*tone_defs).delta = MORSE_TONE_DELTA; // Dot
(*tone_defs++).duration = MORSE_DOT;
(*tone_defs).delta = MORSE_TONE_DELTA; // Dash
(*tone_defs++).duration = MORSE_DASH;
(*tone_defs).delta = 0; // 1 unit silence
(*tone_defs++).duration = MORSE_SPACE;
(*tone_defs).delta = 0; // 3 unit silence
(*tone_defs++).duration = MORSE_LETTER_SPACE;
(*tone_defs).delta = 0; // 7 unit silence
(*tone_defs++).duration = MORSE_WORD_SPACE;
if (!symbol_count) {
nav_.display_modal("Error", "Message too long.", INFO, nullptr);
return false;
}
progressbar.set_max(symbol_count);
transmitter_model.set_tuning_frequency(81800000);
transmitter_model.set_sampling_rate(1536000U);
transmitter_model.set_rf_amp(true);
transmitter_model.set_lna(40);
@ -105,32 +82,54 @@ void MorseView::generate_message(char * text) {
transmitter_model.set_baseband_bandwidth(1750000);
transmitter_model.enable();
//audio::set_rate(audio::Rate::Hz_24000);
baseband::set_tones_data(5000, 0, i, false, false);
baseband::set_tones_data(transmitter_model.bandwidth(), 0, symbol_count, false, false);
return true;
}
void MorseView::transmit_done() {
transmitter_model.disable();
void MorseView::on_tx_progress(const int progress, const bool done) {
if (done) {
transmitter_model.disable();
progressbar.set_value(0);
tx_view.set_transmitting(false);
} else
progressbar.set_value(progress);
}
MorseView::MorseView(
NavigationView& nav
)
) : nav_ (nav)
{
baseband::run_image(portapack::spi_flash::image_tag_tones);
add_children({
&checkbox_foxhunt,
&options_foxhunt,
&button_transmit,
&button_exit
&text_time_unit,
&field_time_unit,
&text_tone,
&field_tone,
&progressbar,
&tx_view
});
button_transmit.on_select = [this](Button&){
//char strtest[] = "TEST";
//generate_message(strtest);
field_time_unit.set_value(50); // 50ms
field_tone.set_value(700); // 700Hz
tx_view.on_edit_frequency = [this, &nav]() {
auto new_view = nav.push<FrequencyKeypadView>(receiver_model.tuning_frequency());
new_view->on_changed = [this](rf::Frequency f) {
receiver_model.set_tuning_frequency(f);
};
};
button_exit.on_select = [&nav](Button&){
nav.pop();
tx_view.on_start = [this]() {
if (start_tx())
tx_view.set_transmitting(true);
};
tx_view.on_stop = [this]() {
tx_view.set_transmitting(false);
};
}

View File

@ -20,24 +20,21 @@
* Boston, MA 02110-1301, USA.
*/
#ifndef __MORSE_TX_H__
#define __MORSE_TX_H__
#include "ui.hpp"
#include "ui_widget.hpp"
#include "ui_navigation.hpp"
#include "ui_font_fixed_8x16.hpp"
#include "ui_transmitter.hpp"
#include "portapack.hpp"
#include "message.hpp"
#include "volume.hpp"
#include "audio.hpp"
#include "receiver_model.hpp"
#include "portapack.hpp"
#include "morse.hpp"
#define MORSE_TONE_DELTA ((1536000 / 800) - 1) // 1536000/800
#define MORSE_UNIT (76800 - 1) // 1536000*0.05 (50ms)
#define MORSE_DOT 1 * MORSE_UNIT
#define MORSE_DASH 3 * MORSE_UNIT
#define MORSE_SPACE 1 * MORSE_UNIT
#define MORSE_LETTER_SPACE 3 * MORSE_UNIT
#define MORSE_WORD_SPACE 7 * MORSE_UNIT
using namespace morse;
namespace ui {
@ -50,123 +47,42 @@ public:
void paint(Painter& painter) override;
private:
//rf::Frequency f;
NavigationView& nav_;
void generate_message(char * text);
void transmit_done();
bool start_tx();
void on_tx_progress(const int progress, const bool done);
const char foxhunt_codes[11][3] = {
{ 'M', 'O', 'E' }, // -----.
{ 'M', 'O', 'I' }, // -----..
{ 'M', 'O', 'S' }, // -----...
{ 'M', 'O', 'H' }, // -----....
{ 'M', 'O', '5' }, // -----.....
{ 'M', 'O', 'N' }, // ------.
{ 'M', 'O', 'D' }, // ------..
{ 'M', 'O', 'B' }, // ------...
{ 'M', 'O', '6' }, // ------....
{ 'M', 'O', 0 }, // -----
{ 'S', 0, 0 } // ...
Text text_time_unit {
{ 4 * 8, 6 * 8, 15 * 8, 16 },
"Time unit: ms"
};
NumberField field_time_unit {
{ 14 * 8, 6 * 8 },
3,
{ 1, 999 },
1,
' '
};
// 0=dot 1=dash
const uint8_t morse_ITU[36] = {
// Code Size
0b11111101, // 0: 11111 101
0b01111101, // 1: 01111 101
0b00111101, // 2: 00111 101
0b00011101, // 3: 00011 101
0b00001101, // 4: 00001 101
0b00000101, // 5: 00000 101
0b10000101, // 6: 10000 101
0b11000101, // 7: 11000 101
0b11100101, // 8: 11100 101
0b11110101, // 9: 11110 101
0b01000010, // A: 01--- 010
0b10000100, // B: 1000- 100
0b10100100, // C: 1010- 100
0b10000011, // D: 100-- 011
0b00000001, // E: 0---- 001
0b00100100, // F: 0010- 100
0b11000011, // G: 110-- 011
0b00000100, // H: 0000- 100
0b00000010, // I: 00--- 010
0b01110100, // J: 0111- 100
0b10100011, // K: 101-- 011
0b01000100, // L: 0100- 100
0b11000010, // M: 11--- 010
0b10000010, // N: 10--- 010
0b11100011, // O: 111-- 011
0b01100100, // P: 0110- 100 .#-###-###.# ##.#-### ##.#-###.# ##.#.# ##.#.#.# = 48 units
0b11010100, // Q: 1101- 100 60s: 1.25s/unit
0b01000011, // R: 010-- 011 75s: 1.5625s/unit
0b00000011, // S: 000-- 011
0b10000001, // T: 1---- 001
0b00100011, // U: 001-- 011
0b00010100, // V: 0001- 100
0b01100011, // W: 011-- 011
0b10010100, // X: 1001- 100
0b10110100, // Y: 1011- 100
0b11000100 // Z: 1100- 100
Text text_tone {
{ 4 * 8, 8 * 8, 11 * 8, 16 },
"Tone: Hz"
};
const uint16_t morse_special[23] = {
// Code Size
0b1010110000000110, // !: 101011- 110
0b0100100000000110, // ": 010010- 110
0, // #
0b0001001000000111, // $: 0001001 111
0, // %
0b0100000000000101, // &: 01000-- 101
0b0111100000000110, // ': 011110- 110
0b1011000000000101, // (: 10110-- 101
0b1011010000000110, // ): 101101- 110
0, // *
0b0101000000000101, // +: 01010-- 101
0b1100110000000110, // ,: 110011- 110
0b1000010000000110, // -: 100001- 110
0b0101010000000110, // .: 010101- 110
0b1001000000000101, // /: 10010-- 101
0b1110000000000110, // :: 111000- 110
0b1010100000000110, // ;: 101010- 110
0, // <
0b1000100000000101, // =: 10001-- 101
0, // >
0b0011000000000110, // ?: 001100- 110
0b0110100000000110, // @: 011010- 110
0b0011010000000110 // _: 001101- 110
NumberField field_tone {
{ 9 * 8, 8 * 8 },
4,
{ 100, 9999 },
20,
' '
};
const uint16_t prosigns[12] = {
// Code Size
0b0001110000001001, // <SOS>: 000111000 1001
0b0101000000000100, // <AA>: 0101----- 0100
0b0101000000000101, // <AR>: 01010---- 0101
0b0100000000000101, // <AS>: 01000---- 0101
0b1000100000000101, // <BT>: 10001---- 0101
0b1010100000000101, // <CT>: 10101---- 0101
0b0000000000001000, // <HH>: 00000000- 1000
0b1010000000000011, // <K>: 101------ 0011
0b1011000000000101, // <KN>: 10110---- 0101
0b1001110000000110, // <NJ>: 100111--- 0110
0b0001010000000110, // <SK>: 000101--- 0110
0b0001100000000101, // <SN>: 00010---- 0101
};
/*Text text_status {
{ 172, 196, 64, 16 },
"Foxhunt code:"
};*/
Checkbox checkbox_foxhunt {
{ 4 * 8, 24 },
{ 4 * 8, 16 },
8,
"Foxhunt:"
};
OptionsField options_foxhunt {
{ 18 * 8, 32 },
{ 17 * 8, 16 + 4 },
7,
{
{ "0 (MOE)", 0 },
@ -178,29 +94,30 @@ private:
{ "6 (MOD)", 6 },
{ "7 (MOB)", 7 },
{ "8 (MO6)", 8 },
{ "9 (MO)", 9 },
{ "10 (S)", 10 }
{ "9 (MO) ", 9 },
{ "10 (S) ", 10 }
}
};
Button button_transmit {
{ 24, 260, 64, 32 },
"TX"
ProgressBar progressbar {
{ 2 * 8, 14 * 16, 208, 16 }
};
Button button_exit {
{ 160, 260, 64, 32 },
"Exit"
TransmitterView tx_view {
16 * 16,
10000,
12
};
MessageHandlerRegistration message_handler_tx_done {
Message::ID::TXDone,
[this](const Message* const p) {
const auto message = *reinterpret_cast<const TXDoneMessage*>(p);
if (message.done)
transmit_done();
this->on_tx_progress(message.progress, message.done);
}
};
};
} /* namespace ui */
#endif/*__MORSE_TX_H__*/

View File

@ -62,7 +62,7 @@ void TonesProcessor::execute(const buffer_c8_t& buffer) {
digit_pos++;
if ((digit >= 32) || (tone_deltas[digit] == 0)) {
if (digit >= 32) { // || (tone_deltas[digit] == 0)
sample_count = shared_memory.bb_data.tones_data.silence;
} else {
if (!dual_tone) {
@ -78,7 +78,7 @@ void TonesProcessor::execute(const buffer_c8_t& buffer) {
}
// Ugly
if (digit >= 32) {
if ((digit >= 32) || (tone_deltas[digit] == 0)) {
tone_sample = 0;
} else {
if (!dual_tone) {
@ -128,7 +128,7 @@ void TonesProcessor::on_message(const Message* const p) {
tone_durations[c] = shared_memory.bb_data.tones_data.tone_defs[c].duration;
}
message_length = message.tone_count;
fm_delta = message.fm_delta * (0xFFFFFFFFULL / 1536000);
fm_delta = message.fm_delta * (0xFFFFFFFFULL / 1536000) * 2;
audio_out = message.audio_out;
dual_tone = message.dual_tone;

89
firmware/common/morse.cpp Normal file
View File

@ -0,0 +1,89 @@
/*
* 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 "morse.hpp"
#include "baseband_api.hpp"
#include "portapack.hpp"
using namespace portapack;
#include "utility.hpp"
namespace morse {
// Returns 0 if message is too long
size_t morse_encode(std::string& message, const uint32_t time_unit_ms, const uint32_t tone) {
size_t i, c;
uint8_t code, code_size;
uint8_t morse_message[256];
ToneDef * tone_defs = shared_memory.bb_data.tones_data.tone_defs;
i = 0;
for (char& ch : message) {
if ((ch >= 'a') && (ch <= 'z')) // Make uppercase
ch -= 32;
if ((ch >= 'A') && (ch <= 'Z')) {
code = morse_ITU[ch - 'A' + 10];
} else if ((ch >= '0') && (ch <= '9')) {
code = morse_ITU[ch - '0'];
} else {
ch = ' '; // Default to space char
code = 0;
}
if (ch == ' ') {
if (i)
morse_message[i - 1] = 4; // Word space
} else {
code_size = code & 7;
for (c = 0; c < code_size; c++) {
morse_message[i++] = ((code << c) & 0x80) ? 1 : 0; // Dot/dash
morse_message[i++] = 2; // Symbol space
}
morse_message[i - 1] = 3; // Letter space
}
}
if (i > 256) return 0;
memcpy(shared_memory.bb_data.tones_data.message, morse_message, i);
// Setup tone "symbols"
tone_defs[0].delta = TONES_F2D(tone); // 0: Dot
tone_defs[0].duration = (TONES_SAMPLERATE * MORSE_DOT * time_unit_ms) / 1000;
tone_defs[1].delta = TONES_F2D(tone); // 1: Dash
tone_defs[1].duration = (TONES_SAMPLERATE * MORSE_DASH * time_unit_ms) / 1000;
tone_defs[2].delta = 0; // 2: Symbol space
tone_defs[2].duration = (TONES_SAMPLERATE * MORSE_SYMBOL_SPACE * time_unit_ms) / 1000;
tone_defs[3].delta = 0; // 3: Letter space
tone_defs[3].duration = (TONES_SAMPLERATE * MORSE_LETTER_SPACE * time_unit_ms) / 1000;
tone_defs[4].delta = 0; // 4: Word space
tone_defs[4].duration = (TONES_SAMPLERATE * MORSE_WORD_SPACE * time_unit_ms) / 1000;
return i;
}
} /* namespace morse */

142
firmware/common/morse.hpp Normal file
View File

@ -0,0 +1,142 @@
/*
* 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.
*/
#ifndef __MORSE_H__
#define __MORSE_H__
#include "tonesets.hpp"
#include "portapack_shared_memory.hpp"
//#define MORSE_UNIT (MORSE_SAMPLE_RATE * 0.05) // 1536000*0.05 (50ms)
#define MORSE_DOT 1
#define MORSE_DASH 3
#define MORSE_SYMBOL_SPACE 1
#define MORSE_LETTER_SPACE 3
#define MORSE_WORD_SPACE 7
namespace morse {
size_t morse_encode(std::string& message, const uint32_t time_unit_ms, const uint32_t tone);
const std::string foxhunt_codes[11] = {
{ "MOE" }, // -----.
{ "MOI" }, // -----..
{ "MOS" }, // -----...
{ "MOH" }, // -----....
{ "MO5" }, // -----.....
{ "MON" }, // ------.
{ "MOD" }, // ------..
{ "MOB" }, // ------...
{ "MO6" }, // ------....
{ "MO" }, // -----
{ "S" } // ...
};
// 0=dot 1=dash
const uint8_t morse_ITU[36] = {
// Code Size
0b11111101, // 0: 11111 101
0b01111101, // 1: 01111 101
0b00111101, // 2: 00111 101
0b00011101, // 3: 00011 101
0b00001101, // 4: 00001 101
0b00000101, // 5: 00000 101
0b10000101, // 6: 10000 101
0b11000101, // 7: 11000 101
0b11100101, // 8: 11100 101
0b11110101, // 9: 11110 101
0b01000010, // A: 01--- 010
0b10000100, // B: 1000- 100
0b10100100, // C: 1010- 100
0b10000011, // D: 100-- 011
0b00000001, // E: 0---- 001
0b00100100, // F: 0010- 100
0b11000011, // G: 110-- 011
0b00000100, // H: 0000- 100
0b00000010, // I: 00--- 010
0b01110100, // J: 0111- 100
0b10100011, // K: 101-- 011
0b01000100, // L: 0100- 100
0b11000010, // M: 11--- 010
0b10000010, // N: 10--- 010
0b11100011, // O: 111-- 011
0b01100100, // P: 0110- 100 .#-###-###.# ##.#-### ##.#-###.# ##.#.# ##.#.#.# = 48 units
0b11010100, // Q: 1101- 100 60s: 1.25s/unit
0b01000011, // R: 010-- 011 75s: 1.5625s/unit
0b00000011, // S: 000-- 011
0b10000001, // T: 1---- 001
0b00100011, // U: 001-- 011
0b00010100, // V: 0001- 100
0b01100011, // W: 011-- 011
0b10010100, // X: 1001- 100
0b10110100, // Y: 1011- 100
0b11000100 // Z: 1100- 100
};
const uint16_t morse_special[23] = {
// Code Size
0b1010110000000110, // !: 101011- 110
0b0100100000000110, // ": 010010- 110
0, // #
0b0001001000000111, // $: 0001001 111
0, // %
0b0100000000000101, // &: 01000-- 101
0b0111100000000110, // ': 011110- 110
0b1011000000000101, // (: 10110-- 101
0b1011010000000110, // ): 101101- 110
0, // *
0b0101000000000101, // +: 01010-- 101
0b1100110000000110, // ,: 110011- 110
0b1000010000000110, // -: 100001- 110
0b0101010000000110, // .: 010101- 110
0b1001000000000101, // /: 10010-- 101
0b1110000000000110, // :: 111000- 110
0b1010100000000110, // ;: 101010- 110
0, // <
0b1000100000000101, // =: 10001-- 101
0, // >
0b0011000000000110, // ?: 001100- 110
0b0110100000000110, // @: 011010- 110
0b0011010000000110 // _: 001101- 110
};
const uint16_t prosigns[12] = {
// Code Size
0b0001110000001001, // <SOS>: 000111000 1001
0b0101000000000100, // <AA>: 0101----- 0100
0b0101000000000101, // <AR>: 01010---- 0101
0b0100000000000101, // <AS>: 01000---- 0101
0b1000100000000101, // <BT>: 10001---- 0101
0b1010100000000101, // <CT>: 10101---- 0101
0b0000000000001000, // <HH>: 00000000- 1000
0b1010000000000011, // <K>: 101------ 0011
0b1011000000000101, // <KN>: 10110---- 0101
0b1001110000000110, // <NJ>: 100111--- 0110
0b0001010000000110, // <SK>: 000101--- 0110
0b0001100000000101, // <SN>: 00010---- 0101
};
} /* namespace morse */
#endif/*__MORSE_H__*/

View File

@ -44,7 +44,7 @@ struct ToneDef {
struct ToneData {
ToneDef tone_defs[32];
uint32_t silence;
uint8_t message[128];
uint8_t message[256];
};
/* NOTE: These structures must be located in the same location in both M4 and M0 binaries */