diff --git a/README.md b/README.md index d872460..cf8dc05 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,7 @@ The purpose of this project is to transfer data (pictures...) via a 2,7kHz SSB channel on the narrow band transponder as fast as possible. Now also including RTTY mode. -# this is work in progress -Version 0.84 +Version 0.87 Windows 10 (should work on Win7, not tested) linux Desktop PC, Odroid SBC diff --git a/WinRelease/hsmodem.exe b/WinRelease/hsmodem.exe index c44d35a..faa4be4 100755 Binary files a/WinRelease/hsmodem.exe and b/WinRelease/hsmodem.exe differ diff --git a/WinRelease/hsmodem.iobj b/WinRelease/hsmodem.iobj new file mode 100755 index 0000000..8040be9 Binary files /dev/null and b/WinRelease/hsmodem.iobj differ diff --git a/WinRelease/hsmodem.ipdb b/WinRelease/hsmodem.ipdb new file mode 100755 index 0000000..f194a6a Binary files /dev/null and b/WinRelease/hsmodem.ipdb differ diff --git a/WinRelease/hsmodem.pdb b/WinRelease/hsmodem.pdb new file mode 100755 index 0000000..f726c97 Binary files /dev/null and b/WinRelease/hsmodem.pdb differ diff --git a/WinRelease/oscardata.exe b/WinRelease/oscardata.exe index fc5426d..ee1dc3e 100755 Binary files a/WinRelease/oscardata.exe and b/WinRelease/oscardata.exe differ diff --git a/hsmodem/announcement.cpp b/hsmodem/announcement.cpp index 86352b7..ff22b9c 100755 --- a/hsmodem/announcement.cpp +++ b/hsmodem/announcement.cpp @@ -45,6 +45,24 @@ void create_a() // create arbitrary pre decimator // if Audio SR is 48000 but caprate is 44100 ratio = (float)((float)caprate / 48000.0); +#ifdef _WIN32_ + /* + * only Windows needs this special resampling ratio + * maybe it has to do with the VAC, I don't know why we have + * to resample twice 48k -> 44.1k + * maybe this will not work on another PC + */ + /* + if(caprate == 44100) + ratio = (float)(40526.0f / 48000.0); + else + ratio = (float)(44100.0f / 48000.0); + */ + if (caprate == 48000) + ratio = (float)(48000.0f / 44100.0); + else + ratio = 1.0f; +#endif anndecim = msresamp_crcf_create(ratio, 40.0f); } @@ -64,7 +82,7 @@ float lowpass(float f) return f; } liquid_float_complex inp, outp; - inp.real = f/5; + inp.real = f; inp.imag = 0; firfilt_crcf_push(qfilt, inp); // push input sample firfilt_crcf_execute(qfilt, &outp); // compute output @@ -72,21 +90,44 @@ float lowpass(float f) return outp.real; } +int measureLevel(char* fn) +{ + int max = 0; + FILE* fp = fopen(fn, "rb"); + if (fp) + { + int len = 0; + int16_t v; + while ((len = fread(&v, sizeof(int16_t), 1, fp))) + { + if (v > max) max = v; + } + fclose(fp); + } + return max; +} + // destination: 1=transceiver, 2=loudspeaker, 3=both void playAudioPCM(char* fn, int destination) { int len; int16_t d[100]; printf("play:%s, caprate:%d\n", fn,caprate); + int max = measureLevel(fn); + float ampl = 32767.0f / (float)max; + //printf("max:%d ampl:%f\n", max, ampl); FILE* fp = fopen(fn, "rb"); - const float ann_volume = 0.3f; // volume reduction for announcement + const float ann_volume = 0.1f; // volume reduction for announcement if (fp) { while ((len = fread(d, sizeof(int16_t), 100, fp))) { for (int i = 0; i < len; i++) { - float f = (float)d[i]; + float f = (float)d[i]; // 16-bit values + f /= 32768; // float values 0..1 + f *= ampl; // normalize volume + f *= ann_volume; // reduce volume // local playback at 48k, no filtering, no interpolation if ((destination & 2) == 2) @@ -103,43 +144,42 @@ void playAudioPCM(char* fn, int destination) } sleep_ms(1); } - f = lowpass(f); - f *= ann_volume; // reduce volume - float f1 = f / 32768; - kmaudio_playsamples(voice_pbidx, &f1, 1, lsvol); + kmaudio_playsamples(voice_pbidx, &f, 1, lsvol); } + // resample if required (PCM files are always 48000) + unsigned int num_written = 1; + liquid_float_complex out[10]; + out[0].real = f; // value, if no resampling +#ifdef _LINUX_ if (caprate == 44100) +#endif { - unsigned int num_written = 0; liquid_float_complex in; - liquid_float_complex out; in.real = f; in.imag = 0; - msresamp_crcf_execute(anndecim, &in, 1, &out, &num_written); - if (num_written != 1) continue; - f = out.real; + msresamp_crcf_execute(anndecim, &in, 1, out, &num_written); } - - f = lowpass(f); - f *= ann_volume; // reduce volume - f /= 32768; - - if ((destination & 1) == 1) + for (unsigned int n = 0; n < num_written; n++) { - int to = 4000; - //while (io_pb_fifo_usedspace() > 10000) - while (io_fifo_usedspace(io_pbidx) > 10000) + f = out[n].real; + f = lowpass(f); + + if ((destination & 1) == 1) { - if (--to == 0) + int to = 4000; + while (io_fifo_usedspace(io_pbidx) > 10000) { - printf("timed out waiting for PB fifo\n"); - fclose(fp); - return; + if (--to == 0) + { + printf("timed out waiting for PB fifo\n"); + fclose(fp); + return; + } + sleep_ms(1); } - sleep_ms(1); + kmaudio_playsamples(io_pbidx, &f, 1, pbvol); } - kmaudio_playsamples(io_pbidx, &f, 1, pbvol); } } @@ -197,7 +237,6 @@ void playIntro() snprintf(fn, 499, "%s/oscardata/intro/intro.pcm", homepath); fn[499] = 0; - //io_clear_voice_fifos(); io_fifo_clear(voice_pbidx); io_fifo_clear(voice_capidx); create_a(); diff --git a/hsmodem/extdata.cpp b/hsmodem/extdata.cpp index 65e4cac..193554d 100755 --- a/hsmodem/extdata.cpp +++ b/hsmodem/extdata.cpp @@ -62,6 +62,8 @@ void ext_rxdata(uint8_t* pdata, int len, struct sockaddr_in* rxsock) id <<= 8; id += pdata[3]; + //printf("incoming data on 40135, ID: %d, pdata[4]:%d\n", id,pdata[4]); + if (id != extDataID) { printf("incoming data on 40135, wrong ID: %d\n", id); diff --git a/hsmodem/hsmodem.cpp b/hsmodem/hsmodem.cpp index 6d501ff..32355d6 100755 --- a/hsmodem/hsmodem.cpp +++ b/hsmodem/hsmodem.cpp @@ -361,9 +361,10 @@ SPEEDRATE sr[NUMSPEEDMODES] = { void startModem() { printf("startModem. Speedmode:%d\n",set_speedmode); - close_dsp(); + close_rtty(); fifo_clear(PSK_GUI_TX); + close_dsp(); speedmode = set_speedmode; if (speedmode < 0 || speedmode >= NUMSPEEDMODES) speedmode = 4; @@ -376,6 +377,18 @@ void startModem() rxPreInterpolfactor = sr[speedmode].rx; linespeed = sr[speedmode].linespeed; opusbitrate = sr[speedmode].codecrate; + + _init_fft(); + if (speedmode < 10) + { + init_dsp(); + } + if (speedmode == 10) + { + rtty_txoff = 1; + init_rtty(); + } + // int TX audio and modulator io_capidx = kmaudio_startCapture(captureDeviceName, caprate); if (io_capidx == -1) @@ -390,18 +403,7 @@ void startModem() printf("PB: cannot open device: %s\n", playbackDeviceName); return; } - - _init_fft(); - if (speedmode < 10) - { - init_dsp(); - } - if (speedmode == 10) - { - rtty_txoff = 1; - init_rtty(); - } init_tune(); } @@ -598,6 +600,9 @@ void bc_rxdata(uint8_t* pdata, int len, struct sockaddr_in* rxsock) // called by UDP RX thread for data from App void appdata_rxdata(uint8_t* pdata, int len, struct sockaddr_in* rxsock) { + // ignore data when modem is starting + if (restart_modems == 1) return; + uint8_t type = pdata[0]; uint8_t minfo = pdata[1]; diff --git a/hsmodem/hsmodem.vcxproj b/hsmodem/hsmodem.vcxproj index 1289f49..8ef1e89 100755 --- a/hsmodem/hsmodem.vcxproj +++ b/hsmodem/hsmodem.vcxproj @@ -125,6 +125,7 @@ Level3 Disabled WIN32;_DEBUG;_CONSOLE;_LIB;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true Console @@ -142,6 +143,7 @@ Level3 Disabled WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) + true Console @@ -158,6 +160,7 @@ true true WIN32;NDEBUG;_CONSOLE;_LIB;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true Console @@ -177,6 +180,7 @@ true true WIN32;NDEBUG;_CONSOLE;_LIB;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true Console @@ -195,6 +199,7 @@ true true WIN32;NDEBUG;_CONSOLE;_LIB;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true Console @@ -213,6 +218,7 @@ true true WIN32;NDEBUG;_CONSOLE;_LIB;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true Console diff --git a/hsmodem/libkmaudio/libkmaudio_fifo.cpp b/hsmodem/libkmaudio/libkmaudio_fifo.cpp index b38fe3c..b09278d 100755 --- a/hsmodem/libkmaudio/libkmaudio_fifo.cpp +++ b/hsmodem/libkmaudio/libkmaudio_fifo.cpp @@ -118,7 +118,11 @@ void io_write_fifo_short(int pipenum, int16_t sample) int io_read_fifo(int pipenum, float* data) { - if (pipenum < 0 || pipenum >= NUM_OF_PIPES) return 0; + if (pipenum < 0 || pipenum >= NUM_OF_PIPES) + { + printf("io_read_fifo: wrong PIP num: %d\n",pipenum); + return 0; + } LOCK(pipenum); @@ -128,7 +132,6 @@ int io_read_fifo(int pipenum, float* data) UNLOCK(pipenum); return 0; } - int16_t id = io_buffer[pipenum][io_rdidx[pipenum]]; if (++io_rdidx[pipenum] >= AUDIO_FIFOFLEN) io_rdidx[pipenum] = 0; UNLOCK(pipenum); diff --git a/hsmodem/libkmaudio/libkmaudio_playback.cpp b/hsmodem/libkmaudio/libkmaudio_playback.cpp index 3a40390..a8e9db4 100755 --- a/hsmodem/libkmaudio/libkmaudio_playback.cpp +++ b/hsmodem/libkmaudio/libkmaudio_playback.cpp @@ -142,18 +142,19 @@ int playCallback( const void* inputBuffer, //measure_speed_bps(framesPerBuffer); - /* das hier ging + /* + // das hier ging + //printf("has:%d: %d\n", devidx,io_fifo_elems_avail(devidx)); int16_t f[FRAMES_PER_BUFFER]; memset(f, 0, sizeof(int16_t) * FRAMES_PER_BUFFER); unsigned int num = io_read_fifo_num_short(devidx, f, framesPerBuffer); if (num < framesPerBuffer) { - //printf("got %d from fifo, requested %d\n", num, framesPerBuffer); + // not enough data, use what we got from fifo, rest is 0 + printf("got %d from fifo, requested %d\n", num, framesPerBuffer); } - int av = io_fifo_elems_avail(devidx); - das nächste ist neu */ - + int16_t f[FRAMES_PER_BUFFER]; // if fifo does not have enough data, just send 0.. (silence) // this gives the fifo a chance to fill up a bit @@ -166,9 +167,10 @@ int playCallback( const void* inputBuffer, else { // nothing to send + //printf("got %d from fifo, requested %d\n", io_fifo_elems_avail(devidx), framesPerBuffer); devlist[devidx].audio_playing = 0; } - + for (unsigned int i = 0; i < framesPerBuffer; i++) { if (chans == 1) rptr[i] = f[i]; diff --git a/hsmodem/liquid_if.cpp b/hsmodem/liquid_if.cpp index 4f75376..411abd8 100755 --- a/hsmodem/liquid_if.cpp +++ b/hsmodem/liquid_if.cpp @@ -28,6 +28,8 @@ #include "hsmodem.h" +int mod_running = 0; + void modulator(uint8_t sym_in); void init_demodulator(); void close_demodulator(); @@ -37,18 +39,28 @@ void close_modulator(); void init_dsp() { printf("init DSP\n"); + //close_dsp(); init_modulator(); io_fifo_clear(io_pbidx); io_fifo_clear(io_capidx); init_demodulator(); + printf("init DSP FIN\n"); + mod_running = 1; } void close_dsp() { + printf("close DSP\n"); + mod_running = 0; + io_fifo_clear(io_pbidx); + io_fifo_clear(io_capidx); + sleep_ms(200); // give system a chance to stop + close_modulator(); close_demodulator(); } + modulation_scheme getMod() { if (bitsPerSymbol == 1) @@ -82,7 +94,6 @@ float tau_FracSymbOffset = -0.2f; // fractional symbol offset void init_modulator() { - close_dsp(); printf("init TX modulator\n"); k_SampPerSymb = txinterpolfactor; @@ -145,7 +156,10 @@ void close_modulator() // len ... number of symbols in d void _sendToModulator(uint8_t *d, int len) { - if(upnco == NULL) return; + if (upnco == NULL) return; + if (mod == NULL) return; + if (TX_interpolator == NULL) return; + if (mod_running == 0) return; int symanz = len * 8 / bitsPerSymbol; uint8_t syms[10000]; @@ -176,6 +190,11 @@ void _sendToModulator(uint8_t *d, int len) // modulates, filters and upmixes symbols and send it to soundcard void modulator(uint8_t sym_in) { + if (upnco == NULL) return; + if (mod == NULL) return; + if (TX_interpolator == NULL) return; + if (mod_running == 0) return; + liquid_float_complex sample; modem_modulate(mod, sym_in, &sample); @@ -203,11 +222,24 @@ void modulator(uint8_t sym_in) // adapt speed to soundcard samplerate int fs; int to = 0; + /* while(keeprunning) { fs = io_fifo_freespace(io_pbidx); // wait until there is space in fifo if(fs > 10) break; + printf("wit:%d: %d\n", io_pbidx,io_fifo_elems_avail(io_pbidx)); + sleep_ms(10); + if (++to >= 400) break; // give up after 4s + }*/ + + // put max. 4 frames in fifo, to minimize latency + // 4 frames are 1032 bytes + while (keeprunning && mod_running) + { + fs = io_fifo_usedspace(io_pbidx); + if (fs <= 20000) break; + //printf("wit:%d: %d\n", io_pbidx, io_fifo_elems_avail(io_pbidx)); sleep_ms(10); if (++to >= 400) break; // give up after 4s } @@ -278,7 +310,10 @@ void close_demodulator() void resetModem() { //printf("Reset Symtrack\n"); + if (dnnco == NULL) return; + if (decim == NULL) return; if (km_symtrack == NULL) return; + if (mod_running == 0) return; km_symtrack_cccf_reset(km_symtrack,0xff); } @@ -363,7 +398,10 @@ static int16_t const_re[CONSTPOINTS]; static int16_t const_im[CONSTPOINTS]; static int const_idx = 0; - if(dnnco == NULL) return 0; + if (dnnco == NULL) return 0; + if (decim == NULL) return 0; + if (km_symtrack == NULL) return 0; + if (mod_running == 0) return 0; // get available received samples float farr[1100]; diff --git a/hsmodemLinux/dxcluster b/hsmodemLinux/dxcluster new file mode 100755 index 0000000..b237c69 Binary files /dev/null and b/hsmodemLinux/dxcluster differ diff --git a/hsmodemLinux/hsmodem b/hsmodemLinux/hsmodem index 0b04dd7..0575789 100755 Binary files a/hsmodemLinux/hsmodem and b/hsmodemLinux/hsmodem differ diff --git a/hsmodemLinux/oscardata.exe b/hsmodemLinux/oscardata.exe index fc5426d..ee1dc3e 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 21610f2..0e022fc 100755 --- a/oscardata/oscardata/Form1.Designer.cs +++ b/oscardata/oscardata/Form1.Designer.cs @@ -68,7 +68,6 @@ this.cb_file_pause = new System.Windows.Forms.ComboBox(); this.label13 = new System.Windows.Forms.Label(); this.cb_file_loop = new System.Windows.Forms.CheckBox(); - this.bt_open_html = new System.Windows.Forms.Button(); this.pictureBox1 = new System.Windows.Forms.PictureBox(); this.button2 = new System.Windows.Forms.Button(); this.bt_openrxfile = new System.Windows.Forms.Button(); @@ -208,6 +207,7 @@ this.label_fifo = new System.Windows.Forms.Label(); this.panel_txspectrum = new oscardata.DoubleBufferedPanel(); this.panel_constel = new oscardata.DoubleBufferedPanel(); + this.bt_open_html = new System.Windows.Forms.Button(); this.statusStrip1.SuspendLayout(); this.tabPage_ber.SuspendLayout(); this.tabPage_image.SuspendLayout(); @@ -698,20 +698,6 @@ this.cb_file_loop.Text = "ON / off"; this.cb_file_loop.UseVisualStyleBackColor = true; // - // bt_open_html - // - this.bt_open_html.ImageAlign = System.Drawing.ContentAlignment.MiddleLeft; - this.bt_open_html.ImageIndex = 2; - this.bt_open_html.ImageList = this.imageList1; - this.bt_open_html.Location = new System.Drawing.Point(17, 337); - this.bt_open_html.Name = "bt_open_html"; - this.bt_open_html.Size = new System.Drawing.Size(137, 51); - this.bt_open_html.TabIndex = 15; - this.bt_open_html.Text = "Open received \r\nHTML file"; - this.bt_open_html.UseVisualStyleBackColor = true; - this.bt_open_html.Visible = false; - this.bt_open_html.Click += new System.EventHandler(this.bt_open_html_Click); - // // pictureBox1 // this.pictureBox1.BackgroundImage = ((System.Drawing.Image)(resources.GetObject("pictureBox1.BackgroundImage"))); @@ -2353,6 +2339,20 @@ this.panel_constel.TabIndex = 5; this.panel_constel.Paint += new System.Windows.Forms.PaintEventHandler(this.panel_constel_Paint); // + // bt_open_html + // + this.bt_open_html.ImageAlign = System.Drawing.ContentAlignment.MiddleLeft; + this.bt_open_html.ImageIndex = 2; + this.bt_open_html.ImageList = this.imageList1; + this.bt_open_html.Location = new System.Drawing.Point(17, 337); + this.bt_open_html.Name = "bt_open_html"; + this.bt_open_html.Size = new System.Drawing.Size(137, 51); + this.bt_open_html.TabIndex = 15; + this.bt_open_html.Text = "Open received \r\nHTML file"; + this.bt_open_html.UseVisualStyleBackColor = true; + this.bt_open_html.Visible = false; + this.bt_open_html.Click += new System.EventHandler(this.bt_open_html_Click); + // // Form1 // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); @@ -2367,7 +2367,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.86 by DJ0ABR"; + this.Text = "AMSAT-DL Multimedia HS Modem V0.87 by DJ0ABR"; this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.Form1_FormClosing); this.statusStrip1.ResumeLayout(false); this.statusStrip1.PerformLayout(); @@ -2602,10 +2602,10 @@ private System.Windows.Forms.ComboBox cb_picres; private System.Windows.Forms.CheckBox cb_extIF; private System.Windows.Forms.TextBox textBox7; - private System.Windows.Forms.Button bt_open_html; private System.Windows.Forms.GroupBox groupBox8; private System.Windows.Forms.ComboBox cb_file_pause; private System.Windows.Forms.Label label13; + private System.Windows.Forms.Button bt_open_html; } } diff --git a/oscardata/oscardata/Form1.cs b/oscardata/oscardata/Form1.cs index 2e1cf85..0ec6eea 100755 --- a/oscardata/oscardata/Form1.cs +++ b/oscardata/oscardata/Form1.cs @@ -185,7 +185,7 @@ namespace oscardata if (ArraySend.getSending() == false) { // transmission is finished, wait until data in TXfifo have been sent - Console.WriteLine("pbf: " + statics.PBfifousage.ToString()); + //Console.WriteLine("pbf: " + statics.PBfifousage.ToString()); if (statics.PBfifousage < 1) { // start sending a new picture diff --git a/oscardata/oscardata/Form1.resx b/oscardata/oscardata/Form1.resx index 7fdadca..d04c2db 100755 --- a/oscardata/oscardata/Form1.resx +++ b/oscardata/oscardata/Form1.resx @@ -137,7 +137,7 @@ AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj00LjAuMC4w LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACZTeXN0 ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAAA+ - JQAAAk1TRnQBSQFMAgEBFwEAAdgBDQHYAQ0BEAEAARABAAT/AQkBAAj/AUIBTQE2AQQGAAE2AQQCAAEo + JQAAAk1TRnQBSQFMAgEBFwEAAegBDQHoAQ0BEAEAARABAAT/AQkBAAj/AUIBTQE2AQQGAAE2AQQCAAEo AwABQAMAAWADAAEBAQABCAYAARgYAAGAAgABgAMAAoABAAGAAwABgAEAAYABAAKAAgADwAEAAcAB3AHA AQAB8AHKAaYBAAEzBQABMwEAATMBAAEzAQACMwIAAxYBAAMcAQADIgEAAykBAANVAQADTQEAA0IBAAM5 AQABgAF8Af8BAAJQAf8BAAGTAQAB1gEAAf8B7AHMAQABxgHWAe8BAAHWAucBAAGQAakBrQIAAf8BMwMA diff --git a/oscardata/oscardata/bin/Release/oscardata.exe b/oscardata/oscardata/bin/Release/oscardata.exe index fc5426d..dbe6e5f 100755 Binary files a/oscardata/oscardata/bin/Release/oscardata.exe and b/oscardata/oscardata/bin/Release/oscardata.exe differ