This commit is contained in:
Kurt 2021-01-18 15:36:29 +01:00
parent 46faf838bc
commit 43cea876bb
34 changed files with 335 additions and 1977 deletions

View File

@ -3,7 +3,7 @@ The purpose of this project is to transfer data (pictures...) via a 2,7kHz SSB c
Now also including RTTY mode.
# this is work in progress
Version 0.64
Version 0.72
Windows 10 (should work on Win7, not tested)
linux Desktop PC,
Odroid SBC
@ -18,7 +18,7 @@ Raspberry 4 (3B+)
* Odroid C2 ... working
* Odroid C4 ... working
* Raspberry: Raspian OS ist NOT working, instead Ubuntu 64bit is required
* Raspberry: Raspian OS ist NOT working, instead Ubuntu 64bit is required. Or use the Beta Rapi-IO-64bit
* Application Software "oscardata.exe" running on Windows, Linux, (possibly MAC-OS, not tested)
@ -29,11 +29,12 @@ this software uses these programs:
* 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)
* portaudio: https://github.com/PortAudio/portaudio
# 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
https://hsmodem.dj0abr.de (Download section)
# building the software for Linux

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -760,8 +760,8 @@ item: Install File
Flags=0000000010000010
end
item: Install File
Source=c:\tmp\WinRelease\libsoundio.dll
Destination=%MAINDIR%\libsoundio.dll
Source=c:\tmp\WinRelease\portaudio_x86.dll
Destination=%MAINDIR%\portaudio_x86.dll
Flags=0000000010000010
end
item: Install File

View File

@ -29,4 +29,5 @@ default: $(OBJ)
clean:
rm -f *.o
rm -f libkmaudio/*.o
rm -f libkmaudio/*.o

View File

@ -92,7 +92,6 @@ void playAudioPCM(char* fn, int destination)
{
int to = 4000;
int res;
//while ((res = io_ls_fifo_usedspace()) > 10000)
while ((res = io_fifo_usedspace(voice_pbidx)) > 10000)
{
if (--to == 0)

View File

@ -88,14 +88,18 @@ int marker = 1;
int init_voice_result = 0;
// number of audio device in libkmaudio
int io_capidx = 0;
int io_pbidx = 0;
int voice_capidx = 0;
int voice_pbidx = 0;
int io_capidx = -1;
int io_pbidx = -1;
int voice_capidx = -1;
int voice_pbidx = -1;
int safemode = 0;
int sendIntro = 0;
char mycallsign[21];
char myqthloc[11];
char myname[21];
int main(int argc, char* argv[])
{
int opt = 0;
@ -239,7 +243,7 @@ int main(int argc, char* argv[])
{
// loop voice mic to LS, and record into PCM file
float f[1100];
while (1)
while (keeprunning)
{
int anz = kmaudio_readsamples(voice_capidx, f, 1000, micvol,0);
if (anz > 0)
@ -324,7 +328,8 @@ typedef struct {
} SPEEDRATE;
// AudioRate, TX-Resampler, RX-Resampler/4, bit/symbol, Codec-Rate
SPEEDRATE sr[11] = {
#define NUMSPEEDMODES 11
SPEEDRATE sr[NUMSPEEDMODES] = {
// BPSK modes
{48000, 40,10, 1, 1200, 800},
{48000, 20, 5, 1, 2400, 2000},
@ -351,6 +356,8 @@ void startModem()
close_dsp();
close_rtty();
speedmode = set_speedmode;
if (speedmode < 0 || speedmode >= NUMSPEEDMODES)
speedmode = 4;
bitsPerSymbol = sr[speedmode].bpsym;
constellationSize = (1 << bitsPerSymbol); // QPSK=4, 8PSK=8
@ -398,12 +405,32 @@ void initVoice()
float f = 0.0f;
io_saveStream(&f, 1); // close recording
close_voiceproc();
close_stream(voice_capidx);
close_stream(voice_pbidx);
}
else
{
int srate = VOICE_SAMPRATE;
voice_capidx = kmaudio_startCapture(micDeviceName, VOICE_SAMPRATE);
voice_pbidx = kmaudio_startPlayback(lsDeviceName, VOICE_SAMPRATE);
// voice always runs with 48000 with one exception:
// if it is used for monitoring only and the digital audio
// stream runs with 44100, then also the monitoring voice audio
// must runs with 44100
if (VoiceAudioMode == VOICEMODE_LISTENAUDIOIN && caprate == 44100)
srate = 44100;
voice_capidx = kmaudio_startCapture(micDeviceName, srate);
if (voice_capidx == -1)
{
printf("Voice CAP: cannot open device: %s\n", micDeviceName);
return;
}
voice_pbidx = kmaudio_startPlayback(lsDeviceName, srate);
if (voice_pbidx == -1)
{
printf("Voice PB: cannot open device: %s\n", lsDeviceName);
return;
}
init_voiceproc();
}
}
@ -439,12 +466,27 @@ void io_setAudioDevices(uint8_t pbvol, uint8_t capvol, uint8_t announce, uint8_t
}
}
uint8_t *getDevList(int* plen)
{
uint8_t* txdata = io_getAudioDevicelist(plen);
txdata[0] = 3; // ID of this UDP message
txdata[1] = (io_capidx != -1 && devlist[io_capidx].working) ? '1' : '0';
txdata[2] = (io_pbidx != -1 && devlist[io_pbidx].working) ? '1' : '0';
txdata[3] = (voice_capidx != -1 && devlist[voice_capidx].working) ? '1' : '0';
txdata[4] = (voice_pbidx != -1 && devlist[voice_pbidx].working) ? '1' : '0';
return txdata;
}
// called from UDP RX thread for Broadcast-search from App
void bc_rxdata(uint8_t* pdata, int len, struct sockaddr_in* rxsock)
{
static uint64_t lastms = 0; // time of last received BC message
uint64_t actms = getms();
if (len > 0 && pdata[0] == 0x3c)
{
/* searchmodem message received
@ -462,6 +504,9 @@ void bc_rxdata(uint8_t* pdata, int len, struct sockaddr_in* rxsock)
* 9 ... unused
* 10 .. 109 ... PB device name
* 110 .. 209 ... CAP device name
* 210 .. 229 ... Callsign
* 230 .. 239 ... qthloc
* 240 .. 259 ... Name
*/
char rxip[20];
@ -491,7 +536,7 @@ void bc_rxdata(uint8_t* pdata, int len, struct sockaddr_in* rxsock)
// 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);
uint8_t* txdata = getDevList(&alen);
sendUDP(appIP, UdpDataPort_ModemToApp, txdata, alen);
}
else
@ -503,13 +548,24 @@ void bc_rxdata(uint8_t* pdata, int len, struct sockaddr_in* rxsock)
// 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);
uint8_t* txdata = getDevList(&alen);
sendUDP(appIP, UdpDataPort_ModemToApp, txdata, alen);
}
else
return;
}
memcpy(mycallsign, pdata + 210, sizeof(mycallsign));
mycallsign[sizeof(mycallsign) - 1] = 0;
memcpy(myqthloc, pdata + 230, sizeof(myqthloc));
myqthloc[sizeof(myqthloc) - 1] = 0;
memcpy(myname, pdata + 240, sizeof(myname));
myname[sizeof(myname) - 1] = 0;
//printf("<%s> <%s> <%s>\n", mycallsign, myqthloc, myname);
//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];
@ -629,6 +685,18 @@ void appdata_rxdata(uint8_t* pdata, int len, struct sockaddr_in* rxsock)
//printf("LS:<%s> MIC:<%s> Mode:%d codec:%d\n", lsDeviceName, micDeviceName, VoiceAudioMode, codec);
init_voice = 1;
if (!strcmp(micDeviceName, captureDeviceName))
{
printf("capture device already in use, ignoring: %s\n", micDeviceName);
init_voice = 0;
}
if (!strcmp(lsDeviceName, playbackDeviceName))
{
printf("playback device already in use, ignoring: %s\n", lsDeviceName);
init_voice = 0;
}
return;
}
@ -734,10 +802,11 @@ void appdata_rxdata(uint8_t* pdata, int len, struct sockaddr_in* rxsock)
// one frame has 258 bytes, so we need for 6s: 6* ((caprate/txinterpolfactor) * bitsPerSymbol / 8) /258 + 1 frames
toGR_sendData(pdata + 2, type, minfo,0);
int numframespreamble = 6 * ((caprate / txinterpolfactor) * bitsPerSymbol / 8) / 258 + 1;
if (type == 1)// BER Test
numframespreamble = 1;
//if (type == 1)// BER Test
// numframespreamble = 1;
for (int i = 0; i < numframespreamble; i++)
toGR_sendData(pdata + 2, type, minfo,1);
sendStationInfo();
}
else if ((len - 2) < PAYLOADLEN)
{
@ -781,11 +850,29 @@ void toGR_sendData(uint8_t* data, int type, int status, int repeat)
int len = 0;
uint8_t* txdata = Pack(data, type, status, &len, repeat);
//showbytestring((char *)"BERtx: ", txdata, len);
//showbytestring((char *)"TX: ", txdata, len);
if (txdata != NULL) sendToModulator(txdata, len);
}
void sendStationInfo()
{
uint8_t payload[PAYLOADLEN];
memcpy(payload, mycallsign, 20);
memcpy(payload+20, myqthloc, 10);
memcpy(payload+30, myname, 20);
int len = 0;
uint8_t* txdata = Pack(payload, 7, 1, &len, 1);
//showbytestring((char *)"TX Userinfo: ", txdata, len);
for (int i = 0; i < 2; i++)
{
if (txdata != NULL) sendToModulator(txdata, len);
}
}
// called by liquid demodulator for received data
void GRdata_rxdata(uint8_t* pdata, int len, struct sockaddr_in* rxsock)
{
@ -797,6 +884,7 @@ void GRdata_rxdata(uint8_t* pdata, int len, struct sockaddr_in* rxsock)
if (pl != NULL)
{
// complete frame received
//printf("type:%d\n", pl[0]);
// send payload to app
uint8_t txpl[PAYLOADLEN + 10 + 1];
memcpy(txpl + 1, pl, PAYLOADLEN + 10);
@ -862,7 +950,7 @@ void GRdata_rxdata(uint8_t* pdata, int len, struct sockaddr_in* rxsock)
rx_in_sync = 0;
if (speedmode < 10)
{
printf("no signal detected, reset RX modem\n");
//printf("no signal detected, reset RX modem\n");
resetModem();
}
lasttime = acttm;

View File

@ -3,6 +3,7 @@
#ifdef _WIN32
#define _WIN32_
// ignore senseless warnings invented by M$ to confuse developers
// I love LINUX :-) which works 100000x better than Windows
#pragma warning( disable : 4091 )
#pragma warning( disable : 4003 )
#else
@ -230,6 +231,7 @@ void clear_rtty_txfifo();
void fmtest();
void rtty_init_pipes();
void initVoice();
void sendStationInfo();
extern int speedmode;

View File

@ -179,13 +179,33 @@ uint8_t* io_getAudioDevicelist(int* len);
*/
uint8_t kmaudio_maxlevel(int id);
/*
* closes a stream which was started by
* kmaudio_startCapture or kmaudio_startPlayback
* id ... stream ID which was returned by kmaudio_startCapture or kmaudio_startPlayback
*/
void close_stream(int id);
/*
* handle the FIFO which is used to buffer audio data
* pipenum ... stream ID which was returned by kmaudio_startCapture or kmaudio_startPlayback
* IMPORTANT: this information MUST be used to synchonize the data flow into
* the fifo. The speed is always defined by the audio sample rate
* by checking the fifo an application knows when it has to put more audio samples
* into the fifo
*/
// returns number of remaining elements (audio 16 bit short values)
int io_fifo_freespace(int pipenum);
// returns number of used elements (audio 16 bit short values)
int io_fifo_usedspace(int pipenum);
void io_fifo_clear(int pipenum);
// like before, but returns a number between 0 and 100 %
int io_fifo_usedpercent(int pipenum);
// clear the fifo
void io_fifo_clear(int pipenum);
// -------- functions for internal use only --------
@ -237,6 +257,8 @@ uint64_t getms();
void init_maxarray();
void kmaudio_detectDropouts(int id);
int io_read_fifo_num_short(int pipenum, int16_t* data, int num);
void close_capture_stream(int idx);
void close_playback_stream(int idx);
extern DEVLIST devlist[MAXDEVICES];
extern int devanz;

View File

@ -40,6 +40,15 @@ int recordCallback(const void* inputBuffer, void* outputBuffer,
PaStreamCallbackFlags statusFlags,
void* userData);
void close_capture_stream(int idx)
{
if (devlist[idx].capStream != NULL)
{
Pa_CloseStream(devlist[idx].capStream);
devlist[idx].capStream = NULL;
}
}
int kmaudio_startCapture(char* devname, int samprate)
{
printf("Start request for CAP stream:%s\n", devname);
@ -59,12 +68,8 @@ int kmaudio_startCapture(char* devname, int samprate)
devlist[idx].working = 0;
if (devlist[idx].capStream != NULL)
{
printf("Closing old CAP stream:%s [%d]\n", devname, idx);
Pa_CloseStream(devlist[idx].capStream);
devlist[idx].capStream = NULL;
}
close_capture_stream(idx);
printf("Starting CAP stream:%s [%d]\n", devname, idx);
io_fifo_clear(idx);

View File

@ -112,6 +112,15 @@ void overflow_callback(struct SoundIoInStream* instream)
printf("overflow %d\n", ++count);
}
void close_capture_stream(int idx)
{
if (devlist[idx].instream != NULL)
{
soundio_instream_destroy(devlist[idx].instream);
devlist[idx].instream = NULL;
}
}
int kmaudio_startCapture(char* devname, int samprate)
{
printf("Start request for CAP stream:%s\n", devname);
@ -127,12 +136,8 @@ int kmaudio_startCapture(char* devname, int samprate)
if (capdevid == NULL) return -1;
// if an old stream is open, close it
if (devlist[idx].instream != NULL)
{
printf("Closing old CAP stream:%s [%d]\n", devname, idx);
soundio_instream_destroy(devlist[idx].instream);
devlist[idx].instream = NULL;
}
close_capture_stream(idx);
printf("Starting CAP stream:%s [%d]\n", devname, idx);
io_fifo_clear(idx);

View File

@ -82,6 +82,8 @@ void init_pipes()
// ignore data if the fifo is full
void io_write_fifo(int pipenum, float sample)
{
if (pipenum < 0 || pipenum >= NUM_OF_PIPES) return;
LOCK(pipenum);
if (((io_wridx[pipenum] + 1) % AUDIO_FIFOFLEN) == io_rdidx[pipenum])
{
@ -98,6 +100,8 @@ void io_write_fifo(int pipenum, float sample)
void io_write_fifo_short(int pipenum, int16_t sample)
{
if (pipenum < 0 || pipenum >= NUM_OF_PIPES) return;
LOCK(pipenum);
if (((io_wridx[pipenum] + 1) % AUDIO_FIFOFLEN) == io_rdidx[pipenum])
{
@ -114,6 +118,8 @@ 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;
LOCK(pipenum);
if (io_rdidx[pipenum] == io_wridx[pipenum])
@ -136,6 +142,8 @@ int io_read_fifo(int pipenum, float* data)
// if num elems not avail, return all what fifo has stored
int io_read_fifo_num(int pipenum, float* data, int num)
{
if (pipenum < 0 || pipenum >= NUM_OF_PIPES) return 0;
LOCK(pipenum);
int elemInFifo = (io_wridx[pipenum] + AUDIO_FIFOFLEN - io_rdidx[pipenum]) % AUDIO_FIFOFLEN;
@ -166,6 +174,8 @@ int io_read_fifo_num(int pipenum, float* data, int num)
int io_read_fifo_num_short(int pipenum, int16_t* data, int num)
{
if (pipenum < 0 || pipenum >= NUM_OF_PIPES) return 0;
LOCK(pipenum);
int elemInFifo = (io_wridx[pipenum] + AUDIO_FIFOFLEN - io_rdidx[pipenum]) % AUDIO_FIFOFLEN;
@ -193,11 +203,15 @@ int io_read_fifo_num_short(int pipenum, int16_t* data, int num)
void io_fifo_clear(int pipenum)
{
if (pipenum < 0 || pipenum >= NUM_OF_PIPES) return;
io_wridx[pipenum] = io_rdidx[pipenum] = 0;
}
int io_fifo_freespace(int pipenum)
{
if (pipenum < 0 || pipenum >= NUM_OF_PIPES) return 0;
int freebuf = 0;
LOCK(pipenum);
@ -211,6 +225,8 @@ int io_fifo_freespace(int pipenum)
int io_fifo_elems_avail(int pipenum)
{
if (pipenum < 0 || pipenum >= NUM_OF_PIPES) return 0;
int elems = 0;
LOCK(pipenum);

View File

@ -235,15 +235,17 @@ int getRealSamprate(int idx)
// build string of audio device name, to be sent to application as response to Broadcast search
// starting with PB devices, sperarator ^, capture devices
// separator between devices: ~
// the first character is 0 or 1 and does not belong to the device name
// it shows if this device was sucessfully started and is currently running (="1")
#define MAXDEVSTRLEN (MAXDEVICES * (MAXDEVNAMELENGTH + 2) + 10)
uint8_t io_devstring[MAXDEVSTRLEN];
void io_buildAudioDevString()
{
memset(io_devstring, 0, sizeof(io_devstring));
io_devstring[0] = ' '; // placeholder for ID for this UDP message
io_devstring[0] = ' '; // placeholder for other data
io_devstring[1] = ' ';
io_devstring[2] = ' ';
io_devstring[3] = ' ';
io_devstring[4] = ' ';
// playback devices
for (int i = 0; i < devanz; i++)
@ -256,7 +258,6 @@ void io_buildAudioDevString()
}
if (devlist[i].in_out == 1)
{
strcat((char*)io_devstring, devlist[i].working?"1":"0");
strcat((char*)io_devstring, devlist[i].name);
strcat((char*)io_devstring, "~"); // audio device separator
}
@ -275,15 +276,12 @@ void io_buildAudioDevString()
}
if (devlist[i].in_out == 0)
{
strcat((char*)io_devstring, devlist[i].working ? "1" : "0");
strcat((char*)io_devstring, devlist[i].name);
strcat((char*)io_devstring, "~"); // audio device separator
}
}
//printf("<%s>\n", (char *)io_devstring);
io_devstring[0] = 3; // ID for this message
}
uint8_t* io_getAudioDevicelist(int* len)

View File

@ -3,6 +3,21 @@
void getMax(int id, float fv);
void close_stream(int id)
{
#ifdef WIN32
if (devlist[id].capStream != NULL)
close_capture_stream(id);
if (devlist[id].pbStream != NULL)
close_playback_stream(id);
#else
if (devlist[id].instream != NULL)
close_capture_stream(id);
if (devlist[id].outstream != NULL)
close_playback_stream(id);
#endif
}
/*
* reads len samples from device id into psamp
* returns: number of values written to psamp , -1=error
@ -124,7 +139,6 @@ uint8_t kmaudio_maxlevel(int id)
void kmaudio_detectDropouts(int id)
{
int dropout = 0;
int stat = 0;
int drlen = 0;

View File

@ -42,6 +42,15 @@ int playCallback(const void* inputBuffer,
PaStreamCallbackFlags statusFlags,
void* userData);
void close_playback_stream(int idx)
{
if (devlist[idx].pbStream != NULL)
{
Pa_CloseStream(devlist[idx].pbStream);
devlist[idx].pbStream = NULL;
}
}
int kmaudio_startPlayback(char* devname, int samprate)
{
printf("Start request for PB stream:%s\n", devname);
@ -61,12 +70,7 @@ int kmaudio_startPlayback(char* devname, int samprate)
devlist[idx].working = 0;
if (devlist[idx].pbStream != NULL)
{
printf("Closing old PB stream:%s [%d]\n", devname, idx);
Pa_CloseStream(devlist[idx].pbStream);
devlist[idx].pbStream = NULL;
}
close_playback_stream(idx);
printf("Starting PB stream:%s [%d]\n", devname, idx);

View File

@ -136,6 +136,15 @@ void underflow_callback(struct SoundIoOutStream* outstream)
printf("underflow %d\n", count++);
}
void close_playback_stream(int idx)
{
if (devlist[idx].outstream != NULL)
{
soundio_outstream_destroy(devlist[idx].outstream);
devlist[idx].outstream = NULL;
}
}
int kmaudio_startPlayback(char* devname, int samprate)
{
printf("Start request for PB stream:%s\n", devname);
@ -150,13 +159,7 @@ int kmaudio_startPlayback(char* devname, int samprate)
char* pbdevid = getDevID(devname, 1, &idx);
if (pbdevid == NULL) return -1;
// if an old stream is open, close it
if (devlist[idx].outstream != NULL)
{
printf("Closing old PB stream:%s [%d]\n", devname, idx);
soundio_outstream_destroy(devlist[idx].outstream);
devlist[idx].outstream = NULL;
}
close_playback_stream(idx);
printf("Starting PB stream:%s [%d]\n", devname, idx);

View File

@ -202,12 +202,14 @@ 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;
sleep_ms(10);
if (++to >= 400) break; // give up after 4s
}
if (marker)

File diff suppressed because it is too large Load Diff

View File

@ -1,665 +0,0 @@
/*
* 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.
*
* soundio.c ... interface to libsoundio
*
*/
#include "hsmodem.h"
void io_cap_write_fifo(float sample);
#define MAXAUDIODEVICES 50
struct SoundIo* soundio = NULL;
struct SoundIoDevice* io_pb_device = NULL;
struct SoundIoDevice* io_cap_device = NULL;
struct SoundIoInStream* instream = NULL;
struct SoundIoOutStream* outstream = NULL;
typedef struct _AUDIODEV_ {
int in_out = 0; // 0=in, 1=out
char name[1000] = { 0 };
char id[1000] = { 0 };
int minsamprate = 44100;
int maxsamprate = 48000;
int stereo_mono = 2; // 1=mono, 2=stereo
} AUDIODEV;
AUDIODEV audiodev[MAXAUDIODEVICES];
int audiodevidx = 0;
void print_devs()
{
printf("\n ==== AUDIO devices ====\n");
for (int i = 0; i < audiodevidx; i++)
{
if(i>0) printf(" -----------------\n");
printf("Name: %s\n", audiodev[i].name);
printf("ID : %s\n", audiodev[i].id);
printf("I/O : %s\n", (audiodev[i].in_out == 0) ? "record":"playback");
printf("Chan: %s\n", (audiodev[i].stereo_mono == 2) ? "stereo" : "mono");
printf("minR: %d\n", audiodev[i].minsamprate);
printf("maxR: %d\n", audiodev[i].maxsamprate);
}
printf("\n =======================\n");
}
static void get_channel_layout(const struct SoundIoChannelLayout* layout)
{
if (layout->name)
{
if (strstr(layout->name, "ereo"))
audiodev[audiodevidx].stereo_mono = 2;
if (strstr(layout->name, "ono"))
audiodev[audiodevidx].stereo_mono = 1;
}
}
int print_device(struct SoundIoDevice* device)
{
if (!device->probe_error)
{
/*#ifdef _WIN32_
// only use raw (exclusive) devices
if (device->is_raw == false) return 0;
#endif*/
// ignore if exists
for (int i = 0; i < audiodevidx; i++)
if (!strcmp(device->id, audiodev[i].id)) return 0;
if (strstr(device->name, "onitor")) return 0;
strncpy(audiodev[audiodevidx].id, device->id, 999);
audiodev[audiodevidx].id[999] = 0;
strncpy(audiodev[audiodevidx].name, device->name, 999);
audiodev[audiodevidx].name[999] = 0;
for (int i = 0; i < device->layout_count; i++)
get_channel_layout(&device->layouts[i]);
for (int i = 0; i < device->sample_rate_count; i++)
{
struct SoundIoSampleRateRange* range = &device->sample_rates[i];
if (range->min < audiodev[audiodevidx].minsamprate)
audiodev[audiodevidx].minsamprate = range->min;
if (range->max > audiodev[audiodevidx].maxsamprate)
audiodev[audiodevidx].maxsamprate = range->max;
}
if (audiodev[audiodevidx].minsamprate > 44100)
return 0;
if (audiodev[audiodevidx].maxsamprate < 48000)
return 0;
return 1;
}
return 0;
}
static int scan_devices(struct SoundIo* soundio)
{
audiodevidx = 0;
for (int i = 0; i < soundio_input_device_count(soundio); i++)
{
struct SoundIoDevice* device = soundio_get_input_device(soundio, i);
if (print_device(device) == 1)
{
audiodev[audiodevidx].in_out = 0;
audiodevidx++;
}
soundio_device_unref(device);
}
for (int i = 0; i < soundio_output_device_count(soundio); i++)
{
struct SoundIoDevice* device = soundio_get_output_device(soundio, i);
if (print_device(device) == 1)
{
audiodev[audiodevidx].in_out = 1;
audiodevidx++;
}
soundio_device_unref(device);
}
return 0;
}
// build string of audio device name, to be sent to application as response to Broadcast search
// starting with PB devices, sperarator ^, capture devices
// separator between devices: ~
uint8_t io_devstring[MAXDEVSTRLEN + 100];
void io_buildUdpAudioList()
{
memset(io_devstring, 0, sizeof(io_devstring));
io_devstring[0] = ' '; // placeholder for ID for this UDP message
io_devstring[1] = '0' + init_audio_result;
io_devstring[2] = '0' + init_voice_result;
// playback devices
for (int i = 0; i < audiodevidx; i++)
{
if (audiodev[i].in_out == 1)
{
strcat((char*)io_devstring, audiodev[i].name);
strcat((char*)io_devstring, "~"); // audio device separator
}
}
strcat((char*)(io_devstring + 1), "^"); // PB, CAP separator
// capture devices
for (int i = 0; i < audiodevidx; i++)
{
if (audiodev[i].in_out == 0)
{
strcat((char*)io_devstring, audiodev[i].name);
strcat((char*)io_devstring, "~"); // audio device separator
}
}
io_devstring[0] = 3; // ID for this UDP message
}
uint8_t* io_getAudioDevicelist(int* len)
{
// update Status
io_devstring[1] = '0' + init_audio_result;
io_devstring[2] = '0' + init_voice_result;
*len = strlen((char*)(io_devstring + 1)) + 1;
return io_devstring;
}
void io_readAudioDevices()
{
if (soundio == NULL) return;
// to get actual data
soundio_flush_events(soundio);
scan_devices(soundio); // read devices
io_buildUdpAudioList();
//print_devs();
}
char* getDevID(char* devname, int io)
{
for (int i = 0; i < audiodevidx; i++)
{
if (!strcmp(devname, audiodev[i].name) && io == audiodev[i].in_out)
{
return audiodev[i].id;
}
}
return NULL;
}
int min_int(int a, int b)
{
return (a < b) ? a : b;
}
void read_callback(struct SoundIoInStream* instream, int frame_count_min, int frame_count_max)
{
int err;
//printf("cap: %d %d\n", frame_count_min, frame_count_max);
//int chans = instream->layout.channel_count;
struct SoundIoChannelArea* areas;
// samples are in areas.ptr
int frames_left = frame_count_max; // take all
while (1)
{
int frame_count = frames_left;
if ((err = soundio_instream_begin_read(instream, &areas, &frame_count)))
{
fprintf(stderr, "begin read error: %s", soundio_strerror(err));
exit(1);
}
if (!frame_count)
break;
for (int frame = 0; frame < frame_count; frame += 1)
{
for (int ch = 0; ch < instream->layout.channel_count; ch += 1)
{
int16_t rxdata;
memcpy(&rxdata, areas[ch].ptr, instream->bytes_per_sample);
areas[ch].ptr += areas[ch].step;
if (ch == 0)
{
float f = rxdata;
f /= 32768;
f *= softwareCAPvolume;
io_cap_write_fifo(f);
}
}
}
//measure_speed_bps(frame_count);
if ((err = soundio_instream_end_read(instream)))
{
fprintf(stderr, "end read error: %s", soundio_strerror(err));
exit(1);
}
frames_left -= frame_count;
if (frames_left <= 0)
break;
}
}
/*
void read_callback(struct SoundIoInStream* instream, int frame_count_min, int frame_count_max)
{
int err;
//printf("cap: %d %d\n", frame_count_min, frame_count_max);
// bytes_per_frame == 4 because we use float
// instream->bytes_per_sample/bytes_per_frame = 1 (mono) or 2 (stereo)
int chans = instream->layout.channel_count;
struct SoundIoChannelArea* areas;
// samples are in areas.ptr
int frames_left = frame_count_max; // take all
while (1)
{
int frame_count = frames_left;
if ((err = soundio_instream_begin_read(instream, &areas, &frame_count)))
{
fprintf(stderr, "begin read error: %s", soundio_strerror(err));
exit(1);
}
if (!frame_count)
break;
// do something with the data in *area.ptr
// take a float every chans*4 Bytes
int16_t* samples = (int16_t*)(areas[0].ptr);
int pos = 0;
for (int i = 0; i < frame_count; i++)
{
float f = samples[pos];
f /= 32768;
f *= softwareCAPvolume;
io_cap_write_fifo(f);
pos += chans;
}
//measure_speed_bps(frame_count);
if ((err = soundio_instream_end_read(instream))) {
fprintf(stderr, "end read error: %s", soundio_strerror(err));
exit(1);
}
frames_left -= frame_count;
if (frames_left <= 0)
break;
}
}
*/
void overflow_callback(struct SoundIoInStream* instream)
{
static int count = 0;
printf("overflow %d\n", ++count);
}
#define MAXCAPCHUNKLEN 50000
static void write_callback(struct SoundIoOutStream* outstream, int frame_count_min, int frame_count_max)
{
struct SoundIoChannelArea* areas;
int err;
int frames_left = frame_count_max;
while (1)
{
int frame_count = frames_left;
if ((err = soundio_outstream_begin_write(outstream, &areas, &frame_count)))
{
fprintf(stderr, "unrecoverable stream error: %s\n", soundio_strerror(err));
exit(1);
}
if (!frame_count)
break;
float f[MAXCAPCHUNKLEN];
int fiforet = io_pb_read_fifo_num(f, frame_count);
if (fiforet == 0)
{
// elements not available, fill with zeroes
//printf("not enough data, send zeroes\n");
memset(f, 0, sizeof(float) * frame_count);
}
const struct SoundIoChannelLayout* layout = &outstream->layout;
for (int frame = 0; frame < frame_count; frame++)
{
for (int channel = 0; channel < layout->channel_count; channel++)
{
write_sample_s16ne(areas[channel].ptr, f[frame]);
areas[channel].ptr += areas[channel].step;
}
}
if ((err = soundio_outstream_end_write(outstream))) {
if (err == SoundIoErrorUnderflow)
return;
fprintf(stderr, "unrecoverable stream error: %s\n", soundio_strerror(err));
exit(1);
}
frames_left -= frame_count;
if (frames_left <= 0)
break;
}
}
/*
static void write_callback(struct SoundIoOutStream* outstream, int frame_count_min, int frame_count_max)
{
int chans = outstream->layout.channel_count;
struct SoundIoChannelArea* areas;
int err;
int frames_left = min_int(frame_count_max,MAXCAPCHUNKLEN);// frame_count_max;
//printf("\nmin: %d max:%d\n", frame_count_min, frame_count_max);
// we have to write frame_count_max, not less, or we get an underrun
// this has to be written in chunks requested by soundio_outstream_begin_write
float f[MAXCAPCHUNKLEN];
while (1)
{
int frame_count = frames_left;
if ((err = soundio_outstream_begin_write(outstream, &areas, &frame_count))) {
printf("unrecoverable soundio_outstream_begin_write error: %s\n", soundio_strerror(err));
exit(1);
}
if (!frame_count) break; // will normally never happen
//printf("chunk: %d\n", frame_count);
// soundio_outstream_begin_write requested to write frame_count elements
int fiforet = io_pb_read_fifo_num(f, frame_count);
if (fiforet == 0)
{
// elements not available, fill with zeroes
//printf("not enough data, send zeroes\n");
memset(f, 0, sizeof(float) * frame_count);
}
// apply volume
for (int i = 0; i < frame_count; i++)
f[i] *= softwarePBvolume;
// put data into soundio buffer
for (int frame = 0; frame < frame_count; frame++)
{
for (int ch = 0; ch < chans; ch++)
{
int16_t* s = (int16_t*)areas[ch].ptr;
*s = (int16_t)(f[frame] * 32768.0);
areas[ch].ptr += areas[ch].step;
}
}
// and finalize this chunk
if ((err = soundio_outstream_end_write(outstream))) {
if (err == SoundIoErrorUnderflow)
return;
printf("unrecoverable soundio_outstream_end_write error: %s\n", soundio_strerror(err));
exit(1);
}
frames_left -= frame_count;
if (frames_left <= 0)
break;
}
}
*/
void underflow_callback(struct SoundIoOutStream* outstream)
{
static int count = 0;
printf("underflow %d\n", count++);
}
int io_init_sound(char *pbname, char *capname)
{
int err;
init_audio_result = 0;
printf("\n ==== IO INIT AUDIO devices ====\n");
printf("requested: <%s> <%s>\ncapture rate:%d\n",pbname,capname,caprate);
io_close_audio();
// prepare and connect to libsoundio
soundio = soundio_create();
if (!soundio) {
printf("soundio_create: out of memory\n");
return 0;
}
#ifdef _WIN32_
if ((err=soundio_connect_backend(soundio, SoundIoBackendWasapi))) {
printf("soundio_connect: %s\n", soundio_strerror(err));
return 0;
}
#endif
#ifdef _LINUX_
if ((err = soundio_connect(soundio))) {
printf("soundio_connect: %s\n", soundio_strerror(err));
return 0;
}
#endif
io_readAudioDevices();
io_init_pipes();
if (pbname == NULL || capname == NULL || strlen(pbname) < 3 || strlen(capname) < 3) // no devices defined yet
{
printf("no devices specified\n");
return 0;
}
char* pbdevid = getDevID(pbname,1);
if (pbdevid == NULL) return 0;
char* capdevid = getDevID(capname,0);
if (capdevid == NULL) return 0;
// define the capture device
printf("selected CAP device:\nname:%s\nid :%s\n", capname, capdevid);
soundio_flush_events(soundio);
for (int i = 0; i < soundio_input_device_count(soundio); i++)
{
io_cap_device = NULL;
struct SoundIoDevice* device = soundio_get_input_device(soundio, i);
if (strcmp(device->id, capdevid) == 0
#ifdef _WIN32_
&& device->is_raw == true
#endif
)
{
io_cap_device = device;
break;
}
soundio_device_unref(device);
}
if (!io_cap_device)
{
printf("Invalid device id: %s\n", capdevid);
return 0;
}
if (io_cap_device->probe_error)
{
printf("Unable to probe device: %s\n", soundio_strerror(io_cap_device->probe_error));
return 0;
}
// create capture callback
instream = soundio_instream_create(io_cap_device);
if (!instream) {
printf("out of memory\n");
return 0;
}
instream->format = SoundIoFormatS16NE;
instream->sample_rate = caprate;
instream->software_latency = 0.0;
instream->read_callback = read_callback;
instream->overflow_callback = overflow_callback;
instream->userdata = NULL;
if ((err = soundio_instream_open(instream))) {
printf("unable to open input stream: %s", soundio_strerror(err));
return 0;
}
if ((err = soundio_instream_start(instream))) {
fprintf(stderr, "unable to start input device: %s", soundio_strerror(err));
return 0;
}
init_audio_result |= 2;
// the CAP callback is running now
// define the playback device
printf("selected PB device:\nname:%s\nid :%s\n", pbname, pbdevid);
for (int i = 0; i < soundio_output_device_count(soundio); i++)
{
io_pb_device = NULL;
struct SoundIoDevice* device = soundio_get_output_device(soundio, i);
if (strcmp(device->id, pbdevid) == 0
#ifdef _WIN32_
&& device->is_raw == true
#endif
)
{
io_pb_device = device;
break;
}
soundio_device_unref(device);
}
if (!io_pb_device)
{
printf("Invalid device id: %s\n", pbdevid);
return 0;
}
if (io_pb_device->probe_error)
{
printf("Unable to probe device: %s\n", soundio_strerror(io_pb_device->probe_error));
return 0;
}
// create playback callback
outstream = soundio_outstream_create(io_pb_device);
if (!outstream) {
printf("soundio_outstream_create: out of memory\n");
return 0;
}
outstream->format = SoundIoFormatS16NE;
outstream->sample_rate = caprate;
outstream->software_latency = 0.0;
outstream->write_callback = write_callback;
outstream->underflow_callback = underflow_callback;
outstream->userdata = NULL;
if ((err = soundio_outstream_open(outstream))) {
printf("unable to open output stream: %s", soundio_strerror(err));
return 0;
}
if ((err = soundio_outstream_start(outstream))) {
fprintf(stderr, "unable to start output device: %s", soundio_strerror(err));
return 0;
}
init_audio_result |= 1;
printf("==== Audio init finished: %d ====\n", init_audio_result);
return init_audio_result;
}
void io_close_audio()
{
printf("close Audio\n");
if(instream) soundio_instream_destroy(instream);
instream = NULL;
if (outstream) soundio_outstream_destroy(outstream);
outstream = NULL;
if(io_pb_device) soundio_device_unref(io_pb_device);
io_pb_device = NULL;
if (io_cap_device) soundio_device_unref(io_cap_device);
io_cap_device = NULL;
if (soundio) soundio_destroy(soundio);
soundio = NULL;
}
void io_setPBvolume(int v)
{
// the volume comes in % 0..99
softwarePBvolume = ((float)v) / 50.0f;
}
void io_setCAPvolume(int v)
{
// the volume comes in % 0..99
softwareCAPvolume = ((float)v) / 50.0f;
}
// set volume
void io_setVolume(int pbcap, int v)
{
if (pbcap == 0) io_setPBvolume(v);
else io_setCAPvolume(v);
}
void io_setLSvolume(int v)
{
// the volume comes in % 0..99
softwareLSvolume = ((float)v) / 50.0f;
}
void io_setMICvolume(int v)
{
// the volume comes in % 0..99
softwareMICvolume = ((float)v) / 50.0f;
}
void setVolume_voice(int pbcap, int v)
{
}

View File

@ -102,13 +102,11 @@ void UdpRxInit(int *sock, int port, void (*rxfunc)(uint8_t *, int, struct sockad
rxcfg_idx++;
}
#ifdef _LINUX_
void* threadfunction(void* param) {
socklen_t fromlen;
pthread_detach(pthread_self());
#endif
#ifdef _WIN32_
void threadfunction(void* param) {
int fromlen;
@ -116,18 +114,24 @@ void threadfunction(void* param) {
RXCFG rxcfg;
memcpy((uint8_t *)(&rxcfg), (uint8_t *)param, sizeof(RXCFG));
int recvlen;
char rxbuf[256];
const int maxUDPpacketsize = 1024;
char rxbuf[maxUDPpacketsize];
struct sockaddr_in fromSock;
fromlen = sizeof(struct sockaddr_in);
while(*rxcfg.keeprunning)
{
recvlen = recvfrom(*rxcfg.sock, rxbuf, 256, 0, (struct sockaddr *)&fromSock, &fromlen);
recvlen = recvfrom(*rxcfg.sock, rxbuf, maxUDPpacketsize, 0, (struct sockaddr *)&fromSock, &fromlen);
if (recvlen > 0)
{
// data received, send it to callback function
(*rxcfg.rxfunc)((uint8_t *)rxbuf,recvlen, &fromSock);
}
if (recvlen < 0)
{
#ifdef _WIN32_
printf("recvfrom error: %d", WSAGetLastError());
#endif
}
}
#ifdef _LINUX_
pthread_exit(NULL); // self terminate this thread

View File

@ -170,7 +170,6 @@ void sendCodecToModulator(uint8_t *pdata, int len)
while (keeprunning)
{
// we have to check if the TX fifo has enough data. In case of an underrun the Q(8A)PSK signal will be distorted
//int us = io_pb_fifo_usedspace();
int us = io_fifo_usedspace(io_pbidx);
if (us < 20000)
{

Binary file not shown.

Binary file not shown.

View File

@ -37,6 +37,8 @@
this.toolStripStatusLabel = new System.Windows.Forms.ToolStripStatusLabel();
this.ts_ip = new System.Windows.Forms.ToolStripStatusLabel();
this.RXstatus = new System.Windows.Forms.ToolStripStatusLabel();
this.toolStrip_spacer = new System.Windows.Forms.ToolStripStatusLabel();
this.ts_userinfo = new System.Windows.Forms.ToolStripStatusLabel();
this.panel_constel = new System.Windows.Forms.Panel();
this.timer_qpsk = new System.Windows.Forms.Timer(this.components);
this.panel_txspectrum = new System.Windows.Forms.Panel();
@ -253,7 +255,9 @@
this.toolStrip_Type,
this.toolStripStatusLabel,
this.ts_ip,
this.RXstatus});
this.RXstatus,
this.toolStrip_spacer,
this.ts_userinfo});
this.statusStrip1.Location = new System.Drawing.Point(0, 671);
this.statusStrip1.Name = "statusStrip1";
this.statusStrip1.Size = new System.Drawing.Size(1296, 22);
@ -286,6 +290,20 @@
this.RXstatus.Size = new System.Drawing.Size(58, 17);
this.RXstatus.Text = "RX-Status";
//
// toolStrip_spacer
//
this.toolStrip_spacer.Name = "toolStrip_spacer";
this.toolStrip_spacer.Size = new System.Drawing.Size(1156, 17);
this.toolStrip_spacer.Spring = true;
//
// ts_userinfo
//
this.ts_userinfo.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Bold);
this.ts_userinfo.ForeColor = System.Drawing.Color.Blue;
this.ts_userinfo.Name = "ts_userinfo";
this.ts_userinfo.Size = new System.Drawing.Size(16, 17);
this.ts_userinfo.Text = "...";
//
// panel_constel
//
this.panel_constel.BackColor = System.Drawing.Color.AliceBlue;
@ -2268,7 +2286,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.71 by DJ0ABR";
this.Text = "AMSAT-DL Multimedia HS Modem V0.72 by DJ0ABR";
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.Form1_FormClosing);
this.statusStrip1.ResumeLayout(false);
this.statusStrip1.PerformLayout();
@ -2498,6 +2516,8 @@
private System.Windows.Forms.CheckBox cb_rx_autosync;
private System.Windows.Forms.TextBox textBox6;
private System.Windows.Forms.Button button6;
private System.Windows.Forms.ToolStripStatusLabel toolStrip_spacer;
private System.Windows.Forms.ToolStripStatusLabel ts_userinfo;
}
}

View File

@ -44,8 +44,8 @@ namespace oscardata
String old_tsip = "";
bool modemrunning = false;
receivefile recfile = new receivefile();
int last_initAudioStatus;
int last_initVoiceStatus;
int last_initAudioStatus = -1;
int last_initVoiceStatus = -1;
int recordStatus = 0;
int recPhase = 0;
const int Rtty_deftext_anz = 20;
@ -220,8 +220,8 @@ namespace oscardata
{
if (s.Length > 1)
{
cb_audioPB.Items.Add(s.Substring(1));
cb_loudspeaker.Items.Add(s.Substring(1));
cb_audioPB.Items.Add(s);
cb_loudspeaker.Items.Add(s);
}
}
cb_loudspeaker.EndUpdate();
@ -238,8 +238,8 @@ namespace oscardata
{
if (s.Length > 1)
{
cb_audioCAP.Items.Add(s.Substring(1));
cb_mic.Items.Add(s.Substring(1));
cb_audioCAP.Items.Add(s);
cb_mic.Items.Add(s);
}
}
cb_mic.EndUpdate();
@ -315,21 +315,17 @@ namespace oscardata
}
}
// correct entries in the Audio Device Comboboxes if Devices have changed
// correct entries in the Audio Device Comboboxes if devices have changed
void findDevice(ComboBox cb)
{
int pos = -1;
if (cb.Text.Length >= 4)
{
// Device Name starts at Index 3 in the string
String dn = cb.Text.Substring(3);
int anz = cb.Items.Count;
for (int i = 0; i < anz; i++)
{
String name = cb.Items[i].ToString();
name = name.Substring(3);
if (dn == name)
if (cb.Text == cb.Items[i].ToString())
{
pos = i;
break;
@ -349,7 +345,6 @@ namespace oscardata
cb.Text = cb.Items[pos].ToString();
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
save_Setup();
@ -443,6 +438,14 @@ namespace oscardata
//Console.WriteLine("minfo:" + minfo + " data:" + rxdata[0].ToString("X2") + " " + rxdata[1].ToString("X2"));
if (rxtype == statics.Userinfo)
{
String call = statics.ByteArrayToString(rxdata, 0, 20);
String qthloc = statics.ByteArrayToString(rxdata, 20, 10);
String name = statics.ByteArrayToString(rxdata, 30, 20);
ts_userinfo.Text = call + " " + name + " " + qthloc;
}
// ========= receive file ==========
// handle file receive
if (rxtype == statics.Image)
@ -1181,13 +1184,17 @@ namespace oscardata
public String GetMyBroadcastIP()
{
String ip = "255.255.255.255";
/*
// selective BCs fail if the computer has multiple IPs
// therefore use 255.255.255.255
String[] myips = statics.getOwnIPs();
//Console.WriteLine("BClen: " + myips.Length.ToString());
Console.WriteLine("BClen: " + myips.Length.ToString());
// if PC has multiple IPs then use 255.255.255.255
/*for (int i = 0; i < myips.Length; i++)
for (int i = 0; i < myips.Length; i++)
{
Console.WriteLine("ip:" + myips[i]);
}*/
}
if (myips.Length >= 1)
{
statics.MyIP = myips[0];
@ -1199,7 +1206,7 @@ namespace oscardata
ip += ".255";
//Console.WriteLine("BCip: " + ip);
}
}
}*/
return ip;
}
@ -1231,7 +1238,7 @@ namespace oscardata
if (cb_safemode.Text.Contains("medium")) safemode = 2;
else if (cb_safemode.Text.Contains("high")) safemode = 4;
Byte[] txb = new byte[210];
Byte[] txb = new byte[260];
txb[0] = 0x3c; // ID of this message
txb[1] = (Byte)tb_PBvol.Value;
txb[2] = (Byte)tb_CAPvol.Value;
@ -1248,6 +1255,7 @@ namespace oscardata
//Byte[] bpb = statics.StringToByteArray(cb_audioPB.Text);
//Byte[] bcap = statics.StringToByteArray(cb_audioCAP.Text);
// 200 Bytes (from 10..209) name of selected sound device
for (int i=0; i<100; i++)
{
if (i >= bpb.Length)
@ -1261,6 +1269,28 @@ namespace oscardata
txb[i + 110] = bcap[i];
}
// 210 .. 229 = Callsign
Byte[] callarr = statics.StringToByteArray(tb_callsign.Text);
for (int i = 0; i < 20; i++)
{
if (i >= callarr.Length) txb[i+210] = 0;
else txb[i + 210] = callarr[i];
}
// 230 .. 239 = qthloc
Byte[] qtharr = statics.StringToByteArray(tb_myqthloc.Text);
for (int i = 0; i < 10; i++)
{
if (i >= qtharr.Length) txb[i + 230] = 0;
else txb[i+230] = qtharr[i];
}
// 240 .. 259 = Name
Byte[] namearr = statics.StringToByteArray(tb_myname.Text);
for (int i = 0; i < 20; i++)
{
if (i >= namearr.Length) txb[i+240] = 0;
else txb[i + 240] = namearr[i];
}
if (statics.ModemIP == "1.2.3.4")
{
// still searching a modem

View File

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

View File

@ -1,10 +1,5 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace oscardata

View File

@ -23,6 +23,7 @@ namespace oscardata
public static Byte HTMLFile = 4;
public static Byte BinaryFile = 5;
public static Byte Audio = 6;
public static Byte Userinfo = 7;
// the upper values are for internal use
public static Byte ResamplingRate = 16;
@ -185,6 +186,23 @@ namespace oscardata
return enc.GetString(ban);
}
public static string ByteArrayToString(byte[] arr, int offset, int length)
{
Byte[] ba = new byte[arr.Length];
int dst = 0;
for (int i = 0; i < length; i++)
{
if (i >= arr.Length) break;
if (arr[i+ offset] != 0) ba[dst++] = arr[i+ offset];
}
Byte[] ban = new byte[dst];
Array.Copy(ba, ban, dst);
System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding();
return enc.GetString(ban);
}
public static string ByteArrayToStringUtf8(byte[] arr, int offset = 0)
{
Byte[] ba = new byte[arr.Length];

View File

@ -123,8 +123,13 @@ namespace oscardata
searchtimeout = 0;
// message b contains audio devices and init status
//String s = statics.ByteArrayToString(b,0);
String s = statics.ByteArrayToStringUtf8(b, 0);
statics.initAudioStatus = (b[0] == '1') ? 2 : 0;
statics.initAudioStatus |= (b[1] == '1') ? 1 : 0;
statics.initVoiceStatus = (b[2] == '1') ? 2 : 0;
statics.initVoiceStatus |= (b[3] == '1') ? 1 : 0;
//String s = statics.ByteArrayToString(b,4);
String s = statics.ByteArrayToStringUtf8(b, 4);
String[] sa1 = s.Split(new char[] { '^' });
statics.AudioPBdevs = sa1[0].Split(new char[] { '~' });
statics.AudioCAPdevs = sa1[1].Split(new char[] { '~' });
@ -143,18 +148,19 @@ namespace oscardata
// FFT data
if (rxtype == statics.udp_fft)
{
statics.PBfifousage = b[0];
statics.CAPfifousage = b[1];
statics.RXlevelDetected = b[2];
statics.RXinSync = b[3];
statics.maxRXlevel = b[4];
statics.maxTXlevel = b[5];
statics.tune_frequency = b[6];
int idx = 0;
statics.PBfifousage = b[idx++];
statics.CAPfifousage = b[idx++];
statics.RXlevelDetected = b[idx++];
statics.RXinSync = b[idx++];
statics.maxRXlevel = b[idx++];
statics.maxTXlevel = b[idx++];
statics.tune_frequency = b[idx++];
statics.tune_frequency <<= 8;
statics.tune_frequency += b[7];
statics.tune_frequency += b[idx++];
//Console.WriteLine("f:" + statics.tune_frequency);
Byte[] b1 = new byte[b.Length - 6];
Array.Copy(b, 6, b1, 0, b1.Length);
Byte[] b1 = new byte[b.Length - idx];
Array.Copy(b, idx, b1, 0, b1.Length);
drawFftBitmap(b1);
}