From 1a80af8d1a83a070443a66f7f54f6c9e0e49ad24 Mon Sep 17 00:00:00 2001 From: hugen79 Date: Sun, 21 Nov 2021 19:45:02 +0800 Subject: [PATCH] Synchronize DiSlord1.0.71 version, Now you can set the time through the "Expert Setting" menu. Both the newly sold NanoVNA-H Rev3.6 and NanoVNA-H4 Rev4.3 have installed a 36.768kHz crystal, and the LSE can be used to keep the time correct after shutting down. Add a 6x11 font version to the 2.8-inch NanoVNA-H to enhance readability as much as possible while maintaining dual-column display. Thanks to DiSlord for providing the new font file. --- FatFs/ff.h | 6 +- FatFs/{ffconf.h => ffconf_072.h} | 0 FatFs/ffconf_303.h | 329 +++ Font6x11.c | 3482 +++++++++++++++++++++++++++ Font7x13b.c => Font7x11b.c | 0 Makefile | 9 +- doc/Schematic_NanoVNA-H4_REV4_3.pdf | Bin 0 -> 265952 bytes lc_matching.c | 317 +++ main.c | 3 +- nanovna.h | 64 +- numfont20x22.c | 23 + plot.c | 53 +- si5351.c | 78 +- si5351.h | 1 + ui.c | 154 +- 15 files changed, 4401 insertions(+), 118 deletions(-) rename FatFs/{ffconf.h => ffconf_072.h} (100%) create mode 100644 FatFs/ffconf_303.h create mode 100644 Font6x11.c rename Font7x13b.c => Font7x11b.c (100%) create mode 100644 doc/Schematic_NanoVNA-H4_REV4_3.pdf diff --git a/FatFs/ff.h b/FatFs/ff.h index 4866576..58efb01 100644 --- a/FatFs/ff.h +++ b/FatFs/ff.h @@ -26,7 +26,11 @@ extern "C" { #endif -#include "ffconf.h" /* FatFs configuration options */ +#if defined(NANOVNA_F303) +#include "ffconf_303.h" /* FatFs configuration options for F303 */ +#else +#include "ffconf_072.h" /* FatFs configuration options for F072 */ +#endif #if FF_DEFINED != FFCONF_DEF #error Wrong configuration file (ffconf.h). diff --git a/FatFs/ffconf.h b/FatFs/ffconf_072.h similarity index 100% rename from FatFs/ffconf.h rename to FatFs/ffconf_072.h diff --git a/FatFs/ffconf_303.h b/FatFs/ffconf_303.h new file mode 100644 index 0000000..737b04a --- /dev/null +++ b/FatFs/ffconf_303.h @@ -0,0 +1,329 @@ +/*---------------------------------------------------------------------------/ +/ FatFs Functional Configurations +/---------------------------------------------------------------------------*/ + +#define FFCONF_DEF 86631 /* Revision ID */ + +/*---------------------------------------------------------------------------/ +/ Function Configurations +/---------------------------------------------------------------------------*/ + +#define FF_FS_READONLY 0 +/* This option switches read-only configuration. (0:Read/Write or 1:Read-only) +/ Read-only configuration removes writing API functions, f_write(), f_sync(), +/ f_unlink(), f_mkdir(), f_chmod(), f_rename(), f_truncate(), f_getfree() +/ and optional writing functions as well. */ + + +#define FF_FS_MINIMIZE 0 +/* This option defines minimization level to remove some basic API functions. +/ +/ 0: Basic functions are fully enabled. +/ 1: f_stat(), f_getfree(), f_unlink(), f_mkdir(), f_truncate() and f_rename() +/ are removed. +/ 2: f_opendir(), f_readdir() and f_closedir() are removed in addition to 1. +/ 3: f_lseek() function is removed in addition to 2. */ + + +#define FF_USE_FIND 1 +/* This option switches filtered directory read functions, f_findfirst() and +/ f_findnext(). (0:Disable, 1:Enable 2:Enable with matching altname[] too) */ + + +#define FF_USE_MKFS 0 +/* This option switches f_mkfs() function. (0:Disable or 1:Enable) */ + + +#define FF_USE_FASTSEEK 0 +/* This option switches fast seek function. (0:Disable or 1:Enable) */ + + +#define FF_USE_EXPAND 0 +/* This option switches f_expand function. (0:Disable or 1:Enable) */ + + +#define FF_USE_CHMOD 0 +/* This option switches attribute manipulation functions, f_chmod() and f_utime(). +/ (0:Disable or 1:Enable) Also FF_FS_READONLY needs to be 0 to enable this option. */ + + +#define FF_USE_LABEL 0 +/* This option switches volume label functions, f_getlabel() and f_setlabel(). +/ (0:Disable or 1:Enable) */ + + +#define FF_USE_FORWARD 0 +/* This option switches f_forward() function. (0:Disable or 1:Enable) */ + + +#define FF_USE_STRFUNC 0 +#define FF_PRINT_LLI 0 +#define FF_PRINT_FLOAT 0 +#define FF_STRF_ENCODE 0 +/* FF_USE_STRFUNC switches string functions, f_gets(), f_putc(), f_puts() and +/ f_printf(). +/ +/ 0: Disable. FF_PRINT_LLI, FF_PRINT_FLOAT and FF_STRF_ENCODE have no effect. +/ 1: Enable without LF-CRLF conversion. +/ 2: Enable with LF-CRLF conversion. +/ +/ FF_PRINT_LLI = 1 makes f_printf() support long long argument and FF_PRINT_FLOAT = 1/2 + makes f_printf() support floating point argument. These features want C99 or later. +/ When FF_LFN_UNICODE >= 1 with LFN enabled, string functions convert the character +/ encoding in it. FF_STRF_ENCODE selects assumption of character encoding ON THE FILE +/ to be read/written via those functions. +/ +/ 0: ANSI/OEM in current CP +/ 1: Unicode in UTF-16LE +/ 2: Unicode in UTF-16BE +/ 3: Unicode in UTF-8 +*/ + + +/*---------------------------------------------------------------------------/ +/ Locale and Namespace Configurations +/---------------------------------------------------------------------------*/ + +#define FF_CODE_PAGE 866 +/* This option specifies the OEM code page to be used on the target system. +/ Incorrect code page setting can cause a file open failure. +/ +/ 437 - U.S. +/ 720 - Arabic +/ 737 - Greek +/ 771 - KBL +/ 775 - Baltic +/ 850 - Latin 1 +/ 852 - Latin 2 +/ 855 - Cyrillic +/ 857 - Turkish +/ 860 - Portuguese +/ 861 - Icelandic +/ 862 - Hebrew +/ 863 - Canadian French +/ 864 - Arabic +/ 865 - Nordic +/ 866 - Russian +/ 869 - Greek 2 +/ 932 - Japanese (DBCS) +/ 936 - Simplified Chinese (DBCS) +/ 949 - Korean (DBCS) +/ 950 - Traditional Chinese (DBCS) +/ 0 - Include all code pages above and configured by f_setcp() +*/ + + +#define FF_USE_LFN 1 +#define FF_MAX_LFN 32 +/* The FF_USE_LFN switches the support for LFN (long file name). +/ +/ 0: Disable LFN. FF_MAX_LFN has no effect. +/ 1: Enable LFN with static working buffer on the BSS. Always NOT thread-safe. +/ 2: Enable LFN with dynamic working buffer on the STACK. +/ 3: Enable LFN with dynamic working buffer on the HEAP. +/ +/ To enable the LFN, ffunicode.c needs to be added to the project. The LFN function +/ requiers certain internal working buffer occupies (FF_MAX_LFN + 1) * 2 bytes and +/ additional (FF_MAX_LFN + 44) / 15 * 32 bytes when exFAT is enabled. +/ The FF_MAX_LFN defines size of the working buffer in UTF-16 code unit and it can +/ be in range of 12 to 255. It is recommended to be set it 255 to fully support LFN +/ specification. +/ When use stack for the working buffer, take care on stack overflow. When use heap +/ memory for the working buffer, memory management functions, ff_memalloc() and +/ ff_memfree() exemplified in ffsystem.c, need to be added to the project. */ + + +#define FF_LFN_UNICODE 0 +/* This option switches the character encoding on the API when LFN is enabled. +/ +/ 0: ANSI/OEM in current CP (TCHAR = char) +/ 1: Unicode in UTF-16 (TCHAR = WCHAR) +/ 2: Unicode in UTF-8 (TCHAR = char) +/ 3: Unicode in UTF-32 (TCHAR = DWORD) +/ +/ Also behavior of string I/O functions will be affected by this option. +/ When LFN is not enabled, this option has no effect. */ + + +#define FF_LFN_BUF 32 +#define FF_SFN_BUF 12 +/* This set of options defines size of file name members in the FILINFO structure +/ which is used to read out directory items. These values should be suffcient for +/ the file names to read. The maximum possible length of the read file name depends +/ on character encoding. When LFN is not enabled, these options have no effect. */ + + +#define FF_FS_RPATH 0 +/* This option configures support for relative path. +/ +/ 0: Disable relative path and remove related functions. +/ 1: Enable relative path. f_chdir() and f_chdrive() are available. +/ 2: f_getcwd() function is available in addition to 1. +*/ + + +/*---------------------------------------------------------------------------/ +/ Drive/Volume Configurations +/---------------------------------------------------------------------------*/ + +#define FF_VOLUMES 1 +/* Number of volumes (logical drives) to be used. (1-10) */ + + +#define FF_STR_VOLUME_ID 0 +#define FF_VOLUME_STRS "RAM","NAND","CF","SD","SD2","USB","USB2","USB3" +/* FF_STR_VOLUME_ID switches support for volume ID in arbitrary strings. +/ When FF_STR_VOLUME_ID is set to 1 or 2, arbitrary strings can be used as drive +/ number in the path name. FF_VOLUME_STRS defines the volume ID strings for each +/ logical drives. Number of items must not be less than FF_VOLUMES. Valid +/ characters for the volume ID strings are A-Z, a-z and 0-9, however, they are +/ compared in case-insensitive. If FF_STR_VOLUME_ID >= 1 and FF_VOLUME_STRS is +/ not defined, a user defined volume string table needs to be defined as: +/ +/ const char* VolumeStr[FF_VOLUMES] = {"ram","flash","sd","usb",... +*/ + + +#define FF_MULTI_PARTITION 0 +/* This option switches support for multiple volumes on the physical drive. +/ By default (0), each logical drive number is bound to the same physical drive +/ number and only an FAT volume found on the physical drive will be mounted. +/ When this function is enabled (1), each logical drive number can be bound to +/ arbitrary physical drive and partition listed in the VolToPart[]. Also f_fdisk() +/ funciton will be available. */ + + +#define FF_MIN_SS 512 +#define FF_MAX_SS 512 +/* This set of options configures the range of sector size to be supported. (512, +/ 1024, 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 FF_MAX_SS is larger than FF_MIN_SS, FatFs is configured +/ for variable sector size mode and disk_ioctl() function needs to implement +/ GET_SECTOR_SIZE command. */ + + +#define FF_LBA64 0 +/* This option switches support for 64-bit LBA. (0:Disable or 1:Enable) +/ To enable the 64-bit LBA, also exFAT needs to be enabled. (FF_FS_EXFAT == 1) */ + + +#define FF_MIN_GPT 0x10000000 +/* Minimum number of sectors to switch GPT as partitioning format in f_mkfs and +/ f_fdisk function. 0x100000000 max. This option has no effect when FF_LBA64 == 0. */ + + +#define FF_USE_TRIM 0 +/* This option switches support for ATA-TRIM. (0:Disable or 1:Enable) +/ To enable Trim function, also CTRL_TRIM command should be implemented to the +/ disk_ioctl() function. */ + + + +/*---------------------------------------------------------------------------/ +/ System Configurations +/---------------------------------------------------------------------------*/ + +#define FF_FS_TINY 0 +/* This option switches tiny buffer configuration. (0:Normal or 1:Tiny) +/ At the tiny configuration, size of file object (FIL) is shrinked FF_MAX_SS bytes. +/ Instead of private sector buffer eliminated from the file object, common sector +/ buffer in the filesystem object (FATFS) is used for the file data transfer. */ + + +#define FF_FS_EXFAT 1 +/* This option switches support for exFAT filesystem. (0:Disable or 1:Enable) +/ To enable exFAT, also LFN needs to be enabled. (FF_USE_LFN >= 1) +/ Note that enabling exFAT discards ANSI C (C89) compatibility. */ + + +#define FF_FS_NORTC 0 +#define FF_NORTC_MON 1 +#define FF_NORTC_MDAY 1 +#define FF_NORTC_YEAR 2020 +/* The option FF_FS_NORTC switches timestamp functiton. If the system does not have +/ any RTC function or valid timestamp is not needed, set FF_FS_NORTC = 1 to disable +/ the timestamp function. Every object modified by FatFs will have a fixed timestamp +/ defined by FF_NORTC_MON, FF_NORTC_MDAY and FF_NORTC_YEAR in local time. +/ To enable timestamp function (FF_FS_NORTC = 0), get_fattime() function need to be +/ added to the project to read current time form real-time clock. FF_NORTC_MON, +/ FF_NORTC_MDAY and FF_NORTC_YEAR have no effect. +/ These options have no effect in read-only configuration (FF_FS_READONLY = 1). */ + + +#define FF_FS_NOFSINFO 0 +/* If you need to know correct free space on the FAT32 volume, set bit 0 of this +/ option, and f_getfree() function at first time after volume mount will force +/ a full FAT scan. Bit 1 controls the use of last allocated cluster number. +/ +/ bit0=0: Use free cluster count in the FSINFO if available. +/ bit0=1: Do not trust free cluster count in the FSINFO. +/ bit1=0: Use last allocated cluster number in the FSINFO if available. +/ bit1=1: Do not trust last allocated cluster number in the FSINFO. +*/ + + +#define FF_FS_LOCK 0 +/* The option FF_FS_LOCK switches file lock function to control duplicated file open +/ and illegal operation to open objects. This option must be 0 when FF_FS_READONLY +/ is 1. +/ +/ 0: Disable file lock function. To avoid volume corruption, application program +/ should avoid illegal open, remove and rename to the open objects. +/ >0: Enable file lock function. The value defines how many files/sub-directories +/ can be opened simultaneously under file lock control. Note that the file +/ lock control is independent of re-entrancy. */ + + +/* #include // O/S definitions */ +#define FF_FS_REENTRANT 0 +#define FF_FS_TIMEOUT 1000 +#define FF_SYNC_t HANDLE +/* The option FF_FS_REENTRANT switches the re-entrancy (thread safe) of the FatFs +/ module itself. Note that regardless of this option, file access to different +/ volume is always re-entrant and volume control functions, f_mount(), f_mkfs() +/ and f_fdisk() function, are always not re-entrant. Only file/directory access +/ to the same volume is under control of this function. +/ +/ 0: Disable re-entrancy. FF_FS_TIMEOUT and FF_SYNC_t have no effect. +/ 1: Enable re-entrancy. Also user provided synchronization handlers, +/ ff_req_grant(), ff_rel_grant(), ff_del_syncobj() and ff_cre_syncobj() +/ function, must be added to the project. Samples are available in +/ option/syscall.c. +/ +/ The FF_FS_TIMEOUT defines timeout period in unit of time tick. +/ The FF_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.h. */ + + +#define _WORD_ACCESS 1 /* 0 or 1 */ +/* The _WORD_ACCESS option is an only platform dependent option. It defines +/ which access method is used to the word data on the FAT volume. +/ +/ 0: Byte-by-byte access. Always compatible with all platforms. +/ 1: Word access. Do not choose this unless under both the following conditions. +/ +/ * Address misaligned memory access is always allowed for ALL instructions. +/ * Byte order on the memory is little-endian. +/ +/ If it is the case, _WORD_ACCESS can also be set to 1 to improve performance and +/ reduce code size. Following table shows an example of some processor types. +/ +/ ARM7TDMI 0 ColdFire 0 V850E2 0 +/ Cortex-M3 0 Z80 0/1 V850ES 0/1 +/ Cortex-M0 0 RX600(LE) 0/1 TLCS-870 0/1 +/ AVR 0/1 RX600(BE) 0 TLCS-900 0/1 +/ AVR32 0 RL78 0 R32C 0 +/ PIC18 0/1 SH-2 0 M16C 0/1 +/ PIC24 0 H8S 0 MSP430 0 +/ PIC32 0 H8/300H 0 x86 0/1 +*/ + +#define FF_USE_STRINGLIB 0 /* 0 or 1 */ +/* + * if 1 Use standard string.h for memcpy, memcmp, memset, strchr + * if 0 use own + */ + +/*--- End of configuration options ---*/ diff --git a/Font6x11.c b/Font6x11.c new file mode 100644 index 0000000..aba6718 --- /dev/null +++ b/Font6x11.c @@ -0,0 +1,3482 @@ +/* + * Copyright (c) 2019-2020, Dmitry (DiSlord) dislordlive@gmail.com + * All rights reserved. + * + * This 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 3, or (at your option) + * any later version. + * + * The software 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 GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#include +/* + * Most font glyph have width 6 pixels + * Check 0 byte of char bitmap data for get width + */ + +#if 1 +// Font definitions for header +#define FONT_START_CHAR 0x17 +#define FONT_MAX_WIDTH 8 +#define FONT_WIDTH 6 +#define FONT_GET_HEIGHT 11 +#define FONT_STR_HEIGHT 11 +#define FONT_GET_DATA(ch) ( &x6x11_bits[(ch-FONT_START_CHAR)*FONT_GET_HEIGHT]) +#define FONT_GET_WIDTH(ch) (8-(x6x11_bits[(ch-FONT_START_CHAR)*FONT_GET_HEIGHT]&7)) +#endif + +#define CHAR7x11_WIDTH_MASK 0x07 +#define CHAR7x11_WIDTH_4px 0x04 +#define CHAR7x11_WIDTH_5px 0x03 +#define CHAR7x11_WIDTH_6px 0x02 +#define CHAR7x11_WIDTH_7px 0x01 +#define CHAR7x11_WIDTH_8px 0x00 + +#if FONT_START_CHAR!=0x17 +#error "Need set correct offset in x6x11_bits font" +#endif + +/* Font character bitmap data. */ +const uint8_t x6x11_bits[] = +{ +#if 0 + /* Character 0 (0x00): + width 7 + +-------+ + | | + | ***** | + | ***** | + | ***** | + | ***** | + | ***** | + | ***** | + | ***** | + | ***** | + | ***** | + | ***** | + +-------+ */ + 0b00000000|CHAR7x11_WIDTH_7px, + 0b01111100, + 0b01111100, + 0b01111100, + 0b01111100, + 0b01111100, + 0b01111100, + 0b01111100, + 0b01111100, + 0b01111100, + 0b01111100, + + /* Character 1 (0x01): + width 7 + +-------+ + | | + | | + | | + | | + | ** | + | **** | + |****** | + | **** | + | ** | + | | + | | + +-------+ */ + 0b00000000|CHAR7x11_WIDTH_7px, + 0b00000000, + 0b00000000, + 0b00000000, + 0b00110000, + 0b01111000, + 0b11111100, + 0b01111000, + 0b00110000, + 0b00000000, + 0b00000000, + + /* Character 2 (0x02): + width 7 + +-------+ + |** ** | + | ** | + |** ** | + | ** | + |** ** | + | ** | + |** ** | + | ** | + |** ** | + | ** | + |** ** | + +-------+ */ + 0b11001100|CHAR7x11_WIDTH_7px, + 0b00110000, + 0b11001100, + 0b00110000, + 0b11001100, + 0b00110000, + 0b11001100, + 0b00110000, + 0b11001100, + 0b00110000, + 0b11001100, + + /* Character 3 (0x03): + width 7 + +-------+ + |** ** | + |** ** | + |***** | + |** ** | + |** ** | + | | + | **** | + | ** | + | ** | + | ** | + | ** | + +-------+ */ + 0b11011000|CHAR7x11_WIDTH_7px, + 0b11011000, + 0b11111000, + 0b11011000, + 0b11011000, + 0b00000000, + 0b00111100, + 0b00011000, + 0b00011000, + 0b00011000, + 0b00011000, + + /* Character 4 (0x04): + width 7 + +-------+ + | ** | + | ** | + | ** | + | ** | + |*******| + |*******| + | | + | | + | | + | | + | | + +-------+ */ + 0b00110000|CHAR7x11_WIDTH_7px, + 0b00110000, + 0b00110000, + 0b00110000, + 0b11111110, + 0b11111110, + 0b00000000, + 0b00000000, + 0b00000000, + 0b00000000, + 0b00000000, + + /* Character 5 (0x05): + width 7 + +-------+ + | *** | + |** | + |** | + |** | + | *** | + | | + | *** | + | ** * | + | *** | + | ** * | + | ** * | + +-------+ */ + 0b01110000|CHAR7x11_WIDTH_7px, + 0b11000000, + 0b11000000, + 0b11000000, + 0b01110000, + 0b00000000, + 0b00111000, + 0b00110100, + 0b00111000, + 0b00110100, + 0b00110100, + + /* Character 6 (0x06): + width 7 + +-------+ + |** | + |** | + |** | + |** | + |**** | + | | + | **** | + | ** | + | *** | + | ** | + | ** | + +-------+ */ + 0b11000000|CHAR7x11_WIDTH_7px, + 0b11000000, + 0b11000000, + 0b11000000, + 0b11110000, + 0b00000000, + 0b00111100, + 0b00110000, + 0b00111000, + 0b00110000, + 0b00110000, + + /* Character 7 (0x07): + width 7 + +-------+ + | | + | **** | + |** ** | + |** ** | + | **** | + | | + | | + | | + | | + | | + | | + +-------+ */ + 0b00000000|CHAR7x11_WIDTH_7px, + 0b01111000, + 0b11001100, + 0b11001100, + 0b01111000, + 0b00000000, + 0b00000000, + 0b00000000, + 0b00000000, + 0b00000000, + 0b00000000, + + /* Character 8 (0x08): + width 7 + +-------+ + | | + | ** | + | ** | + |****** | + |****** | + | ** | + | ** | + | | + |****** | + |****** | + | | + +-------+ */ + 0b00000000|CHAR7x11_WIDTH_7px, + 0b00110000, + 0b00110000, + 0b11111100, + 0b11111100, + 0b00110000, + 0b00110000, + 0b00000000, + 0b11111100, + 0b11111100, + 0b00000000, + + /* Character 9 (0x09): + width 7 + +-------+ + |** ** | + |*** ** | + |****** | + |** *** | + |** ** | + | | + | ** | + | ** | + | ** | + | ** | + | **** | + +-------+ */ + 0b11001100|CHAR7x11_WIDTH_7px, + 0b11101100, + 0b11111100, + 0b11011100, + 0b11001100, + 0b00000000, + 0b00110000, + 0b00110000, + 0b00110000, + 0b00110000, + 0b00111100, + + /* Character 10 (0x0a): + width 7 + +-------+ + |** ** | + |** ** | + | * * | + | **** | + | ** | + | | + | **** | + | ** | + | ** | + | ** | + | ** | + +-------+ */ + 0b11001100|CHAR7x11_WIDTH_7px, + 0b11001100, + 0b01001000, + 0b01111000, + 0b00110000, + 0b00000000, + 0b00111100, + 0b00011000, + 0b00011000, + 0b00011000, + 0b00011000, + + /* Character 11 (0x0b): + width 7 + +-------+ + | ** | + | ** | + | ** | + | ** | + | ** | + |**** | + |**** | + | | + | | + | | + | | + +-------+ */ + 0b00110000|CHAR7x11_WIDTH_7px, + 0b00110000, + 0b00110000, + 0b00110000, + 0b00110000, + 0b11110000, + 0b11110000, + 0b00000000, + 0b00000000, + 0b00000000, + 0b00000000, + + /* Character 12 (0x0c): + width 7 + +-------+ + | | + | | + | | + | | + |**** | + |**** | + | ** | + | ** | + | ** | + | ** | + | ** | + +-------+ */ + 0b00000000|CHAR7x11_WIDTH_7px, + 0b00000000, + 0b00000000, + 0b00000000, + 0b11110000, + 0b11110000, + 0b00110000, + 0b00110000, + 0b00110000, + 0b00110000, + 0b00110000, + + /* Character 13 (0x0d): + width 7 + +-------+ + | | + | | + | | + | | + | *****| + | *****| + | ** | + | ** | + | ** | + | ** | + | ** | + +-------+ */ + 0b00000000|CHAR7x11_WIDTH_7px, + 0b00000000, + 0b00000000, + 0b00000000, + 0b00111110, + 0b00111110, + 0b00110000, + 0b00110000, + 0b00110000, + 0b00110000, + 0b00110000, + + /* Character 14 (0x0e): + width 7 + +-------+ + | ** | + | ** | + | ** | + | ** | + | *****| + | *****| + | | + | | + | | + | | + | | + +-------+ */ + 0b00110000|CHAR7x11_WIDTH_7px, + 0b00110000, + 0b00110000, + 0b00110000, + 0b00111110, + 0b00111110, + 0b00000000, + 0b00000000, + 0b00000000, + 0b00000000, + 0b00000000, + + /* Character 15 (0x0f): + width 7 + +-------+ + | ** | + | ** | + | ** | + | ** | + |*******| + |*******| + | ** | + | ** | + | ** | + | ** | + | ** | + +-------+ */ + 0b00110000|CHAR7x11_WIDTH_7px, + 0b00110000, + 0b00110000, + 0b00110000, + 0b11111110, + 0b11111110, + 0b00110000, + 0b00110000, + 0b00110000, + 0b00110000, + 0b00110000, + + /* Character 16 (0x10): + width 7 + +-------+ + | | + |*******| + |*******| + | | + | | + | | + | | + | | + | | + | | + | | + +-------+ */ + 0b00000000|CHAR7x11_WIDTH_7px, + 0b11111110, + 0b11111110, + 0b00000000, + 0b00000000, + 0b00000000, + 0b00000000, + 0b00000000, + 0b00000000, + 0b00000000, + 0b00000000, + + /* Character 17 (0x11): + width 7 + +-------+ + | | + | | + | | + |*******| + |*******| + | | + | | + | | + | | + | | + | | + +-------+ */ + 0b00000000|CHAR7x11_WIDTH_7px, + 0b00000000, + 0b00000000, + 0b11111110, + 0b11111110, + 0b00000000, + 0b00000000, + 0b00000000, + 0b00000000, + 0b00000000, + 0b00000000, + + /* Character 18 (0x12): + width 7 + +-------+ + | | + | | + | | + | | + | | + |*******| + |*******| + | | + | | + | | + | | + +-------+ */ + 0b00000000|CHAR7x11_WIDTH_7px, + 0b00000000, + 0b00000000, + 0b00000000, + 0b00000000, + 0b11111110, + 0b11111110, + 0b00000000, + 0b00000000, + 0b00000000, + 0b00000000, + + /* Character 19 (0x13): + width 7 + +-------+ + | | + | | + | | + | | + | | + | | + | | + |*******| + |*******| + | | + | | + +-------+ */ + 0b00000000|CHAR7x11_WIDTH_7px, + 0b00000000, + 0b00000000, + 0b00000000, + 0b00000000, + 0b00000000, + 0b00000000, + 0b11111110, + 0b11111110, + 0b00000000, + 0b00000000, + + /* Character 20 (0x14): + width 7 + +-------+ + | | + | | + | | + | | + | | + | | + | | + | | + | | + |*******| + |*******| + +-------+ */ + 0b00000000|CHAR7x11_WIDTH_7px, + 0b00000000, + 0b00000000, + 0b00000000, + 0b00000000, + 0b00000000, + 0b00000000, + 0b00000000, + 0b00000000, + 0b11111110, + 0b11111110, + + /* Character 21 (0x15): + width 7 + +-------+ + | ** | + | ** | + | ** | + | ** | + | *****| + | *****| + | ** | + | ** | + | ** | + | ** | + | ** | + +-------+ */ + 0b00110000|CHAR7x11_WIDTH_7px, + 0b00110000, + 0b00110000, + 0b00110000, + 0b00111110, + 0b00111110, + 0b00110000, + 0b00110000, + 0b00110000, + 0b00110000, + 0b00110000, + + /* Character 22 (0x16): + width 7 + +-------+ + | ** | + | ** | + | ** | + | ** | + |**** | + |**** | + | ** | + | ** | + | ** | + | ** | + | ** | + +-------+ */ + 0b00110000|CHAR7x11_WIDTH_7px, + 0b00110000, + 0b00110000, + 0b00110000, + 0b11110000, + 0b11110000, + 0b00110000, + 0b00110000, + 0b00110000, + 0b00110000, + 0b00110000, +#endif +// FONT_START_CHAR = 23 + /* Character 23 (0x17): + width 8 + +-------+ + | | + | * | + | * | + | * * | + | * * | + | * * | + | * * | + |* *| + |* *| + |*******| + | | + +-------+ */ + 0b00000000|CHAR7x11_WIDTH_8px, + 0b00010000, + 0b00010000, + 0b00101000, + 0b00101000, + 0b01000100, + 0b01000100, + 0b10000010, + 0b10000010, + 0b11111110, + 0b00000000, + + /* Character 24 (0x18): + width 5 + +-------+ + | | + |* | + |** | + |*** | + |**** | + |***** | + |**** | + |*** | + |** | + |* | + | | + +-------+ */ + 0b00000000|CHAR7x11_WIDTH_5px, + 0b10000000, + 0b11000000, + 0b11100000, + 0b11110000, + 0b11111000, + 0b11110000, + 0b11100000, + 0b11000000, + 0b10000000, + 0b00000000, + + /* Character 25 (0x19): + width 8 + +--------+ + | | + | | + | ** *** | + |** ** **| + |* * *| + |* ** *| + |* * *| + |** ** **| + | *** ** | + | | + | | + +--------+ */ + 0b00000000|CHAR7x11_WIDTH_8px, + 0b00000000, + 0b01101110, + 0b11011011, + 0b10010001, + 0b10011001, + 0b10001001, + 0b11011011, + 0b01110110, + 0b00000000, + 0b00000000, + + /* Character 26 (0x1a): + width 8 + +-------+ + | | + | | + | * | + | ** | + | ** | + |*******| + |*******| + | ** | + | ** | + | * | + | | + +-------+ */ + 0b00000000|CHAR7x11_WIDTH_8px, + 0b00000000, + 0b00010000, + 0b00110000, + 0b01100000, + 0b11111110, + 0b11111110, + 0b01100000, + 0b00110000, + 0b00010000, + 0b00000000, + + /* Character 27 (0x1b): + width 7 + +-------+ + | | + | | + | * | + | ** | + | ** | + |*******| + |*******| + | ** | + | ** | + | * | + | | + +-------+ */ + 0b00000000|CHAR7x11_WIDTH_7px, + 0b00000000, + 0b00010000, + 0b00011000, + 0b00001100, + 0b01111110, + 0b01111110, + 0b00001100, + 0b00011000, + 0b00010000, + 0b00000000, + + /* Character 28 (0x1c): + width 7 + +-------+ + | | + | | + | | + | | + | ***** | + | * * | + | * * | + | * * | + |* * * | + |** * | + | | + +-------+ */ + 0b00000000|CHAR7x11_WIDTH_7px, + 0b00000000, + 0b00000000, + 0b00000000, + 0b01111100, + 0b00101000, + 0b00101000, + 0b00101000, + 0b10101000, + 0b11001000, + 0b00000000, + + /* Character 29 (0x1d): + width 8 + +-------+ + | | + | | + | | + | | + |* * | + |* * | + |* * | + |* ** | + |** * * | + |* * * | + |* | + +-------+ */ + 0b00000000|CHAR7x11_WIDTH_7px, + 0b00000000, + 0b00000000, + 0b00000000, + 0b10000100, + 0b10000100, + 0b10000100, + 0b10001100, + 0b11010100, + 0b10100100, + 0b10000000, + + /* Character 30 (0x1e): + width 7 + +-------+ + | | + | **** | + |* * | + |* * | + |* * | + |* * | + |* * | + | * * | + | * * | + |** ** | + | | + +-------+ */ + 0b00000000|CHAR7x11_WIDTH_7px, + 0b01111000, + 0b10000100, + 0b10000100, + 0b10000100, + 0b10000100, + 0b10000100, + 0b01001000, + 0b01001000, + 0b11001100, + 0b00000000, + + /* Character 31 (0x1f): + width 6 + +-------+ + | | + | ** | + |* * | + |* * | + | ** | + | | + | | + | | + | | + | | + | | + +-------+ */ + 0b00000000|CHAR7x11_WIDTH_5px, + 0b01100000, + 0b10010000, + 0b10010000, + 0b01100000, + 0b00000000, + 0b00000000, + 0b00000000, + 0b00000000, + 0b00000000, + 0b00000000, + + /* Character 32 (0x20): + width 4 + +-------+ + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + +-------+ */ + 0b00000000|CHAR7x11_WIDTH_4px, + 0b00000000, + 0b00000000, + 0b00000000, + 0b00000000, + 0b00000000, + 0b00000000, + 0b00000000, + 0b00000000, + 0b00000000, + 0b00000000, + + /* Character 33 (0x21): + width 4 + +-------+ + | | + | * | + | * | + | * | + | * | + | * | + | * | + | * | + | | + | * | + | | + +-------+ */ + 0b00000000|CHAR7x11_WIDTH_4px, + 0b01000000, + 0b01000000, + 0b01000000, + 0b01000000, + 0b01000000, + 0b01000000, + 0b01000000, + 0b00000000, + 0b01000000, + 0b00000000, + + /* Character 34 (0x22): + width 6 + +-------+ + | | + |* * | + |* * | + |* * | + | | + | | + | | + | | + | | + | | + | | + +-------+ */ + 0b00000000|CHAR7x11_WIDTH_5px, + 0b10010000, + 0b10010000, + 0b10010000, + 0b00000000, + 0b00000000, + 0b00000000, + 0b00000000, + 0b00000000, + 0b00000000, + 0b00000000, + + /* Character 35 (0x23): + width 6 + +-------+ + | | + | | + | * * | + | * * | + |***** | + | * * | + | * * | + |***** | + | * * | + | * * | + | | + +-------+ */ + 0b00000000|CHAR7x11_WIDTH_6px, + 0b00000000, + 0b01010000, + 0b01010000, + 0b11111000, + 0b01010000, + 0b01010000, + 0b11111000, + 0b01010000, + 0b01010000, + 0b00000000, + + /* Character 36 (0x24): + width 8 + +-------+ + | | + | * | + | **** | + |* * | + |* * | + | *** | + | * * | + | * * | + |**** | + | * | + | | + +-------+ */ + 0b00000000|CHAR7x11_WIDTH_7px, + 0b00100000, + 0b01111000, + 0b10100000, + 0b10100000, + 0b01110000, + 0b00101000, + 0b00101000, + 0b11110000, + 0b00100000, + 0b00000000, + + /* Character 37 (0x25): + width 8 + +-------+ + | ** | + |* * | + |* * * | + | ** * | + | * | + | * | + | * ** | + |* * * | + | * * | + | ** | + | | + +-------+ */ + 0b01100000|CHAR7x11_WIDTH_7px, + 0b10010000, + 0b10010100, + 0b01101000, + 0b00010000, + 0b00100000, + 0b01011000, + 0b10100100, + 0b00100100, + 0b00011000, + 0b00000000, + + /* Character 38 (0x26): + width 8 + +-------+ + | | + | | + | ** | + | * * | + | * * | + | * *| + | * * * | + |* * | + |* * * | + | ** *| + | | + +-------+ */ + 0b00000000|CHAR7x11_WIDTH_8px, + 0b00000000, + 0b00110000, + 0b01001000, + 0b01010000, + 0b00100010, + 0b01010100, + 0b10001000, + 0b10010100, + 0b01100010, + 0b00000000, + + /* Character 39 (0x27): + width 5 + +-------+ + | | + | ** | + | ** | + |** | + | | + | | + | | + | | + | | + | | + | | + +-------+ */ + 0b00000000|CHAR7x11_WIDTH_4px, + 0b01100000, + 0b01100000, + 0b11000000, + 0b00000000, + 0b00000000, + 0b00000000, + 0b00000000, + 0b00000000, + 0b00000000, + 0b00000000, + + /* Character 40 (0x28): + width 5 + +-------+ + | | + | * | + | * | + | * | + |* | + |* | + |* | + | * | + | * | + | * | + | | + +-------+ */ + 0b00000000|CHAR7x11_WIDTH_4px, + 0b00100000, + 0b01000000, + 0b01000000, + 0b10000000, + 0b10000000, + 0b10000000, + 0b01000000, + 0b01000000, + 0b00100000, + 0b00000000, + + /* Character 41 (0x29): + width 5 + +-------+ + | | + |* | + | * | + | * | + | * | + | * | + | * | + | * | + | * | + |* | + | | + +-------+ */ + 0b00000000|CHAR7x11_WIDTH_4px, + 0b10000000, + 0b01000000, + 0b01000000, + 0b00100000, + 0b00100000, + 0b00100000, + 0b01000000, + 0b01000000, + 0b10000000, + 0b00000000, + + /* Character 42 (0x2a): '*' + width 7 + +-------+ + | | + | | + | | + | * | + |* * * | + | *** | + |* * * | + | * | + | | + | | + | | + +-------+ */ + 0b00000000|CHAR7x11_WIDTH_7px, + 0b00000000, + 0b00000000, + 0b00100000, + 0b10101000, + 0b01110000, + 0b10101000, + 0b00100000, + 0b00000000, + 0b00000000, + 0b00000000, + + /* Character 43 (0x2b): + width 7 + +-------+ + | | + | | + | | + | * | + | * | + |***** | + | * | + | * | + | | + | | + | | + +-------+ */ + 0b00000000|CHAR7x11_WIDTH_7px, + 0b00000000, + 0b00000000, + 0b00100000, + 0b00100000, + 0b11111000, + 0b00100000, + 0b00100000, + 0b00000000, + 0b00000000, + 0b00000000, + + /* Character 44 (0x2c): + width 4 + +-------+ + | | + | | + | | + | | + | | + | | + | | + | | + | ** | + | * | + | * | + +-------+ */ + 0b00000000|CHAR7x11_WIDTH_5px, + 0b00000000, + 0b00000000, + 0b00000000, + 0b00000000, + 0b00000000, + 0b00000000, + 0b00000000, + 0b01100000, + 0b00100000, + 0b01000000, + + /* Character 45 (0x2d): + width 7 + +-------+ + | | + | | + | | + | | + | | + |***** | + | | + | | + | | + | | + | | + +-------+ */ + 0b00000000|CHAR7x11_WIDTH_7px, + 0b00000000, + 0b00000000, + 0b00000000, + 0b00000000, + 0b11111000, + 0b00000000, + 0b00000000, + 0b00000000, + 0b00000000, + 0b00000000, + + /* Character 46 (0x2e): + width 4 + +-------+ + | | + | | + | | + | | + | | + | | + | | + | | + | ** | + | ** | + | | + +-------+ */ + 0b00000000|CHAR7x11_WIDTH_5px, + 0b00000000, + 0b00000000, + 0b00000000, + 0b00000000, + 0b00000000, + 0b00000000, + 0b00000000, + 0b01100000, + 0b01100000, + 0b00000000, + + /* Character 47 (0x2f): + width 7 + +-------+ + | | + | * | + | * | + | * | + | * | + | * | + | * | + | * | + |* | + |* | + | | + +-------+ */ + 0b00000000|CHAR7x11_WIDTH_6px, + 0b00001000, + 0b00001000, + 0b00010000, + 0b00010000, + 0b00100000, + 0b01000000, + 0b01000000, + 0b10000000, + 0b10000000, + 0b00000000, + + /* Character 48 (0x30): + width 7 + +-------+ + | | + | *** | + |* * | + |* * | + |* ** | + |* * * | + |** * | + |* * | + |* * | + | *** | + | | + +-------+ */ + 0b00000000|CHAR7x11_WIDTH_6px, + 0b01110000, + 0b10001000, + 0b10001000, + 0b10011000, + 0b10101000, + 0b11001000, + 0b10001000, + 0b10001000, + 0b01110000, + 0b00000000, + + /* Character 49 (0x31): + width 7 + +-------+ + | | + | * | + | ** | + | * * | + | * | + | * | + | * | + | * | + | * | + | *** | + | | + +-------+ */ + 0b00000000|CHAR7x11_WIDTH_6px, + 0b00010000, + 0b00110000, + 0b01010000, + 0b00010000, + 0b00010000, + 0b00010000, + 0b00010000, + 0b00010000, + 0b00111000, + 0b00000000, + + /* Character 50 (0x32): + width 7 + +-------+ + | | + | *** | + |* * | + |* * | + | * | + | * | + | * | + | * | + |* | + |***** | + | | + +-------+ */ + 0b00000000|CHAR7x11_WIDTH_6px, + 0b01110000, + 0b10001000, + 0b10001000, + 0b00001000, + 0b00010000, + 0b00100000, + 0b01000000, + 0b10000000, + 0b11111000, + 0b00000000, + + /* Character 51 (0x33): + width 7 + +-------+ + | | + | *** | + |* * | + |* * | + | * | + | ** | + | * | + |* * | + |* * | + | *** | + | | + +-------+ */ + 0b00000000|CHAR7x11_WIDTH_6px, + 0b01110000, + 0b10001000, + 0b10001000, + 0b00001000, + 0b00110000, + 0b00001000, + 0b10001000, + 0b10001000, + 0b01110000, + 0b00000000, + + /* Character 52 (0x34): + width 7 + +-------+ + | | + | * | + | ** | + | * * | + |* * | + |* * | + |* * | + |***** | + | * | + | * | + | | + +-------+ */ + 0b00000000|CHAR7x11_WIDTH_6px, + 0b00010000, + 0b00110000, + 0b01010000, + 0b10010000, + 0b10010000, + 0b10010000, + 0b11111000, + 0b00010000, + 0b00010000, + 0b00000000, + + /* Character 53 (0x35): + width 7 + +-------+ + | | + |***** | + |* | + |* | + |**** | + |* * | + | * | + | * | + |* * | + | *** | + | | + +-------+ */ + 0b00000000|CHAR7x11_WIDTH_6px, + 0b11111000, + 0b10000000, + 0b10000000, + 0b11110000, + 0b10001000, + 0b00001000, + 0b00001000, + 0b10001000, + 0b01110000, + 0b00000000, + + /* Character 54 (0x36): + width 7 + +-------+ + | | + | *** | + |* * | + |* | + |**** | + |* * | + |* * | + |* * | + |* * | + | *** | + | | + +-------+ */ + 0b00000000|CHAR7x11_WIDTH_6px, + 0b01110000, + 0b10001000, + 0b10000000, + 0b11110000, + 0b10001000, + 0b10001000, + 0b10001000, + 0b10001000, + 0b01110000, + 0b00000000, + + /* Character 55 (0x37): + width 7 + +-------+ + | | + |***** | + | * | + | * | + | * | + | * | + | * | + | * | + | * | + | * | + | | + +-------+ */ + 0b00000000|CHAR7x11_WIDTH_6px, + 0b11111000, + 0b00001000, + 0b00001000, + 0b00010000, + 0b00010000, + 0b00100000, + 0b00100000, + 0b00100000, + 0b00100000, + 0b00000000, + + /* Character 56 (0x38): + width 7 + +-------+ + | | + | *** | + |* * | + |* * | + |* * | + | *** | + |* * | + |* * | + |* * | + | *** | + | | + +-------+ */ + 0b00000000|CHAR7x11_WIDTH_6px, + 0b01110000, + 0b10001000, + 0b10001000, + 0b10001000, + 0b01110000, + 0b10001000, + 0b10001000, + 0b10001000, + 0b01110000, + 0b00000000, + + /* Character 57 (0x39): + width 7 + +-------+ + | | + | *** | + |* * | + |* * | + |* * | + |* * | + | **** | + | * | + |* * | + | *** | + | | + +-------+ */ + 0b00000000|CHAR7x11_WIDTH_6px, + 0b01110000, + 0b10001000, + 0b10001000, + 0b10001000, + 0b10001000, + 0b01111000, + 0b00001000, + 0b10001000, + 0b01110000, + 0b00000000, + + /* Character 58 (0x3a): + width 4 + +-------+ + | | + | | + | | + |** | + |** | + | | + | | + |** | + |** | + | | + | | + +-------+ */ + 0b00000000|CHAR7x11_WIDTH_4px, + 0b00000000, + 0b00000000, + 0b11000000, + 0b11000000, + 0b00000000, + 0b00000000, + 0b11000000, + 0b11000000, + 0b00000000, + 0b00000000, + + /* Character 59 (0x3b): + width 4 + +-------+ + | | + | | + | | + |** | + |** | + | | + |** | + | * | + |* | + | | + | | + +-------+ */ + 0b00000000|CHAR7x11_WIDTH_4px, + 0b00000000, + 0b00000000, + 0b11000000, + 0b11000000, + 0b00000000, + 0b00000000, + 0b11000000, + 0b01000000, + 0b10000000, + 0b00000000, + + /* Character 60 (0x3c): + width 7 + +-------+ + | | + | * | + | * | + | * | + | * | + |* | + | * | + | * | + | * | + | * | + | | + +-------+ */ + 0b00000000|CHAR7x11_WIDTH_6px, + 0b00001000, + 0b00010000, + 0b00100000, + 0b01000000, + 0b10000000, + 0b01000000, + 0b00100000, + 0b00010000, + 0b00001000, + 0b00000000, + + /* Character 61 (0x3d): + width 7 + +-------+ + | | + | | + | | + | | + |***** | + | | + | | + |***** | + | | + | | + | | + +-------+ */ + 0b00000000|CHAR7x11_WIDTH_6px, + 0b00000000, + 0b00000000, + 0b00000000, + 0b11111000, + 0b00000000, + 0b00000000, + 0b11111000, + 0b00000000, + 0b00000000, + 0b00000000, + + /* Character 62 (0x3e): + width 7 + +-------+ + | | + |* | + | * | + | * | + | * | + | * | + | * | + | * | + | * | + |* | + | | + +-------+ */ + 0b00000000|CHAR7x11_WIDTH_6px, + 0b10000000, + 0b01000000, + 0b00100000, + 0b00010000, + 0b00001000, + 0b00010000, + 0b00100000, + 0b01000000, + 0b10000000, + 0b00000000, + + /* Character 63 (0x3f): + width 7 + +-------+ + | | + | *** | + |* * | + |* * | + | * | + | * | + | * | + | * | + | | + | * | + | | + +-------+ */ + 0b00000000|CHAR7x11_WIDTH_6px, + 0b01110000, + 0b10001000, + 0b10001000, + 0b00001000, + 0b00010000, + 0b00100000, + 0b00100000, + 0b00000000, + 0b00100000, + 0b00000000, + + /* Character 64 (0x40): + width 7 + +-------+ + | | + | *** | + |* * | + |* * | + |* ** | + |* * * | + |* * | + |* | + |* * | + | *** | + | | + +-------+ */ + 0b00000000|CHAR7x11_WIDTH_6px, + 0b01110000, + 0b10001000, + 0b10001000, + 0b10011000, + 0b10101000, + 0b10010000, + 0b10000000, + 0b10001000, + 0b01110000, + 0b00000000, + + /* Character 65 (0x41): + width 7 + +-------+ + | | + | **** | + |* * | + |* * | + |* * | + |***** | + |* * | + |* * | + |* * | + |* * | + | | + +-------+ */ + 0b00000000|CHAR7x11_WIDTH_6px, + 0b01111000, + 0b10001000, + 0b10001000, + 0b10001000, + 0b11111000, + 0b10001000, + 0b10001000, + 0b10001000, + 0b10001000, + 0b00000000, + + /* Character 66 (0x42): + width 7 + +-------+ + | | + |**** | + |* * | + |* * | + |* * | + |**** | + |* * | + |* * | + |* * | + |**** | + | | + +-------+ */ + 0b00000000|CHAR7x11_WIDTH_6px, + 0b11110000, + 0b10001000, + 0b10001000, + 0b10001000, + 0b11110000, + 0b10001000, + 0b10001000, + 0b10001000, + 0b11110000, + 0b00000000, + + /* Character 67 (0x43): + width 7 + +-------+ + | | + | *** | + |* * | + |* * | + |* | + |* | + |* | + |* * | + |* * | + | *** | + | | + +-------+ */ + 0b00000000|CHAR7x11_WIDTH_6px, + 0b01110000, + 0b10001000, + 0b10001000, + 0b10000000, + 0b10000000, + 0b10000000, + 0b10001000, + 0b10001000, + 0b01110000, + 0b00000000, + + /* Character 68 (0x44): + width 7 + +-------+ + | | + |**** | + |* * | + |* * | + |* * | + |* * | + |* * | + |* * | + |* * | + |**** | + | | + +-------+ */ + 0b00000000|CHAR7x11_WIDTH_6px, + 0b11110000, + 0b10001000, + 0b10001000, + 0b10001000, + 0b10001000, + 0b10001000, + 0b10001000, + 0b10001000, + 0b11110000, + 0b00000000, + + /* Character 69 (0x45): + width 7 + +-------+ + | | + |***** | + |* | + |* | + |* | + |**** | + |* | + |* | + |* | + |***** | + | | + +-------+ */ + 0b00000000|CHAR7x11_WIDTH_6px, + 0b11111000, + 0b10000000, + 0b10000000, + 0b10000000, + 0b11110000, + 0b10000000, + 0b10000000, + 0b10000000, + 0b11111000, + 0b00000000, + + /* Character 70 (0x46): + width 7 + +-------+ + | | + |***** | + |* | + |* | + |* | + |**** | + |* | + |* | + |* | + |* | + | | + +-------+ */ + 0b00000000|CHAR7x11_WIDTH_6px, + 0b11111000, + 0b10000000, + 0b10000000, + 0b10000000, + 0b11110000, + 0b10000000, + 0b10000000, + 0b10000000, + 0b10000000, + 0b00000000, + + /* Character 71 (0x47): + width 7 + +-------+ + | | + | *** | + |* * | + |* * | + |* | + |* | + |* ** | + |* * | + |* ** | + | ** * | + | | + +-------+ */ + 0b00000000|CHAR7x11_WIDTH_6px, + 0b01110000, + 0b10001000, + 0b10001000, + 0b10000000, + 0b10000000, + 0b10011000, + 0b10001000, + 0b10011000, + 0b01101000, + 0b00000000, + + /* Character 72 (0x48): + width 7 + +-------+ + | | + |* * | + |* * | + |* * | + |* * | + |***** | + |* * | + |* * | + |* * | + |* * | + | | + +-------+ */ + 0b00000000|CHAR7x11_WIDTH_6px, + 0b10001000, + 0b10001000, + 0b10001000, + 0b10001000, + 0b11111000, + 0b10001000, + 0b10001000, + 0b10001000, + 0b10001000, + 0b00000000, + + /* Character 73 (0x49): + width 5 + +-------+ + | | + |*** | + | * | + | * | + | * | + | * | + | * | + | * | + | * | + |*** | + | | + +-------+ */ + 0b00000000|CHAR7x11_WIDTH_4px, + 0b11100000, + 0b01000000, + 0b01000000, + 0b01000000, + 0b01000000, + 0b01000000, + 0b01000000, + 0b01000000, + 0b11100000, + 0b00000000, + + /* Character 74 (0x4a): + width 7 + +-------+ + | | + | * | + | * | + | * | + | * | + | * | + | * | + | * | + |* * | + | *** | + | | + +-------+ */ + 0b00000000|CHAR7x11_WIDTH_6px, + 0b00001000, + 0b00001000, + 0b00001000, + 0b00001000, + 0b00001000, + 0b00001000, + 0b00001000, + 0b10001000, + 0b01110000, + 0b00000000, + + /* Character 75 (0x4b): + width 7 + +-------+ + | | + |* * | + |* * | + |* * | + |* * | + |*** | + |* * | + |* * | + |* * | + |* * | + | | + +-------+ */ + 0b00000000|CHAR7x11_WIDTH_6px, + 0b10001000, + 0b10001000, + 0b10001000, + 0b10010000, + 0b11100000, + 0b10010000, + 0b10001000, + 0b10001000, + 0b10001000, + 0b00000000, + + /* Character 76 (0x4c): + width 7 + +-------+ + | | + |* | + |* | + |* | + |* | + |* | + |* | + |* | + |* | + |***** | + | | + +-------+ */ + 0b00000000|CHAR7x11_WIDTH_6px, + 0b10000000, + 0b10000000, + 0b10000000, + 0b10000000, + 0b10000000, + 0b10000000, + 0b10000000, + 0b10000000, + 0b11111000, + 0b00000000, + + /* Character 77 (0x4d): + width 8 + +-------+ + | | + |* *| + |** **| + |* * * *| + |* * * *| + |* * *| + |* * *| + |* * *| + |* *| + |* *| + | | + +-------+ */ + 0b00000000|CHAR7x11_WIDTH_8px, + 0b10000010, + 0b11000110, + 0b10101010, + 0b10101010, + 0b10010010, + 0b10010010, + 0b10010010, + 0b10000010, + 0b10000010, + 0b00000000, + + /* Character 78 (0x4e): + width 7 + +-------+ + | | + |* * | + |** * | + |** * | + |* * * | + |* * * | + |* * * | + |* ** | + |* ** | + |* * | + | | + +-------+ */ + 0b00000000|CHAR7x11_WIDTH_6px, + 0b10001000, + 0b11001000, + 0b11001000, + 0b10101000, + 0b10101000, + 0b10011000, + 0b10011000, + 0b10001000, + 0b10001000, + 0b00000000, + + /* Character 79 (0x4f): + width 7 + +-------+ + | | + | *** | + |* * | + |* * | + |* * | + |* * | + |* * | + |* * | + |* * | + | *** | + | | + +-------+ */ + 0b00000000|CHAR7x11_WIDTH_6px, + 0b01110000, + 0b10001000, + 0b10001000, + 0b10001000, + 0b10001000, + 0b10001000, + 0b10001000, + 0b10001000, + 0b01110000, + 0b00000000, + + /* Character 80 (0x50): + width 7 + +-------+ + | | + |**** | + |* * | + |* * | + |* * | + |**** | + |* | + |* | + |* | + |* | + | | + +-------+ */ + 0b00000000|CHAR7x11_WIDTH_6px, + 0b11110000, + 0b10001000, + 0b10001000, + 0b10001000, + 0b11110000, + 0b10000000, + 0b10000000, + 0b10000000, + 0b10000000, + 0b00000000, + + /* Character 81 (0x51): + width 7 + +-------+ + | | + | *** | + |* * | + |* * | + |* * | + |* * | + |* * | + |* * * | + |* * | + | ** * | + | | + +-------+ */ + 0b00000000|CHAR7x11_WIDTH_6px, + 0b01110000, + 0b10001000, + 0b10001000, + 0b10001000, + 0b10001000, + 0b10001000, + 0b10101000, + 0b10010000, + 0b01101000, + 0b00000000, + + /* Character 82 (0x52): + width 7 + +-------+ + | | + |**** | + |* * | + |* * | + |* * | + |**** | + |* * | + |* * | + |* * | + |* * | + | | + +-------+ */ + 0b00000000|CHAR7x11_WIDTH_6px, + 0b11110000, + 0b10001000, + 0b10001000, + 0b10001000, + 0b11110000, + 0b10001000, + 0b10001000, + 0b10001000, + 0b10001000, + 0b00000000, + + /* Character 83 (0x53): + width 7 + +-------+ + | | + | *** | + |* * | + |* * | + | * | + | * | + | * | + |* * | + |* * | + | *** | + | | + +-------+ */ + 0b00000000|CHAR7x11_WIDTH_6px, + 0b01110000, + 0b10001000, + 0b10001000, + 0b01000000, + 0b00100000, + 0b00010000, + 0b10001000, + 0b10001000, + 0b01110000, + 0b00000000, + + /* Character 84 (0x54): + width 7 + +-------+ + | | + |***** | + |* * * | + | * | + | * | + | * | + | * | + | * | + | * | + | * | + | | + +-------+ */ + 0b00000000|CHAR7x11_WIDTH_6px, + 0b11111000, + 0b10101000, + 0b00100000, + 0b00100000, + 0b00100000, + 0b00100000, + 0b00100000, + 0b00100000, + 0b00100000, + 0b00000000, + + /* Character 85 (0x55): + width 7 + +-------+ + | | + |* * | + |* * | + |* * | + |* * | + |* * | + |* * | + |* * | + |* * | + | *** | + | | + +-------+ */ + 0b00000000|CHAR7x11_WIDTH_6px, + 0b10001000, + 0b10001000, + 0b10001000, + 0b10001000, + 0b10001000, + 0b10001000, + 0b10001000, + 0b10001000, + 0b01110000, + 0b00000000, + + /* Character 86 (0x56): + width 8 + +-------+ + | | + |* * | + |* * | + |* * | + | * * | + | * * | + | * * | + | * | + | * | + | * | + | | + +-------+ */ + 0b00000000|CHAR7x11_WIDTH_6px, + 0b10001000, + 0b10001000, + 0b10001000, + 0b01010000, + 0b01010000, + 0b01010000, + 0b00100000, + 0b00100000, + 0b00100000, + 0b00000000, + + /* Character 87 (0x57): + width 7 + +-------+ + | | + |* *| + |* *| + |* *| + |* * *| + |* * *| + |* * *| + |* * *| + |* * *| + | ** ** | + | | + +-------+ */ + 0b00000000|CHAR7x11_WIDTH_8px, + 0b10000010, + 0b10000010, + 0b10000010, + 0b10010010, + 0b10010010, + 0b10010010, + 0b10010010, + 0b10010010, + 0b01101100, + 0b00000000, + + /* Character 88 (0x58): + width 7 + +-------+ + | | + |* * | + |* * | + |* * | + | * * | + | * | + | * * | + |* * | + |* * | + |* * | + | | + +-------+ */ + 0b00000000|CHAR7x11_WIDTH_6px, + 0b10001000, + 0b10001000, + 0b10001000, + 0b01010000, + 0b00100000, + 0b01010000, + 0b10001000, + 0b10001000, + 0b10001000, + 0b00000000, + + /* Character 89 (0x59):Y + width 7 + +-------+ + | | + |* * | + |* * | + |* * | + |* * | + | *** | + | * | + | * | + | * | + | * | + | | + +-------+ */ + 0b00000000|CHAR7x11_WIDTH_6px, + 0b10001000, + 0b10001000, + 0b10001000, + 0b10001000, + 0b01110000, + 0b00100000, + 0b00100000, + 0b00100000, + 0b00100000, + 0b00000000, + + /* Character 90 (0x5a): + width 7 + +-------+ + | | + |***** | + | * | + | * | + | * | + | * | + | * | + |* | + |* | + |***** | + | | + +-------+ */ + 0b00000000|CHAR7x11_WIDTH_6px, + 0b11111000, + 0b00001000, + 0b00001000, + 0b00010000, + 0b00100000, + 0b01000000, + 0b10000000, + 0b10000000, + 0b11111000, + 0b00000000, + + /* Character 91 (0x5b): + width 5 + +-------+ + | | + | *** | + | * | + | * | + | * | + | * | + | * | + | * | + | * | + | *** | + | | + +-------+ */ + 0b00000000|CHAR7x11_WIDTH_4px, + 0b11100000, + 0b10000000, + 0b10000000, + 0b10000000, + 0b10000000, + 0b10000000, + 0b10000000, + 0b10000000, + 0b11100000, + 0b00000000, + + /* Character 92 (0x5c): + width 7 + +-------+ + | | + |* | + |* | + | * | + | * | + | * | + | * | + | * | + | * | + | * | + | | + +-------+ */ + 0b00000000|CHAR7x11_WIDTH_6px, + 0b10000000, + 0b10000000, + 0b01000000, + 0b01000000, + 0b00100000, + 0b00010000, + 0b00010000, + 0b00001000, + 0b00001000, + 0b00000000, + + /* Character 93 (0x5d): + width 5 + +-------+ + | | + |*** | + | * | + | * | + | * | + | * | + | * | + | * | + | * | + |*** | + | | + +-------+ */ + 0b00000000|CHAR7x11_WIDTH_4px, + 0b11100000, + 0b00100000, + 0b00100000, + 0b00100000, + 0b00100000, + 0b00100000, + 0b00100000, + 0b00100000, + 0b11100000, + 0b00000000, + + /* Character 94 (0x5e): + width 7 + +-------+ + | | + | * | + | * * | + |* * | + | | + | | + | | + | | + | | + | | + | | + +-------+ */ + 0b00000000|CHAR7x11_WIDTH_6px, + 0b00100000, + 0b01010000, + 0b10001000, + 0b00000000, + 0b00000000, + 0b00000000, + 0b00000000, + 0b00000000, + 0b00000000, + 0b00000000, + + /* Character 95 (0x5f): + width 7 + +-------+ + | | + | | + | | + | | + | | + | | + | | + | | + | | + |****** | + |****** | + +-------+ */ + 0b00000000|CHAR7x11_WIDTH_7px, + 0b00000000, + 0b00000000, + 0b00000000, + 0b00000000, + 0b00000000, + 0b00000000, + 0b00000000, + 0b00000000, + 0b11111100, + 0b11111100, + + /* Character 96 (0x60): + width 5 + +-------+ + | | + |** | + | ** | + | ** | + | | + | | + | | + | | + | | + | | + | | + +-------+ */ + 0b00000000|CHAR7x11_WIDTH_5px, + 0b11000000, + 0b01100000, + 0b00110000, + 0b00000000, + 0b00000000, + 0b00000000, + 0b00000000, + 0b00000000, + 0b00000000, + 0b00000000, + + /* Character 97 (0x61): + width 7 + +-------+ + | | + | | + | | + | | + | *** | + | * | + | **** | + |* * | + |* * | + | **** | + | | + +-------+ */ + 0b00000000|CHAR7x11_WIDTH_6px, + 0b00000000, + 0b00000000, + 0b00000000, + 0b01110000, + 0b00001000, + 0b01111000, + 0b10001000, + 0b10001000, + 0b01111000, + 0b00000000, + + /* Character 98 (0x62): + width 7 + +-------+ + | | + |* | + |* | + |* | + |* ** | + |** * | + |* * | + |* * | + |** * | + |* ** | + | | + +-------+ */ + 0b00000000|CHAR7x11_WIDTH_6px, + 0b10000000, + 0b10000000, + 0b10000000, + 0b10110000, + 0b11001000, + 0b10001000, + 0b10001000, + 0b11001000, + 0b10110000, + 0b00000000, + + /* Character 99 (0x63): + width 7 + +-------+ + | | + | | + | | + | | + | *** | + |* * | + |* | + |* | + |* * | + | *** | + | | + +-------+ */ + 0b00000000|CHAR7x11_WIDTH_6px, + 0b00000000, + 0b00000000, + 0b00000000, + 0b01110000, + 0b10001000, + 0b10000000, + 0b10000000, + 0b10001000, + 0b01110000, + 0b00000000, + + /* Character 100 (0x64): + width 7 + +-------+ + | | + | * | + | * | + | * | + | ** * | + |* ** | + |* * | + |* * | + |* ** | + | ** * | + | | + +-------+ */ + 0b00000000|CHAR7x11_WIDTH_6px, + 0b00001000, + 0b00001000, + 0b00001000, + 0b01101000, + 0b10011000, + 0b10001000, + 0b10001000, + 0b10011000, + 0b01101000, + 0b00000000, + + /* Character 101 (0x65): + width 7 + +-------+ + | | + | | + | | + | | + | *** | + |* * | + |***** | + |* | + |* * | + | *** | + | | + +-------+ */ + 0b00000000|CHAR7x11_WIDTH_6px, + 0b00000000, + 0b00000000, + 0b00000000, + 0b01110000, + 0b10001000, + 0b11111000, + 0b10000000, + 0b10001000, + 0b01110000, + 0b00000000, + + /* Character 102 (0x66): + width 7 + +-------+ + | | + | ** | + | * * | + | * | + | * | + |*** | + | * | + | * | + | * | + | * | + | | + +-------+ */ + 0b00000000|CHAR7x11_WIDTH_6px, + 0b00110000, + 0b01001000, + 0b01000000, + 0b01000000, + 0b11100000, + 0b01000000, + 0b01000000, + 0b01000000, + 0b01000000, + 0b00000000, + + /* Character 103 (0x67):g + width 7 + +-------+ + | | + | | + | | + | | + | ** * | + |* ** | + |* * | + |* * | + | **** | + | * | + | *** | + +-------+ */ + 0b00000000|CHAR7x11_WIDTH_6px, + 0b00000000, + 0b00000000, + 0b00000000, + 0b01101000, + 0b10011000, + 0b10001000, + 0b10001000, + 0b01111000, + 0b00001000, + 0b01110000, + + /* Character 104 (0x68): + width 7 + +-------+ + | | + |* | + |* | + |* | + |* ** | + |** * | + |* * | + |* * | + |* * | + |* * | + | | + +-------+ */ + 0b00000000|CHAR7x11_WIDTH_6px, + 0b10000000, + 0b10000000, + 0b10000000, + 0b10110000, + 0b11001000, + 0b10001000, + 0b10001000, + 0b10001000, + 0b10001000, + 0b00000000, + + /* Character 105 (0x69): + width 7 + +-------+ + | | + | | + | * | + | | + |** | + | * | + | * | + | * | + | * | + |*** | + | | + +-------+ */ + 0b00000000|CHAR7x11_WIDTH_4px, + 0b00000000, + 0b01000000, + 0b00000000, + 0b11000000, + 0b01000000, + 0b01000000, + 0b01000000, + 0b01000000, + 0b11100000, + 0b00000000, + + /* Character 106 (0x6a): + width 7 + +-------+ + | | + | | + | * | + | | + | * | + | * | + | * | + | * | + | * | + |* * | + | *** | + +-------+ */ + 0b00000000|CHAR7x11_WIDTH_6px, + 0b00000000, + 0b00001000, + 0b00000000, + 0b00001000, + 0b00001000, + 0b00001000, + 0b00001000, + 0b00001000, + 0b10001000, + 0b01110000, + + /* Character 107 (0x6b): + width 7 + +-------+ + | | + |* | + |* | + |* | + |* * | + |* * | + |* * | + |*** | + |* * | + |* * | + | | + +-------+ */ + 0b00000000|CHAR7x11_WIDTH_6px, + 0b10000000, + 0b10000000, + 0b10000000, + 0b10001000, + 0b10010000, + 0b10100000, + 0b11100000, + 0b10010000, + 0b10001000, + 0b00000000, + + /* Character 108 (0x6c): + width 7 + +-------+ + | | + | ** | + | * | + | * | + | * | + | * | + | * | + | * | + | * | + |***** | + | | + +-------+ */ + 0b00000000|CHAR7x11_WIDTH_6px, + 0b01100000, + 0b00100000, + 0b00100000, + 0b00100000, + 0b00100000, + 0b00100000, + 0b00100000, + 0b00100000, + 0b11111000, + 0b00000000, + + /* Character 109 (0x6d): + width 7 + +-------+ + | | + | | + | | + | | + |*** ** | + |* * *| + |* * *| + |* * *| + |* * *| + |* * *| + | | + +-------+ */ + 0b00000000|CHAR7x11_WIDTH_8px, + 0b00000000, + 0b00000000, + 0b00000000, + 0b11101100, + 0b10010010, + 0b10010010, + 0b10010010, + 0b10010010, + 0b10010010, + 0b00000000, + + /* Character 110 (0x6e): + width 7 + +-------+ + | | + | | + | | + | | + |* ** | + |** * | + |* * | + |* * | + |* * | + |* * | + | | + +-------+ */ + 0b00000000|CHAR7x11_WIDTH_6px, + 0b00000000, + 0b00000000, + 0b00000000, + 0b10110000, + 0b11001000, + 0b10001000, + 0b10001000, + 0b10001000, + 0b10001000, + 0b00000000, + + /* Character 111 (0x6f): + width 7 + +-------+ + | | + | | + | | + | | + | *** | + |* * | + |* * | + |* * | + |* * | + | *** | + | | + +-------+ */ + 0b00000000|CHAR7x11_WIDTH_6px, + 0b00000000, + 0b00000000, + 0b00000000, + 0b01110000, + 0b10001000, + 0b10001000, + 0b10001000, + 0b10001000, + 0b01110000, + 0b00000000, + + /* Character 112 (0x70): + width 7 + +-------+ + | | + | | + | | + | | + |* ** | + |** * | + |* * | + |* * | + |**** | + |* | + |* | + +-------+ */ + 0b00000000|CHAR7x11_WIDTH_6px, + 0b00000000, + 0b00000000, + 0b00000000, + 0b10110000, + 0b11001000, + 0b10001000, + 0b10001000, + 0b11110000, + 0b10000000, + 0b10000000, + + /* Character 113 (0x71): + width 7 + +-------+ + | | + | | + | | + | | + | ** * | + |* ** | + |* * | + |* * | + | **** | + | * | + | * | + +-------+ */ + 0b00000000|CHAR7x11_WIDTH_6px, + 0b00000000, + 0b00000000, + 0b00000000, + 0b01101000, + 0b10011000, + 0b10001000, + 0b10001000, + 0b01111000, + 0b00001000, + 0b00001000, + + /* Character 114 (0x72): + width 7 + +-------+ + | | + | | + | | + | | + |* ** | + |** * | + |* | + |* | + |* | + |* | + | | + +-------+ */ + 0b00000000|CHAR7x11_WIDTH_6px, + 0b00000000, + 0b00000000, + 0b00000000, + 0b10110000, + 0b11001000, + 0b10000000, + 0b10000000, + 0b10000000, + 0b10000000, + 0b00000000, + + /* Character 115 (0x73): + width 7 + +-------+ + | | + | | + | | + | | + | *** | + |* * | + | ** | + | ** | + |* * | + | *** | + | | + +-------+ */ + 0b00000000|CHAR7x11_WIDTH_6px, + 0b00000000, + 0b00000000, + 0b00000000, + 0b01110000, + 0b10001000, + 0b01100000, + 0b00110000, + 0b10001000, + 0b01110000, + 0b00000000, + + /* Character 116 (0x74): + width 7 + +-------+ + | | + | | + | * | + | * | + |*** | + | * | + | * | + | * | + | * | + | ** | + | | + +-------+ */ + 0b00000000|CHAR7x11_WIDTH_5px, + 0b00000000, + 0b01000000, + 0b01000000, + 0b11100000, + 0b01000000, + 0b01000000, + 0b01000000, + 0b01000000, + 0b00110000, + 0b00000000, + + /* Character 117 (0x75): + width 7 + +-------+ + | | + | | + | | + | | + |* * | + |* * | + |* * | + |* * | + |* ** | + | ** * | + | | + +-------+ */ + 0b00000000|CHAR7x11_WIDTH_6px, + 0b00000000, + 0b00000000, + 0b00000000, + 0b10001000, + 0b10001000, + 0b10001000, + 0b10001000, + 0b10011000, + 0b01101000, + 0b00000000, + + /* Character 118 (0x76): + width 7 + +-------+ + | | + | | + | | + | | + |* * | + |* * | + | * * | + | * * | + | * | + | * | + | | + +-------+ */ + 0b00000000|CHAR7x11_WIDTH_6px, + 0b00000000, + 0b00000000, + 0b00000000, + 0b10001000, + 0b10001000, + 0b01010000, + 0b01010000, + 0b00100000, + 0b00100000, + 0b00000000, + + /* Character 119 (0x77): + width 7 + +-------+ + | | + | | + | | + | | + |* *| + |* *| + |* * *| + |* * *| + |* * *| + | ** ** | + | | + +-------+ */ + 0b00000000|CHAR7x11_WIDTH_8px, + 0b00000000, + 0b00000000, + 0b00000000, + 0b10000010, + 0b10000010, + 0b10010010, + 0b10010010, + 0b10010010, + 0b01101100, + 0b00000000, + + /* Character 120 (0x78): + width 7 + +-------+ + | | + | | + | | + | | + |* * | + | * * | + | * | + | * | + | * * | + |* * | + | | + +-------+ */ + 0b00000000|CHAR7x11_WIDTH_6px, + 0b00000000, + 0b00000000, + 0b00000000, + 0b10001000, + 0b01010000, + 0b00100000, + 0b00100000, + 0b01010000, + 0b10001000, + 0b00000000, + + /* Character 121 (0x79): + width 7 + +-------+ + | | + | | + | | + | | + |* * | + |* * | + |* * | + | **** | + | * | + |* * | + | *** | + +-------+ */ + 0b00000000|CHAR7x11_WIDTH_6px, + 0b00000000, + 0b00000000, + 0b00000000, + 0b10001000, + 0b10001000, + 0b10001000, + 0b01111000, + 0b00001000, + 0b10001000, + 0b01110000, + + /* Character 122 (0x7a): + width 7 + +-------+ + | | + | | + | | + | | + |**** | + | * | + | * | + | * | + |* | + |**** | + | | + +-------+ */ + 0b00000000|CHAR7x11_WIDTH_5px, + 0b00000000, + 0b00000000, + 0b00000000, + 0b11110000, + 0b00010000, + 0b00100000, + 0b01000000, + 0b10000000, + 0b11110000, + 0b00000000, + + /* Character 123 (0x7b): + width 6 + +-------+ + | | + | ** | + | * | + | * | + | * | + |* | + | * | + | * | + | * | + | ** | + | | + +-------+ */ + 0b00000000|CHAR7x11_WIDTH_5px, + 0b00110000, + 0b01000000, + 0b01000000, + 0b01000000, + 0b10000000, + 0b01000000, + 0b01000000, + 0b01000000, + 0b00110000, + 0b00000000, + + /* Character 124 (0x7c): + width 5 + +-------+ + | | + | * | + | * | + | * | + | * | + | * | + | * | + | * | + | * | + | * | + | | + +-------+ */ + 0b00000000|CHAR7x11_WIDTH_4px, + 0b01000000, + 0b01000000, + 0b01000000, + 0b01000000, + 0b01000000, + 0b01000000, + 0b01000000, + 0b01000000, + 0b01000000, + 0b00000000, + + /* Character 125 (0x7d): + width 6 + +-------+ + | | + |** | + | * | + | * | + | * | + | * | + | * | + | * | + | * | + |** | + | | + +-------+ */ + 0b00000000|CHAR7x11_WIDTH_5px, + 0b11000000, + 0b00100000, + 0b00100000, + 0b00100000, + 0b00010000, + 0b00100000, + 0b00100000, + 0b00100000, + 0b11000000, + 0b00000000, + + /* Character 126 (0x7e): + width 7 + +-------+ + | | + | * * | + |* * * | + |* * | + | | + | | + | | + | | + | | + | | + | | + +-------+ */ + 0b00000000|CHAR7x11_WIDTH_6px, + 0b01001000, + 0b10101000, + 0b10010000, + 0b00000000, + 0b00000000, + 0b00000000, + 0b00000000, + 0b00000000, + 0b00000000, + 0b00000000, +}; diff --git a/Font7x13b.c b/Font7x11b.c similarity index 100% rename from Font7x13b.c rename to Font7x11b.c diff --git a/Makefile b/Makefile index 69bfbf8..e5bb7be 100644 --- a/Makefile +++ b/Makefile @@ -7,15 +7,16 @@ ifeq ($(TARGET),) TARGET = F072 endif -#TARGET=F303 +TARGET=F303 # Compiler options here. ifeq ($(USE_OPT),) ifeq ($(TARGET),F303) -USE_OPT = -O2 -fno-inline-small-functions -ggdb -fomit-frame-pointer -falign-functions=16 --specs=nano.specs -fstack-usage -std=c11 -DLCD_DRIVER_ST7796S -DLCD_480x320 -D__VNA_ENABLE_DAC__ -D__LCD_BRIGHTNESS__ -DPOINTS_COUNT=401 +USE_OPT = -O2 -fno-inline-small-functions -ggdb -fomit-frame-pointer -falign-functions=16 --specs=nano.specs -fstack-usage -std=c11 -DLCD_DRIVER_ST7796S -DLCD_480x320 -D__VNA_ENABLE_DAC__ -D__LCD_BRIGHTNESS__ -DPOINTS_COUNT=401 -D_USE_FONT_=1 -D_USE_BIG_MARKER_=1 #USE_OPT+=-fstack-protector-strong else -USE_OPT = -O2 -fno-inline-small-functions -ggdb -fomit-frame-pointer -falign-functions=16 --specs=nano.specs -fstack-usage -std=c11 -DLCD_DRIVER_ILI9341 -DLCD_320x240 -D__DFU_SOFTWARE_MODE__ -DPOINTS_COUNT=101 +USE_OPT = -O2 -fno-inline-small-functions -ggdb -fomit-frame-pointer -falign-functions=16 --specs=nano.specs -fstack-usage -std=c11 -DLCD_DRIVER_ILI9341 -DLCD_320x240 -D__DFU_SOFTWARE_MODE__ -DPOINTS_COUNT=101 -D_USE_FONT_=1 -D_USE_BIG_MARKER_=1 + endif endif @@ -147,7 +148,7 @@ CSRC = $(STARTUPSRC) \ FatFs/ff.c \ FatFs/ffunicode.c \ usbcfg.c \ - main.c si5351.c tlv320aic3204.c dsp.c plot.c ui.c ili9341.c numfont20x22.c Font5x7.c Font7x13b.c Font10x14.c flash.c adc.c rtc.c vna_math.c + main.c si5351.c tlv320aic3204.c dsp.c plot.c ui.c ili9341.c numfont20x22.c Font5x7.c Font7x11b.c Font10x14.c Font6x11.c flash.c adc.c rtc.c vna_math.c # C++ sources that can be compiled in ARM or THUMB mode depending on the global # setting. diff --git a/doc/Schematic_NanoVNA-H4_REV4_3.pdf b/doc/Schematic_NanoVNA-H4_REV4_3.pdf new file mode 100644 index 0000000000000000000000000000000000000000..21b79272a82609463dba9a523ee6dee122f0d286 GIT binary patch literal 265952 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�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 I{^qm)2PJ~K8UO$Q literal 0 HcmV?d00001 diff --git a/lc_matching.c b/lc_matching.c index 3be7f7e..b9fd398 100644 --- a/lc_matching.c +++ b/lc_matching.c @@ -27,6 +27,105 @@ static void match_quadratic_equation(float a, float b, float c, float *x) x[1] = (-b - sd) / a_x_2; } +// Search functions +// Type of get value function +typedef float (*get_value_t)(uint16_t idx); + +// Search point get_value(x) = y +// Used bilinear interpolation, return value = frequency of this point +#define MEASURE_SEARCH_LEFT -1 +#define MEASURE_SEARCH_RIGHT 1 +static float measure_search_value(uint16_t *idx, float y, get_value_t get, int16_t mode){ + uint16_t x = *idx; + float y1, y2, y3; + y1 = y2 = y3 = get(x); + bool result = (y3 > y); // current position depend from start point + for(; x < sweep_points; x+=mode) { + y3 = get(x); + if(result != (y3 > y)) break; + y1 = y2; + y2 = y3; + } + if (x >= sweep_points) return 0; + x-=mode; + *idx = x; + // Now y1 > y, y2 > y, y3 <= y or y1 < y, y2 < y, y3 >= y + const float a = 0.5f * (y1 + y3) - y2; + const float b = 0.5f * (y3 - y1); + const float c = y2 - y; + float r[2]; + match_quadratic_equation(a, b, c, r); + // Select result in middle 0 and 1 (in middle y2 and y3 result) + float res = (r[0] > 0 && r[0] < 1.0) ? r[0] : r[1]; + // for search left need swap y1 and y3 points (use negative result) + if (mode < 0) res=-res; + return getFrequency(x) + getFrequencyStep() * res; +} + +// Peak search, use bilinear interpolation for peak detect +#define MEASURE_SEARCH_MIN 0 +#define MEASURE_SEARCH_MAX 1 +static bool _greaterf(float x, float y) { return x > y; } +static bool _lesserf(float x, float y) { return x < y; } +static float search_peak_value(uint16_t *xp, get_value_t get, bool mode){ + bool (*compare)(float x, float y) = mode ? _greaterf : _lesserf; + uint16_t x = 0; + float y2 = get(x), ytemp; + for(int i = 1; i < sweep_points; i++) { + if(compare(ytemp = get(i), y2)) { + y2 = ytemp; + x = i; + } + } + if (x < 1 || x >= sweep_points - 1) return y2; + *xp = x; + float y1 = get(x-1); + float y3 = get(x+1); + if (y1 == y3) return y2; +// const float a = 0.5f * (y1 + y3) - y2; +// const float b = 0.5f * (y3 - y1); +// const float c = y2; +// return c - b*b/(4*a); + const float a = 8*(y1 - 2*y2 + y3); + const float b = y3 - y1; + const float c = y2; + return c - b * b / a; +} + +static float bilinear_interpolation(float y1, float y2, float y3, float k1){ + const float a = 0.5f * (y1 + y3) - y2; + const float b = 0.5f * (y3 - y1); + const float c = y2; + return a * k1*k1 + b * k1 + c; +} + +static bool measure_get_value(uint16_t ch, freq_t f, float *data){ + if (f < frequency0 || f > frequency1) + return false; + // Search k1 + uint16_t _points = sweep_points - 1; + freq_t span = frequency1 - frequency0; + uint32_t idx = (uint64_t)(f - frequency0) * (uint64_t)_points / span; + if (idx < 1 && idx > _points) + return false; + uint64_t v = (uint64_t)span * idx + _points/2; + freq_t src_f0 = frequency0 + (v ) / _points; + freq_t src_f1 = frequency0 + (v + span) / _points; + freq_t delta = src_f1 - src_f0; + float k1 = (delta == 0) ? 0.0 : (float)(f - src_f0) / delta; +#if 1 + // Bilinear interpolation by k1 + data[0] = bilinear_interpolation(measured[ch][idx-1][0], measured[ch][idx ][0], measured[ch][idx+1][0],k1); + data[1] = bilinear_interpolation(measured[ch][idx-1][1], measured[ch][idx ][1], measured[ch][idx+1][1],k1); +#else + // Linear Interpolate by k1 + float k0 = 1.0 - k1; + data[0] = measured[ch][idx][0] * k0 + measured[ch][idx+1][0] * k1; + data[1] = measured[ch][idx][1] * k0 + measured[ch][idx+1][1] * k1; +#endif + return true; +} + #ifdef __USE_LC_MATCHING__ // calculate physical component values to match an impendace to 'ref_impedance' (ie 50R) typedef struct @@ -226,5 +325,223 @@ static void draw_lc_match(int x0, int y0) } } #endif // __USE_LC_MATCHING__ +#ifdef __S21_MEASURE__ +typedef struct { + char *header; + freq_t freq; // resonant frequency + freq_t freq1; // fp + float l; + float c; + float c1; // capacitor parallel + float r; + float q; // Q factor + +// freq_t f1; +// freq_t f2; +// float tan45; +} s21_analysis_t; +static s21_analysis_t *s21_measure = (s21_analysis_t *)measure_memory; + +static float s21pow2(uint16_t i) { + const float re = measured[1][i][0]; // S21 real + const float im = measured[1][i][1]; // S21 imaginary + return re*re+im*im; // S21^2 +} + +static float s21tan(uint16_t i) { + const float re = measured[1][i][0]; // S21 real + const float im = measured[1][i][1]; // S21 imaginary + return im/re; // tan(S21) +} + +// Phase Shift Measurement +// https://www.mikrocontroller.net/attachment/473317/Crystal_Motional_Parameters.pdf +static void analysis_lcshunt(void) { + uint16_t xp = 0, x2; + s21_measure->header = "LC-SHUNT"; + // Minimum search + float ypeak = search_peak_value(&xp, s21pow2, MEASURE_SEARCH_MIN); + // peak frequency, R + float att = vna_sqrtf(ypeak); + s21_measure->r = config._measure_r * att / (2 * (1 - att)); + if(s21_measure->r < 0) return; + set_marker_index(0, xp); + + float tan45 = config._measure_r/(config._measure_r + 4 * s21_measure->r); +// s21_measure->tan45 = tan45; + // -45 degree search at left + x2 = xp; + float f1 = measure_search_value(&x2, -tan45, s21tan, MEASURE_SEARCH_LEFT); + if (f1 == 0) return; + set_marker_index(1, x2); + + // +45 degree search at right + x2 = xp; + float f2 = measure_search_value(&x2, tan45, s21tan, MEASURE_SEARCH_RIGHT); + if (f2 == 0) return; + set_marker_index(2, x2); + + // L,C,Q calculations + float bw = f2 - f1; + float fpeak = vna_sqrtf(f2 * f1); + s21_measure->freq = fpeak; + s21_measure->q = fpeak / bw; + s21_measure->l = s21_measure->q * s21_measure->r / ((2 * VNA_PI) * fpeak); + s21_measure->c = 1 / ((2 * VNA_PI) * fpeak * s21_measure->q * s21_measure->r); +} + +static void analysis_lcseries(void) { + uint16_t xp=0, x2; + s21_measure->header = "LC-SERIES"; + // Peak value and it frequency index search + float ypeak = search_peak_value(&xp, s21pow2, MEASURE_SEARCH_MAX); + if (xp == 0) return; // peak not found + // motional resistance, Rm + s21_measure->r = 2 * config._measure_r * (1.0f / vna_sqrtf(ypeak) - 1.0f); + if(s21_measure->r < 0) return; + set_marker_index(0, xp); + + const float tan45 = 1.0f; // tand(45) = 1.0f + // Lookup +45 phase at left of xp index + x2 = xp; + float f1 = measure_search_value(&x2, tan45, s21tan, MEASURE_SEARCH_LEFT); + if (f1 == 0) return; // not found + set_marker_index(1, x2); + + // Lookup -45 phase at right of xp index + x2 = xp; + float f2 = measure_search_value(&x2, -tan45, s21tan, MEASURE_SEARCH_RIGHT); + if (f2 == 0) return; // not found + set_marker_index(2, x2); + + // L,C,Q calculation + float bw = f2 - f1; + float fpeak = vna_sqrtf(f2*f1); + // The total resistance, REFF, seen by the crystal is the sum of the load resistance (input and output) and the motional resistance, Rm: + float reff = 2 * config._measure_r + s21_measure->r; + + s21_measure->freq = fpeak; + s21_measure->l = reff / ((2 * VNA_PI) * bw); + s21_measure->c = bw / ((2 * VNA_PI) * fpeak * fpeak * reff); + // q = 2*pi * Fp * Ls / R + s21_measure->q = (2 * VNA_PI) * fpeak * s21_measure->l / s21_measure->r; + +// s21_measure->f1 = f1; +// s21_measure->f2 = f2; +} + +static void analysis_xtalseries(void) { + analysis_lcseries(); + s21_measure->header = "XTAL-SERIES"; + // search S21 min + uint16_t xp=0; + search_peak_value(&xp, s21pow2, MEASURE_SEARCH_MIN); + if (xp == 0) return; + set_marker_index(3, xp); + + freq_t freq1 = getFrequency(xp); + if(freq1 < s21_measure->freq) return; + s21_measure->freq1 = freq1; + // df = f * c / (2*c1) => c1 = f * c / (2*df) + s21_measure->c1 = s21_measure->c * s21_measure->freq / (2*(s21_measure->freq1 - s21_measure->freq)); +} + +static void draw_serial_result(int x0, int y0){ + int xp = STR_MEASURE_X - x0; + int yp = STR_MEASURE_Y - y0; + cell_printf(xp, yp, s21_measure->header); + if (s21_measure->freq == 0 && s21_measure->freq1 == 0) { + cell_printf(xp, yp+=STR_MEASURE_HEIGHT, "Not found"); + return; + } + if (s21_measure->freq) + { + cell_printf(xp, yp+=STR_MEASURE_HEIGHT, "Fs=%qHz", s21_measure->freq); + cell_printf(xp, yp+=STR_MEASURE_HEIGHT, "Ls=%FH Cs=%FF Rs=%F" S_OHM, s21_measure->l, s21_measure->c, s21_measure->r); + cell_printf(xp, yp+=STR_MEASURE_HEIGHT, "Q=%.3f", s21_measure->q); +// cell_printf(xp, yp+=STR_MEASURE_HEIGHT, "tan45=%.4f", s21_measure->tan45); +// cell_printf(xp, yp+=STR_MEASURE_HEIGHT, "F1=%qHz F2=%qHz", s21_measure->f1, s21_measure->f2); + } + if (s21_measure->freq1){ + cell_printf(xp, yp+=STR_MEASURE_HEIGHT, "Fp=%qHz", s21_measure->freq1); + cell_printf(xp, yp+=STR_MEASURE_HEIGHT, "Cp=%FF", s21_measure->c1); + } +} + +static void prepare_series(uint8_t type, uint8_t update_mask) +{ + (void)update_mask; + uint16_t n; + // for detect completion + s21_measure->freq = 0; + s21_measure->freq1 = 0; + switch (type){ + case MEASURE_SHUNT_LC: n = 4; analysis_lcshunt(); break; + case MEASURE_SERIES_LC: n = 4; analysis_lcseries(); break; + case MEASURE_SERIES_XTAL: n = 6; analysis_xtalseries(); break; + default: return; + } + // Prepare for update + invalidate_rect(STR_MEASURE_X , STR_MEASURE_Y, + STR_MEASURE_X + 3 * STR_MEASURE_WIDTH, STR_MEASURE_Y + n * STR_MEASURE_HEIGHT); + markmap_all_markers(); +} +#endif // __S21_MEASURE__ + +#ifdef __S11_CABLE_MEASURE__ +typedef struct { + float R; + float len; + float loss; + float C0; + float a, b, c; +} s11_cable_measure_t; +static s11_cable_measure_t *s11_cable = (s11_cable_measure_t *)measure_memory; + +static float s11imag(uint16_t i) { + return measured[0][i][1]; +} + +static void draw_s11_cable(int x0, int y0){ + int xp = STR_MEASURE_X - x0; + int yp = STR_MEASURE_Y - y0; + cell_printf(xp, yp, "S11 CABLE"); + if (s11_cable->R){ + cell_printf(xp, yp+=STR_MEASURE_HEIGHT, "Z0 = %F" S_OHM, s11_cable->R); +// cell_printf(xp, yp+=FONT_STR_HEIGHT, "C0 = %FF", s11_cable->C0); + } + if (s11_cable->len) + cell_printf(xp, yp+=STR_MEASURE_HEIGHT, "Length = %Fm (K=%d%%)", s11_cable->len, velocity_factor); + cell_printf(xp, yp+=STR_MEASURE_HEIGHT, "Loss = %FdB", s11_cable->loss); +} + +static void prepare_s11_cable(uint8_t type, uint8_t update_mask) +{ + (void)type; + freq_t f1; + if (update_mask & MEASURE_UPD_SWEEP) { + s11_cable->R = 0.0f; + s11_cable->len = 0.0f; + uint16_t x = 0; + f1 = measure_search_value(&x, 0, s11imag, MEASURE_SEARCH_RIGHT); + if (f1){ + s11_cable->len = velocity_factor * (SPEED_OF_LIGHT / 400.0f) / f1; + float data[2]; + if (measure_get_value(0, f1/2, data)){ + s11_cable->R = vna_fabsf(reactance(0, data)); +// s11_cable->C0 = velocity_factor / (100.0f * SPEED_OF_LIGHT * s11_cable->R); + } + } + } + if (update_mask & MEASURE_UPD_ALL && active_marker != MARKER_INVALID) { + int idx = markers[active_marker].index; + s11_cable->loss = vna_fabsf(logmag(idx, measured[0][idx]) / 2); + } + // Prepare for update + invalidate_rect(STR_MEASURE_X , STR_MEASURE_Y, + STR_MEASURE_X + 3 * STR_MEASURE_WIDTH, STR_MEASURE_Y + 4 * STR_MEASURE_HEIGHT); +} + +#endif // __S11_CABLE_MEASURE__ #endif // __VNA_MEASURE__ diff --git a/main.c b/main.c index 04d53ae..06e4e5b 100644 --- a/main.c +++ b/main.c @@ -129,7 +129,7 @@ static float kaiser_data[FFT_SIZE]; #endif #undef VERSION -#define VERSION "1.0.70" +#define VERSION "1.0.71" // Version text, displayed in Config->Version menu, also send by info command const char *info_about[]={ @@ -910,6 +910,7 @@ config_t config = { ._measure_r = MEASURE_DEFAULT_R, ._lever_mode = LM_MARKER, ._digit_separator = '.', + ._band_mode = 0, }; properties_t current_props; diff --git a/nanovna.h b/nanovna.h index 2490e9d..3aa24a2 100644 --- a/nanovna.h +++ b/nanovna.h @@ -80,9 +80,9 @@ // Add LC match function #define __USE_LC_MATCHING__ // Enable Series measure option -//#define __S21_MEASURE__ +#define __S21_MEASURE__ // Enable S11 cable measure option -//#define __S11_CABLE_MEASURE__ +#define __S11_CABLE_MEASURE__ #endif /* @@ -93,7 +93,7 @@ // Maximum frequency set #define STOP_MAX 2000000000U // Frequency threshold (max frequency for si5351, harmonic mode after) -#define FREQUENCY_THRESHOLD 280000100U +#define FREQUENCY_THRESHOLD 290000100U // XTAL frequency on si5351 #define XTALFREQ 26000000U // Define i2c bus speed, add predefined for 400k, 600k, 900k @@ -103,21 +103,30 @@ // Define ADC sample rate in kilobyte (can be 48k, 96k, 192k, 384k) //#define AUDIO_ADC_FREQ_K 768 -//#define AUDIO_ADC_FREQ_K 384 +#ifdef ARM_MATH_CM4 +#define AUDIO_ADC_FREQ_K 384 +#else #define AUDIO_ADC_FREQ_K 192 +#endif //#define AUDIO_ADC_FREQ_K 96 //#define AUDIO_ADC_FREQ_K 48 // Define sample count for one step measure +#ifndef ARM_MATH_CM4 #define AUDIO_SAMPLES_COUNT (48) -//#define AUDIO_SAMPLES_COUNT (96) +#else +#define AUDIO_SAMPLES_COUNT (96) +#endif //#define AUDIO_SAMPLES_COUNT (192) // Frequency offset, depend from AUDIO_ADC_FREQ settings (need aligned table) // Use real time build table (undef for use constant, see comments) // Constant tables build only for AUDIO_SAMPLES_COUNT = 48 -//#define USE_VARIABLE_OFFSET -//#define USE_VARIABLE_OFFSET_MENU +#define USE_VARIABLE_OFFSET +// Add IF select menu in expert settings +#ifdef USE_VARIABLE_OFFSET +#define USE_VARIABLE_OFFSET_MENU +#endif #if AUDIO_ADC_FREQ_K == 768 #define FREQUENCY_OFFSET_STEP 16000 @@ -190,15 +199,15 @@ typedef uint32_t freq_t; #if POINTS_COUNT >=401 #define POINTS_SET_COUNT 5 #define POINTS_SET {51, 101, 201, 301, POINTS_COUNT} -#define POINTS_COUNT_DEFAULT POINTS_COUNT +#define POINTS_COUNT_DEFAULT 101 #elif POINTS_COUNT >=301 #define POINTS_SET_COUNT 4 #define POINTS_SET {51, 101, 201, POINTS_COUNT} -#define POINTS_COUNT_DEFAULT POINTS_COUNT +#define POINTS_COUNT_DEFAULT 101 #elif POINTS_COUNT >=201 #define POINTS_SET_COUNT 3 #define POINTS_SET {51, 101, POINTS_COUNT} -#define POINTS_COUNT_DEFAULT POINTS_COUNT +#define POINTS_COUNT_DEFAULT 101 #elif POINTS_COUNT >=101 #define POINTS_SET_COUNT 2 #define POINTS_SET {51, POINTS_COUNT} @@ -404,9 +413,9 @@ void tlv320aic3204_write_reg(uint8_t page, uint8_t reg, uint8_t data); // Define maximum distance in pixel for pickup marker (can be bigger for big displays) #define MARKER_PICKUP_DISTANCE 20 // Used marker size settings -#define _USE_BIG_MARKER_ 1 +//#define _USE_BIG_MARKER_ 1 // Used font settings -#define _USE_FONT_ 1 +//#define _USE_FONT_ 3 // Offset of plot area (size of additional info at left side) #if _USE_FONT_== 1 @@ -416,14 +425,25 @@ void tlv320aic3204_write_reg(uint8_t page, uint8_t reg, uint8_t data); // HEIGHT = 8*GRIDY #define HEIGHT 224 #define FREQUENCIES_XPOS2 176 +#define FREQUENCIES_XPOS3 155 +#define MENU_BUTTON_WIDTH 84 +#elif _USE_FONT_== 3 +#define OFFSETX 12 +// WIDTH better be n*(POINTS_COUNT-1) +#define WIDTH 298 +// HEIGHT = 8*GRIDY +#define HEIGHT 224 +#define FREQUENCIES_XPOS2 193 +#define FREQUENCIES_XPOS3 144 #define MENU_BUTTON_WIDTH 84 -#elif +#else #define OFFSETX 10 // WIDTH better be n*(POINTS_COUNT-1) #define WIDTH 300 // HEIGHT = 8*GRIDY #define HEIGHT 232 #define FREQUENCIES_XPOS2 206 +#define FREQUENCIES_XPOS3 135 #define MENU_BUTTON_WIDTH 66 #endif #define OFFSETY 0 @@ -435,7 +455,7 @@ void tlv320aic3204_write_reg(uint8_t page, uint8_t reg, uint8_t data); #define FREQUENCIES_XPOS1 OFFSETX -#define FREQUENCIES_XPOS3 135 + #define FREQUENCIES_YPOS (LCD_HEIGHT-FONT_GET_HEIGHT) // GRIDX calculated depends from frequency span @@ -503,9 +523,9 @@ void tlv320aic3204_write_reg(uint8_t page, uint8_t reg, uint8_t data); // Define maximum distance in pixel for pickup marker (can be bigger for big displays) #define MARKER_PICKUP_DISTANCE 30 // Used marker size settings -#define _USE_BIG_MARKER_ 1 +//#define _USE_BIG_MARKER_ 1 // Used font settings -#define _USE_FONT_ 1 +//#define _USE_FONT_ 1 // Offset of plot area (size of additional info at left side) #define OFFSETX 15 @@ -614,6 +634,17 @@ extern const uint8_t x10x14_bits[]; #define FONT_STR_HEIGHT 16 #define FONT_GET_DATA(ch) ( &x10x14_bits[(ch-FONT_START_CHAR)*2*FONT_GET_HEIGHT ]) #define FONT_GET_WIDTH(ch) (14-(x10x14_bits[(ch-FONT_START_CHAR)*2*FONT_GET_HEIGHT+1]&0x7)) + +#elif _USE_FONT_ == 3 +extern const uint8_t x6x11_bits[]; +#define FONT_START_CHAR 0x17 +#define FONT_MAX_WIDTH 8 +#define FONT_WIDTH 6 +#define FONT_GET_HEIGHT 11 +#define FONT_STR_HEIGHT 11 +#define FONT_GET_DATA(ch) ( &x6x11_bits[(ch-FONT_START_CHAR)*FONT_GET_HEIGHT]) +#define FONT_GET_WIDTH(ch) (8-(x6x11_bits[(ch-FONT_START_CHAR)*FONT_GET_HEIGHT]&7)) +#define HZ14 #endif extern const uint8_t numfont16x22[]; @@ -789,6 +820,7 @@ typedef struct config { float _measure_r; uint8_t _lever_mode; uint8_t _digit_separator; + uint8_t _band_mode; uint32_t checksum; } config_t; diff --git a/numfont20x22.c b/numfont20x22.c index a91d873..ab1a34b 100644 --- a/numfont20x22.c +++ b/numfont20x22.c @@ -551,4 +551,27 @@ const uint8_t numfont16x22[] = { _BMP16(0b1111000000000000), _BMP16(0b1111000000000000), _BMP16(0b1111000000000000), + + _BMP16(0b1111010001011111), // ENTER + _BMP16(0b1000011001000100), + _BMP16(0b1111010101000100), + _BMP16(0b1000010011000100), + _BMP16(0b1111010001000100), + _BMP16(0b0000000000000000), + _BMP16(0b0000000000000000), + _BMP16(0b0000000000001111), + _BMP16(0b0000000000001111), + _BMP16(0b0000000000001111), + _BMP16(0b0000000000001111), + _BMP16(0b0000000000001111), + _BMP16(0b0000000000001111), + _BMP16(0b0000000000001111), + _BMP16(0b0001100000001111), + _BMP16(0b0011100000001111), + _BMP16(0b0111111111111111), + _BMP16(0b1111111111111111), + _BMP16(0b1111111111111111), + _BMP16(0b0111111111111111), + _BMP16(0b0011100000000000), + _BMP16(0b0001100000000000), }; diff --git a/plot.c b/plot.c index 26048f7..56a7dd3 100644 --- a/plot.c +++ b/plot.c @@ -720,10 +720,11 @@ static inline void markmap_upperarea(void) { // Hardcoded, Text info from upper area -#if LCD_WIDTH == 480 || _USE_FONT_== 0 - invalidate_rect(0, 0, AREA_WIDTH_NORMAL, ((MARKERS_MAX+1)/2 + 1)*FONT_STR_HEIGHT); +#if LCD_WIDTH == 320 && _USE_FONT_== 1 + invalidate_rect(0, 0, AREA_WIDTH_NORMAL, (MARKERS_MAX+ 1)*FONT_STR_HEIGHT); #else - invalidate_rect(0, 0, AREA_WIDTH_NORMAL, (MARKERS_MAX+ 1)*FONT_STR_HEIGHT); + invalidate_rect(0, 0, AREA_WIDTH_NORMAL, ((MARKERS_MAX+1)/2 + 1)*FONT_STR_HEIGHT); + #endif } @@ -1584,10 +1585,11 @@ draw_cell(int m, int n) #if 1 int cnt = t_count > m_count ? t_count : m_count; // Get max marker/trace string count add one string for edelay/marker freq -#if LCD_WIDTH == 480 || _USE_FONT_== 0 - if (n <= (((cnt+1)/2 + 1)*FONT_STR_HEIGHT)/CELLHEIGHT) +#if LCD_WIDTH == 320 && _USE_FONT_== 1 + if (n <= ((cnt+ 1)*FONT_STR_HEIGHT)/CELLHEIGHT) #else - if (n <= ((cnt+ 1)*FONT_STR_HEIGHT)/CELLHEIGHT) + if (n <= (((cnt+1)/2 + 1)*FONT_STR_HEIGHT)/CELLHEIGHT) + #endif cell_draw_marker_info(x0, y0); #endif @@ -1711,28 +1713,29 @@ redraw_marker(int8_t marker) } // Marker and trace data position -#if LCD_WIDTH == 480 || _USE_FONT_== 0 +#if LCD_WIDTH == 320 && _USE_FONT_== 1 static const struct {uint16_t x, y;} marker_pos[]={ {1 + CELLOFFSETX, 1 }, - {1 + (WIDTH/2) + CELLOFFSETX, 1 }, {1 + CELLOFFSETX, 1 + FONT_STR_HEIGHT}, - {1 + (WIDTH/2) + CELLOFFSETX, 1 + FONT_STR_HEIGHT}, {1 + CELLOFFSETX, 1 + 2*FONT_STR_HEIGHT}, - {1 + (WIDTH/2) + CELLOFFSETX, 1 + 2*FONT_STR_HEIGHT}, {1 + CELLOFFSETX, 1 + 3*FONT_STR_HEIGHT}, - {1 + (WIDTH/2) + CELLOFFSETX, 1 + 3*FONT_STR_HEIGHT}, + {1 + CELLOFFSETX, 1 + 4*FONT_STR_HEIGHT}, + {1 + CELLOFFSETX, 1 + 5*FONT_STR_HEIGHT}, + {1 + CELLOFFSETX, 1 + 6*FONT_STR_HEIGHT}, + {1 + CELLOFFSETX, 1 + 7*FONT_STR_HEIGHT}, }; #else + static const struct {uint16_t x, y;} marker_pos[]={ {1 + CELLOFFSETX, 1 }, + {1 + (WIDTH/2) + CELLOFFSETX, 1 }, {1 + CELLOFFSETX, 1 + FONT_STR_HEIGHT}, + {1 + (WIDTH/2) + CELLOFFSETX, 1 + FONT_STR_HEIGHT}, {1 + CELLOFFSETX, 1 + 2*FONT_STR_HEIGHT}, + {1 + (WIDTH/2) + CELLOFFSETX, 1 + 2*FONT_STR_HEIGHT}, {1 + CELLOFFSETX, 1 + 3*FONT_STR_HEIGHT}, - {1 + CELLOFFSETX, 1 + 4*FONT_STR_HEIGHT}, - {1 + CELLOFFSETX, 1 + 5*FONT_STR_HEIGHT}, - {1 + CELLOFFSETX, 1 + 6*FONT_STR_HEIGHT}, - {1 + CELLOFFSETX, 1 + 7*FONT_STR_HEIGHT}, + {1 + (WIDTH/2) + CELLOFFSETX, 1 + 3*FONT_STR_HEIGHT}, }; #endif @@ -1807,12 +1810,13 @@ cell_draw_marker_info(int x0, int y0) lcd_set_foreground(LCD_FG_COLOR); // Marker frequency data print -#if LCD_WIDTH == 480 || _USE_FONT_== 0 - xpos = 3 + (WIDTH/2) + CELLOFFSETX - x0; - ypos = 1 + ((j+1)/2)*FONT_STR_HEIGHT - y0; -#else +#if LCD_WIDTH == 320 && _USE_FONT_== 1 xpos = 12+(WIDTH/2) + CELLOFFSETX - x0; ypos = 1 + j*FONT_STR_HEIGHT - y0; +#else + + xpos = 3 + (WIDTH/2) + CELLOFFSETX - x0; + ypos = 1 + ((j+1)/2)*FONT_STR_HEIGHT - y0; #endif if (previous_marker != MARKER_INVALID && current_trace != TRACE_INVALID) { @@ -1848,12 +1852,12 @@ cell_draw_marker_info(int x0, int y0) if (electrical_delay != 0.0f) { // draw electrical delay -#if LCD_WIDTH == 480 || _USE_FONT_== 0 +#if LCD_WIDTH == 320 && _USE_FONT_== 1 + xpos = 1 - x0; + ypos = 1 + (j)*FONT_STR_HEIGHT - y0; +#else xpos = 1 + 18 + CELLOFFSETX - x0; ypos = 1 + ((j+1)/2)*FONT_STR_HEIGHT - y0; -#else - xpos = 1 - x0; - ypos = 1 + (j)*FONT_STR_HEIGHT - y0; #endif if (lever_mode == LM_EDELAY) @@ -1900,6 +1904,9 @@ draw_frequencies(void) #if LCD_WIDTH == 480 || _USE_FONT_== 0 lcd_set_foreground(LCD_BW_TEXT_COLOR); lcd_printf(FREQUENCIES_XPOS3, FREQUENCIES_YPOS,"bw:%uHz %up", get_bandwidth_frequency(config._bandwidth), sweep_points); +#elif LCD_WIDTH == 320 && _USE_FONT_== 3 + lcd_set_foreground(LCD_BW_TEXT_COLOR); + lcd_printf(FREQUENCIES_XPOS3, FREQUENCIES_YPOS,"bw:%uHz", get_bandwidth_frequency(config._bandwidth)); #endif } diff --git a/si5351.c b/si5351.c index e557864..60fd86e 100644 --- a/si5351.c +++ b/si5351.c @@ -157,6 +157,7 @@ si5351_init(void) si5351_bulk_write(p, len); p += len; } + si5351_set_band_mode(config._band_mode); // Set any (let it be XTALFREQ) frequency for AIC can run si5351_set_frequency(XTALFREQ, 0); } @@ -389,68 +390,77 @@ typedef struct { #define SI5351_FIXED_PLL 1 #define SI5351_FIXED_MULT 2 #define SI5351_MIXED 3 - +#define CONST_BAND const +#ifndef CONST_BAND #define CONST_BAND +static band_strategy_t *band_s; +void si5351_update_band_config(int idx, uint32_t pidx, uint32_t v){ + CONST_BAND band_strategy_t *b = &band_s[idx]; + switch(pidx){ + case 0:b->mode = v;break; + case 1:b->freq = v;break; + case 2:b->div = v;break; + case 3:b->mul = v;break; + case 4:b->omul = v;break; + case 5:b->pow = v;break; + case 6:b->opow = v;break; + case 7:b->l_gain = v;break; + case 8:b->r_gain = v;break; + case 9:b->l_gain = b->r_gain = v;break; + case 10:b->freq_align = v;break; + } +} +#else +static const band_strategy_t *band_s; +#endif + /* * Frequency generation divide on band */ -#define THRESHOLD 300000100U -static -#ifdef CONST_BAND -const -#endif -band_strategy_t band_s[] = { +#define THRESHOLD 290000100U +// Mode for H board v3.3 and SI5351 installed +CONST_BAND band_strategy_t band_strategy_33H_SI5351[] = { { 0U, 0, { 0}, 0, 0, -1, -1, -1, -1, 1}, // 0 { 26000U, SI5351_FIXED_PLL, { 8}, 1, 1, SI5351_CLK_DRIVE_STRENGTH_2MA, SI5351_CLK_DRIVE_STRENGTH_2MA, 0, 0, 1}, // 1 { 100000000U, SI5351_FIXED_PLL, {32}, 1, 1, SI5351_CLK_DRIVE_STRENGTH_2MA, SI5351_CLK_DRIVE_STRENGTH_2MA, 0, 0, 1}, // 2 - { 130000000U, SI5351_FIXED_MULT,{ 8}, 1, 1, SI5351_CLK_DRIVE_STRENGTH_8MA, SI5351_CLK_DRIVE_STRENGTH_6MA, 0, 0, 1}, // 3 { 180000000U, SI5351_FIXED_MULT,{ 6}, 1, 1, SI5351_CLK_DRIVE_STRENGTH_8MA, SI5351_CLK_DRIVE_STRENGTH_6MA, 0, 0, 1}, // 4 { 1, SI5351_FIXED_MULT,{ 4}, 1, 1, SI5351_CLK_DRIVE_STRENGTH_8MA, SI5351_CLK_DRIVE_STRENGTH_6MA, 0, 0, 1}, // 5 - { 460000000U, SI5351_FIXED_MULT,{ 6}, 3, 5, SI5351_CLK_DRIVE_STRENGTH_8MA, SI5351_CLK_DRIVE_STRENGTH_6MA, 40, 40, 1}, // 6 { 600000000U, SI5351_FIXED_MULT,{ 4}, 3, 5, SI5351_CLK_DRIVE_STRENGTH_8MA, SI5351_CLK_DRIVE_STRENGTH_6MA, 40, 40, 1}, // 7 { 3, SI5351_FIXED_MULT,{ 4}, 3, 5, SI5351_CLK_DRIVE_STRENGTH_8MA, SI5351_CLK_DRIVE_STRENGTH_6MA, 50, 50, 1}, // 8 - { 1200000000U, SI5351_FIXED_MULT,{ 4}, 5, 7, SI5351_CLK_DRIVE_STRENGTH_8MA, SI5351_CLK_DRIVE_STRENGTH_6MA, 70, 70, 1}, // 9 { 5, SI5351_FIXED_MULT,{ 4}, 5, 7, SI5351_CLK_DRIVE_STRENGTH_8MA, SI5351_CLK_DRIVE_STRENGTH_6MA, 70, 70, 1}, //10 - { 1800000000U, SI5351_FIXED_MULT,{ 4}, 7, 9, SI5351_CLK_DRIVE_STRENGTH_8MA, SI5351_CLK_DRIVE_STRENGTH_8MA, 70, 70, 7*9*4}, //11 { 7, SI5351_FIXED_MULT,{ 4}, 7, 9, SI5351_CLK_DRIVE_STRENGTH_8MA, SI5351_CLK_DRIVE_STRENGTH_8MA, 70, 70, 7*9*4}, //12 - { 2400000000U, SI5351_FIXED_MULT,{ 4}, 9,11, SI5351_CLK_DRIVE_STRENGTH_8MA, SI5351_CLK_DRIVE_STRENGTH_8MA, 85, 85, 9*11*4}, //13 { 9, SI5351_FIXED_MULT,{ 4}, 9,11, SI5351_CLK_DRIVE_STRENGTH_8MA, SI5351_CLK_DRIVE_STRENGTH_8MA, 95, 95, 9*11*4}, //14 { 11, SI5351_FIXED_MULT,{ 4},11,12, SI5351_CLK_DRIVE_STRENGTH_8MA, SI5351_CLK_DRIVE_STRENGTH_8MA, 95, 95, 11*12*4} //15 }; +// Mode for board v3.6 and MS5351 installed +CONST_BAND band_strategy_t band_strategy_36H_MS5351[] = { + { 0U, 0, { 0}, 0, 0, -1, -1, -1, -1, 1}, // 0 + { 24000U, SI5351_FIXED_PLL, {16}, 1, 1, SI5351_CLK_DRIVE_STRENGTH_2MA, SI5351_CLK_DRIVE_STRENGTH_2MA, 0, 0, 1}, // 1 + { 130000000U, SI5351_FIXED_PLL, {32}, 1, 1, SI5351_CLK_DRIVE_STRENGTH_2MA, SI5351_CLK_DRIVE_STRENGTH_2MA, 0, 0, 1}, // 2 + { 1, SI5351_FIXED_MULT,{ 4}, 1, 1, SI5351_CLK_DRIVE_STRENGTH_8MA, SI5351_CLK_DRIVE_STRENGTH_6MA, 0, 0, 1}, // 3 + { 460000000U, SI5351_FIXED_MULT,{ 8}, 3, 3, SI5351_CLK_DRIVE_STRENGTH_8MA, SI5351_CLK_DRIVE_STRENGTH_6MA, 0, 0, 1}, // 4 + { 3, SI5351_FIXED_MULT,{ 4}, 3, 3, SI5351_CLK_DRIVE_STRENGTH_8MA, SI5351_CLK_DRIVE_STRENGTH_6MA, 0, 0, 1}, // 5 + { 5, SI5351_FIXED_MULT,{ 4}, 5, 7, SI5351_CLK_DRIVE_STRENGTH_8MA, SI5351_CLK_DRIVE_STRENGTH_6MA, 20, 25, 1}, // 6 + { 7, SI5351_FIXED_MULT,{ 4}, 7, 9, SI5351_CLK_DRIVE_STRENGTH_8MA, SI5351_CLK_DRIVE_STRENGTH_8MA, 40, 45, 7*9*4}, // 7 + { 9, SI5351_FIXED_MULT,{ 4}, 9,11, SI5351_CLK_DRIVE_STRENGTH_8MA, SI5351_CLK_DRIVE_STRENGTH_8MA, 50, 80, 9*11*4}, // 8 + { 11, SI5351_FIXED_MULT,{ 4},11,12, SI5351_CLK_DRIVE_STRENGTH_8MA, SI5351_CLK_DRIVE_STRENGTH_8MA, 60, 90, 11*12*4} // 9 +}; -void si5351_update_band_config(int idx, uint32_t pidx, uint32_t v){ -#ifdef CONST_BAND - (void)idx; - (void)pidx; - (void)v; -#else - band_strategy_t *b = &band_s[idx]; - switch(pidx){ - case 0:b->mode = v;break; - case 1:b->freq = v;break; - case 2:b->div = v;break; - case 3:b->mul = v;break; - case 4:b->omul = v;break; - case 5:b->pow = v;break; - case 6:b->opow = v;break; - case 7:b->l_gain = v;break; - case 8:b->r_gain = v;break; - case 9:b->l_gain = b->r_gain = v;break; - case 10:b->freq_align = v;break; - } -#endif +void si5351_set_band_mode(uint16_t t) { + band_s = t ? band_strategy_36H_MS5351 : band_strategy_33H_SI5351; } + uint32_t si5351_get_harmonic_lvl(uint32_t freq){ uint16_t i; - for (i = 0; i < ARRAY_COUNT(band_s); i++){ + for (i = 0; ; i++){ uint32_t f = band_s[i].freq; if (f < 20) f*=config._harmonic_freq_threshold; if (freq <= f) return i; diff --git a/si5351.h b/si5351.h index d20d4b9..8758d35 100644 --- a/si5351.h +++ b/si5351.h @@ -79,6 +79,7 @@ void si5351_enable_output(void); void si5351_set_frequency_offset(int32_t offset); int si5351_set_frequency(uint32_t freq, uint8_t drive_strength); void si5351_set_power(uint8_t drive_strength); +void si5351_set_band_mode(uint16_t t); // Defug use functions void si5351_bulk_write(const uint8_t *buf, int len); diff --git a/ui.c b/ui.c index bd8b80d..55b1501 100644 --- a/ui.c +++ b/ui.c @@ -69,6 +69,10 @@ enum { #endif #ifdef __VNA_Z_RENORMALIZATION__ KM_Z_PORT, +#endif +#ifdef __USE_RTC__ + KM_RTC_DATE, + KM_RTC_TIME, #endif KM_NONE }; @@ -429,44 +433,40 @@ touch_wait_pressed(void) #define TOUCH_MARK_X 4 #define TOUCH_MARK_Y 4 static const uint8_t touch_bitmap[]={ -_BMP16(0b0000100000000000), -_BMP16(0b0100100100000000), -_BMP16(0b0010101000000000), -_BMP16(0b0000100000000000), -_BMP16(0b1111011110000000), -_BMP16(0b0000100000000000), -_BMP16(0b0010101000000000), -_BMP16(0b0100100100000000), -_BMP16(0b0000100000000000), + _BMP16(0b0000100000000000), + _BMP16(0b0100100100000000), + _BMP16(0b0010101000000000), + _BMP16(0b0000100000000000), + _BMP16(0b1111011110000000), + _BMP16(0b0000100000000000), + _BMP16(0b0010101000000000), + _BMP16(0b0100100100000000), + _BMP16(0b0000100000000000), }; +static void getTouchPoint(uint16_t x, uint16_t y, const char *name) { + lcd_set_foreground(LCD_FG_COLOR); + lcd_set_background(LCD_BG_COLOR); + lcd_clear_screen(); + + lcd_blitBitmap(x, y, TOUCH_MARK_W, TOUCH_MARK_H, touch_bitmap); + lcd_printf((LCD_WIDTH-18*FONT_WIDTH)/2, (LCD_HEIGHT-FONT_GET_HEIGHT)/2, "TOUCH %s *", name); + touch_wait_release(); +} + void touch_cal_exec(void) { - int x1, x2, y1, y2; - - lcd_set_foreground(LCD_FG_COLOR); - lcd_set_background(LCD_BG_COLOR); - lcd_clear_screen(); - lcd_blitBitmap(CALIBRATION_OFFSET-TOUCH_MARK_X, CALIBRATION_OFFSET-TOUCH_MARK_Y, TOUCH_MARK_W, TOUCH_MARK_H, touch_bitmap); - lcd_printf((LCD_WIDTH-18*FONT_WIDTH)/2, (LCD_HEIGHT-FONT_GET_HEIGHT)/2, "TOUCH UPPER LEFT *"); - - touch_wait_release(); - x1 = last_touch_x; - y1 = last_touch_y; - - lcd_clear_screen(); - lcd_blitBitmap(LCD_WIDTH-1-CALIBRATION_OFFSET-TOUCH_MARK_X, LCD_HEIGHT-1-CALIBRATION_OFFSET-TOUCH_MARK_Y, TOUCH_MARK_W, TOUCH_MARK_H, touch_bitmap); - lcd_printf((LCD_WIDTH-18*FONT_WIDTH)/2, (LCD_HEIGHT-FONT_GET_HEIGHT)/2, "TOUCH LOWER RIGHT *"); - - touch_wait_release(); - x2 = last_touch_x; - y2 = last_touch_y; - - config._touch_cal[0] = x1; - config._touch_cal[1] = y1; - config._touch_cal[2] = x2; - config._touch_cal[3] = y2; + const uint16_t x1 = CALIBRATION_OFFSET - TOUCH_MARK_X; + const uint16_t y1 = CALIBRATION_OFFSET - TOUCH_MARK_Y; + const uint16_t x2 = LCD_WIDTH - 1 - CALIBRATION_OFFSET - TOUCH_MARK_X; + const uint16_t y2 = LCD_HEIGHT - 1 - CALIBRATION_OFFSET - TOUCH_MARK_Y; + getTouchPoint(x1, y1, "UPPER LEFT"); + config._touch_cal[0] = last_touch_x; + config._touch_cal[1] = last_touch_y; + getTouchPoint(x2, y2, "LOWER RIGHT"); + config._touch_cal[2] = last_touch_x; + config._touch_cal[3] = last_touch_y; } void @@ -509,12 +509,13 @@ static void show_version(void) { int x = 5, y = 5, i = 1; - lcd_set_foreground(LCD_FG_COLOR); + lcd_set_foreground(LCD_TRACE_2_COLOR); lcd_set_background(LCD_BG_COLOR); lcd_clear_screen(); uint16_t shift = 0b00010101000; lcd_drawstring_size(BOARD_NAME, x , y, 3); + lcd_set_foreground(LCD_FG_COLOR); y+=FONT_GET_HEIGHT*3+3-5; #if LCD_WIDTH == 480 || _USE_FONT_== 0 while (info_about[i]) { @@ -1427,6 +1428,18 @@ static UI_FUNCTION_CALLBACK(menu_sdcard_cb) } #endif +static UI_FUNCTION_ADV_CALLBACK(menu_band_sel_acb) +{ + (void)data; + if (b){ + b->p1.text = config._band_mode == 0 ? "Si5351" : "MS5351"; + return; + } + config._band_mode = config._band_mode == 0 ? 1 : 0; + si5351_set_band_mode(config._band_mode); +} + + #ifdef __DIGIT_SEPARATOR__ static UI_FUNCTION_ADV_CALLBACK(menu_separator_acb) { @@ -1829,12 +1842,17 @@ const menuitem_t menu_offset[] = { #endif const menuitem_t menu_device[] = { +#if LCD_WIDTH == 480 || _USE_FONT_== 0 { MT_ADV_CALLBACK, KM_THRESHOLD, "THRESHOLD\n%.6q", menu_keyboard_acb }, +#else + { MT_ADV_CALLBACK, KM_THRESHOLD, "THRESHOLD", menu_keyboard_acb }, +#endif { MT_ADV_CALLBACK, KM_XTAL, "TCXO\n%.6q", menu_keyboard_acb }, { MT_ADV_CALLBACK, KM_VBAT, "VBAT OFFSET\n %umV", menu_keyboard_acb }, #ifdef USE_VARIABLE_OFFSET_MENU { MT_ADV_CALLBACK, 0, "IF OFFSET\n %dHz", menu_offset_sel_acb }, #endif + { MT_ADV_CALLBACK, 0, "MODE\n %s", menu_band_sel_acb }, #ifdef __DIGIT_SEPARATOR__ { MT_ADV_CALLBACK, 0, "SEPARATOR\n%s", menu_separator_acb }, #endif @@ -1845,6 +1863,10 @@ const menuitem_t menu_device[] = { { MT_CALLBACK, MENU_CONFIG_LOAD, "LOAD\nCONFIG.INI", menu_config_cb }, #endif { MT_SUBMENU, 0, "CLEAR\nCONFIG", menu_clear }, +#ifdef __USE_RTC__ + { MT_ADV_CALLBACK, KM_RTC_DATE, "SET DATE", (const void *)menu_keyboard_acb }, + { MT_ADV_CALLBACK, KM_RTC_TIME, "SET TIME", (const void *)menu_keyboard_acb }, +#endif { MT_NONE, 0, NULL, menu_back } // next-> menu_back }; @@ -1994,6 +2016,7 @@ menu_invoke(int item) #define KP_KEYPAD 20 #define KP_N 21 #define KP_P 22 +#define KP_ENTER 23 // Stop #define KP_NONE 255 @@ -2029,7 +2052,7 @@ static const keypads_t keypads_scale[] = { { 0, 0, KP_7 }, { 1, 0, KP_8 }, { 2, 0, KP_9 }, - { 3, 3, KP_X1 }, + { 3, 3, KP_ENTER }, { 2, 3, KP_BS }, { 0, 0, KP_NONE } }; @@ -2047,7 +2070,7 @@ static const keypads_t keypads_ref[] = { { 1, 0, KP_8 }, { 2, 0, KP_9 }, { 3, 2, KP_MINUS }, - { 3, 3, KP_X1 }, + { 3, 3, KP_ENTER }, { 2, 3, KP_BS }, { 0, 0, KP_NONE } }; @@ -2092,11 +2115,17 @@ static const keypads_list keypads_mode_tbl[KM_NONE] = { #ifdef __VNA_Z_RENORMALIZATION__ [KM_Z_PORT] = {keypads_scale, "PORT Z 50" S_RARROW }, // Port Z renormalization impedance #endif +#ifdef __USE_RTC__ +[KM_RTC_DATE] = {keypads_scale, "SET DATE\n YYMMDD"}, // Date +[KM_RTC_TIME] = {keypads_scale, "SET TIME\n HHMMSS"}, // Time +#endif }; static void -set_numeric_value(float f_val, freq_t u_val) +set_numeric_value(void) { + float f_val = my_atof(kp_buf); + freq_t u_val = my_atoui(kp_buf); switch (keypad_mode) { case KM_START: set_sweep_frequency(ST_START, u_val); break; case KM_STOP: set_sweep_frequency(ST_STOP, u_val); break; @@ -2117,6 +2146,46 @@ set_numeric_value(float f_val, freq_t u_val) #endif #ifdef __VNA_Z_RENORMALIZATION__ case KM_Z_PORT: current_props._portz = f_val; break; +#endif +#ifdef __USE_RTC__ + case KM_RTC_DATE: + case KM_RTC_TIME: + { + int i = 0; + uint32_t dt_buf[2]; + dt_buf[0] = rtc_get_tr_bcd(); // TR should be read first for sync + dt_buf[1] = rtc_get_dr_bcd(); // DR should be read second + // 0 1 2 4 5 6 + // time[] ={sec, min, hr, 0, day, month, year, 0} + uint8_t *time = (uint8_t*)dt_buf; + for (; i < 6 && kp_buf[i]!=0; i++) kp_buf[i]-= '0'; + for (; i < 6 ; i++) kp_buf[i] = 0; + for (i = 0; i < 3; i++) kp_buf[i] = (kp_buf[2*i]<<4) | kp_buf[2*i+1]; // BCD format + if (keypad_mode == KM_RTC_DATE) { + // Month limit 1 - 12 (in BCD) + if (kp_buf[1] < 1) kp_buf[1] = 1; + else if (kp_buf[1] > 0x12) kp_buf[1] = 0x12; + // Day limit (depend from month): + uint8_t day_max = 28 + ((0b11101100000000000010111110111011001100>>(kp_buf[1]<<1))&3); + day_max = ((day_max/10)<<4)|(day_max%10); // to BCD + if (kp_buf[2] < 1) kp_buf[2] = 1; + else if (kp_buf[2] > day_max) kp_buf[2] = day_max; + time[6] = kp_buf[0]; // year + time[5] = kp_buf[1]; // month + time[4] = kp_buf[2]; // day + } + else { + // Hour limit 0 - 23, min limit 0 - 59, sec limit 0 - 59 (in BCD) + if (kp_buf[0] > 0x23) kp_buf[0] = 0x23; + if (kp_buf[1] > 0x59) kp_buf[1] = 0x59; + if (kp_buf[2] > 0x59) kp_buf[2] = 0x59; + time[2] = kp_buf[0]; // hour + time[1] = kp_buf[1]; // min + time[0] = kp_buf[2]; // sec + } + rtc_set_time(dt_buf[1], dt_buf[0]); + } + break; #endif } } @@ -2202,7 +2271,13 @@ draw_numeric_input(const char *buf) bool focused = FALSE; uint16_t x = 14 + 10 * FONT_WIDTH; uint16_t y = LCD_HEIGHT-(NUM_FONT_GET_HEIGHT+NUM_INPUT_HEIGHT)/2; - uint16_t xsim = (0b00100100100100100 >>(2-(period_pos()%3)))&(~1); + uint16_t xsim; +#ifdef __USE_RTC__ + if ((1<>(2-(period_pos()%3)))&(~1); int c; while(*buf) { c = *buf++; @@ -2629,6 +2704,7 @@ static int keypad_click(int key) { int c = keypads[key].c; + if (c == KP_ENTER) c = KP_X1; if ((c >= KP_X1 && c <= KP_G) || c == KP_N || c == KP_P) { if (kp_index == 0) return KP_CANCEL; @@ -2646,7 +2722,7 @@ keypad_click(int key) } } // numeric input done - set_numeric_value(my_atof(kp_buf), my_atoui(kp_buf)); + set_numeric_value(); return KP_DONE; }