diff --git a/firmware/application/CMakeLists.txt b/firmware/application/CMakeLists.txt index 5fad90a2..6af44c1f 100644 --- a/firmware/application/CMakeLists.txt +++ b/firmware/application/CMakeLists.txt @@ -152,8 +152,9 @@ set(CPPSRC audio.cpp ${COMMON}/bch_code.cpp ctcss.cpp - encoder.cpp de_bruijn.cpp + encoder.cpp + emu_cc1101.cpp freqman.cpp ${COMMON}/lcd_ili9341.cpp ${COMMON}/ui.cpp @@ -208,6 +209,7 @@ set(CPPSRC ui_tabview.cpp ui_textentry.cpp ui_touch_calibration.cpp + ui_touchtunes.cpp ui_transmitter.cpp ui_whipcalc.cpp # ui_loadmodule.cpp diff --git a/firmware/application/emu_cc1101.cpp b/firmware/application/emu_cc1101.cpp new file mode 100644 index 00000000..bcb986ad --- /dev/null +++ b/firmware/application/emu_cc1101.cpp @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2017 Jared Boone, ShareBrained Technology, Inc. + * Copyright (C) 2017 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 "emu_cc1101.hpp" + +namespace cc1101 { + +} /* namespace cc1101 */ diff --git a/firmware/application/ui_about.hpp b/firmware/application/ui_about.hpp index e9cd3d38..cc0fd2b4 100644 --- a/firmware/application/ui_about.hpp +++ b/firmware/application/ui_about.hpp @@ -65,15 +65,6 @@ private: bool loop { false }; std::string text { }; - - enum flags { - SECTION = 0, - MEMBER = 1, - MEMBER_LF = 0x41, - TITLE = 2, - TITLE_LF = 0x42, - END = 0x80 - }; typedef struct credits_t { size_t start_pos; @@ -81,18 +72,19 @@ private: int32_t delay; } credits_t; - const credits_t credits[19] = { + const credits_t credits[20] = { { 60, "PortaPack|HAVOC", 0 }, { 7 * 8, "Git hash " GIT_REVISION, 16 }, - { 9 * 8, "Gurus J. Boone", 0 }, - { 16 * 8, "M. Ossmann", 16 }, - { 9 * 8, "HAVOC Furrtek", 16 }, - { 5 * 8, "POCSAG rx T. Sailer", 0 }, - { 16 * 8, "E. Oenal", 16 }, - { 2 * 8, "RDS waveform C. Jacquet", 16 }, - { 5 * 8, "Xy. infos cLx", 16 }, - { 0, "OOK scan trick Samy Kamkar", 16 }, - { 5 * 8, "World map NASA", 24 }, + { 11 * 8, "Gurus J. Boone", 0 }, + { 18 * 8, "M. Ossmann", 16 }, + { 11 * 8, "HAVOC Furrtek", 16 }, + { 7 * 8, "POCSAG rx T. Sailer", 0 }, + { 18 * 8, "E. Oenal", 16 }, + { 4 * 8, "RDS waveform C. Jacquet", 16 }, + { 7 * 8, "Xy. infos cLx", 16 }, + { 2 * 8, "OOK scan trick Samy Kamkar", 16 }, + { 7 * 8, "World map NASA", 16 }, + { 0 * 8, "TouchTunes infos Notpike", 24 }, { 12 * 8, "Thanks", 16 }, { 1 * 8, "Rainer Matla Keld Norman", 0 }, { 1 * 8, " Giorgio C. DC1RDB", 0 }, diff --git a/firmware/application/ui_navigation.cpp b/firmware/application/ui_navigation.cpp index 1f6327b3..6367a932 100644 --- a/firmware/application/ui_navigation.cpp +++ b/firmware/application/ui_navigation.cpp @@ -56,6 +56,7 @@ #include "ui_setup.hpp" #include "ui_soundboard.hpp" #include "ui_sstvtx.hpp" +#include "ui_touchtunes.hpp" #include "ui_whipcalc.hpp" #include "analog_audio_app.hpp" @@ -311,7 +312,7 @@ TransmittersMenuView::TransmittersMenuView(NavigationView& nav) { { "Microphone", ui::Color::green(), &bitmap_icon_microphone, [&nav](){ nav.push(); } }, { "Morse code", ui::Color::green(), &bitmap_icon_morse, [&nav](){ nav.push(); } }, { "NTTWorks burger pager", ui::Color::yellow(), &bitmap_icon_burger, [&nav](){ nav.push(); } }, - { "Numbers station", ui::Color::grey(), &bitmap_icon_numbers, [&nav](){ nav.push(); } }, // NumbersStationView + { "TouchTunes remote", ui::Color::orange(), nullptr, [&nav](){ nav.push(); } }, { "Nuoptix DTMF timecode", ui::Color::green(), &bitmap_icon_nuoptix, [&nav](){ nav.push(); } }, { "OOK remote encoders", ui::Color::yellow(), &bitmap_icon_remote, [&nav](){ nav.push(); } }, { "POCSAG", ui::Color::green(), &bitmap_icon_pocsag, [&nav](){ nav.push(); } }, diff --git a/firmware/application/ui_touchtunes.cpp b/firmware/application/ui_touchtunes.cpp new file mode 100644 index 00000000..7a880f5a --- /dev/null +++ b/firmware/application/ui_touchtunes.cpp @@ -0,0 +1,169 @@ +/* + * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc. + * Copyright (C) 2017 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 "ui_touchtunes.hpp" +#include "encoders.hpp" + +#include "baseband_api.hpp" +#include "string_format.hpp" + +using namespace portapack; +using namespace encoders; + +namespace ui { + +void TouchTunesView::focus() { + field_pin.focus(); +} + +TouchTunesView::~TouchTunesView() { + transmitter_model.disable(); + baseband::shutdown(); +} + +void TouchTunesView::on_tx_progress(const int progress, const bool done) { + if (!done) { + // Repeating + if (tx_mode == SINGLE) { + progressbar.set_value(progress); + } else if (tx_mode == SCAN) { + progressbar.set_value((pin * 4) + progress); + } + } else { + // Done transmitting + if (tx_mode == SINGLE) { + transmitter_model.disable(); + tx_mode = IDLE; + progressbar.set_value(0); + } else if (tx_mode == SCAN) { + pin++; + if (pin == 256) { + transmitter_model.disable(); + tx_mode = IDLE; + progressbar.set_value(0); + } else { + field_pin.set_value(pin); + start_tx(scan_button_index); + } + } + } +} + +void TouchTunesView::start_tx(const uint32_t button_index) { + std::string fragments; + size_t bit; + uint64_t frame_data { 0 }; + + if (check_scan.value()) { + scan_button_index = button_index; + tx_mode = SCAN; + progressbar.set_max(256 * 4); + } else { + tx_mode = SINGLE; + progressbar.set_max(4); + } + + frame_data = 0x5D; // Sync word + + for (bit = 0; bit < 8; bit++) { + frame_data <<= 1; + if (pin & (1 << bit)) + frame_data |= 1; + } + + frame_data <<= 16; + frame_data |= button_codes[button_index]; + + for (bit = 0; bit < (8 + 8 + 16); bit++) { + fragments += (frame_data & 0x80000000UL) ? "1000" : "10"; + frame_data <<= 1; + } + fragments = "111111111111111100000000" + fragments + "1000"; // End pulse + + size_t bitstream_length = make_bitstream(fragments); + + transmitter_model.set_tuning_frequency(433920000); + transmitter_model.set_sampling_rate(OOK_SAMPLERATE); + transmitter_model.set_rf_amp(true); + transmitter_model.set_baseband_bandwidth(1750000); + transmitter_model.enable(); + + baseband::set_ook_data( + bitstream_length, + OOK_SAMPLERATE / 1766, // 1766 baud, 566us/bit + 4, // Repeats + 100 + ); +} + +TouchTunesView::TouchTunesView( + NavigationView& +) +{ + baseband::run_image(portapack::spi_flash::image_tag_ook); + + add_children({ + &labels, + &field_pin, + &button_on_off, + &button_pause, + &button_p1, + &button_ok, + &button_vol_inc1, + &button_vol_inc2, + &button_vol_inc3, + &check_scan, + &text_status, + &progressbar + }); + + field_pin.set_value(pin); + + field_pin.on_change = [this](int32_t v) { + pin = v; + }; + + button_on_off.on_select = [this](Button&) { + start_tx(0); + }; + + button_pause.on_select = [this](Button&) { + start_tx(1); + }; + button_p1.on_select = [this](Button&) { + start_tx(2); + }; + button_ok.on_select = [this](Button&) { + start_tx(3); + }; + button_vol_inc1.on_select = [this](Button&) { + start_tx(4); + }; + button_vol_inc2.on_select = [this](Button&) { + start_tx(5); + }; + button_vol_inc3.on_select = [this](Button&) { + start_tx(6); + }; +} + +} /* namespace ui */ diff --git a/firmware/application/ui_touchtunes.hpp b/firmware/application/ui_touchtunes.hpp new file mode 100644 index 00000000..dfa1a4ed --- /dev/null +++ b/firmware/application/ui_touchtunes.hpp @@ -0,0 +1,163 @@ +/* + * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc. + * Copyright (C) 2017 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 "ui.hpp" +#include "ui_transmitter.hpp" +#include "transmitter_model.hpp" + +// The coding in notpike's script is quite complex, using multiple LUTs to form the data sent to the YSO. +// The format is actually very simple if it is rather seen as short and long gaps between pulses (as seen in many OOK remotes): + +// Pin 0 - On/Off +// ffff00 a2888a2aaaa8888aa2aa2220 +// 1010 0010 1000 1000 1000 1010 0010 1010 1010 1010 1010 1000 1000 1000 1000 1010 1010 0010 1010 1010 0010 0010 0010 0000 +// 101000101000100010001010001010101010101010101000100010001000101010100010101010100010001000100000 +// S L S L L L S L S S S S S S S S S L L L L S S S L S S S S L L L + +// Pin 1 - On/Off +// ffff00 a2888a22aaaa2222a8aa8888 +// 1010 0010 1000 1000 1000 1010 0010 0010 1010 1010 1010 1010 0010 0010 0010 0010 1010 1000 1010 1010 1000 1000 1000 1000 +// 101000101000100010001010001000101010101010101010001000100010001010101000101010101000100010001000 +// S L S L L L S L L S S S S S S S S L L L L S S S L S S S S L L L + +// Pin 2 - On/Off +// ffff00 a2888a28aaaa2222a8aa8888 +// 1010 0010 1000 1000 1000 1010 0010 1000 1010 1010 1010 1010 0010 0010 0010 0010 1010 1000 1010 1010 1000 1000 1000 1000 +// 101000101000100010001010001010001010101010101010001000100010001010101000101010101000100010001000 +// S L S L L L S L S L S S S S S S S L L L L S S S L S S S S L L L + +// Pin 3 - On/Off +// ffff00 a2888a222aaa8888aa2aa222 +// 1010 0010 1000 1000 1000 1010 0010 0010 0010 1010 1010 1010 1000 1000 1000 1000 1010 1010 0010 1010 1010 0010 0010 0010 0000 0000 +// 10100010100010001000101000100010001010101010101010001000100010001010101000101010101000100010001000 +// S L S L L L S L L L S S S S S S S L L L L S S S L S S S S L L L + +// The sync word seems to be SLSLLLSL (01011101, or 0xBA reversed) +// The pin # is sent LSB first +// The button data seems to be SLLLLSSSLSSSSLLL (0111100010000111 and a terminating pulse, or 0x7887 reversed) +// The hex data only seems scrambled because of the shift induced by the short or long gaps (10 or 1000) +// The radio frame's duration depends on the value of the bits + +const uint16_t button_codes[7] = { + 0x7887, // On/Off + 0xB34C, // Pause + 0xF10E, // P1 + 0xDD22, // OK + 0xF40B, // Zone 1 Vol+ + 0xF609, // Zone 2 Vol+ + 0xFC03 // Zone 3 Vol+ +}; + +namespace ui { + +class TouchTunesView : public View { +public: + TouchTunesView(NavigationView& nav); + ~TouchTunesView(); + + void focus() override; + + std::string title() const override { return "TouchTunes TX"; }; + +private: + Labels labels { + { { 2 * 8, 2 * 8 }, "PIN:", Color::light_grey() } + }; + + uint32_t scan_button_index { }; + uint32_t pin { 0 }; + + enum tx_modes { + IDLE = 0, + SINGLE, + SCAN + }; + + tx_modes tx_mode = IDLE; + + void start_tx(const uint32_t button_index); + void on_tx_progress(const int progress, const bool done); + + NumberField field_pin { + { 6 * 8, 1 * 16 }, + 3, + { 0, 255 }, + 1, + ' ' + }; + + Button button_on_off { + { 2 * 8, 3 * 16, 8 * 8, 2 * 16 }, + "ON/OFF" + }; + + Button button_pause { + { 2 * 8, 6 * 16, 8 * 8, 2 * 16 }, + "PAUSE" + }; + Button button_p1 { + { 11 * 8, 6 * 16, 8 * 8, 2 * 16 }, + "P1" + }; + Button button_ok { + { 20 * 8, 6 * 16, 8 * 8, 2 * 16 }, + "OK" + }; + + Button button_vol_inc1 { + { 2 * 8, 9 * 16, 8 * 8, 2 * 16 }, + "VOL+ 1" + }; + Button button_vol_inc2 { + { 11 * 8, 9 * 16, 8 * 8, 2 * 16 }, + "VOL+ 2" + }; + Button button_vol_inc3 { + { 20 * 8, 9 * 16, 8 * 8, 2 * 16 }, + "VOL+ 3" + }; + + Checkbox check_scan { + { 2 * 8, 13 * 16 }, + 4, + "Scan" + }; + + Text text_status { + { 2 * 8, 15 * 16, 128, 16 }, + "Ready" + }; + + ProgressBar progressbar { + { 2 * 8, 15 * 16 + 20, 208, 16 } + }; + + MessageHandlerRegistration message_handler_tx_done { + Message::ID::TXDone, + [this](const Message* const p) { + const auto message = *reinterpret_cast(p); + this->on_tx_progress(message.progress, message.done); + } + }; +}; + +} /* namespace ui */ diff --git a/firmware/common/emu_cc1101.hpp b/firmware/common/emu_cc1101.hpp new file mode 100644 index 00000000..724e0049 --- /dev/null +++ b/firmware/common/emu_cc1101.hpp @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2017 Jared Boone, ShareBrained Technology, Inc. + * Copyright (C) 2017 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 __EMU_CC1101_H__ +#define __EMU_CC1101_H__ + +#include +#include + +#include "utility.hpp" + +namespace cc1101 { + +// Data rate (Bauds) +// Whitening: Everything except preamble and sync word, init value = 111111111 +// See datasheet page 38 for logic schematic +// Packet format: preamble, sync word, (opt) length, (opt) address, payload, (opt) CRC +// Preamble: 8*n bits of 10101010 +// Sync word: 2 bytes (can be repeated twice) +// Length: 1 byte (address + payload) +// 2-FSK: 0=-dev, 1=+dev +// 4-FSK: 00=-1/3dev, 01=-dev, 10=1/3dev, 11=+dev (preamble and sync are in 2-FSK) +// OOK: PA on or off +// ASK: Power can be adjusted +// FEC: ? + +class CC1101Emu { +public: + //CC1101Emu(); + //~CC1101Emu(); + + enum packet_mode_t { + FIXED_LENGTH, + VARIABLE_LENGTH, + INFINITE_LENGTH + }; + + enum modulation_t { + TWO_FSK, + GFSK, + OOK, + FOUR_FSK, + MSK, + }; + + void set_sync_word(const uint16_t sync_word) { + sync_word_ = sync_word; + }; + void set_address(const uint8_t address) { + address_ = address; + }; + void set_packet_length(const uint8_t packet_length) { + packet_length_ = packet_length; + }; + void set_data_config(const bool CRC, const bool manchester, const bool whitening) { + CRC_ = CRC; + manchester_ = manchester; + whitening_ = whitening; + }; + void set_packet_mode(const packet_mode_t packet_mode) { + packet_mode_ = packet_mode; + }; + void set_modulation(const modulation_t modulation) { + modulation_ = modulation; + } + void set_num_preamble(const uint8_t num_preamble) { // 2, 3, 4, 6, 8, 12, 16, or 24 + num_preamble_ = num_preamble; + }; + void set_deviation(const size_t deviation) { + deviation_ = deviation; + }; + +private: + uint16_t sync_word_ { 0xD391 }; + uint8_t address_ { 0x00 }; + uint8_t packet_length_ { 0 }; + bool CRC_ { false }; + bool manchester_ { false }; + bool whitening_ { true }; + packet_mode_t packet_mode_ { VARIABLE_LENGTH }; + modulation_t modulation_ { TWO_FSK }; + uint8_t num_preamble_ { 4 }; + size_t deviation_ { 4000 }; +}; + +} /* namespace cc1101 */ + +#endif/*__EMU_CC1101_H__*/ diff --git a/firmware/portapack-h1-havoc.bin b/firmware/portapack-h1-havoc.bin index 35d4a62f..5c01174b 100644 Binary files a/firmware/portapack-h1-havoc.bin and b/firmware/portapack-h1-havoc.bin differ