diff --git a/.cproject b/.cproject new file mode 100644 index 0000000..1e880c3 --- /dev/null +++ b/.cproject @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.gitignore b/.gitignore index d2fc5aa..675f5d5 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,7 @@ python TAGS .emacs-dirvars *png +*.bak +version.txt +dorelease.bat +ChibiOS diff --git a/.project b/.project new file mode 100644 index 0000000..f5b7df6 --- /dev/null +++ b/.project @@ -0,0 +1,27 @@ + + + nanoVNA-Erik + + + + + + org.eclipse.cdt.managedbuilder.core.genmakebuilder + clean,full,incremental, + + + + + org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder + full,incremental, + + + + + + org.eclipse.cdt.core.cnature + org.eclipse.cdt.managedbuilder.core.managedBuildNature + org.eclipse.cdt.managedbuilder.core.ScannerConfigNature + org.eclipse.cdt.core.ccnature + + diff --git a/.settings/language.settings.xml b/.settings/language.settings.xml new file mode 100644 index 0000000..47218fa --- /dev/null +++ b/.settings/language.settings.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/Font7x13b.c b/Font7x13b.c new file mode 100644 index 0000000..b3656b2 --- /dev/null +++ b/Font7x13b.c @@ -0,0 +1,3959 @@ +/* Generated by convbdf on Mon Apr 29 14:40:18 2019. */ + +/* Font information: + name: 7x13B + facename: -Misc-Fixed-Bold-R-Normal--13-120-75-75-C-70-ISO8859-2 + w x h: 7x13 + size: 127 + ascent: 11 + descent: 2 + first char: 0 (0x00) + last char: 126 (0x7e) + default char: 0 (0x00) + proportional: no + Public domain font. Share and enjoy. Copyright (c) 1996 BIZNET Poland, Inc. All Rights Reserved. +*/ + +#include + +/* Font character bitmap data. */ +const uint16_t x7x13b_bits [] = +{ + + /* Character 0 (0x00): + width 7 + +-------+ + | | + | ***** | + | ***** | + | ***** | + | ***** | + | ***** | + | ***** | + | ***** | + | ***** | + | ***** | + | ***** | + | ***** | + | | + +-------+ */ + 0x0000, + 0x7c00, + 0x7c00, + 0x7c00, + 0x7c00, + 0x7c00, + 0x7c00, + 0x7c00, + 0x7c00, + 0x7c00, + 0x7c00, + 0x7c00, + 0x0000, + + /* Character 1 (0x01): + width 7 + +-------+ + | | + | | + | | + | | + | | + | ** | + | **** | + |****** | + | **** | + | ** | + | | + | | + | | + +-------+ */ + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x3000, + 0x7800, + 0xfc00, + 0x7800, + 0x3000, + 0x0000, + 0x0000, + 0x0000, + + /* Character 2 (0x02): + width 7 + +-------+ + | | + |** ** | + | ** | + |** ** | + | ** | + |** ** | + | ** | + |** ** | + | ** | + |** ** | + | ** | + |** ** | + | | + +-------+ */ + 0x0000, + 0xcc00, + 0x3000, + 0xcc00, + 0x3000, + 0xcc00, + 0x3000, + 0xcc00, + 0x3000, + 0xcc00, + 0x3000, + 0xcc00, + 0x0000, + + /* Character 3 (0x03): + width 7 + +-------+ + | | + |** ** | + |** ** | + |***** | + |** ** | + |** ** | + | | + | **** | + | ** | + | ** | + | ** | + | ** | + | | + +-------+ */ + 0x0000, + 0xd800, + 0xd800, + 0xf800, + 0xd800, + 0xd800, + 0x0000, + 0x3c00, + 0x1800, + 0x1800, + 0x1800, + 0x1800, + 0x0000, + + /* Character 4 (0x04): + width 7 + +-------+ + | | + |**** | + |** | + |*** | + |** | + |** | + | | + | **** | + | ** | + | *** | + | ** | + | ** | + | | + +-------+ */ + 0x0000, + 0xf000, + 0xc000, + 0xe000, + 0xc000, + 0xc000, + 0x0000, + 0x3c00, + 0x3000, + 0x3800, + 0x3000, + 0x3000, + 0x0000, + + /* Character 5 (0x05): + width 7 + +-------+ + | | + | *** | + |** | + |** | + |** | + | *** | + | | + | *** | + | ** * | + | *** | + | ** * | + | ** * | + | | + +-------+ */ + 0x0000, + 0x7000, + 0xc000, + 0xc000, + 0xc000, + 0x7000, + 0x0000, + 0x3800, + 0x3400, + 0x3800, + 0x3400, + 0x3400, + 0x0000, + + /* Character 6 (0x06): + width 7 + +-------+ + | | + |** | + |** | + |** | + |** | + |**** | + | | + | **** | + | ** | + | *** | + | ** | + | ** | + | | + +-------+ */ + 0x0000, + 0xc000, + 0xc000, + 0xc000, + 0xc000, + 0xf000, + 0x0000, + 0x3c00, + 0x3000, + 0x3800, + 0x3000, + 0x3000, + 0x0000, + + /* Character 7 (0x07): + width 7 + +-------+ + | | + | | + | **** | + |** ** | + |** ** | + | **** | + | | + | | + | | + | | + | | + | | + | | + +-------+ */ + 0x0000, + 0x0000, + 0x7800, + 0xcc00, + 0xcc00, + 0x7800, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + + /* Character 8 (0x08): + width 7 + +-------+ + | | + | | + | ** | + | ** | + |****** | + |****** | + | ** | + | ** | + | | + |****** | + |****** | + | | + | | + +-------+ */ + 0x0000, + 0x0000, + 0x3000, + 0x3000, + 0xfc00, + 0xfc00, + 0x3000, + 0x3000, + 0x0000, + 0xfc00, + 0xfc00, + 0x0000, + 0x0000, + + /* Character 9 (0x09): + width 7 + +-------+ + | | + |** ** | + |*** ** | + |****** | + |** *** | + |** ** | + | | + | ** | + | ** | + | ** | + | ** | + | **** | + | | + +-------+ */ + 0x0000, + 0xcc00, + 0xec00, + 0xfc00, + 0xdc00, + 0xcc00, + 0x0000, + 0x3000, + 0x3000, + 0x3000, + 0x3000, + 0x3c00, + 0x0000, + + /* Character 10 (0x0a): + width 7 + +-------+ + | | + |** ** | + |** ** | + | * * | + | **** | + | ** | + | | + | **** | + | ** | + | ** | + | ** | + | ** | + | | + +-------+ */ + 0x0000, + 0xcc00, + 0xcc00, + 0x4800, + 0x7800, + 0x3000, + 0x0000, + 0x3c00, + 0x1800, + 0x1800, + 0x1800, + 0x1800, + 0x0000, + + /* Character 11 (0x0b): + width 7 + +-------+ + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + |**** | + |**** | + | | + | | + | | + | | + | | + +-------+ */ + 0x3000, + 0x3000, + 0x3000, + 0x3000, + 0x3000, + 0x3000, + 0xf000, + 0xf000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + + /* Character 12 (0x0c): + width 7 + +-------+ + | | + | | + | | + | | + | | + | | + |**** | + |**** | + | ** | + | ** | + | ** | + | ** | + | ** | + +-------+ */ + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0xf000, + 0xf000, + 0x3000, + 0x3000, + 0x3000, + 0x3000, + 0x3000, + + /* Character 13 (0x0d): + width 7 + +-------+ + | | + | | + | | + | | + | | + | | + | *****| + | *****| + | ** | + | ** | + | ** | + | ** | + | ** | + +-------+ */ + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x3e00, + 0x3e00, + 0x3000, + 0x3000, + 0x3000, + 0x3000, + 0x3000, + + /* Character 14 (0x0e): + width 7 + +-------+ + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | *****| + | *****| + | | + | | + | | + | | + | | + +-------+ */ + 0x3000, + 0x3000, + 0x3000, + 0x3000, + 0x3000, + 0x3000, + 0x3e00, + 0x3e00, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + + /* Character 15 (0x0f): + width 7 + +-------+ + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + |*******| + |*******| + | ** | + | ** | + | ** | + | ** | + | ** | + +-------+ */ + 0x3000, + 0x3000, + 0x3000, + 0x3000, + 0x3000, + 0x3000, + 0xfe00, + 0xfe00, + 0x3000, + 0x3000, + 0x3000, + 0x3000, + 0x3000, + + /* Character 16 (0x10): + width 7 + +-------+ + | | + | | + |*******| + |*******| + | | + | | + | | + | | + | | + | | + | | + | | + | | + +-------+ */ + 0x0000, + 0x0000, + 0xfe00, + 0xfe00, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + + /* Character 17 (0x11): + width 7 + +-------+ + | | + | | + | | + | | + |*******| + |*******| + | | + | | + | | + | | + | | + | | + | | + +-------+ */ + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0xfe00, + 0xfe00, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + + /* Character 18 (0x12): + width 7 + +-------+ + | | + | | + | | + | | + | | + | | + |*******| + |*******| + | | + | | + | | + | | + | | + +-------+ */ + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0xfe00, + 0xfe00, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + + /* Character 19 (0x13): + width 7 + +-------+ + | | + | | + | | + | | + | | + | | + | | + | | + |*******| + |*******| + | | + | | + | | + +-------+ */ + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0xfe00, + 0xfe00, + 0x0000, + 0x0000, + 0x0000, + + /* Character 20 (0x14): + width 7 + +-------+ + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + |*******| + |*******| + | | + +-------+ */ + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0xfe00, + 0xfe00, + 0x0000, + + /* Character 21 (0x15): + width 7 + +-------+ + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | *****| + | *****| + | ** | + | ** | + | ** | + | ** | + | ** | + +-------+ */ + 0x3000, + 0x3000, + 0x3000, + 0x3000, + 0x3000, + 0x3000, + 0x3e00, + 0x3e00, + 0x3000, + 0x3000, + 0x3000, + 0x3000, + 0x3000, + + /* Character 22 (0x16): + width 7 + +-------+ + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + |**** | + |**** | + | ** | + | ** | + | ** | + | ** | + | ** | + +-------+ */ + 0x3000, + 0x3000, + 0x3000, + 0x3000, + 0x3000, + 0x3000, + 0xf000, + 0xf000, + 0x3000, + 0x3000, + 0x3000, + 0x3000, + 0x3000, + + /* Character 23 (0x17): + width 7 + +-------+ + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + |*******| + |*******| + | | + | | + | | + | | + | | + +-------+ */ + 0x3000, + 0x3000, + 0x3000, + 0x3000, + 0x3000, + 0x3000, + 0xfe00, + 0xfe00, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + + /* Character 24 (0x18): + width 7 + +-------+ + | | + | | + | | + | | + | | + | | + |*******| + |*******| + | ** | + | ** | + | ** | + | ** | + | ** | + +-------+ */ + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0xfe00, + 0xfe00, + 0x3000, + 0x3000, + 0x3000, + 0x3000, + 0x3000, + + /* Character 25 (0x19): + width 7 + +-------+ + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + +-------+ */ + 0x3000, + 0x3000, + 0x3000, + 0x3000, + 0x3000, + 0x3000, + 0x3000, + 0x3000, + 0x3000, + 0x3000, + 0x3000, + 0x3000, + 0x3000, + + /* Character 26 (0x1a): + width 7 + +-------+ + | | + | | + | | + | * | + | ** | + |****** | + |****** | + | ** | + | * | + | | + | | + | | + | | + +-------+ */ +0x0000, +0x0000, +0x0000, +0x2000, +0x6000, +0xfc00, +0xfc00, +0x6000, +0x2000, +0x0000, +0x0000, +0x0000, +0x0000, + /* Character 27 (0x1b): + width 7 + +-------+ + | | + | | + | | + | * | + | ** | + |****** | + |****** | + | ** | + | * | + | | + | | + | | + | | + +-------+ */ +0x0000, +0x0000, +0x0000, +0x1000, +0x1800, +0xfc00, +0xfc00, +0x1800, +0x1000, +0x0000, +0x0000, +0x0000, +0x0000, + + + /* Character 28 (0x1c): + width 7 + +-------+ + | | + | | + | | + | | + | | + |****** | + | ** ** | + | ** ** | + | ** ** | + |*** ** | + |** ** | + | | + | | + +-------+ */ + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0xfc00, + 0x6c00, + 0x6c00, + 0x6c00, + 0xec00, + 0xcc00, + 0x0000, + 0x0000, + + /* Character 29 (0x1d): + width 7 + +-------+ + | | + | | + | | + | | + | | + |** ** | + |** ** | + |** ** | + |** ** | + |** ** | + |****** | + |** | + |** | + +-------+ */ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0xcc00, +0xcc00, +0xcc00, +0xcc00, +0xcc00, +0xfc00, +0xc000, +0xc000, + /* Character 30 (0x1e): + width 7 + +-------+ + | | + | | + | **** | + |** ** | + |** ** | + |** ** | + |** ** | + |** ** | + | * * | + | * * | + |** ** | + | | + | | + +-------+ */ +0x0000, +0x0000, +0x7800, +0xcc00, +0xcc00, +0xcc00, +0xcc00, +0xcc00, +0x4800, +0x4800, +0xcc00, +0x0000, +0x0000, + + /* Character 31 (0x1f): + width 7 + +-------+ + | | + | | + | **** | + |** ** | + |** ** | + | **** | + | | + | | + | | + | | + | | + | | + | | + +-------+ */ +0x0000, +0x0000, +0x7800, +0xcc00, +0xcc00, +0x7800, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + + /* Character 32 (0x20): + width 7 + +-------+ + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + +-------+ */ + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + + /* Character 33 (0x21): + width 7 + +-------+ + | | + | | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | | + | ** | + | ** | + | | + | | + +-------+ */ + 0x0000, + 0x0000, + 0x3000, + 0x3000, + 0x3000, + 0x3000, + 0x3000, + 0x3000, + 0x0000, + 0x3000, + 0x3000, + 0x0000, + 0x0000, + + /* Character 34 (0x22): + width 7 + +-------+ + | | + | | + | ** ** | + | ** ** | + | ** ** | + | | + | | + | | + | | + | | + | | + | | + | | + +-------+ */ + 0x0000, + 0x0000, + 0x6c00, + 0x6c00, + 0x6c00, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + + /* Character 35 (0x23): + width 7 + +-------+ + | | + | | + | * * | + | * * | + | ***** | + | ***** | + | * * | + | ***** | + | ***** | + | * * | + | * * | + | | + | | + +-------+ */ + 0x0000, + 0x0000, + 0x2800, + 0x2800, + 0x7c00, + 0x7c00, + 0x2800, + 0x7c00, + 0x7c00, + 0x2800, + 0x2800, + 0x0000, + 0x0000, + + /* Character 36 (0x24): + width 7 + +-------+ + | | + | | + | ** | + | **** | + |* ** * | + |* ** | + | **** | + | ** * | + |* ** * | + | **** | + | ** | + | | + | | + +-------+ */ + 0x0000, + 0x0000, + 0x3000, + 0x7800, + 0xb400, + 0xb000, + 0x7800, + 0x3400, + 0xb400, + 0x7800, + 0x3000, + 0x0000, + 0x0000, + + /* Character 37 (0x25): + width 7 + +-------+ + | | + | | + |*** * | + |* * ** | + |*** * | + | ** | + | ** | + | ** | + | * *** | + |** * * | + |* *** | + | | + | | + +-------+ */ + 0x0000, + 0x0000, + 0xe400, + 0xac00, + 0xe800, + 0x1800, + 0x3000, + 0x6000, + 0x5c00, + 0xd400, + 0x9c00, + 0x0000, + 0x0000, + + /* Character 38 (0x26): + width 7 + +-------+ + | | + | | + | *** | + |** ** | + |** ** | + |** ** | + | *** | + |** * * | + |** *** | + |** ** | + | *** * | + | | + | | + +-------+ */ + 0x0000, + 0x0000, + 0x7000, + 0xd800, + 0xd800, + 0xd800, + 0x7000, + 0xd400, + 0xdc00, + 0xd800, + 0x7400, + 0x0000, + 0x0000, + + /* Character 39 (0x27): + width 7 + +-------+ + | | + | | + | *** | + | *** | + | ** | + | ** | + | | + | | + | | + | | + | | + | | + | | + +-------+ */ + 0x0000, + 0x0000, + 0x3800, + 0x3800, + 0x3000, + 0x6000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + + /* Character 40 (0x28): + width 7 + +-------+ + | | + | | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | | + | | + +-------+ */ + 0x0000, + 0x0000, + 0x1800, + 0x3000, + 0x3000, + 0x6000, + 0x6000, + 0x6000, + 0x3000, + 0x3000, + 0x1800, + 0x0000, + 0x0000, + + /* Character 41 (0x29): + width 7 + +-------+ + | | + | | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | | + | | + +-------+ */ + 0x0000, + 0x0000, + 0x6000, + 0x3000, + 0x3000, + 0x1800, + 0x1800, + 0x1800, + 0x3000, + 0x3000, + 0x6000, + 0x0000, + 0x0000, + + /* Character 42 (0x2a): + width 7 + +-------+ + | | + | | + | | + | | + | * * | + | ** | + |****** | + |****** | + | ** | + | * * | + | | + | | + | | + +-------+ */ + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x4800, + 0x3000, + 0xfc00, + 0xfc00, + 0x3000, + 0x4800, + 0x0000, + 0x0000, + 0x0000, + + /* Character 43 (0x2b): + width 7 + +-------+ + | | + | | + | | + | | + | ** | + | ** | + |****** | + |****** | + | ** | + | ** | + | | + | | + | | + +-------+ */ + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x3000, + 0x3000, + 0xfc00, + 0xfc00, + 0x3000, + 0x3000, + 0x0000, + 0x0000, + 0x0000, + + /* Character 44 (0x2c): + width 7 + +-------+ + | | + | | + | | + | | + | | + | | + | | + | | + | *** | + | *** | + | ** | + | ** | + | | + +-------+ */ + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x3800, + 0x3800, + 0x3000, + 0x6000, + 0x0000, + + /* Character 45 (0x2d): + width 7 + +-------+ + | | + | | + | | + | | + | | + | | + |****** | + |****** | + | | + | | + | | + | | + | | + +-------+ */ + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0xfc00, + 0xfc00, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + + /* Character 46 (0x2e): + width 7 + +-------+ + | | + | | + | | + | | + | | + | | + | | + | | + | | + | ** | + | **** | + | ** | + | | + +-------+ */ + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x3000, + 0x7800, + 0x3000, + 0x0000, + + /* Character 47 (0x2f): + width 7 + +-------+ + | | + | | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + |** | + |** | + | | + | | + +-------+ */ + 0x0000, + 0x0000, + 0x0c00, + 0x0c00, + 0x1800, + 0x1800, + 0x3000, + 0x6000, + 0x6000, + 0xc000, + 0xc000, + 0x0000, + 0x0000, + /* Character 48 (0x30): + width 7 + +-------+ + | | + | | + | ** | + | * * | + |** ** | + |** ** | + |** ** | + |** ** | + |** ** | + | * * | + | ** | + | | + | | + +-------+ */ + 0x0000, + 0x0000, + 0x3000, + 0x4800, + 0xcc00, + 0xcc00, + 0xcc00, + 0xcc00, + 0xcc00, + 0x4800, + 0x3000, + 0x0000, + 0x0000, + + /* Character 49 (0x31): + width 7 + +-------+ + | | + | | + | ** | + | *** | + |* ** | + | ** | + | ** | + | ** | + | ** | + | ** | + |****** | + | | + | | + +-------+ */ + 0x0000, + 0x0000, + 0x3000, + 0x7000, + 0xb000, + 0x3000, + 0x3000, + 0x3000, + 0x3000, + 0x3000, + 0xfc00, + 0x0000, + 0x0000, + + /* Character 50 (0x32): + width 7 + +-------+ + | | + | | + | **** | + |** ** | + |** ** | + | ** | + | *** | + | ** | + |** | + |** | + |****** | + | | + | | + +-------+ */ + 0x0000, + 0x0000, + 0x7800, + 0xcc00, + 0xcc00, + 0x0c00, + 0x3800, + 0x6000, + 0xc000, + 0xc000, + 0xfc00, + 0x0000, + 0x0000, + + /* Character 51 (0x33): + width 7 + +-------+ + | | + | | + |****** | + | ** | + | ** | + | ** | + | **** | + | ** | + | ** | + |** ** | + | **** | + | | + | | + +-------+ */ + 0x0000, + 0x0000, + 0xfc00, + 0x0c00, + 0x1800, + 0x3000, + 0x7800, + 0x0c00, + 0x0c00, + 0xcc00, + 0x7800, + 0x0000, + 0x0000, + + /* Character 52 (0x34): + width 7 + +-------+ + | | + | | + | ** | + | *** | + | **** | + | ** ** | + |** ** | + |** ** | + |****** | + | ** | + | ** | + | | + | | + +-------+ */ + 0x0000, + 0x0000, + 0x0c00, + 0x1c00, + 0x3c00, + 0x6c00, + 0xcc00, + 0xcc00, + 0xfc00, + 0x0c00, + 0x0c00, + 0x0000, + 0x0000, + + /* Character 53 (0x35): + width 7 + +-------+ + | | + | | + |****** | + |** | + |** | + |***** | + |** ** | + | ** | + | ** | + |** ** | + | **** | + | | + | | + +-------+ */ + 0x0000, + 0x0000, + 0xfc00, + 0xc000, + 0xc000, + 0xf800, + 0xcc00, + 0x0c00, + 0x0c00, + 0xcc00, + 0x7800, + 0x0000, + 0x0000, + + /* Character 54 (0x36): + width 7 + +-------+ + | | + | | + | **** | + |** ** | + |** | + |** | + |***** | + |** ** | + |** ** | + |** ** | + | **** | + | | + | | + +-------+ */ + 0x0000, + 0x0000, + 0x7800, + 0xcc00, + 0xc000, + 0xc000, + 0xf800, + 0xcc00, + 0xcc00, + 0xcc00, + 0x7800, + 0x0000, + 0x0000, + + /* Character 55 (0x37): + width 7 + +-------+ + | | + | | + |****** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | | + | | + +-------+ */ + 0x0000, + 0x0000, + 0xfc00, + 0x0c00, + 0x0c00, + 0x1800, + 0x1800, + 0x3000, + 0x3000, + 0x6000, + 0x6000, + 0x0000, + 0x0000, + + /* Character 56 (0x38): + width 7 + +-------+ + | | + | | + | **** | + |** ** | + |** ** | + |** ** | + | **** | + |** ** | + |** ** | + |** ** | + | **** | + | | + | | + +-------+ */ + 0x0000, + 0x0000, + 0x7800, + 0xcc00, + 0xcc00, + 0xcc00, + 0x7800, + 0xcc00, + 0xcc00, + 0xcc00, + 0x7800, + 0x0000, + 0x0000, + + /* Character 57 (0x39): + width 7 + +-------+ + | | + | | + | **** | + |** ** | + |** ** | + |** ** | + | ***** | + | ** | + | ** | + |** ** | + | **** | + | | + | | + +-------+ */ + 0x0000, + 0x0000, + 0x7800, + 0xcc00, + 0xcc00, + 0xcc00, + 0x7c00, + 0x0c00, + 0x0c00, + 0xcc00, + 0x7800, + 0x0000, + 0x0000, + + /* Character 58 (0x3a): + width 7 + +-------+ + | | + | | + | | + | | + | ** | + | **** | + | ** | + | | + | | + | ** | + | **** | + | ** | + | | + +-------+ */ + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x3000, + 0x7800, + 0x3000, + 0x0000, + 0x0000, + 0x3000, + 0x7800, + 0x3000, + 0x0000, + + /* Character 59 (0x3b): + width 7 + +-------+ + | | + | | + | | + | | + | ** | + | **** | + | ** | + | | + | *** | + | *** | + | ** | + | ** | + | | + +-------+ */ + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x3000, + 0x7800, + 0x3000, + 0x0000, + 0x3800, + 0x3800, + 0x3000, + 0x6000, + 0x0000, + + /* Character 60 (0x3c): + width 7 + +-------+ + | | + | | + | ** | + | ** | + | ** | + | ** | + |** | + | ** | + | ** | + | ** | + | ** | + | | + | | + +-------+ */ + 0x0000, + 0x0000, + 0x0c00, + 0x1800, + 0x3000, + 0x6000, + 0xc000, + 0x6000, + 0x3000, + 0x1800, + 0x0c00, + 0x0000, + 0x0000, + + /* Character 61 (0x3d): + width 7 + +-------+ + | | + | | + | | + | | + | | + |****** | + | | + | | + |****** | + | | + | | + | | + | | + +-------+ */ + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0xfc00, + 0x0000, + 0x0000, + 0xfc00, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + + /* Character 62 (0x3e): + width 7 + +-------+ + | | + | | + |** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + |** | + | | + | | + +-------+ */ + 0x0000, + 0x0000, + 0xc000, + 0x6000, + 0x3000, + 0x1800, + 0x0c00, + 0x1800, + 0x3000, + 0x6000, + 0xc000, + 0x0000, + 0x0000, + + /* Character 63 (0x3f): + width 7 + +-------+ + | | + | | + | **** | + |** ** | + |** ** | + | ** | + | *** | + | ** | + | | + | ** | + | ** | + | | + | | + +-------+ */ + 0x0000, + 0x0000, + 0x7800, + 0xcc00, + 0xcc00, + 0x0c00, + 0x3800, + 0x3000, + 0x0000, + 0x3000, + 0x3000, + 0x0000, + 0x0000, + + /* Character 64 (0x40): + width 7 + +-------+ + | | + | | + | **** | + |* ** | + |* ** | + |* **** | + |* * ** | + |* **** | + |* | + |* ** | + | **** | + | | + | | + +-------+ */ + 0x0000, + 0x0000, + 0x7800, + 0x8c00, + 0x8c00, + 0xbc00, + 0xac00, + 0xbc00, + 0x8000, + 0x8c00, + 0x7800, + 0x0000, + 0x0000, + + /* Character 65 (0x41): + width 7 + +-------+ + | | + | | + | **** | + |** ** | + |** ** | + |** ** | + |****** | + |** ** | + |** ** | + |** ** | + |** ** | + | | + | | + +-------+ */ + 0x0000, + 0x0000, + 0x7800, + 0xcc00, + 0xcc00, + 0xcc00, + 0xfc00, + 0xcc00, + 0xcc00, + 0xcc00, + 0xcc00, + 0x0000, + 0x0000, + + /* Character 66 (0x42): + width 7 + +-------+ + | | + | | + |***** | + |** ** | + |** ** | + |** ** | + |***** | + |** ** | + |** ** | + |** ** | + |***** | + | | + | | + +-------+ */ + 0x0000, + 0x0000, + 0xf800, + 0xcc00, + 0xcc00, + 0xcc00, + 0xf800, + 0xcc00, + 0xcc00, + 0xcc00, + 0xf800, + 0x0000, + 0x0000, + + /* Character 67 (0x43): + width 7 + +-------+ + | | + | | + | **** | + |** ** | + |** | + |** | + |** | + |** | + |** | + |** ** | + | **** | + | | + | | + +-------+ */ + 0x0000, + 0x0000, + 0x7800, + 0xcc00, + 0xc000, + 0xc000, + 0xc000, + 0xc000, + 0xc000, + 0xcc00, + 0x7800, + 0x0000, + 0x0000, + + /* Character 68 (0x44): + width 7 + +-------+ + | | + | | + |***** | + |** ** | + |** ** | + |** ** | + |** ** | + |** ** | + |** ** | + |** ** | + |***** | + | | + | | + +-------+ */ + 0x0000, + 0x0000, + 0xf800, + 0xcc00, + 0xcc00, + 0xcc00, + 0xcc00, + 0xcc00, + 0xcc00, + 0xcc00, + 0xf800, + 0x0000, + 0x0000, + + /* Character 69 (0x45): + width 7 + +-------+ + | | + | | + |****** | + |** | + |** | + |** | + |***** | + |** | + |** | + |** | + |****** | + | | + | | + +-------+ */ + 0x0000, + 0x0000, + 0xfc00, + 0xc000, + 0xc000, + 0xc000, + 0xf800, + 0xc000, + 0xc000, + 0xc000, + 0xfc00, + 0x0000, + 0x0000, + + /* Character 70 (0x46): + width 7 + +-------+ + | | + | | + |****** | + |** | + |** | + |** | + |***** | + |** | + |** | + |** | + |** | + | | + | | + +-------+ */ + 0x0000, + 0x0000, + 0xfc00, + 0xc000, + 0xc000, + 0xc000, + 0xf800, + 0xc000, + 0xc000, + 0xc000, + 0xc000, + 0x0000, + 0x0000, + + /* Character 71 (0x47): + width 7 + +-------+ + | | + | | + | **** | + |** ** | + |** | + |** | + |** *** | + |** ** | + |** ** | + |** ** | + | ***** | + | | + | | + +-------+ */ + 0x0000, + 0x0000, + 0x7800, + 0xcc00, + 0xc000, + 0xc000, + 0xdc00, + 0xcc00, + 0xcc00, + 0xcc00, + 0x7c00, + 0x0000, + 0x0000, + + /* Character 72 (0x48): + width 7 + +-------+ + | | + | | + |** ** | + |** ** | + |** ** | + |** ** | + |****** | + |** ** | + |** ** | + |** ** | + |** ** | + | | + | | + +-------+ */ + 0x0000, + 0x0000, + 0xcc00, + 0xcc00, + 0xcc00, + 0xcc00, + 0xfc00, + 0xcc00, + 0xcc00, + 0xcc00, + 0xcc00, + 0x0000, + 0x0000, + + /* Character 73 (0x49): + width 7 + +-------+ + | | + | | + |****** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + |****** | + | | + | | + +-------+ */ + 0x0000, + 0x0000, + 0xfc00, + 0x3000, + 0x3000, + 0x3000, + 0x3000, + 0x3000, + 0x3000, + 0x3000, + 0xfc00, + 0x0000, + 0x0000, + + /* Character 74 (0x4a): + width 7 + +-------+ + | | + | | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + |** ** | + | **** | + | | + | | + +-------+ */ + 0x0000, + 0x0000, + 0x0c00, + 0x0c00, + 0x0c00, + 0x0c00, + 0x0c00, + 0x0c00, + 0x0c00, + 0xcc00, + 0x7800, + 0x0000, + 0x0000, + + /* Character 75 (0x4b): + width 7 + +-------+ + | | + | | + |** * | + |** ** | + |** ** | + |**** | + |*** | + |**** | + |** ** | + |** ** | + |** * | + | | + | | + +-------+ */ + 0x0000, + 0x0000, + 0xc400, + 0xcc00, + 0xd800, + 0xf000, + 0xe000, + 0xf000, + 0xd800, + 0xcc00, + 0xc400, + 0x0000, + 0x0000, + + /* Character 76 (0x4c): + width 7 + +-------+ + | | + | | + |** | + |** | + |** | + |** | + |** | + |** | + |** | + |** | + |****** | + | | + | | + +-------+ */ + 0x0000, + 0x0000, + 0xc000, + 0xc000, + 0xc000, + 0xc000, + 0xc000, + 0xc000, + 0xc000, + 0xc000, + 0xfc00, + 0x0000, + 0x0000, + + /* Character 77 (0x4d): + width 7 + +-------+ + | | + | | + |* * | + |** ** | + |****** | + |****** | + |** ** | + |** ** | + |** ** | + |** ** | + |** ** | + | | + | | + +-------+ */ + 0x0000, + 0x0000, + 0x8400, + 0xcc00, + 0xfc00, + 0xfc00, + 0xcc00, + 0xcc00, + 0xcc00, + 0xcc00, + 0xcc00, + 0x0000, + 0x0000, + + /* Character 78 (0x4e): + width 7 + +-------+ + | | + | | + |** ** | + |** ** | + |*** ** | + |*** ** | + |****** | + |** *** | + |** *** | + |** ** | + |** ** | + | | + | | + +-------+ */ + 0x0000, + 0x0000, + 0xcc00, + 0xcc00, + 0xec00, + 0xec00, + 0xfc00, + 0xdc00, + 0xdc00, + 0xcc00, + 0xcc00, + 0x0000, + 0x0000, + + /* Character 79 (0x4f): + width 7 + +-------+ + | | + | | + | **** | + |** ** | + |** ** | + |** ** | + |** ** | + |** ** | + |** ** | + |** ** | + | **** | + | | + | | + +-------+ */ + 0x0000, + 0x0000, + 0x7800, + 0xcc00, + 0xcc00, + 0xcc00, + 0xcc00, + 0xcc00, + 0xcc00, + 0xcc00, + 0x7800, + 0x0000, + 0x0000, + + /* Character 80 (0x50): + width 7 + +-------+ + | | + | | + |***** | + |** ** | + |** ** | + |** ** | + |***** | + |** | + |** | + |** | + |** | + | | + | | + +-------+ */ + 0x0000, + 0x0000, + 0xf800, + 0xcc00, + 0xcc00, + 0xcc00, + 0xf800, + 0xc000, + 0xc000, + 0xc000, + 0xc000, + 0x0000, + 0x0000, + + /* Character 81 (0x51): + width 7 + +-------+ + | | + | | + | **** | + |** ** | + |** ** | + |** ** | + |** ** | + |** ** | + |*** ** | + |** *** | + | **** | + | ** | + | | + +-------+ */ + 0x0000, + 0x0000, + 0x7800, + 0xcc00, + 0xcc00, + 0xcc00, + 0xcc00, + 0xcc00, + 0xec00, + 0xdc00, + 0x7800, + 0x0c00, + 0x0000, + + /* Character 82 (0x52): + width 7 + +-------+ + | | + | | + |***** | + |** ** | + |** ** | + |** ** | + |***** | + |**** | + |** ** | + |** ** | + |** * | + | | + | | + +-------+ */ + 0x0000, + 0x0000, + 0xf800, + 0xcc00, + 0xcc00, + 0xcc00, + 0xf800, + 0xf000, + 0xd800, + 0xcc00, + 0xc400, + 0x0000, + 0x0000, + + /* Character 83 (0x53): + width 7 + +-------+ + | | + | | + | **** | + |** ** | + |** | + |** | + | **** | + | ** | + | ** | + |** ** | + | **** | + | | + | | + +-------+ */ + 0x0000, + 0x0000, + 0x7800, + 0xcc00, + 0xc000, + 0xc000, + 0x7800, + 0x0c00, + 0x0c00, + 0xcc00, + 0x7800, + 0x0000, + 0x0000, + + /* Character 84 (0x54): + width 7 + +-------+ + | | + | | + |****** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | | + | | + +-------+ */ + 0x0000, + 0x0000, + 0xfc00, + 0x3000, + 0x3000, + 0x3000, + 0x3000, + 0x3000, + 0x3000, + 0x3000, + 0x3000, + 0x0000, + 0x0000, + + /* Character 85 (0x55): + width 7 + +-------+ + | | + | | + |** ** | + |** ** | + |** ** | + |** ** | + |** ** | + |** ** | + |** ** | + |** ** | + | **** | + | | + | | + +-------+ */ + 0x0000, + 0x0000, + 0xcc00, + 0xcc00, + 0xcc00, + 0xcc00, + 0xcc00, + 0xcc00, + 0xcc00, + 0xcc00, + 0x7800, + 0x0000, + 0x0000, + + /* Character 86 (0x56): + width 7 + +-------+ + | | + | | + |** ** | + |** ** | + |** ** | + | * * | + | * * | + | **** | + | ** | + | ** | + | ** | + | | + | | + +-------+ */ + 0x0000, + 0x0000, + 0xcc00, + 0xcc00, + 0xcc00, + 0x4800, + 0x4800, + 0x7800, + 0x3000, + 0x3000, + 0x3000, + 0x0000, + 0x0000, + + /* Character 87 (0x57): + width 7 + +-------+ + | | + | | + |** ** | + |** ** | + |** ** | + |** ** | + |** ** | + |****** | + |****** | + |** ** | + |* * | + | | + | | + +-------+ */ + 0x0000, + 0x0000, + 0xcc00, + 0xcc00, + 0xcc00, + 0xcc00, + 0xcc00, + 0xfc00, + 0xfc00, + 0xcc00, + 0x8400, + 0x0000, + 0x0000, + + /* Character 88 (0x58): + width 7 + +-------+ + | | + | | + |* * | + |** ** | + | * * | + | **** | + | ** | + | **** | + | * * | + |** ** | + |* * | + | | + | | + +-------+ */ + 0x0000, + 0x0000, + 0x8400, + 0xcc00, + 0x4800, + 0x7800, + 0x3000, + 0x7800, + 0x4800, + 0xcc00, + 0x8400, + 0x0000, + 0x0000, + + /* Character 89 (0x59): + width 7 + +-------+ + | | + | | + |** ** | + |** ** | + | **** | + | **** | + | ** | + | ** | + | ** | + | ** | + | ** | + | | + | | + +-------+ */ + 0x0000, + 0x0000, + 0xcc00, + 0xcc00, + 0x7800, + 0x7800, + 0x3000, + 0x3000, + 0x3000, + 0x3000, + 0x3000, + 0x0000, + 0x0000, + + /* Character 90 (0x5a): + width 7 + +-------+ + | | + | | + |****** | + | ** | + | ** | + | ** | + | ** | + | ** | + |** | + |** | + |****** | + | | + | | + +-------+ */ + 0x0000, + 0x0000, + 0xfc00, + 0x0c00, + 0x0c00, + 0x1800, + 0x3000, + 0x6000, + 0xc000, + 0xc000, + 0xfc00, + 0x0000, + 0x0000, + + /* Character 91 (0x5b): + width 7 + +-------+ + | | + | | + | **** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | **** | + | | + | | + +-------+ */ + 0x0000, + 0x0000, + 0x7800, + 0x6000, + 0x6000, + 0x6000, + 0x6000, + 0x6000, + 0x6000, + 0x6000, + 0x7800, + 0x0000, + 0x0000, + + /* Character 92 (0x5c): + width 7 + +-------+ + | | + | | + |** | + |** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | | + | | + +-------+ */ + 0x0000, + 0x0000, + 0xc000, + 0xc000, + 0x6000, + 0x6000, + 0x3000, + 0x1800, + 0x1800, + 0x0c00, + 0x0c00, + 0x0000, + 0x0000, + + /* Character 93 (0x5d): + width 7 + +-------+ + | | + | | + | **** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | **** | + | | + | | + +-------+ */ + 0x0000, + 0x0000, + 0x7800, + 0x1800, + 0x1800, + 0x1800, + 0x1800, + 0x1800, + 0x1800, + 0x1800, + 0x7800, + 0x0000, + 0x0000, + + /* Character 94 (0x5e): + width 7 + +-------+ + | | + | | + | ** | + | **** | + |** ** | + |* * | + | | + | | + | | + | | + | | + | | + | | + +-------+ */ + 0x0000, + 0x0000, + 0x3000, + 0x7800, + 0xcc00, + 0x8400, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + + /* Character 95 (0x5f): + width 7 + +-------+ + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + |****** | + |****** | + | | + +-------+ */ + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0xfc00, + 0xfc00, + 0x0000, + + /* Character 96 (0x60): + width 7 + +-------+ + | | + | ** | + | ** | + | ** | + | | + | | + | | + | | + | | + | | + | | + | | + | | + +-------+ */ + 0x0000, + 0x6000, + 0x3000, + 0x1800, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + + /* Character 97 (0x61): + width 7 + +-------+ + | | + | | + | | + | | + | | + | **** | + | ** | + | ***** | + |** ** | + |** ** | + | ***** | + | | + | | + +-------+ */ + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x7800, + 0x0c00, + 0x7c00, + 0xcc00, + 0xcc00, + 0x7c00, + 0x0000, + 0x0000, + + /* Character 98 (0x62): + width 7 + +-------+ + | | + | | + |** | + |** | + |** | + |***** | + |** ** | + |** ** | + |** ** | + |** ** | + |***** | + | | + | | + +-------+ */ + 0x0000, + 0x0000, + 0xc000, + 0xc000, + 0xc000, + 0xf800, + 0xcc00, + 0xcc00, + 0xcc00, + 0xcc00, + 0xf800, + 0x0000, + 0x0000, + + /* Character 99 (0x63): + width 7 + +-------+ + | | + | | + | | + | | + | | + | **** | + |** ** | + |** | + |** | + |** ** | + | **** | + | | + | | + +-------+ */ + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x7800, + 0xcc00, + 0xc000, + 0xc000, + 0xcc00, + 0x7800, + 0x0000, + 0x0000, + + /* Character 100 (0x64): + width 7 + +-------+ + | | + | | + | ** | + | ** | + | ** | + | ***** | + |** ** | + |** ** | + |** ** | + |** ** | + | ***** | + | | + | | + +-------+ */ + 0x0000, + 0x0000, + 0x0c00, + 0x0c00, + 0x0c00, + 0x7c00, + 0xcc00, + 0xcc00, + 0xcc00, + 0xcc00, + 0x7c00, + 0x0000, + 0x0000, + + /* Character 101 (0x65): + width 7 + +-------+ + | | + | | + | | + | | + | | + | **** | + |** ** | + |****** | + |** | + |** ** | + | **** | + | | + | | + +-------+ */ + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x7800, + 0xcc00, + 0xfc00, + 0xc000, + 0xcc00, + 0x7800, + 0x0000, + 0x0000, + + /* Character 102 (0x66): + width 7 + +-------+ + | | + | | + | *** | + | ** ** | + | ** | + | ** | + |**** | + | ** | + | ** | + | ** | + | ** | + | | + | | + +-------+ */ + 0x0000, + 0x0000, + 0x3800, + 0x6c00, + 0x6000, + 0x6000, + 0xf000, + 0x6000, + 0x6000, + 0x6000, + 0x6000, + 0x0000, + 0x0000, + + /* Character 103 (0x67): + width 7 + +-------+ + | | + | | + | | + | | + | | + | *** * | + |** ** | + |** ** | + | **** | + |** | + | **** | + |** ** | + | **** | + +-------+ */ + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x7400, + 0xcc00, + 0xcc00, + 0x7800, + 0xc000, + 0x7800, + 0xcc00, + 0x7800, + + /* Character 104 (0x68): + width 7 + +-------+ + | | + | | + |** | + |** | + |** | + |***** | + |** ** | + |** ** | + |** ** | + |** ** | + |** ** | + | | + | | + +-------+ */ + 0x0000, + 0x0000, + 0xc000, + 0xc000, + 0xc000, + 0xf800, + 0xcc00, + 0xcc00, + 0xcc00, + 0xcc00, + 0xcc00, + 0x0000, + 0x0000, + + /* Character 105 (0x69): + width 7 + +-------+ + | | + | | + | ** | + | ** | + | | + | *** | + | ** | + | ** | + | ** | + | ** | + |****** | + | | + | | + +-------+ */ + 0x0000, + 0x0000, + 0x3000, + 0x3000, + 0x0000, + 0x7000, + 0x3000, + 0x3000, + 0x3000, + 0x3000, + 0xfc00, + 0x0000, + 0x0000, + + /* Character 106 (0x6a): + width 7 + +-------+ + | | + | | + | ** | + | ** | + | | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + |** ** | + | **** | + +-------+ */ + 0x0000, + 0x0000, + 0x0c00, + 0x0c00, + 0x0000, + 0x0c00, + 0x0c00, + 0x0c00, + 0x0c00, + 0x0c00, + 0x0c00, + 0xcc00, + 0x7800, + + /* Character 107 (0x6b): + width 7 + +-------+ + | | + | | + |** | + |** | + |** | + |** ** | + |** ** | + |**** | + |**** | + |** ** | + |** ** | + | | + | | + +-------+ */ + 0x0000, + 0x0000, + 0xc000, + 0xc000, + 0xc000, + 0xcc00, + 0xd800, + 0xf000, + 0xf000, + 0xd800, + 0xcc00, + 0x0000, + 0x0000, + + /* Character 108 (0x6c): + width 7 + +-------+ + | | + | | + | *** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + |****** | + | | + | | + +-------+ */ + 0x0000, + 0x0000, + 0x7000, + 0x3000, + 0x3000, + 0x3000, + 0x3000, + 0x3000, + 0x3000, + 0x3000, + 0xfc00, + 0x0000, + 0x0000, + + /* Character 109 (0x6d): + width 7 + +-------+ + | | + | | + | | + | | + | | + |** ** | + |****** | + |****** | + |** ** | + |** ** | + |** ** | + | | + | | + +-------+ */ + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0xd800, + 0xfc00, + 0xfc00, + 0xcc00, + 0xcc00, + 0xcc00, + 0x0000, + 0x0000, + + /* Character 110 (0x6e): + width 7 + +-------+ + | | + | | + | | + | | + | | + |***** | + |** ** | + |** ** | + |** ** | + |** ** | + |** ** | + | | + | | + +-------+ */ + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0xf800, + 0xcc00, + 0xcc00, + 0xcc00, + 0xcc00, + 0xcc00, + 0x0000, + 0x0000, + + /* Character 111 (0x6f): + width 7 + +-------+ + | | + | | + | | + | | + | | + | **** | + |** ** | + |** ** | + |** ** | + |** ** | + | **** | + | | + | | + +-------+ */ + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x7800, + 0xcc00, + 0xcc00, + 0xcc00, + 0xcc00, + 0x7800, + 0x0000, + 0x0000, + + /* Character 112 (0x70): + width 7 + +-------+ + | | + | | + | | + | | + | | + |***** | + |** ** | + |** ** | + |** ** | + |***** | + |** | + |** | + |** | + +-------+ */ + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0xf800, + 0xcc00, + 0xcc00, + 0xcc00, + 0xf800, + 0xc000, + 0xc000, + 0xc000, + + /* Character 113 (0x71): + width 7 + +-------+ + | | + | | + | | + | | + | | + | ***** | + |** ** | + |** ** | + |** ** | + | ***** | + | ** | + | ** | + | ** | + +-------+ */ + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x7c00, + 0xcc00, + 0xcc00, + 0xcc00, + 0x7c00, + 0x0c00, + 0x0c00, + 0x0c00, + + /* Character 114 (0x72): + width 7 + +-------+ + | | + | | + | | + | | + | | + |***** | + |** ** | + |** | + |** | + |** | + |** | + | | + | | + +-------+ */ + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0xf800, + 0xcc00, + 0xc000, + 0xc000, + 0xc000, + 0xc000, + 0x0000, + 0x0000, + + /* Character 115 (0x73): + width 7 + +-------+ + | | + | | + | | + | | + | | + | **** | + |** ** | + | ** | + | ** | + |** ** | + | **** | + | | + | | + +-------+ */ + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x7800, + 0xcc00, + 0x6000, + 0x1800, + 0xcc00, + 0x7800, + 0x0000, + 0x0000, + + /* Character 116 (0x74): + width 7 + +-------+ + | | + | | + | | + | ** | + | ** | + |***** | + | ** | + | ** | + | ** | + | ** ** | + | *** | + | | + | | + +-------+ */ + 0x0000, + 0x0000, + 0x0000, + 0x6000, + 0x6000, + 0xf800, + 0x6000, + 0x6000, + 0x6000, + 0x6c00, + 0x3800, + 0x0000, + 0x0000, + + /* Character 117 (0x75): + width 7 + +-------+ + | | + | | + | | + | | + | | + |** ** | + |** ** | + |** ** | + |** ** | + |** ** | + | ***** | + | | + | | + +-------+ */ + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0xcc00, + 0xcc00, + 0xcc00, + 0xcc00, + 0xcc00, + 0x7c00, + 0x0000, + 0x0000, + + /* Character 118 (0x76): + width 7 + +-------+ + | | + | | + | | + | | + | | + |** ** | + |** ** | + |** ** | + | **** | + | **** | + | ** | + | | + | | + +-------+ */ + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0xcc00, + 0xcc00, + 0xcc00, + 0x7800, + 0x7800, + 0x3000, + 0x0000, + 0x0000, + + /* Character 119 (0x77): + width 7 + +-------+ + | | + | | + | | + | | + | | + |** ** | + |** ** | + |** ** | + |****** | + |****** | + | * * | + | | + | | + +-------+ */ + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0xcc00, + 0xcc00, + 0xcc00, + 0xfc00, + 0xfc00, + 0x4800, + 0x0000, + 0x0000, + + /* Character 120 (0x78): + width 7 + +-------+ + | | + | | + | | + | | + | | + |** ** | + |** ** | + | **** | + | **** | + |** ** | + |** ** | + | | + | | + +-------+ */ + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0xcc00, + 0xcc00, + 0x7800, + 0x7800, + 0xcc00, + 0xcc00, + 0x0000, + 0x0000, + + /* Character 121 (0x79): + width 7 + +-------+ + | | + | | + | | + | | + | | + |** ** | + |** ** | + |** ** | + |** ** | + | ***** | + | ** | + |** ** | + | **** | + +-------+ */ + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0xcc00, + 0xcc00, + 0xcc00, + 0xcc00, + 0x7c00, + 0x0c00, + 0xcc00, + 0x7800, + + /* Character 122 (0x7a): + width 7 + +-------+ + | | + | | + | | + | | + | | + |****** | + | ** | + | ** | + | ** | + |** | + |****** | + | | + | | + +-------+ */ + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0xfc00, + 0x0c00, + 0x1800, + 0x6000, + 0xc000, + 0xfc00, + 0x0000, + 0x0000, + + /* Character 123 (0x7b): + width 7 + +-------+ + | | + | | + | *** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | *** | + | | + | | + +-------+ */ + 0x0000, + 0x0000, + 0x3800, + 0x6000, + 0x6000, + 0x3000, + 0x6000, + 0x3000, + 0x6000, + 0x6000, + 0x3800, + 0x0000, + 0x0000, + + /* Character 124 (0x7c): + width 7 + +-------+ + | | + | | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | | + | | + +-------+ */ + 0x0000, + 0x0000, + 0x3000, + 0x3000, + 0x3000, + 0x3000, + 0x3000, + 0x3000, + 0x3000, + 0x3000, + 0x3000, + 0x0000, + 0x0000, + + /* Character 125 (0x7d): + width 7 + +-------+ + | | + | | + | *** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | *** | + | | + | | + +-------+ */ + 0x0000, + 0x0000, + 0x7000, + 0x1800, + 0x1800, + 0x3000, + 0x1800, + 0x3000, + 0x1800, + 0x1800, + 0x7000, + 0x0000, + 0x0000, + + /* Character 126 (0x7e): + width 7 + +-------+ + | | + | | + | ** * | + |****** | + |* ** | + | | + | | + | | + | | + | | + | | + | | + | | + +-------+ */ + 0x0000, + 0x0000, + 0x6400, + 0xfc00, + 0x9800, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, +}; + + diff --git a/Makefile b/Makefile index bec51b8..aec3636 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,8 @@ # Compiler options here. ifeq ($(USE_OPT),) - USE_OPT = -O2 -fno-inline-small-functions -ggdb -fomit-frame-pointer -falign-functions=16 --specs=nano.specs -fstack-usage + USE_OPT = -Og -fno-inline-small-functions -ggdb -fomit-frame-pointer -falign-functions=16 --specs=nano.specs -fstack-usage +# USE_OPT = -O2 -fno-inline-small-functions -ggdb -fomit-frame-pointer -falign-functions=16 --specs=nano.specs -fstack-usage endif # C specific options here (added to USE_OPT). @@ -54,7 +55,7 @@ endif ############################################################################## ifeq ($(VERSION),) - VERSION="$(shell git describe --tags)" + VERSION="tinySA_$(shell git describe --tags)" endif ############################################################################## @@ -64,7 +65,7 @@ endif # Stack size to be allocated to the Cortex-M process stack. This stack is # the stack used by the main() thread. ifeq ($(USE_PROCESS_STACKSIZE),) - USE_PROCESS_STACKSIZE = 0x200 + USE_PROCESS_STACKSIZE = 0x240 endif # Stack size to the allocated to the Cortex-M main/exceptions stack. This @@ -82,7 +83,7 @@ endif # # Define project name here -PROJECT = ch +PROJECT = tinySA # Imported source files and paths #CHIBIOS = ../ChibiOS-RT @@ -119,7 +120,7 @@ CSRC = $(STARTUPSRC) \ $(BOARDSRC) \ $(STREAMSSRC) \ usbcfg.c \ - main.c si5351.c tlv320aic3204.c dsp.c plot.c ui.c ili9341.c numfont20x22.c Font5x7.c flash.c adc.c + main.c plot.c ui.c ili9341.c numfont20x22.c Font5x7.c flash.c adc.c si4432.c Font7x13b.c # C++ sources that can be compiled in ARM or THUMB mode depending on the global # setting. @@ -225,6 +226,7 @@ flash: build/ch.bin dfu-util -d 0483:df11 -a 0 -s 0x08000000:leave -D build/ch.bin dfu: + c:/work/dfu/HEX2DFU build/ch.hex build/ch.dfu -@printf "reset dfu\r" >/dev/cu.usbmodem401 diff --git a/NANOVNA_STM32_F072/board.h b/NANOVNA_STM32_F072/board.h index c64cf75..06944c9 100644 --- a/NANOVNA_STM32_F072/board.h +++ b/NANOVNA_STM32_F072/board.h @@ -21,8 +21,8 @@ * Board identifier. */ #define BOARD_NANOVNA_STM32_F072 -#define BOARD_NAME "NanoVNA" - +#define BOARD_NAME "tinySA v0.2" +#define BOARD_VERSION 0 /* * Board frequencies. */ @@ -47,14 +47,16 @@ /* on-board */ -#define GPIOA_BUTTON 0 +//#define GPIO_PE_SEL 0 #define GPIOA_LEVER1 1 #define GPIOA_LEVER2 2 #define GPIOA_PUSH 3 -#define GPIOA_DAC2 5 +//#define GPIO_RX_SEL 4 +//#define GPIO_LO_SEL 5 #define GPIOA_XP 6 #define GPIOA_YP 7 #define GPIOA_MCO 8 +#define GPIOA_TX 9 #define GPIOA_USB_DISC 10 #define GPIOA_USB_DM 11 #define GPIOA_USB_DP 12 @@ -71,14 +73,19 @@ #define GPIOB_LCD_CS 6 #define GPIOB_LCD_CD 7 #define GPIOB_I2C1_SCL 8 -#define GPIOB_I2C1_SDA 9 -#define GPIOB_SD_GP2 10 +#define GPIO_RF_PWR 9 +#define GPIO_SPI2_CLK 10 #define GPIOB_SD_CS 11 -#define GPIOB_I2S2_WCLK 12 -#define GPIOB_I2S2_BCLK 13 -#define GPIOB_I2S2_MOSI 15 +#define GPIO_SPI2_SDO 14 +#define GPIO_SPI2_SDI 15 + +// Port C +#define GPIO_PE_SEL 13 +#define GPIO_RX_SEL 14 +#define GPIO_LO_SEL 15 -#define GPIOC_LED 13 + +#define GPIOB_LED 11 #define GPIOF_OSC_IN 0 #define GPIOF_OSC_OUT 1 @@ -115,19 +122,19 @@ * PA13 - SWDIO (alternate 0). * PA14 - SWCLK (alternate 0). */ -#define VAL_GPIOA_MODER (PIN_MODE_INPUT(0U) | \ +#define VAL_GPIOA_MODER (PIN_MODE_INPUT(0U) | \ PIN_MODE_INPUT(1U) | \ PIN_MODE_INPUT(2U) | \ PIN_MODE_INPUT(3U) | \ - PIN_MODE_INPUT(4U) | \ - PIN_MODE_ANALOG(GPIOA_DAC2) | \ + PIN_MODE_INPUT(4U) | \ + PIN_MODE_INPUT(5U) | \ PIN_MODE_ANALOG(GPIOA_XP) | \ PIN_MODE_ANALOG(GPIOA_YP) | \ PIN_MODE_ALTERNATE(GPIOA_MCO) | \ PIN_MODE_INPUT(9U) | \ PIN_MODE_OUTPUT(GPIOA_USB_DISC) | \ - PIN_MODE_ALTERNATE(GPIOA_USB_DM) | \ - PIN_MODE_ALTERNATE(GPIOA_USB_DP) | \ + PIN_MODE_INPUT(GPIOA_USB_DM) | \ + PIN_MODE_INPUT(GPIOA_USB_DP) | \ PIN_MODE_ALTERNATE(GPIOA_JTMS) | \ PIN_MODE_ALTERNATE(GPIOA_JTCK) | \ PIN_MODE_OUTPUT(GPIOA_LCD_RESET)) @@ -151,40 +158,40 @@ PIN_OSPEED_2M(1) | \ PIN_OSPEED_2M(2) | \ PIN_OSPEED_2M(3) | \ - PIN_OSPEED_2M(4) | \ - PIN_OSPEED_2M(5) | \ + PIN_OSPEED_100M(4) | \ + PIN_OSPEED_100M(5) | \ PIN_OSPEED_2M(6) | \ PIN_OSPEED_2M(7) | \ PIN_OSPEED_100M(GPIOA_MCO) | \ PIN_OSPEED_100M(9) | \ - PIN_OSPEED_100M(GPIOA_USB_DISC) | \ + PIN_OSPEED_100M(10) | \ PIN_OSPEED_100M(GPIOA_USB_DM) | \ PIN_OSPEED_100M(GPIOA_USB_DP) | \ PIN_OSPEED_100M(GPIOA_JTMS) | \ PIN_OSPEED_100M(GPIOA_JTCK) | \ PIN_OSPEED_100M(GPIOA_LCD_RESET)) -#define VAL_GPIOA_PUPDR (PIN_PUPDR_PULLDOWN(0) | \ +#define VAL_GPIOA_PUPDR ( PIN_PUPDR_PULLDOWN(0) | \ PIN_PUPDR_PULLDOWN(1) | \ PIN_PUPDR_PULLDOWN(2) | \ PIN_PUPDR_PULLDOWN(3) | \ - PIN_PUPDR_PULLUP(4) | \ - PIN_PUPDR_FLOATING(5) | \ + PIN_PUPDR_PULLDOWN(4) | \ + PIN_PUPDR_PULLDOWN(5) | \ PIN_PUPDR_FLOATING(6) | \ PIN_PUPDR_FLOATING(7) | \ PIN_PUPDR_PULLUP(GPIOA_MCO) | \ PIN_PUPDR_PULLUP(9) | \ - PIN_PUPDR_FLOATING(GPIOA_USB_DISC) | \ + PIN_PUPDR_PULLUP(GPIOA_USB_DISC) | \ PIN_PUPDR_FLOATING(GPIOA_USB_DM) | \ PIN_PUPDR_FLOATING(GPIOA_USB_DP) | \ PIN_PUPDR_PULLDOWN(GPIOA_JTMS) | \ PIN_PUPDR_PULLDOWN(GPIOA_JTCK) | \ PIN_PUPDR_PULLDOWN(GPIOA_LCD_RESET)) -#define VAL_GPIOA_ODR (PIN_ODR_HIGH(0) | \ +#define VAL_GPIOA_ODR ( PIN_ODR_HIGH(0) | \ PIN_ODR_HIGH(1) | \ PIN_ODR_HIGH(2) | \ PIN_ODR_HIGH(3) | \ PIN_ODR_HIGH(4) | \ - PIN_ODR_LOW(5) | \ + PIN_ODR_HIGH(5) | \ PIN_ODR_HIGH(6) | \ PIN_ODR_HIGH(7) | \ PIN_ODR_HIGH(GPIOA_MCO) | \ @@ -234,14 +241,14 @@ PIN_MODE_ALTERNATE(GPIOB_SPI_MOSI) | \ PIN_MODE_OUTPUT(6) | \ PIN_MODE_OUTPUT(7) | \ - PIN_MODE_ALTERNATE(GPIOB_I2C1_SCL) | \ - PIN_MODE_ALTERNATE(GPIOB_I2C1_SDA) | \ - PIN_MODE_OUTPUT(10) | \ + PIN_MODE_OUTPUT(8) | \ + PIN_MODE_OUTPUT(GPIO_RF_PWR) | \ + PIN_MODE_OUTPUT(GPIO_SPI2_CLK) | \ PIN_MODE_OUTPUT(11) | \ - PIN_MODE_ALTERNATE(GPIOB_I2S2_WCLK) | \ - PIN_MODE_ALTERNATE(GPIOB_I2S2_BCLK) | \ - PIN_MODE_ALTERNATE(14) | \ - PIN_MODE_ALTERNATE(GPIOB_I2S2_MOSI)) + PIN_MODE_OUTPUT(12) | \ + PIN_MODE_OUTPUT(13) | \ + PIN_MODE_INPUT(GPIO_SPI2_SDO) | \ + PIN_MODE_OUTPUT(GPIO_SPI2_SDI)) #define VAL_GPIOB_OTYPER (PIN_OTYPE_PUSHPULL(0) | \ PIN_OTYPE_PUSHPULL(1) | \ PIN_OTYPE_PUSHPULL(2) | \ @@ -250,14 +257,14 @@ PIN_OTYPE_PUSHPULL(5) | \ PIN_OTYPE_PUSHPULL(6) | \ PIN_OTYPE_PUSHPULL(7) | \ - PIN_OTYPE_PUSHPULL(GPIOB_I2C1_SCL) | \ - PIN_OTYPE_PUSHPULL(GPIOB_I2C1_SDA) | \ - PIN_OTYPE_PUSHPULL(10) | \ + PIN_OTYPE_PUSHPULL(8) | \ + PIN_OTYPE_PUSHPULL(GPIO_RF_PWR) | \ + PIN_OTYPE_PUSHPULL(GPIO_SPI2_CLK) | \ PIN_OTYPE_PUSHPULL(11) | \ - PIN_OTYPE_PUSHPULL(GPIOB_I2S2_WCLK) | \ - PIN_OTYPE_PUSHPULL(GPIOB_I2S2_BCLK) | \ - PIN_OTYPE_PUSHPULL(14) | \ - PIN_OTYPE_PUSHPULL(GPIOB_I2S2_MOSI)) + PIN_OTYPE_PUSHPULL(12) | \ + PIN_OTYPE_PUSHPULL(13) | \ + PIN_OTYPE_PUSHPULL(GPIO_SPI2_SDO) | \ + PIN_OTYPE_PUSHPULL(GPIO_SPI2_SDI)) #define VAL_GPIOB_OSPEEDR (PIN_PUPDR_FLOATING(GPIOB_XN) | \ PIN_PUPDR_FLOATING(GPIOB_YN) | \ PIN_OSPEED_100M(2) | \ @@ -266,14 +273,14 @@ PIN_OSPEED_100M(5) | \ PIN_OSPEED_100M(6) | \ PIN_OSPEED_100M(7) | \ - PIN_OSPEED_100M(GPIOB_I2C1_SCL) | \ - PIN_OSPEED_100M(GPIOB_I2C1_SDA) | \ + PIN_OSPEED_100M(8) | \ + PIN_OSPEED_100M(9) | \ PIN_OSPEED_100M(10) | \ PIN_OSPEED_100M(11) | \ - PIN_OSPEED_100M(GPIOB_I2S2_WCLK) | \ - PIN_OSPEED_100M(GPIOB_I2S2_BCLK) | \ + PIN_OSPEED_100M(12) | \ + PIN_OSPEED_100M(13) | \ PIN_OSPEED_100M(14) | \ - PIN_OSPEED_100M(GPIOB_I2S2_MOSI)) + PIN_OSPEED_100M(15)) #define VAL_GPIOB_PUPDR (PIN_PUPDR_PULLUP(0) | \ PIN_PUPDR_PULLUP(1) | \ PIN_PUPDR_PULLUP(2) | \ @@ -282,14 +289,14 @@ PIN_PUPDR_PULLUP(5) | \ PIN_PUPDR_PULLUP(6) | \ PIN_PUPDR_PULLUP(7) | \ - PIN_PUPDR_PULLUP(GPIOB_I2C1_SCL) | \ - PIN_PUPDR_PULLUP(GPIOB_I2C1_SDA) | \ + PIN_PUPDR_PULLUP(8) | \ + PIN_PUPDR_PULLUP(9) | \ PIN_PUPDR_PULLUP(10) | \ PIN_PUPDR_PULLUP(11) | \ - PIN_PUPDR_PULLUP(GPIOB_I2S2_WCLK) | \ - PIN_PUPDR_PULLUP(GPIOB_I2S2_BCLK) | \ + PIN_PUPDR_PULLUP(12) | \ + PIN_PUPDR_PULLUP(13) | \ PIN_PUPDR_PULLUP(14) | \ - PIN_PUPDR_PULLUP(GPIOB_I2S2_MOSI)) + PIN_PUPDR_PULLUP(14)) #define VAL_GPIOB_ODR (PIN_ODR_HIGH(0) | \ PIN_ODR_HIGH(1) | \ PIN_ODR_HIGH(2) | \ @@ -298,14 +305,14 @@ PIN_ODR_HIGH(5) | \ PIN_ODR_HIGH(6) | \ PIN_ODR_HIGH(7) | \ - PIN_ODR_HIGH(GPIOB_I2C1_SCL) | \ - PIN_ODR_HIGH(GPIOB_I2C1_SDA) | \ + PIN_ODR_HIGH(8) | \ + PIN_ODR_HIGH(9) | \ PIN_ODR_HIGH(10) | \ PIN_ODR_HIGH(11) | \ - PIN_ODR_HIGH(GPIOB_I2S2_WCLK) | \ - PIN_ODR_HIGH(GPIOB_I2S2_BCLK) | \ + PIN_ODR_HIGH(12) | \ + PIN_ODR_HIGH(13) | \ PIN_ODR_HIGH(14) | \ - PIN_ODR_HIGH(GPIOB_I2S2_MOSI)) + PIN_ODR_HIGH(15)) #define VAL_GPIOB_AFRL (PIN_AFIO_AF(0, 0) | \ PIN_AFIO_AF(1, 0) | \ PIN_AFIO_AF(2, 0) | \ @@ -314,20 +321,21 @@ PIN_AFIO_AF(GPIOB_SPI_MISO, 0) | \ PIN_AFIO_AF(6, 0) | \ PIN_AFIO_AF(7, 0)) -#define VAL_GPIOB_AFRH (PIN_AFIO_AF(GPIOB_I2C1_SCL, 1) | \ - PIN_AFIO_AF(GPIOB_I2C1_SDA, 1) | \ +#define VAL_GPIOB_AFRH (PIN_AFIO_AF(8, 1) | \ + PIN_AFIO_AF(9, 1) | \ PIN_AFIO_AF(10, 0) | \ PIN_AFIO_AF(11, 0) | \ - PIN_AFIO_AF(GPIOB_I2S2_WCLK, 0) | \ - PIN_AFIO_AF(GPIOB_I2S2_BCLK, 0) | \ + PIN_AFIO_AF(12, 0) | \ + PIN_AFIO_AF(13, 0) | \ PIN_AFIO_AF(14, 0) | \ - PIN_AFIO_AF(GPIOB_I2S2_MOSI, 0)) + PIN_AFIO_AF(15, 0)) /* * GPIOC setup: * * PC13 - LED (output pushpull maximum). * PC14 - USB DISC (output pushpull maximum). */ + #define VAL_GPIOC_MODER (PIN_MODE_INPUT(0) | \ PIN_MODE_INPUT(1) | \ PIN_MODE_INPUT(2) | \ @@ -341,9 +349,9 @@ PIN_MODE_INPUT(10) | \ PIN_MODE_INPUT(11) | \ PIN_MODE_INPUT(12) | \ - PIN_MODE_OUTPUT(GPIOC_LED) | \ - PIN_MODE_INPUT(14) | \ - PIN_MODE_INPUT(15)) + PIN_MODE_OUTPUT(GPIO_PE_SEL) | \ + PIN_MODE_OUTPUT(GPIO_RX_SEL) | \ + PIN_MODE_OUTPUT(GPIO_LO_SEL)) #define VAL_GPIOC_OTYPER (PIN_OTYPE_PUSHPULL(0) | \ PIN_OTYPE_PUSHPULL(1) | \ PIN_OTYPE_PUSHPULL(2) | \ @@ -357,7 +365,7 @@ PIN_OTYPE_PUSHPULL(10) | \ PIN_OTYPE_PUSHPULL(11) | \ PIN_OTYPE_PUSHPULL(12) | \ - PIN_OTYPE_PUSHPULL(GPIOC_LED) | \ + PIN_OTYPE_PUSHPULL(13) | \ PIN_OTYPE_PUSHPULL(14) | \ PIN_OTYPE_PUSHPULL(15)) #define VAL_GPIOC_OSPEEDR (PIN_OSPEED_100M(0) | \ @@ -373,7 +381,7 @@ PIN_OSPEED_100M(10) | \ PIN_OSPEED_100M(11) | \ PIN_OSPEED_100M(12) | \ - PIN_OSPEED_100M(GPIOC_LED) | \ + PIN_OSPEED_100M(13) | \ PIN_OSPEED_100M(14) | \ PIN_OSPEED_100M(15)) #define VAL_GPIOC_PUPDR (PIN_PUPDR_PULLUP(0) | \ @@ -389,8 +397,8 @@ PIN_PUPDR_PULLUP(10) | \ PIN_PUPDR_PULLUP(11) | \ PIN_PUPDR_PULLUP(12) | \ - PIN_PUPDR_FLOATING(GPIOC_LED) | \ - PIN_PUPDR_FLOATING(14) | \ + PIN_PUPDR_PULLUP(13) | \ + PIN_PUPDR_PULLUP(14) | \ PIN_PUPDR_PULLUP(15)) #define VAL_GPIOC_ODR (PIN_ODR_HIGH(0) | \ PIN_ODR_HIGH(1) | \ @@ -405,7 +413,7 @@ PIN_ODR_HIGH(10) | \ PIN_ODR_HIGH(11) | \ PIN_ODR_HIGH(12) | \ - PIN_ODR_HIGH(GPIOC_LED) | \ + PIN_ODR_HIGH(13) | \ PIN_ODR_HIGH(14) | \ PIN_ODR_HIGH(15)) #define VAL_GPIOC_AFRL (PIN_AFIO_AF(0, 0) | \ @@ -421,7 +429,7 @@ PIN_AFIO_AF(10, 0) | \ PIN_AFIO_AF(11, 0) | \ PIN_AFIO_AF(12, 0) | \ - PIN_AFIO_AF(GPIOC_LED, 0) | \ + PIN_AFIO_AF(13, 0) | \ PIN_AFIO_AF(14, 0) | \ PIN_AFIO_AF(15, 0)) @@ -743,6 +751,7 @@ PIN_AFIO_AF(14, 0) | \ PIN_AFIO_AF(15, 0)) + #if !defined(_FROM_ASM_) #ifdef __cplusplus extern "C" { diff --git a/STM32F072xB.ld b/STM32F072xB.ld index 577e87f..8f7b034 100644 --- a/STM32F072xB.ld +++ b/STM32F072xB.ld @@ -19,14 +19,14 @@ */ MEMORY { - flash0 : org = 0x08000000, len = 96k + flash0 : org = 0x08000000, len = 108k flash1 : org = 0x00000000, len = 0 flash2 : org = 0x00000000, len = 0 flash3 : org = 0x00000000, len = 0 flash4 : org = 0x00000000, len = 0 flash5 : org = 0x00000000, len = 0 flash6 : org = 0x00000000, len = 0 - flash7 : org = 0x08018000, len = 32k + flash7 : org = 0x0801B000, len = 20k ram0 : org = 0x20000000, len = 16k ram1 : org = 0x00000000, len = 0 ram2 : org = 0x00000000, len = 0 diff --git a/chconf.h b/chconf.h index fd54b74..08860ae 100644 --- a/chconf.h +++ b/chconf.h @@ -147,7 +147,7 @@ * * @note The default is @p TRUE. */ -#define CH_CFG_USE_REGISTRY FALSE +#define CH_CFG_USE_REGISTRY TRUE /** * @brief Threads synchronization APIs. diff --git a/chprintf.c b/chprintf.c index fbfd1cd..3e19b26 100644 --- a/chprintf.c +++ b/chprintf.c @@ -52,7 +52,7 @@ static const uint32_t pow10[FLOAT_PRECISION+1] = { static char bigPrefix[] = {' ', 'k', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y', 0}; // Prefixes for values less then 1.0 // 1e-3, 1e-6, 1e-9, 1e-12, 1e-15, 1e-18, 1e-21, 1e-24 -static char smallPrefix[] = {'m', 0x1d, 'n', 'p', 'f', 'a', 'z', 'y', 0}; +static char smallPrefix[] = {'m', 'u', 'n', 'p', 'f', 'a', 'z', 'y', 0}; #pragma pack(pop) @@ -195,12 +195,15 @@ static char *ftoaS(char *p, float num, uint32_t precision) { ; prefix = num > 1e-3 ? ptr[-1] : 0; } - // Auto set prescision + if (prefix) + precision--; + + // Auto set precision uint32_t l = num; - if (l < 10) - precision+=2; - else if (l < 100) - precision+=1; + if (l > 100) + precision-=2; + else if (l > 10) + precision-=1; p=ftoa(p, num, precision); if (prefix) *p++ = prefix; diff --git a/dsp.c b/dsp.c deleted file mode 100644 index 4b616dc..0000000 --- a/dsp.c +++ /dev/null @@ -1,131 +0,0 @@ -/* - * Copyright (c) 2014-2015, TAKAHASHI Tomohiro (TTRFTECH) edy555@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 -#include "nanovna.h" - -#ifdef ENABLED_DUMP -int16_t samp_buf[SAMPLE_LEN]; -int16_t ref_buf[SAMPLE_LEN]; -#endif - -const int16_t sincos_tbl[48][2] = { - { 10533, 31029 }, { 27246, 18205 }, { 32698, -2143 }, { 24636, -21605 }, - { 6393, -32138 }, {-14493, -29389 }, {-29389, -14493 }, {-32138, 6393 }, - {-21605, 24636 }, { -2143, 32698 }, { 18205, 27246 }, { 31029, 10533 }, - { 31029, -10533 }, { 18205, -27246 }, { -2143, -32698 }, {-21605, -24636 }, - {-32138, -6393 }, {-29389, 14493 }, {-14493, 29389 }, { 6393, 32138 }, - { 24636, 21605 }, { 32698, 2143 }, { 27246, -18205 }, { 10533, -31029 }, - {-10533, -31029 }, {-27246, -18205 }, {-32698, 2143 }, {-24636, 21605 }, - { -6393, 32138 }, { 14493, 29389 }, { 29389, 14493 }, { 32138, -6393 }, - { 21605, -24636 }, { 2143, -32698 }, {-18205, -27246 }, {-31029, -10533 }, - {-31029, 10533 }, {-18205, 27246 }, { 2143, 32698 }, { 21605, 24636 }, - { 32138, 6393 }, { 29389, -14493 }, { 14493, -29389 }, { -6393, -32138 }, - {-24636, -21605 }, {-32698, -2143 }, {-27246, 18205 }, {-10533, 31029 } -}; - -float acc_samp_s; -float acc_samp_c; -float acc_ref_s; -float acc_ref_c; - -void -dsp_process(int16_t *capture, size_t length) -{ - uint32_t *p = (uint32_t*)capture; - uint32_t len = length / 2; - uint32_t i; - int32_t samp_s = 0; - int32_t samp_c = 0; - int32_t ref_s = 0; - int32_t ref_c = 0; - - for (i = 0; i < len; i++) { - uint32_t sr = *p++; - int16_t ref = sr & 0xffff; - int16_t smp = (sr>>16) & 0xffff; -#ifdef ENABLED_DUMP - ref_buf[i] = ref; - samp_buf[i] = smp; -#endif - int32_t s = sincos_tbl[i][0]; - int32_t c = sincos_tbl[i][1]; - samp_s += smp * s / 16; - samp_c += smp * c / 16; - ref_s += ref * s / 16; - ref_c += ref * c / 16; -#if 0 - uint32_t sc = *(uint32_t)&sincos_tbl[i]; - samp_s = __SMLABB(sr, sc, samp_s); - samp_c = __SMLABT(sr, sc, samp_c); - ref_s = __SMLATB(sr, sc, ref_s); - ref_c = __SMLATT(sr, sc, ref_c); -#endif - } - acc_samp_s += samp_s; - acc_samp_c += samp_c; - acc_ref_s += ref_s; - acc_ref_c += ref_c; -} - -void -calculate_gamma(float gamma[2]) -{ -#if 1 - // calculate reflection coeff. by samp divide by ref - float rs = acc_ref_s; - float rc = acc_ref_c; - float rr = rs * rs + rc * rc; - //rr = sqrtf(rr) * 1e8; - float ss = acc_samp_s; - float sc = acc_samp_c; - gamma[0] = (sc * rc + ss * rs) / rr; - gamma[1] = (ss * rc - sc * rs) / rr; -#elif 0 - gamma[0] = acc_samp_s; - gamma[1] = acc_samp_c; -#else - gamma[0] = acc_ref_s; - gamma[1] = acc_ref_c; -#endif -} - -void -fetch_amplitude(float gamma[2]) -{ - gamma[0] = acc_samp_s * 1e-9; - gamma[1] = acc_samp_c * 1e-9; -} - -void -fetch_amplitude_ref(float gamma[2]) -{ - gamma[0] = acc_ref_s * 1e-9; - gamma[1] = acc_ref_c * 1e-9; -} - -void -reset_dsp_accumerator(void) -{ - acc_ref_s = 0; - acc_ref_c = 0; - acc_samp_s = 0; - acc_samp_c = 0; -} diff --git a/ffconf.h b/ffconf.h deleted file mode 100644 index ae0d38d..0000000 --- a/ffconf.h +++ /dev/null @@ -1,193 +0,0 @@ -/* CHIBIOS FIX */ -#include "ch.h" - -/*---------------------------------------------------------------------------/ -/ FatFs - FAT file system module configuration file R0.09 (C)ChaN, 2011 -/----------------------------------------------------------------------------/ -/ -/ CAUTION! Do not forget to make clean the project after any changes to -/ the configuration options. -/ -/----------------------------------------------------------------------------*/ -#ifndef _FFCONF -#define _FFCONF 6502 /* Revision ID */ - - -/*---------------------------------------------------------------------------/ -/ Functions and Buffer Configurations -/----------------------------------------------------------------------------*/ - -#define _FS_TINY 0 /* 0:Normal or 1:Tiny */ -/* When _FS_TINY is set to 1, FatFs uses the sector buffer in the file system -/ object instead of the sector buffer in the individual file object for file -/ data transfer. This reduces memory consumption 512 bytes each file object. */ - - -#define _FS_READONLY 0 /* 0:Read/Write or 1:Read only */ -/* Setting _FS_READONLY to 1 defines read only configuration. This removes -/ writing functions, f_write, f_sync, f_unlink, f_mkdir, f_chmod, f_rename, -/ f_truncate and useless f_getfree. */ - - -#define _FS_MINIMIZE 0 /* 0 to 3 */ -/* The _FS_MINIMIZE option defines minimization level to remove some functions. -/ -/ 0: Full function. -/ 1: f_stat, f_getfree, f_unlink, f_mkdir, f_chmod, f_truncate and f_rename -/ are removed. -/ 2: f_opendir and f_readdir are removed in addition to 1. -/ 3: f_lseek is removed in addition to 2. */ - - -#define _USE_STRFUNC 0 /* 0:Disable or 1-2:Enable */ -/* To enable string functions, set _USE_STRFUNC to 1 or 2. */ - - -#define _USE_MKFS 1 /* 0:Disable or 1:Enable */ -/* To enable f_mkfs function, set _USE_MKFS to 1 and set _FS_READONLY to 0 */ - - -#define _USE_FORWARD 0 /* 0:Disable or 1:Enable */ -/* To enable f_forward function, set _USE_FORWARD to 1 and set _FS_TINY to 1. */ - - -#define _USE_FASTSEEK 0 /* 0:Disable or 1:Enable */ -/* To enable fast seek feature, set _USE_FASTSEEK to 1. */ - - - -/*---------------------------------------------------------------------------/ -/ Locale and Namespace Configurations -/----------------------------------------------------------------------------*/ - -#define _CODE_PAGE 1251 -/* The _CODE_PAGE specifies the OEM code page to be used on the target system. -/ Incorrect setting of the code page can cause a file open failure. -/ -/ 932 - Japanese Shift-JIS (DBCS, OEM, Windows) -/ 936 - Simplified Chinese GBK (DBCS, OEM, Windows) -/ 949 - Korean (DBCS, OEM, Windows) -/ 950 - Traditional Chinese Big5 (DBCS, OEM, Windows) -/ 1250 - Central Europe (Windows) -/ 1251 - Cyrillic (Windows) -/ 1252 - Latin 1 (Windows) -/ 1253 - Greek (Windows) -/ 1254 - Turkish (Windows) -/ 1255 - Hebrew (Windows) -/ 1256 - Arabic (Windows) -/ 1257 - Baltic (Windows) -/ 1258 - Vietnam (OEM, Windows) -/ 437 - U.S. (OEM) -/ 720 - Arabic (OEM) -/ 737 - Greek (OEM) -/ 775 - Baltic (OEM) -/ 850 - Multilingual Latin 1 (OEM) -/ 858 - Multilingual Latin 1 + Euro (OEM) -/ 852 - Latin 2 (OEM) -/ 855 - Cyrillic (OEM) -/ 866 - Russian (OEM) -/ 857 - Turkish (OEM) -/ 862 - Hebrew (OEM) -/ 874 - Thai (OEM, Windows) -/ 1 - ASCII only (Valid for non LFN cfg.) -*/ - - -#define _USE_LFN 1 /* 0 to 3 */ -#define _MAX_LFN 255 /* Maximum LFN length to handle (12 to 255) */ -/* The _USE_LFN option switches the LFN support. -/ -/ 0: Disable LFN feature. _MAX_LFN and _LFN_UNICODE have no effect. -/ 1: Enable LFN with static working buffer on the BSS. Always NOT reentrant. -/ 2: Enable LFN with dynamic working buffer on the STACK. -/ 3: Enable LFN with dynamic working buffer on the HEAP. -/ -/ The LFN working buffer occupies (_MAX_LFN + 1) * 2 bytes. To enable LFN, -/ Unicode handling functions ff_convert() and ff_wtoupper() must be added -/ to the project. When enable to use heap, memory control functions -/ ff_memalloc() and ff_memfree() must be added to the project. */ - - -#define _LFN_UNICODE 0 /* 0:ANSI/OEM or 1:Unicode */ -/* To switch the character code set on FatFs API to Unicode, -/ enable LFN feature and set _LFN_UNICODE to 1. */ - - -#define _FS_RPATH 0 /* 0 to 2 */ -/* The _FS_RPATH option configures relative path feature. -/ -/ 0: Disable relative path feature and remove related functions. -/ 1: Enable relative path. f_chdrive() and f_chdir() are available. -/ 2: f_getcwd() is available in addition to 1. -/ -/ Note that output of the f_readdir fnction is affected by this option. */ - - - -/*---------------------------------------------------------------------------/ -/ Physical Drive Configurations -/----------------------------------------------------------------------------*/ - -#define _VOLUMES 1 -/* Number of volumes (logical drives) to be used. */ - - -#define _MAX_SS 512 /* 512, 1024, 2048 or 4096 */ -/* Maximum sector size to be handled. -/ Always set 512 for memory card and hard disk but a larger value may be -/ required for on-board flash memory, floppy disk and optical disk. -/ When _MAX_SS is larger than 512, it configures FatFs to variable sector size -/ and GET_SECTOR_SIZE command must be implememted to the disk_ioctl function. */ - - -#define _MULTI_PARTITION 0 /* 0:Single partition, 1/2:Enable multiple partition */ -/* When set to 0, each volume is bound to the same physical drive number and -/ it can mount only first primaly partition. When it is set to 1, each volume -/ is tied to the partitions listed in VolToPart[]. */ - - -#define _USE_ERASE 1 /* 0:Disable or 1:Enable */ -/* To enable sector erase feature, set _USE_ERASE to 1. CTRL_ERASE_SECTOR command -/ should be added to the disk_ioctl functio. */ - - - -/*---------------------------------------------------------------------------/ -/ System Configurations -/----------------------------------------------------------------------------*/ - -#define _WORD_ACCESS 1 /* 0 or 1 */ -/* Set 0 first and it is always compatible with all platforms. The _WORD_ACCESS -/ option defines which access method is used to the word data on the FAT volume. -/ -/ 0: Byte-by-byte access. -/ 1: Word access. Do not choose this unless following condition is met. -/ -/ When the byte order on the memory is big-endian or address miss-aligned word -/ access results incorrect behavior, the _WORD_ACCESS must be set to 0. -/ If it is not the case, the value can also be set to 1 to improve the -/ performance and code size. -*/ - - -/* A header file that defines sync object types on the O/S, such as -/ windows.h, ucos_ii.h and semphr.h, must be included prior to ff.h. */ - -#define _FS_REENTRANT 0 /* 0:Disable or 1:Enable */ -#define _FS_TIMEOUT 1000 /* Timeout period in unit of time ticks */ -#define _SYNC_t Semaphore * /* O/S dependent type of sync object. e.g. HANDLE, OS_EVENT*, ID and etc.. */ - -/* The _FS_REENTRANT option switches the reentrancy (thread safe) of the FatFs module. -/ -/ 0: Disable reentrancy. _SYNC_t and _FS_TIMEOUT have no effect. -/ 1: Enable reentrancy. 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. */ - - -#define _FS_SHARE 0 /* 0:Disable or >=1:Enable */ -/* To enable file shareing feature, set _FS_SHARE to 1 or greater. The value - defines how many files can be opened simultaneously. */ - - -#endif /* _FFCONFIG */ diff --git a/fft.h b/fft.h deleted file mode 100644 index dbaa32f..0000000 --- a/fft.h +++ /dev/null @@ -1,90 +0,0 @@ -/* - * fft.h is Based on - * Free FFT and convolution (C) - * - * Copyright (c) 2019 Project Nayuki. (MIT License) - * https://www.nayuki.io/page/free-small-fft-in-multiple-languages - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of - * the Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - The Software is provided "as is", without warranty of any kind, express or - * implied, including but not limited to the warranties of merchantability, - * fitness for a particular purpose and noninfringement. In no event shall the - * authors or copyright holders be liable for any claim, damages or other - * liability, whether in an action of contract, tort or otherwise, arising from, - * out of or in connection with the Software or the use or other dealings in the - * Software. - */ - - -#include -#include - -static uint16_t reverse_bits(uint16_t x, int n) { - uint16_t result = 0; - int i; - for (i = 0; i < n; i++, x >>= 1) - result = (result << 1) | (x & 1U); - return result; -} - -/*** - * dir = forward: 0, inverse: 1 - * https://www.nayuki.io/res/free-small-fft-in-multiple-languages/fft.c - */ -static void fft256(float array[][2], const uint8_t dir) { - const uint16_t n = 256; - const uint8_t levels = 8; // log2(n) - - const uint8_t real = dir & 1; - const uint8_t imag = ~real & 1; - uint16_t i; - uint16_t size; - - for (i = 0; i < n; i++) { - uint16_t j = reverse_bits(i, levels); - if (j > i) { - float temp = array[i][real]; - array[i][real] = array[j][real]; - array[j][real] = temp; - temp = array[i][imag]; - array[i][imag] = array[j][imag]; - array[j][imag] = temp; - } - } - - // Cooley-Tukey decimation-in-time radix-2 FFT - for (size = 2; size <= n; size *= 2) { - uint16_t halfsize = size / 2; - uint16_t tablestep = n / size; - uint16_t i; - for (i = 0; i < n; i += size) { - uint16_t j, k; - for (j = i, k = 0; j < i + halfsize; j++, k += tablestep) { - uint16_t l = j + halfsize; - float tpre = array[l][real] * cos(2 * VNA_PI * k / 256) + array[l][imag] * sin(2 * VNA_PI * k / 256); - float tpim = -array[l][real] * sin(2 * VNA_PI * k / 256) + array[l][imag] * cos(2 * VNA_PI * k / 256); - array[l][real] = array[j][real] - tpre; - array[l][imag] = array[j][imag] - tpim; - array[j][real] += tpre; - array[j][imag] += tpim; - } - } - if (size == n) // Prevent overflow in 'size *= 2' - break; - } -} - -static inline void fft256_forward(float array[][2]) { - fft256(array, 0); -} - -static inline void fft256_inverse(float array[][2]) { - fft256(array, 1); -} diff --git a/flash.c b/flash.c index a66315d..62dc281 100644 --- a/flash.c +++ b/flash.c @@ -120,48 +120,62 @@ config_recall(void) return 0; } -const uint32_t saveareas[SAVEAREA_MAX] = { +const uint32_t saveareas[SAVEAREA_MAX] = +{ SAVE_PROP_CONFIG_0_ADDR, SAVE_PROP_CONFIG_1_ADDR, SAVE_PROP_CONFIG_2_ADDR, SAVE_PROP_CONFIG_3_ADDR, - SAVE_PROP_CONFIG_4_ADDR }; + SAVE_PROP_CONFIG_4_ADDR, + SAVE_PROP_CONFIG_5_ADDR, + SAVE_PROP_CONFIG_6_ADDR, + SAVE_PROP_CONFIG_7_ADDR, + SAVE_PROP_CONFIG_8_ADDR, +}; int16_t lastsaveid = 0; int caldata_save(int id) { - uint16_t *src = (uint16_t*)¤t_props; + uint16_t *src = (uint16_t*)&setting; uint16_t *dst; - int count = sizeof(properties_t) / sizeof(uint16_t); + int count = sizeof(setting_t) / sizeof(uint16_t); if (id < 0 || id >= SAVEAREA_MAX) return -1; dst = (uint16_t*)saveareas[id]; - current_props.magic = CONFIG_MAGIC; - current_props.checksum = checksum( - ¤t_props, sizeof current_props - sizeof current_props.checksum); + setting.magic = CONFIG_MAGIC; + setting.checksum = checksum( + &setting, sizeof setting - sizeof setting.checksum); flash_unlock(); /* erase flash pages */ void *p = dst; - void *tail = p + sizeof(properties_t); + void *tail = p + sizeof(setting_t); while (p < tail) { flash_erase_page((uint32_t)p); p += FLASH_PAGESIZE; } - /* write to flahs */ + /* write to flash */ + while (count-- > 0) { + flash_program_half_word((uint32_t)dst, *src++); + dst++; + } + + // Flash stored trace + count = sizeof(stored_t) / sizeof(uint16_t); + src = (uint16_t*)&stored_t[0]; while (count-- > 0) { flash_program_half_word((uint32_t)dst, *src++); dst++; } /* after saving data, make active configuration points to flash */ - active_props = (properties_t*)saveareas[id]; +// active_props = (setting_t*)saveareas[id]; lastsaveid = id; return 0; @@ -170,39 +184,42 @@ caldata_save(int id) int caldata_recall(int id) { - properties_t *src; - void *dst = ¤t_props; + setting_t *src; + void *dst = &setting; if (id < 0 || id >= SAVEAREA_MAX) - goto load_default; + return -1; // point to saved area on the flash memory - src = (properties_t*)saveareas[id]; + src = (setting_t*)saveareas[id]; if (src->magic != CONFIG_MAGIC) - goto load_default; - if (checksum(src, sizeof *src - sizeof src->checksum) != src->checksum) - goto load_default; + return -1; + if (checksum(src, sizeof setting - sizeof src->checksum) != src->checksum) + return -1; /* active configuration points to save data on flash memory */ - active_props = src; +// active_props = src; lastsaveid = id; /* duplicated saved data onto sram to be able to modify marker/trace */ - memcpy(dst, src, sizeof(properties_t)); + memcpy(dst, src, sizeof(setting_t)); + // Restore stored trace + memcpy(stored_t, &src[1], sizeof(stored_t)); + + update_frequencies(); + set_scale(setting.scale); + set_reflevel(setting.reflevel); return 0; -load_default: - load_default_properties(); - return -1; } - -const properties_t * +#if 0 +const setting_t * caldata_ref(int id) { - const properties_t *src; + const setting_t *src; if (id < 0 || id >= SAVEAREA_MAX) return NULL; - src = (const properties_t*)saveareas[id]; + src = (const setting_t*)saveareas[id]; if (src->magic != CONFIG_MAGIC) return NULL; @@ -210,6 +227,7 @@ caldata_ref(int id) return NULL; return src; } +#endif const uint32_t save_config_prop_area_size = SAVE_CONFIG_AREA_SIZE; diff --git a/halconf.h b/halconf.h index 38341a0..af6c283 100644 --- a/halconf.h +++ b/halconf.h @@ -76,14 +76,14 @@ * @brief Enables the I2C subsystem. */ #if !defined(HAL_USE_I2C) || defined(__DOXYGEN__) -#define HAL_USE_I2C TRUE +#define HAL_USE_I2C FALSE #endif /** * @brief Enables the I2S subsystem. */ #if !defined(HAL_USE_I2S) || defined(__DOXYGEN__) -#define HAL_USE_I2S TRUE +#define HAL_USE_I2S FALSE #endif /** @@ -132,7 +132,7 @@ * @brief Enables the SERIAL subsystem. */ #if !defined(HAL_USE_SERIAL) || defined(__DOXYGEN__) -#define HAL_USE_SERIAL FALSE +#define HAL_USE_SERIAL TRUE #endif /** diff --git a/ili9341.c b/ili9341.c index f1e4674..5496c3c 100644 --- a/ili9341.c +++ b/ili9341.c @@ -27,8 +27,8 @@ uint16_t foreground_color = 0; uint16_t background_color = 0; // Display width and height definition -#define ILI9341_WIDTH 320 -#define ILI9341_HEIGHT 240 +#define ILI9341_WIDTH LCD_WIDTH +#define ILI9341_HEIGHT LCD_HEIGHT // Display commands list #define ILI9341_NOP 0x00 @@ -294,9 +294,11 @@ static const uint8_t ili9341_init_seq[] = { // POWER_CONTROL_2 ILI9341_POWER_CONTROL_2, 1, 0x11, // VCOM_CONTROL_1 - ILI9341_VCOM_CONTROL_1, 2, 0x35, 0x3E, +// ILI9341_VCOM_CONTROL_1, 2, 0x35, 0x3E, + ILI9341_VCOM_CONTROL_1, 2, 0x3e, 0x28, // VCOM_CONTROL_2 ILI9341_VCOM_CONTROL_2, 1, 0xBE, +// ILI9341_VCOM_CONTROL_2, 1, 0x86, // MEMORY_ACCESS_CONTROL //ILI9341_MEMORY_ACCESS_CONTROL, 1, 0x48, // portlait ILI9341_MEMORY_ACCESS_CONTROL, 1, DISPLAY_ROTATION_0, // landscape @@ -309,9 +311,9 @@ static const uint8_t ili9341_init_seq[] = { // gamma set for curve 01/2/04/08 ILI9341_GAMMA_SET, 1, 0x01, // positive gamma correction -//ILI9341_POSITIVE_GAMMA_CORRECTION, 15, 0x1F, 0x1A, 0x18, 0x0A, 0x0F, 0x06, 0x45, 0x87, 0x32, 0x0A, 0x07, 0x02, 0x07, 0x05, 0x00, +ILI9341_POSITIVE_GAMMA_CORRECTION, 15, 0x1F, 0x1A, 0x18, 0x0A, 0x0F, 0x06, 0x45, 0x87, 0x32, 0x0A, 0x07, 0x02, 0x07, 0x05, 0x00, // negativ gamma correction -//ILI9341_NEGATIVE_GAMMA_CORRECTION, 15, 0x00, 0x25, 0x27, 0x05, 0x10, 0x09, 0x3A, 0x78, 0x4D, 0x05, 0x18, 0x0D, 0x38, 0x3A, 0x1F, +ILI9341_NEGATIVE_GAMMA_CORRECTION, 15, 0x00, 0x25, 0x27, 0x05, 0x10, 0x09, 0x3A, 0x78, 0x4D, 0x05, 0x18, 0x0D, 0x38, 0x3A, 0x1F, // Column Address Set //ILI9341_COLUMN_ADDRESS_SET, 4, 0x00, 0x00, 0x01, 0x3f, // width 320 // Page Address Set @@ -383,41 +385,8 @@ void ili9341_bulk(int x, int y, int w, int h) SPI_WRITE_16BIT(*buf++); } } - -static uint8_t ssp_sendrecvdata(void) -{ - // Start RX clock (by sending data) - SPI_WRITE_8BIT(0); - while (SPI_RX_IS_EMPTY && SPI_IS_BUSY) - ; - return SPI_READ_DATA; -} - -void ili9341_read_memory(int x, int y, int w, int h, int len, uint16_t *out) -{ - // uint8_t xx[4] = { x >> 8, x, (x+w-1) >> 8, (x+w-1) }; - // uint8_t yy[4] = { y >> 8, y, (y+h-1) >> 8, (y+h-1) }; - uint32_t xx = __REV16(x | ((x + w - 1) << 16)); - uint32_t yy = __REV16(y | ((y + h - 1) << 16)); - send_command(ILI9341_COLUMN_ADDRESS_SET, 4, (uint8_t *)&xx); - send_command(ILI9341_PAGE_ADDRESS_SET, 4, (uint8_t*)&yy); - send_command(ILI9341_MEMORY_READ, 0, NULL); - - // Skip data from rx buffer - while (SPI_RX_IS_NOT_EMPTY) - (void) SPI_READ_DATA; - // require 8bit dummy clock - ssp_sendrecvdata(); - while (len-- > 0) { - // read data is always 18bit - uint8_t r = ssp_sendrecvdata(); - uint8_t g = ssp_sendrecvdata(); - uint8_t b = ssp_sendrecvdata(); - *out++ = RGB565(r, g, b); - } - CS_HIGH; -} #else + // // Use DMA for send data // @@ -469,7 +438,7 @@ void ili9341_bulk(int x, int y, int w, int h) STM32_DMA_CR_MSIZE_HWORD | STM32_DMA_CR_MINC); dmaStreamFlush(w * h); } - +#if 1 // Read DMA hangs // Copy screen data to buffer // Warning!!! buffer size must be greater then 3*len + 1 bytes void ili9341_read_memory(int x, int y, int w, int h, int len, uint16_t *out) @@ -485,6 +454,7 @@ void ili9341_read_memory(int x, int y, int w, int h, int len, uint16_t *out) // Skip SPI rx buffer while (SPI_RX_IS_NOT_EMPTY) (void)SPI_READ_DATA; // Init Rx DMA buffer, size, mode (spi and mem data size is 8 bit) + chSysLock(); dmaStreamSetMemory0(dmarx, rgbbuf); dmaStreamSetTransactionSize(dmarx, data_size); dmaStreamSetMode(dmarx, rxdmamode | STM32_DMA_CR_PSIZE_BYTE | STM32_DMA_CR_MSIZE_BYTE | @@ -499,7 +469,18 @@ void ili9341_read_memory(int x, int y, int w, int h, int len, uint16_t *out) dmaStreamEnable(dmarx); // Wait DMA completion dmaWaitCompletion(dmatx); +#if 0 + int count = 0; + while ((dmarx)->channel->CNDTR > 0U) { + chThdSleepMicroseconds(100); + if (count++ > 10) + break; + } + dmaStreamDisable(dmarx); +#else dmaWaitCompletion(dmarx); +#endif + chSysUnlock(); CS_HIGH; // Parce recived data @@ -515,13 +496,49 @@ void ili9341_read_memory(int x, int y, int w, int h, int len, uint16_t *out) rgbbuf += 3; } } +#else +static uint8_t ssp_sendrecvdata(void) +{ + // Start RX clock (by sending data) + SPI_WRITE_8BIT(0); + while (SPI_RX_IS_EMPTY && SPI_IS_BUSY) + ; + return SPI_READ_DATA; +} + +void ili9341_read_memory(int x, int y, int w, int h, int len, uint16_t *out) +{ + // uint8_t xx[4] = { x >> 8, x, (x+w-1) >> 8, (x+w-1) }; + // uint8_t yy[4] = { y >> 8, y, (y+h-1) >> 8, (y+h-1) }; + uint32_t xx = __REV16(x | ((x + w - 1) << 16)); + uint32_t yy = __REV16(y | ((y + h - 1) << 16)); + send_command(ILI9341_COLUMN_ADDRESS_SET, 4, (uint8_t *)&xx); + send_command(ILI9341_PAGE_ADDRESS_SET, 4, (uint8_t*)&yy); + send_command(ILI9341_MEMORY_READ, 0, NULL); + + // Skip data from rx buffer + while (SPI_RX_IS_NOT_EMPTY) + (void) SPI_READ_DATA; + // require 8bit dummy clock + ssp_sendrecvdata(); + while (len-- > 0) { + // read data is always 18bit + uint8_t r = ssp_sendrecvdata(); + uint8_t g = ssp_sendrecvdata(); + uint8_t b = ssp_sendrecvdata(); + *out++ = RGB565(r, g, b); + } + CS_HIGH; +} + +#endif #endif void ili9341_clear_screen(void) { ili9341_fill(0, 0, ILI9341_WIDTH, ILI9341_HEIGHT, background_color); } - +#if 0 void ili9341_set_foreground(uint16_t fg) { foreground_color = fg; @@ -531,7 +548,7 @@ void ili9341_set_background(uint16_t bg) { background_color = bg; } - +#endif void ili9341_set_rotation(uint8_t r) { // static const uint8_t rotation_const[]={DISPLAY_ROTATION_0, DISPLAY_ROTATION_90, @@ -553,7 +570,7 @@ void blit8BitWidthBitmap(uint16_t x, uint16_t y, uint16_t width, uint16_t height ili9341_bulk(x, y, width, height); } -static void blit16BitWidthBitmap(uint16_t x, uint16_t y, uint16_t width, uint16_t height, +void blit16BitWidthBitmap(uint16_t x, uint16_t y, uint16_t width, uint16_t height, const uint16_t *bitmap) { uint16_t *buf = spi_buffer; @@ -567,6 +584,12 @@ static void blit16BitWidthBitmap(uint16_t x, uint16_t y, uint16_t width, uint16_ ili9341_bulk(x, y, width, height); } +int ili9341_size = 1; + +void ili9341_charsize(int s) +{ + ili9341_size = s; +} void ili9341_drawchar(uint8_t ch, int x, int y) { blit8BitWidthBitmap(x, y, FONT_GET_WIDTH(ch), FONT_GET_HEIGHT, FONT_GET_DATA(ch)); @@ -583,6 +606,16 @@ void ili9341_drawstring(const char *str, int x, int y) } } +void ili9341_drawstring_7x13(const char *str, int x, int y) +{ + while (*str) { + uint8_t ch = *str++; + const uint16_t *char_buf = &x7x13b_bits[(ch * 13)]; // All chars start at row 2 + blit16BitWidthBitmap(x, y, 7, 13, char_buf); // Only 'Q' has 12 rows, 'g' requires 13 rows + x += 7; + } +} + void ili9341_drawstringV(const char *str, int x, int y) { ili9341_set_rotation(DISPLAY_ROTATION_270); @@ -693,15 +726,15 @@ void ili9341_test(int mode) switch (mode) { default: #if 1 - ili9341_fill(0, 0, 320, 240, 0); - for (y = 0; y < 240; y++) { - ili9341_fill(0, y, 320, 1, RGB(240-y, y, (y + 120) % 256)); + ili9341_fill(0, 0, LCD_WIDTH, LCD_HEIGHT, 0); + for (y = 0; y < LCD_HEIGHT; y++) { + ili9341_fill(0, y, LCD_WIDTH, 1, RGB(LCD_HEIGHT-y, y, (y + 120) % 256)); } break; case 1: - ili9341_fill(0, 0, 320, 240, 0); - for (y = 0; y < 240; y++) { - for (x = 0; x < 320; x++) { + ili9341_fill(0, 0, LCD_WIDTH, LCD_HEIGHT, 0); + for (y = 0; y < LCD_HEIGHT; y++) { + for (x = 0; x < LCD_WIDTH; x++) { ili9341_pixel(x, y, (y<<8)|x); } } diff --git a/main.c b/main.c index 91f475c..40efb1d 100644 --- a/main.c +++ b/main.c @@ -1,6 +1,4 @@ /* - * Copyright (c) 2016-2017, TAKAHASHI Tomohiro (TTRFTECH) edy555@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 @@ -17,18 +15,34 @@ * the Free Software Foundation, Inc., 51 Franklin Street, * Boston, MA 02110-1301, USA. */ +//#define HAL_USE_SERIAL 1 +//#define STM32_SERIAL_USE_USART1 1 #include "ch.h" #include "hal.h" + +//#include "hal_serial.h" + #include "usbcfg.h" +#ifdef __VNA__ #include "si5351.h" +#endif #include "nanovna.h" +#ifdef __VNA__ #include "fft.h" +#endif #include #include #include +extern float minFreq; +extern float maxFreq; +float frequencyStart; +float frequencyStop; +int32_t frequencyExtra; +#define START_MIN minFreq +#define STOP_MAX maxFreq /* * Shell settings */ @@ -60,7 +74,7 @@ static volatile vna_shellcmd_t shell_function = 0; //#define ENABLED_DUMP // Allow get threads debug info -//#define ENABLE_THREADS_COMMAND +#define ENABLE_THREADS_COMMAND // RTC time not used //#define ENABLE_TIME_COMMAND // Enable vbat_offset command, allow change battery voltage correction in config @@ -69,13 +83,15 @@ static volatile vna_shellcmd_t shell_function = 0; #define ENABLE_INFO_COMMAND // Enable color command, allow change config color for traces, grid, menu #define ENABLE_COLOR_COMMAND - +#ifdef __VNA__ static void apply_error_term_at(int i); static void apply_edelay_at(int i); static void cal_interpolate(int s); -static void update_frequencies(void); +#endif +void update_frequencies(void); static void set_frequencies(uint32_t start, uint32_t stop, uint16_t points); static bool sweep(bool break_on_operation); +#ifdef __VNA__ static void transform_domain(void); #define DRIVE_STRENGTH_AUTO (-1) @@ -85,14 +101,16 @@ static void transform_domain(void); #define cal_auto_interpolate TRUE static int8_t drive_strength = DRIVE_STRENGTH_AUTO; +#endif int8_t sweep_mode = SWEEP_ENABLE; volatile uint8_t redraw_request = 0; // contains REDRAW_XXX flags // Version text, displayed in Config->Version menu, also send by info command const char *info_about[]={ BOARD_NAME, + "2019-2020 Copyright @Erik Kaashoek", "2016-2020 Copyright @edy555", - "Licensed under GPL. See: https://github.com/ttrftech/NanoVNA", + "SW licensed under GPL. See: https://github.com/erikkaashoek/tinySA", "Version: " VERSION, "Build Time: " __DATE__ " - " __TIME__, "Kernel: " CH_KERNEL_VERSION, @@ -102,20 +120,36 @@ const char *info_about[]={ "Platform: " PLATFORM_NAME, 0 // sentinel }; +extern int dirty; + +bool completed = false; -static THD_WORKING_AREA(waThread1, 640); +static THD_WORKING_AREA(waThread1, 900); static THD_FUNCTION(Thread1, arg) { (void)arg; chRegSetThreadName("sweep"); + ui_process(); + while (1) { - bool completed = false; if (sweep_mode&(SWEEP_ENABLE|SWEEP_ONCE)) { - completed = sweep(true); +// if (dirty) + completed = sweep(true); sweep_mode&=~SWEEP_ONCE; + } else if (sweep_mode & SWEEP_SELFTEST) { + // call from lowest level to save stack space + self_test(setting.test); + sweep_mode = SWEEP_ENABLE; + } else if (sweep_mode & SWEEP_REMOTE) { + sweep_remote(); + } else if (sweep_mode & SWEEP_CALIBRATE) { + // call from lowest level to save stack space + calibrate(); + sweep_mode = SWEEP_ENABLE; } else { - __WFI(); +// if (setting.mode != -1) + __WFI(); } // Run Shell command in sweep thread if (shell_function) { @@ -128,8 +162,10 @@ static THD_FUNCTION(Thread1, arg) ui_process(); // Process collected data, calculate trace coordinates and plot only if scan // completed - if (sweep_mode & SWEEP_ENABLE && completed) { + if (/* sweep_mode & SWEEP_ENABLE && */ completed) { +#ifdef __VNA__ if ((domain_mode & DOMAIN_MODE) == DOMAIN_TIME) transform_domain(); +#endif // Prepare draw graphics, cache all lines, mark screen cells for redraw plot_into_index(measured); redraw_request |= REDRAW_CELLS | REDRAW_BATTERY; @@ -148,6 +184,12 @@ static THD_FUNCTION(Thread1, arg) } } +int +is_paused(void) +{ + return !(sweep_mode & SWEEP_ENABLE); +} + static inline void pause_sweep(void) { @@ -166,6 +208,7 @@ toggle_sweep(void) sweep_mode ^= SWEEP_ENABLE; } +#ifdef __VNA__ static float bessel0(float x) { @@ -261,9 +304,10 @@ transform_domain(void) } } } +#endif // Shell commands output -static int shell_printf(const char *fmt, ...) +int shell_printf(const char *fmt, ...) { va_list ap; int formatted_bytes; @@ -287,9 +331,10 @@ VNA_SHELL_FUNCTION(cmd_resume) // restore frequencies array and cal update_frequencies(); +#ifdef __VNA__ if (cal_auto_interpolate && (cal_status & CALSTAT_APPLY)) cal_interpolate(lastsaveid); - +#endif resume_sweep(); } @@ -316,6 +361,7 @@ VNA_SHELL_FUNCTION(cmd_reset) ; } +#ifdef __VNA__ const int8_t gain_table[] = { 0, // 0 ~ 300MHz 40, // 300 ~ 600MHz @@ -341,9 +387,12 @@ adjust_gain(uint32_t newfreq) } return 0; } +#endif int set_frequency(uint32_t freq) { + (void) freq; +#ifdef __VNA__ int delay = adjust_gain(freq); int8_t ds = drive_strength; if (ds == DRIVE_STRENGTH_AUTO) { @@ -351,6 +400,8 @@ int set_frequency(uint32_t freq) } delay += si5351_set_frequency(freq, ds); return delay; +#endif + return 1; } // Use macro, std isdigit more big @@ -368,6 +419,11 @@ static int32_t my_atoi(const char *p) if (*p == '+') p++; while ((c = *p++ - '0') < 10) value = value * 10 + c; + switch (*(--p)) { + case 'k': value *= 1000; break; + case 'M': value *= 1000000; break; + case 'G': value *= 1000000000; break; + } return neg ? -value : value; } @@ -431,6 +487,16 @@ my_atof(const char *p) exp++; } } + switch (*p) { + case 'k': x *= 1e+3; break; + case 'M': x *= 1e+6; break; + case 'G': x *= 1e+9; break; + case 'm': x /= 1e+3; break; + case 'u': x /= 1e+6; break; + case 'n': x /= 1e+9; break; + case 'p': x /= 1e+12; break; + } + if (neg) x = -x; return x; @@ -467,7 +533,7 @@ static int get_str_index(char *v, const char *list) } return -1; } - +#ifdef __VNA__ VNA_SHELL_FUNCTION(cmd_offset) { if (argc != 1) { @@ -476,6 +542,7 @@ VNA_SHELL_FUNCTION(cmd_offset) } si5351_set_frequency_offset(my_atoi(argv[0])); } +#endif VNA_SHELL_FUNCTION(cmd_freq) { @@ -490,16 +557,18 @@ VNA_SHELL_FUNCTION(cmd_freq) usage: shell_printf("usage: freq {frequency(Hz)}\r\n"); } - +#ifdef __VNA__ VNA_SHELL_FUNCTION(cmd_power) { if (argc != 1) { shell_printf("usage: power {0-3|-1}\r\n"); return; } + (void)argv; drive_strength = my_atoi(argv[0]); // set_frequency(frequency); } +#endif #ifdef ENABLE_TIME_COMMAND #if HAL_USE_RTC == FALSE @@ -528,6 +597,7 @@ VNA_SHELL_FUNCTION(cmd_dac) dacPutChannelX(&DACD2, 0, value); } +#ifdef __VNA__ VNA_SHELL_FUNCTION(cmd_threshold) { uint32_t value; @@ -539,6 +609,7 @@ VNA_SHELL_FUNCTION(cmd_threshold) value = my_atoui(argv[0]); config.harmonic_freq_threshold = value; } +#endif VNA_SHELL_FUNCTION(cmd_saveconfig) { @@ -565,6 +636,7 @@ VNA_SHELL_FUNCTION(cmd_clearconfig) "Do reset manually to take effect. Then do touch cal and save.\r\n"); } +#ifdef __VNA__ static struct { int16_t rms[2]; int16_t ave[2]; @@ -596,22 +668,9 @@ const int8_t bandwidth_accumerate_count[] = { }; float measured[2][POINTS_COUNT][2]; - -static inline void -dsp_start(int count) -{ - wait_count = count; - accumerate_count = bandwidth_accumerate_count[bandwidth]; - reset_dsp_accumerator(); -} - -static inline void -dsp_wait(void) -{ - while (accumerate_count > 0) - __WFI(); -} - +#endif +measurement_t measured; +#ifdef __VNA__ #ifdef ENABLED_DUMP static void duplicate_buffer_to_dump(int16_t *p) @@ -664,26 +723,23 @@ static const I2SConfig i2sconfig = { 0, // i2scfgr 2 // i2spr }; +#endif +#define MAX_DATA 2 VNA_SHELL_FUNCTION(cmd_data) { int i; int sel = 0; - float (*array)[2]; if (argc == 1) sel = my_atoi(argv[0]); - if (sel == 0 || sel == 1) - array = measured[sel]; - else if (sel >= 2 && sel < 7) - array = cal_data[sel-2]; - else - goto usage; - for (i = 0; i < sweep_points; i++) - shell_printf("%f %f\r\n", array[i][0], array[i][1]); - return; -usage: - shell_printf("usage: data [array]\r\n"); + + if (sel >= 0 && sel <= MAX_DATA) { + for (i = 0; i < sweep_points; i++) + shell_printf("%f\r\n", measured[sel][i]); + return; + } + shell_printf("usage: data [0-2]\r\n"); } #ifdef ENABLED_DUMP @@ -715,15 +771,15 @@ VNA_SHELL_FUNCTION(cmd_capture) (void)argc; (void)argv; int i, y; -#if SPI_BUFFER_SIZE < (3*320 + 1) +#if SPI_BUFFER_SIZE < (3*LCD_WIDTH + 1) #error "Low size of spi_buffer for cmd_capture" #endif // read 2 row pixel time (read buffer limit by 2/3 + 1 from spi_buffer size) - for (y = 0; y < 240; y += 2) { + for (y = 0; y < LCD_HEIGHT; y += 2) { // use uint16_t spi_buffer[2048] (defined in ili9341) for read buffer uint8_t *buf = (uint8_t *)spi_buffer; - ili9341_read_memory(0, y, 320, 2, 2 * 320, spi_buffer); - for (i = 0; i < 4 * 320; i++) { + ili9341_read_memory(0, y, LCD_WIDTH, 2, 2 * LCD_WIDTH, spi_buffer); + for (i = 0; i < 4 * LCD_WIDTH; i++) { streamPut(shell_stream, *buf++); } } @@ -745,7 +801,7 @@ VNA_SHELL_FUNCTION(cmd_gamma) shell_printf("%d %d\r\n", gamma[0], gamma[1]); } #endif - +#ifdef __VNA__ static void (*sample_func)(float *gamma) = calculate_gamma; VNA_SHELL_FUNCTION(cmd_sample) @@ -769,34 +825,42 @@ VNA_SHELL_FUNCTION(cmd_sample) usage: shell_printf("usage: sample {%s}\r\n", cmd_sample_list); } - +#endif config_t config = { .magic = CONFIG_MAGIC, .dac_value = 1922, .grid_color = DEFAULT_GRID_COLOR, .menu_normal_color = DEFAULT_MENU_COLOR, .menu_active_color = DEFAULT_MENU_ACTIVE_COLOR, - .trace_color = { DEFAULT_TRACE_1_COLOR, DEFAULT_TRACE_2_COLOR, DEFAULT_TRACE_3_COLOR, DEFAULT_TRACE_4_COLOR }, + .trace_color = { DEFAULT_TRACE_1_COLOR, DEFAULT_TRACE_2_COLOR, DEFAULT_TRACE_3_COLOR}, // .touch_cal = { 693, 605, 124, 171 }, // 2.4 inch LCD panel .touch_cal = { 338, 522, 153, 192 }, // 2.8 inch LCD panel .freq_mode = FREQ_MODE_START_STOP, +#ifdef __VNA__ .harmonic_freq_threshold = 300000000, - .vbat_offset = 500 +#endif + .vbat_offset = 500, + .low_level_offset = 100, // Uncalibrated + .high_level_offset = 100, // Uncalibrated + .correction_frequency = { 100000, 200000, 400000, 1000000, 2000000, 50000000, 100000000, 200000000, 300000000, 350000000 }, + .correction_value = { +4.0, +2.0, +1.5, +0.5, 0.0, 0.0, +1.0, +1.0, +2.5, +5.0 }, }; -properties_t current_props; -properties_t *active_props = ¤t_props; +//properties_t current_props; +//properties_t *active_props = ¤t_props; // NanoVNA Default settings static const trace_t def_trace[TRACES_MAX] = {//enable, type, channel, reserved, scale, refpos - { 1, TRC_LOGMAG, 0, 0, 10.0, NGRIDY-1 }, - { 1, TRC_LOGMAG, 1, 0, 10.0, NGRIDY-1 }, - { 1, TRC_SMITH, 0, 0, 1.0, 0 }, - { 1, TRC_PHASE, 1, 0, 90.0, NGRIDY/2 } + { 0, TRC_LOGMAG, 0, 0, 10.0, (float) NGRIDY+1 }, //Temp + { 0, TRC_LOGMAG, 1, 0, 10.0, (float) NGRIDY+1 }, //Stored + { 1, TRC_LOGMAG, 2, 0, 10.0, (float) NGRIDY+1 } //Actual }; static const marker_t def_markers[MARKERS_MAX] = { - { 1, 30, 0 }, { 0, 40, 0 }, { 0, 60, 0 }, { 0, 80, 0 } + { M_ENABLED, M_REFERENCE | M_TRACKING, 30, 0 }, + { M_DISABLED, M_NORMAL, 40, 0 }, + { M_DISABLED, M_NORMAL, 60, 0 }, + { M_DISABLED, M_NORMAL, 80, 0 } }; // Load propeties default settings @@ -804,28 +868,38 @@ void load_default_properties(void) { //Magic add on caldata_save //current_props.magic = CONFIG_MAGIC; - current_props._frequency0 = 50000; // start = 50kHz - current_props._frequency1 = 900000000; // end = 900MHz - current_props._sweep_points = POINTS_COUNT; - current_props._cal_status = 0; +// current_props._setting.frequency0 = 0; // start = 0Hz +// current_props._setting.frequency1 = 350000000; // end = 350MHz +// current_props._setting.frequency_IF= 433800000, + + setting._sweep_points = POINTS_COUNT; + #ifdef VNA__ + setting._cal_status = 0; //This data not loaded by default -//current_props._frequencies[POINTS_COUNT]; -//current_props._cal_data[5][POINTS_COUNT][2]; +//setting._frequencies[POINTS_COUNT]; +//setting._cal_data[5][POINTS_COUNT][2]; //============================================= - current_props._electrical_delay = 0.0; - memcpy(current_props._trace, def_trace, sizeof(def_trace)); - memcpy(current_props._markers, def_markers, sizeof(def_markers)); - current_props._velocity_factor = 0.7; - current_props._active_marker = 0; - current_props._domain_mode = 0; - current_props._marker_smith_format = MS_RLC; + setting._electrical_delay = 0.0; +#endif + memcpy(setting._trace, def_trace, sizeof(def_trace)); + memcpy(setting._markers, def_markers, sizeof(def_markers)); +#ifdef __VNA__ + setting._velocity_factor = 0.7; +#endif + setting._active_marker = 0; +#ifdef __VNA__ + setting._domain_mode = 0; + setting._marker_smith_format = MS_RLC; +#endif + reset_settings(M_LOW); //Checksum add on caldata_save -//current_props.checksum = 0; +//setting.checksum = 0; } void ensure_edit_config(void) { +#ifdef __VNA__ if (active_props == ¤t_props) return; @@ -833,8 +907,14 @@ ensure_edit_config(void) active_props = ¤t_props; // move to uncal state cal_status = 0; +#endif } +#include "sa_core.c" +#ifdef __VNA__ +#define DSP_START(delay) wait_count = delay; +#define DSP_WAIT_READY while (wait_count) __WFI(); + #define DELAY_CHANNEL_CHANGE 2 // main loop for measurement @@ -842,7 +922,7 @@ bool sweep(bool break_on_operation) { int i, delay; // blink LED while scanning - palClearPad(GPIOC, GPIOC_LED); + palClearPad(GPIOB, GPIOB_LED); // Power stabilization after LED off, also align timings on i == 0 for (i = 0; i < sweep_points; i++) { // 5300 if (frequencies[i] == 0) break; @@ -876,9 +956,10 @@ bool sweep(bool break_on_operation) return false; } // blink LED while scanning - palSetPad(GPIOC, GPIOC_LED); + palSetPad(GPIOB, GPIOB_LED); return true; } +#endif VNA_SHELL_FUNCTION(cmd_scan) { @@ -892,7 +973,7 @@ VNA_SHELL_FUNCTION(cmd_scan) start = my_atoui(argv[0]); stop = my_atoui(argv[1]); - if (start == 0 || stop == 0 || start > stop) { + if (start > stop) { shell_printf("frequency range is invalid\r\n"); return; } @@ -905,8 +986,10 @@ VNA_SHELL_FUNCTION(cmd_scan) } set_frequencies(start, stop, points); +#ifdef __VNA__ if (cal_auto_interpolate && (cal_status & CALSTAT_APPLY)) cal_interpolate(lastsaveid); +#endif pause_sweep(); sweep(false); // Output data after if set (faster data recive) @@ -915,8 +998,9 @@ VNA_SHELL_FUNCTION(cmd_scan) if (mask) { for (i = 0; i < points; i++) { if (mask & 1) shell_printf("%u ", frequencies[i]); - if (mask & 2) shell_printf("%f %f ", measured[0][i][0], measured[0][i][1]); - if (mask & 4) shell_printf("%f %f ", measured[1][i][0], measured[1][i][1]); + if (mask & 2) shell_printf("%f ", measured[0][i]); + if (mask & 4) shell_printf("%f ", measured[1][i]); + if (mask & 8) shell_printf("%f ", measured[2][i]); shell_printf("\r\n"); } } @@ -971,9 +1055,11 @@ set_frequencies(uint32_t start, uint32_t stop, uint16_t points) // disable at out of sweep range for (; i < POINTS_COUNT; i++) frequencies[i] = 0; + setting.frequency_step = delta; + update_rbw(); } -static void +void update_frequencies(void) { uint32_t start, stop; @@ -992,7 +1078,9 @@ update_frequencies(void) void set_sweep_frequency(int type, uint32_t freq) { +#ifdef __VNA__ int cal_applied = cal_status & CALSTAT_APPLY; +#endif // Check frequency for out of bounds (minimum SPAN can be any value) if (type != ST_SPAN && freq < START_MIN) @@ -1003,78 +1091,80 @@ set_sweep_frequency(int type, uint32_t freq) ensure_edit_config(); switch (type) { case ST_START: - config.freq_mode &= ~FREQ_MODE_CENTER_SPAN; - if (frequency0 != freq) { - frequency0 = freq; + setting.freq_mode &= ~FREQ_MODE_CENTER_SPAN; + if (setting.frequency0 != freq) { + setting.frequency0 = freq; // if start > stop then make start = stop - if (frequency1 < freq) frequency1 = freq; + if (setting.frequency1 < freq) setting.frequency1 = freq; } break; case ST_STOP: - config.freq_mode &= ~FREQ_MODE_CENTER_SPAN; - if (frequency1 != freq) { - frequency1 = freq; + setting.freq_mode &= ~FREQ_MODE_CENTER_SPAN; + if (setting.frequency1 != freq) { + setting.frequency1 = freq; // if start > stop then make start = stop - if (frequency0 > freq) frequency0 = freq; + if (setting.frequency0 > freq) setting.frequency0 = freq; } break; case ST_CENTER: - config.freq_mode |= FREQ_MODE_CENTER_SPAN; - uint32_t center = frequency0 / 2 + frequency1 / 2; + setting.freq_mode |= FREQ_MODE_CENTER_SPAN; + uint32_t center = setting.frequency0 / 2 + setting.frequency1 / 2; if (center != freq) { - uint32_t span = frequency1 - frequency0; + uint32_t span = setting.frequency1 - setting.frequency0; if (freq < START_MIN + span / 2) { span = (freq - START_MIN) * 2; } if (freq > STOP_MAX - span / 2) { span = (STOP_MAX - freq) * 2; } - frequency0 = freq - span / 2; - frequency1 = freq + span / 2; + setting.frequency0 = freq - span / 2; + setting.frequency1 = freq + span / 2; } break; case ST_SPAN: - config.freq_mode |= FREQ_MODE_CENTER_SPAN; - if (frequency1 - frequency0 != freq) { - uint32_t center = frequency0 / 2 + frequency1 / 2; + setting.freq_mode |= FREQ_MODE_CENTER_SPAN; + if (setting.frequency1 - setting.frequency0 != freq) { + uint32_t center = setting.frequency0 / 2 + setting.frequency1 / 2; if (center < START_MIN + freq / 2) { center = START_MIN + freq / 2; } if (center > STOP_MAX - freq / 2) { center = STOP_MAX - freq / 2; } - frequency0 = center - freq / 2; - frequency1 = center + freq / 2; + setting.frequency0 = center - freq / 2; + setting.frequency1 = center + freq / 2; } break; case ST_CW: - config.freq_mode |= FREQ_MODE_CENTER_SPAN; - if (frequency0 != freq || frequency1 != freq) { - frequency0 = freq; - frequency1 = freq; + setting.freq_mode |= FREQ_MODE_CENTER_SPAN; + if (setting.frequency0 != freq || setting.frequency1 != freq) { + setting.frequency0 = freq; + setting.frequency1 = freq; } break; } update_frequencies(); +#ifdef __VNA__ if (cal_auto_interpolate && cal_applied) cal_interpolate(lastsaveid); +#endif } uint32_t get_sweep_frequency(int type) { // Obsolete, ensure correct start/stop, start always must be < stop - if (frequency0 > frequency1) { - uint32_t t = frequency0; - frequency0 = frequency1; - frequency1 = t; + if (setting.frequency0 > setting.frequency1) { + uint32_t t = setting.frequency0; + setting.frequency0 = setting.frequency1; + setting.frequency1 = t; } switch (type) { - case ST_START: return frequency0; - case ST_STOP: return frequency1; - case ST_CENTER: return frequency0/2 + frequency1/2; - case ST_SPAN: return frequency1 - frequency0; - case ST_CW: return frequency0; + case ST_START: return setting.frequency0; + case ST_STOP: return setting.frequency1; + case ST_CENTER: return setting.frequency0/2 + setting.frequency1/2; + case ST_SPAN: return setting.frequency1 - setting.frequency0; + case ST_CW: return setting.frequency0; } return 0; } @@ -1115,7 +1205,7 @@ usage: "\tsweep {%s} {freq(Hz)}\r\n", sweep_cmd); } - +#ifdef __VNA__ static void eterm_set(int term, float re, float im) { @@ -1532,13 +1622,15 @@ VNA_SHELL_FUNCTION(cmd_recall) usage: shell_printf("recall {id}\r\n"); } +#endif static const struct { const char *name; uint16_t refpos; float scale_unit; } trace_info[] = { - { "LOGMAG", NGRIDY-1, 10.0 }, + { "LOGMAG", NGRIDY, 10.0 }, +#ifdef __VNA__ { "PHASE", NGRIDY/2, 90.0 }, { "DELAY", NGRIDY/2, 1e-9 }, { "SMITH", 0, 1.00 }, @@ -1549,12 +1641,17 @@ static const struct { { "IMAG", NGRIDY/2, 0.25 }, { "R", NGRIDY/2, 100.0 }, { "X", NGRIDY/2, 100.0 } +#endif }; +#ifdef __VNA__ static const char * const trc_channel_name[] = { "CH0", "CH1" }; - +#endif +const char * const trc_channel_name[] = { + "ACTUAL", "STORED", "COMPUTED" +}; const char *get_trace_typename(int t) { return trace_info[trace[t].type].name; @@ -1623,7 +1720,7 @@ VNA_SHELL_FUNCTION(cmd_trace) if (argc == 0) { for (t = 0; t < TRACES_MAX; t++) { if (trace[t].enabled) { - const char *type = get_trace_typename(t); + const char *type = unit_string[setting.unit]; // get_trace_typename(t); const char *channel = trc_channel_name[trace[t].channel]; float scale = get_trace_scale(t); float refpos = get_trace_refpos(t); @@ -1633,63 +1730,78 @@ VNA_SHELL_FUNCTION(cmd_trace) return; } - if (strcmp(argv[0], "all") == 0 && - argc > 1 && strcmp(argv[1], "off") == 0) { - for (t = 0; t < TRACES_MAX; t++) - set_trace_type(t, TRC_OFF); - goto exit; - } - - t = my_atoi(argv[0]); - if (t < 0 || t >= TRACES_MAX) - goto usage; - if (argc == 1) { + if ('0' <= argv[0][0] && argv[0][0] <= '9') { + t = my_atoi(argv[0]); + if (argc != 1 || t < 0 || t >= TRACES_MAX) + goto usage; const char *type = get_trace_typename(t); const char *channel = trc_channel_name[trace[t].channel]; shell_printf("%d %s %s\r\n", t, type, channel); return; } -#if MAX_TRACE_TYPE != 12 -#error "Trace type enum possibly changed, check cmd_trace function" +#if MAX_UNIT_TYPE != 4 +#error "Unit type enum possibly changed, check cmd_trace function" #endif - // enum TRC_LOGMAG, TRC_PHASE, TRC_DELAY, TRC_SMITH, TRC_POLAR, TRC_LINEAR, TRC_SWR, TRC_REAL, TRC_IMAG, TRC_R, TRC_X, TRC_OFF - static const char cmd_type_list[] = "logmag|phase|delay|smith|polar|linear|swr|real|imag|r|x|off"; - int type = get_str_index(argv[1], cmd_type_list); - if (type >= 0) { - set_trace_type(t, type); - goto check_ch_num; + static const char cmd_type_list[] = "dBm|dBmV|dBuV|V|W"; + if (argc == 1) { + int type = get_str_index(argv[0], cmd_type_list); + if (type >= 0) { + set_unit(type); + goto update; + } + goto usage; } - // 0 1 - static const char cmd_scale_ref_list[] = "scale|refpos"; - if (argc >= 3) { - switch (get_str_index(argv[1], cmd_scale_ref_list)) { + static const char cmd_store_list[] = "store|clear|subtract"; + if (argc == 1) { + int type = get_str_index(argv[0], cmd_store_list); + if (type >= 0) { + switch(type) { case 0: - //trace[t].scale = my_atof(argv[2]); - set_trace_scale(t, my_atof(argv[2])); - goto exit; + set_storage(); + goto update; case 1: - //trace[t].refpos = my_atof(argv[2]); - set_trace_refpos(t, my_atof(argv[2])); - goto exit; - default: - goto usage; + set_clear_storage(); + goto update; + case 2: + set_subtract_storage(); + goto update; + } } + goto usage; } -check_ch_num: - if (argc > 2) { - int src = my_atoi(argv[2]); - if (src != 0 && src != 1) - goto usage; - trace[t].channel = src; + // 0 1 + static const char cmd_scale_ref_list[] = "scale|reflevel"; + if (argc == 2) { + switch (get_str_index(argv[0], cmd_scale_ref_list)) { + case 0: + if (strcmp(argv[1],"auto") == 0) { + set_auto_reflevel(true); + } else { + user_set_scale(my_atof(argv[1])); + } + goto update; + case 1: + //trace[t].refpos = my_atof(argv[2]); + if (strcmp(argv[1],"auto") == 0) { + set_auto_reflevel(true); + } else { + user_set_reflevel(my_atof(argv[1])); + } + goto update; + } + goto usage; } -exit: +update: +redraw_request |= REDRAW_CAL_STATUS; return; usage: - shell_printf("trace {0|1|2|3|all} [%s] [src]\r\n"\ - "trace {0|1|2|3} {%s} {value}\r\n", cmd_type_list, cmd_scale_ref_list); + shell_printf("trace {%s}\r\n"\ + "trace {%s}\r\n"\ + "trace {%s} {value|auto}\r\n", cmd_store_list, cmd_type_list, cmd_scale_ref_list); } +#ifdef __VNA__ void set_electrical_delay(float picoseconds) { if (electrical_delay != picoseconds) { @@ -1714,6 +1826,7 @@ VNA_SHELL_FUNCTION(cmd_edelay) set_electrical_delay(my_atof(argv[0])); } } +#endif VNA_SHELL_FUNCTION(cmd_marker) @@ -1722,7 +1835,7 @@ VNA_SHELL_FUNCTION(cmd_marker) if (argc == 0) { for (t = 0; t < MARKERS_MAX; t++) { if (markers[t].enabled) { - shell_printf("%d %d %d\r\n", t+1, markers[t].index, markers[t].frequency); + shell_printf("%d %d %d %.2f\r\n", t+1, markers[t].index, markers[t].frequency, actual_t[markers[t].index]); } } return; @@ -1738,7 +1851,7 @@ VNA_SHELL_FUNCTION(cmd_marker) if (t < 0 || t >= MARKERS_MAX) goto usage; if (argc == 1) { - shell_printf("%d %d %d\r\n", t+1, markers[t].index, markers[t].frequency); + shell_printf("%d %d %d %.2f\r\n", t+1, markers[t].index, markers[t].frequency, actual_t[markers[t].index]); active_marker = t; // select active marker markers[t].enabled = TRUE; @@ -1799,6 +1912,7 @@ VNA_SHELL_FUNCTION(cmd_frequencies) } } +#ifdef __VNA__ static void set_domain_mode(int mode) // accept DOMAIN_FREQ or DOMAIN_TIME { @@ -1863,6 +1977,7 @@ VNA_SHELL_FUNCTION(cmd_transform) usage: shell_printf("usage: transform {%s} [...]\r\n", cmd_transform_list); } +#endif VNA_SHELL_FUNCTION(cmd_test) { @@ -1872,14 +1987,14 @@ VNA_SHELL_FUNCTION(cmd_test) #if 0 int i; for (i = 0; i < 100; i++) { - palClearPad(GPIOC, GPIOC_LED); + palClearPad(GPIOB, GPIOB_LED); set_frequency(10000000); - palSetPad(GPIOC, GPIOC_LED); + palSetPad(GPIOB, GPIOB_LED); chThdSleepMilliseconds(50); - palClearPad(GPIOC, GPIOC_LED); + palClearPad(GPIOB, GPIOB_LED); set_frequency(90000000); - palSetPad(GPIOC, GPIOC_LED); + palSetPad(GPIOB, GPIOB_LED); chThdSleepMilliseconds(50); } #endif @@ -1891,9 +2006,9 @@ VNA_SHELL_FUNCTION(cmd_test) mode = my_atoi(argv[0]); for (i = 0; i < 20; i++) { - palClearPad(GPIOC, GPIOC_LED); + palClearPad(GPIOB, GPIOB_LED); ili9341_test(mode); - palSetPad(GPIOC, GPIOC_LED); + palSetPad(GPIOB, GPIOB_LED); chThdSleepMilliseconds(50); } #endif @@ -1920,6 +2035,7 @@ VNA_SHELL_FUNCTION(cmd_test) } } +#ifdef __VNA__ VNA_SHELL_FUNCTION(cmd_gain) { int rvalue; @@ -1980,6 +2096,7 @@ VNA_SHELL_FUNCTION(cmd_stat) // extern int awd_count; // shell_printf("awd: %d\r\n", awd_count); } +#endif #ifndef VERSION #define VERSION "unknown" @@ -2082,7 +2199,7 @@ VNA_SHELL_FUNCTION(cmd_threads) thread_t *tp; (void)argc; (void)argv; - shell_printf("stklimit| stack|stk free| addr|refs|prio| state| name"VNA_SHELL_NEWLINE_STR); + shell_printf("stklimit| |stk free| addr|refs|prio| state| name"VNA_SHELL_NEWLINE_STR); tp = chRegFirstThread(); do { uint32_t max_stack_use = 0U; @@ -2103,6 +2220,8 @@ VNA_SHELL_FUNCTION(cmd_threads) } #endif +#include "sa_cmd.c" + //============================================================================= VNA_SHELL_FUNCTION(cmd_help); @@ -2121,7 +2240,9 @@ static const VNAShellCommand commands[] = {"version" , cmd_version , 0}, {"reset" , cmd_reset , 0}, {"freq" , cmd_freq , CMD_WAIT_MUTEX}, +#ifdef __VNA__ {"offset" , cmd_offset , 0}, +#endif #ifdef ENABLE_TIME_COMMAND {"time" , cmd_time , 0}, #endif @@ -2133,11 +2254,13 @@ static const VNAShellCommand commands[] = {"dump" , cmd_dump , 0}, #endif {"frequencies" , cmd_frequencies , 0}, +#ifdef __VNA__ {"port" , cmd_port , 0}, {"stat" , cmd_stat , 0}, {"gain" , cmd_gain , 0}, {"power" , cmd_power , 0}, {"sample" , cmd_sample , 0}, +#endif // {"gamma" , cmd_gamma , 0}, {"scan" , cmd_scan , CMD_WAIT_MUTEX}, {"sweep" , cmd_sweep , 0}, @@ -2146,19 +2269,25 @@ static const VNAShellCommand commands[] = {"touchtest" , cmd_touchtest , CMD_WAIT_MUTEX}, {"pause" , cmd_pause , 0}, {"resume" , cmd_resume , 0}, +#ifdef __VNA__ {"cal" , cmd_cal , CMD_WAIT_MUTEX}, {"save" , cmd_save , 0}, {"recall" , cmd_recall , CMD_WAIT_MUTEX}, +#endif {"trace" , cmd_trace , 0}, {"marker" , cmd_marker , 0}, +#ifdef __VNA__ {"edelay" , cmd_edelay , 0}, +#endif {"capture" , cmd_capture , CMD_WAIT_MUTEX}, {"vbat" , cmd_vbat , 0}, #ifdef ENABLE_VBAT_OFFSET_COMMAND {"vbat_offset" , cmd_vbat_offset , 0}, #endif +#ifdef __VNA__ {"transform" , cmd_transform , 0}, {"threshold" , cmd_threshold , 0}, +#endif {"help" , cmd_help , 0}, #ifdef ENABLE_INFO_COMMAND {"info" , cmd_info , 0}, @@ -2166,6 +2295,34 @@ static const VNAShellCommand commands[] = #ifdef ENABLE_COLOR_COMMAND {"color" , cmd_color , 0}, #endif + { "if", cmd_if, 0 }, + { "attenuate", cmd_attenuate, 0 }, + { "level", cmd_level, 0 }, + { "leveloffset", cmd_leveloffset, 0 }, + { "levelsweep", cmd_levelsweep, 0 }, + { "modulation", cmd_modulation, 0 }, + { "rbw", cmd_rbw, 0 }, + { "mode", cmd_mode, 0 }, + { "spur", cmd_spur, 0 }, + { "load", cmd_load, 0 }, + { "selftest", cmd_selftest, 0 }, +#ifdef __ULTRA_SA__ + { "x", cmd_x, 0 }, +#endif + { "y", cmd_y, 0 }, + { "i", cmd_i, 0 }, + { "v", cmd_v, 0 }, + { "a", cmd_a, 0 }, + { "b", cmd_b, 0 }, + { "t", cmd_t, 0 }, + { "e", cmd_e, 0 }, + { "s", cmd_s, 0 }, + { "m", cmd_m, 0 }, + { "p", cmd_p, 0 }, + { "w", cmd_w, 0 }, + { "o", cmd_o, 0 }, + { "d", cmd_d, 0 }, + { "correction", cmd_correction, 0 }, #ifdef ENABLE_THREADS_COMMAND {"threads" , cmd_threads , 0}, #endif @@ -2282,7 +2439,7 @@ THD_FUNCTION(myshellThread, p) { (void)p; chRegSetThreadName("shell"); - shell_printf(VNA_SHELL_NEWLINE_STR"NanoVNA Shell"VNA_SHELL_NEWLINE_STR); + shell_printf(VNA_SHELL_NEWLINE_STR"tinySA Shell"VNA_SHELL_NEWLINE_STR); while (true) { shell_printf(VNA_SHELL_PROMPT_STR); if (VNAShell_readLine(shell_line, VNA_SHELL_MAX_LENGTH)) @@ -2293,6 +2450,7 @@ THD_FUNCTION(myshellThread, p) } #endif +#ifdef __VNA__ // I2C clock bus setting: depend from STM32_I2C1SW in mcuconf.h static const I2CConfig i2ccfg = { .timingr = // TIMINGR register initialization. (use I2C timing configuration tool for STM32F3xx and STM32F0xx microcontrollers (AN4235)) @@ -2320,13 +2478,77 @@ static const I2CConfig i2ccfg = { .cr1 = 0, // CR1 register initialization. .cr2 = 0 // CR2 register initialization. }; - static DACConfig dac1cfg1 = { //init: 2047U, init: 1922U, datamode: DAC_DHRM_12BIT_RIGHT }; +#endif + + +static const GPTConfig gpt4cfg = { + 1000000, // 1 MHz timer clock. + NULL, // No callback + 0, 0 +}; + +void my_microsecond_delay(int t) +{ + if (t>0) gptPolledDelay(&GPTD14, t); // t us delay +} +#if 0 +/* + * UART driver configuration structure. + */ +static UARTConfig uart_cfg_1 = { + NULL, //txend1, + NULL, //txend2, + NULL, //rxend, + NULL, //rxchar, + NULL, //rxerr, + 800000, + 0, + 0, //USART_CR2_LINEN, + 0 +}; +#endif + +#if 0 +static const SerialConfig default_config = +{ + 9600, + 0, + USART_CR2_STOP2_BITS, + 0 +}; + +void myWrite(char *buf) +{ + int len = strlen(buf); + while(len-- > 0) { + sdPut(&SD1,*buf++); + osalThreadSleepMicroseconds(1000); + } +} + +static int serial_count = 0; +int mySerialReadline(unsigned char *buf, int len) +{ + int i; + do { + i = sdReadTimeout(&SD1,&buf[serial_count], 20-serial_count,TIME_IMMEDIATE); + serial_count += i; + if (i > 0) + osalThreadSleepMicroseconds(1000); + } while (serial_count < len && i > 0); + if (buf[serial_count-1] == '\n') { + serial_count = 0; + return(i); + } else + return 0; +} +#endif // Main thread stack size defined in makefile USE_PROCESS_STACKSIZE = 0x200 // Profile stack usage (enable threads command by def ENABLE_THREADS_COMMAND) show: @@ -2339,8 +2561,10 @@ int main(void) //palSetPadMode(GPIOB, 8, PAL_MODE_ALTERNATE(1) | PAL_STM32_OTYPE_OPENDRAIN); //palSetPadMode(GPIOB, 9, PAL_MODE_ALTERNATE(1) | PAL_STM32_OTYPE_OPENDRAIN); +#ifdef __VNA__ i2cStart(&I2CD1, &i2ccfg); si5351_init(); +#endif // MCO on PA8 //palSetPadMode(GPIOA, 8, PAL_MODE_ALTERNATE(0)); @@ -2359,26 +2583,83 @@ int main(void) usbStart(serusbcfg.usbp, &usbcfg); usbConnectBus(serusbcfg.usbp); -/* + /* + * Powercycle the RF part to reset SI4432 + */ + + palClearPad(GPIOB, GPIO_RF_PWR); + chThdSleepMilliseconds(200); + palSetPad(GPIOB, GPIO_RF_PWR); + chThdSleepMilliseconds(500); + + +#if 0 + /* + * UART initialize + */ + uartStart(&UARTD1, &uart_cfg_1); + + uartStartSend(&UARTD1, 1, "H"); + uartStartReceive(&UARTD1, 1, buf); +#endif + +#if 0 + palSetPadMode(GPIOA, 9, PAL_MODE_ALTERNATE(1)); // USART1 TX. + palSetPadMode(GPIOA,10, PAL_MODE_ALTERNATE(1)); // USART1 RX. + + uint8_t buf[10]; + sdStart(&SD1,&default_config); + osalThreadSleepMilliseconds(10); + mySerialWrite("Hallo!?\n"); + + osalThreadSleepMilliseconds(10); + + mySerialReadline(buf, 10); + + sdReadTimeout(&SD1,buf,10, 10); + + sdWrite(&SD1,(const uint8_t *)"Test123",7); + osalThreadSleepMicroseconds(10); + sdReadTimeout(&SD1,buf,10,TIME_IMMEDIATE); + sdReadTimeout(&SD1,buf,10, 10); + int i = sdReadTimeout(&SD1,buf,10,TIME_IMMEDIATE); + +#endif +#ifdef __ULTRA_SA__ + ADF4351_Setup(); +#endif + /* * SPI LCD Initialize */ ili9341_init(); +/* + * Initiate 1 micro second timer + */ + gptStart(&GPTD14, &gpt4cfg); + gptPolledDelay(&GPTD14, 10); // 10 us delay + /* restore config */ config_recall(); + if (caldata_recall(0) == -1) { + load_default_properties(); + } /* restore frequencies and calibration 0 slot properties from flash memory */ - caldata_recall(0); - +#ifdef __VNA__ dac1cfg1.init = config.dac_value; /* * Starting DAC1 driver, setting up the output pin as analog as suggested * by the Reference Manual. */ dacStart(&DACD2, &dac1cfg1); - +#endif + setupSA(); + sweep_points = 290; /* initial frequencies */ update_frequencies(); + +#ifdef __VNA__ /* * I2S Initialize */ @@ -2387,11 +2668,28 @@ int main(void) i2sObjectInit(&I2SD2); i2sStart(&I2SD2, &i2sconfig); i2sStartExchange(&I2SD2); - +#endif + area_height = AREA_HEIGHT_NORMAL; ui_init(); //Initialize graph plotting plot_init(); + +// if (setting.mode != -1) { +// menu_mode_cb(setting.mode,0); +// } redraw_frame(); + + set_mode(M_HIGH); + sweep(true); + osalThreadSleepMilliseconds(100); + + set_mode(M_LOW); + sweep(true); + + set_refer_output(-1); + ui_mode_menu(); // Show menu when autostarting mode + + chThdCreateStatic(waThread1, sizeof(waThread1), NORMALPRIO-1, Thread1, NULL); while (1) { @@ -2405,7 +2703,7 @@ int main(void) myshellThread, NULL); chThdWait(shelltp); #else - shell_printf(VNA_SHELL_NEWLINE_STR"NanoVNA Shell"VNA_SHELL_NEWLINE_STR); + shell_printf(VNA_SHELL_NEWLINE_STR"tinySA Shell"VNA_SHELL_NEWLINE_STR); do { shell_printf(VNA_SHELL_PROMPT_STR); if (VNAShell_readLine(shell_line, VNA_SHELL_MAX_LENGTH)) diff --git a/mcuconf.h b/mcuconf.h index a1da287..241b42d 100644 --- a/mcuconf.h +++ b/mcuconf.h @@ -104,7 +104,7 @@ #define STM32_GPT_USE_TIM1 FALSE #define STM32_GPT_USE_TIM2 FALSE #define STM32_GPT_USE_TIM3 TRUE -#define STM32_GPT_USE_TIM14 FALSE +#define STM32_GPT_USE_TIM14 TRUE #define STM32_GPT_TIM1_IRQ_PRIORITY 2 #define STM32_GPT_TIM2_IRQ_PRIORITY 2 #define STM32_GPT_TIM3_IRQ_PRIORITY 2 @@ -113,7 +113,7 @@ /* * I2C driver system settings. */ -#define STM32_I2C_USE_I2C1 TRUE +#define STM32_I2C_USE_I2C1 FALSE #define STM32_I2C_USE_I2C2 FALSE #define STM32_I2C_BUSY_TIMEOUT 50 #define STM32_I2C_I2C1_IRQ_PRIORITY 3 @@ -133,7 +133,7 @@ * I2S driver system settings. */ #define STM32_I2S_USE_SPI1 FALSE -#define STM32_I2S_USE_SPI2 TRUE +#define STM32_I2S_USE_SPI2 FALSE #define STM32_I2S_SPI1_MODE (STM32_I2S_MODE_MASTER | \ STM32_I2S_MODE_RX) #define STM32_I2S_SPI2_MODE (STM32_I2S_MODE_SLAVE | \ diff --git a/nanovna.h b/nanovna.h index ec03e18..a8f6484 100644 --- a/nanovna.h +++ b/nanovna.h @@ -1,5 +1,4 @@ -/* - * Copyright (c) 2014-2015, TAKAHASHI Tomohiro (TTRFTECH) edy555@gmail.com +/* Copyright (c) 2014-2015, TAKAHASHI Tomohiro (TTRFTECH) edy555@gmail.com * All rights reserved. * * This is free software; you can redistribute it and/or modify @@ -22,10 +21,44 @@ // Need enable HAL_USE_SPI in halconf.h #define __USE_DISPLAY_DMA__ +#define __SA__ +//#define __SIMULATION__ +//#define __PIPELINE__ +#define __SCROLL__ +#define __ICONS__ +#define __MEASURE__ +#define __SELFTEST__ +#define __CALIBRATE__ +#define __FAST_SWEEP__ // Pre-fill SI4432 RSSI buffer to get fastest sweep in zero span mode + +//#define __ULTRA__ // Add harmonics mode on low input. +//#define __ULTRA_SA__ // Adds ADF4351 control for extra high 1st IF stage +#define __SPUR__ // Does spur reduction by shifting IF + /* * main.c */ +#ifdef __SA__ +#define POINTS_COUNT 290 +#define MARKER_COUNT 4 + +#define TRACES_MAX 3 +#define TRACE_AGE 3 +#define TRACE_ACTUAL 2 +#define TRACE_STORED 1 +#define TRACE_TEMP 0 +// #define age_t measured[TRACE_AGE] +#define stored_t measured[TRACE_STORED] +#define actual_t measured[TRACE_ACTUAL] +#define temp_t measured[TRACE_TEMP] + +#define CORRECTION_POINTS 10 // Frequency dependent level correction table entries + +typedef float measurement_t[TRACES_MAX][POINTS_COUNT]; +extern measurement_t measured; +#endif +#ifdef __VNA__ // Minimum frequency set #define START_MIN 50000 // Maximum frequency set @@ -81,25 +114,120 @@ extern float measured[2][POINTS_COUNT][2]; void cal_collect(int type); void cal_done(void); - +#endif #define MAX_FREQ_TYPE 5 enum stimulus_type { ST_START=0, ST_STOP, ST_CENTER, ST_SPAN, ST_CW }; +void update_frequencies(void); void set_sweep_frequency(int type, uint32_t frequency); uint32_t get_sweep_frequency(int type); - +void my_microsecond_delay(int t); double my_atof(const char *p); +int shell_printf(const char *fmt, ...); void toggle_sweep(void); +void toggle_mute(void); void load_default_properties(void); -#define SWEEP_ENABLE 0x01 -#define SWEEP_ONCE 0x02 +extern float perform(bool b, int i, uint32_t f, int e); +enum { + AV_OFF, AV_MIN, AV_MAX_HOLD, AV_MAX_DECAY, AV_4, AV_16 +}; +enum { + M_LOW, M_HIGH, M_GENLOW, M_GENHIGH, M_ULTRA +}; + +enum { + MO_NONE, MO_AM_1kHz, MO_AM_10Hz, MO_NFM, MO_WFM, MO_EXTERNAL, +}; + +#define MODE_OUTPUT(x) ((x) == M_GENLOW || (x) == M_GENHIGH ) +#ifdef __ULTRA__ +#define MODE_INPUT(x) ((x) == M_LOW || (x) == M_HIGH || (x) == M_ULTRA ) +#else +#define MODE_INPUT(x) ((x) == M_LOW || (x) == M_HIGH ) +#endif +#define MODE_HIGH(x) ((x) == M_HIGH || (x) == M_GENHIGH ) +#define MODE_LOW(x) ((x) == M_LOW || (x) == M_GENLOW ) +#define MODE_SELECT(x) (MODE_HIGH(x) ? 1 : 0) + +#define SWEEP_ENABLE 0x01 +#define SWEEP_ONCE 0x02 +#define SWEEP_CALIBRATE 0x04 +#define SWEEP_SELFTEST 0x08 +#define SWEEP_REMOTE 0x10 + extern int8_t sweep_mode; +extern bool completed; extern const char *info_about[]; +// ------------------------------- sa_core.c ---------------------------------- +void reset_settings(int); +//void ui_process_touch(void); +void SetPowerGrid(int); +void SetRefLevel(float); +void set_refer_output(int); +void toggle_below_IF(void); +int get_refer_output(void); +void set_attenuation(int); +int get_attenuation(void); +void set_harmonic(int); +//extern int setting.harmonic; +int search_is_greater(void); +void set_auto_attenuation(void); +void set_auto_reflevel(int); +int is_paused(void); +void set_actual_power(float); +void SetGenerate(int); +void set_RBW(int); +void set_drive(int d); +void set_IF(int f); +void set_step_delay(int t); +void set_repeat(int); +void set_level_sweep(float); +void set_level(float); +void set_sweep_time(float); +//extern int setting.repeat; +//extern int setting.rbw; +#ifdef __SPUR__ +//extern int setting.spur; +void SetSpur(int v); +#endif +void set_average(int); +int GetAverage(void); +//extern int setting.average; +void set_storage(void); +void set_clear_storage(void); +void set_subtract_storage(void); +void toggle_waterfall(void); +void set_mode(int); +int GetMode(void); +void set_reflevel(float); +void user_set_reflevel(float); +#define REFLEVEL_MAX 9999.0 +#define REFLEVEL_MIN 1.0e-12 +void set_scale(float); +void user_set_scale(float); +void AllDirty(void); +void MenuDirty(void); +void toggle_LNA(void); +void toggle_AGC(void); +void redrawHisto(void); +void self_test(int); +void set_decay(int); +void set_noise(int); +void toggle_tracking_output(void); +extern int32_t frequencyExtra; +void set_10mhz(int); +void set_modulation(int); +//extern int setting.modulation; +void set_measurement(int); +// extern int settingSpeed; +//extern int setting.step_delay; +void sweep_remote(void); +#ifdef __VNA__ /* * dsp.c */ @@ -121,7 +249,9 @@ void reset_dsp_accumerator(void); void calculate_gamma(float *gamma); void fetch_amplitude(float *gamma); void fetch_amplitude_ref(float *gamma); +#endif +#ifdef __VNA__ /* * tlv320aic3204.c */ @@ -130,21 +260,32 @@ extern void tlv320aic3204_init(void); extern void tlv320aic3204_set_gain(int lgain, int rgain); extern void tlv320aic3204_select(int channel); +#endif /* * plot.c */ // Offset of plot area -#define OFFSETX 10 -#define OFFSETY 0 - -// WIDTH better be n*(POINTS_COUNT-1) -#define WIDTH 300 +#define OFFSETX 30 +#define OFFSETY 0 +#define BUTTON_WIDTH 60 +#ifdef __SCROLL__ +#define HEIGHT _height +extern int _height; +#define HEIGHT_SCROLL 180 +#define HEIGHT_NOSCROLL 232 +#else // HEIGHT = 8*GRIDY #define HEIGHT 232 +// WIDTH better be n*(POINTS_COUNT-1) +#endif +#define WIDTH 290 + +#define CELLWIDTH (32) +#define CELLHEIGHT (32) -//#define NGRIDY 10 -#define NGRIDY 8 +#define NGRIDY 10 +//#define NGRIDY 9 #define FREQUENCIES_XPOS1 OFFSETX #define FREQUENCIES_XPOS2 200 @@ -155,8 +296,8 @@ extern void tlv320aic3204_select(int channel); #define GRIDY (HEIGHT / NGRIDY) // -#define CELLOFFSETX 5 -#define AREA_WIDTH_NORMAL (CELLOFFSETX + WIDTH + 1 + 4) +#define CELLOFFSETX 0 +#define AREA_WIDTH_NORMAL (CELLOFFSETX + WIDTH) #define AREA_HEIGHT_NORMAL ( HEIGHT + 1) // Smith/polar chart @@ -169,6 +310,7 @@ extern int16_t area_height; // font extern const uint8_t x5x7_bits []; +extern const uint16_t x7x13b_bits []; #define FONT_GET_DATA(ch) (&x5x7_bits[ch*7]) #define FONT_GET_WIDTH(ch) (8-(x5x7_bits[ch*7]&7)) #define FONT_MAX_WIDTH 7 @@ -190,8 +332,6 @@ extern const uint16_t numfont16x22[]; #define S_OHM "\036" // trace -#define TRACES_MAX 4 - #define MAX_TRACE_TYPE 12 enum trace_type { TRC_LOGMAG=0, TRC_PHASE, TRC_DELAY, TRC_SMITH, TRC_POLAR, TRC_LINEAR, TRC_SWR, TRC_REAL, TRC_IMAG, TRC_R, TRC_X, TRC_OFF @@ -209,6 +349,15 @@ enum trace_type { // Electrical Delay // Phase +#define MAX_UNIT_TYPE 4 +enum unit_type { + U_DBM=0, U_DBMV, U_DBUV, U_VOLT, U_WATT, U_DBC // dBc only for displaying delta marker info +}; +#define UNIT_IS_LINEAR(T) ( T >= U_VOLT ? true : false) +#define UNIT_IS_LOG(T) ( T >= U_VOLT ? false : true) + +float value(float); + typedef struct trace { uint8_t enabled; uint8_t type; @@ -231,13 +380,21 @@ typedef struct config { uint16_t trace_color[TRACES_MAX]; int16_t touch_cal[4]; int8_t freq_mode; +#ifdef __VNA__ uint32_t harmonic_freq_threshold; +#endif uint16_t vbat_offset; - uint8_t _reserved[22]; + int16_t low_level_offset; + int16_t high_level_offset; + uint32_t correction_frequency[CORRECTION_POINTS]; + float correction_value[CORRECTION_POINTS]; +// uint8_t _reserved[22]; uint32_t checksum; } config_t; extern config_t config; +//#define settingLevelOffset config.level_offset +int get_level_offset(void); void set_trace_type(int t, int type); void set_trace_channel(int t, int channel); @@ -246,21 +403,31 @@ void set_trace_refpos(int t, float refpos); float get_trace_scale(int t); float get_trace_refpos(int t); const char *get_trace_typename(int t); +extern int in_selftest; +#ifdef __VNA void set_electrical_delay(float picoseconds); float get_electrical_delay(void); float groupdelay_from_array(int i, float array[POINTS_COUNT][2]); - +#endif // marker +enum { + M_NORMAL=0,M_REFERENCE=1, M_DELTA=2, M_NOISE=4, M_TRACKING=8, M_DELETE=16 // Tracking must be last. +}; -#define MARKERS_MAX 4 +enum { + M_DISABLED = false, M_ENABLED = true +}; -typedef struct marker { +typedef struct { int8_t enabled; + int8_t mtype; int16_t index; uint32_t frequency; } marker_t; +#define MARKERS_MAX 4 + extern int8_t previous_marker; extern int8_t marker_tracking; @@ -272,7 +439,7 @@ void redraw_frame(void); void request_to_draw_cells_behind_menu(void); void request_to_draw_cells_behind_numeric_input(void); void redraw_marker(int marker); -void plot_into_index(float measured[2][POINTS_COUNT][2]); +void plot_into_index(measurement_t measured); void force_set_markmap(void); void draw_frequencies(void); void draw_all(bool flush); @@ -287,6 +454,10 @@ void set_marker_search(int mode); int marker_search(void); int marker_search_left(int from); int marker_search_right(int from); +int marker_search_left_max(int from); +int marker_search_right_max(int from); +int marker_search_left_min(int from); +int marker_search_right_min(int from); // _request flag for update screen #define REDRAW_CELLS (1<<0) @@ -302,25 +473,36 @@ extern volatile uint8_t redraw_request; */ // SPI bus revert byte order //gggBBBbb RRRrrGGG -#define RGB565(r,g,b) ( (((g)&0x1c)<<11) | (((b)&0xf8)<<5) | ((r)&0xf8) | (((g)&0xe0)>>5) ) +#define byteReverse16(x) (uint16_t)(((x) << 8) & 0xff00) | (((x) >> 8) & 0xff) +#define RGB565(r,g,b) byteReverse16( ((((uint16_t)r)<<8)&0b1111100000000000) | ((((uint16_t)g)<<3)&0b0000011111100000) | ((((uint16_t)b)>>3)&0b0000000000011111) ) + +//#define RGB565(r,g,b) ( (((g)&0x1c)<<11) | (((b)&0xf8)<<5) | ((r)&0xf8) | (((g)&0xe0)>>5) ) #define RGBHEX(hex) ( (((hex)&0x001c00)<<3) | (((hex)&0x0000f8)<<5) | (((hex)&0xf80000)>>16) | (((hex)&0x00e000)>>13) ) // Define size of screen buffer in pixels (one pixel 16bit size) -#define SPI_BUFFER_SIZE 2048 +#define SPI_BUFFER_SIZE 1024 + +#define LCD_WIDTH 320 +#define LCD_HEIGHT 240 #define DEFAULT_FG_COLOR RGB565(255,255,255) #define DEFAULT_BG_COLOR RGB565( 0, 0, 0) +#define DARK_GREY RGB565(140,140,140) +#define LIGHT_GREY RGB565(220,220,220) #define DEFAULT_GRID_COLOR RGB565(128,128,128) #define DEFAULT_MENU_COLOR RGB565(255,255,255) #define DEFAULT_MENU_TEXT_COLOR RGB565( 0, 0, 0) #define DEFAULT_MENU_ACTIVE_COLOR RGB565(180,255,180) -#define DEFAULT_TRACE_1_COLOR RGB565(255,255, 0) -#define DEFAULT_TRACE_2_COLOR RGB565( 0,255,255) -#define DEFAULT_TRACE_3_COLOR RGB565( 0,255, 0) -#define DEFAULT_TRACE_4_COLOR RGB565(255, 0,255) +#define DEFAULT_TRACE_1_COLOR RGB565(255, 0, 0) /* RGB565(255,255, 0) */ +#define DEFAULT_TRACE_2_COLOR RGB565( 0,255, 0)/* RGB565( 0,255,255) */ +#define DEFAULT_TRACE_3_COLOR RGB565(255,255, 0)/* RGB565( 0,255, 0) */ +//#define DEFAULT_TRACE_4_COLOR RGB565(255, 0,255) #define DEFAULT_NORMAL_BAT_COLOR RGB565( 31,227, 0) #define DEFAULT_LOW_BAT_COLOR RGB565(255, 0, 0) #define DEFAULT_SPEC_INPUT_COLOR RGB565(128,255,128); +#define BRIGHT_COLOR_BLUE RGB565(200,200,255) +#define BRIGHT_COLOR_RED RGB565(255,200,200) +#define BRIGHT_COLOR_GREEN RGB565(200,255,200) extern uint16_t foreground_color; extern uint16_t background_color; @@ -331,12 +513,18 @@ void ili9341_init(void); void ili9341_test(int mode); void ili9341_bulk(int x, int y, int w, int h); void ili9341_fill(int x, int y, int w, int h, int color); +#if 0 void ili9341_set_foreground(uint16_t fg); void ili9341_set_background(uint16_t fg); +#else +#define ili9341_set_foreground(fg) { foreground_color = fg; } +#define ili9341_set_background(bg) { background_color = bg;} +#endif void ili9341_clear_screen(void); void blit8BitWidthBitmap(uint16_t x, uint16_t y, uint16_t width, uint16_t height, const uint8_t *bitmap); void ili9341_drawchar(uint8_t ch, int x, int y); void ili9341_drawstring(const char *str, int x, int y); +void ili9341_drawstring_7x13(const char *str, int x, int y); void ili9341_drawstringV(const char *str, int x, int y); int ili9341_drawchar_size(uint8_t ch, int x, int y, uint8_t size); void ili9341_drawstring_size(const char *str, int x, int y, uint8_t size); @@ -349,73 +537,192 @@ void show_logo(void); /* * flash.c */ -#define SAVEAREA_MAX 5 -// Begin addr 0x08018000 -#define SAVE_CONFIG_AREA_SIZE 0x00008000 + + +typedef struct setting +{ + uint32_t magic; +// uint32_t _frequency0; +// uint32_t _frequency1; + int mode; + uint16_t _sweep_points; + int attenuate; + int auto_attenuation; + int step_atten; + int rbw; + int below_IF; + int average; + int show_stored; + int subtract_stored; + int drive; // 0-7 , 7=+20dBm, 3dB steps + int agc; + int lna; + int auto_reflevel; + float reflevel; + float scale; + int tracking; + int modulation; + int step_delay; + int frequency_step; + int test; + int harmonic; + int decay; + int noise; + float vbw; + int tracking_output; + int repeat; + uint32_t frequency0; + uint32_t frequency1; + uint32_t frequency_IF; + int freq_mode; + int measurement; + int refer; + int spur; + trace_t _trace[TRACES_MAX]; + marker_t _markers[MARKERS_MAX]; + int8_t _active_marker; + int8_t unit; + float offset; + float trigger_level; + int trigger; + int linearity_step; + float level; + float level_sweep; + float sweep_time; + float actual_sweep_time; + int test_argument; + int auto_IF; + unsigned int unit_scale_index; + float unit_scale; + int mute; + uint32_t checksum; +}setting_t; + +extern setting_t setting; + +extern int setting_frequency_10mhz; +void reset_settings(int m); + + +#define S_IS_AUTO(x) ((x)&2) +#define S_STATE(X) ((X)&1) +enum { S_OFF=0, S_ON=1, S_AUTO_OFF=2, S_AUTO_ON=3 }; + +#ifdef __FAST_SWEEP__ +#define MINIMUM_SWEEP_TIME 3 // Minimum sweep time on zero span in miliseconds +#else +#define MINIMUM_SWEEP_TIME 15 // Minimum sweep time on zero span in miliseconds +#endif +#define REPEAT_TIME 134.0 // Time per extra repeat in uS +#define MEASURE_TIME 175.0 // Time per vbwstep without stepdelay in uS + +extern uint32_t frequencies[POINTS_COUNT]; +extern const float unit_scale_value[]; +extern const char * const unit_scale_text[]; + +#if 1 +#define SAVEAREA_MAX 9 // config save area -#define SAVE_CONFIG_ADDR 0x08018000 +#define SAVE_CONFIG_ADDR 0x0801B000 +// setting_t save area +#define SAVE_PROP_CONFIG_0_ADDR 0x0801B800 +#define SAVE_PROP_CONFIG_1_ADDR 0x0801C000 +#define SAVE_PROP_CONFIG_2_ADDR 0x0801C800 +#define SAVE_PROP_CONFIG_3_ADDR 0x0801D000 +#define SAVE_PROP_CONFIG_4_ADDR 0x0801D800 +#define SAVE_PROP_CONFIG_5_ADDR 0x0801E000 +#define SAVE_PROP_CONFIG_6_ADDR 0x0801E800 +#define SAVE_PROP_CONFIG_7_ADDR 0x0801F000 +#define SAVE_PROP_CONFIG_8_ADDR 0x0801F800 + +#define SAVE_CONFIG_AREA_SIZE (0x0801F800 - SAVE_CONFIG_ADDR) // Should include all save slots + +#else +#define SAVEAREA_MAX 4 +// Begin addr 0x0801C000 +#define SAVE_CONFIG_AREA_SIZE 0x00004000 +// config save area +#define SAVE_CONFIG_ADDR 0x0801C000 // properties_t save area -#define SAVE_PROP_CONFIG_0_ADDR 0x08018800 -#define SAVE_PROP_CONFIG_1_ADDR 0x0801a000 -#define SAVE_PROP_CONFIG_2_ADDR 0x0801b800 -#define SAVE_PROP_CONFIG_3_ADDR 0x0801d000 +#define SAVE_PROP_CONFIG_0_ADDR 0x0801C800 +#define SAVE_PROP_CONFIG_1_ADDR 0x0801D000 +#define SAVE_PROP_CONFIG_2_ADDR 0x0801D800 +#define SAVE_PROP_CONFIG_3_ADDR 0x0801E000 #define SAVE_PROP_CONFIG_4_ADDR 0x0801e800 - +#endif +#if 0 typedef struct properties { uint32_t magic; - uint32_t _frequency0; - uint32_t _frequency1; + preset_t setting; +// uint32_t _frequency0; +// uint32_t _frequency1; uint16_t _sweep_points; +#ifdef __VNA__ uint16_t _cal_status; - uint32_t _frequencies[POINTS_COUNT]; +#endif +#ifdef __SA__ +// uint32_t _frequency_IF; //IF frequency +#endif +// uint32_t _frequencies[POINTS_COUNT]; +#ifdef __VNA__ float _cal_data[5][POINTS_COUNT][2]; float _electrical_delay; // picoseconds - +#endif trace_t _trace[TRACES_MAX]; marker_t _markers[MARKERS_MAX]; - - float _velocity_factor; // % int8_t _active_marker; +#ifdef __VNA__ + float _velocity_factor; // % uint8_t _domain_mode; /* 0bxxxxxffm : where ff: TD_FUNC m: DOMAIN_MODE */ uint8_t _marker_smith_format; uint8_t _bandwidth; - uint8_t _reserved[50]; +#endif + uint8_t _reserved[2]; uint32_t checksum; } properties_t; +#endif + //sizeof(properties_t) == 0x1200 #define CONFIG_MAGIC 0x434f4e45 /* 'CONF' */ extern int16_t lastsaveid; -extern properties_t *active_props; -extern properties_t current_props; +//extern properties_t *active_props; + +//extern properties_t current_props; -#define frequency0 current_props._frequency0 -#define frequency1 current_props._frequency1 -#define sweep_points current_props._sweep_points +//#define frequency0 current_props._frequency0 +//#define frequency1 current_props._frequency1 +#define sweep_points setting._sweep_points +#ifdef __VNA__ #define cal_status current_props._cal_status -#define frequencies current_props._frequencies +#endif +#ifdef __SA__ +//#define frequency_IF current_props._frequency_IF +#endif +//#define frequencies current_props._frequencies +#ifdef __VNA__ #define cal_data active_props->_cal_data #define electrical_delay current_props._electrical_delay - -#define trace current_props._trace -#define markers current_props._markers -#define active_marker current_props._active_marker +#endif +#define trace setting._trace +#define markers setting._markers +#define active_marker setting._active_marker +#ifdef __VNA__ #define domain_mode current_props._domain_mode #define velocity_factor current_props._velocity_factor #define marker_smith_format current_props._marker_smith_format #define bandwidth current_props._bandwidth +#endif -#define FREQ_IS_STARTSTOP() (!(config.freq_mode&FREQ_MODE_CENTER_SPAN)) -#define FREQ_IS_CENTERSPAN() (config.freq_mode&FREQ_MODE_CENTER_SPAN) -#define FREQ_IS_CW() (frequency0 == frequency1) - -int caldata_save(int id); +#define FREQ_IS_STARTSTOP() (!(setting.freq_mode&FREQ_MODE_CENTER_SPAN)) +#define FREQ_IS_CENTERSPAN() (setting.freq_mode&FREQ_MODE_CENTER_SPAN) +#define FREQ_IS_CW() (setting.frequency0 == setting.frequency1) int caldata_recall(int id); -const properties_t *caldata_ref(int id); - +int caldata_save(int id); +//const properties_t *caldata_ref(int id); int config_save(void); int config_recall(void); @@ -426,11 +733,17 @@ void clear_all_config_prop_data(void); */ extern void ui_init(void); extern void ui_process(void); +int current_menu_is_form(void); + +void menu_mode_cb(int, uint8_t); +void ui_mode_normal(void); +void ui_mode_menu(void); // Irq operation process set #define OP_NONE 0x00 #define OP_LEVER 0x01 #define OP_TOUCH 0x02 +#define OP_CONSOLE 0x04 //#define OP_FREQCHANGE 0x04 extern volatile uint8_t operation_requested; @@ -448,11 +761,13 @@ typedef struct uistat { int8_t digit; /* 0~5 */ int8_t digit_mode; int8_t current_trace; /* 0..3 */ - uint32_t value; // for editing at numeric input area + float value; // for editing at numeric input area // uint32_t previous_value; uint8_t lever_mode; uint8_t marker_delta; + uint8_t marker_noise; uint8_t marker_tracking; + char text[20]; } uistat_t; extern uistat_t uistat; @@ -486,11 +801,63 @@ int16_t adc_vbat_read(void); */ int plot_printf(char *str, int, const char *fmt, ...); #define PULSE do { palClearPad(GPIOC, GPIOC_LED); palSetPad(GPIOC, GPIOC_LED);} while(0) +//extern int setting_attenuate; +//extern int settingPowerCal; +//extern int setting_step_delay; +//extern int actualStepDelay; +//extern int setting_mode; +void update_rbw(void); +int get_actual_RBW(void); + +#define byte uint8_t +extern volatile int SI4432_Sel; // currently selected SI4432 +void SI4432_Write_Byte(byte ADR, byte DATA ); +byte SI4432_Read_Byte( byte ADR ); + +void SI4432_Init(void); +void SI4432_Drive(int); +float SI4432_RSSI(uint32_t i, int s); +#ifdef __FAST_SWEEP__ +void SI4432_Fill(int s, int start); +#endif +void SI4432_Set_Frequency ( long Freq ); +float SI4432_SET_RBW(float WISH); +void SI4432_SetReference(int freq); // Speed profile definition #define START_PROFILE systime_t time = chVTGetSystemTimeX(); -#define STOP_PROFILE {char string_buf[12];plot_printf(string_buf, sizeof string_buf, "T:%06d", chVTGetSystemTimeX() - time);ili9341_drawstringV(string_buf, 1, 60);} +#define RESTART_PROFILE time = chVTGetSystemTimeX(); +#define STOP_PROFILE {char string_buf[12];plot_printf(string_buf, sizeof string_buf, "T:%06d", chVTGetSystemTimeX() - time);ili9341_drawstringV(string_buf, 1, 180);} // Macros for convert define value to string #define STR1(x) #x #define define_to_STR(x) STR1(x) + +// sa_core.c +int get_waterfall(void); +void toggle_tracking(void); +void calibrate(void); +void reset_calibration(void); +void set_reflevel(float); +void set_offset(float); +void set_unit(int); +void set_RBW(int); +void set_switches(int); +void set_trigger_level(float); +void set_trigger(int); +//extern int setting_measurement; +void self_test(int); +//extern int setting_test; +void wait_user(void); +void calibrate(void); +float to_dBm(float); +float calc_min_sweep_time(void); +extern float actual_rbw; + +enum { + M_OFF, M_IMD, M_OIP3, M_PHASE_NOISE, M_STOP_BAND, M_PASS_BAND, M_LINEARITY +}; + +enum { + T_AUTO, T_NORMAL, T_SINGLE, T_DONE +}; /*EOF*/ diff --git a/numfont20x22.c b/numfont20x22.c index 85498ec..9affa97 100644 --- a/numfont20x22.c +++ b/numfont20x22.c @@ -507,6 +507,7 @@ const uint16_t numfont16x22[] = { 0b0000000000000000, 0b0000000000000000, + 0b0000000000000000, // m 0b0000000000000000, 0b0000000000000000, 0b0000000000000000, @@ -514,6 +515,51 @@ const uint16_t numfont16x22[] = { 0b0000000000000000, 0b0000000000000000, 0b0000000000000000, + 0b1111001100110000, + 0b1111011111111100, + 0b1111111111111110, + 0b1111111111111110, + 0b1111111111011111, + 0b1111101111001111, + 0b1111001111001111, + 0b1111001111001111, + 0b1111001111001111, + 0b1111001111001111, + 0b1111001111001111, + 0b1111001111001111, + 0b1111001111001111, + 0b1111001111001111, + + 0b0000000000000000, // u + 0b0000000000000000, + 0b0000000000000000, + 0b0000000000000000, + 0b0000000000000000, + 0b0000000000000000, + 0b0000000000000000, + 0b0000000000000000, + 0b1111000000001111, + 0b1111000000001111, + 0b1111000000001111, + 0b1111000000001111, + 0b1111000000001111, + 0b1111000000001111, + 0b1111000000001111, + 0b1111000000001111, + 0b1111000000011111, + 0b1111100000111111, + 0b1111110001111111, + 0b0111111111111111, + 0b0011111111101111, + 0b0001111111001111, + + 0b0000000000000000, // n + 0b0000000000000000, + 0b0000000000000000, + 0b0000000000000000, + 0b0000000000000000, + 0b0000000000000000, + 0b0000000000000000, 0b0000000000000000, 0b1111000111110000, 0b1111011111111100, @@ -530,7 +576,7 @@ const uint16_t numfont16x22[] = { 0b1111000000001111, 0b1111000000001111, - 0b0000000000000000, + 0b0000000000000000, // p 0b0000000000000000, 0b0000000000000000, 0b0000000000000000, diff --git a/plot.c b/plot.c index 01b1e85..933bc5a 100644 --- a/plot.c +++ b/plot.c @@ -1,6 +1,4 @@ -/* - * Copyright (c) 2014-2015, TAKAHASHI Tomohiro (TTRFTECH) edy555@gmail.com - * All rights reserved. +/* 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 @@ -25,30 +23,37 @@ #include "chprintf.h" #include "nanovna.h" +#ifdef __SCROLL__ +int _height = HEIGHT_NOSCROLL; +int waterfall = false; +int fullscreen = true; +#endif static void cell_draw_marker_info(int x0, int y0); static void draw_battery_status(void); +void cell_draw_test_info(int x0, int y0); +void frequency_string(char *buf, size_t len, int32_t freq); static int16_t grid_offset; static int16_t grid_width; int16_t area_width = AREA_WIDTH_NORMAL; -int16_t area_height = AREA_HEIGHT_NORMAL; +int16_t area_height; // initialized in main() = AREA_HEIGHT_NORMAL; // Cell render use spi buffer typedef uint16_t pixel_t; pixel_t *cell_buffer = (pixel_t *)spi_buffer; // Cell size // Depends from spi_buffer size, CELLWIDTH*CELLHEIGHT*sizeof(pixel) <= sizeof(spi_buffer) -#define CELLWIDTH (64) -#define CELLHEIGHT (32) +//#define CELLWIDTH (64) // moved to nanovna.h +//#define CELLHEIGHT (32) // Check buffer size #if CELLWIDTH*CELLHEIGHT > SPI_BUFFER_SIZE #error "Too small spi_buffer size SPI_BUFFER_SIZE < CELLWIDTH*CELLHEIGH" #endif // indicate dirty cells (not redraw if cell data not changed) -#define MAX_MARKMAP_X ((320+CELLWIDTH-1)/CELLWIDTH) -#define MAX_MARKMAP_Y ((240+CELLHEIGHT-1)/CELLHEIGHT) +#define MAX_MARKMAP_X ((LCD_WIDTH+CELLWIDTH-1)/CELLWIDTH) +#define MAX_MARKMAP_Y ((LCD_HEIGHT+CELLHEIGHT-1)/CELLHEIGHT) // Define markmap mask size #if MAX_MARKMAP_X <= 8 typedef uint8_t map_t; @@ -58,13 +63,37 @@ typedef uint16_t map_t; typedef uint32_t map_t; #endif +uint16_t marker_color(int mtype) +{ + if (mtype & M_REFERENCE) + return(RGBHEX(0xFFFFFF)); + if (mtype & M_DELTA) + return(RGBHEX(0x00FF00)); + if (mtype & M_NOISE) + return(RGBHEX(0x00FFFF)); + return(RGBHEX(0xFFFF00)); +} + +//#if 4 != M_TRACKING +//#error "Wrong marker numbers" +//#endif + +char marker_letter[5] = +{ + 'R', + ' ', + 'D', + 'N', + 'T' +}; + map_t markmap[2][MAX_MARKMAP_Y]; uint8_t current_mappage = 0; // Trace data cache, for faster redraw cells // CELL_X[16:31] x position // CELL_Y[ 0:15] y position -typedef uint32_t index_t; +typedef uint32_t index_t; static index_t trace_index[TRACES_MAX][POINTS_COUNT]; #define INDEX(x, y) ((((index_t)x)<<16)|(((index_t)y))) @@ -87,6 +116,12 @@ void update_grid(void) uint32_t fspan = get_sweep_frequency(ST_SPAN); uint32_t grid; + if (fspan == 0) { + fspan = setting.actual_sweep_time; // Time in mS + fspan *= 1000; + fstart = 0; + } + while (gdigit > 100) { grid = 5 * gdigit; if (fspan / grid >= 4) @@ -107,6 +142,7 @@ void update_grid(void) redraw_request |= REDRAW_FREQUENCY; } +#ifdef __VNA__ static inline int circle_inout(int x, int y, int r) { @@ -339,7 +375,7 @@ smith_grid3(int x, int y) return 0; } #endif - +#endif #if 0 static int rectangular_grid(int x, int y) @@ -421,12 +457,54 @@ draw_on_strut(int v0, int d, int color) /* * calculate log10(abs(gamma)) */ -static float -logmag(const float *v) +float +value(const float v) { - return log10f(v[0]*v[0] + v[1]*v[1]) * 10; + switch(setting.unit) + { + case U_DBMV: + return v + 30.0 + 20.0*log10(sqrt(50)); + break; + case U_DBUV: + return v + 90.0 + 20.0*log10(sqrt(50.0)); + break; + case U_VOLT: + return pow(10, (v-30.0)/20.0) * sqrt(50.0); + break; + case U_WATT: + return pow(10, v/10.0)/1000.0; + break; + } +// case U_DBM: + return v; // raw data is in logmag*10 format + } +float +to_dBm(const float v) +{ + switch(setting.unit) + { + case U_DBMV: + return v - 30.0 - 20.0*log10(sqrt(50)); + break; + case U_DBUV: + return v - 90.0 - 20.0*log10(sqrt(50.0)); + break; + case U_VOLT: + return log10( v / (sqrt(50.0))) * 20.0 + 30.0 ; + break; + case U_WATT: + return log10(v*1000.0)*10.0; + break; + } +// case U_DBM: + return v; // raw data is in logmag*10 format + +} + + +#ifdef __VNA_ /* * calculate phase[-2:2] of coefficient */ @@ -529,21 +607,23 @@ gamma2reactance(const float v[2]) float d = z0 / ((1-v[0])*(1-v[0])+v[1]*v[1]); return 2*v[1] * d; } +#endif static index_t -trace_into_index(int t, int i, float array[POINTS_COUNT][2]) +trace_into_index(int t, int i, float array[POINTS_COUNT]) { int y, x; + float coeff = array[i]; + float refpos = get_trace_refpos(t); + float v=0; + float scale = get_trace_scale(t); - float *coeff = array[i]; - float refpos = NGRIDY - get_trace_refpos(t); - float v = refpos; - float scale = 1 / get_trace_scale(t); switch (trace[t].type) { case TRC_LOGMAG: - v-= logmag(coeff) * scale; + v = ( refpos - value(coeff) ) / scale; break; - case TRC_PHASE: +#ifdef __VNA__ + case TRC_PHASE: v-= phase(coeff) * scale; break; case TRC_DELAY: @@ -572,15 +652,17 @@ trace_into_index(int t, int i, float array[POINTS_COUNT][2]) case TRC_POLAR: cartesian_scale(coeff[0], coeff[1], &x, &y, scale); goto set_index; - } +#endif + } if (v < 0) v = 0; if (v > NGRIDY) v = NGRIDY; x = (i * (WIDTH) + (sweep_points-1)/2) / (sweep_points-1) + CELLOFFSETX; y = float2int(v * GRIDY); -set_index: +// set_index: return INDEX(x, y); } +#ifdef __VNA__ static void format_smith_value(char *buf, int len, const float coeff[2], uint32_t frequency) { @@ -625,7 +707,9 @@ format_smith_value(char *buf, int len, const float coeff[2], uint32_t frequency) break; } } +#endif +#ifdef __VNA__ static void trace_get_value_string(int t, char *buf, int len, float array[POINTS_COUNT][2], int i) { @@ -738,7 +822,103 @@ trace_get_value_string_delta(int t, char *buf, int len, float array[POINTS_COUNT } plot_printf(buf, len, format, v); } +#endif + +extern const char *unit_string[]; + +static void trace_get_value_string( + int t, char *buf, int len, + int i, float coeff[POINTS_COUNT], + uint32_t freq[POINTS_COUNT], + int point_count, + int ri, int mtype) +{ + (void) t; + (void)freq; + (void) point_count; + float v; + char buf2[11]; + char buf3[8]; + buf2[0]=' '; + uint32_t dfreq = 0; + float rlevel = 0; + int ii = i; + int unit_index = setting.unit; + if (mtype & M_DELTA) { + unit_index = setting.unit+5; + if (ri > i) { + dfreq = frequencies[ri] - frequencies[i]; + ii = ri - i; + buf2[0] = '-'; + } else { + dfreq = frequencies[i] - frequencies[ri]; + ii = i - ri; + buf2[0] = '+'; + } + rlevel = value(coeff[ri]); + } else { + dfreq = frequencies[i]; + } + if (FREQ_IS_CW()) { + float t = ii*(setting.actual_sweep_time)*1000.0/290.0; +#if 1 + plot_printf(&buf2[1], sizeof(buf2) -1, "%.3FS" , t/1000000.0); +#else + if (t>1000000.0){ + plot_printf(&buf2[1], sizeof(buf2) -1, "%4f" , t/1000000.0); + buf2[5] = 'S'; + buf2[6]=0; + } + else if (t>1000.0) { + plot_printf(&buf2[1], sizeof(buf2) -1, "%4f" , t/1000.0); + buf2[5] = 'm'; + buf2[6] = 'S'; + buf2[7]=0; + } + else { + plot_printf(&buf2[1], sizeof(buf2) -1, "%4f" , t); + buf2[5] = 'u'; + buf2[6] = 'S'; + buf2[7]=0; + } +#endif + } else { + uint32_t resolution = get_sweep_frequency(ST_SPAN)/290; +#if 0 + if (resolution <= 2000) + plot_printf(&buf2[1], sizeof(buf2) -1, "%3.3f" , (dfreq + 500) / 1000000.0); + else if (resolution <= 20000) + plot_printf(&buf2[1], sizeof(buf2) -1, "%3.2f" , (dfreq + 5000) / 1000000.0); + else + plot_printf(&buf2[1], sizeof(buf2) -1, "%3.1f" , (dfreq + 50000) / 1000000.0); + } +#else + int digits = 1; + if (resolution <= 2000) + digits = 3; + else if (resolution <= 20000) + digits = 2; + plot_printf(&buf2[1], sizeof(buf2) -1, "%3.*f" , digits, (dfreq + 50000) / 1000000.0); + } +#endif + // frequency_string(&buf2[1], sizeof(buf2) -1, dfreq); + v = value(coeff[i]); + if (mtype & M_NOISE) + v = v - 10*log10(actual_rbw*1000.0); + if (v == -INFINITY) + plot_printf(buf, len, "-INF"); + else { + v = v - rlevel; + if (UNIT_IS_LINEAR(setting.unit)) { + plot_printf(buf3, sizeof(buf3), "%.3F", v); // 5 characters incl u,m,etc... + } else { + plot_printf(buf3, sizeof(buf3), "%.1f", v); + } + plot_printf(buf, len, "%s %s%s%s", buf2, buf3, unit_string[unit_index],(mtype & M_NOISE?"/Hz":"")); + } +} +#ifdef __VNA__ static int trace_get_info(int t, char *buf, int len) { @@ -773,6 +953,7 @@ static float distance_of_index(int idx) ((float)(frequencies[1] - frequencies[0]) * (float)FFT_SIZE * 2.0); return distance * velocity_factor; } +#endif static inline void mark_map(int x, int y) @@ -1028,7 +1209,7 @@ markmap_marker(int marker) int t; if (!markers[marker].enabled) return; - for (t = 0; t < TRACES_MAX; t++) { + for (t = TRACE_ACTUAL; t <= TRACE_ACTUAL; t++) { if (!trace[t].enabled) continue; index_t index = trace_index[t][markers[marker].index]; @@ -1038,7 +1219,7 @@ markmap_marker(int marker) } } -static void +void markmap_all_markers(void) { int i; @@ -1058,10 +1239,10 @@ marker_position(int m, int t, int *x, int *y) *y = CELL_Y(index); } -static int greater(int x, int y) { return x > y; } -static int lesser(int x, int y) { return x < y; } +static int greater(int x, int y, int d) { return x - d > y; } +static int lesser(int x, int y, int d) { return x - d < y; } -static int (*compare)(int x, int y) = lesser; +static int (*compare)(int x, int y, int d) = greater; int marker_search(void) @@ -1072,11 +1253,11 @@ marker_search(void) if (uistat.current_trace == -1) return -1; - int value = CELL_Y(trace_index[uistat.current_trace][0]); + int value = CELL_Y(trace_index[TRACE_ACTUAL][0]); for (i = 0; i < sweep_points; i++) { - index_t index = trace_index[uistat.current_trace][i]; - if ((*compare)(value, CELL_Y(index))) { - value = CELL_Y(index); + int new_value = CELL_Y(trace_index[TRACE_ACTUAL][i]); + if ((*compare)(value, new_value, 0)) { + value = new_value; found = i; } } @@ -1090,30 +1271,38 @@ set_marker_search(int mode) compare = (mode == 0) ? greater : lesser; } +int +search_is_greater(void) +{ + return(compare == greater); +} + +#define MINMAX_DELTA 10 + int marker_search_left(int from) { int i; int found = -1; - if (uistat.current_trace == -1) return -1; - int value = CELL_Y(trace_index[uistat.current_trace][from]); + int value = CELL_Y(trace_index[TRACE_ACTUAL][from]); for (i = from - 1; i >= 0; i--) { - index_t index = trace_index[uistat.current_trace][i]; - if ((*compare)(value, CELL_Y(index))) + int new_value = CELL_Y(trace_index[TRACE_ACTUAL][i]); + if ((*compare)(value, new_value, MINMAX_DELTA)) break; - value = CELL_Y(index); } for (; i >= 0; i--) { - index_t index = trace_index[uistat.current_trace][i]; - if ((*compare)(CELL_Y(index), value)) { + int new_value = CELL_Y(trace_index[TRACE_ACTUAL][i]); + if ((*compare)(new_value, value, -MINMAX_DELTA)) { break; } - found = i; - value = CELL_Y(index); + if ((*compare)(value, new_value, 0)) { + found = i; + value = new_value; + } } return found; } @@ -1126,22 +1315,22 @@ marker_search_right(int from) if (uistat.current_trace == -1) return -1; - - int value = CELL_Y(trace_index[uistat.current_trace][from]); + int value = CELL_Y(trace_index[TRACE_ACTUAL][from]); for (i = from + 1; i < sweep_points; i++) { - index_t index = trace_index[uistat.current_trace][i]; - if ((*compare)(value, CELL_Y(index))) + int new_value = CELL_Y(trace_index[TRACE_ACTUAL][i]); + if ((*compare)(value, new_value, MINMAX_DELTA)) break; - value = CELL_Y(index); + value = new_value; } - for (; i < sweep_points; i++) { - index_t index = trace_index[uistat.current_trace][i]; - if ((*compare)(CELL_Y(index), value)) { + int new_value = CELL_Y(trace_index[TRACE_ACTUAL][i]); + if ((*compare)(new_value, value, -MINMAX_DELTA)) { break; } - found = i; - value = CELL_Y(index); + if ((*compare)(value, new_value, 0)) { + found = i; + value = new_value; + } } return found; } @@ -1170,7 +1359,7 @@ search_nearest_index(int x, int y, int t) } void -plot_into_index(float measured[2][POINTS_COUNT][2]) +plot_into_index(measurement_t measured) { int t, i; for (t = 0; t < TRACES_MAX; t++) { @@ -1258,6 +1447,7 @@ draw_cell(int m, int n) } } } +#ifdef __VNA__ // Smith greed line (1000 system ticks for all screen calls) if (trace_type & (1 << TRC_SMITH)) { for (y = 0; y < h; y++) @@ -1281,6 +1471,7 @@ draw_cell(int m, int n) #endif #endif // PULSE; +#endif // Draw traces (50-600 system ticks for all screen calls, depend from lines // count and size) #if 1 @@ -1317,17 +1508,27 @@ draw_cell(int m, int n) for (i = 0; i < MARKERS_MAX; i++) { if (!markers[i].enabled) continue; - for (t = 0; t < TRACES_MAX; t++) { - if (!trace[t].enabled) - continue; +// for (t = 0; t < TRACES_MAX; t++) { +// if (!trace[t].enabled) +// continue; + t = TRACE_ACTUAL; index_t index = trace_index[t][markers[i].index]; int x = CELL_X(index) - x0 - X_MARKER_OFFSET; int y = CELL_Y(index) - y0 - Y_MARKER_OFFSET; // Check marker icon on cell +#if 1 + + if (x + MARKER_WIDTH >= 0 && x < CELLWIDTH && + y + MARKER_HEIGHT >= 0 && y < CELLHEIGHT) + draw_marker(x, y, marker_color(markers[i].mtype), i); +#else + if (x + MARKER_WIDTH >= 0 && x - MARKER_WIDTH < CELLWIDTH && y + MARKER_HEIGHT >= 0 && y - MARKER_HEIGHT < CELLHEIGHT) - draw_marker(x, y, config.trace_color[t], i); - } + draw_marker(x, y, marker_color(markers[i].mtype), i); +#endif + // draw_marker(x, y, config.trace_color[t], i); +// } } #endif // Draw trace and marker info on the top (50 system ticks for all screen calls) @@ -1335,7 +1536,10 @@ draw_cell(int m, int n) if (n == 0) cell_draw_marker_info(x0, y0); #endif -// PULSE; +#ifdef __SELFTEST__ + cell_draw_test_info(x0, y0); +#endif + // PULSE; // Draw reference position (<10 system ticks for all screen calls) for (t = 0; t < TRACES_MAX; t++) { if (!trace[t].enabled) @@ -1364,6 +1568,12 @@ draw_cell(int m, int n) ili9341_bulk(OFFSETX + x0, OFFSETY + y0, w, h); } +extern float peakLevel; +extern float min_level; +int w_max = -130; +int w_min = 0; + + static void draw_all_cells(bool flush_markmap) { @@ -1385,6 +1595,108 @@ draw_all_cells(bool flush_markmap) // clear map for next plotting clear_markmap(); } +#ifdef __SCROLL__ + int w = area_width; + if (w < 5) w = 5; + if (waterfall) { + for (m = 226; m >= HEIGHT+3; m -= 1) { // Scroll down + uint16_t *buf = &spi_buffer[0]; + ili9341_read_memory(6*5, m, w, 1, w, buf); + ili9341_bulk(6*5,m+1, w,1); + } + for (int i=0; i<290; i++) { // Add new topline +#if 0 + int k = (actual_t[i]+120 + 10)* 3 / 2; + unsigned int r=0,g=0,b=0; + if (k < 64) + r = k*4; + else if (k<128) { + r = 255; + g = (k-64)*4; + } else { + r = 255; + g = 255; + b = (k-128)*4; + } +#else + if (w_min > (int)min_level) + w_min = (int)min_level; + if (w_max < (int)peakLevel) + w_max = (int)peakLevel; +/* + def rgb(minimum, maximum, value): + minimum, maximum = float(minimum), float(maximum) + ratio = 2 * (value-minimum) / (maximum - minimum) + b = int(max(0, 255*(1 - ratio))) + r = int(max(0, 255*(ratio - 1))) + g = 255 - b - r + return r, g, b + */ + + int r,g,b; +#if 0 + int ratio = (int)(1024 * (actual_t[i] - w_min) / (w_max - w_min)); + + r = ratio - 512; + if (r<0) r=0; + b = (1024 - ratio*4) - 512; + if (b<0) b=0; + g = 512-r-b; + if (r>255) r=255; + if (g>255) g=255; + if (b>255) b=255; + +#define gamma_correct(X,L) X = (L + X * (255 - L)/255 ) + gamma_correct(r,160); + gamma_correct(g,160); + gamma_correct(b,160); + +#endif + +#if 1 + float ratio = (int)(510.0 * (actual_t[i] - w_min) / (w_max - w_min)); +// ratio = (i*2); // Uncomment for testing the waterfall colors + b = 255 - ratio; + if (b > 255) b = 255; + if (b < 0) b = 0; + r = ratio - 255; + if (r > 255) r = 255; + if (r < 0) r = 0; +// g = 255 - b; // if red is too weak to be seen..... + g = 255 - b - r; +#if 1 +#define gamma_correct(X) X = (X < 64 ? X * 2 : X < 128 ? 128 + (X-64) : X < 192 ? 192 + (X - 128)/2 : 225 + (X - 192) / 4) + gamma_correct(r); + gamma_correct(g); + gamma_correct(b); +#endif +#endif + +#if 0 + int k = (actual_t[i]+120)* 2 * 8; + k &= 255; + unsigned int r=0,g=0,b=0; + if (k < 64) { + b = 255; + g = k*2 + 128; + } else if (k < 128) { + g = 255; + b = 255 - (k-64)*2; + } else if (k < 192) { + g = 255; + r = (k-128)*2 + 128; + } else + { + g = 255 - (k-192)*2; + r = 255; + } +#endif +#endif + spi_buffer[i] = RGB565(r,g,b); + } + ili9341_bulk(6*5,HEIGHT+3, w,1); + } +#endif } void @@ -1428,7 +1740,10 @@ void request_to_draw_cells_behind_menu(void) { // Values Hardcoded from ui.c - invalidate_rect(320-70, 0, 319, 239); + if (current_menu_is_form()) + invalidate_rect(25, 0, LCD_WIDTH-1, LCD_HEIGHT-1); + else + invalidate_rect(LCD_WIDTH-60 - 25, 0, LCD_WIDTH-1, LCD_HEIGHT-1); redraw_request |= REDRAW_CELLS; } @@ -1436,7 +1751,7 @@ void request_to_draw_cells_behind_numeric_input(void) { // Values Hardcoded from ui.c - invalidate_rect(0, 240-32, 319, 239); + invalidate_rect(0, LCD_HEIGHT-32, LCD_WIDTH-1, LCD_HEIGHT-1); redraw_request |= REDRAW_CELLS; } @@ -1464,7 +1779,36 @@ cell_drawchar(uint8_t ch, int x, int y) return ch_size; } -static void +static int +cell_drawchar_size(uint8_t ch, int x, int y, int size) +{ + uint8_t bits; + int c, r, ch_size; + const uint8_t *char_buf = FONT_GET_DATA(ch); + ch_size = FONT_GET_WIDTH(ch); + // if (y <= -FONT_GET_HEIGHT || y >= CELLHEIGHT || x <= -ch_size || x >= CELLWIDTH) + // return ch_size; + if (x <= -ch_size*size) + return ch_size*size; + for (c = 0; c < FONT_GET_HEIGHT; c++) { + for (int i=0; i < size; i++) { + bits = *char_buf; + if ((y + c*size+i) < 0 || (y + c*size+i) >= CELLHEIGHT) + continue; + for (r = 0; r < ch_size; r++) { + for (int j = 0; j < size; j++) { + if ((x+r*size + j) >= 0 && (x+r*size+j) < CELLWIDTH && (0x80 & bits)) + cell_buffer[(y+c*size+i)*CELLWIDTH + (x+r*size+j)] = foreground_color; + } + bits <<= 1; + } + } + char_buf++; + } + return ch_size*size; +} + +void cell_drawstring(char *str, int x, int y) { if (y <= -FONT_GET_HEIGHT || y >= CELLHEIGHT) @@ -1476,6 +1820,55 @@ cell_drawstring(char *str, int x, int y) } } +void +cell_drawstring_size(char *str, int x, int y, int size) +{ + if (y <= -FONT_GET_HEIGHT*2 || y >= CELLHEIGHT) + return; + while (*str) { + if (x >= CELLWIDTH) + return; + x += cell_drawchar_size(*str++, x, y, size); + } +} + +static int +cell_drawchar_7x13(uint8_t ch, int x, int y) +{ + uint16_t bits; + int c, r, ch_size; + ch_size = 7; + // if (y <= -FONT_GET_HEIGHT || y >= CELLHEIGHT || x <= -ch_size || x >= CELLWIDTH) + // return ch_size; + if (x <= -ch_size) + return ch_size; + for (c = 0; c < 13; c++) { + bits = x7x13b_bits[(ch * 13) + c]; + if ((y + c) < 0 || (y + c) >= CELLHEIGHT) + continue; + for (r = 0; r < ch_size; r++) { + if ((x+r) >= 0 && (x+r) < CELLWIDTH && (0x8000 & bits)) + cell_buffer[(y+c)*CELLWIDTH + (x+r)] = foreground_color; + bits <<= 1; + } + } + return ch_size; +} + + +void +cell_drawstring_7x13(char *str, int x, int y) +{ + if (y <= -13 || y >= CELLHEIGHT) + return; + while (*str) { + if (x >= CELLWIDTH) + return; + x += cell_drawchar_7x13(*str++, x, y); + } +} + +#ifdef __VNA__ static void cell_draw_marker_info(int x0, int y0) { @@ -1601,15 +1994,167 @@ cell_draw_marker_info(int x0, int y0) cell_drawstring(buf, xpos, ypos); } } +#endif +static void cell_draw_marker_info(int x0, int y0) +{ + char buf[25]; + int t; + int ref_marker = 0; + int j = 0; + for (int i = 0; i < MARKER_COUNT; i++) { + if (markers[i].enabled && markers[i].mtype & M_REFERENCE) { + ref_marker = i; + break; + } + } + for (int i = 0; i < MARKER_COUNT; i++) { + if (i >= 2 && setting.measurement == M_OIP3 && markers[2].enabled && markers[3].enabled) { + float il = value((actual_t[markers[2].index])); + float ir = value((actual_t[markers[3].index])); + float sl = value((actual_t[markers[0].index])); + float sr = value((actual_t[markers[1].index])); + + float ip = sl+ (sr - il)/2; + plot_printf(buf, sizeof buf, "OIP3: %4.1fdB", ip); + j = 2; + int xpos = 1 + (j%2)*(WIDTH/2) + CELLOFFSETX - x0; + int ypos = 1 + (j/2)*(16) - y0; + cell_drawstring_7x13(buf, xpos, ypos); + + ip = sr+ (sl - ir)/2; + plot_printf(buf, sizeof buf, "OIP3: %4.1fdB", ip); + j = 3; + xpos = 1 + (j%2)*(WIDTH/2) + CELLOFFSETX - x0; + ypos = 1 + (j/2)*(16) - y0; + cell_drawstring_7x13(buf, xpos, ypos); + break; + } +#if 0 + if (i >= 2 && in_selftest) { + plot_printf(buf, sizeof buf, "DO NOT SWITCH OFF!!"); + j = 2; + int xpos = 1 + CELLOFFSETX +25 - x0; + int ypos = 1 + 16 - y0; + + cell_drawstring_7x13(buf, xpos, ypos); + break; + } +#endif + if (!markers[i].enabled) + continue; + int idx = markers[i].index; + int ridx = markers[ref_marker].index; + for (t = TRACE_ACTUAL; t <= TRACE_ACTUAL; t++) { // Only show info on actual trace + if (!trace[t].enabled) + continue; +#if 1 + int xpos = 1 + (j%2)*(WIDTH/2) + CELLOFFSETX - x0; +// int ypos = 1 + (j/2)*(13) - y0; + int ypos = 1 + (j/2)*(16) - y0; +#else + int xpos = 1 + CELLOFFSETX - x0; + int ypos = 1 + j*(FONT_GET_HEIGHT*2+1) - y0; +#endif + int k = 0; + if (i == active_marker) { +// ili9341_set_foreground(DEFAULT_BG_COLOR); +// ili9341_set_background(marker_color(markers[i].mtype)); + buf[k++] = '\033'; // Right arrow (?) + } else { +// ili9341_set_background(DEFAULT_BG_COLOR); +// ili9341_set_foreground(marker_color(markers[i].mtype)); + buf[k++] = ' '; +// buf[k++] = ' '; + } + buf[k++] = i+'1'; + if (markers[i].mtype & M_REFERENCE) + buf[k++] = 'R'; + if (markers[i].mtype & M_TRACKING) + buf[k++] = 'T'; + if (markers[i].mtype & M_DELTA) + buf[k++] = 'D'; + if (markers[i].mtype & M_NOISE) + buf[k++] = 'N'; + buf[k++] = ' '; + buf[k++] = 0; + ili9341_set_background(DEFAULT_BG_COLOR); + ili9341_set_foreground(marker_color(markers[i].mtype)); +// if (setting.unit) +// cell_drawstring(buf, xpos, ypos); +// else +// cell_drawstring_7x13(buf, xpos, ypos); + int offs = strlen(buf); + trace_get_value_string( + t, &buf[offs], (sizeof buf) - offs, + idx, measured[trace[t].channel], frequencies, sweep_points, ridx, markers[i].mtype); + if (strlen(buf)*7> WIDTH/2 ) + cell_drawstring(buf, xpos, ypos); + else + cell_drawstring_7x13(buf, xpos, ypos); + j++; + } + } +} +void frequency_string(char *buf, size_t len, int32_t freq) +{ + if (freq < 0) { + freq = -freq; + *buf++ = '-'; + len -= 1; + } +#ifdef __VNA__ + if (freq < 1000) { + plot_printf(buf, len, "%d Hz", (int)freq); + } else if (freq < 1000000) { + plot_printf(buf, len, "%d.%03d kHz", + (int)(freq / 1000), + (int)(freq % 1000)); + } else { + plot_printf(buf, len, "%d.%03d %03d MHz", + (int)(freq / 1000000), + (int)((freq / 1000) % 1000), + (int)(freq % 1000)); + } +#endif +#ifdef __SA__ +/* + if (freq < 1000) { + plot_printf(buf, len, "%dHz", (int)freq); + } else if (freq < 1000000) { + plot_printf(buf, len, "%d.%03dkHz", + (int)(freq / 1000), + (int)(freq % 1000)); + } else +*/ { + plot_printf(buf, len, "%d.%03", + (int)(freq / 1000000), + (int)((freq / 1000) % 1000)); + } +#endif +} void draw_frequencies(void) { char buf1[32]; char buf2[32]; buf2[0] = 0; + if (MODE_OUTPUT(setting.mode)) // No frequencies during output + return; + if (current_menu_is_form() && !in_selftest) + return; + +#ifdef __VNA__ if ((domain_mode & DOMAIN_MODE) == DOMAIN_FREQ) { +#endif if (FREQ_IS_CW()) { plot_printf(buf1, sizeof(buf1), " CW %qHz", get_sweep_frequency(ST_CW)); + float t = setting.actual_sweep_time; // in mS + ; // in mS + if (t>=1000) + plot_printf(buf2, sizeof(buf2), "%.2fS",t/1000.0); + else + plot_printf(buf2, sizeof(buf2), "%.2fmS", t); + } else if (FREQ_IS_STARTSTOP()) { plot_printf(buf1, sizeof(buf1), " START %qHz", get_sweep_frequency(ST_START)); plot_printf(buf2, sizeof(buf2), " STOP %qHz", get_sweep_frequency(ST_STOP)); @@ -1617,21 +2162,27 @@ draw_frequencies(void) plot_printf(buf1, sizeof(buf1), " CENTER %qHz", get_sweep_frequency(ST_CENTER)); plot_printf(buf2, sizeof(buf2), " SPAN %qHz", get_sweep_frequency(ST_SPAN)); } +#ifdef __VNA__ } else { plot_printf(buf1, sizeof(buf1), " START 0s"); plot_printf(buf2, sizeof(buf2), "STOP %Fs (%Fm)", time_of_index(sweep_points-1), distance_of_index(sweep_points-1)); } +#endif ili9341_set_foreground(DEFAULT_FG_COLOR); ili9341_set_background(DEFAULT_BG_COLOR); - ili9341_fill(0, FREQUENCIES_YPOS, 320, FONT_GET_HEIGHT, DEFAULT_BG_COLOR); + ili9341_fill(0, FREQUENCIES_YPOS, LCD_WIDTH, FONT_GET_HEIGHT, DEFAULT_BG_COLOR); if (uistat.lever_mode == LM_CENTER) buf1[0] = S_SARROW[0]; if (uistat.lever_mode == LM_SPAN) buf2[0] = S_SARROW[0]; + int p2 = FREQUENCIES_XPOS2; + if (FREQ_IS_CW()) { + p2 = LCD_WIDTH - 7*strlen(buf2); + } ili9341_drawstring(buf1, FREQUENCIES_XPOS1, FREQUENCIES_YPOS); - ili9341_drawstring(buf2, FREQUENCIES_XPOS2, FREQUENCIES_YPOS); + ili9341_drawstring(buf2, p2, FREQUENCIES_YPOS); } - +#ifdef __VNA__ void draw_cal_status(void) { @@ -1660,7 +2211,7 @@ draw_cal_status(void) if (cal_status & calibration_text[i].mask) ili9341_drawstring(&calibration_text[i].text, x, y); } - +#endif // Draw battery level #define BATTERY_TOP_LEVEL 4100 #define BATTERY_BOTTOM_LEVEL 3100 @@ -1692,7 +2243,7 @@ static void draw_battery_status(void) // string_buf[x++] = 0b10000001; string_buf[x++] = 0b11111111; // Draw battery - blit8BitWidthBitmap(1, 1, 8, x, string_buf); + blit8BitWidthBitmap(1, 200, 8, x, string_buf); } void @@ -1711,6 +2262,32 @@ redraw_frame(void) draw_cal_status(); } + +int get_waterfall(void) +{ + return(waterfall); +} + +void +toggle_waterfall(void) +{ + if (!waterfall) { + _height = HEIGHT_SCROLL; + ili9341_fill(5*5, HEIGHT, LCD_WIDTH - 5*5, 236-HEIGHT, 0); + waterfall = true; + fullscreen = false; + w_min = (int)min_level; + w_max = (int)peakLevel; + if (w_max < w_min + 20) + w_max = w_min + 20; + + } else { + _height = HEIGHT_NOSCROLL; + waterfall = false; + fullscreen = true; + } + request_to_redraw_grid(); +} void plot_init(void) { diff --git a/sa_cmd.c b/sa_cmd.c new file mode 100644 index 0000000..94176f6 --- /dev/null +++ b/sa_cmd.c @@ -0,0 +1,447 @@ + +extern volatile int SI4432_Sel; // currently selected SI4432 +void SI4432_Write_Byte(byte ADR, byte DATA ); +byte SI4432_Read_Byte( byte ADR ); +int VFO = 0; +int points = 101; // For 's' and 'm' commands + +VNA_SHELL_FUNCTION(cmd_mode) +{ + static const char cmd_low_high[] = "low|high"; + static const char cmd_in_out[] = "input|output"; + if (argc != 2) { + usage: + shell_printf("usage: mode %s %s\r\n", cmd_low_high,cmd_in_out); + return; + } + int lh = get_str_index(argv[0], cmd_low_high); + int io = get_str_index(argv[1], cmd_in_out); + if (lh<0 || io<0) + goto usage; + switch(lh+io*2) + { + case 0: + set_mode(M_LOW); + break; + case 1: + set_mode(M_HIGH); + break; + case 2: + set_mode(M_GENLOW); + break; + case 3: + set_mode(M_GENHIGH); + break; + } +} + +VNA_SHELL_FUNCTION(cmd_modulation ) +{ + static const char cmd_mod[] = "off|AM_1kHz|AM_10Hz|NFM|WFM|extern"; + if (argc != 1) { + usage: + shell_printf("usage: modulation %s\r\n", cmd_mod); + return; + } + static const int cmd_mod_val[] = { MO_NONE, MO_AM_1kHz, MO_AM_10Hz, MO_NFM, MO_WFM, MO_EXTERNAL}; + int m = get_str_index(argv[1], cmd_mod); + if (m<0) + goto usage; + set_modulation(cmd_mod_val[m]); +} + +VNA_SHELL_FUNCTION(cmd_spur) +{ + if (argc != 1) { + usage: + shell_printf("usage: spur on|off\r\n"); + return; + } + if (strcmp(argv[0],"on") == 0) { + setting.spur = 1; + } else if (strcmp(argv[0],"off") == 0) { + setting.spur = 0; + } else + goto usage; +} + +VNA_SHELL_FUNCTION(cmd_load) +{ + if (argc != 1) { + usage: + shell_printf("usage: load 0..4\r\n"); + return; + } + int a = my_atoi(argv[0]); + if (0 <= a && a <= 4) { + caldata_recall(a); + } else + goto usage; +} + + +VNA_SHELL_FUNCTION(cmd_attenuate) +{ + if (argc != 1) { + usage: + shell_printf("usage: attenuate 0..31|auto\r\n"); + return; + } + if (strcmp(argv[0],"auto") == 0) { + set_auto_attenuation(); + } else { + int a = my_atoi(argv[0]); + if (a < 0 || a>31) + goto usage; + set_attenuation(a); + } +} + +VNA_SHELL_FUNCTION(cmd_level) +{ + if (argc != 1) { + shell_printf("usage: level -76..-6\r\n"); + return; + } + float f = my_atof(argv[0]); + set_level(f); +} + + + +VNA_SHELL_FUNCTION(cmd_levelsweep) +{ + if (argc != 1) { + shell_printf("usage: levelsweep -76..+76\r\n"); + return; + } + float f = my_atof(argv[0]); + set_level_sweep(f); +} + +VNA_SHELL_FUNCTION(cmd_leveloffset) +{ + if (argc == 0) { + shell_printf("leveloffset low %.1f\r\n", (float) config.low_level_offset); + shell_printf("leveloffset high %.1f\r\n", (float)config.high_level_offset); + return; + } else if (argc == 2) { + float v = my_atof(argv[1]); + if (strcmp(argv[0],"low") == 0) + config.low_level_offset = v; + else if (strcmp(argv[0],"high") == 0) + config.low_level_offset = v; + else + goto usage; + } else { + usage: + shell_printf("leveloffset [low|high] []\r\n"); + } +} + + +VNA_SHELL_FUNCTION(cmd_rbw) +{ + if (argc != 1) { + usage: + shell_printf("usage: rbw 2..600|auto\r\n"); + return; + } + if (strcmp(argv[0],"auto") == 0 || strcmp(argv[0],"0") == 0) { + set_RBW(0); + } else { + int a = my_atoi(argv[0]); + if (a < 2 || a>600) + goto usage; + set_RBW(a); + } +} + +VNA_SHELL_FUNCTION(cmd_if) +{ + if (argc != 1) { + usage: + shell_printf("usage: if {433M..435M}\r\n"); + return; + } else { + int a = my_atoi(argv[0]); + if (a!= 0 &&( a < 433000000 || a>435000000)) + goto usage; + setting.auto_IF = false; + set_IF(a); + } +} + + +VNA_SHELL_FUNCTION(cmd_v) + + +{ + if (argc != 1) { + shell_printf("%d\r\n", SI4432_Sel); + return; + } + VFO = my_atoi(argv[0]); + shell_printf("VFO %d\r\n", VFO); +} + +int xtoi(char *t) +{ + + int v=0; + while (*t) { + if ('0' <= *t && *t <= '9') + v = v*16 + *t - '0'; + else if ('a' <= *t && *t <= 'f') + v = v*16 + *t - 'a' + 10; + else if ('A' <= *t && *t <= 'F') + v = v*16 + *t - 'A' + 10; + else + return v; + t++; + } + return v; +} + +VNA_SHELL_FUNCTION(cmd_y) +{ + int rvalue; + int lvalue = 0; + if (argc != 1 && argc != 2) { + shell_printf("usage: y {addr(0-95)} [value(0-FF)]\r\n"); + return; + } + rvalue = xtoi(argv[0]); + SI4432_Sel = VFO; + if (argc == 2){ + lvalue = xtoi(argv[1]); + SI4432_Write_Byte(rvalue, lvalue); + } else { + lvalue = SI4432_Read_Byte(rvalue); + shell_printf("%x\r\n", lvalue); + } +} + +VNA_SHELL_FUNCTION(cmd_selftest) +{ + if (argc < 1 || argc > 2) { + shell_printf("usage: selftest (1-3) [arg]\r\n"); + return; + } + setting.test = my_atoi(argv[0]); + if (argc == 1) + setting.test_argument = 0; + else + setting.test_argument = my_atoi(argv[1]); + sweep_mode = SWEEP_SELFTEST; +} + +#ifdef __ULTRA_SA__ +VNA_SHELL_FUNCTION(cmd_x) +{ + uint32_t reg; + + + if (argc != 1) { + shell_printf("usage: x value(0-FFFFFFFF)\r\n"); + return; + } + reg = xtoi(argv[0]); + + if ((reg & 7) == 5) { + if (reg & (1<<22)) + VFO = 1; + else + VFO = 0; + reg &= ~0xc00000; // Force led to show lock + reg |= 0x400000; + } + + ADF4351_WriteRegister32(VFO, reg); + shell_printf("x=%x\r\n", reg); +} +#endif + + +VNA_SHELL_FUNCTION(cmd_i) +{ + int rvalue; +return; // Don't use!!!! + SI4432_Init(); + shell_printf("SI4432 init done\r\n"); + if (argc == 1) { + rvalue = xtoi(argv[0]); + set_switches(rvalue); + set_mode(rvalue); + shell_printf("SI4432 mode %d set\r\n", rvalue); + } +} + +VNA_SHELL_FUNCTION(cmd_o) +{ + (void) argc; + uint32_t value = my_atoi(argv[0]); + if (VFO == 0) + setting.frequency_IF = value; + set_freq(VFO, value); +} + +VNA_SHELL_FUNCTION(cmd_d) +{ + (void) argc; + (void) argv; +// int32_t a = my_atoi(argv[0]); +// setting.drive = a; +} + + +VNA_SHELL_FUNCTION(cmd_a) +{ + (void)argc; + if (argc != 1) { + shell_printf("a=%d\r\n", frequencyStart); + return; + } + int32_t value = my_atoi(argv[0]); + frequencyStart = value; +} + + +VNA_SHELL_FUNCTION(cmd_b) +{ + (void)argc; + if (argc != 1) { + shell_printf("b=%d\r\n", frequencyStop); + return; + } + int32_t value = my_atoi(argv[0]); + frequencyStop = value; +} + +VNA_SHELL_FUNCTION(cmd_t) +{ + (void)argc; + (void)argv; +} + +VNA_SHELL_FUNCTION(cmd_e) +{ + (void)argc; + if (argc != 1) { + shell_printf("e=%d\r\n", setting.tracking); + return; + } + setting.tracking = my_atoi(argv[0]); + if (setting.tracking == -1) + setting.tracking = false; + else + setting.tracking = true; + + if (argc >1) + frequencyExtra = my_atoi(argv[1]); +} + +VNA_SHELL_FUNCTION(cmd_s) +{ + (void)argc; + if (argc != 1) { + shell_printf("s=%d\r\n", points); + return; + } + points = my_atoi(argv[0]); +} + +void sweep_remote(void) +{ + int old_step = setting.frequency_step; + uint32_t f_step = (frequencyStop-frequencyStart)/ points; + setting.frequency_step = f_step; + streamPut(shell_stream, '{'); + dirty = true; + for (int i = 0; i>8) & 0xFF)); + // enable led + } + streamPut(shell_stream, '}'); + setting.frequency_step = old_step; + sweep_mode = 0; +} + +VNA_SHELL_FUNCTION(cmd_m) +{ + (void)argc; + (void)argv; + +// set_mode(0); +// setting.tracking = false; //Default test setup +// setting.step_atten = false; +// set_attenuation(0); +// set_reflevel(-10); +// set_sweep_frequency(ST_START,frequencyStart - setting.frequency_IF ); +// set_sweep_frequency(ST_STOP, frequencyStop - setting.frequency_IF); +// draw_cal_status(); + + pause_sweep(); +// update_rbw(); + chThdSleepMilliseconds(10); + sweep_mode = SWEEP_REMOTE; +// update_rbw(); +} + +VNA_SHELL_FUNCTION(cmd_p) +{ + (void)argc; +return; + int p = my_atoi(argv[0]); + int a = my_atoi(argv[1]); + if (p==5) + set_attenuation(-a); + if (p==6) + set_mode(a); + if (p==1) + if (get_refer_output() != a) + set_refer_output(a); +} + +VNA_SHELL_FUNCTION(cmd_w) +{ + (void)argc; + int p = my_atoi(argv[0]); +return; + set_RBW(p); +} + +VNA_SHELL_FUNCTION(cmd_correction) +{ + (void)argc; + if (argc == 0) { + shell_printf("index frequency value\r\n"); + for (int i=0; i= 1000) + a = 15.0 / 290.0; // time per step in CW mode with repeat + } + t = vbwSteps * sweep_points * (setting.spur ? 2 : 1) * ( (a + (setting.repeat - 1)* REPEAT_TIME/1000.0)); + } + return t; +} + + +void set_refer_output(int v) +{ + setting.refer = v; + dirty = true; +} + +void set_decay(int d) +{ + if (d < 0 || d > 200) + return; + setting.decay = d; + dirty = true; +} + +void set_noise(int d) +{ + if (d < 2 || d > 50) + return; + setting.noise = d; + dirty = true; +} + +void set_measurement(int m) +{ + setting.measurement = m; + if (m == M_LINEARITY) { + trace[TRACE_STORED].enabled = true; + for (int j = 0; j < setting._sweep_points; j++) + stored_t[j] = -150; + setting.linearity_step = 0; + setting.attenuate = 29; + setting.auto_attenuation = false; + } + dirty = true; +} +void set_drive(int d) +{ + setting.drive = d; + dirty = true; +} + +void set_level_sweep(float l) +{ + setting.level_sweep = l; + dirty = true; +} + +void set_sweep_time(float t) +{ + if (t < MINIMUM_SWEEP_TIME) + t = MINIMUM_SWEEP_TIME; + if (t > 600000.0) + t = 600000.0; + setting.sweep_time = t; + if (FREQ_IS_CW()) + update_grid(); // Really only needed in zero span mode + dirty = true; +} + +void set_tracking_output(int t) +{ + setting.tracking_output = t; + dirty = true; +} + +void toggle_tracking_output(void) +{ + setting.tracking_output = !setting.tracking_output; + dirty = true; +} + +void toggle_mute(void) +{ + setting.mute = !setting.mute; + dirty = true; +} + +void toggle_below_IF(void) +{ + if (S_IS_AUTO(setting.below_IF )) + setting.below_IF = false; + else if (setting.below_IF) + setting.below_IF = S_AUTO_OFF; + else + setting.below_IF = true; + dirty = true; +} + +void set_modulation(int m) +{ + setting.modulation = m; + dirty = true; +} + +void set_repeat(int r) +{ + if (r > 0 && r <= 100) { + setting.repeat = r; + dirty = true; + } +} + +void set_IF(int f) +{ + if (f == 0) + setting.auto_IF = true; + setting.frequency_IF = f; + dirty = true; +} + +#define POWER_STEP 0 // Should be 5 dB but appearently it is lower +#define POWER_OFFSET 15 +#define SWITCH_ATTENUATION 30 + + +void set_auto_attenuation(void) +{ + setting.auto_attenuation = true; + setting.attenuate = 30; +} + +void set_auto_reflevel(int v) +{ + setting.auto_reflevel = v; +} + +int get_attenuation(void) +{ + if (setting.mode == M_GENLOW) { + if (setting.step_atten) + return ( -(POWER_OFFSET + setting.attenuate - (setting.step_atten-1)*POWER_STEP + SWITCH_ATTENUATION)); + else + return ( -POWER_OFFSET - setting.attenuate + (setting.drive & 7) * 3); + } + return(setting.attenuate); +} + +void set_level(float v) +{ + setting.level = v; + set_attenuation((int)v); + dirty = true; +} + +void set_attenuation(int a) +{ + if (setting.mode == M_GENLOW) { + setting.drive = 8; // Start at lowest drive level; + a = a + POWER_OFFSET; + if (a > 0) { + setting.drive++; + a = a - 3; + } + if (a > 0) { + setting.drive++; + a = a - 3; + } + if (a > 0) { + setting.drive++; + a = a - 3; + } + if (a > 0) + a = 0; + if( a > - SWITCH_ATTENUATION) { + setting.step_atten = 0; + } else { + a = a + SWITCH_ATTENUATION; + setting.step_atten = 1; + } + a = -a; + } else { + setting.step_atten = 0; + setting.auto_attenuation = false; + } + if (a<0) + a = 0; + if (a> 31) + a=31; +// if (setting.attenuate == a) +// return; + setting.attenuate = a; + dirty = true; +} + +void set_storage(void) +{ + for (int i=0; i 360) + set_RBW(300); + dirty = true; +} +#endif + +void set_harmonic(int h) +{ + setting.harmonic = h; + minFreq = 684000000.0; + if (setting.harmonic * 240000000+434000000 > minFreq) + minFreq = setting.harmonic * 240000000.0+434000000.0; + maxFreq = 4360000000; + if (setting.harmonic != 0 && (960000000.0 * setting.harmonic + 434000000.0 )< 4360000000.0) + maxFreq = (960000000.0 * setting.harmonic + 434000000.0 ); + set_sweep_frequency(ST_START, (uint32_t) minFreq); + set_sweep_frequency(ST_STOP, (uint32_t) maxFreq); +} + +void set_step_delay(int d) +{ + + if ((2 <= d && d < 300) || d > 30000) + return; + setting.step_delay = d; + dirty = true; +} + +void set_average(int v) +{ + setting.average = v; + trace[TRACE_TEMP].enabled = (v != 0); + dirty = true; +} + +void toggle_LNA(void) +{ + if (S_IS_AUTO(setting.lna )) + setting.lna = false; + else if (setting.lna) + setting.lna = S_AUTO_OFF; + else + setting.lna = true; + dirty = true; +} + +void toggle_tracking(void) +{ + setting.tracking = !setting.tracking; + if (setting.tracking) { + set_refer_output(2); + set_sweep_frequency(ST_CENTER, 10000000); + set_sweep_frequency(ST_SPAN, 5000000); + } else { + set_refer_output(-1); + } + dirty = true; +} + +void toggle_AGC(void) +{ + if (S_IS_AUTO(setting.agc )) + setting.agc = false; + else if (setting.agc) + setting.agc = S_AUTO_ON; + else + setting.agc = true; + dirty = true; +} + +void set_unit(int u) +{ + if (setting.unit == u) + return; + float r = to_dBm(setting.reflevel); // Get neutral unit + float s = to_dBm(setting.scale); +// float t = setting.trigger; // Is always in dBm + // float m = r - NGRIDSY*s; + + setting.unit = u; // Switch unit + + r = value(r); // Convert to target unit + s = value(s); + if (UNIT_IS_LINEAR(setting.unit)) { + if (r < REFLEVEL_MIN) + r = REFLEVEL_MIN; // Minimum value to ensure display + if (r >REFLEVEL_MAX) + r = REFLEVEL_MAX; // Maximum value + set_scale(r/NGRIDY); + set_reflevel(setting.scale*NGRIDY); + if (S_IS_AUTO(setting.agc)) + setting.agc = S_AUTO_ON; + if (S_IS_AUTO(setting.lna)) + setting.lna = S_AUTO_OFF; + } else { + r = 10 * round((r*1.2)/10.0); + set_reflevel(r); + set_scale(10); + if (S_IS_AUTO(setting.agc)) + setting.agc = S_AUTO_ON; + if (S_IS_AUTO(setting.lna)) + setting.lna = S_AUTO_OFF; + } + plot_into_index(measured); + force_set_markmap(); + dirty = true; +} +float const unit_scale_value[]={1,0.001,0.000001,0.000000001,0.000000000001}; +const char * const unit_scale_text[]= {"","m", "u", "n", "p"}; + +void user_set_reflevel(float level) +{ + set_auto_reflevel(false); + if (UNIT_IS_LINEAR(setting.unit) && level < setting.scale*NGRIDY) { + set_scale(level/NGRIDY); + set_reflevel(setting.scale*NGRIDY); + } else + set_reflevel(level); +} + +void set_reflevel(float level) +{ + + if (UNIT_IS_LINEAR(setting.unit)) { + if (level < REFLEVEL_MIN) + level = REFLEVEL_MIN; + if (level > REFLEVEL_MAX) + level = REFLEVEL_MAX; + } + + setting.unit_scale_index = 0; + setting.unit_scale = 1.0; + while (UNIT_IS_LINEAR(setting.unit) && setting.unit_scale_index < sizeof(unit_scale_value)/sizeof(float) - 1) { + if (level > unit_scale_value[setting.unit_scale_index]) + break; + setting.unit_scale_index++; + } + setting.unit_scale = unit_scale_value[setting.unit_scale_index]; + + setting.reflevel = level; + set_trace_refpos(0, /* NGRIDY - */ level /* / get_trace_scale(0) */); + set_trace_refpos(1, /* NGRIDY - */ level /* / get_trace_scale(0) */ ); + set_trace_refpos(2, /* NGRIDY - */ level /* / get_trace_scale(0) */ ); + redraw_request |= REDRAW_AREA | REDRAW_CAL_STATUS; +// dirty = true; +} + +void round_reflevel_to_scale(void) { + int multi = floor((setting.reflevel + setting.scale/2)/setting.scale); + if (UNIT_IS_LINEAR(setting.unit)) { + if (multi < NGRIDY) { + setting.reflevel = setting.scale*10; // Never negative bottom + } + } else { + + } + setting.reflevel = multi*setting.scale; + set_trace_refpos(0,setting.reflevel); + set_trace_refpos(1,setting.reflevel); + set_trace_refpos(2,setting.reflevel); +} + +void user_set_scale(float s) +{ + if (UNIT_IS_LINEAR(setting.unit)) + set_auto_reflevel(false); + set_scale(s); + if (UNIT_IS_LINEAR(setting.unit) && setting.reflevel < setting.scale*NGRIDY) + set_reflevel(setting.scale*NGRIDY); +} + +void set_scale(float t) { + if (UNIT_IS_LINEAR(setting.unit)) { + if (t < REFLEVEL_MIN/10.0) + t = REFLEVEL_MIN/10.0; + if (t > REFLEVEL_MAX/10.0) + t = REFLEVEL_MAX/10.0; + } else { + if (t > 20.0) + t = 20.0; + else if (t < 1) + t = 1.0; + } + + float m = 1; +// t = t * 1.2; + while (t > 10) { m *= 10; t/=10; } + while (t < 1.0) { m /= 10; t*=10; } + if (t>5.0001) + t = 10.0; + else if (t>2.0001) + t = 5.0; + else if (t > 1.0001) + t = 2.0; + else + t = 1.0; + t = t*m; + setting.scale = t; + set_trace_scale(0, t); + set_trace_scale(1, t); + set_trace_scale(2, t); + round_reflevel_to_scale(); + redraw_request |= REDRAW_AREA | REDRAW_CAL_STATUS; +} + + +void set_offset(float offset) +{ + setting.offset = offset; + dirty = true; +} + +void show_stored_trace_at(float v) +{ + for (int j = 0; j < setting._sweep_points; j++) + stored_t[j] = v; + trace[TRACE_STORED].enabled = true; +} + +void set_trigger_level(float trigger_level) +{ + setting.trigger_level = trigger_level; + if (setting.trigger != T_AUTO) { + show_stored_trace_at(setting.trigger_level); + } + dirty = true; +} + +void set_trigger(int trigger) +{ + setting.trigger = trigger; + if (trigger == T_AUTO) { + trace[TRACE_STORED].enabled = false; + } else { + show_stored_trace_at(setting.trigger_level); + } + sweep_mode = SWEEP_ENABLE; + dirty = true; +} + + +//int GetRefpos(void) { +// return (NGRIDY - get_trace_refpos(2)) * get_trace_scale(2); +//} + +//int GetScale(void) { +// return get_trace_refpos(2); +//} +void set_mode(int m) +{ +#ifdef __ULTRA__ + if (m == 6) + m = M_ULTRA; +#endif + dirty = true; + if (setting.mode == m) + return; + reset_settings(m); +} + +void apply_settings(void) +{ + set_switches(setting.mode); + if (setting.mode == M_HIGH) + PE4302_Write_Byte(40); // Ensure defined input impedance of low port when using high input mode (power calibration) + else + PE4302_Write_Byte(setting.attenuate * 2); + SI4432_SetReference(setting.refer); + update_rbw(); + if (setting.frequency_step == 0.0) { + if (setting.step_delay <= 1) + actualStepDelay = 0; + else + actualStepDelay = setting.step_delay; + } else if (setting.step_delay < 2){ + if (actual_rbw >= 191.0) actualStepDelay = 280; + else if (actual_rbw >= 142.0) actualStepDelay = 350; + else if (actual_rbw >= 75.0) actualStepDelay = 450; + else if (actual_rbw >= 56.0) actualStepDelay = 650; + else if (actual_rbw >= 37.0) actualStepDelay = 700; + else if (actual_rbw >= 18.0) actualStepDelay = 1100; + else if (actual_rbw >= 9.0) actualStepDelay = 1700; + else if (actual_rbw >= 5.0) actualStepDelay = 3300; + else actualStepDelay = 6400; + if (setting.step_delay == 1) + actualStepDelay *= 2; + } else + actualStepDelay = setting.step_delay; +} + +//------------------------------------------ +#if 0 +#define CORRECTION_POINTS 10 + +static const uint32_t correction_frequency[CORRECTION_POINTS] = +{ 100000, 200000, 400000, 1000000, 2000000, 50000000, 100000000, 200000000, 300000000, 350000000 }; + +static const float correction_value[CORRECTION_POINTS] = +{ +4.0, +2.0, +1.5, +0.5, 0.0, 0.0, +1.0, +1.0, +2.5, +5.0 }; +#endif + +float get_frequency_correction(uint32_t f) +{ + if (!(setting.mode == M_LOW)) + return(0.0); + int i = 0; + while (f > config.correction_frequency[i] && i < CORRECTION_POINTS) + i++; + if (i >= CORRECTION_POINTS) + return(config.correction_value[CORRECTION_POINTS-1]); + if (i == 0) + return(config.correction_value[0]); + f = f - config.correction_frequency[i-1]; + uint32_t m = config.correction_frequency[i] - config.correction_frequency[i-1] ; + float cv = config.correction_value[i-1] + (config.correction_value[i] - config.correction_value[i-1]) * (float)f / (float)m; + return(cv); +} + + +float peakLevel; +float min_level; +uint32_t peakFreq; +int peakIndex; +float temppeakLevel; +int temppeakIndex; +static unsigned long old_freq[4] = { 0, 0, 0, 0 }; + + +void setupSA(void) +{ + SI4432_Init(); + old_freq[0] = 0; + old_freq[1] = 0; + SI4432_Sel = 0; + SI4432_Receive(); + + SI4432_Sel = 1; + SI4432_Transmit(0); + PE4302_init(); + PE4302_Write_Byte(0); +} + +void set_freq(int V, unsigned long freq) +{ + if (old_freq[V] != freq) { + if (V <= 1) { + SI4432_Sel = V; + if (freq < 240000000 || freq > 960000000) { + old_freq[V] = freq + 1; + return; + } + SI4432_Set_Frequency(freq); +#ifdef __ULTRA_SA__ + } else { + ADF4351_set_frequency(V-2,freq,3); +#endif + } + old_freq[V] = freq; + } +} + +void set_switch_transmit(void) { + SI4432_Write_Byte(0x0b, 0x1f);// Set switch to transmit + SI4432_Write_Byte(0x0c, 0x1d); +} + +void set_switch_receive(void) { + SI4432_Write_Byte(0x0b, 0x1d);// Set switch to receive + SI4432_Write_Byte(0x0c, 0x1f); +} + +void set_switch_off(void) { + SI4432_Write_Byte(0x0b, 0x1d);// Set both switch off + SI4432_Write_Byte(0x0c, 0x1f); +} + +void set_AGC_LNA(void) { + unsigned char v = 0x40; + if (S_STATE(setting.agc)) v |= 0x20; + if (S_STATE(setting.lna)) v |= 0x10; + SI4432_Write_Byte(0x69, v); +} + +void set_switches(int m) +{ + SI4432_Init(); + old_freq[0] = 0; + old_freq[1] = 0; +switch(m) { +case M_LOW: // Mixed into 0 +#ifdef __ULTRA__ +case M_ULTRA: +#endif + SI4432_Sel = 0; + SI4432_Receive(); + if (setting.step_atten) { + set_switch_transmit(); + } else { + set_switch_receive(); + } + set_AGC_LNA(); + + SI4432_Sel = 1; + if (setting.tracking_output) + set_switch_transmit(); + else + set_switch_off(); +// SI4432_Receive(); For noise testing only + SI4432_Transmit(setting.drive); + // SI4432_SetReference(setting.refer); + break; +case M_HIGH: // Direct into 1 +mute: + // SI4432_SetReference(-1); // Stop reference output + SI4432_Sel = 0; // both as receiver to avoid spurs + set_switch_receive(); + SI4432_Receive(); + + SI4432_Sel = 1; + SI4432_Receive(); + set_switch_receive(); + set_AGC_LNA(); + + break; +case M_GENLOW: // Mixed output from 0 + if (setting.mute) + goto mute; + SI4432_Sel = 0; + if (setting.step_atten) { + set_switch_off(); + } else { + set_switch_transmit(); + } + SI4432_Transmit(setting.drive); + + SI4432_Sel = 1; + if (setting.modulation == MO_EXTERNAL) { + set_switch_transmit(); // High input for external LO scuh as tracking output of other tinySA + SI4432_Receive(); + } else { + set_switch_off(); + SI4432_Transmit(12); // Fix LO drive a 10dBm + } + break; +case M_GENHIGH: // Direct output from 1 + if (setting.mute) + goto mute; + SI4432_Sel = 0; + SI4432_Receive(); + set_switch_receive(); + + SI4432_Sel = 1; + if (setting.drive < 8) { + set_switch_off(); + } else { + set_switch_transmit(); + } + SI4432_Transmit(setting.drive); + + break; + } + SI4432_Sel = 1; + SI4432_Write_Byte(0x73, 0); // Back to nominal offset + SI4432_Write_Byte(0x74, 0); + +} + +void update_rbw(void) +{ + if (setting.frequency_step > 0 && MODE_INPUT(setting.mode)) { + setting.vbw = (setting.frequency_step)/1000.0; + } else { + setting.vbw = 300; // trick to get right default rbw in zero span mode + } + actual_rbw = setting.rbw; + if (actual_rbw == 0) + actual_rbw = 2*setting.vbw; + if (actual_rbw < 2.6) + actual_rbw = 2.6; + if (actual_rbw > 600) + actual_rbw = 600; + + SI4432_Sel = MODE_SELECT(setting.mode); + actual_rbw = SI4432_SET_RBW(actual_rbw); + + if (setting.frequency_step > 0 && MODE_INPUT(setting.mode)) { + if (setting.step_delay==1) // Precise + vbwSteps = ((int)(2 * (setting.vbw + (actual_rbw/2)) / (actual_rbw / 2))); + else + vbwSteps = ((int)(2 * (setting.vbw + (actual_rbw/2)) / actual_rbw)); + + if (vbwSteps < 1) + vbwSteps = 1; + } else { + setting.vbw = actual_rbw; + vbwSteps = 1; + } + dirty = true; +} + +int binary_search_frequency(int f) +{ + int L = 0; + int R = (sizeof frequencies)/sizeof(int) - 1; + int fmin = f - ((int)actual_rbw ) * 1000; + int fplus = f + ((int)actual_rbw ) * 1000; + while (L <= R) { + int m = (L + R) / 2; + if ((int)frequencies[m] < fmin) + L = m + 1; + else if ((int)frequencies[m] > fplus) + R = m - 1; + else + return m; // index is m + } + return -1; +} + + +#define MAX_MAX 4 +int +search_maximum(int m, int center, int span) +{ + center = binary_search_frequency(center); + if (center < 0) + return false; + int from = center - span/2; + int found = false; + int to = center + span/2; + int cur_max = 0; // Always at least one maximum + int max_index[4]; + if (from<0) + from = 0; + if (to > setting._sweep_points-1) + to = setting._sweep_points-1; + temppeakIndex = 0; + temppeakLevel = actual_t[from]; + max_index[cur_max] = from; + int downslope = true; + + for (int i = from; i <= to; i++) { + if (downslope) { + if (temppeakLevel > actual_t[i]) { // Follow down + temppeakIndex = i; // Latest minimum + temppeakLevel = actual_t[i]; + } else if (temppeakLevel + setting.noise < actual_t[i]) { // Local minimum found + temppeakIndex = i; // This is now the latest maximum + temppeakLevel = actual_t[i]; + downslope = false; + } + } else { + if (temppeakLevel < actual_t[i]) { // Follow up + temppeakIndex = i; + temppeakLevel = actual_t[i]; + } else if (temppeakLevel - setting.noise > actual_t[i]) { // Local max found + + found = true; + int j = 0; // Insertion index + while (j= temppeakLevel) // Find where to insert + j++; + if (j < MAX_MAX) { // Larger then one of the previous found + int k = MAX_MAX-1; + while (k > j) { // Shift to make room for max + max_index[k] = max_index[k-1]; + // maxlevel_index[k] = maxlevel_index[k-1]; // Only for debugging + k--; + } + max_index[j] = temppeakIndex; + // maxlevel_index[j] = actual_t[temppeakIndex]; // Only for debugging + if (cur_max < MAX_MAX) { + cur_max++; + } + //STOP_PROFILE + } + temppeakIndex = i; // Latest minimum + temppeakLevel = actual_t[i]; + + downslope = true; + } + } + } + markers[m].index = max_index[0]; + return found; +} + +//static int spur_old_stepdelay = 0; +static const unsigned int spur_IF = 433800000; +static const unsigned int spur_alternate_IF = 433900000; +static const int spur_table[] = +{ + 580000, // 433.8 MHz table + 961000, + 1600000, + 1837000, // Real signal + 2755000, // Real signal + 2760000, + 2961000, + 4933000, + 4960000, + 6961000, + 6980000, + 8267000, + 8961000, + 10000000, + 10960000, + 11600000, + 16960000, + 22960000, + 28960000, + 29800000, + 38105000, + 49500000, +#ifdef IF_AT_4339 + 780000, // 433.9MHz table + 830000, + 880000, + 949000, + 1390000, + 1468000, + 1830000, + 1900000, + 2770000, + 2840000, + 2880000, + 4710000, + 4780000, + 4800000, + 4880000, + 6510000, + 6750000, + 6790000, + 6860000, + 7340000, + 8100000, + 8200000, + 8880000, +// 9970000, 10MHz!!!!!! + 10870000, + 11420000, + 14880000, + 16820000, +#endif +}; + +int binary_search(int f) +{ + int L = 0; + int R = (sizeof spur_table)/sizeof(int) - 1; + int fmin = f - ((int)actual_rbw ) * 1000; + int fplus = f + ((int)actual_rbw ) * 1000; + while (L <= R) { + int m = (L + R) / 2; + if (spur_table[m] < fmin) + L = m + 1; + else if (spur_table[m] > fplus) + R = m - 1; + else + return true; // index is m + } + return false; +} + + +int avoid_spur(int f) +{ +// int window = ((int)actual_rbw ) * 1000*2; +// if (window < 50000) +// window = 50000; + if (! setting.mode == M_LOW || !setting.auto_IF || actual_rbw > 300.0) + return(false); + return binary_search(f); +} + +static int modulation_counter = 0; + +static const int am_modulation[5] = { 4,0,1,5,7 }; +static const int nfm_modulation[5] = { 0, 2, 1, -1, -2}; +static const int wfm_modulation[5] = { 0, 190, 118, -118, -190 }; + +char age[POINTS_COUNT]; + +static int old_a = -150; + +float perform(bool break_on_operation, int i, uint32_t f, int tracking) +{ + if (i == 0 && dirty ) { // SCan initiation + apply_settings(); + scandirty = true; + dirty = false; + if (setting.spur) + setting.spur = 1; // resync spur in case of previous abort + } + + if (setting.mode == M_GENLOW && setting.level_sweep != 0.0) { + int a = setting.level + (i / 290.0) * setting.level_sweep; + if (a != old_a) { + old_a = a; + int d = 0; // Start at lowest drive level; + a = a + POWER_OFFSET; + if (a > 0) { + d++; + a = a - 3; + } + if (a > 0) { + d++; + a = a - 3; + } + if (a > 0) { + d++; + a = a - 3; + } + SI4432_Sel = 0; + SI4432_Drive(d); + if (a > 0) + a = 0; + if( a > - SWITCH_ATTENUATION) { + set_switch_transmit(); + } else { + a = a + SWITCH_ATTENUATION; + set_switch_receive(); + } + a = -a; + PE4302_Write_Byte(a * 2 ); + } + } + + if (setting.mode == M_LOW && S_IS_AUTO(setting.agc) && UNIT_IS_LOG(setting.unit)) { + unsigned char v; + static unsigned char old_v; + if (f < 500000) + v = 0x50; // Disable AGC and enable LNA + else + v = 0x60; // Enable AGC and disable LNA + if (old_v != v) { + SI4432_Write_Byte(0x69, v); + old_v = v; + } + } + if (MODE_OUTPUT(setting.mode) && (setting.modulation == MO_AM_1kHz||setting.modulation == MO_AM_10Hz)) { // AM modulation + int p = setting.attenuate * 2 + am_modulation[modulation_counter]; + if (p>63) + p = 63; + if (p<0) + p = 0; + PE4302_Write_Byte(p); + if (modulation_counter == 4) { // 3dB modulation depth + modulation_counter = 0; + } else { + modulation_counter++; + } + if (setting.modulation == MO_AM_10Hz) + my_microsecond_delay(20000); + else + my_microsecond_delay(200); +// chThdSleepMicroseconds(200); + + } else if (MODE_OUTPUT(setting.mode) && (setting.modulation == MO_NFM || setting.modulation == MO_WFM )) { //FM modulation + SI4432_Sel = 1; + int offset; + if (setting.modulation == MO_NFM ) { + offset = nfm_modulation[modulation_counter] ; + SI4432_Write_Byte(0x73, (offset & 0xff )); // Use frequency hopping channel for FM modulation + SI4432_Write_Byte(0x74, ((offset >> 8) & 0x03 )); // Use frequency hopping channel for FM modulation + } + else { + offset = wfm_modulation[modulation_counter] ; + SI4432_Write_Byte(0x73, (offset & 0xff )); // Use frequency hopping channel for FM modulation + SI4432_Write_Byte(0x74, ((offset >> 8) & 0x03 )); // Use frequency hopping channel for FM modulation + } + if (modulation_counter == 4) + modulation_counter = 0; + else + modulation_counter++; + my_microsecond_delay(200); +// chThdSleepMicroseconds(200); + } + + float RSSI = -150.0; + int t = 0; + do { // ------------- Acquisition loop ---------- + int offs = 0,sm; + uint32_t lf = (uint32_t)f; + if (vbwSteps > 1) { // Calculate sub steps + if (setting.step_delay == 1) + sm = 250; // steps of a quarter rbw + else + sm = 500; // steps of half the rbw + if (vbwSteps & 1) { // Uneven steps, center + offs = (t - (vbwSteps >> 1)) * sm; + } else { // Even, shift half step + offs = (t - (vbwSteps >> 1)) * sm + sm/2; + } + offs = (int)(offs * actual_rbw); + lf = (uint32_t)(f + offs); + } + + + + // --------------- Set all the LO's ------------------------ +#ifdef __SPUR__ + float spur_RSSI = 0; +#endif + + + if (MODE_INPUT(setting.mode) && i > 0 && FREQ_IS_CW()) + goto skip_LO_setting; // No LO changes during CW loop + + long local_IF; + again: + if (MODE_HIGH(setting.mode)) + local_IF = 0; + else { + if (setting.auto_IF) { + if (setting.spur) + local_IF = 433900000; + else + local_IF = 433800000; + } + else + local_IF = setting.frequency_IF; + } + if (setting.mode == M_LOW && tracking) { // Measure BPF + set_freq (0, local_IF + lf - reffer_freq[setting.refer]); // Offset so fundamental of reffer is visible + } else if (MODE_LOW(setting.mode)) { + if (setting.mode == M_LOW && !in_selftest && avoid_spur(f)) { + local_IF = spur_alternate_IF; +#ifdef __SPUR__ + } else if (setting.mode== M_LOW && setting.spur){ + if (S_IS_AUTO(setting.below_IF) && lf < 150000000) // if below 150MHz and auto_below_IF swap IF + { // else low/above IF + if (setting.spur == 1) + setting.below_IF = S_AUTO_ON; + else + setting.below_IF = S_AUTO_OFF; + } + else + local_IF = local_IF + (int)(actual_rbw < 350.0 ? setting.spur*300000 : 0 ); +#endif + } else { +// local_IF = setting.frequency_IF ; + } + if (setting.mode == M_GENLOW && setting.modulation == MO_EXTERNAL) // LO input via high port + local_IF += lf; + set_freq (0, local_IF); +#ifdef __ULTRA__ + } else if (setting.mode == M_ULTRA) { // No above/below IF mode in Ultra + local_IF = setting.frequency_IF + (int)(actual_rbw < 350.0 ? setting.spur*300000 : 0 ); + set_freq (0, local_IF); + // local_IF = setting.frequency_IF + (int)(actual_rbw < 300.0?setting.spur * 1000 * actual_rbw:0); +#endif + } else // This must be high mode + local_IF= 0; +#ifdef __ULTRA__ + if (setting.mode == M_ULTRA) { // Set LO to correct harmonic in Ultra mode +// if (lf > 3406000000 ) +// setFreq (1, local_IF/5 + lf/5); +// else + if (setting.spur != 1) { // Left of tables + if (lf > 3250000000 ) + set_freq (1, lf/5 - local_IF/5); + if (lf > 1250000000 ) + set_freq (1, lf/3 - local_IF/3); + else + set_freq (1, lf - local_IF); + + } else { // Right of tables + if (lf >= 2350000000) + set_freq (1, lf/5 + local_IF/5); + else + set_freq (1, lf/3 + local_IF/3); + } + } else +#endif + { // Else set LO ('s) +#ifdef __ULTRA_SA__ +//#define IF_1 2550000000 +#define IF_2 2025000000 // First IF in Ultra SA mode + + set_freq (2, IF_2 + lf); // Scanning LO up to IF2 + set_freq (3, IF_2 - 433800000); // Down from IF2 to fixed second IF in Ultra SA mode + set_freq (1, 433800000); // Second IF fixe in Ultra SA mode +#else + if (setting.mode == M_LOW && !setting.tracking && S_STATE(setting.below_IF)) + set_freq (1, local_IF-lf); + else + set_freq (1, local_IF+lf); +#endif + } + if (MODE_OUTPUT(setting.mode)) // No substepping and no RSSI in output mode + return(0); + + // ---------------- Prepare RSSI ---------------------- + + float signal_path_loss; + + skip_LO_setting: +#ifdef __FAST_SWEEP__ + if (i == 0 && setting.frequency_step == 0 && setting.trigger == T_AUTO && actualStepDelay == 0 && setting.repeat == 1 && setting.sweep_time < 1000) { + SI4432_Fill(MODE_SELECT(setting.mode), 0); + } +#endif + +#ifdef __ULTRA__ + if (setting.mode == M_ULTRA) + signal_path_loss = -15; // Loss in dB, -9.5 for v0.1, -12.5 for v0.2 + else +#endif + if (setting.mode == M_LOW) + signal_path_loss = -5.5; // Loss in dB, -9.5 for v0.1, -12.5 for v0.2 + else + signal_path_loss = +7; // Loss in dB (+ is gain) + + int wait_for_trigger = false; + int old_actual_step_delay = actualStepDelay; + if (i == 0 && setting.frequency_step == 0 && setting.trigger != T_AUTO) { // prepare for wait for trigger to happen + wait_for_trigger = true; + actualStepDelay = 0; // fastest possible in zero span trigger mode + } + float subRSSI; + + static float correct_RSSI; + if (i == 0 || setting.frequency_step != 0 ) // only cases where the value can change + correct_RSSI = get_level_offset()+ setting.attenuate - signal_path_loss - setting.offset + get_frequency_correction(f); + wait: + subRSSI = SI4432_RSSI(lf, MODE_SELECT(setting.mode)) + correct_RSSI ; +// if ( i < 3) +// shell_printf("%d %.3f %.3f %.1f\r\n", i, local_IF/1000000.0, lf/1000000.0, subRSSI); + + if (wait_for_trigger) { // wait for trigger to happen + if ((operation_requested || shell_function) && break_on_operation) + break; // abort + if (subRSSI < setting.trigger_level) + goto wait; +#ifdef __FAST_SWEEP__ + if (i == 0 && setting.frequency_step == 0 /* && setting.trigger == T_AUTO */ && old_actual_step_delay == 0 && setting.repeat == 1 && setting.sweep_time < 1000) { + SI4432_Fill(MODE_SELECT(setting.mode), 1); + } +#endif + actualStepDelay = old_actual_step_delay; // Trigger happened, restore step delay + if (setting.trigger == T_SINGLE) + pause_sweep(); // Trigger once so pause after this sweep has completed!!!!!!! + } + +#ifdef __SPUR__ + if (setting.spur == 1) { // If first spur pass + spur_RSSI = subRSSI; + setting.spur = -1; + goto again; // Skip all other processing + } else if (setting.spur == -1) { // If second spur pass + subRSSI = ( subRSSI < spur_RSSI ? subRSSI : spur_RSSI); // Take minimum of two + setting.spur = 1; + } +#endif + + if (RSSI < subRSSI) // Take max during subscanning + RSSI = subRSSI; + t++; + if ((operation_requested || shell_function ) && break_on_operation) // break subscanning if requested + break; // abort + } while (t < vbwSteps); + return(RSSI); +} + +#define MAX_MAX 4 +int16_t max_index[MAX_MAX]; +int16_t cur_max = 0; + +static int low_count = 0; + + +// main loop for measurement +static bool sweep(bool break_on_operation) +{ + float RSSI; + int16_t downslope; +// if (setting.mode== -1) +// return; +// START_PROFILE; +again: + downslope = true; + palClearPad(GPIOB, GPIOB_LED); + temppeakLevel = -150; + float temp_min_level = 100; + // spur_old_stepdelay = 0; + int repeats = 1; +// shell_printf("\r\n"); + if (MODE_OUTPUT(setting.mode) && setting.modulation != MO_NONE) { + repeats = 1000; // to avoid interrupting the tone during UI processing + modulation_counter = 0; + } + float t = setting.sweep_time - calc_min_sweep_time(); // Time to delay in mS + if (t < 0) + t = 0; + t = t * 1000 / 290.0; // Now in uS per point + if (MODE_OUTPUT(setting.mode) && t < 500) // Minimum wait time to prevent LO from lockup + t = 500; + while (repeats--) { + for (int i = 0; i < sweep_points; i++) { + + RSSI = perform(break_on_operation, i, frequencies[i], setting.tracking); + if (MODE_INPUT(setting.mode) || setting.modulation == MO_NONE) { + if (t < 30000) + my_microsecond_delay((int)t); + else + osalThreadSleepMilliseconds(((int)t)/1000); + } + + // back to toplevel to handle ui operation + if ((operation_requested || shell_function) && break_on_operation) + return false; + if (MODE_OUTPUT(setting.mode)) { + continue; // Skip all other processing + } + + if (MODE_INPUT(setting.mode)) { + + if (setting.average != AV_OFF) + temp_t[i] = RSSI; + if (setting.subtract_stored) { + RSSI = RSSI - stored_t[i] ; + } +// stored_t[i] = (SI4432_Read_Byte(0x69) & 0x0f) * 3.0 - 90.0; // Display the AGC value in the stored trace + if (scandirty || setting.average == AV_OFF) { // Level calculations + actual_t[i] = RSSI; + age[i] = 0; + } else { + switch(setting.average) { + case AV_MIN: if (actual_t[i] > RSSI) actual_t[i] = RSSI; break; + case AV_MAX_HOLD: if (actual_t[i] < RSSI) actual_t[i] = RSSI; break; + case AV_MAX_DECAY: + if (actual_t[i] < RSSI) { + actual_t[i] = RSSI; + age[i] = 0; + } else { + if (age[i] > setting.decay) + actual_t[i] -= 0.5; + else + age[i] += 1; + } + break; + case AV_4: actual_t[i] = (actual_t[i]*3 + RSSI) / 4.0; break; + case AV_16: actual_t[i] = (actual_t[i]*15 + RSSI) / 16.0; break; + } + } +#if 1 + + // START_PROFILE + if (i == 0) { // Prepare peak finding + cur_max = 0; // Always at least one maximum + temppeakIndex = 0; + temppeakLevel = actual_t[i]; + max_index[0] = 0; + downslope = true; + } + if (downslope) { // If in down slope peak finding + if (temppeakLevel > actual_t[i]) { // Follow down + temppeakIndex = i; // Latest minimum + temppeakLevel = actual_t[i]; + } else if (temppeakLevel + setting.noise < actual_t[i] ) { // Local minimum found + temppeakIndex = i; // This is now the latest maximum + temppeakLevel = actual_t[i]; + downslope = false; + } + } else { // up slope peak finding + if (temppeakLevel < actual_t[i]) { // Follow up + temppeakIndex = i; + temppeakLevel = actual_t[i]; + } else if (actual_t[i] < temppeakLevel - setting.noise) { // Local max found + + + int j = 0; // Insert max in sorted table + while (j= temppeakLevel) // Find where to insert + j++; + if (j < MAX_MAX) { // Larger then one of the previous found + int k = MAX_MAX-1; + while (k > j) { // Shift to make room for max + max_index[k] = max_index[k-1]; + // maxlevel_index[k] = maxlevel_index[k-1]; // Only for debugging + k--; + } + max_index[j] = temppeakIndex; + // maxlevel_index[j] = actual_t[temppeakIndex]; // Only for debugging + if (cur_max < MAX_MAX) { + cur_max++; + } + //STOP_PROFILE + } + // Insert done + temppeakIndex = i; // Latest minimum + temppeakLevel = actual_t[i]; + + downslope = true; + } + } + } // end of peak finding +#else + if (frequencies[i] > 1000000) { + if (temppeakLevel < actual_t[i]) { + temppeakIndex = i; + temppeakLevel = actual_t[i]; + } + } +#endif + if (temp_min_level > actual_t[i]) // Remember minimum + temp_min_level = actual_t[i]; + + } + + if (setting.trigger != T_AUTO && setting.frequency_step > 0) { // Trigger active + if (actual_t[max_index[0]] < setting.trigger_level) { + goto again; + } else { + if (setting.trigger == T_SINGLE) + pause_sweep(); // Stop scanning after completing this sweep if above trigger + } + scandirty = true; // To show trigger happened + } + + if (scandirty) { + scandirty = false; + redraw_request |= REDRAW_CAL_STATUS; + } + + if (!in_selftest && setting.mode == M_LOW && setting.auto_attenuation && max_index[0] > 0) { // Auto attenuate + int old_attenuate = setting.attenuate; + float actual_max_level = actual_t[max_index[0]] - setting.attenuate; + if (actual_max_level < - 31 && setting.attenuate >= 10) { + setting.attenuate -= 10; + } else if (actual_max_level < - 26 && setting.attenuate >= 5) { + setting.attenuate -= 5; + } else if (actual_max_level > - 19 && setting.attenuate <= 20) { + setting.attenuate += 10; + } + if (old_attenuate != setting.attenuate) { + redraw_request |= REDRAW_CAL_STATUS; + PE4302_Write_Byte(setting.attenuate * 2); + // dirty = true; // Must be above if(scandirty!!!!!) + } + } + if (!in_selftest && MODE_INPUT(setting.mode) && S_IS_AUTO(setting.agc) && UNIT_IS_LINEAR(setting.unit)) { // Auto AGC in linear mode + unsigned char v; + static unsigned char old_v; + float actual_max_level = actual_t[max_index[0]] - setting.attenuate; + if (actual_max_level > - 45) + v = 0x50; // Disable AGC and enable LNA + else + v = 0x60; // Enable AGC and disable LNA + if (old_v != v) { + SI4432_Write_Byte(0x69, v); + old_v = v; + } + + } + if (max_index[0] > 0) + temppeakLevel = actual_t[max_index[0]]; + + float r = value(temppeakLevel); + float s_r = r / setting.scale; + + if (!in_selftest && MODE_INPUT(setting.mode) && setting.auto_reflevel) { // Auto reflevel + if (UNIT_IS_LINEAR(setting.unit)) { // Linear scales can not have negative values + if (setting.reflevel > REFLEVEL_MIN) { + if (s_r < 2) + low_count = 5; + else if (s_r < 4) + low_count++; + else + low_count = 0; + } + if ((low_count > 4) || (setting.reflevel < REFLEVEL_MAX && s_r > NGRIDY) ) { // ensure minimum and maximum reflevel + if (r < REFLEVEL_MIN) + r = REFLEVEL_MIN; + if (r > REFLEVEL_MAX) + r = REFLEVEL_MAX; + if (r != setting.reflevel) { + //if (setting.scale * NGRIDY > r) + set_scale(r / NGRIDY); + set_reflevel(setting.scale*NGRIDY); + dirty = false; // Prevent reset of SI4432 + redraw_request |= REDRAW_CAL_STATUS; + } + } + } else { + float s_min = value(temp_min_level)/setting.scale; + float s_ref = setting.reflevel/setting.scale; + if (s_r < s_ref - NGRIDY || s_min > s_ref) { //Completely outside + set_reflevel(setting.scale*(floor(s_r)+1)); + redraw_request |= REDRAW_CAL_STATUS; +// dirty = true; // Must be above if(scandirty!!!!!) + }else if (s_r > s_ref - 0.5 || s_min > s_ref - 8.8 ) { // maximum to high or minimum to high + set_reflevel(setting.reflevel + setting.scale); + redraw_request |= REDRAW_CAL_STATUS; +// dirty = true; // Must be above if(scandirty!!!!!) + } else if (s_min < s_ref - 10.1 && s_r < s_ref - 1.5) { // minimum to low and maximum can move up + set_reflevel(setting.reflevel - setting.scale); + redraw_request |= REDRAW_CAL_STATUS; +// dirty = true; // Must be above if(scandirty!!!!!) + } + dirty = false; // Prevent reset of SI4432 + } + } +#if 1 + if (MODE_INPUT(setting.mode)) { // Assign maxima found to tracking markers + int i = 0; + int m = 0; + while (i < cur_max) { // For all maxima found + while (m < MARKERS_MAX) { + if (markers[m].enabled && markers[m].mtype & M_TRACKING) { // Available marker found + markers[m].index = max_index[i]; + markers[m].frequency = frequencies[markers[m].index]; + m++; + break; // Next maximum + } + m++; // Try next marker + } + i++; + } + while (m < MARKERS_MAX) { // Insufficient maxima found + if (markers[m].enabled && markers[m].mtype & M_TRACKING) { // More available markers found + markers[m].index = 0; // Enabled but no max so set to left most frequency + markers[m].frequency = frequencies[markers[m].index]; + } + m++; // Try next marker + } +#ifdef __MEASURE__ + if (setting.measurement == M_IMD && markers[0].index > 10) { // IMD measurement + markers[1].enabled = search_maximum(1, frequencies[markers[0].index]*2, 8); + markers[2].enabled = search_maximum(2, frequencies[markers[0].index]*3, 12); + markers[3].enabled = search_maximum(3, frequencies[markers[0].index]*4, 16); + } else if (setting.measurement == M_OIP3 && markers[0].index > 10 && markers[1].index > 10) { // IOP measurement + int l = markers[0].index; + int r = markers[1].index; + if (r < l) { + l = markers[1].index; + r = markers[0].index; + markers[0].index = l; + markers[1].index = r; + } + uint32_t lf = frequencies[l]; + uint32_t rf = frequencies[r]; + markers[2].enabled = search_maximum(2, lf - (rf - lf), 12); + markers[3].enabled = search_maximum(3, rf + (rf - lf), 12); + } else if (setting.measurement == M_PHASE_NOISE && markers[0].index > 10) { // Phase noise measurement + markers[1].index = markers[0].index + (setting.mode == M_LOW ? 290/4 : -290/4); // Position phase noise marker at requested offset + } else if (setting.measurement == M_STOP_BAND && markers[0].index > 10) { // Stop band measurement + markers[1].index = marker_search_left_min(markers[0].index); + if (markers[1].index < 0) markers[1].index = 0; + markers[2].index = marker_search_right_min(markers[0].index); + if (markers[2].index < 0) markers[1].index = setting._sweep_points - 1; + } else if (setting.measurement == M_PASS_BAND && markers[0].index > 10) { // Pass band measurement + int t = markers[0].index; + float v = actual_t[t]; + while (t > 0 && actual_t[t] > v - 3.0) // Find left -3dB point + t --; + if (t > 0) + markers[1].index = t; + t = markers[0].index; + while (t < setting._sweep_points - 1 && actual_t[t] > v - 3.0) // find right -3dB point + t ++; + if (t < setting._sweep_points - 1 ) + markers[2].index = t; + } +#endif + peakIndex = max_index[0]; + peakLevel = actual_t[peakIndex]; + peakFreq = frequencies[peakIndex]; +#else + int peak_marker = 0; + markers[peak_marker].enabled = true; + markers[peak_marker].index = peakIndex; + markers[peak_marker].frequency = frequencies[markers[peak_marker].index]; +#endif + min_level = temp_min_level; + } + } + if (setting.measurement == M_LINEARITY && setting.linearity_step < setting._sweep_points) { + setting.attenuate = 29 - setting.linearity_step * 30 / 290; + dirty = true; + stored_t[setting.linearity_step] = peakLevel; + setting.linearity_step++; + } + + // redraw_marker(peak_marker, FALSE); +// STOP_PROFILE; + palSetPad(GPIOB, GPIOB_LED); + return true; +} + +//------------------------------- SEARCH --------------------------------------------- + +int +marker_search_left_max(int from) +{ + int i; + int found = -1; + if (uistat.current_trace == -1) + return -1; + + int value = actual_t[from]; + for (i = from - 1; i >= 0; i--) { + int new_value = actual_t[i]; + if (new_value < value) { + value = new_value; + found = i; + } else if (new_value > value + setting.noise ) + break; + } + + for (; i >= 0; i--) { + int new_value = actual_t[i]; + if (new_value > value) { + value = new_value; + found = i; + } else if (new_value < value - setting.noise ) + break; + } + return found; +} + +int +marker_search_right_max(int from) +{ + int i; + int found = -1; + + if (uistat.current_trace == -1) + return -1; + int value = actual_t[from]; + for (i = from + 1; i < sweep_points; i++) { + int new_value = actual_t[i]; + if (new_value < value) { // follow down + value = new_value; + found = i; + } else if (new_value > value + setting.noise) // larger then lowest value + noise + break; // past the minimum + } + for (; i < sweep_points; i++) { + int new_value = actual_t[i]; + if (new_value > value) { // follow up + value = new_value; + found = i; + } else if (new_value < value - setting.noise) + break; + } + return found; +} + +#define MINMAX_DELTA 10 + + +int +marker_search_left_min(int from) +{ + int i; + int found = from; + if (uistat.current_trace == -1) + return -1; + + int value = actual_t[from]; + for (i = from - 1; i >= 0; i--) { + int new_value = actual_t[i]; + if (new_value > value) { + value = new_value; // follow up +// found = i; + } else if (new_value < value - MINMAX_DELTA ) + break; // past the maximum + } + + for (; i >= 0; i--) { + int new_value = actual_t[i]; + if (new_value < value) { + value = new_value; // follow down + found = i; + } else if (new_value > value + MINMAX_DELTA ) + break; + } + return found; +} + +int +marker_search_right_min(int from) +{ + int i; + int found = from; + + if (uistat.current_trace == -1) + return -1; + int value = actual_t[from]; + for (i = from + 1; i < sweep_points; i++) { + int new_value = actual_t[i]; + if (new_value > value) { // follow up + value = new_value; +// found = i; + } else if (new_value < value - MINMAX_DELTA) // less then largest value - noise + break; // past the maximum + } + for (; i < sweep_points; i++) { + int new_value = actual_t[i]; + if (new_value < value) { // follow down + value = new_value; + found = i; + } else if (new_value > value + MINMAX_DELTA) // larger then smallest value + noise + break; + } + return found; +} + + + + + +// -------------------------- CAL STATUS --------------------------------------------- +const char * const averageText[] = { "OFF", "MIN", "MAX", "MAXD", " A 4", "A 16"}; +const char * const dBText[] = { "1dB/", "2dB/", "5dB/", "10dB/", "20dB/"}; +const int refMHz[] = { 30, 15, 10, 4, 3, 2, 1 }; + +float my_round(float v) +{ + float m = 1; + int sign = 1; + if (v < 0) { + sign = -1; + v = -v; + } + while (v < 100) { + v = v * 10; + m = m / 10; + } + while (v > 1000) { + v = v / 10; + m = m * 10; + } + v = (int)(v+0.5); + v = v * m; + if (sign == -1) { + v = -v; + } + return v; +} + +const char * const unit_string[] = { "dBm", "dBmV", "dBuV", "V", "W", "dBc", "dBmVc", "dBuVc", "Vc", "Wc" }; // unit + 5 is delta unit + +static const float scale_value[]={50000, 20000, 10000, 5000, 2000, 1000, 500, 200, 100, 50, 20,10,5,2,1,0.5,0.2,0.1,0.05,0.02,0.01,0.005,0.002, 0.001,0.0005,0.0002, 0.0001}; +static const char * const scale_vtext[]= {"50000", "20000", "10000", "5000", "2000", "1000", "500", "200", "100", "50", "20","10","5","2","1","0.5","0.2","0.1","0.05","0.02","0.01", "0.005","0.002","0.001", "0.0005","0.0002","0.0001"}; + + + +void draw_cal_status(void) +{ +#define BLEN 10 + char buf[BLEN]; +#define YSTEP 8 + int x = 0; + int y = OFFSETY; + unsigned int color; + int rounding = false; + if (!UNIT_IS_LINEAR(setting.unit)) + rounding = true; + const char * const unit = unit_string[setting.unit]; + + +#define XSTEP 40 + + if (MODE_OUTPUT(setting.mode)) { // No cal status during output + ili9341_fill(x, y, OFFSETX-5, HEIGHT, 0x0000); + return; + } + ili9341_fill(x, y, OFFSETX, HEIGHT, 0x0000); + + // if (current_menu_is_form() && !in_selftest) +// return; + + ili9341_set_background(DEFAULT_BG_COLOR); + + float yMax = setting.reflevel; + // Top level + if (rounding) + plot_printf(buf, BLEN, "%4d", (int)yMax); + else + plot_printf(buf, BLEN, "%.3F", (yMax/setting.unit_scale)); +// buf[5]=0; + if (level_is_calibrated()) { + if (setting.auto_reflevel) + color = DEFAULT_FG_COLOR; + else + color = BRIGHT_COLOR_GREEN; + } + else + color = BRIGHT_COLOR_RED; + ili9341_set_foreground(color); + ili9341_drawstring(buf, x, y); + + // Unit +#if 0 + color = DEFAULT_FG_COLOR; + ili9341_set_foreground(color); + if (setting.auto_reflevel){ + y += YSTEP + YSTEP/2 ; + ili9341_drawstring("AUTO", x, y); + } +#endif + y += YSTEP + YSTEP/2 ; + plot_printf(buf, BLEN, "%s%s",unit_scale_text[setting.unit_scale_index], unit); + ili9341_drawstring(buf, x, y); + + // Scale + color = DEFAULT_FG_COLOR; + ili9341_set_foreground(color); + y += YSTEP + YSTEP/2; +#if 1 + unsigned int i = 0; + while (i < sizeof(scale_value)/sizeof(float)) { + float t = (setting.scale/setting.unit_scale) / scale_value[i];; + if (t > 0.9 && t < 1.1){ + plot_printf(buf, BLEN, "%s%s/",scale_vtext[i],unit_scale_text[setting.unit_scale_index]); + break; + } + i++; + } +#else + plot_printf(buf, BLEN, "%.2F/",setting.scale); +#endif + ili9341_drawstring(buf, x, y); + + // Attenuation + if (setting.auto_attenuation) + color = DEFAULT_FG_COLOR; + else + color = BRIGHT_COLOR_GREEN; + ili9341_set_foreground(color); + y += YSTEP + YSTEP/2 ; + ili9341_drawstring("Attn:", x, y); + + y += YSTEP; + plot_printf(buf, BLEN, "%ddB", setting.attenuate); + buf[6]=0; + ili9341_drawstring(buf, x, y); + + // Average + if (setting.average>0) { + ili9341_set_foreground(BRIGHT_COLOR_BLUE); + y += YSTEP + YSTEP/2 ; + ili9341_drawstring("Calc:", x, y); + + y += YSTEP; + plot_printf(buf, BLEN, "%s",averageText[setting.average]); + buf[6]=0; + ili9341_drawstring(buf, x, y); + } + // Spur +#ifdef __SPUR__ + if (setting.spur) { + ili9341_set_foreground(BRIGHT_COLOR_GREEN); + y += YSTEP + YSTEP/2 ; + ili9341_drawstring("Spur:", x, y); + + y += YSTEP; + plot_printf(buf, BLEN, "ON"); + ili9341_drawstring(buf, x, y); + } +#endif + + // RBW + if (setting.rbw) + color = BRIGHT_COLOR_GREEN; + else + color = DEFAULT_FG_COLOR; + ili9341_set_foreground(color); + + y += YSTEP + YSTEP/2 ; + ili9341_drawstring("RBW:", x, y); + + y += YSTEP; + plot_printf(buf, BLEN, "%dkHz", (int)actual_rbw); + buf[6]=0; + ili9341_drawstring(buf, x, y); + + // VBW + if (setting.frequency_step > 0) { + ili9341_set_foreground(DEFAULT_FG_COLOR); + y += YSTEP + YSTEP/2 ; + ili9341_drawstring("VBW:", x, y); + + y += YSTEP; + plot_printf(buf, BLEN, "%dkHz",(int)setting.vbw); + buf[6]=0; + ili9341_drawstring(buf, x, y); + } + + // Sweep time + if (dirty) + color = BRIGHT_COLOR_RED; + else if (setting.step_delay) + color = BRIGHT_COLOR_GREEN; + else + color = DEFAULT_FG_COLOR; + + ili9341_set_foreground(color); + + y += YSTEP + YSTEP/2 ; + ili9341_drawstring("Scan:", x, y); + + y += YSTEP; + float t = calc_min_sweep_time(); + if (t < setting.sweep_time) + t = setting.sweep_time; + setting.actual_sweep_time = t; + if (t>=10000.0) + plot_printf(buf, BLEN, "%5d",(int)(t/1000)); + else if (t>=1000) + plot_printf(buf, BLEN, "%5f",t/1000.0); + else { + plot_printf(buf, BLEN, "%4dm",(int)t); + buf[4] = 'm'; + } + buf[5]='S'; + buf[6]=0; + ili9341_drawstring(buf, x, y); + + // Cal output + if (setting.refer >= 0) { + ili9341_set_foreground(BRIGHT_COLOR_RED); + y += YSTEP + YSTEP/2 ; + ili9341_drawstring("Ref:", x, y); + + y += YSTEP; + plot_printf(buf, BLEN, "%dMHz",reffer_freq[setting.refer]/1000000); + buf[6]=0; + ili9341_drawstring(buf, x, y); + } + + // Offset + if (setting.offset != 0.0) { + ili9341_set_foreground(BRIGHT_COLOR_RED); + y += YSTEP + YSTEP/2 ; + ili9341_drawstring("Amp:", x, y); + + y += YSTEP; + plot_printf(buf, BLEN, "%.1fdB",setting.offset); + buf[6]=0; + ili9341_drawstring(buf, x, y); + } + + // Repeat + if (setting.repeat != 1) { + ili9341_set_foreground(BRIGHT_COLOR_GREEN); + y += YSTEP + YSTEP/2 ; + ili9341_drawstring("Repeat:", x, y); + + y += YSTEP; + plot_printf(buf, BLEN, "%d",setting.repeat); + buf[6]=0; + ili9341_drawstring(buf, x, y); + } + + // Trigger + if (setting.trigger != T_AUTO) { + if (is_paused()) { + ili9341_set_foreground(BRIGHT_COLOR_GREEN); + } else { + ili9341_set_foreground(BRIGHT_COLOR_RED); + } + y += YSTEP + YSTEP/2 ; + ili9341_drawstring("TRIG:", x, y); + + y += YSTEP; + if (rounding) + plot_printf(buf, BLEN, "%4f", value(setting.trigger_level)); + else + plot_printf(buf, BLEN, "%.4F", value(setting.trigger_level)); +// plot_printf(buf, BLEN, "%4f", value(setting.trigger_level)/setting.unit_scale); + buf[6]=0; + ili9341_drawstring(buf, x, y); + } + + // Mode + if (level_is_calibrated()) + color = BRIGHT_COLOR_GREEN; + else + color = BRIGHT_COLOR_RED; + ili9341_set_foreground(color); + y += YSTEP + YSTEP/2 ; + if (MODE_LOW(setting.mode)) + ili9341_drawstring_7x13("LOW", x, y); + else + ili9341_drawstring_7x13("HIGH", x, y); + + // Compact status string +// ili9341_set_background(DEFAULT_FG_COLOR); + ili9341_set_foreground(DEFAULT_FG_COLOR); + y += YSTEP + YSTEP/2 ; + strncpy(buf," ",BLEN); + if (setting.auto_attenuation) + buf[0] = 'a'; + else + buf[0] = 'A'; + if (setting.auto_IF) + buf[1] = 'f'; + else + buf[1] = 'F'; + if (setting.auto_reflevel) + buf[2] = 'r'; + else + buf[2] = 'R'; + if (S_IS_AUTO(setting.agc)) + buf[3] = 'g'; + else if (S_STATE(setting.agc)) + buf[3] = 'G'; + if (S_IS_AUTO(setting.lna)) + buf[4] = 'n'; + else if (S_STATE(setting.lna)) + buf[4] = 'N'; + if (S_IS_AUTO(setting.below_IF)) + buf[5] = 'b'; + else if (S_STATE(setting.below_IF)) + buf[5] = 'B'; + ili9341_drawstring(buf, x, y); + + // Version + y += YSTEP + YSTEP/2 ; + strncpy(buf,&VERSION[8],6); + buf[6]=0; + ili9341_drawstring(buf, x, y); + +// ili9341_set_background(DEFAULT_BG_COLOR); + + // Bottom level + y = HEIGHT-7 + OFFSETY; + if (rounding) + plot_printf(buf, BLEN, "%4d", (int)(yMax - setting.scale * NGRIDY)); + else + plot_printf(buf, BLEN, "%.3F", ((yMax - setting.scale * NGRIDY)/setting.unit_scale)); +// buf[5]=0; + if (level_is_calibrated()) + if (setting.auto_reflevel) + color = DEFAULT_FG_COLOR; + else + color = BRIGHT_COLOR_GREEN; + else + color = BRIGHT_COLOR_RED; + ili9341_set_foreground(color); + ili9341_drawstring(buf, x, y); + +} + +// -------------------- Self testing ------------------------------------------------- + +enum { + TC_SIGNAL, TC_BELOW, TC_ABOVE, TC_FLAT, TC_MEASURE, TC_SET, TC_END, +}; + +enum { + TP_SILENT, TPH_SILENT, TP_10MHZ, TP_10MHZEXTRA, TP_10MHZ_SWITCH, TP_30MHZ, TPH_30MHZ +}; + +#define TEST_COUNT 17 + +static const struct { + int kind; + int setup; + float center; // In MHz + float span; // In MHz + float pass; + int width; + float stop; +} test_case [TEST_COUNT] = +{// Condition Preparation Center Span Pass Width Stop + {TC_BELOW, TP_SILENT, 0.005, 0.01, 0,0, 0}, // 1 Zero Hz leakage + {TC_BELOW, TP_SILENT, 0.01, 0.01, -30, 0, 0}, // 2 Phase noise of zero Hz + {TC_SIGNAL, TP_10MHZ, 20, 7, -37, 30, -90 }, // 3 + {TC_SIGNAL, TP_10MHZ, 30, 7, -32, 30, -90 }, // 4 + {TC_BELOW, TP_SILENT, 200, 100, -75, 0, 0}, // 5 Wide band noise floor low mode + {TC_BELOW, TPH_SILENT, 600, 720, -75, 0, 0}, // 6 Wide band noise floor high mode + {TC_SIGNAL, TP_10MHZEXTRA, 10, 8, -20, 80, -80 }, // 7 BPF loss and stop band + {TC_FLAT, TP_10MHZEXTRA, 10, 4, -18, 20, -60}, // 8 BPF pass band flatness + {TC_BELOW, TP_30MHZ, 430, 60, -80, 0, -80}, // 9 LPF cutoff + {TC_SIGNAL, TP_10MHZ_SWITCH,20, 7, -58, 30, -95 }, // 10 Switch isolation + {TC_END, 0, 0, 0, 0, 0, 0}, + {TC_MEASURE, TP_30MHZ, 30, 7, -22.5, 30, -70 }, // 12 Measure power level and noise + {TC_MEASURE, TP_30MHZ, 270, 4, -50, 30, -75 }, // 13 Measure powerlevel and noise + {TC_MEASURE, TPH_30MHZ, 270, 4, -40, 30, -65 }, // 14 Calibrate power high mode + {TC_END, 0, 0, 0, 0, 0, 0}, + {TC_MEASURE, TP_30MHZ, 30, 1, -20, 30, -70 }, // 16 Measure RBW step time + {TC_END, 0, 0, 0, 0, 0, 0}, +}; + +enum { + TS_WAITING, TS_PASS, TS_FAIL, TS_CRITICAL +}; +static const char *(test_text [4]) = +{ + "Waiting", "Pass", "Fail", "Critical" +}; +static const char *(test_fail_cause [TEST_COUNT]); + +static int test_status[TEST_COUNT]; +static int show_test_info = FALSE; +static volatile int test_wait = false; +static float test_value; + +static void test_acquire(int i) +{ + (void)i; + pause_sweep(); +#if 0 + if (test_case[i].center < 300) + setting.mode = M_LOW; + else + setting.mode = M_HIGH; +#endif +// SetAverage(4); + sweep(false); +// sweep(false); +// sweep(false); +// sweep(false); + plot_into_index(measured); + redraw_request |= REDRAW_CELLS | REDRAW_FREQUENCY; +} + +extern void cell_drawstring_5x7(int w, int h, char *str, int x, int y, uint16_t fg); +extern void cell_drawstring_7x13(int w, int h, char *str, int x, int y, uint16_t fg); +void cell_drawstring(char *str, int x, int y); + +static char self_test_status_buf[35]; +void cell_draw_test_info(int x0, int y0) +{ +#define INFO_SPACING 13 +// char self_test_status_buf[35]; + if (!show_test_info) + return; + int i = -2; + do { + i++; + int xpos = 25 - x0; + int ypos = 50+i*INFO_SPACING - y0; + unsigned int color = RGBHEX(0xFFFFFF); + if (i == -1) { + plot_printf(self_test_status_buf, sizeof self_test_status_buf, "Self test status:"); + } else if (test_case[i].kind == TC_END) { + if (test_wait) + plot_printf(self_test_status_buf, sizeof self_test_status_buf, "Touch screen to continue"); + else + self_test_status_buf[0] = 0; + } else { + plot_printf(self_test_status_buf, sizeof self_test_status_buf, "Test %d: %s%s", i+1, test_fail_cause[i], test_text[test_status[i]] ); + if (test_status[i] == TS_PASS) + color = RGBHEX(0x00FF00); + else if (test_status[i] == TS_CRITICAL) + color = RGBHEX(0xFFFF00); + else if (test_status[i] == TS_FAIL) + color = RGBHEX(0xFF7F7F); + else + color = RGBHEX(0x0000FF); + } + ili9341_set_foreground(color); + cell_drawstring(self_test_status_buf, xpos, ypos); + } while (test_case[i].kind != TC_END); +} + +#define fabs(X) ((X)<0?-(X):(X)) + +int validate_signal_within(int i, float margin) +{ + test_fail_cause[i] = "Signal level "; + if (fabs(peakLevel-test_case[i].pass) > 2*margin) { + return TS_FAIL; + } + if (fabs(peakLevel-test_case[i].pass) > margin) { + return TS_CRITICAL; + } + test_fail_cause[i] = "Frequency "; + if (peakFreq < test_case[i].center * 1000000 - 200000 || test_case[i].center * 1000000 + 200000 < peakFreq ) + return TS_FAIL; + test_fail_cause[i] = ""; + return TS_PASS; +} + +int validate_peak_below(int i, float margin) { + return(test_case[i].pass - peakLevel > margin); +} + +int validate_below(int tc, int from, int to) { + int status = TS_PASS; + float threshold=stored_t[from]; + float sum = 0; + int sum_count = 0; + for (int j = from; j < to; j++) { + sum += actual_t[j]; + sum_count++; + if (actual_t[j] > threshold) { + status = TS_FAIL; + break; + } + } + sum = sum / sum_count; + if (sum > threshold - 5) + status = TS_CRITICAL; + if (status != TS_PASS) + test_fail_cause[tc] = "Above "; + return(status); +} + +int validate_flatness(int i) { + volatile int j; + test_fail_cause[i] = "Passband "; + for (j = peakIndex; j < setting._sweep_points; j++) { + if (actual_t[j] < peakLevel - 6) // Search right -3dB + break; + } + //shell_printf("\n\rRight width %d\n\r", j - peakIndex ); + if (j - peakIndex < test_case[i].width) + return(TS_FAIL); + for (j = peakIndex; j > 0; j--) { + if (actual_t[j] < peakLevel - 6) // Search left -3dB + break; + } + //shell_printf("Left width %d\n\r", j - peakIndex ); + if (peakIndex - j < test_case[i].width) + return(TS_FAIL); + test_fail_cause[i] = ""; + return(TS_PASS); +} + +int validate_above(int tc) { + int status = TS_PASS; + for (int j = 0; j < setting._sweep_points; j++) { + if (actual_t[j] < stored_t[j] + 5) + status = TS_CRITICAL; + else if (actual_t[j] < stored_t[j]) { + status = TS_FAIL; + break; + } + } + if (status != TS_PASS) + test_fail_cause[tc] = "Below "; + return(status); +} + + +int test_validate(int i) +{ +// draw_all(TRUE); + int current_test_status = TS_PASS; + switch (test_case[i].kind) { + case TC_SET: + if (test_case[i].pass == 0) { + if (test_value != 0) + set_actual_power(test_value); + } else + set_actual_power(test_case[i].pass); + goto common; + case TC_MEASURE: + case TC_SIGNAL: // Validate signal + common: current_test_status = validate_signal_within(i, 5.0); + if (current_test_status == TS_PASS) { // Validate noise floor + current_test_status = validate_below(i, 0, setting._sweep_points/2 - test_case[i].width); + if (current_test_status == TS_PASS) { + current_test_status = validate_below(i, setting._sweep_points/2 + test_case[i].width, setting._sweep_points); + } + if (current_test_status != TS_PASS) + test_fail_cause[i] = "Stopband "; + } + if (current_test_status == TS_PASS && test_case[i].kind == TC_MEASURE) + test_value = peakLevel; + else + test_value = 0; // Not valid + break; + case TC_ABOVE: // Validate signal above curve + current_test_status = validate_above(i); + break; + case TC_BELOW: // Validate signal below curve + current_test_status = validate_below(i, 0, setting._sweep_points); + break; + case TC_FLAT: // Validate passband flatness + current_test_status = validate_flatness(i); + break; + + } + + // Report status + + if (current_test_status != TS_PASS || test_case[i+1].kind == TC_END) + test_wait = true; + test_status[i] = current_test_status; // Must be set before draw_all() !!!!!!!! + // draw_frequencies(); +// draw_cal_status(); + draw_all(TRUE); + resume_sweep(); + return current_test_status; +} + +void test_prepare(int i) +{ + setting.tracking = false; //Default test setup + setting.step_atten = false; + setting.frequency_IF = 433800000; // Default frequency + setting.auto_IF = true; + set_attenuation(0); + switch(test_case[i].setup) { // Prepare test conditions + case TPH_SILENT: // No input signal + set_mode(M_HIGH); + goto common_silent; + case TP_SILENT: // No input signal + set_mode(M_LOW); +common_silent: + set_refer_output(-1); + for (int j = 0; j < setting._sweep_points; j++) + stored_t[j] = test_case[i].pass; + break; + case TP_10MHZ_SWITCH: + set_mode(M_LOW); + set_refer_output(2); + setting.step_atten = true; + goto common; + case TP_10MHZEXTRA: // Swept receiver + set_mode(M_LOW); + setting.tracking = true; //Sweep BPF + setting.auto_IF = false; + setting.frequency_IF = 434000000; // Center on SAW filters + set_refer_output(2); + goto common; + case TP_10MHZ: // 10MHz input + set_mode(M_LOW); + set_refer_output(2); + set_step_delay(1); // Precise scanning speed +#ifdef __SPUR__ + setting.spur = 1; +#endif + common: + + for (int j = 0; j < setting._sweep_points/2 - test_case[i].width; j++) + stored_t[j] = test_case[i].stop; + for (int j = setting._sweep_points/2 + test_case[i].width; j < setting._sweep_points; j++) + stored_t[j] = test_case[i].stop; + for (int j = setting._sweep_points/2 - test_case[i].width; j < setting._sweep_points/2 + test_case[i].width; j++) + stored_t[j] = test_case[i].pass; + break; + case TP_30MHZ: + set_mode(M_LOW); + set_refer_output(0); + // set_step_delay(1); // Do not set !!!!! +#ifdef __SPUR__ + setting.spur = 1; +#endif + goto common; + case TPH_30MHZ: + set_mode(M_HIGH); + set_refer_output(0); + goto common; + } + setting.auto_attenuation = false; + setting.attenuate = 0; + trace[TRACE_STORED].enabled = true; + set_reflevel(test_case[i].pass+10); + set_sweep_frequency(ST_CENTER, (int32_t)(test_case[i].center * 1000000)); + set_sweep_frequency(ST_SPAN, (int32_t)(test_case[i].span * 1000000)); + draw_cal_status(); +} + +extern void menu_autosettings_cb(int item); +extern float SI4432_force_RBW(int i); + +int last_spur = 0; +int add_spur(int f) +{ + for (int i = 0; i < last_spur; i++) { + if (temp_t[i] == f) { + stored_t[i] += 1; + return stored_t[i]; + } + } + if (last_spur < 290) { + temp_t[last_spur] = f; + stored_t[last_spur++] = 1; + } + return 1; +} + + +void self_test(int test) +{ + if (test ==1) { + in_selftest = true; // Spur search + reset_settings(M_LOW); + test_prepare(4); + int f = 400000; // Start search at 400kHz + // int i = 0; // Index in spur table (temp_t) + float p2, p1, p; + +#define FREQ_STEP 3000 + + set_RBW(FREQ_STEP/1000); + last_spur = 0; + for (int j = 0; j < 10; j++) { + + p2 = perform(false, 0, f, false); + vbwSteps = 1; + f += FREQ_STEP; + p1 = perform(false, 1, f, false); + f += FREQ_STEP; + shell_printf("\n\rStarting with %4.2f, %4.2f and IF at %d\n\r", p2, p1, setting.frequency_IF); + + f = 400000; + while (f < 100000000) { + p = perform(false, 1, f, false); +#define SPUR_DELTA 6 + if ( p2 < p1 - SPUR_DELTA && p < p1 - SPUR_DELTA) { + // temp_t[i++] = f - FREQ_STEP; + shell_printf("Spur of %4.2f at %d with count %d\n\r", p1,(f - FREQ_STEP)/1000, add_spur(f - FREQ_STEP)); + } + // else + // shell_printf("%f at %d\n\r", p1,f - FREQ_STEP); + p2 = p1; + p1 = p; + f += FREQ_STEP; + } + } + shell_printf("\n\rTable for IF at %d\n\r", setting.frequency_IF); + for (int j = 0; j < last_spur; j++) { + if ((int)stored_t[j] > 1) + shell_printf("%d, %d\n\r", ((int)temp_t[j])/1000, (int)stored_t[j]); + } + } else if (test == 2) { + // Attenuator test + in_selftest = true; + reset_settings(M_LOW); + int i = 15; // calibrate attenuator at 30 MHz; + float reference_peak_level = 0; + test_prepare(i); + for (int j= 0; j < 32; j++ ) { + test_prepare(i); + set_attenuation(j); + float summed_peak_level = 0; + for (int k=0; k<10; k++) { + test_acquire(i); // Acquire test + test_validate(i); // Validate test + summed_peak_level += peakLevel; + } + peakLevel = summed_peak_level / 10; + if (j == 0) + reference_peak_level = peakLevel; + shell_printf("Target %d, actual %f, delta %f\n\r",j, peakLevel, peakLevel - reference_peak_level); + } + return; + } else if (test == 3) { + // RBW step time search + in_selftest = true; + reset_settings(M_LOW); + setting.auto_IF = false; + setting.frequency_IF=433900000; + ui_mode_normal(); + int i = 15; // calibrate low mode power on 30 MHz; + test_prepare(i); + setting.step_delay = 8000; + for (int j= 0; j < 57; j++ ) { + test_prepare(i); + setting.step_delay = setting.step_delay * 5 / 4; + setting.rbw = SI4432_force_RBW(j); + shell_printf("RBW = %d, ",setting.rbw); + set_sweep_frequency(ST_SPAN, (int32_t)(setting.rbw * 10000)); + setting.repeat = 10; + test_acquire(i); // Acquire test + test_validate(i); // Validate test + float saved_peakLevel = peakLevel; + if (peakLevel < -35) { + shell_printf("Peak level too low, abort\n\r"); + return; + } + + shell_printf("Start level = %f, ",peakLevel); + while (setting.step_delay > 10 && peakLevel > saved_peakLevel - 1) { + test_prepare(i); + setting.step_delay = setting.step_delay * 4 / 5; + // shell_printf("\n\rRBW = %f",SI4432_force_RBW(j)); + set_sweep_frequency(ST_SPAN, (int32_t)(setting.rbw * 10000)); + setting.repeat = 10; + test_acquire(i); // Acquire test + test_validate(i); // Validate test + // shell_printf(" Step %f, %d",peakLevel, setting.step_delay); + } + setting.step_delay = setting.step_delay * 5 / 4; + shell_printf("End level = %f, step time = %d\n\r",peakLevel, setting.step_delay); + } + } else if (test == 0) { + reset_settings(M_LOW); // Make sure we are in a defined state + in_selftest = true; + menu_autosettings_cb(0); + for (int i=0; i < TEST_COUNT; i++) { // All test cases waiting + if (test_case[i].kind == TC_END) + break; + test_status[i] = TS_WAITING; + test_fail_cause[i] = ""; + } + show_test_info = TRUE; + int i=0; + if (setting.test_argument > 0) + i=setting.test_argument-1; + do { + test_prepare(i); + test_acquire(i); // Acquire test + test_status[i] = test_validate(i); // Validate test + if (test_status[i] != TS_PASS) { + wait_user(); + } + i++; + } while (test_case[i].kind != TC_END && setting.test_argument == 0 ); + ili9341_set_foreground(BRIGHT_COLOR_GREEN); + ili9341_drawstring_7x13("Self test complete", 50, 200); + ili9341_drawstring_7x13("Touch screen to continue", 50, 215); + wait_user(); + ili9341_clear_screen(); + + sweep_mode = SWEEP_ENABLE; + show_test_info = FALSE; + set_refer_output(-1); + reset_settings(M_LOW); + in_selftest = false; + } +} + +void reset_calibration(void) +{ + config.high_level_offset = 100; + config.low_level_offset = 100; +} + +#define CALIBRATE_RBWS 1 +const int power_rbw [5] = { 100, 300, 30, 10, 3 }; + +void calibrate(void) +{ +#ifdef __CALIBRATE__ + int local_test_status; + in_selftest = true; + reset_calibration(); + reset_settings(M_LOW); + int i = 11; // calibrate low mode power on 30 MHz; + for (int j= 0; j < CALIBRATE_RBWS; j++ ) { + set_RBW(power_rbw[j]); + test_prepare(i); + test_acquire(i); // Acquire test + local_test_status = test_validate(i); // Validate test +// chThdSleepMilliseconds(1000); + if (local_test_status != TS_PASS) { + ili9341_set_foreground(BRIGHT_COLOR_RED); + ili9341_drawstring_7x13("Calibration failed", 30, 120); + goto quit; + } else { + set_actual_power(-22.5); // Should be -22.5dBm + chThdSleepMilliseconds(1000); + } + } +#if 0 // No high input calibration as CAL OUTPUT is unreliable + + i = 12; // Measure 270MHz in low mode + set_RBW(100); + test_prepare(i); + test_acquire(i); // Acquire test + float last_peak_level = peakLevel; + local_test_status = test_validate(i); // Validate test + chThdSleepMilliseconds(1000); + + config.high_level_offset = 0; /// Preliminary setting + + i = 13; // Calibrate 270MHz in high mode + for (int j = 0; j < CALIBRATE_RBWS; j++) { + set_RBW(power_rbw[j]); + test_prepare(i); + test_acquire(i); // Acquire test + local_test_status = test_validate(i); // Validate test +// if (local_test_status != TS_PASS) { // Do not validate due to variations in SI4432 +// ili9341_set_foreground(BRIGHT_COLOR_RED); +// ili9341_drawstring_7x13("Calibration failed", 30, 120); +// goto quit; +// } else + set_actual_power(last_peak_level); + chThdSleepMilliseconds(1000); + } + +#endif + + config_save(); + ili9341_set_foreground(BRIGHT_COLOR_GREEN); + ili9341_drawstring_7x13("Calibration complete", 30, 120); +quit: + ili9341_drawstring_7x13("Touch screen to continue", 30, 140); + wait_user(); + ili9341_clear_screen(); + + in_selftest = false; + sweep_mode = SWEEP_ENABLE; + set_refer_output(0); + reset_settings(M_LOW); +#endif +} + + diff --git a/si4432.c b/si4432.c new file mode 100644 index 0000000..d855249 --- /dev/null +++ b/si4432.c @@ -0,0 +1,995 @@ +/* Copyright (c) 2014-2015, TAKAHASHI Tomohiro (TTRFTECH) edy555@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 "ch.h" +#include "hal.h" +#include "nanovna.h" +#include +#include "si4432.h" + +#define CS_SI0_HIGH palSetPad(GPIOC, GPIO_RX_SEL) +#define CS_SI1_HIGH palSetPad(GPIOC, GPIO_LO_SEL) +#define CS_PE_HIGH palSetPad(GPIOC, GPIO_PE_SEL) + +#define RF_POWER_HIGH palSetPad(GPIOB, GPIO_RF_PWR) + + +#define CS_SI0_LOW palClearPad(GPIOC, GPIO_RX_SEL) +#define CS_SI1_LOW palClearPad(GPIOC, GPIO_LO_SEL) +#define CS_PE_LOW palClearPad(GPIOC, GPIO_PE_SEL) + +#define SPI2_CLK_HIGH palSetPad(GPIOB, GPIO_SPI2_CLK) +#define SPI2_CLK_LOW palClearPad(GPIOB, GPIO_SPI2_CLK) + +#define SPI2_SDI_HIGH palSetPad(GPIOB, GPIO_SPI2_SDI) +#define SPI2_SDI_LOW palClearPad(GPIOB, GPIO_SPI2_SDI) + +#define SPI2_SDO ((palReadPort(GPIOB) & (1< 6207) WISH=6207; // Final value in RBW_choices[] + if (WISH > 1379) dwn3 = 1 ; + for (i=3; i= (int)(sizeof RBW_choices) / 2 ) + return 0; + return(RBW_choices[i*4-1]); +} + +int setting_frequency_10mhz = 10000000; + +void set_10mhz(int f) +{ + setting_frequency_10mhz = f; +} + +int SI4432_frequency_changed = false; + +void SI4432_Set_Frequency ( long Freq ) { + int hbsel; + long Carrier; + if (Freq >= 480000000) { + hbsel = 1; + Freq = Freq / 2; + } else { + hbsel = 0; + } + int sbsel = 1; + long N = Freq / setting_frequency_10mhz; + Carrier = ( 4 * ( Freq - N * setting_frequency_10mhz )) / 625; + int Freq_Band = ( N - 24 ) | ( hbsel << 5 ) | ( sbsel << 6 ); +#if 0 + SI4432_Write_Byte ( 0x75, Freq_Band ); + SI4432_Write_Byte ( 0x76, (Carrier>>8) & 0xFF ); + SI4432_Write_Byte ( 0x77, Carrier & 0xFF ); +#else + SI4432_Write_3_Byte ( 0x75, Freq_Band, (Carrier>>8) & 0xFF, Carrier & 0xFF ); +#endif + SI4432_frequency_changed = true; +} + +int actualStepDelay = 1500; +//extern int setting.repeat; + +#ifdef __FAST_SWEEP__ +extern char age[POINTS_COUNT]; +static int buf_index = 0; +static bool buf_read = false; + +void SI4432_Fill(int s, int start) +{ + SI4432_Sel = s; + int sel = SI_nSEL[SI4432_Sel]; + float t = setting.sweep_time - calc_min_sweep_time(); // Time to delay in mS + if (t < 0) + t = 0; + int ti = t * 1000 / 290.0; // Now in uS per point if (t < 30000) + for (int i=start; i 0) { + my_microsecond_delay(100); + goto again; + } + if (setting.repeat > 1) + RSSI_RAW = RSSI_RAW / setting.repeat; + // if (MODE_INPUT(setting.mode) && RSSI_RAW == 0) + // SI4432_Init(); + float dBm = ((float)RSSI_RAW)/32.0 + SI4432_RSSI_correction; +#ifdef __SIMULATION__ + dBm = Simulated_SI4432_RSSI(i,s); +#endif +//STOP_PROFILE + // Serial.println(dBm,2); + return dBm ; +} + + +void SI4432_Sub_Init(void) +{ + SI4432_Reset(); + + + SI4432_Write_Byte(0x69, 0x60); //AGC override according to WBS3 + + +#if 0 // Not sure if these add any value + //set VCO and PLL Only for SI4432 V2 + SI4432_Write_Byte(0x72, 0x1F); //write 0x1F to the Frequency Deviation register + // VCO tuning registers + SI4432_Write_Byte(0x5A, 0x7F); //write 0x7F to the VCO Current Trimming register + SI4432_Write_Byte(0x58, 0x80); //write 0xD7 to the ChargepumpCurrentTrimmingOverride register + SI4432_Write_Byte(0x59, 0x40); //write 0x40 to the Divider Current Trimming register +#endif +#if 0 + //set the AGC, BAD FOR PERFORMANCE!!!!!! + SI4432_Write_Byte(0x6A, 0x0B); //write 0x0B to the AGC Override 2 register + //set ADC reference voltage to 0.9V, BAD FOR PERFORMANCE!!!!!! + SI4432_Write_Byte(0x68, 0x04); //write 0x04 to the Deltasigma ADC Tuning 2 register + + SI4432_Write_Byte(0x1F, 0x03); //write 0x03 to the Clock Recovery Gearshift Override register + +#endif + + + SI4432_Write_Byte(0x05, 0x0); + SI4432_Write_Byte(0x06, 0x0); + // Enable receiver chain +// SI4432_Write_Byte(0x07, 0x05); + // Clock Recovery Gearshift Value + SI4432_Write_Byte(0x1F, 0x00); + // IF Filter Bandwidth + SI4432_SET_RBW(10) ; +// // Register 0x75 Frequency Band Select +// byte sbsel = 1 ; // recommended setting +// byte hbsel = 0 ; // low bands +// byte fb = 19 ; // 430�439.9 MHz +// byte FBS = (sbsel << 6 ) | (hbsel << 5 ) | fb ; +// SI4432_Write_Byte(0x75, FBS) ; + SI4432_Write_Byte(0x75, 0x46) ; + // Register 0x76 Nominal Carrier Frequency + // WE USE 433.92 MHz + // Si443x-Register-Settings_RevB1.xls +// SI4432_Write_Byte(0x76, 0x62) ; + SI4432_Write_Byte(0x76, 0x00) ; + // Register 0x77 Nominal Carrier Frequency + SI4432_Write_Byte(0x77, 0x00) ; + // RX MODEM SETTINGS + SI4432_Write_3_Byte(0x1C, 0x81, 0x3C, 0x02) ; +// SI4432_Write_Byte(0x1C, 0x81) ; +// SI4432_Write_Byte(0x1D, 0x3C) ; +// SI4432_Write_Byte(0x1E, 0x02) ; + SI4432_Write_Byte(0x1F, 0x03) ; + // SI4432_Write_Byte(0x20, 0x78) ; + SI4432_Write_3_Byte(0x21, 0x01, 0x11, 0x11) ; +// SI4432_Write_Byte(0x21, 0x01) ; +// SI4432_Write_Byte(0x22, 0x11) ; +// SI4432_Write_Byte(0x23, 0x11) ; + SI4432_Write_Byte(0x24, 0x01) ; + SI4432_Write_Byte(0x25, 0x13) ; + SI4432_Write_Byte(0x2A, 0xFF) ; + + SI4432_Write_3_Byte(0x2C, 0x28, 0x0c, 0x28) ; +// SI4432_Write_Byte(0x2C, 0x28) ; +// SI4432_Write_Byte(0x2D, 0x0C) ; +// SI4432_Write_Byte(0x2E, 0x28) ; + + + SI4432_Write_Byte(0x69, 0x60); // AGC, no LNA, fast gain increment + + +// GPIO automatic antenna switching + SI4432_Write_Byte(0x0B, 0x12) ; // Normal + SI4432_Write_Byte(0x0C, 0x15) ; + +} + +#define V0_XTAL_CAPACITANCE 0x64 +#define V1_XTAL_CAPACITANCE 0x64 + + + +void SI4432_Init() +{ + + palClearPad(GPIOB, GPIO_RF_PWR); + chThdSleepMilliseconds(20); + palSetPad(GPIOB, GPIO_RF_PWR); + chThdSleepMilliseconds(20); + + + //DebugLine("IO set"); + SI4432_Sel = 0; + SI4432_Sub_Init(); + + SI4432_Sel = 1; + SI4432_Sub_Init(); +//DebugLine("1 init done"); + + SI4432_Sel = 0; +// SI4432_Receive();// Enable receiver chain +// SI4432_Write_Byte(0x09, V0_XTAL_CAPACITANCE);// Tune the crystal + SI4432_Set_Frequency(433800000); + SI4432_Write_Byte(0x0D, 0x1F) ; // Set GPIO2 output to ground + + + SI4432_Sel = 1; +// SI4432_Write_Byte(0x09, V1_XTAL_CAPACITANCE);// Tune the crystal + SI4432_Set_Frequency(443800000); + SI4432_Write_Byte(0x0D, 0x1F) ; // Set GPIO2 output to ground + + // SI4432_Write_Byte(0x6D, 0x1C);//Set low power +// SI4432_Transmit(0); + +// SI4432_Write_Byte(0x0D, 0xC0) ; // Set GPIO2 maximumdrive and clock output +// SI4432_Write_Byte(0x0A, 0x02) ; // Set 10MHz output +} + +void SI4432_SetReference(int freq) +{ + SI4432_Sel = 1; //Select Lo module + if (freq < 0 || freq > 7 ) { + SI4432_Write_Byte(0x0D, 0x1F) ; // Set GPIO2 to GND + } else { + SI4432_Write_Byte(0x0D, 0xC0) ; // Set GPIO2 maximumdrive and clock output + SI4432_Write_Byte(0x0A, freq & 0x07) ; // Set GPIO2 frequency + } +} + +//------------PE4302 ----------------------------------------------- + +// Comment out this define to use parallel mode PE4302 + +#define PE4302_en 10 + +void PE4302_init(void) { + CS_PE_LOW; +} + +#define PE4302_DELAY 100 +#if 0 +void PE4302_shiftOut(uint8_t val) +{ + uint8_t i; + SI4432_log(SI4432_Sel); + SI4432_log(val); + for (i = 0; i < 8; i++) { + if (val & (1 << (7 - i))) + SPI2_SDI_HIGH; + else + SPI2_SDI_LOW; +// chThdSleepMicroseconds(PE4302_DELAY); + SPI2_CLK_HIGH; +// chThdSleepMicroseconds(PE4302_DELAY); + SPI2_CLK_LOW; +// chThdSleepMicroseconds(PE4302_DELAY); + } +} +#endif +void PE4302_Write_Byte(unsigned char DATA ) +{ +// chThdSleepMicroseconds(PE4302_DELAY); + SPI2_CLK_LOW; +// chThdSleepMicroseconds(PE4302_DELAY); +// PE4302_shiftOut(DATA); + + shiftOut(DATA); +// chThdSleepMicroseconds(PE4302_DELAY); + CS_PE_HIGH; +// chThdSleepMicroseconds(PE4302_DELAY); + CS_PE_LOW; +// chThdSleepMicroseconds(PE4302_DELAY); + +} + +#endif + + + +#if 0 +//-----------------SI4432 dummy------------------ +void SI4432_Write_Byte(unsigned char ADR, unsigned char DATA ) {} +unsigned char SI4432_Read_Byte(unsigned char ADR) {return ADR;} +float SI4432_SET_RBW(float WISH) {return (WISH > 600.0?600: (WISH<3.0?3:WISH));} +void SI4432_SetReference(int p) {} +void SI4432_Set_Frequency(long f) {} +void PE4302_Write_Byte(unsigned char DATA ) {} +void PE4302_init(void) {} +#endif + +#ifdef __SIMULATION__ +unsigned long seed = 123456789; +extern float actual_rbw; +float myfrand(void) +{ + seed = (unsigned int) (1103515245 * seed + 12345) ; + return ((float) seed) / 1000000000.0; +} +#define NOISE ((myfrand()-2) * 2) // +/- 4 dBm noise +extern int settingAttenuate; + +//#define LEVEL(i, f, v) (v * (1-(fabs(f - frequencies[i])/actual_rbw/1000))) + +float LEVEL(uint32_t i, uint32_t f, int v) +{ + float dv; + float df = fabs((float)f - (float)i); + if (df < actual_rbw*1000) + dv = df/(actual_rbw*1000); + else + dv = 1 + 50*(df - actual_rbw*1000)/(actual_rbw*1000); + return (v - dv - settingAttenuate); +} + +float Simulated_SI4432_RSSI(uint32_t i, int s) +{ + SI4432_Sel = s; + float v = -100 + log10(actual_rbw)*10 + NOISE; + if(s == 0) { + v = fmax(LEVEL(i,10000000,-20),v); + v = fmax(LEVEL(i,20000000,-40),v); + v = fmax(LEVEL(i,30000000,-30),v); + v = fmax(LEVEL(i,40000000,-90),v); + } else { + v = fmax(LEVEL(i,320000000,-20),v); + v = fmax(LEVEL(i,340000000,-40),v); + v = fmax(LEVEL(i,360000000,-30),v); + v = fmax(LEVEL(i,380000000,-90),v); + } + return(v); +} + +#endif +//------------------------------- ADF4351 ------------------------------------- + +#ifdef __ULTRA_SA__ + +#define bitRead(value, bit) (((value) >> (bit)) & 0x01) +#define bitSet(value, bit) ((value) |= (1UL << (bit))) +#define bitClear(value, bit) ((value) &= ~(1UL << (bit))) +#define bitWrite(value, bit, bitvalue) (bitvalue ? bitSet(value, bit) : bitClear(value, bit)) + +#define CS_ADF0_HIGH palSetPad(GPIOA, 9) +#define CS_ADF1_HIGH palSetPad(GPIOA, 10) + +#define CS_ADF0_LOW palClearPad(GPIOA, 9) +#define CS_ADF1_LOW palClearPad(GPIOA, 10) + +#define SPI3_CLK_HIGH palSetPad(GPIOA, 1) +#define SPI3_CLK_LOW palClearPad(GPIOA, 1) + +#define SPI3_SDI_HIGH palSetPad(GPIOA, 2) +#define SPI3_SDI_LOW palClearPad(GPIOA, 2) + + +void ADF_shiftOut(uint8_t val) +{ + uint8_t i; + for (i = 0; i < 8; i++) { + if (val & (1 << (7 - i))) + SPI3_SDI_HIGH; + else + SPI3_SDI_LOW; +// chThdSleepMicroseconds(10); + SPI3_CLK_HIGH; +// chThdSleepMicroseconds(10); + SPI3_CLK_LOW; +// chThdSleepMicroseconds(10); + } +} + +//unsigned long registers[6] = {0x4580A8, 0x80080C9, 0x4E42, 0x4B3, 0xBC803C, 0x580005} ; +//unsigned long registers[6] = {0x4C82C8, 0x80083E9, 0x6E42, 0x8004B3, 0x8C81FC, 0x580005} ; + +//uint32_t registers[6] = {0x320000, 0x8008011, 0x4E42, 0x4B3,0x8C803C , 0x580005} ; //25 MHz ref + +uint32_t registers[6] = {0xA00000, 0x8000011, 0x4E42, 0x4B3,0xDC003C , 0x580005} ; //10 MHz ref + +int debug = 0; +int ADF4351_LE[2] = { 9, 10}; +int ADF4351_Mux = 7; + + +//#define DEBUG(X) // Serial.print( X ) +//#define DEBUGLN(X) Serial.println( X ) +//#define DEBUGFLN(X,Y) Serial.println( X,Y ) +//#define DEBUGF(X,Y) Serial.print( X,Y ) +#define DEBUG(X) +#define DEBUGLN(X) + + +double RFout, //Output freq in MHz +#if 0 //Black modules + PFDRFout[6] = {25.0,25.0,25.0,10.0,10.0,10.0}, //Reference freq in MHz + Chrystal[6] = {25.0,25.0,25.0,10.0,10.0,10.0}, +#else // Green modules + PFDRFout[6] = {10.0,10.0,10.0,10.0,10.0,10.0}, //Reference freq in MHz + Chrystal[6] = {10.0,10.0,10.0,10.0,10.0,10.0}, +#endif + + OutputChannelSpacing = 0.010, // = 0.01 + FRACF; // Temp + +unsigned int long RFint, // Output freq/10Hz + INTA, // Temp + RFcalc, //UI + MOD, //Temp + FRAC; //Temp + +byte OutputDivider; // Temp +byte lock=2; //Not used + +// Lock = A4 + +void ADF4351_Setup() +{ +// palSetPadMode(GPIOA, 1, PAL_MODE_OUTPUT_PUSHPULL ); +// palSetPadMode(GPIOA, 2, PAL_MODE_OUTPUT_PUSHPULL ); + + SPI3_CLK_HIGH; + SPI3_SDI_HIGH; + CS_ADF0_HIGH; + CS_ADF1_HIGH; +// bitSet (registers[2], 17); // R set to 8 +// bitClear (registers[2], 14); // R set to 8 + +// while(1) { +// + ADF4351_set_frequency(0,100000000,0); + ADF4351_set_frequency(1,150000000,0); +// ADF4351_Set(0); +// ADF4351_Set(1); +// chThdSleepMilliseconds(1000); +// } +// bitSet (registers[2], 17); // R set to 8 +// bitClear (registers[2], 14); // R set to 8 +// for (int i=0; i<6; i++) pinMode(ADF4351_LE[i], OUTPUT); // Setup pins +// for (int i=0; i<6; i++) digitalWrite(ADF4351_LE[i], HIGH); +// pinMode(ADF4351_Mux, INPUT); +// SPI.begin(); // Init SPI bus +// SPI.beginTransaction(SPISettings(8000000, MSBFIRST, SPI_MODE0)); + //SPI.setDataMode(SPI_MODE0); // CPHA = 0 Clock positive + //SPI.setBitOrder(MSBFIRST); +} + +void ADF4351_WriteRegister32(int channel, const uint32_t value) +{ + palClearPad(GPIOA, ADF4351_LE[channel]); +// chThdSleepMicroseconds(10); + for (int i = 3; i >= 0; i--) ADF_shiftOut((value >> (8 * i)) & 0xFF); +// chThdSleepMicroseconds(10); + palSetPad(GPIOA, ADF4351_LE[channel]); +// chThdSleepMicroseconds(10); + palClearPad(GPIOA, ADF4351_LE[channel]); +// chThdSleepMicroseconds(10); +} + +void ADF4351_disable_output() +{ + bitClear (registers[4], 5); // digital lock + ADF4351_Set(0); +} + +void ADF4351_enable_output() +{ + bitSet (registers[4], 5); // digital lock + ADF4351_Set(0); +} +void ADF4351_Set(int channel) +{ for (int i = 5; i >= 0; i--) { + ADF4351_WriteRegister32(channel, registers[i]); +// if (debug) Serial.println(registers[i],HEX); +} +} + +void ADF4351_set_frequency(int channel, unsigned long freq, int drive) // freq / 10Hz +{ + ADF4351_prep_frequency(channel,freq, drive); + ADF4351_Set(channel); +} + +void ADF4351_spur_mode(int S) +{ + if (S & 1) { + bitSet (registers[2], 29); // R set to 8 + } else { + bitClear (registers[2], 29); // R set to 8 + } + if (S & 2) + bitSet (registers[2], 30); // R set to 8 + else + bitClear (registers[2], 30); // R set to 8 +} + +void ADF4351_R_counter(int R) +{ + int dbl = false; + if (R < 0) { + dbl = true; + R = -R; + } + if (R<1) + return; + if (dbl) { + bitSet (registers[2], 25); // Reference doubler + } else { + bitClear (registers[2], 25); // Reference doubler + } + for (int channel=0; channel < 6; channel++) { + PFDRFout[channel] = Chrystal[channel] * (dbl?2:1) / R; + } + registers[2] &= ~ (((unsigned long)0x3FF) << 14); + registers[2] |= (((unsigned long)R) << 14); +} + +void ADF4351_CP(int p) +{ + registers[2] &= ~ (((unsigned long)0xF) << 9); + registers[2] |= (((unsigned long)p) << 9); +} + +void ADF4351_level(int p) +{ + registers[4] &= ~ (((unsigned long)0x3) << 3); + registers[4] |= (((unsigned long)p) << 3); +} + +void ADF4351_channel_spacing(int spacing) +{ + OutputChannelSpacing = 0.001 * spacing; +} + +static uint32_t gcd(uint32_t x, uint32_t y) +{ + uint32_t z; + while (y != 0) { + z = x % y; + x = y; + y = z; + } + return x; +} + +void ADF4351_prep_frequency(int channel, unsigned long freq, int drive) // freq / 10Hz +{ + (void)drive; +// if (channel == 0) + RFout=freq/1000000.0; // To MHz +// else + // RFout=freq/1000002.764; // To MHz + + if (RFout >= 2200) { + OutputDivider = 1; + bitWrite (registers[4], 22, 0); + bitWrite (registers[4], 21, 0); + bitWrite (registers[4], 20, 0); + } else if (RFout >= 1100) { + OutputDivider = 2; + bitWrite (registers[4], 22, 0); + bitWrite (registers[4], 21, 0); + bitWrite (registers[4], 20, 1); + } else if (RFout >= 550) { + OutputDivider = 4; + bitWrite (registers[4], 22, 0); + bitWrite (registers[4], 21, 1); + bitWrite (registers[4], 20, 0); + } else if (RFout >= 275) { + OutputDivider = 8; + bitWrite (registers[4], 22, 0); + bitWrite (registers[4], 21, 1); + bitWrite (registers[4], 20, 1); + } else if (RFout >= 137.5) { + OutputDivider = 16; + bitWrite (registers[4], 22, 1); + bitWrite (registers[4], 21, 0); + bitWrite (registers[4], 20, 0); + } else if (RFout >= 68.75) { + OutputDivider = 32; + bitWrite (registers[4], 22, 1); + bitWrite (registers[4], 21, 0); + bitWrite (registers[4], 20, 1); + } else { + OutputDivider = 64; + bitWrite (registers[4], 22, 1); + bitWrite (registers[4], 21, 1); + bitWrite (registers[4], 20, 0); + } + + INTA = (RFout * OutputDivider) / PFDRFout[channel]; + MOD = (PFDRFout[channel] / OutputChannelSpacing) + 0.01; +// MOD = 3125; + FRACF = (((RFout * OutputDivider) / PFDRFout[channel]) - INTA) * MOD; + FRAC = round(FRACF); + + while (FRAC > 4095 || MOD > 4095) { + FRAC = FRAC >> 1; + MOD = MOD >> 1; + // Serial.println( "MOD/FRAC reduced"); + } + + int32_t k = gcd(FRAC, MOD); + if (k > 1) { + FRAC /= k; + MOD /= k; +// Serial.print( "MOD/FRAC gcd reduced"); + } +// while (denom >= (1<<20)) { +// num >>= 1; +// denom >>= 1; +// } + + +// if (INTA <= 75) Serial.println( "INTA <= 75"); +// if (FRAC > 4095) Serial.println( "FRAC > 4095"); +// if (MOD > 4095) Serial.println( "MOD > 4095"); + + +// if (FRAC > 4095) Serial.println( "FRAC > 4095"); +// if (MOD > 4095) Serial.println( "MOD > 4095"); +// if (INTA > 4095) Serial.println( "INT > 4095"); + + if (debug) { + DEBUG(" ODIV="); + DEBUG(OutputDivider); + DEBUG(" INT="); + DEBUG(INTA); + DEBUG(" FRAC="); + DEBUG(FRAC); + DEBUG(" MOD="); + DEBUG(MOD); + DEBUG( " CalF="); +// DEBUGFLN(PFDRFout[channel] *(INTA + ((double)FRAC)/MOD)/OutputDivider,6); + +// DEBUG(" FRACF="); +// DEBUGF(FRACF,6); + } + registers[0] = 0; + registers[0] = INTA << 15; // OK + FRAC = FRAC << 3; + registers[0] = registers[0] + FRAC; + if (MOD == 1) MOD = 2; + registers[1] = 0; + registers[1] = MOD << 3; + registers[1] = registers[1] + 1 ; // restore address "001" + bitSet (registers[1], 27); // Prescaler at 8/9 +/* + drive = 1; + if (drive == 0) { + bitClear (registers[4], 3); // +5dBm + out + bitClear (registers[4], 4); // +5dBm + bitClear (registers[4], 6); // +5dBm - out + bitClear (registers[4], 7); // +5dBm + } else if (drive == 1) { + bitSet (registers[4], 6); // +5dBm + bitClear (registers[4], 7); // +5dBm - out + bitSet (registers[4], 3); // +5dBm + bitClear (registers[4], 4); // +5dBm + out + } else if (drive == 2) { + bitClear (registers[4], 6); // +5dBm - out + bitSet (registers[4], 7); // +5dBm + bitClear (registers[4], 3); // +5dBm + out + bitSet (registers[4], 4); // +5dBm + } + else { + bitSet (registers[4], 6); // +5dBm - out + bitSet (registers[4], 7); // +5dBm + bitSet (registers[4], 3); // +5dBm + out + bitSet (registers[4], 4); // +5dBm + } +*/ +// bitSet (registers[4], 5); // enable + output +// bitClear (registers[4], 8); // enable B output + +#if 0 + if (FRAC == 0) + bitSet (registers[2], 8); // INT mode + else + bitClear (registers[2], 8); // INT mode + bitSet (registers[2], 13); // Double buffered + + bitSet (registers[2], 28); // Digital lock == "110" sur b28 b27 b26 + bitSet (registers[2], 27); // digital lock + bitClear (registers[2], 26); // digital lock + + //bitSet (registers[4], 10); // Mute till lock +// bitSet (registers[3], 23); // Fast lock + #endif +// bitSet (registers[4], 10); // Mute till lock +// ADF4351_Set(channel); +} + + + +#endif diff --git a/si4432.h b/si4432.h new file mode 100644 index 0000000..8473302 --- /dev/null +++ b/si4432.h @@ -0,0 +1,44 @@ +#ifndef __SI4432_H__ + +#define __SI4432_H__ + +#define byte uint8_t +extern volatile int SI4432_Sel; // currently selected SI4432 +void SI4432_Write_Byte(byte ADR, byte DATA ); +byte SI4432_Read_Byte( byte ADR ); + +void SI4432_Init(void); +float SI4432_RSSI(uint32_t i, int s); +#ifdef __SIMULATION__ +float Simulated_SI4432_RSSI(uint32_t i, int s); +#endif +void SI4432_Set_Frequency ( long Freq ); +void SI4432_Transmit(int d); +void SI4432_Receive(void); +float SI4432_SET_RBW(float WISH); +void PE4302_Write_Byte(unsigned char DATA ); +void PE4302_init(void); + +#ifdef __ULTRA_SA__ +extern int ADF4351_LE[]; +extern int debug; +void ADF4351_Setup(void); + + +void ADF4351_WriteRegister32(int channel, const uint32_t value); +void ADF4351_set_frequency(int channel, uint32_t freq, int drive_strength); +void ADF4351_prep_frequency(int channel, uint32_t freq, int drive_strength); +//int ADF4351_set_frequency_with_offset(uint32_t freq, int offset, uint8_t drive_strength); +void ADF4351_Set(int channel); +void ADF4351_enable_output(void); +void ADF4351_disable_output(void); +void ADF4351_spur_mode(int S); +void ADF4351_R_counter(int R); +void ADF4351_channel_spacing(int spacing); +void ADF4351_CP(int p); +void ADF4351_level(int p); +int ADF4351_locked(void); +#endif + + +#endif //__SI4432_H__ diff --git a/si5351.c b/si5351.c deleted file mode 100644 index 8f7c9c5..0000000 --- a/si5351.c +++ /dev/null @@ -1,473 +0,0 @@ -/* - * Copyright (c) 2014-2015, TAKAHASHI Tomohiro (TTRFTECH) edy555@gmail.com - * Modified by 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 "hal.h" -#include "nanovna.h" -#include "si5351.h" - -// Enable cache for SI5351 CLKX_CONTROL register, little speedup exchange -#define USE_CLK_CONTROL_CACHE TRUE - -// XTAL frequency on si5351 -#define XTALFREQ 26000000U -// MCLK (processor clock if set, audio codec) frequency clock -#define CLK2_FREQUENCY 8000000U - -// Fixed PLL mode multiplier (used in band 1) -#define PLL_N 32 - -// I2C address on bus (only 0x60 for Si5351A in 10-Pin MSOP) -#define SI5351_I2C_ADDR 0x60 - -static uint8_t current_band = 0; -static uint32_t current_freq = 0; -static int32_t current_offset = FREQUENCY_OFFSET; - -// Minimum value is 2, freq change apply at next dsp measure, and need skip it -#define DELAY_NORMAL 2 -// Delay for bands (depend set band 1 more fast (can change before next dsp buffer ready, need wait additional interval) -#define DELAY_BAND_1 3 -#define DELAY_BAND_2 2 -// Band changes need set delay after reset PLL -#define DELAY_BANDCHANGE_1 3 -#define DELAY_BANDCHANGE_2 3 -// Delay after set new PLL values, and send reset (on band 1 unstable if less then 900, on 4000-5000 no amplitude spike on change) -#define DELAY_RESET_PLL 5000 - -uint32_t si5351_get_frequency(void) -{ - return current_freq; -} - -void si5351_set_frequency_offset(int32_t offset) -{ - current_offset = offset; - current_freq = 0; // reset freq, for -} - -static void -si5351_bulk_write(const uint8_t *buf, int len) -{ - i2cAcquireBus(&I2CD1); - (void)i2cMasterTransmitTimeout(&I2CD1, SI5351_I2C_ADDR, buf, len, NULL, 0, 1000); - i2cReleaseBus(&I2CD1); -} - -#if 0 -static bool si5351_bulk_read(uint8_t reg, uint8_t* buf, int len) -{ - i2cAcquireBus(&I2CD1); - msg_t mr = i2cMasterTransmitTimeout(&I2CD1, SI5351_I2C_ADDR, ®, 1, buf, len, 1000); - i2cReleaseBus(&I2CD1); - return mr == MSG_OK; -} - -static void si5351_wait_pll_lock(void) -{ - uint8_t status; - int count = 100; - do{ - status=0xFF; - si5351_bulk_read(0, &status, 1); - if ((status & 0x60) == 0) // PLLA and PLLB locked - return; - }while (--count); -} -#endif - -static inline void -si5351_write(uint8_t reg, uint8_t dat) -{ - uint8_t buf[] = { reg, dat }; - si5351_bulk_write(buf, 2); -} - -// register addr, length, data, ... -const uint8_t si5351_configs[] = { - 2, SI5351_REG_3_OUTPUT_ENABLE_CONTROL, 0xff, - 4, SI5351_REG_16_CLK0_CONTROL, SI5351_CLK_POWERDOWN, SI5351_CLK_POWERDOWN, SI5351_CLK_POWERDOWN, - 2, SI5351_REG_183_CRYSTAL_LOAD, SI5351_CRYSTAL_LOAD_8PF, -// All of this init code run late on sweep -#if 0 - // setup PLL (26MHz * 32 = 832MHz, 32/2-2=14) - 9, SI5351_REG_PLL_A, /*P3*/0, 1, /*P1*/0, 14, 0, /*P3/P2*/0, 0, 0, - 9, SI5351_REG_PLL_B, /*P3*/0, 1, /*P1*/0, 14, 0, /*P3/P2*/0, 0, 0, - // RESET PLL - 2, SI5351_REG_177_PLL_RESET, SI5351_PLL_RESET_A | SI5351_PLL_RESET_B | 0x0C, // - // setup multisynth (832MHz / 104 = 8MHz, 104/2-2=50) - 9, SI5351_REG_58_MULTISYNTH2, /*P3*/0, 1, /*P1*/0, 50, 0, /*P2|P3*/0, 0, 0, - 2, SI5351_REG_18_CLK2_CONTROL, SI5351_CLK_DRIVE_STRENGTH_2MA | SI5351_CLK_INPUT_MULTISYNTH_N | SI5351_CLK_INTEGER_MODE, -#endif - 2, SI5351_REG_3_OUTPUT_ENABLE_CONTROL, ~(SI5351_CLK0_EN|SI5351_CLK1_EN|SI5351_CLK2_EN), - 0 // sentinel -}; - -void -si5351_init(void) -{ - const uint8_t *p = si5351_configs; - while (*p) { - uint8_t len = *p++; - si5351_bulk_write(p, len); - p += len; - } -} - -static const uint8_t disable_output[] = { - SI5351_REG_16_CLK0_CONTROL, - SI5351_CLK_POWERDOWN, // CLK 0 - SI5351_CLK_POWERDOWN, // CLK 1 - SI5351_CLK_POWERDOWN // CLK 2 -}; - -/* Get the appropriate starting point for the PLL registers */ -static const uint8_t msreg_base[] = { - SI5351_REG_42_MULTISYNTH0, - SI5351_REG_50_MULTISYNTH1, - SI5351_REG_58_MULTISYNTH2, -}; -static const uint8_t clkctrl[] = { - SI5351_REG_16_CLK0_CONTROL, - SI5351_REG_17_CLK1_CONTROL, - SI5351_REG_18_CLK2_CONTROL -}; - -// Reset PLL need then band changes -static void si5351_reset_pll(uint8_t mask) -{ - // Writing a 1<<5 will reset PLLA, 1<<7 reset PLLB, this is a self clearing bits. - // !!! Need delay before reset PLL for apply PLL freq changes before - chThdSleepMicroseconds(DELAY_RESET_PLL); - si5351_write(SI5351_REG_177_PLL_RESET, mask | 0x0C); -} - -void si5351_disable_output(void) -{ - si5351_write(SI5351_REG_3_OUTPUT_ENABLE_CONTROL, 0xFF); - si5351_bulk_write(disable_output, sizeof(disable_output)); - current_band = 0; -} - -void si5351_enable_output(void) -{ - si5351_write(SI5351_REG_3_OUTPUT_ENABLE_CONTROL, ~(SI5351_CLK0_EN|SI5351_CLK1_EN|SI5351_CLK2_EN)); -//si5351_reset_pll(SI5351_PLL_RESET_A | SI5351_PLL_RESET_B); - current_freq = 0; - current_band = 0; -} - -// Set PLL freq = XTALFREQ * (mult + num/denom) -static void si5351_setupPLL(uint8_t pllSource, /* SI5351_REG_PLL_A or SI5351_REG_PLL_B */ - uint32_t mult, - uint32_t num, - uint32_t denom) -{ - /* Feedback Multisynth Divider Equation - * where: a = mult, b = num and c = denom - * P1 register is an 18-bit value using following formula: - * P1[17:0] = 128 * mult + int((128*num)/denom) - 512 - * P2 register is a 20-bit value using the following formula: - * P2[19:0] = (128 * num) % denom - * P3 register is a 20-bit value using the following formula: - * P3[19:0] = denom - */ - /* Set the main PLL config registers */ - mult <<= 7; - num <<= 7; - uint32_t P1 = mult - 512; // Integer mode - uint32_t P2 = 0; - uint32_t P3 = 1; - if (num) { // Fractional mode - P1+= num / denom; - P2 = num % denom; - P3 = denom; - } - // Pll MSN(A|B) registers Datasheet - uint8_t reg[9]; - reg[0] = pllSource; // SI5351_REG_PLL_A or SI5351_REG_PLL_B - reg[1] = (P3 & 0x0FF00) >> 8; // MSN_P3[15: 8] - reg[2] = (P3 & 0x000FF); // MSN_P3[ 7: 0] - reg[3] = (P1 & 0x30000) >> 16; // MSN_P1[17:16] - reg[4] = (P1 & 0x0FF00) >> 8; // MSN_P1[15: 8] - reg[5] = (P1 & 0x000FF); // MSN_P1[ 7: 0] - reg[6] = ((P3 & 0xF0000) >> 12) | ((P2 & 0xF0000) >> 16); // MSN_P3[19:16] | MSN_P2[19:16] - reg[7] = (P2 & 0x0FF00) >> 8; // MSN_P2[15: 8] - reg[8] = (P2 & 0x000FF); // MSN_P2[ 7: 0] - si5351_bulk_write(reg, 9); -} - -// Set Multisynth divider = (div + num/denom) * rdiv -static void -si5351_setupMultisynth(uint8_t channel, - uint32_t div, // 4,6,8, 8+ ~ 900 - uint32_t num, - uint32_t denom, - uint32_t rdiv, // SI5351_R_DIV_1~128 - uint8_t chctrl) // SI5351_REG_16_CLKX_CONTROL settings -{ - /* Output Multisynth Divider Equations - * where: a = div, b = num and c = denom - * P1 register is an 18-bit value using following formula: - * P1[17:0] = 128 * a + int((128*b)/c) - 512 - * P2 register is a 20-bit value using the following formula: - * P2[19:0] = (128 * b) % c - * P3 register is a 20-bit value using the following formula: - * P3[19:0] = c - */ - /* Set the main PLL config registers */ - uint32_t P1 = 0; - uint32_t P2 = 0; - uint32_t P3 = 1; - if (div == 4) - rdiv|= SI5351_DIVBY4; - else { - num<<=7; - div<<=7; - P1 = div - 512; // Integer mode - if (num) { // Fractional mode - P1+= num / denom; - P2 = num % denom; - P3 = denom; - } - } - /* Set the MSx config registers */ - uint8_t reg[9]; - reg[0] = msreg_base[channel]; // SI5351_REG_42_MULTISYNTH0, SI5351_REG_50_MULTISYNTH1, SI5351_REG_58_MULTISYNTH2 - reg[1] = (P3 & 0x0FF00)>>8; // MSx_P3[15: 8] - reg[2] = (P3 & 0x000FF); // MSx_P3[ 7: 0] - reg[3] = ((P1 & 0x30000)>>16)| rdiv; // Rx_DIV[2:0] | MSx_DIVBY4[1:0] | MSx_P1[17:16] - reg[4] = (P1 & 0x0FF00)>> 8; // MSx_P1[15: 8] - reg[5] = (P1 & 0x000FF); // MSx_P1[ 7: 0] - reg[6] = ((P3 & 0xF0000)>>12)|((P2 & 0xF0000)>>16); // MSx_P3[19:16] | MSx_P2[19:16] - reg[7] = (P2 & 0x0FF00)>>8; // MSx_P2[15: 8] - reg[8] = (P2 & 0x000FF); // MSx_P2[ 7: 0] - si5351_bulk_write(reg, 9); - - /* Configure the clk control and enable the output */ - uint8_t dat = chctrl | SI5351_CLK_INPUT_MULTISYNTH_N; - if (num == 0) - dat |= SI5351_CLK_INTEGER_MODE; - -#if USE_CLK_CONTROL_CACHE == TRUE - // Use cache for this reg, not update if not change - static uint8_t clk_cache[3]; - if (clk_cache[channel]!=dat) { - si5351_write(clkctrl[channel], dat); - clk_cache[channel]=dat; - } -#else - si5351_write(clkctrl[channel], dat); -#endif -} - -// Find better approximate values for n/d -#define MAX_DENOMINATOR ((1 << 20) - 1) -static inline void approximate_fraction(uint32_t *n, uint32_t *d) -{ - // cf. https://github.com/python/cpython/blob/master/Lib/fractions.py#L227 - uint32_t denom = *d; - if (denom > MAX_DENOMINATOR) { - uint32_t num = *n; - uint32_t p0 = 0, q0 = 1, p1 = 1, q1 = 0; - while (denom != 0) { - uint32_t a = num / denom; - uint32_t b = num % denom; - uint32_t q2 = q0 + a*q1; - if (q2 > MAX_DENOMINATOR) - break; - uint32_t p2 = p0 + a*p1; - p0 = p1; q0 = q1; p1 = p2; q1 = q2; - num = denom; denom = b; - } - *n = p1; - *d = q1; - } -} - -// Setup Multisynth divider for get correct output freq if fixed PLL = pllfreq -static void -si5351_set_frequency_fixedpll(uint8_t channel, uint64_t pllfreq, uint32_t freq, uint32_t rdiv, uint8_t chctrl) -{ - uint32_t denom = freq; - uint32_t div = pllfreq / denom; // range: 8 ~ 1800 - uint32_t num = pllfreq % denom; - approximate_fraction(&num, &denom); - si5351_setupMultisynth(channel, div, num, denom, rdiv, chctrl); -} - -// Setup PLL freq if Multisynth divider fixed = div (need get output = freq/mul) -static void -si5351_setupPLL_freq(uint32_t pllSource, uint32_t freq, uint32_t div, uint32_t mul) -{ - uint32_t denom = XTALFREQ * mul; - uint64_t pllfreq = (uint64_t)freq * div; - uint32_t multi = pllfreq / denom; - uint32_t num = pllfreq % denom; - approximate_fraction(&num, &denom); - si5351_setupPLL(pllSource, multi, num, denom); -} - -#if 0 -static void -si5351_set_frequency_fixeddiv(uint8_t channel, uint32_t pll, uint32_t freq, uint32_t div, - uint8_t chctrl, uint32_t mul) -{ - si5351_setupPLL_freq(pll, freq, div, mul); - si5351_setupMultisynth(channel, div, 0, 1, SI5351_R_DIV_1, chctrl); -} - -void -si5351_set_frequency(int channel, uint32_t freq, uint8_t drive_strength) -{ - if (freq <= 100000000) { - si5351_setupPLL(SI5351_PLL_B, 32, 0, 1); - si5351_set_frequency_fixedpll(channel, SI5351_PLL_B, PLLFREQ, freq, SI5351_R_DIV_1, drive_strength, 1); - } else if (freq < 150000000) { - si5351_set_frequency_fixeddiv(channel, SI5351_PLL_B, freq, 6, drive_strength, 1); - } else { - si5351_set_frequency_fixeddiv(channel, SI5351_PLL_B, freq, 4, drive_strength, 1); - } -} -#endif - -/* - * Frequency generation divide on 3 band - * Band 1 - * 1~100MHz fixed PLL = XTALFREQ * PLL_N, fractional divider - * Band 2 - * 100~150MHz fractional PLL = 600- 900MHz, fixed divider 'fdiv = 6' - * Band 3 - * 150~300MHz fractional PLL = 600-1200MHz, fixed divider 'fdiv = 4' - * - * For FREQ_HARMONICS = 300MHz - band range is: - * +-----------------------------------------------------------------------------------------------------------------------+ - * | Band 1 | Band 2 | Band 3 | Band 2 | Band 3 | - * +-----------------------------------------------------------------------------------------------------------------------+ - * | Direct mode x1 : x1 | x3 : x5 | x5-x7 | x7-x9 | x9-x11 | - * +-----------------------------------------------------------------------------------------------------------------------+ - * | 50kHz - 100MHz | 100 - 150MHz | 150 - 300MHz | 300-450MHz | 450-900MHz | 900-1500MHz | 1500-2100MHz | 2100-2700MHz | - * +-----------------------------------------------------------------------------------------------------------------------+ - * | f = 50kHz-300MHz | f=100-150 | f=150-300 | f=150-300 | f=214-300 | f=233-300 | - * | of = 50kHz-300MHz |of= 60- 90 |of= 90-180 |of=128-215 |of=166-234 |of=190-246 | - * +-----------------------------------------------------------------------------------------------------------------------+ - */ -static inline uint8_t -si5351_get_band(uint32_t freq) -{ - if (freq < 100000000U) return 1; - if (freq < 150000000U) return 2; - return 3; -} - -/* - * Maximum supported frequency = FREQ_HARMONICS * 9U - * configure output as follows: - * CLK0: frequency + offset - * CLK1: frequency - * CLK2: fixed 8MHz - */ -int -si5351_set_frequency(uint32_t freq, uint8_t drive_strength) -{ - uint8_t band; - int delay = DELAY_NORMAL; - if (freq == current_freq) - return delay; - else if (current_freq > freq) // Reset band on sweep begin (if set range 150-600, fix error then 600 MHz band 2 or 3 go back) - current_band = 0; - current_freq = freq; - uint32_t ofreq = freq + current_offset; - uint32_t mul = 1, omul = 1; - uint32_t rdiv = SI5351_R_DIV_1; - uint32_t fdiv; - // Fix possible incorrect input - drive_strength&=SI5351_CLK_DRIVE_STRENGTH_MASK; - - if (freq >= config.harmonic_freq_threshold * 7U) { - mul = 9; - omul = 11; - } else if (freq >= config.harmonic_freq_threshold * 5U) { - mul = 7; - omul = 9; - } else if (freq >= config.harmonic_freq_threshold * 3U) { - mul = 5; - omul = 7; - } else if (freq >= config.harmonic_freq_threshold) { - mul = 3; - omul = 5; - } else if (freq <= 500000U) { - rdiv = SI5351_R_DIV_64; - freq<<= 6; - ofreq<<= 6; - } else if (freq <= 4000000U) { - rdiv = SI5351_R_DIV_8; - freq<<= 3; - ofreq<<= 3; - } - band = si5351_get_band(freq / mul); - switch (band) { - case 1: - // Setup CH0 and CH1 constant PLLA freq at band change, and set CH2 freq = - // CLK2_FREQUENCY - if (current_band != 1) { - si5351_setupPLL(SI5351_REG_PLL_A, PLL_N, 0, 1); - si5351_set_frequency_fixedpll( - 2, XTALFREQ * PLL_N, CLK2_FREQUENCY, SI5351_R_DIV_1, - SI5351_CLK_DRIVE_STRENGTH_2MA | SI5351_CLK_PLL_SELECT_A); - delay = DELAY_BANDCHANGE_1; - } else { - delay = DELAY_BAND_1; - } - // Calculate and set CH0 and CH1 divider - si5351_set_frequency_fixedpll(0, (uint64_t)omul * XTALFREQ * PLL_N, ofreq, rdiv, - drive_strength | SI5351_CLK_PLL_SELECT_A); - si5351_set_frequency_fixedpll(1, (uint64_t)mul * XTALFREQ * PLL_N, freq, rdiv, - drive_strength | SI5351_CLK_PLL_SELECT_A); - break; - case 2: // fdiv = 6 - case 3: // fdiv = 4; - fdiv = (band == 2) ? 6 : 4; - // Setup CH0 and CH1 constant fdiv divider at change - if (current_band != band) { - si5351_setupMultisynth(0, fdiv, 0, 1, SI5351_R_DIV_1, - drive_strength | SI5351_CLK_PLL_SELECT_A); - si5351_setupMultisynth(1, fdiv, 0, 1, SI5351_R_DIV_1, - drive_strength | SI5351_CLK_PLL_SELECT_B); - delay = DELAY_BANDCHANGE_2; - } else { - delay = DELAY_BAND_2; - } - // Calculate and set CH0 and CH1 PLL freq - si5351_setupPLL_freq(SI5351_REG_PLL_A, ofreq, fdiv, - omul); // set PLLA freq = (ofreq/omul)*fdiv - si5351_setupPLL_freq(SI5351_REG_PLL_B, freq, fdiv, - mul); // set PLLB freq = ( freq/ mul)*fdiv - // Calculate CH2 freq = CLK2_FREQUENCY, depend from calculated before CH1 PLLB = (freq/mul)*fdiv - si5351_set_frequency_fixedpll( - 2, (uint64_t)freq * fdiv, CLK2_FREQUENCY * mul, SI5351_R_DIV_1, - SI5351_CLK_DRIVE_STRENGTH_2MA | SI5351_CLK_PLL_SELECT_B); - break; - } - if (current_band != band) { - si5351_reset_pll(SI5351_PLL_RESET_A|SI5351_PLL_RESET_B); - current_band = band; - } - return delay; -} diff --git a/si5351.h b/si5351.h deleted file mode 100644 index 315ce3c..0000000 --- a/si5351.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (c) 2014-2015, TAKAHASHI Tomohiro (TTRFTECH) edy555@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. - */ - -#define SI5351_REG_3_OUTPUT_ENABLE_CONTROL 3 -#define SI5351_CLK0_EN (1<<0) -#define SI5351_CLK1_EN (1<<1) -#define SI5351_CLK2_EN (1<<2) - -// Reg 16-18 CLKX_CONTROL -#define SI5351_REG_16_CLK0_CONTROL 16 -#define SI5351_REG_17_CLK1_CONTROL 17 -#define SI5351_REG_18_CLK2_CONTROL 18 -#define SI5351_CLK_POWERDOWN (1<<7) -#define SI5351_CLK_INTEGER_MODE (1<<6) -#define SI5351_CLK_PLL_SELECT_A (0<<5) -#define SI5351_CLK_PLL_SELECT_B (1<<5) -#define SI5351_CLK_INVERT (1<<4) -#define SI5351_CLK_INPUT_MASK (3<<2) -#define SI5351_CLK_INPUT_XTAL (0<<2) -#define SI5351_CLK_INPUT_CLKIN (1<<2) -#define SI5351_CLK_INPUT_MULTISYNTH_0_4 (2<<2) -#define SI5351_CLK_INPUT_MULTISYNTH_N (3<<2) -#define SI5351_CLK_DRIVE_STRENGTH_MASK (3<<0) -#define SI5351_CLK_DRIVE_STRENGTH_2MA (0<<0) -#define SI5351_CLK_DRIVE_STRENGTH_4MA (1<<0) -#define SI5351_CLK_DRIVE_STRENGTH_6MA (2<<0) -#define SI5351_CLK_DRIVE_STRENGTH_8MA (3<<0) - -#define SI5351_REG_PLL_A 26 -#define SI5351_REG_PLL_B 34 - -#define SI5351_REG_42_MULTISYNTH0 42 -#define SI5351_REG_50_MULTISYNTH1 50 -#define SI5351_REG_58_MULTISYNTH2 58 -#define SI5351_DIVBY4 (3<<2) -#define SI5351_R_DIV_1 (0<<4) -#define SI5351_R_DIV_2 (1<<4) -#define SI5351_R_DIV_4 (2<<4) -#define SI5351_R_DIV_8 (3<<4) -#define SI5351_R_DIV_16 (4<<4) -#define SI5351_R_DIV_32 (5<<4) -#define SI5351_R_DIV_64 (6<<4) -#define SI5351_R_DIV_128 (7<<4) - -#define SI5351_REG_177_PLL_RESET 177 -#define SI5351_PLL_RESET_B (1<<7) -#define SI5351_PLL_RESET_A (1<<5) - -#define SI5351_REG_183_CRYSTAL_LOAD 183 -#define SI5351_CRYSTAL_LOAD_6PF (1<<6) -#define SI5351_CRYSTAL_LOAD_8PF (2<<6) -#define SI5351_CRYSTAL_LOAD_10PF (3<<6) - -void si5351_init(void); -void si5351_disable_output(void); -void si5351_enable_output(void); - -void si5351_set_frequency_offset(int32_t offset); -int si5351_set_frequency(uint32_t freq, uint8_t drive_strength); -uint32_t si5351_get_frequency(void); diff --git a/tlv320aic3204.c b/tlv320aic3204.c deleted file mode 100644 index 21fbe84..0000000 --- a/tlv320aic3204.c +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright (c) 2014-2015, TAKAHASHI Tomohiro (TTRFTECH) edy555@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 "hal.h" -#include "nanovna.h" - -#define REFCLK_8000KHZ -#define AIC3204_ADDR 0x18 - -#define wait_ms(ms) chThdSleepMilliseconds(ms) - -static const uint8_t conf_data[] = { -// reg, data, -// PLL clock config - 0x00, 0x00, /* Initialize to Page 0 */ - 0x01, 0x01, /* Initialize the device through software reset */ - 0x04, 0x43, /* PLL Clock High, MCLK, PLL */ -#ifdef REFCLK_8000KHZ - /* 8.000MHz*10.7520 = 86.016MHz, 86.016MHz/(2*7*128) = 48kHz */ - 0x05, 0x91, /* Power up PLL, P=1,R=1 */ - 0x06, 0x0a, /* J=10 */ - 0x07, 29, /* D=7520 = (29<<8) + 96 */ - 0x08, 96, -#endif -// Clock config, default fs=48kHz - 0x0b, 0x82, /* Power up the NDAC divider with value 2 */ - 0x0c, 0x87, /* Power up the MDAC divider with value 7 */ - 0x0d, 0x00, /* Program the OSR of DAC to 128 */ - 0x0e, 0x80, - 0x3c, 0x08, /* Set the DAC Mode to PRB_P8 */ - //0x3c, 25, /* Set the DAC Mode to PRB_P25 */ - 0x1b, 0x0c, /* Set the BCLK,WCLK as output */ - 0x1e, 0x80 + 28, /* Enable the BCLKN divider with value 28 */ - 0x25, 0xee, /* DAC power up */ - - 0x12, 0x82, /* Power up the NADC divider with value 2 */ - 0x13, 0x87, /* Power up the MADC divider with value 7 */ - 0x14, 0x80, /* Program the OSR of ADC to 128 */ - 0x3d, 0x01, /* Select ADC PRB_R1 */ -// Data routing - 0x00, 0x01, /* Select Page 1 */ - 0x01, 0x08, /* Disable Internal Crude AVdd in presence of external AVdd supply or before powering up internal AVdd LDO*/ - 0x02, 0x01, /* Enable Master Analog Power Control */ - 0x7b, 0x01, /* Set the REF charging time to 40ms */ - 0x14, 0x25, /* HP soft stepping settings for optimal pop performance at power up Rpop used is 6k with N = 6 and soft step = 20usec. This should work with 47uF coupling capacitor. Can try N=5,6 or 7 time constants as well. Trade-off delay vs “pop” sound. */ - 0x0a, 0x33, /* Set the Input Common Mode to 0.9V and Output Common Mode for Headphone to 1.65V */ - - 0x3d, 0x00, /* Select ADC PTM_R4 */ - 0x47, 0x32, /* Set MicPGA startup delay to 3.1ms */ - 0x7b, 0x01, /* Set the REF charging time to 40ms */ - 0x34, 0x10, /* Route IN2L to LEFT_P with 10K */ - 0x36, 0x10, /* Route IN2R to LEFT_N with 10K */ -//0x37, 0x04, /* Route IN3R to RIGHT_P with 10K */ -//0x39, 0x04, /* Route IN3L to RIGHT_N with 10K */ -//0x3b, 0x00, /* Unmute Left MICPGA, Gain selection of 32dB to make channel gain 0dB */ -//0x3c, 0x00, /* Unmute Right MICPGA, Gain selection of 32dB to make channel gain 0dB */ -}; - -static const uint8_t conf_data_unmute[] = { -// reg, data, - 0x00, 0x00, /* Select Page 0 */ - 0x51, 0xc0, /* Power up Left and Right ADC Channels */ - 0x52, 0x00, /* Unmute Left and Right ADC Digital Volume Control */ -}; - -static const uint8_t conf_data_ch3_select[] = { -// reg, data, - 0x00, 0x01, /* Select Page 1 */ - 0x37, 0x04, /* Route IN3R to RIGHT_P with input impedance of 10K */ - 0x39, 0x04, /* Route IN3L to RIGHT_N with input impedance of 10K */ -}; - -static const uint8_t conf_data_ch1_select[] = { -// reg, data, - 0x00, 0x01, /* Select Page 1 */ - 0x37, 0x40, /* Route IN1R to RIGHT_P with input impedance of 10K */ - 0x39, 0x10, /* Route IN1L to RIGHT_N with input impedance of 10K */ -}; - -static inline void -tlv320aic3204_bulk_write(const uint8_t *buf, int len) -{ - (void)i2cMasterTransmitTimeout(&I2CD1, AIC3204_ADDR, buf, len, NULL, 0, 1000); -} - -#if 0 -static int -tlv320aic3204_read(uint8_t d0) -{ - int addr = AIC3204_ADDR; - uint8_t buf[] = { d0 }; - i2cAcquireBus(&I2CD1); - i2cMasterTransmitTimeout(&I2CD1, addr, buf, 1, buf, 1, 1000); - i2cReleaseBus(&I2CD1); - return buf[0]; -} -#endif - -static void -tlv320aic3204_config(const uint8_t *data, int len) -{ - i2cAcquireBus(&I2CD1); - for (; len--; data += 2) - tlv320aic3204_bulk_write(data, 2); - i2cReleaseBus(&I2CD1); -} - -void tlv320aic3204_init(void) -{ - tlv320aic3204_config(conf_data, sizeof(conf_data)/2); - wait_ms(40); - tlv320aic3204_config(conf_data_unmute, sizeof(conf_data_unmute)/2); -} - -void tlv320aic3204_select(int channel) -{ - tlv320aic3204_config(channel ? conf_data_ch1_select : conf_data_ch3_select, sizeof(conf_data_ch3_select)/2); -} - -void tlv320aic3204_set_gain(int lgain, int rgain) -{ - uint8_t data[] = { - 0x00, 0x01, /* Select Page 1 */ - 0x3b, lgain, /* Unmute Left MICPGA, set gain */ - 0x3c, rgain, /* Unmute Right MICPGA, set gain */ - }; - tlv320aic3204_config(data, sizeof(data)/2); -} diff --git a/ui.c b/ui.c index 3e10a58..818f63d 100644 --- a/ui.c +++ b/ui.c @@ -1,5 +1,4 @@ -/* - * Copyright (c) 2014-2015, TAKAHASHI Tomohiro (TTRFTECH) edy555@gmail.com +/* Copyright (c) 2014-2015, TAKAHASHI Tomohiro (TTRFTECH) edy555@gmail.com * All rights reserved. * * This is free software; you can redistribute it and/or modify @@ -30,7 +29,9 @@ uistat_t uistat = { current_trace: 0, lever_mode: LM_MARKER, marker_delta: FALSE, + marker_noise: FALSE, marker_tracking : FALSE, + text : "", }; #define NO_EVENT 0 @@ -52,7 +53,11 @@ uistat_t uistat = { #define BIT_DOWN1 1 #define READ_PORT() palReadPort(GPIOA) -#define BUTTON_MASK 0b1111 +#ifdef __ULTRA_SA__ +#define BUTTON_MASK 0 +#else +#define BUTTON_MASK 0b1110 +#endif static uint16_t last_button = 0b0000; static uint32_t last_button_down_ticks; @@ -67,9 +72,11 @@ enum { UI_NORMAL, UI_MENU, UI_NUMERIC, UI_KEYPAD }; +#ifdef __VNA__ enum { KM_START, KM_STOP, KM_CENTER, KM_SPAN, KM_CW, KM_SCALE, KM_REFPOS, KM_EDELAY, KM_VELOCITY_FACTOR, KM_SCALEDELAY }; +#endif #define NUMINPUT_LEN 10 @@ -78,8 +85,9 @@ static uint8_t keypad_mode; static uint8_t keypads_last_index; static char kp_buf[NUMINPUT_LEN+1]; static int8_t kp_index = 0; +static char *kp_help_text = NULL; static uint8_t menu_current_level = 0; -static int8_t selection = 0; +static int selection = 0; // Set structure align as WORD (save flash memory) #pragma pack(push, 2) @@ -111,8 +119,8 @@ static int16_t last_touch_y; #define KP_DONE 1 #define KP_CANCEL 2 -static void ui_mode_normal(void); -static void ui_mode_menu(void); +void ui_mode_normal(void); +//static void ui_mode_menu(void); static void ui_mode_numeric(int _keypad_mode); static void ui_mode_keypad(int _keypad_mode); static void draw_menu(void); @@ -120,9 +128,11 @@ static void leave_ui_mode(void); static void erase_menu_buttons(void); static void ui_process_keypad(void); static void ui_process_numeric(void); +static void choose_active_marker(void); static void menu_move_back(void); static void menu_push_submenu(const menuitem_t *submenu); +//static const menuitem_t menu_marker_type[]; static int btn_check(void) { @@ -287,11 +297,11 @@ touch_check(void) return stat ? EVT_TOUCH_DOWN : EVT_TOUCH_NONE; } -static inline void +void touch_wait_release(void) { while (touch_check() != EVT_TOUCH_RELEASED) - ; + chThdSleepMilliseconds(20); } static inline void @@ -319,8 +329,8 @@ touch_cal_exec(void) y1 = last_touch_y; ili9341_clear_screen(); - ili9341_line(320-1, 240-1, 320-1, 240-32); - ili9341_line(320-1, 240-1, 320-32, 240-1); + ili9341_line(LCD_WIDTH-1, LCD_HEIGHT-1, LCD_WIDTH-1, LCD_HEIGHT-32); + ili9341_line(LCD_WIDTH-1, LCD_HEIGHT-1, LCD_WIDTH-32, LCD_HEIGHT-1); ili9341_drawstring("TOUCH LOWER RIGHT", 230, 220); touch_wait_release(); @@ -329,8 +339,8 @@ touch_cal_exec(void) config.touch_cal[0] = x1; config.touch_cal[1] = y1; - config.touch_cal[2] = (x2 - x1) * 16 / 320; - config.touch_cal[3] = (y2 - y1) * 16 / 240; + config.touch_cal[2] = (x2 - x1) * 16 / LCD_WIDTH; + config.touch_cal[3] = (y2 - y1) * 16 / LCD_HEIGHT; //redraw_all(); touch_start_watchdog(); @@ -430,11 +440,20 @@ enum { MT_SUBMENU, MT_CALLBACK, MT_CANCEL, - MT_CLOSE + MT_TITLE, + MT_CLOSE, + MT_KEYPAD, + MT_ICON = 0x10, + MT_LOW = 0x40, // Only applicable to low mode + MT_FORM = 0x80, // Large button menu }; +#define MT_BACK 0x40 +#define MT_LEAVE 0x20 +#define MT_MASK(x) (0xF & (x)) typedef void (*menuaction_cb_t)(int item, uint8_t data); +#ifdef __VNA__ static void menu_calop_cb(int item, uint8_t data) { @@ -654,9 +673,11 @@ static void menu_scale_cb(int item, uint8_t data) { (void)item; +#ifdef __VNA__ if (data == KM_SCALE && trace[uistat.current_trace].type == TRC_DELAY) { data = KM_SCALEDELAY; } +#endif if (btn_wait_release() & EVT_BUTTON_DOWN_LONG) { ui_mode_numeric(data); ui_process_numeric(); @@ -692,6 +713,7 @@ menu_stimulus_cb(int item, uint8_t data) break; } } +#endif static uint32_t get_marker_frequency(int marker) @@ -706,11 +728,12 @@ get_marker_frequency(int marker) static void menu_marker_op_cb(int item, uint8_t data) { + (void)item; uint32_t freq = get_marker_frequency(active_marker); if (freq == 0) return; // no active marker - switch (item) { + switch (data) { case 0: /* MARKER->START */ case 1: /* MARKER->STOP */ case 2: /* MARKER->CENTER */ @@ -737,6 +760,7 @@ menu_marker_op_cb(int item, uint8_t data) } } break; +#ifdef __VNA__ case 4: /* MARKERS->EDELAY */ { if (uistat.current_trace == -1) @@ -746,34 +770,45 @@ menu_marker_op_cb(int item, uint8_t data) set_electrical_delay(electrical_delay + (v / 1e-12)); } break; +#endif } + menu_move_back(); ui_mode_normal(); - draw_cal_status(); + redraw_request |= REDRAW_CAL_STATUS; //redraw_all(); } static void menu_marker_search_cb(int item, uint8_t data) { - (void)data; + (void)item; int i = -1; if (active_marker == -1) return; - - switch (item) { + if (data < 4) + markers[active_marker].mtype &= ~M_TRACKING; + switch (data) { + case 0: /* search Left */ + i = marker_search_left_min(markers[active_marker].index); + break; + case 1: /* search right */ + i = marker_search_right_min(markers[active_marker].index); + break; +#if 0 case 0: /* maximum */ case 1: /* minimum */ - set_marker_search(item); + set_marker_search(data); i = marker_search(); break; +#endif case 2: /* search Left */ - i = marker_search_left(markers[active_marker].index); + i = marker_search_left_max(markers[active_marker].index); break; case 3: /* search right */ - i = marker_search_right(markers[active_marker].index); + i = marker_search_right_max(markers[active_marker].index); break; case 4: /* tracking */ - uistat.marker_tracking = !uistat.marker_tracking; + markers[active_marker].mtype ^= M_TRACKING; break; } if (i != -1) @@ -782,7 +817,7 @@ menu_marker_search_cb(int item, uint8_t data) redraw_marker(active_marker); select_lever_mode(LM_SEARCH); } - +#ifdef __VNA__ static void menu_marker_smith_cb(int item, uint8_t data) { @@ -791,6 +826,7 @@ menu_marker_smith_cb(int item, uint8_t data) redraw_marker(active_marker); draw_menu(); } +#endif static void active_marker_select(int item) @@ -812,32 +848,46 @@ static void menu_marker_sel_cb(int item, uint8_t data) { (void)data; - int t; +// int t; if (item >= 0 && item < MARKERS_MAX) { if (markers[item].enabled) { if (item == active_marker) { // disable if active trace is selected - markers[item].enabled = FALSE; + markers[item].enabled = M_DISABLED; active_marker_select(-1); } else { active_marker_select(item); } } else { - markers[item].enabled = TRUE; + markers[item].enabled = M_ENABLED; active_marker_select(item); + markers[item].mtype = M_NORMAL; + markers[item].mtype |= (uistat.marker_delta ? M_DELTA : 0); + markers[item].mtype |= (uistat.marker_noise ? M_NOISE : 0); + markers[item].mtype |= (uistat.marker_tracking ? M_TRACKING : 0); } + // if (markers[item].enabled) + // menu_push_submenu(menu_marker_type); +#if 0 } else if (item == 4) { /* all off */ for (t = 0; t < MARKERS_MAX; t++) - markers[t].enabled = FALSE; + markers[t].enabled = M_DISABLED; previous_marker = -1; active_marker = -1; - } else if (item == 5) { /* marker delta */ +#endif + } else if (item == 4) { /* marker delta */ uistat.marker_delta = !uistat.marker_delta; + } else if (item == 5) { /* marker noise */ + uistat.marker_noise = !uistat.marker_noise; + // if (uistat.marker_noise) uistat.marker_delta = true; //Default behavior + } else if (item == 6) { /* marker tracking */ + uistat.marker_tracking = !uistat.marker_tracking; + // if (uistat.marker_tracking) uistat.marker_noise = false; //Default behavior } redraw_marker(active_marker); draw_menu(); } - +#ifdef __VNA__ static const menuitem_t menu_calop[] = { { MT_CALLBACK, CAL_OPEN, "OPEN", menu_calop_cb }, { MT_CALLBACK, CAL_SHORT, "SHORT", menu_calop_cb }, @@ -1053,8 +1103,19 @@ const menuitem_t menu_top[] = { { MT_SUBMENU, 0, "CONFIG", menu_config }, { MT_NONE, 0, NULL, NULL } // sentinel }; +#endif + + +#define MENU_BUTTON_WIDTH 60 +#define MENU_BUTTON_START (LCD_WIDTH-MENU_BUTTON_WIDTH) +#define MENU_FORM_WIDTH 295 +#define MENU_FORM_START (LCD_WIDTH - MENU_FORM_WIDTH) +#define MENU_BUTTON_HEIGHT 30 +#define NUM_INPUT_HEIGHT 30 + +#include "ui_sa.c" -#define MENU_STACK_DEPTH_MAX 4 +#define MENU_STACK_DEPTH_MAX 5 const menuitem_t *menu_stack[MENU_STACK_DEPTH_MAX] = { menu_top, NULL, NULL, NULL }; @@ -1063,8 +1124,12 @@ static void ensure_selection(void) { const menuitem_t *menu = menu_stack[menu_current_level]; - int i; - for (i = 0; menu[i].type != MT_NONE; i++) + int i=0; + if (MT_MASK(menu[0].type) == MT_TITLE && selection == 0) { + selection = 1; + return; + } + for (i = 0; MT_MASK(menu[i].type) != MT_NONE; i++) ; if (selection >= i) selection = i-1; @@ -1075,23 +1140,51 @@ menu_move_back(void) { if (menu_current_level == 0) return; + erase_menu_buttons(); menu_current_level--; + if (selection >= 0) + selection = 0; ensure_selection(); - erase_menu_buttons(); + + if (current_menu_is_form()) { + redraw_frame(); + area_width = 0; + } else { + redraw_frame(); + request_to_redraw_grid(); + area_width = AREA_WIDTH_NORMAL - MENU_BUTTON_WIDTH; + } + draw_menu(); } static void menu_push_submenu(const menuitem_t *submenu) { + ui_mode = UI_MENU; // Only needed for auto mode setting + erase_menu_buttons(); if (menu_current_level < MENU_STACK_DEPTH_MAX-1) menu_current_level++; menu_stack[menu_current_level] = submenu; + if (selection >= 0) + selection = 0; ensure_selection(); - erase_menu_buttons(); + if (menu_is_form(submenu)) { + redraw_frame(); + area_width = 0; + } else { + redraw_frame(); + request_to_redraw_grid(); + area_width = AREA_WIDTH_NORMAL - MENU_BUTTON_WIDTH; + } draw_menu(); } +int current_menu_is_form(void) +{ + return menu_is_form(menu_stack[menu_current_level]); +} + /* static void menu_move_top(void) @@ -1108,10 +1201,11 @@ menu_move_top(void) static void menu_invoke(int item) { + int status; const menuitem_t *menu = menu_stack[menu_current_level]; menu = &menu[item]; - switch (menu->type) { + switch (MT_MASK(menu->type)) { case MT_NONE: case MT_BLANK: case MT_CLOSE: @@ -1127,25 +1221,40 @@ menu_invoke(int item) if (cb == NULL) return; (*cb)(item, menu->data); +// if (!(menu->type & MT_FORM)) + redraw_request |= REDRAW_CAL_STATUS; break; } case MT_SUBMENU: menu_push_submenu((const menuitem_t*)menu->reference); break; + + case MT_KEYPAD: + status = btn_wait_release(); + if (status & EVT_BUTTON_DOWN_LONG) { + ui_mode_numeric(menu->data); + // ui_process_numeric(); + } else { + if (menu->type & MT_FORM) { + area_width = AREA_WIDTH_NORMAL - MENU_BUTTON_WIDTH; + redraw_frame(); // Remove form numbers + } + kp_help_text = (char *)menu->reference; + ui_mode_keypad(menu->data); + ui_process_keypad(); + } + redraw_request |= REDRAW_CAL_STATUS; + break; } } -#define MENU_BUTTON_WIDTH 60 -#define MENU_BUTTON_HEIGHT 30 -#define NUM_INPUT_HEIGHT 30 - #define KP_WIDTH 48 #define KP_HEIGHT 48 // Key x, y position (0 - 15) on screen -#define KP_GET_X(posx) ((posx)*KP_WIDTH + (320-64-KP_WIDTH*4)) +#define KP_GET_X(posx) ((posx)*KP_WIDTH + (LCD_WIDTH-64-KP_WIDTH*4)) #define KP_GET_Y(posy) ((posy)*KP_HEIGHT + 12 ) - +#ifdef __VNA__ // Key names #define KP_0 0 #define KP_1 1 @@ -1251,6 +1360,11 @@ static const keypads_t * const keypads_mode_tbl[] = { static const char * const keypad_mode_label[] = { "START", "STOP", "CENTER", "SPAN", "CW FREQ", "SCALE", "REFPOS", "EDELAY", "VELOCITY%", "DELAY" }; +#endif + +static const char * const keypad_scale_text[] = { "1", "2", "5", "10", "20" , "50", "100", "200", "500"}; +//static const int keypad_scale_value[] = { 1, 2, 5, 10, 20 , 50, 100, 200, 500}; + static void draw_keypad(void) @@ -1264,21 +1378,37 @@ draw_keypad(void) ili9341_set_background(bg); int x = KP_GET_X(keypads[i].x); int y = KP_GET_Y(keypads[i].y); +// ili9341_fill(x, y, KP_WIDTH, KP_HEIGHT, DEFAULT_MENU_TEXT_COLOR); // black area around button, causes flicker.... ili9341_fill(x+2, y+2, KP_WIDTH-4, KP_HEIGHT-4, bg); - ili9341_drawfont(keypads[i].c, + if (keypads[i].c < 32) { // KP_1 + ili9341_drawfont(keypads[i].c, x + (KP_WIDTH - NUM_FONT_GET_WIDTH) / 2, y + (KP_HEIGHT - NUM_FONT_GET_HEIGHT) / 2); + } else { + const char *t = keypad_scale_text[keypads[i].c - KP_1]; + ili9341_drawstring_size(t, + x + (KP_WIDTH - 5*strlen(t)*2) / 2, + y + (KP_HEIGHT - 13) / 2,2); + } i++; } } +static int +menu_is_multiline(const char *label, const char **l1, const char **l2); static void draw_numeric_area_frame(void) { - ili9341_fill(0, 240-NUM_INPUT_HEIGHT, 320, NUM_INPUT_HEIGHT, config.menu_normal_color); + const char *l1; + const char *l2; + ili9341_fill(0, LCD_HEIGHT-NUM_INPUT_HEIGHT, LCD_WIDTH, NUM_INPUT_HEIGHT, config.menu_normal_color); ili9341_set_foreground(DEFAULT_MENU_TEXT_COLOR); ili9341_set_background(config.menu_normal_color); - ili9341_drawstring(keypad_mode_label[keypad_mode], 10, 240-(FONT_GET_HEIGHT+NUM_INPUT_HEIGHT)/2); + if (menu_is_multiline(keypad_mode_label[keypad_mode], &l1, &l2)) { + ili9341_drawstring_7x13(l1, 10, LCD_HEIGHT-NUM_INPUT_HEIGHT+1); + ili9341_drawstring_7x13(l2, 10, LCD_HEIGHT-NUM_INPUT_HEIGHT/2 + 1); + } else + ili9341_drawstring_7x13(keypad_mode_label[keypad_mode], 10, LCD_HEIGHT-(FONT_GET_HEIGHT+NUM_INPUT_HEIGHT)/2); //ili9341_drawfont(KP_KEYPAD, 300, 216); } @@ -1290,9 +1420,9 @@ draw_numeric_input(const char *buf) int focused = FALSE; uint16_t xsim = 0b0010010000000000; + uint16_t fg = DEFAULT_MENU_TEXT_COLOR; + uint16_t bg = config.menu_normal_color; for (i = 0, x = 64; i < 10 && buf[i]; i++, xsim<<=1) { - uint16_t fg = DEFAULT_MENU_TEXT_COLOR; - uint16_t bg = config.menu_normal_color; int c = buf[i]; if (c == '.') c = KP_PERIOD; @@ -1310,16 +1440,27 @@ draw_numeric_input(const char *buf) ili9341_set_foreground(fg); ili9341_set_background(bg); if (c >= 0) // c is number - ili9341_drawfont(c, x, 240-NUM_INPUT_HEIGHT+4); + ili9341_drawfont(c, x, LCD_HEIGHT-NUM_INPUT_HEIGHT+4); else if (focused) // c not number, but focused - ili9341_drawfont(0, x, 240-NUM_INPUT_HEIGHT+4); + ili9341_drawfont(0, x, LCD_HEIGHT-NUM_INPUT_HEIGHT+4); else // erase - ili9341_fill(x, 240-NUM_INPUT_HEIGHT+4, NUM_FONT_GET_HEIGHT, NUM_FONT_GET_WIDTH+2+8, bg); + ili9341_fill(x, LCD_HEIGHT-NUM_INPUT_HEIGHT+4, NUM_FONT_GET_HEIGHT, NUM_FONT_GET_WIDTH+2+8, bg); x += xsim&0x8000 ? NUM_FONT_GET_WIDTH+2+8 : NUM_FONT_GET_WIDTH+2; } // erase last - ili9341_fill(x, 240-NUM_INPUT_HEIGHT+4, NUM_FONT_GET_WIDTH+2+8, NUM_FONT_GET_WIDTH+2+8, config.menu_normal_color); +// ili9341_fill(x, LCD_HEIGHT-NUM_INPUT_HEIGHT+4, NUM_FONT_GET_WIDTH+2+8, NUM_FONT_GET_WIDTH+2+8, config.menu_normal_color); + ili9341_fill(x, LCD_HEIGHT-NUM_INPUT_HEIGHT+4, LCD_WIDTH-64, NUM_FONT_GET_WIDTH+2+8, config.menu_normal_color); + if (buf[0] == 0 && kp_help_text != NULL) { + ili9341_set_foreground(fg); + ili9341_set_background(bg); + const char *l1,*l2; + if (menu_is_multiline(kp_help_text, &l1, &l2)) { + ili9341_drawstring_7x13(l1, 64+NUM_FONT_GET_WIDTH+2, LCD_HEIGHT-NUM_INPUT_HEIGHT+1); + ili9341_drawstring_7x13(l2, 64+NUM_FONT_GET_WIDTH+2, LCD_HEIGHT-NUM_INPUT_HEIGHT/2 + 1); + } else + ili9341_drawstring_7x13(kp_help_text, 64+NUM_FONT_GET_WIDTH+2, LCD_HEIGHT-(FONT_GET_HEIGHT+NUM_INPUT_HEIGHT)/2); + } } static int @@ -1333,6 +1474,7 @@ menu_is_multiline(const char *label, const char **l1, const char **l2) return TRUE; } +#ifdef __VNA__ static void menu_item_modify_attribute(const menuitem_t *menu, int item, uint16_t *fg, uint16_t *bg) @@ -1407,36 +1549,106 @@ menu_item_modify_attribute(const menuitem_t *menu, int item, } } } +#endif + +#ifndef __VNA__ +extern void menu_item_modify_attribute( + const menuitem_t *menu, int item, uint16_t *fg, uint16_t *bg); +#endif static void draw_menu_buttons(const menuitem_t *menu) { int i = 0; - for (i = 0; i < 7; i++) { + char text[30]; + int y = 0; + for (i = 0; i < 8; i++) { const char *l1, *l2; - if (menu[i].type == MT_NONE) + if ((menu[i].type & MT_LOW) && !MODE_LOW(setting.mode)) //not applicable to mode + continue; + if (MT_MASK(menu[i].type) == MT_NONE) break; - if (menu[i].type == MT_BLANK) + if (MT_MASK(menu[i].type) == MT_BLANK) continue; - int y = MENU_BUTTON_HEIGHT*i; - uint16_t bg = config.menu_normal_color; - uint16_t fg = DEFAULT_MENU_TEXT_COLOR; + uint16_t bg; + uint16_t fg; + if (MT_MASK(menu[i].type) == MT_TITLE) { + fg = config.menu_normal_color; + bg = DEFAULT_MENU_TEXT_COLOR; + } else { + bg = config.menu_normal_color; + fg = DEFAULT_MENU_TEXT_COLOR; + } // focus only in MENU mode but not in KEYPAD mode if (ui_mode == UI_MENU && i == selection) bg = config.menu_active_color; - ili9341_fill(320-MENU_BUTTON_WIDTH, y, MENU_BUTTON_WIDTH, MENU_BUTTON_HEIGHT-2, bg); - - menu_item_modify_attribute(menu, i, &fg, &bg); + + uint16_t old_bg = bg; + int active_button_width; + int active_button_start; + menu_item_modify_attribute(menu, i, &fg, &bg); // before plot_printf to create status text + if (menu[i].type & MT_FORM) { + active_button_start = LCD_WIDTH - MENU_FORM_WIDTH; + active_button_width = MENU_FORM_WIDTH - 30; // Shorten at the right + if (MT_MASK(menu[i].type) == MT_KEYPAD) { // Only keypad retrieves value + keypad_mode = menu[i].data; + fetch_numeric_target(); + } + plot_printf(text, sizeof text, menu[i].label, uistat.text); + } + else { + active_button_width = MENU_BUTTON_WIDTH; + active_button_start = LCD_WIDTH - MENU_BUTTON_WIDTH; + } + ili9341_fill(active_button_start, y, active_button_width, MENU_BUTTON_HEIGHT-4, old_bg); // Set button to unmodified background color +#if 0 + // 3D button accent + int bw = LCD_WIDTH; + + if (MT_MASK(menu[i].type) != MT_TITLE) { + ili9341_fill(bw-active_button_width, y, 2, MENU_BUTTON_HEIGHT-4, LIGHT_GREY); // Set button to unmodified background color + ili9341_fill(bw-active_button_width, y, active_button_width, 2, LIGHT_GREY); // Set button to unmodified background color + ili9341_fill(bw-2, y, 2, MENU_BUTTON_HEIGHT-4, DARK_GREY); // Set button to unmodified background color + ili9341_fill(bw-active_button_width, y+MENU_BUTTON_HEIGHT-4, active_button_width, 2, DARK_GREY); // Set button to unmodified background color + } +#endif + ili9341_set_foreground(fg); ili9341_set_background(bg); - if (menu_is_multiline(menu[i].label, &l1, &l2)) { - ili9341_fill(320-MENU_BUTTON_WIDTH+3, y+5, MENU_BUTTON_WIDTH-6, 2+FONT_GET_HEIGHT+1+FONT_GET_HEIGHT+2, bg); - ili9341_drawstring(l1, 320-MENU_BUTTON_WIDTH+5, y+7); - ili9341_drawstring(l2, 320-MENU_BUTTON_WIDTH+5, y+7+FONT_GET_HEIGHT+1); + if (menu[i].type & MT_FORM) { + ili9341_fill(active_button_start+2, y+2, active_button_width-4, FONT_GET_HEIGHT*2+8, bg); + ili9341_drawstring_size(text, active_button_start+6, y+6, 2); +#ifdef __ICONS__ + if (menu[i].type & MT_ICON) { + blit16BitWidthBitmap(LCD_HEIGHT,y+6,16,16,&left_icons[((menu[i].data >>4)&0xf)*16]); + blit16BitWidthBitmap(256,y+6,16,16,&right_icons[((menu[i].data >>0)&0xf)*16]); + } +#endif } else { - ili9341_fill(320-MENU_BUTTON_WIDTH+3, y+8, MENU_BUTTON_WIDTH-6, 2+FONT_GET_HEIGHT+2, bg); - ili9341_drawstring(menu[i].label, 320-MENU_BUTTON_WIDTH+5, y+10); + if (menu_is_multiline(menu[i].label, &l1, &l2)) { +#define BIG_BUTTON_FONT 1 +#ifdef BIG_BUTTON_FONT +#undef FONT_HEIGHT +#define FONT_HEIGHT 13 + ili9341_fill(active_button_start+1, y+1, active_button_width-2, 13+13 -2, bg); + ili9341_drawstring_7x13(l1, active_button_start+2, y+1); + ili9341_drawstring_7x13(l2, active_button_start+2, y+1+13-1); +#else + ili9341_fill(active_button_start+3, y+5, active_button_width-6, 2+FONT_GET_HEIGHT+1+FONT_GET_HEIGHT+2, bg); + ili9341_drawstring(l1, active_button_start+5, y+7); + ili9341_drawstring(l2, active_button_start+5, y+7+FONT_GET_HEIGHT+1); +#endif + } else { +#ifdef BIG_BUTTON_FONT + ili9341_fill(active_button_start+1, y+1, active_button_width-2, 13+13 -2, bg); + ili9341_drawstring_7x13(menu[i].label, active_button_start+2, y+6); +#else + ili9341_fill(active_button_start+3, y+8, active_button_width-6, 2+FONT_GET_HEIGHT+2, bg); + ili9341_drawstring(menu[i].label, active_button_start+5, y+10); +#endif + } } + y += MENU_BUTTON_HEIGHT; } } @@ -1456,20 +1668,31 @@ menu_apply_touch(void) int touch_x, touch_y; const menuitem_t *menu = menu_stack[menu_current_level]; int i; - + int y = 0; touch_position(&touch_x, &touch_y); - for (i = 0; i < 7; i++) { - if (menu[i].type == MT_NONE) + for (i = 0; i < 8; i++) { + if ((menu[i].type & MT_LOW) && !MODE_LOW(setting.mode)) //not applicable to mode + continue; + if (MT_MASK(menu[i].type) == MT_NONE) break; - if (menu[i].type == MT_BLANK) + if (MT_MASK(menu[i].type == MT_BLANK) || MT_MASK(menu[i].type) == MT_TITLE) { + y += MENU_BUTTON_HEIGHT; continue; - int y = MENU_BUTTON_HEIGHT*i; - if (y < touch_y && touch_y < y+MENU_BUTTON_HEIGHT && 320-MENU_BUTTON_WIDTH < touch_x) { + } + int active_button_width; + if (menu[i].type & MT_FORM) + active_button_width = MENU_FORM_WIDTH; + else + active_button_width = MENU_BUTTON_WIDTH; + + if (y < touch_y && touch_y < y+MENU_BUTTON_HEIGHT && LCD_WIDTH-active_button_width < touch_x) { menu_select_touch(i); return; } + y += MENU_BUTTON_HEIGHT; } - + if (menu_is_form(menu)) + return; touch_wait_release(); ui_mode_normal(); } @@ -1483,13 +1706,18 @@ draw_menu(void) static void erase_menu_buttons(void) { - ili9341_fill(320-MENU_BUTTON_WIDTH, 0, MENU_BUTTON_WIDTH, MENU_BUTTON_HEIGHT*7, DEFAULT_BG_COLOR); +// ili9341_fill(area_width, 0, LCD_WIDTH - area_width, area_height, DEFAULT_BG_COLOR); + if (current_menu_is_form()) + ili9341_fill(5*5, 0,LCD_WIDTH-5*5, MENU_BUTTON_HEIGHT*8, DEFAULT_BG_COLOR); + else + ili9341_fill(LCD_WIDTH-MENU_BUTTON_WIDTH, 0, MENU_BUTTON_WIDTH, MENU_BUTTON_HEIGHT*8, DEFAULT_BG_COLOR); + draw_frequencies(); } static void erase_numeric_input(void) { - ili9341_fill(0, 240-NUM_INPUT_HEIGHT, 320, NUM_INPUT_HEIGHT, DEFAULT_BG_COLOR); + ili9341_fill(0, LCD_HEIGHT-NUM_INPUT_HEIGHT, LCD_WIDTH, NUM_INPUT_HEIGHT, DEFAULT_BG_COLOR); } static void @@ -1505,6 +1733,7 @@ leave_ui_mode() } } +#ifdef __VNA__ static void fetch_numeric_target(void) { @@ -1551,6 +1780,7 @@ fetch_numeric_target(void) // uistat.previous_value = uistat.value; } + static void set_numeric_value(void) { @@ -1584,16 +1814,17 @@ set_numeric_value(void) break; } } +#endif static void draw_numeric_area(void) { char buf[10]; - plot_printf(buf, sizeof buf, "%9d", uistat.value); + plot_printf(buf, sizeof buf, "%9d", ((int32_t)uistat.value)); draw_numeric_input(buf); } -static void +void ui_mode_menu(void) { if (ui_mode == UI_MENU) @@ -1619,7 +1850,7 @@ ui_mode_numeric(int _keypad_mode) keypad_mode = _keypad_mode; ui_mode = UI_NUMERIC; area_width = AREA_WIDTH_NORMAL; - area_height = 240-NUM_INPUT_HEIGHT;//AREA_HEIGHT_NORMAL - 32; + area_height = LCD_HEIGHT-NUM_INPUT_HEIGHT;//AREA_HEIGHT_NORMAL - 32; draw_numeric_area_frame(); fetch_numeric_target(); @@ -1629,7 +1860,7 @@ ui_mode_numeric(int _keypad_mode) static void ui_mode_keypad(int _keypad_mode) { - if (ui_mode == UI_KEYPAD) + if (ui_mode == UI_KEYPAD && keypad_mode == _keypad_mode ) return; // keypads array @@ -1643,13 +1874,14 @@ ui_mode_keypad(int _keypad_mode) ui_mode = UI_KEYPAD; area_width = AREA_WIDTH_NORMAL - MENU_BUTTON_WIDTH; area_height = HEIGHT - 32; - draw_menu(); + if (!current_menu_is_form()) + draw_menu(); draw_keypad(); draw_numeric_area_frame(); draw_numeric_input(""); } -static void +void ui_mode_normal(void) { if (ui_mode == UI_NORMAL) @@ -1664,18 +1896,29 @@ ui_mode_normal(void) static void lever_move_marker(int status) { + int step = 1; + int count = 0; do { if (active_marker >= 0 && markers[active_marker].enabled) { if ((status & EVT_DOWN) && markers[active_marker].index > 0) { - markers[active_marker].index--; + markers[active_marker].index -= step; + if (markers[active_marker].index < 0) + markers[active_marker].index = 0 ; markers[active_marker].frequency = frequencies[markers[active_marker].index]; redraw_marker(active_marker); } if ((status & EVT_UP) && markers[active_marker].index < sweep_points-1) { - markers[active_marker].index++; + markers[active_marker].index += step; + if (markers[active_marker].index > POINTS_COUNT-1) + markers[active_marker].index = POINTS_COUNT-1 ; markers[active_marker].frequency = frequencies[markers[active_marker].index]; redraw_marker(active_marker); } + count++; + if (count > 10) { + step *= 2; + count = 0; + } } status = btn_wait_release(); } while (status != 0); @@ -1745,7 +1988,7 @@ lever_move(int status, int mode) } #define STEPRATIO 0.2 - +#ifdef __VNA__ static void lever_edelay(int status) { @@ -1760,7 +2003,7 @@ lever_edelay(int status) } set_electrical_delay(value); } - +#endif static void ui_process_normal(void) { @@ -1781,9 +2024,11 @@ ui_process_normal(void) else lever_zoom_span(status); break; +#ifdef __VNA__ case LM_EDELAY: lever_edelay(status); break; +#endif } } } @@ -1795,20 +2040,30 @@ ui_process_menu(void) int status = btn_check(); if (status != 0) { if (status & EVT_BUTTON_SINGLE_CLICK) { + if (selection == -1) { + selection = 0; + goto activate; + } menu_invoke(selection); } else { do { if (status & EVT_UP) { // close menu if next item is sentinel + while ((menu_stack[menu_current_level][selection+1].type & MT_LOW) && !MODE_LOW(setting.mode)) + selection++; if (menu_stack[menu_current_level][selection+1].type == MT_NONE) goto menuclose; - selection++; + if (!(menu_stack[menu_current_level][selection+1].type == (MT_FORM | MT_NONE))) + selection++; } if (status & EVT_DOWN) { - if (selection == 0) - goto menuclose; - selection--; + while ((menu_stack[menu_current_level][selection+1].type & MT_LOW) && !MODE_LOW(setting.mode)) + selection--; + if (! ( selection == 0 && menu_stack[menu_current_level][0].type & MT_FORM)) + selection--; } +activate: + ensure_selection(); draw_menu(); status = btn_wait_release(); } while (status != 0); @@ -1824,17 +2079,25 @@ static int keypad_click(int key) { int c = keypads[key].c; - if ((c >= KP_X1 && c <= KP_G) || c == KP_N || c == KP_P) { - int32_t scale = 1; + if ((c >= KP_X1 && c <= KP_G) || c == KP_m || c == KP_u || c == KP_n) { + float scale = 1.0; if (c >= KP_X1 && c <= KP_G) { int n = c - KP_X1; while (n-- > 0) - scale *= 1000; - } else if (c == KP_N) { - scale *= 1000; + scale *= 1000.0; + } else if (c == KP_m) { + scale /= 1000.0; + } else if (c == KP_u) { + scale /= 1000000.0; + } else if (c == KP_n) { + scale /= 1000000000.0; } /* numeric input done */ double value = my_atof(kp_buf) * scale; +#if 1 + uistat.value = value; + set_numeric_value(); +#else switch (keypad_mode) { case KM_START: set_sweep_frequency(ST_START, value); @@ -1867,10 +2130,16 @@ keypad_click(int key) set_trace_scale(uistat.current_trace, value * 1e-12); // pico second break; } - +#endif return KP_DONE; } else if (c <= 9 && kp_index < NUMINPUT_LEN) { kp_buf[kp_index++] = '0' + c; + } else if (c>=KP_1) { + kp_buf[kp_index++] = keypad_scale_text[c-KP_1][0]; + if (c >=KP_10) + kp_buf[kp_index++] = '0'; + if (c >=KP_100) + kp_buf[kp_index++] = '0'; } else if (c == KP_PERIOD && kp_index < NUMINPUT_LEN) { // check period in former input int j; @@ -1935,7 +2204,7 @@ numeric_apply_touch(void) return; } - if (touch_y > 240-40) { + if (touch_y > LCD_HEIGHT-40) { int n = 9 - (touch_x - 64) / 20; uistat.digit = n; uistat.digit_mode = TRUE; @@ -2056,10 +2325,16 @@ ui_process_keypad(void) break; } } - + kp_help_text = NULL; redraw_frame(); - request_to_redraw_grid(); - ui_mode_normal(); + if (current_menu_is_form()) { + ui_mode_menu(); //Reactivate menu after keypad + selection = -1; + ensure_selection(); + } else { + ui_mode_normal(); + request_to_redraw_grid(); + } //redraw_all(); touch_start_watchdog(); } @@ -2153,11 +2428,50 @@ touch_lever_mode_select(void) return TRUE; } if (touch_y < 25) { +#ifdef __VNA__ if (touch_x < FREQUENCIES_XPOS2 && get_electrical_delay() != 0.0) { select_lever_mode(LM_EDELAY); } else { +#endif select_lever_mode(LM_MARKER); +#ifdef __VNA__ + } +#endif + return TRUE; + } + return FALSE; +} + +static int +touch_marker_select(void) +{ + int selected_marker = 0; + int touch_x, touch_y; + touch_position(&touch_x, &touch_y); + if (current_menu_is_form() || touch_x > LCD_WIDTH-MENU_BUTTON_WIDTH || touch_x < 25 || touch_y > 30) + return FALSE; + if (touch_y > 15) + selected_marker = 2; + selected_marker += (touch_x >150 ? 1 : 0); + for (int i = 0; i < MARKERS_MAX; i++) { + if (markers[i].enabled) { + if (selected_marker == 0) { + active_marker = i; + break; + } + selected_marker --; } + } + if (touch_y < 25) { +#ifdef __VNA__ + if (touch_x < FREQUENCIES_XPOS2 && get_electrical_delay() != 0.0) { + select_lever_mode(LM_EDELAY); + } else { +#endif + select_lever_mode(LM_MARKER); +#ifdef __VNA__ + } +#endif return TRUE; } return FALSE; @@ -2176,14 +2490,18 @@ void ui_process_touch(void) // Try drag marker if (touch_pickup_marker()) break; + if (touch_marker_select()) + break; // Try select lever mode (top and bottom screen) if (touch_lever_mode_select()) { touch_wait_release(); break; } + // switch menu mode after release touch_wait_release(); selection = -1; // hide keyboard mode selection + ensure_selection(); ui_mode_menu(); break; case UI_MENU: @@ -2198,11 +2516,20 @@ void ui_process_touch(void) touch_start_watchdog(); } +static int previous_button_state = 0; + void ui_process(void) { - if (operation_requested&OP_LEVER) + int button_state = READ_PORT() & BUTTON_MASK; + if (ui_mode == UI_NORMAL && current_menu_is_form()) { // Force into menu mode + selection = -1; // hide keyboard mode selection + ui_mode_menu(); + } + if (operation_requested&OP_LEVER || previous_button_state != button_state) { ui_process_lever(); + previous_button_state = button_state; + } if (operation_requested&OP_TOUCH) ui_process_touch(); operation_requested = OP_NONE; @@ -2214,14 +2541,19 @@ static void extcb1(EXTDriver *extp, expchannel_t channel) (void)extp; (void)channel; operation_requested|=OP_LEVER; - //cur_button = READ_PORT() & BUTTON_MASK; + // cur_button = READ_PORT() & BUTTON_MASK; } static const EXTConfig extcfg = { { {EXT_CH_MODE_DISABLED, NULL}, +#ifdef __ULTRA_SA__ + {EXT_CH_MODE_DISABLED, NULL}, + {EXT_CH_MODE_DISABLED, NULL}, +#else {EXT_CH_MODE_RISING_EDGE | EXT_CH_MODE_AUTOSTART | EXT_MODE_GPIOA, extcb1}, {EXT_CH_MODE_RISING_EDGE | EXT_CH_MODE_AUTOSTART | EXT_MODE_GPIOA, extcb1}, +#endif {EXT_CH_MODE_RISING_EDGE | EXT_CH_MODE_AUTOSTART | EXT_MODE_GPIOA, extcb1}, {EXT_CH_MODE_DISABLED, NULL}, {EXT_CH_MODE_DISABLED, NULL}, @@ -2279,8 +2611,8 @@ ui_init() /* * Activates the EXT driver 1. */ - extStart(&EXTD1, &extcfg); + extStart(&EXTD1, &extcfg); #if 1 gptStart(&GPTD3, &gpt3cfg); gptPolledDelay(&GPTD3, 10); /* Small delay.*/ @@ -2290,3 +2622,20 @@ ui_init() touch_start_watchdog(); } + +void wait_user(void) +{ + adc_stop(); + touch_wait_release(); +#if 0 + operation_requested = OP_NONE; + while (true) { + if (operation_requested & OP_TOUCH) + break; + if (operation_requested & OP_LEVER) + break; + } +#endif + touch_start_watchdog(); +} + diff --git a/ui_sa.c b/ui_sa.c new file mode 100644 index 0000000..20e3e5d --- /dev/null +++ b/ui_sa.c @@ -0,0 +1,1906 @@ +void markmap_all_markers(void); +static void menu_marker_modify_cb(int item, uint8_t data); +extern const menuitem_t menu_marker_modify[]; +void set_sweep_frequency(int type, uint32_t frequency); +uint32_t get_sweep_frequency(int type); +void clearDisplay(void); + +void blit16BitWidthBitmap(uint16_t x, uint16_t y, uint16_t width, uint16_t height, + const uint16_t *bitmap); + + +const uint16_t left_icons [] = +{ +#define I_EMPTY 0*16 + 0x0000, + 0x0000, + 0x0000, + 0x0001, + 0x0001, + 0x0001, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0001, + 0x0001, + 0x0001, + 0x0000, + 0x0000, + 0x0000, + +#define I_HIGH_INPUT 1*16 + /* +-----------------+ + | | + | ** | + | *** | + | ************ | + | *** | + | ** | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + +-----------------+ */ + 0x0000, + 0x0000, + 0x0060, + 0x0039, + 0x0fff, + 0x0039, + 0x0060, + 0x0000, + 0x0000, + 0x0000, + 0x0001, + 0x0001, + 0x0001, + 0x0000, + 0x0000, + 0x0000, + +#define I_LOW_INPUT 2*16 + /* +-----------------+ + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | ** | + | **** | + | ************ | + | **** | + | ** | + | | + +-----------------+ */ + 0x0000, + 0x0000, + 0x0000, + 0x0001, + 0x0001, + 0x0001, + 0x0000, + 0x0000, + 0x0000, + 0x0060, + 0x0039, + 0x0fff, + 0x0039, + 0x0060, + 0x0000, + 0x0000, + +#define I_LOW_OUTPUT 3*16 + + 0b0000000000000000, + 0b0000000000000000, + 0b0000000000000000, + 0b0000000000000001, + 0b0000000000000001, + 0b0000000000000001, + 0b0000000000000000, + 0b0000000000000000, + 0b0000000000000000, + 0b0000000110000000, + 0b0000011100000001, + 0b0000111111111111, + 0b0000011100000001, + 0b0000000110000000, + 0b0000000000000000, + 0b0000000000000000, + +#define I_HIGH_OUTPUT 4*16 + + 0b0000000000000000, + 0b0000000000000000, + 0b0000000110000000, + 0b0000011100000001, + 0b0000111111111111, + 0b0000011100000001, + 0b0000000110000000, + 0b0000000000000000, + 0b0000000000000000, + 0b0000000000000000, + 0b0000000000000001, + 0b0000000000000001, + 0b0000000000000001, + 0b0000000000000000, + 0b0000000000000000, + 0b0000000000000000, + +#define I_CONNECT 5*16 + + 0b0000000000000000, + 0b0000000000000000, + 0b0000000000110000, + 0b0000000000111101, + 0b0000001111111111, + 0b0000010000111101, + 0b0000100000110000, + 0b0001000000000000, + 0b0001000000000000, + 0b0000100000110000, + 0b0000010000111101, + 0b0000001111111111, + 0b0000000000111101, + 0b0000000000110000, + 0b0000000000000000, + 0b0000000000000000, + +}; + +const uint16_t right_icons [] = +{ +#define I_SA 0 + /* Character 0 (0x00): + width 16 + +-----------------+ + | | + | *************** | + | * * | + |** * | + | * * * | + | * * * | + | * * * * | + | * * * * | + | * * * * * | + | * * * * * * | + | * * * * * * * | + | * * * * * * * | + |** *********** * | + | * * | + | *************** | + | | + +-----------------+ */ + 0x0000, + 0x7fff, + 0x4001, + 0xc001, + 0xc001, + 0xc001, + 0x4801, + 0x4801, + 0x4a89, + 0x4aa9, + 0xcaa9, + 0xdffd, + 0xc001, + 0x4001, + 0x7fff, + 0x0000, + +#define I_GEN 1 + /* Character 0 (0x00): + width 16 + +-----------------+ + | | + | *************** | + | * * | + |** * | + | * ***** ** * | + | * * * * * | + | * * * * * | + | * * * * * | + | * * * * * | + | * * * * * | + | * * * * * | + | * ** ***** * | + |** * | + | * * | + | *************** | + | | + +-----------------+ */ + 0x0000, + 0x7fff, + 0x4001, + 0xc001, + 0xcf8d, + 0xc889, + 0x4889, + 0x4889, + 0x4889, + 0x4889, + 0xc889, + 0xd8f9, + 0xc001, + 0x4001, + 0x7fff, + 0x0000, + +#define I_CONFIG 2 + + 0b0000000000000000, + 0b0111111111111111, + 0b0100000000000001, + 0b1100000010000001, + 0b1100001111000001, + 0b1100011110001001, + 0b0100011100011101, + 0b0100011110111001, + 0b0100001111111001, + 0b0100011111110001, + 0b1100111110000001, + 0b1101111100000001, + 0b1100111000000001, + 0b0100000000000001, + 0b0111111111111111, + 0b0000000000000000, + +#define I_SINUS 3 + + 0b0000000000000000, + 0b0111111111111111, // 1 + 0b0100000000000001, // 2 + 0b1100000000000001, // 3 + 0b1100000000110001, // 4 + 0b1100000001001001, // 5 + 0b0100000010000101, // 6 + 0b0101000010000101, // 7 + 0b0101000010000101, // 8 + 0b0101000010000001, // 9 + 0b1100100100000001, //10 + 0b1100011000000001, //11 + 0b1100000000000001, //12 + 0b0100000000000001, //13 + 0b0111111111111111, //14 + 0b0000000000000000, +}; + +enum { + KM_START=1, KM_STOP, KM_CENTER, KM_SPAN, KM_CW, KM_REFLEVEL, KM_SCALE, KM_ATTENUATION, + KM_ACTUALPOWER, KM_IF, KM_SAMPLETIME, KM_DRIVE, KM_LOWOUTLEVEL, KM_DECAY, KM_NOISE, + KM_10MHZ, KM_REPEAT, KM_OFFSET, KM_TRIGGER, KM_LEVELSWEEP, KM_SWEEP_TIME, +}; + + + +#define KP_X(x) (48*(x) + 2 + (LCD_WIDTH-BUTTON_WIDTH-192)) +#define KP_Y(y) (48*(y) + 2) + + +#define KP_PERIOD 10 +#define KP_MINUS 11 +#define KP_X1 12 +#define KP_K 13 +#define KP_M 14 +#define KP_G 15 +#define KP_BS 16 +#define KP_INF 17 +#define KP_DB 18 +#define KP_PLUSMINUS 19 +#define KP_KEYPAD 20 +#define KP_m 21 +#define KP_u 22 +#define KP_n 23 + +#define KP_1 32 +#define KP_2 33 +#define KP_5 34 +#define KP_10 35 +#define KP_20 36 +#define KP_50 37 +#define KP_100 38 +#define KP_200 39 +#define KP_500 40 + + +typedef struct { + uint8_t x:4; + uint8_t y:4; + int8_t c; +} keypads_t; + +static const keypads_t *keypads; + +static uint8_t keypads_last_index; + +// 7 8 9 G +// 4 5 6 M +// 1 2 3 k +// 0 . < x + +static const keypads_t keypads_freq[] = { + { 1, 3, KP_PERIOD }, + { 0, 3, 0 }, + { 0, 2, 1 }, + { 1, 2, 2 }, + { 2, 2, 3 }, + { 0, 1, 4 }, + { 1, 1, 5 }, + { 2, 1, 6 }, + { 0, 0, 7 }, + { 1, 0, 8 }, + { 2, 0, 9 }, + { 3, 0, KP_G }, + { 3, 1, KP_M }, + { 3, 2, KP_K }, + { 3, 3, KP_X1 }, + { 2, 3, KP_BS }, + { 0, 0, -1 } +}; + +// 7 8 9 +// 4 5 6 +// 1 2 3 +// 0 . < x + +static const keypads_t keypads_positive[] = { + { 1, 3, KP_PERIOD }, + { 0, 3, 0 }, + { 0, 2, 1 }, + { 1, 2, 2 }, + { 2, 2, 3 }, + { 0, 1, 4 }, + { 1, 1, 5 }, + { 2, 1, 6 }, + { 0, 0, 7 }, + { 1, 0, 8 }, + { 2, 0, 9 }, + { 3, 3, KP_X1 }, + { 2, 3, KP_BS }, + { 0, 0, -1 } +}; + +// 100 200 500 n +// 10 20 50 u +// 1 2 5 m +// 0 . < x + +static const keypads_t keypads_pos_unit[] = { + { 1, 3, KP_PERIOD }, + { 0, 3, 0 }, + { 0, 2, KP_1 }, + { 1, 2, KP_2 }, + { 2, 2, KP_5 }, + { 0, 1, KP_10 }, + { 1, 1, KP_20 }, + { 2, 1, KP_50 }, + { 0, 0, KP_100 }, + { 1, 0, KP_200 }, + { 2, 0, KP_500 }, + { 3, 0, KP_n }, + { 3, 1, KP_u }, + { 3, 2, KP_m }, + { 3, 3, KP_X1 }, + { 2, 3, KP_BS }, + { 0, 0, -1 } +}; + +// 7 8 9 m +// 4 5 6 u +// 1 2 3 - +// 0 . < x + +static const keypads_t keypads_plusmin_unit[] = { + { 1, 3, KP_PERIOD }, + { 0, 3, 0 }, + { 0, 2, 1 }, + { 1, 2, 2 }, + { 2, 2, 3 }, + { 0, 1, 4 }, + { 1, 1, 5 }, + { 2, 1, 6 }, + { 0, 0, 7 }, + { 1, 0, 8 }, + { 2, 0, 9 }, + { 3, 0, KP_u}, + { 3, 1, KP_m}, + { 3, 2, KP_MINUS }, + { 3, 3, KP_X1 }, + { 2, 3, KP_BS }, + { 0, 0, -1 } +}; +// 7 8 9 +// 4 5 6 +// 1 2 3 - +// 0 . < x + +static const keypads_t keypads_plusmin[] = { + { 1, 3, KP_PERIOD }, + { 0, 3, 0 }, + { 0, 2, 1 }, + { 1, 2, 2 }, + { 2, 2, 3 }, + { 0, 1, 4 }, + { 1, 1, 5 }, + { 2, 1, 6 }, + { 0, 0, 7 }, + { 1, 0, 8 }, + { 2, 0, 9 }, + { 3, 0, KP_u}, + { 3, 1, KP_m}, + { 3, 2, KP_MINUS }, + { 3, 3, KP_X1 }, + { 2, 3, KP_BS }, + { 0, 0, -1 } +}; + +// 7 8 9 +// 4 5 6 +// 1 2 3 m +// 0 . < x +static const keypads_t keypads_time[] = { + { 1, 3, KP_PERIOD }, + { 0, 3, 0 }, + { 0, 2, 1 }, + { 1, 2, 2 }, + { 2, 2, 3 }, + { 0, 1, 4 }, + { 1, 1, 5 }, + { 2, 1, 6 }, + { 0, 0, 7 }, + { 1, 0, 8 }, + { 2, 0, 9 }, +// { 3, 0, KP_n}, +// { 3, 1, KP_u}, + { 3, 2, KP_m }, + { 3, 3, KP_X1 }, + { 2, 3, KP_BS }, + { 0, 0, -1 } +}; + +static const keypads_t * const keypads_mode_tbl[] = { + NULL, // never used + keypads_freq, // start + keypads_freq, // stop + keypads_freq, // center + keypads_freq, // span + keypads_freq, // cw freq + keypads_plusmin_unit, // reflevel + keypads_pos_unit, // scale + keypads_positive, // attenuation + keypads_plusmin_unit, // actual power + keypads_freq, // IF + keypads_positive, // sample delay + keypads_positive, // drive + keypads_plusmin, // KM_LOWOUTLEVEL + keypads_positive, // KM_DECAY + keypads_positive, // KM_NOISE + keypads_plusmin, // KM_10MHz + keypads_positive, // KM_REPEA + keypads_plusmin, // KM_OFFSET + keypads_plusmin_unit, // KM_TRIGGER + keypads_plusmin, // KM_LEVELSWEEP + keypads_time, // KM_SWEEP_TIME +}; + +#ifdef __VNA__ +static const char * const keypad_mode_label[] = { + "START", "STOP", "CENTER", "SPAN", "CW FREQ", "SCALE", "REFPOS", "EDELAY", "VELOCITY%", "DELAY" +}; +#endif +#ifdef __SA__ +static const char * const keypad_mode_label[] = { + "error", "START", "STOP", "CENTER", "SPAN", "FREQ", "\2REF\0LEVEL", "SCALE", // 0-7 + "\2ATTENUATE\0 0-31dB", "\2ACTUAL\0POWER", "IF", "\2SAMPLE\0DELAY", "DRIVE", "LEVEL", "SCANS", "LEVEL", // 8-15 + "OFFSET" , "\2SAMPLE\0REPEAT", "OFFSET", "\2TRIGGER\0LEVEL", "\2LEVEL\0SWEEP", "\2SWEEP\0SECONDS"// 16- +}; +#endif + + +// ===[MENU CALLBACKS]========================================================= + + +int generator_enabled = false; + +extern const menuitem_t menu_lowoutputmode[]; +extern const menuitem_t menu_highoutputmode[]; +extern const menuitem_t menu_modulation[]; +extern const menuitem_t menu_top[]; +extern const menuitem_t menu_tophigh[]; +extern const menuitem_t menu_topultra[]; + + void menu_mode_cb(int item, uint8_t data) +{ + (void)data; + set_mode(item); +// draw_cal_status(); + switch (item) { + case 0: +// if (setting.mode != M_LOW) +// set_mode(M_LOW); + menu_move_back(); + ui_mode_normal(); + break; + case 1: +// if (setting.mode != M_HIGH) +// set_mode(M_HIGH); + menu_move_back(); + ui_mode_normal(); + break; + case 2: + menu_push_submenu(menu_lowoutputmode); + break; + case 3: + menu_push_submenu(menu_highoutputmode); + break; +#ifdef __ULTRA__ + case 7: + menu_push_submenu(menu_topultra); + break; +#endif + } + redraw_request |= REDRAW_CAL_STATUS; +} + +void menu_load_preset_cb(int item, uint8_t data) +{ + (void)item; + if (caldata_recall(data) == -1) { + if (data == 0) + reset_settings(setting.mode); // Restore all defaults + else { + draw_menu(); + return; + } + } + menu_move_back(); + ui_mode_normal(); +} + +void menu_store_preset_cb(int item, uint8_t data) +{ + (void)item; + if (data == 100) { + reset_settings(M_LOW); // Restore all defaults in Low mode + // setting.mode = -1; + data = 0; + } + caldata_save(data); + menu_move_back(); + ui_mode_normal(); +} + + +extern int dirty; +void menu_autosettings_cb(int item, uint8_t data) +{ + (void)item; + (void)data; + reset_settings(setting.mode); + + active_marker = 0; + for (int i = 1; i= 0 && item < MARKERS_MAX) { + markers[item].enabled = true; + active_marker_select(item); + menu_push_submenu(menu_marker_modify); + redraw_marker(active_marker); + draw_menu(); + } +} + +static void menu_marker_modify_cb(int item, uint8_t data) +{ + (void)item; + if (markers[active_marker].enabled == M_ENABLED) + { + if (data == M_DELETE) { + markers[active_marker].enabled = false; + menu_move_back(); +// ui_mode_normal(); +// return; + } else if (data == M_NORMAL) { + markers[active_marker].mtype = M_NORMAL; + } else if (data == M_REFERENCE) { + for (int i = 0; i 1) { + mark = true; + } +#ifdef __ULTRA__ + } else if (MT_MASK(menu[item].type) == MT_CALLBACK && menu == menu_harmonic) { + if (data == setting.harmonic) + mark = true; +#endif + } else if (MT_MASK(menu[item].type) == MT_CALLBACK && menu == menu_settings2) { + int v=0; + switch(data) { + case 1: v = setting.agc; break; + case 2: v = setting.lna; break; + case 3: v = setting.tracking; break; + case 4: v = setting.below_IF; break; + } + if (S_IS_AUTO(v)) + m_auto = true; + else if (v == S_ON) + mark = true; + } else if (menu == menu_marker_modify && active_marker >= 0 && markers[active_marker].enabled == M_ENABLED) { + if (data & markers[active_marker].mtype) + mark = true; + else if (item < 5 && data==markers[active_marker].mtype) // This catches the M_NORMAL case + mark = true; + } else if (menu == menu_marker_search) { + if (item == 4 && markers[active_marker].mtype & M_TRACKING) + mark = true; + } else if (menu == menu_marker_sel || menu == menu_marker_select) { + if (item < 4 && markers[item].enabled) + mark = true; + else if (item == 4 && uistat.marker_delta) + mark = true; + else if (item == 5 && uistat.marker_noise) + mark = true; + else if (item == 6 && uistat.marker_tracking) + mark = true; + } else if (menu == menu_reflevel) { + if ((item == 0 && setting.auto_reflevel) || (item == 1 && !setting.auto_reflevel)) + mark = true; + } else if (menu == menu_atten) { + if ((item == 0 && setting.auto_attenuation ) || (item == 1 && !setting.auto_attenuation)) + mark = true; + } + if (m_auto) { + *bg = LIGHT_GREY; + *fg = config.menu_normal_color; + } else if (mark) { + *bg = DEFAULT_MENU_TEXT_COLOR; + *fg = config.menu_normal_color; + } + if (ui_mode == UI_MENU && menu_is_form(menu)) { + // if (item == 0) + // redraw_frame(); + if (item <= 1) { + area_width = 0; + } + }else{ + area_width = AREA_WIDTH_NORMAL - MENU_BUTTON_WIDTH; + } +} + +static void fetch_numeric_target(void) +{ + switch (keypad_mode) { + case KM_START: + uistat.value = get_sweep_frequency(ST_START); + plot_printf(uistat.text, sizeof uistat.text, "%3.3fMHz", uistat.value / 1000000.0); + break; + case KM_STOP: + uistat.value = get_sweep_frequency(ST_STOP); + plot_printf(uistat.text, sizeof uistat.text, "%3.3fMHz", uistat.value / 1000000.0); + break; + case KM_CENTER: + uistat.value = get_sweep_frequency(ST_CENTER); + plot_printf(uistat.text, sizeof uistat.text, "%3.3fMHz", uistat.value / 1000000.0); + break; + case KM_SPAN: + uistat.value = get_sweep_frequency(ST_SPAN); + plot_printf(uistat.text, sizeof uistat.text, "%3.3fMHz", uistat.value / 1000000.0); + break; + case KM_CW: + uistat.value = get_sweep_frequency(ST_CW); + plot_printf(uistat.text, sizeof uistat.text, "%3.3fMHz", uistat.value / 1000000.0); + break; + case KM_SCALE: + uistat.value = setting.scale; + plot_printf(uistat.text, sizeof uistat.text, "%f/", uistat.value); + break; + case KM_REFLEVEL: + uistat.value = setting.reflevel; + plot_printf(uistat.text, sizeof uistat.text, "%f", uistat.value); + break; + case KM_ATTENUATION: + uistat.value = get_attenuation(); + plot_printf(uistat.text, sizeof uistat.text, "%ddB", ((int32_t)uistat.value)); + break; + case KM_ACTUALPOWER: + uistat.value = get_level_offset(); + plot_printf(uistat.text, sizeof uistat.text, "%ddB", ((int32_t)uistat.value)); + break; + case KM_IF: + uistat.value = setting.frequency_IF; + plot_printf(uistat.text, sizeof uistat.text, "%3.3fMHz", uistat.value / 1000000.0); + break; + case KM_SAMPLETIME: + uistat.value = setting.step_delay; + plot_printf(uistat.text, sizeof uistat.text, "%3duS", ((int32_t)uistat.value)); + break; + case KM_REPEAT: + uistat.value = setting.repeat; + plot_printf(uistat.text, sizeof uistat.text, "%2d", ((int32_t)uistat.value)); + break; + case KM_DRIVE: + uistat.value = setting.drive; + plot_printf(uistat.text, sizeof uistat.text, "%3ddB", ((int32_t)uistat.value)); + break; + case KM_LOWOUTLEVEL: + uistat.value = get_attenuation(); // compensation for dB offset during low output mode + plot_printf(uistat.text, sizeof uistat.text, "%ddB", ((int32_t)uistat.value)); + break; + case KM_DECAY: + uistat.value = setting.decay; + plot_printf(uistat.text, sizeof uistat.text, "%3d", ((int32_t)uistat.value)); + break; + case KM_NOISE: + uistat.value = setting.noise; + plot_printf(uistat.text, sizeof uistat.text, "%3d", ((int32_t)uistat.value)); + break; + case KM_10MHZ: + uistat.value = setting_frequency_10mhz; + plot_printf(uistat.text, sizeof uistat.text, "%3.6fMHz", uistat.value / 1000000.0); + break; + case KM_OFFSET: + uistat.value = setting.offset; + plot_printf(uistat.text, sizeof uistat.text, "%.1fdB", uistat.value); + break; + case KM_LEVELSWEEP: + uistat.value = setting.level_sweep; + plot_printf(uistat.text, sizeof uistat.text, "%.1fdB", uistat.value); + break; + case KM_SWEEP_TIME: + if (setting.sweep_time < calc_min_sweep_time()) + uistat.value = calc_min_sweep_time(); + else + uistat.value = setting.sweep_time; + uistat.value /= 1000.0; + plot_printf(uistat.text, sizeof uistat.text, "%.3FS", uistat.value); + break; + case KM_TRIGGER: + uistat.value = setting.trigger_level; + plot_printf(uistat.text, sizeof uistat.text, "%.1fdB", uistat.value); + break; + + } + + { + uint32_t x = uistat.value; + int n = 0; + for (; x >= 10 && n < 9; n++) + x /= 10; + uistat.digit = n; + } +// uistat.previous_value = uistat.value; +} + +static void +set_numeric_value(void) +{ + switch (keypad_mode) { + case KM_START: + set_sweep_frequency(ST_START, uistat.value); + break; + case KM_STOP: + set_sweep_frequency(ST_STOP, uistat.value); + break; + case KM_CENTER: + set_sweep_frequency(ST_CENTER, uistat.value); + break; + case KM_SPAN: + setting.modulation = MO_NONE; + set_sweep_frequency(ST_SPAN, uistat.value); + break; + case KM_CW: + set_sweep_frequency(ST_CW, uistat.value); + break; + case KM_SCALE: + user_set_scale(uistat.value); + break; + case KM_REFLEVEL: + user_set_reflevel(uistat.value); + break; + case KM_ATTENUATION: + setting.auto_attenuation = false; + set_attenuation(uistat.value); + break; + case KM_ACTUALPOWER: + set_actual_power(uistat.value); + config_save(); + break; + case KM_IF: + setting.auto_IF = false; + set_IF(uistat.value); +// config_save(); + break; + case KM_SAMPLETIME: + set_step_delay(uistat.value); + break; + case KM_REPEAT: + set_repeat(uistat.value); + break; + case KM_DRIVE: + set_drive(uistat.value); + break; + case KM_LOWOUTLEVEL: + set_level(uistat.value); + break; + case KM_DECAY: + set_decay(uistat.value); + break; + case KM_NOISE: + set_noise(uistat.value); + break; + case KM_10MHZ: + if (uistat.value < 9000000) { + set_10mhz(setting_frequency_10mhz + uistat.value); + } else + set_10mhz(uistat.value); + dirty = true; + break; + case KM_OFFSET: + set_offset(uistat.value); + break; + case KM_LEVELSWEEP: + setting.modulation = MO_NONE; + set_level_sweep(uistat.value); + break; + case KM_SWEEP_TIME: + set_sweep_time(uistat.value*1000.0); + update_grid(); + break; + case KM_TRIGGER: + if (setting.trigger == T_AUTO ) + set_trigger(T_NORMAL); + set_trigger_level(to_dBm(uistat.value)); + redraw_request |= REDRAW_CAL_STATUS | REDRAW_AREA; + completed = true; + + break; + } +}