From ccc86aad1415ac5a5213eaed08d64794262aaca1 Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Wed, 1 Aug 2018 21:05:10 -0700 Subject: [PATCH] Add support for PortaPack user interface add-on board. --- firmware/common/hackrf-ui.h | 4 + firmware/common/hackrf_core.c | 4 +- firmware/common/hackrf_core.h | 24 + firmware/common/rf_path.c | 4 + firmware/common/ui_portapack.c | 931 +++++++++++++++++++++++++++++++++ firmware/common/ui_portapack.h | 59 +++ firmware/hackrf-common.cmake | 17 +- 7 files changed, 1041 insertions(+), 2 deletions(-) create mode 100644 firmware/common/ui_portapack.c create mode 100644 firmware/common/ui_portapack.h diff --git a/firmware/common/hackrf-ui.h b/firmware/common/hackrf-ui.h index 95b82489..2bff25e8 100644 --- a/firmware/common/hackrf-ui.h +++ b/firmware/common/hackrf-ui.h @@ -14,4 +14,8 @@ void hackrf_ui_setBBLNAGain(const uint32_t gain_db) __attribute__((weak)); void hackrf_ui_setBBVGAGain(const uint32_t gain_db) __attribute__((weak)); void hackrf_ui_setBBTXVGAGain(const uint32_t gain_db) __attribute__((weak)); +void hackrf_ui_setFirstIFFrequency(const uint64_t freq) __attribute__((weak)); +void hackrf_ui_setFilter(const rf_path_filter_t filter) __attribute__((weak)); +void hackrf_ui_setAntennaBias(bool antenna_bias) __attribute__((weak)); + #endif diff --git a/firmware/common/hackrf_core.c b/firmware/common/hackrf_core.c index 64448206..028f9cc7 100644 --- a/firmware/common/hackrf_core.c +++ b/firmware/common/hackrf_core.c @@ -796,9 +796,11 @@ void pin_setup(void) { /* Configure RF power supply (VAA) switch control signal as output */ gpio_output(&gpio_vaa_disable); +#ifndef USER_INTERFACE_PORTAPACK + /* Not sure why this is necessary for stock HackRF. Just "rhyming" with the RAD1O code? */ scu_pinmux(SCU_PINMUX_GPIO3_10, SCU_GPIO_PDN | SCU_CONF_FUNCTION0); scu_pinmux(SCU_PINMUX_GPIO3_11, SCU_GPIO_PDN | SCU_CONF_FUNCTION0); - +#endif #endif #ifdef RAD1O diff --git a/firmware/common/hackrf_core.h b/firmware/common/hackrf_core.h index 36c03759..1b1fc5f7 100644 --- a/firmware/common/hackrf_core.h +++ b/firmware/common/hackrf_core.h @@ -77,8 +77,16 @@ extern "C" /* GPIO Input PinMux */ #define SCU_PINMUX_BOOT0 (P1_1) /* GPIO0[8] on P1_1 */ #define SCU_PINMUX_BOOT1 (P1_2) /* GPIO0[9] on P1_2 */ +#ifdef USER_INTERFACE_PORTAPACK +#define SCU_PINMUX_PP_LCD_TE (P2_3) /* GPIO5[3] on P2_3 */ +#define SCU_PINMUX_PP_LCD_RDX (P2_4) /* GPIO5[4] on P2_4 */ +#define SCU_PINMUX_PP_UNUSED (P2_8) /* GPIO5[7] on P2_8 */ +#define SCU_PINMUX_PP_LCD_WRX (P2_9) /* GPIO1[10] on P2_9 */ +#define SCU_PINMUX_PP_DIR (P2_13) /* GPIO1[13] on P2_13 */ +#else #define SCU_PINMUX_BOOT2 (P2_8) /* GPIO5[7] on P2_8 */ #define SCU_PINMUX_BOOT3 (P2_9) /* GPIO1[10] on P2_9 */ +#endif /* USB peripheral */ #ifdef JAWBREAKER @@ -206,6 +214,16 @@ extern "C" #define SCU_RX_LNA (P6_7) /* GPIO5[15] on P6_7 */ #endif +#ifdef USER_INTERFACE_PORTAPACK +#define SCU_PINMUX_PP_D0 (P7_0) /* GPIO3[8] */ +#define SCU_PINMUX_PP_D1 (P7_1) /* GPIO3[9] */ +#define SCU_PINMUX_PP_D2 (P7_2) /* GPIO3[10] */ +#define SCU_PINMUX_PP_D3 (P7_3) /* GPIO3[11] */ +#define SCU_PINMUX_PP_D4 (P7_4) /* GPIO3[12] */ +#define SCU_PINMUX_PP_D5 (P7_5) /* GPIO3[13] */ +#define SCU_PINMUX_PP_D6 (P7_6) /* GPIO3[14] */ +#define SCU_PINMUX_PP_D7 (P7_7) /* GPIO3[15] */ +#else /* TODO add other Pins */ #define SCU_PINMUX_GPIO3_8 (P7_0) /* GPIO3[8] */ #define SCU_PINMUX_GPIO3_9 (P7_1) /* GPIO3[9] */ @@ -215,6 +233,7 @@ extern "C" #define SCU_PINMUX_GPIO3_13 (P7_5) /* GPIO3[13] */ #define SCU_PINMUX_GPIO3_14 (P7_6) /* GPIO3[14] */ #define SCU_PINMUX_GPIO3_15 (P7_7) /* GPIO3[15] */ +#endif #define SCU_PINMUX_SD_POW (P1_5) /* GPIO1[8] */ #define SCU_PINMUX_SD_CMD (P1_6) /* GPIO1[9] */ @@ -225,8 +244,13 @@ extern "C" #define SCU_PINMUX_SD_DAT3 (P1_12) /* GPIO1[5] */ #define SCU_PINMUX_SD_CD (P1_13) /* GPIO1[6] */ +#ifdef USER_INTERFACE_PORTAPACK +#define SCU_PINMUX_PP_IO_STBX (P2_0) /* GPIO5[0] */ +#define SCU_PINMUX_PP_ADDR (P2_1) /* GPIO5[1] */ +#else #define SCU_PINMUX_U0_TXD (P2_0) /* GPIO5[0] */ #define SCU_PINMUX_U0_RXD (P2_1) /* GPIO5[1] */ +#endif #define SCU_PINMUX_ISP (P2_7) /* GPIO0[7] */ diff --git a/firmware/common/rf_path.c b/firmware/common/rf_path.c index 05a627bd..a854367c 100644 --- a/firmware/common/rf_path.c +++ b/firmware/common/rf_path.c @@ -415,6 +415,8 @@ void rf_path_set_filter(rf_path_t* const rf_path, const rf_path_filter_t filter) } switchctrl_set(rf_path, rf_path->switchctrl); + + hackrf_ui_setFilter(filter); } void rf_path_set_lna(rf_path_t* const rf_path, const uint_fast8_t enable) { @@ -447,4 +449,6 @@ void rf_path_set_antenna(rf_path_t* const rf_path, const uint_fast8_t enable) { } switchctrl_set(rf_path, rf_path->switchctrl); + + hackrf_ui_setAntennaBias(enable); } diff --git a/firmware/common/ui_portapack.c b/firmware/common/ui_portapack.c new file mode 100644 index 00000000..7ba19e22 --- /dev/null +++ b/firmware/common/ui_portapack.c @@ -0,0 +1,931 @@ +/* + * Copyright 2018 Jared Boone + * + * This file is part of HackRF. + * + * 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 "hackrf-ui.h" + +#include "ui_portapack.h" + +#include "hackrf_core.h" +#include "gpio_lpc.h" + +#include + +#include + +#ifdef USER_INTERFACE_PORTAPACK + +/* Pixel data within a font or bitmap byte is "reversed": LSB is left-most pixel. */ + +static const uint8_t font_fixed_8x16_glyph_data[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x08, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x24, 0x24, 0x24, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x48, 0x48, 0x48, 0xff, 0x24, 0x24, 0xff, 0x12, 0x12, 0x12, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x10, 0x78, 0x14, 0x14, 0x14, 0x18, 0x30, 0x50, 0x50, 0x50, 0x3c, 0x10, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x46, 0x29, 0x29, 0x19, 0x16, 0x68, 0x98, 0x94, 0x94, 0x62, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x18, 0x24, 0x24, 0x14, 0x88, 0x54, 0x72, 0x22, 0x62, 0x9c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x40, 0x20, 0x10, 0x10, 0x08, 0x08, 0x08, 0x08, 0x10, 0x10, 0x20, 0x40, 0x00, + 0x00, 0x00, 0x00, 0x02, 0x04, 0x08, 0x08, 0x10, 0x10, 0x10, 0x10, 0x08, 0x08, 0x04, 0x02, 0x00, + 0x00, 0x00, 0x00, 0x08, 0x2a, 0x1c, 0x2a, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0xfe, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x20, 0x20, 0x10, 0x10, 0x08, 0x08, 0x04, 0x04, 0x02, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x18, 0x24, 0x42, 0x42, 0x5a, 0x5a, 0x42, 0x42, 0x24, 0x18, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x0c, 0x0a, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x3e, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x1e, 0x20, 0x20, 0x20, 0x20, 0x10, 0x08, 0x04, 0x02, 0x3e, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x1e, 0x20, 0x20, 0x10, 0x0c, 0x10, 0x20, 0x20, 0x10, 0x0e, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x30, 0x30, 0x28, 0x28, 0x24, 0x24, 0x22, 0x7e, 0x20, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x7c, 0x04, 0x04, 0x04, 0x3c, 0x40, 0x40, 0x40, 0x40, 0x3c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x38, 0x04, 0x02, 0x02, 0x3a, 0x46, 0x42, 0x42, 0x44, 0x38, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x7e, 0x40, 0x20, 0x20, 0x10, 0x10, 0x10, 0x08, 0x08, 0x04, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x24, 0x18, 0x24, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x1c, 0x22, 0x42, 0x42, 0x62, 0x5c, 0x40, 0x40, 0x20, 0x1c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x00, 0x00, 0x00, 0x08, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x00, 0x00, 0x00, 0x08, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x20, 0x18, 0x04, 0x18, 0x20, 0x40, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x08, 0x30, 0x40, 0x30, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x38, 0x44, 0x40, 0x40, 0x30, 0x08, 0x08, 0x00, 0x08, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x1c, 0x22, 0x41, 0x59, 0x55, 0x55, 0x55, 0x39, 0x01, 0x02, 0x3c, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x08, 0x14, 0x14, 0x14, 0x14, 0x22, 0x3e, 0x22, 0x41, 0x41, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x3e, 0x42, 0x42, 0x42, 0x3e, 0x42, 0x42, 0x42, 0x42, 0x3e, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x38, 0x44, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x44, 0x38, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x1e, 0x22, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x22, 0x1e, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x7e, 0x02, 0x02, 0x02, 0x7e, 0x02, 0x02, 0x02, 0x02, 0x7e, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x7e, 0x02, 0x02, 0x02, 0x7e, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x38, 0x44, 0x02, 0x02, 0x02, 0x72, 0x42, 0x42, 0x44, 0x38, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x42, 0x42, 0x42, 0x42, 0x7e, 0x42, 0x42, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x3e, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x3e, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x1e, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x82, 0x42, 0x22, 0x12, 0x0a, 0x0e, 0x12, 0x22, 0x42, 0x82, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x7e, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x42, 0x66, 0x66, 0x5a, 0x5a, 0x42, 0x42, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x42, 0x46, 0x46, 0x4a, 0x4a, 0x52, 0x52, 0x62, 0x62, 0x42, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x18, 0x24, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x24, 0x18, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x3e, 0x42, 0x42, 0x3e, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x18, 0x24, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x24, 0x18, 0x10, 0x60, 0x00, + 0x00, 0x00, 0x00, 0x3e, 0x42, 0x42, 0x42, 0x3e, 0x12, 0x22, 0x22, 0x42, 0x82, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x3c, 0x42, 0x02, 0x02, 0x0c, 0x30, 0x40, 0x40, 0x42, 0x3c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x7f, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x41, 0x41, 0x22, 0x22, 0x22, 0x14, 0x14, 0x14, 0x14, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x41, 0x41, 0x41, 0x49, 0x49, 0x55, 0x55, 0x55, 0x22, 0x22, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x41, 0x22, 0x22, 0x14, 0x08, 0x08, 0x14, 0x22, 0x22, 0x41, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x41, 0x22, 0x22, 0x14, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x7e, 0x40, 0x20, 0x10, 0x10, 0x08, 0x08, 0x04, 0x02, 0x7e, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x38, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x38, 0x00, + 0x00, 0x00, 0x00, 0x02, 0x02, 0x04, 0x04, 0x08, 0x08, 0x10, 0x10, 0x20, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x0e, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x0e, 0x00, + 0x00, 0x00, 0x00, 0x10, 0x28, 0x44, 0x44, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, + 0x00, 0x00, 0x00, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x42, 0x40, 0x7c, 0x42, 0x62, 0x5c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x1a, 0x26, 0x42, 0x42, 0x42, 0x26, 0x1a, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x04, 0x02, 0x02, 0x02, 0x04, 0x78, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x40, 0x40, 0x40, 0x58, 0x64, 0x42, 0x42, 0x42, 0x64, 0x58, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x24, 0x42, 0x7e, 0x02, 0x04, 0x78, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x70, 0x08, 0x08, 0x7e, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x22, 0x22, 0x22, 0x1c, 0x02, 0x3e, 0x42, 0x42, 0x3c, + 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x3a, 0x46, 0x42, 0x42, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x1c, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x1c, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x0e, + 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x22, 0x12, 0x0a, 0x0e, 0x12, 0x22, 0x42, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x0e, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x38, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x37, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3a, 0x46, 0x42, 0x42, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1a, 0x26, 0x42, 0x42, 0x42, 0x26, 0x1a, 0x02, 0x02, 0x02, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0x64, 0x42, 0x42, 0x42, 0x64, 0x58, 0x40, 0x40, 0x40, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x74, 0x0c, 0x04, 0x04, 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x02, 0x02, 0x3c, 0x40, 0x40, 0x3e, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x3c, 0x08, 0x08, 0x08, 0x08, 0x08, 0x70, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x62, 0x5c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x22, 0x22, 0x36, 0x14, 0x14, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x41, 0x49, 0x55, 0x55, 0x22, 0x22, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x24, 0x18, 0x18, 0x18, 0x24, 0x42, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x22, 0x22, 0x14, 0x14, 0x14, 0x08, 0x08, 0x04, 0x03, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x20, 0x10, 0x08, 0x08, 0x04, 0x7e, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x10, 0x08, 0x08, 0x08, 0x08, 0x04, 0x08, 0x08, 0x08, 0x08, 0x08, 0x10, 0x00, + 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, + 0x00, 0x00, 0x00, 0x08, 0x10, 0x10, 0x10, 0x10, 0x20, 0x10, 0x10, 0x10, 0x10, 0x10, 0x08, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8e, 0x71, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +static const ui_font_t font_fixed_8x16 = { + { 8, 16 }, + font_fixed_8x16_glyph_data, + 0x20, 95, + (8 * 16 + 7U) >> 3 +}; + +static const uint8_t font_fixed_24x19_glyph_data[] = { + 0xe0, 0xff, 0x07, 0xf8, 0xff, 0x1f, 0xf8, 0xff, 0x1f, 0x3c, 0x00, 0x3c, 0x1c, 0x00, 0x38, 0x1c, 0x00, 0x38, 0x1c, 0x00, 0x38, 0x1c, 0x00, 0x38, 0x1c, 0x00, 0x38, 0x1c, 0x00, 0x38, 0x1c, 0x00, 0x38, 0x1c, 0x00, 0x38, 0x1c, 0x00, 0x38, 0x1c, 0x00, 0x38, 0x1c, 0x00, 0x38, 0x3c, 0x00, 0x3c, 0xf8, 0xff, 0x1f, 0xf8, 0xff, 0x1f, 0xe0, 0xff, 0x07, + 0x00, 0x78, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x7f, 0x00, 0x80, 0x77, 0x00, 0xc0, 0x73, 0x00, 0xc0, 0x71, 0x00, 0xc0, 0x70, 0x00, 0x00, 0x70, 0x00, 0x00, 0x70, 0x00, 0x00, 0x70, 0x00, 0x00, 0x70, 0x00, 0x00, 0x70, 0x00, 0x00, 0x70, 0x00, 0x00, 0x70, 0x00, 0x00, 0x70, 0x00, 0x00, 0x70, 0x00, 0x00, 0x70, 0x00, 0x00, 0x70, 0x00, + 0xe0, 0xff, 0x07, 0xf8, 0xff, 0x1f, 0xf8, 0xff, 0x1f, 0x3c, 0x00, 0x3c, 0x1c, 0x00, 0x38, 0x1c, 0x00, 0x38, 0x00, 0x00, 0x38, 0x00, 0x00, 0x38, 0x00, 0x00, 0x3c, 0x00, 0xfc, 0x1f, 0xe0, 0xff, 0x1f, 0xf8, 0xff, 0x07, 0xfc, 0x07, 0x00, 0x3c, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x1c, 0x00, 0x00, 0xfc, 0xff, 0x3f, 0xfc, 0xff, 0x3f, 0xfc, 0xff, 0x3f, + 0xe0, 0xff, 0x07, 0xf8, 0xff, 0x1f, 0xf8, 0xff, 0x3f, 0x3c, 0x00, 0x38, 0x1c, 0x00, 0x38, 0x1c, 0x00, 0x38, 0x00, 0x00, 0x38, 0x00, 0x00, 0x38, 0x00, 0xfe, 0x3f, 0x00, 0xfe, 0x1f, 0x00, 0xfe, 0x3f, 0x00, 0x00, 0x38, 0x00, 0x00, 0x38, 0x1c, 0x00, 0x38, 0x1c, 0x00, 0x38, 0x3c, 0x00, 0x38, 0xf8, 0xff, 0x3f, 0xf8, 0xff, 0x1f, 0xe0, 0xff, 0x07, + 0x00, 0x80, 0x0f, 0x00, 0xc0, 0x0f, 0x00, 0xe0, 0x0f, 0x00, 0xf8, 0x0f, 0x00, 0x7c, 0x0f, 0x00, 0x1e, 0x0f, 0x00, 0x0f, 0x0f, 0xc0, 0x07, 0x0f, 0xe0, 0x01, 0x0f, 0xf0, 0x00, 0x0f, 0x7c, 0x00, 0x0f, 0x1e, 0x00, 0x0f, 0xfe, 0xff, 0x7f, 0xfe, 0xff, 0x7f, 0xfe, 0xff, 0x7f, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x0f, + 0xfc, 0xff, 0x3f, 0xfc, 0xff, 0x3f, 0xfc, 0xff, 0x3f, 0x1c, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x1c, 0x00, 0x00, 0xdc, 0xff, 0x07, 0xfc, 0xff, 0x1f, 0xfc, 0xff, 0x1f, 0x3c, 0x00, 0x3c, 0x1c, 0x00, 0x38, 0x00, 0x00, 0x38, 0x00, 0x00, 0x38, 0x1c, 0x00, 0x38, 0x1c, 0x00, 0x38, 0x3c, 0x00, 0x3c, 0xf8, 0xff, 0x1f, 0xf8, 0xff, 0x1f, 0xe0, 0xff, 0x07, + 0xe0, 0xff, 0x07, 0xf8, 0xff, 0x1f, 0xf8, 0xff, 0x1f, 0x3c, 0x00, 0x3c, 0x1c, 0x00, 0x38, 0x1c, 0x00, 0x38, 0x1c, 0x00, 0x00, 0xdc, 0xff, 0x07, 0xfc, 0xff, 0x1f, 0xfc, 0xff, 0x1f, 0x3c, 0x00, 0x3c, 0x1c, 0x00, 0x38, 0x1c, 0x00, 0x38, 0x1c, 0x00, 0x38, 0x1c, 0x00, 0x38, 0x3c, 0x00, 0x3c, 0xf8, 0xff, 0x1f, 0xf8, 0xff, 0x1f, 0xe0, 0xff, 0x07, + 0xfc, 0xff, 0x7f, 0xfc, 0xff, 0x7f, 0xfc, 0xff, 0x7f, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x0f, 0x00, 0x80, 0x07, 0x00, 0xc0, 0x03, 0x00, 0xe0, 0x01, 0x00, 0xf0, 0x01, 0x00, 0xf0, 0x00, 0x00, 0x78, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x0f, 0x00, 0x80, 0x0f, 0x00, 0x80, 0x07, 0x00, 0xc0, 0x03, 0x00, + 0xe0, 0xff, 0x07, 0xf8, 0xff, 0x1f, 0xf8, 0xff, 0x1f, 0x3c, 0x00, 0x3c, 0x1c, 0x00, 0x38, 0x1c, 0x00, 0x38, 0x1c, 0x00, 0x38, 0x3c, 0x00, 0x3c, 0xf8, 0xff, 0x1f, 0xf0, 0xff, 0x0f, 0xf8, 0xff, 0x1f, 0x3c, 0x00, 0x38, 0x1c, 0x00, 0x38, 0x1c, 0x00, 0x38, 0x1c, 0x00, 0x38, 0x3c, 0x00, 0x3c, 0xf8, 0xff, 0x1f, 0xf8, 0xff, 0x1f, 0xe0, 0xff, 0x07, + 0xe0, 0xff, 0x07, 0xf8, 0xff, 0x1f, 0xf8, 0xff, 0x1f, 0x3c, 0x00, 0x3c, 0x1c, 0x00, 0x38, 0x1c, 0x00, 0x38, 0x1c, 0x00, 0x38, 0x1c, 0x00, 0x38, 0x3c, 0x00, 0x3c, 0xf8, 0xff, 0x3f, 0xf8, 0xff, 0x3f, 0xe0, 0xff, 0x3b, 0x00, 0x00, 0x38, 0x1c, 0x00, 0x38, 0x1c, 0x00, 0x38, 0x3c, 0x00, 0x3c, 0xf8, 0xff, 0x1f, 0xf8, 0xff, 0x1f, 0xe0, 0xff, 0x07, +}; + +static const ui_font_t font_fixed_24x19 = { + { 24, 19 }, + font_fixed_24x19_glyph_data, + 0x30, 10, + (24 * 19 + 7U) >> 3 +}; + +static const uint8_t font_fixed_16x14_glyph_data[] = { + 0xf8, 0x1f, 0xfc, 0x3f, 0x0e, 0x70, 0x06, 0x60, 0x06, 0x60, 0x06, 0x60, 0x06, 0x60, 0x06, 0x60, 0x06, 0x60, 0x06, 0x60, 0x06, 0x60, 0x0e, 0x70, 0xfc, 0x3f, 0xf8, 0x1f, + 0x00, 0x03, 0x80, 0x03, 0xc0, 0x03, 0xe0, 0x03, 0x70, 0x03, 0x20, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, + 0xf8, 0x1f, 0xfc, 0x3f, 0x0e, 0x70, 0x06, 0x60, 0x00, 0x60, 0x00, 0x70, 0x80, 0x3f, 0xf8, 0x1f, 0xfc, 0x00, 0x0e, 0x00, 0x06, 0x00, 0x06, 0x00, 0xfe, 0x7f, 0xfe, 0x7f, + 0xf8, 0x1f, 0xfc, 0x3f, 0x0e, 0x70, 0x06, 0x60, 0x00, 0x60, 0x00, 0x60, 0xc0, 0x3f, 0xc0, 0x7f, 0x00, 0x60, 0x00, 0x60, 0x06, 0x60, 0x0e, 0x70, 0xfc, 0x3f, 0xf8, 0x1f, + 0x00, 0x1c, 0x00, 0x1e, 0x00, 0x1f, 0x80, 0x1b, 0xc0, 0x19, 0xe0, 0x18, 0x70, 0x18, 0x38, 0x18, 0x1c, 0x18, 0xfe, 0x7f, 0xfe, 0x7f, 0x00, 0x18, 0x00, 0x18, 0x00, 0x18, + 0xfe, 0x7f, 0xfe, 0x7f, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0xf6, 0x1f, 0xfe, 0x3f, 0x0e, 0x70, 0x00, 0x60, 0x00, 0x60, 0x06, 0x60, 0x0e, 0x70, 0xfc, 0x3f, 0xf8, 0x1f, + 0xf8, 0x1f, 0xfc, 0x3f, 0x0e, 0x70, 0x06, 0x60, 0x06, 0x00, 0xf6, 0x1f, 0xfe, 0x3f, 0x0e, 0x70, 0x06, 0x60, 0x06, 0x60, 0x06, 0x60, 0x0e, 0x70, 0xfc, 0x3f, 0xf8, 0x1f, + 0xfe, 0x7f, 0xfe, 0x7f, 0x00, 0x70, 0x00, 0x30, 0x00, 0x18, 0x00, 0x1c, 0x00, 0x0c, 0x00, 0x06, 0x00, 0x07, 0x80, 0x03, 0x80, 0x01, 0xc0, 0x00, 0xe0, 0x00, 0x60, 0x00, + 0xf8, 0x1f, 0xfc, 0x3f, 0x0e, 0x70, 0x06, 0x60, 0x06, 0x60, 0x0e, 0x70, 0xfc, 0x3f, 0xfc, 0x3f, 0x0e, 0x70, 0x06, 0x60, 0x06, 0x60, 0x0e, 0x70, 0xfc, 0x3f, 0xf8, 0x1f, + 0xf8, 0x1f, 0xfc, 0x3f, 0x0e, 0x70, 0x06, 0x60, 0x06, 0x60, 0x06, 0x60, 0x0e, 0x70, 0xfc, 0x7f, 0xf8, 0x6f, 0x00, 0x60, 0x06, 0x60, 0x0e, 0x70, 0xfc, 0x3f, 0xf8, 0x1f, +}; + +static const ui_font_t font_fixed_16x14 = { + { 16, 14 }, + font_fixed_16x14_glyph_data, + 0x30, 10, + (16 * 14 + 7U) >> 3 +}; + +static const uint8_t bitmap_amp_rx_data[] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x0c, 0x00, 0x30, 0x0c, 0x00, 0x30, 0x18, 0x00, 0x18, 0x18, 0x00, 0x18, 0x30, 0x00, 0x0c, 0x30, 0x00, 0x0c, 0x60, 0x00, 0x06, 0x60, 0x00, 0x06, 0xc0, 0x00, 0x03, 0xc0, 0x00, 0x03, 0x80, 0x81, 0x01, 0x80, 0x81, 0x01, 0x00, 0xc3, 0x00, 0x00, 0xc3, 0x00, 0x00, 0x66, 0x00, 0x00, 0x66, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x00 +}; + +static const ui_bitmap_t bitmap_amp_rx = { + { 24, 24 }, bitmap_amp_rx_data +}; + +static const uint8_t bitmap_amp_tx_data[] = { + 0x00, 0x18, 0x00, 0x00, 0x18, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x66, 0x00, 0x00, 0x66, 0x00, 0x00, 0xc3, 0x00, 0x00, 0xc3, 0x00, 0x80, 0x81, 0x01, 0x80, 0x81, 0x01, 0xc0, 0x00, 0x03, 0xc0, 0x00, 0x03, 0x60, 0x00, 0x06, 0x60, 0x00, 0x06, 0x30, 0x00, 0x0c, 0x30, 0x00, 0x0c, 0x18, 0x00, 0x18, 0x18, 0x00, 0x18, 0x0c, 0x00, 0x30, 0x0c, 0x00, 0x30, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff +}; + +static const ui_bitmap_t bitmap_amp_tx = { + { 24, 24 }, bitmap_amp_tx_data +}; + +static const uint8_t bitmap_antenna_data[] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x06, 0x18, 0x60, 0x06, 0x18, 0x60, 0x0c, 0x18, 0x30, 0x0c, 0x18, 0x30, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x30, 0x18, 0x0c, 0x30, 0x18, 0x0c, 0x60, 0x18, 0x06, 0x60, 0x18, 0x06, 0xc0, 0x18, 0x03, 0xc0, 0x18, 0x03, 0x80, 0x99, 0x01, 0x80, 0x99, 0x01, 0x00, 0xdb, 0x00, 0x00, 0xdb, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x00 +}; + +static const ui_bitmap_t bitmap_antenna = { + { 24, 24 }, bitmap_antenna_data +}; + +static const uint8_t bitmap_filter_hp_data[] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00, 0xc0, 0x03, 0x00, 0xc0, 0x03, 0x00, 0xc0, 0x03, 0x00, 0xc0, 0x03, 0xf8, 0xc7, 0x03, 0xfc, 0xc7, 0x03, 0x0e, 0xc0, 0x03, 0x06, 0xc0, 0x03, 0x03, 0xc0, 0x03, 0x03, 0xc0, 0x83, 0x01, 0xc0, 0x83, 0x01, 0xc0, 0xc3, 0x00, 0xc0, 0xc3, 0x00, 0xc0, 0x63, 0x00, 0xc0, 0x63, 0x00, 0xc0, 0x03, 0x00, 0xc0, 0x03, 0x00, 0xc0, 0x03, 0x00, 0xc0, 0x03, 0x00, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff +}; + +static const ui_bitmap_t bitmap_filter_hp = { + { 24, 24 }, bitmap_filter_hp_data +}; + +static const uint8_t bitmap_filter_lp_data[] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00, 0xc0, 0x03, 0x00, 0xc0, 0x03, 0x00, 0xc0, 0x03, 0x00, 0xc0, 0xe3, 0x1f, 0xc0, 0xe3, 0x3f, 0xc0, 0x03, 0x70, 0xc0, 0x03, 0x60, 0xc0, 0x03, 0xc0, 0xc0, 0x03, 0xc0, 0xc0, 0x03, 0x80, 0xc1, 0x03, 0x80, 0xc1, 0x03, 0x00, 0xc3, 0x03, 0x00, 0xc3, 0x03, 0x00, 0xc6, 0x03, 0x00, 0xc6, 0x03, 0x00, 0xc0, 0x03, 0x00, 0xc0, 0x03, 0x00, 0xc0, 0x03, 0x00, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff +}; + +static const ui_bitmap_t bitmap_filter_lp = { + { 24, 24 }, bitmap_filter_lp_data +}; + +static const uint8_t bitmap_mixer_data[] = { + 0x00, 0x7e, 0x00, 0xc0, 0xff, 0x03, 0xe0, 0x81, 0x07, 0x70, 0x00, 0x0e, 0x38, 0x00, 0x1c, 0x7c, 0x00, 0x3e, 0xee, 0x00, 0x77, 0xc6, 0x81, 0x63, 0x86, 0xc3, 0x61, 0x03, 0xe7, 0xc0, 0x03, 0x7e, 0xc0, 0x03, 0x3c, 0xc0, 0x03, 0x3c, 0xc0, 0x03, 0x7e, 0xc0, 0x03, 0xe7, 0xc0, 0x86, 0xc3, 0x61, 0xc6, 0x81, 0x63, 0xee, 0x00, 0x77, 0x7c, 0x00, 0x3e, 0x38, 0x00, 0x1c, 0x70, 0x00, 0x0e, 0xe0, 0x81, 0x07, 0xc0, 0xff, 0x03, 0x00, 0x7e, 0x00 +}; + +static const ui_bitmap_t bitmap_mixer = { + { 24, 24 }, bitmap_mixer_data +}; + +static const uint8_t bitmap_wire_8_data[] = { + 0xff, 0xff +}; + +static const ui_bitmap_t bitmap_wire_8 = { + { 2, 8 }, bitmap_wire_8_data +}; + +static const uint8_t bitmap_wire_24_data[] = { + 0x00, 0x18, 0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x00 +}; + +static const ui_bitmap_t bitmap_wire_24 = { + { 24, 24 }, bitmap_wire_24_data +}; + +static const uint8_t bitmap_waves_data[] = { + 0x00, 0x03, 0x00, 0x03, 0x00, 0x06, 0x30, 0x06, 0x30, 0x06, 0x30, 0x06, 0x60, 0x0c, 0x63, 0x0c, 0x63, 0x0c, 0x63, 0x0c, 0x63, 0x0c, 0x63, 0x0c, 0x63, 0x0c, 0x60, 0x0c, 0x30, 0x06, 0x30, 0x06, 0x30, 0x06, 0x00, 0x06, 0x00, 0x03, 0x00, 0x03 +}; + +static const ui_bitmap_t bitmap_waves = { + { 16, 20 }, bitmap_waves_data +}; + +static ui_color_t portapack_color_rgb( + const uint_fast8_t r, + const uint_fast8_t g, + const uint_fast8_t b +) { + const ui_color_t result = { + .v = ((r & 0xf8) << 8) | ((g & 0xfc) << 3) | ((b & 0xf8) >> 3) + }; + return result; +} + +#define ARRAY_SIZEOF(x) (sizeof(x) / sizeof(x[0])) + +static void portapack_sleep_milliseconds(const uint32_t milliseconds) { + /* NOTE: Naively assumes 204 MHz instruction cycle clock and five instructions per count */ + delay(milliseconds * 40800); +} + +static struct gpio_t gpio_io_stbx = GPIO(5, 0); /* P2_0 */ +static struct gpio_t gpio_addr = GPIO(5, 1); /* P2_1 */ +static struct gpio_t gpio_lcd_te = GPIO(5, 3); /* P2_3 */ +static struct gpio_t gpio_unused = GPIO(5, 7); /* P2_8 */ +static struct gpio_t gpio_lcd_rdx = GPIO(5, 4); /* P2_4 */ +static struct gpio_t gpio_lcd_wrx = GPIO(1, 10); /* P2_9 */ +static struct gpio_t gpio_dir = GPIO(1, 13); /* P2_13 */ + +typedef struct portapack_t { + gpio_t gpio_dir; + gpio_t gpio_lcd_rdx; + gpio_t gpio_lcd_wrx; + gpio_t gpio_io_stbx; + gpio_t gpio_addr; + gpio_port_t* const gpio_port_data; + uint8_t io_reg; +} portapack_t; + +portapack_t portapack = { + .gpio_dir = &gpio_dir, + .gpio_lcd_rdx = &gpio_lcd_rdx, + .gpio_lcd_wrx = &gpio_lcd_wrx, + .gpio_io_stbx = &gpio_io_stbx, + .gpio_addr = &gpio_addr, + .gpio_port_data = GPIO_LPC_PORT(3), + .io_reg = 0x03, +}; + +/* NOTE: Code below assumes the shift value is "8". */ +#define GPIO_DATA_SHIFT (8) +static const uint32_t gpio_data_mask = 0xFFU << GPIO_DATA_SHIFT; + +static void portapack_data_mask_set(portapack_t* const portapack) { + portapack->gpio_port_data->mask = ~gpio_data_mask; +} + +static void portapack_data_write_low(portapack_t* const portapack, const uint32_t value) { + portapack->gpio_port_data->mpin = (value << GPIO_DATA_SHIFT); +} + +static void portapack_data_write_high(portapack_t* const portapack, const uint32_t value) { + /* NOTE: Assumes no other bits in the port are masked. */ + /* NOTE: Assumes that bits 15 through 8 are masked. */ + portapack->gpio_port_data->mpin = value; +} + +static void portapack_dir_read(portapack_t* const portapack) { + portapack->gpio_port_data->dir &= ~gpio_data_mask; + gpio_set(portapack->gpio_dir); +} + +static void portapack_dir_write(portapack_t* const portapack) { + gpio_clear(portapack->gpio_dir); + portapack->gpio_port_data->dir |= gpio_data_mask; + /* TODO: Manipulating DIR[3] makes me queasy. The RFFC5072 DATA pin + * is also on port 3, and switches direction periodically... + * Time to resort to bit-banding to enforce atomicity? But then, how + * to change direction on eight bits efficiently? Or do I care, since + * the PortaPack data bus shouldn't change direction too frequently? + */ +} + +static void portapack_lcd_rd_assert(portapack_t* const portapack) { + gpio_clear(portapack->gpio_lcd_rdx); +} + +static void portapack_lcd_rd_deassert(portapack_t* const portapack) { + gpio_set(portapack->gpio_lcd_rdx); +} + +static void portapack_lcd_wr_assert(portapack_t* const portapack) { + gpio_clear(portapack->gpio_lcd_wrx); +} + +static void portapack_lcd_wr_deassert(portapack_t* const portapack) { + gpio_set(portapack->gpio_lcd_wrx); +} + +static void portapack_io_stb_assert(portapack_t* const portapack) { + gpio_clear(portapack->gpio_io_stbx); +} + +static void portapack_io_stb_deassert(portapack_t* const portapack) { + gpio_set(portapack->gpio_io_stbx); +} + +static void portapack_addr(portapack_t* const portapack, const bool value) { + gpio_write(portapack->gpio_addr, value); +} + +static void portapack_lcd_command(portapack_t* const portapack, const uint32_t value) { + portapack_data_write_high(portapack, 0); /* Drive high byte (with zero -- don't care) */ + portapack_dir_write(portapack); /* Turn around data bus, MCU->CPLD */ + portapack_addr(portapack, 0); /* Indicate command */ + __asm__("nop"); + __asm__("nop"); + __asm__("nop"); + portapack_lcd_wr_assert(portapack); /* Latch high byte */ + + portapack_data_write_low(portapack, value); /* Drive low byte (pass-through) */ + __asm__("nop"); + __asm__("nop"); + __asm__("nop"); + portapack_lcd_wr_deassert(portapack); /* Complete write operation */ + + portapack_addr(portapack, 1); /* Set up for data phase (most likely after a command) */ +} + +static void portapack_lcd_write_data(portapack_t* const portapack, const uint32_t value) { + // NOTE: Assumes and DIR=0 and ADDR=1 from command phase. + portapack_data_write_high(portapack, value); /* Drive high byte */ + __asm__("nop"); + portapack_lcd_wr_assert(portapack); /* Latch high byte */ + + portapack_data_write_low(portapack, value); /* Drive low byte (pass-through) */ + __asm__("nop"); + __asm__("nop"); + __asm__("nop"); + portapack_lcd_wr_deassert(portapack); /* Complete write operation */ +} + +static void portapack_io_write(portapack_t* const portapack, const bool address, const uint_fast16_t value) { + portapack_data_write_low(portapack, value); + portapack_dir_write(portapack); + portapack_addr(portapack, address); + __asm__("nop"); + __asm__("nop"); + __asm__("nop"); + portapack_io_stb_assert(portapack); + __asm__("nop"); + __asm__("nop"); + __asm__("nop"); + portapack_io_stb_deassert(portapack); +} + +static void portapack_lcd_data_write_command_and_data( + portapack_t* const portapack, + const uint_fast8_t command, + const uint8_t* data, + const size_t data_count +) { + portapack_lcd_command(portapack, command); + for(size_t i=0; iio_reg = (portapack->io_reg & 0x7f) | (on ? (1 << 7) : 0); + portapack_io_write(portapack, 1, portapack->io_reg); +} + +static void portapack_lcd_reset_state(portapack_t* const portapack, const bool active) { + portapack->io_reg = (portapack->io_reg & 0xfe) | (active ? (1 << 0) : 0); + portapack_io_write(portapack, 1, portapack->io_reg); +} + +static void portapack_lcd_sleep_out(portapack_t* const portapack) { + const uint8_t cmd_11[] = {}; + portapack_lcd_data_write_command_and_data(portapack, 0x11, cmd_11, ARRAY_SIZEOF(cmd_11)); + // "It will be necessary to wait 120msec after sending Sleep Out + // command (when in Sleep In Mode) before Sleep In command can be + // sent." + portapack_sleep_milliseconds(120); +} + +static void portapack_lcd_display_on(portapack_t* const portapack) { + const uint8_t cmd_29[] = {}; + portapack_lcd_data_write_command_and_data(portapack, 0x29, cmd_29, ARRAY_SIZEOF(cmd_29)); +} + +static void portapack_lcd_wake(portapack_t* const portapack) { + portapack_lcd_sleep_out(portapack); + portapack_lcd_display_on(portapack); +} + +static void portapack_if_init(portapack_t* const portapack) { + portapack_data_mask_set(portapack); + portapack_data_write_high(portapack, 0); + + portapack_dir_read(portapack); + portapack_lcd_rd_deassert(portapack); + portapack_lcd_wr_deassert(portapack); + portapack_io_stb_deassert(portapack); + portapack_addr(portapack, 0); + + gpio_output(portapack->gpio_dir); + gpio_output(portapack->gpio_lcd_rdx); + gpio_output(portapack->gpio_lcd_wrx); + gpio_output(portapack->gpio_io_stbx); + gpio_output(portapack->gpio_addr); + /* gpio_input(portapack->gpio_rot_a); */ + /* gpio_input(portapack->gpio_rot_b); */ + + scu_pinmux(SCU_PINMUX_PP_D0, SCU_CONF_FUNCTION0 | SCU_GPIO_PDN); + scu_pinmux(SCU_PINMUX_PP_D1, SCU_CONF_FUNCTION0 | SCU_GPIO_PDN); + scu_pinmux(SCU_PINMUX_PP_D2, SCU_CONF_FUNCTION0 | SCU_GPIO_PDN); + scu_pinmux(SCU_PINMUX_PP_D3, SCU_CONF_FUNCTION0 | SCU_GPIO_PDN); + scu_pinmux(SCU_PINMUX_PP_D4, SCU_CONF_FUNCTION0 | SCU_GPIO_PDN); + scu_pinmux(SCU_PINMUX_PP_D5, SCU_CONF_FUNCTION0 | SCU_GPIO_PDN); + scu_pinmux(SCU_PINMUX_PP_D6, SCU_CONF_FUNCTION0 | SCU_GPIO_PDN); + scu_pinmux(SCU_PINMUX_PP_D7, SCU_CONF_FUNCTION0 | SCU_GPIO_PDN); + + scu_pinmux(SCU_PINMUX_PP_DIR, SCU_CONF_FUNCTION0 | SCU_GPIO_NOPULL); + scu_pinmux(SCU_PINMUX_PP_LCD_RDX, SCU_CONF_FUNCTION4 | SCU_GPIO_NOPULL); + scu_pinmux(SCU_PINMUX_PP_LCD_WRX, SCU_CONF_FUNCTION0 | SCU_GPIO_NOPULL); + scu_pinmux(SCU_PINMUX_PP_IO_STBX, SCU_CONF_FUNCTION4 | SCU_GPIO_NOPULL); + scu_pinmux(SCU_PINMUX_PP_ADDR, SCU_CONF_FUNCTION4 | SCU_GPIO_NOPULL); + /* scu_pinmux(SCU_PINMUX_PP_LCD_TE, SCU_CONF_FUNCTION4 | SCU_GPIO_NOPULL); */ + /* scu_pinmux(SCU_PINMUX_PP_UNUSED, SCU_CONF_FUNCTION4 | SCU_GPIO_NOPULL); */ +} + +static void portapack_lcd_reset(portapack_t* const portapack) { + portapack_lcd_reset_state(portapack, false); + portapack_sleep_milliseconds(1); + portapack_lcd_reset_state(portapack, true); + portapack_sleep_milliseconds(10); + portapack_lcd_reset_state(portapack, false); + portapack_sleep_milliseconds(120); +} + +static void portapack_lcd_init(portapack_t* const portapack) { + // LCDs are configured for IM[2:0] = 001 + // 8080-I system, 16-bit parallel bus + + // + // 0x3a: DBI[2:0] = 101 + // MDT[1:0] = XX (if not in 18-bit mode, right?) + + // Power control B + // 0 + // PCEQ=1, DRV_ena=0, Power control=3 + const uint8_t cmd_cf[] = { 0x00, 0xD9, 0x30 }; + portapack_lcd_data_write_command_and_data(portapack, 0xCF, cmd_cf, ARRAY_SIZEOF(cmd_cf)); + + // Power on sequence control + const uint8_t cmd_ed[] = { 0x64, 0x03, 0x12, 0x81 }; + portapack_lcd_data_write_command_and_data(portapack, 0xED, cmd_ed, ARRAY_SIZEOF(cmd_ed)); + + // Driver timing control A + const uint8_t cmd_e8[] = { 0x85, 0x10, 0x78 }; + portapack_lcd_data_write_command_and_data(portapack, 0xE8, cmd_e8, ARRAY_SIZEOF(cmd_e8)); + + // Power control A + const uint8_t cmd_cb[] = { 0x39, 0x2C, 0x00, 0x34, 0x02 }; + portapack_lcd_data_write_command_and_data(portapack, 0xCB, cmd_cb, ARRAY_SIZEOF(cmd_cb)); + + // Pump ratio control + const uint8_t cmd_f7[] = { 0x20 }; + portapack_lcd_data_write_command_and_data(portapack, 0xF7, cmd_f7, ARRAY_SIZEOF(cmd_f7)); + + // Driver timing control B + const uint8_t cmd_ea[] = { 0x00, 0x00 }; + portapack_lcd_data_write_command_and_data(portapack, 0xEA, cmd_ea, ARRAY_SIZEOF(cmd_ea)); + + const uint8_t cmd_b1[] = { 0x00, 0x1B }; + portapack_lcd_data_write_command_and_data(portapack, 0xB1, cmd_b1, ARRAY_SIZEOF(cmd_b1)); + + // Blanking Porch Control + // VFP = 0b0000010 = 2 (number of HSYNC of vertical front porch) + // VBP = 0b0000010 = 2 (number of HSYNC of vertical back porch) + // HFP = 0b0001010 = 10 (number of DOTCLOCK of horizontal front porch) + // HBP = 0b0010100 = 20 (number of DOTCLOCK of horizontal back porch) + const uint8_t cmd_b5[] = { 0x02, 0x02, 0x0a, 0x14 }; + portapack_lcd_data_write_command_and_data(portapack, 0xB5, cmd_b5, ARRAY_SIZEOF(cmd_b5)); + + // Display Function Control + // PT[1:0] = 0b10 + // PTG[1:0] = 0b10 + // ISC[3:0] = 0b0010 (scan cycle interval of gate driver: 5 frames) + // SM = 0 (gate driver pin arrangement in combination with GS) + // SS = 1 (source output scan direction S720 -> S1) + // GS = 0 (gate output scan direction G1 -> G320) + // REV = 1 (normally white) + // NL = 0b100111 (default) + // PCDIV = 0b000000 (default?) + const uint8_t cmd_b6[] = { 0x0A, 0xA2, 0x27, 0x00 }; + portapack_lcd_data_write_command_and_data(portapack, 0xB6, cmd_b6, ARRAY_SIZEOF(cmd_b6)); + + // Power Control 1 + //VRH[5:0] + const uint8_t cmd_c0[] = { 0x1B }; + portapack_lcd_data_write_command_and_data(portapack, 0xC0, cmd_c0, ARRAY_SIZEOF(cmd_c0)); + + // Power Control 2 + //SAP[2:0];BT[3:0] + const uint8_t cmd_c1[] = { 0x12 }; + portapack_lcd_data_write_command_and_data(portapack, 0xC1, cmd_c1, ARRAY_SIZEOF(cmd_c1)); + + // VCOM Control 1 + const uint8_t cmd_c5[] = { 0x32, 0x3C }; + portapack_lcd_data_write_command_and_data(portapack, 0xC5, cmd_c5, ARRAY_SIZEOF(cmd_c5)); + + // VCOM Control 2 + const uint8_t cmd_c7[] = { 0x9B }; + portapack_lcd_data_write_command_and_data(portapack, 0xC7, cmd_c7, ARRAY_SIZEOF(cmd_c7)); + + // Memory Access Control + // Invert X and Y memory access order, so upper-left of + // screen is (0,0) when writing to display. + const uint8_t cmd_36[] = { + (1 << 7) | // MY=1 + (1 << 6) | // MX=1 + (0 << 5) | // MV=0 + (1 << 4) | // ML=1: reverse vertical refresh to simplify scrolling logic + (1 << 3) // BGR=1: For Kingtech LCD, BGR filter. + }; + portapack_lcd_data_write_command_and_data(portapack, 0x36, cmd_36, ARRAY_SIZEOF(cmd_36)); + + // COLMOD: Pixel Format Set + // DPI=101 (16 bits/pixel), DBI=101 (16 bits/pixel) + const uint8_t cmd_3a[] = { 0x55 }; + portapack_lcd_data_write_command_and_data(portapack, 0x3A, cmd_3a, ARRAY_SIZEOF(cmd_3a)); + + //portapack_lcd_data_write_command_and_data(0xF6, { 0x01, 0x30 }); + // WEMODE=1 (reset column and page number on overflow) + // MDT[1:0] + // EPF[1:0]=00 (use channel MSB for LSB) + // RIM=0 (If COLMOD[6:4]=101 (65k color), 16-bit RGB interface (1 transfer/pixel)) + // RM=0 (system interface/VSYNC interface) + // DM[1:0]=00 (internal clock operation) + // ENDIAN=0 (doesn't matter with 16-bit interface) + const uint8_t cmd_f6[] = { 0x01, 0x30, 0x00 }; + portapack_lcd_data_write_command_and_data(portapack, 0xF6, cmd_f6, ARRAY_SIZEOF(cmd_f6)); + + // 3Gamma Function Disable + const uint8_t cmd_f2[] = { 0x00 }; + portapack_lcd_data_write_command_and_data(portapack, 0xF2, cmd_f2, ARRAY_SIZEOF(cmd_f2)); + + // Gamma curve selected + const uint8_t cmd_26[] = { 0x01 }; + portapack_lcd_data_write_command_and_data(portapack, 0x26, cmd_26, ARRAY_SIZEOF(cmd_26)); + + // Set Gamma + const uint8_t cmd_e0[] = { + 0x0F, 0x1D, 0x19, 0x0E, 0x10, 0x07, 0x4C, 0x63, + 0x3F, 0x03, 0x0D, 0x00, 0x26, 0x24, 0x04 + }; + portapack_lcd_data_write_command_and_data(portapack, 0xE0, cmd_e0, ARRAY_SIZEOF(cmd_e0)); + + // Set Gamma + const uint8_t cmd_e1[] = { + 0x00, 0x1C, 0x1F, 0x02, 0x0F, 0x03, 0x35, 0x25, + 0x47, 0x04, 0x0C, 0x0B, 0x29, 0x2F, 0x05 + }; + portapack_lcd_data_write_command_and_data(portapack, 0xE1, cmd_e1, ARRAY_SIZEOF(cmd_e1)); + + portapack_lcd_wake(portapack); + + // Turn on Tearing Effect Line (TE) output signal. + const uint8_t cmd_35[] = { 0b00000000 }; + portapack_lcd_data_write_command_and_data(portapack, 0x35, cmd_35, ARRAY_SIZEOF(cmd_35)); +} + +static void portapack_lcd_ramwr_start(portapack_t* const portapack) { + const uint8_t cmd_2c[] = {}; + portapack_lcd_data_write_command_and_data(portapack, 0x2c, cmd_2c, ARRAY_SIZEOF(cmd_2c)); +} + +static void portapack_lcd_set(portapack_t* const portapack, const uint_fast8_t command, const uint_fast16_t start, const uint_fast16_t end) { + const uint8_t data[] = { + (start >> 8), (start & 0xff), + (end >> 8), (end & 0xff) + }; + portapack_lcd_data_write_command_and_data(portapack, command, data, ARRAY_SIZEOF(data)); +} + +static void portapack_lcd_caset(portapack_t* const portapack, const uint_fast16_t start_column, uint_fast16_t end_column) { + portapack_lcd_set(portapack, 0x2a, start_column, end_column); +} + +static void portapack_lcd_paset(portapack_t* const portapack, const uint_fast16_t start_page, const uint_fast16_t end_page) { + portapack_lcd_set(portapack, 0x2b, start_page, end_page); +} + + +static void portapack_lcd_start_ram_write( + portapack_t* const portapack, + ui_rect_t rect +) { + portapack_lcd_caset(portapack, rect.point.x, rect.point.x + rect.size.width - 1); + portapack_lcd_paset(portapack, rect.point.y, rect.point.y + rect.size.height - 1); + portapack_lcd_ramwr_start(portapack); +} + +static void portapack_lcd_fill_rectangle( + portapack_t* const portapack, + ui_rect_t rect, + ui_color_t color +) { + portapack_lcd_start_ram_write(portapack, rect); + portapack_lcd_write_pixels_color(portapack, color, rect.size.width * rect.size.height); +} + +static void portapack_draw_bitmap( + portapack_t* const portapack, + const ui_point_t point, + const ui_bitmap_t bitmap, + const ui_color_t foreground, + const ui_color_t background +) { + const ui_rect_t rect = { + .point = point, + .size = bitmap.size + }; + + portapack_lcd_start_ram_write(portapack, rect); + + const size_t count = bitmap.size.width * bitmap.size.height; + for(size_t i=0; i> 3] & (1U << (i & 0x7)); + portapack_lcd_write_pixel(portapack, pixel ? foreground : background); + } +} + +static ui_bitmap_t portapack_font_glyph( + const ui_font_t* const font, + const char c +) { + if( c >= font->c_start ) { + const uint_fast8_t index = c - font->c_start; + if( index < font->c_count ) { + const ui_bitmap_t bitmap = { + .size = font->glyph_size, + .data = &font->data[index * font->data_stride] + }; + return bitmap; + } + } + + const ui_bitmap_t bitmap = { + .size = font->glyph_size, + .data = font->data, + }; + return bitmap; +} + +static void portapack_lcd_draw_int(portapack_t* const portapack, const ui_point_t point, uint64_t value, size_t field_width) { + ui_point_t point_next = { + .x = point.x + font_fixed_8x16.glyph_size.width * field_width, + .y = point.y + }; + + const ui_color_t color_background = portapack_color_rgb(0x00, 0x00, 0xff); + const ui_color_t color_foreground = portapack_color_rgb(0xff, 0xff, 0xff); + + while(value) { + const char c = '0' + value % 10; + value /= 10; + + const ui_bitmap_t glyph = portapack_font_glyph(&font_fixed_8x16, c); + point_next.x -= glyph.size.width; + portapack_draw_bitmap(portapack, point_next, glyph, color_foreground, color_background); + } + + while(point_next.x > point.x) { + const char c = ' '; + const ui_bitmap_t glyph = portapack_font_glyph(&font_fixed_8x16, c); + point_next.x -= glyph.size.width; + portapack_draw_bitmap(portapack, point_next, glyph, color_foreground, color_background); + } +} + +static void portapack_lcd_clear(portapack_t* const portapack) { + const ui_rect_t rect_screen = { { 0, 0 }, { 240, 320 } }; + const ui_color_t color_background = portapack_color_rgb(0x00, 0x00, 0xff); + portapack_lcd_fill_rectangle(portapack, rect_screen, color_background); +} + +typedef struct draw_list_t { + const ui_bitmap_t* bitmap; + const ui_point_t point; +} draw_list_t; + +static draw_list_t radio_draw_list[] = { + { &bitmap_antenna, { 32, 64 } }, + { &bitmap_wire_8, { 43, 88 } }, + { &bitmap_amp_rx, { 32, 96 } }, + { &bitmap_wire_8, { 43, 120 } }, + { &bitmap_filter_hp, { 32, 128 } }, + { &bitmap_wire_8, { 43, 152 } }, + { &bitmap_mixer, { 32, 160 } }, + { &bitmap_wire_8, { 43, 184 } }, + { &bitmap_amp_rx, { 32, 192 } }, + { &bitmap_wire_8, { 43, 216 } }, + { &bitmap_mixer, { 32, 224 } }, + { &bitmap_wire_8, { 43, 248 } }, + { &bitmap_filter_lp, { 32, 256 } }, + { &bitmap_wire_8, { 43, 280 } }, + { &bitmap_amp_rx, { 32, 288 } }, + { &bitmap_wire_8, { 43, 312 } }, +}; + +typedef enum { + RADIO_DRAW_LIST_ITEM_ANTENNA = 0, + RADIO_DRAW_LIST_ITEM_RF_AMP = 2, + RADIO_DRAW_LIST_ITEM_IMAGE_FILTER = 4, + RADIO_DRAW_LIST_ITEM_RF_MIXER = 6, + RADIO_DRAW_LIST_ITEM_BB_LNA_AMP = 8, + RADIO_DRAW_LIST_ITEM_BB_MIXER = 10, + RADIO_DRAW_LIST_ITEM_BB_FILTER = 12, + RADIO_DRAW_LIST_ITEM_BB_VGA_AMP = 14 +} radio_draw_list_item_t; + +static const uint8_t VALUES_X = 72; + +static void portapack_draw_radio_path( + portapack_t* const portapack, + const draw_list_t* const draw_list, + const size_t count +) { + const ui_color_t color_background = portapack_color_rgb(0x00, 0x00, 0xff); + const ui_color_t color_foreground = portapack_color_rgb(0xff, 0xff, 0xff); + + for( size_t i=0; i0) && (value == 0) ) { + const ui_bitmap_t glyph = portapack_font_glyph(&font_fixed_24x19, '0'); + point.x -= glyph.size.width; + const ui_rect_t rect = { point, glyph.size }; + portapack_lcd_fill_rectangle(&portapack, rect, color_background); + } else { + const char c = '0' + value % 10; + value /= 10; + + const ui_bitmap_t glyph = portapack_font_glyph(&font_fixed_24x19, c); + point.x -= glyph.size.width; + portapack_draw_bitmap(&portapack, point, glyph, color_foreground, color_background); + } + } +} + +static rf_path_direction_t portapack_direction = RF_PATH_DIRECTION_OFF; + +static void portapack_radio_path_redraw() { + portapack_draw_radio_path(&portapack, radio_draw_list, ARRAY_SIZEOF(radio_draw_list)); +} + +void hackrf_ui_setDirection(const rf_path_direction_t direction) { + switch(direction) { + case RF_PATH_DIRECTION_TX: + radio_draw_list[RADIO_DRAW_LIST_ITEM_RF_AMP].bitmap = &bitmap_amp_tx; + radio_draw_list[RADIO_DRAW_LIST_ITEM_BB_LNA_AMP].bitmap = &bitmap_amp_tx; + radio_draw_list[RADIO_DRAW_LIST_ITEM_BB_VGA_AMP].bitmap = &bitmap_wire_24; + break; + + case RF_PATH_DIRECTION_RX: + radio_draw_list[RADIO_DRAW_LIST_ITEM_RF_AMP].bitmap = &bitmap_amp_rx; + radio_draw_list[RADIO_DRAW_LIST_ITEM_BB_LNA_AMP].bitmap = &bitmap_amp_rx; + radio_draw_list[RADIO_DRAW_LIST_ITEM_BB_VGA_AMP].bitmap = &bitmap_amp_rx; + break; + + case RF_PATH_DIRECTION_OFF: + default: + break; + } + + portapack_radio_path_redraw(); + + portapack_direction = direction; +} + +void hackrf_ui_setLNAPower(bool lna_on) { + radio_draw_list[RADIO_DRAW_LIST_ITEM_RF_AMP].bitmap = lna_on + ? ((portapack_direction == RF_PATH_DIRECTION_TX) ? &bitmap_amp_tx : &bitmap_amp_rx) + : &bitmap_wire_24; + portapack_radio_path_redraw(); +} + +void hackrf_ui_setFilter(const rf_path_filter_t filter) { + const ui_bitmap_t* bitmap = &bitmap_wire_24; + + switch(filter) { + case RF_PATH_FILTER_BYPASS: + bitmap = &bitmap_wire_24; + break; + + case RF_PATH_FILTER_LOW_PASS: + bitmap = &bitmap_filter_lp; + break; + + case RF_PATH_FILTER_HIGH_PASS: + bitmap = &bitmap_filter_hp; + break; + } + + radio_draw_list[RADIO_DRAW_LIST_ITEM_IMAGE_FILTER].bitmap = bitmap; + portapack_radio_path_redraw(); +} + +void hackrf_ui_setBBLNAGain(const uint32_t gain_db) { + ui_point_t point = { VALUES_X, radio_draw_list[RADIO_DRAW_LIST_ITEM_BB_LNA_AMP].point.y + 4 }; + portapack_lcd_draw_int(&portapack, point, gain_db, 2); +} + +void hackrf_ui_setFilterBW(uint32_t bandwidth) { + ui_point_t point = { VALUES_X, radio_draw_list[RADIO_DRAW_LIST_ITEM_BB_FILTER].point.y + 4 }; + portapack_lcd_draw_int(&portapack, point, bandwidth, 8); +} + +void hackrf_ui_setBBVGAGain(const uint32_t gain_db) { + ui_point_t point = { VALUES_X, radio_draw_list[RADIO_DRAW_LIST_ITEM_BB_VGA_AMP].point.y + 4 }; + portapack_lcd_draw_int(&portapack, point, gain_db, 2); +} + +void hackrf_ui_setSampleRate(uint32_t sample_rate) { + ui_point_t point = { VALUES_X, 320 - 1 * 16 }; + portapack_lcd_draw_int(&portapack, point, sample_rate, 8); +} + +#endif diff --git a/firmware/common/ui_portapack.h b/firmware/common/ui_portapack.h new file mode 100644 index 00000000..d4ddda18 --- /dev/null +++ b/firmware/common/ui_portapack.h @@ -0,0 +1,59 @@ +/* + * Copyright 2018 Jared Boone + * + * This file is part of HackRF. + * + * 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 __UI_PORTAPACK_H__ +#define __UI_PORTAPACK_H__ + +#include + +typedef struct ui_color_t { + uint16_t v; +} ui_color_t; + +typedef struct ui_point_t { + int16_t x; + int16_t y; +} ui_point_t; + +typedef struct ui_size_t { + int16_t width; + int16_t height; +} ui_size_t; + +typedef struct ui_rect_t { + ui_point_t point; + ui_size_t size; +} ui_rect_t; + +typedef struct ui_bitmap_t { + ui_size_t size; + const uint8_t* const data; +} ui_bitmap_t; + +typedef struct ui_font_t { + const ui_size_t glyph_size; + const uint8_t* const data; + char c_start; + size_t c_count; + size_t data_stride; +} ui_font_t; + +#endif/*__UI_PORTAPACK_H__*/ diff --git a/firmware/hackrf-common.cmake b/firmware/hackrf-common.cmake index 8a456e04..baa77b78 100644 --- a/firmware/hackrf-common.cmake +++ b/firmware/hackrf-common.cmake @@ -58,11 +58,19 @@ else() set(MCU_PARTNO LPC4330) endif() +if(BOARD STREQUAL "RAD1O") + set(USER_INTERFACE RAD1O) +endif() + +if(NOT DEFINED USER_INTERFACE) + set(USER_INTERFACE NONE) +endif() + if(NOT DEFINED SRC_M0) set(SRC_M0 "${PATH_HACKRF_FIRMWARE_COMMON}/m0_sleep.c") endif() -SET(HACKRF_OPTS "-D${BOARD} -DLPC43XX -D${MCU_PARTNO} -DTX_ENABLE -D'VERSION_STRING=\"git-${VERSION}\"'") +SET(HACKRF_OPTS "-D${BOARD} -DUSER_INTERFACE_${USER_INTERFACE} -DLPC43XX -D${MCU_PARTNO} -DTX_ENABLE -D'VERSION_STRING=\"git-${VERSION}\"'") SET(LDSCRIPT_M4 "-T${PATH_HACKRF_FIRMWARE_COMMON}/${MCU_PARTNO}_M4_memory.ld -Tlibopencm3_lpc43xx_rom_to_ram.ld -T${PATH_HACKRF_FIRMWARE_COMMON}/LPC43xx_M4_M0_image_from_text.ld") @@ -129,6 +137,13 @@ macro(DeclareTargets) ) endif() + if(USER_INTERFACE STREQUAL "PORTAPACK") + SET(SRC_M4 + ${SRC_M4} + ${PATH_HACKRF_FIRMWARE_COMMON}/ui_portapack.c + ) + endif() + configure_file( ${PATH_HACKRF_FIRMWARE_COMMON}/m0_bin.s.cmake m0_bin.s