diff --git a/WinRelease/hsmodem.exe b/WinRelease/hsmodem.exe index c2f5a1f..048d8a9 100755 Binary files a/WinRelease/hsmodem.exe and b/WinRelease/hsmodem.exe differ diff --git a/WinRelease/hsmodem.iobj b/WinRelease/hsmodem.iobj index 1fbcac8..2289cf4 100755 Binary files a/WinRelease/hsmodem.iobj and b/WinRelease/hsmodem.iobj differ diff --git a/WinRelease/hsmodem.ipdb b/WinRelease/hsmodem.ipdb index 2346a5b..da71cc2 100755 Binary files a/WinRelease/hsmodem.ipdb and b/WinRelease/hsmodem.ipdb differ diff --git a/WinRelease/hsmodem.pdb b/WinRelease/hsmodem.pdb index 69478ee..29e3771 100755 Binary files a/WinRelease/hsmodem.pdb and b/WinRelease/hsmodem.pdb differ diff --git a/WinRelease/oscardata.exe b/WinRelease/oscardata.exe index 82afc41..28bc9e3 100755 Binary files a/WinRelease/oscardata.exe and b/WinRelease/oscardata.exe differ diff --git a/hsmodem/Makefile b/hsmodem/Makefile index 656ae2a..a5a2525 100755 --- a/hsmodem/Makefile +++ b/hsmodem/Makefile @@ -9,7 +9,7 @@ CXXFLAGS = -Wall -O3 -std=c++0x -Wno-write-strings -Wno-narrowing LDFLAGS = -lpthread -lrt -lsndfile -lasound -lm -lopus -lfftw3 -lfftw3_threads -lliquid -lcodec2 -lsoundio -OBJ = hsmodem.o constellation.o crc16.o frame_packer.o main_helper.o scrambler.o speed.o fec.o udp.o fft.o liquid_if.o symboltracker.o voiceprocessor.o codec2.o soundio.o fifo.o announcement.o fifo_voice.o voiceio.o tuning.o +OBJ = hsmodem.o constellation.o crc16.o frame_packer.o main_helper.o scrambler.o speed.o fec.o udp.o fft.o liquid_if.o symboltracker.o voiceprocessor.o codec2.o soundio.o fifo.o announcement.o fifo_voice.o voiceio.o tuning.o rtty.o default: $(OBJ) mkdir -p ../hsmodemLinux diff --git a/hsmodem/Release/announcement.obj b/hsmodem/Release/announcement.obj deleted file mode 100755 index 3bdde8d..0000000 Binary files a/hsmodem/Release/announcement.obj and /dev/null differ diff --git a/hsmodem/Release/codec2.obj b/hsmodem/Release/codec2.obj deleted file mode 100755 index e9d13cb..0000000 Binary files a/hsmodem/Release/codec2.obj and /dev/null differ diff --git a/hsmodem/Release/constellation.obj b/hsmodem/Release/constellation.obj deleted file mode 100755 index ff547b8..0000000 Binary files a/hsmodem/Release/constellation.obj and /dev/null differ diff --git a/hsmodem/Release/crc16.obj b/hsmodem/Release/crc16.obj deleted file mode 100755 index 12bc6f7..0000000 Binary files a/hsmodem/Release/crc16.obj and /dev/null differ diff --git a/hsmodem/Release/fec.obj b/hsmodem/Release/fec.obj deleted file mode 100755 index 895d19e..0000000 Binary files a/hsmodem/Release/fec.obj and /dev/null differ diff --git a/hsmodem/Release/fft.obj b/hsmodem/Release/fft.obj deleted file mode 100755 index 42f29c9..0000000 Binary files a/hsmodem/Release/fft.obj and /dev/null differ diff --git a/hsmodem/Release/fifo.obj b/hsmodem/Release/fifo.obj deleted file mode 100755 index 4348d34..0000000 Binary files a/hsmodem/Release/fifo.obj and /dev/null differ diff --git a/hsmodem/Release/fifo_voice.obj b/hsmodem/Release/fifo_voice.obj deleted file mode 100755 index b32ff78..0000000 Binary files a/hsmodem/Release/fifo_voice.obj and /dev/null differ diff --git a/hsmodem/Release/frame_packer.obj b/hsmodem/Release/frame_packer.obj deleted file mode 100755 index 88275ff..0000000 Binary files a/hsmodem/Release/frame_packer.obj and /dev/null differ diff --git a/hsmodem/Release/hsmodem.Build.CppClean.log b/hsmodem/Release/hsmodem.Build.CppClean.log deleted file mode 100755 index 7e8dd76..0000000 --- a/hsmodem/Release/hsmodem.Build.CppClean.log +++ /dev/null @@ -1,32 +0,0 @@ -e:\funk\hsmodem\hsmodem\release\vc140.pdb -e:\funk\hsmodem\hsmodem\release\tuning.obj -e:\funk\hsmodem\hsmodem\release\liquid_if.obj -e:\funk\hsmodem\hsmodem\release\fft.obj -e:\funk\hsmodem\hsmodem\release\voiceprocessor.obj -e:\funk\hsmodem\hsmodem\release\voiceio.obj -e:\funk\hsmodem\hsmodem\release\udp.obj -e:\funk\hsmodem\hsmodem\release\symboltracker.obj -e:\funk\hsmodem\hsmodem\release\speed.obj -e:\funk\hsmodem\hsmodem\release\soundio.obj -e:\funk\hsmodem\hsmodem\release\scrambler.obj -e:\funk\hsmodem\hsmodem\release\main_helper.obj -e:\funk\hsmodem\hsmodem\release\hsmodem.obj -e:\funk\hsmodem\hsmodem\release\frame_packer.obj -e:\funk\hsmodem\hsmodem\release\fifo_voice.obj -e:\funk\hsmodem\hsmodem\release\fifo.obj -e:\funk\hsmodem\hsmodem\release\fec.obj -e:\funk\hsmodem\hsmodem\release\crc16.obj -e:\funk\hsmodem\hsmodem\release\constellation.obj -e:\funk\hsmodem\hsmodem\release\codec2.obj -e:\funk\hsmodem\hsmodem\release\announcement.obj -e:\funk\hsmodem\winrelease\hsmodem.exe -e:\funk\hsmodem\winrelease\hsmodem.ipdb -e:\funk\hsmodem\winrelease\hsmodem.iobj -e:\funk\hsmodem\winrelease\hsmodem.pdb -e:\funk\hsmodem\hsmodem\..\winrelease\hsmodem.exe -e:\funk\hsmodem\hsmodem\release\hsmodem.tlog\cl.command.1.tlog -e:\funk\hsmodem\hsmodem\release\hsmodem.tlog\cl.read.1.tlog -e:\funk\hsmodem\hsmodem\release\hsmodem.tlog\cl.write.1.tlog -e:\funk\hsmodem\hsmodem\release\hsmodem.tlog\link.command.1.tlog -e:\funk\hsmodem\hsmodem\release\hsmodem.tlog\link.read.1.tlog -e:\funk\hsmodem\hsmodem\release\hsmodem.tlog\link.write.1.tlog diff --git a/hsmodem/Release/hsmodem.log b/hsmodem/Release/hsmodem.log deleted file mode 100755 index 6a30007..0000000 --- a/hsmodem/Release/hsmodem.log +++ /dev/null @@ -1,24 +0,0 @@ - announcement.cpp - codec2.cpp - constellation.cpp - crc16.cpp - fec.cpp - fft.cpp - fifo.cpp - fifo_voice.cpp - frame_packer.cpp - hsmodem.cpp - liquid_if.cpp - main_helper.cpp - scrambler.cpp - soundio.cpp - speed.cpp - symboltracker.cpp - tuning.cpp - udp.cpp - voiceio.cpp - voiceprocessor.cpp - Code wird generiert. - All 602 functions were compiled because no usable IPDB/IOBJ from previous compilation was found. - Codegenerierung ist abgeschlossen. - hsmodem.vcxproj -> E:\funk\hsmodem\hsmodem\..\WinRelease\hsmodem.exe diff --git a/hsmodem/Release/hsmodem.obj b/hsmodem/Release/hsmodem.obj deleted file mode 100755 index 8fd2ecf..0000000 Binary files a/hsmodem/Release/hsmodem.obj and /dev/null differ diff --git a/hsmodem/Release/hsmodem.tlog/CL.command.1.tlog b/hsmodem/Release/hsmodem.tlog/CL.command.1.tlog deleted file mode 100755 index 70e5322..0000000 Binary files a/hsmodem/Release/hsmodem.tlog/CL.command.1.tlog and /dev/null differ diff --git a/hsmodem/Release/hsmodem.tlog/CL.read.1.tlog b/hsmodem/Release/hsmodem.tlog/CL.read.1.tlog deleted file mode 100755 index ef9120e..0000000 Binary files a/hsmodem/Release/hsmodem.tlog/CL.read.1.tlog and /dev/null differ diff --git a/hsmodem/Release/hsmodem.tlog/CL.write.1.tlog b/hsmodem/Release/hsmodem.tlog/CL.write.1.tlog deleted file mode 100755 index 6b01914..0000000 Binary files a/hsmodem/Release/hsmodem.tlog/CL.write.1.tlog and /dev/null differ diff --git a/hsmodem/Release/hsmodem.tlog/hsmodem.lastbuildstate b/hsmodem/Release/hsmodem.tlog/hsmodem.lastbuildstate deleted file mode 100755 index d1d5971..0000000 --- a/hsmodem/Release/hsmodem.tlog/hsmodem.lastbuildstate +++ /dev/null @@ -1,2 +0,0 @@ -#TargetFrameworkVersion=v4.0:PlatformToolSet=v140_xp:EnableManagedIncrementalBuild=false:VCToolArchitecture=Native32Bit:WindowsTargetPlatformVersion=8.1 -Release|Win32|E:\funk\hsmodem\| diff --git a/hsmodem/Release/hsmodem.tlog/link.command.1.tlog b/hsmodem/Release/hsmodem.tlog/link.command.1.tlog deleted file mode 100755 index bc14a2c..0000000 Binary files a/hsmodem/Release/hsmodem.tlog/link.command.1.tlog and /dev/null differ diff --git a/hsmodem/Release/hsmodem.tlog/link.read.1.tlog b/hsmodem/Release/hsmodem.tlog/link.read.1.tlog deleted file mode 100755 index 0513737..0000000 Binary files a/hsmodem/Release/hsmodem.tlog/link.read.1.tlog and /dev/null differ diff --git a/hsmodem/Release/hsmodem.tlog/link.write.1.tlog b/hsmodem/Release/hsmodem.tlog/link.write.1.tlog deleted file mode 100755 index 02829da..0000000 Binary files a/hsmodem/Release/hsmodem.tlog/link.write.1.tlog and /dev/null differ diff --git a/hsmodem/Release/hsmodem.vcxproj.FileListAbsolute.txt b/hsmodem/Release/hsmodem.vcxproj.FileListAbsolute.txt deleted file mode 100755 index e69de29..0000000 diff --git a/hsmodem/Release/liquid_if.obj b/hsmodem/Release/liquid_if.obj deleted file mode 100755 index 24c40b9..0000000 Binary files a/hsmodem/Release/liquid_if.obj and /dev/null differ diff --git a/hsmodem/Release/main_helper.obj b/hsmodem/Release/main_helper.obj deleted file mode 100755 index abdc194..0000000 Binary files a/hsmodem/Release/main_helper.obj and /dev/null differ diff --git a/hsmodem/Release/scrambler.obj b/hsmodem/Release/scrambler.obj deleted file mode 100755 index 9454855..0000000 Binary files a/hsmodem/Release/scrambler.obj and /dev/null differ diff --git a/hsmodem/Release/soundio.obj b/hsmodem/Release/soundio.obj deleted file mode 100755 index 5fe8b4f..0000000 Binary files a/hsmodem/Release/soundio.obj and /dev/null differ diff --git a/hsmodem/Release/speed.obj b/hsmodem/Release/speed.obj deleted file mode 100755 index dce1202..0000000 Binary files a/hsmodem/Release/speed.obj and /dev/null differ diff --git a/hsmodem/Release/symboltracker.obj b/hsmodem/Release/symboltracker.obj deleted file mode 100755 index 0cf525a..0000000 Binary files a/hsmodem/Release/symboltracker.obj and /dev/null differ diff --git a/hsmodem/Release/tuning.obj b/hsmodem/Release/tuning.obj deleted file mode 100755 index 222443d..0000000 Binary files a/hsmodem/Release/tuning.obj and /dev/null differ diff --git a/hsmodem/Release/udp.obj b/hsmodem/Release/udp.obj deleted file mode 100755 index 3994531..0000000 Binary files a/hsmodem/Release/udp.obj and /dev/null differ diff --git a/hsmodem/Release/vc140.pdb b/hsmodem/Release/vc140.pdb deleted file mode 100755 index a3e3c8d..0000000 Binary files a/hsmodem/Release/vc140.pdb and /dev/null differ diff --git a/hsmodem/Release/voiceio.obj b/hsmodem/Release/voiceio.obj deleted file mode 100755 index 27326cb..0000000 Binary files a/hsmodem/Release/voiceio.obj and /dev/null differ diff --git a/hsmodem/Release/voiceprocessor.obj b/hsmodem/Release/voiceprocessor.obj deleted file mode 100755 index df245ce..0000000 Binary files a/hsmodem/Release/voiceprocessor.obj and /dev/null differ diff --git a/hsmodem/fft.cpp b/hsmodem/fft.cpp index d53aefa..ef1918b 100755 --- a/hsmodem/fft.cpp +++ b/hsmodem/fft.cpp @@ -153,8 +153,8 @@ uint16_t *make_waterfall(float fre, int *retlen) } // smooth fft output -const int smoothX = 6; // must be an even number ! -const int smoothY = 3; +const int smoothX = 2; // must be an even number ! +const int smoothY = 10; int yidx = 0; uint16_t* mean(uint16_t* f) @@ -164,7 +164,7 @@ uint16_t* mean(uint16_t* f) if (tuning) return f; - + // first smooth X values for (int x = 0; x < smoothX / 2; x++) fa[x] = f[x]; @@ -179,8 +179,9 @@ uint16_t* mean(uint16_t* f) for (int x = fftcount - smoothX / 2; x < fftcount; x++) fa[x] = f[x]; - + // smooth Y values + static uint16_t yarr[smoothY][FFT_AUDIOSAMPLERATE / 2 + 1]; for (int i = 0; i < fftcount; i++) yarr[yidx][i] = fa[i]; @@ -194,10 +195,6 @@ uint16_t* mean(uint16_t* f) fa[i] /= smoothY; } - // do not smooth 2950 to 3050 Hz - for (int i = 295; i < 305; i++) - fa[i] = f[i]; - return fa; } @@ -216,7 +213,7 @@ void _init_fft() // decimate 44.1k or 48k down to 8000Hz // the FFT rate is 800, but we feed it with 8000 Samplerate // this results in a new fft every 100ms with a resolution of 10 Hz - float ratio = 10.0f * (float)FFT_AUDIOSAMPLERATE / (float)physcaprate; + float ratio = 10.0f * (float)FFT_AUDIOSAMPLERATE / (float)physRXcaprate; fftdecim = msresamp_crcf_create(ratio, 40.0f); } diff --git a/hsmodem/hsmodem.cpp b/hsmodem/hsmodem.cpp index e084475..806d484 100755 --- a/hsmodem/hsmodem.cpp +++ b/hsmodem/hsmodem.cpp @@ -68,7 +68,7 @@ int trigger_resetmodem = 0; char homepath[1000] = { 0 }; int caprate = 44100; -int physcaprate = 44100; +int physRXcaprate = 44100; int txinterpolfactor = 20; int rxPreInterpolfactor = 5; int linespeed = 4410; @@ -87,7 +87,7 @@ int announcement = 0; int VoiceAudioMode = VOICEMODE_OFF; int codec = 1; // 0=opus, 1=codec2 int tuning = 0; -int marker = 0; +int marker = 1; int init_audio_result = 0; int init_voice_result = 0; @@ -382,6 +382,8 @@ void bc_rxdata(uint8_t* pdata, int len, struct sockaddr_in* rxsock) char rxip[20]; strcpy(rxip, inet_ntoa(rxsock->sin_addr)); + //printf("GUI search received:%s\n",rxip); + if (fixappIP == 0) { if (strcmp(appIP, rxip)) @@ -391,13 +393,14 @@ void bc_rxdata(uint8_t* pdata, int len, struct sockaddr_in* rxsock) // there was an appIP already // before accepting this new one, wait 3 seconds int ts = (int)(actms - lastms); - printf("new app IP: %s since %d, restarting modems\n", rxip,ts); + //printf("new app IP: %s since %d, restarting modems\n", rxip,ts); if (ts < 3000) return; } - printf("first app IP: %s, restarting modems\n", rxip); + //printf("first 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 @@ -569,8 +572,7 @@ void appdata_rxdata(uint8_t* pdata, int len, struct sockaddr_in* rxsock) if (type == 27) { // send Tuning tones - printf("Tuning mode active\n"); - VoiceAudioMode = VOICEMODE_OFF; + printf("Tuning mode active:%d\n",minfo); tuning_runtime = 0; tuning = minfo; return; @@ -583,6 +585,15 @@ void appdata_rxdata(uint8_t* pdata, int len, struct sockaddr_in* rxsock) return; } + if (type == 29) + { + int v = minfo; + if (v > 128) + v = v - 255; + modifyRXfreq(float(v)); + return; + } + // here we are with payload data to be sent via the modulator if (len != (PAYLOADLEN + 2)) diff --git a/hsmodem/hsmodem.h b/hsmodem/hsmodem.h index eaf03e9..43744d6 100755 --- a/hsmodem/hsmodem.h +++ b/hsmodem/hsmodem.h @@ -206,6 +206,10 @@ void io_clear_voice_fifos(); float do_tuning(int send); void init_tune(); float singleFrequency(); +void rtty_tx(); +int rtty_rx(); +void modifyRXfreq(float fr); +void showbytestring16(char* title, uint16_t* data, int anz); extern int speedmode; @@ -240,7 +244,7 @@ extern int rxlevel_deteced; extern int rx_in_sync; extern float softwareMICvolume; extern float softwareLSvolume; -extern int physcaprate; +extern int physRXcaprate; extern int restart_modems; extern int safemode; extern char homepath[]; diff --git a/hsmodem/hsmodem.vcxproj b/hsmodem/hsmodem.vcxproj index 8c992c6..ffff591 100755 --- a/hsmodem/hsmodem.vcxproj +++ b/hsmodem/hsmodem.vcxproj @@ -251,6 +251,7 @@ + diff --git a/hsmodem/hsmodem.vcxproj.filters b/hsmodem/hsmodem.vcxproj.filters index c4015bf..f1cf294 100755 --- a/hsmodem/hsmodem.vcxproj.filters +++ b/hsmodem/hsmodem.vcxproj.filters @@ -75,6 +75,9 @@ Source Files + + Source Files + diff --git a/hsmodem/liquid_if.cpp b/hsmodem/liquid_if.cpp index 3c0356d..a42c075 100755 --- a/hsmodem/liquid_if.cpp +++ b/hsmodem/liquid_if.cpp @@ -209,7 +209,7 @@ void modulator(uint8_t sym_in) } if(marker) - usb += singleFrequency() / 10.0f; + usb += singleFrequency() / 4.0f; io_pb_write_fifo(usb * 0.2f); // reduce volume and send to soundcard } @@ -221,6 +221,7 @@ nco_crcf dnnco = NULL; symtrack_cccf symtrack = NULL; firdecim_crcf decim = NULL; msresamp_crcf adecim = NULL; +msresamp_crcf lsresamp = NULL; // decimator parameters unsigned int m_predec = 8; // filter delay @@ -240,16 +241,27 @@ float bandwidth_st = 0.9f; // loop filter bandwidth uint8_t maxLevel = 0; // maximum RXlevel over the last x samples in % uint8_t maxTXLevel = 0; // maximum TXlevel over the last x samples in % +float radians_per_sample = ((2.0f * (float)M_PI * (float)FREQUENCY) / (float)caprate); +float last_radians_per_sample = 0; +float actfrequency = (float)FREQUENCY; + +void modifyRXfreq(float diff_Hz) +{ + actfrequency += diff_Hz; + printf("set:%f Hz\n", actfrequency); + radians_per_sample = ((2.0f * (float)M_PI * actfrequency) / (float)caprate); +} + void init_demodulator() { printf("init RX demodulator\n"); // downmixer oscillator - float RADIANS_PER_SAMPLE = ((2.0f*(float)M_PI*(float)FREQUENCY)/(float)caprate); + radians_per_sample = ((2.0f*(float)M_PI*(float)FREQUENCY)/(float)caprate); dnnco = nco_crcf_create(LIQUID_NCO); nco_crcf_set_phase(dnnco, 0.0f); - nco_crcf_set_frequency(dnnco, RADIANS_PER_SAMPLE); + nco_crcf_set_frequency(dnnco, radians_per_sample); // create pre-decimator decim = firdecim_crcf_create_kaiser(rxPreInterpolfactor, m_predec, As_predec); @@ -259,6 +271,8 @@ void init_demodulator() // if Audio SR is 48000 but caprate is 44100 r_OutDivInRatio = (float)((float)caprate / 48000.0); adecim = msresamp_crcf_create(r_OutDivInRatio, As_adecim); + + lsresamp = msresamp_crcf_create((float)(48000.0/44100.0), As_adecim); // create symbol tracking synchronizer km_symtrack_cccf_create(ftype_st, k_st, m_st, beta_st, getMod()); @@ -268,10 +282,15 @@ void init_demodulator() void close_demodulator() { if(decim != NULL) firdecim_crcf_destroy(decim); - if(adecim) msresamp_crcf_destroy(adecim); - symtrack = NULL; decim = NULL; + if(adecim) msresamp_crcf_destroy(adecim); adecim = NULL; + if (lsresamp) msresamp_crcf_destroy(lsresamp); + lsresamp = NULL; + if (symtrack != NULL) symtrack_cccf_destroy(symtrack); + symtrack = NULL; + if (dnnco != NULL) nco_crcf_destroy(dnnco); + dnnco = NULL; } void resetModem() @@ -288,6 +307,33 @@ void make_FFTdata(float f) uint16_t* fft = make_waterfall(f, &fftlen); if (fft != NULL) { + // fft data are in fft[] size: 0..fftlen + // 10 Hz per value + float fdiff = (float)FREQUENCY - actfrequency; + // shift spectrum if we are off 1500 Hz + int diff10Hz = (int)(fdiff / 10.0); + if (diff10Hz != 0) + { + //printf("%d %f %f %d\n", FREQUENCY, actfrequency, fdiff, diff10Hz); + if (diff10Hz < 0) + { + diff10Hz = -diff10Hz; + for (int i = 0; i < (fftlen-diff10Hz); i++) + fft[i] = fft[i + diff10Hz]; + + for (int i = (fftlen - diff10Hz); i < fftlen; i++) + fft[i] = 0; + } + else + { + for (int i = fftlen-1; i >= diff10Hz; i--) + fft[i] = fft[i - diff10Hz]; + + for (int i = 0; i < diff10Hz; i++) + fft[i] = 0; + } + } + uint8_t txpl[10000]; if (fftlen > (10000 * 2 + 1)) { @@ -367,7 +413,29 @@ static int const_idx = 0; if(ret == 0) return 0; if (VoiceAudioMode == VOICEMODE_LISTENAUDIOIN) - io_ls_write_fifo(f); + { + if (physRXcaprate == 44100) + { + // Loudspeaker Audio "ls" works only with 48k + // so we have to resample 44k1 to 48k + unsigned int num_written = 0; + liquid_float_complex in; + liquid_float_complex out[100]; + in.real = f; + in.imag = 0; + msresamp_crcf_execute(lsresamp, &in, 1, out, &num_written); + if (num_written != 0) + { + for (unsigned int i = 0; i < num_written; i++) + { + float fout = out[i].real; + io_ls_write_fifo(fout); + } + } + } + else + io_ls_write_fifo(f); + } // input volume f *= softwareCAPvolume; @@ -375,7 +443,7 @@ static int const_idx = 0; getMax(f); make_FFTdata(f * 100); - if (caprate == 44100 && physcaprate == 48000) + if (caprate == 44100 && physRXcaprate == 48000) { // the sound card capture for a VAC always works with 48000 because // a VAC cannot be set to a specific cap rate in shared mode @@ -389,7 +457,15 @@ static int const_idx = 0; if (num_written == 0) return 1; f = out.real; } - + + // if user changed frequency + if (radians_per_sample != last_radians_per_sample) + { + //printf("new QRG. Rad:%f\n", radians_per_sample); + nco_crcf_set_frequency(dnnco, radians_per_sample); + last_radians_per_sample = radians_per_sample; + } + // downconvert 1,5kHz into baseband, still at soundcard sample rate nco_crcf_step(dnnco); diff --git a/hsmodem/rtty.cpp b/hsmodem/rtty.cpp new file mode 100755 index 0000000..8f5f443 --- /dev/null +++ b/hsmodem/rtty.cpp @@ -0,0 +1,262 @@ +/* +* High Speed modem to transfer data in a 2,7kHz SSB channel +* ========================================================= +* Author: DJ0ABR +* +* (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. +* +* +* RTTY: +* ===== +* bit/symbol: 1 +* BW: 170 Hz +* carrier: 1500 Hz +* speed: 45.45 bits/s +* samples/symbol: 33 +*/ + +#include "hsmodem.h" + +#define rtty_CENTERFREQUENCY 1500 + +fskmod rtty_mod = NULL; +fskdem rtty_dem = NULL; + +unsigned int rtty_m = 1; // bits/symbol +const unsigned int rtty_k = 33; // samples/symbol (periods of the 1500 Hz Carrier in one symbol) +float rtty_bandwith = (170.0f/2)/ (float)rtty_CENTERFREQUENCY; // 170 Hz spacing normalized to 1500 Hz + +firinterp_crcf rtty_TX_interpolator = NULL; +unsigned int rtty_k_SampPerSymb = 20; // 44100 / (4410/2) +unsigned int rtty_m_filterDelay_Symbols = 15; // not too short for good filter +float rtty_beta_excessBW = 0.2f; // filter excess bandwidth factor +float rtty_tau_FracSymbOffset = -0.2f; // fractional symbol offset + +nco_crcf rtty_upnco = NULL; +nco_crcf rtty_dnnco = NULL; + +firdecim_crcf rtty_decim = NULL; +unsigned int rtty_m_predec = 8; // filter delay +float rtty_As_predec = 40.0f; // stop-band att + +void close_rtty(); + +void init_rtty() +{ + close_rtty(); + + rtty_mod = fskmod_create(rtty_m, rtty_k, rtty_bandwith); + rtty_dem = fskdem_create(rtty_m, rtty_k, rtty_bandwith); + + // TX: Interpolator Filter + rtty_k_SampPerSymb = caprate / rtty_CENTERFREQUENCY; + + // compute delay + while (rtty_tau_FracSymbOffset < 0) rtty_tau_FracSymbOffset += 1.0f; // ensure positive tau + float g = rtty_k_SampPerSymb * rtty_tau_FracSymbOffset; // number of samples offset + int ds = (int)floorf(g); // additional symbol delay + float dt = (g - (float)ds); // fractional sample offset + // force dt to be in [0.5,0.5] + if (dt > 0.5f) + { + dt -= 1.0f; + ds++; + } + + // calculate filter coeffs + unsigned int h_len_NumFilterCoeefs = 2 * rtty_k_SampPerSymb * rtty_m_filterDelay_Symbols + 1; + float h[4000]; + if (h_len_NumFilterCoeefs >= 4000) + { + printf("rtty h in h_len_NumFilterCoeefs too small, need %d\n", h_len_NumFilterCoeefs); + return; + } + liquid_firdes_prototype(LIQUID_FIRFILT_RRC, + rtty_k_SampPerSymb, + rtty_m_filterDelay_Symbols, + rtty_beta_excessBW, + dt, + h); + // create the filter + rtty_TX_interpolator = firinterp_crcf_create(rtty_k_SampPerSymb, h, h_len_NumFilterCoeefs); + + // create NCO for upmixing to 1500 Hz + float rtty_RADIANS_PER_SAMPLE = ((2.0f * (float)M_PI * (float)rtty_CENTERFREQUENCY) / (float)caprate); + rtty_upnco = nco_crcf_create(LIQUID_NCO); + nco_crcf_set_phase(rtty_upnco, 0.0f); + nco_crcf_set_frequency(rtty_upnco, rtty_RADIANS_PER_SAMPLE); + + rtty_dnnco = nco_crcf_create(LIQUID_NCO); + nco_crcf_set_phase(rtty_dnnco, 0.0f); + nco_crcf_set_frequency(rtty_dnnco, rtty_RADIANS_PER_SAMPLE); + + rtty_decim = firdecim_crcf_create_kaiser(rtty_k_SampPerSymb, rtty_m_predec, rtty_As_predec); + firdecim_crcf_set_scale(rtty_decim, 1.0f / (float)rtty_k_SampPerSymb); +} + +void close_rtty() +{ + if (rtty_mod != NULL) fskmod_destroy(rtty_mod); + rtty_mod = NULL; + if (rtty_TX_interpolator != NULL) firinterp_crcf_destroy(rtty_TX_interpolator); + rtty_TX_interpolator = NULL; + if (rtty_upnco != NULL) nco_crcf_destroy(rtty_upnco); + rtty_upnco = NULL; + if (rtty_dnnco != NULL) nco_crcf_destroy(rtty_dnnco); + rtty_dnnco = NULL; + if (rtty_decim != NULL) firdecim_crcf_destroy(rtty_decim); + rtty_decim = NULL; + if (rtty_dem != NULL) fskdem_destroy(rtty_dem); + rtty_dem = NULL; +} + +char text[6] = {"ABCD\n"}; +int tidx = 0; +int bitidx = 1; + +void rtty_tx() +{ + if (rtty_mod == NULL) + init_rtty(); + + unsigned int sym = (text[tidx] & bitidx) ? 1 : 0; + bitidx <<= 1; + if (bitidx == 0x0100) + { + bitidx = 1; + tidx++; + if (tidx == 6) tidx = 0; + } + + liquid_float_complex rtty_txbuf[33+1]; + + // gets one symbol at a speed of 45.45 + fskmod_modulate(rtty_mod, sym, rtty_txbuf); + // here we have the complex RTTY signal in baseband + // one symbol was expanded to rtty_k periods: + // 45.454545 * 33 = 1500 periods + + for (unsigned int i = 0; i < rtty_k; i++) + { + // resample it to the soundcard rate caprate + // interpolate by k_SampPerSymb + liquid_float_complex y[40]; + if (rtty_k_SampPerSymb >= 40) + { + printf("y in k_SampPerSymb too small, need %d\n", rtty_k_SampPerSymb); + return; + } + + firinterp_crcf_execute(rtty_TX_interpolator, rtty_txbuf[i], y); + // here we have rtty_k_SampPerSymb samples in y[] in the baseband at caprate + // speed + + for (unsigned int i = 0; i < rtty_k_SampPerSymb; i++) + { + // move sample to 1,5kHz carrier + nco_crcf_step(rtty_upnco); + + liquid_float_complex c; + nco_crcf_mix_up(rtty_upnco, y[i], &c); + float usb = c.real + c.imag; + + // speed: 48000 + // adapt speed to soundcard samplerate + int fs; + while (1) + { + fs = io_pb_fifo_freespace(0); + // wait until there is space in fifo + if (fs > 20000) break; + sleep_ms(10); + } + + io_pb_write_fifo(usb * 0.2f); // reduce volume and send to soundcard + } + } +} + +// RTTY: sample rate HAS TO BE 48000 +int rtty_rx() +{ + static liquid_float_complex ccol[500]; + static unsigned int ccol_idx = 0; + + if (rtty_dnnco == NULL) return 0; + + // get one received sample + float f; + int ret = io_cap_read_fifo(&f); + if (ret == 0) return 0; + + if (VoiceAudioMode == VOICEMODE_LISTENAUDIOIN) + io_ls_write_fifo(f); + + // input volume + f *= softwareCAPvolume; + + //getMax(f); + //make_FFTdata(f * 100); + + // downconvert 1,5kHz into baseband, still at soundcard sample rate + nco_crcf_step(rtty_dnnco); + + liquid_float_complex in; + in.real = f; + in.imag = f; + liquid_float_complex c; + nco_crcf_mix_down(rtty_dnnco, in, &c); + + // c is the actual sample, converted to complex and shifted to baseband + + // this is the first decimator. We need to collect rtty_k_SampPerSymb number of samples + // then call execute which will give us one decimated sample + ccol[ccol_idx++] = c; + if (ccol_idx < rtty_k_SampPerSymb) return 1; + ccol_idx = 0; + + // we have rtty_k_SampPerSymb samples in ccol + liquid_float_complex y; + firdecim_crcf_execute(rtty_decim, ccol, &y); + // the output of the pre decimator is exactly one sample in y + // ready for demodulation + // here we have 1500 samples/s + // collect rtty_k (33) samples then demodulate, 1500/33 = 45.45 + static unsigned int cs = 0; + static liquid_float_complex camps[rtty_k]; + camps[cs] = y; + if (++cs < rtty_k) return 1; + cs = 0; + + //measure_speed_bps(1); + + unsigned int sym_out = fskdem_demodulate(rtty_dem, camps); + + static int sym = 0; + static int symidx = 0; + sym |= sym_out << symidx; + symidx++; + if (symidx == 8) + { + symidx = 0; + printf("%d: %c\n", sym, sym); + sym = 0; + } + + return 1; +} diff --git a/hsmodem/soundio.cpp b/hsmodem/soundio.cpp index 0df6f2e..c3839a0 100755 --- a/hsmodem/soundio.cpp +++ b/hsmodem/soundio.cpp @@ -522,14 +522,14 @@ int io_init_sound(char *pbname, char *capname) { instream->format = SoundIoFormatS16NE; instream->sample_rate = caprate; - physcaprate = caprate; + physRXcaprate = caprate; } else { // a VAC needs these settings or it will not work with 44100 instream->format = SoundIoFormatFloat32NE; instream->sample_rate = AUDIO_SAMPRATE; - physcaprate = AUDIO_SAMPRATE; + physRXcaprate = AUDIO_SAMPRATE; } instream->software_latency = latenz; instream->read_callback = read_callback; @@ -548,7 +548,7 @@ int io_init_sound(char *pbname, char *capname) init_audio_result |= 2; printf("selected CAPTURE device:\nname:%s\nid :%s\n", capname, capdevid); - printf("physical capture rate:%d, logical capture rate:%d\n", physcaprate, caprate); + printf("physical capture rate:%d, logical capture rate:%d\n", physRXcaprate, caprate); printf("format: %s\n\n", soundio_format_string(instream->format)); // the CAP callback is running now diff --git a/hsmodem/speed.cpp b/hsmodem/speed.cpp index 3bf40f6..94bd0a0 100755 --- a/hsmodem/speed.cpp +++ b/hsmodem/speed.cpp @@ -157,13 +157,12 @@ void measure_speed_bps(int len) return; } - elems += len; if (timespan < 1000) return; double dspd = elems; dspd = dspd * 1e3 / timespan; - speed = meanvalbps((int)dspd); + speed = (int)dspd; // here we have number of elements after 1s printf(" ======================= %d bit/s\n", speed); diff --git a/hsmodem/symboltracker.cpp b/hsmodem/symboltracker.cpp index 93d6d1c..41bd425 100755 --- a/hsmodem/symboltracker.cpp +++ b/hsmodem/symboltracker.cpp @@ -166,8 +166,7 @@ void km_symtrack_execute(liquid_float_complex _x, liquid_float_complex* _y, unsi /*float fr = nco_crcf_get_frequency(q->nco); float ph = nco_crcf_get_phase(q->nco); - - printf("%10.6f %10.6f %10.6f %10.6f\n", fr, ph, _x.real, _x.imag);*/ + printf("f:%10.6f ph:%10.6f\n", fr, ph);*/ * _ny = num_outputs; } diff --git a/hsmodem/tuning.cpp b/hsmodem/tuning.cpp index 9d48137..5580d31 100755 --- a/hsmodem/tuning.cpp +++ b/hsmodem/tuning.cpp @@ -26,11 +26,8 @@ #include "hsmodem.h" - - - -#define NUMFREQ 12 -int tunefreq[NUMFREQ] = { 150,420,690,960,1230,1500,1770,2040,2310,2580,2850,3000 }; +#define NUMFREQ 13 +int tunefreq[NUMFREQ] = { 150,420,690,960,1230,1500,1770,2040,2310,2580,2850,2890,100 }; nco_crcf tunenco[NUMFREQ]; uint32_t tuning_runtime = 0; @@ -49,7 +46,6 @@ void init_tune() if (tunenco[i] != NULL) nco_crcf_destroy(tunenco[i]); // create NCO for frequency - printf("tuning: physcaprate:%d\n", physcaprate); float rad_per_sample = ((2.0f * (float)M_PI * (float)tunefreq[i]) / (float)caprate); tunenco[i] = nco_crcf_create(LIQUID_NCO); nco_crcf_set_phase(tunenco[i], 0.0f); @@ -62,7 +58,7 @@ void init_tune() float do_tuning(int send) { if (tunenco == NULL) return 0.0f; - if (send < 0 || send > 4) return 0.0f; + if (send < 0 || send > 11) return 0.0f; float f = 0; if (send == 1) @@ -77,8 +73,8 @@ float do_tuning(int send) } else { - nco_crcf_step(tunenco[send-2]); - f = nco_crcf_sin(tunenco[send-2]); + nco_crcf_step(tunenco[send]); + f = nco_crcf_sin(tunenco[send]); } // adapt speed to soundcard samplerate @@ -104,10 +100,15 @@ float do_tuning(int send) float singleFrequency() { - int i = 11; // 3000 Hz - + int /*i = 11; // 2900 Hz if (tunenco[i] == NULL) return 0.0f; - nco_crcf_step(tunenco[i]); - return nco_crcf_sin(tunenco[i]); + float f = nco_crcf_sin(tunenco[i]);*/ + + i = 12; // 2930 Hz + if (tunenco[i] == NULL) return 0.0f; + nco_crcf_step(tunenco[i]); + float f = nco_crcf_sin(tunenco[i]); + + return f; } diff --git a/hsmodemLinux/hsmodem b/hsmodemLinux/hsmodem index 1bb6492..c1ed2a1 100755 Binary files a/hsmodemLinux/hsmodem and b/hsmodemLinux/hsmodem differ diff --git a/hsmodemLinux/oscardata.exe b/hsmodemLinux/oscardata.exe index 706dd5f..2568aac 100755 Binary files a/hsmodemLinux/oscardata.exe and b/hsmodemLinux/oscardata.exe differ diff --git a/oscardata/oscardata/Form1.Designer.cs b/oscardata/oscardata/Form1.Designer.cs index ad688c5..3747193 100755 --- a/oscardata/oscardata/Form1.Designer.cs +++ b/oscardata/oscardata/Form1.Designer.cs @@ -109,6 +109,11 @@ this.bt_resetmodem = new System.Windows.Forms.Button(); this.textBox3 = new System.Windows.Forms.TextBox(); this.groupBox3 = new System.Windows.Forms.GroupBox(); + this.pictureBox4 = new System.Windows.Forms.PictureBox(); + this.pictureBox3 = new System.Windows.Forms.PictureBox(); + this.bt_tune_plus = new System.Windows.Forms.Button(); + this.bt_tune_minus = new System.Windows.Forms.Button(); + this.cb_marker = new System.Windows.Forms.CheckBox(); this.pb_audioCAPstatus = new System.Windows.Forms.PictureBox(); this.pb_audioPBstatus = new System.Windows.Forms.PictureBox(); this.label6 = new System.Windows.Forms.Label(); @@ -116,9 +121,7 @@ this.tb_CAPvol = new System.Windows.Forms.TrackBar(); this.tb_PBvol = new System.Windows.Forms.TrackBar(); this.cb_audioPB = new System.Windows.Forms.ComboBox(); - this.label3 = new System.Windows.Forms.Label(); this.cb_audioCAP = new System.Windows.Forms.ComboBox(); - this.label4 = new System.Windows.Forms.Label(); this.groupBox2 = new System.Windows.Forms.GroupBox(); this.lb_rec = new System.Windows.Forms.Label(); this.tb_recintro = new System.Windows.Forms.TextBox(); @@ -151,7 +154,6 @@ this.progressBar_fifo = new oscardata.KmProgressBar(); this.vu_cap = new oscardata.KmProgressBar(); this.vu_pb = new oscardata.KmProgressBar(); - this.cb_marker = new System.Windows.Forms.CheckBox(); this.statusStrip1.SuspendLayout(); this.tabPage_ber.SuspendLayout(); this.tabPage_image.SuspendLayout(); @@ -174,6 +176,8 @@ this.tabPage_setup.SuspendLayout(); this.groupBox4.SuspendLayout(); this.groupBox3.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox4)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox3)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.pb_audioCAPstatus)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.pb_audioPBstatus)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.tb_CAPvol)).BeginInit(); @@ -274,11 +278,11 @@ // // bt_allf // - this.bt_allf.Location = new System.Drawing.Point(537, 18); + this.bt_allf.Location = new System.Drawing.Point(561, 18); this.bt_allf.Name = "bt_allf"; - this.bt_allf.Size = new System.Drawing.Size(95, 23); + this.bt_allf.Size = new System.Drawing.Size(71, 23); this.bt_allf.TabIndex = 25; - this.bt_allf.Text = "150..2850 Hz"; + this.bt_allf.Text = "1500 Hz"; this.bt_allf.UseVisualStyleBackColor = true; this.bt_allf.Click += new System.EventHandler(this.bt_allf_Click); // @@ -987,11 +991,11 @@ // label12 // this.label12.AutoSize = true; - this.label12.Location = new System.Drawing.Point(253, 23); + this.label12.Location = new System.Drawing.Point(221, 23); this.label12.Name = "label12"; - this.label12.Size = new System.Drawing.Size(54, 13); + this.label12.Size = new System.Drawing.Size(103, 13); this.label12.TabIndex = 26; - this.label12.Text = "language:"; + this.label12.Text = "Language/Sprache:"; // // cb_safemode // @@ -1081,6 +1085,10 @@ // // groupBox3 // + this.groupBox3.Controls.Add(this.pictureBox4); + this.groupBox3.Controls.Add(this.pictureBox3); + this.groupBox3.Controls.Add(this.bt_tune_plus); + this.groupBox3.Controls.Add(this.bt_tune_minus); this.groupBox3.Controls.Add(this.cb_marker); this.groupBox3.Controls.Add(this.vu_cap); this.groupBox3.Controls.Add(this.vu_pb); @@ -1091,9 +1099,7 @@ this.groupBox3.Controls.Add(this.tb_CAPvol); this.groupBox3.Controls.Add(this.tb_PBvol); this.groupBox3.Controls.Add(this.cb_audioPB); - this.groupBox3.Controls.Add(this.label3); this.groupBox3.Controls.Add(this.cb_audioCAP); - this.groupBox3.Controls.Add(this.label4); this.groupBox3.Location = new System.Drawing.Point(12, 144); this.groupBox3.Name = "groupBox3"; this.groupBox3.Size = new System.Drawing.Size(743, 163); @@ -1101,11 +1107,70 @@ this.groupBox3.TabStop = false; this.groupBox3.Text = "Transceiver Audio"; // + // pictureBox4 + // + this.pictureBox4.BackgroundImage = global::oscardata.Properties.Resources.captureicon; + this.pictureBox4.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Zoom; + this.pictureBox4.Location = new System.Drawing.Point(0, 61); + this.pictureBox4.Name = "pictureBox4"; + this.pictureBox4.Size = new System.Drawing.Size(132, 87); + this.pictureBox4.TabIndex = 16; + this.pictureBox4.TabStop = false; + // + // pictureBox3 + // + this.pictureBox3.BackgroundImage = ((System.Drawing.Image)(resources.GetObject("pictureBox3.BackgroundImage"))); + this.pictureBox3.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Zoom; + this.pictureBox3.Location = new System.Drawing.Point(5, -7); + this.pictureBox3.Name = "pictureBox3"; + this.pictureBox3.Size = new System.Drawing.Size(127, 85); + this.pictureBox3.TabIndex = 16; + this.pictureBox3.TabStop = false; + // + // bt_tune_plus + // + this.bt_tune_plus.Font = new System.Drawing.Font("Microsoft Sans Serif", 10F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.bt_tune_plus.Location = new System.Drawing.Point(602, 79); + this.bt_tune_plus.Name = "bt_tune_plus"; + this.bt_tune_plus.Size = new System.Drawing.Size(24, 23); + this.bt_tune_plus.TabIndex = 22; + this.bt_tune_plus.Text = "+"; + this.bt_tune_plus.UseVisualStyleBackColor = true; + this.bt_tune_plus.Visible = false; + this.bt_tune_plus.Click += new System.EventHandler(this.bt_tune_plus_Click); + // + // bt_tune_minus + // + this.bt_tune_minus.Font = new System.Drawing.Font("Microsoft Sans Serif", 10F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.bt_tune_minus.Location = new System.Drawing.Point(602, 55); + this.bt_tune_minus.Name = "bt_tune_minus"; + this.bt_tune_minus.Size = new System.Drawing.Size(24, 23); + this.bt_tune_minus.TabIndex = 21; + this.bt_tune_minus.Text = "-"; + this.bt_tune_minus.UseVisualStyleBackColor = true; + this.bt_tune_minus.Visible = false; + this.bt_tune_minus.Click += new System.EventHandler(this.bt_tune_minus_Click); + // + // cb_marker + // + this.cb_marker.AutoSize = true; + this.cb_marker.Checked = true; + this.cb_marker.CheckState = System.Windows.Forms.CheckState.Checked; + this.cb_marker.Location = new System.Drawing.Point(605, 23); + this.cb_marker.Name = "cb_marker"; + this.cb_marker.RightToLeft = System.Windows.Forms.RightToLeft.No; + this.cb_marker.Size = new System.Drawing.Size(129, 17); + this.cb_marker.TabIndex = 27; + this.cb_marker.Text = "100Hz Tuning Marker"; + this.cb_marker.UseVisualStyleBackColor = true; + this.cb_marker.Visible = false; + this.cb_marker.CheckedChanged += new System.EventHandler(this.cb_marker_CheckedChanged); + // // pb_audioCAPstatus // this.pb_audioCAPstatus.BackgroundImage = ((System.Drawing.Image)(resources.GetObject("pb_audioCAPstatus.BackgroundImage"))); this.pb_audioCAPstatus.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Zoom; - this.pb_audioCAPstatus.Location = new System.Drawing.Point(375, 63); + this.pb_audioCAPstatus.Location = new System.Drawing.Point(375, 87); this.pb_audioCAPstatus.Name = "pb_audioCAPstatus"; this.pb_audioCAPstatus.Size = new System.Drawing.Size(21, 21); this.pb_audioCAPstatus.TabIndex = 18; @@ -1115,7 +1180,7 @@ // this.pb_audioPBstatus.BackgroundImage = ((System.Drawing.Image)(resources.GetObject("pb_audioPBstatus.BackgroundImage"))); this.pb_audioPBstatus.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Zoom; - this.pb_audioPBstatus.Location = new System.Drawing.Point(375, 19); + this.pb_audioPBstatus.Location = new System.Drawing.Point(375, 21); this.pb_audioPBstatus.Name = "pb_audioPBstatus"; this.pb_audioPBstatus.Size = new System.Drawing.Size(21, 21); this.pb_audioPBstatus.TabIndex = 17; @@ -1124,7 +1189,7 @@ // label6 // this.label6.AutoSize = true; - this.label6.Location = new System.Drawing.Point(428, 65); + this.label6.Location = new System.Drawing.Point(428, 89); this.label6.Name = "label6"; this.label6.Size = new System.Drawing.Size(45, 13); this.label6.TabIndex = 16; @@ -1133,7 +1198,7 @@ // label5 // this.label5.AutoSize = true; - this.label5.Location = new System.Drawing.Point(428, 23); + this.label5.Location = new System.Drawing.Point(428, 25); this.label5.Name = "label5"; this.label5.Size = new System.Drawing.Size(45, 13); this.label5.TabIndex = 15; @@ -1142,7 +1207,7 @@ // tb_CAPvol // this.tb_CAPvol.Cursor = System.Windows.Forms.Cursors.SizeAll; - this.tb_CAPvol.Location = new System.Drawing.Point(479, 61); + this.tb_CAPvol.Location = new System.Drawing.Point(479, 85); this.tb_CAPvol.Maximum = 100; this.tb_CAPvol.MaximumSize = new System.Drawing.Size(0, 24); this.tb_CAPvol.Minimum = 1; @@ -1157,7 +1222,7 @@ // tb_PBvol // this.tb_PBvol.Cursor = System.Windows.Forms.Cursors.SizeAll; - this.tb_PBvol.Location = new System.Drawing.Point(479, 19); + this.tb_PBvol.Location = new System.Drawing.Point(479, 21); this.tb_PBvol.Maximum = 100; this.tb_PBvol.MaximumSize = new System.Drawing.Size(0, 24); this.tb_PBvol.Minimum = 1; @@ -1172,39 +1237,21 @@ // cb_audioPB // this.cb_audioPB.FormattingEnabled = true; - this.cb_audioPB.Location = new System.Drawing.Point(138, 19); + this.cb_audioPB.Location = new System.Drawing.Point(138, 21); this.cb_audioPB.Name = "cb_audioPB"; this.cb_audioPB.Size = new System.Drawing.Size(230, 21); this.cb_audioPB.TabIndex = 7; this.cb_audioPB.Text = "Default"; // - // label3 - // - this.label3.AutoSize = true; - this.label3.Location = new System.Drawing.Point(12, 23); - this.label3.Name = "label3"; - this.label3.Size = new System.Drawing.Size(121, 13); - this.label3.TabIndex = 8; - this.label3.Text = "Audio Playback Device:"; - // // cb_audioCAP // this.cb_audioCAP.FormattingEnabled = true; - this.cb_audioCAP.Location = new System.Drawing.Point(138, 63); + this.cb_audioCAP.Location = new System.Drawing.Point(138, 87); this.cb_audioCAP.Name = "cb_audioCAP"; this.cb_audioCAP.Size = new System.Drawing.Size(230, 21); this.cb_audioCAP.TabIndex = 9; this.cb_audioCAP.Text = "Default"; // - // label4 - // - this.label4.AutoSize = true; - this.label4.Location = new System.Drawing.Point(12, 67); - this.label4.Name = "label4"; - this.label4.Size = new System.Drawing.Size(112, 13); - this.label4.TabIndex = 10; - this.label4.Text = "Audio Record Device:"; - // // groupBox2 // this.groupBox2.Controls.Add(this.lb_rec); @@ -1224,7 +1271,7 @@ this.groupBox2.Controls.Add(this.cb_stampcall); this.groupBox2.Location = new System.Drawing.Point(12, 13); this.groupBox2.Name = "groupBox2"; - this.groupBox2.Size = new System.Drawing.Size(734, 127); + this.groupBox2.Size = new System.Drawing.Size(743, 127); this.groupBox2.TabIndex = 13; this.groupBox2.TabStop = false; this.groupBox2.Text = "Personal Settings"; @@ -1234,7 +1281,7 @@ this.lb_rec.AutoSize = true; this.lb_rec.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.lb_rec.ForeColor = System.Drawing.Color.Red; - this.lb_rec.Location = new System.Drawing.Point(498, 101); + this.lb_rec.Location = new System.Drawing.Point(576, 101); this.lb_rec.Name = "lb_rec"; this.lb_rec.Size = new System.Drawing.Size(23, 13); this.lb_rec.TabIndex = 29; @@ -1246,7 +1293,7 @@ this.tb_recintro.BorderStyle = System.Windows.Forms.BorderStyle.None; this.tb_recintro.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.tb_recintro.ForeColor = System.Drawing.Color.Black; - this.tb_recintro.Location = new System.Drawing.Point(256, 100); + this.tb_recintro.Location = new System.Drawing.Point(334, 100); this.tb_recintro.Multiline = true; this.tb_recintro.Name = "tb_recintro"; this.tb_recintro.Size = new System.Drawing.Size(121, 19); @@ -1259,7 +1306,7 @@ this.bt_astop.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Center; this.bt_astop.FlatStyle = System.Windows.Forms.FlatStyle.Flat; this.bt_astop.ForeColor = System.Drawing.SystemColors.Control; - this.bt_astop.Location = new System.Drawing.Point(449, 89); + this.bt_astop.Location = new System.Drawing.Point(527, 89); this.bt_astop.Name = "bt_astop"; this.bt_astop.Size = new System.Drawing.Size(32, 36); this.bt_astop.TabIndex = 27; @@ -1272,7 +1319,7 @@ this.bt_aplay.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Center; this.bt_aplay.FlatStyle = System.Windows.Forms.FlatStyle.Flat; this.bt_aplay.ForeColor = System.Drawing.SystemColors.Control; - this.bt_aplay.Location = new System.Drawing.Point(411, 89); + this.bt_aplay.Location = new System.Drawing.Point(489, 89); this.bt_aplay.Name = "bt_aplay"; this.bt_aplay.Size = new System.Drawing.Size(32, 36); this.bt_aplay.TabIndex = 26; @@ -1285,7 +1332,7 @@ this.bt_arecord.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Center; this.bt_arecord.FlatStyle = System.Windows.Forms.FlatStyle.Flat; this.bt_arecord.ForeColor = System.Drawing.SystemColors.Control; - this.bt_arecord.Location = new System.Drawing.Point(373, 89); + this.bt_arecord.Location = new System.Drawing.Point(451, 89); this.bt_arecord.Name = "bt_arecord"; this.bt_arecord.Size = new System.Drawing.Size(32, 36); this.bt_arecord.TabIndex = 25; @@ -1504,7 +1551,7 @@ // lb_rxsync // this.lb_rxsync.AutoSize = true; - this.lb_rxsync.Location = new System.Drawing.Point(1094, 643); + this.lb_rxsync.Location = new System.Drawing.Point(984, 596); this.lb_rxsync.Name = "lb_rxsync"; this.lb_rxsync.Size = new System.Drawing.Size(52, 13); this.lb_rxsync.TabIndex = 20; @@ -1514,7 +1561,7 @@ // this.pb_rxsync.BackgroundImage = ((System.Drawing.Image)(resources.GetObject("pb_rxsync.BackgroundImage"))); this.pb_rxsync.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Zoom; - this.pb_rxsync.Location = new System.Drawing.Point(1155, 636); + this.pb_rxsync.Location = new System.Drawing.Point(1047, 591); this.pb_rxsync.Name = "pb_rxsync"; this.pb_rxsync.Size = new System.Drawing.Size(24, 24); this.pb_rxsync.TabIndex = 19; @@ -1553,30 +1600,18 @@ // // vu_cap // - this.vu_cap.Location = new System.Drawing.Point(479, 87); + this.vu_cap.Location = new System.Drawing.Point(479, 111); this.vu_cap.Name = "vu_cap"; this.vu_cap.Size = new System.Drawing.Size(100, 10); this.vu_cap.TabIndex = 20; // // vu_pb // - this.vu_pb.Location = new System.Drawing.Point(479, 45); + this.vu_pb.Location = new System.Drawing.Point(479, 47); this.vu_pb.Name = "vu_pb"; this.vu_pb.Size = new System.Drawing.Size(100, 10); this.vu_pb.TabIndex = 19; // - // cb_marker - // - this.cb_marker.AutoSize = true; - this.cb_marker.Location = new System.Drawing.Point(605, 21); - this.cb_marker.Name = "cb_marker"; - this.cb_marker.RightToLeft = System.Windows.Forms.RightToLeft.No; - this.cb_marker.Size = new System.Drawing.Size(123, 17); - this.cb_marker.TabIndex = 27; - this.cb_marker.Text = "3kHz Tuning Marker"; - this.cb_marker.UseVisualStyleBackColor = true; - this.cb_marker.CheckedChanged += new System.EventHandler(this.cb_marker_CheckedChanged); - // // Form1 // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); @@ -1601,7 +1636,7 @@ this.ForeColor = System.Drawing.SystemColors.ControlText; this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); this.Name = "Form1"; - this.Text = "AMSAT-DL Multimedia HS Modem V0.55 by DJ0ABR"; + this.Text = "AMSAT-DL Multimedia HS Modem V0.56 by DJ0ABR"; this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.Form1_FormClosing); this.statusStrip1.ResumeLayout(false); this.statusStrip1.PerformLayout(); @@ -1635,6 +1670,8 @@ this.groupBox4.PerformLayout(); this.groupBox3.ResumeLayout(false); this.groupBox3.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox4)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox3)).EndInit(); ((System.ComponentModel.ISupportInitialize)(this.pb_audioCAPstatus)).EndInit(); ((System.ComponentModel.ISupportInitialize)(this.pb_audioPBstatus)).EndInit(); ((System.ComponentModel.ISupportInitialize)(this.tb_CAPvol)).EndInit(); @@ -1700,9 +1737,7 @@ private System.Windows.Forms.TextBox tb_shutdown; private System.Windows.Forms.Button bt_shutdown; private System.Windows.Forms.Button bt_resetmodem; - private System.Windows.Forms.Label label4; private System.Windows.Forms.ComboBox cb_audioCAP; - private System.Windows.Forms.Label label3; private System.Windows.Forms.ComboBox cb_audioPB; private System.Windows.Forms.GroupBox groupBox4; private System.Windows.Forms.GroupBox groupBox3; @@ -1773,6 +1808,10 @@ private System.Windows.Forms.Label lb_tuningqrgs; private System.Windows.Forms.Button bt_allf; private System.Windows.Forms.CheckBox cb_marker; + private System.Windows.Forms.PictureBox pictureBox3; + private System.Windows.Forms.PictureBox pictureBox4; + private System.Windows.Forms.Button bt_tune_minus; + private System.Windows.Forms.Button bt_tune_plus; } } diff --git a/oscardata/oscardata/Form1.cs b/oscardata/oscardata/Form1.cs index 651318a..ac2f82a 100755 --- a/oscardata/oscardata/Form1.cs +++ b/oscardata/oscardata/Form1.cs @@ -1100,10 +1100,15 @@ namespace oscardata String ip = "255.255.255.255"; String[] myips = statics.getOwnIPs(); //Console.WriteLine("BClen: " + myips.Length.ToString()); - // nur wenn der PC eine IP hat - // hat er mehr, dann wissen wir nicht in welchem Netz wird broadcasten sollen, nehmen also die 255.255.255.255 - if (myips.Length == 1) + // if PC has multiple IPs then use 255.255.255.255 + /*for (int i = 0; i < myips.Length; i++) { + Console.WriteLine("ip:" + myips[i]); + }*/ + if (myips.Length >= 1) + { + statics.MyIP = myips[0]; + // PC has one IP, make it to a broadcast IP by adding 255 int idx = myips[0].LastIndexOf('.'); if (idx >= 0) { @@ -1173,11 +1178,22 @@ namespace oscardata txb[i + 110] = bcap[i]; } - Udp.UdpBCsend(txb, GetMyBroadcastIP(), statics.UdpBCport_AppToModem); + if (statics.ModemIP == "1.2.3.4") + { + // still searching a modem + //Console.WriteLine("1: send BCsearch to: " + GetMyBroadcastIP()); + Udp.UdpBCsend(txb, GetMyBroadcastIP(), statics.UdpBCport_AppToModem); + } + else + { + // modem IP is known, send to it directly, no broadcast + //Console.WriteLine("2: send BCsearch to: " + statics.ModemIP); + Udp.UdpBCsend(txb, statics.ModemIP, statics.UdpBCport_AppToModem); + } Udp.searchtimeout++; if (Udp.searchtimeout >= 3) - statics.ModemIP = "1.2.3.4"; + statics.ModemIP = "1.2.3.4"; // which means: no IP known } private void bt_file_send_Click(object sender, EventArgs e) @@ -1229,7 +1245,9 @@ namespace oscardata private void comboBox1_SelectedIndexChanged(object sender, EventArgs e) { + bool b = cb_switchtoLS.Checked; allVoiceModesOff(); + cb_switchtoLS.Checked = b; if (cb_speed.Text.Contains("3000")) statics.real_datarate = 3000; if (cb_speed.Text.Contains("4000")) statics.real_datarate = 4000; @@ -1388,6 +1406,14 @@ namespace oscardata if (cb_audioPB.Text.Length <= 1) cb_audioPB.Text = "Default"; if (cb_audioCAP.Text.Length <= 1) cb_audioCAP.Text = "Default"; + + if (tb_callsign.Text == "DJ0ABR") + { + bt_resetmodem.Visible = true; + bt_tune_minus.Visible = true; + bt_tune_plus.Visible = true; + cb_marker.Visible = true; + } } void save_Setup() @@ -1727,8 +1753,6 @@ namespace oscardata groupBox3.Text = "Transceiver Audio"; label6.Text = "Volume:"; label5.Text = "Volume:"; - label3.Text = "Audio Playback Device:"; - label4.Text = "Audio Record Device:"; groupBox2.Text = "Personal Settings"; cb_stampinfo.Text = "Insert Info into picture"; textBox4.Text = "transmissions"; @@ -1742,10 +1766,11 @@ namespace oscardata label_capfifo.Text = "RX Buffer:"; lb_rxsignal.Text = "RX Signal:"; lb_rxsync.Text = "RX Sync:"; - cb_sendIntro.Text = "send introduction"; + cb_sendIntro.Text = "send introduction before TX"; tb_recintro.Text = "record introduction"; - lb_tuningqrgs.Text = "Frequency Test"; - cb_marker.Text = "3kHz Tuning Marker"; + lb_tuningqrgs.Text = "Send Mid-Frequency:"; + cb_marker.Text = "2.9kHz Tuning Marker"; + label13.Text = "Data Security:"; } if (language == 1) @@ -1793,17 +1818,16 @@ namespace oscardata cb_stampinfo.Text = "Füge Infotext ins Bild ein"; textBox1.Text = "sende Ansagetext vor TX, alle"; textBox4.Text = "Aussendungen"; - label3.Text = "Audio Wiedergabe"; - label4.Text = "Audio Eingang"; label5.Text = "Lautst.:"; label6.Text = "Lautst.:"; groupBox4.Text = "Wartung"; textBox3.Text = "Ausschalten wenn hsmodem auf separatem PC läuft"; tb_shutdown.Text = "Vor dem Ausschalten eines SBC diesen hier herunterfahren"; - cb_sendIntro.Text = "sende Vorstellung"; + cb_sendIntro.Text = "sende Vorstellung vor TX"; tb_recintro.Text = "Vorstellung aufnehmen"; - lb_tuningqrgs.Text = "Frequenz Test:"; - cb_marker.Text = "3kHz Tuning Markierung"; + lb_tuningqrgs.Text = "Sende Mittenfrequenz:"; + cb_marker.Text = "2,9kHz Tuning Markierung"; + label13.Text = "Datensicherheit:"; } } @@ -1936,7 +1960,7 @@ namespace oscardata private void bt_allf_Click(object sender, EventArgs e) { - bt_tuning(1); + bt_tuning(5); } private void cb_marker_CheckedChanged(object sender, EventArgs e) @@ -1946,6 +1970,22 @@ namespace oscardata txdata[1] = (Byte)(cb_marker.Checked ? 1 : 0); Udp.UdpSendCtrl(txdata); } + + private void bt_tune_minus_Click(object sender, EventArgs e) + { + Byte[] txdata = new byte[2]; + txdata[0] = statics.setfreq; + txdata[1] = 10; + Udp.UdpSendCtrl(txdata); + } + + private void bt_tune_plus_Click(object sender, EventArgs e) + { + Byte[] txdata = new byte[2]; + txdata[0] = statics.setfreq; + txdata[1] = 255 - 10; + Udp.UdpSendCtrl(txdata); + } } } diff --git a/oscardata/oscardata/Form1.resx b/oscardata/oscardata/Form1.resx index 43c08c7..ddd53e9 100755 --- a/oscardata/oscardata/Form1.resx +++ b/oscardata/oscardata/Form1.resx @@ -137,7 +137,7 @@ AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj00LjAuMC4w LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACZTeXN0 ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAABw - FwAAAk1TRnQBSQFMAgEBDQEAAQgBBQEIAQUBEAEAARABAAT/AQkBAAj/AUIBTQE2AQQGAAE2AQQCAAEo + FwAAAk1TRnQBSQFMAgEBDQEAAUABBgFAAQYBEAEAARABAAT/AQkBAAj/AUIBTQE2AQQGAAE2AQQCAAEo AwABQAMAAUADAAEBAQABCAYAARAYAAGAAgABgAMAAoABAAGAAwABgAEAAYABAAKAAgADwAEAAcAB3AHA AQAB8AHKAaYBAAEzBQABMwEAATMBAAEzAQACMwIAAxYBAAMcAQADIgEAAykBAANVAQADTQEAA0IBAAM5 AQABgAF8Af8BAAJQAf8BAAGTAQAB1gEAAf8B7AHMAQABxgHWAe8BAAHWAucBAAGQAakBrQIAAf8BMwMA @@ -4495,6 +4495,344 @@ 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 + wIg2Hr6dReMAAAAASUVORK5CYII= + + + + + iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABGdBTUEAALGPC/xhBQAAAtxJREFUSEvt + 0m1Ik1EUB3C3yk193OPUJZovm69Zznwpw2BYkE6TNDdNbaXOt+l0Pr61FNNSFMs0bUUayoKIgpaYmNN0 + U1MxJCKiD2VFkBBRBNGnovKcDG6CGFHql8IfHC6c87/nfrkWa/4PTmVOXLVBrY3SRQlJa/Vw1VxLXh2v + Vz+jR6FO+IKlYbmT0cpRamqDY4PjzYp7FWB4awDdEx3Qp+hndDm9iUSWj5fDW+9c63ydMTPYNdMFnTOd + +KMaphtA0iG5TWJL+df4y5huZtz3uK8vaS1hl2u3zq3G7UqeUYWtD1qw5X4zNE+fwaapJhSfF3+xLbVN + JNHFeIW8+IhLks+Nk3WwvTX0lQvj4kVGC+wz7dmiKlFX9q0MqJ+sgbq71XBypBpqTScgpC34K1vFPkKi + iwk0guiws8GfKoYYrDQzcHSoAHc0hr50znde+BkOCgeWt9a7XXkjBapGi6HCxKB2kMGqwXKQ6MK/cVSc + TBJdyqfSx6juVoCmTwnMgBJKhpVQPJAOodXbnjtlbXTlK/gsz0LRubSr8VBmzoLiO0oo6leC1qgG6YU9 + c1Y5Viqy6teoDMrL85jrbKYhDnP75JA/KMcCUyIW9MsgqGzrU/ds9/ZUfSRoRpJAPSTHPKMcSgYyUNYR + PUdlURqy5vds0mz8/LTC15k9kaAciMRsUxTmjkVBbn8kpuolmD8egyUTiVA6mjz/cBwc7IgGOyVdRq7/ + GRuFzZaActGbtN6dmDwoxkPmQFCMilExGoDJw5tR2iOA3ddojDjtBfbp/Epy7e9QSVSguMjjXUKfC0Sb + aYgdn68JGvaNzZ/DfJC2+oBdKl1D4stDJVAhQRqP94en3ED2iI/yx3xMeuiA8Rf9gJbR9SS2Mtb7rcNC + Cz0+qGY8MG1WgCmX/ZGO5TVxpBwWiawcN4YbvosRfVQbgoEnpdo4ey1Xb/lPggO2YZ6pjgVULJdNWmv+ + GRYW3wHoVCJ7F4lIiQAAAABJRU5ErkJggg== + + + + + iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABGdBTUEAALGPC/xhBQAAAtxJREFUSEvt + 0m1Ik1EUB3C3yk193OPUJZovm69Zznwpw2BYkE6TNDdNbaXOt+l0Pr61FNNSFMs0bUUayoKIgpaYmNN0 + U1MxJCKiD2VFkBBRBNGnovKcDG6CGFHql8IfHC6c87/nfrkWa/4PTmVOXLVBrY3SRQlJa/Vw1VxLXh2v + Vz+jR6FO+IKlYbmT0cpRamqDY4PjzYp7FWB4awDdEx3Qp+hndDm9iUSWj5fDW+9c63ydMTPYNdMFnTOd + +KMaphtA0iG5TWJL+df4y5huZtz3uK8vaS1hl2u3zq3G7UqeUYWtD1qw5X4zNE+fwaapJhSfF3+xLbVN + JNHFeIW8+IhLks+Nk3WwvTX0lQvj4kVGC+wz7dmiKlFX9q0MqJ+sgbq71XBypBpqTScgpC34K1vFPkKi + iwk0guiws8GfKoYYrDQzcHSoAHc0hr50znde+BkOCgeWt9a7XXkjBapGi6HCxKB2kMGqwXKQ6MK/cVSc + TBJdyqfSx6juVoCmTwnMgBJKhpVQPJAOodXbnjtlbXTlK/gsz0LRubSr8VBmzoLiO0oo6leC1qgG6YU9 + c1Y5Viqy6teoDMrL85jrbKYhDnP75JA/KMcCUyIW9MsgqGzrU/ds9/ZUfSRoRpJAPSTHPKMcSgYyUNYR + PUdlURqy5vds0mz8/LTC15k9kaAciMRsUxTmjkVBbn8kpuolmD8egyUTiVA6mjz/cBwc7IgGOyVdRq7/ + GRuFzZaActGbtN6dmDwoxkPmQFCMilExGoDJw5tR2iOA3ddojDjtBfbp/Epy7e9QSVSguMjjXUKfC0Sb + aYgdn68JGvaNzZ/DfJC2+oBdKl1D4stDJVAhQRqP94en3ED2iI/yx3xMeuiA8Rf9gJbR9SS2Mtb7rcNC + Cz0+qGY8MG1WgCmX/ZGO5TVxpBwWiawcN4YbvosRfVQbgoEnpdo4ey1Xb/lPggO2YZ6pjgVULJdNWmv+ + GRYW3wHoVCJ7F4lIiQAAAABJRU5ErkJggg== @@ -4874,42 +5212,6 @@ aYgdn68JGvaNzZ/DfJC2+oBdKl1D4stDJVAhQRqP94en3ED2iI/yx3xMeuiA8Rf9gJbR9SS2Mtb7rcNC Cz0+qGY8MG1WgCmX/ZGO5TVxpBwWiawcN4YbvosRfVQbgoEnpdo4ey1Xb/lPggO2YZ6pjgVULJdNWmv+ GRYW3wHoVCJ7F4lIiQAAAABJRU5ErkJggg== - - - - - iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABGdBTUEAALGPC/xhBQAAAtxJREFUSEvt - 0m1Ik1EUB3C3yk193OPUJZovm69Zznwpw2BYkE6TNDdNbaXOt+l0Pr61FNNSFMs0bUUayoKIgpaYmNN0 - U1MxJCKiD2VFkBBRBNGnovKcDG6CGFHql8IfHC6c87/nfrkWa/4PTmVOXLVBrY3SRQlJa/Vw1VxLXh2v - Vz+jR6FO+IKlYbmT0cpRamqDY4PjzYp7FWB4awDdEx3Qp+hndDm9iUSWj5fDW+9c63ydMTPYNdMFnTOd - +KMaphtA0iG5TWJL+df4y5huZtz3uK8vaS1hl2u3zq3G7UqeUYWtD1qw5X4zNE+fwaapJhSfF3+xLbVN - JNHFeIW8+IhLks+Nk3WwvTX0lQvj4kVGC+wz7dmiKlFX9q0MqJ+sgbq71XBypBpqTScgpC34K1vFPkKi - iwk0guiws8GfKoYYrDQzcHSoAHc0hr50znde+BkOCgeWt9a7XXkjBapGi6HCxKB2kMGqwXKQ6MK/cVSc - TBJdyqfSx6juVoCmTwnMgBJKhpVQPJAOodXbnjtlbXTlK/gsz0LRubSr8VBmzoLiO0oo6leC1qgG6YU9 - c1Y5Viqy6teoDMrL85jrbKYhDnP75JA/KMcCUyIW9MsgqGzrU/ds9/ZUfSRoRpJAPSTHPKMcSgYyUNYR - PUdlURqy5vds0mz8/LTC15k9kaAciMRsUxTmjkVBbn8kpuolmD8egyUTiVA6mjz/cBwc7IgGOyVdRq7/ - GRuFzZaActGbtN6dmDwoxkPmQFCMilExGoDJw5tR2iOA3ddojDjtBfbp/Epy7e9QSVSguMjjXUKfC0Sb - aYgdn68JGvaNzZ/DfJC2+oBdKl1D4stDJVAhQRqP94en3ED2iI/yx3xMeuiA8Rf9gJbR9SS2Mtb7rcNC - Cz0+qGY8MG1WgCmX/ZGO5TVxpBwWiawcN4YbvosRfVQbgoEnpdo4ey1Xb/lPggO2YZ6pjgVULJdNWmv+ - GRYW3wHoVCJ7F4lIiQAAAABJRU5ErkJggg== - - - - - iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABGdBTUEAALGPC/xhBQAAAtxJREFUSEvt - 0m1Ik1EUB3C3yk193OPUJZovm69Zznwpw2BYkE6TNDdNbaXOt+l0Pr61FNNSFMs0bUUayoKIgpaYmNN0 - U1MxJCKiD2VFkBBRBNGnovKcDG6CGFHql8IfHC6c87/nfrkWa/4PTmVOXLVBrY3SRQlJa/Vw1VxLXh2v - Vz+jR6FO+IKlYbmT0cpRamqDY4PjzYp7FWB4awDdEx3Qp+hndDm9iUSWj5fDW+9c63ydMTPYNdMFnTOd - +KMaphtA0iG5TWJL+df4y5huZtz3uK8vaS1hl2u3zq3G7UqeUYWtD1qw5X4zNE+fwaapJhSfF3+xLbVN - JNHFeIW8+IhLks+Nk3WwvTX0lQvj4kVGC+wz7dmiKlFX9q0MqJ+sgbq71XBypBpqTScgpC34K1vFPkKi - iwk0guiws8GfKoYYrDQzcHSoAHc0hr50znde+BkOCgeWt9a7XXkjBapGi6HCxKB2kMGqwXKQ6MK/cVSc - TBJdyqfSx6juVoCmTwnMgBJKhpVQPJAOodXbnjtlbXTlK/gsz0LRubSr8VBmzoLiO0oo6leC1qgG6YU9 - c1Y5Viqy6teoDMrL85jrbKYhDnP75JA/KMcCUyIW9MsgqGzrU/ds9/ZUfSRoRpJAPSTHPKMcSgYyUNYR - PUdlURqy5vds0mz8/LTC15k9kaAciMRsUxTmjkVBbn8kpuolmD8egyUTiVA6mjz/cBwc7IgGOyVdRq7/ - GRuFzZaActGbtN6dmDwoxkPmQFCMilExGoDJw5tR2iOA3ddojDjtBfbp/Epy7e9QSVSguMjjXUKfC0Sb - aYgdn68JGvaNzZ/DfJC2+oBdKl1D4stDJVAhQRqP94en3ED2iI/yx3xMeuiA8Rf9gJbR9SS2Mtb7rcNC - Cz0+qGY8MG1WgCmX/ZGO5TVxpBwWiawcN4YbvosRfVQbgoEnpdo4ey1Xb/lPggO2YZ6pjgVULJdNWmv+ - GRYW3wHoVCJ7F4lIiQAAAABJRU5ErkJggg== diff --git a/oscardata/oscardata/Properties/Resources.Designer.cs b/oscardata/oscardata/Properties/Resources.Designer.cs index c5dd736..aa88aeb 100755 --- a/oscardata/oscardata/Properties/Resources.Designer.cs +++ b/oscardata/oscardata/Properties/Resources.Designer.cs @@ -80,6 +80,16 @@ namespace oscardata.Properties { } } + /// + /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap captureicon { + get { + object obj = ResourceManager.GetObject("captureicon", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + /// /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. /// @@ -250,6 +260,16 @@ namespace oscardata.Properties { } } + /// + /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap playbackicon { + get { + object obj = ResourceManager.GetObject("playbackicon", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + /// /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. /// diff --git a/oscardata/oscardata/Properties/Resources.resx b/oscardata/oscardata/Properties/Resources.resx index 8d6411a..a88624c 100755 --- a/oscardata/oscardata/Properties/Resources.resx +++ b/oscardata/oscardata/Properties/Resources.resx @@ -226,4 +226,10 @@ stopplay.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + captureicon.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + playbackicon.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + \ No newline at end of file diff --git a/oscardata/oscardata/Properties/captureicon.png b/oscardata/oscardata/Properties/captureicon.png new file mode 100644 index 0000000..ed3d1c7 Binary files /dev/null and b/oscardata/oscardata/Properties/captureicon.png differ diff --git a/oscardata/oscardata/Properties/playbackicon.png b/oscardata/oscardata/Properties/playbackicon.png new file mode 100644 index 0000000..5079aa1 Binary files /dev/null and b/oscardata/oscardata/Properties/playbackicon.png differ diff --git a/oscardata/oscardata/bin/Release/oscardata.exe b/oscardata/oscardata/bin/Release/oscardata.exe index 82afc41..28bc9e3 100755 Binary files a/oscardata/oscardata/bin/Release/oscardata.exe and b/oscardata/oscardata/bin/Release/oscardata.exe differ diff --git a/oscardata/oscardata/config.cs b/oscardata/oscardata/config.cs index 7cf7d05..275d8e0 100755 --- a/oscardata/oscardata/config.cs +++ b/oscardata/oscardata/config.cs @@ -38,6 +38,7 @@ namespace oscardata public static Byte terminate = 26; public static Byte tuning = 27; public static Byte marker = 28; + public static Byte setfreq = 29; // frame sequence, modem needs that for i.e. sending a preamble public static Byte FirstFrame = 0; @@ -54,6 +55,7 @@ namespace oscardata // global static variables public static bool running = true; public static String ModemIP = "1.2.3.4"; + public static String MyIP = "1.2.3.4"; public static int UdpBCport_AppToModem = 40131; // broadcast port for modem search public static int UdpTXport = 40132; // to modem public static int UdpRXport = 40133; // from modem diff --git a/oscardata/oscardata/oscardata.csproj b/oscardata/oscardata/oscardata.csproj index bbb6d61..2004078 100755 --- a/oscardata/oscardata/oscardata.csproj +++ b/oscardata/oscardata/oscardata.csproj @@ -150,6 +150,8 @@ + + diff --git a/oscardata/oscardata/udp.cs b/oscardata/oscardata/udp.cs index 2004f34..e1488f2 100755 --- a/oscardata/oscardata/udp.cs +++ b/oscardata/oscardata/udp.cs @@ -61,8 +61,11 @@ namespace oscardata } // Udp RX Loop runs in its own thread + static void Udprxloop() { + int extIPcnt = 0; + // define UDP port UdpClient udpc = new UdpClient(statics.UdpRXport); udpc.Client.ReceiveTimeout = 100; @@ -95,7 +98,27 @@ namespace oscardata // Broadcast response if (rxtype == statics.udp_bc) { - statics.ModemIP = RemoteEndpoint.Address.ToString(); + String ModIP = RemoteEndpoint.Address.ToString(); + if (ModIP != statics.MyIP) + { + // this is not the local IP + // wait for 3 Receptions before accepting it + if (extIPcnt < 3) + { + //Console.WriteLine("myIP:"+statics.MyIP+" modem is ext IP:"+ModIP+", waiting:" + extIPcnt); + if (extIPcnt < 4) extIPcnt++; + if (extIPcnt < 3) + continue; + } + //Console.WriteLine("modem is ext IP, accepted"); + } + else + { + //Console.WriteLine("modem is local IP"); + extIPcnt = 0; + } + + statics.ModemIP = ModIP; searchtimeout = 0; // message b contains audio devices and init status statics.initAudioStatus = b[0]; @@ -266,10 +289,10 @@ namespace oscardata for (int x = 10; x <= 390; x += 10) gr.DrawLine(pen, x, yl, x, yh); + gr.DrawLine(penred, 10, yl, 10, yh); gr.DrawLine(penred, 150, yl, 150, yh); gr.DrawLine(pensolid, 20, yl, 20, yh); gr.DrawLine(pensolid, 280, yl, 280, yh); - gr.DrawLine(penred, 300, yl, 300, yh); gr.DrawLine(pensolid, 360, yl, 360, yh); gr.DrawRectangle(penred, 15, yh, 270, yl-yh);