This commit is contained in:
Kurt Moraw 2020-12-15 14:38:56 +01:00
parent d38ab5f736
commit 7e306d77dc
18 changed files with 178 additions and 67 deletions

View File

@ -1,8 +1,83 @@
# QO-100-modem
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.
# the actual version is hosted in the Amsat-DL Github Repo:
# this is work in progress
Version 0.4 is working on:
Windows 10 (should work on Win7, not tested)
linux Desktop PC,
Odroid SBC
Raspberry 4 (3B+)
https://github.com/amsat-dl/QO-100-Modem
# Prerequisites
* Windopws 10 Desktop PC ... working
* LINUX Desktop PC ... working
* Raspberry PI 4 ... working
* Raspberry PI 3B+ ... working, but not 100% error free in fullduplex mode (RX only or TX only is working)
* Odroid N2 ... working
* Odroid C2 ... working
* Odroid C4 ... working
* Raspberry: Raspian OS ist NOT working, instead Ubuntu 64bit is required
* Application Software "oscardata.exe" running on Windows, Linux, (possibly MAC-OS, not tested)
# 3rd Party Libraries
this software uses these programs:
* Shifra Reed Solomon code: https://www.schifra.com/ (GPL V.2)
* liquid-SDR: https://github.com/jgaeddert/liquid-dsp (MIT License)
* libsoundio: https://github.com/andrewrk/libsoundio (MIT License)
* fftw3: http://www.fftw.org (GPL V.2 or later)
* libcodec2: https://github.com/drowe67/codec2 (LGPL 2.1, Linux: standard lib, Windows: from freeDV)
# Download alternatives
* download from github and build from source
* download windows installer and download Odroid and Raspberry images:
https://dj0abr.de/german/technik/sat/modem/images.htm
# building the software for Linux
* Linux
1. Download from github the file hsmodem/hsmodem.sh, ONLY ! Do not clone the repository, download ONLY this single file.
2. copy hsmodem.hs to your home directory and make it executable (chmod 755 hsmodem.sh)
3. run the file: ./hsmodem.sh
this will make download, compile hsmodem an install all required files
the resulting project is in ./SSB_HighSpeed_Modem/hsmodemLinux
# starting the modem and application
you need to run 2 programs, the first one is "hsmodem" which runs in a termimal without GUI. This is the modem doing all modulation and demodulation staff.
The second program is the user interface "oscardata.exe".
oscardata.exe starts hsmodem automatically in the background. If you want to run hsmodem on one machine and oscardata on another then deactivate the autostart in the Setup menu in oscardata.exe
* Windows
if the software was installed with this setup file:
https://wx.spdns.de/german/technik/sat/modem/images.htm
then you find the program under the program group "amsat" in the Window's start menu
* Linux
1. go into the folder ..../SSB_HighSpeed_Modem/hsmodemLinux
2. run the software: mono oscardata.exe
# tested scenarious
* QO-100 via IC-9700, IC-7300 or IC-7100 ... working
* Short Wave 6m band via IC-7300, IC-7100 ... working. In case of significant noise, use the lowest bit rate (3000 bit/s)
# usage
In the IC-9700 activate the DATA mode and the RX filter FIL1 to full range of 3.6kHz.
In oscardata.exe go to the "BER" tab. Then click START. If you change the bitrate, wait a few seconds before starting again.
The program is now sending test data frames to the default sound card. If your sound card is properly connected to the transceiver then switch the transceiver to TX and the data will be sent to QO-100.
Receive your transmission, feed it to the default soundcard. As soon as oscardata.exe detects a correct data frame it will display status messages on the screen.
(For testing purposes you can just connect Line-Out of your soundcard with Line-IN with a cable.)
To assign the soundcard to the modem I recommend to use pavucontrol. Using the TX volume set a signal level of about 20 to 24 dB over noise floor. You will need about -10dB compared to the BPSK400 beacon. The received audio volume can be adjusted with help of the spectrum display in oscardata.exe-
Now as the transmission is OK, you can go to the "Image RX/TX" tab. First, select a picture quality then load a picture and finally press SEND to send it to QO-100. When you correctly receive your own transmission the RX picture will be displayed line by line.
vy 73, DJ0ABR

BIN
WinRelease/Satellite-icon.ico Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

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.

BIN
WinRelease/sio_list_devices.exe Executable file

Binary file not shown.

BIN
WinRelease/sio_sine.exe Executable file

Binary file not shown.

View File

@ -128,7 +128,7 @@ uint16_t *make_waterfall(float fre, int *retlen)
// check if signal detected or not
if (idiff > 100) sig = 0;
if (idiff < 20) sig = 1;
if (idiff < 30) sig = 1;
rxlevel_deteced = sig;

View File

@ -307,11 +307,6 @@ void bc_rxdata(uint8_t* pdata, int len, struct sockaddr_in* rxsock)
* 110 .. 209 ... CAP device name
*/
//printf("%d %d %d %d %d %d %d \n",pdata[1], pdata[2], pdata[3], pdata[4], pdata[5], pdata[6], pdata[7]);
io_setAudioDevices(pdata[1], pdata[2], pdata[3], pdata[4], pdata[5], (char *)(pdata + 10), (char *)(pdata + 110));
safemode = pdata[6];
char rxip[20];
strcpy(rxip, inet_ntoa(rxsock->sin_addr));
@ -336,14 +331,19 @@ void bc_rxdata(uint8_t* pdata, int len, struct sockaddr_in* rxsock)
if (!strcmp(appIP, rxip))
{
//printf("app (%s) is searching modem. Sending modem IP to the app\n",appIP);
restart_modems = 1;
// App searches for the modem IP, mirror the received messages
// so the app gets an UDP message with this local IP
int alen;
uint8_t* txdata = io_getAudioDevicelist(&alen);
sendUDP(appIP, UdpDataPort_ModemToApp, txdata, alen);
}
else
return;
}
//printf("%d %d %d %d %d %d %d \n",pdata[1], pdata[2], pdata[3], pdata[4], pdata[5], pdata[6], pdata[7]);
io_setAudioDevices(pdata[1], pdata[2], pdata[3], pdata[4], pdata[5], (char*)(pdata + 10), (char*)(pdata + 110));
safemode = pdata[6];
}
}
@ -560,16 +560,14 @@ void GRdata_rxdata(uint8_t* pdata, int len, struct sockaddr_in* rxsock)
uint8_t* pl = unpack_data(pdata, len);
if (pl != NULL)
{
if (VoiceAudioMode != VOICEMODE_DV_FULLDUPLEX)
{
// complete frame received
// send payload to app
uint8_t txpl[PAYLOADLEN + 10 + 1];
memcpy(txpl + 1, pl, PAYLOADLEN + 10);
txpl[0] = 1; // type 1: payload data follows
sendUDP(appIP, UdpDataPort_ModemToApp, txpl, PAYLOADLEN + 10 + 1);
}
else
// complete frame received
// send payload to app
uint8_t txpl[PAYLOADLEN + 10 + 1];
memcpy(txpl + 1, pl, PAYLOADLEN + 10);
txpl[0] = 1; // type 1: payload data follows
sendUDP(appIP, UdpDataPort_ModemToApp, txpl, PAYLOADLEN + 10 + 1);
if (VoiceAudioMode == VOICEMODE_DV_FULLDUPLEX)
{
// send to Codec decoder
if (*(pl + 3) != 0) // minfo=0 ... just a filler, ignore

View File

@ -429,7 +429,7 @@ static int ccol_idx = 0;
// we have about 2000 S/s, but this many points would make the GUI slow
// so we send only every x
static int ev = 0;
if (++ev >= 10)
if (++ev >= 5)//10)
{
ev = 0;
int32_t re = (int32_t)(syms.real * 16777216.0);

View File

@ -33,6 +33,7 @@
this.timer_udpTX = new System.Windows.Forms.Timer(this.components);
this.timer_udprx = new System.Windows.Forms.Timer(this.components);
this.statusStrip1 = new System.Windows.Forms.StatusStrip();
this.toolStrip_Type = new System.Windows.Forms.ToolStripStatusLabel();
this.toolStripStatusLabel = new System.Windows.Forms.ToolStripStatusLabel();
this.ts_ip = new System.Windows.Forms.ToolStripStatusLabel();
this.RXstatus = new System.Windows.Forms.ToolStripStatusLabel();
@ -107,8 +108,6 @@
this.bt_resetmodem = new System.Windows.Forms.Button();
this.textBox3 = new System.Windows.Forms.TextBox();
this.groupBox3 = new System.Windows.Forms.GroupBox();
this.vu_cap = new oscardata.KmProgressBar();
this.vu_pb = new oscardata.KmProgressBar();
this.pb_audioCAPstatus = new System.Windows.Forms.PictureBox();
this.pb_audioPBstatus = new System.Windows.Forms.PictureBox();
this.label6 = new System.Windows.Forms.Label();
@ -135,15 +134,17 @@
this.cb_speed = new System.Windows.Forms.ComboBox();
this.label_speed = new System.Windows.Forms.Label();
this.timer_searchmodem = new System.Windows.Forms.Timer(this.components);
this.progressBar_fifo = new oscardata.KmProgressBar();
this.label_fifo = new System.Windows.Forms.Label();
this.bt_blockinfo = new System.Windows.Forms.Button();
this.progressBar_capfifo = new oscardata.KmProgressBar();
this.label_capfifo = new System.Windows.Forms.Label();
this.lb_rxsignal = new System.Windows.Forms.Label();
this.lb_rxsync = new System.Windows.Forms.Label();
this.pb_rxsync = new System.Windows.Forms.PictureBox();
this.pb_rxsignal = new System.Windows.Forms.PictureBox();
this.progressBar_capfifo = new oscardata.KmProgressBar();
this.progressBar_fifo = new oscardata.KmProgressBar();
this.vu_cap = new oscardata.KmProgressBar();
this.vu_pb = new oscardata.KmProgressBar();
this.statusStrip1.SuspendLayout();
this.tabPage_ber.SuspendLayout();
this.tabPage_image.SuspendLayout();
@ -188,6 +189,7 @@
//
this.statusStrip1.ImageScalingSize = new System.Drawing.Size(20, 20);
this.statusStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.toolStrip_Type,
this.toolStripStatusLabel,
this.ts_ip,
this.RXstatus});
@ -197,6 +199,13 @@
this.statusStrip1.TabIndex = 4;
this.statusStrip1.Text = "statusStrip1";
//
// toolStrip_Type
//
this.toolStrip_Type.Font = new System.Drawing.Font("Verdana", 9F, System.Drawing.FontStyle.Bold);
this.toolStrip_Type.ForeColor = System.Drawing.Color.Red;
this.toolStrip_Type.Name = "toolStrip_Type";
this.toolStrip_Type.Size = new System.Drawing.Size(0, 17);
//
// toolStripStatusLabel
//
this.toolStripStatusLabel.Name = "toolStripStatusLabel";
@ -1070,20 +1079,6 @@
this.groupBox3.TabStop = false;
this.groupBox3.Text = "Transceiver Audio";
//
// vu_cap
//
this.vu_cap.Location = new System.Drawing.Point(479, 87);
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.Name = "vu_pb";
this.vu_pb.Size = new System.Drawing.Size(100, 10);
this.vu_pb.TabIndex = 19;
//
// pb_audioCAPstatus
//
this.pb_audioCAPstatus.BackgroundImage = global::oscardata.Properties.Resources.ok;
@ -1375,17 +1370,6 @@
this.timer_searchmodem.Interval = 1000;
this.timer_searchmodem.Tick += new System.EventHandler(this.timer_searchmodem_Tick);
//
// progressBar_fifo
//
this.progressBar_fifo.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(128)))), ((int)(((byte)(255)))), ((int)(((byte)(255)))));
this.progressBar_fifo.Location = new System.Drawing.Point(658, 618);
this.progressBar_fifo.Maximum = 20;
this.progressBar_fifo.Name = "progressBar_fifo";
this.progressBar_fifo.Size = new System.Drawing.Size(304, 18);
this.progressBar_fifo.Step = 11;
this.progressBar_fifo.Style = System.Windows.Forms.ProgressBarStyle.Continuous;
this.progressBar_fifo.TabIndex = 13;
//
// label_fifo
//
this.label_fifo.AutoSize = true;
@ -1405,16 +1389,6 @@
this.bt_blockinfo.UseVisualStyleBackColor = true;
this.bt_blockinfo.Click += new System.EventHandler(this.bt_blockinfo_Click);
//
// progressBar_capfifo
//
this.progressBar_capfifo.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(255)))), ((int)(((byte)(192)))), ((int)(((byte)(128)))));
this.progressBar_capfifo.Location = new System.Drawing.Point(658, 642);
this.progressBar_capfifo.Name = "progressBar_capfifo";
this.progressBar_capfifo.Size = new System.Drawing.Size(304, 18);
this.progressBar_capfifo.Step = 1;
this.progressBar_capfifo.Style = System.Windows.Forms.ProgressBarStyle.Continuous;
this.progressBar_capfifo.TabIndex = 15;
//
// label_capfifo
//
this.label_capfifo.AutoSize = true;
@ -1462,6 +1436,41 @@
this.pb_rxsignal.TabIndex = 17;
this.pb_rxsignal.TabStop = false;
//
// progressBar_capfifo
//
this.progressBar_capfifo.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(255)))), ((int)(((byte)(192)))), ((int)(((byte)(128)))));
this.progressBar_capfifo.Location = new System.Drawing.Point(658, 642);
this.progressBar_capfifo.Name = "progressBar_capfifo";
this.progressBar_capfifo.Size = new System.Drawing.Size(304, 18);
this.progressBar_capfifo.Step = 1;
this.progressBar_capfifo.Style = System.Windows.Forms.ProgressBarStyle.Continuous;
this.progressBar_capfifo.TabIndex = 15;
//
// progressBar_fifo
//
this.progressBar_fifo.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(128)))), ((int)(((byte)(255)))), ((int)(((byte)(255)))));
this.progressBar_fifo.Location = new System.Drawing.Point(658, 618);
this.progressBar_fifo.Maximum = 20;
this.progressBar_fifo.Name = "progressBar_fifo";
this.progressBar_fifo.Size = new System.Drawing.Size(304, 18);
this.progressBar_fifo.Step = 11;
this.progressBar_fifo.Style = System.Windows.Forms.ProgressBarStyle.Continuous;
this.progressBar_fifo.TabIndex = 13;
//
// vu_cap
//
this.vu_cap.Location = new System.Drawing.Point(479, 87);
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.Name = "vu_pb";
this.vu_pb.Size = new System.Drawing.Size(100, 10);
this.vu_pb.TabIndex = 19;
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
@ -1485,7 +1494,7 @@
this.ForeColor = System.Drawing.SystemColors.ControlText;
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
this.Name = "Form1";
this.Text = "QO-100 NB Transponder HS Multimedia Modem AMSAT-DL V0.50 by DJ0ABR";
this.Text = "AMSAT-DL Multimedia HS Modem V0.51 by DJ0ABR";
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.Form1_FormClosing);
this.statusStrip1.ResumeLayout(false);
this.statusStrip1.PerformLayout();
@ -1648,6 +1657,7 @@
private System.Windows.Forms.ComboBox cb_safemode;
private KmProgressBar vu_cap;
private KmProgressBar vu_pb;
private System.Windows.Forms.ToolStripStatusLabel toolStrip_Type;
}
}

View File

@ -397,6 +397,22 @@ namespace oscardata
}
}
int lasttype = -1;
void showType(int rxtype)
{
if(rxtype != lasttype)
{
if (rxtype == statics.Image) toolStrip_Type.Text = "RX: IMAGE";
if (rxtype == statics.AsciiFile) toolStrip_Type.Text = "RX: TEXT";
if (rxtype == statics.HTMLFile) toolStrip_Type.Text = "RX: HTML/Web";
if (rxtype == statics.BinaryFile) toolStrip_Type.Text = "RX: BINARY";
if (rxtype == statics.BERtest) toolStrip_Type.Text = "RX: BER TEST";
if (rxtype == statics.Audio) toolStrip_Type.Text = "RX: DV-Audio";
if (rxtype == -1) toolStrip_Type.Text = "no RX";
lasttype = rxtype;
}
}
// RX timer
int rxstat = 0;
int speed;
@ -426,6 +442,8 @@ namespace oscardata
Byte[] rxdata = new byte[rxd.Length - 10];
Array.Copy(rxd, 10, rxdata, 0, rxd.Length - 10);
showType(rxtype);
//Console.WriteLine("minfo:" + minfo + " data:" + rxdata[0].ToString("X2") + " " + rxdata[1].ToString("X2"));
// ========= receive file ==========
@ -578,7 +596,15 @@ namespace oscardata
if (statics.CAPfifousage > 50) progressBar_capfifo.ForeColor = Color.Red; else progressBar_capfifo.ForeColor = Color.Green;
// Show RX Status LEDs
if (statics.RXlevelDetected == 1) pb_rxsignal.BackgroundImage = Resources.greenmarker; else pb_rxsignal.BackgroundImage = Resources.redmarker;
if (statics.RXlevelDetected == 1)
{
pb_rxsignal.BackgroundImage = Resources.greenmarker;
}
else
{
pb_rxsignal.BackgroundImage = Resources.redmarker;
showType(-1);
}
if (statics.RXinSync == 1 && statics.RXlevelDetected == 1) pb_rxsync.BackgroundImage = Resources.greenmarker; else pb_rxsync.BackgroundImage = Resources.redmarker;
// update rx,tx level progress bar

View File

@ -137,7 +137,7 @@
AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj00LjAuMC4w
LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACZTeXN0
ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAABw
FwAAAk1TRnQBSQFMAgEBDQEAAUgBAgFIAQIBEAEAARABAAT/AQkBAAj/AUIBTQE2AQQGAAE2AQQCAAEo
FwAAAk1TRnQBSQFMAgEBDQEAAaABAgGgAQIBEAEAARABAAT/AQkBAAj/AUIBTQE2AQQGAAE2AQQCAAEo
AwABQAMAAUADAAEBAQABCAYAARAYAAGAAgABgAMAAoABAAGAAwABgAEAAYABAAKAAgADwAEAAcAB3AHA
AQAB8AHKAaYBAAEzBQABMwEAATMBAAEzAQACMwIAAxYBAAMcAQADIgEAAykBAANVAQADTQEAA0IBAAM5
AQABgAF8Af8BAAJQAf8BAAGTAQAB1gEAAf8B7AHMAQABxgHWAe8BAAHWAucBAAGQAakBrQIAAf8BMwMA
@ -241,11 +241,13 @@
</value>
</data>
<data name="richTextBox1.Text" xml:space="preserve">
<value>QO-100 Multimedia High Speed Modem (Linux &amp; Windows)
<value>Amsat-DL Multimedia High Speed Modem (Linux &amp; Windows)
(c) DJ0ABR, Kurt Moraw, Germany https://dj0abr.de/
Author: (c) DJ0ABR, Kurt Moraw, Germany https://dj0abr.de/
Wiki: https://hsmodem.dj0abr.de/doku.php
License: GPL V2 or later
Amsat-DL: https://amsat-dl.org/
Open Source: https://github.com/dj0abr/SSB_HighSpeed_Modem
Open Source: https://github.com/amsat-dl
3rd Party, Credits and Licensing:

View File

@ -189,7 +189,7 @@ namespace oscardata
if (!autoRXnum)
blockidx = rxfrmnum;
Console.WriteLine("minfo:" + minfo + " framenum:" + rxfrmnum + " blockidx:" + blockidx);
//Console.WriteLine("minfo:" + minfo + " framenum:" + rxfrmnum + " blockidx:" + blockidx);
Array.Copy(rxd, 10, rxdata, 0, rxd.Length - 10);
return true;

View File

@ -175,7 +175,7 @@ namespace oscardata
}
static int panelw = 75, panelh = 75;
static int maxdrawanz = 160;
static int maxdrawanz = 350;//160;
static int drawanz = 0;
static Bitmap bm;
static void drawBitmap(Int32 re, Int32 im)