├── .gitignore ├── README.md └── SDR_RA8875 ├── .clang-format ├── .vscode ├── arduino.json ├── c_cpp_properties.json ├── settings.json └── tasks.json ├── Aux_Lib_Files ├── Audio │ ├── Audio.h │ ├── control_wm8960.cpp │ ├── control_wm8960.h │ └── readme.txt ├── OpenAudio_Library │ ├── AudioStream_F32.h │ └── Readme.txt ├── RS-HFIQ Omni-RIg │ ├── RS-HFIQ-1.ini │ ├── RS-HFIQ-2.ini │ └── RS-HFIQ.ini ├── SV1AFN_BandpassFilters │ ├── SVN1AFN_BandpassFilters.cpp │ ├── SVN1AFN_BandpassFilters.h │ └── examples │ │ └── SV1AFNBandpassFilterTest │ │ └── SV1AFNBandpassFilterTest.ino └── cores_IDE_2.0 │ ├── AudioStream..txt │ ├── boards.local.txt │ ├── readme.txt │ ├── usb.c │ ├── usb_audio.cpp │ ├── usb_audio.h │ ├── usb_desc.c │ └── usb_desc.h ├── Bandwidth2.cpp ├── Bandwidth2.h ├── Controls.cpp ├── Controls.h ├── Display.cpp ├── Display.h ├── Hardware ├── 4.3inch Motherboard PCB │ └── K7MDL V2.1 Teensy 4.1 SDR Motherboard for 4.3in RA887 Displays.jpg ├── 7inch Motherboard PCB │ ├── Gerber_PCB - Teensy RA8876 audio backpack V2.1 - 7 inch (1).zip │ ├── K7MDL Teensy 4.1 SDR Motherboard for 7in and 4.3in RA8876-RA8875 Displays.jpg │ ├── Schematic_V2-1_7-inch_Teensy_PCB_2022-12-24.pdf │ ├── Teensy Motherboard RA8876 V2.1 BOM 12-30-2022-NOT EXACT.xlsx │ └── V2.1 Teensy Motherboard DigiKey Order with Pricing (K7MDL Build) - 1-6-2023 -DRAFT.xlsx └── Teensy_SDR_4-3_Inch_Front_Panel_V1 - no engraving - fixed origin.fpd ├── Hilbert.h ├── Mode.cpp ├── Mode.h ├── Pictures ├── 20210409_040442.jpg ├── 20210420_172251.jpg ├── 20210424_160849.jpg ├── 20210425_181802.jpg ├── 20231203_114901.jpg ├── 20231203_114909.jpg ├── 3-10-2021 ScreenShot.jpg ├── 3-25-2021 ScreenShot.jpg ├── 4.3inch Hammond Front Panel Milling-2.jpg ├── 4.3inch Hammond Front Panel Milling.jpg ├── 7inch with x2 Zoom.jpg ├── 7inch with x4 Zoom.jpg ├── K7MDL Teensy 4.1 SDR Motherboard for 7in and 4.3in RA8876-RA8875 Displays.jpg ├── Teens_SDR_end_Panel-2.jpg ├── Teensy SDR 7inch under construction DEC 2022.jpg ├── Teensy SDR V2.1 PCB - assembled.jpg ├── Teensy SDR V2.2 Motherboard - Feb 2023.jpg ├── Teensy SDR in Hammond Case.jpg ├── TeensySDR in Hammond 1455N1601-1.jpg ├── TeensySDR in Hammond 1455N1601-2.jpg ├── TeensySDR in Hammond 1455N1601-End_View.jpg ├── TeensySDR in Hammond 1455N1601-Front-1.jpg ├── TeensySDR in Hammond 1455N1601-Front.jpg ├── TeensySDR in Hammond 1455N1601-USB Host connection to Nano.jpg └── Teensy_SDR_end_panel_1.jpg ├── README.md ├── RadioConfig.h ├── SDR_CAT.cpp ├── SDR_CAT.h ├── SDR_CAT_Serial.cpp ├── SDR_CAT_Serial.h ├── SDR_Data.h ├── SDR_I2C_Encoder.cpp ├── SDR_I2C_Encoder.h ├── SDR_Network.cpp ├── SDR_Network.h ├── SDR_RA8875.code-workspace ├── SDR_RA8875.h ├── SDR_RA8875.ino ├── SDR_RS_HFIQ.cpp ├── SDR_RS_HFIQ.h ├── SD_Card.cpp ├── SD_Card.h ├── Smeter.cpp ├── Smeter.h ├── Spectrum_RA887x.cpp ├── Spectrum_RA887x.h ├── Tuner.cpp ├── Tuner.h ├── UserInput.cpp ├── UserInput.h ├── Vfo.cpp ├── Vfo.h ├── hilbert121A.h ├── hilbert19A.h └── hilbert251A.h /.gitignore: -------------------------------------------------------------------------------- 1 | .pio 2 | .vscode/.browse.c_cpp.db* 3 | .vscode/c_cpp_properties.json 4 | .vscode/launch.json 5 | .vscode/ipch 6 | .vsteensy 7 | .lib 8 | .*.zip 9 | **/lib/** 10 | **/build/** 11 | SDR_RA8875/.vscode/settings.json 12 | SDR_RA8875/.vscode/c_cpp_properties.json 13 | SDR_RA8875/makefile 14 | SDR_RA8875/.vscode/arduino.json 15 | .gitignore 16 | SDR_RA8875/SDR_RA8875.code-workspace 17 | SDR_RA8875/makefile 18 | SDR_RA8875/.vscode/tasks.json 19 | .vscode/arduino.json 20 | SDR_RA8875/makefile 21 | SDR_RA8875/.vscode/tasks.json 22 | SDR_RA8875/.vscode/c_cpp_properties.json 23 | SDR_RA8875/.vscode/arduino.json 24 | SDR_RA8875/.vscode/arduino.json 25 | SDR_RA8875/build/build.options.json 26 | SDR_RA8875/build/build 27 | SDR_RA8875/.vscode/tasks.json 28 | SDR_RA8875/.vscode/settings.json 29 | SDR_RA8875/.vscode/c_cpp_properties.json 30 | SDR_RA8875/.vscode/arduino.json 31 | SDR_RA8875/.theia/launch.json 32 | SDR_RA8875/sbitxdefs.txt 33 | SDR_RA8875/makefile 34 | SDR_RA8875/SDR_RA8875.code-workspace 35 | SDR_RA8875-shadow_vfo.zip 36 | SDR_RA8875/SDR_RA8875.code-workspace 37 | SDR_RA8875/Spectrum_RA887x.cpp.old 38 | SDR_RA8875/.vscode/c_cpp_properties.json 39 | SDR_RA8875/.vscode/c_cpp_properties.json 40 | SDR_RA8875/.vscode/settings.json 41 | SDR_RA8875/.vscode/tasks.json 42 | SDR_RA8875/.vscode/arduino.json 43 | SDR_RA8875/.vscode/c_cpp_properties.json 44 | SDR_RA8875/.vscode/settings.json 45 | .gitignore 46 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # KEITHSDR 2 | Teensy4.X with PJRC audio card Arduino based SDR Radio project. 3 | 4 | The project has a forum and more wiki pages and info at https://groups.io/g/keithsdr 5 | 6 | This is a GitHub Repository for Group Member builds and variations of hardware and feature experiments. There is a simpler version maintained by Keith, and this is my derivative, maintained by me, Mike. 7 | 8 | The folder SDR_RA8875 is one such SDR project folder and is built on Teensy 4.1 with Audio Card and RA8875 based capacitive touchscreen at 800x480, or a RA8876 capacitive touchscreen at 1024x600. The UI elements use table driven data so they are resizeable/relocatable. The size screen is less important than the controller used. I am leveraging the BTE (Bit Transfer Engine) feature of these controllers to offload the CPU enabling high resolution spectrum and waterfall graphics with minimal CPU overhead. 9 | 10 | ![K7MDL Front Panel RA8875 Compact Teensy SDR](https://github.com/K7MDL2/KEITHSDR/blob/main/SDR_RA8875/Pictures/TeensySDR%20in%20Hammond%201455N1601-Front-1.jpg) 11 | More pics at https://github.com/K7MDL2/KEITHSDR/tree/main/SDR_RA8875/Pictures 12 | and at my website https://k7mdl2.wixsite.com/k7mdl/copy-of-teensy-4-sdr 13 | 14 | 15 | Features: 16 | 17 | 1. 4096, 2048 and 1024 point I&Q FFTs using the OpenAudio_Library converted to 32 bit Floating Point by W7PUA. Uses all 3 FFT sizes chosen according to the zoom level. Zoom simply uses FFT size today, no other processing done. 18 | 2. Resizable Spectrum and Waterfall module can be dropped into most any Arduino project using the RA8875 or with minor mods RA8876 based display controllers for minimal CPU overhead for waterfall graphics. As of Jan 2022 the Spectrum Display related code is now in an new Arduino Library. 19 | 3. Supports the FT5206 Capacitive Touch screen controller for touch and gestures. 20 | 4. Custom gesture code replaces the poorly working internal FT5206 Gesture detection. Found in UserInput.h 21 | 5. Table driven UI configuration, per-band settings, and User Profile settings with centralized control functions. 22 | 6. Supports both RA8875 and RA8876 based displays with capacitive touch controllers 23 | 7. Supports USB Host connection to a RS-HFIQ 5W SDR transceiver. Can use many other hardware choices and build your own RF sections. 24 | 8. Deafult sample rate used is 48KHz. 25 | 9. Supports USB Audio connection ((both in ane Out) at 48KHz to a PC for external digital mode programs along with CAT control port using the Kenwood/Elecraft K3 command set. Works great with WSJT-X. Instructions provided in the Wiki on how to set up a custom Dual Serial+Audio USB 48Khz configuration. 26 | 27 | See the README file in each project for specifics about that build. 28 | 29 | UI as of 3/25/2021. 40M FT-8. Testing colors and styles of indicators. 30 | 31 | Sample rate at 102.4KHz with 4096 point I and Q FFT on a 800x480 4.3" display. 24% max CPU, 4% average. 1:1 bins-per-pixel mapping. 32 | 33 | ![UI Screenshot 3-25-2021](https://github.com/K7MDL2/KEITHSDR/blob/main/SDR_RA8875/Pictures/3-25-2021%20ScreenShot.jpg) 34 | 35 | There are many Wiki Pages with hardware and software notes and how to build and configure. I sugest reviewing them and then this page to start your first build. 36 | https://github.com/K7MDL2/KEITHSDR/wiki/Getting-Started-Building-SDR_887x-SDR-program 37 | -------------------------------------------------------------------------------- /SDR_RA8875/.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | Standard: Cpp11 3 | BasedOnStyle: LLVM 4 | 5 | IndentWidth: 4 6 | TabWidth: 4 7 | AccessModifierOffset: -3 8 | ColumnLimit: 0 9 | UseTab: Never 10 | 11 | AllowShortIfStatementsOnASingleLine: true 12 | AllowShortLoopsOnASingleLine : true 13 | AllowShortBlocksOnASingleLine: true 14 | IndentCaseLabels: true 15 | 16 | PointerAlignment: Left 17 | 18 | AlignTrailingComments: true 19 | AlignConsecutiveAssignments: true 20 | 21 | NamespaceIndentation: All 22 | FixNamespaceComments: false 23 | 24 | IndentPPDirectives: AfterHash 25 | 26 | CompactNamespaces: true 27 | 28 | BreakBeforeBraces: Custom 29 | BraceWrapping: 30 | AfterStruct: true 31 | AfterClass: true 32 | AfterControlStatement: true 33 | AfterNamespace: true 34 | AfterFunction: true 35 | AfterUnion: true 36 | AfterExternBlock: false 37 | AfterEnum: false 38 | BeforeElse: true 39 | SplitEmptyFunction: false 40 | SplitEmptyRecord: true 41 | SplitEmptyNamespace: true 42 | 43 | IncludeBlocks: Merge 44 | -------------------------------------------------------------------------------- /SDR_RA8875/.vscode/arduino.json: -------------------------------------------------------------------------------- 1 | { 2 | "sketch": "SDR_RA8875.ino", 3 | "configuration": "usb=serialserialaudio,speed=816,opt=o2std,keys=en-us", 4 | "board": "teensy:avr:teensy41", 5 | "output": "..\\build", 6 | "port": "COM27" 7 | } -------------------------------------------------------------------------------- /SDR_RA8875/.vscode/c_cpp_properties.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 4, 3 | "configurations": [ 4 | { 5 | "name": "Arduino", 6 | "compilerPath": "C:\\Users\\Mike\\AppData\\Local\\Arduino15\\packages\\teensy\\tools\\teensy-tools\\1.57.2\\arm\\bin\\arm-none-eabi-g++", 7 | "compilerArgs": [ 8 | "-Wall", 9 | "-ffunction-sections", 10 | "-fdata-sections", 11 | "-nostdlib" 12 | ], 13 | "intelliSenseMode": "gcc-x64", 14 | "includePath": [ 15 | "d:\\Documents\\GitHub\\SDRProjects\\KEITHSDR\\build\\pch", 16 | "D:\\Program Files\\Arduino\\hardware\\teensy\\avr\\cores\\teensy4", 17 | "D:\\Program Files\\Arduino\\hardware\\teensy\\avr\\libraries\\SPI", 18 | "D:\\Program Files\\Arduino\\hardware\\teensy\\avr\\libraries\\Wire", 19 | "D:\\Program Files\\Arduino\\hardware\\teensy\\avr\\libraries\\Time", 20 | "D:\\Program Files\\Arduino\\hardware\\teensy\\avr\\libraries\\Encoder", 21 | "D:\\Documents\\Arduino\\libraries\\Metro", 22 | "D:\\Documents\\Arduino\\libraries\\OpenAudio_ArduinoLibrary", 23 | "D:\\Program Files\\Arduino\\hardware\\teensy\\avr\\libraries\\Audio", 24 | "D:\\Program Files\\Arduino\\hardware\\teensy\\avr\\libraries\\SD\\src", 25 | "D:\\Program Files\\Arduino\\hardware\\teensy\\avr\\libraries\\SdFat\\src", 26 | "D:\\Program Files\\Arduino\\hardware\\teensy\\avr\\libraries\\SerialFlash", 27 | "D:\\Documents\\Arduino\\libraries\\InternalTemperature", 28 | "D:\\Documents\\Arduino\\libraries\\RA8876_t3\\src", 29 | "D:\\Program Files\\Arduino\\hardware\\teensy\\avr\\libraries\\ILI9488_t3\\src", 30 | "D:\\Documents\\Arduino\\libraries\\FT5206", 31 | "D:\\Documents\\Arduino\\libraries\\i2cEncoderLibV2\\src", 32 | "D:\\Program Files\\Arduino\\hardware\\teensy\\avr\\libraries\\USBHost_t36", 33 | "d:\\program files\\arduino\\hardware\\tools\\arm\\arm-none-eabi\\include\\c++\\5.4.1", 34 | "d:\\program files\\arduino\\hardware\\tools\\arm\\arm-none-eabi\\include\\c++\\5.4.1\\arm-none-eabi", 35 | "d:\\program files\\arduino\\hardware\\tools\\arm\\arm-none-eabi\\include\\c++\\5.4.1\\backward", 36 | "d:\\program files\\arduino\\hardware\\tools\\arm\\lib\\gcc\\arm-none-eabi\\5.4.1\\include", 37 | "d:\\program files\\arduino\\hardware\\tools\\arm\\lib\\gcc\\arm-none-eabi\\5.4.1\\include-fixed", 38 | "d:\\program files\\arduino\\hardware\\tools\\arm\\arm-none-eabi\\include" 39 | ], 40 | "forcedInclude": [ 41 | "d:\\Documents\\GitHub\\SDRProjects\\KEITHSDR\\build\\pch\\Arduino.h" 42 | ], 43 | "cStandard": "c11", 44 | "cppStandard": "c++14", 45 | "defines": [ 46 | "__IMXRT1062__", 47 | "TEENSYDUINO=157", 48 | "ARDUINO=10819", 49 | "ARDUINO_TEENSY41", 50 | "F_CPU=816000000", 51 | "USB_SERIAL_SERIAL_AUDIO", 52 | "LAYOUT_US_ENGLISH", 53 | "__DBL_MIN_EXP__=(-1021)", 54 | "__HQ_FBIT__=15", 55 | "__UINT_LEAST16_MAX__=0xffff", 56 | "__ARM_SIZEOF_WCHAR_T=4", 57 | "__ATOMIC_ACQUIRE=2", 58 | "__SFRACT_IBIT__=0", 59 | "__FLT_MIN__=1.1754943508222875e-38F", 60 | "__GCC_IEC_559_COMPLEX=0", 61 | "__UFRACT_MAX__=0XFFFFP-16UR", 62 | "__UINT_LEAST8_TYPE__=unsigned char", 63 | "__DQ_FBIT__=63", 64 | "__INTMAX_C(c)=c ## LL", 65 | "__ULFRACT_FBIT__=32", 66 | "__SACCUM_EPSILON__=0x1P-7HK", 67 | "__CHAR_BIT__=8", 68 | "__USQ_IBIT__=0", 69 | "__UINT8_MAX__=0xff", 70 | "__ACCUM_FBIT__=15", 71 | "__WINT_MAX__=0xffffffffU", 72 | "__USFRACT_FBIT__=8", 73 | "__ORDER_LITTLE_ENDIAN__=1234", 74 | "__SIZE_MAX__=0xffffffffU", 75 | "__ARM_ARCH_ISA_ARM=1", 76 | "__WCHAR_MAX__=0xffffffffU", 77 | "__LACCUM_IBIT__=32", 78 | "__DBL_DENORM_MIN__=double(4.9406564584124654e-324L)", 79 | "__GCC_ATOMIC_CHAR_LOCK_FREE=1", 80 | "__GCC_IEC_559=0", 81 | "__FLT_EVAL_METHOD__=0", 82 | "__cpp_binary_literals=201304", 83 | "__LLACCUM_MAX__=0X7FFFFFFFFFFFFFFFP-31LLK", 84 | "__GCC_ATOMIC_CHAR32_T_LOCK_FREE=1", 85 | "__FRACT_FBIT__=15", 86 | "__UINT_FAST64_MAX__=0xffffffffffffffffULL", 87 | "__SIG_ATOMIC_TYPE__=int", 88 | "__UACCUM_FBIT__=16", 89 | "__DBL_MIN_10_EXP__=(-307)", 90 | "__FINITE_MATH_ONLY__=0", 91 | "__ARMEL__=1", 92 | "__LFRACT_IBIT__=0", 93 | "__GNUC_PATCHLEVEL__=1", 94 | "__LFRACT_MAX__=0X7FFFFFFFP-31LR", 95 | "__UINT_FAST8_MAX__=0xffffffffU", 96 | "__has_include(STR)=__has_include__(STR)", 97 | "__DEC64_MAX_EXP__=385", 98 | "__INT8_C(c)=c", 99 | "__UINT_LEAST64_MAX__=0xffffffffffffffffULL", 100 | "__SA_FBIT__=15", 101 | "__SHRT_MAX__=0x7fff", 102 | "__LDBL_MAX__=1.7976931348623157e+308L", 103 | "__FRACT_MAX__=0X7FFFP-15R", 104 | "__UFRACT_FBIT__=16", 105 | "__UFRACT_MIN__=0.0UR", 106 | "__UINT_LEAST8_MAX__=0xff", 107 | "__GCC_ATOMIC_BOOL_LOCK_FREE=1", 108 | "__UINTMAX_TYPE__=long long unsigned int", 109 | "__LLFRACT_EPSILON__=0x1P-63LLR", 110 | "__DEC32_EPSILON__=1E-6DF", 111 | "__CHAR_UNSIGNED__=1", 112 | "__UINT32_MAX__=0xffffffffUL", 113 | "__ULFRACT_MAX__=0XFFFFFFFFP-32ULR", 114 | "__TA_IBIT__=64", 115 | "__LDBL_MAX_EXP__=1024", 116 | "__WINT_MIN__=0U", 117 | "__ULLFRACT_MIN__=0.0ULLR", 118 | "__SCHAR_MAX__=0x7f", 119 | "__WCHAR_MIN__=0U", 120 | "__INT64_C(c)=c ## LL", 121 | "__DBL_DIG__=15", 122 | "__GCC_ATOMIC_POINTER_LOCK_FREE=1", 123 | "__LLACCUM_MIN__=(-0X1P31LLK-0X1P31LLK)", 124 | "__SIZEOF_INT__=4", 125 | "__SIZEOF_POINTER__=4", 126 | "__GCC_ATOMIC_CHAR16_T_LOCK_FREE=1", 127 | "__USACCUM_IBIT__=8", 128 | "__USER_LABEL_PREFIX__", 129 | "__STDC_HOSTED__=1", 130 | "__LDBL_HAS_INFINITY__=1", 131 | "__LFRACT_MIN__=(-0.5LR-0.5LR)", 132 | "__HA_IBIT__=8", 133 | "__TQ_IBIT__=0", 134 | "__FLT_EPSILON__=1.1920928955078125e-7F", 135 | "__APCS_32__=1", 136 | "__GXX_WEAK__=1", 137 | "__USFRACT_IBIT__=0", 138 | "__LDBL_MIN__=2.2250738585072014e-308L", 139 | "__FRACT_MIN__=(-0.5R-0.5R)", 140 | "__DEC32_MAX__=9.999999E96DF", 141 | "__DA_IBIT__=32", 142 | "__ARM_SIZEOF_MINIMAL_ENUM=1", 143 | "__INT32_MAX__=0x7fffffffL", 144 | "__UQQ_FBIT__=8", 145 | "__SIZEOF_LONG__=4", 146 | "__UACCUM_MAX__=0XFFFFFFFFP-16UK", 147 | "__UINT16_C(c)=c", 148 | "__DECIMAL_DIG__=17", 149 | "__LFRACT_EPSILON__=0x1P-31LR", 150 | "__ULFRACT_MIN__=0.0ULR", 151 | "__has_include_next(STR)=__has_include_next__(STR)", 152 | "__LDBL_HAS_QUIET_NAN__=1", 153 | "__ULACCUM_IBIT__=32", 154 | "__UACCUM_EPSILON__=0x1P-16UK", 155 | "__GNUC__=5", 156 | "__ULLACCUM_MAX__=0XFFFFFFFFFFFFFFFFP-32ULLK", 157 | "__GXX_RTTI=1", 158 | "__HQ_IBIT__=0", 159 | "__FLT_HAS_DENORM__=1", 160 | "__SIZEOF_LONG_DOUBLE__=8", 161 | "__BIGGEST_ALIGNMENT__=8", 162 | "__DQ_IBIT__=0", 163 | "__DBL_MAX__=double(1.7976931348623157e+308L)", 164 | "__ULFRACT_IBIT__=0", 165 | "__INT_FAST32_MAX__=0x7fffffff", 166 | "__DBL_HAS_INFINITY__=1", 167 | "__INT64_MAX__=0x7fffffffffffffffLL", 168 | "__ACCUM_IBIT__=16", 169 | "__DEC32_MIN_EXP__=(-94)", 170 | "__THUMB_INTERWORK__=1", 171 | "__LACCUM_MAX__=0X7FFFFFFFFFFFFFFFP-31LK", 172 | "__INT_FAST16_TYPE__=int", 173 | "__LDBL_HAS_DENORM__=1", 174 | "__cplusplus=199711L", 175 | "__DEC128_MAX__=9.999999999999999999999999999999999E6144DL", 176 | "__INT_LEAST32_MAX__=0x7fffffffL", 177 | "__ARM_PCS=1", 178 | "__DEC32_MIN__=1E-95DF", 179 | "__ACCUM_MAX__=0X7FFFFFFFP-15K", 180 | "__DEPRECATED=1", 181 | "__DBL_MAX_EXP__=1024", 182 | "__USACCUM_EPSILON__=0x1P-8UHK", 183 | "__DEC128_EPSILON__=1E-33DL", 184 | "__SFRACT_MAX__=0X7FP-7HR", 185 | "__FRACT_IBIT__=0", 186 | "__PTRDIFF_MAX__=0x7fffffff", 187 | "__UACCUM_MIN__=0.0UK", 188 | "__UACCUM_IBIT__=16", 189 | "__GNUG__=5", 190 | "__LONG_LONG_MAX__=0x7fffffffffffffffLL", 191 | "__SIZEOF_SIZE_T__=4", 192 | "__ULACCUM_MAX__=0XFFFFFFFFFFFFFFFFP-32ULK", 193 | "__SIZEOF_WINT_T__=4", 194 | "__SA_IBIT__=16", 195 | "__ULLACCUM_MIN__=0.0ULLK", 196 | "__GXX_ABI_VERSION=1009", 197 | "__UTA_FBIT__=64", 198 | "__SOFTFP__=1", 199 | "__FLT_MIN_EXP__=(-125)", 200 | "__USFRACT_MAX__=0XFFP-8UHR", 201 | "__UFRACT_IBIT__=0", 202 | "__INT_FAST64_TYPE__=long long int", 203 | "__DBL_MIN__=double(2.2250738585072014e-308L)", 204 | "__FLT_MIN_10_EXP__=(-37)", 205 | "__LACCUM_MIN__=(-0X1P31LK-0X1P31LK)", 206 | "__ULLACCUM_FBIT__=32", 207 | "__GXX_TYPEINFO_EQUALITY_INLINE=0", 208 | "__ULLFRACT_EPSILON__=0x1P-64ULLR", 209 | "__USES_INITFINI__=1", 210 | "__DEC128_MIN__=1E-6143DL", 211 | "__REGISTER_PREFIX__", 212 | "__UINT16_MAX__=0xffff", 213 | "__DBL_HAS_DENORM__=1", 214 | "__ACCUM_MIN__=(-0X1P15K-0X1P15K)", 215 | "__SQ_IBIT__=0", 216 | "__UINT8_TYPE__=unsigned char", 217 | "__UHA_FBIT__=8", 218 | "__NO_INLINE__=1", 219 | "__SFRACT_MIN__=(-0.5HR-0.5HR)", 220 | "__UTQ_FBIT__=128", 221 | "__FLT_MANT_DIG__=24", 222 | "__VERSION__=\"5.4.1 20160919 (release) [ARM/embedded-5-branch revision 240496]\"", 223 | "__UINT64_C(c)=c ## ULL", 224 | "__ULLFRACT_FBIT__=64", 225 | "__FRACT_EPSILON__=0x1P-15R", 226 | "__ULACCUM_MIN__=0.0ULK", 227 | "__UDA_FBIT__=32", 228 | "__LLACCUM_EPSILON__=0x1P-31LLK", 229 | "__GCC_ATOMIC_INT_LOCK_FREE=1", 230 | "__FLOAT_WORD_ORDER__=__ORDER_LITTLE_ENDIAN__", 231 | "__USFRACT_MIN__=0.0UHR", 232 | "__ULLACCUM_IBIT__=32", 233 | "__UQQ_IBIT__=0", 234 | "__INT32_C(c)=c ## L", 235 | "__DEC64_EPSILON__=1E-15DD", 236 | "__ORDER_PDP_ENDIAN__=3412", 237 | "__DEC128_MIN_EXP__=(-6142)", 238 | "__UHQ_FBIT__=16", 239 | "__LLACCUM_FBIT__=31", 240 | "__INT_FAST32_TYPE__=int", 241 | "__UINT_LEAST16_TYPE__=short unsigned int", 242 | "__INT16_MAX__=0x7fff", 243 | "__cpp_rtti=199711", 244 | "__SIZE_TYPE__=unsigned int", 245 | "__UINT64_MAX__=0xffffffffffffffffULL", 246 | "__UDQ_FBIT__=64", 247 | "__INT8_TYPE__=signed char", 248 | "__ELF__=1", 249 | "__ULFRACT_EPSILON__=0x1P-32ULR", 250 | "__LLFRACT_FBIT__=63", 251 | "__FLT_RADIX__=2", 252 | "__INT_LEAST16_TYPE__=short int", 253 | "__LDBL_EPSILON__=2.2204460492503131e-16L", 254 | "__UINTMAX_C(c)=c ## ULL", 255 | "__SACCUM_MAX__=0X7FFFP-7HK", 256 | "__SIG_ATOMIC_MAX__=0x7fffffff", 257 | "__GCC_ATOMIC_WCHAR_T_LOCK_FREE=1", 258 | "__VFP_FP__=1", 259 | "__SIZEOF_PTRDIFF_T__=4", 260 | "__LACCUM_EPSILON__=0x1P-31LK", 261 | "__DEC32_SUBNORMAL_MIN__=0.000001E-95DF", 262 | "__INT_FAST16_MAX__=0x7fffffff", 263 | "__UINT_FAST32_MAX__=0xffffffffU", 264 | "__UINT_LEAST64_TYPE__=long long unsigned int", 265 | "__USACCUM_MAX__=0XFFFFP-8UHK", 266 | "__SFRACT_EPSILON__=0x1P-7HR", 267 | "__FLT_HAS_QUIET_NAN__=1", 268 | "__FLT_MAX_10_EXP__=38", 269 | "__LONG_MAX__=0x7fffffffL", 270 | "__DEC128_SUBNORMAL_MIN__=0.000000000000000000000000000000001E-6143DL", 271 | "__FLT_HAS_INFINITY__=1", 272 | "__USA_FBIT__=16", 273 | "__UINT_FAST16_TYPE__=unsigned int", 274 | "__DEC64_MAX__=9.999999999999999E384DD", 275 | "__ARM_32BIT_STATE=1", 276 | "__CHAR16_TYPE__=short unsigned int", 277 | "__PRAGMA_REDEFINE_EXTNAME=1", 278 | "__INT_LEAST16_MAX__=0x7fff", 279 | "__DEC64_MANT_DIG__=16", 280 | "__UINT_LEAST32_MAX__=0xffffffffUL", 281 | "__SACCUM_FBIT__=7", 282 | "__GCC_ATOMIC_LONG_LOCK_FREE=1", 283 | "__INT_LEAST64_TYPE__=long long int", 284 | "__INT16_TYPE__=short int", 285 | "__INT_LEAST8_TYPE__=signed char", 286 | "__SQ_FBIT__=31", 287 | "__DEC32_MAX_EXP__=97", 288 | "__ARM_ARCH_ISA_THUMB=1", 289 | "__INT_FAST8_MAX__=0x7fffffff", 290 | "__ARM_ARCH=4", 291 | "__INTPTR_MAX__=0x7fffffff", 292 | "__QQ_FBIT__=7", 293 | "__UTA_IBIT__=64", 294 | "__EXCEPTIONS=1", 295 | "__LDBL_MANT_DIG__=53", 296 | "__SFRACT_FBIT__=7", 297 | "__SACCUM_MIN__=(-0X1P7HK-0X1P7HK)", 298 | "__DBL_HAS_QUIET_NAN__=1", 299 | "__SIG_ATOMIC_MIN__=(-__SIG_ATOMIC_MAX__ - 1)", 300 | "__INTPTR_TYPE__=int", 301 | "__UINT16_TYPE__=short unsigned int", 302 | "__WCHAR_TYPE__=unsigned int", 303 | "__SIZEOF_FLOAT__=4", 304 | "__USQ_FBIT__=32", 305 | "__UINTPTR_MAX__=0xffffffffU", 306 | "__DEC64_MIN_EXP__=(-382)", 307 | "__INT_FAST64_MAX__=0x7fffffffffffffffLL", 308 | "__GCC_ATOMIC_TEST_AND_SET_TRUEVAL=1", 309 | "__FLT_DIG__=6", 310 | "__UINT_FAST64_TYPE__=long long unsigned int", 311 | "__INT_MAX__=0x7fffffff", 312 | "__LACCUM_FBIT__=31", 313 | "__USACCUM_MIN__=0.0UHK", 314 | "__UHA_IBIT__=8", 315 | "__INT64_TYPE__=long long int", 316 | "__FLT_MAX_EXP__=128", 317 | "__UTQ_IBIT__=0", 318 | "__DBL_MANT_DIG__=53", 319 | "__INT_LEAST64_MAX__=0x7fffffffffffffffLL", 320 | "__DEC64_MIN__=1E-383DD", 321 | "__WINT_TYPE__=unsigned int", 322 | "__UINT_LEAST32_TYPE__=long unsigned int", 323 | "__SIZEOF_SHORT__=2", 324 | "__ULLFRACT_IBIT__=0", 325 | "__LDBL_MIN_EXP__=(-1021)", 326 | "__arm__=1", 327 | "__UDA_IBIT__=32", 328 | "__INT_LEAST8_MAX__=0x7f", 329 | "__LFRACT_FBIT__=31", 330 | "__WCHAR_UNSIGNED__=1", 331 | "__LDBL_MAX_10_EXP__=308", 332 | "__ATOMIC_RELAXED=0", 333 | "__DBL_EPSILON__=double(2.2204460492503131e-16L)", 334 | "__UINT8_C(c)=c", 335 | "__INT_LEAST32_TYPE__=long int", 336 | "__SIZEOF_WCHAR_T__=4", 337 | "__UINT64_TYPE__=long long unsigned int", 338 | "__LLFRACT_MAX__=0X7FFFFFFFFFFFFFFFP-63LLR", 339 | "__TQ_FBIT__=127", 340 | "__INT_FAST8_TYPE__=int", 341 | "__ULLACCUM_EPSILON__=0x1P-32ULLK", 342 | "__UHQ_IBIT__=0", 343 | "__LLACCUM_IBIT__=32", 344 | "__DBL_DECIMAL_DIG__=17", 345 | "__DEC_EVAL_METHOD__=2", 346 | "__TA_FBIT__=63", 347 | "__UDQ_IBIT__=0", 348 | "__ORDER_BIG_ENDIAN__=4321", 349 | "__cpp_runtime_arrays=198712", 350 | "__ACCUM_EPSILON__=0x1P-15K", 351 | "__UINT32_C(c)=c ## UL", 352 | "__INTMAX_MAX__=0x7fffffffffffffffLL", 353 | "__BYTE_ORDER__=__ORDER_LITTLE_ENDIAN__", 354 | "__FLT_DENORM_MIN__=1.4012984643248171e-45F", 355 | "__LLFRACT_IBIT__=0", 356 | "__INT8_MAX__=0x7f", 357 | "__UINT_FAST32_TYPE__=unsigned int", 358 | "__CHAR32_TYPE__=long unsigned int", 359 | "__FLT_MAX__=3.4028234663852886e+38F", 360 | "__USACCUM_FBIT__=8", 361 | "__INT32_TYPE__=long int", 362 | "__SIZEOF_DOUBLE__=8", 363 | "__cpp_exceptions=199711", 364 | "__UFRACT_EPSILON__=0x1P-16UR", 365 | "__INTMAX_TYPE__=long long int", 366 | "__DEC128_MAX_EXP__=6145", 367 | "__ATOMIC_CONSUME=1", 368 | "__GNUC_MINOR__=4", 369 | "__UINTMAX_MAX__=0xffffffffffffffffULL", 370 | "__DEC32_MANT_DIG__=7", 371 | "__HA_FBIT__=7", 372 | "__DBL_MAX_10_EXP__=308", 373 | "__LDBL_DENORM_MIN__=4.9406564584124654e-324L", 374 | "__INT16_C(c)=c", 375 | "__STDC__=1", 376 | "__ARM_ARCH_4T__=1", 377 | "__PTRDIFF_TYPE__=int", 378 | "__LLFRACT_MIN__=(-0.5LLR-0.5LLR)", 379 | "__ATOMIC_SEQ_CST=5", 380 | "__DA_FBIT__=31", 381 | "__UINT32_TYPE__=long unsigned int", 382 | "__UINTPTR_TYPE__=unsigned int", 383 | "__USA_IBIT__=16", 384 | "__DEC64_SUBNORMAL_MIN__=0.000000000000001E-383DD", 385 | "__ARM_EABI__=1", 386 | "__DEC128_MANT_DIG__=34", 387 | "__LDBL_MIN_10_EXP__=(-307)", 388 | "__SIZEOF_LONG_LONG__=8", 389 | "__ULACCUM_EPSILON__=0x1P-32ULK", 390 | "__SACCUM_IBIT__=8", 391 | "__GCC_ATOMIC_LLONG_LOCK_FREE=1", 392 | "__LDBL_DIG__=15", 393 | "__FLT_DECIMAL_DIG__=9", 394 | "__UINT_FAST16_MAX__=0xffffffffU", 395 | "__GNUC_GNU_INLINE__=1", 396 | "__GCC_ATOMIC_SHORT_LOCK_FREE=1", 397 | "__ULLFRACT_MAX__=0XFFFFFFFFFFFFFFFFP-64ULLR", 398 | "__UINT_FAST8_TYPE__=unsigned int", 399 | "__USFRACT_EPSILON__=0x1P-8UHR", 400 | "__ULACCUM_FBIT__=32", 401 | "__QQ_IBIT__=0", 402 | "__ATOMIC_ACQ_REL=4", 403 | "__ATOMIC_RELEASE=3", 404 | "USBCON" 405 | ] 406 | } 407 | ] 408 | } -------------------------------------------------------------------------------- /SDR_RA8875/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.exclude": { 3 | "**/.git": true, 4 | "**/.lib": true, 5 | "**/.vsteensy/**": true, 6 | ".pio": true, 7 | ".vscode/.browse.c_cpp.db*": true, 8 | ".vscode/c_cpp_properties.json": true, 9 | ".vscode/launch.json": true, 10 | ".vscode/ipch": true, 11 | ".lib": true, 12 | ".*.zip": true 13 | }, 14 | "C_Cpp.exclusionPolicy": "checkFilesAndFolders", 15 | "C_Cpp.errorSquiggles": "enabled", 16 | "C_Cpp.default.includePath": [ 17 | "C:\\ProgramFiles\\Arduino", 18 | "C:\\Program Files (x86)\\Arduino", 19 | "C:\\Users\\%USERPROFILE%\\Documents\\Arduino\\libraries", 20 | "C:\\Program Files (x86)\\Arduino\\hardware\\teensy\\avr\\libraries" 21 | ], 22 | "task.autoDetect": "off", 23 | "compiler-explorer.url": "http://localhost:10240", 24 | "compiler-explorer.compiler": "g54", 25 | "compiler-explorer.options": [ 26 | "-D__IMXRT1062__ -DTEENSYDUINO=156", 27 | "-DF_CPU=816000000", 28 | "-DUSB_SERIAL_SERIAL_AUDIO", 29 | "-DLAYOUT_US_ENGLISH", 30 | "-DARDUINO_TEENSY41", 31 | "-DARDUINO=10815", 32 | "-std=gnu++14 -fno-exceptions -fpermissive -fno-rtti -fno-threadsafe-statics -felide-constructors -Wno-error=narrowing", 33 | "-mthumb -mcpu=cortex-m7 -mfloat-abi=hard -mfpu=fpv5-d16", 34 | "-O2", 35 | "-g -Wall -ffunction-sections -fdata-sections -nostdlib", 36 | null 37 | ], 38 | "gnuGlobal.libraryPath": [ 39 | "C:\\Program Files (x86)\\Arduino\\libraries" 40 | ], 41 | "C_Cpp.default.compilerPath": "", 42 | "C_Cpp.default.mergeConfigurations": true 43 | } -------------------------------------------------------------------------------- /SDR_RA8875/.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "tasks": [ 3 | { 4 | "label": "Build", 5 | "group": { 6 | "kind": "build", 7 | "isDefault": false 8 | }, 9 | "command": "%VIRTUAL_TEENSY_PATH%/make.exe", 10 | "args": [ 11 | "all", 12 | "", 13 | "" 14 | ] 15 | }, 16 | { 17 | "label": "Clean", 18 | "group": { 19 | "kind": "build", 20 | "isDefault": false 21 | }, 22 | "command": "%VIRTUAL_TEENSY_PATH%/make.exe", 23 | "args": [ 24 | "clean" 25 | ] 26 | }, 27 | { 28 | "label": "Upload (teensy.exe)", 29 | "group": { 30 | "kind": "build", 31 | "isDefault": false 32 | }, 33 | "command": "%VIRTUAL_TEENSY_PATH%/make.exe", 34 | "args": [ 35 | "upload", 36 | "", 37 | "" 38 | ] 39 | }, 40 | { 41 | "label": "Upload (TyCommander)", 42 | "group": { 43 | "kind": "build", 44 | "isDefault": true 45 | }, 46 | "command": "%VIRTUAL_TEENSY_PATH%/make.exe", 47 | "args": [ 48 | "uploadTy", 49 | "", 50 | "" 51 | ] 52 | }, 53 | { 54 | "label": "Echo Path", 55 | "type": "shell", 56 | "command": "echo %VIRTUAL_TEENSY_PATH%" 57 | } 58 | ], 59 | "version": "2.0.0", 60 | "type": "shell", 61 | "problemMatcher": "$gcc", 62 | "presentation": { 63 | "echo": true, 64 | "clear": true, 65 | "reveal": "always", 66 | "focus": false, 67 | "panel": "shared", 68 | "showReuseMessage": false 69 | } 70 | } -------------------------------------------------------------------------------- /SDR_RA8875/Aux_Lib_Files/Audio/Audio.h: -------------------------------------------------------------------------------- 1 | /* Audio Library for Teensy 3.X 2 | * Copyright (c) 2014, Paul Stoffregen, paul@pjrc.com 3 | * 4 | * Development of this audio library was funded by PJRC.COM, LLC by sales of 5 | * Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop 6 | * open source software by purchasing Teensy or other PJRC products. 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy 9 | * of this software and associated documentation files (the "Software"), to deal 10 | * in the Software without restriction, including without limitation the rights 11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the Software is 13 | * furnished to do so, subject to the following conditions: 14 | * 15 | * The above copyright notice, development funding notice, and this permission 16 | * notice shall be included in all copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | * THE SOFTWARE. 25 | */ 26 | 27 | #ifndef Audio_h_ 28 | #define Audio_h_ 29 | 30 | #if TEENSYDUINO < 120 31 | #error "Teensyduino version 1.20 or later is required to compile the Audio library." 32 | #endif 33 | #ifdef __AVR__ 34 | #error "The Audio Library only works with Teensy 3.X. Teensy 2.0 is unsupported." 35 | #endif 36 | 37 | #include "DMAChannel.h" 38 | #if !defined(DMACHANNEL_HAS_BEGIN) || !defined(DMACHANNEL_HAS_BOOLEAN_CTOR) 39 | #error "You need to update DMAChannel.h & DMAChannel.cpp" 40 | #error "https://github.com/PaulStoffregen/cores/blob/master/teensy3/DMAChannel.h" 41 | #error "https://github.com/PaulStoffregen/cores/blob/master/teensy3/DMAChannel.cpp" 42 | #endif 43 | 44 | // When changing multiple audio object settings that must update at 45 | // the same time, these functions allow the audio library interrupt 46 | // to be disabled. For example, you may wish to begin playing a note 47 | // in response to reading an analog sensor. If you have "velocity" 48 | // information, you might start the sample playing and also adjust 49 | // the gain of a mixer channel. Use AudioNoInterrupts() first, then 50 | // make both changes to the 2 separate objects. Then allow the audio 51 | // library to update with AudioInterrupts(). Both changes will happen 52 | // at the same time, because AudioNoInterrupts() prevents any updates 53 | // while you make changes. 54 | // 55 | #define AudioNoInterrupts() (NVIC_DISABLE_IRQ(IRQ_SOFTWARE)) 56 | #define AudioInterrupts() (NVIC_ENABLE_IRQ(IRQ_SOFTWARE)) 57 | 58 | // include all the library headers, so a sketch can use a single 59 | // #include to get the whole library 60 | // 61 | #include "analyze_fft256.h" 62 | #include "analyze_fft1024.h" 63 | #include "analyze_print.h" 64 | #include "analyze_tonedetect.h" 65 | #include "analyze_notefreq.h" 66 | #include "analyze_peak.h" 67 | #include "analyze_rms.h" 68 | #include "async_input_spdif3.h" 69 | #include "control_sgtl5000.h" 70 | #include "control_wm8731.h" 71 | #include "control_ak4558.h" 72 | #include "control_cs4272.h" 73 | #include "control_cs42448.h" 74 | #include "control_tlv320aic3206.h" 75 | #include "effect_bitcrusher.h" 76 | #include "effect_chorus.h" 77 | #include "effect_fade.h" 78 | #include "effect_flange.h" 79 | #include "effect_envelope.h" 80 | #include "effect_multiply.h" 81 | #include "effect_delay.h" 82 | #include "effect_delay_ext.h" 83 | #include "effect_midside.h" 84 | #include "effect_reverb.h" 85 | #include "effect_freeverb.h" 86 | #include "effect_waveshaper.h" 87 | #include "effect_granular.h" 88 | #include "effect_combine.h" 89 | #include "effect_rectifier.h" 90 | #include "effect_wavefolder.h" 91 | #include "filter_biquad.h" 92 | #include "filter_fir.h" 93 | #include "filter_variable.h" 94 | #include "filter_ladder.h" 95 | #include "input_adc.h" 96 | #include "input_adcs.h" 97 | #include "input_i2s.h" 98 | #include "input_i2s2.h" 99 | #include "input_i2s_quad.h" 100 | #include "input_i2s_hex.h" 101 | #include "input_i2s_oct.h" 102 | #include "input_tdm.h" 103 | #include "input_tdm2.h" 104 | #include "input_pdm.h" 105 | #include "input_pdm_i2s2.h" 106 | #include "input_spdif3.h" 107 | #include "mixer.h" 108 | #include "output_dac.h" 109 | #include "output_dacs.h" 110 | #include "output_i2s.h" 111 | #include "output_i2s2.h" 112 | #include "output_i2s_quad.h" 113 | #include "output_i2s_hex.h" 114 | #include "output_i2s_oct.h" 115 | #include "output_mqs.h" 116 | #include "output_pwm.h" 117 | #include "output_spdif.h" 118 | #include "output_spdif2.h" 119 | #include "output_spdif3.h" 120 | #include "output_pt8211.h" 121 | #include "output_pt8211_2.h" 122 | #include "output_tdm.h" 123 | #include "output_tdm2.h" 124 | #include "output_adat.h" 125 | #include "play_memory.h" 126 | #include "play_queue.h" 127 | #include "play_sd_raw.h" 128 | #include "play_sd_wav.h" 129 | #include "play_serialflash_raw.h" 130 | #include "record_queue.h" 131 | #include "synth_tonesweep.h" 132 | #include "synth_sine.h" 133 | #include "synth_waveform.h" 134 | #include "synth_dc.h" 135 | #include "synth_whitenoise.h" 136 | #include "synth_pinknoise.h" 137 | #include "synth_karplusstrong.h" 138 | #include "synth_simple_drum.h" 139 | #include "synth_pwm.h" 140 | #include "synth_wavetable.h" 141 | 142 | #endif 143 | -------------------------------------------------------------------------------- /SDR_RA8875/Aux_Lib_Files/Audio/control_wm8960.cpp: -------------------------------------------------------------------------------- 1 | /* Teensy support for wm8960 audio codec 2 | * Copyright (c) 2021, Steve Haynal, steve@softerhardware.com 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice, development funding notice, and this permission 12 | * notice shall be included in all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | #include 24 | #include "control_wm8960.h" 25 | #include 26 | 27 | // See https://blog.titanwolf.in/a?ID=00500-80a77412-7973-49b3-b2e9-bc1beb847257 28 | 29 | 30 | #define WM8960_I2C_ADDR 0x1A 31 | 32 | // mask set bits are the bits in val which should be written 33 | bool AudioControlWM8960::write(uint16_t reg, uint16_t val, uint16_t mask, bool force=false) 34 | { 35 | 36 | uint16_t newval; 37 | 38 | newval = (regmap[reg] & ~mask) | (val & mask); 39 | 40 | if ((newval != regmap[reg]) || force) { 41 | regmap[reg] = newval; 42 | 43 | Wire1.beginTransmission(WM8960_I2C_ADDR); 44 | 45 | Wire1.write((reg << 1) | ((newval >> 8) & 1)); 46 | Wire1.write(newval & 0xFF); 47 | 48 | if (Wire1.endTransmission() == 0) return true; 49 | return false; 50 | } 51 | return true; 52 | } 53 | 54 | bool AudioControlWM8960::disable(void) 55 | { 56 | // Reset 57 | return write(0x0f, 0, 0b01, true); 58 | } 59 | 60 | 61 | bool AudioControlWM8960::enable(void) 62 | { 63 | //Wire.begin(); 64 | delay(750); 65 | // Reset 66 | if (!write(0x0f, 0, 0b01, true)) { 67 | Serial.println("WM8960 Reset Failed"); 68 | //return false; // no WM8960 chip responding 69 | } 70 | else 71 | Serial.println("WM8960 Reset Completed"); 72 | 73 | delay(5); 74 | 75 | // Enable VMID and VREF 76 | write(0x19, 0b111000000, 0b111000000); 77 | 78 | // Enable DAC, Headphones and Speakers 79 | write(0x1a, 0b111111000, 0b111111000); 80 | 81 | // Enable mixer 82 | write(0x2f, 0b000001100, 0b000001100); 83 | 84 | //#define USE_MCLK 85 | //#define PLL_CLOCKING 86 | #define PLL_CLOCKING1 87 | // Setup clocking 88 | 89 | #ifdef PLL_CLOCKING1 90 | //#elif defined PLL_CLOCKING1 91 | int32_t freq = 48000; 92 | write(0x04, 0b000000001, 0b111111111); 93 | write(0x1a, 0b000000001, 0b000000001); // Power up PLL 94 | // PLL between 27*24 = 648MHz und 54*24=1296MHz 95 | int n1 = 4; //SAI prescaler 4 => (n1*n2) = multiple of 4 96 | int n2 = 1 + (24000000 * 27) / (freq * 256 * n1); 97 | double C = ((double)freq * 256 * n1 * n2) / 24000000; 98 | int c0 = C; 99 | int c2 = 10000; 100 | int c1 = C * c2 - (c0 * c2); 101 | set_audioClock(c0, c1, c2, true); 102 | CCM_CS1CDR = (CCM_CS1CDR & ~(CCM_CS1CDR_SAI1_CLK_PRED_MASK | CCM_CS1CDR_SAI1_CLK_PODF_MASK)) 103 | | CCM_CS1CDR_SAI1_CLK_PRED(n1-1) // &0x07 104 | | CCM_CS1CDR_SAI1_CLK_PODF(n2-1); // &0x3f 105 | Serial.printf("SetI2SFreq(%d)\n",freq); 106 | #endif 107 | 108 | #ifdef PLL_CLOCKING 109 | // Configure PLL clock 110 | // MCLK->PLL->SYSCLK->DAC/ADC sample Freq = 24MHz/544.217 = 44.100kHz 111 | // See calculation pages 60 and table 44 in manual 112 | // f2 = 4 x 2 x 11.2896Hz = 90.3168MHz 113 | // R = 90.316 / 12 = 7.5264 114 | // PLLN = int R = 7 115 | // k = int ( 2^24 x (7.5264 – 7)) = 8831526 116 | // N = 7 117 | // Fractional 24bit value = 86C226h 118 | 119 | // FOR 48KHz: 120 | // MCLK->PLL->SYSCLK->DAC/ADC sample Freq = 24MHz/500 = 48.0kHz 121 | // See calculation pages 60 and table 44 in manual 122 | // f2 = 4 x 2 x 12.288MHz = 98.304MHz 123 | // R = 98.304 / 12 = 8.192 124 | // PLLN = int R = 8 125 | // k = int ( 2^24 x (8.192 – 8)) = 126 | // N = 8 127 | // Fractional 24bit value = 3126E8h 128 | int delay1 = 1000; 129 | int delay2 = 500; 130 | uint8_t res; 131 | 132 | write(0x1a, 0b000000001, 0b000000001); // Power up PLL 133 | delayMicroseconds(delay2); 134 | 135 | res = write(0x04, 0x0001, 0b111111111); // Select PLL 136 | if (res == 0) Serial.println("WM8960 Configure clock"); 137 | else 138 | { 139 | Serial.println("WM8960 Configure clock failed"); 140 | return res; 141 | } 142 | delayMicroseconds(delay1); 143 | 144 | // Power on PLL 145 | res = write(0x34, 0x0028, 0b111111111); // Select PLL 1 146 | 147 | // Configure PLL 1 0011 0111 = 37h 148 | // 00010 0111 27h 149 | res = write(0x34, 0x0028, 0b000101111); // Select PLL 1 150 | delayMicroseconds(delay1); 151 | 152 | // Configure PLL 2 bit 8 reserved 7-0 data 153 | //res = write(0x35, 0x0086, 0b010000110); // Select PLL 2 154 | res = write(0x35, 0x0031, 0b000111111); // Select PLL 2 155 | delayMicroseconds(delay1); 156 | 157 | // Configure PLL 3 158 | //res = write(0x36, 0x00C2, 0b011000010); // Select PLL 3 159 | res = write(0x36, 0x0026, 0b111111111); // Select PLL 3 160 | delayMicroseconds(delay1); 161 | 162 | // Configure PLL 4 163 | //res = write(0x37, 0x0026, 0b000100110); // Select PLL 4 164 | res = write(0x37, 0x00E8, 0b111111111); // Select PLL 4 165 | delayMicroseconds(delay1); 166 | #endif 167 | 168 | #ifdef USE_MCLK 169 | write(0x04, 0b000000000, 0b111111111); 170 | write(0x1a, 0b000000000, 0b000000001); 171 | #endif 172 | 173 | // Unmute DAC 174 | write(0x05, 0b000000000, 0b000001000); 175 | 176 | // 16-bit data and i2s interface 177 | write(0x07, 0b000000010, 0b000001111); // I2S, 16 bit, MCLK slave 178 | 179 | // Mute headphone and speakers, but enable zero crossing changes only 180 | write(0x02, 0b010000000, 0b011111111); 181 | write(0x03, 0b110000000, 0b111111111); 182 | // Speakers 183 | write(0x28, 0b010000000, 0b011111111); 184 | write(0x29, 0b110000000, 0b111111111); 185 | 186 | // Set DAC Volume to max 0dB, full range of DAC 187 | write(0x0a, 0b011111111, 0b011111111); 188 | write(0x0b, 0b111111111, 0b111111111); 189 | 190 | // Connect Left DAC to left output mixer 191 | write(0x22, 0b100000000, 0b100000000); 192 | 193 | // Connect Right DAC to right output mixer 194 | write(0x25, 0b100000000, 0b100000000); 195 | 196 | 197 | // Enable headphone detect to disable speaker 198 | // Enable HPSWEN and set HPSWPOL 199 | write(0x18, 0b001000000, 0b001100000); 200 | // Use JD2 as jack detect input 201 | write(0x30, 0b000001000, 0b000001100); 202 | // Enable slow clock for jack detect 203 | write(0x17, 0b000000001, 0b000000011); 204 | 205 | 206 | // Enable speaker outputs 207 | write(0x31, 0b001000000, 0b011000000); 208 | // Speaker amp DC boost 209 | write(0x33, 0b000000000, 0b000111000); 210 | // Speaker amp AC boost 211 | write(0x33, 0b000000000, 0b000000111); 212 | 213 | //// Configure input 214 | //// Enable AINL/AINR, and ADCL/ADCR 215 | write(0x19, 0b000111100, 0b000111100); 216 | 217 | // Unmute and set zero crossing input level change 218 | write(0x00, 0b101000000, 0b111000000); 219 | write(0x01, 0b101000000, 0b111000000); 220 | 221 | delay(100); // how long to power up? 222 | 223 | return true; 224 | } 225 | 226 | bool AudioControlWM8960::volume(float n) { 227 | headphoneVolume(n,n); 228 | return speakerVolume(n,n); 229 | } 230 | 231 | bool AudioControlWM8960::volume(float l, float r) { 232 | headphoneVolume(l,r); 233 | return speakerVolume(l,r); 234 | } 235 | 236 | bool AudioControlWM8960::headphoneVolume(float l, float r) // 0 to 1.0 to produce 47 to 127 237 | { 238 | uint16_t i; 239 | i = 47 + (uint16_t) (80.0*l+0.5); 240 | // Left headphone 241 | write(0x02, (i & 0b01111111), 0b001111111, true); 242 | 243 | i = 47 + (uint16_t) (80.0*r+0.5); 244 | // Right headphone 245 | return write(0x03, 0b100000000 | (i & 0b01111111), 0b101111111, true); 246 | } 247 | 248 | bool AudioControlWM8960::headphonePower(uint8_t p) 249 | { 250 | uint16_t mask; 251 | uint16_t value; 252 | 253 | value = (p & 0b11) << 5; 254 | mask = 0b011 << 5; 255 | 256 | // LOUT1 Enable 257 | return write(0x1a, value, mask); 258 | } 259 | 260 | bool AudioControlWM8960::speakerVolume(float l, float r) // 0 to 1.0 to produce 47 to 127 261 | { 262 | uint16_t i; 263 | i = 47 + (uint16_t) (80.0*l+0.5); 264 | // Left speaker 265 | write(0x28, (i & 0b01111111), 0b001111111, true); 266 | 267 | i = 47 + (uint16_t) (80.0*r+0.5); 268 | // Right speaker 269 | return write(0x29, 0b100000000 | (i & 0b01111111), 0b101111111, true); 270 | } 271 | 272 | bool AudioControlWM8960::speakerPower(uint8_t p) 273 | { 274 | uint16_t mask; 275 | uint16_t value; 276 | 277 | value = (p & 0b11) << 3; 278 | mask = 0b011 << 3; 279 | 280 | // SPK_PN Output Enable 281 | write(0x1a, value, mask); 282 | 283 | // SPK_OP_EN 284 | // Bits are swapped 285 | value = (p & 0b01) ? 0b010000000 : 0b0; 286 | value = (p & 0b10) ? (value | 0b001000000) : value; 287 | mask = 0b011 << 6; 288 | return write(0x31, value, mask); 289 | } 290 | 291 | // Write 1 to disable, 0 to enable, default is enabled 292 | bool AudioControlWM8960::disableADCHPF(uint8_t v) 293 | { 294 | return write(0x05, v, 0b01); 295 | } 296 | 297 | // Write 1 to enable 298 | bool AudioControlWM8960::enableMicBias(uint8_t v) 299 | { 300 | return write(0x19,v << 1,0b000000010); 301 | } 302 | 303 | // Write 1 to enable 304 | bool AudioControlWM8960::enableALC(uint16_t v) 305 | { 306 | // FIXME set LINVOL and RINVOL to same value if both are enabled 307 | return write(0x11, v << 7, 0b110000000); 308 | } 309 | 310 | bool AudioControlWM8960::micPower(uint8_t p) 311 | { 312 | uint16_t mask; 313 | uint16_t value; 314 | 315 | 316 | // Select microphone inputs with +29dB boost 317 | if (p & 0b010) { 318 | // enable left 319 | write(0x20,0b100111000,0b111111000); 320 | } else { 321 | // disable left 322 | write(0x20,0b000000000,0b111111000); 323 | } 324 | 325 | if (p & 0b001) { 326 | // enable right (MEMS) 327 | write(0x21,0b100111000,0b111111000); 328 | } else { 329 | // disable right 330 | write(0x21,0b000000000,0b111111000); 331 | } 332 | 333 | // enable microphone inputs 334 | value = p << 4; 335 | mask = 0b011 << 4; 336 | 337 | return write(0x2f, value, mask); 338 | } 339 | 340 | bool AudioControlWM8960::lineinPower(uint8_t p) 341 | { 342 | uint16_t mask; 343 | uint16_t value; 344 | 345 | 346 | // Select line2 347 | if (p & 0b010) { 348 | // enable left 349 | write(0x20,0b001000000,0b111111000); 350 | } else { 351 | // disable left 352 | write(0x20,0b000000000,0b111111000); 353 | } 354 | 355 | if (p & 0b001) { 356 | // enable right 357 | write(0x21,0b001000000,0b111111000); 358 | } else { 359 | // disable left 360 | write(0x21,0b000000000,0b111111000); 361 | } 362 | 363 | // disable microphone inputs 364 | value = p << 4; 365 | mask = 0b011 << 4; 366 | return write(0x2f, value, mask); 367 | } 368 | 369 | bool AudioControlWM8960::inputLevel(float n) 370 | { 371 | return inputLevel(n,n); 372 | 373 | } 374 | 375 | bool AudioControlWM8960::inputLevel(float l, float r) 376 | { 377 | uint16_t i; 378 | i = (uint16_t) (63.0*l+0.5); 379 | // Left input 380 | write(0x0, i, 0b000111111, true); 381 | 382 | i = (uint16_t) (63.0*r+0.5); 383 | // Right input (MEMS) 384 | return write(0x1, 0b100000000 | i, 0b100111111, true); 385 | } 386 | 387 | bool AudioControlWM8960::inputSelect(int n) 388 | { 389 | if (n) { 390 | return lineinPower(0b011); 391 | } else { 392 | return micPower(0b011); 393 | } 394 | } 395 | 396 | void AudioControlWM8960::dacVolumeRampDisable(void) 397 | { 398 | write(0x06, 0b000000000, 0b000001000); 399 | } 400 | 401 | void AudioControlWM8960::dacVolumeRamp(void) 402 | { 403 | write(0x06, 0b000001100, 0b000001100); 404 | } 405 | 406 | void AudioControlWM8960::dacVolumeRampLinear(void) 407 | { 408 | write(0x06, 0b000001000, 0b000001100); 409 | } 410 | 411 | void AudioControlWM8960::dacVolume(float vol) 412 | { 413 | volume(vol, vol); 414 | } 415 | 416 | void AudioControlWM8960::muteHeadphone(void) 417 | { 418 | volume(0.0f, 0.0f); 419 | } 420 | 421 | void AudioControlWM8960::unmuteHeadphone(void) 422 | { 423 | volume(1.0f, 1.0f); 424 | } 425 | 426 | void AudioControlWM8960::lineInLevel(float x) 427 | { 428 | inputLevel(x); 429 | } 430 | 431 | void AudioControlWM8960::unmuteLineout(void) 432 | { 433 | volume(1.0f, 1.0f); 434 | } 435 | 436 | void AudioControlWM8960::muteLineout(void) 437 | { 438 | volume(0.0f, 0.0f); 439 | } 440 | 441 | void AudioControlWM8960::adcHighPassFilterEnable(void) 442 | { 443 | disableADCHPF(0); 444 | //write(0x05, 0b000000000, 0b000000001); 445 | } 446 | 447 | void AudioControlWM8960::adcHighPassFilterDisable(void) 448 | { 449 | disableADCHPF(1); 450 | //write(0x05, 0b000000001, 0b000000001); 451 | } 452 | 453 | void AudioControlWM8960::audioProcessorDisable(void) 454 | { 455 | write(0x05, 0b000000000, 0b000000110); // De-emphasis control 2:1 = 1 = 48Khz sample rate 456 | write(0x11, 0b000000000, 0b110000000); // ALC = OFF 457 | } 458 | 459 | void AudioControlWM8960::audioPreProcessorEnable(void) // AVC on Line-In level 460 | { 461 | write(0x05, 0b000000110, 0b000000110); // De-emphasis control 2:1 = 1 = 48Khz sample rate 462 | write(0x11, 0b110000000, 0b110000000); // ALC = Stereo mode 463 | } 464 | 465 | void AudioControlWM8960::audioPostProcessorEnable(void) 466 | { 467 | write(0x05, 0b000000110, 0b000000110); // De-emphasis control 2:1 = 1 = 48Khz sample rate 468 | } -------------------------------------------------------------------------------- /SDR_RA8875/Aux_Lib_Files/Audio/control_wm8960.h: -------------------------------------------------------------------------------- 1 | /* Teensy support for wm8960 audio codec 2 | * Copyright (c) 2021, Steve Haynal, steve@softerhardware.com 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice, development funding notice, and this permission 12 | * notice shall be included in all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | #ifndef control_wm8960_h_ 24 | #define control_wm8960_h_ 25 | 26 | #include "AudioControl.h" 27 | #include "Wire.h" 28 | 29 | class AudioControlWM8960 : public AudioControl 30 | { 31 | public: 32 | AudioControlWM8960(void) { Wire1.begin(); delay(5); } 33 | // Reset and configure ww8960 34 | bool enable(void); 35 | // Reset, most settings are in a powered off state when reset 36 | bool disable(void); 37 | 38 | // Input level, either stereo or combined 39 | bool inputLevel(float n); 40 | bool inputLevel(float l, float r); 41 | 42 | // Select input, 0 is microphones, 1 is linein 43 | bool inputSelect(int n); 44 | 45 | // Master volume for both headphones and speaker, either stereo or combined 46 | bool volume(float n); 47 | bool volume(float l, float r); 48 | 49 | // Stereo volume for headphones only 50 | bool headphoneVolume(float l, float r); 51 | // Two bits, set L and R to 1 in 0b0LR to turn on channels 52 | bool headphonePower(uint8_t p); 53 | 54 | // Stereo volume for headphones only 55 | bool speakerVolume(float l, float r); 56 | // Two bits, set L and R to 1 in 0b0LR to turn on channels 57 | bool speakerPower(uint8_t p); 58 | 59 | // Write 1 to disable, 0 to enable, default is enabled 60 | bool disableADCHPF(uint8_t v); 61 | 62 | // Write 1 to enable, 0 to disable, default is disabled 63 | bool enableMicBias(uint8_t v); 64 | 65 | // Two bits, set L and R to 1 in 0b0LR to turn on channels 66 | bool enableALC(uint16_t v); 67 | 68 | // Two bits, set L and R to 1 in 0b0LR to turn on channels 69 | bool micPower(uint8_t p); 70 | 71 | // Two bits, set L and R to 1 in 0b0LR to turn on channels 72 | bool lineinPower(uint8_t p); 73 | 74 | // Write directly to wm8960 75 | bool write(uint16_t reg, uint16_t val, uint16_t mask, bool force); 76 | 77 | // return to default fast ramp, max delay 10.7ms 78 | void dacVolumeRampDisable(void); 79 | 80 | // set slow ramp, max delay 171ms 81 | void dacVolumeRamp(void); 82 | 83 | // same as RampDisable, set to default fast ramp 84 | void dacVolumeRampLinear(void); 85 | 86 | void dacVolume(float vol); 87 | 88 | void muteHeadphone(void); 89 | void unmuteHeadphone(void); 90 | 91 | void audioProcessorDisable(void); // Default 92 | void audioPreProcessorEnable(void); // AVC on Line-In level 93 | void audioPostProcessorEnable(void); 94 | 95 | void lineInLevel(float x); 96 | 97 | void unmuteLineout(void); 98 | 99 | void muteLineout(void); 100 | 101 | void adcHighPassFilterEnable(void); 102 | void adcHighPassFilterDisable(void); 103 | 104 | 105 | protected: 106 | 107 | // wm8960 state is write only, this keeps track of state and is initialized with defaults 108 | uint16_t regmap[56] = { 109 | 0x097, 0x097, 0x000, 0x000, 0x000, 0x008, 0x000, 0x00a, // Registers 0x00-0x07 110 | 0x1c0, 0x000, 0x0ff, 0x0ff, 0x000, 0x000, 0x000, 0x000, // Registers 0x08-0x0f 111 | 0x000, 0x00b, 0x100, 0x032, 0x000, 0x0c3, 0x0c3, 0x1c0, // Registers 0x10-0x17 112 | 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, // Registers 0x18-0x1f 113 | 0x100, 0x100, 0x050, 0x050, 0x050, 0x050, 0x000, 0x000, // Registers 0x20-0x27 114 | 0x100, 0x100, 0x040, 0x000, 0x000, 0x050, 0x050, 0x000, // Registers 0x28-0x2f 115 | 0x002, 0x037, 0x04d, 0x080, 0x008, 0x031, 0x026, 0x0e9 // Registers 0x30-0x37 116 | }; 117 | 118 | }; 119 | 120 | #endif 121 | -------------------------------------------------------------------------------- /SDR_RA8875/Aux_Lib_Files/Audio/readme.txt: -------------------------------------------------------------------------------- 1 | As of May 31, 2022 2 | ____________________________ 3 | 4 | Place these 3 files in the TeensyDuino Audio Library folder: 5 | 6 | C:\Program Files (x86)\Arduino\hardware\teensy\avr\libraries\Audio 7 | 8 | control_wm8960.h // established the class for the WM8960 chip. 9 | 10 | control_wm8960.cpp // Extended version of softerhardware CWkeyer project. 11 | // Added identical function names to match the SGTL5000 12 | // In some cases just calling existing WM8960 functions 13 | // In other cases created new function and took a quick swag at an equivalent chip register write. 14 | // It is not a perfect remapping but close enough to start with, some further fine tuning would be good. 15 | // Not all SGTL5000 functions are reproduced such as ALC, just the ones I am using in the SDR project today. 16 | 17 | ** Note ** : This WM8960 file is using the alternate i2c bus on the Teensy 4.0/4.1 on pins 17 and 18 (SDA1/SCL1). 18 | This is simply referenced in the code at Wire1 instead of Wire. 19 | This was necessary due to unfavorable interaction noted between the RA8876 touch controller and the WM8960 when on the same Wire bus. 20 | 21 | 22 | Audio.h // Added the new control_wm8960.h file to the inventory 23 | 24 | The module used for testing was the Waveshare WM8960 Audio module, not the Raspberry Pi Hat version. 25 | It is a smaller module with speaker connector and mic/headphone jacks on one end, and the CPU interface connectors on the other end. 26 | Wire/trace length is important, must be kept short! I used < 1.5" wires right off the Teensy CPU pins as I used extended length (double sided) header pins. 27 | The headphone jack is a 4ckt jack with mic mono input and stereo output. It can be grounded so can connect to an audio amp safely. 28 | The speakers are driven by an internal audio amp up to 1W depending on the voltage. This module uses 3.3V so the output is not loud. 5V would be better. 29 | Ideally this module should be powered off a separate 3.3V supply as the audio amp will max out the Teensy 250ma 3.3V supply. The headphones do not seem to be a problem. 30 | The chip has 4 pairs of inputs but this module uses: 31 | LInput L3 for the Jack Detect to switch speakers and headphones (JD2) 32 | Input R1 for mic jack audio 33 | Input L1 for the onboard MEMEs mic 34 | By default the MEMS mic and mic jack are both enabled, this will probably be changes to switch over in due time. 35 | 36 | This module has no connections for the Line2 L & R inputs. These are the ones needed for the I and Q from the RX/TX board. 37 | Some very fine soldering is required to bring out wires from the tiny chip pins for these 2 inputs. I have not done that yet and probably won't. 38 | This audio module was used mostly to explore what it performs like compared to the SGTL5000, how the amp works, and to create the library code. 39 | I expect to create a version the Teensy SDR PCBs we have made with the WM8960 or other Cirrus Logic chips soldered to the board in place of the 40 | SGTL5000 plug-in module used today. -------------------------------------------------------------------------------- /SDR_RA8875/Aux_Lib_Files/OpenAudio_Library/AudioStream_F32.h: -------------------------------------------------------------------------------- 1 | /* 2 | * AudioStream_F32 3 | * 4 | * Created: Chip Audette, November 2016 5 | * Purpose; Extend the Teensy Audio Library's "AudioStream" to permit floating-point audio data. 6 | * 7 | * I modeled it directly on the Teensy code in "AudioStream.h" and "AudioStream.cpp", which are 8 | * available here: https://github.com/PaulStoffregen/cores/tree/master/teensy3 9 | * 10 | * Added id to audio_block_f32_t class, per Tympan. Bob Larkin June 2020 11 | * 12 | * MIT License. use at your own risk. 13 | */ 14 | 15 | #ifndef _AudioStream_F32_h 16 | #define _AudioStream_F32_h 17 | 18 | #include //ARM DSP extensions. for speed! 19 | #include //Teensy Audio Library 20 | #include "AudioSettings_F32.h" 21 | 22 | #define USB_AUDIO_48KHZ 1 23 | 24 | #ifndef AUDIO_BLOCK_SAMPLES 25 | #ifdef USB_AUDIO_48KHZ 26 | #define AUDIO_BLOCK_SAMPLES 128 // 32 27 | #else 28 | #define AUDIO_BLOCK_SAMPLES 128 29 | #endif 30 | #endif 31 | 32 | #ifndef AUDIO_SAMPLE_RATE_EXACT 33 | #ifdef USB_AUDIO_48KHZ 34 | #define AUDIO_SAMPLE_RATE_EXACT 48000.0f 35 | #else 36 | #define AUDIO_SAMPLE_RATE_EXACT 44100.0f 37 | #endif 38 | #endif 39 | 40 | #define AUDIO_SAMPLE_RATE AUDIO_SAMPLE_RATE_EXACT 41 | 42 | // /////////////// class prototypes 43 | class AudioStream_F32; 44 | class AudioConnection_F32; 45 | 46 | 47 | // ///////////// class definitions 48 | 49 | //create a new structure to hold audio as floating point values. 50 | //modeled on the existing teensy audio block struct, which uses Int16 51 | //https://github.com/PaulStoffregen/cores/blob/268848cdb0121f26b7ef6b82b4fb54abbe465427/teensy3/AudioStream.h 52 | // Added id, per Tympan. Should not disturb existing programs. Bob Larkin June 2020 53 | class audio_block_f32_t { 54 | public: 55 | audio_block_f32_t(void) {}; 56 | audio_block_f32_t(const AudioSettings_F32 &settings) { 57 | fs_Hz = settings.sample_rate_Hz; 58 | length = settings.audio_block_samples; 59 | }; 60 | 61 | unsigned char ref_count; 62 | unsigned char memory_pool_index; 63 | unsigned char reserved1; 64 | unsigned char reserved2; 65 | float32_t data[AUDIO_BLOCK_SAMPLES]; // AUDIO_BLOCK_SAMPLES is 128, from AudioStream.h 66 | const int full_length = AUDIO_BLOCK_SAMPLES; 67 | int length = AUDIO_BLOCK_SAMPLES; // AUDIO_BLOCK_SAMPLES is 128, from AudioStream.h 68 | float fs_Hz = AUDIO_SAMPLE_RATE; // AUDIO_SAMPLE_RATE is 44117.64706 from AudioStream.h 69 | unsigned long id; 70 | }; 71 | 72 | class AudioConnection_F32 73 | { 74 | public: 75 | AudioConnection_F32(AudioStream_F32 &source, AudioStream_F32 &destination) : 76 | src(source), dst(destination), src_index(0), dest_index(0), 77 | next_dest(NULL) 78 | { connect(); } 79 | AudioConnection_F32(AudioStream_F32 &source, unsigned char sourceOutput, 80 | AudioStream_F32 &destination, unsigned char destinationInput) : 81 | src(source), dst(destination), 82 | src_index(sourceOutput), dest_index(destinationInput), 83 | next_dest(NULL) 84 | { connect(); } 85 | friend class AudioStream_F32; 86 | protected: 87 | void connect(void); 88 | AudioStream_F32 &src; 89 | AudioStream_F32 &dst; 90 | unsigned char src_index; 91 | unsigned char dest_index; 92 | AudioConnection_F32 *next_dest; 93 | }; 94 | 95 | 96 | class AudioStream_F32 : public AudioStream { 97 | public: 98 | AudioStream_F32(unsigned char n_input_f32, audio_block_f32_t **iqueue) : AudioStream(1, inputQueueArray_i16), 99 | num_inputs_f32(n_input_f32), inputQueue_f32(iqueue) { 100 | //active_f32 = false; 101 | destination_list_f32 = NULL; 102 | for (int i=0; i < n_input_f32; i++) { 103 | inputQueue_f32[i] = NULL; 104 | } 105 | }; 106 | static void initialize_f32_memory(audio_block_f32_t *data, unsigned int num); 107 | static void initialize_f32_memory(audio_block_f32_t *data, unsigned int num, const AudioSettings_F32 &settings); 108 | //virtual void update(audio_block_f32_t *) = 0; 109 | static uint8_t f32_memory_used; 110 | static uint8_t f32_memory_used_max; 111 | static audio_block_f32_t * allocate_f32(void); 112 | static void release(audio_block_f32_t * block); 113 | 114 | protected: 115 | //bool active_f32; 116 | unsigned char num_inputs_f32; 117 | void transmit(audio_block_f32_t *block, unsigned char index = 0); 118 | audio_block_f32_t * receiveReadOnly_f32(unsigned int index = 0); 119 | audio_block_f32_t * receiveWritable_f32(unsigned int index = 0); 120 | friend class AudioConnection_F32; 121 | 122 | private: 123 | AudioConnection_F32 *destination_list_f32; 124 | audio_block_f32_t **inputQueue_f32; 125 | virtual void update(void) = 0; 126 | audio_block_t *inputQueueArray_i16[1]; //two for stereo 127 | static audio_block_f32_t *f32_memory_pool; 128 | static uint32_t f32_memory_pool_available_mask[6]; 129 | }; 130 | 131 | /* 132 | #define AudioMemory_F32(num) ({ \ 133 | static audio_block_f32_t data_f32[num]; \ 134 | AudioStream_F32::initialize_f32_memory(data_f32, num); \ 135 | }) 136 | */ 137 | 138 | void AudioMemory_F32(const int num); 139 | void AudioMemory_F32(const int num, const AudioSettings_F32 &settings); 140 | #define AudioMemory_F32_wSettings(num,settings) (AudioMemory_F32(num,settings)) //for historical compatibility 141 | 142 | 143 | #define AudioMemoryUsage_F32() (AudioStream_F32::f32_memory_used) 144 | #define AudioMemoryUsageMax_F32() (AudioStream_F32::f32_memory_used_max) 145 | #define AudioMemoryUsageMaxReset_F32() (AudioStream_F32::f32_memory_used_max = AudioStream_F32::f32_memory_used) 146 | 147 | 148 | #endif 149 | -------------------------------------------------------------------------------- /SDR_RA8875/Aux_Lib_Files/OpenAudio_Library/Readme.txt: -------------------------------------------------------------------------------- 1 | The files in this folder are modified slightly to support the experimental WM8960 codec 2 | and 48KHz (though this should be picked up through the I16 AudioStream.h file) 3 | 4 | Copy these files into your OpenAudio_Libary folder, usually found here: 5 | 6 | C:\Users\\Documents\Arduino\libraries\OpenAudio_ArduinoLibrary -------------------------------------------------------------------------------- /SDR_RA8875/Aux_Lib_Files/RS-HFIQ Omni-RIg/RS-HFIQ-1.ini: -------------------------------------------------------------------------------- 1 | ;------------------------------------------------------------------------------- 2 | ; TeensySDR Interface for RS-HFIQ SDR Transceiver 3 | ; 4 | ; File created by Jim Veatch WA2EUJ 5 | ; Modified by K7MDL to extend data set in useful ways for use with the SDR_RA8875 Teensy 4 SDR program CAT interface 6 | ;------------------------------------------------------------------------------- 7 | 8 | ;------------------------------------------------------------------------------- 9 | ; initialize 10 | ;------------------------------------------------------------------------------- 11 | [INIT1] 12 | ;*/r/n 13 | Command=2A.0D.0A 14 | ReplyEnd=0A 15 | 16 | [INIT2] 17 | ;*W/r 18 | Command=2A.57.0D 19 | ReplyEnd=0A 20 | 21 | [INIT3] 22 | ;*OF3/r 23 | Command=2A.4F.46.33.0D 24 | ReplyLength=0 25 | 26 | ;------------------------------------------------------------------------------- 27 | ; set frequency 28 | ;------------------------------------------------------------------------------- 29 | 30 | ;Modified to differentiate VFO A and B on the Teensy. 31 | ;RS-HFIQ only knows the *F12345678\r command 32 | ;VFOA 33 | [pmFreqA] 34 | ;*FA12345678\r 35 | Command=2A.46.41.00.00.00.00.00.00.00.00.0D 36 | Value=3|8|vfText|1|0 37 | ;no reply 38 | ReplyLength=0 39 | 40 | ;VFOB 41 | [pmFreqB] 42 | ;*FB12345678\r 43 | Command=2A.46.42.00.00.00.00.00.00.00.00.0D 44 | Value=3|8|vfText|1|0 45 | ;no reply 46 | ReplyLength=0 47 | 48 | ; Active VFO 49 | [pmFreq] 50 | ;*F12345678\r 51 | Command=2A.46.00.00.00.00.00.00.00.00.0D 52 | Value=2|8|vfText|1|0 53 | ;no reply 54 | ReplyLength=0 55 | 56 | [pmVfoSwap] 57 | ;*S0\r 58 | Command=2A.53.30.0D 59 | ReplyLength=0 60 | 61 | [pmRitOffset] 62 | ;not supported 63 | 64 | [pmSplitOn] 65 | ;*FR1 66 | Command=2A.46.52.31.0D 67 | ReplyLength=0 68 | 69 | [pmSplitOff] 70 | ;*FR0 71 | Command=2A.46.52.30.0D 72 | ReplyLength=0 73 | 74 | [pmRit0] 75 | ;not supported 76 | 77 | [pmPitch] 78 | ;not supported 79 | 80 | [pmTx] 81 | ;*X1\r 82 | Command=2A.58.31.0D 83 | ;no reply 84 | ReplyLength=0 85 | 86 | [pmRx] 87 | ;*X0\r 88 | Command=2A.58.30.0D 89 | ;no reply 90 | ReplyLength=0 91 | 92 | [STATUS1] 93 | ;*F?\r 94 | Command=2A.46.3F.0D 95 | ;reply is 8 char value, ends with \r 96 | ReplyEnd=0D 97 | Validate=00.00.00.00.00.00.00.00.0D 98 | Value1=0|8|vfText|1|0|pmFreq 99 | 100 | ;pmCW_U, pmCW_L, pmSSB_U, pmSSB_L, pmDIG_U, pmDIG_L, pmAM, pmFM 101 | ; pmRitOn, pmRitOff, 102 | ; pmXitOn, pmXitOff, 103 | ; pmFreq, pmFreqA, pmFreqB, pmPitch, pmRitOffset, pmRit0, 104 | ; pmVfoAA, pmVfoAB, pmVfoBA, pmVfoBB, pmVfoA, pmVfoB, pmVfoEqual, pmVfoSwap, -------------------------------------------------------------------------------- /SDR_RA8875/Aux_Lib_Files/RS-HFIQ Omni-RIg/RS-HFIQ-2.ini: -------------------------------------------------------------------------------- 1 | ;------------------------------------------------------------------------------- 2 | ; TeensySDR Interface for RS-HFIQ SDR Transceiver 3 | ; 4 | ; File created by Jim Veatch WA2EUJ 5 | ; Modified by K7MDL to extend data set in useful ways for use with the SDR_RA8875 Teensy 4 SDR program CAT interface 6 | ;------------------------------------------------------------------------------- 7 | 8 | ;------------------------------------------------------------------------------- 9 | ; initialize 10 | ;------------------------------------------------------------------------------- 11 | [INIT1] 12 | ;*/r/n 13 | Command=2A.0D.0A 14 | ReplyEnd=0A 15 | 16 | [INIT2] 17 | ;*W/r 18 | Command=2A.57.0D 19 | ReplyEnd=0A 20 | 21 | [INIT3] 22 | ;*OF3/r 23 | Command=2A.4F.46.33.0D 24 | ReplyLength=0 25 | 26 | ;------------------------------------------------------------------------------- 27 | ; set frequency 28 | ;------------------------------------------------------------------------------- 29 | 30 | ;Modified to differentiate VFO A and B on the Teensy. 31 | ;RS-HFIQ only knows the *F12345678\r command 32 | ;VFOA 33 | [pmFreqA] 34 | ;*FA12345678\r 35 | Command=2A.46.41.00.00.00.00.00.00.00.00.0D 36 | Value=3|8|vfText|1|0 37 | ;no reply 38 | ReplyLength=0 39 | 40 | ;VFOB 41 | [pmFreqB] 42 | ;*FB12345678\r 43 | Command=2A.46.42.00.00.00.00.00.00.00.00.0D 44 | Value=3|8|vfText|1|0 45 | ;no reply 46 | ReplyLength=0 47 | 48 | ; Active VFO 49 | [pmFreq] 50 | ;*F12345678\r 51 | Command=2A.46.00.00.00.00.00.00.00.00.0D 52 | Value=2|8|vfText|1|0 53 | ;no reply 54 | ReplyLength=0 55 | 56 | [pmVfoSwap] 57 | ;*S0\r 58 | Command=2A.53.30.0D 59 | ReplyLength=0 60 | 61 | [pmRitOffset] 62 | ;not supported 63 | 64 | [pmSplitOn] 65 | ;*FR1 66 | Command=2A.46.52.31.0D 67 | ReplyLength=0 68 | 69 | [pmSplitOff] 70 | ;*FR0 71 | Command=2A.46.52.30.0D 72 | ReplyLength=0 73 | 74 | [pmRit0] 75 | ;not supported 76 | 77 | [pmPitch] 78 | ;not supported 79 | 80 | [pmTx] 81 | ;*X1\r 82 | Command=2A.58.31.0D 83 | ;no reply 84 | ReplyLength=0 85 | 86 | [pmRx] 87 | ;*X0\r 88 | Command=2A.58.30.0D 89 | ;no reply 90 | ReplyLength=0 91 | 92 | [STATUS1] 93 | ;*F?\r 94 | Command=2A.46.3F.0D 95 | ;reply is 8 char value, ends with \r 96 | ReplyEnd=0D 97 | Validate=00.00.00.00.00.00.00.00.0D 98 | Value1=0|8|vfText|1|0|pmFreq 99 | 100 | [STATUS2] 101 | ;*FA?\r 102 | Command=2A.46.41.3F.0D 103 | ;reply is 8 char value, ends with \r 104 | ReplyEnd=0D 105 | Validate=00.00.00.00.00.00.00.00.0D 106 | Value1=0|8|vfText|1|0|pmFreqA 107 | 108 | [STATUS3] 109 | ;*FB?\r 110 | Command=2A.46.42.3F.0D 111 | ;reply is 8 char value, ends with \r 112 | ReplyEnd=0D 113 | Validate=00.00.00.00.00.00.00.00.0D 114 | Value1=0|8|vfText|1|0|pmFreqB 115 | 116 | 117 | ;pmCW_U, pmCW_L, pmSSB_U, pmSSB_L, pmDIG_U, pmDIG_L, pmAM, pmFM 118 | ; pmRitOn, pmRitOff, 119 | ; pmXitOn, pmXitOff, 120 | ; pmFreq, pmFreqA, pmFreqB, pmPitch, pmRitOffset, pmRit0, 121 | ; pmVfoAA, pmVfoAB, pmVfoBA, pmVfoBB, pmVfoA, pmVfoB, pmVfoEqual, pmVfoSwap, -------------------------------------------------------------------------------- /SDR_RA8875/Aux_Lib_Files/RS-HFIQ Omni-RIg/RS-HFIQ.ini: -------------------------------------------------------------------------------- 1 | ;------------------------------------------------------------------------------- 2 | ; RS-HFIQ SDR Transceiver 3 | ; 4 | ; File created by Jim Veatch WA2EUJ 5 | ;------------------------------------------------------------------------------- 6 | 7 | ;------------------------------------------------------------------------------- 8 | ; initialize 9 | ;------------------------------------------------------------------------------- 10 | [INIT1] 11 | Command=2A.0D.0A 12 | ReplyEnd=0A 13 | 14 | [INIT2] 15 | Command=2A.57.0D 16 | ReplyEnd=0A 17 | 18 | 19 | [INIT3] 20 | Command=2A.4F.46.33.0D 21 | ReplyLength=0 22 | 23 | ;------------------------------------------------------------------------------- 24 | ; set frequency 25 | ;------------------------------------------------------------------------------- 26 | [pmFreqA] 27 | Command=2A.46.00.00.00.00.00.00.00.00.0D 28 | Value=2|8|vfText|1|0 29 | ReplyLength=0 30 | 31 | [pmFreqB] 32 | Command=2A.46.00.00.00.00.00.00.00.00.0D 33 | Value=2|8|vfText|1|0 34 | ReplyLength=0 35 | 36 | [pmFreq] 37 | Command=2A.46.00.00.00.00.00.00.00.00.0D 38 | Value=2|8|vfText|1|0 39 | ReplyLength=0 40 | 41 | [pmRitOffset] 42 | ;not supported 43 | 44 | [pmRit0] 45 | ;not supported 46 | 47 | [pmPitch] 48 | ;not supported 49 | 50 | [pmTx] 51 | Command=2A.58.31.0D 52 | ReplyLength=0 53 | 54 | [pmRx] 55 | Command=2A.58.30.0D 56 | ReplyLength=0 57 | 58 | [STATUS1] 59 | Command=2A.46.3F.0D 60 | ReplyEnd=0D 61 | Validate=00.00.00.00.00.00.00.00.0D 62 | Value1=0|8|vfText|1|0|pmFreq 63 | -------------------------------------------------------------------------------- /SDR_RA8875/Aux_Lib_Files/SV1AFN_BandpassFilters/SVN1AFN_BandpassFilters.cpp: -------------------------------------------------------------------------------- 1 | #include "SVN1AFN_BandpassFilters.h" 2 | #include "Wire.h" 3 | 4 | SVN1AFN_BandpassFilters::SVN1AFN_BandpassFilters() 5 | { 6 | _mcp = new Adafruit_MCP23X17(); 7 | } 8 | 9 | void SVN1AFN_BandpassFilters::begin(uint8_t address, TwoWire *theWire) 10 | { 11 | // call versoin of begin for I2C bus (new since V2 adafruit mcp23017 library) 12 | _mcp->begin_I2C(address, theWire); 13 | _mcp->pinMode(J9_1M8, OUTPUT); 14 | _mcp->pinMode(J9_3M5, OUTPUT); 15 | _mcp->pinMode(J9_5M, OUTPUT); 16 | _mcp->pinMode(J9_7M, OUTPUT); 17 | _mcp->pinMode(J9_10M, OUTPUT); 18 | _mcp->pinMode(J9_14M, OUTPUT); 19 | _mcp->pinMode(J9_18M, OUTPUT); 20 | _mcp->pinMode(J9_21M, OUTPUT); 21 | _mcp->pinMode(J9_24M, OUTPUT); 22 | _mcp->pinMode(J9_28M, OUTPUT); 23 | _mcp->pinMode(J9_BP, OUTPUT); 24 | _mcp->pinMode(J9_ATT2, OUTPUT); 25 | _mcp->pinMode(J9_LNA2, OUTPUT); 26 | } 27 | 28 | void SVN1AFN_BandpassFilters::setBand(HFBand band) 29 | { 30 | switch(band) 31 | { 32 | case HF160: 33 | setBandBit(J9_1M8); 34 | break; 35 | case HF80: 36 | setBandBit(J9_3M5); 37 | break; 38 | case HF60: 39 | setBandBit(J9_5M); 40 | break; 41 | case HF40: 42 | setBandBit(J9_7M); 43 | break; 44 | case HF30: 45 | setBandBit(J9_10M); 46 | break; 47 | case HF20: 48 | setBandBit(J9_14M); 49 | break; 50 | case HF17: 51 | setBandBit(J9_18M); 52 | break; 53 | case HF15: 54 | setBandBit(J9_21M); 55 | break; 56 | case HF12: 57 | setBandBit(J9_24M); 58 | break; 59 | case HF10: 60 | setBandBit(J9_28M); 61 | break; 62 | case HFBypass: 63 | setBandBit(J9_BP); 64 | break; 65 | case HFNone: 66 | setNoFilters(); 67 | break; 68 | } 69 | } 70 | 71 | void SVN1AFN_BandpassFilters::setBandBit(uint8_t bandBit) 72 | { 73 | // Read the current state of all 16 bits. 74 | uint16_t currentBits = _mcp->readGPIOAB(); 75 | 76 | uint16_t allFilters = ALLFILTERS; 77 | 78 | allFilters = ~allFilters; 79 | 80 | // Set all band bits to 0 81 | currentBits &= allFilters; 82 | 83 | uint16_t shiftedBandBit = 1 << bandBit; 84 | 85 | // Set the desired band bit 86 | currentBits = currentBits | shiftedBandBit; 87 | _mcp->writeGPIOAB(currentBits); 88 | } 89 | 90 | void SVN1AFN_BandpassFilters::setNoFilters() 91 | { 92 | // Read the current state of all 16 bits. 93 | uint16_t currentBits = _mcp->readGPIOAB(); 94 | 95 | uint16_t allFilters = ALLFILTERS; 96 | 97 | allFilters = ~allFilters; 98 | 99 | // Set all band bits to 0 100 | currentBits &= allFilters; 101 | 102 | _mcp->writeGPIOAB(currentBits); 103 | } 104 | 105 | void SVN1AFN_BandpassFilters::setAttenuator(bool on) 106 | { 107 | _mcp->digitalWrite(J9_ATT2, (uint8_t)on); 108 | } 109 | 110 | void SVN1AFN_BandpassFilters::setPreamp(bool on) 111 | { 112 | _mcp->digitalWrite(J9_LNA2, (uint8_t)on); 113 | } -------------------------------------------------------------------------------- /SDR_RA8875/Aux_Lib_Files/SV1AFN_BandpassFilters/SVN1AFN_BandpassFilters.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef SVN1AFN_BandpassFilters_h 3 | #define SVN1AFN_BandpassFilters_h 4 | 5 | #include "Arduino.h" 6 | #include 7 | #include "Adafruit_MCP23X17.h" 8 | 9 | // GPIO bits on latch A 10 | #define PA0 0 11 | #define PA1 1 12 | #define PA2 2 13 | #define PA3 3 14 | #define PA4 4 15 | #define PA5 5 16 | #define PA6 6 17 | #define PA7 7 18 | 19 | // GPIO bits on latch B 20 | #define PB0 8 21 | #define PB1 9 22 | #define PB2 10 23 | #define PB3 11 24 | #define PB4 12 25 | #define PB5 13 26 | #define PB6 14 27 | #define PB7 15 28 | 29 | // GPIO map to Pins on J9 of bandpass filter. 30 | // Feel free to change the mapping to suit your connections. 31 | #define J9_1M8 PA0 32 | #define J9_3M5 PA1 33 | #define J9_7M PA2 34 | #define J9_10M PA3 35 | #define J9_14M PA4 36 | #define J9_18M PA5 37 | #define J9_21M PA6 38 | #define J9_24M PA7 39 | #define J9_28M PB0 40 | #define J9_BP PB1 41 | #define J9_ATT2 PB2 42 | #define J9_LNA2 PB3 43 | #define J9_5M PB4 44 | 45 | #define ALLFILTERS 1< 3 | #include 4 | // Expanded test program to cycle through all relays, 1 per second. Supports 60M band with modified library. 5 | 6 | SVN1AFN_BandpassFilters _bpf; 7 | 8 | void setup() { 9 | // put your setup code here, to run once: 10 | 11 | // bpf.begin(uint8_t baseAddressOffset, TwoWire &Wire); 12 | 13 | // I2C base address for the MCP23017 is 0x20; 14 | // You can change address jumpers on the I/O board to set it 15 | // to anywhere between 0x20 and 0x28. You would do this if you 16 | // have multiple port expanders on the same I2C bus. 17 | // Use respective base address offset. 18 | // Example: Base address set to 0x23, 19 | // call with bpf.begin(3, &Wire); 20 | 21 | // Wire.h accomodates other I2C buses on the processor. 22 | // Wire = the first bus, Wire1 = second bus, and so forth. 23 | // If the bandpass filters are on the second bus, use 24 | // bpf.begin(0, &Wire1); 25 | Serial.begin(9600); 26 | delay(1000); 27 | Serial.println("Init Start"); 28 | 29 | _bpf.begin(0, &Wire); 30 | 31 | // Call with HF160, HF80, HF60, HF40, HF30, HF20, HF17, HF15, HF12, HF10, HFBypass, or HFNone 32 | _bpf.setBand(HF40); 33 | 34 | // To change bands call setBand again 35 | _bpf.setBand(HF80); 36 | 37 | _bpf.setPreamp(true); 38 | _bpf.setAttenuator(false); 39 | 40 | // To deactivate all relays on the filter board. 41 | _bpf.setBand(HFNone); 42 | _bpf.setPreamp(false); 43 | _bpf.setAttenuator(false); 44 | 45 | Serial.println("Init Done"); 46 | } 47 | 48 | void loop() { 49 | // put your main code here, to run repeatedly: 50 | delay(1000); 51 | _bpf.setBand(HF160); 52 | Serial.println(HF160); 53 | delay(1000); 54 | _bpf.setBand(HF80); 55 | Serial.println(HF80); 56 | delay(1000); 57 | _bpf.setBand(HF60); 58 | Serial.println(HF60); 59 | delay(1000); 60 | _bpf.setBand(HF40); 61 | Serial.println(HF40); 62 | delay(1000); 63 | _bpf.setBand(HF30); 64 | Serial.println(HF30); 65 | delay(1000); 66 | _bpf.setBand(HF20); 67 | Serial.println(HF20); 68 | delay(1000); 69 | _bpf.setBand(HF17); 70 | Serial.println(HF17); 71 | delay(1000); 72 | _bpf.setBand(HF15); 73 | Serial.println(HF15); 74 | delay(1000); 75 | _bpf.setBand(HF12); 76 | Serial.println(HF12); 77 | delay(1000); 78 | _bpf.setBand(HF10); 79 | Serial.println(HF10); 80 | delay(1000); 81 | _bpf.setPreamp(false); 82 | Serial.println("Preamp Off"); 83 | delay(1000); 84 | _bpf.setAttenuator(true); 85 | Serial.println("Preamp On"); 86 | delay(1000); 87 | _bpf.setAttenuator(false); 88 | Serial.println("Attenuator Off"); 89 | delay(1000); 90 | _bpf.setAttenuator(true); 91 | Serial.println("Attenuator On"); 92 | delay(3000); 93 | } 94 | -------------------------------------------------------------------------------- /SDR_RA8875/Aux_Lib_Files/cores_IDE_2.0/AudioStream..txt: -------------------------------------------------------------------------------- 1 | // add/replace these lines to the top of your AudioStream.h file. 2 | 3 | 4 | //#define USB_AUDIO_48KHZ 1 // This line is likely set elsewhere but included here just in case needed. 5 | 6 | #ifndef AUDIO_SAMPLE_RATE_EXACT 7 | #ifdef USB_AUDIO_48KHZ 8 | #define AUDIO_SAMPLE_RATE_EXACT 48000.0f // New 48KHz 9 | #else 10 | #define AUDIO_SAMPLE_RATE_EXACT 44100.0f // Original 44.1K 11 | #endif 12 | #endif 13 | 14 | #define AUDIO_SAMPLE_RATE AUDIO_SAMPLE_RATE_EXACT 15 | -------------------------------------------------------------------------------- /SDR_RA8875/Aux_Lib_Files/cores_IDE_2.0/boards.local.txt: -------------------------------------------------------------------------------- 1 | # Solution for Arduino IDE 2.0 recognizing changes to this file: 2 | # https://github.com/arduino/arduino-ide/issues/1030#issuecomment-1152005617 3 | # Add to Tools Menu in Ardiuno IDE for 2Serial+1 Audio. Requires matching usb file changes 4 | 5 | teensy41.menu.usb.serialserialaudio=Serial + Serial + Audio 6 | teensy41.menu.usb.serialserialaudio.build.usbtype=USB_SERIAL_SERIAL_AUDIO 7 | teensy41.menu.usb.serialserialaudio.upload_port.usbtype=USB_SERIAL_SERIAL_AUDIO 8 | -------------------------------------------------------------------------------- /SDR_RA8875/Aux_Lib_Files/cores_IDE_2.0/readme.txt: -------------------------------------------------------------------------------- 1 | Dec 21, 2022 Update 2 | I was able to get Windows to recognize the Teensy USB Audio Sample Rate at 48KHz and get clean audio on both TX and RX by doing the steps below. 3 | The default Teensy usb audio sample rate is 44.1KHz. We want 48KHz. 4 | 5 | Thanks threads in the PJRC forum, and the work of Steve KF7O, DL1YCF, and others creating a Teensy keyer with low latency audio at 48KHz, I am able to get things working. It also works with the OpenAudio_Library F32 functions. 6 | 7 | The CW keyer code used AUDIO_BLOCK_SAMPLES 32 and has lots of code for on the fly feedback correction. 8 | I am not using either so left that code out to keep things simpler. 9 | 10 | Be aware that TeensyDuino supplied files are overwritten with each package update or manual install of TeensyDuino. 11 | You must make these changes each time after such and update. The files typically do nto change much but you need to check. 12 | I am using TeensyDuino 1.57.2 and Arduino IDE 2.0.3 as I write this. 13 | 14 | I put the following 6 modified files (5 usb related, 1 AudioStream.h) into the repository under the libraries folder. 15 | 16 | AudioStream.h 17 | usb_desc.h 18 | usb_desc.c 19 | usb.c 20 | usb_audio.h 21 | usb_audio.c 22 | 23 | In my reading files placed in a library folder under the sketch folder should be processed before all other library locations including the stock TeensyDuino library but I have not verified this yet. 24 | 25 | 1. You can find the TeensyDuinbo files 26 | a. For IDE 2.0.x go to C:\Users\Mike\AppData\Local\Arduino15\packages\teensy\hardware\avr\1.57.2\cores\teensy4 27 | b. For IDE 1.8.x go to C:\Program Files (x86)\Arduino\hardware\teensy\avr\cores\teensy4 28 | 29 | 2. Edit AudioStream.h - Update, USB_AUDIO_48KHZ only needs to be set in usb_desc.h 30 | a. NA- About line 40, after the __ASSEMBLER__ #endif section, add the line 31 | #define USB_AUDIO_48KHZ 1 32 | b. Find the lines 33 | #ifndef AUDIO_SAMPLE_RATE_EXACT 34 | #define AUDIO_SAMPLE_RATE_EXACT 48000.0f 35 | #endif 36 | and replace with 37 | #ifdef USB_AUDIO_48KHZ 38 | # define AUDIO_SAMPLE_RATE_EXACT 48000.0f 39 | #else 40 | #define AUDIO_SAMPLE_RATE_EXACT 44100.0f 41 | #endif 42 | #endif 43 | c. AudioStream_F32.h already sets this to 48000 but if you do not enable the #define USB32 then the 16bit version will be active, 44 | needing this #define anyway. 45 | 46 | 3. Edit usb_desc.h 47 | a. Insert the below line at line 113 between the comment section and teh line #if defined(USB_SERIAL) 48 | #define USB_AUDIO_48KHZ 1 49 | b. Editing this file first will cause to the new #ifdef USB_AUDIO_48KHZ sections to be added next to light up if using an editor like Visual Studio Code making edits color coded, shaded, and error checking far easier to deal with. 50 | 51 | 4. Edit usb_audio.h 52 | a. Find the lines below around 390 53 | unsigned int usb_audio_transmit_callback(void) 54 | { 55 | static uint32_t count=5; 56 | uint32_t avail, num, target, offset, len=0; 57 | audio_block_t *left, *right; 58 | 59 | if (++count < 10) { // TODO: dynamic adjust to match USB rate 60 | target = 44; 61 | } else { 62 | count = 0; 63 | target = 45; 64 | } 65 | ... 66 | b. Replace with these lines 67 | unsigned int usb_audio_transmit_callback(void) 68 | { 69 | 70 | uint32_t avail, num, target, offset, len=0; 71 | audio_block_t *left, *right; 72 | 73 | #ifdef USB_AUDIO_48KHZ 74 | target = 48; 75 | #else 76 | static uint32_t count=5; 77 | if (++count < 10) { // TODO: dynamic adjust to match USB rate 78 | target = 44; 79 | } else { 80 | count = 0; 81 | target = 45; 82 | } 83 | #endif 84 | ... 85 | 86 | 3. Edit usb_desc.c file. #define PRODUCT_ID 0x048A 87 | a. Search for "MICROPHONE". You will find it in 2 places inside #ifdef AUDIO_INTERFACE sections 88 | b. The 3 lines for wTerminalType will look like below with the Digital Audio likely set. 89 | //0x01, 0x02, // wTerminalType, 0x0201 = MICROPHONE 90 | //0x03, 0x06, // wTerminalType, 0x0603 = Line Connector 91 | 0x02, 0x06, // wTerminalType, 0x0602 = Digital Audio 92 | c. Change the wTerminalType to something else like Line Connector to get Windows to recognize the change in the cached driver 93 | //0x01, 0x02, // wTerminalType, 0x0201 = MICROPHONE 94 | 0x03, 0x06, // wTerminalType, 0x0603 = Line Connector 95 | //0x02, 0x06, // wTerminalType, 0x0602 = Digital Audio 96 | d. Search for "Headphones". You will find it in 2 places inside #ifdef AUDIO_INTERFACE sections 97 | //0x02, 0x03, // wTerminalType, 0x0302 = Headphones 98 | 0x02, 0x06, // wTerminalType, 0x0602 = Digital Audio 99 | e. Change the wTerminalType from Digital Audio to Headphones to get Windows to recognize the change in the cached driver 100 | 0x02, 0x03, // wTerminalType, 0x0302 = Headphones 101 | //0x02, 0x06, // wTerminalType, 0x0602 = Digital Audio 102 | f. change #define PRODUCT_ID 0x048A to 0x48B. 103 | 104 | 4. Edit usb_desc.c file. 105 | a. Search for LSB(44100). You will find it in 4 places 106 | Replace 107 | LSB(44100), MSB(44100), 0, // tSamFreq 108 | with 109 | #ifdef USB_AUDIO_48KHZ 110 | LSB(48000), MSB(48000), 0, 111 | #else 112 | LSB(44100), MSB(44100), 0, // tSamFreq 113 | #endif 114 | 115 | 5. Edit usb_desc.h. This updates the sample rate length for USB_MIDI_AUDIO_SERIAL and 3 other sectoins containing Audio. 116 | a. In the #elif defined(USB_XXXXXXX) sections 117 | replace 118 | #define AUDIO_TX_SIZE 180 119 | #define AUDIO_RX_SIZE 180 120 | with 121 | #ifdef USB_AUDIO_48KHZ 122 | #define AUDIO_TX_SIZE 196 // longer buffer 123 | #define AUDIO_RX_SIZE 196 124 | #else 125 | #define AUDIO_TX_SIZE 180 126 | #define AUDIO_RX_SIZE 180 127 | #endif 128 | b. Be careful to not delete or edit the #define AUDIO_TX_ENDPOINT x and #define AUDIO_RX_ENDPOINT y lines, they are mixed in. 129 | The endpoint numbers are unique to each section so leave them as they are. 130 | c. I chose to customize the Product Name to use my call sign. Each section contain a product name. 131 | Since we are only using USB_MIDI_AUDIO_SERIAL for this SDR project I chose to only edit this section replacing the MIDI/Audio name with my own string. 132 | #define PRODUCT_NAME {'K','7','M','D','L',' ','S','D','R'} 133 | #define PRODUCT_NAME_LEN 9 134 | 135 | 6. Edit usb.c 136 | a. Search for 0x81A2 around line 662 and replace 137 | endpoint0_buffer[0] = 44100 & 255; 138 | endpoint0_buffer[1] = 44100 >> 8; 139 | with 140 | #ifdef USB_AUDIO_48KHZ 141 | endpoint0_buffer[0] = 48000 & 255; 142 | endpoint0_buffer[1] = 48000 >> 8; 143 | #else 144 | endpoint0_buffer[0] = 44100 & 255; 145 | endpoint0_buffer[1] = 44100 >> 8; 146 | #endif 147 | 148 | 7. Uninstall the previous Record and Playback Teensy Digital Audio device instances that were likely at 44.1KHz using the Sound Control Panel or Device Manager. 149 | 150 | 8. Unplug the Teensy USB and reboot your Windows computer to finish the removal. 151 | 152 | 9. Plug the Teensy USB cable back in. You should now have new Teensy MIDI/Audio devices in both Playback and Record views. 153 | 154 | 10. Both should have an Advanced tab with 16bit 48000 Hz DVD Quality listed. Turn off any offered enchancements. 155 | 156 | 11. Rename each device from to something you prefer. I like "SDR Audio RX Input" and SDR Audio TX Output" to help identify these easier. Change the icon if you like. 157 | 158 | 12. Enable listen on the SDR Line In record device and play it back to your speakers and see if it sounds proper. 159 | 160 | 13. In usb_desc.c you can change the Headphone and Line devices wTerminal type back to Digital Audio if desired. 161 | Sometimes this is needed to get your low level edits to register correctly due to the device caching. Or try changing the USB PRoduct ID (see later steps). May also need to reboot. 162 | 163 | 14. Adding a Custom USB type for the Teensy to enable 2 Serial ports plus Audio to the Arduino 2.0 IDE. This enables debug on Serial and the optional CAT interface on USBSerial1. 164 | a. add this section into usb_desc.h after the USB_AUDIO section. 165 | The Product ID must be unique from the other entries in this file or the IDE menu will use the name of the matching ID and likely be wrong. 166 | #elif defined(USB_SERIAL_SERIAL_AUDIO) 167 | #define VENDOR_ID 0x16C0 168 | #define PRODUCT_ID 0x0484 // usually make this unique. See project wiki notes though 169 | #define MANUFACTURER_NAME {'T','e','e','n','s','y','d','u','i','n','o'} 170 | #define MANUFACTURER_NAME_LEN 11 171 | #define PRODUCT_NAME {'K','7','M','D','L',' ','S','D','R'} 172 | #define PRODUCT_NAME_LEN 9 173 | #define EP0_SIZE 64 174 | #define NUM_ENDPOINTS 7 // 5 for 2 serial, + 2 for audio 175 | #define NUM_INTERFACE 7 // 4 for 2 serial, + 3 for audio 176 | #define CDC_IAD_DESCRIPTOR 1 177 | #define CDC_STATUS_INTERFACE 0 178 | #define CDC_DATA_INTERFACE 1 // Serial 179 | #define CDC_ACM_ENDPOINT 2 180 | #define CDC_RX_ENDPOINT 3 181 | #define CDC_TX_ENDPOINT 3 182 | #define CDC_ACM_SIZE 16 183 | #define CDC_RX_SIZE_480 512 184 | #define CDC_TX_SIZE_480 512 185 | #define CDC_RX_SIZE_12 64 186 | #define CDC_TX_SIZE_12 64 187 | #define CDC2_STATUS_INTERFACE 2 // SerialUSB1 188 | #define CDC2_DATA_INTERFACE 3 189 | #define CDC2_ACM_ENDPOINT 4 190 | #define CDC2_RX_ENDPOINT 5 191 | #define CDC2_TX_ENDPOINT 5 192 | #define AUDIO_INTERFACE 4 // Audio (uses 3 consecutive interfaces) 193 | #define AUDIO_TX_ENDPOINT 6 194 | #define AUDIO_RX_ENDPOINT 6 195 | #ifdef USB_AUDIO_48KHZ 196 | #define AUDIO_TX_SIZE 196 // longer buffer 197 | #define AUDIO_RX_SIZE 196 198 | #else 199 | #define AUDIO_TX_SIZE 180 200 | #define AUDIO_RX_SIZE 180 201 | #endif 202 | #define AUDIO_SYNC_ENDPOINT 7 203 | #define ENDPOINT2_CONFIG ENDPOINT_RECEIVE_UNUSED + ENDPOINT_TRANSMIT_INTERRUPT 204 | #define ENDPOINT3_CONFIG ENDPOINT_RECEIVE_BULK + ENDPOINT_TRANSMIT_BULK 205 | #define ENDPOINT4_CONFIG ENDPOINT_RECEIVE_UNUSED + ENDPOINT_TRANSMIT_INTERRUPT 206 | #define ENDPOINT5_CONFIG ENDPOINT_RECEIVE_BULK + ENDPOINT_TRANSMIT_BULK 207 | #define ENDPOINT6_CONFIG ENDPOINT_RECEIVE_ISOCHRONOUS + ENDPOINT_TRANSMIT_ISOCHRONOUS 208 | #define ENDPOINT7_CONFIG ENDPOINT_RECEIVE_UNUSED + ENDPOINT_TRANSMIT_ISOCHRONOUS 209 | Note: as a workaround the file usb_desc.h I supply in libraries folder has the same contents for USB_SERIAL_MIDI_AUDIO. More below. 210 | 211 | Updated method Jan 2 2023. 212 | b. To add custom Serial + Serial + Audio USB type into the IDE Tools:USB Type menu do the following. 213 | Create a new file called boards.local.txt with the following 3 lines. It will add to the existing Teensy Menu items. I have already created one in the Cores subfolder. 214 | 215 | teensy41.menu.usb.serialserialaudio=Serial + Serial + Audio 216 | teensy41.menu.usb.serialserialaudio.build.usbtype=USB_SERIAL_SERIAL_AUDIO 217 | teensy41.menu.usb.serialserialaudio.upload_port.usbtype=USB_SERIAL_SERIAL_AUDIO 218 | 219 | Place your boards.local.txt into %AppData%\Local\Arduino15\packages\teensy\hardware\avr\xxxxx. 220 | xxxxx is the TeensyDuino version you have installed and are using. In my test case it is 0.58.3 (aka 1.58 beta 3) 221 | 222 | The USB_SERIAL_SERIAL_AUDIO becomes a #define during compile. The file usb-desc.h has all teh usb combo descriptions and uses similar #define to activate your chosen combo. 223 | I have provided a modified usb_desc.h file that uses this define and supports the 48K mod. 224 | Other files are provided to also "patch" the library and are related to the 48KHz modification only. 225 | 226 | c. Shutdown the Arduino IDE. 227 | 228 | d. There is a known bug in IDE that does not update its cache (a small dB) when board.txt is changed. 229 | See https://github.com/arduino/arduino-ide/issues/1030 230 | For Windows users, this is typically C:\Users\\AppData\Roaming\arduino-ide 231 | Further reading I found a less drastic solution proposed just delete 1 sub folder called leveldb 232 | In %AppData%\Roaming\arduino-ide\Local Storage folder delete the leveldb folder. 233 | 234 | e. Start the Arduino IDE 2.0. Ignore the errors in the output window. Restart the IDE and it will clear the error. 235 | 236 | f. Under Tools 237 | Board choose Teensy 4.1 238 | Port choose the port displayed under the teensy ports section. 239 | The correct name may not show up until you do your first compile, maybe not even then but you will see 2 serial ports. 240 | CPU Speed choose 816MHz (recommended, but anything you like that works) 241 | USB Type choose Serial + Serial + Audio. This is our new custom USB device type. 242 | 243 | g. If DEBUG is enabled in top of SDR_RA8875.h, debug output will be on the first serial port. 244 | 245 | h. If you have the RS_HFIQ, the second serial port will be CAT control at 38400 which emulates an Elecraft K3. 246 | 247 | 248 | Configuration Note: I have IDE 2.03 and TeensyDuino 0.58.3 installed. Along the way I removed 1.8.19 as I found the VS Code was still using it and I wanted a clean 2.0 system. 249 | 250 | _________________________________________________________________________________________ 251 | 252 | Previous version notes from the IDE 1.8.x days: 253 | 254 | This file is a modified version of the original TeensyDuino file called AudioStream.h 255 | 256 | For Arduino IDE < 2.0 257 | C:\Program Files (x86)\Arduino\hardware\teensy\avr\cores\teensy4 258 | 259 | or for Arduino > 2.0 260 | 261 | C:\Users\[username]\AppData\Local\Arduino15\packages\teensy\hardware\avr\1.57.2\cores 262 | 263 | The changes are in the #defines at the top to set the default to either 44.1KHz or 48KHz. 264 | 265 | We are using 48KHz. Kept the sample block count the same at 128. The CWKeyer project used 32 to keep latency low and has lots of feedback loop code for on the fly corrections. 266 | 267 | 268 | 269 | -------------------------------------------------------------------------------- /SDR_RA8875/Aux_Lib_Files/cores_IDE_2.0/usb_audio.cpp: -------------------------------------------------------------------------------- 1 | /* Teensyduino Core Library 2 | * http://www.pjrc.com/teensy/ 3 | * Copyright (c) 2017 PJRC.COM, LLC. 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining 6 | * a copy of this software and associated documentation files (the 7 | * "Software"), to deal in the Software without restriction, including 8 | * without limitation the rights to use, copy, modify, merge, publish, 9 | * distribute, sublicense, and/or sell copies of the Software, and to 10 | * permit persons to whom the Software is furnished to do so, subject to 11 | * the following conditions: 12 | * 13 | * 1. The above copyright notice and this permission notice shall be 14 | * included in all copies or substantial portions of the Software. 15 | * 16 | * 2. If the Software is incorporated into a build system that allows 17 | * selection among a list of target devices, then similar target 18 | * devices manufactured by PJRC.COM must be included in the list of 19 | * target devices and selectable in the same manner. 20 | * 21 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 22 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 23 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 24 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 25 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 26 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 27 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 28 | * SOFTWARE. 29 | */ 30 | 31 | #include 32 | #include "usb_dev.h" 33 | #include "usb_audio.h" 34 | #include "debug/printf.h" 35 | 36 | #ifdef AUDIO_INTERFACE 37 | 38 | bool AudioInputUSB::update_responsibility; 39 | audio_block_t * AudioInputUSB::incoming_left; 40 | audio_block_t * AudioInputUSB::incoming_right; 41 | audio_block_t * AudioInputUSB::ready_left; 42 | audio_block_t * AudioInputUSB::ready_right; 43 | uint16_t AudioInputUSB::incoming_count; 44 | uint8_t AudioInputUSB::receive_flag; 45 | 46 | struct usb_audio_features_struct AudioInputUSB::features = {0,0,FEATURE_MAX_VOLUME/2}; 47 | 48 | extern volatile uint8_t usb_high_speed; 49 | static void rx_event(transfer_t *t); 50 | static void tx_event(transfer_t *t); 51 | 52 | /*static*/ transfer_t rx_transfer __attribute__ ((used, aligned(32))); 53 | /*static*/ transfer_t sync_transfer __attribute__ ((used, aligned(32))); 54 | /*static*/ transfer_t tx_transfer __attribute__ ((used, aligned(32))); 55 | DMAMEM static uint8_t rx_buffer[AUDIO_RX_SIZE] __attribute__ ((aligned(32))); 56 | DMAMEM static uint8_t tx_buffer[AUDIO_RX_SIZE] __attribute__ ((aligned(32))); 57 | DMAMEM uint32_t usb_audio_sync_feedback __attribute__ ((aligned(32))); 58 | 59 | uint8_t usb_audio_receive_setting=0; 60 | uint8_t usb_audio_transmit_setting=0; 61 | uint8_t usb_audio_sync_nbytes; 62 | uint8_t usb_audio_sync_rshift; 63 | 64 | uint32_t feedback_accumulator; 65 | 66 | volatile uint32_t usb_audio_underrun_count; 67 | volatile uint32_t usb_audio_overrun_count; 68 | 69 | 70 | static void rx_event(transfer_t *t) 71 | { 72 | if (t) { 73 | int len = AUDIO_RX_SIZE - ((rx_transfer.status >> 16) & 0x7FFF); 74 | printf("rx %u\n", len); 75 | usb_audio_receive_callback(len); 76 | } 77 | usb_prepare_transfer(&rx_transfer, rx_buffer, AUDIO_RX_SIZE, 0); 78 | arm_dcache_delete(&rx_buffer, AUDIO_RX_SIZE); 79 | usb_receive(AUDIO_RX_ENDPOINT, &rx_transfer); 80 | } 81 | 82 | static void sync_event(transfer_t *t) 83 | { 84 | // USB 2.0 Specification, 5.12.4.2 Feedback, pages 73-75 85 | //printf("sync %x\n", sync_transfer.status); // too slow, can't print this much 86 | usb_audio_sync_feedback = feedback_accumulator >> usb_audio_sync_rshift; 87 | usb_prepare_transfer(&sync_transfer, &usb_audio_sync_feedback, usb_audio_sync_nbytes, 0); 88 | arm_dcache_flush(&usb_audio_sync_feedback, usb_audio_sync_nbytes); 89 | usb_transmit(AUDIO_SYNC_ENDPOINT, &sync_transfer); 90 | } 91 | 92 | void usb_audio_configure(void) 93 | { 94 | printf("usb_audio_configure\n"); 95 | usb_audio_underrun_count = 0; 96 | usb_audio_overrun_count = 0; 97 | feedback_accumulator = 739875226; // 44.1 * 2^24 98 | if (usb_high_speed) { 99 | usb_audio_sync_nbytes = 4; 100 | usb_audio_sync_rshift = 8; 101 | } else { 102 | usb_audio_sync_nbytes = 3; 103 | usb_audio_sync_rshift = 10; 104 | } 105 | memset(&rx_transfer, 0, sizeof(rx_transfer)); 106 | usb_config_rx_iso(AUDIO_RX_ENDPOINT, AUDIO_RX_SIZE, 1, rx_event); 107 | rx_event(NULL); 108 | memset(&sync_transfer, 0, sizeof(sync_transfer)); 109 | usb_config_tx_iso(AUDIO_SYNC_ENDPOINT, usb_audio_sync_nbytes, 1, sync_event); 110 | sync_event(NULL); 111 | memset(&tx_transfer, 0, sizeof(tx_transfer)); 112 | usb_config_tx_iso(AUDIO_TX_ENDPOINT, AUDIO_TX_SIZE, 1, tx_event); 113 | tx_event(NULL); 114 | } 115 | 116 | void AudioInputUSB::begin(void) 117 | { 118 | incoming_count = 0; 119 | incoming_left = NULL; 120 | incoming_right = NULL; 121 | ready_left = NULL; 122 | ready_right = NULL; 123 | receive_flag = 0; 124 | // update_responsibility = update_setup(); 125 | // TODO: update responsibility is tough, partly because the USB 126 | // interrupts aren't sychronous to the audio library block size, 127 | // but also because the PC may stop transmitting data, which 128 | // means we no longer get receive callbacks from usb.c 129 | update_responsibility = false; 130 | } 131 | 132 | static void copy_to_buffers(const uint32_t *src, int16_t *left, int16_t *right, unsigned int len) 133 | { 134 | uint32_t *target = (uint32_t*) src + len; 135 | while ((src < target) && (((uintptr_t) left & 0x02) != 0)) { 136 | uint32_t n = *src++; 137 | *left++ = n & 0xFFFF; 138 | *right++ = n >> 16; 139 | } 140 | 141 | while ((src < target - 2)) { 142 | uint32_t n1 = *src++; 143 | uint32_t n = *src++; 144 | *(uint32_t *)left = (n1 & 0xFFFF) | ((n & 0xFFFF) << 16); 145 | left+=2; 146 | *(uint32_t *)right = (n1 >> 16) | ((n & 0xFFFF0000)) ; 147 | right+=2; 148 | } 149 | 150 | while ((src < target)) { 151 | uint32_t n = *src++; 152 | *left++ = n & 0xFFFF; 153 | *right++ = n >> 16; 154 | } 155 | } 156 | 157 | // Called from the USB interrupt when an isochronous packet arrives 158 | // we must completely remove it from the receive buffer before returning 159 | // 160 | #if 1 161 | void usb_audio_receive_callback(unsigned int len) 162 | { 163 | unsigned int count, avail; 164 | audio_block_t *left, *right; 165 | const uint32_t *data; 166 | 167 | AudioInputUSB::receive_flag = 1; 168 | len >>= 2; // 1 sample = 4 bytes: 2 left, 2 right 169 | data = (const uint32_t *)rx_buffer; 170 | 171 | count = AudioInputUSB::incoming_count; 172 | left = AudioInputUSB::incoming_left; 173 | right = AudioInputUSB::incoming_right; 174 | if (left == NULL) { 175 | left = AudioStream::allocate(); 176 | if (left == NULL) return; 177 | AudioInputUSB::incoming_left = left; 178 | } 179 | if (right == NULL) { 180 | right = AudioStream::allocate(); 181 | if (right == NULL) return; 182 | AudioInputUSB::incoming_right = right; 183 | } 184 | while (len > 0) { 185 | avail = AUDIO_BLOCK_SAMPLES - count; 186 | if (len < avail) { 187 | copy_to_buffers(data, left->data + count, right->data + count, len); 188 | AudioInputUSB::incoming_count = count + len; 189 | return; 190 | } else if (avail > 0) { 191 | copy_to_buffers(data, left->data + count, right->data + count, avail); 192 | data += avail; 193 | len -= avail; 194 | if (AudioInputUSB::ready_left || AudioInputUSB::ready_right) { 195 | // buffer overrun, PC sending too fast 196 | AudioInputUSB::incoming_count = count + avail; 197 | if (len > 0) { 198 | usb_audio_overrun_count++; 199 | printf("!"); 200 | //serial_phex(len); 201 | } 202 | return; 203 | } 204 | send: 205 | AudioInputUSB::ready_left = left; 206 | AudioInputUSB::ready_right = right; 207 | //if (AudioInputUSB::update_responsibility) AudioStream::update_all(); 208 | left = AudioStream::allocate(); 209 | if (left == NULL) { 210 | AudioInputUSB::incoming_left = NULL; 211 | AudioInputUSB::incoming_right = NULL; 212 | AudioInputUSB::incoming_count = 0; 213 | return; 214 | } 215 | right = AudioStream::allocate(); 216 | if (right == NULL) { 217 | AudioStream::release(left); 218 | AudioInputUSB::incoming_left = NULL; 219 | AudioInputUSB::incoming_right = NULL; 220 | AudioInputUSB::incoming_count = 0; 221 | return; 222 | } 223 | AudioInputUSB::incoming_left = left; 224 | AudioInputUSB::incoming_right = right; 225 | count = 0; 226 | } else { 227 | if (AudioInputUSB::ready_left || AudioInputUSB::ready_right) return; 228 | goto send; // recover from buffer overrun 229 | } 230 | } 231 | AudioInputUSB::incoming_count = count; 232 | } 233 | #endif 234 | 235 | void AudioInputUSB::update(void) 236 | { 237 | audio_block_t *left, *right; 238 | 239 | __disable_irq(); 240 | left = ready_left; 241 | ready_left = NULL; 242 | right = ready_right; 243 | ready_right = NULL; 244 | uint16_t c = incoming_count; 245 | uint8_t f = receive_flag; 246 | receive_flag = 0; 247 | __enable_irq(); 248 | if (f) { 249 | int diff = AUDIO_BLOCK_SAMPLES/2 - (int)c; 250 | feedback_accumulator += diff * 1; 251 | //uint32_t feedback = (feedback_accumulator >> 8) + diff * 100; 252 | //usb_audio_sync_feedback = feedback; 253 | 254 | //printf(diff >= 0 ? "." : "^"); 255 | } 256 | //serial_phex(c); 257 | //serial_print("."); 258 | if (!left || !right) { 259 | usb_audio_underrun_count++; 260 | //printf("#"); // buffer underrun - PC sending too slow 261 | if (f) feedback_accumulator += 3500; 262 | } 263 | if (left) { 264 | transmit(left, 0); 265 | release(left); 266 | } 267 | if (right) { 268 | transmit(right, 1); 269 | release(right); 270 | } 271 | } 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | #if 1 290 | bool AudioOutputUSB::update_responsibility; 291 | audio_block_t * AudioOutputUSB::left_1st; 292 | audio_block_t * AudioOutputUSB::left_2nd; 293 | audio_block_t * AudioOutputUSB::right_1st; 294 | audio_block_t * AudioOutputUSB::right_2nd; 295 | uint16_t AudioOutputUSB::offset_1st; 296 | 297 | /*DMAMEM*/ uint16_t usb_audio_transmit_buffer[AUDIO_TX_SIZE/2] __attribute__ ((used, aligned(32))); 298 | 299 | 300 | static void tx_event(transfer_t *t) 301 | { 302 | int len = usb_audio_transmit_callback(); 303 | usb_audio_sync_feedback = feedback_accumulator >> usb_audio_sync_rshift; 304 | usb_prepare_transfer(&tx_transfer, usb_audio_transmit_buffer, len, 0); 305 | arm_dcache_flush_delete(usb_audio_transmit_buffer, len); 306 | usb_transmit(AUDIO_TX_ENDPOINT, &tx_transfer); 307 | } 308 | 309 | 310 | void AudioOutputUSB::begin(void) 311 | { 312 | update_responsibility = false; 313 | left_1st = NULL; 314 | right_1st = NULL; 315 | } 316 | 317 | static void copy_from_buffers(uint32_t *dst, int16_t *left, int16_t *right, unsigned int len) 318 | { 319 | // TODO: optimize... 320 | while (len > 0) { 321 | *dst++ = (*right++ << 16) | (*left++ & 0xFFFF); 322 | len--; 323 | } 324 | } 325 | 326 | void AudioOutputUSB::update(void) 327 | { 328 | audio_block_t *left, *right; 329 | 330 | // TODO: we shouldn't be writing to these...... 331 | //left = receiveReadOnly(0); // input 0 = left channel 332 | //right = receiveReadOnly(1); // input 1 = right channel 333 | left = receiveWritable(0); // input 0 = left channel 334 | right = receiveWritable(1); // input 1 = right channel 335 | if (usb_audio_transmit_setting == 0) { 336 | if (left) release(left); 337 | if (right) release(right); 338 | if (left_1st) { release(left_1st); left_1st = NULL; } 339 | if (left_2nd) { release(left_2nd); left_2nd = NULL; } 340 | if (right_1st) { release(right_1st); right_1st = NULL; } 341 | if (right_2nd) { release(right_2nd); right_2nd = NULL; } 342 | offset_1st = 0; 343 | return; 344 | } 345 | if (left == NULL) { 346 | left = allocate(); 347 | if (left == NULL) { 348 | if (right) release(right); 349 | return; 350 | } 351 | memset(left->data, 0, sizeof(left->data)); 352 | } 353 | if (right == NULL) { 354 | right = allocate(); 355 | if (right == NULL) { 356 | release(left); 357 | return; 358 | } 359 | memset(right->data, 0, sizeof(right->data)); 360 | } 361 | __disable_irq(); 362 | if (left_1st == NULL) { 363 | left_1st = left; 364 | right_1st = right; 365 | offset_1st = 0; 366 | } else if (left_2nd == NULL) { 367 | left_2nd = left; 368 | right_2nd = right; 369 | } else { 370 | // buffer overrun - PC is consuming too slowly 371 | audio_block_t *discard1 = left_1st; 372 | left_1st = left_2nd; 373 | left_2nd = left; 374 | audio_block_t *discard2 = right_1st; 375 | right_1st = right_2nd; 376 | right_2nd = right; 377 | offset_1st = 0; // TODO: discard part of this data? 378 | //serial_print("*"); 379 | release(discard1); 380 | release(discard2); 381 | } 382 | __enable_irq(); 383 | } 384 | 385 | 386 | // Called from the USB interrupt when ready to transmit another 387 | // isochronous packet. If we place data into the transmit buffer, 388 | // the return is the number of bytes. Otherwise, return 0 means 389 | // no data to transmit 390 | unsigned int usb_audio_transmit_callback(void) 391 | { 392 | 393 | uint32_t avail, num, target, offset, len=0; 394 | audio_block_t *left, *right; 395 | 396 | #ifdef USB_AUDIO_48KHZ 397 | target = 48; 398 | #else 399 | static uint32_t count=5; 400 | if (++count < 10) { // TODO: dynamic adjust to match USB rate 401 | target = 44; 402 | } else { 403 | count = 0; 404 | target = 45; 405 | } 406 | #endif 407 | while (len < target) { 408 | num = target - len; 409 | left = AudioOutputUSB::left_1st; 410 | if (left == NULL) { 411 | // buffer underrun - PC is consuming too quickly 412 | memset(usb_audio_transmit_buffer + len, 0, num * 4); 413 | //serial_print("%"); 414 | break; 415 | } 416 | right = AudioOutputUSB::right_1st; 417 | offset = AudioOutputUSB::offset_1st; 418 | 419 | avail = AUDIO_BLOCK_SAMPLES - offset; 420 | if (num > avail) num = avail; 421 | 422 | copy_from_buffers((uint32_t *)usb_audio_transmit_buffer + len, 423 | left->data + offset, right->data + offset, num); 424 | len += num; 425 | offset += num; 426 | if (offset >= AUDIO_BLOCK_SAMPLES) { 427 | AudioStream::release(left); 428 | AudioStream::release(right); 429 | AudioOutputUSB::left_1st = AudioOutputUSB::left_2nd; 430 | AudioOutputUSB::left_2nd = NULL; 431 | AudioOutputUSB::right_1st = AudioOutputUSB::right_2nd; 432 | AudioOutputUSB::right_2nd = NULL; 433 | AudioOutputUSB::offset_1st = 0; 434 | } else { 435 | AudioOutputUSB::offset_1st = offset; 436 | } 437 | } 438 | return target * 4; 439 | } 440 | #endif 441 | 442 | 443 | 444 | 445 | struct setup_struct { 446 | union { 447 | struct { 448 | uint8_t bmRequestType; 449 | uint8_t bRequest; 450 | union { 451 | struct { 452 | uint8_t bChannel; // 0=main, 1=left, 2=right 453 | uint8_t bCS; // Control Selector 454 | }; 455 | uint16_t wValue; 456 | }; 457 | union { 458 | struct { 459 | uint8_t bIfEp; // type of entity 460 | uint8_t bEntityId; // UnitID, TerminalID, etc. 461 | }; 462 | uint16_t wIndex; 463 | }; 464 | uint16_t wLength; 465 | }; 466 | }; 467 | }; 468 | 469 | int usb_audio_get_feature(void *stp, uint8_t *data, uint32_t *datalen) 470 | { 471 | struct setup_struct setup = *((struct setup_struct *)stp); 472 | if (setup.bmRequestType==0xA1) { // should check bRequest, bChannel, and UnitID 473 | if (setup.bCS==0x01) { // mute 474 | data[0] = AudioInputUSB::features.mute; // 1=mute, 0=unmute 475 | *datalen = 1; 476 | return 1; 477 | } 478 | else if (setup.bCS==0x02) { // volume 479 | if (setup.bRequest==0x81) { // GET_CURR 480 | data[0] = AudioInputUSB::features.volume & 0xFF; 481 | data[1] = (AudioInputUSB::features.volume>>8) & 0xFF; 482 | } 483 | else if (setup.bRequest==0x82) { // GET_MIN 484 | //serial_print("vol get_min\n"); 485 | data[0] = 0; // min level is 0 486 | data[1] = 0; 487 | } 488 | else if (setup.bRequest==0x83) { // GET_MAX 489 | data[0] = FEATURE_MAX_VOLUME; // max level, for range of 0 to MAX 490 | data[1] = 0; 491 | } 492 | else if (setup.bRequest==0x84) { // GET_RES 493 | data[0] = 1; // increment vol by by 1 494 | data[1] = 0; 495 | } 496 | else { // pass over SET_MEM, etc. 497 | return 0; 498 | } 499 | *datalen = 2; 500 | return 1; 501 | } 502 | } 503 | return 0; 504 | } 505 | 506 | int usb_audio_set_feature(void *stp, uint8_t *buf) 507 | { 508 | struct setup_struct setup = *((struct setup_struct *)stp); 509 | if (setup.bmRequestType==0x21) { // should check bRequest, bChannel and UnitID 510 | if (setup.bCS==0x01) { // mute 511 | if (setup.bRequest==0x01) { // SET_CUR 512 | AudioInputUSB::features.mute = buf[0]; // 1=mute,0=unmute 513 | AudioInputUSB::features.change = 1; 514 | return 1; 515 | } 516 | } 517 | else if (setup.bCS==0x02) { // volume 518 | if (setup.bRequest==0x01) { // SET_CUR 519 | AudioInputUSB::features.volume = buf[0]; 520 | AudioInputUSB::features.change = 1; 521 | return 1; 522 | } 523 | } 524 | } 525 | return 0; 526 | } 527 | 528 | 529 | #endif // AUDIO_INTERFACE 530 | -------------------------------------------------------------------------------- /SDR_RA8875/Aux_Lib_Files/cores_IDE_2.0/usb_audio.h: -------------------------------------------------------------------------------- 1 | /* Teensyduino Core Library 2 | * http://www.pjrc.com/teensy/ 3 | * Copyright (c) 2017 PJRC.COM, LLC. 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining 6 | * a copy of this software and associated documentation files (the 7 | * "Software"), to deal in the Software without restriction, including 8 | * without limitation the rights to use, copy, modify, merge, publish, 9 | * distribute, sublicense, and/or sell copies of the Software, and to 10 | * permit persons to whom the Software is furnished to do so, subject to 11 | * the following conditions: 12 | * 13 | * 1. The above copyright notice and this permission notice shall be 14 | * included in all copies or substantial portions of the Software. 15 | * 16 | * 2. If the Software is incorporated into a build system that allows 17 | * selection among a list of target devices, then similar target 18 | * devices manufactured by PJRC.COM must be included in the list of 19 | * target devices and selectable in the same manner. 20 | * 21 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 22 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 23 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 24 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 25 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 26 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 27 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 28 | * SOFTWARE. 29 | */ 30 | 31 | #pragma once 32 | 33 | #include "usb_desc.h" 34 | #ifdef AUDIO_INTERFACE 35 | 36 | #define FEATURE_MAX_VOLUME 0xFF // volume accepted from 0 to 0xFF 37 | 38 | //#define USB_AUDIO_48KHZ 39 | 40 | #ifdef __cplusplus 41 | extern "C" { 42 | #endif 43 | extern void usb_audio_configure(); 44 | extern uint16_t usb_audio_receive_buffer[]; 45 | extern uint16_t usb_audio_transmit_buffer[]; 46 | extern uint32_t usb_audio_sync_feedback; 47 | extern uint8_t usb_audio_receive_setting; 48 | extern uint8_t usb_audio_transmit_setting; 49 | extern void usb_audio_receive_callback(unsigned int len); 50 | extern unsigned int usb_audio_transmit_callback(void); 51 | extern int usb_audio_set_feature(void *stp, uint8_t *buf); 52 | extern int usb_audio_get_feature(void *stp, uint8_t *data, uint32_t *datalen); 53 | #ifdef USB_AUDIO_FEEDBACK_SOF 54 | void usb_audio_update_sof_count(void); 55 | #endif 56 | #ifdef __cplusplus 57 | } 58 | #endif 59 | 60 | // audio features supported 61 | struct usb_audio_features_struct { 62 | int change; // set to 1 when any value is changed 63 | int mute; // 1=mute, 0=unmute 64 | int volume; // volume from 0 to FEATURE_MAX_VOLUME, maybe should be float from 0.0 to 1.0 65 | }; 66 | 67 | #ifdef __cplusplus 68 | #include "AudioStream.h" 69 | 70 | class AudioInputUSB : public AudioStream 71 | { 72 | public: 73 | AudioInputUSB(void) : AudioStream(0, NULL) { begin(); } 74 | virtual void update(void); 75 | void begin(void); 76 | friend void usb_audio_receive_callback(unsigned int len); 77 | friend int usb_audio_set_feature(void *stp, uint8_t *buf); 78 | friend int usb_audio_get_feature(void *stp, uint8_t *data, uint32_t *datalen); 79 | static struct usb_audio_features_struct features; 80 | float volume(void) { 81 | if (features.mute) return 0.0; 82 | return (float)(features.volume) * (1.0 / (float)FEATURE_MAX_VOLUME); 83 | } 84 | private: 85 | static bool update_responsibility; 86 | static audio_block_t *incoming_left; 87 | static audio_block_t *incoming_right; 88 | static audio_block_t *ready_left; 89 | static audio_block_t *ready_right; 90 | static uint16_t incoming_count; 91 | static uint8_t receive_flag; 92 | }; 93 | 94 | class AudioOutputUSB : public AudioStream 95 | { 96 | public: 97 | AudioOutputUSB(void) : AudioStream(2, inputQueueArray) { begin(); } 98 | virtual void update(void); 99 | void begin(void); 100 | friend unsigned int usb_audio_transmit_callback(void); 101 | private: 102 | static bool update_responsibility; 103 | static audio_block_t *left_1st; 104 | static audio_block_t *left_2nd; 105 | static audio_block_t *right_1st; 106 | static audio_block_t *right_2nd; 107 | static uint16_t offset_1st; 108 | audio_block_t *inputQueueArray[2]; 109 | }; 110 | #endif // __cplusplus 111 | 112 | #endif // AUDIO_INTERFACE 113 | -------------------------------------------------------------------------------- /SDR_RA8875/Bandwidth2.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Bandwidth2.cpp 3 | // 4 | // 5 | #include "SDR_RA8875.h" 6 | #include "RadioConfig.h" 7 | //#include "Bandwidth2.h" 8 | //#include "Hilbert.h" // filter coefficients 9 | 10 | //extern AudioFilterFIR_F32 RX_Hilbert_Plus_45; 11 | //extern AudioFilterFIR_F32 RX_Hilbert_Minus_45; 12 | //extern AudioFilterBiquad_F32 CW_Filter; 13 | extern struct Band_Memory bandmem[]; 14 | extern uint8_t curr_band; // global tracks our current band setting. 15 | extern const struct Filter_Settings filter[]; 16 | extern void SetFilter(void); 17 | extern struct User_Settings user_settings[]; 18 | extern uint8_t user_Profile; 19 | extern int16_t filterCenter; 20 | extern int16_t filterBandwidth; 21 | extern AudioEffectGain_F32 Amp1_L; // Some well placed gain stages 22 | extern AudioEffectGain_F32 Amp1_R; // Some well placed gain stages 23 | 24 | 25 | 26 | //////////////////////////////////////////////////////////////////////////////////// 27 | COLD void selectBandwidth(uint8_t bndx) 28 | { 29 | Amp1_L.setGain_dB(AUDIOBOOST); // Adjustable fixed output boost in dB. 30 | Amp1_R.setGain_dB(AUDIOBOOST); 31 | // For convolutional filter method, just set a single fixed Hibert filter width. Rest is taken care of after the summer 32 | 33 | if(bndx==0) 34 | { 35 | //bandwidth="Bw 250 Hz"; 36 | //CW_Filter.end(); 37 | //CW_Filter.setBandpass(0,250.0f,9.0f); 38 | //CW_Filter.begin(); 39 | filterCenter = user_settings[user_Profile].pitch; // Use pitch since this is a CW filter 40 | filterBandwidth = 250; 41 | AudioNoInterrupts(); 42 | Amp1_L.setGain_dB(AUDIOBOOST+8.0f); // Adjustable fixed output boost in dB. 43 | Amp1_R.setGain_dB(AUDIOBOOST+8.0f); 44 | AudioInterrupts(); 45 | SetFilter(); 46 | } 47 | 48 | if(bndx==1) 49 | { 50 | //bandwidth="Bw 500 Hz"; 51 | //CW_Filter.end(); 52 | //CW_Filter.setBandpass(0,500.0f,9.0f); 53 | //CW_Filter.begin(); 54 | filterCenter = user_settings[user_Profile].pitch; // Use pitch since this is a CW filter 55 | filterBandwidth = 500; 56 | AudioNoInterrupts(); 57 | Amp1_L.setGain_dB(AUDIOBOOST+6.0f); // Adjustable fixed output boost in dB. 58 | Amp1_R.setGain_dB(AUDIOBOOST+6.0f); 59 | AudioInterrupts(); 60 | SetFilter(); 61 | } 62 | 63 | if(bndx==2) 64 | { 65 | //bandwidth="Bw 700 Hz"; 66 | //CW_Filter.end(); 67 | //CW_Filter.setBandpass(0,700.0f,9.0f); 68 | //CW_Filter.begin(); 69 | filterCenter = user_settings[user_Profile].pitch; // Use pitch since this is a CW filter 70 | filterBandwidth = 700; 71 | AudioNoInterrupts(); 72 | Amp1_L.setGain_dB(AUDIOBOOST+5.0f); // Adjustable fixed output boost in dB. 73 | Amp1_R.setGain_dB(AUDIOBOOST+5.0f); 74 | AudioInterrupts(); 75 | SetFilter(); 76 | } 77 | 78 | if(bndx==3) 79 | { 80 | //bandwidth="Bw 1.0 kHz"; 81 | //CW_Filter.end(); 82 | //CW_Filter.setBandpass(0,1000.0f,9.0f); 83 | //CW_Filter.begin(); 84 | filterCenter = user_settings[user_Profile].pitch; // Use pitch since this is a CW filter 85 | filterBandwidth=1000; 86 | AudioNoInterrupts(); 87 | Amp1_L.setGain_dB(AUDIOBOOST+3.0f); // Adjustable fixed output boost in dB. 88 | Amp1_R.setGain_dB(AUDIOBOOST+3.0f); 89 | AudioInterrupts(); 90 | SetFilter(); 91 | } 92 | 93 | // Above are CW mode filter widths. Below are wider filters for voice and data modes 94 | 95 | if(bndx==4) 96 | { 97 | //bandwidth="Bw 1.8 kHz"; 98 | filterCenter = 1900/2; 99 | filterBandwidth = 1800; 100 | SetFilter(); 101 | } 102 | 103 | if(bndx==5) 104 | { 105 | //bandwidth="Bw 2.3kHz"; 106 | filterCenter = 2500/2; 107 | filterBandwidth = 2300; 108 | SetFilter(); 109 | } 110 | 111 | if(bndx==6) 112 | { 113 | //bandwidth="Bw 2.8 kHz"; 114 | filterCenter = 3000/2; 115 | filterBandwidth = 2800; 116 | SetFilter(); 117 | } 118 | 119 | if(bndx==7) 120 | { 121 | //bandwidth="Bw 3.2 kHz"; 122 | filterCenter = 3400/2; 123 | filterBandwidth = 3200; 124 | SetFilter(); 125 | } 126 | 127 | if(bndx==8) 128 | { 129 | //bandwidth="4.0 kHz"; 130 | filterCenter = 4200/2; 131 | filterBandwidth = 4000; 132 | SetFilter(); 133 | } 134 | 135 | if(bndx==9) 136 | { 137 | //bandwidth="6.0 kHz"; 138 | filterCenter = 6000/2; 139 | filterBandwidth = 6000; 140 | SetFilter(); 141 | } 142 | bandmem[curr_band].filter = bndx; // Set new filter into memory 143 | //DPRINTF("Filter Set to "); DPRINTLN(filter[bandmem[curr_band].filter].Filter_name); 144 | //displayFilter(); 145 | } -------------------------------------------------------------------------------- /SDR_RA8875/Bandwidth2.h: -------------------------------------------------------------------------------- 1 | #ifndef _BANDWIDTH2_H_ 2 | #define _BANDWIDTH2_H_ 3 | // 4 | // Bandwidth2.h 5 | // 6 | #include 7 | 8 | void selectBandwidth(uint8_t bndx); 9 | 10 | #endif // _BANDWIDTH2_H_ 11 | -------------------------------------------------------------------------------- /SDR_RA8875/Controls.h: -------------------------------------------------------------------------------- 1 | #ifndef _CONTROLS_H_ 2 | #define _CONTROLS_H_ 3 | // 4 | // Controls.h 5 | // 6 | // Core functions that control things. The controller may be a touch event from a button or label object 7 | // or from a mechanical device or another function in a chain of interdepedencies. 8 | // 9 | // Many controls have multipe possible controllers so have to adopt an Controller->control->display model 10 | // allowing parallel control requests. 11 | // The control object changes (or requests to change) states, the display only scans and reports the state. 12 | // It becomes importan to pass through this as remote control and monitoring get built. 13 | #include 14 | 15 | void Set_Spectrum_Scale(int8_t zoom_dir); 16 | void Set_Spectrum_RefLvl(int8_t zoom_dir); 17 | void changeBands(int8_t direction); 18 | void Mute(); 19 | void Menu(); 20 | void Display(); 21 | void Band(uint8_t new_band); 22 | void BandDn(); 23 | void BandUp(); 24 | void Notch(); 25 | void Spot(); 26 | void Enet(); 27 | void setNR(); 28 | void setNB(int8_t toggle); 29 | void Xmit(uint8_t state); 30 | void Ant(); 31 | void Fine(); 32 | void Rate(int8_t dir); 33 | void setMode(int8_t dir); 34 | void AGC(int8_t dir); 35 | void Filter(int8_t dir); 36 | void Variable_Filter(int8_t dir); 37 | void ATU(uint8_t state); 38 | void Split(uint8_t state); 39 | void setXIT(int8_t toggle); 40 | void XIT(int8_t delta); 41 | void setRIT(int8_t toggle); 42 | void RIT(int8_t delta); 43 | void Preamp(int8_t toggle); 44 | void setAtten(int8_t toggle); 45 | void VFO_AB(); 46 | void Atten(int8_t delta); 47 | void setAFgain(int8_t toggle); 48 | void AFgain(int8_t delta); 49 | void setRFgain(int8_t toggle); 50 | void RFgain(int8_t delta); 51 | void setRefLevel(int8_t toggle); 52 | void NBLevel(int8_t delta); 53 | void RefLevel(int8_t newval); 54 | void TouchTune(int16_t touch_Freq); 55 | void selectStep(uint8_t fndx); 56 | void selectAgc(uint8_t andx); 57 | void Zoom(int8_t dir); 58 | void setZoom(int8_t toggle); 59 | void setPAN(int8_t toggle); 60 | void PAN(int8_t delta); 61 | void digital_step_attenuator_PE4305(int16_t _atten); // Takes a 0 to 100 input, converts to the appropriate hardware steps such as 0-31dB in 1 dB steps 62 | uint64_t find_new_band(uint64_t new_frequency, uint8_t &_curr_band); 63 | void clearMeter(void); 64 | 65 | #endif // _CONTROLS_H_ 66 | -------------------------------------------------------------------------------- /SDR_RA8875/Display.h: -------------------------------------------------------------------------------- 1 | #ifndef _DISPLAY_H_ 2 | #define _DISPLAY_H_ 3 | ////////////////////////////////////////////////////////////// 4 | // 5 | // Display.h 6 | // 7 | ////////////////////////////////////////////////////////////// 8 | #include 9 | 10 | //void ringMeter(int val, int minV, int maxV, int16_t x, int16_t y, uint16_t r, const char* units, uint16_t colorScheme,uint16_t backSegColor,int16_t angle,uint8_t inc); 11 | uint16_t grandient(uint8_t val); 12 | void draw_2_state_Button(uint8_t button, uint8_t *function_ptr); 13 | void refreshScreen(void); 14 | const char * formatVFO(uint64_t vfo); 15 | void displayTime(void); 16 | void displayMeter(int val, const char *string, uint16_t colorscheme); 17 | void drawLabel(uint8_t lbl_num, uint8_t *function_ptr); 18 | void displayRefresh(); 19 | // Bottom Panel Anchor button 20 | void displayFn(); // make fn=1 to call displayFn() to prevent calling itself 21 | void displayFreq(); // display frequency 22 | // Panel 1 buttons 23 | void displayMode(); 24 | void displayFilter(); 25 | void displayVarFilter(); 26 | void displayAttn(); 27 | void displayRate(); 28 | void displayPreamp(); 29 | void displayBand(); 30 | //Panel 2 buttons 31 | void displayNB(); 32 | void displayNR(); 33 | void displayNotch(); 34 | void displayAgc(); 35 | void displayZoom(); 36 | void displayPan(); 37 | //Panel 3 buttons 38 | void displayMenu(); 39 | void displayANT(); 40 | void displayATU(); 41 | void displayXMIT(); 42 | void displayBandUp(); 43 | void displayBandDn(); 44 | //Panel 4 buttons 45 | void displayRIT(); 46 | void displayXIT(); 47 | void displayFine(); 48 | void displaySplit(); 49 | void displayDisplay(); 50 | void displayVFO_AB(); 51 | //Panel 5 buttons 52 | void displayEnet(); 53 | void displayXVTR(); 54 | void displayRFgain(); 55 | void displayRefLevel(); 56 | void displayAFgain(); 57 | void displayMute(); 58 | // Band Select Window 59 | void displayBand_Menu(uint8_t state); 60 | 61 | // pop up window controls 62 | void pop_win_up(uint8_t win_num); 63 | void pop_win_down(uint8_t win_num); 64 | 65 | void update_icon_outline(void); 66 | void displayClip(void); 67 | 68 | //void displaySpot(); // spare 69 | 70 | #endif //_DISPLAY_H_ -------------------------------------------------------------------------------- /SDR_RA8875/Hardware/4.3inch Motherboard PCB/K7MDL V2.1 Teensy 4.1 SDR Motherboard for 4.3in RA887 Displays.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/K7MDL2/KEITHSDR/833a58dfaaa263c2475ed974e0e84d75e244bb03/SDR_RA8875/Hardware/4.3inch Motherboard PCB/K7MDL V2.1 Teensy 4.1 SDR Motherboard for 4.3in RA887 Displays.jpg -------------------------------------------------------------------------------- /SDR_RA8875/Hardware/7inch Motherboard PCB/Gerber_PCB - Teensy RA8876 audio backpack V2.1 - 7 inch (1).zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/K7MDL2/KEITHSDR/833a58dfaaa263c2475ed974e0e84d75e244bb03/SDR_RA8875/Hardware/7inch Motherboard PCB/Gerber_PCB - Teensy RA8876 audio backpack V2.1 - 7 inch (1).zip -------------------------------------------------------------------------------- /SDR_RA8875/Hardware/7inch Motherboard PCB/K7MDL Teensy 4.1 SDR Motherboard for 7in and 4.3in RA8876-RA8875 Displays.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/K7MDL2/KEITHSDR/833a58dfaaa263c2475ed974e0e84d75e244bb03/SDR_RA8875/Hardware/7inch Motherboard PCB/K7MDL Teensy 4.1 SDR Motherboard for 7in and 4.3in RA8876-RA8875 Displays.jpg -------------------------------------------------------------------------------- /SDR_RA8875/Hardware/7inch Motherboard PCB/Schematic_V2-1_7-inch_Teensy_PCB_2022-12-24.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/K7MDL2/KEITHSDR/833a58dfaaa263c2475ed974e0e84d75e244bb03/SDR_RA8875/Hardware/7inch Motherboard PCB/Schematic_V2-1_7-inch_Teensy_PCB_2022-12-24.pdf -------------------------------------------------------------------------------- /SDR_RA8875/Hardware/7inch Motherboard PCB/Teensy Motherboard RA8876 V2.1 BOM 12-30-2022-NOT EXACT.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/K7MDL2/KEITHSDR/833a58dfaaa263c2475ed974e0e84d75e244bb03/SDR_RA8875/Hardware/7inch Motherboard PCB/Teensy Motherboard RA8876 V2.1 BOM 12-30-2022-NOT EXACT.xlsx -------------------------------------------------------------------------------- /SDR_RA8875/Hardware/7inch Motherboard PCB/V2.1 Teensy Motherboard DigiKey Order with Pricing (K7MDL Build) - 1-6-2023 -DRAFT.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/K7MDL2/KEITHSDR/833a58dfaaa263c2475ed974e0e84d75e244bb03/SDR_RA8875/Hardware/7inch Motherboard PCB/V2.1 Teensy Motherboard DigiKey Order with Pricing (K7MDL Build) - 1-6-2023 -DRAFT.xlsx -------------------------------------------------------------------------------- /SDR_RA8875/Hardware/Teensy_SDR_4-3_Inch_Front_Panel_V1 - no engraving - fixed origin.fpd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/K7MDL2/KEITHSDR/833a58dfaaa263c2475ed974e0e84d75e244bb03/SDR_RA8875/Hardware/Teensy_SDR_4-3_Inch_Front_Panel_V1 - no engraving - fixed origin.fpd -------------------------------------------------------------------------------- /SDR_RA8875/Mode.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Mode.cpp 3 | // 4 | #include "SDR_RA8875.h" 5 | #include "RadioConfig.h" 6 | //#include "Mode.h" 7 | 8 | extern AudioMixer4_F32 RX_Summer; 9 | extern AudioSwitch4_OA_F32 RxTx_InputSwitch_L; 10 | extern AudioSwitch4_OA_F32 RxTx_InputSwitch_R; 11 | extern int32_t ModeOffset; 12 | extern struct User_Settings user_settings[]; 13 | extern uint8_t user_Profile; 14 | 15 | COLD void selectMode(uint8_t mndx) // Change Mode of the current active VFO by increment delta. 16 | { 17 | ModeOffset = 0; // Holds displayed VFO offset based on CW mode pitch. 0 default for non-CW modes 18 | if(mndx == CW) 19 | { 20 | //mode="CW"; 21 | AudioNoInterrupts(); 22 | RX_Summer.gain(0, 1.0f); // Turn on non-FM 23 | RX_Summer.gain(1, 1.0f); 24 | RX_Summer.gain(3, 0.0f); // Turn off FM 25 | // Select our sources for the FFT. mode.h will change this so CW uses the output (for now as an experiment) 26 | RxTx_InputSwitch_L.setChannel(0); // Select RX path 27 | RxTx_InputSwitch_R.setChannel(0); // Select RX path 28 | AudioInterrupts(); 29 | ModeOffset = (int32_t) user_settings[user_Profile].pitch; // show shaded filter width on right side of center 30 | } 31 | 32 | if(mndx == CW_REV) 33 | { 34 | //mode="CW_REV; 35 | AudioNoInterrupts(); 36 | RX_Summer.gain(0, 1.0f); 37 | RX_Summer.gain(1, -1.0f); 38 | RX_Summer.gain(3, 0.0f); // Turn off FM 39 | // Select our sources for the FFT. mode.h will change this so CW uses the output (for now as an experiment) 40 | RxTx_InputSwitch_L.setChannel(0); // Select RX path 41 | RxTx_InputSwitch_R.setChannel(0); // Select RX path 42 | AudioInterrupts(); 43 | ModeOffset = -1 * (int32_t) user_settings[user_Profile].pitch; // show shaded filter width on left side of center 44 | } 45 | 46 | if(mndx == USB) 47 | { 48 | //mode="USB"; 49 | AudioNoInterrupts(); 50 | RX_Summer.gain(0, 1.0f); 51 | RX_Summer.gain(1, 1.0f); 52 | RX_Summer.gain(3, 0.0f); // Turn off FM 53 | // Select our sources for the FFT. mode.h will change this so CW uses the output (for now as an experiment) 54 | RxTx_InputSwitch_L.setChannel(0); // Select RX path 55 | RxTx_InputSwitch_R.setChannel(0); // Select RX path 56 | AudioInterrupts(); 57 | ModeOffset = 1; // show shaded filter width on right side of center 58 | } 59 | 60 | if(mndx == LSB) 61 | { 62 | //mode="LSB"; 63 | AudioNoInterrupts(); 64 | RX_Summer.gain(0, 1.0f); 65 | RX_Summer.gain(1, -1.0f); 66 | RX_Summer.gain(3, 0.0f); // Turn off FM 67 | // Select our sources for the FFT. mode.h will change this so CW uses the output (for now as an experiment) 68 | RxTx_InputSwitch_L.setChannel(0); // Select RX path 69 | RxTx_InputSwitch_R.setChannel(0); // Select RX path 70 | AudioInterrupts(); 71 | ModeOffset = -1; // show shaded filter width on left side of center 72 | } 73 | 74 | if(mndx == DATA) 75 | { 76 | //mode="DATA"; 77 | AudioNoInterrupts(); 78 | RX_Summer.gain(0, 1.0f); 79 | RX_Summer.gain(1, 1.0f); 80 | RX_Summer.gain(3, 0.0f); // Turn off FM 81 | // Select our sources for the FFT. mode.h will change this so CW uses the output (for now as an experiment) 82 | RxTx_InputSwitch_L.setChannel(0); // Select RX path 83 | RxTx_InputSwitch_R.setChannel(0); // Select RX path 84 | AudioInterrupts(); 85 | ModeOffset = 1; // show shaded filter width on right side of center 86 | NBLevel(-100); // Turn off NB for data modes 87 | } 88 | 89 | if(mndx == DATA_REV) 90 | { 91 | //mode="DATA_REV"; 92 | AudioNoInterrupts(); 93 | RX_Summer.gain(0, 1.0f); 94 | RX_Summer.gain(1, -1.0f); 95 | RX_Summer.gain(3, 0.0f); // Turn off FM 96 | // Select our sources for the FFT. mode.h will change this so CW uses the output (for now as an experiment) 97 | RxTx_InputSwitch_L.setChannel(0); // Select RX path 98 | RxTx_InputSwitch_R.setChannel(0); // Select RX path 99 | AudioInterrupts(); 100 | ModeOffset = -1; // show shaded filter width on left side of center 101 | NBLevel(-100); // Turn off NB for data modes 102 | } 103 | 104 | if(mndx == AM) 105 | { 106 | //mode="AM"; 107 | AudioNoInterrupts(); 108 | RX_Summer.gain(0, 1.0f); 109 | RX_Summer.gain(1, 1.0f); 110 | RX_Summer.gain(3, 0.0f); // Turn off FM 111 | // Select our sources for the FFT. mode.h will change this so CW uses the output (for now as an experiment) 112 | RxTx_InputSwitch_L.setChannel(0); // Select RX path 113 | RxTx_InputSwitch_R.setChannel(0); // Select RX path 114 | AudioInterrupts(); 115 | ModeOffset = 0; // show shaded filter width on both sides of center 116 | } 117 | 118 | if(mndx == FM) 119 | { 120 | //mode="FM"; 121 | AudioNoInterrupts(); 122 | RX_Summer.gain(0, 0.0f); 123 | RX_Summer.gain(1, 0.0f); // Turn off other modes 124 | RX_Summer.gain(3, 1.0f); // Select FM path 125 | RxTx_InputSwitch_L.setChannel(2); // Select FM path 126 | RxTx_InputSwitch_R.setChannel(2); // Shut off unused output (in this mode) 127 | AudioInterrupts(); 128 | ModeOffset = 0; // show shaded filter width on both sides of center 129 | NBLevel(-100); // Turn off NB for FM mode 130 | } 131 | 132 | //extern struct Modes_List modeList[]; 133 | //DPRINT("Set ModeOffset "); DPRINTLN(ModeOffset); 134 | //DPRINT("Set mode to "); DPRINTLN(modeList[mndx].mode_label); 135 | //displayMode(); 136 | } 137 | -------------------------------------------------------------------------------- /SDR_RA8875/Mode.h: -------------------------------------------------------------------------------- 1 | #ifndef _MODE_H_ 2 | #define _MODE_H_ 3 | // 4 | // Mode.h 5 | // 6 | #include 7 | 8 | void selectMode(uint8_t mndx); 9 | 10 | #endif //_MODE_H_ 11 | -------------------------------------------------------------------------------- /SDR_RA8875/Pictures/20210409_040442.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/K7MDL2/KEITHSDR/833a58dfaaa263c2475ed974e0e84d75e244bb03/SDR_RA8875/Pictures/20210409_040442.jpg -------------------------------------------------------------------------------- /SDR_RA8875/Pictures/20210420_172251.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/K7MDL2/KEITHSDR/833a58dfaaa263c2475ed974e0e84d75e244bb03/SDR_RA8875/Pictures/20210420_172251.jpg -------------------------------------------------------------------------------- /SDR_RA8875/Pictures/20210424_160849.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/K7MDL2/KEITHSDR/833a58dfaaa263c2475ed974e0e84d75e244bb03/SDR_RA8875/Pictures/20210424_160849.jpg -------------------------------------------------------------------------------- /SDR_RA8875/Pictures/20210425_181802.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/K7MDL2/KEITHSDR/833a58dfaaa263c2475ed974e0e84d75e244bb03/SDR_RA8875/Pictures/20210425_181802.jpg -------------------------------------------------------------------------------- /SDR_RA8875/Pictures/20231203_114901.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/K7MDL2/KEITHSDR/833a58dfaaa263c2475ed974e0e84d75e244bb03/SDR_RA8875/Pictures/20231203_114901.jpg -------------------------------------------------------------------------------- /SDR_RA8875/Pictures/20231203_114909.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/K7MDL2/KEITHSDR/833a58dfaaa263c2475ed974e0e84d75e244bb03/SDR_RA8875/Pictures/20231203_114909.jpg -------------------------------------------------------------------------------- /SDR_RA8875/Pictures/3-10-2021 ScreenShot.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/K7MDL2/KEITHSDR/833a58dfaaa263c2475ed974e0e84d75e244bb03/SDR_RA8875/Pictures/3-10-2021 ScreenShot.jpg -------------------------------------------------------------------------------- /SDR_RA8875/Pictures/3-25-2021 ScreenShot.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/K7MDL2/KEITHSDR/833a58dfaaa263c2475ed974e0e84d75e244bb03/SDR_RA8875/Pictures/3-25-2021 ScreenShot.jpg -------------------------------------------------------------------------------- /SDR_RA8875/Pictures/4.3inch Hammond Front Panel Milling-2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/K7MDL2/KEITHSDR/833a58dfaaa263c2475ed974e0e84d75e244bb03/SDR_RA8875/Pictures/4.3inch Hammond Front Panel Milling-2.jpg -------------------------------------------------------------------------------- /SDR_RA8875/Pictures/4.3inch Hammond Front Panel Milling.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/K7MDL2/KEITHSDR/833a58dfaaa263c2475ed974e0e84d75e244bb03/SDR_RA8875/Pictures/4.3inch Hammond Front Panel Milling.jpg -------------------------------------------------------------------------------- /SDR_RA8875/Pictures/7inch with x2 Zoom.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/K7MDL2/KEITHSDR/833a58dfaaa263c2475ed974e0e84d75e244bb03/SDR_RA8875/Pictures/7inch with x2 Zoom.jpg -------------------------------------------------------------------------------- /SDR_RA8875/Pictures/7inch with x4 Zoom.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/K7MDL2/KEITHSDR/833a58dfaaa263c2475ed974e0e84d75e244bb03/SDR_RA8875/Pictures/7inch with x4 Zoom.jpg -------------------------------------------------------------------------------- /SDR_RA8875/Pictures/K7MDL Teensy 4.1 SDR Motherboard for 7in and 4.3in RA8876-RA8875 Displays.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/K7MDL2/KEITHSDR/833a58dfaaa263c2475ed974e0e84d75e244bb03/SDR_RA8875/Pictures/K7MDL Teensy 4.1 SDR Motherboard for 7in and 4.3in RA8876-RA8875 Displays.jpg -------------------------------------------------------------------------------- /SDR_RA8875/Pictures/Teens_SDR_end_Panel-2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/K7MDL2/KEITHSDR/833a58dfaaa263c2475ed974e0e84d75e244bb03/SDR_RA8875/Pictures/Teens_SDR_end_Panel-2.jpg -------------------------------------------------------------------------------- /SDR_RA8875/Pictures/Teensy SDR 7inch under construction DEC 2022.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/K7MDL2/KEITHSDR/833a58dfaaa263c2475ed974e0e84d75e244bb03/SDR_RA8875/Pictures/Teensy SDR 7inch under construction DEC 2022.jpg -------------------------------------------------------------------------------- /SDR_RA8875/Pictures/Teensy SDR V2.1 PCB - assembled.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/K7MDL2/KEITHSDR/833a58dfaaa263c2475ed974e0e84d75e244bb03/SDR_RA8875/Pictures/Teensy SDR V2.1 PCB - assembled.jpg -------------------------------------------------------------------------------- /SDR_RA8875/Pictures/Teensy SDR V2.2 Motherboard - Feb 2023.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/K7MDL2/KEITHSDR/833a58dfaaa263c2475ed974e0e84d75e244bb03/SDR_RA8875/Pictures/Teensy SDR V2.2 Motherboard - Feb 2023.jpg -------------------------------------------------------------------------------- /SDR_RA8875/Pictures/Teensy SDR in Hammond Case.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/K7MDL2/KEITHSDR/833a58dfaaa263c2475ed974e0e84d75e244bb03/SDR_RA8875/Pictures/Teensy SDR in Hammond Case.jpg -------------------------------------------------------------------------------- /SDR_RA8875/Pictures/TeensySDR in Hammond 1455N1601-1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/K7MDL2/KEITHSDR/833a58dfaaa263c2475ed974e0e84d75e244bb03/SDR_RA8875/Pictures/TeensySDR in Hammond 1455N1601-1.jpg -------------------------------------------------------------------------------- /SDR_RA8875/Pictures/TeensySDR in Hammond 1455N1601-2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/K7MDL2/KEITHSDR/833a58dfaaa263c2475ed974e0e84d75e244bb03/SDR_RA8875/Pictures/TeensySDR in Hammond 1455N1601-2.jpg -------------------------------------------------------------------------------- /SDR_RA8875/Pictures/TeensySDR in Hammond 1455N1601-End_View.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/K7MDL2/KEITHSDR/833a58dfaaa263c2475ed974e0e84d75e244bb03/SDR_RA8875/Pictures/TeensySDR in Hammond 1455N1601-End_View.jpg -------------------------------------------------------------------------------- /SDR_RA8875/Pictures/TeensySDR in Hammond 1455N1601-Front-1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/K7MDL2/KEITHSDR/833a58dfaaa263c2475ed974e0e84d75e244bb03/SDR_RA8875/Pictures/TeensySDR in Hammond 1455N1601-Front-1.jpg -------------------------------------------------------------------------------- /SDR_RA8875/Pictures/TeensySDR in Hammond 1455N1601-Front.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/K7MDL2/KEITHSDR/833a58dfaaa263c2475ed974e0e84d75e244bb03/SDR_RA8875/Pictures/TeensySDR in Hammond 1455N1601-Front.jpg -------------------------------------------------------------------------------- /SDR_RA8875/Pictures/TeensySDR in Hammond 1455N1601-USB Host connection to Nano.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/K7MDL2/KEITHSDR/833a58dfaaa263c2475ed974e0e84d75e244bb03/SDR_RA8875/Pictures/TeensySDR in Hammond 1455N1601-USB Host connection to Nano.jpg -------------------------------------------------------------------------------- /SDR_RA8875/Pictures/Teensy_SDR_end_panel_1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/K7MDL2/KEITHSDR/833a58dfaaa263c2475ed974e0e84d75e244bb03/SDR_RA8875/Pictures/Teensy_SDR_end_panel_1.jpg -------------------------------------------------------------------------------- /SDR_RA8875/SDR_CAT.h: -------------------------------------------------------------------------------- 1 | #ifndef _SDR_CAT_H_ 2 | #define _SDR_CAT_H_ 3 | // 4 | // SDR_CAT.h 5 | // 6 | // Serial port control protocol useful for control head and panadapter information exchange. 7 | // 8 | // 9 | #include "SDR_RA8875.h" 10 | #include "RadioConfig.h" 11 | 12 | #ifndef USE_CAT_SER 13 | #ifdef PAN_CAT 14 | 15 | void CAT_handler(void); 16 | void CAT_setup(void); 17 | void print_CAT_status(void); 18 | void init_CAT_comms(void); 19 | 20 | #endif 21 | #endif // ! USE_CAT_SER 22 | 23 | #endif // _SDR_CAT_H_ 24 | -------------------------------------------------------------------------------- /SDR_RA8875/SDR_CAT_Serial.cpp: -------------------------------------------------------------------------------- 1 | //*************************************************************************************************** 2 | // 3 | // SDR_CAT_Serial.cpp 4 | // 5 | // SDR_CAT_Serial Class for CAT side interface using Elecraft K3/Kenwood CAT protocol to enable programs 6 | // like WSJT-X Hamlib interface to set split and follow BAND/VFO changes from the radio side. 7 | // Accepts expanded set of CAT port commands such as *FA, *FB, *SW0, etc. for Elecraft K3 protocol 8 | // and passes back these controls to the main program. 9 | // 10 | // Called to parse CA serial message by RS-HFIQ and non-RSHFIQ configurations 11 | // 12 | // Feb 3, 2023 by K7MDL 13 | // 14 | // Placed in the Public Domain. 15 | // 16 | //*************************************************************************************************** 17 | #include 18 | #include "RadioConfig.h" 19 | #include "SDR_RA8875.h" 20 | #include "SDR_CAT_Serial.h" 21 | 22 | #ifdef USE_CAT_SER 23 | #ifndef USE_RS_HFIQ 24 | 25 | //#define DBG 26 | //#define DEBUG_CAT //set to true for debug output, false for no debug output 27 | 28 | #ifdef DEBUG_CAT 29 | //#define DSERIALBEGIN(...) Serial.begin(__VA_ARGS__) 30 | //#define DPRINTLN(...) Serial.println(__VA_ARGS__) 31 | //#define DPRINT(...) Serial.print(__VA_ARGS__) 32 | //#define DRINTF(...) Serial.print(F(__VA_ARGS__)) 33 | //#define DPRINTLNF(...) Serial.println(F(__VA_ARGS__)) //printing text using the F macro 34 | //#define DELAY(...) delay(__VA_ARGS__) 35 | //#define PINMODE(...) pinMode(__VA_ARGS__) 36 | //#define TOGGLEd13 PINB = 0x20 //UNO's pin D13 37 | #define DEBUG_PRINT(...) Serial.print(F(#__VA_ARGS__" = ")); Serial.print(__VA_ARGS__); Serial.print(F(" ")) 38 | #define DEBUG_PRINTLN(...) DEBUG_PRINT(__VA_ARGS__); Serial.println() 39 | #define DEBUG_PRINTF(...) Serial.printf(__VA_ARGS__) 40 | #else 41 | //#define DSERIALBEGIN(...) 42 | //#define DPRINTLN(...) 43 | //#define DPRINT(...) 44 | //#define DPRINTF(...) 45 | //#define DPRINTLNF(...) 46 | //#define DELAY(...) 47 | //#define PINMODE(...) 48 | //#define TOGGLEd13 49 | //#define DEBUG_PRINT(...) 50 | //#define DEBUG_PRINTLN(...) 51 | //#define DEBUG_PRINTF(...) 52 | #endif 53 | 54 | 55 | #ifdef USE_RA8875 56 | extern RA8875 tft; 57 | #else 58 | extern RA8876_t3 tft; 59 | #endif 60 | 61 | // Serial port for external CAT control 62 | #ifndef ALT_CAT_PORT 63 | #define CAT_port SerialUSB1 // if you have 2 serial ports. Make this the 2nd. 64 | #else 65 | #define CAT_port Serial // if you only have 1 serial port and want CAT, turn off DEBUG and use this. 66 | #endif 67 | 68 | uint64_t rs_freq; 69 | static char S_Input[20]; 70 | 71 | extern struct User_Settings user_settings[]; 72 | extern uint8_t user_Profile; 73 | extern struct Band_Memory bandmem[]; 74 | extern uint8_t curr_band; // global tracks our current band setting. 75 | extern uint64_t find_new_band(uint64_t new_frequency, uint8_t &_curr_band); 76 | 77 | // ************************************************* Setup ***************************************** 78 | // 79 | // ************************************************************************************************* 80 | void SDR_CAT_Serial::setup_CAT_Serial() // 0 non block, 1 blocking 81 | { 82 | CAT_port.begin(38400); 83 | DPRINTLNF("\nStart of CAT Serial Setup"); 84 | tft.setFont(Arial_14); 85 | tft.setTextColor(BLUE); 86 | tft.setCursor(60, 320); 87 | tft.print(F("Waiting for connection to USB port - Is it connected?")); 88 | delay(1000); 89 | 90 | DPRINTLNF("End of CAT Serial Setup"); 91 | } 92 | 93 | // The RS-HFIQ has only 1 "VFO" so does not itself care about VFO A or B or split, or which is active 94 | // However this is also the CAT interface and commands will come down for such things. 95 | // We need to act on the active VFO and pass back the info needed to the calling program. 96 | uint64_t SDR_CAT_Serial::cmd_console(uint8_t &_swap_vfo, uint64_t &_VFOA, uint64_t &_VFOB, uint8_t &_curr_band, uint8_t &_xmit, uint8_t &_split, uint8_t &_mode, uint8_t &_clip) // returns new or unchanged active VFO value 97 | { 98 | char c; 99 | //static unsigned char Ser_Flag = 0, Ser_NDX = 0; 100 | static uint8_t swap_vfo_last = 0; 101 | static uint8_t _ai = 0; // track AI mode 102 | 103 | rs_freq = _VFOA; 104 | 105 | while (CAT_port.available() > 0) // Process any and all characters in the buffer 106 | { 107 | c = CAT_port.readBytesUntil(';',S_Input, 15); // c is length of string 108 | //CAT_port.print("SDR_CAT_Serial: c = "); CAT_port.print(c); 109 | 110 | if (c>0) 111 | { 112 | #ifdef DBG 113 | DPRINTF("SDR_CAT_Serial: Cmd String = "); DPRINTLN(S_Input); 114 | #endif 115 | if (!strncmp(S_Input, "ID", 2)) 116 | { 117 | CAT_port.print("ID017;"); 118 | } 119 | else if (!strncmp(S_Input, "OM", 2)) // && c == 13) 120 | { 121 | CAT_port.print("OM ------------;"); 122 | } 123 | else if (!strncmp(S_Input, "K20", 3)) // && strlen(S_Input) == 2) // && c == 13) 124 | { 125 | //CAT_port.print("K20;"); 126 | } 127 | else if (!strncmp(S_Input, "K22", 3)) // && strlen(S_Input) == 2) // && c == 13) 128 | { 129 | //CAT_port.print("K22;"); 130 | } 131 | else if (!strncmp(S_Input, "K2", 2)) // && strlen(S_Input) == 2) // && c == 13) 132 | { 133 | CAT_port.print("K20;"); 134 | } 135 | else if (!strncmp(S_Input, "K3", 2)) //&& strlen(S_Input) == 2) // && c == 13) 136 | { 137 | CAT_port.print("K30;"); 138 | } 139 | else if (!strncmp(S_Input, "RVM", 3)&& strlen(S_Input) == 3) 140 | { 141 | CAT_port.print("RVM05.67;"); 142 | } 143 | else if (!strncmp(S_Input, "RVD", 3)&& strlen(S_Input) == 3) 144 | { 145 | CAT_port.print("RVD02.88;"); 146 | } 147 | else if (!strncmp(S_Input, "RVA", 3)&& strlen(S_Input) == 3) 148 | { 149 | CAT_port.print("RVA99.99;"); 150 | } 151 | else if (!strncmp(S_Input, "RVR", 3)&& strlen(S_Input) == 3) 152 | { 153 | CAT_port.print("RVR99.99;"); 154 | } 155 | else if (!strncmp(S_Input, "RVF", 3)&& strlen(S_Input) == 3) 156 | { 157 | CAT_port.print("RVF01.26;"); 158 | } 159 | else if (!strncmp(S_Input, "BW", 2) && strlen(S_Input) == 2) 160 | { 161 | CAT_port.print("BW4000;"); 162 | } 163 | else if (!strncmp(S_Input, "BW$", 3) && strlen(S_Input) == 3) 164 | { 165 | CAT_port.print("BW$4000;"); 166 | } 167 | else if (!strncmp(S_Input, "LN", 2) && strlen(S_Input) == 2) 168 | { 169 | CAT_port.print("LN0;"); 170 | } 171 | else if (!strncmp(S_Input, "PS", 2) && strlen(S_Input) == 2) 172 | { 173 | CAT_port.print("PS1;"); // radio is turned on 174 | } 175 | else if (!strncmp(S_Input, "FR", 2) && strlen(S_Input) == 2) 176 | { 177 | CAT_port.print("FR0;"); 178 | } 179 | else if (!strncmp(S_Input, "FT", 2) && strlen(S_Input) == 2) 180 | { 181 | if (_split == 0) CAT_port.print("FT0;"); 182 | else CAT_port.print("FT1;"); 183 | } 184 | else if (!strncmp(S_Input, "FR0", 3) && strlen(S_Input) == 3) // Split OFF 185 | { 186 | _split = 0; 187 | #ifdef DBG 188 | DPRINTLNF("SDR_CAT_Serial: Split Mode OFF"); 189 | #endif 190 | } 191 | else if (!strncmp(S_Input, "FT1", 3) && strlen(S_Input) == 3) // Split ON 192 | { 193 | _split = 1; 194 | #ifdef DBG 195 | DPRINTLNF("SDR_CAT_Serial: Split Mode ON VFOB=TX"); 196 | #endif 197 | } 198 | else if (!strncmp(S_Input, "FT0", 3) && strlen(S_Input) == 3) // Split ON 199 | { 200 | _split = 0; 201 | #ifdef DBG 202 | DPRINTLNF("SDR_CAT_Serial: Split Mode ON VFOA=TX"); 203 | #endif 204 | } 205 | else if (!strncmp(S_Input, "DT", 2) && strlen(S_Input) == 2) 206 | { 207 | CAT_port.print("DT0;"); // return 0 = DATA A mode 208 | } 209 | else if (!strncmp(S_Input, "FI", 2) && strlen(S_Input) == 2) 210 | { 211 | CAT_port.print("FI5000;"); // last 4 digits of the IF cener frequency used for shifting panadapater. 212 | } 213 | else if (!strncmp(S_Input, "AI", 2) && strlen(S_Input) == 2) 214 | { 215 | CAT_port.printf("AI%1d;", _ai); // return current AI mode 216 | } 217 | else if (!strncmp(S_Input, "AI0", 3) && strlen(S_Input) == 3) 218 | { 219 | _ai = 0; 220 | //CAT_port.print("AI0;"); 221 | } 222 | else if (!strncmp(S_Input, "AI1", 3) && strlen(S_Input) == 3) 223 | { 224 | _ai = 1; 225 | CAT_port.printf("IF%011llu -000000 00%d600%d001 ;", rs_freq, user_settings[user_Profile].xmit, _split); 226 | } 227 | else if (!strncmp(S_Input, "AI2", 3) && strlen(S_Input) == 3) 228 | { 229 | _ai = 2; 230 | //CAT_port.print("AI2;"); 231 | //CAT_port.printf("IF%011llu -000000 00%d600%d001 ;", rs_freq, user_settings[user_Profile].xmit, *split); 232 | } 233 | else if (!strncmp(S_Input, "IF", 2)) // Transceiver Info 234 | { 235 | CAT_port.printf("IF%011llu -000000 00%d600%d001 ;", rs_freq, user_settings[user_Profile].xmit, _split); 236 | } 237 | else if (!strncmp(S_Input, "KS", 2)) // Keyer Speed. Fake it at 12wpm 238 | { 239 | CAT_port.printf("KS012;"); 240 | } 241 | else if ((!strncmp(S_Input, "MD$", 3) && (strlen(S_Input) == 3)) || (!strncmp(S_Input, "MD", 2) && (strlen(S_Input) == 2))) // report Radio current Mode per K3 numbering 242 | { 243 | uint8_t _mode_ = 0; 244 | 245 | switch (_mode) 246 | { 247 | case LSB: _mode_ = 1; break; 248 | case USB: _mode_ = 2;; break; 249 | case CW: _mode_ = 3; break; 250 | case FM: _mode_ = 4; break; 251 | case AM: _mode_ = 5; break; 252 | case DATA: _mode_ = 6; break; 253 | case CW_REV: _mode_ = 7; break; 254 | case DATA_REV: _mode_ = 9; break; 255 | default: break; 256 | } 257 | 258 | if (!strncmp(S_Input, "MD$", 3)) 259 | CAT_port.printf("MD$%d;", _mode_); 260 | else 261 | CAT_port.printf("MD%d;", _mode_); 262 | } 263 | else if ((!strncmp(S_Input, "MD", 2) && strlen(S_Input) == 3) || (!strncmp(S_Input, "MD$", 3) && (strlen(S_Input) == 4))) // map incoming mode change request from K3 values to our mode numbering and return the value 264 | { 265 | uint8_t _mode_ = 0; 266 | 267 | if (S_Input[2] == '$') 268 | _mode_ = S_Input[3]; 269 | else 270 | _mode_ = S_Input[2]; 271 | 272 | switch (_mode_) 273 | { 274 | case '1': _mode = LSB; break; 275 | case '2': _mode = USB; break; 276 | case '3': _mode = CW; break; 277 | case '4': _mode = FM; break; 278 | case '5': _mode = AM; break; 279 | case '6': _mode = DATA; break; 280 | case '7': _mode = CW_REV; break; 281 | case '9': _mode = DATA_REV; break; 282 | default: break; 283 | } 284 | } 285 | else if (!strncmp(S_Input, "FA", 2) && strlen(S_Input) == 2) 286 | { 287 | CAT_port.printf("FA%011llu;", _VFOA); // Respond back for confirmation FA + 11 freq + ; 288 | } 289 | else if (!strncmp(S_Input, "FB", 2) && strlen(S_Input) == 2) 290 | { 291 | CAT_port.printf("FB%011llu;", _VFOB); // Respond back for confirmation FA + 11 freq + ; 292 | } 293 | else if (!strncmp(S_Input, "FA", 2) && strlen(S_Input) > 2) 294 | { 295 | _VFOA = rs_freq = atoll(&S_Input[2]); // Pass thru to main program to deal with and reply back to CAT program 296 | } 297 | else if (!strncmp(S_Input, "FB", 2) && strlen(S_Input) > 2) 298 | { 299 | _VFOB = rs_freq = atoll(&S_Input[2]); // Pass thru to main program to deal with and reply back to CAT program 300 | } 301 | else if (!strncmp(S_Input, "RX", 2)) 302 | { 303 | #ifdef DBG 304 | DPRINTLN(F("SDR_CAT_Serial: RX->XMIT OFF")); 305 | #endif 306 | _xmit = 0; 307 | } 308 | else if (!strncmp(S_Input, "TX", 2)) 309 | { 310 | #ifdef DBG 311 | DPRINTLN(F("SDR_CAT_Serial: TX->XMIT ON")); 312 | #endif 313 | _xmit = 1; 314 | } 315 | else if (!strncmp(S_Input, "SW0", 3)) 316 | { 317 | if (swap_vfo_last) 318 | swap_vfo_last = 0; 319 | else 320 | swap_vfo_last = 1; 321 | _swap_vfo = swap_vfo_last; 322 | #ifdef DBG 323 | DPRINT(F("SDR_CAT_Serial: Swap VFOs: ")); DPRINTLN(_swap_vfo); 324 | #endif 325 | } 326 | } 327 | } 328 | S_Input[0] = '\0'; 329 | for (int z = 0; z < 16; z++) // Fill the buffer with spaces 330 | S_Input[z] = '\0'; 331 | //Ser_Flag = 0; 332 | S_Input[0] = '\0'; 333 | c=0; 334 | CAT_port.flush(); 335 | //DPRINTF("rs_freq = "); DPRINTLN(rs_freq); 336 | //DPRINTF("_VFOA = "); DPRINTLN(_VFOA); 337 | return rs_freq; 338 | } 339 | 340 | #endif //USE_RS_HFIQ 341 | #endif //USE_CAT_SER -------------------------------------------------------------------------------- /SDR_RA8875/SDR_CAT_Serial.h: -------------------------------------------------------------------------------- 1 | // 2 | // SDR_CAT_Serial.h 3 | // 4 | // Generic Hamlib compatible K3/Kenwood CAT cpontrol message parser 5 | // 6 | // CAT Serial control library 7 | // Feb 3, 2023 by K7MDL 8 | // 9 | // Placed in the Public Domain 10 | // 11 | // 12 | 13 | #ifndef _SDR_CAT_SERIAL_H_ 14 | #define _SDR_CAT_SERIAL_H_ 15 | 16 | #ifdef USE_CAT_SER 17 | #ifndef USE_RS_HFIQ 18 | 19 | #include 20 | 21 | class SDR_CAT_Serial 22 | { 23 | public: 24 | SDR_CAT_Serial() // -- Place any args here -- 25 | // Place functions here if needed --- 26 | {} // Copy arguments to local variables 27 | // publish externally available functions 28 | uint64_t cmd_console(uint8_t &_swap_vfo, uint64_t &_VFOA, uint64_t &_VFOB, uint8_t &_curr_band, uint8_t &_xmit, uint8_t &_split, uint8_t &_mode, uint8_t &_clip); // returns new or unchanged active VFO value 29 | // returns new or unchanged VFO value and modified band index and other parameters 30 | void setup_CAT_Serial(void); 31 | //void send_variable_cmd_to_RSHFIQ(const char * str, char * cmd_str); 32 | char * convert_freq_to_Str(uint64_t freq); 33 | //void send_fixed_cmd_to_RSHFIQ(const char * str); 34 | uint64_t find_new_band(uint64_t new_frequency, uint8_t &_curr_band); // Validate frequency is RS-HFIQ comtaptible and retured band and frequency 35 | // If freq is out of RS-HFIQ band then the freq returned is 0; 36 | //void print_RSHFIQ(int flag); // reads response from RS-HFIQ and prints to the CAT terminal 37 | //void print_RSHFIQ_User(int flag); // reads response from RS-HFIQ and prints to the user terminal 38 | 39 | private: 40 | char freq_str[22] = "7074000"; // *Fxxxx command to set LO freq, PLL Clock 0 41 | 42 | //bool refresh_RSHFIQ(void); 43 | //void init_PLL(void); 44 | //void wait_reply(int blocking); // BLOCKING CALL! Use with care 45 | //void update_VFOs(uint64_t newfreq); 46 | //void write_RSHFIQ(int ch); 47 | //int read_RSHFIQ(int flag); 48 | }; 49 | #endif //USE_RS_HFIQ 50 | #endif //USE_CAT_SER 51 | #endif // _SDR_CAT_SERIAL_H_ 52 | -------------------------------------------------------------------------------- /SDR_RA8875/SDR_I2C_Encoder.h: -------------------------------------------------------------------------------- 1 | #ifndef _SDR_I2C_Encoder_H_ 2 | #define _SDR_I2C_Encoder_H_ 3 | // 4 | // SDR_I2C_Encoder.h 5 | // 6 | // A collection of I2C encoder functions. 7 | // Setup for each encoder 8 | // Interrupt driven callback back function that do something when tehre is a pus or turn event. 9 | // Also has a range of RGB LED light effects 10 | // 11 | #include 12 | #include 13 | //#include "RadioConfig.h" 14 | 15 | // These are the per-encoder function declarations 16 | #ifdef I2C_ENC1_ADDR 17 | void blink_I2C_ENC1_RGB(void); 18 | #endif 19 | #ifdef I2C_ENC2_ADDR 20 | void blink_I2C_ENC2_RGB(void); 21 | #endif 22 | #ifdef I2C_ENC3_ADDR 23 | void blink_I2C_ENC3_RGB(void); 24 | #endif 25 | #ifdef I2C_ENC4_ADDR 26 | void blink_I2C_ENC4_RGB(void); 27 | #endif 28 | #ifdef I2C_ENC5_ADDR 29 | void blink_I2C_ENC5_RGB(void); 30 | #endif 31 | #ifdef I2C_ENC6_ADDR 32 | void blink_I2C_ENC6_RGB(void); 33 | #endif 34 | void set_I2CEncoders(void); 35 | 36 | // These are generic callback functions - meaning when a hardware event occurs these functions are 37 | // called with the info associated with that encoder. We can assing each encoder to things like AF and RF gain. 38 | void i2c_encoder_rotated(i2cEncoderLibV2* obj); 39 | void i2c_switch_click(i2cEncoderLibV2* obj, uint8_t slot); 40 | void i2c_encoder_thresholds(i2cEncoderLibV2* obj, uint8_t slot); 41 | void gpio_switch_timer_start(uint8_t _id); 42 | void gpio_switch_click(uint8_t _id); 43 | void gpio_encoder_rotated(i2cEncoderLibV2* obj, int32_t count); 44 | 45 | #endif // _SDR_I2C_Encoder_H_ 46 | -------------------------------------------------------------------------------- /SDR_RA8875/SDR_Network.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // SDR_Network.cpp 3 | // 4 | // Contains ethernet code for the SDR. 5 | // Goal is to use UDP messages to connect a control head to the SDR base rig. 6 | // The FFT output and 2-way control messages are passed over UDP. 7 | // Audio connection to the control head will for now be analog. 8 | // The Control head could be another Teensy/arduino with display, or a PC client app. 9 | // 10 | #include "RadioConfig.h" 11 | #include "SDR_RA8875.h" 12 | //#include "SDR_Network.h" 13 | 14 | #ifdef ENET // Skip all of this file if no enet 15 | 16 | #include 17 | #include 18 | #include 19 | 20 | extern tmElements_t tm; 21 | 22 | #define TX_BUFFER_SIZE 4100 23 | #define RX_BUFFER_SIZE 255 24 | // Choose or create your desired time zone offset or use 0 for UTC. 25 | //const int timeZone = 1; // Central European Time 26 | const int timeZone = 0; // UTC 27 | //const int timeZone = -5; // Eastern Standard Time (USA) 28 | //const int timeZone = -4; // Eastern Daylight Time (USA) 29 | //const int timeZone = -8; // Pacific Standard Time (USA) 30 | //const int timeZone = -7; // Pacific Daylight Time (USA) 31 | 32 | // Enter a MAC address and IP address for your controller below. MAC not required for Teensy cause we are using TeensyMAC function. 33 | // The IP address will be dependent on your local network: don't need this since we can automatically figure ou tthe mac 34 | //byte mac[] = { 35 | // 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xEC 36 | //}; 37 | 38 | // Choose to use DHCP or a static IP address for the SDR - set in RadioConfig.h 39 | #ifndef USE_DHCP 40 | // The IP Address is ignored if using DHCP 41 | IPAddress ip(192, 168, 1, 237); // Our static IP address. Could use DHCP but preferring static address. 42 | IPAddress dns(192, 168, 1, 1); // Our static IP address. Could use DHCP but preferring static address. 43 | IPAddress gateway(192, 168, 1, 1); // Our static IP address. Could use DHCP but preferring static address. 44 | #endif // USE_DHCP 45 | 46 | unsigned int localPort = MY_LOCAL_PORTNUM; // local port to LISTEN for the remote display/Desktop app 47 | 48 | //#define REMOTE_OPS - conditionally defined in main header file for now 49 | #ifdef REMOTE_OPS 50 | // This is for later remote operation usage 51 | //Udp.beginPacket(Udp.remoteIP(), Udp.remotePort()); 52 | IPAddress remote_ip(192, 168, 1, 7); // Destination IP (desktop app or remote display Arduino) 53 | unsigned int remoteport = MY_REMOTE_PORTNUM; // The destination port to SENDTO (a remote display or Desktop app) 54 | #endif // REMOTE_OPS 55 | 56 | // This is for the NTP service to update the clock when connected to the internet 57 | unsigned int localPort_NTP = 8888; // Local port to listen for UDP packets 58 | const char timeServer[] = "time.nist.gov"; // time.nist.gov NTP server 59 | extern time_t prevDisplay; // When the digital clock was displayed 60 | 61 | // function declarations 62 | void toggle_enet_data_out(uint8_t mode); 63 | uint8_t enet_write(uint8_t *tx_buffer, const int count); 64 | uint8_t enet_read(void); 65 | void teensyMAC(uint8_t *mac); 66 | void enet_start(void); 67 | 68 | // NTP client time setup 69 | time_t getNtpTime(); 70 | void sendNTPpacket(const char * address); 71 | //void RX_NTP_time(void); 72 | 73 | const int NTP_PACKET_SIZE = 48; // NTP time stamp is in the first 48 bytes of the message 74 | byte packetBuffer_NTP[NTP_PACKET_SIZE]; //buffer to hold incoming and outgoing packets 75 | // A UDP instance to let us send and receive packets over UDP 76 | EthernetUDP Udp_NTP; 77 | 78 | // SDR network setup 79 | // buffers for receiving and sending data 80 | char packetBuffer[UDP_TX_PACKET_MAX_SIZE]; // buffer to hold incoming packet, 81 | char ReplyBuffer[] = "Random Reply"; // a string to send back 82 | 83 | // our variables 84 | uint8_t enet_ready = 0; 85 | unsigned long enet_start_fail_time = 0; 86 | uint8_t rx_buffer[RX_BUFFER_SIZE]; 87 | uint8_t tx_buffer[TX_BUFFER_SIZE]; 88 | uint8_t rx_count = 0; 89 | uint8_t tx_count = 0; 90 | uint8_t enet_data_out = 0; 91 | uint8_t sdata[RX_BUFFER_SIZE], *pSdata1=sdata, *pSdata2=sdata; 92 | extern uint8_t user_Profile; 93 | extern uint8_t NTP_hour; //NTP time 94 | extern uint8_t NTP_min; 95 | extern uint8_t NTP_sec; 96 | extern void displayTime(void); 97 | extern const int timeZone; 98 | extern uint8_t user_Profile; // global tracks our current user profile 99 | extern struct User_Settings user_settings[]; 100 | 101 | // An EthernetUDP instance to let us send and receive packets over UDP 102 | EthernetUDP Udp; 103 | 104 | // Toggle UDP output data 105 | COLD void toggle_enet_data_out(uint8_t mode) 106 | { 107 | if (mode == 1) 108 | enet_data_out = 1; 109 | if (mode ==0) 110 | enet_data_out = 0; 111 | if (mode ==2){ 112 | if (enet_data_out == 0) 113 | enet_data_out = 1; 114 | else 115 | enet_data_out = 0; 116 | } 117 | if (enet_data_out == 1){ 118 | user_settings[user_Profile].enet_output = ON; 119 | DPRINTLN(">Enabled UDP Data Output"); 120 | } 121 | else { 122 | user_settings[user_Profile].enet_output = OFF; 123 | DPRINTLN(">Disabled UDP Data Output"); 124 | } 125 | } 126 | 127 | COLD void teensyMAC(uint8_t *mac) 128 | { 129 | static char teensyMac[23]; 130 | 131 | #if defined (HW_OCOTP_MAC1) && defined(HW_OCOTP_MAC0) 132 | DPRINTLN("using HW_OCOTP_MAC* - see https://forum.pjrc.com/threads/57595-Serial-amp-MAC-Address-Teensy-4-0"); 133 | for(uint8_t by=0; by<2; by++) mac[by]=(HW_OCOTP_MAC1 >> ((1-by)*8)) & 0xFF; 134 | for(uint8_t by=0; by<4; by++) mac[by+2]=(HW_OCOTP_MAC0 >> ((3-by)*8)) & 0xFF; 135 | 136 | #define MAC_OK 137 | 138 | #else 139 | 140 | mac[0] = 0x04; 141 | mac[1] = 0xE9; 142 | mac[2] = 0xE5; 143 | 144 | uint32_t SN=0; 145 | __disable_irq(); 146 | 147 | #if defined(HAS_KINETIS_FLASH_FTFA) || defined(HAS_KINETIS_FLASH_FTFL) 148 | DPRINTLN("using FTFL_FSTAT_FTFA - vis teensyID.h - see https://github.com/sstaub/TeensyID/blob/master/TeensyID.h"); 149 | 150 | FTFL_FSTAT = FTFL_FSTAT_RDCOLERR | FTFL_FSTAT_ACCERR | FTFL_FSTAT_FPVIOL; 151 | FTFL_FCCOB0 = 0x41; 152 | FTFL_FCCOB1 = 15; 153 | FTFL_FSTAT = FTFL_FSTAT_CCIF; 154 | while (!(FTFL_FSTAT & FTFL_FSTAT_CCIF)) ; // wait 155 | SN = *(uint32_t *)&FTFL_FCCOB7; 156 | 157 | #define MAC_OK 158 | 159 | #elif defined(HAS_KINETIS_FLASH_FTFE) 160 | DPRINTLN("using FTFL_FSTAT_FTFE - vis teensyID.h - see https://github.com/sstaub/TeensyID/blob/master/TeensyID.h"); 161 | 162 | kinetis_hsrun_disable(); 163 | FTFL_FSTAT = FTFL_FSTAT_RDCOLERR | FTFL_FSTAT_ACCERR | FTFL_FSTAT_FPVIOL; 164 | *(uint32_t *)&FTFL_FCCOB3 = 0x41070000; 165 | FTFL_FSTAT = FTFL_FSTAT_CCIF; 166 | while (!(FTFL_FSTAT & FTFL_FSTAT_CCIF)) ; // wait 167 | SN = *(uint32_t *)&FTFL_FCCOBB; 168 | kinetis_hsrun_enable(); 169 | 170 | #define MAC_OK 171 | 172 | #endif 173 | 174 | __enable_irq(); 175 | 176 | for(uint8_t by=0; by<3; by++) mac[by+3]=(SN >> ((2-by)*8)) & 0xFF; 177 | 178 | #endif 179 | 180 | #ifdef MAC_OK 181 | sprintf(teensyMac, "MAC: %02x:%02x:%02x:%02x:%02x:%02x", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); 182 | DPRINTLN(teensyMac); 183 | #else 184 | DPRINTLN("ERROR: could not get MAC"); 185 | #endif 186 | } 187 | 188 | HOT uint8_t enet_read(void) 189 | { 190 | if (enet_ready && user_settings[user_Profile].enet_enabled) 191 | { 192 | // experiment with this --> udp.listen( true ); // and wait for incoming messag 193 | 194 | rx_count = 0; 195 | int count = 0; 196 | 197 | // if there's data available, read a packet 198 | count = Udp.parsePacket(); 199 | rx_buffer[0] = _NULL; 200 | if (count > 0) 201 | { 202 | Udp.read(rx_buffer, RX_BUFFER_SIZE); 203 | rx_buffer[count] = '\0'; 204 | rx_count = count; 205 | DPRINTLN(rx_count); 206 | DPRINTLN((char *) rx_buffer); 207 | 208 | // initially p1 = p2. parser will move p1 up to p2 and when they are equal, buffer is empty, parser will reset p1 and p2 back to start of sData 209 | memcpy(pSdata2, rx_buffer, rx_count+1); // append the new buffer data to current end marked by pointer 2 210 | pSdata2 += rx_count; // Update the end pointer position. The function processing chars will update the p1 and p2 pointer 211 | rx_count = pSdata2 - pSdata1; // update count for total unread chars. 212 | //DPRINTLN(rx_count); 213 | } 214 | rx_buffer[0] = '\0'; 215 | return rx_count; 216 | } 217 | return 0; 218 | } 219 | 220 | HOT uint8_t enet_write(uint8_t *tx_buffer, const int count) //, uint16_t tx_count) 221 | { 222 | #ifdef REMOTE_OPS 223 | if (enet_ready && user_settings[user_Profile].enet_enabled && user_settings[user_Profile].enet_output) // skip if no enet connection 224 | { 225 | //DPRINT("ENET Write: "); 226 | //DPRINTLN((char *) tx_buffer); 227 | Udp.beginPacket(remote_ip, remoteport); 228 | Udp.write(tx_buffer, count); 229 | Udp.endPacket(); 230 | return 1; 231 | } 232 | #endif 233 | return 0; 234 | } 235 | 236 | COLD void enet_start(void) 237 | { 238 | if (!user_settings[user_Profile].enet_enabled) 239 | return; 240 | 241 | uint8_t mac[6]; 242 | teensyMAC(mac); 243 | // byte mac[] = { 244 | // 0x04, 0xE9, 0xE5, 0x0D, 0x63, 0x2C 245 | // }; 246 | 247 | // start the Ethernet 248 | #ifdef USE_DHCP 249 | // If using DHCP (leave off the ip arg) works but more difficult to configure the desktop and remote touchscreen clients 250 | Ethernet.begin(mac); // DHCP option 251 | #else 252 | Ethernet.begin(mac, ip); // Static IP option 253 | #endif 254 | 255 | // Check for Ethernet hardware present 256 | enet_ready = 0; 257 | if (Ethernet.hardwareStatus() == EthernetNoHardware) 258 | { 259 | DPRINTLN(F("Ethernet shield was not found. Sorry, can't run the network without hardware. :(")); 260 | enet_ready = 0; // shut down usage of enet 261 | } 262 | else 263 | { 264 | //delay(1000); 265 | DPRINT(F("Ethernet Address = ")); 266 | DPRINTLN(Ethernet.localIP()); 267 | //delay(4000); 268 | if (Ethernet.linkStatus() == LinkOFF) 269 | { 270 | DPRINTLN(F("Ethernet cable is not connected.")); 271 | enet_ready = 0; 272 | } 273 | else 274 | { 275 | enet_ready = 1; 276 | //delay(100); 277 | DPRINTLN(F("Ethernet cable connected.")); 278 | // start UDP 279 | Udp.begin(localPort); // Startup our SDR comms 280 | Udp_NTP.begin(localPort_NTP); // startup NTP Client comms 281 | } 282 | } 283 | } 284 | // 285 | /*--------------------------------------- NTP code -----------------------------------*/ 286 | // 287 | COLD time_t getNtpTime() 288 | { 289 | int size = Udp_NTP.parsePacket(); 290 | if (size >= NTP_PACKET_SIZE) 291 | { 292 | //DPRINTLN("Receive NTP Response"); 293 | Udp_NTP.read(packetBuffer_NTP, NTP_PACKET_SIZE); // read packet into the buffer 294 | unsigned long secsSince1900; 295 | // convert four bytes starting at location 40 to a long integer 296 | secsSince1900 = (unsigned long)packetBuffer_NTP[40] << 24; 297 | secsSince1900 |= (unsigned long)packetBuffer_NTP[41] << 16; 298 | secsSince1900 |= (unsigned long)packetBuffer_NTP[42] << 8; 299 | secsSince1900 |= (unsigned long)packetBuffer_NTP[43]; 300 | //DPRINTLN(secsSince1900 - 2208988800UL + timeZone * SECS_PER_HOUR); 301 | time_t t; 302 | t = secsSince1900 - 2208988790UL + timeZone * SECS_PER_HOUR; 303 | Teensy3Clock.set(t); // set the RTC 304 | setTime(t); // set the time structure 305 | return t; 306 | } 307 | DPRINTLN(F("No NTP Response :-(")); 308 | return 0; // return 0 if unable to get the time 309 | } 310 | 311 | // send an NTP request to the time server at the given address 312 | COLD void sendNTPpacket(const char * address) 313 | { 314 | // set all bytes in the buffer to 0 315 | memset(packetBuffer_NTP, 0, NTP_PACKET_SIZE); 316 | // Initialize values needed to form NTP request 317 | // (see URL above for details on the packets) 318 | packetBuffer_NTP[0] = 0b11100011; // LI, Version, Mode 319 | packetBuffer_NTP[1] = 0; // Stratum, or type of clock 320 | packetBuffer_NTP[2] = 6; // Polling Interval 321 | packetBuffer_NTP[3] = 0xEC; // Peer Clock Precision 322 | // 8 bytes of zero for Root Delay & Root Dispersion 323 | packetBuffer_NTP[12] = 49; 324 | packetBuffer_NTP[13] = 0x4E; 325 | packetBuffer_NTP[14] = 49; 326 | packetBuffer_NTP[15] = 52; 327 | // all NTP fields have been given values, now 328 | // you can send a packet requesting a timestamp: 329 | Udp_NTP.beginPacket(address, 123); // NTP requests are to port 123 330 | Udp_NTP.write(packetBuffer_NTP, NTP_PACKET_SIZE); 331 | Udp_NTP.endPacket(); 332 | } 333 | 334 | /* Mod required for NativeEthernet.cpp file in Ethernet.begin class. 335 | * At end of the function is a statement that hangs if no ethernet cable is connected. 336 | * 337 | * while(!link_status){ 338 | * return; 339 | * } 340 | * 341 | * You can never progress to use the link status function to query if a cable is connected and the program is halted. 342 | * 343 | * Add the below to let it escape. Use the enet_ready flag to signal if enet started OK or not. 344 | * 345 | uint16_t escape_counter = 0; 346 | while(!link_status && escape_counter < 200){ 347 | escape_counter++; 348 | DPRINTLN("Waiting for Link Status"); 349 | delay(10); 350 | return; 351 | } 352 | * 353 | */ 354 | #endif //ENET 355 | -------------------------------------------------------------------------------- /SDR_RA8875/SDR_Network.h: -------------------------------------------------------------------------------- 1 | #ifndef _SDR_NETWORK_H_ 2 | #define _SDR_NETWORK_H_ 3 | // 4 | // SDR_Network.h 5 | // 6 | // Contains ethernet code for the SDR. 7 | // Goal is to use UDP messages to connect a control head to the SDR base rig. 8 | // The FFT output and 2-way control messages are passed over UDP. 9 | // Audio connection to the control head will for now be analog. 10 | // The Control head could be another Teensy/arduino with display, or a PC client app. 11 | // 12 | #include 13 | //#include "RadioConfig.h" 14 | 15 | //#ifdef ENET 16 | 17 | // function declarations 18 | void toggle_enet_data_out(uint8_t mode); 19 | uint8_t enet_write(uint8_t *tx_buffer, const int count); 20 | uint8_t enet_read(void); 21 | void teensyMAC(uint8_t *mac); 22 | void enet_start(void); 23 | 24 | // NTP client time setup 25 | time_t getNtpTime(); 26 | void sendNTPpacket(const char * address); 27 | //void RX_NTP_time(void); 28 | extern const char timeServer[]; // time.nist.gov NTP server 29 | extern time_t prevDisplay; // When the digital clock was displayed 30 | 31 | //#endif //ENET 32 | 33 | #endif //_SDR_NETWORK_ 34 | -------------------------------------------------------------------------------- /SDR_RA8875/SDR_RA8875.code-workspace: -------------------------------------------------------------------------------- 1 | { 2 | "folders": [ 3 | { 4 | "path": "." 5 | } 6 | ], 7 | "settings": { 8 | "git.ignoreLimitWarning": true, 9 | "files.exclude": { 10 | "**/.vteensy/**": true 11 | }, 12 | "files.watcherExclude": { 13 | "**/.vteensy/*/**": true 14 | }, 15 | "C_Cpp.default.includePath": [], 16 | "files.associations": { 17 | "functional": "cpp", 18 | "array": "cpp", 19 | "deque": "cpp", 20 | "string": "cpp", 21 | "unordered_map": "cpp", 22 | "unordered_set": "cpp", 23 | "vector": "cpp", 24 | "initializer_list": "cpp", 25 | "streambuf": "cpp", 26 | "glcdfont.c": "cpp", 27 | "*.tcc": "cpp", 28 | "sdr_ra8875.h": "c", 29 | "spi.h": "c", 30 | "string_view": "cpp", 31 | "regex": "cpp", 32 | "sdr_i2c_encoder.h": "c", 33 | "encoder.h": "c" 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /SDR_RA8875/SDR_RS_HFIQ.h: -------------------------------------------------------------------------------- 1 | // 2 | // SDR_RS_HFIQ.h 3 | // 4 | // Teensy 4 USB host port serial control library for RS-HFIQ SDR 5W transceiver board 5 | // April 24, 2022 by K7MDL 6 | // 7 | // Placed in the Public Domain 8 | // 9 | // 10 | #ifndef _SDR_RS_HFIQ_SERIAL_H_ 11 | #define _SDR_RS_HFIQ_SERIAL_H_ 12 | 13 | #ifdef USE_RS_HFIQ 14 | 15 | #include 16 | 17 | class SDR_RS_HFIQ 18 | { 19 | public: 20 | SDR_RS_HFIQ() // -- Place any args here -- 21 | // Place functions here if needed --- 22 | {} // Copy arguments to local variables here 23 | // publish externally available functions below 24 | uint64_t cmd_console(uint8_t &_swap_vfo, uint64_t &_VFOA, uint64_t &_VFOB, uint8_t &_curr_band, uint8_t &_xmit, uint8_t &_split, uint8_t &_mode, uint8_t &_clip); // returns new or unchanged active VFO value 25 | // returns new or unchanged VFO value and modified band index and other parameters 26 | void setup_RSHFIQ(int _blocking, uint64_t VFO); 27 | void send_variable_cmd_to_RSHFIQ(const char * str, char * cmd_str); 28 | char * convert_freq_to_Str(uint64_t freq); 29 | void send_fixed_cmd_to_RSHFIQ(const char * str); 30 | uint64_t find_new_band(uint64_t new_frequency, uint8_t &_curr_band); // Validate frequency is RS-HFIQ comtaptible and retured band and frequency 31 | // If freq is out of RS-HFIQ band then the freq returned is 0; 32 | void print_RSHFIQ(int flag); // reads response from RS-HFIQ and prints to the CAT terminal 33 | void print_RSHFIQ_User(int flag); // reads response from RS-HFIQ and prints to the user terminal 34 | 35 | private: 36 | char freq_str[22] = "7074000"; // *Fxxxx command to set LO freq, PLL Clock 0 37 | const char s_initPLL[5] = "*OF3"; // turns on LO clock0 output and sets drive current. 38 | const char q_freq[4] = "*F?"; // returns current LO frequency 39 | const char s_freq[3] = "*F"; // set LO frequency template. 3 to 30Mhz range 40 | const char q_dev_name[3] = "*?"; // example "RSHFIQ" 41 | const char q_ver_num[3] = "*W"; // example "RS-HFIQ FW 2.4a" 42 | const char s_TX_OFF[4] = "*X0"; // Transmit OFF 43 | const char s_TX_ON[4] = "*X1"; // Transmit ON - power is controlled via audio input level 44 | const char q_Temp[3] = "*T"; // Temp on board in degrees C 45 | const char q_Analog_Read[3] = "*L"; // analog read 46 | const char q_EXT_freq[4] = "*E?"; // query the setting for PLL Clock 2 frequency presented on EX-RF jack or used for CW 47 | const char s_EXT_freq[15] = "*E"; // sets PLL Clock 1. 4KHz to 225Mhz range 48 | const char q_F_Offset[4] = "*D?"; // Query Offset added to LO, BIT, or EXT frequency 49 | const char s_F_Offset[15] = "*D"; // Sets Offset to add to LO, BIT, or EXT frequency 50 | const char q_clip_on[3] = "*C"; // clipping occuring, add external attenuation 51 | const char q_BIT_freq[4] = "*B?"; // Built In Test. Uses PLL clock 1 // Internal band validation. Can be bypassed for any frequency if desired in the code. 52 | const char s_BIT_freq[4] = "*B"; // Built In Test. Uses PLL clock 1 // Internal band validation. Can be bypassed for any frequency if desired in the code. 53 | 54 | bool refresh_RSHFIQ(void); 55 | void init_PLL(void); 56 | void wait_reply(int blocking); // BLOCKING CALL! Use with care 57 | void update_VFOs(uint64_t newfreq); 58 | void write_RSHFIQ(int ch); 59 | int read_RSHFIQ(int flag); 60 | }; 61 | 62 | #endif // USE_RS_HFIQ 63 | #endif // _SDR_RS_HFIQ_SERIAL_H_ 64 | -------------------------------------------------------------------------------- /SDR_RA8875/SD_Card.h: -------------------------------------------------------------------------------- 1 | #ifndef _SD_CARD_H_ 2 | #define _SD_CARD_H_ 3 | // 4 | // SD_CARD.h 5 | // 6 | // SD card related support 7 | // 8 | // 9 | #include "SDR_RA8875.h" 10 | #include "RadioConfig.h" 11 | 12 | bool Open_SD_cfgfile(void); 13 | void SD_CardInfo(void); 14 | void write_db_tables(void); 15 | void write_cfg(void); 16 | 17 | void read_db_tables(void); 18 | bool write_radiocfg_h(void); 19 | 20 | #endif // _SD_CARD_H_ 21 | -------------------------------------------------------------------------------- /SDR_RA8875/Smeter.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Smeter.cpp 3 | // 4 | 5 | #include "SDR_RA8875.h" 6 | #include "RadioConfig.h" 7 | #include "Smeter.h" 8 | 9 | //#include 10 | uint8_t smeter_avg = 0; // Smeter mode. 1 = averaging, 0 = peak 11 | 12 | extern AudioAnalyzePeak_F32 S_Peak; 13 | #ifdef USE_RA8875 14 | extern RA8875 tft; 15 | #else 16 | extern RA8876_t3 tft; 17 | extern void ringMeter(int val, int minV, int maxV, int16_t x, int16_t y, uint16_t r, const char* units, uint16_t colorScheme,uint16_t backSegColor,int16_t angle,uint8_t inc); 18 | #endif 19 | extern uint8_t user_Profile; 20 | extern struct User_Settings user_settings[]; 21 | extern uint8_t MF_client; // Flag for current owner of MF knob services 22 | extern bool MeterInUse; // S-meter flag to block updates while the MF knob has control 23 | extern int16_t barGraph; // used for remote meter in Panadapter mode 24 | 25 | #define WINDOW_SIZE 30 // number of s meter readings to average. About 1ms per sample. 26 | 27 | float Peak_avg(float val); // calculate average raw smeter readings 28 | 29 | ////////////////////////// this is the S meter code/////totall uncalibrated use at your own risk 30 | COLD float Peak(void) 31 | { 32 | float s_sample; // Raw signal strength (max per 1ms) 33 | float uv, dbuv, s;// microvolts, db-microvolts, s-units 34 | char string[80]; // print format stuff 35 | float pk_avg = 0; // used for RF AGC limiting 36 | 37 | if (S_Peak.available()) 38 | { 39 | s_sample =S_Peak.read(); 40 | pk_avg = Peak_avg(s_sample); // while here build up an average for the RF_AGC Limiter 41 | if (smeter_avg) // use average or skip to use peak 42 | s_sample = pk_avg; 43 | uv= s_sample * 1000; 44 | dbuv = 20.0*log10(uv); 45 | /* 46 | tft.fillRect(700, 38, 99,25,BLACK); 47 | tft.setFont(Arial_14); 48 | tft.setCursor(720, 42); 49 | tft.setTextColor(GREEN); 50 | tft.print(dbuv); 51 | tft.fillRect(130, 47, 550,10, BLACK); 52 | tft.fillRect(130, 47,abs(dbuv*4),10,GREEN ); 53 | */ 54 | s = (dbuv-3)/6.0; 55 | 56 | if (s <0.0) 57 | s=0.0; 58 | 59 | if (s>9.0) 60 | s = 9.0; 61 | else 62 | dbuv = 0; 63 | 64 | tft.setTextColor(BLUE); 65 | tft.setFont(Arial_14); 66 | 67 | /* 68 | // bar meter 69 | tft.fillRect(72, 38, 57, 25, BLACK); 70 | tft.setCursor(1, 42); 71 | if (dbuv == 0) 72 | sprintf(string,"S-Meter:%1.0f",s); 73 | else 74 | sprintf(string,"S-Meter:9+%02.0f",dbuv); 75 | tft.print(string); 76 | */ 77 | 78 | #ifdef PANADAPTER 79 | if (user_settings[user_Profile].xmit) 80 | sprintf(string," P-%1.0d", barGraph); 81 | else 82 | sprintf(string," S-%1.0d", barGraph); 83 | #else 84 | // rounded meter 85 | if (dbuv == 0) 86 | sprintf(string," S-%1.0f",s); 87 | else 88 | sprintf(string,"S-9+%02.0f",dbuv); 89 | #endif 90 | 91 | 92 | if (!MeterInUse) // don't write while the MF knob is busy with a temporary focus 93 | displayMeter((int) s, string, 3); // Call the button object display function. 94 | } 95 | return pk_avg; 96 | } 97 | 98 | // Use the S-meter results to build an average 99 | HOT float Peak_avg(float val) 100 | { 101 | static int16_t idx = 0; 102 | static float sum = 0; 103 | static float Readings[WINDOW_SIZE] = {}; 104 | static float P_avg = 0; 105 | 106 | sum = sum - Readings[idx]; // Remove the oldest entry from the sum 107 | Readings[idx] = val; // Add the newest reading to the window 108 | sum = sum + val; // Add the newest reading to the sum 109 | idx = (idx+1) % WINDOW_SIZE; // Increment the index, and wrap to 0 if it exceeds the window size 110 | 111 | P_avg = sum / WINDOW_SIZE; // Divide the sum of the window by the window size for the result 112 | 113 | //DPRINT("S meter avg = "); 114 | //DPRINTLN(P_avg); 115 | 116 | return P_avg; 117 | } -------------------------------------------------------------------------------- /SDR_RA8875/Smeter.h: -------------------------------------------------------------------------------- 1 | #ifndef _SMETER_H_ 2 | #define _SMETER_H_ 3 | // 4 | // Smeter.h 5 | // 6 | // 7 | 8 | float Peak(void); 9 | 10 | #endif // _SMETER_H_ 11 | 12 | -------------------------------------------------------------------------------- /SDR_RA8875/Spectrum_RA887x.h: -------------------------------------------------------------------------------- 1 | // 2 | // Spectrum_RA887x.h 3 | // 4 | // Spectrum_RA887x Library draws the spectrum display in a resizable window area at any reasonable X,Y coordinate 5 | // This version is optimized for the RA8875 or RA8876 displays. 6 | // The #define USE_RA8875 determines which display is used, they use slightly different libraries, function calls, parameters 7 | // This #define is normally specified in your main program (RadioConfig.h in my SDR_8875 program) 8 | // Scrolls the waterfall and draws a spectrum chart or dot style 9 | // Depends on Layer1 mosde and BTE capability of hte RA8875 display controller 10 | // Most of this will work unchanged in other displays provided the waterfall scroll effect can be worked out another way and the 2-3 lines of code yused forf waterfall scrlling here are modified to suit.. 11 | // The RA8875/76 BTE approach means the CPU only draws 1 line of colors 1 pixel high per scheduleed update and issues 2 block mnove commands whcih copy the block to layer 2, then moves it back 1 row lower on layer 1. 12 | // The controller does all the work this way, no large data transfers required. 13 | // 14 | // 15 | #ifndef SPECTRUM_RA887x_H_ 16 | #define SPECTRUM_RA887x_H_ 17 | /* Some of the waterfall averaging code and colorMap() function used in this spectrum.h were adopted from Waterfall example in the Arduino Audio library Analysis examples. 18 | * 19 | * Waterfall Audio Spectrum Analyzer, adapted from Nathaniel Quillin's 20 | award winning (most over the top) Hackaday SuperCon 2015 Badge Hack. 21 | 22 | https://hackaday.io/project/8575-audio-spectrum-analyzer-a-supercon-badge 23 | https://github.com/nqbit/superconbadge 24 | 25 | ILI9341 Color TFT Display is used to display spectral data. 26 | Two pots on analog A2 and A3 are required to adjust sensitivity. 27 | 28 | Copyright (c) 2015 Nathaniel Quillin 29 | 30 | Permission is hereby granted, free of charge, to any person obtaining 31 | a copy of this software and associated documentation files 32 | (the "Software"), to deal in the Software without restriction, 33 | including without limitation the rights to use, copy, modify, merge, 34 | publish, distribute, sublicense, and/or sell copies of the Software, 35 | and to permit persons to whom the Software is furnished to do so, 36 | subject to the following conditions: 37 | 38 | The above copyright notice and this permission notice shall be 39 | included in all copies or substantial portions of the Software. 40 | 41 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 42 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 43 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 44 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 45 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 46 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 47 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 48 | */ 49 | #include 50 | //#include // F32 library located on GitHub. https://github.com/chipaudette/OpenAudio_ArduinoLibrary 51 | //#include 52 | //#include "ILI9341_t3.h" 53 | //#include // GitHub https://github.com/nusolar/Metro 54 | 55 | // Vars from main program. Eventually pass these into function at run time. 56 | extern struct Spectrum_Parms Sp_Parms_Def[]; // The main program should have at least 1 layout record defined 57 | extern struct New_Spectrum_Layout Custom_Layout[1]; 58 | 59 | struct Spectrum_Parms { 60 | int16_t wf_sp_width; // User specified active graphing area width with no padding. Max is fft_bins, can be smaller. 61 | int16_t border_space_min; // Left and right side minimum border space. Total width minimum is graph width*2*border_space_minimum. 62 | int16_t border_space; // Self-calculated value. Border padding size used on both sides of graphing area 63 | int16_t l_graph_edge; // Self calculated. Left side of active graph 64 | int16_t r_graph_edge; // Self calculated. Right side of active graph 65 | int16_t c_graph; // Self calculated. Center of graph window area 66 | int16_t sp_txt_row_height; // Self calculated. Space for span frequency marker labels 67 | int16_t tick_height; // Self calculated. Frequency markers top and bottom of display regions. 68 | int16_t sp_txt_row; // Self calculated. Spectrum text line below the top of space we have 69 | int16_t sp_tick_row; // Self calculated. Bottom of tick mark rectangle space that is 1 space below text 70 | int16_t sp_top_line; // Self calculated. Spectrum top of graphing active area or window 71 | int16_t wf_tick_row; // Self calculated. Bottom of tick mark rectangle space that is 1 space below text 72 | int16_t wf_bottom_line; // Self calculated. Bottom line of waterfall window 73 | int16_t sp_height; // Self calculated. Account for span label and tic mark space outside of spectrum and waterfall 74 | int16_t wf_height; // Self calculated. Waterfall height is what height is left after all other spaces have been figured 75 | int16_t sp_bottom_line; // Self calculated. Bottom of spectrum window 76 | int16_t wf_top_line; // Self calculated. Top Line of waterfall window 77 | int16_t spect_x; // User specified X coordinate of the NE anchor point of outermost spectrum object box 78 | int16_t spect_y; // User specified Y coordinate of the NE anchor point of outermost spectrum object box 79 | int16_t spect_width; // User specified overall width and height 80 | int16_t spect_height; // User specified overall height. All other heights are calculated to fit within this box. 81 | int16_t spect_center; // User specified center ratio of the line dividing the spectrum and waterfall. SMaller - smaller spectrum, bigger waterfall. 82 | int16_t spect_span; // User specified span width. The actual box width may not allow so it becomes best effort 83 | int16_t spect_wf_style; // User specified waterfall averaging algorithym to use 84 | int16_t spect_wf_colortemp; // User specified colorization of the data in the waterfall. Experimentally decided value. 85 | float spect_wf_scale; // User specified requested waterfall zoom level actual size or sample rate may cause best effort 86 | float spect_LPFcoeff; // User specified data smoothing factor. 87 | int16_t spect_dot_bar_mode; // User specified spectrum presentation mode. 0=BAR, 1=DOT, 2=LINE - Line is experimental line draw attempt. Might be acheived via dot averaging 88 | int16_t spect_sp_scale; // User specified vertical spectrum scale in dB. This is to be the top dBm leel in the box. 89 | // Ths is usually between 10 and 80dB. Limited by spectrum_scale_maxdB and spectrum_scale_mindB vars 90 | // The diff between this and box bottom results in scaling (zoom). If peaks occur outside the box bounds then they are not drawn. 91 | int16_t spect_floor; // Slides the data up and down relative to the specrum bottom box line. The noise floor may be above or below and if outside the box is simply not drawn. 92 | int16_t spect_wf_rate; // Used by external timer to control refresh rate for this layout. drawSpectrumFRame() will read this and set the timer 93 | }; 94 | 95 | // The main program should define at least 1 layout record based on this structure. 96 | // Here is a working example usually placed in your main program header files. 97 | /* 98 | struct Spectrum_Parms Sp_Parms_Def[PRESETS] = { // define default sets of spectrum window parameters, mostly for easy testing but could be used for future custom preset layout options 99 | //W LE RE CG x y w h c sp st clr sc mode scal reflvl wfrate 100 | #ifdef USE_RA8875 101 | {798,0, 0, 0,798,398,14,8,157,179,179,408,400,110,111,289,289, 0,153,799,256,50,20,6,240,1.0,0.9,1,20, 8, 70}, 102 | #else 103 | {1020,1,1, 1,1021,510,14,8,143,165,165,528,520,142,213,307,307, 0,139,1022,390,40,20,6,890,1.5,0.9,1,20,10, 80}, 104 | #endif 105 | }; 106 | */ 107 | 108 | struct New_Spectrum_Layout { // Temp storage for generating new layouts 109 | int16_t spectrum_x; // 0 to width of display - window width. Must fit within the button frame edges left and right 110 | // ->Pay attention to the fact that position X starts with 0 so 100 pixels wide makes the right side value of x=99. 111 | int16_t spectrum_y; // 0 to vertical height of display - height of your window. Odd Numbers are best if needed to make the height an even number and still fit on the screen 112 | int16_t spectrum_height; // Total height of the window. Even numbers are best. (height + Y) cannot exceed height of the display or the window will be off screen. 113 | int16_t spectrum_center; // Value 0 to 100. Smaller value = biggger waterfall. Specifies the relative size (%) between the spectrum and waterfall areas by moving the dividing line up or down as a percentage 114 | // Smaller value makes spectrum smaller, waterfall bigger 115 | int16_t spectrum_width; // Total width of window. Even numbers are best. 552 is minimum to fit a full 512 pixel graph plus the min 20 pixel border used on each side. Can be smaller but will reduce graph area 116 | int16_t spectrum_span; // Value in KHz. Ths will be the maximum span shown in the display graphs. 117 | // The graph code knows how many Hz per bin so will scale down to magnify a smaller range. 118 | // Max value and resolutoin (pixels per bin) is dependent on sample frequency 119 | // 25000 is max for 1024 FFT with 500 bins at 1:1 bins per pixel 120 | // 12500 would result in 2 pixels per bin. Bad numbers here should be corrected to best fit by the function 121 | int16_t spectrum_wf_style; // Range 1- 6. Specifies the Waterfall style. 122 | int16_t spectrum_wf_colortemp; // Range 1 - 1023. Specifies the waterfall color temperature to tune it to your liking 123 | float spectrum_wf_scale; // 0.0f to 40.0f. Specifies thew waterfall zoom level - may be redundant when Span is worked out later. 124 | float spectrum_LPFcoeff; // 1.0f to 0.0f. Data smoothing 125 | int16_t spectrum_dot_bar_mode; // 0=bar, 1=Line. Spectrum box 126 | int16_t spectrum_sp_scale; // 10 to 80. Spectrum scale factor in dB. This is the height of the scale (if possible by windows sizes). Will plot the spectrum window of values between the floor and the scale value creating a zoom effect. 127 | int16_t spectrum_floor; // 0 to -150. The reference point for plotting values. Anything signal value > than this (less negative) will be plotted until stronger than the window height*scale factor. 128 | int16_t spectrum_wf_rate; // window update rate in ms. 25 is fast enough to see dit and dahs well 129 | }; 130 | 131 | uint64_t spectrum_update(int16_t s, int16_t VFOA_YES, uint64_t VfoA, uint64_t VfoB, int32_t Offset, uint16_t filterCenter, uint16_t filterBandwidth, float _pan, uint16_t fft_sz, float fft_bin_sz, int16_t fft_binc); 132 | void Spectrum_Parm_Generator(int16_t parm_set, int16_t preset, int16_t fft_binc); 133 | void drawSpectrumFrame(uint8_t s); 134 | void initSpectrum(int16_t preset); 135 | void setActiveWindow(int16_t XL,int16_t XR ,int16_t YT ,int16_t YB); 136 | void setActiveWindow_default(void); 137 | void updateActiveWindow(bool full); 138 | 139 | #endif -------------------------------------------------------------------------------- /SDR_RA8875/Tuner.cpp: -------------------------------------------------------------------------------- 1 | ///////////////////////////spin the encoder win a frequency!!//////////////////////////// 2 | // 3 | // Tuner.cpp 4 | // 5 | // Input: Counts from encoder to change the current VFO by the current step rate. 6 | // If newFreq is 0, then just use VFOx which may have been set elsewhere to a desired frequency 7 | // use this function rather than setFreq() since this tracks VFOs and updates their memories. 8 | // 9 | 10 | #include "SDR_RA8875.h" 11 | #include "RadioConfig.h" 12 | #include "Tuner.h" 13 | 14 | #ifdef USE_RS_HFIQ 15 | extern SDR_RS_HFIQ RS_HFIQ; // init the RS-HFIQ library 16 | extern void send_variable_cmd_to_RSHFIQ(const char * str, char * cmd_str); 17 | extern char * convert_freq_to_Str(uint64_t freq); 18 | #endif 19 | extern uint8_t curr_band; // global tracks our current band setting. 20 | extern uint64_t VFOA; // 0 value should never be used more than 1st boot before EEPROM since init should read last used from table. 21 | extern struct Band_Memory bandmem[]; 22 | extern struct User_Settings user_settings[]; 23 | extern uint8_t user_Profile; 24 | extern const struct TuneSteps tstep[]; 25 | extern int16_t rit_offset; // global rit value in Hz 26 | extern int16_t xit_offset; // global xit value in Hz 27 | extern uint64_t xvtr_offset; // Adds 'LO" to displayed frequency for transverters. 28 | extern int64_t Fc; 29 | 30 | #ifdef SV1AFN_BPF 31 | #include 32 | extern SVN1AFN_BandpassFilters bpf; 33 | #endif 34 | 35 | //static const uint64_t topFreq = 54000000; // sets receiver upper frequency limit 30 MHz 36 | static const uint64_t bottomFreq = 1000000; // sets the receiver lower frequency limit 1.6 MHz 37 | 38 | // 39 | //-------------------------- selectFrequency -------------------------------------- 40 | // 41 | COLD void selectFrequency(int64_t newFreq) // 0 = no change unless an offset is required for mode 42 | { 43 | uint16_t fstep = tstep[bandmem[curr_band].tune_step].step; 44 | uint64_t Freq; 45 | 46 | if (bandmem[curr_band].split && user_settings[user_Profile].xmit) 47 | Freq = user_settings[user_Profile].sub_VFO; 48 | else 49 | Freq = VFOA - (VFOA % fstep); // Round down to step size if step > 1Hz 50 | 51 | Freq += newFreq * fstep; 52 | 53 | //DPRINTF("TUNER: Initial Freq = "); DPRINT(Freq); DPRINTF(" rit = "); DPRINT(rit_offset); DPRINTF(" xit = "); DPRINT(xit_offset); DPRINTF(" xvtr_offset = "); DPRINTLN(xvtr_offset); 54 | 55 | // Keep frequency within limits 56 | //if (Freq >= topFreq) 57 | // Freq = topFreq; 58 | if (Freq <= bottomFreq) 59 | Freq = bottomFreq; 60 | 61 | 62 | // If this is configured to be a panadapter then change from VFO to fixed LO. 63 | #ifdef PANADAPTER 64 | Freq = PANADAPTER_LO; 65 | if (bandmem[curr_band].mode_A == DATA) 66 | Freq += PANADAPTER_MODE_OFFSET_DATA; // offset if in DATA mode 67 | #else 68 | if (bandmem[curr_band].split && user_settings[user_Profile].xmit) 69 | user_settings[user_Profile].sub_VFO = Freq; 70 | else 71 | { 72 | VFOA = Freq; // Do not store rit_offset into VFOA! 73 | bandmem[curr_band].vfo_A_last = VFOA; // save for band stacking 74 | } 75 | 76 | //Now have the correct Freq for VFO A or B when using xit or rit. Account for Xvtr LO 77 | if (user_settings[user_Profile].xmit) 78 | Freq += xit_offset - xvtr_offset; // Add in any XIT offset. If Xvtr band then remove the LO offset 79 | else 80 | Freq += rit_offset - xvtr_offset; // Add in any RIT offset. If Xvtr band then remove the LO offset 81 | 82 | Freq += Fc; 83 | 84 | DPRINTF("TUNER: VFOA = "); DPRINT(VFOA); DPRINTF(" PLL = "); DPRINT(Freq); DPRINTF(" Fc = "); DPRINT((int32_t) Fc); DPRINTF(" rit = "); DPRINT(rit_offset); DPRINTF(" xit = "); DPRINT(xit_offset); DPRINTF(" xvtr_offset = "); DPRINTLN(xvtr_offset); 85 | #endif 86 | 87 | #ifdef PANADAPTER 88 | #ifdef SV1AFN_BPF 89 | bpf.setBand(HFBand(HFBypass)); 90 | #endif 91 | #else 92 | #ifdef SV1AFN_BPF 93 | if (Freq < bandmem[curr_band].edge_lower || Freq > bandmem[curr_band].edge_upper) 94 | { 95 | //RampVolume(0.0, 1); // 0 ="No Ramp (instant)" // loud pop due to instant change || 1="Normal Ramp" // graceful transition between volume levels || 2= "Linear Ramp" 96 | //DPRINT("BPF Set to ");DPRINTLN("Bypassed"); 97 | bpf.setBand(HFBand(HFBypass)); 98 | //RampVolume(xx, 1); // 0 ="No Ramp (instant)" // loud pop due to instant change || 1="Normal Ramp" // graceful transition between volume levels || 2= "Linear Ramp" 99 | } 100 | else 101 | { 102 | //RampVolume(0.0, 1); // 0 ="No Ramp (instant)" // loud pop due to instant change || 1="Normal Ramp" // graceful transition between volume levels || 2= "Linear Ramp" 103 | //DPRINT("BPF Set to ");DPRINTLN(bandmem[curr_band].preselector); 104 | bpf.setBand(HFBand(bandmem[curr_band].preselector)); 105 | //RampVolume(xx, 1); // 0 ="No Ramp (instant)" // loud pop due to instant change || 1="Normal Ramp" // graceful transition between volume levels || 2= "Linear Ramp" 106 | } 107 | #endif 108 | #endif 109 | 110 | #ifdef USE_RS_HFIQ 111 | RS_HFIQ.send_variable_cmd_to_RSHFIQ("*F", RS_HFIQ.convert_freq_to_Str(Freq)); 112 | displayFreq(); 113 | #else 114 | SetFreq(Freq); // send freq to SI5351 115 | displayFreq(); // show freq on display 116 | #endif 117 | } 118 | -------------------------------------------------------------------------------- /SDR_RA8875/Tuner.h: -------------------------------------------------------------------------------- 1 | #ifndef _TUNER_H_ 2 | #define _TUNER_H_ 3 | // 4 | // Tuner.h 5 | // 6 | #include 7 | 8 | void selectFrequency(int64_t newFreq); 9 | 10 | #endif // _TUNER_H_ 11 | -------------------------------------------------------------------------------- /SDR_RA8875/UserInput.h: -------------------------------------------------------------------------------- 1 | #ifndef _USERINPUT_H_ 2 | #define _USERINPUT_H_ 3 | /* 4 | * UserInput.h 5 | * 6 | * Usage: A touch event broker that tracks touch point events and uses time, distance, and number of touch points 7 | * to determine if an event is a button press, a swipe or a pinch activity. Data is stored in Touch_Control structure. 8 | * 9 | * Button: 1 touch point < BUTTON_TOUCH max travel. It passes on the last X and Y coordinates. 10 | * 11 | * Gesture: 1 or 2 touch points exceeding BUTTON_TOUCH minimum travel. It passes the distance to the gesture handler 12 | * Direction is positive or negatiove distance fopr X and Y. 13 | * 14 | * Non_Blocking: This is a non-blocking state engine with timer "gesture_timer" set for max press duration. 15 | * The event is reset after timer expiration. When a finger is eventually lifted it can become a valid press 16 | * or gesture again but with new start points. See Dragging description for exception. 17 | * 18 | * Dragging: The starting x,y coordinate are stored and a timer started. While waiting for a press event to complete 19 | * the current x, y coordinates are updated to permit feedback for dragging type events such as operating a slider. 20 | * The starting coordinates are not reset so the total drag distance can still be determined even though the timer has expired. 21 | * 22 | * Number of touch points can be up to 5 but the code is only working with 2 here. 23 | */ 24 | #include 25 | 26 | // Function declarations 27 | void Button_Handler(int16_t x, uint16_t y, uint8_t _holdtime); 28 | uint8_t Gesture_Handler(uint8_t _gesture, uint8_t _dragEvent, uint8_t _holdtime); 29 | void setPanel(void); 30 | void Touch(void); 31 | void Button_Action(uint16_t button_name); 32 | 33 | #endif //end of _USERINPUT_H_ 34 | -------------------------------------------------------------------------------- /SDR_RA8875/Vfo.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Vfo.cpp 3 | // 4 | 5 | // ToDO: Fix up Quadrature Ouput config (VFO_MULT==1) to work with OCXO_10MHz preoperly). Currently code is either/or. 6 | 7 | // 8 | #include "SDR_RA8875.h" 9 | #include "Vfo.h" 10 | #include "RadioConfig.h" 11 | 12 | #ifndef USE_RS_HFIQ 13 | #if defined(OCXO_10MHZ) || (VFO_MULT == 1) 14 | #include "si5351.h" 15 | extern Si5351 si5351; 16 | #else 17 | #include "si5351mcu.h" 18 | extern Si5351mcu si5351; 19 | #endif 20 | #endif 21 | 22 | extern uint64_t VFOA; // 0 value should never be used more than 1st boot before EEPROM since init should read last used from table. 23 | extern int64_t Fc; 24 | 25 | //#define VFO_MULT 2 // 4x for QRP-Labs RX, 2x for NT7V QSE/QSD board, defined in RadioCfg.h 26 | #if (VFO_MULT == 1) 27 | static int currentEvenDivisor = 0; 28 | int calcDivisor(uint32_t freq) 29 | { 30 | int evenDivisor = 2; 31 | if (freq < 6850000) evenDivisor = 126; 32 | else if (freq < 9500000) evenDivisor = 88; 33 | else if (freq < 13600000)evenDivisor = 64; 34 | else if (freq < 17500000) evenDivisor = 44; 35 | else if (freq < 25000000) evenDivisor = 34; 36 | else if (freq < 36000000) evenDivisor = 24; 37 | else if (freq < 45000000) evenDivisor = 18; 38 | else if (freq < 60000000) evenDivisor = 14; 39 | else if (freq < 80000000) evenDivisor = 10; 40 | else if (freq < 100000000) evenDivisor = 8; 41 | else if (freq < 146600000) evenDivisor = 6; 42 | else if (freq < 220000000) evenDivisor = 4; 43 | return evenDivisor; 44 | } 45 | #endif // VFO_MULT == 1 46 | 47 | //////////////////////////Initialize VFO/DDS////////////////////////////////////////////////////// 48 | COLD void initVfo(void) 49 | { 50 | 51 | #ifdef USE_RS_HFIQ 52 | return; 53 | #else 54 | 55 | delay(100); 56 | 57 | //#define OCXO_10MHZ in main header file - Uncomment it there for external reference on the si5351C board version 58 | #ifdef OCXO_10MHZ 59 | /* 60 | * init(uint8_t xtal_load_c, uint32_t ref_osc_freq, int32_t corr) 61 | * 62 | * Setup communications to the Si5351 and set the crystal 63 | * load capacitance. 64 | * 65 | * xtal_load_c - Crystal load capacitance. Use the SI5351_CRYSTAL_LOAD_*PF 66 | * defines in the header file 67 | * xo_freq - Crystal/reference oscillator frequency in 1 Hz increments. 68 | * Defaults to 25000000 if a 0 is used here. 69 | * 27000000 is also common for some boards so be sure to enter thqt number if yours is 27Mhz. 70 | * corr - Frequency correction constant in parts-per-billion 71 | * 72 | * Returns a boolean that indicates whether a device was found on the desired 73 | * I2C address. 74 | */ 75 | 76 | // --------------- Internal Crystal Clock Section --------------------------------- 77 | // Initialize the Si5351 to use a 27 MHz clock on the XO input 78 | #ifndef K7MDL_OCXO 79 | //si5351.init(SI5351_CRYSTAL_LOAD_8PF, 27000000, 0); //set up our PLL for internal crystal or TCXO 80 | si5351.init(SI5351_CRYSTAL_LOAD_0PF, 24999899, 0); 81 | //si5351.init(SI5351_CRYSTAL_LOAD_0PF, 10000000, 0); 82 | si5351.set_clock_source(SI5351_CLK0, SI5351_CLK_SRC_XTAL); 83 | // --------------- End Internal Clock section ------------------------------------- 84 | #endif 85 | // ---- OR ------// 86 | 87 | #ifdef K7MDL_OCXO 88 | // --------------- External Reference Clock Section ------------------------------- 89 | //Initialize the Si5351 to use an external clock like a 10Mhz OCXO 90 | si5351.init(SI5351_CRYSTAL_LOAD_0PF, 0, 0); 91 | //This section is for external ref clock 92 | si5351.set_clock_source(SI5351_CLK0, SI5351_CLK_SRC_CLKIN); // Use the OCXO for Clock 0 output 93 | // Set the CLKIN reference frequency to 10 MHz 94 | si5351.set_ref_freq(10000000UL, SI5351_PLL_INPUT_CLKIN); 95 | // Apply a correction factor to CLKIN 96 | si5351.set_correction(0, SI5351_PLL_INPUT_CLKIN); 97 | // Set PLLA and PLLB to use the signal on CLKIN instead of the XTAL 98 | si5351.set_pll_input(SI5351_PLLA, SI5351_PLL_INPUT_CLKIN); 99 | si5351.set_pll_input(SI5351_PLLB, SI5351_PLL_INPUT_CLKIN); 100 | // ------------ ---End Ext Clock section ---------------------------------------- 101 | #endif // K7MDL_OCXO 102 | 103 | // Below is common to both Ext Clk and Internal Xtal 104 | si5351.drive_strength(SI5351_CLK0, SI5351_DRIVE_2MA); 105 | si5351.output_enable(SI5351_CLK0, 1); // ON by default but just in case. 106 | si5351.output_enable(SI5351_CLK1, 0); // OFF by default but just in case. 107 | //si5351.output_enable(SI5351_CLK2, 0); // OFF by default but just in case. 108 | //si5351.output_enable(SI5351_CLK3, 0); // outputs 3 - 7 only apply to the C version PLL 109 | //si5351.output_enable(SI5351_CLK4, 0); 110 | //si5351.output_enable(SI5351_CLK5, 0); 111 | //si5351.output_enable(SI5351_CLK6, 0); 112 | //si5351.output_enable(SI5351_CLK7, 0); 113 | // Set CLK0 to output Dial Frequency 114 | si5351.set_freq((VFOA+Fc) * VFO_MULT + 100ULL , SI5351_CLK0); // set the output freq on CLK 0 top 5Mhz to start out. 115 | si5351.reset(); // Must do this for external clock! 116 | #elif (VFO_MULT == 1) 117 | si5351.init(SI5351_CRYSTAL_LOAD_8PF, 0, 330); // 330 is the frequency compensation value and needs to measured. 118 | //si5351.set_correction(330); // Set to specific Si5351 calibration number 119 | si5351.set_pll(SI5351_PLL_FIXED, SI5351_PLLA); 120 | si5351.set_pll(SI5351_PLL_FIXED, SI5351_PLLB); //also make PPLB have an input 121 | si5351.drive_strength(SI5351_CLK0, SI5351_DRIVE_2MA); // note these were 8MA 122 | si5351.drive_strength(SI5351_CLK1, SI5351_DRIVE_2MA); 123 | si5351.drive_strength(SI5351_CLK2, SI5351_DRIVE_2MA); 124 | si5351.set_ms_source (SI5351_CLK2, SI5351_PLLB); // CLK2 uses PLLB so it won't move around as we move PLLA 125 | currentEvenDivisor = calcDivisor(VFO_A); 126 | si5351.set_freq_manual(VFO_A * SI5351_FREQ_MULT, currentEvenDivisor * VFO_A * SI5351_FREQ_MULT, SI5351_CLK0); 127 | 128 | si5351.set_freq_manual(VFO_A * SI5351_FREQ_MULT, currentEvenDivisor * VFO_A * SI5351_FREQ_MULT, SI5351_CLK1); 129 | si5351.set_phase(SI5351_CLK0, 0); 130 | si5351.set_phase(SI5351_CLK1, currentEvenDivisor); 131 | si5351.pll_reset(SI5351_PLLA); 132 | 133 | #else 134 | 135 | // Choose one of these 3 lines. The first is the default crystal which is varied among boards 136 | //si5351.init(); // Set this to 25MHz or 27MHz depending on what your PLL uses. 137 | #ifdef si5351_XTAL_25MHZ 138 | //si5351.init(25000000); 139 | si5351.init(24999899); // value for TCXO board 140 | #else 141 | si5351.init(27000000); 142 | #endif // si5351_XTAL_IS_25MHZ 143 | 144 | /// Si5351mcu library modified by K7MDL to accept load capacitor setting. Comment this out for standard library 145 | #ifdef si5351_TCXO 146 | si5351.load_c(SI5351_CRYSTAL_LOAD_0PF); // this is for replacing a crystal with a TCXO 147 | #endif //si5351_TCXO 148 | 149 | // The lines below are stanard to any crystal 150 | #ifdef si5351_CORRECTION 151 | si5351.correction(si5351_CORRECTION); // Set this for your own PLL's crystal error. 100 seems like about 25Hz 152 | #endif 153 | si5351.setPower(0, SIOUT_8mA); // 0 is Clock 0 154 | si5351.setFreq(0, (VFOA+Fc) * VFO_MULT); // Multiply x4 for RX board 155 | si5351.enable(0); // these enable/disables are optional 156 | si5351.disable(1); 157 | si5351.disable(2); 158 | // si5351.set_pll(SI5351_PLL_FIXED, SI5351_PLLA); 159 | si5351.reset(); // Only do for very large change and after initial setup. 160 | #endif 161 | #endif 162 | } 163 | 164 | // Fc, Filter offsets, XIT and RIT offsets should all be taken into account for the value of Freq 165 | COLD void SetFreq(uint64_t Freq) 166 | { 167 | #if (VFO_MULT == 1) 168 | 169 | int oldEvenDivisor = currentEvenDivisor; 170 | currentEvenDivisor = calcDivisor(Freq); 171 | si5351.set_freq_manual(Freq * SI5351_FREQ_MULT, currentEvenDivisor * Freq * SI5351_FREQ_MULT, SI5351_CLK0); 172 | 173 | si5351.set_freq_manual(Freq * SI5351_FREQ_MULT, currentEvenDivisor * Freq * SI5351_FREQ_MULT, SI5351_CLK1); 174 | si5351.set_phase(SI5351_CLK0, 0); 175 | si5351.set_phase(SI5351_CLK1, currentEvenDivisor); 176 | if (currentEvenDivisor != oldEvenDivisor) { // Reset of the SI5351 is needed only after a change in divisor 177 | si5351.pll_reset(SI5351_PLLA); 178 | } 179 | #else // VFO_MULT != 1 180 | #ifdef USE_RS_HFIQ 181 | return; 182 | #else 183 | #ifdef OCXO_10MHZ 184 | si5351.set_freq((Freq) * VFO_MULT * 100ULL, SI5351_CLK0); // generating 4 x frequency ... set 400ULL to 100ULL for 1x frequency 185 | #else 186 | si5351.setFreq(0, (Freq) * VFO_MULT); // use 4x for QRP-Labs RX vboard and some others. Use 1x if using 2 outputs shifted by 90 degrees 187 | #endif 188 | #endif 189 | #endif // VFO_MULT == 1 190 | } 191 | -------------------------------------------------------------------------------- /SDR_RA8875/Vfo.h: -------------------------------------------------------------------------------- 1 | #ifndef _VFO_H_ 2 | #define _VFO_H_ 3 | 4 | // VFO.h 5 | #include 6 | 7 | void initVfo(void); 8 | void SetFreq(uint64_t Freq); 9 | 10 | #endif //_VFO_H_ -------------------------------------------------------------------------------- /SDR_RA8875/hilbert121A.h: -------------------------------------------------------------------------------- 1 | // Following is 121 term Hilbert FIR filter 2 | float32_t hilbert121A[121] = { 3 | 0.000000000000000000, 4 | 0.000773378567767513, 5 | 0.000000000000000000, 6 | 0.001046207887980644, 7 | 0.000000000000000000, 8 | 0.001368896533613985, 9 | 0.000000000000000000, 10 | 0.001746769975247667, 11 | 0.000000000000000000, 12 | 0.002185555845922462, 13 | 0.000000000000000000, 14 | 0.002691457154069645, 15 | 0.000000000000000000, 16 | 0.003271251311125927, 17 | 0.000000000000000000, 18 | 0.003932423233774751, 19 | 0.000000000000000000, 20 | 0.004683343721596901, 21 | 0.000000000000000000, 22 | 0.005533508538632429, 23 | 0.000000000000000000, 24 | 0.006493859804516438, 25 | 0.000000000000000000, 26 | 0.007577220484233372, 27 | 0.000000000000000000, 28 | 0.008798886675905997, 29 | 0.000000000000000000, 30 | 0.010177443901536392, 31 | 0.000000000000000000, 32 | 0.011735907609641917, 33 | 0.000000000000000000, 34 | 0.013503343224246872, 35 | 0.000000000000000000, 36 | 0.015517212970554440, 37 | 0.000000000000000000, 38 | 0.017826854793349920, 39 | 0.000000000000000000, 40 | 0.020498780519188083, 41 | 0.000000000000000000, 42 | 0.023625003856774591, 43 | 0.000000000000000000, 44 | 0.027336628208641155, 45 | 0.000000000000000000, 46 | 0.031827023036304102, 47 | 0.000000000000000000, 48 | 0.037393534868609392, 49 | 0.000000000000000000, 50 | 0.044517689704988733, 51 | 0.000000000000000000, 52 | 0.054032871748808158, 53 | 0.000000000000000000, 54 | 0.067515548043274365, 55 | 0.000000000000000000, 56 | 0.088347125250410385, 57 | 0.000000000000000000, 58 | 0.125324201622410869, 59 | 0.000000000000000000, 60 | 0.210709715079613419, 61 | 0.000000000000000000, 62 | 0.634897508268964295, 63 | 0.000000000000000000, 64 | -0.634897508268964295, 65 | 0.000000000000000000, 66 | -0.210709715079613419, 67 | 0.000000000000000000, 68 | -0.125324201622410869, 69 | 0.000000000000000000, 70 | -0.088347125250410385, 71 | 0.000000000000000000, 72 | -0.067515548043274365, 73 | 0.000000000000000000, 74 | -0.054032871748808158, 75 | 0.000000000000000000, 76 | -0.044517689704988733, 77 | 0.000000000000000000, 78 | -0.037393534868609392, 79 | 0.000000000000000000, 80 | -0.031827023036304102, 81 | 0.000000000000000000, 82 | -0.027336628208641155, 83 | 0.000000000000000000, 84 | -0.023625003856774591, 85 | 0.000000000000000000, 86 | -0.020498780519188083, 87 | 0.000000000000000000, 88 | -0.017826854793349920, 89 | 0.000000000000000000, 90 | -0.015517212970554440, 91 | 0.000000000000000000, 92 | -0.013503343224246872, 93 | 0.000000000000000000, 94 | -0.011735907609641917, 95 | 0.000000000000000000, 96 | -0.010177443901536392, 97 | 0.000000000000000000, 98 | -0.008798886675905997, 99 | 0.000000000000000000, 100 | -0.007577220484233372, 101 | 0.000000000000000000, 102 | -0.006493859804516438, 103 | 0.000000000000000000, 104 | -0.005533508538632429, 105 | 0.000000000000000000, 106 | -0.004683343721596901, 107 | 0.000000000000000000, 108 | -0.003932423233774751, 109 | 0.000000000000000000, 110 | -0.003271251311125927, 111 | 0.000000000000000000, 112 | -0.002691457154069645, 113 | 0.000000000000000000, 114 | -0.002185555845922462, 115 | 0.000000000000000000, 116 | -0.001746769975247667, 117 | 0.000000000000000000, 118 | -0.001368896533613985, 119 | 0.000000000000000000, 120 | -0.001046207887980644, 121 | 0.000000000000000000, 122 | -0.000773378567767513, 123 | 0.000000000000000000}; 124 | -------------------------------------------------------------------------------- /SDR_RA8875/hilbert19A.h: -------------------------------------------------------------------------------- 1 | // Following is a 19 term Hilbert FIR filter 2 | float hilbert19A[]={ 3 | 0.003006666677728199, 4 | 0.000000000000000000, 5 | 0.017439390086760032, 6 | 0.000000000000000000, 7 | 0.058235158985840196, 8 | 0.000000000000000000, 9 | 0.161905323559397157, 10 | 0.000000000000000000, 11 | 0.617838316334015092, 12 | 0.000000000000000000, 13 | -0.617838316334015092, 14 | 0.000000000000000000, 15 | -0.161905323559397157, 16 | 0.000000000000000000, 17 | -0.058235158985840196, 18 | 0.000000000000000000, 19 | -0.017439390086760032, 20 | 0.000000000000000000, 21 | -0.003006666677728199}; 22 | -------------------------------------------------------------------------------- /SDR_RA8875/hilbert251A.h: -------------------------------------------------------------------------------- 1 | // Following is 251 term Hilbert FIR filter 2 | float32_t hilbert251A[]={ 3 | 0.0000003255, 4 | 0.0000000000, 5 | 0.0000030702, 6 | 0.0000000000, 7 | 0.0000089286, 8 | 0.0000000000, 9 | 0.0000183061, 10 | 0.0000000000, 11 | 0.0000316287, 12 | 0.0000000000, 13 | 0.0000493436, 14 | 0.0000000000, 15 | 0.0000719193, 16 | 0.0000000000, 17 | 0.0000998451, 18 | 0.0000000000, 19 | 0.0001336320, 20 | 0.0000000000, 21 | 0.0001738120, 22 | 0.0000000000, 23 | 0.0002209393, 24 | 0.0000000000, 25 | 0.0002755899, 26 | 0.0000000000, 27 | 0.0003383625, 28 | 0.0000000000, 29 | 0.0004098790, 30 | 0.0000000000, 31 | 0.0004907853, 32 | 0.0000000000, 33 | 0.0005817525, 34 | 0.0000000000, 35 | 0.0006834782, 36 | 0.0000000000, 37 | 0.0007966881, 38 | 0.0000000000, 39 | 0.0009221383, 40 | 0.0000000000, 41 | 0.0010606178, 42 | 0.0000000000, 43 | 0.0012129515, 44 | 0.0000000000, 45 | 0.0013800041, 46 | 0.0000000000, 47 | 0.0015626848, 48 | 0.0000000000, 49 | 0.0017619529, 50 | 0.0000000000, 51 | 0.0019788241, 52 | 0.0000000000, 53 | 0.0022143787, 54 | 0.0000000000, 55 | 0.0024697715, 56 | 0.0000000000, 57 | 0.0027462425, 58 | 0.0000000000, 59 | 0.0030451312, 60 | 0.0000000000, 61 | 0.0033678928, 62 | 0.0000000000, 63 | 0.0037161183, 64 | 0.0000000000, 65 | 0.0040915578, 66 | 0.0000000000, 67 | 0.0044961498, 68 | 0.0000000000, 69 | 0.0049320558, 70 | 0.0000000000, 71 | 0.0054017033, 72 | 0.0000000000, 73 | 0.0059078375, 74 | 0.0000000000, 75 | 0.0064535860, 76 | 0.0000000000, 77 | 0.0070425380, 78 | 0.0000000000, 79 | 0.0076788436, 80 | 0.0000000000, 81 | 0.0083673390, 82 | 0.0000000000, 83 | 0.0091137048, 84 | 0.0000000000, 85 | 0.0099246683, 86 | 0.0000000000, 87 | 0.0108082660, 88 | 0.0000000000, 89 | 0.0117741868, 90 | 0.0000000000, 91 | 0.0128342256, 92 | 0.0000000000, 93 | 0.0140028938, 94 | 0.0000000000, 95 | 0.0152982506, 96 | 0.0000000000, 97 | 0.0167430570, 98 | 0.0000000000, 99 | 0.0183664064, 100 | 0.0000000000, 101 | 0.0202060801, 102 | 0.0000000000, 103 | 0.0223120327, 104 | 0.0000000000, 105 | 0.0247516963, 106 | 0.0000000000, 107 | 0.0276183140, 108 | 0.0000000000, 109 | 0.0310445375, 110 | 0.0000000000, 111 | 0.0352256211, 112 | 0.0000000000, 113 | 0.0404611696, 114 | 0.0000000000, 115 | 0.0472354231, 116 | 0.0000000000, 117 | 0.0563851215, 118 | 0.0000000000, 119 | 0.0694911881, 120 | 0.0000000000, 121 | 0.0899418673, 122 | 0.0000000000, 123 | 0.1265473875, 124 | 0.0000000000, 125 | 0.2116132716, 126 | 0.0000000000, 127 | 0.6358933477, 128 | 0.0000000000, 129 | -0.6358933478, 130 | 0.0000000000, 131 | -0.2116132717, 132 | 0.0000000000, 133 | -0.1265473876, 134 | 0.0000000000, 135 | -0.0899418674, 136 | 0.0000000000, 137 | -0.0694911882, 138 | 0.0000000000, 139 | -0.0563851216, 140 | 0.0000000000, 141 | -0.0472354232, 142 | 0.0000000000, 143 | -0.0404611697, 144 | 0.0000000000, 145 | -0.0352256212, 146 | 0.0000000000, 147 | -0.0310445376, 148 | 0.0000000000, 149 | -0.0276183141, 150 | 0.0000000000, 151 | -0.0247516964, 152 | 0.0000000000, 153 | -0.0223120328, 154 | 0.0000000000, 155 | -0.0202060802, 156 | 0.0000000000, 157 | -0.0183664065, 158 | 0.0000000000, 159 | -0.0167430571, 160 | 0.0000000000, 161 | -0.0152982507, 162 | 0.0000000000, 163 | -0.0140028939, 164 | 0.0000000000, 165 | -0.0128342257, 166 | 0.0000000000, 167 | -0.0117741869, 168 | 0.0000000000, 169 | -0.0108082661, 170 | 0.0000000000, 171 | -0.0099246684, 172 | 0.0000000000, 173 | -0.0091137049, 174 | 0.0000000000, 175 | -0.0083673391, 176 | 0.0000000000, 177 | -0.0076788437, 178 | 0.0000000000, 179 | -0.0070425381, 180 | 0.0000000000, 181 | -0.0064535861, 182 | 0.0000000000, 183 | -0.0059078376, 184 | 0.0000000000, 185 | -0.0054017034, 186 | 0.0000000000, 187 | -0.0049320559, 188 | 0.0000000000, 189 | -0.0044961499, 190 | 0.0000000000, 191 | -0.0040915579, 192 | 0.0000000000, 193 | -0.0037161184, 194 | 0.0000000000, 195 | -0.0033678929, 196 | 0.0000000000, 197 | -0.0030451313, 198 | 0.0000000000, 199 | -0.0027462426, 200 | 0.0000000000, 201 | -0.0024697716, 202 | 0.0000000000, 203 | -0.0022143788, 204 | 0.0000000000, 205 | -0.0019788242, 206 | 0.0000000000, 207 | -0.0017619530, 208 | 0.0000000000, 209 | -0.0015626849, 210 | 0.0000000000, 211 | -0.0013800042, 212 | 0.0000000000, 213 | -0.0012129516, 214 | 0.0000000000, 215 | -0.0010606179, 216 | 0.0000000000, 217 | -0.0009221384, 218 | 0.0000000000, 219 | -0.0007966882, 220 | 0.0000000000, 221 | -0.0006834783, 222 | 0.0000000000, 223 | -0.0005817526, 224 | 0.0000000000, 225 | -0.0004907854, 226 | 0.0000000000, 227 | -0.0004098791, 228 | 0.0000000000, 229 | -0.0003383626, 230 | 0.0000000000, 231 | -0.0002755900, 232 | 0.0000000000, 233 | -0.0002209394, 234 | 0.0000000000, 235 | -0.0001738121, 236 | 0.0000000000, 237 | -0.0001336321, 238 | 0.0000000000, 239 | -0.0000998452, 240 | 0.0000000000, 241 | -0.0000719194, 242 | 0.0000000000, 243 | -0.0000493437, 244 | 0.0000000000, 245 | -0.0000316288, 246 | 0.0000000000, 247 | -0.0000183062, 248 | 0.0000000000, 249 | -0.0000089287, 250 | 0.0000000000, 251 | -0.0000030703, 252 | 0.0000000000, 253 | -0.0000003256}; 254 | --------------------------------------------------------------------------------