mirror of
https://github.com/portapack-mayhem/mayhem-firmware.git
synced 2026-09-11 00:59:28 +00:00
Merge remote-tracking branch 'upstream/master'
Base class for text entry
This commit is contained in:
@@ -72,8 +72,11 @@ set(USE_FPU no)
|
||||
# Project, sources and paths
|
||||
#
|
||||
|
||||
set(CPLD_SVF_PATH ${HARDWARE_PATH}/portapack_h1/cpld/output_files/portapack_h1_cpld.svf)
|
||||
set(CPLD_DATA_CPP ${CMAKE_CURRENT_BINARY_DIR}/portapack_cpld_data.cpp)
|
||||
set(CPLD_20150901_SVF_PATH ${HARDWARE_PATH}/portapack_h1/cpld/20150901/output_files/portapack_h1_cpld.svf)
|
||||
set(CPLD_20150901_DATA_CPP ${CMAKE_CURRENT_BINARY_DIR}/portapack_cpld_20150901_data.cpp)
|
||||
|
||||
set(CPLD_20170522_SVF_PATH ${HARDWARE_PATH}/portapack_h1/cpld/20170522/output_files/portapack_h1_cpld.svf)
|
||||
set(CPLD_20170522_DATA_CPP ${CMAKE_CURRENT_BINARY_DIR}/portapack_cpld_20170522_data.cpp)
|
||||
|
||||
set(HACKRF_CPLD_DATA_HPP ${CMAKE_CURRENT_BINARY_DIR}/hackrf_cpld_data.hpp)
|
||||
set(HACKRF_CPLD_DATA_CPP ${CMAKE_CURRENT_BINARY_DIR}/hackrf_cpld_data.cpp)
|
||||
@@ -123,8 +126,9 @@ set(CPPSRC
|
||||
clock_manager.cpp
|
||||
si5351.cpp
|
||||
${COMMON}/wm8731.cpp
|
||||
${COMMON}/ak4951.cpp
|
||||
radio.cpp
|
||||
baseband_cpld.cpp
|
||||
${COMMON}/baseband_cpld.cpp
|
||||
tuning.cpp
|
||||
rf_path.cpp
|
||||
rffc507x.cpp
|
||||
@@ -242,8 +246,9 @@ set(CPPSRC
|
||||
${COMMON}/cpld_xilinx.cpp
|
||||
${COMMON}/jtag.cpp
|
||||
${COMMON}/jtag_tap.cpp
|
||||
cpld_update.cpp
|
||||
${CPLD_DATA_CPP}
|
||||
${COMMON}/cpld_update.cpp
|
||||
${CPLD_20150901_DATA_CPP}
|
||||
${CPLD_20170522_DATA_CPP}
|
||||
${HACKRF_CPLD_DATA_CPP}
|
||||
)
|
||||
|
||||
@@ -362,14 +367,20 @@ include(${RULESPATH}/rules.cmake)
|
||||
##############################################################################
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT ${CPLD_DATA_CPP}
|
||||
COMMAND ${EXTRACT_CPLD_DATA} ${CPLD_SVF_PATH} >${CPLD_DATA_CPP}
|
||||
DEPENDS ${EXTRACT_CPLD_DATA} ${CPLD_SVF_PATH}
|
||||
OUTPUT ${CPLD_20150901_DATA_CPP}
|
||||
COMMAND ${EXTRACT_CPLD_DATA} ${CPLD_20150901_SVF_PATH} rev_20150901 >${CPLD_20150901_DATA_CPP}
|
||||
DEPENDS ${EXTRACT_CPLD_DATA} ${CPLD_20150901_SVF_PATH}
|
||||
)
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT ${CPLD_20170522_DATA_CPP}
|
||||
COMMAND ${EXTRACT_CPLD_DATA} ${CPLD_20170522_SVF_PATH} rev_20170522 >${CPLD_20170522_DATA_CPP}
|
||||
DEPENDS ${EXTRACT_CPLD_DATA} ${CPLD_20170522_SVF_PATH}
|
||||
)
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT ${HACKRF_CPLD_DATA_HPP} ${HACKRF_CPLD_DATA_CPP}
|
||||
COMMAND ${EXTRACT_SVF_DATA_XC2C64A} ${HACKRF_CPLD_SVF_PATH} hackrf::one::cpld::verify_blocks ${HACKRF_CPLD_DATA_HPP} ${HACKRF_CPLD_DATA_CPP}
|
||||
COMMAND ${EXTRACT_SVF_DATA_XC2C64A} ${HACKRF_CPLD_SVF_PATH} hackrf::one::cpld::verify_blocks ${HACKRF_CPLD_DATA_CPP}
|
||||
DEPENDS ${EXTRACT_SVF_DATA_XC2C64A} ${HACKRF_CPLD_SVF_PATH}
|
||||
)
|
||||
|
||||
|
||||
@@ -23,11 +23,9 @@
|
||||
#include "audio.hpp"
|
||||
|
||||
#include "portapack.hpp"
|
||||
using portapack::i2c0;
|
||||
using portapack::clock_manager;
|
||||
|
||||
#include "wm8731.hpp"
|
||||
using wolfson::wm8731::WM8731;
|
||||
#include "portapack_hal.hpp"
|
||||
|
||||
#include "i2s.hpp"
|
||||
using namespace lpc43xx;
|
||||
@@ -98,24 +96,10 @@ constexpr i2s::ConfigDMA i2s0_config_dma {
|
||||
},
|
||||
};
|
||||
|
||||
constexpr uint8_t wm8731_i2c_address = 0x1a;
|
||||
|
||||
WM8731 audio_codec { i2c0, wm8731_i2c_address };
|
||||
static audio::Codec* audio_codec = nullptr;
|
||||
|
||||
} /* namespace */
|
||||
|
||||
namespace input {
|
||||
|
||||
void start() {
|
||||
i2s::i2s0::rx_start();
|
||||
}
|
||||
|
||||
void stop() {
|
||||
i2s::i2s0::rx_stop();
|
||||
}
|
||||
|
||||
} /* namespace input */
|
||||
|
||||
namespace output {
|
||||
|
||||
void start() {
|
||||
@@ -130,53 +114,80 @@ void stop() {
|
||||
|
||||
void mute() {
|
||||
i2s::i2s0::tx_mute();
|
||||
|
||||
audio_codec.headphone_mute();
|
||||
audio_codec->headphone_disable();
|
||||
}
|
||||
|
||||
void unmute() {
|
||||
i2s::i2s0::tx_unmute();
|
||||
audio_codec->headphone_enable();
|
||||
}
|
||||
|
||||
} /* namespace output */
|
||||
|
||||
namespace input {
|
||||
|
||||
void start() {
|
||||
audio_codec->microphone_enable();
|
||||
i2s::i2s0::rx_start();
|
||||
}
|
||||
|
||||
void stop() {
|
||||
i2s::i2s0::rx_stop();
|
||||
audio_codec->microphone_disable();
|
||||
}
|
||||
|
||||
} /* namespace input */
|
||||
|
||||
namespace headphone {
|
||||
|
||||
volume_range_t volume_range() {
|
||||
return wolfson::wm8731::headphone_gain_range;
|
||||
return audio_codec->headphone_gain_range();
|
||||
}
|
||||
|
||||
void set_volume(const volume_t volume) {
|
||||
audio_codec.set_headphone_volume(volume);
|
||||
audio_codec->set_headphone_volume(volume);
|
||||
}
|
||||
|
||||
} /* namespace headphone */
|
||||
|
||||
namespace debug {
|
||||
|
||||
int reg_count() {
|
||||
return wolfson::wm8731::reg_count;
|
||||
size_t reg_count() {
|
||||
return audio_codec->reg_count();
|
||||
}
|
||||
|
||||
uint16_t reg_read(const int register_number) {
|
||||
return audio_codec.read(register_number);
|
||||
uint32_t reg_read(const size_t register_number) {
|
||||
return audio_codec->reg_read(register_number);
|
||||
}
|
||||
|
||||
std::string codec_name() {
|
||||
return audio_codec->name();
|
||||
}
|
||||
|
||||
size_t reg_bits() {
|
||||
return audio_codec->reg_bits();
|
||||
}
|
||||
|
||||
} /* namespace debug */
|
||||
|
||||
void init() {
|
||||
void init(audio::Codec* const codec) {
|
||||
audio_codec = codec;
|
||||
|
||||
clock_manager.start_audio_pll();
|
||||
audio_codec.init();
|
||||
audio_codec->init();
|
||||
|
||||
i2s::i2s0::configure(
|
||||
i2s0_config_tx,
|
||||
i2s0_config_rx,
|
||||
i2s0_config_dma
|
||||
);
|
||||
|
||||
// Set pin mode, since it's likely GPIO (as left after CPLD JTAG interactions).
|
||||
portapack::pin_i2s0_rx_sda.mode(3);
|
||||
}
|
||||
|
||||
void shutdown() {
|
||||
audio_codec.reset();
|
||||
audio_codec->reset();
|
||||
output::stop();
|
||||
}
|
||||
|
||||
|
||||
@@ -26,9 +26,34 @@
|
||||
#include "volume.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace audio {
|
||||
|
||||
class Codec {
|
||||
public:
|
||||
virtual ~Codec() { }
|
||||
|
||||
virtual std::string name() const = 0;
|
||||
|
||||
virtual bool reset() = 0;
|
||||
virtual void init() = 0;
|
||||
|
||||
virtual void headphone_enable() = 0;
|
||||
virtual void headphone_disable() = 0;
|
||||
virtual volume_range_t headphone_gain_range() const = 0;
|
||||
virtual void set_headphone_volume(const volume_t volume) = 0;
|
||||
|
||||
virtual void microphone_enable() = 0;
|
||||
virtual void microphone_disable() = 0;
|
||||
|
||||
virtual size_t reg_count() const = 0;
|
||||
virtual size_t reg_bits() const = 0;
|
||||
virtual uint32_t reg_read(const size_t register_number) = 0;
|
||||
};
|
||||
|
||||
namespace output {
|
||||
|
||||
void start();
|
||||
@@ -56,12 +81,14 @@ void set_volume(const volume_t volume);
|
||||
|
||||
namespace debug {
|
||||
|
||||
int reg_count();
|
||||
uint16_t reg_read(const int register_number);
|
||||
size_t reg_count();
|
||||
uint32_t reg_read(const size_t register_number);
|
||||
std::string codec_name();
|
||||
size_t reg_bits();
|
||||
|
||||
} /* namespace debug */
|
||||
|
||||
void init();
|
||||
void init(audio::Codec* const codec);
|
||||
void shutdown();
|
||||
|
||||
enum class Rate {
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
|
||||
*
|
||||
* 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 "baseband_cpld.hpp"
|
||||
|
||||
#include "hackrf_gpio.hpp"
|
||||
using namespace hackrf::one;
|
||||
|
||||
namespace baseband {
|
||||
|
||||
void CPLD::init() {
|
||||
set_invert(false);
|
||||
gpio_baseband_invert.output();
|
||||
}
|
||||
|
||||
void CPLD::set_invert(const bool invert) {
|
||||
gpio_baseband_invert.write(invert);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
|
||||
*
|
||||
* 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 __BASEBAND_CPLD_H__
|
||||
#define __BASEBAND_CPLD_H__
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace baseband {
|
||||
|
||||
class CPLD {
|
||||
public:
|
||||
void init();
|
||||
|
||||
void set_invert(const bool invert);
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif/*__BASEBAND_CPLD_H__*/
|
||||
@@ -1,122 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
|
||||
*
|
||||
* 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 "cpld_update.hpp"
|
||||
|
||||
#include "hackrf_gpio.hpp"
|
||||
#include "portapack_hal.hpp"
|
||||
|
||||
#include "jtag_target_gpio.hpp"
|
||||
#include "cpld_max5.hpp"
|
||||
#include "cpld_xilinx.hpp"
|
||||
#include "portapack_cpld_data.hpp"
|
||||
#include "hackrf_cpld_data.hpp"
|
||||
|
||||
bool cpld_update_if_necessary() {
|
||||
jtag::GPIOTarget target {
|
||||
portapack::gpio_cpld_tck,
|
||||
portapack::gpio_cpld_tms,
|
||||
portapack::gpio_cpld_tdi,
|
||||
portapack::gpio_cpld_tdo
|
||||
};
|
||||
jtag::JTAG jtag { target };
|
||||
cpld::max5::CPLD cpld { jtag };
|
||||
|
||||
/* Unknown state */
|
||||
cpld.reset();
|
||||
cpld.run_test_idle();
|
||||
|
||||
/* Run-Test/Idle */
|
||||
if( !cpld.idcode_ok() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Enter ISP:
|
||||
* Ensures that the I/O pins transition smoothly from user mode to ISP
|
||||
* mode. All pins are tri-stated.
|
||||
*/
|
||||
cpld.enter_isp();
|
||||
|
||||
/* If silicon ID doesn't match, there's a serious problem. Leave CPLD
|
||||
* in passive state.
|
||||
*/
|
||||
if( !cpld.silicon_id_ok() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Verify CPLD contents against current bitstream. */
|
||||
auto ok = cpld.verify(
|
||||
portapack::cpld::block_0,
|
||||
portapack::cpld::block_1
|
||||
);
|
||||
|
||||
/* CPLD verifies incorrectly. Erase and program with current bitstream. */
|
||||
if( !ok ) {
|
||||
ok = cpld.program(
|
||||
portapack::cpld::block_0,
|
||||
portapack::cpld::block_1
|
||||
);
|
||||
}
|
||||
|
||||
/* If programming OK, reset CPLD to user mode. Otherwise leave it in
|
||||
* passive (ISP) state.
|
||||
*/
|
||||
if( ok ) {
|
||||
cpld.exit_isp();
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
static jtag::GPIOTarget jtag_target_hackrf() {
|
||||
return {
|
||||
hackrf::one::gpio_cpld_tck,
|
||||
hackrf::one::gpio_cpld_tms,
|
||||
hackrf::one::gpio_cpld_tdi,
|
||||
hackrf::one::gpio_cpld_tdo,
|
||||
};
|
||||
}
|
||||
|
||||
bool cpld_hackrf_load_sram() {
|
||||
auto jtag_target_hackrf_cpld = jtag_target_hackrf();
|
||||
cpld::xilinx::XC2C64A hackrf_cpld { jtag_target_hackrf_cpld };
|
||||
|
||||
hackrf_cpld.write_sram(hackrf::one::cpld::verify_blocks);
|
||||
const auto ok = hackrf_cpld.verify_sram(hackrf::one::cpld::verify_blocks);
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool cpld_hackrf_verify_eeprom() {
|
||||
auto jtag_target_hackrf_cpld = jtag_target_hackrf();
|
||||
cpld::xilinx::XC2C64A hackrf_cpld { jtag_target_hackrf_cpld };
|
||||
|
||||
const auto ok = hackrf_cpld.verify_eeprom(hackrf::one::cpld::verify_blocks);
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
void cpld_hackrf_init_from_eeprom() {
|
||||
auto jtag_target_hackrf_cpld = jtag_target_hackrf();
|
||||
cpld::xilinx::XC2C64A hackrf_cpld { jtag_target_hackrf_cpld };
|
||||
|
||||
hackrf_cpld.init_from_eeprom();
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
|
||||
*
|
||||
* 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 __CPLD_UPDATE_H__
|
||||
#define __CPLD_UPDATE_H__
|
||||
|
||||
bool cpld_update_if_necessary();
|
||||
|
||||
bool cpld_hackrf_load_sram();
|
||||
bool cpld_hackrf_verify_eeprom();
|
||||
void cpld_hackrf_init_from_eeprom();
|
||||
|
||||
#endif/*__CPLD_UPDATE_H__*/
|
||||
@@ -5,7 +5,7 @@
|
||||
/ FatFs - FAT file system module configuration file
|
||||
/---------------------------------------------------------------------------*/
|
||||
|
||||
#define _FFCONF 80186 /* Revision ID */
|
||||
#define _FFCONF 68300 /* Revision ID */
|
||||
|
||||
/*---------------------------------------------------------------------------/
|
||||
/ Function Configurations
|
||||
@@ -76,7 +76,7 @@
|
||||
/* This option specifies the OEM code page to be used on the target system.
|
||||
/ Incorrect setting of the code page can cause a file open failure.
|
||||
/
|
||||
/ 1 - ASCII (No extended character. Non-LFN cfg. only)
|
||||
/ 1 - ASCII (No support of extended character. Non-LFN cfg. only)
|
||||
/ 437 - U.S.
|
||||
/ 720 - Arabic
|
||||
/ 737 - Greek
|
||||
@@ -151,7 +151,7 @@
|
||||
/---------------------------------------------------------------------------*/
|
||||
|
||||
#define _VOLUMES 1
|
||||
/* Number of volumes (logical drives) to be used. */
|
||||
/* Number of volumes (logical drives) to be used. (1-10) */
|
||||
|
||||
|
||||
#define _STR_VOLUME_ID 0
|
||||
@@ -175,11 +175,11 @@
|
||||
#define _MIN_SS 512
|
||||
#define _MAX_SS 512
|
||||
/* These options configure the range of sector size to be supported. (512, 1024,
|
||||
/ 2048 or 4096) Always set both 512 for most systems, all type of memory cards and
|
||||
/ 2048 or 4096) Always set both 512 for most systems, generic memory card and
|
||||
/ harddisk. But a larger value may be required for on-board flash memory and some
|
||||
/ type of optical media. When _MAX_SS is larger than _MIN_SS, FatFs is configured
|
||||
/ to variable sector size and GET_SECTOR_SIZE command must be implemented to the
|
||||
/ disk_ioctl() function. */
|
||||
/ to variable sector size and GET_SECTOR_SIZE command needs to be implemented to
|
||||
/ the disk_ioctl() function. */
|
||||
|
||||
|
||||
#define _USE_TRIM 0
|
||||
@@ -207,15 +207,15 @@
|
||||
|
||||
#define _FS_TINY 0
|
||||
/* This option switches tiny buffer configuration. (0:Normal or 1:Tiny)
|
||||
/ At the tiny configuration, size of the file object (FIL) is reduced _MAX_SS bytes.
|
||||
/ At the tiny configuration, size of file object (FIL) is shrinked _MAX_SS bytes.
|
||||
/ Instead of private sector buffer eliminated from the file object, common sector
|
||||
/ buffer in the file system object (FATFS) is used for the file data transfer. */
|
||||
|
||||
|
||||
#define _FS_EXFAT 0
|
||||
/* This option switches support of exFAT file system in addition to the traditional
|
||||
/ FAT file system. (0:Disable or 1:Enable) To enable exFAT, also LFN must be enabled.
|
||||
/ Note that enabling exFAT discards C89 compatibility. */
|
||||
/* This option switches support of exFAT file system. (0:Disable or 1:Enable)
|
||||
/ When enable exFAT, also LFN needs to be enabled. (_USE_LFN >= 1)
|
||||
/ Note that enabling exFAT discards ANSI C (C89) compatibility. */
|
||||
|
||||
|
||||
#define _FS_NORTC 0
|
||||
@@ -228,7 +228,7 @@
|
||||
/ defined by _NORTC_MON, _NORTC_MDAY and _NORTC_YEAR in local time.
|
||||
/ To enable timestamp function (_FS_NORTC = 0), get_fattime() function need to be
|
||||
/ added to the project to get current time form real-time clock. _NORTC_MON,
|
||||
/ _NORTC_MDAY and _NORTC_YEAR have no effect.
|
||||
/ _NORTC_MDAY and _NORTC_YEAR have no effect.
|
||||
/ These options have no effect at read-only configuration (_FS_READONLY = 1). */
|
||||
|
||||
|
||||
@@ -261,8 +261,11 @@
|
||||
/
|
||||
/ The _FS_TIMEOUT defines timeout period in unit of time tick.
|
||||
/ The _SYNC_t defines O/S dependent sync object type. e.g. HANDLE, ID, OS_EVENT*,
|
||||
/ SemaphoreHandle_t and etc.. A header file for O/S definitions needs to be
|
||||
/ included somewhere in the scope of ff.c. */
|
||||
/ SemaphoreHandle_t and etc. A header file for O/S definitions needs to be
|
||||
/ included somewhere in the scope of ff.h. */
|
||||
|
||||
/* #include <windows.h> // O/S definitions */
|
||||
|
||||
|
||||
|
||||
/*--- End of configuration options ---*/
|
||||
|
||||
@@ -130,23 +130,23 @@ static void event_loop() {
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
portapack::init();
|
||||
if( portapack::init() ) {
|
||||
portapack::display.init();
|
||||
|
||||
portapack::io.init();
|
||||
portapack::display.init();
|
||||
sdcStart(&SDCD1, nullptr);
|
||||
|
||||
sdcStart(&SDCD1, nullptr);
|
||||
controls_init();
|
||||
lcd_frame_sync_configure();
|
||||
rtc_interrupt_enable();
|
||||
|
||||
controls_init();
|
||||
lcd_frame_sync_configure();
|
||||
rtc_interrupt_enable();
|
||||
event_loop();
|
||||
|
||||
event_loop();
|
||||
sdcDisconnect(&SDCD1);
|
||||
sdcStop(&SDCD1);
|
||||
|
||||
sdcDisconnect(&SDCD1);
|
||||
sdcStop(&SDCD1);
|
||||
portapack::shutdown();
|
||||
}
|
||||
|
||||
portapack::shutdown();
|
||||
m4_init(portapack::spi_flash::image_tag_hackrf, portapack::memory::map::m4_code_hackrf);
|
||||
m0_halt();
|
||||
|
||||
|
||||
@@ -21,6 +21,8 @@
|
||||
|
||||
#include "portapack.hpp"
|
||||
#include "portapack_hal.hpp"
|
||||
#include "portapack_dma.hpp"
|
||||
#include "portapack_cpld_data.hpp"
|
||||
#include "portapack_persistent_memory.hpp"
|
||||
|
||||
#include "hackrf_hal.hpp"
|
||||
@@ -32,8 +34,16 @@ using namespace hackrf::one;
|
||||
#include "touch_adc.hpp"
|
||||
#include "audio.hpp"
|
||||
|
||||
#include "wm8731.hpp"
|
||||
using wolfson::wm8731::WM8731;
|
||||
|
||||
#include "ak4951.hpp"
|
||||
using asahi_kasei::ak4951::AK4951;
|
||||
|
||||
#include "cpld_update.hpp"
|
||||
|
||||
#include "optional.hpp"
|
||||
|
||||
namespace portapack {
|
||||
|
||||
portapack::IO io {
|
||||
@@ -60,6 +70,9 @@ ClockManager clock_manager {
|
||||
i2c0, clock_generator
|
||||
};
|
||||
|
||||
WM8731 audio_codec_wm8731 { i2c0, 0x1a };
|
||||
AK4951 audio_codec_ak4951 { i2c0, 0x12 };
|
||||
|
||||
ReceiverModel receiver_model;
|
||||
|
||||
TemperatureLogger temperature_logger;
|
||||
@@ -106,7 +119,53 @@ private:
|
||||
|
||||
static Power power;
|
||||
|
||||
void init() {
|
||||
enum class PortaPackModel {
|
||||
R1_20150901,
|
||||
R2_20170522,
|
||||
};
|
||||
|
||||
static PortaPackModel portapack_model() {
|
||||
static Optional<PortaPackModel> model;
|
||||
|
||||
if( !model.is_valid() ) {
|
||||
if( audio_codec_wm8731.detected() ) {
|
||||
model = PortaPackModel::R1_20150901;
|
||||
} else {
|
||||
model = PortaPackModel::R2_20170522;
|
||||
}
|
||||
}
|
||||
|
||||
return model.value();
|
||||
}
|
||||
|
||||
static audio::Codec* portapack_audio_codec() {
|
||||
return (portapack_model() == PortaPackModel::R2_20170522)
|
||||
? static_cast<audio::Codec*>(&audio_codec_ak4951)
|
||||
: static_cast<audio::Codec*>(&audio_codec_wm8731)
|
||||
;
|
||||
}
|
||||
|
||||
static const portapack::cpld::Config& portapack_cpld_config() {
|
||||
return (portapack_model() == PortaPackModel::R2_20170522)
|
||||
? portapack::cpld::rev_20170522::config
|
||||
: portapack::cpld::rev_20150901::config
|
||||
;
|
||||
}
|
||||
|
||||
static void shutdown_base() {
|
||||
clock_manager.shutdown();
|
||||
|
||||
power.shutdown();
|
||||
// TODO: Wait a bit for supplies to discharge?
|
||||
|
||||
chSysDisable();
|
||||
|
||||
systick_stop();
|
||||
|
||||
hackrf::one::reset();
|
||||
}
|
||||
|
||||
bool init() {
|
||||
for(const auto& pin : pins) {
|
||||
pin.init();
|
||||
}
|
||||
@@ -147,7 +206,18 @@ void init() {
|
||||
clock_manager.set_reference_ppb(persistent_memory::correction_ppb());
|
||||
clock_manager.run_at_full_speed();
|
||||
|
||||
audio::init();
|
||||
if( !portapack::cpld::update_if_necessary(portapack_cpld_config()) ) {
|
||||
shutdown_base();
|
||||
return false;
|
||||
}
|
||||
|
||||
if( !hackrf::cpld::load_sram() ) {
|
||||
chSysHalt();
|
||||
}
|
||||
|
||||
portapack::io.init();
|
||||
|
||||
audio::init(portapack_audio_codec());
|
||||
|
||||
clock_manager.enable_first_if_clock();
|
||||
clock_manager.enable_second_if_clock();
|
||||
@@ -156,33 +226,23 @@ void init() {
|
||||
|
||||
touch::adc::init();
|
||||
|
||||
if( !cpld_update_if_necessary() ) {
|
||||
chSysHalt();
|
||||
}
|
||||
LPC_CREG->DMAMUX = portapack::gpdma_mux;
|
||||
gpdma::controller.enable();
|
||||
|
||||
if( !cpld_hackrf_load_sram() ) {
|
||||
chSysHalt();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void shutdown() {
|
||||
gpdma::controller.disable();
|
||||
|
||||
display.shutdown();
|
||||
|
||||
radio::disable();
|
||||
audio::shutdown();
|
||||
|
||||
cpld_hackrf_init_from_eeprom();
|
||||
hackrf::cpld::init_from_eeprom();
|
||||
|
||||
clock_manager.shutdown();
|
||||
|
||||
power.shutdown();
|
||||
// TODO: Wait a bit for supplies to discharge?
|
||||
|
||||
chSysDisable();
|
||||
|
||||
systick_stop();
|
||||
|
||||
hackrf::one::reset();
|
||||
shutdown_base();
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
@@ -53,7 +53,7 @@ extern uint8_t bl_tick_counter;
|
||||
|
||||
extern TemperatureLogger temperature_logger;
|
||||
|
||||
void init();
|
||||
bool init();
|
||||
void shutdown();
|
||||
|
||||
} /* namespace portapack */
|
||||
|
||||
@@ -132,8 +132,6 @@ AboutView::AboutView(
|
||||
NavigationView& nav
|
||||
)
|
||||
{
|
||||
//uint8_t p, c;
|
||||
|
||||
add_children({
|
||||
&text_cpld_hackrf,
|
||||
&text_cpld_hackrf_status,
|
||||
@@ -150,13 +148,13 @@ AboutView::AboutView(
|
||||
add_child(&text);
|
||||
}
|
||||
|
||||
if( cpld_hackrf_verify_eeprom() ) {
|
||||
if( hackrf::cpld::verify_eeprom() ) {
|
||||
text_cpld_hackrf_status.set(" OK");
|
||||
} else {
|
||||
text_cpld_hackrf_status.set("BAD");
|
||||
}
|
||||
|
||||
button_ok.on_select = [this,&nav](Button&){
|
||||
button_ok.on_select = [&nav](Button&){
|
||||
nav.pop();
|
||||
};
|
||||
}
|
||||
|
||||
@@ -136,7 +136,7 @@ ADSBTxView::ADSBTxView(NavigationView& nav) {
|
||||
generate_frame();
|
||||
};
|
||||
button_callsign.on_select = [this, &nav](Button&) {
|
||||
text_entry(nav, &callsign, 9);
|
||||
text_prompt(nav, &callsign, 9);
|
||||
};
|
||||
|
||||
field_altitude.set_value(11000);
|
||||
|
||||
@@ -26,11 +26,8 @@
|
||||
#include "hackrf_hal.hpp"
|
||||
#include "portapack_shared_memory.hpp"
|
||||
|
||||
#include <cstring>
|
||||
#include <algorithm>
|
||||
|
||||
using namespace hackrf::one;
|
||||
|
||||
namespace ui {
|
||||
|
||||
void AlphanumView::paint(Painter&) {
|
||||
@@ -41,23 +38,14 @@ AlphanumView::AlphanumView(
|
||||
NavigationView& nav,
|
||||
std::string * str,
|
||||
size_t max_length
|
||||
) : _max_length(max_length),
|
||||
_str(str)
|
||||
) : TextEntryView(nav, str, max_length)
|
||||
{
|
||||
size_t n;
|
||||
|
||||
// Trim from right
|
||||
_str->erase(std::find_if(_str->rbegin(), _str->rend(), std::not1(std::ptr_fun<int, int>(std::isspace))).base(), _str->end());
|
||||
cursor_pos = _str->length();
|
||||
|
||||
_str->resize(_max_length, 0);
|
||||
|
||||
add_children({
|
||||
&text_input,
|
||||
&button_mode,
|
||||
&text_raw,
|
||||
&field_raw,
|
||||
&button_ok
|
||||
&field_raw
|
||||
});
|
||||
|
||||
const auto button_fn = [this](Button& button) {
|
||||
@@ -97,22 +85,6 @@ AlphanumView::AlphanumView(
|
||||
update_text();
|
||||
}
|
||||
|
||||
void AlphanumView::draw_cursor() {
|
||||
Point draw_pos;
|
||||
|
||||
draw_pos = {text_input.screen_rect().location().x() + 8 + std::min((Coord)cursor_pos, (Coord)28) * 8,
|
||||
text_input.screen_rect().location().y() + 16};
|
||||
|
||||
portapack::display.fill_rectangle(
|
||||
{{text_input.screen_rect().location().x(), draw_pos.y()}, {text_input.screen_rect().size().width(), 4}},
|
||||
Color::black()
|
||||
);
|
||||
portapack::display.fill_rectangle(
|
||||
{draw_pos, {8, 4}},
|
||||
Color::white()
|
||||
);
|
||||
}
|
||||
|
||||
void AlphanumView::set_mode(const uint32_t new_mode) {
|
||||
size_t n = 0;
|
||||
|
||||
@@ -137,10 +109,6 @@ void AlphanumView::set_mode(const uint32_t new_mode) {
|
||||
button_mode.set_text(key_sets[0].first);
|
||||
}
|
||||
|
||||
void AlphanumView::focus() {
|
||||
button_ok.focus();
|
||||
}
|
||||
|
||||
void AlphanumView::on_button(Button& button) {
|
||||
const auto c = button.text()[0];
|
||||
|
||||
@@ -152,27 +120,4 @@ void AlphanumView::on_button(Button& button) {
|
||||
update_text();
|
||||
}
|
||||
|
||||
void AlphanumView::char_add(const char c) {
|
||||
if (cursor_pos >= _max_length) return;
|
||||
|
||||
_str->replace(cursor_pos, 1, 1, c);
|
||||
cursor_pos++;
|
||||
}
|
||||
|
||||
void AlphanumView::char_delete() {
|
||||
if (!cursor_pos) return;
|
||||
|
||||
cursor_pos--;
|
||||
_str->replace(cursor_pos, 1, 1, 0);
|
||||
}
|
||||
|
||||
void AlphanumView::update_text() {
|
||||
if (cursor_pos <= 28)
|
||||
text_input.set(' ' + *_str + std::string(_max_length - _str->length(), ' '));
|
||||
else
|
||||
text_input.set('<' + _str->substr(cursor_pos - 28, 28));
|
||||
|
||||
draw_cursor();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -26,16 +26,13 @@
|
||||
#include "ui.hpp"
|
||||
#include "ui_widget.hpp"
|
||||
#include "ui_painter.hpp"
|
||||
#include "ui_textentry.hpp"
|
||||
#include "ui_menu.hpp"
|
||||
#include "ui_navigation.hpp"
|
||||
#include "ui_font_fixed_8x16.hpp"
|
||||
|
||||
namespace ui {
|
||||
|
||||
class AlphanumView : public View {
|
||||
class AlphanumView : public TextEntryView {
|
||||
public:
|
||||
std::function<void(std::string*)> on_changed { };
|
||||
|
||||
AlphanumView(NavigationView& nav, std::string * str, size_t max_length);
|
||||
|
||||
AlphanumView(const AlphanumView&) = delete;
|
||||
@@ -44,9 +41,6 @@ public:
|
||||
AlphanumView& operator=(AlphanumView&&) = delete;
|
||||
|
||||
void paint(Painter& painter) override;
|
||||
void focus() override;
|
||||
|
||||
std::string title() const override { return "Text entry"; };
|
||||
|
||||
private:
|
||||
const char * const keys_upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ' .<";
|
||||
@@ -59,21 +53,10 @@ private:
|
||||
{ "Digit", keys_digit }
|
||||
};
|
||||
|
||||
size_t _max_length { };
|
||||
uint32_t cursor_pos { 0 };
|
||||
uint32_t mode = 0; // Uppercase
|
||||
std::string * _str { };
|
||||
uint32_t mode = 0; // Uppercase
|
||||
|
||||
void char_add(const char c);
|
||||
void char_delete();
|
||||
void set_mode(const uint32_t new_mode);
|
||||
void draw_cursor();
|
||||
void on_button(Button& button);
|
||||
void update_text();
|
||||
|
||||
Text text_input {
|
||||
{ 0, 0, 240, 16 }
|
||||
};
|
||||
|
||||
std::array<Button, 30> buttons { };
|
||||
|
||||
|
||||
@@ -173,12 +173,12 @@ void RegistersWidget::paint(Painter& painter) {
|
||||
void RegistersWidget::draw_legend(const Coord left, Painter& painter) {
|
||||
const auto pos = screen_pos();
|
||||
|
||||
for(int i=0; i<config.registers_count; i+=config.registers_per_row) {
|
||||
for(int i=0; i<config.registers_count; i+=config.registers_per_row()) {
|
||||
const Point offset {
|
||||
left, (i / config.registers_per_row) * row_height
|
||||
left, (i / config.registers_per_row()) * row_height
|
||||
};
|
||||
|
||||
const auto text = to_string_hex(i, config.legend_length);
|
||||
const auto text = to_string_hex(i, config.legend_length());
|
||||
painter.draw_string(
|
||||
pos + offset,
|
||||
style().invert(),
|
||||
@@ -195,13 +195,13 @@ void RegistersWidget::draw_values(
|
||||
|
||||
for(int i=0; i<config.registers_count; i++) {
|
||||
const Point offset = {
|
||||
left + config.legend_width() + 8 + (i % config.registers_per_row) * (config.value_width() + 8),
|
||||
(i / config.registers_per_row) * row_height
|
||||
left + config.legend_width() + 8 + (i % config.registers_per_row()) * (config.value_width() + 8),
|
||||
(i / config.registers_per_row()) * row_height
|
||||
};
|
||||
|
||||
const auto value = reader(i);
|
||||
|
||||
const auto text = to_string_hex(value, config.value_length);
|
||||
const auto text = to_string_hex(value, config.value_length());
|
||||
painter.draw_string(
|
||||
pos + offset,
|
||||
style(),
|
||||
@@ -247,37 +247,37 @@ void RegistersView::focus() {
|
||||
/* DebugPeripheralsMenuView **********************************************/
|
||||
|
||||
DebugPeripheralsMenuView::DebugPeripheralsMenuView(NavigationView& nav) {
|
||||
add_items<4>({ {
|
||||
{ "RFFC5072", ui::Color::white(), nullptr, [&nav](){ nav.push<RegistersView>(
|
||||
"RFFC5072", RegistersWidgetConfig { 31, 2, 4, 4 },
|
||||
add_items({
|
||||
{ "RFFC5072", ui::Color::white(), nullptr, [&nav](){ nav.push<RegistersView>(
|
||||
"RFFC5072", RegistersWidgetConfig { 31, 16 },
|
||||
[](const size_t register_number) { return radio::debug::first_if::register_read(register_number); }
|
||||
); } },
|
||||
{ "MAX2837", ui::Color::white(), nullptr, [&nav](){ nav.push<RegistersView>(
|
||||
"MAX2837", RegistersWidgetConfig { 32, 2, 3, 4 },
|
||||
{ "MAX2837", ui::Color::white(), nullptr, [&nav](){ nav.push<RegistersView>(
|
||||
"MAX2837", RegistersWidgetConfig { 32, 10 },
|
||||
[](const size_t register_number) { return radio::debug::second_if::register_read(register_number); }
|
||||
); } },
|
||||
{ "Si5351C", ui::Color::white(), nullptr, [&nav](){ nav.push<RegistersView>(
|
||||
"Si5351C", RegistersWidgetConfig { 96, 2, 2, 8 },
|
||||
{ "Si5351C", ui::Color::white(), nullptr, [&nav](){ nav.push<RegistersView>(
|
||||
"Si5351C", RegistersWidgetConfig { 96, 8 },
|
||||
[](const size_t register_number) { return portapack::clock_generator.read_register(register_number); }
|
||||
); } },
|
||||
{ "WM8731",ui::Color::white(), nullptr, [&nav](){ nav.push<RegistersView>(
|
||||
"WM8731", RegistersWidgetConfig { audio::debug::reg_count(), 1, 3, 4 },
|
||||
{ audio::debug::codec_name(), ui::Color::white(), nullptr, [&nav](){ nav.push<RegistersView>(
|
||||
audio::debug::codec_name(), RegistersWidgetConfig { audio::debug::reg_count(), audio::debug::reg_bits() },
|
||||
[](const size_t register_number) { return audio::debug::reg_read(register_number); }
|
||||
); } },
|
||||
} });
|
||||
});
|
||||
on_left = [&nav](){ nav.pop(); };
|
||||
}
|
||||
|
||||
/* DebugMenuView *********************************************************/
|
||||
|
||||
DebugMenuView::DebugMenuView(NavigationView& nav) {
|
||||
add_items<4>({ {
|
||||
add_items({
|
||||
{ "Memory", ui::Color::white(), nullptr, [&nav](){ nav.push<DebugMemoryView>(); } },
|
||||
{ "Radio State", ui::Color::white(), nullptr, [&nav](){ nav.push<NotImplementedView>(); } },
|
||||
//{ "SD Card", ui::Color::white(), nullptr, [&nav](){ nav.push<SDCardDebugView>(); } },
|
||||
{ "Peripherals", ui::Color::white(), nullptr, [&nav](){ nav.push<DebugPeripheralsMenuView>(); } },
|
||||
{ "Temperature", ui::Color::white(), nullptr, [&nav](){ nav.push<TemperatureView>(); } },
|
||||
} });
|
||||
});
|
||||
on_left = [&nav](){ nav.pop(); };
|
||||
}
|
||||
|
||||
|
||||
@@ -131,20 +131,30 @@ private:
|
||||
|
||||
struct RegistersWidgetConfig {
|
||||
int registers_count;
|
||||
int legend_length;
|
||||
int value_length;
|
||||
int registers_per_row;
|
||||
int register_bits;
|
||||
|
||||
constexpr int legend_length() const {
|
||||
return (registers_count >= 0x10) ? 2 : 1;
|
||||
}
|
||||
|
||||
constexpr int legend_width() const {
|
||||
return legend_length * 8;
|
||||
return legend_length() * 8;
|
||||
}
|
||||
|
||||
constexpr int value_length() const {
|
||||
return (register_bits + 3) / 4;
|
||||
}
|
||||
|
||||
constexpr int value_width() const {
|
||||
return value_length * 8;
|
||||
return value_length() * 8;
|
||||
}
|
||||
|
||||
constexpr int registers_per_row() const {
|
||||
return (value_length() >= 3) ? 4 : 8;
|
||||
}
|
||||
|
||||
constexpr int registers_row_length() const {
|
||||
return (registers_per_row * (value_length + 1)) - 1;
|
||||
return (registers_per_row() * (value_length() + 1)) - 1;
|
||||
}
|
||||
|
||||
constexpr int registers_row_width() const {
|
||||
@@ -156,7 +166,7 @@ struct RegistersWidgetConfig {
|
||||
}
|
||||
|
||||
constexpr int rows() const {
|
||||
return registers_count / registers_per_row;
|
||||
return registers_count / registers_per_row();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -25,14 +25,12 @@
|
||||
#include "portapack.hpp"
|
||||
#include "event_m0.hpp"
|
||||
|
||||
//#include <cstring>
|
||||
|
||||
using namespace portapack;
|
||||
|
||||
namespace ui {
|
||||
|
||||
void FrequencySaveView::on_save_name() {
|
||||
text_entry(nav_, &desc_buffer, 7, [this](std::string * buffer) {
|
||||
text_prompt(nav_, &desc_buffer, 7, [this](std::string * buffer) {
|
||||
database.entries.push_back({ value_, "", *buffer, (int32_t)options_category.selected_index_value() });
|
||||
nav_.pop();
|
||||
});
|
||||
@@ -209,7 +207,7 @@ void FreqManView::on_edit_freq(rf::Frequency f) {
|
||||
}
|
||||
|
||||
void FreqManView::on_edit_desc(NavigationView& nav) {
|
||||
text_entry(nav, &desc_buffer, 28, [this](std::string * buffer) {
|
||||
text_prompt(nav, &desc_buffer, 28, [this](std::string * buffer) {
|
||||
database.entries[menu_view.highlighted()].description = *buffer;
|
||||
//setup_list();
|
||||
});
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
#include "hackrf_hal.hpp"
|
||||
#include "portapack_shared_memory.hpp"
|
||||
|
||||
#include <cstring>
|
||||
#include <algorithm>
|
||||
|
||||
using namespace portapack;
|
||||
|
||||
@@ -40,24 +40,15 @@ HandWriteView::HandWriteView(
|
||||
NavigationView& nav,
|
||||
std::string * str,
|
||||
size_t max_length
|
||||
) : _max_length(max_length),
|
||||
_str(str)
|
||||
) : TextEntryView(nav, str, max_length)
|
||||
{
|
||||
size_t n;
|
||||
|
||||
// Trim from right
|
||||
_str->erase(std::find_if(_str->rbegin(), _str->rend(), std::not1(std::ptr_fun<int, int>(std::isspace))).base(), _str->end());
|
||||
cursor_pos = _str->length();
|
||||
|
||||
_str->resize(_max_length, 0);
|
||||
|
||||
// Handwriting alphabet definition here
|
||||
handwriting = &handwriting_unistroke;
|
||||
|
||||
add_children({
|
||||
&text_input,
|
||||
&button_case,
|
||||
&button_ok
|
||||
&button_case
|
||||
});
|
||||
|
||||
const auto button_fn = [this](Button& button) {
|
||||
@@ -224,9 +215,8 @@ void HandWriteView::guess_letter() {
|
||||
char_add('A' + symbol - 1);
|
||||
clear_zone(Color::green(), true); // Green flash
|
||||
} else {
|
||||
if (cursor_pos) {
|
||||
cursor_pos--;
|
||||
_str->replace(cursor_pos, 1, 1, 0);
|
||||
if (_cursor_pos) {
|
||||
char_delete();
|
||||
clear_zone(Color::yellow(), true); // Yellow flash
|
||||
} else {
|
||||
clear_zone(Color::red(), true); // Red flash
|
||||
@@ -257,26 +247,7 @@ void HandWriteView::sample_pen() {
|
||||
int16_t diff_x, diff_y;
|
||||
uint8_t dir, dir_ud, dir_lr, stroke_prev;
|
||||
|
||||
// Blink cursor
|
||||
if (!(sample_skip & 15)) {
|
||||
Point draw_pos;
|
||||
|
||||
draw_pos = {text_input.screen_rect().location().x() + 8 + std::min((Coord)cursor_pos, (Coord)28) * 8,
|
||||
text_input.screen_rect().location().y() + 16 - 4};
|
||||
|
||||
if (cursor) {
|
||||
display.fill_rectangle(
|
||||
{draw_pos, {text_input.screen_rect().size().width() - draw_pos.x(), 4}},
|
||||
Color::black()
|
||||
);
|
||||
} else {
|
||||
display.fill_rectangle(
|
||||
{draw_pos, {8, 4}},
|
||||
Color::white()
|
||||
);
|
||||
}
|
||||
cursor = !cursor;
|
||||
}
|
||||
draw_cursor();
|
||||
|
||||
if (flash_timer) {
|
||||
if (flash_timer == 1) clear_zone(Color::black(), false);
|
||||
@@ -385,18 +356,4 @@ void HandWriteView::on_button(Button& button) {
|
||||
update_text();
|
||||
}
|
||||
|
||||
void HandWriteView::char_add(const char c) {
|
||||
if (cursor_pos >= _max_length) return;
|
||||
|
||||
_str->replace(cursor_pos, 1, 1, c);
|
||||
cursor_pos++;
|
||||
}
|
||||
|
||||
void HandWriteView::update_text() {
|
||||
if (cursor_pos <= 28)
|
||||
text_input.set(' ' + *_str + std::string(_max_length - _str->length(), ' '));
|
||||
else
|
||||
text_input.set('<' + _str->substr(cursor_pos - 28, 28));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -26,58 +26,44 @@
|
||||
#include "ui.hpp"
|
||||
#include "ui_widget.hpp"
|
||||
#include "ui_painter.hpp"
|
||||
#include "ui_navigation.hpp"
|
||||
#include "ui_textentry.hpp"
|
||||
#include "unistroke.hpp"
|
||||
|
||||
namespace ui {
|
||||
|
||||
class HandWriteView : public View {
|
||||
class HandWriteView : public TextEntryView {
|
||||
public:
|
||||
std::function<void(std::string*)> on_changed { };
|
||||
|
||||
HandWriteView(NavigationView& nav, std::string * str, size_t max_length);
|
||||
|
||||
|
||||
HandWriteView(const HandWriteView&) = delete;
|
||||
HandWriteView(HandWriteView&&) = delete;
|
||||
HandWriteView& operator=(const HandWriteView&) = delete;
|
||||
HandWriteView& operator=(HandWriteView&&) = delete;
|
||||
|
||||
|
||||
void paint(Painter& painter) override;
|
||||
void on_show() override;
|
||||
bool on_touch(const TouchEvent event) override;
|
||||
|
||||
std::string title() const override { return "Text entry"; };
|
||||
|
||||
private:
|
||||
const char special_chars[5] = {'\'', '.', '?', '!', '='};
|
||||
const char special_chars[5] = { '\'', '.', '?', '!', '=' };
|
||||
|
||||
const HandWriting * handwriting { };
|
||||
Painter * _painter { };
|
||||
size_t _max_length;
|
||||
uint8_t dir_cnt { 0 };
|
||||
uint8_t dir_prev { 0 };
|
||||
uint8_t flash_timer { 0 };
|
||||
uint32_t cursor_pos { 0 };
|
||||
bool cursor { false };
|
||||
bool tracing { false };
|
||||
uint8_t stroke_index { 0 };
|
||||
uint8_t sample_skip { 0 }, move_wait { 0 };
|
||||
uint8_t stroke_list[8];
|
||||
Point start_pos { }, current_pos { }, last_pos { };
|
||||
bool _lowercase = false;
|
||||
std::string * _str { };
|
||||
|
||||
void sample_pen();
|
||||
void add_stroke(uint8_t dir);
|
||||
void guess_letter();
|
||||
void clear_zone(const Color color, const bool flash);
|
||||
void char_add(const char c);
|
||||
void on_button(Button& button);
|
||||
void update_text();
|
||||
|
||||
Text text_input {
|
||||
{ 8, 0, 232, 16 }
|
||||
};
|
||||
|
||||
std::array<Button, 10> num_buttons { };
|
||||
std::array<Button, 5> special_buttons { };
|
||||
|
||||
@@ -186,7 +186,7 @@ void LCRView::start_tx(const bool scan) {
|
||||
}
|
||||
|
||||
void LCRView::on_button_setam(NavigationView& nav, Button& button) {
|
||||
text_entry(nav, &litteral[button.id], 7);
|
||||
text_prompt(nav, &litteral[button.id], 7);
|
||||
}
|
||||
|
||||
LCRView::LCRView(NavigationView& nav) {
|
||||
@@ -263,7 +263,7 @@ LCRView::LCRView(NavigationView& nav) {
|
||||
button_scan.set_style(&style_val);
|
||||
|
||||
button_setrgsb.on_select = [this,&nav](Button&) {
|
||||
text_entry(nav, &rgsb, 4);
|
||||
text_prompt(nav, &rgsb, 4);
|
||||
};
|
||||
|
||||
button_txsetup.on_select = [&nav](Button&) {
|
||||
|
||||
@@ -138,11 +138,17 @@ void MenuView::clear() {
|
||||
}
|
||||
}
|
||||
|
||||
void MenuView::add_item(const MenuItem item) {
|
||||
void MenuView::add_item(MenuItem item) {
|
||||
add_child(new MenuItemView { item, keep_highlight_ });
|
||||
update_items();
|
||||
}
|
||||
|
||||
void MenuView::add_items(std::initializer_list<MenuItem> items) {
|
||||
for(auto item : items) {
|
||||
add_item(item);
|
||||
}
|
||||
}
|
||||
|
||||
void MenuView::update_items() {
|
||||
size_t i = 0;
|
||||
int32_t y_pos;
|
||||
|
||||
@@ -51,7 +51,7 @@ public:
|
||||
MenuItemView(
|
||||
MenuItem item,
|
||||
bool keep_highlight
|
||||
) : item(item),
|
||||
) : item { item },
|
||||
keep_highlight_ { keep_highlight }
|
||||
{
|
||||
}
|
||||
@@ -75,15 +75,9 @@ public:
|
||||
|
||||
~MenuView();
|
||||
|
||||
void add_item(const MenuItem item);
|
||||
void add_item(MenuItem item);
|
||||
void add_items(std::initializer_list<MenuItem> items);
|
||||
void clear();
|
||||
|
||||
template<size_t N>
|
||||
void add_items(const std::array<MenuItem, N>& items) {
|
||||
for (const auto& item : items) {
|
||||
add_item(item);
|
||||
}
|
||||
}
|
||||
|
||||
MenuItemView* item_view(size_t index) const;
|
||||
|
||||
|
||||
@@ -71,7 +71,7 @@ static msg_t ookthread_fn(void * arg) {
|
||||
}
|
||||
|
||||
void MorseView::on_set_text(NavigationView& nav) {
|
||||
text_entry(nav, &buffer, 28);
|
||||
text_prompt(nav, &buffer, 28);
|
||||
}
|
||||
|
||||
void MorseView::focus() {
|
||||
|
||||
@@ -281,7 +281,7 @@ void NavigationView::focus() {
|
||||
/* ReceiversMenuView *****************************************************/
|
||||
|
||||
ReceiversMenuView::ReceiversMenuView(NavigationView& nav) {
|
||||
add_items<9>({ {
|
||||
add_items({
|
||||
{ "ADS-B: Planes", ui::Color::grey(), &bitmap_icon_adsb, [&nav](){ nav.push<NotImplementedView>(); }, },
|
||||
{ "AIS: Boats", ui::Color::green(), &bitmap_icon_ais, [&nav](){ nav.push<AISAppView>(); } },
|
||||
{ "APRS", ui::Color::grey(), &bitmap_icon_aprs, [&nav](){ nav.push<NotImplementedView>(); } },
|
||||
@@ -291,14 +291,14 @@ ReceiversMenuView::ReceiversMenuView(NavigationView& nav) {
|
||||
{ "SIGFOX", ui::Color::grey(), &bitmap_icon_fox, [&nav](){ nav.push<NotImplementedView>(); } }, // SIGFRXView
|
||||
{ "SSTV", ui::Color::grey(), &bitmap_icon_sstv, [&nav](){ nav.push<NotImplementedView>(); } },
|
||||
{ "TPMS: Cars", ui::Color::green(), &bitmap_icon_tpms, [&nav](){ nav.push<TPMSAppView>(); } },
|
||||
} });
|
||||
});
|
||||
on_left = [&nav](){ nav.pop(); };
|
||||
}
|
||||
|
||||
/* TransmittersMenuView **************************************************/
|
||||
|
||||
TransmittersMenuView::TransmittersMenuView(NavigationView& nav) {
|
||||
add_items<16>({ {
|
||||
add_items({
|
||||
{ "ADS-B Mode S", ui::Color::orange(), &bitmap_icon_adsb, [&nav](){ nav.push<ADSBTxView>(); } },
|
||||
{ "APRS", ui::Color::grey(), &bitmap_icon_aprs, [&nav](){ nav.push<APRSTXView>(); } },
|
||||
{ "BHT Xy/EP", ui::Color::green(), &bitmap_icon_bht, [&nav](){ nav.push<BHTView>(); } },
|
||||
@@ -315,20 +315,20 @@ TransmittersMenuView::TransmittersMenuView(NavigationView& nav) {
|
||||
{ "SSTV", ui::Color::green(), &bitmap_icon_sstv, [&nav](){ nav.push<SSTVTXView>(); } },
|
||||
{ "TEDI/LCR AFSK", ui::Color::yellow(), &bitmap_icon_lcr, [&nav](){ nav.push<LCRView>(); } },
|
||||
{ "Whistle", ui::Color::green(), &bitmap_icon_whistle, [&nav](){ nav.push<WhistleView>(); } },
|
||||
} });
|
||||
});
|
||||
on_left = [&nav](){ nav.pop(); };
|
||||
}
|
||||
|
||||
/* UtilitiesMenuView *****************************************************/
|
||||
|
||||
UtilitiesMenuView::UtilitiesMenuView(NavigationView& nav) {
|
||||
add_items<5>({ {
|
||||
add_items({
|
||||
{ "Frequency manager", ui::Color::green(), &bitmap_icon_freqman, [&nav](){ nav.push<FreqManView>(); } },
|
||||
{ "CW generator", ui::Color::green(), &bitmap_icon_cwgen, [&nav](){ nav.push<CWTXView>(); } },
|
||||
{ "Whip antenna length", ui::Color::yellow(),nullptr, [&nav](){ nav.push<WhipCalcView>(); } },
|
||||
{ "Notepad", ui::Color::grey(), &bitmap_icon_notepad, [&nav](){ nav.push<NotImplementedView>(); } },
|
||||
{ "Wipe SD card", ui::Color::red(), nullptr, [&nav](){ nav.push<WipeSDView>(); } },
|
||||
} });
|
||||
});
|
||||
on_left = [&nav](){ nav.pop(); };
|
||||
}
|
||||
|
||||
@@ -345,7 +345,7 @@ void SystemMenuView::hackrf_mode(NavigationView& nav) {
|
||||
}
|
||||
|
||||
SystemMenuView::SystemMenuView(NavigationView& nav) {
|
||||
add_items<10>({ {
|
||||
add_items({
|
||||
{ "Play dead", ui::Color::red(), &bitmap_icon_playdead, [&nav](){ nav.push<PlayDeadView>(); } },
|
||||
{ "Receivers", ui::Color::cyan(), &bitmap_icon_receivers, [&nav](){ nav.push<ReceiversMenuView>(); } },
|
||||
{ "Transmitters", ui::Color::green(), nullptr, [&nav](){ nav.push<TransmittersMenuView>(); } },
|
||||
@@ -357,7 +357,7 @@ SystemMenuView::SystemMenuView(NavigationView& nav) {
|
||||
//{ "Debug", ui::Color::white(), nullptr, [&nav](){ nav.push<DebugMenuView>(); } },
|
||||
{ "HackRF mode", ui::Color::white(), &bitmap_icon_hackrf, [this, &nav](){ hackrf_mode(nav); } },
|
||||
{ "About", ui::Color::white(), nullptr, [&nav](){ nav.push<AboutView>(); } }
|
||||
} });
|
||||
});
|
||||
|
||||
set_highlighted(1); // Startup selection is "Receivers"
|
||||
}
|
||||
|
||||
@@ -124,7 +124,7 @@ void POCSAGTXView::paint(Painter&) {
|
||||
}
|
||||
|
||||
void POCSAGTXView::on_set_text(NavigationView& nav) {
|
||||
text_entry(nav, &buffer, 16);
|
||||
text_prompt(nav, &buffer, 16);
|
||||
}
|
||||
|
||||
POCSAGTXView::POCSAGTXView(
|
||||
|
||||
@@ -136,11 +136,11 @@ RDSView::RDSView(NavigationView& nav) {
|
||||
options_coverage.set_selected_index(0); // Local
|
||||
|
||||
button_editpsn.on_select = [this, &nav](Button&) {
|
||||
text_entry(nav, &PSN, 8);
|
||||
text_prompt(nav, &PSN, 8);
|
||||
};
|
||||
|
||||
button_editradiotext.on_select = [this, &nav](Button&){
|
||||
text_entry(nav, &RadioText, 24);
|
||||
text_prompt(nav, &RadioText, 24);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -445,7 +445,7 @@ void ModInfoView::focus() {
|
||||
}*/
|
||||
|
||||
SetupMenuView::SetupMenuView(NavigationView& nav) {
|
||||
add_items<6>({ {
|
||||
add_items({
|
||||
{ "UI", ui::Color::white(), nullptr, [&nav](){ nav.push<SetUIView>(); } },
|
||||
//{ "SD card modules", ui::Color::white(), [&nav](){ nav.push<ModInfoView>(); } },
|
||||
{ "Date/Time", ui::Color::white(), nullptr, [&nav](){ nav.push<SetDateTimeView>(); } },
|
||||
@@ -453,7 +453,7 @@ SetupMenuView::SetupMenuView(NavigationView& nav) {
|
||||
{ "Antenna Bias Voltage", ui::Color::white(), nullptr, [&nav](){ nav.push<AntennaBiasSetupView>(); } },
|
||||
{ "Touch screen", ui::Color::white(), nullptr, [&nav](){ nav.push<TouchCalibrationView>(); } },
|
||||
{ "Play dead", ui::Color::red(), &bitmap_icon_playdead, [&nav](){ nav.push<SetPlayDeadView>(); } }
|
||||
} });
|
||||
});
|
||||
on_left = [&nav](){ nav.pop(); };
|
||||
}
|
||||
|
||||
|
||||
@@ -22,11 +22,15 @@
|
||||
|
||||
#include "ui_textentry.hpp"
|
||||
#include "portapack_persistent_memory.hpp"
|
||||
#include "ui_handwrite.hpp"
|
||||
#include "ui_alphanum.hpp"
|
||||
|
||||
using namespace portapack;
|
||||
|
||||
namespace ui {
|
||||
|
||||
void text_entry(NavigationView& nav, std::string * str, const size_t max_length, const std::function<void(std::string *)> on_done) {
|
||||
if (portapack::persistent_memory::ui_config_textentry() == 0) {
|
||||
void text_prompt(NavigationView& nav, std::string * str, const size_t max_length, const std::function<void(std::string *)> on_done) {
|
||||
if (persistent_memory::ui_config_textentry() == 0) {
|
||||
auto te_view = nav.push<AlphanumView>(str, max_length);
|
||||
te_view->on_changed = [on_done](std::string * value) {
|
||||
if (on_done)
|
||||
@@ -41,4 +45,73 @@ void text_entry(NavigationView& nav, std::string * str, const size_t max_length,
|
||||
}
|
||||
}
|
||||
|
||||
void TextEntryView::update_text() {
|
||||
if (_cursor_pos <= 28)
|
||||
text_input.set(' ' + *_str + std::string(_max_length - _str->length(), ' '));
|
||||
else
|
||||
text_input.set('<' + _str->substr(_cursor_pos - 28, 28));
|
||||
|
||||
draw_cursor();
|
||||
}
|
||||
|
||||
void TextEntryView::char_delete() {
|
||||
if (!_cursor_pos) return;
|
||||
|
||||
_cursor_pos--;
|
||||
_str->replace(_cursor_pos, 1, 1, 0);
|
||||
}
|
||||
|
||||
void TextEntryView::char_add(const char c) {
|
||||
if (_cursor_pos >= _max_length) return;
|
||||
|
||||
_str->replace(_cursor_pos, 1, 1, c);
|
||||
_cursor_pos++;
|
||||
}
|
||||
|
||||
void TextEntryView::draw_cursor() {
|
||||
Point draw_pos;
|
||||
|
||||
draw_pos = { text_input.screen_rect().location().x() + 8 + std::min((Coord)_cursor_pos, (Coord)28) * 8,
|
||||
text_input.screen_rect().location().y() + 16 };
|
||||
|
||||
display.fill_rectangle(
|
||||
{ { text_input.screen_rect().location().x(), draw_pos.y() }, { text_input.screen_rect().size().width(), 4 } },
|
||||
Color::black()
|
||||
);
|
||||
display.fill_rectangle(
|
||||
{ draw_pos, { 8, 4 } },
|
||||
Color::white()
|
||||
);
|
||||
}
|
||||
|
||||
void TextEntryView::focus() {
|
||||
button_ok.focus();
|
||||
}
|
||||
|
||||
TextEntryView::TextEntryView(
|
||||
NavigationView& nav,
|
||||
std::string * str,
|
||||
size_t max_length
|
||||
) : _str(str),
|
||||
_max_length(max_length)
|
||||
{
|
||||
|
||||
// Trim from right
|
||||
_str->erase(std::find_if(_str->rbegin(), _str->rend(), std::not1(std::ptr_fun<int, int>(std::isspace))).base(), _str->end());
|
||||
_cursor_pos = _str->length();
|
||||
|
||||
_str->resize(_max_length, 0);
|
||||
|
||||
add_children({
|
||||
&text_input,
|
||||
&button_ok
|
||||
});
|
||||
|
||||
button_ok.on_select = [this, &nav](Button&) {
|
||||
if (on_changed)
|
||||
on_changed(_str);
|
||||
nav.pop();
|
||||
};
|
||||
}
|
||||
|
||||
} /* namespace ui */
|
||||
|
||||
@@ -25,12 +25,44 @@
|
||||
|
||||
#include "ui.hpp"
|
||||
#include "ui_navigation.hpp"
|
||||
#include "ui_handwrite.hpp"
|
||||
#include "ui_alphanum.hpp"
|
||||
|
||||
namespace ui {
|
||||
|
||||
void text_entry(NavigationView& nav, std::string * str, size_t max_length, const std::function<void(std::string*)> on_done = nullptr);
|
||||
class TextEntryView : public View {
|
||||
public:
|
||||
std::function<void(std::string*)> on_changed { };
|
||||
|
||||
void focus() override;
|
||||
std::string title() const override { return "Text entry"; };
|
||||
|
||||
protected:
|
||||
TextEntryView(NavigationView& nav, std::string * str, size_t max_length);
|
||||
|
||||
TextEntryView(const TextEntryView&) = delete;
|
||||
TextEntryView(TextEntryView&&) = delete;
|
||||
TextEntryView& operator=(const TextEntryView&) = delete;
|
||||
TextEntryView& operator=(TextEntryView&&) = delete;
|
||||
|
||||
void char_add(const char c);
|
||||
void char_delete();
|
||||
void draw_cursor();
|
||||
void update_text();
|
||||
|
||||
std::string * _str;
|
||||
size_t _max_length;
|
||||
uint32_t _cursor_pos { 0 };
|
||||
|
||||
Text text_input {
|
||||
{ 0, 0, 240, 16 }
|
||||
};
|
||||
|
||||
Button button_ok {
|
||||
{ 10 * 8, 33 * 8, 9 * 8, 32 },
|
||||
"OK"
|
||||
};
|
||||
};
|
||||
|
||||
void text_prompt(NavigationView& nav, std::string * str, size_t max_length, const std::function<void(std::string*)> on_done = nullptr);
|
||||
|
||||
} /* namespace ui */
|
||||
|
||||
|
||||
Reference in New Issue
Block a user