This commit is contained in:
Kurt 2021-03-15 18:46:24 +01:00
parent 135fc75eee
commit 7088804826
20 changed files with 166 additions and 72 deletions

View File

@ -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

Binary file not shown.

BIN
WinRelease/hsmodem.iobj Executable file

Binary file not shown.

BIN
WinRelease/hsmodem.ipdb Executable file

Binary file not shown.

BIN
WinRelease/hsmodem.pdb Executable file

Binary file not shown.

Binary file not shown.

View File

@ -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();

View File

@ -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);

View File

@ -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];

View File

@ -125,6 +125,7 @@
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;_LIB;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
@ -142,6 +143,7 @@
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
@ -158,6 +160,7 @@
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_LIB;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
@ -177,6 +180,7 @@
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_LIB;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
@ -195,6 +199,7 @@
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_LIB;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
@ -213,6 +218,7 @@
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_LIB;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>

View File

@ -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);

View File

@ -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];

View File

@ -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];

BIN
hsmodemLinux/dxcluster Executable file

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -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;
}
}

View File

@ -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

View File

@ -137,7 +137,7 @@
AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj00LjAuMC4w
LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACZTeXN0
ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAAA+
JQAAAk1TRnQBSQFMAgEBFwEAAdgBDQHYAQ0BEAEAARABAAT/AQkBAAj/AUIBTQE2AQQGAAE2AQQCAAEo
JQAAAk1TRnQBSQFMAgEBFwEAAegBDQHoAQ0BEAEAARABAAT/AQkBAAj/AUIBTQE2AQQGAAE2AQQCAAEo
AwABQAMAAWADAAEBAQABCAYAARgYAAGAAgABgAMAAoABAAGAAwABgAEAAYABAAKAAgADwAEAAcAB3AHA
AQAB8AHKAaYBAAEzBQABMwEAATMBAAEzAQACMwIAAxYBAAMcAQADIgEAAykBAANVAQADTQEAA0IBAAM5
AQABgAF8Af8BAAJQAf8BAAGTAQAB1gEAAf8B7AHMAQABxgHWAe8BAAHWAucBAAGQAakBrQIAAf8BMwMA