├── LICENSE ├── Makefile ├── README.md ├── hl2_tcp.c └── hl2_tx.c /LICENSE: -------------------------------------------------------------------------------- 1 | Mozilla Public License Version 2.0 2 | ================================== 3 | 4 | 1. Definitions 5 | -------------- 6 | 7 | 1.1. "Contributor" 8 | means each individual or legal entity that creates, contributes to 9 | the creation of, or owns Covered Software. 10 | 11 | 1.2. "Contributor Version" 12 | means the combination of the Contributions of others (if any) used 13 | by a Contributor and that particular Contributor's Contribution. 14 | 15 | 1.3. "Contribution" 16 | means Covered Software of a particular Contributor. 17 | 18 | 1.4. "Covered Software" 19 | means Source Code Form to which the initial Contributor has attached 20 | the notice in Exhibit A, the Executable Form of such Source Code 21 | Form, and Modifications of such Source Code Form, in each case 22 | including portions thereof. 23 | 24 | 1.5. "Incompatible With Secondary Licenses" 25 | means 26 | 27 | (a) that the initial Contributor has attached the notice described 28 | in Exhibit B to the Covered Software; or 29 | 30 | (b) that the Covered Software was made available under the terms of 31 | version 1.1 or earlier of the License, but not also under the 32 | terms of a Secondary License. 33 | 34 | 1.6. "Executable Form" 35 | means any form of the work other than Source Code Form. 36 | 37 | 1.7. "Larger Work" 38 | means a work that combines Covered Software with other material, in 39 | a separate file or files, that is not Covered Software. 40 | 41 | 1.8. "License" 42 | means this document. 43 | 44 | 1.9. "Licensable" 45 | means having the right to grant, to the maximum extent possible, 46 | whether at the time of the initial grant or subsequently, any and 47 | all of the rights conveyed by this License. 48 | 49 | 1.10. "Modifications" 50 | means any of the following: 51 | 52 | (a) any file in Source Code Form that results from an addition to, 53 | deletion from, or modification of the contents of Covered 54 | Software; or 55 | 56 | (b) any new file in Source Code Form that contains any Covered 57 | Software. 58 | 59 | 1.11. "Patent Claims" of a Contributor 60 | means any patent claim(s), including without limitation, method, 61 | process, and apparatus claims, in any patent Licensable by such 62 | Contributor that would be infringed, but for the grant of the 63 | License, by the making, using, selling, offering for sale, having 64 | made, import, or transfer of either its Contributions or its 65 | Contributor Version. 66 | 67 | 1.12. "Secondary License" 68 | means either the GNU General Public License, Version 2.0, the GNU 69 | Lesser General Public License, Version 2.1, the GNU Affero General 70 | Public License, Version 3.0, or any later versions of those 71 | licenses. 72 | 73 | 1.13. "Source Code Form" 74 | means the form of the work preferred for making modifications. 75 | 76 | 1.14. "You" (or "Your") 77 | means an individual or a legal entity exercising rights under this 78 | License. For legal entities, "You" includes any entity that 79 | controls, is controlled by, or is under common control with You. For 80 | purposes of this definition, "control" means (a) the power, direct 81 | or indirect, to cause the direction or management of such entity, 82 | whether by contract or otherwise, or (b) ownership of more than 83 | fifty percent (50%) of the outstanding shares or beneficial 84 | ownership of such entity. 85 | 86 | 2. License Grants and Conditions 87 | -------------------------------- 88 | 89 | 2.1. Grants 90 | 91 | Each Contributor hereby grants You a world-wide, royalty-free, 92 | non-exclusive license: 93 | 94 | (a) under intellectual property rights (other than patent or trademark) 95 | Licensable by such Contributor to use, reproduce, make available, 96 | modify, display, perform, distribute, and otherwise exploit its 97 | Contributions, either on an unmodified basis, with Modifications, or 98 | as part of a Larger Work; and 99 | 100 | (b) under Patent Claims of such Contributor to make, use, sell, offer 101 | for sale, have made, import, and otherwise transfer either its 102 | Contributions or its Contributor Version. 103 | 104 | 2.2. Effective Date 105 | 106 | The licenses granted in Section 2.1 with respect to any Contribution 107 | become effective for each Contribution on the date the Contributor first 108 | distributes such Contribution. 109 | 110 | 2.3. Limitations on Grant Scope 111 | 112 | The licenses granted in this Section 2 are the only rights granted under 113 | this License. No additional rights or licenses will be implied from the 114 | distribution or licensing of Covered Software under this License. 115 | Notwithstanding Section 2.1(b) above, no patent license is granted by a 116 | Contributor: 117 | 118 | (a) for any code that a Contributor has removed from Covered Software; 119 | or 120 | 121 | (b) for infringements caused by: (i) Your and any other third party's 122 | modifications of Covered Software, or (ii) the combination of its 123 | Contributions with other software (except as part of its Contributor 124 | Version); or 125 | 126 | (c) under Patent Claims infringed by Covered Software in the absence of 127 | its Contributions. 128 | 129 | This License does not grant any rights in the trademarks, service marks, 130 | or logos of any Contributor (except as may be necessary to comply with 131 | the notice requirements in Section 3.4). 132 | 133 | 2.4. Subsequent Licenses 134 | 135 | No Contributor makes additional grants as a result of Your choice to 136 | distribute the Covered Software under a subsequent version of this 137 | License (see Section 10.2) or under the terms of a Secondary License (if 138 | permitted under the terms of Section 3.3). 139 | 140 | 2.5. Representation 141 | 142 | Each Contributor represents that the Contributor believes its 143 | Contributions are its original creation(s) or it has sufficient rights 144 | to grant the rights to its Contributions conveyed by this License. 145 | 146 | 2.6. Fair Use 147 | 148 | This License is not intended to limit any rights You have under 149 | applicable copyright doctrines of fair use, fair dealing, or other 150 | equivalents. 151 | 152 | 2.7. Conditions 153 | 154 | Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted 155 | in Section 2.1. 156 | 157 | 3. Responsibilities 158 | ------------------- 159 | 160 | 3.1. Distribution of Source Form 161 | 162 | All distribution of Covered Software in Source Code Form, including any 163 | Modifications that You create or to which You contribute, must be under 164 | the terms of this License. You must inform recipients that the Source 165 | Code Form of the Covered Software is governed by the terms of this 166 | License, and how they can obtain a copy of this License. You may not 167 | attempt to alter or restrict the recipients' rights in the Source Code 168 | Form. 169 | 170 | 3.2. Distribution of Executable Form 171 | 172 | If You distribute Covered Software in Executable Form then: 173 | 174 | (a) such Covered Software must also be made available in Source Code 175 | Form, as described in Section 3.1, and You must inform recipients of 176 | the Executable Form how they can obtain a copy of such Source Code 177 | Form by reasonable means in a timely manner, at a charge no more 178 | than the cost of distribution to the recipient; and 179 | 180 | (b) You may distribute such Executable Form under the terms of this 181 | License, or sublicense it under different terms, provided that the 182 | license for the Executable Form does not attempt to limit or alter 183 | the recipients' rights in the Source Code Form under this License. 184 | 185 | 3.3. Distribution of a Larger Work 186 | 187 | You may create and distribute a Larger Work under terms of Your choice, 188 | provided that You also comply with the requirements of this License for 189 | the Covered Software. If the Larger Work is a combination of Covered 190 | Software with a work governed by one or more Secondary Licenses, and the 191 | Covered Software is not Incompatible With Secondary Licenses, this 192 | License permits You to additionally distribute such Covered Software 193 | under the terms of such Secondary License(s), so that the recipient of 194 | the Larger Work may, at their option, further distribute the Covered 195 | Software under the terms of either this License or such Secondary 196 | License(s). 197 | 198 | 3.4. Notices 199 | 200 | You may not remove or alter the substance of any license notices 201 | (including copyright notices, patent notices, disclaimers of warranty, 202 | or limitations of liability) contained within the Source Code Form of 203 | the Covered Software, except that You may alter any license notices to 204 | the extent required to remedy known factual inaccuracies. 205 | 206 | 3.5. Application of Additional Terms 207 | 208 | You may choose to offer, and to charge a fee for, warranty, support, 209 | indemnity or liability obligations to one or more recipients of Covered 210 | Software. However, You may do so only on Your own behalf, and not on 211 | behalf of any Contributor. You must make it absolutely clear that any 212 | such warranty, support, indemnity, or liability obligation is offered by 213 | You alone, and You hereby agree to indemnify every Contributor for any 214 | liability incurred by such Contributor as a result of warranty, support, 215 | indemnity or liability terms You offer. You may include additional 216 | disclaimers of warranty and limitations of liability specific to any 217 | jurisdiction. 218 | 219 | 4. Inability to Comply Due to Statute or Regulation 220 | --------------------------------------------------- 221 | 222 | If it is impossible for You to comply with any of the terms of this 223 | License with respect to some or all of the Covered Software due to 224 | statute, judicial order, or regulation then You must: (a) comply with 225 | the terms of this License to the maximum extent possible; and (b) 226 | describe the limitations and the code they affect. Such description must 227 | be placed in a text file included with all distributions of the Covered 228 | Software under this License. Except to the extent prohibited by statute 229 | or regulation, such description must be sufficiently detailed for a 230 | recipient of ordinary skill to be able to understand it. 231 | 232 | 5. Termination 233 | -------------- 234 | 235 | 5.1. The rights granted under this License will terminate automatically 236 | if You fail to comply with any of its terms. However, if You become 237 | compliant, then the rights granted under this License from a particular 238 | Contributor are reinstated (a) provisionally, unless and until such 239 | Contributor explicitly and finally terminates Your grants, and (b) on an 240 | ongoing basis, if such Contributor fails to notify You of the 241 | non-compliance by some reasonable means prior to 60 days after You have 242 | come back into compliance. Moreover, Your grants from a particular 243 | Contributor are reinstated on an ongoing basis if such Contributor 244 | notifies You of the non-compliance by some reasonable means, this is the 245 | first time You have received notice of non-compliance with this License 246 | from such Contributor, and You become compliant prior to 30 days after 247 | Your receipt of the notice. 248 | 249 | 5.2. If You initiate litigation against any entity by asserting a patent 250 | infringement claim (excluding declaratory judgment actions, 251 | counter-claims, and cross-claims) alleging that a Contributor Version 252 | directly or indirectly infringes any patent, then the rights granted to 253 | You by any and all Contributors for the Covered Software under Section 254 | 2.1 of this License shall terminate. 255 | 256 | 5.3. In the event of termination under Sections 5.1 or 5.2 above, all 257 | end user license agreements (excluding distributors and resellers) which 258 | have been validly granted by You or Your distributors under this License 259 | prior to termination shall survive termination. 260 | 261 | ************************************************************************ 262 | * * 263 | * 6. Disclaimer of Warranty * 264 | * ------------------------- * 265 | * * 266 | * Covered Software is provided under this License on an "as is" * 267 | * basis, without warranty of any kind, either expressed, implied, or * 268 | * statutory, including, without limitation, warranties that the * 269 | * Covered Software is free of defects, merchantable, fit for a * 270 | * particular purpose or non-infringing. The entire risk as to the * 271 | * quality and performance of the Covered Software is with You. * 272 | * Should any Covered Software prove defective in any respect, You * 273 | * (not any Contributor) assume the cost of any necessary servicing, * 274 | * repair, or correction. This disclaimer of warranty constitutes an * 275 | * essential part of this License. No use of any Covered Software is * 276 | * authorized under this License except under this disclaimer. * 277 | * * 278 | ************************************************************************ 279 | 280 | ************************************************************************ 281 | * * 282 | * 7. Limitation of Liability * 283 | * -------------------------- * 284 | * * 285 | * Under no circumstances and under no legal theory, whether tort * 286 | * (including negligence), contract, or otherwise, shall any * 287 | * Contributor, or anyone who distributes Covered Software as * 288 | * permitted above, be liable to You for any direct, indirect, * 289 | * special, incidental, or consequential damages of any character * 290 | * including, without limitation, damages for lost profits, loss of * 291 | * goodwill, work stoppage, computer failure or malfunction, or any * 292 | * and all other commercial damages or losses, even if such party * 293 | * shall have been informed of the possibility of such damages. This * 294 | * limitation of liability shall not apply to liability for death or * 295 | * personal injury resulting from such party's negligence to the * 296 | * extent applicable law prohibits such limitation. Some * 297 | * jurisdictions do not allow the exclusion or limitation of * 298 | * incidental or consequential damages, so this exclusion and * 299 | * limitation may not apply to You. * 300 | * * 301 | ************************************************************************ 302 | 303 | 8. Litigation 304 | ------------- 305 | 306 | Any litigation relating to this License may be brought only in the 307 | courts of a jurisdiction where the defendant maintains its principal 308 | place of business and such litigation shall be governed by laws of that 309 | jurisdiction, without reference to its conflict-of-law provisions. 310 | Nothing in this Section shall prevent a party's ability to bring 311 | cross-claims or counter-claims. 312 | 313 | 9. Miscellaneous 314 | ---------------- 315 | 316 | This License represents the complete agreement concerning the subject 317 | matter hereof. If any provision of this License is held to be 318 | unenforceable, such provision shall be reformed only to the extent 319 | necessary to make it enforceable. Any law or regulation which provides 320 | that the language of a contract shall be construed against the drafter 321 | shall not be used to construe this License against a Contributor. 322 | 323 | 10. Versions of the License 324 | --------------------------- 325 | 326 | 10.1. New Versions 327 | 328 | Mozilla Foundation is the license steward. Except as provided in Section 329 | 10.3, no one other than the license steward has the right to modify or 330 | publish new versions of this License. Each version will be given a 331 | distinguishing version number. 332 | 333 | 10.2. Effect of New Versions 334 | 335 | You may distribute the Covered Software under the terms of the version 336 | of the License under which You originally received the Covered Software, 337 | or under the terms of any subsequent version published by the license 338 | steward. 339 | 340 | 10.3. Modified Versions 341 | 342 | If you create software not governed by this License, and you want to 343 | create a new license for such software, you may create and use a 344 | modified version of this License if you rename the license and remove 345 | any references to the name of the license steward (except to note that 346 | such modified license differs from this License). 347 | 348 | 10.4. Distributing Source Code Form that is Incompatible With Secondary 349 | Licenses 350 | 351 | If You choose to distribute Source Code Form that is Incompatible With 352 | Secondary Licenses under the terms of this version of the License, the 353 | notice described in Exhibit B of this License must be attached. 354 | 355 | Exhibit A - Source Code Form License Notice 356 | ------------------------------------------- 357 | 358 | This Source Code Form is subject to the terms of the Mozilla Public 359 | License, v. 2.0. If a copy of the MPL was not distributed with this 360 | file, You can obtain one at http://mozilla.org/MPL/2.0/. 361 | 362 | If it is not possible or desirable to put the notice in a particular 363 | file, then You may include the notice in a location (such as a LICENSE 364 | file in a relevant directory) where a recipient would be likely to look 365 | for such a notice. 366 | 367 | You may add additional accurate notices of copyright ownership. 368 | 369 | Exhibit B - "Incompatible With Secondary Licenses" Notice 370 | --------------------------------------------------------- 371 | 372 | This Source Code Form is "Incompatible With Secondary Licenses", as 373 | defined by the Mozilla Public License, v. 2.0. 374 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # hl2_tcp makefile 3 | # 4 | 5 | OS := $(shell uname) 6 | 7 | ifeq ($(OS), Darwin) 8 | CC = clang 9 | LL = -lm -lpthread 10 | else 11 | ifeq ($(OS), Linux) 12 | CC = cc 13 | LL = -lm -lpthread 14 | STD = -std=c99 15 | else 16 | $(error OS not detected) 17 | endif 18 | endif 19 | 20 | FLAGS = -Os 21 | # FLAGS = -g 22 | 23 | FILES_2 = hl2_tcp.c hl2_tx.c 24 | 25 | all: hl2_tcp 26 | 27 | hl2_tcp: $(FILES_2) 28 | $(CC) $(FILES_2) $(LL) -lpthread -Os -o hl2_tcp 29 | 30 | clean: 31 | rm -f hl2_tcp 32 | 33 | # 34 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## hl2_tcp 2 | 3 | This repository contains source code for hl2_tcp, 4 | a rtl_tcp server for [Hermes Lite 2](http://www.hermeslite.com) 5 | SDR radio. 6 | 7 | The Hermes-Lite is a low-cost 8 | direct conversion 9 | software defined amateur radio HF transceiver 10 | based on the AD9866 broadband modem chip, 11 | an Altera Cyclone IV EP4CE22 FPGA, 12 | and the [HPSDR/Hermes SDR project](http://openhpsdr.org). 13 | 14 | 15 | The hl2_tcp server 16 | can connect to a Hermes Lite 2 SDR 17 | via UDP over ethernet, 18 | transcode received RF IQ samples, 19 | and then serve that data 20 | via the rtl_tcp protocol. 21 | 22 | [rtl_tcp](https://github.com/osmocom/rtl-sdr) 23 | is a command-line tool developed by OsmoCom and others, 24 | for various Realtek RTL2832-based DVB-T USB peripherals, 25 | to serve IQ samples from those USB devices over TCP. 26 | There are multiple SDR applications, 27 | available for Linux, macOS, or Wintel systems, 28 | that can connect to a local or remote SDR radio peripheral 29 | via the rtl_tcp protocol. 30 | This server allows using those SDR applications 31 | with a Hermes Lite 2 SDR, 32 | but only if the application supports the 33 | HL2 sample rates (48k, 96k, 192k, and 384k). 34 | Among the SDR applications 35 | supporting those sample rates 36 | are the iOS and macOS apps: 37 | _rtl_tcp SDR_ 38 | and 39 | _SDR Receiver_, 40 | allowing HL2 SDR reception an iPhone, iPad, or Mac. 41 | 42 | Usage: 43 | 44 | hl2_tcp -d 45 | 46 | Discovers Hermes Lite 2 IP Address. 47 | Prints random diagnostics. 48 | 49 | hl2_tcp -d xx.yy.zz.aa 50 | 51 | Discovers HL2 IP Address by scanning the subnet xx.yy.zz.* 52 | 53 | hl2_tcp -a Hermes_IP_Addr [-p tcp_server_port] [-b 8/16] 54 | 55 | Starts a server for the rtl_tcp protocol 56 | on a local TCP server port (default rtl_tcp port 1234) 57 | and waits for a TCP connection. 58 | Upon opening an rcp_tcp TCP connection, 59 | starts a UDP connection to the Hermes Lite 2 60 | at Hermes_IP_Addr on UDP port 1024, 61 | and transcodes OpenHPSDR/Metis UDP data to rtl_tcp TCP data. 62 | Also prints more random diagnostics. 63 | 64 | Add custom rtl_tcp command 0x4D to control HL2 transmit capability. 65 | 66 | Important note: Under macOS Catalina 10.15.7 or later, or macOS Big Sur, 67 | this server may need to be installed and run from an Admin account, 68 | due to new macOS firewall security/privacy features. 69 | 70 | More information on the Hermes Lite 2 can be found on this web sites: 71 | [Hermes-Lite2 wiki](https://github.com/softerhardware/Hermes-Lite2/wiki) 72 | 73 | -- 74 | 75 | rhn@nicholson.com \ 76 | N6YWU \ 77 | http://www.nicholson.com/rhn/ 78 | 79 | License: MPL 2.0 with exhibit B \ 80 | No warrantees implied. 81 | 82 | -- 83 | -------------------------------------------------------------------------------- /hl2_tcp.c: -------------------------------------------------------------------------------- 1 | // 2 | // hl2_tcp.c 3 | // 4 | #define VERSION "v.1.4.105" // 2023-01-05 2021-04-11 5 | // macOS : clang -lm -lpthread -Os -o hl2_tcp hl2_tcp.c hl2_tx.c 6 | // pi : cc -lm -lpthread -Os -o hl2_tcp hl2_tcp.c hl2_tx.c 7 | // (hl2_tx.c) 8 | // 9 | // Serves IQ data using the rtl_tcp protocol 10 | // from an Hermes Lite 2 on port 1024 11 | // to iPv6 port 1234 12 | // 13 | // initial version 2020-01-27 rhn 14 | // 15 | // Copyright 2017,2020,2022 Ronald H Nicholson Jr. All Rights Reserved. 16 | // This code may only be redistributed under terms of 17 | // the Mozilla Public License 2.0 plus Exhibit B (no copyleft exception) 18 | // See: https://www.mozilla.org/en-US/MPL/2.0/ 19 | 20 | // #define DEBUG_MODE_0 21 | 22 | int discover_use_ip = 0; 23 | 24 | #ifdef __clang__ 25 | #endif 26 | 27 | #include 28 | float cwGain1 = 0.0; 29 | int slices = 1; 30 | int sliceLoop = 0; 31 | 32 | int epcnt = 0; 33 | int ep4cnt = 0; 34 | 35 | extern long int random(void);; 36 | int tx_freq ; 37 | int dbugCnt = 0; 38 | 39 | #define TX_OK 40 | // #define NO_MAIN 41 | 42 | #define TITLE ("hl2_tcp ") 43 | #define SOCKET_READ_TIMEOUT ( 30.0 * 60.0 ) // 30 minutes in seconds 44 | // #define SAMPLE_BITS ( 8) // default to match rtl_tcp 45 | #define SAMPLE_BITS (16) // default to match rsp_tcp 46 | // #define SAMPLE_BITS (32) // HPSDR 24-bit->float32 IQ data ? 47 | // #define GAIN8 (4096.0) // default gain ? 48 | #define TCP_PORT (1234) // default rtp_tcp server port 49 | #define HERMES_PORT (1024) // UDP port 50 | 51 | #define RING_BUFFER_ALLOCATION (2L * 1024L * 1024L) // 2MB 52 | #define MAX_NUMBER_OF_START_COMMANDS (8) 53 | #define START_LOOP_DELAY (50000) // microseconds 54 | 55 | #define _POSIX_C_SOURCE 200112L 56 | #include 57 | #include 58 | #include 59 | #include 60 | #include 61 | #include 62 | #include 63 | #include 64 | #include 65 | #include 66 | #include 67 | #include 68 | #include 69 | 70 | #include 71 | #include 72 | #include 73 | #include 74 | #include 75 | #include 76 | #include 77 | 78 | #include 79 | #include 80 | 81 | #ifndef _UNISTD_H_ 82 | int usleep(unsigned long int usec); 83 | #endif 84 | 85 | #ifndef M_PI 86 | #define M_PI (3.14159265358979323846264) 87 | typedef void *caddr_t; 88 | #endif 89 | 90 | static void sighandler(int signum); 91 | void *tcp_connection_handler(void); // main thread 92 | void *udp_rcv_thread_runner(void *param); // on a pthread 93 | 94 | int discover_main(void); 95 | void hl2_stop(void); 96 | void print_hl2_stats(void) ; 97 | void setFilterEnables(void) ; 98 | 99 | uint32_t hl2_ipAddr = 0x7f000001; // 127.0.0.1 == localhost 100 | int portno = TCP_PORT; // 101 | int hl2_running = 0; // Metis response 102 | int udp_running = 0; // udp socket live 103 | int C0_addr = 0; // 104 | 105 | int hl2_sampRate = 192000; // 384000; 106 | int hl2_sampleBits = SAMPLE_BITS; 107 | volatile int hermes_rx_freq = 14100000; // 100k to 30M 108 | volatile int hermes_rx2_freq = 14110000; // 109 | volatile int hermes_rx3_freq = 14120000; // 110 | volatile int hermes_tx_freq = 0; // 111 | volatile int hermes_tx_offset = 0; // 112 | volatile int hermes_lna_gain = 19; // LNA gain -12 to +48 dB 113 | int hermes_tx_drive_level = 0; // 0 .. 15 114 | int hermes_enable_power_amp = 0; // 115 | int hermes_Q5_switch_ext_ptt_lp = 0; 116 | int tx_gear_ratio = 1; 117 | int tx_gear_counter = 0; 118 | volatile int seqNum = 0; // tx sequence number 119 | 120 | int hl2_rcvSeqNum = 0; 121 | int hl2_ep6 = 0; 122 | 123 | // Rx and Tx filters; default no HPF ? 124 | int n2adr_filter_rx = 0; 125 | int n2adr_filter_tx = 0; 126 | 127 | int sendErrorFlag = 0; 128 | // int sampleBits = SAMPLE_BITS; 129 | int sampleRates = 1; 130 | long int totalSamples = 0; 131 | long sampRate = 192000; // 48000 to 384000 132 | long previousSRate = -1; 133 | int gClientSocketID = -1; 134 | 135 | char *ring_buffer_ptr = NULL; 136 | int decimateFlag = 1; 137 | int decimateCntr = 0; 138 | 139 | volatile float gain0 = 32768.0; // 8.0 * GAIN8; 140 | 141 | struct sigaction sigact, sigign; 142 | 143 | int tcp_listen_sockfd = -1; 144 | static volatile int do_exit = 0; 145 | float acc_r = 0.0; // accumulated rounding 146 | float sMax = 0.0; // for debug 147 | float sMin = 0.0; 148 | int sendblockcount = 0; 149 | int threads_running = 0; 150 | 151 | char *hl2_ip_string = "127.0.0.1"; // 0x7f000001 == localhost 152 | 153 | // for TX_OK 154 | long int tcp_tx_cmd = 0; 155 | int hl2_tx_on = 0; // includes hang 156 | int tx_key_down_1 = 0; // Morse code key for hang 157 | int tx_delay = 0; // tx/ptt hold time 158 | int last_key_down = 0; 159 | int tx_param_x = 0; 160 | int tx_param_w = 0; 161 | int tx_dot_offset = 0; // dot Tx df frequency offset 162 | float hl2_tx_lvl = 0.0; 163 | int hl2_tx_drive = 0; 164 | 165 | #ifdef TX_OK 166 | // external transmit data routines 167 | extern void tx_setup(); 168 | extern void tx_cleanup(); 169 | extern int get_tx_key(void) ; // sets MOX bit 170 | extern void tx_block_setup(int seqN); // prepare 2*63 samples 171 | extern void get_tx_sample(int *tx_i, int *tx_q) ; 172 | extern int get_tx_drive(void) ; // 0 .. 15 173 | // extern int get_tx_offset() { return(tx_dot_offset); } // f0 df 174 | extern void resetTxDotQueue() ; 175 | extern int queueTxDotCommand(int k, int on, int off) ; 176 | extern void set_tx_offset(float df); 177 | extern void set_tx_level(float v); 178 | extern void set_tx_drive(float d); 179 | #else 180 | // dummy stubs 181 | void tx_setup() { return; } 182 | void tx_cleanup() { return; } 183 | #define get_tx_key() (0) 184 | #define tx_block_setup(X) // nop 185 | #define get_tx_sample(X,Y) // nop 186 | #define get_tx_drive() (0) 187 | #define get_tx_offset() (0) 188 | #define resetTxDotQueue() (0) 189 | static int queueTxDotCommand(int k, int on, int off) { return 0; } 190 | #endif 191 | 192 | char UsageString1[] 193 | = "Usage: hl2_tcp -a hermes_IPaddr [-p local_port] [-b 8/16]"; 194 | char UsageString2[] 195 | = " hl2_tcp -d "; 196 | 197 | void print_usage_and_exit() 198 | { 199 | printf("%s\n", UsageString1); 200 | printf("%s\n", UsageString2); 201 | exit(0); 202 | } 203 | 204 | int hl2_tcp(void); 205 | 206 | #ifndef NO_MAIN 207 | // int tcp_main(int argc, char *argv[]) 208 | int main(int argc, char *argv[]) 209 | { 210 | if (argc > 1) { 211 | if (strcmp(argv[1], "-d") == 0) { 212 | if (argc > 2) { 213 | hl2_ip_string = argv[2]; 214 | discover_use_ip = 1; 215 | } else { 216 | } 217 | int e = discover_main(); 218 | return(e); 219 | } 220 | if ((argc % 2) != 1) { 221 | print_usage_and_exit(); 222 | } 223 | for (int arg=3; arg<=argc; arg+=2) { 224 | if (strcmp(argv[arg-2], "-p") == 0) { 225 | portno = atoi(argv[arg-1]); 226 | if (portno == 0) { 227 | printf("invalid port number entry %s\n", argv[arg-1]); 228 | exit(0); 229 | } 230 | } else if (strcmp(argv[arg-2], "-b") == 0) { 231 | if (strcmp(argv[arg-1],"16") == 0) { 232 | hl2_sampleBits = 16; 233 | } else if (strcmp(argv[arg-1],"8") == 0) { 234 | hl2_sampleBits = 8; 235 | } else { 236 | print_usage_and_exit(); 237 | } 238 | } else if (strcmp(argv[arg-2], "-a") == 0) { 239 | hl2_ip_string = argv[arg-1]; 240 | } else if (strcmp(argv[arg-2], "-x") == 0) { 241 | tx_param_x = atoi(argv[arg-1]); 242 | } else { 243 | print_usage_and_exit(); 244 | } 245 | } 246 | } else { 247 | print_usage_and_exit(); 248 | } 249 | 250 | return(hl2_tcp()); 251 | } 252 | #endif 253 | 254 | int hl2_tcp() 255 | { 256 | struct sockaddr_in6 serv_addr ; 257 | char client_addr_ipv6[100]; 258 | 259 | printf("hl2_tcp Version %s\n", VERSION); 260 | printf("Will look for Hermes Lite 2 at IP: %s UDP Port: %d \n", 261 | hl2_ip_string, HERMES_PORT); 262 | 263 | ring_buffer_ptr = (char *)malloc(RING_BUFFER_ALLOCATION + 4); 264 | if (ring_buffer_ptr == NULL) { exit(-1); } 265 | bzero(ring_buffer_ptr, RING_BUFFER_ALLOCATION + 2); 266 | 267 | printf("Converts Metis to rtl_tcp format %d-bit IQ samples \n", 268 | hl2_sampleBits); 269 | printf("Starting hl2_tcp server on TCP port %d\n", portno); 270 | 271 | tx_setup(); 272 | 273 | sigact.sa_handler = sighandler; 274 | sigemptyset(&sigact.sa_mask); 275 | sigact.sa_flags = 0; 276 | sigaction(SIGINT, &sigact, NULL); 277 | sigaction(SIGTERM, &sigact, NULL); 278 | sigaction(SIGQUIT, &sigact, NULL); 279 | #ifdef __APPLE__ 280 | signal(SIGPIPE, SIG_IGN); 281 | #else 282 | sigign.sa_handler = SIG_IGN; 283 | sigaction(SIGPIPE, &sigign, NULL); 284 | #endif 285 | 286 | previousSRate = sampRate; 287 | 288 | // printf("\nhl2_tcp server started on port %d\n", portno); 289 | 290 | tcp_listen_sockfd = socket(AF_INET6, SOCK_STREAM, 0); 291 | if (tcp_listen_sockfd < 0) { 292 | printf("ERROR opening socket"); 293 | return(-1); 294 | } 295 | 296 | struct linger ling = {1,0}; 297 | int rr = 1; 298 | setsockopt(tcp_listen_sockfd, SOL_SOCKET, SO_REUSEADDR, 299 | (char *)&rr, sizeof(int)); 300 | setsockopt(tcp_listen_sockfd, SOL_SOCKET, SO_LINGER, 301 | (char *)&ling, sizeof(ling)); 302 | 303 | bzero((char *) &serv_addr, sizeof(serv_addr)); 304 | serv_addr.sin6_flowinfo = 0; 305 | serv_addr.sin6_family = AF_INET6; 306 | serv_addr.sin6_addr = in6addr_any; 307 | serv_addr.sin6_port = htons(portno); 308 | 309 | // Sockets Layer Call: bind() 310 | if (bind( tcp_listen_sockfd, (struct sockaddr *)&serv_addr, 311 | sizeof(serv_addr) ) < 0) { 312 | printf("ERROR on bind to listen\n"); 313 | return(-1); 314 | } 315 | 316 | listen(tcp_listen_sockfd, 5); 317 | fprintf(stdout, "listening for socket connection \n"); 318 | 319 | while (1) { 320 | 321 | // accept a connection 322 | 323 | struct sockaddr_in6 cli_addr; 324 | socklen_t claddrlen = sizeof(cli_addr); 325 | gClientSocketID = accept( tcp_listen_sockfd, 326 | (struct sockaddr *) &cli_addr, 327 | &claddrlen ); 328 | if (gClientSocketID < 0) { 329 | printf("ERROR on accept\n"); 330 | break; 331 | } 332 | 333 | inet_ntop(AF_INET6, &(cli_addr.sin6_addr), client_addr_ipv6, 100); 334 | printf("\nConnected to client with IP address: %s\n", 335 | client_addr_ipv6); 336 | 337 | tcp_connection_handler(); 338 | 339 | printf("tcp connection ended \n"); 340 | } 341 | 342 | udp_running = -1; 343 | hl2_stop(); 344 | tx_cleanup(); 345 | 346 | fflush(stdout); 347 | return 0; 348 | } // main 349 | 350 | static void sighandler(int signum) 351 | { 352 | fprintf(stderr, "Signal caught, exiting!\n"); 353 | fflush(stderr); 354 | close(tcp_listen_sockfd); 355 | if (gClientSocketID != 0) { 356 | close(gClientSocketID); 357 | gClientSocketID = -1; 358 | } 359 | udp_running = -1; 360 | hl2_stop(); 361 | tx_cleanup(); 362 | exit(-1); 363 | // do_exit = 1; 364 | } 365 | 366 | int stop_send_thread = 0; 367 | int thread_counter = 0; 368 | int thread_running = 0; 369 | 370 | // circular buffer / ring buffer 371 | 372 | // char *ring_buffer_ptr = NULL; 373 | int ring_buffer_size = RING_BUFFER_ALLOCATION; 374 | volatile long int ring_wr_count = 0; 375 | volatile long int ring_wr_index = 0; 376 | volatile long int ring_rd_index = 0; 377 | 378 | void ring_init() 379 | { 380 | ring_wr_count = 0; 381 | ring_wr_index = 0; 382 | ring_rd_index = 0; 383 | } 384 | 385 | int ring_data_available() 386 | { 387 | long int n = 0; 388 | long int w_index = ring_wr_index; // 389 | long int r_index = ring_rd_index; // 390 | n = w_index - r_index; 391 | if (n < 0) { n += ring_buffer_size; } 392 | if (n < 0) { n = 0; } // error condition ? 393 | if (n >= ring_buffer_size) { n = 0; } // error condition 394 | return(n); 395 | } 396 | 397 | int ring_write(unsigned char *from_ptr, int amount) 398 | { 399 | int wrap = 0; 400 | long int w_index = ring_wr_index; // my index 401 | long int r_index = ring_rd_index; // other threads index 402 | if ( ring_buffer_ptr == NULL ) { return(-1); } 403 | if ( (w_index < 0) 404 | || (w_index >= ring_buffer_size) ) { return(-1); } // error ! 405 | if (decimateFlag > 1) { 406 | int i; 407 | for (i = 0; i < amount; i += 2) { 408 | if (decimateCntr == 0) { 409 | ring_buffer_ptr[w_index ] = from_ptr[i ]; 410 | ring_buffer_ptr[w_index+1] = from_ptr[i+1]; 411 | w_index += 2; 412 | if (w_index >= ring_buffer_size) { w_index = 0; } 413 | } 414 | decimateCntr += 1; 415 | if (decimateCntr >= decimateFlag) { decimateCntr = 0; } 416 | } 417 | } else if (w_index + amount < ring_buffer_size) { 418 | memcpy(&ring_buffer_ptr[w_index], from_ptr, amount); 419 | w_index += amount; 420 | } else { 421 | int i; 422 | for (i = 0; i < amount; i += 1) { 423 | ring_buffer_ptr[w_index] = from_ptr[i]; 424 | w_index += 1; 425 | if (w_index >= ring_buffer_size) { w_index = 0; } 426 | } 427 | } 428 | // 429 | /// ToDo: insert memory barrier here 430 | // 431 | ring_wr_index = w_index; // update lock free input info 432 | int m = ring_data_available(); 433 | if (m > ring_buffer_size/2) { wrap = 1; } 434 | ring_wr_count += amount; // assume no decimate 435 | return(wrap); 436 | } 437 | 438 | int ring_read(unsigned char *to_ptr, int amount, int always) 439 | { 440 | int bytes_read = 0; 441 | long int r_index = ring_rd_index; // my index 442 | long int w_index = ring_wr_index; // other threads index 443 | long int available = w_index - r_index; 444 | if (available < 0) { available += ring_buffer_size; } 445 | if ( ring_buffer_ptr == NULL ) { return(-1); } 446 | if ( to_ptr == NULL ) { return(-1); } 447 | if (always != 0) { 448 | bzero(to_ptr, amount); 449 | } 450 | if (available <= 0) { return(bytes_read); } 451 | long int n = amount; 452 | if (n > available) { n = available; } // min(n, available) 453 | if (r_index + n < ring_buffer_size) { 454 | memcpy(to_ptr, &ring_buffer_ptr[r_index], n); 455 | r_index += n; 456 | } else { 457 | int i; 458 | for (i = 0; i < n; i += 1) { 459 | to_ptr[i] = ring_buffer_ptr[r_index]; 460 | r_index += 1; 461 | if (r_index >= ring_buffer_size) { r_index = 0; } 462 | } 463 | } 464 | bytes_read = n; 465 | ring_rd_index = r_index; // update lock free extract info 466 | return(bytes_read); 467 | } 468 | 469 | float tmpFPBuf[4*32768]; 470 | uint8_t tmpBuf[ 4*32768]; 471 | long int *param = NULL; 472 | 473 | int tcp_send_poll() 474 | { 475 | int sz0 = 1408; // MTU size or 1008 ?? 476 | int pad = 32768 * 2; 477 | ssize_t b = 0; 478 | int send_sockfd = gClientSocketID ; 479 | 480 | if (send_sockfd > 0) { 481 | if (ring_data_available() >= (sz0 + pad)) { 482 | int sz = ring_read(tmpBuf, sz0, 0); 483 | if (sz > 0) { 484 | if (totalSamples == 0) { 485 | // fprintf(stderr, "hl2 udp IQ data received \n"); 486 | } 487 | #ifdef __APPLE__ 488 | b = send(send_sockfd, tmpBuf, sz, 0); 489 | #else 490 | b = send(send_sockfd, tmpBuf, sz, MSG_NOSIGNAL); 491 | #endif 492 | if (b <= 0) { sendErrorFlag = -1; } 493 | if (totalSamples == 0) { 494 | fprintf(stderr, 495 | "Started rtl_tcp IQ streaming with %ld bytes\n", b); 496 | } 497 | totalSamples += sz; 498 | sendblockcount += 1; 499 | } 500 | pad = 0; 501 | } 502 | } 503 | return(b); 504 | } 505 | 506 | int hl2_udp_setup(void); 507 | void hl2_send_start_cmds(int n); 508 | void hl2_udp_rcv(int loopFlag); 509 | int hl2_udp_rcv_end(void); 510 | 511 | void *tcp_connection_handler() 512 | { 513 | char buffer[256]; 514 | int m = 0; 515 | int printCmdBytes = 0; // 516 | int i; 517 | 518 | if (do_exit != 0) { return(NULL); } 519 | 520 | if (1) { // send 12 or 16-byte rtl_tcp header 521 | ssize_t b = 0; 522 | int sz = 16; 523 | if (hl2_sampleBits == 8) { sz = 12; } 524 | // "HL20" in 16 byte header 525 | char header[16] = { 0x48,0x4C,0x32,0x30, 526 | 0x30,0x30,0x30+sampleRates,0x30+hl2_sampleBits, 527 | 0,0,0,1, 0,0,0,2 }; 528 | #ifdef __APPLE__ 529 | b = send(gClientSocketID, header, sz, 0); 530 | #else 531 | b = send(gClientSocketID, header, sz, MSG_NOSIGNAL); 532 | #endif 533 | /* 534 | fprintf(stdout, "rtl_tcp header sent , %d bytes\n", n); // 535 | fflush(stdout); 536 | */ 537 | } 538 | 539 | sendErrorFlag = 0; 540 | stop_send_thread = 0; 541 | ring_wr_index = 0; 542 | ring_rd_index = 0; 543 | 544 | param = (long int *)malloc(4 * sizeof(long int)); /// ToDo: fix leak 545 | for (i=0;i<4;i++) { param[i] = 0; } 546 | 547 | if (hl2_running == 0) { 548 | ring_init(); 549 | resetTxDotQueue() ; 550 | hl2_udp_setup(); 551 | hl2_send_start_cmds(1); 552 | 553 | pthread_t udp_rcv_thread; 554 | if ( pthread_create( &udp_rcv_thread, 555 | NULL , 556 | udp_rcv_thread_runner, 557 | (void *)param ) < 0 ) { 558 | printf("could not create udp streaming thread"); 559 | return(NULL); 560 | } else { 561 | printf("udp streaming thread started \n"); 562 | } 563 | 564 | int n = MAX_NUMBER_OF_START_COMMANDS; 565 | hl2_send_start_cmds(n); 566 | } 567 | 568 | acc_r = 0.0; 569 | totalSamples = 0; 570 | // printf("hl2 start status = %d\n", m); 571 | if (m < 0) { exit(-1); } 572 | usleep(250L * 1000L); 573 | 574 | // set a timeout so receive call won't block forever 575 | struct timeval timeout; 576 | timeout.tv_sec = SOCKET_READ_TIMEOUT; // seconds 577 | timeout.tv_usec = 0; 578 | setsockopt( gClientSocketID, SOL_SOCKET, SO_RCVTIMEO, 579 | &timeout, sizeof(timeout) ); 580 | 581 | ssize_t b = 1; 582 | while ((b > 0) && (sendErrorFlag == 0)) { 583 | int i, j; 584 | // receive 5 byte commands (or a multiple thereof) 585 | memset(buffer,0, 256); 586 | b = recv(gClientSocketID, buffer, 255, 0); 587 | if ((b <= 0) || (sendErrorFlag != 0)) { 588 | udp_running = -1; 589 | close(gClientSocketID); 590 | gClientSocketID = -1; 591 | // fprintf(stdout, "hl2 stop status = %d\n", m); 592 | fflush(stdout); 593 | break; 594 | } 595 | if (b > 0) { 596 | for (i=0; i < b; i+=5) { 597 | // decode 5 byte rtl_tcp command messages 598 | int msg = 0x00ff & buffer[i]; 599 | if (printCmdBytes) { printf("0x%02x ", msg); } 600 | int data = 0; 601 | for (j=1;j<5;j++) { 602 | int byte = (0x00ff & buffer[i+j]); 603 | data = (256 * data) + byte; 604 | if (printCmdBytes) { printf("0x%02x ", byte); } 605 | } 606 | if (printCmdBytes) { printf(" = %d\n", data); } 607 | 608 | if (msg == 0x01) { // set frequency 609 | int f0 = data; 610 | if (f0 >= 100000 && f0 <= 30000000) { 611 | hermes_rx_freq = f0; // hl2 612 | setFilterEnables(); 613 | // hermes_tx_offset = get_tx_offset(); 614 | } 615 | fprintf(stdout, "setting frequency to: %d\n", f0); 616 | } else if (msg == 0x02) { // set sample rate 617 | int r = data; 618 | if ( (r == 48000) 619 | || (r == 96000) 620 | || (r == 192000) 621 | || (r == 384000)) { 622 | // if (r != previousSRate) { 623 | sampRate = r; 624 | tx_gear_ratio = r / 48000; 625 | printf("setting samplerate to : %d\n", r); 626 | // } 627 | } else { 628 | // ignore 629 | } 630 | } else if (msg == 0x03) { // other 631 | fprintf(stdout, "message = %d, data = %d\n", msg, data); 632 | } else if (msg == 0x04) { // gain 633 | if ( (hl2_sampleBits == 8) 634 | || (hl2_sampleBits == 16) ) { 635 | // from set gain 0 to 400 636 | float g1 = data; // data : in 10th dB's 637 | float g2 = 0.1 * (float)(data); // undo 10ths 638 | // fprintf(stdout, "setting gain to: %f dB\n", g2); 639 | float g2h = 1.50 * g2 ; 640 | int g9 = 0.0 + roundf(g2h - 12.0); 641 | // hermes_lna_gain : LNA gain -12 to +48 dB 642 | if (g9 < -12) { g9 = -12; } 643 | if (g9 > 48) { g9 = 48; } 644 | hermes_lna_gain = g9; 645 | fprintf(stdout, "set hl2 lna gain to : %d\n", g9); 646 | } 647 | #ifdef TX_OK 648 | } else if (msg == 77) { // 0x4d tx command extension 649 | // command added 2022-12 650 | if (data < 256) { 651 | tcp_tx_cmd = 3 * data; // 381 = 127 * 3 652 | } else { 653 | int data0 = (0xff000000L & data) >> 24; 654 | int data1 = (0x00ff0000L & data) >> 16; 655 | int data2 = (0x0000ff00L & data) >> 8; 656 | int data3 = (0x000000ffL & data) ; 657 | int k = 0; 658 | if (data0 == 68) { // 'D' 659 | // convert milliseconds to Tx samples 660 | int on = 48 * data1; 661 | int off = 48 * data2; 662 | if (on == 0 && off == 0) { 663 | k = 0; 664 | queueTxDotCommand(k, on, off) ; 665 | } else { 666 | k = 1; 667 | queueTxDotCommand(k, on, off) ; 668 | } 669 | } 670 | if (data0 == 70) { // 'F' 671 | // convert to Hz for f0 offset 672 | if (data3 > 127) { data3 = data3 - 256; } 673 | float f0 = 10 * data3; 674 | tx_dot_offset = f0; 675 | set_tx_offset(f0); 676 | } 677 | if (data0 == 76) { // 'L' 678 | float v = 128 * data3; 679 | hl2_tx_lvl = v; 680 | set_tx_level(v); 681 | #ifdef DEBUG_MODE_0 682 | fprintf(stderr, "set tx level %f \n", v); 683 | #endif 684 | } 685 | if (data0 == 66) { // 'B' drive 686 | float d = data3; 687 | hl2_tx_drive = d; 688 | set_tx_drive(d); 689 | #ifdef DEBUG_MODE_0 690 | fprintf(stderr, "set drive %f \n", d); 691 | #endif 692 | } 693 | } 694 | // printf("tcp_tx_cmd = %d \n", tcp_tx_cmd); // 695 | #endif 696 | } else { // other 697 | fprintf(stdout, "message = %d, data = %d\n", msg, data); 698 | if (msg == 8) { 699 | fprintf(stdout, "set agc mode ignored\n"); 700 | } 701 | } 702 | } 703 | } 704 | if (b < 0) { 705 | fprintf(stdout, "read socket timeout %ld \n", b); 706 | fflush(stdout); 707 | } 708 | // loop until error (socket close) or timeout 709 | } ; 710 | 711 | if (m) { 712 | fprintf(stdout,"stopping now 00 \n"); 713 | printf("hl2 stop status = %d\n", m); 714 | } 715 | udp_running = -1; 716 | 717 | close(gClientSocketID); 718 | gClientSocketID = -1; 719 | return(param); 720 | } // tcp_connection_handler() 721 | 722 | // uint8_t tmpBuf[4*32768]; 723 | 724 | typedef union 725 | { 726 | uint32_t i; 727 | float f; 728 | } Float32_t; 729 | 730 | float rand_float_co() 731 | { 732 | Float32_t x; 733 | x.i = 0x3f800000 | (rand() & 0x007fffff); 734 | return(x.f - 1.0f); 735 | } 736 | 737 | // 738 | // 739 | 740 | #define FILTER_HPF (0x40) 741 | #define FILTER_160 (0x01) 742 | #define FILTER_80 (0x02) 743 | #define FILTER_40 (0x04) 744 | #define FILTER_30_20 (0x08) 745 | #define FILTER_17_15 (0x10) 746 | #define FILTER_10 (0x20) 747 | 748 | struct sockaddr_in recv_Addr; 749 | socklen_t addrLen = sizeof(recv_Addr); 750 | unsigned char udpBuffer[1600]; // Original Protocol Command & Control 751 | 752 | // 753 | 754 | double samp_db = 0.0; 755 | float rnd0v = 0.0; 756 | float rnd0u = 0.0; 757 | 758 | float tmp_temperature = 0.0; 759 | float tmp_fwd_power = 0.0; 760 | float tmp_rev_power = 0.0; 761 | float tmp_pa_current = 0.0; 762 | int tmp_temp_count = 0; 763 | int tmp_revp_count = 0; 764 | 765 | float hermes_temperature = 0; 766 | float hermes_fwd_power = 0; 767 | float hermes_rev_power = 0; 768 | float hermes_pa_current = 0; 769 | 770 | int hwCmdState = 0; 771 | int hwCmdSeqNum = 0; 772 | unsigned char hwCmd[8] = { 0,0,0,0,0 }; // 1+4 fpga command bytes 773 | 774 | void *udp_rcv_thread_runner(void *param) 775 | { 776 | if (hl2_running == 0) { 777 | hl2_udp_rcv(1); 778 | hl2_udp_rcv_end(); 779 | } 780 | return(param); 781 | } 782 | 783 | // extract command replies, status, and 24-bit IQ 784 | // transcode to 8 or 16 bit IQ 785 | 786 | int hl2_adcOverload ; 787 | int hl2_txfifoLevel ; 788 | int firmwareVersion ; 789 | 790 | double slice2Pwr = 0.0; 791 | int hl2_clip8_flag = 0; 792 | 793 | float hl2_tx_hang = 0.2; // seconds 794 | int hl2_tx_mode = 0; 795 | 796 | int last_t1 = -1; 797 | 798 | int handleRcvData(unsigned char *hl2Buf, int n) 799 | { 800 | unsigned char *buf = hl2Buf; 801 | int j, jj; 802 | int rcvSeqNum; 803 | double samp_m2 = 0.0; 804 | unsigned char uv[1024]; 805 | 806 | hl2_clip8_flag = 0; 807 | 808 | // gain scaling adjustments 809 | // 012345670123456701234567 HPDSR 24 bits 810 | // ============ ADC 12 bits 811 | // ---------------- TCP 16 bits 812 | // -------- TCP 8 bits 813 | float g8_r = 1.0 / 65536.0; // shift down 16 bits 814 | float g16_r = 1.0 / 4096.0; // shift down 12 bits 815 | 816 | int headerOK = ( (buf[ 0] == 0xEF) 817 | && (buf[ 1] == 0xFE) 818 | && (buf[ 2] == 0x01) ); 819 | int ep = buf[ 3] ; 820 | 821 | if (ep != 6) { 822 | printf("******** ep error \n" ); 823 | return(0); 824 | } 825 | 826 | int syncErr = ( (buf[11 - 3] != 0x7F) 827 | || (buf[11 - 2] != 0x7F) 828 | || (buf[11 - 1] != 0x7F)); 829 | if (syncErr) { return(-1); } 830 | 831 | rcvSeqNum = (buf[4] << 24) | (buf[5] << 16) | (buf[6] << 8) | (buf[7]); 832 | if (rcvSeqNum != (hl2_rcvSeqNum + 1)) { 833 | hl2_ep6 += 1; 834 | // printf("err %d + 1 != %d \n", hl2_rcvSeqNum , rcvSeqNum); 835 | } 836 | hl2_rcvSeqNum = rcvSeqNum; 837 | 838 | for (jj=0; jj<1024; jj+=512) { 839 | int replyBit = (buf[jj+11] & 0x80) ; 840 | int dt = rcvSeqNum - hwCmdSeqNum; 841 | if (replyBit) { 842 | int i; 843 | int cmdEcho = (buf[jj+11] & 0x7F) >> 1; 844 | // printf("******** # %d hw cmd ack 0x%02x : ", dt, cmdEcho); 845 | // for (i=0;i<5;i++) { printf("0x%02x ", buf[jj+11+i]); } 846 | // printf("\n"); 847 | cmdEcho = hwCmd[0]; /// ToDo: test or fix 848 | if ( cmdEcho == hwCmd[0] ) { 849 | hwCmdState = 0; 850 | // command acknowledged ? 851 | // hwCmdSeqNum = rcvSeqNum; 852 | } 853 | if (buf[jj+11] == 0xff) { 854 | hwCmdState = -1; 855 | // fprintf(stdout,"******** hw cmd error \n" ); 856 | } 857 | } 858 | } 859 | 860 | int dtype0 = buf[11 ] >> 3; 861 | int dtype1 = buf[11+512] >> 3; 862 | if (dtype0 == 0) { 863 | int jj = 0; 864 | int kk = 11+jj; 865 | hl2_txfifoLevel = ( (buf[kk+1] << 24) 866 | | (buf[kk+2] << 16) 867 | | (buf[kk+3] << 8) 868 | | (buf[kk+4] ) ); 869 | 870 | hl2_adcOverload = buf[11+jj+1] ; 871 | // hl2_txfifoLevel = buf[11+jj+3] ; 872 | firmwareVersion = buf[11+jj+4] ; 873 | } 874 | if (dtype1 == 0) { 875 | int jj = 512; 876 | int kk = 11+jj; 877 | hl2_txfifoLevel = ( (buf[kk+1] << 24) 878 | | (buf[kk+2] << 16) 879 | | (buf[kk+3] << 8) 880 | | (buf[kk+4] ) ); 881 | 882 | hl2_adcOverload = buf[11+jj+1] ; 883 | // hl2_txfifoLevel = buf[11+jj+3] ; 884 | firmwareVersion = buf[11+jj+4] ; 885 | } 886 | if (dtype0 == 1) { 887 | int jj = 0; 888 | tmp_temperature += ((buf[11+jj+1] << 8) | (buf[11+jj+2])); 889 | tmp_fwd_power += ((buf[11+jj+3] << 8) | (buf[11+jj+4])); 890 | tmp_temp_count += 1; 891 | } 892 | if (dtype1 == 1) { 893 | int jj = 512; 894 | tmp_temperature += ((buf[11+jj+1] << 8) | (buf[11+jj+2])); 895 | tmp_fwd_power += ((buf[11+jj+3] << 8) | (buf[11+jj+4])); 896 | tmp_temp_count += 1; 897 | } 898 | if (dtype0 == 2) { 899 | tmp_rev_power += ((buf[11 + 1] << 8) | (buf[11 + 2])); 900 | tmp_pa_current += ((buf[11 + 3] << 8) | (buf[11 + 4])); 901 | tmp_revp_count += 1; 902 | } 903 | if (dtype1 == 2) { 904 | int jj = 512; 905 | tmp_rev_power += ((buf[11+jj+1] << 8) | (buf[11+jj+2])); 906 | tmp_pa_current += ((buf[11+jj+3] << 8) | (buf[11+jj+4])); 907 | tmp_revp_count += 1; 908 | } 909 | // 1 slice 8..15 step by 8 910 | // 911 | // 2 slices 8..21 step by 14 912 | // 913 | int sfc = 8; 914 | if (slices == 2) { sfc = 14; } 915 | 916 | double scale = 32768.0 * 32768.0 * 2.0; // 33 bit shift 917 | double scale_r = 1.0 / scale; 918 | int16_t *tmp16ptr = (int16_t *)&uv[0]; 919 | int k = 0; 920 | int kk = 0; 921 | for (jj=0; jj<1024; jj+=512) { 922 | for (j=8+jj+8; j<8+jj+512; j += 8) { 923 | int imagp1, realp1; 924 | double u1,v1; 925 | // reversed order IQ 926 | imagp1 = buf[j ] << 24 | buf[j + 1] << 16 | buf[j + 2] << 8; 927 | realp1 = buf[j + 3] << 24 | buf[j + 4] << 16 | buf[j + 5] << 8; 928 | v1 = realp1; 929 | u1 = imagp1; 930 | if (slices == 2) { 931 | int imagp2, realp2; 932 | double u2,v2; 933 | // reversed order IQ 934 | imagp2 = buf[j+6] << 24 | buf[j+7 ] << 16 | buf[j+8 ] << 8; 935 | realp2 = buf[j+9] << 24 | buf[j+10] << 16 | buf[j+11] << 8; 936 | // sddddddd ddddx000 00000000 937 | // 00000000 ssssdddd dddddddx 938 | /// ToDo: // currently 2nd slice data is unused 939 | } 940 | 941 | // transmitter duplex gain reductions 942 | if (hl2_tx_on > 0) { 943 | if (hl2_tx_mode == 55) { // ssb 944 | v1 *= 10.0; 945 | u1 *= 10.0; 946 | } 947 | if (hl2_tx_lvl > 255) { // relative to Tx power 948 | v1 /= (hl2_tx_lvl + 1.0) / 256.0; // ??? 949 | u1 /= (hl2_tx_lvl + 1.0) / 256.0; 950 | } 951 | } 952 | 953 | if (hl2_sampleBits == 16) { // for HERMES !!! 954 | float v2 = g16_r * v1; 955 | float u2 = g16_r * u1; 956 | int vv = (int)roundf(v2); 957 | int uu = (int)roundf(u2); 958 | tmp16ptr[kk ] = vv; 959 | tmp16ptr[kk+1] = uu; 960 | kk += 2; // 2 16-bit samples 961 | k += 4; // is 4 bytes 962 | } else { // convert to 8-bit samples for rtl_tcp compatibility 963 | // magnitude for testing 964 | samp_m2 += u1*u1 + v1*v1; 965 | // scale and add triangular noise shaping (dither) 966 | float vv = g8_r * v1; 967 | float rnd1v = rand_float_co(); 968 | float rv = rnd1v - rnd0v; 969 | vv = vv + rv; 970 | float rvv = roundf(vv); 971 | int vi = (int)rvv; 972 | rnd0v = rnd1v; 973 | float uu = g8_r * u1; 974 | float rnd1u = rand_float_co(); 975 | float ru = rnd1u - rnd0u; 976 | uu = uu + ru; 977 | float ruu = roundf(uu); 978 | int ui = (int)ruu; 979 | rnd0u = rnd1u; 980 | if (vi > 127) { vi = 127; hl2_clip8_flag++; } 981 | if (vi < -128) { vi = -128; hl2_clip8_flag++; } 982 | if (ui > 127) { vi = 127; hl2_clip8_flag++; } 983 | if (ui < -128) { vi = -128; hl2_clip8_flag++; } 984 | // unsigned 8-bit samples 985 | uv[k] = vi + 128; 986 | uv[k+1] = ui + 128; 987 | k += 2; // 2 bytes for 8-bit IQ 988 | } 989 | } 990 | } 991 | ring_write(&uv[0], k); 992 | // 993 | int nSamples = (2 * (512-8))/4; // == 1008/4 == 252 994 | double samp_rms = sqrt(samp_m2 / nSamples) / scale; 995 | if (samp_rms > 0.0) { 996 | samp_db = 20.0 * log10(samp_rms); 997 | } 998 | // 999 | if (tmp_temp_count >= 16) { 1000 | hermes_temperature = tmp_temperature / (float)tmp_temp_count; 1001 | hermes_rev_power = tmp_fwd_power / (float)tmp_temp_count; 1002 | tmp_temperature = 0.0; 1003 | tmp_fwd_power = 0.0; 1004 | tmp_temp_count = 0; 1005 | } 1006 | if (tmp_revp_count >= 16) { 1007 | hermes_fwd_power = tmp_rev_power / (float)tmp_revp_count; 1008 | tmp_rev_power = 0.0; 1009 | 1010 | float tmp2_pa_current ; 1011 | float tmp3_pa_current ; 1012 | tmp2_pa_current = tmp_pa_current / (float)tmp_revp_count; 1013 | tmp3_pa_current = 3.26 * tmp2_pa_current / (4096.0 * 50.0 * 0.04); 1014 | hermes_pa_current = 1270.0 * tmp3_pa_current / 1000.0; 1015 | tmp_pa_current = 0.0; 1016 | tmp_revp_count = 0; 1017 | } 1018 | return(k); 1019 | } 1020 | 1021 | // 1022 | // 1023 | 1024 | uint32_t getDecimalValueOfIPV4_String(const char* ipAddress, int mod) 1025 | { 1026 | uint8_t ipbytes[4]={}; 1027 | int i = 0; 1028 | int8_t j = 3; 1029 | while (ipAddress+i && i 0) { a = mod; } // for testing 1045 | return (a + b + c + d); 1046 | } 1047 | 1048 | /* 1049 | */ 1050 | 1051 | void configStartCmd(char* buf, int flag) 1052 | { 1053 | if (buf == NULL) { return; } 1054 | char myData[64]; 1055 | 1056 | bzero(myData, 64); 1057 | 1058 | myData[0] = 0xef; 1059 | myData[1] = 0xfe; 1060 | myData[2] = 0x04; 1061 | myData[3] = flag; // 0x01; 1062 | bcopy(myData, buf, 64); 1063 | } 1064 | 1065 | void setFilterEnables() // open collector 1066 | { 1067 | n2adr_filter_rx = 0; 1068 | if (hermes_rx_freq > 3000000) { 1069 | n2adr_filter_rx = FILTER_HPF; 1070 | } 1071 | 1072 | n2adr_filter_tx = FILTER_160; 1073 | if (hermes_tx_freq > 3500000) { 1074 | n2adr_filter_tx = FILTER_80; 1075 | } 1076 | if (hermes_tx_freq > 7000000) { 1077 | n2adr_filter_tx = FILTER_40; 1078 | } 1079 | if (hermes_tx_freq > 14000000) { 1080 | n2adr_filter_tx = FILTER_30_20; 1081 | } 1082 | if (hermes_tx_freq > 21000000) { 1083 | n2adr_filter_tx = FILTER_10; /// ToDo: bug 1084 | } 1085 | } 1086 | 1087 | void configSendUDP_packet(unsigned char *opccBuf) 1088 | { 1089 | int i; 1090 | 1091 | bzero(opccBuf, 1032); 1092 | opccBuf[0] = 0xEF; 1093 | opccBuf[1] = 0xFE; 1094 | opccBuf[2] = 0x01; 1095 | opccBuf[3] = 0x02; // Metis UDP/IP for USB EP2 1096 | 1097 | opccBuf[4] = seqNum >> 24 & 0xFF; 1098 | opccBuf[5] = seqNum >> 16 & 0xFF; 1099 | opccBuf[6] = seqNum >> 8 & 0xFF; 1100 | opccBuf[7] = seqNum & 0xFF; 1101 | 1102 | opccBuf[ 8] = 0x7F; 1103 | opccBuf[ 9] = 0x7F; 1104 | opccBuf[ 10] = 0x7F; 1105 | opccBuf[520] = 0x7F; 1106 | opccBuf[521] = 0x7F; 1107 | opccBuf[522] = 0x7F; 1108 | #ifdef TX_OK 1109 | tx_key_down_1 = get_tx_key() ? 1 : 0; // 1110 | #endif 1111 | if (hermes_tx_freq < 1800000) { tx_key_down_1 = 0; } 1112 | if (tx_key_down_1) { 1113 | hermes_tx_drive_level = get_tx_drive(); // lvl 0..15 1114 | // ? 1.5 second delay in 382 rate UDP packets 1115 | // tx_delay = 1.5 * 382.0 * (sampRate/48000.0); 1116 | tx_delay = hl2_tx_hang * 382.0; 1117 | } else { 1118 | // hermes_tx_drive_level = 0; 1119 | if (tx_delay > 0) { tx_delay -= 1; } 1120 | } 1121 | hl2_tx_on = tx_key_down_1 | ((tx_delay > 0) ? 1 : 0); 1122 | if (hl2_tx_on == 0) { 1123 | // hermes_tx_drive_level = 0; // for testing 1124 | } 1125 | 1126 | opccBuf[ 11] = (C0_addr + 0) << 1 | hl2_tx_on; // 1127 | for (i=0;i<4;i++) { opccBuf[ 12+i] = 0; } 1128 | opccBuf[523] = (C0_addr + 1) << 1 | hl2_tx_on; // 1129 | for (i=0;i<4;i++) { opccBuf[524+i] = 0; } 1130 | 1131 | if (tx_freq > 48000) { 1132 | hermes_tx_freq = tx_freq; 1133 | } else { 1134 | hermes_tx_freq = hermes_rx_freq + hermes_tx_offset ; 1135 | } 1136 | // setFilterEnables(); 1137 | 1138 | if (C0_addr == 0) { 1139 | opccBuf[11] = (C0_addr << 1) | hl2_tx_on; // 0 1140 | 1141 | // [25:24] Speed (00=48kHz, 01=96kHz, 10=192kHz, 11=384kHz) 1142 | int r0 = 0; 1143 | if ( sampRate == 384000) { 1144 | r0 = 3; 1145 | } else if (sampRate == 192000) { 1146 | r0 = 2; 1147 | } else if (sampRate == 96000) { 1148 | r0 = 1; 1149 | } 1150 | opccBuf[12] = r0; 1151 | 1152 | // [23:17] Open Collector Outputs on Penelope or Hermes 1153 | opccBuf[13] = 0; 1154 | if (hl2_tx_on) { // send filter selection on J16 1155 | opccBuf[13] = n2adr_filter_tx << 1; // C2 1156 | } else { 1157 | opccBuf[13] = n2adr_filter_rx << 1; 1158 | } 1159 | 1160 | // [10] VNA fixed RX Gain (0=-6dB, 1=+6dB) 1161 | opccBuf[14] = 0; 1162 | 1163 | // [6:3] Number of Receivers (0000=1 to max 1011=12) 1164 | // [2] Duplex (0=off, 1=on) 1165 | opccBuf[15] = 0x04; // C4 duplex on 1166 | 1167 | opccBuf[523] = ((C0_addr + 1) << 1) | hl2_tx_on; // addr 1 1168 | // transmitter frequency ? 1169 | opccBuf[524] = (hermes_tx_freq >> 24) & 0xFF; // C1 1170 | opccBuf[525] = (hermes_tx_freq >> 16) & 0xFF; // C2 1171 | opccBuf[526] = (hermes_tx_freq >> 8) & 0xFF; // C3 1172 | opccBuf[527] = (hermes_tx_freq ) & 0xFF; // C4 1173 | } 1174 | 1175 | if (C0_addr == 2) { 1176 | // rx slice 1 1177 | opccBuf[11] = (C0_addr << 1) | hl2_tx_on; // C0 1178 | opccBuf[12] = (hermes_rx_freq >> 24) & 0x00ff; // C1 1179 | opccBuf[13] = (hermes_rx_freq >> 16) & 0x00ff; // C2 1180 | opccBuf[14] = (hermes_rx_freq >> 8) & 0x00ff; // C3 1181 | opccBuf[15] = (hermes_rx_freq ) & 0x00ff; // C4 1182 | // rx slice 2 1183 | int hermes_tmpF0 = hermes_rx2_freq; 1184 | if ((sliceLoop % 8) > 3) { 1185 | // hermes_tmpF0 = hermes_rx3_freq; 1186 | } 1187 | opccBuf[523 ] = ((C0_addr + 1) << 1) | hl2_tx_on; // C0 1188 | opccBuf[523+1] = (hermes_tmpF0 >> 24) & 0x00ff; // C1 1189 | opccBuf[523+2] = (hermes_tmpF0 >> 16) & 0x00ff; // C2 1190 | opccBuf[523+3] = (hermes_tmpF0 >> 8) & 0x00ff; // C3 1191 | opccBuf[523+4] = (hermes_tmpF0 ) & 0x00ff; // C4 1192 | } 1193 | if (C0_addr == 4) { 1194 | // rx 3 1195 | opccBuf[ 11] = (C0_addr << 1) | hl2_tx_on; // C0 == 4 1196 | opccBuf[12] = (hermes_rx_freq >> 24) & 0x00ff; // C1 1197 | opccBuf[13] = (hermes_rx_freq >> 16) & 0x00ff; // C2 1198 | opccBuf[14] = (hermes_rx_freq >> 8) & 0x00ff; // C3 1199 | opccBuf[15] = (hermes_rx_freq ) & 0x00ff; // C4 1200 | // rx 4 1201 | int hermes_tmpF0 = hermes_rx2_freq; 1202 | opccBuf[523] = ((C0_addr + 1) << 1) | hl2_tx_on; // 5 1203 | opccBuf[523+1] = (hermes_tmpF0 >> 24) & 0x00ff; // C1 1204 | opccBuf[523+2] = (hermes_tmpF0 >> 16) & 0x00ff; // C2 1205 | opccBuf[523+3] = (hermes_tmpF0 >> 8) & 0x00ff; // C3 1206 | opccBuf[523+4] = (hermes_tmpF0 ) & 0x00ff; // C4 1207 | } 1208 | if (C0_addr == 6) { 1209 | // special commands requiring an ack 1210 | opccBuf[ 11] = (C0_addr << 1) | hl2_tx_on; // 6 1211 | opccBuf[523] = ((C0_addr + 1) << 1) | hl2_tx_on; // 7 1212 | // 1213 | // checkForSpecialCommands(seqNum); // sets hwCmdState 1214 | if ((hwCmdState == 3) || (hwCmdState == 7)) { 1215 | opccBuf[523] = (hwCmd[0] << 1) | hl2_tx_on | 0x80; // ? 1216 | for (i=1;i<=4;i++) { 1217 | opccBuf[523+i] = hwCmd[i]; // 4 fpga command bytes 1218 | } 1219 | hwCmdState = hwCmdState & 0x0e; // clear LSB (2,6) 1220 | hwCmdSeqNum = seqNum; 1221 | } else { 1222 | // opccBuff 524..527 are already zero'd 1223 | } 1224 | } 1225 | if (C0_addr == 8) { 1226 | // filter selection 1227 | opccBuf[ 11] = (C0_addr << 1) | hl2_tx_on; // 8 1228 | opccBuf[523] = ((C0_addr + 1) << 1) | hl2_tx_on; // 9 1229 | 1230 | // 0x09 [31:24] Hermes TX Drive Level (only [31:28] used) 1231 | opccBuf[524] = ( (hermes_tx_drive_level << 4) 1232 | + hermes_tx_drive_level ) ; // 0..15 1233 | if (hl2_tx_on) { 1234 | hermes_enable_power_amp = 1; 1235 | hermes_Q5_switch_ext_ptt_lp = 1; 1236 | opccBuf[525] = ( (hermes_enable_power_amp << 3) 1237 | | (hermes_Q5_switch_ext_ptt_lp << 2) ); 1238 | opccBuf[526] = 0; // C3 1239 | opccBuf[527] = 0; // C4 1240 | } else { 1241 | opccBuf[524] = 0; 1242 | opccBuf[525] = 0; 1243 | opccBuf[526] = 0; 1244 | opccBuf[527] = 0; // something called "Alex" ??? 1245 | } 1246 | } 1247 | if (C0_addr == 10) { 1248 | // C0_addr is 10, 11 (0x0a,0x0b) 1249 | int gTmp = hermes_lna_gain; 1250 | if (hl2_tx_on != 0) { gTmp = -6; } 1251 | opccBuf[ 11] = (C0_addr << 1) | hl2_tx_on; // 10 1252 | opccBuf[ 15] = ((gTmp + 12) & 0x3F) | 0x40; 1253 | opccBuf[523] = ((C0_addr + 1) << 1) | hl2_tx_on; // 11 1254 | 1255 | // 1256 | #ifdef hang_time_and_latency_experiment_1 1257 | int CX_addr; 1258 | CX_addr = 0x17; // 23 1259 | opccBuf[523] = (CX_addr << 1) | hl2_tx_on; 1260 | 1261 | opccBuf[526] = 24; // default 4mS PTT hang time 1262 | opccBuf[527] = 20; // mS Tx buffer latency (10..31) 1263 | #endif 1264 | 1265 | } 1266 | C0_addr += 2; // receiver 1 frequency 1267 | if (sliceLoop > 0) { 1268 | C0_addr = 2; // receiver frequencies 1269 | } 1270 | if (C0_addr > 10 & slices > 1) { 1271 | sliceLoop += 1; 1272 | C0_addr = 2; // receiver frequencies 1273 | } 1274 | if (C0_addr > 10) { C0_addr = 0; } 1275 | 1276 | // get IQ transmit samples, if any, or zero fill 1277 | 1278 | tx_block_setup(seqNum); 1279 | 1280 | int jj; 1281 | for (jj = 0; jj < 1024; jj+=512) { 1282 | for (i = 0; i < 63; i++) { 1283 | // update audio & tx IQ sent to hl2 1284 | int k = 16 + jj + 8 * i; 1285 | 1286 | opccBuf[k ] = 0; // Left Audio 1287 | opccBuf[k+1] = 0; // lsb 1288 | opccBuf[k+2] = 0; // Right Audio 1289 | opccBuf[k+3] = 0; // lsb 1290 | 1291 | int txI = 0; 1292 | int txQ = 0; 1293 | #ifdef TX_OK 1294 | get_tx_sample(&txI, &txQ); 1295 | #endif 1296 | 1297 | // normal IQ order 1298 | opccBuf[k+6] = (txI >> 8) & 0xff; // bigEndian I 1299 | opccBuf[k+7] = (txI ) & 0xff; // lsb 1300 | opccBuf[k+4] = (txQ >> 8) & 0xff; // Q 1301 | opccBuf[k+5] = (txQ ) & 0xff; // lsb 1302 | } 1303 | } 1304 | seqNum += 1; 1305 | } 1306 | 1307 | struct sockaddr_in hl2_sockAddr; 1308 | 1309 | int udp_send_count = 0; 1310 | 1311 | int hl2_udp_rcv_loop(int fd, int mode) 1312 | { 1313 | unsigned char hl2RcvBuf[1500]; 1314 | // struct sockaddr_in from_Addr; 1315 | socklen_t addrLen2 = sizeof(struct sockaddr_in); 1316 | int k = 0; 1317 | ssize_t b = 0; 1318 | int n2 = 1500; 1319 | 1320 | bzero(hl2RcvBuf, 1500); 1321 | // from_Addr = hl2_sockAddr; 1322 | while (udp_running > 0) { 1323 | // fd = hl2_fd 1324 | b = recvfrom(fd, &hl2RcvBuf[0], n2, 0, 1325 | (struct sockaddr *)&hl2_sockAddr, &addrLen2); 1326 | if (b > 0) { // got UDP data from HL2 1327 | hl2_running = 1; 1328 | ssize_t bb; 1329 | 1330 | // unpack and write IQ to ring buffer 1331 | handleRcvData(hl2RcvBuf, b); // stuff IQ into FIFO 1332 | // then if enough IQ samples send from FIFO via rtl_tcp 1333 | tcp_send_poll(); // remove from FIFO 1334 | if (sendErrorFlag < 0) { 1335 | fprintf(stdout, "tcp send error \n"); 1336 | udp_running = -3; 1337 | } 1338 | 1339 | if (tx_gear_counter % tx_gear_ratio == 0) { 1340 | configSendUDP_packet(udpBuffer); // inc send sequence # 1341 | int msgLen = 1032; // send UDP pkt to HL2 1342 | bb = sendto( fd, &udpBuffer[0], msgLen, 0, 1343 | (struct sockaddr *)&hl2_sockAddr, addrLen); 1344 | if (bb > 0) { 1345 | udp_send_count += 1; 1346 | if ((tcp_tx_cmd & 0x00ff) != 0) { 1347 | tcp_tx_cmd -= 1; 1348 | // printf("tcp_tx_cmd = %d ", tcp_tx_cmd); 1349 | } 1350 | } else { // quit loop on error 1351 | fprintf(stdout, "udp to hl2 send error \n"); 1352 | udp_running = -2; 1353 | return(bb); 1354 | } 1355 | } 1356 | tx_gear_counter += 1; 1357 | } else { 1358 | fprintf(stdout, "udp from hl2 rcv error \n"); 1359 | udp_running = -1; 1360 | return(b); 1361 | } 1362 | k += 1; 1363 | } // loop forever 1364 | return(0); 1365 | } 1366 | 1367 | unsigned int getDecimalValueOfIPV4_String(const char* ipAddress, int mod); 1368 | 1369 | // int hl2_running = 0; 1370 | int hl2_fd = -1; 1371 | 1372 | int hl2_udp_setup() 1373 | { 1374 | // uint32_t hl2_ipAddr = 0x7f000001; // 127.0.0.1 == localhost 1375 | // int port = HERMES_PORT; 1376 | int fd = -1; 1377 | 1378 | tmp_temperature = 0.0; 1379 | tmp_fwd_power = 0.0; 1380 | tmp_rev_power = 0.0; 1381 | tmp_pa_current = 0.0; 1382 | tmp_temp_count = 0; 1383 | tmp_revp_count = 0; 1384 | bzero(udpBuffer, 1032); 1385 | 1386 | if (1) { 1387 | char *s = hl2_ip_string; 1388 | if (s) { 1389 | hl2_ipAddr = getDecimalValueOfIPV4_String(s, -1); 1390 | printf("hl2 ip addr: %s = 0x%lx\n", s, (long int)hl2_ipAddr); 1391 | } else { 1392 | return(-1); 1393 | } 1394 | } 1395 | 1396 | if ( (fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ) { 1397 | perror("socket failed"); 1398 | return(-1); 1399 | } 1400 | hl2_fd = fd; 1401 | /* 1402 | int optval = 6; 1403 | int r1 = setsockopt( fd, SOL_SOCKET, SO_PRIORITY, 1404 | &optval, sizeof(optval) ); 1405 | if (r1 < 0) { perror("udp socket err: SO_PRIORITY"); } 1406 | */ 1407 | memset( &hl2_sockAddr, 0, sizeof(hl2_sockAddr) ); 1408 | hl2_sockAddr.sin_family = AF_INET; 1409 | hl2_sockAddr.sin_port = htons( HERMES_PORT ); 1410 | // hl2_sockAddr.sin_addr.s_addr = htonl( 0x7f000001 ); // 127.0.0.1 1411 | hl2_sockAddr.sin_addr.s_addr = htonl( hl2_ipAddr ); 1412 | 1413 | return(0); 1414 | } 1415 | 1416 | void hl2_send_start_cmds(int n) 1417 | { 1418 | char myMsg[1500]; 1419 | // int n = MAX_NUMBER_OF_START_COMMANDS; 1420 | 1421 | for ( int i = 0; i < n; i++ ) { 1422 | 1423 | int flag = 0x01; // send start command to HL2 1424 | configStartCmd(myMsg, flag); // 64 bytes 1425 | int msgLen = 64; 1426 | 1427 | int addrLen = sizeof(hl2_sockAddr); 1428 | if (sendto( hl2_fd, &myMsg[0], msgLen, 0, 1429 | (struct sockaddr *)&hl2_sockAddr, addrLen) < 0 ) { 1430 | perror( "sendto failed" ); 1431 | break; 1432 | } 1433 | if (i == 0) { 1434 | // printf( "Cmd %d sent, %d bytes of UDP\n", flag, msgLen); 1435 | } 1436 | if (ring_data_available() > 0) { 1437 | int nt = i + 1; 1438 | printf("hl2 start cmd sent %d times\n", nt); 1439 | printf("hl2 udp IQ data received \n"); 1440 | break; 1441 | } 1442 | 1443 | usleep(START_LOOP_DELAY); 1444 | #ifdef RESPONSE_WAIT 1445 | char ackvar[1500]; 1446 | bzero(ackvar, 1500); 1447 | int n2 = 1500; 1448 | int b = -1; 1449 | if ((b = recvfrom(hl2_fd, &ackvar[0], n2, 0, NULL, NULL)) < 0 ) { 1450 | printf("hl2 receive error: errno %d\n", errno); 1451 | // exit(1); 1452 | } else { 1453 | if (b > 0) { 1454 | printf("received %d bytes of data >%s< \n", b, "x"); 1455 | hl2_running = 1; 1456 | break; 1457 | } 1458 | } 1459 | #endif 1460 | } 1461 | 1462 | /* 1463 | int b = 0; 1464 | int msgLen = 1032; 1465 | C0_addr = 0; // for rx 1 & transmitter 1 frequency 1466 | 1467 | configSendUDP_packet(udpBuffer); 1468 | b = sendto( hl2_fd, &udpBuffer[0], msgLen, 0, 1469 | (struct sockaddr *)&hl2_sockAddr, addrLen); 1470 | printf("sent %d bytes of f0 cmd \n", b); 1471 | C0_addr = 2; 1472 | configSendUDP_packet(udpBuffer); 1473 | b = sendto( hl2_fd, &udpBuffer[0], msgLen, 0, 1474 | (struct sockaddr *)&hl2_sockAddr, addrLen); 1475 | // printf("sent %d bytes of f0 cmd \n", b); 1476 | */ 1477 | } 1478 | 1479 | 1480 | void hl2_udp_rcv(int loopFlag) 1481 | { 1482 | if (loopFlag) { 1483 | udp_running = 1; 1484 | int mode = 1; 1485 | hl2_udp_rcv_loop(hl2_fd, mode); // loop until error 1486 | } else { 1487 | // int count = 2048; 1488 | // udp_rcv_n_bytes(hl2_fd, count); // unused 1489 | } 1490 | } 1491 | 1492 | int hl2_udp_rcv_end() 1493 | { 1494 | char myMsg[1500]; 1495 | int msgLen = 64; 1496 | int flag = 0x00; // send stop UDP to HL2 twice 1497 | 1498 | print_hl2_stats() ; 1499 | 1500 | configStartCmd(myMsg, flag); 1501 | 1502 | msgLen = 64; 1503 | sendto( hl2_fd, &myMsg[0], msgLen, 0, 1504 | (struct sockaddr *)&hl2_sockAddr, addrLen); 1505 | usleep(50000); 1506 | sendto( hl2_fd, &myMsg[0], msgLen, 0, 1507 | (struct sockaddr *)&hl2_sockAddr, addrLen); 1508 | if (0) { 1509 | // printf( "Cmd %d sent, %d bytes of UDP\n", flag, msgLen); 1510 | } 1511 | usleep(50000); 1512 | 1513 | hl2_running = 0; 1514 | udp_running = 0; 1515 | 1516 | // cleanup 1517 | close( hl2_fd ); 1518 | seqNum = 0; 1519 | tx_gear_counter = 0; 1520 | fprintf(stdout, "hl2 UDP stream stopped \n\n"); 1521 | hl2_fd = -1; 1522 | return 0; 1523 | } 1524 | 1525 | void print_hl2_stats() 1526 | { 1527 | float tc = ((3.26 * hermes_temperature / 4096.0) - 0.5) / 0.01; 1528 | float tf = (tc * 9.0 / 5.0) + 32.0; 1529 | printf("temp = %5.1f C = %5.1f F\n", tc, tf); 1530 | printf("Rx rms db = %lf \n", samp_db); 1531 | // printf("hermes_fwd_power: %f \n", hermes_fwd_power ); 1532 | // printf("hermes_rev_power: %f \n", hermes_rev_power ); 1533 | // printf("hermes_pa_current: %f \n", hermes_pa_current); 1534 | printf("seqNum = %d \n", seqNum); 1535 | } 1536 | 1537 | void hl2_stop() 1538 | { 1539 | if (hl2_fd >= 0) { 1540 | char myMsg[1500] ; 1541 | int msgLen = 64; 1542 | int flag = 0x00; // stop 1543 | configStartCmd(myMsg, flag); 1544 | sendto( hl2_fd, &myMsg[0], msgLen, 0, 1545 | (struct sockaddr *)&hl2_sockAddr, addrLen); 1546 | usleep(50000); 1547 | sendto( hl2_fd, &myMsg[0], msgLen, 0, 1548 | (struct sockaddr *)&hl2_sockAddr, addrLen); 1549 | hl2_running = 0; 1550 | close(hl2_fd); 1551 | hl2_fd = -1; 1552 | 1553 | fprintf(stdout, "hl2 UDP stream stopped \n"); 1554 | } 1555 | seqNum = 0; 1556 | print_hl2_stats() ; 1557 | resetTxDotQueue() ; 1558 | } // hl2_stop() 1559 | 1560 | // 1561 | // 1562 | 1563 | // hermes_discovery.c 1564 | // 2020-02-04 2019-12-23 rhn 2017-jun-xx 1565 | // 1566 | #define D_VERSION ("0.2.115") 1567 | 1568 | #define DISCOVER 1569 | #define USE_FD 1570 | #define ECHO_WAIT (1) 1571 | 1572 | /* 1573 | #include 1574 | #include 1575 | #include 1576 | #include 1577 | #include 1578 | #include 1579 | #include 1580 | #include 1581 | #include 1582 | 1583 | #include 1584 | #include 1585 | #include 1586 | #include 1587 | #include 1588 | #include 1589 | #include 1590 | #include 1591 | */ 1592 | 1593 | #define HERMES_PORT (1024) 1594 | 1595 | #define ADR_SIZE (32) 1596 | #define INVALID_SOCKET (-1) 1597 | 1598 | char ip_string[ADR_SIZE]; 1599 | unsigned char sendbuf[1500]; 1600 | int rx_discover_socket = -1; 1601 | int sockfd = -1; 1602 | int rx_udp_socket = INVALID_SOCKET; // -1 1603 | // int seqNum = 0; 1604 | 1605 | int total = 0; 1606 | 1607 | #ifndef USE_FD 1608 | struct sockaddr_in hermes_Addr; 1609 | #endif 1610 | struct sockaddr_in recv_Addr; 1611 | // socklen_t addrLen = sizeof(recv_Addr); 1612 | 1613 | static int hl2_found = 0; 1614 | 1615 | void do_discovery(void); 1616 | void do_scan_discovery(void); 1617 | 1618 | // int main(int argc, char **argv) 1619 | int discover_main() 1620 | { 1621 | hl2_found = 0; 1622 | printf("Hermes Lite 2 UDP IP Address Discovery %s\n", VERSION); 1623 | 1624 | #ifdef DISCOVER 1625 | if (discover_use_ip == 0) { 1626 | do_discovery(); 1627 | } else { 1628 | do_scan_discovery(); 1629 | } 1630 | #endif 1631 | 1632 | printf("Done.\n"); 1633 | return(0); 1634 | } 1635 | 1636 | // 1637 | 1638 | 1639 | void do_scan_discovery() 1640 | { 1641 | unsigned char data[1500]; 1642 | ssize_t b; 1643 | int fl; 1644 | int j = -1; 1645 | 1646 | rx_discover_socket = socket(PF_INET, SOCK_DGRAM, 0); 1647 | fl = fcntl(rx_discover_socket, F_GETFL); 1648 | fcntl(rx_discover_socket, F_SETFL, fl | O_NONBLOCK); 1649 | 1650 | if (1) { 1651 | char *s = hl2_ip_string; 1652 | int msgLen = 63; 1653 | int fd = rx_discover_socket; 1654 | long int ipTmp; 1655 | 1656 | data[0] = 0xEF; 1657 | data[1] = 0xFE; 1658 | data[2] = 0x02; 1659 | for (int i = 3; i < 64; i++) { data[i] = 0; } 1660 | memset( &hl2_sockAddr, 0, sizeof(hl2_sockAddr) ); 1661 | hl2_sockAddr.sin_family = AF_INET; 1662 | hl2_sockAddr.sin_port = htons( HERMES_PORT ); 1663 | for (j=1;j<255;j+=1) { 1664 | ipTmp = getDecimalValueOfIPV4_String(s, j); 1665 | // printf("testing ip addr: %s = 0x%lx\n\n", s, (long int)ipTmp); 1666 | hl2_sockAddr.sin_addr.s_addr = htonl( ipTmp ); 1667 | strncpy(ip_string, inet_ntoa( hl2_sockAddr.sin_addr), ADR_SIZE); 1668 | // printf("testing %s 0x%08X \n", ip_string, ntohl(ipTmp)); 1669 | int bb = sendto( fd, &data[0], msgLen, 0, 1670 | (struct sockaddr *)&hl2_sockAddr, addrLen); 1671 | // printf("1 UDP broadcast of %d bytes\n", bb); 1672 | b = recvfrom(rx_discover_socket, (char *)data, 1500, 0, 1673 | (struct sockaddr *)&recv_Addr, &addrLen); 1674 | if (b > 0) { hl2_found = 1; break; } 1675 | usleep(5000); 1676 | } 1677 | printf("sent %d UDP packets of %d bytes\n", j, msgLen); 1678 | } 1679 | 1680 | if (b <= 0 ) { 1681 | for (int i=0;i<100;i++) { 1682 | b = recvfrom(rx_discover_socket, (char *)data, 1500, 0, 1683 | (struct sockaddr *)&recv_Addr, &addrLen); 1684 | if (b > 0) break; 1685 | usleep(50000); 1686 | } 1687 | } 1688 | if (b > 0) { 1689 | uint32_t ipAddr; 1690 | strncpy(ip_string, inet_ntoa(recv_Addr.sin_addr), ADR_SIZE); 1691 | printf("discover ip = %s : ", ip_string); 1692 | ipAddr = *(uint32_t *)&recv_Addr.sin_addr; 1693 | printf("0x%08X \n", ntohl(ipAddr)); 1694 | int p = ntohs(recv_Addr.sin_port); 1695 | printf("discover port = %d \n", p); 1696 | } 1697 | close(rx_discover_socket); 1698 | rx_discover_socket = -1; 1699 | if (b >= 60) { 1700 | int j; 1701 | hl2_found = 1; 1702 | printf("Received %ld bytes from UDP broadcast discover \n", b); 1703 | for (j=0;j<3;j++) { 1704 | printf("0x%02x ", data[j]); 1705 | } 1706 | printf("\n"); 1707 | printf("MAC Address: "); 1708 | for (j=3;j<9;j++) { 1709 | printf("%02x", data[j]); 1710 | if (j != 8) { printf("."); } 1711 | } 1712 | printf("\n"); 1713 | printf("Protocol: %d\n", data[10]); 1714 | printf("Gateware Version: %d\n", data[ 9]); 1715 | } else { 1716 | exit(-1); 1717 | } 1718 | } 1719 | 1720 | void broadcast_discover(int rx_discover_socket); 1721 | 1722 | void do_discovery() 1723 | { 1724 | // short int port = HERMES_PORT; 1725 | int i; 1726 | // ssize_t b; 1727 | int b; 1728 | int fl; 1729 | unsigned char data[1500]; 1730 | 1731 | rx_discover_socket = socket(PF_INET, SOCK_DGRAM, 0); 1732 | setsockopt(rx_discover_socket, SOL_SOCKET, SO_BROADCAST, 1733 | (char *)&i, sizeof(i)); 1734 | fl = fcntl(rx_discover_socket, F_GETFL); 1735 | fcntl(rx_discover_socket, F_SETFL, fl | O_NONBLOCK); 1736 | 1737 | broadcast_discover(rx_discover_socket); 1738 | printf("listening for HL2 response ... \n"); 1739 | b = recvfrom(rx_discover_socket, (char *)data, 1500, 0, 1740 | (struct sockaddr *)&recv_Addr, &addrLen); 1741 | if (b <= 0 ) { 1742 | for (i=0;i<10;i++) { 1743 | usleep(50000); 1744 | // printf("%d\n",i); 1745 | b = recvfrom(rx_discover_socket, (char *)data, 1500, 0, 1746 | (struct sockaddr *)&recv_Addr, &addrLen); 1747 | if (b > 0) break; 1748 | } 1749 | } 1750 | if (b > 0) { 1751 | if (0) { // for packet content debug 1752 | printf("%d bytes \n", b); 1753 | for (i=0;i= 60) { 1767 | int j; 1768 | if (0) { // for packet content debug 1769 | printf("Received %d bytes from UDP broadcast discover \n", b); 1770 | for (int j=0;j<3;j++) { 1771 | printf("0x%02x ", data[j]); 1772 | } 1773 | printf("\n"); 1774 | } 1775 | printf("MAC Address: "); 1776 | for (int j=3;j<9;j++) { 1777 | printf("%02x", data[j]); 1778 | if (j != 8) { printf("."); } 1779 | } 1780 | printf("\n"); 1781 | printf("Protocol: %d\n", data[10]); 1782 | printf("Gateware Version: %d\n", data[ 9]); 1783 | } else { 1784 | exit(-1); 1785 | } 1786 | // is set_ip(rx_discover_socket) needed ??? 1787 | } 1788 | 1789 | // 1790 | // broadcast_discoverer 1791 | // 1792 | 1793 | void broadcast_discover(int rx_discover_socket) 1794 | { 1795 | static struct sockaddr_in bcast_Addr; 1796 | unsigned char data[64]; 1797 | char ip_str[ADR_SIZE]; 1798 | struct ifaddrs *ifap; 1799 | struct ifaddrs *p; 1800 | ssize_t b = 0; 1801 | int port = 1024; 1802 | int n = 0; 1803 | 1804 | data[0] = 0xEF; 1805 | data[1] = 0xFE; 1806 | data[2] = 0x02; 1807 | for (int i = 3; i < 64; i++) { data[i] = 0; } 1808 | memset(&bcast_Addr, 0, sizeof(bcast_Addr)); 1809 | bcast_Addr.sin_family = AF_INET; 1810 | bcast_Addr.sin_port = htons(port); 1811 | if (getifaddrs(&ifap) == 0) { 1812 | p = ifap; 1813 | while(p) { 1814 | if ((p->ifa_addr) && p->ifa_addr->sa_family == AF_INET) { 1815 | strncpy(ip_str, inet_ntoa(bcast_Addr.sin_addr), ADR_SIZE); 1816 | bcast_Addr.sin_addr 1817 | = ((struct sockaddr_in *)(p->ifa_broadaddr))->sin_addr; 1818 | b = sendto(rx_discover_socket, (char *)data, 63, 0, 1819 | (const struct sockaddr *)&bcast_Addr, 1820 | sizeof(bcast_Addr)); 1821 | n++; 1822 | printf("%d try ip: %s %ld\n", n, ip_str, b); 1823 | if (n > 9 && b > 0) break; 1824 | } 1825 | // printf("bcast %d %d\n", i, n); 1826 | if (n > 255) { break; } 1827 | // usleep(50000); 1828 | usleep(1000); 1829 | p = p->ifa_next; 1830 | } 1831 | freeifaddrs(ifap); 1832 | } 1833 | printf("%d UDP broadcasts of %ld bytes\n", n, b); 1834 | } 1835 | 1836 | // Copyright 2017,2020,2022 Ronald H Nicholson Jr. All Rights Reserved. 1837 | // This code may only be redistributed under terms of 1838 | // the Mozilla Public License, Version 2.0. 1839 | // See: https://www.mozilla.org/en-US/MPL/2.0/ 1840 | // Exhibit B - "Incompatible With Secondary Licenses" Notice 1841 | // This Source Code Form is "Incompatible With Secondary Licenses", 1842 | // as defined by the Mozilla Public License, v. 2.0. 1843 | 1844 | // eof 1845 | -------------------------------------------------------------------------------- /hl2_tx.c: -------------------------------------------------------------------------------- 1 | // 2 | // hl2_tx.c for hl2_tcp.c 3 | #define VERSION "v.1.4.105" // 2023-01-05 2020-06-19 01 4 | // 5 | 6 | #define TX_OK 7 | // #define TX_DISABLE 8 | 9 | #define NO_MODULO 10 | 11 | #define TX_OFFSET ( 656.0) // default for USB SSB 12 | static float cw_df = TX_OFFSET; // synthesized USB IQ offset 13 | // default Tx power approx 1 mW 14 | // #define TX_DRIVE (15) // dac drive 0..15 15 | #define TX_DRIVE ( 3) // dac drive 0..15 16 | float tx_drive = TX_DRIVE; 17 | #define TX_LEVEL (512.0) // amplitude 16.0 to 32767.0 18 | float tx_lvl = TX_LEVEL; 19 | 20 | void set_tx_level(float x) { tx_lvl = x; } 21 | void set_tx_drive(float x) { tx_drive = x; } 22 | void set_tx_offset(float f) { cw_df = f; } 23 | 24 | #include 25 | #include 26 | #include 27 | 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | 47 | extern long sampRate; 48 | extern void print_hl2_stats() ; 49 | extern volatile int hl2_tx_on; 50 | static int tx_key_down_0; 51 | extern volatile int tx_key_down_1; 52 | extern long int tcp_tx_cmd; 53 | extern int hermes_tx_freq; 54 | extern int tx_param_w; 55 | extern int tx_param_x; 56 | 57 | #ifdef TX_OK 58 | 59 | extern int last_key_down ; 60 | static int last_get_key_x = 0; 61 | int txRiseCntr = 0; 62 | int txFallCntr = 0; 63 | int txOn_DnCntr = 0; 64 | int txOffDnCntr = 0; 65 | // open collector outputs on HL2; Rx and Tx filters; default no HPF 66 | 67 | float txRiseWin[257]; 68 | 69 | float m_srate = 48000.0; 70 | float tx_ph = 0.0; 71 | float tx_dph = 0.1; 72 | float ditherBuffer[64*1024+1]; 73 | int ditherIdx = 0; 74 | 75 | extern long random(void); 76 | 77 | static long int tx_counter = 0; 78 | 79 | void tx_setup() 80 | { 81 | char *addr = NULL; 82 | int sz = 2; 83 | int i; 84 | 85 | last_key_down = 0; 86 | txRiseCntr = 0; 87 | txFallCntr = 0; 88 | tx_counter = 0; 89 | 90 | if (tx_param_x >= 16 && tx_param_x <= 32768) { 91 | tx_lvl = tx_param_x; 92 | } 93 | 94 | for (i=0;i<64*1024;i++) { 95 | int r1 = 0x0fff & random(); // 0 .. 4095 96 | int r2 = 0x0fff & random(); 97 | int r0 = r1 - r2; // triangular -8192 .. 8190 98 | float r = 1.0 * (float)r0 / (8192.0f); // -2.0 .. 2.0 99 | ditherBuffer[i] = r; // ditherIdx 100 | } 101 | 102 | tx_dph = 2.0 * M_PI * cw_df / m_srate; 103 | 104 | // 5.3 mS rise time 105 | for (i=0; i<=256; i++) { 106 | float x = 0.5 - 0.5 * cosf((float)i * M_PI / 256.0); // no 2pi 107 | txRiseWin[i] = x; 108 | } 109 | 110 | } 111 | void tx_cleanup() 112 | { 113 | tcp_tx_cmd = 0; 114 | } 115 | 116 | extern void resetTxDotQueue() ; 117 | extern int queueTxDotCommand(int k, int on, int off) ; 118 | extern int getNextTxDotCommand(void) ; 119 | 120 | #define TDC_LIM (1024) 121 | static int td1c_rb[TDC_LIM]; 122 | static int td0c_rb[TDC_LIM]; 123 | static int tdc_in = 0 ; 124 | static int tdc_out = 0 ; 125 | 126 | void resetTxDotQueue() { 127 | txOn_DnCntr = 0; 128 | txOffDnCntr = 1; 129 | tx_key_down_1 = 0; // reset in hl2_tcp.c 130 | tx_key_down_0 = 0; 131 | tdc_in = 0; 132 | tdc_out = 0; 133 | for (int i=0;i= TDC_LIM) { tdc_in = 0; } 147 | td1c_rb[tdc_in] = 0; 148 | td0c_rb[tdc_in] = 0; 149 | } 150 | if (txOn_DnCntr <= 0 && txOffDnCntr <= 0) { 151 | getNextTxDotCommand() ; 152 | } 153 | return(r); 154 | } 155 | 156 | int getNextTxDotCommand() { 157 | int on = 0; 158 | int off = 0; 159 | int n = tdc_out - tdc_in; 160 | int j = tdc_out; 161 | if (n < 0) { n += TDC_LIM; } 162 | if (n > 0) { 163 | on = td1c_rb[tdc_out]; 164 | off = td0c_rb[tdc_out]; 165 | tdc_out += 1; 166 | if (tdc_out >= TDC_LIM) { tdc_out = 0; } 167 | } 168 | if (on == 48 && off == 0) { 169 | resetTxDotQueue() ; 170 | on = 0; 171 | } else { 172 | txOn_DnCntr = on ; 173 | txOffDnCntr = off; 174 | } 175 | if (on < 0) { on = 0; } 176 | return(on); 177 | } 178 | 179 | static int last_key = 0; 180 | 181 | int get_tx_key() 182 | { 183 | int key = 0; 184 | if (key == 0) { 185 | key = ((tcp_tx_cmd + 1) > 1) ? 1 : 0; 186 | } 187 | if (key == 0) { 188 | key = tx_key_down_0; 189 | } 190 | #ifdef TX_DISABLE 191 | key = 0; 192 | #endif 193 | last_get_key_x = key; 194 | return(key); 195 | } 196 | 197 | static float save_tx_ph = 0.0; 198 | static int save_ditherIdx = 0; 199 | 200 | void tx_block_setup(int seqN) { 201 | int skip_modulo = (sampRate / 48000); // 1,2,4,8 202 | tx_dph = 2.0 * M_PI * cw_df / m_srate; 203 | 204 | #ifdef NO_MODULO 205 | skip_modulo = 1; // 206 | #endif 207 | if (((seqN + 0) % skip_modulo) == 0) { 208 | save_tx_ph = tx_ph ; // save starting phase 209 | save_ditherIdx = ditherIdx ; 210 | } else { 211 | tx_ph = save_tx_ph ; // repeat last tx IQ phase 212 | ditherIdx = save_ditherIdx; 213 | } 214 | } 215 | 216 | void get_tx_sample(int *tx_i, int *tx_q) 217 | { 218 | if (txOn_DnCntr > 0) { 219 | txOn_DnCntr -= 1; 220 | if (txOn_DnCntr <= 0) { 221 | tx_key_down_0 = 0; 222 | } else { 223 | tx_key_down_0 = 1; 224 | } 225 | } else if (txOffDnCntr > 0) { 226 | txOffDnCntr -= 1; 227 | if (txOffDnCntr <= 0) { 228 | int t = getNextTxDotCommand(); 229 | if (t > 0) { // getCmd sets txOn_DnCntr = t; 230 | tx_key_down_0 = 1; 231 | } else { 232 | tx_key_down_0 = 0; // getCmd sets txOffDnCntr 233 | } 234 | } 235 | } 236 | if (tx_key_down_1 != last_key_down) { // MOXtx_enb 237 | if (tx_key_down_1 == 1) { 238 | txRiseCntr = 255; 239 | } else { 240 | txFallCntr = 255; 241 | } 242 | } 243 | if ((tx_key_down_1 == 1) || (txFallCntr > 0)) { 244 | float x = cosf(tx_ph); 245 | float y = sinf(tx_ph); 246 | tx_ph += tx_dph; // 247 | if ( tx_ph > 2.0f * (float)M_PI) { 248 | tx_ph -= 2.0f * (float)M_PI; 249 | } else if (tx_ph < -2.0f * (float)M_PI) { 250 | tx_ph += 2.0f * (float)M_PI; 251 | } 252 | 253 | float w = 1.0; 254 | // rise time taper 255 | if (txRiseCntr > 0) { 256 | w *= txRiseWin[255 - txRiseCntr] ; 257 | txRiseCntr -= 1; 258 | } 259 | if (txFallCntr > 0) { 260 | w *= txRiseWin[txFallCntr] ; 261 | txFallCntr -= 1; 262 | } 263 | // w = 1.0; 264 | 265 | float x2 = x * w * tx_lvl; 266 | float y2 = y * w * tx_lvl; 267 | if (1 && tx_lvl > 0 && tx_lvl <= 512) { 268 | x2 += ditherBuffer[ditherIdx ]; 269 | y2 += ditherBuffer[ditherIdx+1]; 270 | } 271 | ditherIdx = (ditherIdx + 2) & 0x7ffe; 272 | #ifdef TX_DISABLE 273 | if (tx_i != NULL) { *tx_i = 0; } 274 | if (tx_q != NULL) { *tx_q = 0; } 275 | #else 276 | if (tx_i != NULL) { *tx_i = floor(0.499 + x2); } 277 | if (tx_q != NULL) { *tx_q = floor(0.499 + y2); } // 278 | #endif 279 | } 280 | last_key_down = tx_key_down_1 ; 281 | tx_counter += 1; 282 | } 283 | 284 | int get_tx_drive() 285 | { 286 | #ifdef TX_DISABLE 287 | return(0); 288 | #else 289 | return(tx_drive); 290 | #endif 291 | } 292 | #else // no TX_OK 293 | #endif 294 | 295 | int get_tx_offset() { return(cw_df); } 296 | 297 | // The above source code is: 298 | // Copyright 2017,2020,2022 Ronald H Nicholson Jr. All Rights Reserved. 299 | // This code may only be redistributed under terms of 300 | // the Mozilla Public License 2.0 plus Exhibit B (no copyleft exception) 301 | // See: https://www.mozilla.org/en-US/MPL/2.0/ 302 | 303 | // eof 304 | --------------------------------------------------------------------------------