qtsoundmodem/sm_main.c

1422 lines
29 KiB
C
Raw Normal View History

2023-09-04 19:06:44 +01:00
/*
Copyright (C) 2019-2020 Andrei Kopanchuk UZ7HO
This file is part of QtSoundModem
QtSoundModem 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 3 of the License, or
(at your option) any later version.
QtSoundModem 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.
newsamp
You should have received a copy of the GNU General Public License
along with QtSoundModem. If not, see http://www.gnu.org/licenses
*/
// UZ7HO Soundmodem Port by John Wiseman G8BPQ
#include "UZ7HOStuff.h"
void make_core_BPF(UCHAR snd_ch, short freq, short width);
void make_core_TXBPF(UCHAR snd_ch, float freq, float width);
void make_core_INTR(UCHAR snd_ch);
void make_core_LPF(UCHAR snd_ch, short width);
2023-09-12 21:38:15 +01:00
void dw9600ProcessSample(int snd_ch, short Sample);
void init_RUH48(int snd_ch);
void init_RUH96(int snd_ch);
2023-09-04 19:06:44 +01:00
2023-09-12 21:38:15 +01:00
char modes_name[modes_count][21] =
2023-09-04 19:06:44 +01:00
{
"AFSK AX.25 300bd","AFSK AX.25 1200bd","AFSK AX.25 600bd","AFSK AX.25 2400bd",
"BPSK AX.25 1200bd","BPSK AX.25 600bd","BPSK AX.25 300bd","BPSK AX.25 2400bd",
"QPSK AX.25 4800bd","QPSK AX.25 3600bd","QPSK AX.25 2400bd","BPSK FEC 4x100bd",
2023-09-12 21:38:15 +01:00
"QPSK V26A 2400bps","8PSK V27 4800bps","QPSK V26B 2400bps", "Not Available",
"QPSK V26A 600bps", "8PSK 900bps", "RUH 4800(DW)", "RUH 9600(DW)"
2023-09-04 19:06:44 +01:00
};
typedef struct wavehdr_tag {
unsigned short * lpData; /* pointer to locked data buffer */
int dwBufferLength; /* length of data buffer */
int dwBytesRecorded; /* used for input only */
int * dwUser; /* for client's use */
int dwFlags; /* assorted flags (see defines) */
int dwLoops; /* loop control counter */
struct wavehdr_tag *lpNext; /* reserved for driver */
int * reserved; /* reserved for driver */
} WAVEHDR, *PWAVEHDR, * NPWAVEHDR, * LPWAVEHDR;
extern int pnt_change[5];
int debugmode = 0;
extern float src_buf[5][2048];
extern Byte RCVR[5];
int SatelliteMode = 0;
int UDPServerPort = 8884;
int UDPClientPort = 8888;
int TXPort = 8884;
BOOL Firstwaterfall = 1;
BOOL Secondwaterfall = 1;
int multiCore = FALSE;
BOOL MinOnStart = 0;
//RS TReedSolomon;
// Form1 TForm1;
// WaveFormat TWaveFormatEx;
int Channels = 2;
int BitsPerSample = 16;
float TX_Samplerate = 12000;
float RX_Samplerate = 12000;
2024-07-23 21:26:30 +01:00
//int RX_SR = 11025;
//int TX_SR = 11025;
2023-09-04 19:06:44 +01:00
int RX_PPM = 0;
int TX_PPM = 0;
int tx_bufsize = 512;
int rx_bufsize = 512;
int tx_bufcount = 16;
int rx_bufcount = 16;
int mouse_down[2] = {0, 0};
//UCHAR * RX_pBuf array[257];
// RX_header array[1..256] of TWaveHdr;
// TX_pBuf array[1..4,1..256] of pointer;
//TX_header array[1..4,1..256] of TWaveHdr;
UCHAR calib_mode[5] = {0,0,0,0};
UCHAR snd_status [5] = {0,0,0,0};
UCHAR buf_status [5] = {0,0,0,0};
UCHAR tx_buf_num1 [5] = {0,0,0,0};
UCHAR tx_buf_num [5] = {0,0,0,0};
extern short active_rx_freq[5];
2023-09-12 21:38:15 +01:00
unsigned int pskStates[4] = {0, 0, 0, 0};
2023-09-04 19:06:44 +01:00
int speed[5] = {0,0,0,0};
int panels[6] = {1,1,1,1,1};
short fft_buf[2][8192];
UCHAR fft_disp[2][1024];
int fftCount = 0; // FTF samples collected
// bm array[1..4] of TBitMap;
// bm1,bm2,bm3 TBitMap;
// WaveInHandle hWaveIn;
// WaveOutHandle array[1..4] of hWaveOut;
int RXBufferLength;
int grid_time = 0;
int fft_mult = 0;
int fft_spd = 3;
int grid_timer = 0;
int stop_wf = 0;
int raduga = DISP_RGB;
char snd_rx_device_name[32] = "";
char snd_tx_device_name[32] = "";
int snd_rx_device = 0;
int snd_tx_device = 0;
UCHAR mod_icon_status = MOD_IDLE;
UCHAR last_mod_icon_status = MOD_IDLE;
UCHAR icon_timer = 0;
// TelIni TIniFile;
char cur_dir[] = "";
// TimerId1 cardinal;
// TimerId2 cardinal;
UCHAR TimerStat1 = TIMER_FREE;
UCHAR TimerStat2 = TIMER_FREE;
int stat_log = FALSE;
int PTT_device = FALSE;
int RX_device = FALSE;
int TX_device = FALSE;
int TX_rotate = FALSE;
int UsingBothChannels = FALSE;
int UsingLeft = FALSE;
int UsingRight = FALSE;
int SCO = FALSE;
int DualPTT = TRUE;
UCHAR DebugMode = 0;
UCHAR TimerEvent = TIMER_EVENT_OFF;
int nr_monitor_lines = 50;
int UTC_Time = FALSE;
int MainPriority = 0;
// MainThreadHandle THandle;
UCHAR w_state = WIN_MAXIMIZED;
2023-09-12 21:38:15 +01:00
2023-09-04 19:06:44 +01:00
void get_filter_values(UCHAR snd_ch)
{
//, unsigned short dbpf,
//unsigned short dtxbpf,
//unsigned short dbpftap,
//unsigned short dlpf,
//unsigned short dlpftap)
// speed[snd_ch], bpf[snd_ch], txbpf[snd_ch], bpf_tap[snd_ch], lpf[snd_ch], lpf_tap[snd_ch]);
switch (speed[snd_ch])
{
case SPEED_8P4800:
lpf[snd_ch] = MODEM_8P4800_LPF;
bpf[snd_ch] = MODEM_8P4800_BPF;
txbpf[snd_ch] = MODEM_8P4800_TXBPF;
BPF_tap[snd_ch] = MODEM_8P4800_BPF_TAP;
LPF_tap[snd_ch] = MODEM_8P4800_LPF_TAP;
break;
case SPEED_MP400:
lpf[snd_ch] = MODEM_MP400_LPF;
bpf[snd_ch] = MODEM_MP400_BPF;
txbpf[snd_ch] = MODEM_MP400_TXBPF;
BPF_tap[snd_ch] = MODEM_MP400_BPF_TAP;
LPF_tap[snd_ch] = MODEM_MP400_LPF_TAP;
break;
case SPEED_Q4800:
lpf[snd_ch] = MODEM_Q4800_LPF;
bpf[snd_ch] = MODEM_Q4800_BPF;
txbpf[snd_ch] = MODEM_Q4800_TXBPF;
BPF_tap[snd_ch] = MODEM_Q4800_BPF_TAP;
LPF_tap[snd_ch] = MODEM_Q4800_LPF_TAP;
break;
case SPEED_Q3600:
lpf[snd_ch] = MODEM_Q3600_LPF;
bpf[snd_ch] = MODEM_Q3600_BPF;
txbpf[snd_ch] = MODEM_Q3600_TXBPF;
BPF_tap[snd_ch] = MODEM_Q3600_BPF_TAP;
LPF_tap[snd_ch] = MODEM_Q3600_LPF_TAP;
break;
case SPEED_Q2400:
lpf[snd_ch] = MODEM_Q2400_LPF;
bpf[snd_ch] = MODEM_Q2400_BPF;
txbpf[snd_ch] = MODEM_Q2400_TXBPF;
BPF_tap[snd_ch] = MODEM_Q2400_BPF_TAP;
LPF_tap[snd_ch] = MODEM_Q2400_LPF_TAP;
break;
case SPEED_DW2400:
2023-09-12 21:38:15 +01:00
case SPEED_2400V26B:
2023-09-04 19:06:44 +01:00
lpf[snd_ch] = MODEM_DW2400_LPF;
bpf[snd_ch] = MODEM_DW2400_BPF;
txbpf[snd_ch] = MODEM_DW2400_TXBPF;
BPF_tap[snd_ch] = MODEM_DW2400_BPF_TAP;
LPF_tap[snd_ch] = MODEM_DW2400_LPF_TAP;
break;
case SPEED_P2400:
lpf[snd_ch] = MODEM_P2400_LPF;
bpf[snd_ch] = MODEM_P2400_BPF;
txbpf[snd_ch] = MODEM_P2400_TXBPF;
BPF_tap[snd_ch] = MODEM_P2400_BPF_TAP;
LPF_tap[snd_ch] = MODEM_P2400_LPF_TAP;
break;
case SPEED_P1200:
lpf[snd_ch] = MODEM_P1200_LPF;
bpf[snd_ch] = MODEM_P1200_BPF;
txbpf[snd_ch] = MODEM_P1200_TXBPF;
BPF_tap[snd_ch] = MODEM_P1200_BPF_TAP;
LPF_tap[snd_ch] = MODEM_P1200_LPF_TAP;
break;
case SPEED_P600:
lpf[snd_ch] = MODEM_P600_LPF;
bpf[snd_ch] = MODEM_P600_BPF;
txbpf[snd_ch] = MODEM_P600_TXBPF;
BPF_tap[snd_ch] = MODEM_P600_BPF_TAP;
LPF_tap[snd_ch] = MODEM_P600_LPF_TAP;
break;
case SPEED_P300:
lpf[snd_ch] = MODEM_P300_LPF;
bpf[snd_ch] = MODEM_P300_BPF;
txbpf[snd_ch] = MODEM_P300_TXBPF;
BPF_tap[snd_ch] = MODEM_P300_BPF_TAP;
LPF_tap[snd_ch] = MODEM_P300_LPF_TAP;
break;
case SPEED_300:
lpf[snd_ch] = MODEM_300_LPF;
bpf[snd_ch] = MODEM_300_BPF;
txbpf[snd_ch] = MODEM_300_TXBPF;
BPF_tap[snd_ch] = MODEM_300_BPF_TAP;
LPF_tap[snd_ch] = MODEM_300_LPF_TAP;
break;
case SPEED_600:
lpf[snd_ch] = MODEM_600_LPF;
bpf[snd_ch] = MODEM_600_BPF;
txbpf[snd_ch] = MODEM_600_TXBPF;
BPF_tap[snd_ch] = MODEM_600_BPF_TAP;
LPF_tap[snd_ch] = MODEM_600_LPF_TAP;
break;
case SPEED_1200:
lpf[snd_ch] = MODEM_1200_LPF;
bpf[snd_ch] = MODEM_1200_BPF;
txbpf[snd_ch] = MODEM_1200_TXBPF;
BPF_tap[snd_ch] = MODEM_1200_BPF_TAP;
LPF_tap[snd_ch] = MODEM_1200_LPF_TAP;
break;
case SPEED_2400:
lpf[snd_ch] = MODEM_2400_LPF;
bpf[snd_ch] = MODEM_2400_BPF;
txbpf[snd_ch] = MODEM_2400_TXBPF;
BPF_tap[snd_ch] = MODEM_2400_BPF_TAP;
LPF_tap[snd_ch] = MODEM_2400_LPF_TAP;
break;
2023-09-12 21:38:15 +01:00
case SPEED_Q300:
case SPEED_8PSK300:
lpf[snd_ch] = MODEM_P300_LPF;
bpf[snd_ch] = MODEM_P300_BPF;
txbpf[snd_ch] = MODEM_P300_TXBPF;
BPF_tap[snd_ch] = MODEM_P300_BPF_TAP;
LPF_tap[snd_ch] = MODEM_P300_LPF_TAP;
break;
/*
case SPEED_Q1200:
lpf[snd_ch] = MODEM_P1200_LPF;
bpf[snd_ch] = MODEM_P1200_BPF;
txbpf[snd_ch] = MODEM_P1200_TXBPF;
BPF_tap[snd_ch] = MODEM_P1200_BPF_TAP;
LPF_tap[snd_ch] = MODEM_P1200_LPF_TAP;
break;
*/
}
2023-09-04 19:06:44 +01:00
}
void init_2400(int snd_ch)
{
modem_mode[snd_ch] = MODE_FSK;
rx_shift[snd_ch] = 1805;
rx_baudrate[snd_ch] = 2400;
2023-09-12 21:38:15 +01:00
tx_bitrate[snd_ch] = 2400;
2023-09-04 19:06:44 +01:00
if (modem_def[snd_ch])
get_filter_values(snd_ch);
}
void init_1200(int snd_ch)
{
modem_mode[snd_ch] = MODE_FSK;
rx_shift[snd_ch] = 1000;
if (stdtones)
rx_freq[snd_ch] = 1700;
rx_baudrate[snd_ch] = 1200;
2023-09-12 21:38:15 +01:00
tx_bitrate[snd_ch] = 1200;
2023-09-04 19:06:44 +01:00
if (modem_def[snd_ch])
get_filter_values(snd_ch);
}
void init_600(int snd_ch)
{
modem_mode[snd_ch] = MODE_FSK;
rx_shift[snd_ch] = 450;
rx_baudrate[snd_ch] = 600;
2023-09-12 21:38:15 +01:00
tx_bitrate[snd_ch] = 600;
2023-09-04 19:06:44 +01:00
if (modem_def[snd_ch])
get_filter_values(snd_ch);
}
void init_300(int snd_ch)
{
modem_mode[snd_ch] = MODE_FSK;
rx_shift[snd_ch] = 200;
rx_baudrate[snd_ch] = 300;
2023-09-12 21:38:15 +01:00
tx_bitrate[snd_ch] = 300;
2023-09-04 19:06:44 +01:00
if (modem_def[snd_ch])
get_filter_values(snd_ch);
}
void init_MP400(int snd_ch)
{
modem_mode[snd_ch] = MODE_MPSK;
rx_shift[snd_ch] = 175 /*sbc*/ * 3;
rx_baudrate[snd_ch] = 100;
2023-09-12 21:38:15 +01:00
tx_bitrate[snd_ch] = 400;
2023-09-04 19:06:44 +01:00
if (modem_def[snd_ch])
get_filter_values(snd_ch);
}
void init_8P4800(int snd_ch)
{
modem_mode[snd_ch] = MODE_8PSK;
if (stdtones)
rx_freq[snd_ch] = 1800;
rx_shift[snd_ch] = 1600;
rx_baudrate[snd_ch] = 1600;
2023-09-12 21:38:15 +01:00
tx_bitrate[snd_ch] = 4800;
pskStates[snd_ch] = 8;
2023-09-04 19:06:44 +01:00
if (modem_def[snd_ch])
get_filter_values(snd_ch);
}
2023-09-12 21:38:15 +01:00
void init_V26B2400(int snd_ch)
2023-09-04 19:06:44 +01:00
{
qpsk_set[snd_ch].mode = QPSK_V26;
modem_mode[snd_ch] = MODE_PI4QPSK;
if (stdtones)
rx_freq[snd_ch] = 1800;
rx_shift[snd_ch] = 1200;
rx_baudrate[snd_ch] = 1200;
2023-09-12 21:38:15 +01:00
tx_bitrate[snd_ch] = 2400;
pskStates[snd_ch] = 8; // Pretend 8 so quality calc works
2023-09-04 19:06:44 +01:00
if (modem_def[snd_ch])
get_filter_values(snd_ch);
}
void init_DW2400(int snd_ch)
{
qpsk_set[snd_ch].mode = QPSK_V26;
modem_mode[snd_ch] = MODE_QPSK;
if (stdtones)
rx_freq[snd_ch] = 1800;
rx_shift[snd_ch] = 1200;
rx_baudrate[snd_ch] = 1200;
2023-09-12 21:38:15 +01:00
tx_bitrate[snd_ch] = 2400;
pskStates[snd_ch] = 4;
2023-09-04 19:06:44 +01:00
if (modem_def[snd_ch])
get_filter_values(snd_ch);
}
void init_Q4800(int snd_ch)
{
qpsk_set[snd_ch].mode = QPSK_SM;
modem_mode[snd_ch] = MODE_QPSK;
rx_shift[snd_ch] = 2400;
rx_baudrate[snd_ch] = 2400;
2023-09-12 21:38:15 +01:00
tx_bitrate[snd_ch] = 4800;
pskStates[snd_ch] = 4;
2023-09-04 19:06:44 +01:00
if (modem_def[snd_ch])
get_filter_values(snd_ch);
}
void init_Q3600(int snd_ch)
{
2024-07-23 21:26:30 +01:00
qpsk_set[snd_ch].mode = QPSK_V26; // QPSK_SM;
2023-09-04 19:06:44 +01:00
modem_mode[snd_ch] = MODE_QPSK;
rx_shift[snd_ch] = 1800;
rx_baudrate[snd_ch] = 1800;
2023-09-12 21:38:15 +01:00
tx_bitrate[snd_ch] = 3600;
2024-07-23 21:26:30 +01:00
pskStates[snd_ch] = 4;
2023-09-04 19:06:44 +01:00
if (modem_def[snd_ch])
get_filter_values(snd_ch);
}
void init_Q2400(int snd_ch)
{
qpsk_set[snd_ch].mode = QPSK_SM;
modem_mode[snd_ch] = MODE_QPSK;
rx_shift[snd_ch] = 1200;
rx_baudrate[snd_ch] = 1200;
2023-09-12 21:38:15 +01:00
tx_bitrate[snd_ch] = 2400;
pskStates[snd_ch] = 4;
2023-09-04 19:06:44 +01:00
if (modem_def[snd_ch])
get_filter_values(snd_ch);
}
void init_P2400(int snd_ch)
{
modem_mode[snd_ch] = MODE_BPSK;
rx_shift[snd_ch] = 2400;
rx_baudrate[snd_ch] = 2400;
2023-09-12 21:38:15 +01:00
tx_bitrate[snd_ch] = 2400;
pskStates[snd_ch] = 2;
if (modem_def[snd_ch])
2023-09-04 19:06:44 +01:00
get_filter_values(snd_ch);
}
void init_P1200(int snd_ch)
{
modem_mode[snd_ch] = MODE_BPSK;
rx_shift[snd_ch] = 1200;
rx_baudrate[snd_ch] = 1200;
2023-09-12 21:38:15 +01:00
tx_bitrate[snd_ch] = 1200;
pskStates[snd_ch] = 2;
2023-09-04 19:06:44 +01:00
if (modem_def[snd_ch])
get_filter_values(snd_ch);
}
void init_P600(int snd_ch)
{
modem_mode[snd_ch] = MODE_BPSK;
rx_shift[snd_ch] = 600;
rx_baudrate[snd_ch] = 600;
2023-09-12 21:38:15 +01:00
tx_bitrate[snd_ch] = 600;
pskStates[snd_ch] = 2;
2023-09-04 19:06:44 +01:00
if (modem_def[snd_ch])
get_filter_values(snd_ch);
}
void init_P300(int snd_ch)
{
modem_mode[snd_ch] = MODE_BPSK;
rx_shift[snd_ch] = 300;
rx_baudrate[snd_ch] = 300;
2023-09-12 21:38:15 +01:00
pskStates[snd_ch] = 2;
tx_bitrate[snd_ch] = 300;
if (modem_def[snd_ch])
get_filter_values(snd_ch);
}
void init_Q300(int snd_ch)
{
qpsk_set[snd_ch].mode = QPSK_V26;
modem_mode[snd_ch] = MODE_QPSK;
rx_shift[snd_ch] = 300;
rx_baudrate[snd_ch] = 300;
tx_bitrate[snd_ch] = 600;
pskStates[snd_ch] = 4;
if (modem_def[snd_ch])
get_filter_values(snd_ch);
}
void init_8PSK300(int snd_ch)
{
modem_mode[snd_ch] = MODE_8PSK;
rx_shift[snd_ch] = 300;
rx_baudrate[snd_ch] = 300;
tx_bitrate[snd_ch] = 900;
pskStates[snd_ch] = 8;
2023-09-04 19:06:44 +01:00
if (modem_def[snd_ch])
get_filter_values(snd_ch);
}
void init_ARDOP(int snd_ch)
{
modem_mode[snd_ch] = MODE_ARDOP;
rx_shift[snd_ch] = 500;
rx_freq[snd_ch] = 1500;
rx_baudrate[snd_ch] = 500;
2023-09-12 21:38:15 +01:00
tx_bitrate[snd_ch] = 500;
2023-09-04 19:06:44 +01:00
if (modem_def[snd_ch])
get_filter_values(snd_ch);
}
void init_speed(int snd_ch);
void set_speed(int snd_ch, int Modem)
{
speed[snd_ch] = Modem;
init_speed(snd_ch);
}
2023-09-12 21:38:15 +01:00
int needPSKRefresh = 0;
2023-09-04 19:06:44 +01:00
void init_speed(int snd_ch)
{
int low, high;
2023-09-12 21:38:15 +01:00
pskStates[snd_ch] = 0; // Not PSK
2023-09-04 19:06:44 +01:00
switch (speed[snd_ch])
{
case SPEED_8P4800:
init_8P4800(snd_ch);
break;
2023-09-12 21:38:15 +01:00
case SPEED_2400V26B:
init_V26B2400(snd_ch);
2023-09-04 19:06:44 +01:00
break;
case SPEED_DW2400:
init_DW2400(snd_ch);
break;
case SPEED_MP400:
init_MP400(snd_ch);
break;
case SPEED_Q4800:
init_Q4800(snd_ch);
break;
case SPEED_Q3600:
init_Q3600(snd_ch);
break;
case SPEED_Q2400:
init_Q2400(snd_ch);
break;
case SPEED_P2400:
init_P2400(snd_ch);
break;
case SPEED_P1200:
init_P1200(snd_ch);
break;
2023-09-12 21:38:15 +01:00
// case SPEED_Q1200:
// init_Q1200(snd_ch);
// break;
2023-09-04 19:06:44 +01:00
case SPEED_P600:
init_P600(snd_ch);
break;
case SPEED_P300:
init_P300(snd_ch);
break;
2023-09-12 21:38:15 +01:00
case SPEED_Q300:
init_Q300(snd_ch);
break;
case SPEED_8PSK300:
init_8PSK300(snd_ch);
break;
2023-09-04 19:06:44 +01:00
case SPEED_300:
init_300(snd_ch);
break;
case SPEED_600:
init_600(snd_ch);
break;
case SPEED_1200:
init_1200(snd_ch);
break;
case SPEED_2400:
init_2400(snd_ch);
break;
case SPEED_ARDOP:
init_ARDOP(snd_ch);
break;
2023-09-12 21:38:15 +01:00
case SPEED_RUH48:
init_RUH48(snd_ch);
break;
case SPEED_RUH96:
init_RUH96(snd_ch);
break;
2023-09-04 19:06:44 +01:00
}
//QPSK_SM: begin move(#0#1#2#3, tx[0], 4); move(#0#32#64#96, rx[0], 4); end;
//QPSK_V26: begin move(#2#3#1#0, tx[0], 4); move(#96#64#0#32, rx[0], 4); end;
if (modem_mode[snd_ch] == MODE_QPSK || modem_mode[snd_ch] == MODE_PI4QPSK)
{
switch (qpsk_set[snd_ch].mode)
{
case QPSK_SM:
memcpy(&qpsk_set[snd_ch].tx[0], "\0\1\2\3", 4);
memcpy(&qpsk_set[snd_ch].rx[0], "\x0\x20\x40\x60", 4);
break;
case QPSK_V26:
memcpy(&qpsk_set[snd_ch].tx[0], "\2\3\1\0", 4);
memcpy(&qpsk_set[snd_ch].rx[0], "\x60\x40\0\x20", 4);
break;
}
}
tx_shift[snd_ch] = rx_shift[snd_ch];
tx_baudrate[snd_ch] = rx_baudrate[snd_ch];
low = roundf(rx_shift[snd_ch] / 2 + RCVR[snd_ch] * rcvr_offset[snd_ch] + 1);
high = roundf(RX_Samplerate / 2 - (rx_shift[snd_ch] / 2 + RCVR[snd_ch] * rcvr_offset[snd_ch]));
if (rx_freq[snd_ch] - low < 0) rx_freq[snd_ch] = low;
if (high - rx_freq[snd_ch] < 0) rx_freq[snd_ch] = high;
tx_freq[snd_ch] = rx_freq[snd_ch];
make_core_BPF(snd_ch, rx_freq[snd_ch], bpf[snd_ch]);
make_core_TXBPF(snd_ch, tx_freq[snd_ch], txbpf[snd_ch]);
make_core_INTR(snd_ch);
make_core_LPF(snd_ch, lpf[snd_ch]);
/*
for i = 0 to 16 do
for j = 0 to nr_emph do with DET[j,i] do
begin
minamp[snd_ch] = 0;
maxamp[snd_ch] = 0;
ones[snd_ch] = 0;
zeros[snd_ch] = 0;
sample_cnt[snd_ch] = 0;
bit_cnt[snd_ch] = 0;
bit_osc[snd_ch] = 0;
frame_status[snd_ch] = FRAME_WAIT;
end;
form1.show_modes;
form1.show_freq_a;
form1.show_freq_b;
*/
2023-12-17 13:53:32 +00:00
NeedWaterfallHeaders = TRUE;
2023-09-04 19:06:44 +01:00
2023-09-12 21:38:15 +01:00
CheckPSKWindows();
2023-09-04 19:06:44 +01:00
}
void chk_snd_buf(float * buf, int len)
{
word i;
boolean good;
single prev_amp;
if (len < 2)
return;
good = FALSE;
i = 1;
prev_amp = buf[0];
do
{
if (buf[i++] != prev_amp)
good = TRUE;
} while (good == FALSE && i < len);
// Make noise
if (!good)
for (i = 0; i < len; i++)
buf[i] = rand();
}
#ifdef WIN32
typedef void *HANDLE;
typedef unsigned long DWORD;
#define WINAPI __stdcall
__declspec(dllimport)
DWORD
WINAPI
WaitForSingleObject(
__in HANDLE hHandle,
__in DWORD dwMilliseconds
);
#define pthread_t uintptr_t
uintptr_t _beginthread(void(__cdecl *start_address)(void *), unsigned stack_size, void *arglist);
#else
#include <pthread.h>
pthread_t _beginthread(void(*start_address)(void *), unsigned stack_size, void * arglist)
{
pthread_t thread;
if (pthread_create(&thread, NULL, (void * (*)(void *))start_address, (void*)arglist) != 0)
perror("New Thread");
return thread;
}
#endif
void runModemthread(void * param);
void runModems()
{
int snd_ch, res;
pthread_t thread[4] = { 0,0,0,0 };
for (snd_ch = 0; snd_ch < 4; snd_ch++)
{
if (soundChannel[snd_ch] == 0) // Unused channed
continue;
if (modem_mode[snd_ch] == MODE_ARDOP)
continue; // Processed above
2023-09-12 21:38:15 +01:00
if (modem_mode[snd_ch] == MODE_RUH)
continue; // Processed above
// do we need to do this again ??
// make_core_BPF(snd_ch, rx_freq[snd_ch], bpf[snd_ch]);
2023-09-04 19:06:44 +01:00
if (multiCore) // Run modems in separate threads
thread[snd_ch] = _beginthread(runModemthread, 0, (void *)(size_t)snd_ch);
else
runModemthread((void *)(size_t)snd_ch);
}
if (multiCore)
{
#ifdef WIN32
if (thread[0]) WaitForSingleObject(&thread[0], 2000);
if (thread[1]) WaitForSingleObject(&thread[1], 2000);
if (thread[2]) WaitForSingleObject(&thread[2], 2000);
if (thread[3]) WaitForSingleObject(&thread[3], 2000);
#else
if (thread[0]) pthread_join(thread[0], &res);
if (thread[1]) pthread_join(thread[1], &res);
if (thread[2]) pthread_join(thread[2], &res);
if (thread[3]) pthread_join(thread[3], &res);
#endif
}
}
Byte rcvr_idx;
void runModemthread(void * param)
{
int snd_ch = (int)(size_t)param;
// I want to run lowest to highest to simplify my display
int offset = -(RCVR[snd_ch] * rcvr_offset[snd_ch]); // lowest
int lastrx = RCVR[snd_ch] * 2;
if (soundChannel[snd_ch] == 0) // Unused channed
return;
for (rcvr_idx = 0; rcvr_idx <= lastrx; rcvr_idx++)
{
active_rx_freq[snd_ch] = rxOffset + chanOffset[snd_ch] + rx_freq[snd_ch] + offset;
offset += rcvr_offset[snd_ch];
Demodulator(snd_ch, rcvr_idx, src_buf[modemtoSoundLR[snd_ch]], rcvr_idx == lastrx, offset == 0);
}
}
// I think this processes a buffer of samples
2023-12-17 13:53:32 +00:00
int Toggle = 0;
2023-09-04 19:06:44 +01:00
void BufferFull(short * Samples, int nSamples) // These are Stereo Samples
{
2023-09-12 21:38:15 +01:00
word i, i1, j;
2023-09-04 19:06:44 +01:00
Byte snd_ch, rcvr_idx;
int buf_offset;
int Needed;
short * data1;
short * data2 = 0;
// if UDP server active send as UDP Datagram
if (UDPServ) // Extract just left
{
short Buff[1024];
i1 = 0;
for (i = 0; i < rx_bufsize; i++)
{
Buff[i] = Samples[i1];
i1 += 2;
}
sendSamplestoUDP(Buff, 512, TXPort);
}
// Do RSID processing (can we also use this for waterfall??
RSIDProcessSamples(Samples, nSamples);
// Do FFT on every 4th buffer (2048 samples)
// if in Satellite Mode look for a Tuning signal
// if (SatelliteMode)
// {
// doTuning(Samples, nSamples);
// }
for (snd_ch = 0; snd_ch < 4; snd_ch++)
{
if (soundChannel[snd_ch] == 0) // Unused channed
continue;
if (pnt_change[snd_ch])
{
make_core_BPF(snd_ch, rx_freq[snd_ch], bpf[snd_ch]);
make_core_TXBPF(snd_ch, tx_freq[snd_ch], txbpf[snd_ch]);
pnt_change[snd_ch] = FALSE;
}
}
// I don't think we should process RX if either is sending
if (snd_status[0] != SND_TX && snd_status[1] != SND_TX && snd_status[2] != SND_TX && snd_status[3] != SND_TX)
{
for (snd_ch = 0; snd_ch < 4; snd_ch++)
{
if (soundChannel[snd_ch] == 0) // Unused channed
continue;
if (modem_mode[snd_ch] == MODE_ARDOP)
{
short ardopbuff[1200];
i1 = 0;
2023-09-12 21:38:15 +01:00
if (using48000)
2023-09-04 19:06:44 +01:00
{
2023-09-12 21:38:15 +01:00
i1 = 0;
j = 0;
// Need to downsample 48K to 12K
// Try just skipping 3 samples
nSamples /= 4;
for (i = 0; i < nSamples; i++)
{
ardopbuff[i] = Samples[i1];
i1 += 8;
}
}
else
{
for (i = 0; i < nSamples; i++)
{
ardopbuff[i] = Samples[i1];
i1++;
i1++;
}
}
ARDOPProcessNewSamples(snd_ch, ardopbuff, nSamples);
}
else if (modem_mode[snd_ch] == MODE_RUH)
{
i1 = 0;
if (modemtoSoundLR[snd_ch] == 1) // Using Right Chan
i1++;
for (i = 0; i < nSamples; i++)
{
dw9600ProcessSample(snd_ch, Samples[i1]);
2023-09-04 19:06:44 +01:00
i1++;
i1++;
}
}
2023-09-12 21:38:15 +01:00
ProcessRXFrames(snd_ch);
2023-09-04 19:06:44 +01:00
}
// extract mono samples from data.
data1 = Samples;
2023-09-12 21:38:15 +01:00
if (using48000)
{
i1 = 0;
j = 0;
// Need to downsample 48K to 12K
// Try just skipping 3 samples
nSamples /= 4;
for (i = 0; i < nSamples; i++)
{
Samples[j++] = Samples[i1];
Samples[j++] = Samples[i1 + 1];
i1 += 8;
}
}
2023-09-04 19:06:44 +01:00
i1 = 0;
// src_buf[0] is left data,. src_buf[1] right
// We could skip extracting other channel if only one in use - is it worth it??
if (UsingBothChannels)
{
2023-09-12 21:38:15 +01:00
for (i = 0; i < nSamples; i++)
2023-09-04 19:06:44 +01:00
{
src_buf[0][i] = data1[i1];
i1++;
src_buf[1][i] = data1[i1];
i1++;
}
}
else if (UsingRight)
{
// Extract just right
i1 = 1;
2023-09-12 21:38:15 +01:00
for (i = 0; i < nSamples; i++)
2023-09-04 19:06:44 +01:00
{
src_buf[1][i] = data1[i1];
i1 += 2;
}
}
else
{
// Extract just left
2023-09-12 21:38:15 +01:00
for (i = 0; i < nSamples; i++)
2023-09-04 19:06:44 +01:00
{
src_buf[0][i] = data1[i1];
i1 += 2;
}
}
// Run modems before waterfall so fft buffer has values from before sync was detected
runModems();
// Do whichever waterfall is needed
// We need to run the waterfall FFT for the frequency guessing to work
2024-07-23 21:26:30 +01:00
2023-09-04 19:06:44 +01:00
int FirstWaterfallChan = 0;
2024-07-23 21:26:30 +01:00
2023-09-04 19:06:44 +01:00
short * ptr1 = &fft_buf[0][fftCount];
short * ptr2 = &fft_buf[1][fftCount];
int remainingSamples = rx_bufsize;
if (UsingLeft == 0)
{
FirstWaterfallChan = 1;
data1++; // to Right Samples
}
if (UsingBothChannels) // Second is always Right
data2 = &Samples[1]; // to Right Samples
// FFT size isn't necessarily a multiple of rx_bufsize, so this is a bit more complicated
// Save FFTSize samples then process. Put the unused bits back in the fft buffer
// Collect samples for both channels if needed
2023-12-17 13:53:32 +00:00
Toggle++;
2023-09-04 19:06:44 +01:00
Needed = FFTSize - fftCount;
if (Needed <= rx_bufsize)
{
// add Needed samples to fft_buf and process. Copy rest to start of fft_buf
for (i = 0; i < Needed; i++)
{
*ptr1++ = *data1;
data1 += 2;
}
2023-12-17 13:53:32 +00:00
if ((Toggle & 1) || (UsingBothChannels == 0))
doWaterfall(FirstWaterfallChan);
2023-09-04 19:06:44 +01:00
if (data2)
{
for (i = 0; i < Needed; i++)
{
*ptr2++ = *data2;
data2 += 2;
}
2023-12-17 13:53:32 +00:00
if (((Toggle & 1) == 0))
2024-07-23 21:26:30 +01:00
doWaterfall(1);
2023-09-04 19:06:44 +01:00
}
2023-12-17 13:53:32 +00:00
if (Firstwaterfall || Secondwaterfall)
displayWaterfall();
2023-09-04 19:06:44 +01:00
remainingSamples = rx_bufsize - Needed;
fftCount = 0;
ptr1 = &fft_buf[0][0];
ptr2 = &fft_buf[1][0];
}
for (i = 0; i < remainingSamples; i++)
{
*ptr1++ = *data1;
data1 += 2;
}
if (data2)
{
for (i = 0; i < remainingSamples; i++)
{
*ptr2++ = *data2;
data2 += 2;
}
}
fftCount += remainingSamples;
}
if (TimerEvent == TIMER_EVENT_ON)
{
timer_event();
// timer_event2();
}
}
/*
procedure TForm1.BufferFull1(var Msg TMessage);
var
i,snd_ch byte;
begin
for snd_ch = 1 to 2 do
if pnt_change[snd_ch] then
begin
make_core_BPF(snd_ch,rx_freq[snd_ch],bpf[snd_ch]);
make_core_TXBPF(snd_ch,tx_freq[snd_ch],txbpf[snd_ch]);
pnt_change[snd_ch] = FALSE;
end;
snd_ch = 0;
for i = 1 to 2 do if msg.WParam = WaveOutHandle[i] then snd_ch = i;
if (snd_ch = 0) then exit;
if (snd_status[snd_ch]<>SND_TX) then exit;
inc(tx_buf_num[snd_ch]); if tx_buf_num[snd_ch]>tx_bufcount then tx_buf_num[snd_ch] = 1;
if (buf_status[snd_ch] = BUF_EMPTY) and (tx_buf_num[snd_ch] = tx_buf_num1[snd_ch]) then TX2RX(snd_ch);
if buf_status[snd_ch] = BUF_FULL then
beginf
make_wave_buf(snd_ch,TX_pbuf[snd_ch][tx_buf_num[snd_ch]]);
WaveOutWrite(WaveOutHandle[snd_ch],@TX_header[snd_ch][tx_buf_num[snd_ch]],sizeof(TWaveHdr));
inc(tx_buf_num1[snd_ch]); if tx_buf_num1[snd_ch]>tx_bufcount then tx_buf_num1[snd_ch] = 1;
end;
end;
procedure TForm1.TX2RX(snd_ch byte);
begin
if snd_status[snd_ch] = SND_TX then stoptx(snd_ch);
if snd_status[snd_ch] = SND_IDLE then begin pttoff(snd_ch); end;
end;
*/
// Monitor Code - from moncode.asm
#define CMDBIT 4 // CURRENT MESSAGE IS A COMMAND
#define RESP 2 // CURRENT MSG IS RESPONSE
#define VER1 1 // CURRENT MSG IS VERSION 1
#define UI 3
#define SABM 0x2F
#define DISC 0x43
#define DM 0x0F
#define UA 0x63
#define FRMR 0x87
#define RR 1
#define RNR 5
#define REJ 9
#define SREJ 0x0D
#define SABME 0x6F
#define XID 0xAF
#define TEST 0xE3
#define PFBIT 0x10 // POLL/FINAL BIT IN CONTROL BYTE
#define NETROM_PID 0xCF
#define IP_PID 0xCC
#define ARP_PID 0xCD
#define NODES_SIG 0xFF
char FrameData[1024] = "";
char * frame_monitor(string * frame, char * code, int tx_stat)
{
char mon_frm[512];
char AGW_path[256];
string * AGW_data;
const Byte * frm = "???";
Byte * datap;
Byte _data[512] = "";
Byte * p_data = _data;
int _datalen;
char agw_port;
char CallFrom[10], CallTo[10], Digi[80];
char TR = 'R';
char codestr[64] = "";
integer i;
char time_now[32];
int len;
AGWUser * AGW;
Byte pid, nr, ns, f_type, f_id;
Byte rpt, cr, pf;
Byte path[80];
char c;
const char * p;
string * data = newString();
if (code[0] && strlen(code) < 60)
sprintf(codestr, "[%s]", code);
if (tx_stat)
TR = 'T';
decode_frame(frame->Data, frame->Length, path, data, &pid, &nr, &ns, &f_type, &f_id, &rpt, &pf, &cr);
datap = data->Data;
len = data->Length;
// if (pid == 0xCF)
// data = parse_NETROM(data, f_id);
// IP parsing
// else if (pid == 0xCC)
// data = parse_IP(data);
// ARP parsing
// else if (pid == 0xCD)
// data = parse_ARP(data);
//
if (len > 0)
{
for (i = 0; i < len; i++)
{
if (datap[i] > 31 || datap[i] == 13 || datap[i] == 9)
*(p_data++) = datap[i];
}
}
_datalen = p_data - _data;
if (_datalen)
{
Byte * ptr = _data;
i = 0;
// remove successive cr or cr on end while (i < _datalen)
while (i < _datalen)
{
if ((_data[i] == 13) && (_data[i + 1] == 13))
i++;
else
*(ptr++) = _data[i++];
}
if (*(ptr - 1) == 13)
ptr--;
*ptr = 0;
_datalen = ptr - _data;
}
get_monitor_path(path, CallTo, CallFrom, Digi);
if (cr)
{
c = 'C';
if (pf)
p = " P";
else p = "";
}
else
{
c = 'R';
if (pf)
p = " F";
else
p = "";
}
switch (f_id)
{
case I_I:
frm = "I";
break;
case S_RR:
frm = "RR";
break;
case S_RNR:
frm = "RNR";
break;
case S_REJ:
frm = "REJ";
break;
case S_SREJ:
frm = "SREJ";
break;
case U_SABM:
frm = "SABM";
break;
case SABME:
frm = "SABME";
break;
case U_DISC:
frm = "DISC";
break;
case U_DM:
frm = "DM";
break;
case U_UA:
frm = "UA";
break;
case U_FRMR:
frm = "FRMR";
break;
case U_UI:
frm = "UI";
2023-09-12 21:38:15 +01:00
break;
case U_XID:
frm = "XID";
break;
case U_TEST:
frm = "TEST";
2023-09-04 19:06:44 +01:00
}
2023-09-12 21:38:15 +01:00
2023-09-04 19:06:44 +01:00
if (Digi[0])
sprintf(AGW_path, "Fm %s To %s Via %s <%s %c%s",CallFrom, CallTo, Digi, frm, c, p);
else
sprintf(AGW_path, "Fm %s To %s <%s %c %s", CallFrom, CallTo, frm, c, p);
switch (f_type)
{
case I_FRM:
//mon_frm = AGW_path + ctrl + ' R' + inttostr(nr) + ' S' + inttostr(ns) + ' pid=' + dec2hex(pid) + ' Len=' + inttostr(len) + ' >' + time_now + #13 + _data + #13#13;
sprintf(mon_frm, "%s R%d S%d pid=%X Len=%d>[%s%c]%s\r%s\r", AGW_path, nr, ns, pid, len, ShortDateTime(), TR, codestr, _data);
break;
case U_FRM:
if (f_id == U_UI)
{
sprintf(mon_frm, "%s pid=%X Len=%d>[%s%c]%s\r%s\r", AGW_path, pid, len, ShortDateTime(), TR, codestr, _data); // "= AGW_path + ctrl + '>' + time_now + #13;
}
else if (f_id == U_FRMR)
{
sprintf(mon_frm, "%s>%02x %02x %02x[%s]\r", AGW_path, datap[0], datap[1], datap[2], ShortDateTime()); // "= AGW_path + ctrl + '>' + time_now + #13;
}
else
sprintf(mon_frm, "%s>[%s%c]%s\r", AGW_path, ShortDateTime(), TR, codestr); // "= AGW_path + ctrl + '>' + time_now + #13;
break;
case S_FRM:
// mon_frm = AGW_path + ctrl + ' R' + inttostr(nr) + ' >' + time_now + #13;
sprintf(mon_frm, "%s R%d>[%s%c]%s\r", AGW_path, nr, ShortDateTime(), TR, codestr); // "= AGW_path + ctrl + '>' + time_now + #13;
break;
}
sprintf(FrameData, "%s", mon_frm);
return FrameData;
}