| 
									
										
										
										
											2020-11-05 19:11:57 +01:00
										 |  |  | /*
 | 
					
						
							|  |  |  | * High Speed modem to transfer data in a 2,7kHz SSB channel | 
					
						
							|  |  |  | * ========================================================= | 
					
						
							|  |  |  | * Author: DJ0ABR | 
					
						
							|  |  |  | * made for: AMSAT-DL | 
					
						
							|  |  |  | * | 
					
						
							|  |  |  | *   (c) DJ0ABR | 
					
						
							|  |  |  | *   www.dj0abr.de | 
					
						
							|  |  |  | * | 
					
						
							|  |  |  | *   This program is free software; you can redistribute it and/or modify | 
					
						
							|  |  |  | *   it under the terms of the GNU General Public License as published by | 
					
						
							|  |  |  | *   the Free Software Foundation; either version 2 of the License, or | 
					
						
							|  |  |  | *   (at your option) any later version. | 
					
						
							|  |  |  | * | 
					
						
							|  |  |  | *   This program is distributed in the hope that it will be useful, | 
					
						
							|  |  |  | *   but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  | *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
					
						
							|  |  |  | *   GNU General Public License for more details. | 
					
						
							|  |  |  | * | 
					
						
							|  |  |  | *   You should have received a copy of the GNU General Public License | 
					
						
							|  |  |  | *   along with this program; if not, write to the Free Software | 
					
						
							|  |  |  | *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | 
					
						
							|  |  |  | * | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  | * this is a console program | 
					
						
							|  |  |  | * it can be compiled under Linux: make | 
					
						
							|  |  |  | * and under Windows: Visual-Studio | 
					
						
							|  |  |  | *  | 
					
						
							| 
									
										
										
										
											2020-11-24 16:07:52 +01:00
										 |  |  | * !!! compile x86 (32bit) version !!! all supplied dlls are 32 bit !!! | 
					
						
							|  |  |  | * ==================================================================== | 
					
						
							|  |  |  | *  | 
					
						
							| 
									
										
										
										
											2020-11-05 19:11:57 +01:00
										 |  |  | * 3rd party libraries: | 
					
						
							|  |  |  | * 1) BASS Audio from https://www.un4seen.com/
 | 
					
						
							|  |  |  | 	copy bass.h and bass.lib into source directory | 
					
						
							|  |  |  | 	Windows: copy bass.dll into executable directory | 
					
						
							|  |  |  | 	Linux: copy libbass.so into shared-lib folder, usually /usr/local/lib | 
					
						
							|  |  |  | 	! NOTE: for PC-Linux and ARM-Linux you need different libraries ! | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 2) liquid-DSP | 
					
						
							|  |  |  | 	Linux Install Script: | 
					
						
							|  |  |  | 		this installs it from source | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		sudo apt install git autoconf libsndfile-dev libasound-dev | 
					
						
							|  |  |  | 		git clone git://github.com/jgaeddert/liquid-dsp.git
 | 
					
						
							|  |  |  | 		cd liquid-dsp | 
					
						
							|  |  |  | 		./bootstrap.sh | 
					
						
							|  |  |  | 		./configure | 
					
						
							|  |  |  | 		make -j 8 | 
					
						
							|  |  |  | 		sudo make install | 
					
						
							|  |  |  | 		sudo ldconfig | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		a working copy of the source code is in ../3rdParty/liquid-dsp | 
					
						
							|  |  |  | 		to use this source simply remove the "git clone" line from above script | 
					
						
							|  |  |  | 		it installs libliquid.so into /usr/local/lib (Ubuntu) and | 
					
						
							|  |  |  | 		liquid.h into /usr/local/include/liquid/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	Windows: | 
					
						
							|  |  |  | 		ready libraries are in ../3rdParty/liquid-dsp-windows | 
					
						
							|  |  |  | 		copy liquid.h and liquid.lib into source directory | 
					
						
							|  |  |  | 		copy liquid.dll into executable directory | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "hsmodem.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void toGR_sendData(uint8_t* data, int type, int status); | 
					
						
							|  |  |  | void bc_rxdata(uint8_t* pdata, int len, struct sockaddr_in* rxsock); | 
					
						
							|  |  |  | void appdata_rxdata(uint8_t* pdata, int len, struct sockaddr_in* rxsock); | 
					
						
							|  |  |  | void startModem(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // threads will exit if set to 0
 | 
					
						
							|  |  |  | int keeprunning = 1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // UDP I/O
 | 
					
						
							|  |  |  | int BC_sock_AppToModem = -1; | 
					
						
							|  |  |  | int DATA_sock_AppToModem = -1; | 
					
						
							| 
									
										
										
										
											2020-11-21 19:54:47 +01:00
										 |  |  | //int DATA_sock_from_GR = -1;
 | 
					
						
							| 
									
										
										
										
											2020-11-05 19:11:57 +01:00
										 |  |  | int DATA_sock_FFT_from_GR = -1; | 
					
						
							|  |  |  | int DATA_sock_I_Q_from_GR = -1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int UdpBCport_AppToModem = 40131; | 
					
						
							|  |  |  | int UdpDataPort_AppToModem = 40132; | 
					
						
							|  |  |  | int UdpDataPort_ModemToApp = 40133; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // op mode depending values
 | 
					
						
							|  |  |  | // default mode if not set by the app
 | 
					
						
							| 
									
										
										
										
											2020-11-10 02:23:21 +01:00
										 |  |  | int speedmode = 2; | 
					
						
							| 
									
										
										
										
											2020-11-05 19:11:57 +01:00
										 |  |  | int bitsPerSymbol = 2;      // QPSK=2, 8PSK=3
 | 
					
						
							|  |  |  | int constellationSize = 4;  // QPSK=4, 8PSK=8
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | char localIP[] = { "127.0.0.1" }; | 
					
						
							|  |  |  | char ownfilename[] = { "hsmodem" }; | 
					
						
							|  |  |  | char appIP[20] = { 0 }; | 
					
						
							|  |  |  | int fixappIP = 0; | 
					
						
							|  |  |  | int restart_modems = 0; | 
					
						
							| 
									
										
										
										
											2020-11-24 16:07:52 +01:00
										 |  |  | int trigger_resetmodem = 0; | 
					
						
							| 
									
										
										
										
											2020-11-05 19:11:57 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | int caprate = 44100; | 
					
						
							|  |  |  | int txinterpolfactor = 20; | 
					
						
							|  |  |  | int rxPreInterpolfactor = 5; | 
					
						
							| 
									
										
										
										
											2020-11-10 02:23:21 +01:00
										 |  |  | int linespeed = 4410; | 
					
						
							| 
									
										
										
										
											2020-11-05 19:11:57 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | int captureDeviceNo = -1; | 
					
						
							|  |  |  | int playbackDeviceNo = -1; | 
					
						
							| 
									
										
										
										
											2020-11-21 19:54:47 +01:00
										 |  |  | int MicDeviceNo = -1; | 
					
						
							|  |  |  | int LSDeviceNo = -1; | 
					
						
							| 
									
										
										
										
											2020-11-07 18:07:55 +01:00
										 |  |  | int initialPBvol = -1; | 
					
						
							|  |  |  | int initialCAPvol = -1; | 
					
						
							| 
									
										
										
										
											2020-11-10 02:23:21 +01:00
										 |  |  | int announcement = 0; | 
					
						
							| 
									
										
										
										
											2020-11-21 19:54:47 +01:00
										 |  |  | int VoiceAudioMode = VOICEMODE_OFF; | 
					
						
							|  |  |  | int codec = 1;  // 0=opus, 1=codec2
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int init_audio_result = 0; | 
					
						
							|  |  |  | int init_voice_result = 0; | 
					
						
							| 
									
										
										
										
											2020-11-05 19:11:57 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | int main(int argc, char* argv[]) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     int opt = 0; | 
					
						
							|  |  |  |     char* modemip = NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #ifdef _LINUX_
 | 
					
						
							|  |  |  |     while ((opt = getopt(argc, argv, "m:")) != -1) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         switch (opt) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |         case 'm': | 
					
						
							|  |  |  |             // specify IP of application: hsmodem -m 192.168.0.1
 | 
					
						
							|  |  |  |             modemip = optarg; | 
					
						
							|  |  |  |             memset(appIP, 0, 20); | 
					
						
							|  |  |  |             int len = strlen(modemip); | 
					
						
							|  |  |  |             if (len < 16) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 memcpy(appIP, modemip, len); | 
					
						
							|  |  |  |                 fixappIP = 1; | 
					
						
							|  |  |  |                 printf("Application IP set to: %s\n", modemip); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             else | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 printf("invalid Application IP: %s\n", modemip); | 
					
						
							|  |  |  |                 exit(0); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (isRunning(ownfilename) == 1) | 
					
						
							|  |  |  |         exit(0); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     install_signal_handler(); | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #ifdef _WIN32_
 | 
					
						
							|  |  |  |     if (argc != 1 && argc != 3) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         printf("invalid argument\n"); | 
					
						
							|  |  |  |         exit(0); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (argc == 3) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         memset(appIP, 0, 20); | 
					
						
							|  |  |  |         int len = strlen(argv[2]); | 
					
						
							|  |  |  |         if (len < 16) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             memcpy(appIP, argv[2], len); | 
					
						
							|  |  |  |             fixappIP = 1; | 
					
						
							|  |  |  |             printf("Application IP set to: %s\n", argv[2]); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             printf("invalid Application IP: %s\n", modemip); | 
					
						
							|  |  |  |             exit(0); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2020-11-21 19:54:47 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-07 18:07:55 +01:00
										 |  |  |      | 
					
						
							| 
									
										
										
										
											2020-11-05 19:11:57 +01:00
										 |  |  |     init_packer(); | 
					
						
							|  |  |  |     initFEC(); | 
					
						
							|  |  |  |     init_fft(); | 
					
						
							| 
									
										
										
										
											2020-11-21 19:54:47 +01:00
										 |  |  |     init_voiceproc(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /*int ar = init_audio(playbackDeviceNo, captureDeviceNo);
 | 
					
						
							| 
									
										
										
										
											2020-11-05 19:11:57 +01:00
										 |  |  |     if (ar == -1) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         keeprunning = 0; | 
					
						
							|  |  |  |         exit(0); | 
					
						
							| 
									
										
										
										
											2020-11-21 19:54:47 +01:00
										 |  |  |     }*/ | 
					
						
							| 
									
										
										
										
											2020-11-05 19:11:57 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // start udp RX to listen for broadcast search message from Application
 | 
					
						
							|  |  |  |     UdpRxInit(&BC_sock_AppToModem, UdpBCport_AppToModem, &bc_rxdata, &keeprunning); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // start udp RX for data from application
 | 
					
						
							|  |  |  |     UdpRxInit(&DATA_sock_AppToModem, UdpDataPort_AppToModem, &appdata_rxdata, &keeprunning); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // start udp RX to listen for data from GR Receiver
 | 
					
						
							| 
									
										
										
										
											2020-11-21 19:54:47 +01:00
										 |  |  |     //UdpRxInit(&DATA_sock_from_GR, UdpDataPort_fromGR, &GRdata_rxdata, &keeprunning);
 | 
					
						
							| 
									
										
										
										
											2020-11-05 19:11:57 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     printf("QO100modem initialised and running\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     while (keeprunning) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         if (restart_modems == 1) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             startModem(); | 
					
						
							|  |  |  |             restart_modems = 0; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         //doArraySend();
 | 
					
						
							| 
									
										
										
										
											2020-11-21 19:54:47 +01:00
										 |  |  |         if (VoiceAudioMode == VOICEMODE_INTERNALLOOP) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             // loop voice mic to LS
 | 
					
						
							|  |  |  |             float f; | 
					
						
							|  |  |  |             if (cap_read_fifo_voice(&f)) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 if(softwareCAPvolume_voice >= 0) | 
					
						
							|  |  |  |                     f *= softwareCAPvolume_voice; | 
					
						
							|  |  |  |                 pb_write_fifo_voice(f); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (VoiceAudioMode == VOICEMODE_CODECLOOP || VoiceAudioMode == VOICEMODE_DV_FULLDUPLEX) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             // send mic to codec
 | 
					
						
							|  |  |  |             float f; | 
					
						
							|  |  |  |             if (cap_read_fifo_voice(&f)) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 if (softwareCAPvolume_voice >= 0) | 
					
						
							|  |  |  |                     f *= softwareCAPvolume_voice; | 
					
						
							|  |  |  |                 encode(f); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2020-11-05 19:11:57 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-21 19:54:47 +01:00
										 |  |  |         // demodulate incoming audio data stream
 | 
					
						
							|  |  |  |         static int old_tm = 0; | 
					
						
							|  |  |  |         int tm = getus(); | 
					
						
							|  |  |  |         if (tm >= (old_tm + 1000000)) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             // read Audio device list every 1s
 | 
					
						
							|  |  |  |             readAudioDevices(); | 
					
						
							|  |  |  |             old_tm = tm; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         int dret = demodulator(); | 
					
						
							| 
									
										
										
										
											2020-11-24 16:07:52 +01:00
										 |  |  |         if (dret == 0) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             // no new data in fifo
 | 
					
						
							|  |  |  |             // not important how long to sleep, 10ms is fine
 | 
					
						
							|  |  |  |             sleep_ms(10);    | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2020-11-05 19:11:57 +01:00
										 |  |  |     } | 
					
						
							|  |  |  |     printf("stopped: %d\n", keeprunning); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #ifdef _LINUX_
 | 
					
						
							|  |  |  |     close(BC_sock_AppToModem); | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | #ifdef _WIN32_
 | 
					
						
							|  |  |  |     closesocket(BC_sock_AppToModem); | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | typedef struct { | 
					
						
							|  |  |  |     int audio; | 
					
						
							|  |  |  |     int tx; | 
					
						
							|  |  |  |     int rx; | 
					
						
							|  |  |  |     int bpsym; | 
					
						
							| 
									
										
										
										
											2020-11-10 02:23:21 +01:00
										 |  |  |     int linespeed; | 
					
						
							| 
									
										
										
										
											2020-11-21 19:54:47 +01:00
										 |  |  |     int codecrate; | 
					
						
							| 
									
										
										
										
											2020-11-05 19:11:57 +01:00
										 |  |  | } SPEEDRATE; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-21 19:54:47 +01:00
										 |  |  | // AudioRate, TX-Resampler, RX-Resampler/4, bit/symbol, Codec-Rate
 | 
					
						
							| 
									
										
										
										
											2020-11-10 02:23:21 +01:00
										 |  |  | SPEEDRATE sr[8] = { | 
					
						
							| 
									
										
										
										
											2020-11-05 19:11:57 +01:00
										 |  |  |     // QPSK modes
 | 
					
						
							| 
									
										
										
										
											2020-11-21 19:54:47 +01:00
										 |  |  |     {48000, 32, 8, 2, 3000, 2400},  | 
					
						
							|  |  |  |     {48000, 24, 6, 2, 4000, 3200}, | 
					
						
							|  |  |  |     {44100, 20, 5, 2, 4410, 3600}, | 
					
						
							|  |  |  |     {48000, 20, 5, 2, 4800, 4000}, | 
					
						
							| 
									
										
										
										
											2020-11-05 19:11:57 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // 8PSK modes
 | 
					
						
							| 
									
										
										
										
											2020-11-21 19:54:47 +01:00
										 |  |  |     {44100, 24, 6, 3, 5500, 4400}, | 
					
						
							|  |  |  |     {48000, 24, 6, 3, 6000, 4800}, | 
					
						
							|  |  |  |     {44100, 20, 5, 3, 6600, 5200}, | 
					
						
							|  |  |  |     {48000, 20, 5, 3, 7200, 6000} | 
					
						
							| 
									
										
										
										
											2020-11-05 19:11:57 +01:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void startModem() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     bitsPerSymbol = sr[speedmode].bpsym; | 
					
						
							|  |  |  |     constellationSize = (1 << bitsPerSymbol); // QPSK=4, 8PSK=8
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     caprate = sr[speedmode].audio; | 
					
						
							|  |  |  |     txinterpolfactor = sr[speedmode].tx; | 
					
						
							|  |  |  |     rxPreInterpolfactor = sr[speedmode].rx; | 
					
						
							| 
									
										
										
										
											2020-11-10 02:23:21 +01:00
										 |  |  |     linespeed = sr[speedmode].linespeed; | 
					
						
							| 
									
										
										
										
											2020-11-21 19:54:47 +01:00
										 |  |  |     opusbitrate = sr[speedmode].codecrate; | 
					
						
							| 
									
										
										
										
											2020-11-05 19:11:57 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // int TX audio and modulator
 | 
					
						
							|  |  |  |     close_dsp(); | 
					
						
							| 
									
										
										
										
											2020-11-21 19:54:47 +01:00
										 |  |  |     init_audio_result = init_audio(playbackDeviceNo, captureDeviceNo); | 
					
						
							| 
									
										
										
										
											2020-11-07 18:07:55 +01:00
										 |  |  |     setPBvolume(initialPBvol); | 
					
						
							|  |  |  |     setCAPvolume(initialCAPvol); | 
					
						
							| 
									
										
										
										
											2020-11-05 19:11:57 +01:00
										 |  |  |     init_dsp(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-21 19:54:47 +01:00
										 |  |  | void setAudioDevices(int pb, int cap, int pbvol, int capvol, int announce, int pbls, int pbmic) | 
					
						
							| 
									
										
										
										
											2020-11-05 19:11:57 +01:00
										 |  |  | { | 
					
						
							|  |  |  |     //printf("%d %d\n", pb, cap);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (pb != playbackDeviceNo || cap != captureDeviceNo) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         restart_modems = 1; | 
					
						
							|  |  |  |         playbackDeviceNo = pb; | 
					
						
							|  |  |  |         captureDeviceNo = cap; | 
					
						
							| 
									
										
										
										
											2020-11-07 18:07:55 +01:00
										 |  |  |         initialPBvol = pbvol; | 
					
						
							|  |  |  |         initialCAPvol = capvol; | 
					
						
							| 
									
										
										
										
											2020-11-21 19:54:47 +01:00
										 |  |  |         initialLSvol = pbls; | 
					
						
							|  |  |  |         initialMICvol = pbmic; | 
					
						
							| 
									
										
										
										
											2020-11-05 19:11:57 +01:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-11-10 02:23:21 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     announcement = announce; | 
					
						
							| 
									
										
										
										
											2020-11-05 19:11:57 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // called from UDP RX thread for Broadcast-search from App
 | 
					
						
							|  |  |  | void bc_rxdata(uint8_t* pdata, int len, struct sockaddr_in* rxsock) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (len > 0 && pdata[0] == 0x3c) | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2020-11-21 19:54:47 +01:00
										 |  |  |         setAudioDevices(pdata[1], pdata[2], pdata[3], pdata[4], pdata[5], pdata[6], pdata[7]); | 
					
						
							| 
									
										
										
										
											2020-11-05 19:11:57 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |         char rxip[20]; | 
					
						
							|  |  |  |         strcpy(rxip, inet_ntoa(rxsock->sin_addr)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (fixappIP == 0) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             if (strcmp(appIP, rxip)) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 printf("new app IP: %s, restarting modems\n", rxip); | 
					
						
							|  |  |  |                 restart_modems = 1; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             strcpy(appIP, rxip); | 
					
						
							|  |  |  |             //printf("app (%s) is searching modem. Sending modem IP to the app\n",appIP);
 | 
					
						
							|  |  |  |             // App searches for the modem IP, mirror the received messages
 | 
					
						
							|  |  |  |             // so the app gets an UDP message with this local IP
 | 
					
						
							|  |  |  |             int alen; | 
					
						
							|  |  |  |             uint8_t* txdata = getAudioDevicelist(&alen); | 
					
						
							|  |  |  |             sendUDP(appIP, UdpDataPort_ModemToApp, txdata, alen); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             // appIP is fixed, answer only to this IP
 | 
					
						
							|  |  |  |             if (!strcmp(appIP, rxip)) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 //printf("app (%s) is searching modem. Sending modem IP to the app\n",appIP);
 | 
					
						
							|  |  |  |                 restart_modems = 1; | 
					
						
							|  |  |  |                 // App searches for the modem IP, mirror the received messages
 | 
					
						
							|  |  |  |                 // so the app gets an UDP message with this local IP
 | 
					
						
							|  |  |  |                 int alen; | 
					
						
							|  |  |  |                 uint8_t* txdata = getAudioDevicelist(&alen); | 
					
						
							|  |  |  |                 sendUDP(appIP, UdpDataPort_ModemToApp, txdata, alen); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // called by UDP RX thread for data from App
 | 
					
						
							|  |  |  | void appdata_rxdata(uint8_t* pdata, int len, struct sockaddr_in* rxsock) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     uint8_t type = pdata[0]; | 
					
						
							|  |  |  |     uint8_t minfo = pdata[1]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // type values: see oscardata config.cs: frame types
 | 
					
						
							|  |  |  |     if (type == 16) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         // Byte 1 contains the resampler ratio for TX and RX modem
 | 
					
						
							| 
									
										
										
										
											2020-11-21 19:54:47 +01:00
										 |  |  |         if (pdata[1] >= 8) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             printf("wrong speedmode %d, ignoring\n", pdata[1]); | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2020-11-05 19:11:57 +01:00
										 |  |  |         speedmode = pdata[1]; | 
					
						
							|  |  |  |         printf("set speedmode to %d\n", speedmode); | 
					
						
							|  |  |  |         restart_modems = 1; | 
					
						
							| 
									
										
										
										
											2020-11-10 02:23:21 +01:00
										 |  |  |         transmissions = 1000;   // announcement at next TX
 | 
					
						
							| 
									
										
										
										
											2020-11-05 19:11:57 +01:00
										 |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (type == 17) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         // auto send file
 | 
					
						
							|  |  |  |         // TODO
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // for testing only:
 | 
					
						
							|  |  |  |         // simulate sending a text file with 1kB length
 | 
					
						
							|  |  |  |         /*int testlen = 100000;
 | 
					
						
							|  |  |  |         uint8_t arr[100000]; | 
					
						
							|  |  |  |         char c = 'A'; | 
					
						
							|  |  |  |         for (int i = 0; i < testlen; i++) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             arr[i] = c; | 
					
						
							|  |  |  |             if (++c > 'Z') c = 'A'; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         arraySend(arr, testlen, 3, (char*)"testfile.txt");*/ | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (type == 18) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         // auto send folder
 | 
					
						
							|  |  |  |         // TODO
 | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (type == 19) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         // shut down this modem PC
 | 
					
						
							| 
									
										
										
										
											2020-11-24 16:07:52 +01:00
										 |  |  | #ifdef _LINUX_
 | 
					
						
							| 
									
										
										
										
											2020-11-05 19:11:57 +01:00
										 |  |  |         int r = system("sudo shutdown now"); | 
					
						
							|  |  |  |         exit(r); | 
					
						
							| 
									
										
										
										
											2020-11-24 16:07:52 +01:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2020-11-05 19:11:57 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (type == 20) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         // reset liquid RX modem
 | 
					
						
							|  |  |  |         resetModem(); | 
					
						
							| 
									
										
										
										
											2020-11-07 18:07:55 +01:00
										 |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (type == 21) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         // set playback volume (in % 0..100)
 | 
					
						
							|  |  |  |         setVolume(0,minfo); | 
					
						
							|  |  |  |         return; | 
					
						
							| 
									
										
										
										
											2020-11-05 19:11:57 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-07 18:07:55 +01:00
										 |  |  |     if (type == 22) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         // set capture volume (in % 0..100)
 | 
					
						
							|  |  |  |         setVolume(1,minfo); | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-21 19:54:47 +01:00
										 |  |  |     if (type == 23) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         // set playback volume (in % 0..100)
 | 
					
						
							|  |  |  |         setVolume_voice(0, minfo); | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (type == 24) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         // set capture volume (in % 0..100)
 | 
					
						
							|  |  |  |         setVolume_voice(1, minfo); | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (type == 25) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         //printf("%d %d %d %d %d\n", pdata[0], pdata[1], pdata[2], pdata[3], pdata[4]);
 | 
					
						
							|  |  |  |         LSDeviceNo = pdata[1]; | 
					
						
							|  |  |  |         MicDeviceNo = pdata[2]; | 
					
						
							|  |  |  |         VoiceAudioMode = pdata[3]; | 
					
						
							|  |  |  |         codec = pdata[4]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // init voice audio
 | 
					
						
							|  |  |  |         init_voice_result = init_audio_voice(LSDeviceNo, MicDeviceNo); | 
					
						
							|  |  |  |         init_voiceproc(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (type == 26) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         // GUI requests termination of this hsmodem
 | 
					
						
							|  |  |  |         printf("shut down hsmodem\n"); | 
					
						
							|  |  |  |         closeAllandTerminate(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-07 18:07:55 +01:00
										 |  |  |     if (len != (PAYLOADLEN + 2)) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         printf("data from app: wrong length:%d (should be %d)\n", len - 2, PAYLOADLEN); | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-05 19:11:57 +01:00
										 |  |  |     //if (getSending() == 1) return;   // already sending (Array sending)
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-15 01:32:47 +01:00
										 |  |  |     if (minfo == 0 || minfo == 3) | 
					
						
							| 
									
										
										
										
											2020-11-05 19:11:57 +01:00
										 |  |  |     { | 
					
						
							|  |  |  |         // this is the first frame of a larger file
 | 
					
						
							| 
									
										
										
										
											2020-11-10 02:23:21 +01:00
										 |  |  |         sendAnnouncement(); | 
					
						
							| 
									
										
										
										
											2020-11-05 19:11:57 +01:00
										 |  |  |         // send it multiple times, like a preamble, to give the
 | 
					
						
							|  |  |  |         // receiver some time for synchronisation
 | 
					
						
							|  |  |  |         // caprate: samples/s. This are symbols: caprate/txinterpolfactor
 | 
					
						
							|  |  |  |         // and bits: symbols * bitsPerSymbol
 | 
					
						
							|  |  |  |         // and bytes/second: bits/8 = (caprate/txinterpolfactor) * bitsPerSymbol / 8
 | 
					
						
							| 
									
										
										
										
											2020-11-15 01:32:47 +01:00
										 |  |  |         // one frame has 258 bytes, so we need for 6s: 6* ((caprate/txinterpolfactor) * bitsPerSymbol / 8) /258 + 1 frames
 | 
					
						
							|  |  |  |         int numframespreamble = 6 * ((caprate / txinterpolfactor) * bitsPerSymbol / 8) / 258 + 1; | 
					
						
							| 
									
										
										
										
											2020-11-05 19:11:57 +01:00
										 |  |  |         for (int i = 0; i < numframespreamble; i++) | 
					
						
							|  |  |  |             toGR_sendData(pdata + 2, type, minfo); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else if ((len - 2) < PAYLOADLEN) | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2020-11-10 02:23:21 +01:00
										 |  |  |         // if not enough data for a full payload add Zeros 
 | 
					
						
							| 
									
										
										
										
											2020-11-05 19:11:57 +01:00
										 |  |  |         uint8_t payload[PAYLOADLEN]; | 
					
						
							|  |  |  |         memset(payload, 0, PAYLOADLEN); | 
					
						
							|  |  |  |         memcpy(payload, pdata + 2, len - 2); | 
					
						
							|  |  |  |         toGR_sendData(payload, type, minfo); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         toGR_sendData(pdata + 2, type, minfo); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void toGR_sendData(uint8_t* data, int type, int status) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     int len = 0; | 
					
						
							|  |  |  |     uint8_t* txdata = Pack(data, type, status, &len); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     //showbytestring((char *)"BERtx: ", txdata, len);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (txdata != NULL) | 
					
						
							|  |  |  |         sendToModulator(txdata, len); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-10 02:23:21 +01:00
										 |  |  | // called by liquid demodulator for received data
 | 
					
						
							| 
									
										
										
										
											2020-11-05 19:11:57 +01:00
										 |  |  | void GRdata_rxdata(uint8_t* pdata, int len, struct sockaddr_in* rxsock) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     static int fnd = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // raw symbols
 | 
					
						
							|  |  |  |     uint8_t* pl = unpack_data(pdata, len); | 
					
						
							|  |  |  |     if (pl != NULL) | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2020-11-21 19:54:47 +01:00
										 |  |  |         if (VoiceAudioMode != VOICEMODE_DV_FULLDUPLEX) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             // complete frame received
 | 
					
						
							|  |  |  |             // send payload to app
 | 
					
						
							|  |  |  |             uint8_t txpl[PAYLOADLEN + 10 + 1]; | 
					
						
							|  |  |  |             memcpy(txpl + 1, pl, PAYLOADLEN + 10); | 
					
						
							|  |  |  |             txpl[0] = 1;    // type 1: payload data follows
 | 
					
						
							|  |  |  |             sendUDP(appIP, UdpDataPort_ModemToApp, txpl, PAYLOADLEN + 10 + 1); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             // send to Codec decoder
 | 
					
						
							|  |  |  |             if (*(pl + 3) != 0) // minfo=0 ... just a filler, ignore
 | 
					
						
							|  |  |  |                 toCodecDecoder(pl + 10, PAYLOADLEN); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2020-11-05 19:11:57 +01:00
										 |  |  |         fnd = 0; | 
					
						
							| 
									
										
										
										
											2020-11-24 16:07:52 +01:00
										 |  |  |         trigger_resetmodem = 0; | 
					
						
							|  |  |  |         rx_in_sync = 1; | 
					
						
							| 
									
										
										
										
											2020-11-05 19:11:57 +01:00
										 |  |  |     } | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         // no frame found
 | 
					
						
							|  |  |  |         // if longer ws seconds nothing found, reset liquid RX modem
 | 
					
						
							|  |  |  |         // comes here with symbol rate, i.e. 4000 S/s
 | 
					
						
							| 
									
										
										
										
											2020-11-24 16:07:52 +01:00
										 |  |  |         int ws = 5;  | 
					
						
							| 
									
										
										
										
											2020-11-05 19:11:57 +01:00
										 |  |  |         int wt = sr[speedmode].audio / sr[speedmode].tx; | 
					
						
							| 
									
										
										
										
											2020-11-24 16:07:52 +01:00
										 |  |  |         if (++fnd >= (wt * ws) || trigger_resetmodem) | 
					
						
							| 
									
										
										
										
											2020-11-05 19:11:57 +01:00
										 |  |  |         { | 
					
						
							|  |  |  |             fnd = 0; | 
					
						
							| 
									
										
										
										
											2020-11-24 16:07:52 +01:00
										 |  |  |             trigger_resetmodem = 0; | 
					
						
							|  |  |  |             rx_in_sync = 0; | 
					
						
							| 
									
										
										
										
											2020-11-15 01:32:47 +01:00
										 |  |  |             printf("no signal detected %d, reset RX modem\n", wt); | 
					
						
							| 
									
										
										
										
											2020-11-05 19:11:57 +01:00
										 |  |  |             resetModem(); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2020-11-24 16:07:52 +01:00
										 |  |  |         else if (fnd >= wt) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             rx_in_sync = 0; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2020-11-05 19:11:57 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | } |