kopia lustrzana https://github.com/sp9skp/spdxl
2790 wiersze
80 KiB
C
2790 wiersze
80 KiB
C
/*
|
|
* dxlAPRS toolchain
|
|
*
|
|
* Copyright (C) Christian Rabler <oe5dxl@oevsv.at>
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0+
|
|
*/
|
|
|
|
|
|
#define X2C_int32
|
|
#define X2C_index32
|
|
#ifndef X2C_H_
|
|
#include "X2C.h"
|
|
#endif
|
|
#define afskmodem_C_
|
|
#ifndef soundctl_H_
|
|
#include "soundctl.h"
|
|
#endif
|
|
#ifndef udp_H_
|
|
#include "udp.h"
|
|
#endif
|
|
#include <fcntl.h>
|
|
#ifndef osi_H_
|
|
#include "osi.h"
|
|
#endif
|
|
#include <osic.h>
|
|
#ifndef mlib_H_
|
|
#include "mlib.h"
|
|
#endif
|
|
#ifndef aprsstr_H_
|
|
#include "aprsstr.h"
|
|
#endif
|
|
#include <unistd.h>
|
|
#ifndef afskmodemptt_H_
|
|
#include "afskmodemptt.h"
|
|
#endif
|
|
#include <signal.h>
|
|
|
|
/* (a)fsk - kiss/axudp stereo soundcard afsk/fsk multimodem by OE5DXL */
|
|
/*FROM setsighandler IMPORT SIGTERM, SIGINT, setsignalproc, SIGPROC; */
|
|
#define afskmodem_MAXLEN 339
|
|
|
|
#define afskmodem_MAXMODEMS 8
|
|
|
|
#define afskmodem_TXBUFLEN 60
|
|
/* default kiss buffers */
|
|
|
|
#define afskmodem_ADCBUFLEN 4096
|
|
|
|
#define afskmodem_BAUDSAMP 65536
|
|
|
|
#define afskmodem_PLLSHIFT 4096
|
|
|
|
#define afskmodem_DEFTIMEOUT 60
|
|
/* then unsent frames are discarded */
|
|
|
|
#define afskmodem_AFIRLEN 32
|
|
/*32, 64*/
|
|
|
|
#define afskmodem_AOVERSAMP 16
|
|
/*16*/
|
|
|
|
#define afskmodem_DFIRLEN 64
|
|
|
|
#define afskmodem_DOVERSAMP 16
|
|
|
|
#define afskmodem_TFIRLEN 64
|
|
/* 2^ */
|
|
/*32/5*/
|
|
|
|
#define afskmodem_SHIFTBITS 6
|
|
|
|
#define afskmodem_TFIRFINE 128
|
|
|
|
#define afskmodem_MAXVOL 25000.0
|
|
/* max dac / overswing */
|
|
|
|
static uint32_t afskmodem_POLYNOM = 0x8408UL;
|
|
|
|
static uint32_t afskmodem_CRCINIT = 0xFFFFUL;
|
|
|
|
static uint32_t afskmodem_CRCRESULT = 0x9F0BUL;
|
|
|
|
#define afskmodem_MINFLEN 9
|
|
|
|
#define afskmodem_STUFFLEN 5
|
|
|
|
#define afskmodem_FEND 192
|
|
|
|
#define afskmodem_FESC 219
|
|
|
|
#define afskmodem_TFEND 220
|
|
|
|
#define afskmodem_TFESC 221
|
|
|
|
struct KISSBUF;
|
|
|
|
typedef struct KISSBUF * pKISSNEXT;
|
|
|
|
|
|
struct KISSBUF {
|
|
pKISSNEXT next;
|
|
char port;
|
|
uint32_t time0;
|
|
uint32_t len;
|
|
char data[341]; /* +2 byte crc */
|
|
};
|
|
|
|
typedef float TXFIRTAB[128][64];
|
|
|
|
typedef char FILENAME[1024];
|
|
|
|
enum MONITOR {afskmodem_off, afskmodem_noinfo, afskmodem_normal,
|
|
afskmodem_passall};
|
|
|
|
|
|
enum CHANNELS {afskmodem_LEFT, afskmodem_RIGHT};
|
|
|
|
|
|
typedef float DFIRTAB[1024];
|
|
|
|
typedef float DFIR[64];
|
|
|
|
typedef float AFIRTAB[512];
|
|
|
|
struct MPAR;
|
|
|
|
|
|
struct MPAR {
|
|
uint8_t ch;
|
|
int32_t baudfine;
|
|
int32_t pllshift;
|
|
float left;
|
|
float tcnt;
|
|
float freq;
|
|
float afskmidfreq;
|
|
float clamp;
|
|
float squelchdcd;
|
|
float noise;
|
|
float afshift;
|
|
float afmid;
|
|
float txvolum;
|
|
float afskhighpass;
|
|
uint8_t monitor;
|
|
float sqmed[2];
|
|
uint32_t dfin;
|
|
DFIRTAB dfirtab;
|
|
DFIR dfir;
|
|
AFIRTAB afirtab;
|
|
char afsk;
|
|
char cbit;
|
|
char oldd;
|
|
char plld;
|
|
char scramb;
|
|
char data1;
|
|
char axudp2;
|
|
char dcdmsgs;
|
|
char haddcd;
|
|
char hadtxdata;
|
|
char haddcdrand;
|
|
char flagbeg;
|
|
uint32_t flagc; /* for statistic */
|
|
uint32_t flags;
|
|
uint32_t flage;
|
|
uint32_t rxstuffc;
|
|
uint32_t rxbyte;
|
|
uint32_t rxbitc;
|
|
uint32_t rxp;
|
|
uint32_t demodbaud;
|
|
uint32_t txbaud;
|
|
uint32_t port16;
|
|
uint32_t dcdclockm;
|
|
uint32_t bertc;
|
|
uint32_t berterr;
|
|
uint32_t txdel;
|
|
uint32_t txtail;
|
|
uint32_t rxcrc;
|
|
uint32_t scrambler;
|
|
char rxbuf[339];
|
|
pKISSNEXT txbufin;
|
|
pKISSNEXT txbufout;
|
|
uint32_t timeout;
|
|
uint32_t configbaud;
|
|
uint32_t configtxdel;
|
|
uint32_t configtxtail;
|
|
uint32_t txdelpattern;
|
|
uint32_t configafskshift;
|
|
uint32_t configafskmid;
|
|
uint32_t confignyquist;
|
|
int32_t configequalizer;
|
|
int32_t leveldcd;
|
|
int32_t bert;
|
|
char configured;
|
|
char kissignore;
|
|
int32_t udpsocket;
|
|
uint32_t udpport;
|
|
uint32_t udpbind;
|
|
uint32_t udpip;
|
|
char checkip;
|
|
};
|
|
|
|
enum TXSTATE {afskmodem_receiv, afskmodem_slotwait, afskmodem_sendtxdel,
|
|
afskmodem_senddata, afskmodem_sendtxtail};
|
|
|
|
|
|
enum DUPLEX {afskmodem_simplex, afskmodem_shiftdigi, afskmodem_fullduplex,
|
|
afskmodem_onetx};
|
|
|
|
|
|
struct CHAN;
|
|
|
|
|
|
struct CHAN {
|
|
uint32_t gmqtime;
|
|
uint32_t gmcnt; /* gm900 quiet tx time after ptt */
|
|
uint32_t dcdclock;
|
|
uint32_t pttsoundbufs;
|
|
uint32_t dds;
|
|
uint32_t txbaudgen;
|
|
uint32_t addrandom;
|
|
uint32_t tbyte;
|
|
uint32_t tbytec;
|
|
int32_t txstuffc;
|
|
int32_t tbitc;
|
|
char * hptt;
|
|
char pttstate;
|
|
char tnrzi;
|
|
uint8_t state;
|
|
uint8_t duplex;
|
|
float persist;
|
|
float hipasscap;
|
|
uint32_t tscramb;
|
|
int32_t adcmax;
|
|
int32_t actmodem;
|
|
uint32_t configpersist;
|
|
float afir[32];
|
|
};
|
|
|
|
static int32_t pipefd;
|
|
|
|
static int32_t soundfd;
|
|
|
|
static int32_t debfd;
|
|
|
|
static char esc;
|
|
|
|
static char abortonsounderr;
|
|
|
|
static char badsounddriver;
|
|
|
|
static char deb01;
|
|
|
|
static uint32_t debp;
|
|
|
|
static uint32_t getst;
|
|
|
|
static uint32_t afin;
|
|
|
|
static uint32_t soundbufs;
|
|
|
|
static uint32_t maxsoundbufs;
|
|
|
|
static uint32_t adcrate;
|
|
|
|
static uint32_t adcbuflen;
|
|
|
|
static uint32_t adcbytes;
|
|
|
|
static uint32_t fragmentsize;
|
|
|
|
static uint32_t extraaudiodelay;
|
|
|
|
static uint32_t clock0;
|
|
|
|
static uint32_t systime;
|
|
|
|
static uint8_t maxchannels;
|
|
|
|
static struct CHAN chan[2];
|
|
|
|
static pKISSNEXT pTxFree;
|
|
|
|
static pKISSNEXT pGetKiss;
|
|
|
|
static TXFIRTAB TFIR;
|
|
|
|
static struct MPAR modpar[8];
|
|
|
|
static float SIN[32768];
|
|
|
|
static uint8_t CRCL[256];
|
|
|
|
static uint8_t CRCH[256];
|
|
|
|
static FILENAME soundfn;
|
|
|
|
static char debb[81];
|
|
|
|
|
|
static void Error(char text[], uint32_t text_len)
|
|
{
|
|
X2C_PCOPY((void **)&text,text_len);
|
|
osi_WrStr(text, text_len);
|
|
osi_WrStrLn(" error abort", 13ul);
|
|
X2C_ABORT();
|
|
X2C_PFREE(text);
|
|
} /* end Error() */
|
|
|
|
/*
|
|
PROCEDURE SetStatLine(fd:INTEGER; rts, dtr:BOOLEAN):BOOLEAN;
|
|
VAR arg : ARRAY[0..255] OF CARDINAL;
|
|
r:INTEGER;
|
|
BEGIN
|
|
arg[0]:=TIOCM_RTS;
|
|
IF rts THEN r:=ioctl(fd, TIOCMBIS, ADR(arg)) ELSE r:=ioctl(fd, TIOCMBIC,
|
|
ADR(arg)) END;
|
|
IF r>=0 THEN
|
|
arg[0]:=TIOCM_DTR;
|
|
IF dtr THEN r:=ioctl(fd, TIOCMBIS, ADR(arg)) ELSE r:=ioctl(fd, TIOCMBIC,
|
|
ADR(arg)) END;
|
|
END;
|
|
RETURN r>=0
|
|
END SetStatLine;
|
|
*/
|
|
|
|
static void Hamming(float f[], uint32_t f_len)
|
|
{
|
|
uint32_t i;
|
|
uint32_t tmp;
|
|
tmp = f_len-1;
|
|
i = 0UL;
|
|
if (i<=tmp) for (;; i++) {
|
|
f[i] = f[i]*(0.54f+0.46f*osic_cos(3.1415926535898f*(X2C_DIVR((float)
|
|
i,(float)(1UL+(f_len-1))))));
|
|
if (i==tmp) break;
|
|
} /* end for */
|
|
} /* end Hamming() */
|
|
|
|
|
|
static void initdfir(DFIRTAB dfirtab, uint32_t fg)
|
|
{
|
|
uint32_t f;
|
|
uint32_t i;
|
|
float t[512];
|
|
float e;
|
|
float f1;
|
|
uint32_t tmp;
|
|
for (i = 0UL; i<=511UL; i++) {
|
|
t[i] = 0.5f;
|
|
} /* end for */
|
|
f1 = X2C_DIVR((float)(fg*64UL),(float)adcrate);
|
|
tmp = (uint32_t)X2C_TRUNCC(f1,0UL,X2C_max_longcard)+1UL;
|
|
f = 1UL;
|
|
if (f<=tmp) for (;; f++) {
|
|
e = 1.0f;
|
|
if (f==(uint32_t)X2C_TRUNCC(f1,0UL,X2C_max_longcard)+1UL) {
|
|
e = f1-(float)(uint32_t)X2C_TRUNCC(f1,0UL,X2C_max_longcard);
|
|
}
|
|
for (i = 0UL; i<=511UL; i++) {
|
|
t[i] = t[i]+e*osic_cos(X2C_DIVR(3.1415926535898f*(float)(i*f),
|
|
512.0f));
|
|
} /* end for */
|
|
if (f==tmp) break;
|
|
} /* end for */
|
|
/*
|
|
FOR f:=1 TO fg*DFIRLEN DIV adcrate DO
|
|
FOR i:=0 TO HIGH(t) DO t[i]:=t[i]+cos(pi*FLOAT(i*f)/FLOAT(HIGH(t)+1))
|
|
END;
|
|
END;
|
|
*/
|
|
Hamming(t, 512ul);
|
|
/* FOR i:=0 TO HIGH(t) DO t[i]:=t[i]*(0.54+0.46*cos(pi*(FLOAT(i)
|
|
/FLOAT(1+HIGH(t))))) END; */
|
|
for (i = 0UL; i<=511UL; i++) {
|
|
dfirtab[511UL+i] = t[i];
|
|
dfirtab[511UL-i] = t[i];
|
|
} /* end for */
|
|
/*
|
|
IO.WrLn;
|
|
FOR i:=0 TO HIGH(dfirtab) DO IO.WrFixed(dfirtab[i], 2,8) END;
|
|
IO.WrLn;
|
|
*/
|
|
/*
|
|
fd:=FIO.Create("/tmp/td.raw");
|
|
FOR i:=0 TO HIGH(dfirtab) DO n:=VAL(INTEGER, dfirtab[i]*2000.0);
|
|
FIO.WrBin(fd,n,2) END;
|
|
FIO.Close(fd);
|
|
*/
|
|
} /* end initdfir() */
|
|
|
|
|
|
static void initafir(AFIRTAB atab, uint32_t F0, uint32_t F1,
|
|
float eq)
|
|
{
|
|
uint32_t f;
|
|
uint32_t i;
|
|
float t[256];
|
|
float f10;
|
|
float f00;
|
|
float e;
|
|
uint32_t tmp;
|
|
f00 = X2C_DIVR((float)(F0*32UL),(float)adcrate);
|
|
f10 = X2C_DIVR((float)(F1*32UL),(float)adcrate);
|
|
for (i = 0UL; i<=255UL; i++) {
|
|
t[i] = 0.0f;
|
|
} /* end for */
|
|
tmp = (uint32_t)X2C_TRUNCC(f10,0UL,X2C_max_longcard)+1UL;
|
|
f = (uint32_t)X2C_TRUNCC(f00,0UL,X2C_max_longcard);
|
|
if (f<=tmp) for (;; f++) {
|
|
e = 1.0f+eq*((X2C_DIVR((float)f,X2C_DIVR((float)((F0+F1)*32UL),
|
|
(float)adcrate)))*2.0f-1.0f);
|
|
/*
|
|
e:=1.0 + eq*(FLOAT(f)/FLOAT((F0+F1)*AFIRLEN DIV adcrate)*2.0-1.0);
|
|
*/
|
|
if (e<0.0f) e = 0.0f;
|
|
if (f==(uint32_t)X2C_TRUNCC(f00,0UL,X2C_max_longcard)) {
|
|
e = e*(1.0f-(f00-(float)(uint32_t)X2C_TRUNCC(f00,0UL,
|
|
X2C_max_longcard)));
|
|
}
|
|
if (f==(uint32_t)X2C_TRUNCC(f10,0UL,X2C_max_longcard)+1UL) {
|
|
e = e*(f10-(float)(uint32_t)X2C_TRUNCC(f10,0UL,
|
|
X2C_max_longcard));
|
|
}
|
|
/*
|
|
IF eq<>0 THEN IO.WrFixed(e,2,2);IO.WrLn; END;
|
|
*/
|
|
if (f==0UL) {
|
|
for (i = 0UL; i<=255UL; i++) {
|
|
t[i] = t[i]+e*0.5f;
|
|
} /* end for */
|
|
}
|
|
else {
|
|
for (i = 0UL; i<=255UL; i++) {
|
|
t[i] = t[i]+e*osic_cos(X2C_DIVR(3.1415926535898f*(float)(i*f),
|
|
256.0f));
|
|
} /* end for */
|
|
}
|
|
if (f==tmp) break;
|
|
} /* end for */
|
|
Hamming(t, 256ul);
|
|
for (i = 0UL; i<=255UL; i++) {
|
|
atab[255UL+i] = t[i];
|
|
atab[255UL-i] = t[i];
|
|
} /* end for */
|
|
if (F0>0UL) {
|
|
/* make dc level zero */
|
|
e = 0.0f;
|
|
for (i = 0UL; i<=511UL; i++) {
|
|
e = e+atab[i];
|
|
} /* end for */
|
|
e = X2C_DIVR(e,512.0f);
|
|
for (i = 0UL; i<=511UL; i++) {
|
|
atab[i] = atab[i]-e;
|
|
} /* end for */
|
|
}
|
|
/*
|
|
IO.WrLn;
|
|
FOR i:=0 TO HIGH(atab) DO IO.WrFixed(atab[i], 2,8) END;
|
|
IO.WrLn;
|
|
*/
|
|
/*
|
|
IF eq<>0.0 THEN
|
|
debfd:=FIO.Create("/tmp/ta.raw");
|
|
FOR i:=0 TO HIGH(atab) DO f:=VAL(INTEGER, atab[i]*1000.0);
|
|
FIO.WrBin(debfd,f,2) END;
|
|
FIO.Close(debfd);
|
|
END;
|
|
*/
|
|
} /* end initafir() */
|
|
|
|
|
|
static void initTFIR(void)
|
|
{
|
|
uint32_t b;
|
|
uint32_t f;
|
|
uint32_t j;
|
|
uint32_t i;
|
|
float sym[384];
|
|
float sum[128];
|
|
float s[774];
|
|
float max0;
|
|
float k;
|
|
float fr;
|
|
for (i = 0UL; i<=383UL; i++) {
|
|
sym[i] = 0.5f;
|
|
} /* end for */
|
|
fr = 2.88f;
|
|
for (f = 1UL; f<=3UL; f++) {
|
|
if (f==(uint32_t)X2C_TRUNCC(fr,0UL,X2C_max_longcard)+1UL) {
|
|
k = fr-(float)(uint32_t)X2C_TRUNCC(fr,0UL,X2C_max_longcard);
|
|
}
|
|
else k = 1.0f;
|
|
for (i = 0UL; i<=383UL; i++) {
|
|
sym[i] = sym[i]+k*osic_cos(X2C_DIVR(3.1415926535898f*(float)(i*f)
|
|
,384.0f));
|
|
} /* end for */
|
|
} /* end for */
|
|
Hamming(sym, 384ul);
|
|
for (i = 0UL; i<=773UL; i++) {
|
|
s[i] = 0.0f;
|
|
} /* end for */
|
|
max0 = 0.0f;
|
|
for (i = 0UL; i<=383UL; i++) {
|
|
s[383UL+i+3UL] = sym[i];
|
|
s[(383UL-i)+3UL] = sym[i];
|
|
if ((float)fabs(sym[i])>max0) max0 = (float)fabs(sym[i]);
|
|
} /* end for */
|
|
max0 = X2C_DIVR(2.0f,max0);
|
|
for (j = 0UL; j<=63UL; j++) {
|
|
for (i = 0UL; i<=127UL; i++) {
|
|
sum[i] = 0.0f;
|
|
} /* end for */
|
|
for (b = 0UL; b<=5UL; b++) {
|
|
for (i = 0UL; i<=127UL; i++) {
|
|
sum[i] = sum[i]+s[i+b*128UL]*((float)(uint32_t)X2C_IN(b,32,
|
|
(uint32_t)j)-0.5f);
|
|
} /* end for */
|
|
} /* end for */
|
|
for (i = 0UL; i<=127UL; i++) {
|
|
TFIR[i][j] = sum[i]*max0;
|
|
} /* end for */
|
|
} /* end for */
|
|
} /* end initTFIR() */
|
|
|
|
|
|
static void SetMixer(char mixfn[], uint32_t mixfn_len,
|
|
uint32_t chan0, uint32_t left, uint32_t right)
|
|
{
|
|
int32_t fd;
|
|
X2C_PCOPY((void **)&mixfn,mixfn_len);
|
|
fd = osi_OpenRW(mixfn, mixfn_len);
|
|
if (fd>=0L) {
|
|
if (chan0==255UL) chan0 = recnum();
|
|
setmixer(fd, chan0, (right<<8)+left);
|
|
}
|
|
else {
|
|
osi_WrStr(mixfn, mixfn_len);
|
|
Error(" open", 6ul);
|
|
}
|
|
X2C_PFREE(mixfn);
|
|
} /* end SetMixer() */
|
|
|
|
|
|
static void OpenSound(void)
|
|
{
|
|
int32_t s;
|
|
int32_t i;
|
|
soundfd = osi_OpenRW(soundfn, 1024ul);
|
|
if (soundfd>=0L) {
|
|
i = samplesize(soundfd, 16UL); /* 8, 16 */
|
|
i = channels(soundfd, (uint32_t)maxchannels+1UL); /* 1, 2 */
|
|
i = setfragment(soundfd, fragmentsize); /* 2^bufsize * 65536*bufs*/
|
|
if (i) {
|
|
osi_WrStr("sound setfragment returns ", 27ul);
|
|
osic_WrINT32((uint32_t)i, 1UL);
|
|
osic_WrLn();
|
|
}
|
|
i = sampelrate(soundfd, adcrate); /* 8000..48000 */
|
|
s = (int32_t)getsampelrate(soundfd);
|
|
if (s!=(int32_t)adcrate) {
|
|
osi_WrStr("sound device returns ", 22ul);
|
|
osic_WrINT32((uint32_t)s, 1UL);
|
|
osi_WrStrLn("Hz!", 4ul);
|
|
}
|
|
}
|
|
else if (abortonsounderr) {
|
|
/*
|
|
IF s>=0 THEN Error("") END;
|
|
*/
|
|
osi_WrStr(soundfn, 1024ul);
|
|
Error(" open", 6ul);
|
|
}
|
|
} /* end OpenSound() */
|
|
|
|
|
|
static void ttypar(char fn[], uint32_t fn_len)
|
|
{
|
|
struct termios term;
|
|
int32_t fd;
|
|
int32_t res;
|
|
X2C_PCOPY((void **)&fn,fn_len);
|
|
fd = osi_OpenNONBLOCK(fn, fn_len);
|
|
if (fd>=0L) {
|
|
res = tcgetattr(fd, &term);
|
|
/*
|
|
term.c_lflag:=CAST(CARDINAL, CAST(BITSET,
|
|
term.c_lflag) - CAST(BITSET, ECHO));
|
|
*/
|
|
term.c_lflag = 0UL;
|
|
res = tcsetattr(fd, 0L, &term);
|
|
}
|
|
/*
|
|
res:=tcsetattr (fd, 0, term);
|
|
*/
|
|
osic_Close(fd);
|
|
X2C_PFREE(fn);
|
|
} /* end ttypar() */
|
|
|
|
|
|
static int32_t Opentty(char linkname[], uint32_t linkname_len)
|
|
{
|
|
int32_t fd;
|
|
char voidok;
|
|
char ptsname[4096];
|
|
int32_t Opentty_ret;
|
|
X2C_PCOPY((void **)&linkname,linkname_len);
|
|
fd = osi_OpenNONBLOCK("/dev/ptmx", 10ul);
|
|
if (fd<0L) Error("/dev/ptmx open", 15ul);
|
|
if (osi_getptsname(fd, (char *)ptsname, 4096UL)) {
|
|
Error("no ttyname", 11ul);
|
|
}
|
|
/*
|
|
IO.WrStr(ptsname); IO.WrLn;
|
|
*/
|
|
if (osic_grantpts(fd)) Error("ptty grant", 11ul);
|
|
if (osic_unlockpts(fd)) Error("ptty unlock", 12ul);
|
|
ttypar(ptsname, 4096ul);
|
|
/*make link*/
|
|
osi_Erase(linkname, linkname_len, &voidok);
|
|
if (osi_symblink((char *)ptsname, (char *)linkname)) {
|
|
osi_WrStr("cannot create link <", 21ul);
|
|
osi_WrStr(linkname, linkname_len);
|
|
osi_WrStrLn(">, starting without kiss interface", 35ul);
|
|
osic_Close(fd);
|
|
fd = -1L;
|
|
}
|
|
Opentty_ret = fd;
|
|
X2C_PFREE(linkname);
|
|
return Opentty_ret;
|
|
} /* end Opentty() */
|
|
|
|
|
|
static void Makekissbufs(uint32_t n)
|
|
{
|
|
pKISSNEXT pt;
|
|
uint32_t i;
|
|
pTxFree = 0;
|
|
pGetKiss = 0;
|
|
i = 0UL;
|
|
for (;;) {
|
|
if (i>=n) break;
|
|
osic_alloc((char * *) &pt, sizeof(struct KISSBUF));
|
|
++i;
|
|
if (pt==0) break;
|
|
pt->next = pTxFree;
|
|
pTxFree = pt;
|
|
}
|
|
} /* end Makekissbufs() */
|
|
|
|
|
|
static void StoBuf(int32_t m, pKISSNEXT p)
|
|
{
|
|
struct MPAR * anonym;
|
|
{ /* with */
|
|
struct MPAR * anonym = &modpar[m];
|
|
if (anonym->configured && pTxFree) {
|
|
p->next = 0;
|
|
if (anonym->txbufin==0) anonym->txbufin = p;
|
|
else anonym->txbufout->next = p;
|
|
anonym->txbufout = p;
|
|
}
|
|
else {
|
|
p->next = pTxFree; /* discard frame, out of memory */
|
|
pTxFree = p;
|
|
}
|
|
}
|
|
} /* end StoBuf() */
|
|
|
|
|
|
static void ExtractWord(char w[], uint32_t w_len, char s[],
|
|
uint32_t s_len)
|
|
{
|
|
uint32_t j;
|
|
uint32_t i;
|
|
w[0UL] = 0;
|
|
i = 0UL;
|
|
while ((i<=s_len-1 && s[i]) && s[i]!=':') {
|
|
if (i<=w_len-1) w[i] = s[i];
|
|
++i;
|
|
}
|
|
if (i<=w_len-1) w[i] = 0;
|
|
j = 0UL;
|
|
if (i<=s_len-1 && s[i]) {
|
|
++i;
|
|
while (i<=s_len-1 && s[i]) {
|
|
s[j] = s[i];
|
|
++i;
|
|
++j;
|
|
}
|
|
}
|
|
s[j] = 0;
|
|
} /* end ExtractWord() */
|
|
|
|
|
|
static void Config(void)
|
|
{
|
|
int32_t i;
|
|
uint8_t c;
|
|
struct CHAN * anonym;
|
|
struct MPAR * anonym0;
|
|
for (c = afskmodem_LEFT;; c++) {
|
|
{ /* with */
|
|
struct CHAN * anonym = &chan[c];
|
|
anonym->persist = (float)
|
|
((anonym->configpersist*adcrate*((uint32_t)maxchannels+1UL)
|
|
)/adcbuflen)*0.001f; /* ms */
|
|
}
|
|
if (c==afskmodem_RIGHT) break;
|
|
} /* end for */
|
|
for (i = 0L; i<=7L; i++) {
|
|
{ /* with */
|
|
struct MPAR * anonym0 = &modpar[i];
|
|
anonym0->txbaud = (anonym0->configbaud*65536UL)/adcrate;
|
|
anonym0->demodbaud = anonym0->txbaud*2UL;
|
|
anonym0->txdel = (anonym0->configbaud*anonym0->configtxdel)/8000UL;
|
|
anonym0->txtail = 2UL+2UL*(uint32_t)
|
|
anonym0->scramb+(anonym0->configbaud*anonym0->configtxtail)
|
|
/8000UL;
|
|
anonym0->afskmidfreq = X2C_DIVR((float)
|
|
anonym0->configafskmid*2.0f,(float)adcrate);
|
|
anonym0->afshift = X2C_DIVR(0.5f*(float)
|
|
(anonym0->configafskshift*32768UL),(float)adcrate);
|
|
anonym0->afmid = X2C_DIVR((float)(anonym0->configafskmid*32768UL)
|
|
,(float)adcrate);
|
|
if (anonym0->afsk) {
|
|
initafir(anonym0->afirtab,
|
|
(anonym0->configafskmid-anonym0->configafskshift/2UL)
|
|
-anonym0->configbaud/4UL,
|
|
anonym0->configafskmid+anonym0->configafskshift/2UL+anonym0->configbaud/4UL,
|
|
X2C_DIVR((float)anonym0->configequalizer,100.0f));
|
|
initdfir(anonym0->dfirtab,
|
|
(anonym0->configbaud*anonym0->confignyquist)/100UL);
|
|
}
|
|
else {
|
|
initafir(anonym0->afirtab, 0UL,
|
|
(anonym0->configbaud*anonym0->confignyquist)/100UL,
|
|
X2C_DIVR((float)anonym0->configequalizer,100.0f));
|
|
}
|
|
anonym0->baudfine = 0L;
|
|
anonym0->left = 0.0f;
|
|
anonym0->tcnt = 0.0f;
|
|
anonym0->freq = 0.0f;
|
|
anonym0->dfin = 0UL;
|
|
anonym0->cbit = 0;
|
|
anonym0->rxp = 0UL;
|
|
anonym0->rxbitc = 0UL;
|
|
anonym0->rxcrc = 0xFFFFUL;
|
|
}
|
|
} /* end for */
|
|
} /* end Config() */
|
|
|
|
/*
|
|
PROCEDURE GetIp(h:ARRAY OF CHAR; VAR ip:IPNUM; VAR dp, lp:UDPPORT;
|
|
VAR fd:INTEGER; VAR check:BOOLEAN):INTEGER;
|
|
VAR i, p, n:CARDINAL;
|
|
ok:BOOLEAN;
|
|
BEGIN
|
|
p:=0;
|
|
h[HIGH(h)]:=0C;
|
|
ip:=0;
|
|
n:=0;
|
|
FOR i:=0 TO 5 DO
|
|
n:=0;
|
|
ok:=FALSE;
|
|
WHILE (h[p]>="0") & (h[p]<="9") DO
|
|
ok:=TRUE;
|
|
n:=n*10+ORD(h[p])-ORD("0");
|
|
INC(p);
|
|
END;
|
|
IF NOT ok THEN RETURN -1 END;
|
|
IF i<3 THEN
|
|
IF (h[p]<>".") OR (n>255) THEN RETURN -1 END;
|
|
ip:=ip*256+n;
|
|
ELSIF i=3 THEN
|
|
ip:=ip*256+n;
|
|
IF (h[p]<>":")OR (n>255) THEN RETURN -1 END;
|
|
ELSIF i=4 THEN
|
|
check:=h[p]<>"/";
|
|
IF (h[p]<>":") & (h[p]<>"/") OR (n>65535) THEN RETURN -1 END;
|
|
dp:=n;
|
|
ELSIF n>65535 THEN RETURN -1 END;
|
|
lp:=n;
|
|
INC(p);
|
|
END;
|
|
|
|
fd:=udp.openudp();
|
|
IF (fd<0) OR (udp.bindudp(fd, lp)<0) (*OR (udp.udpnonblock(fd)<0)*) THEN RETURN -1 END;
|
|
RETURN 0
|
|
|
|
END GetIp;
|
|
*/
|
|
|
|
static int32_t GetIp(char h[], uint32_t h_len, uint32_t * ip,
|
|
uint32_t * dp, uint32_t * lp, int32_t * fd,
|
|
char * check)
|
|
{
|
|
int32_t GetIp_ret;
|
|
X2C_PCOPY((void **)&h,h_len);
|
|
if (aprsstr_GetIp2(h, h_len, ip, dp, lp, check)<0L) {
|
|
GetIp_ret = -1L;
|
|
goto label;
|
|
}
|
|
*fd = openudp();
|
|
if (*fd<0L || bindudp(*fd, *lp)<0L) {
|
|
/*OR (udp.udpnonblock(fd)<0)*/
|
|
GetIp_ret = -1L;
|
|
goto label;
|
|
}
|
|
GetIp_ret = 0L;
|
|
label:;
|
|
X2C_PFREE(h);
|
|
return GetIp_ret;
|
|
} /* end GetIp() */
|
|
|
|
|
|
static void bertstart(void)
|
|
{
|
|
pKISSNEXT p;
|
|
uint32_t i;
|
|
struct MPAR * anonym;
|
|
for (i = 0UL; i<=7UL; i++) {
|
|
{ /* with */
|
|
struct MPAR * anonym = &modpar[i];
|
|
if (anonym->bert>0L && pTxFree) {
|
|
p = pTxFree;
|
|
pTxFree = pTxFree->next;
|
|
p->port = (char)i;
|
|
p->len = 0UL;
|
|
p->time0 = X2C_max_longcard;
|
|
StoBuf((int32_t)i, p);
|
|
}
|
|
}
|
|
} /* end for */
|
|
} /* end bertstart() */
|
|
|
|
|
|
static void Parms(void)
|
|
{
|
|
char err;
|
|
FILENAME pipefn;
|
|
FILENAME mixfn;
|
|
FILENAME h1;
|
|
FILENAME h;
|
|
char ptth[4096];
|
|
uint32_t right;
|
|
uint32_t left;
|
|
uint32_t cnum;
|
|
uint32_t kissbufs;
|
|
int32_t inum;
|
|
int32_t modem;
|
|
int32_t channel;
|
|
uint8_t c;
|
|
struct CHAN * anonym;
|
|
struct MPAR * anonym0;
|
|
struct MPAR * anonym1;
|
|
err = 0;
|
|
abortonsounderr = 0;
|
|
adcrate = 16000UL;
|
|
adcbytes = 2UL;
|
|
adcbuflen = 256UL;
|
|
fragmentsize = 9UL;
|
|
maxchannels = afskmodem_LEFT;
|
|
extraaudiodelay = 1UL;
|
|
debfd = -1L;
|
|
deb01 = 0;
|
|
debp = 0UL;
|
|
badsounddriver = 0;
|
|
for (cnum = 0UL; cnum<=32767UL; cnum++) {
|
|
SIN[cnum] = osic_cos(X2C_DIVR((float)cnum*2.0f*3.1415926535898f,
|
|
32768.0f));
|
|
} /* end for */
|
|
for (c = afskmodem_LEFT;; c++) {
|
|
{ /* with */
|
|
struct CHAN * anonym = &chan[c];
|
|
anonym->state = afskmodem_receiv;
|
|
anonym->pttsoundbufs = 0UL;
|
|
anonym->dds = 0UL;
|
|
anonym->duplex = afskmodem_simplex;
|
|
anonym->persist = 800.0f;
|
|
anonym->actmodem = -1L;
|
|
anonym->hptt = 0;
|
|
anonym->configpersist = 800UL;
|
|
anonym->tscramb = 0x1UL; /* for bert */
|
|
anonym->gmqtime = 0UL;
|
|
}
|
|
if (c==afskmodem_RIGHT) break;
|
|
} /* end for */
|
|
for (cnum = 0UL; cnum<=7UL; cnum++) {
|
|
{ /* with */
|
|
struct MPAR * anonym0 = &modpar[cnum];
|
|
anonym0->configured = cnum==0UL;
|
|
anonym0->configbaud = 1200UL;
|
|
anonym0->configtxdel = 300UL;
|
|
anonym0->configtxtail = 20UL;
|
|
anonym0->configafskshift = 1000UL;
|
|
anonym0->configafskmid = 1700UL;
|
|
anonym0->confignyquist = 75UL;
|
|
anonym0->configequalizer = 0L;
|
|
anonym0->kissignore = 0;
|
|
anonym0->leveldcd = 10L;
|
|
anonym0->pllshift = 4096L;
|
|
anonym0->ch = afskmodem_LEFT;
|
|
anonym0->afsk = 1;
|
|
anonym0->monitor = afskmodem_normal;
|
|
anonym0->scramb = 0;
|
|
anonym0->clamp = 0.996f;
|
|
anonym0->port16 = cnum*16UL;
|
|
anonym0->squelchdcd = 0.14f;
|
|
anonym0->txbufin = 0;
|
|
anonym0->bert = 0L;
|
|
anonym0->txdelpattern = 126UL;
|
|
anonym0->txvolum = 25000.0f;
|
|
anonym0->afskhighpass = 0.0f;
|
|
anonym0->timeout = 60UL;
|
|
anonym0->udpsocket = -1L;
|
|
}
|
|
} /* end for */
|
|
kissbufs = 60UL;
|
|
channel = -1L;
|
|
modem = -1L;
|
|
X2C_COPY("/dev/dsp",9ul,soundfn,1024u);
|
|
pipefn[0U] = 0;
|
|
X2C_COPY("/dev/mixer",11ul,mixfn,1024u);
|
|
maxsoundbufs = 10UL;
|
|
for (;;) {
|
|
osi_NextArg(h, 1024ul);
|
|
if (h[0U]==0) break;
|
|
if ((h[0U]=='-' && h[1U]) && h[2U]==0) {
|
|
if (h[1U]=='a') {
|
|
if (modem>=0L) modpar[modem].afsk = 0;
|
|
else if (channel<=0L) abortonsounderr = 1;
|
|
else Error("need modem number -M before -a", 31ul);
|
|
}
|
|
else if (h[1U]=='b') {
|
|
osi_NextArg(h, 1024ul);
|
|
if (modem>=0L) {
|
|
if (!aprsstr_StrToCard(h, 1024ul, &cnum)) err = 1;
|
|
if (cnum>=adcrate) {
|
|
Error("sampelrate -f too low for this baud", 36ul);
|
|
}
|
|
modpar[modem].configbaud = cnum;
|
|
}
|
|
else {
|
|
if (!aprsstr_StrToCard(h, 1024ul, &cnum)) err = 1;
|
|
maxsoundbufs = cnum;
|
|
}
|
|
}
|
|
else if (h[1U]=='B') {
|
|
if (modem<0L && channel<0L) {
|
|
badsounddriver = 1;
|
|
}
|
|
else {
|
|
osi_NextArg(h, 1024ul);
|
|
if (!aprsstr_StrToInt(h, 1024ul, &inum)) err = 1;
|
|
if (modem>=0L) modpar[modem].bert = inum*8000L;
|
|
else Error("need modem number -M before -B", 31ul);
|
|
}
|
|
}
|
|
else if (h[1U]=='C') {
|
|
osi_NextArg(h, 1024ul);
|
|
if (!aprsstr_StrToCard(h, 1024ul, &cnum)) err = 1;
|
|
if (cnum>1UL) Error("channel 0 to 1", 15ul);
|
|
channel = (int32_t)cnum;
|
|
}
|
|
else if (h[1U]=='c') {
|
|
osi_NextArg(h, 1024ul);
|
|
if (!aprsstr_StrToCard(h, 1024ul, &cnum)) err = 1;
|
|
if (modem>=0L) {
|
|
if (cnum>(uint32_t)maxchannels) {
|
|
Error("channel too high", 17ul);
|
|
}
|
|
modpar[modem].ch = (uint8_t)cnum;
|
|
}
|
|
else {
|
|
if (cnum<1UL || cnum>2UL) Error("maxchannels 1..2", 17ul);
|
|
maxchannels = (uint8_t)(cnum-1UL);
|
|
}
|
|
}
|
|
else if (h[1U]=='D') {
|
|
osi_NextArg(h1, 1024ul);
|
|
debfd = creat(h1, 420L);
|
|
inum = 0L;
|
|
while (inum<1023L && h1[inum]) ++inum;
|
|
deb01 = (((inum>=4L && h1[inum-4L]=='.') && h1[inum-3L]=='t')
|
|
&& h1[inum-2L]=='x') && h1[inum-1L]=='t';
|
|
}
|
|
else if (h[1U]=='d') {
|
|
osi_NextArg(h, 1024ul);
|
|
if (!aprsstr_StrToCard(h, 1024ul, &cnum)) err = 1;
|
|
if (modem>=0L) {
|
|
modpar[modem].squelchdcd = X2C_DIVR((float)cnum,400.0f);
|
|
}
|
|
else Error("need modem number -M before -d", 31ul);
|
|
}
|
|
else if (h[1U]=='e') {
|
|
osi_NextArg(h, 1024ul);
|
|
if (modem>=0L) {
|
|
if (!aprsstr_StrToInt(h, 1024ul, &inum)) err = 1;
|
|
if (labs(inum)>999L) Error("equalizer -999..999", 20ul);
|
|
modpar[modem].configequalizer = inum;
|
|
}
|
|
else {
|
|
if (channel>=0L) {
|
|
Error("need modem number -M before -e", 31ul);
|
|
}
|
|
if (!aprsstr_StrToCard(h, 1024ul, &extraaudiodelay)) err = 1;
|
|
}
|
|
}
|
|
else if (h[1U]=='f') {
|
|
osi_NextArg(h, 1024ul);
|
|
if (!aprsstr_StrToCard(h, 1024ul, &cnum)) err = 1;
|
|
if (modem>=0L) modpar[modem].configafskmid = cnum;
|
|
else if (channel>=0L) {
|
|
if (cnum>3UL) Error("duplex 0..3", 12ul);
|
|
chan[channel].duplex = (uint8_t)cnum;
|
|
}
|
|
else {
|
|
if (cnum<8000UL || cnum>96000UL) {
|
|
Error("sampelrate 8000..96000", 23ul);
|
|
}
|
|
adcrate = cnum;
|
|
}
|
|
}
|
|
else if (h[1U]=='g') {
|
|
if (modem>=0L) modpar[modem].scramb = 1;
|
|
else if (channel>=0L) {
|
|
osi_NextArg(h, 1024ul);
|
|
if (!aprsstr_StrToCard(h, 1024ul, &cnum) || cnum>999UL) {
|
|
Error("-g <ms>", 8ul);
|
|
}
|
|
chan[channel].gmqtime = (cnum*adcrate)/1000UL;
|
|
}
|
|
else Error("need modem number -M before -g", 31ul);
|
|
}
|
|
else if (h[1U]=='H') {
|
|
osi_NextArg(h, 1024ul);
|
|
if (!aprsstr_StrToCard(h, 1024ul, &cnum)) err = 1;
|
|
if (modem>=0L) modpar[modem].afskhighpass = (float)cnum*0.01f;
|
|
else Error("need modem number -M before -H", 31ul);
|
|
}
|
|
else if (h[1U]=='i') {
|
|
if (modem>=0L) modpar[modem].kissignore = 1;
|
|
else osi_NextArg(pipefn, 1024ul);
|
|
}
|
|
else if (h[1U]=='k') {
|
|
osi_NextArg(h, 1024ul);
|
|
if (!aprsstr_StrToCard(h, 1024ul, &cnum)) err = 1;
|
|
if (modem>=0L) {
|
|
if (cnum>7UL) Error("kissports 0..7", 15ul);
|
|
modpar[modem].port16 = cnum*16UL;
|
|
}
|
|
else kissbufs = cnum;
|
|
}
|
|
else if (h[1U]=='l') {
|
|
osi_NextArg(h, 1024ul);
|
|
if (!aprsstr_StrToCard(h, 1024ul, &cnum)) err = 1;
|
|
if (cnum>=16UL && cnum<=4096UL) adcbuflen = cnum;
|
|
else Error("sound buffer out of range", 26ul);
|
|
}
|
|
else if (h[1U]=='M') {
|
|
osi_NextArg(h, 1024ul);
|
|
if (!aprsstr_StrToCard(h, 1024ul, &cnum)) err = 1;
|
|
if (cnum>7UL) Error(">maxmodems", 11ul);
|
|
modem = (int32_t)cnum;
|
|
modpar[modem].configured = 1;
|
|
}
|
|
else if (h[1U]=='m') {
|
|
osi_NextArg(h, 1024ul);
|
|
if (modem<0L && channel<0L) {
|
|
while (h[0U]) {
|
|
ExtractWord(h1, 1024ul, h, 1024ul);
|
|
if (h1[0U]=='/') X2C_COPY(h1,1024u,mixfn,1024u);
|
|
else {
|
|
if (!aprsstr_StrToCard(h1, 1024ul, &cnum)) err = 1;
|
|
ExtractWord(h1, 1024ul, h, 1024ul);
|
|
if (!aprsstr_StrToCard(h1, 1024ul, &left)) err = 1;
|
|
ExtractWord(h1, 1024ul, h, 1024ul);
|
|
if (!aprsstr_StrToCard(h1, 1024ul, &right)) err = 1;
|
|
if (!err) SetMixer(mixfn, 1024ul, cnum, left, right);
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
if (!aprsstr_StrToCard(h, 1024ul, &cnum)) err = 1;
|
|
if (cnum>3UL) Error("monitor 0..3", 13ul);
|
|
if (modem>=0L) modpar[modem].monitor = (uint8_t)cnum;
|
|
else Error("need modem number -M before -m", 31ul);
|
|
}
|
|
}
|
|
else if (h[1U]=='n') {
|
|
osi_NextArg(h, 1024ul);
|
|
if (!aprsstr_StrToCard(h, 1024ul, &cnum)) err = 1;
|
|
if (modem>=0L) modpar[modem].confignyquist = cnum;
|
|
else Error("need modem number -M before -n", 31ul);
|
|
}
|
|
else if (h[1U]=='o') osi_NextArg(soundfn, 1024ul);
|
|
else if (h[1U]=='p') {
|
|
if (modem>=0L) {
|
|
osi_NextArg(h, 1024ul);
|
|
if (!aprsstr_StrToCard(h, 1024ul, &cnum)) err = 1;
|
|
modpar[modem].pllshift = (int32_t)(cnum*256UL);
|
|
}
|
|
else if (channel>=0L) {
|
|
osi_NextArg(h1, 1024ul);
|
|
osi_NextArg(h, 1024ul);
|
|
if (!aprsstr_StrToInt(h, 1024ul, &inum)) err = 1;
|
|
inum = labs(inum)+1L;
|
|
if (h[0U]=='-') inum = -inum;
|
|
chan[channel].hptt = pttinit((char *)h1, inum);
|
|
}
|
|
}
|
|
else if (h[1U]=='q') {
|
|
if (modem>=0L) {
|
|
osi_NextArg(h, 1024ul);
|
|
if (!aprsstr_StrToCard(h, 1024ul, &cnum)) err = 1;
|
|
modpar[modem].leveldcd = (int32_t)cnum;
|
|
}
|
|
else Error("need modem number -M before -q", 31ul);
|
|
}
|
|
else if (h[1U]=='r') {
|
|
osi_NextArg(h, 1024ul);
|
|
if (!aprsstr_StrToCard(h, 1024ul, &cnum)) err = 1;
|
|
if (channel>=0L) {
|
|
if (!aprsstr_StrToCard(h, 1024ul,
|
|
&chan[channel].configpersist)) err = 1;
|
|
}
|
|
else Error("need channel number -C before -r", 33ul);
|
|
}
|
|
else if (h[1U]=='s') {
|
|
osi_NextArg(h, 1024ul);
|
|
if (!aprsstr_StrToCard(h, 1024ul, &cnum)) err = 1;
|
|
if (modem>=0L) modpar[modem].configafskshift = cnum;
|
|
else fragmentsize = cnum;
|
|
}
|
|
else if (h[1U]=='t') {
|
|
if (modem>=0L) {
|
|
osi_NextArg(h, 1024ul);
|
|
if (!aprsstr_StrToCard(h, 1024ul, &cnum)) err = 1;
|
|
modpar[modem].configtxdel = cnum;
|
|
}
|
|
}
|
|
else if (h[1U]=='u') {
|
|
if (channel>=0L) pttSetclaim(chan[channel].hptt, 1L);
|
|
}
|
|
else if ((h[1U]=='U' || h[1U]=='L') || h[1U]=='P') {
|
|
if (modem>=0L) {
|
|
modpar[modem].axudp2 = h[1U]!='U'; /* switch on axudp2 */
|
|
modpar[modem].dcdmsgs = h[1U]=='P';
|
|
/* send dcd change & txbuffer empty messages*/
|
|
osi_NextArg(h, 1024ul);
|
|
{ /* with */
|
|
struct MPAR * anonym1 = &modpar[modem];
|
|
if (GetIp(h, 1024ul, &anonym1->udpip, &anonym1->udpport,
|
|
&anonym1->udpbind, &anonym1->udpsocket,
|
|
&anonym1->checkip)<0L) Error("cannot open udp socket", 23ul);
|
|
}
|
|
}
|
|
else Error("need modem number -M before -U", 31ul);
|
|
}
|
|
else if (h[1U]=='v') {
|
|
if (modem>=0L) {
|
|
osi_NextArg(h, 1024ul);
|
|
if (!aprsstr_StrToCard(h, 1024ul, &cnum)) err = 1;
|
|
if (cnum>100UL) cnum = 100UL;
|
|
modpar[modem].txvolum = (float)cnum*250.0f;
|
|
}
|
|
else Error("need modem number -M before -w", 31ul);
|
|
}
|
|
else if (h[1U]=='T') {
|
|
if (modem>=0L) {
|
|
osi_NextArg(h, 1024ul);
|
|
if (!aprsstr_StrToCard(h, 1024ul, &cnum)) err = 1;
|
|
modpar[modem].timeout = cnum;
|
|
}
|
|
else Error("need modem number -M before -T", 31ul);
|
|
}
|
|
else if (h[1U]=='w') {
|
|
if (modem>=0L) {
|
|
osi_NextArg(h, 1024ul);
|
|
if (!aprsstr_StrToCard(h, 1024ul, &cnum)) err = 1;
|
|
modpar[modem].txdelpattern = cnum;
|
|
}
|
|
else Error("need modem number -M before -w", 31ul);
|
|
}
|
|
else if (h[1U]=='x') {
|
|
if (modem>=0L) {
|
|
osi_NextArg(h, 1024ul);
|
|
if (!aprsstr_StrToCard(h, 1024ul, &cnum)) err = 1;
|
|
modpar[modem].configtxtail = cnum;
|
|
}
|
|
else Error("need modem number -M before -x", 31ul);
|
|
}
|
|
else if (h[1U]=='z') {
|
|
osi_NextArg(h, 1024ul);
|
|
if (!aprsstr_StrToCard(h, 1024ul, &cnum)) err = 1;
|
|
if (modem>=0L) {
|
|
modpar[modem].clamp = X2C_DIVR((float)cnum,1000.0f);
|
|
}
|
|
else Error("need modem number -M before -z", 31ul);
|
|
}
|
|
else {
|
|
if (h[1U]=='h') {
|
|
osi_WrStrLn("first for all modems", 21ul);
|
|
osi_WrStrLn(" -a abort on sounddevice error else r\
|
|
etry to open", 62ul);
|
|
osi_WrStrLn(" -b <num> tx dacbuffers (10) (more to avoid\
|
|
underruns)", 61ul);
|
|
osi_WrStrLn(" -B bad sound driver repair, sending \
|
|
continuous quietness to avoid receive", 87ul);
|
|
osi_WrStrLn(" sample loss on start/stop of soun\
|
|
d output. Use for stereo or fullduplex)", 89ul);
|
|
osi_WrStrLn(" -c <num> maxchannels (1) (1=mono, 2=stereo\
|
|
)", 51ul);
|
|
osi_WrStrLn(" -D <filename> (debug) write raw soundcard input\
|
|
data to file or pipe", 71ul);
|
|
osi_WrStrLn(" -D <filename>.txt (debug) write demodulated bit\
|
|
s as \"01..\" to file or pipe", 77ul);
|
|
osi_WrStrLn(" -e <num> additional ptt hold time (if soun\
|
|
dsystem has delay) unit=adcbuffers (1)", 88ul);
|
|
osi_WrStrLn(" -f <num> adcrate (16000) (8000..96000)",
|
|
46ul);
|
|
osi_WrStrLn(" -h help", 21ul);
|
|
osi_WrStrLn(" -i <filename> kiss pipename (/dev/kiss/soundmod\
|
|
em)", 53ul);
|
|
osi_WrStrLn(" -k <num> tx kiss bufs (60)", 34ul);
|
|
osi_WrStrLn(" -l <num> adcbuffer length (256) more: lowe\
|
|
r system load but slower reaction", 83ul);
|
|
osi_WrStrLn(" -m [<mixername>:]<channel>:<left>:<right> (0..25\
|
|
5) ossmixer (/dev/mixer)", 74ul);
|
|
osi_WrStrLn(" -o <filename> oss devicename (/dev/dsp)",
|
|
42ul);
|
|
osi_WrStrLn(" -s <num> fragment size in 2^n (9)", 41ul);
|
|
osic_WrLn();
|
|
osi_WrStrLn("repeat for each channel -C ... :", 33ul);
|
|
osi_WrStrLn(" -C <num> (0..1) channel parameters\
|
|
follow (repeat for each channel)", 83ul);
|
|
pttHelp((char *)ptth, 4096UL);
|
|
osi_WrStrLn(ptth, 4096ul);
|
|
osi_WrStrLn(" -f <num> (0) (0=halfduplex, 1=mast\
|
|
er fullduplex, 2=all fullduplex,", 82ul);
|
|
osi_WrStrLn(" 3=simplex \'stereo never \
|
|
both tx same time\')", 68ul);
|
|
osi_WrStrLn(" -g <ms> GM900 audio quiet time af\
|
|
ter ptt on (0)", 64ul);
|
|
osi_WrStrLn(" -r <num> max random wait time afte\
|
|
r dcd before start tx (ms) (800)", 82ul);
|
|
osic_WrLn();
|
|
osi_WrStrLn("repeat for each modem -M ... :", 31ul);
|
|
osi_WrStrLn(" -M <num> (0..7) modem parameters follow (repea\
|
|
t for each modem)", 67ul);
|
|
osi_WrStrLn(" -a afsk off, fsk on (on)", 34ul);
|
|
osi_WrStrLn(" -b <num> baud (1200) (1..32000)", 35ul);
|
|
osi_WrStrLn(" -B <kbyte> send BERT, (negative bytes receive \
|
|
only)", 55ul);
|
|
osi_WrStrLn(" -c <num> use stereo channel 0=left (or mono), \
|
|
1=right", 57ul);
|
|
osi_WrStrLn(" -d <num> dcdlevel, 0 no dcd (56) (0..100)",
|
|
45ul);
|
|
osi_WrStrLn(" -e <num> demod equalizer (0) 100=6db/oct highp\
|
|
ass (-999..999)", 67ul);
|
|
osi_WrStrLn(" -f <num> afsk mid frequency, tx and rx (hz) (1\
|
|
700)", 54ul);
|
|
osi_WrStrLn(" -g g3ruh scrambler on (off)", 37ul);
|
|
osi_WrStrLn(" -H <num> afsk tx highpass (0) (0..100)",
|
|
42ul);
|
|
osi_WrStrLn(" -i ignore modem parameters from kiss (of\
|
|
f)", 52ul);
|
|
osi_WrStrLn(" -k <num> received data send to this kiss port \
|
|
(0) (0..7)", 60ul);
|
|
/*
|
|
WrStrLn("# -l <num> filterlow (hz)");
|
|
*/
|
|
osi_WrStrLn(" -m <num> monitor (2) (0=off, 1=header, 2=all, \
|
|
3=passall)", 60ul);
|
|
osi_WrStrLn(" -n <num> nyquist filter baseband -6db point in\
|
|
% of baudrate (65) (0..100)", 78ul);
|
|
osi_WrStrLn(" -P same as -U but use AXUDP v2, send dcd and t\
|
|
xbuffer empty messages", 72ul);
|
|
osi_WrStrLn(" -p <num> receive clock pll aquisition speed (1\
|
|
6) (num/256 of bit time)", 74ul);
|
|
osi_WrStrLn(" -q <num> quiet adc level to save cpu or avoid \
|
|
reciption of channel crosstalk (0)", 84ul);
|
|
/*
|
|
WrStrLn("# -r rzi -1 1");
|
|
*/
|
|
osi_WrStrLn(" -s <num> afsk shift tx (for rx bandfilter widt\
|
|
h) (1000) (hz)", 64ul);
|
|
osi_WrStrLn(" -t <num> txdelay (300) (ms)", 31ul);
|
|
osi_WrStrLn(" -T <seconds> timeout for tx buffered frame (60\
|
|
) (s)", 55ul);
|
|
/*
|
|
WrStrLn("# -u filterup (hz)");
|
|
*/
|
|
osi_WrStrLn(" -U <[x.x.x.x]:destport:listenport> use axudp i\
|
|
nstead of kiss /listenport check ip", 85ul);
|
|
osi_WrStrLn(" -L same as -U but use AXUDP v2 (no dcd and txb\
|
|
uffer empty messages)", 71ul);
|
|
osi_WrStrLn(" -v <num> tx loudness (100)", 30ul);
|
|
osi_WrStrLn(" -w <num> txdelay pattern before 1 flag (126) (\
|
|
0..255)", 57ul);
|
|
osi_WrStrLn(" -x <num> txtail (20) (ms), ptt hold for fulldu\
|
|
plex", 54ul);
|
|
osi_WrStrLn(" -z <num> fsk rx baseband dc regeneration clamp\
|
|
speed (996) (0=off, 1=fast, 999=slow)", 88ul);
|
|
osi_WrStrLn("example: ./afskmodem -f 22050 -c 2 -C 0 -p /dev/t\
|
|
tyS0 0 -M 0 -c 0 -b 1200 -M 1 -c 1 -b 9600 -a -g -U 127.0.0.1:6001:1093",
|
|
121ul);
|
|
X2C_ABORT();
|
|
}
|
|
err = 1;
|
|
}
|
|
}
|
|
else {
|
|
/*
|
|
h[0]:=0C;
|
|
*/
|
|
err = 1;
|
|
}
|
|
if (err) break;
|
|
}
|
|
if (err) {
|
|
osi_WrStr(">", 2ul);
|
|
osi_WrStr(h, 1024ul);
|
|
osi_WrStrLn("< use -h", 9ul);
|
|
X2C_ABORT();
|
|
}
|
|
Config();
|
|
OpenSound();
|
|
pipefd = -1L;
|
|
if (pipefn[0U]) pipefd = Opentty(pipefn, 1024ul);
|
|
Makekissbufs(kissbufs);
|
|
bertstart();
|
|
} /* end Parms() */
|
|
|
|
|
|
static void AppCRC(char frame[], uint32_t frame_len, int32_t size)
|
|
{
|
|
uint8_t h;
|
|
uint8_t l;
|
|
uint8_t b;
|
|
int32_t i;
|
|
int32_t tmp;
|
|
l = 0U;
|
|
h = 0U;
|
|
tmp = size-1L;
|
|
i = 0L;
|
|
if (i<=tmp) for (;; i++) {
|
|
b = (uint8_t)((uint8_t)(uint8_t)frame[i]^l);
|
|
l = CRCL[b]^h;
|
|
h = CRCH[b];
|
|
if (i==tmp) break;
|
|
} /* end for */
|
|
frame[size] = (char)l;
|
|
frame[size+1L] = (char)h;
|
|
} /* end AppCRC() */
|
|
|
|
|
|
static void Kisscmd(void)
|
|
{
|
|
uint32_t x;
|
|
uint32_t cmd;
|
|
int32_t modem;
|
|
struct MPAR * anonym;
|
|
cmd = (uint32_t)(uint8_t)pGetKiss->port;
|
|
modem = (int32_t)(cmd>>4&7UL);
|
|
cmd = cmd&15UL;
|
|
osi_WrStr("p=", 3ul);
|
|
osic_WrINT32((uint32_t)modem, 1UL);
|
|
osic_WrLn();
|
|
{ /* with */
|
|
struct MPAR * anonym = &modpar[modem];
|
|
if (anonym->configured && !anonym->kissignore) {
|
|
x = (uint32_t)(uint8_t)pGetKiss->data[0U];
|
|
if (cmd==1UL) {
|
|
anonym->configtxdel = x*10UL;
|
|
osi_WrStr("txdel=", 7ul);
|
|
osic_WrINT32(anonym->configtxdel, 1UL);
|
|
osic_WrLn();
|
|
}
|
|
else if (cmd==2UL) {
|
|
chan[modpar[modem].ch].configpersist = 10UL*(255UL-x);
|
|
osi_WrStr("persist=", 9ul);
|
|
osic_WrINT32(chan[modpar[modem].ch].configpersist, 1UL);
|
|
osic_WrLn();
|
|
}
|
|
else if (cmd==4UL) {
|
|
/*3 SlotTime*/
|
|
anonym->configtxtail = x*10UL;
|
|
osi_WrStr("txtail=", 8ul);
|
|
osic_WrINT32(anonym->configtxtail, 1UL);
|
|
osic_WrLn();
|
|
}
|
|
else if (cmd==5UL) {
|
|
if (x<=2UL) chan[modpar[modem].ch].duplex = (uint8_t)x;
|
|
osi_WrStr("duplex=", 8ul);
|
|
osic_WrINT32(x, 1UL);
|
|
osic_WrLn();
|
|
}
|
|
Config();
|
|
}
|
|
}
|
|
} /* end Kisscmd() */
|
|
|
|
|
|
static void getkiss(void)
|
|
{
|
|
char b[1024];
|
|
int32_t i;
|
|
int32_t l;
|
|
int32_t m;
|
|
int32_t tmp;
|
|
for (;;) {
|
|
if (pipefd<0L) break;
|
|
l = read(pipefd, (char *)b, 1024UL);
|
|
if (l<=0L) break;
|
|
tmp = l-1L;
|
|
i = 0L;
|
|
if (i<=tmp) for (;; i++) {
|
|
/*allocate buffer*/
|
|
if (pGetKiss==0) {
|
|
if (pTxFree==0) goto loop_exit;
|
|
pGetKiss = pTxFree;
|
|
pTxFree = pTxFree->next;
|
|
}
|
|
/*allocate buffer*/
|
|
if (b[i]=='\300') {
|
|
esc = 0;
|
|
if (getst>2UL) {
|
|
pGetKiss->len = getst-2UL;
|
|
getst = 0UL;
|
|
/*store frame*/
|
|
m = (int32_t)((uint32_t)(uint8_t)pGetKiss->port>>4&7UL);
|
|
if (m<=7L) {
|
|
if (((uint32_t)(uint8_t)pGetKiss->port&15UL)==0UL) {
|
|
/* data frame */
|
|
pGetKiss->port = (char)m;
|
|
AppCRC(pGetKiss->data, 341ul, (int32_t)pGetKiss->len);
|
|
pGetKiss->time0 = systime+modpar[m].timeout;
|
|
StoBuf(m, pGetKiss);
|
|
pGetKiss = 0;
|
|
}
|
|
else Kisscmd();
|
|
}
|
|
}
|
|
else {
|
|
/*store frame*/
|
|
getst = 1UL;
|
|
}
|
|
}
|
|
else if (b[i]=='\333' && getst>0UL) esc = 1;
|
|
else {
|
|
if (esc) {
|
|
if (b[i]=='\335') b[i] = '\333';
|
|
else if (b[i]=='\334') b[i] = '\300';
|
|
esc = 0;
|
|
}
|
|
if (getst==1UL) {
|
|
pGetKiss->port = b[i];
|
|
getst = 2UL;
|
|
}
|
|
else if (getst>=2UL && getst-2UL<339UL) {
|
|
pGetKiss->data[getst-2UL] = b[i];
|
|
++getst;
|
|
}
|
|
}
|
|
if (i==tmp) break;
|
|
} /* end for */
|
|
}
|
|
loop_exit:;
|
|
} /* end getkiss() */
|
|
|
|
|
|
static float dB(uint32_t v)
|
|
{
|
|
if (v>0UL) return osic_ln((float)v)*8.685889638f-96.5f;
|
|
else return 0.0f;
|
|
return 0;
|
|
} /* end dB() */
|
|
|
|
|
|
static float noiselevel(uint32_t m)
|
|
/* 0.0 perfect, ~0.25 noise only*/
|
|
{
|
|
struct MPAR * anonym;
|
|
{ /* with */
|
|
struct MPAR * anonym = &modpar[m];
|
|
if (anonym->sqmed[1]==anonym->sqmed[0]) return 0.0f;
|
|
else return X2C_DIVR(anonym->noise,anonym->sqmed[1]-anonym->sqmed[0]);
|
|
}
|
|
return 0;
|
|
} /* end noiselevel() */
|
|
|
|
|
|
static void app(uint32_t * i, uint32_t * p, char b[501], char c,
|
|
int32_t v)
|
|
{
|
|
char s[51];
|
|
b[*p] = c;
|
|
++*p;
|
|
aprsstr_IntToStr(v, 0UL, s, 51ul);
|
|
*i = 0UL;
|
|
while (s[*i]) {
|
|
b[*p] = s[*i];
|
|
++*p;
|
|
++*i;
|
|
}
|
|
b[*p] = ' ';
|
|
++*p;
|
|
} /* end app() */
|
|
|
|
|
|
static void sendaxudp2(uint32_t modem, uint32_t datalen,
|
|
char parms, char data[], uint32_t data_len)
|
|
{
|
|
char b[501];
|
|
int32_t ret;
|
|
uint32_t ff;
|
|
uint32_t i;
|
|
uint32_t p;
|
|
float q;
|
|
struct MPAR * anonym;
|
|
X2C_PCOPY((void **)&data,data_len);
|
|
{ /* with */
|
|
struct MPAR * anonym = &modpar[modem];
|
|
if (anonym->udpsocket>=0L) {
|
|
b[0U] = '\001';
|
|
b[1U] = (char)(48UL+(uint32_t)
|
|
anonym->haddcdrand*2UL+(uint32_t)
|
|
anonym->hadtxdata*4UL+(uint32_t)chan[anonym->ch].pttstate);
|
|
p = 2UL;
|
|
if (parms) {
|
|
app(&i, &p, b, 'D', (int32_t)(uint32_t)(chan[anonym->ch].duplex==afskmodem_fullduplex));
|
|
app(&i, &p, b, 'B', (int32_t)anonym->configbaud);
|
|
app(&i, &p, b, 't', (int32_t)anonym->configtxdel);
|
|
}
|
|
if (datalen>0UL) {
|
|
/* with data */
|
|
ff = (anonym->flags*1000UL)/anonym->configbaud;
|
|
if (ff>0UL) app(&i, &p, b, 'T', (int32_t)ff);
|
|
app(&i, &p, b, 'V', (int32_t)X2C_TRUNCI(dB((uint32_t)chan[anonym->ch].adcmax),
|
|
X2C_min_longint,X2C_max_longint)); /* volume in dB */
|
|
q = noiselevel(modem);
|
|
if (q>0.0f) {
|
|
q = 100.5f-q*200.0f;
|
|
if (q<1.0f) q = 1.0f;
|
|
app(&i, &p, b, 'Q', (int32_t)X2C_TRUNCI(q,X2C_min_longint,
|
|
X2C_max_longint)); /* quality in % */
|
|
}
|
|
b[p] = 0; /* end of axudp2 header */
|
|
++p;
|
|
i = 0UL;
|
|
do {
|
|
b[p] = data[i];
|
|
++p;
|
|
++i;
|
|
} while (i<datalen);
|
|
}
|
|
else {
|
|
b[p] = 0;
|
|
++p;
|
|
}
|
|
AppCRC(b, 501ul, (int32_t)p);
|
|
ret = udpsend(anonym->udpsocket, b, (int32_t)(p+2UL),
|
|
anonym->udpport, anonym->udpip);
|
|
}
|
|
}
|
|
X2C_PFREE(data);
|
|
} /* end sendaxudp2() */
|
|
|
|
|
|
static void getudp(void)
|
|
{
|
|
pKISSNEXT p;
|
|
uint32_t i;
|
|
int32_t ulen;
|
|
uint32_t fromport;
|
|
uint32_t fromip;
|
|
char crc2;
|
|
char crc1;
|
|
char udp2[100];
|
|
struct MPAR * anonym;
|
|
for (i = 0UL; i<=7UL; i++) {
|
|
{ /* with */
|
|
struct MPAR * anonym = &modpar[i];
|
|
if (anonym->udpsocket>=0L && pTxFree) {
|
|
ulen = udpreceive(anonym->udpsocket, pTxFree->data, 341L,
|
|
&fromport, &fromip);
|
|
if ((ulen>2L && ulen<341L)
|
|
&& (!anonym->checkip || fromip==anonym->udpip)) {
|
|
crc1 = pTxFree->data[ulen-2L];
|
|
crc2 = pTxFree->data[ulen-1L];
|
|
AppCRC(pTxFree->data, 341ul, ulen-2L);
|
|
if (crc1==pTxFree->data[ulen-2L]
|
|
&& crc2==pTxFree->data[ulen-1L]) {
|
|
if (pTxFree->data[0U]=='\001') {
|
|
aprsstr_extrudp2(pTxFree->data, 341ul, udp2, 100ul,
|
|
&ulen);
|
|
AppCRC(pTxFree->data, 341ul, ulen-2L);
|
|
}
|
|
/* axudp2 */
|
|
if (ulen>2L) {
|
|
p = pTxFree;
|
|
pTxFree = pTxFree->next;
|
|
p->port = (char)i;
|
|
p->len = (uint32_t)(ulen-2L);
|
|
p->time0 = systime+anonym->timeout;
|
|
StoBuf((int32_t)i, p);
|
|
}
|
|
else if (udp2[1U]=='?' && udp2[2U]==0) {
|
|
sendaxudp2(i, 0UL, 1, udp2, 100ul);
|
|
/* on axudp2 header only send dcd & txbuf status */
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} /* end for */
|
|
/* else crc error */
|
|
/* else wrong len or source ip */
|
|
} /* end getudp() */
|
|
|
|
|
|
static void sendkiss(char data[], uint32_t data_len, int32_t len,
|
|
uint32_t port16)
|
|
{
|
|
char b[683];
|
|
int32_t i;
|
|
int32_t l;
|
|
char d;
|
|
uint32_t po;
|
|
struct MPAR * anonym;
|
|
int32_t tmp;
|
|
/*
|
|
FOR i:=0 TO len-1 DO IO.WrHex(ORD(data[i]),3) END; IO.WrLn;
|
|
*/
|
|
po = port16>>4&7UL;
|
|
if (po<=7UL && modpar[po].udpsocket>=0L) {
|
|
{ /* with */
|
|
struct MPAR * anonym = &modpar[po];
|
|
if (anonym->axudp2) {
|
|
sendaxudp2(po, (uint32_t)len, 0, data, data_len);
|
|
/* makes new crc */
|
|
}
|
|
else {
|
|
i = udpsend(anonym->udpsocket, data, len+2L, anonym->udpport,
|
|
anonym->udpip);
|
|
}
|
|
}
|
|
}
|
|
else if (pipefd>=0L) {
|
|
b[0U] = '\300';
|
|
b[1U] = (char)port16;
|
|
l = 2L;
|
|
tmp = len-1L;
|
|
i = 0L;
|
|
if (i<=tmp) for (;; i++) {
|
|
d = data[i];
|
|
if (d=='\300') {
|
|
b[l] = '\333';
|
|
++l;
|
|
b[l] = '\334';
|
|
}
|
|
else if (d=='\333') {
|
|
b[l] = '\333';
|
|
++l;
|
|
b[l] = '\335';
|
|
}
|
|
else b[l] = d;
|
|
++l;
|
|
if (i==tmp) break;
|
|
} /* end for */
|
|
b[l] = '\300';
|
|
++l;
|
|
i = write(pipefd, (char *)b, (uint32_t)l);
|
|
}
|
|
} /* end sendkiss() */
|
|
|
|
|
|
static void WrQuali(float q)
|
|
{
|
|
if (q>0.0f) {
|
|
q = 100.5f-q*200.0f;
|
|
if (q<0.0f) q = 0.0f;
|
|
osi_WrStr(" q:", 4ul);
|
|
osic_WrINT32((uint32_t)X2C_TRUNCC(q,0UL,X2C_max_longcard), 1UL);
|
|
}
|
|
} /* end WrQuali() */
|
|
|
|
|
|
static void WrdB(int32_t volt)
|
|
{
|
|
if (volt>0L) {
|
|
osic_WrFixed(dB((uint32_t)volt), 1L, 6UL);
|
|
osi_WrStr("dB", 3ul);
|
|
}
|
|
} /* end WrdB() */
|
|
|
|
|
|
static void WrTXD(uint32_t ms)
|
|
{
|
|
osi_WrStr(" txd:", 6ul);
|
|
osic_WrINT32(ms, 1UL);
|
|
osi_WrStr("ms", 3ul);
|
|
} /* end WrTXD() */
|
|
|
|
|
|
static void WCh(char c)
|
|
{
|
|
if (c!='\015') {
|
|
if ((uint8_t)c<' ' || (uint8_t)c>='\177') osi_WrStr(".", 2ul);
|
|
else osi_WrStr((char *) &c, 1u/1u);
|
|
}
|
|
} /* end WCh() */
|
|
|
|
|
|
static void ShowCall(char f[], uint32_t f_len, uint32_t pos)
|
|
{
|
|
uint32_t e;
|
|
uint32_t i;
|
|
uint32_t tmp;
|
|
e = pos;
|
|
tmp = pos+5UL;
|
|
i = pos;
|
|
if (i<=tmp) for (;; i++) {
|
|
if (f[i]!='@') e = i;
|
|
if (i==tmp) break;
|
|
} /* end for */
|
|
tmp = e;
|
|
i = pos;
|
|
if (i<=tmp) for (;; i++) {
|
|
WCh((char)((uint32_t)(uint8_t)f[i]>>1));
|
|
if (i==tmp) break;
|
|
} /* end for */
|
|
if ((uint32_t)(uint8_t)f[pos+6UL]>>1&15UL) {
|
|
osi_WrStr("-", 2ul);
|
|
osic_WrINT32((uint32_t)(uint8_t)f[pos+6UL]>>1&15UL, 1UL);
|
|
}
|
|
} /* end ShowCall() */
|
|
|
|
static uint32_t afskmodem_UA = 0x63UL;
|
|
|
|
static uint32_t afskmodem_DM = 0xFUL;
|
|
|
|
static uint32_t afskmodem_SABM = 0x2FUL;
|
|
|
|
static uint32_t afskmodem_DISC = 0x43UL;
|
|
|
|
static uint32_t afskmodem_FRMR = 0x87UL;
|
|
|
|
static uint32_t afskmodem_UI = 0x3UL;
|
|
|
|
static uint32_t afskmodem_RR = 0x1UL;
|
|
|
|
static uint32_t afskmodem_REJ = 0x9UL;
|
|
|
|
static uint32_t afskmodem_RNR = 0x5UL;
|
|
|
|
|
|
static void Showctl(uint32_t com, uint32_t cmd)
|
|
{
|
|
uint32_t cm;
|
|
char PF[4];
|
|
char tmp;
|
|
osi_WrStr(" ctl ", 6ul);
|
|
cm = (uint32_t)cmd&~0x10UL;
|
|
if ((cm&0xFUL)==0x1UL) {
|
|
osi_WrStr("RR", 3ul);
|
|
osi_WrStr((char *)(tmp = (char)(48UL+(cmd>>5)),&tmp), 1u/1u);
|
|
}
|
|
else if ((cm&0xFUL)==0x5UL) {
|
|
osi_WrStr("RNR", 4ul);
|
|
osi_WrStr((char *)(tmp = (char)(48UL+(cmd>>5)),&tmp), 1u/1u);
|
|
}
|
|
else if ((cm&0xFUL)==0x9UL) {
|
|
osi_WrStr("REJ", 4ul);
|
|
osi_WrStr((char *)(tmp = (char)(48UL+(cmd>>5)),&tmp), 1u/1u);
|
|
}
|
|
else if ((cm&0x1UL)==0UL) {
|
|
osi_WrStr("I", 2ul);
|
|
osi_WrStr((char *)(tmp = (char)(48UL+(cmd>>5)),&tmp), 1u/1u);
|
|
osi_WrStr((char *)(tmp = (char)(48UL+(cmd>>1&7UL)),&tmp),
|
|
1u/1u);
|
|
}
|
|
else if (cm==0x3UL) osi_WrStr("UI", 3ul);
|
|
else if (cm==0xFUL) osi_WrStr("DM", 3ul);
|
|
else if (cm==0x2FUL) osi_WrStr("SABM", 5ul);
|
|
else if (cm==0x43UL) osi_WrStr("DISC", 5ul);
|
|
else if (cm==0x63UL) osi_WrStr("UA", 3ul);
|
|
else if (cm==0x87UL) osi_WrStr("FRMR", 5ul);
|
|
else osi_WrHex(cmd, 1UL);
|
|
strncpy(PF,"v^-+",4u);
|
|
if (com==0UL || com==3UL) osi_WrStr("v1", 3ul);
|
|
else {
|
|
osi_WrStr((char *) &PF[(com&1UL)+2UL*(uint32_t)
|
|
((0x10UL & (uint32_t)cmd)!=0)], 1u/1u);
|
|
}
|
|
} /* end Showctl() */
|
|
|
|
|
|
static void ShowFrame(char f[], uint32_t f_len, uint32_t len,
|
|
int32_t modem, int32_t volt, char noinfo)
|
|
{
|
|
uint32_t ff;
|
|
uint32_t i;
|
|
char d;
|
|
char v;
|
|
char tmp;
|
|
X2C_PCOPY((void **)&f,f_len);
|
|
i = 0UL;
|
|
while (!((uint32_t)(uint8_t)f[i]&1)) {
|
|
++i;
|
|
if (i>len) goto label;
|
|
}
|
|
/* no address end mark found */
|
|
/*
|
|
IF i=1 THEN
|
|
flexmon(f, len);
|
|
i:=13;
|
|
END;
|
|
*/
|
|
if (i%7UL!=6UL) goto label;
|
|
/* address end not modulo 7 error */
|
|
osi_WrStr((char *)(tmp = (char)((modem&7L)+48L),&tmp), 1u/1u);
|
|
osi_WrStr(":fm ", 5ul);
|
|
ShowCall(f, f_len, 7UL);
|
|
osi_WrStr(" to ", 5ul);
|
|
ShowCall(f, f_len, 0UL);
|
|
i = 14UL;
|
|
v = 1;
|
|
while (i+6UL<len && !((uint32_t)(uint8_t)f[i-1UL]&1)) {
|
|
if (v) {
|
|
osi_WrStr(" via", 5ul);
|
|
v = 0;
|
|
}
|
|
osi_WrStr(" ", 2ul);
|
|
ShowCall(f, f_len, i);
|
|
if ((uint32_t)(uint8_t)f[i+6UL]>=128UL && (((uint32_t)(uint8_t)
|
|
f[i+6UL]&1) || (uint32_t)(uint8_t)f[i+13UL]<128UL)) {
|
|
osi_WrStr("*", 2ul);
|
|
}
|
|
i += 7UL;
|
|
}
|
|
/*
|
|
IO.WrStr(" ctl "); IO.WrHex(ORD(f[i]),1);
|
|
*/
|
|
Showctl((uint32_t)((0x80U & (uint8_t)(uint8_t)f[6UL])!=0)
|
|
+2UL*(uint32_t)((0x80U & (uint8_t)(uint8_t)f[13UL])!=0)
|
|
, (uint32_t)(uint8_t)f[i]);
|
|
++i;
|
|
if (i<len) {
|
|
osi_WrStr(" pid ", 6ul);
|
|
osi_WrHex((uint32_t)(uint8_t)f[i], 1UL);
|
|
}
|
|
++i;
|
|
if (volt>0L) {
|
|
WrQuali(noiselevel((uint32_t)modem));
|
|
WrdB(volt);
|
|
ff = (modpar[modem].flags*1000UL)/modpar[modem].configbaud;
|
|
if (ff>0UL) WrTXD(ff);
|
|
}
|
|
/*
|
|
IO.WrCard(bufree(), 3);
|
|
*/
|
|
osic_WrLn();
|
|
if (!noinfo) {
|
|
d = 0;
|
|
while (i<len) {
|
|
if (f[i]!='\015') {
|
|
WCh(f[i]);
|
|
d = 1;
|
|
}
|
|
else if (d) {
|
|
osic_WrLn();
|
|
d = 0;
|
|
}
|
|
++i;
|
|
}
|
|
if (d) osic_WrLn();
|
|
}
|
|
label:;
|
|
X2C_PFREE(f);
|
|
/*
|
|
FOR i:=0 TO len-1 DO WrStr("\"); WrInt(ASH(ORD(f[i]), -6),1);
|
|
IO.WrCard(ORD(f[i]) DIV 8 MOD 8,1);IO.WrCard(ORD(f[i]) MOD 8,1);
|
|
END;
|
|
IO.WrLn;
|
|
*/
|
|
} /* end ShowFrame() */
|
|
|
|
#define afskmodem_POLINOM 0x8408
|
|
|
|
|
|
static void Gencrctab(void)
|
|
{
|
|
uint32_t c;
|
|
uint32_t crc;
|
|
uint32_t i;
|
|
for (c = 0UL; c<=255UL; c++) {
|
|
crc = 255UL-c;
|
|
for (i = 0UL; i<=7UL; i++) {
|
|
if ((crc&1)) crc = (uint32_t)((uint32_t)(crc>>1)^0x8408UL);
|
|
else crc = crc>>1;
|
|
} /* end for */
|
|
CRCL[c] = (uint8_t)crc;
|
|
CRCH[c] = (uint8_t)(255UL-(crc>>8));
|
|
} /* end for */
|
|
} /* end Gencrctab() */
|
|
|
|
|
|
static float Fir(uint32_t in, uint32_t sub, uint32_t step,
|
|
float fir[], uint32_t fir_len, float firtab[],
|
|
uint32_t firtab_len)
|
|
{
|
|
float s;
|
|
uint32_t i;
|
|
s = 0.0f;
|
|
i = sub;
|
|
do {
|
|
s = s+fir[in]*firtab[i];
|
|
++in;
|
|
if (in>fir_len-1) in = 0UL;
|
|
i += step;
|
|
} while (i<=firtab_len-1);
|
|
return s;
|
|
} /* end Fir() */
|
|
|
|
|
|
static void demodbit(int32_t m, char d)
|
|
{
|
|
char xor;
|
|
struct MPAR * anonym;
|
|
{ /* with */
|
|
struct MPAR * anonym = &modpar[m];
|
|
/*descrambler*/
|
|
if (anonym->scramb) {
|
|
/*
|
|
scrambler:=CAST(BITSET, CAST(CARDINAL, scrambler)*2 + ORD(d));
|
|
|
|
*/
|
|
anonym->scrambler = X2C_LSH(anonym->scrambler,32,1);
|
|
if (d) anonym->scrambler |= 0x1UL;
|
|
d = ((0x1UL & anonym->scrambler)!=0)
|
|
==(((0x1000UL & anonym->scrambler)!=0)
|
|
==((0x20000UL & anonym->scrambler)!=0));
|
|
/*result is xor bit 0 12 17*/
|
|
}
|
|
/*nrzi*/
|
|
xor = d;
|
|
d = d==anonym->data1;
|
|
anonym->data1 = xor;
|
|
if (deb01) {
|
|
debb[debp] = (char)(48UL+(uint32_t)d);
|
|
++debp;
|
|
if (debp>=80UL) {
|
|
debb[80U] = '\012';
|
|
debp = (uint32_t)write(debfd, (char *)debb, debp+1UL);
|
|
debp = 0UL;
|
|
}
|
|
}
|
|
/*bert*/
|
|
if (anonym->bert) {
|
|
if (!d) ++anonym->berterr;
|
|
++anonym->bertc;
|
|
if (anonym->bert<0L) {
|
|
/* receive only */
|
|
++anonym->bert;
|
|
if (anonym->bert==0L) osi_WrStrLn("---- end BERT", 14ul);
|
|
}
|
|
if (anonym->bertc>2000UL) {
|
|
osic_WrINT32(anonym->berterr, 4UL);
|
|
osic_WrINT32((uint32_t)m, 2UL);
|
|
WrQuali(noiselevel((uint32_t)m));
|
|
WrdB(chan[anonym->ch].adcmax);
|
|
osic_WrLn();
|
|
anonym->bertc = 0UL;
|
|
anonym->berterr = 0UL;
|
|
}
|
|
}
|
|
if (anonym->rxstuffc<5UL) {
|
|
/*bit to byte*/
|
|
anonym->rxbyte = anonym->rxbyte/2UL+((uint32_t)d<<7);
|
|
++anonym->rxbitc;
|
|
/*crc*/
|
|
xor = d!=((0x1UL & anonym->rxcrc)!=0); /*databit xor crcbit0*/
|
|
/*
|
|
rxcrc:=CAST(BITSET, CAST(CARDINAL, rxcrc) DIV 2);
|
|
(*shift right crc register*)
|
|
*/
|
|
anonym->rxcrc = X2C_LSH(anonym->rxcrc,32,-1);
|
|
if (xor) anonym->rxcrc = anonym->rxcrc^0x8408UL;
|
|
/*byte to frame*/
|
|
if (anonym->rxbitc>=8UL) {
|
|
if (anonym->rxp<339UL) {
|
|
anonym->rxbuf[anonym->rxp] = (char)anonym->rxbyte;
|
|
++anonym->rxp;
|
|
}
|
|
/*else frame too long error*/
|
|
anonym->rxbitc = 0UL;
|
|
if (anonym->flagbeg) {
|
|
/* start of data */
|
|
if (anonym->flage>2UL) anonym->flagc = 0UL;
|
|
anonym->flags = anonym->flagc;
|
|
anonym->flagbeg = 0;
|
|
}
|
|
else if (anonym->rxbyte && anonym->flagc>64UL) {
|
|
++anonym->flage; /* looks like data not txdel patterns */
|
|
}
|
|
}
|
|
}
|
|
else if (anonym->rxstuffc>5UL) {
|
|
/*flag*/
|
|
/*flag*/
|
|
if (((!d && anonym->rxbitc==6UL) && anonym->rxp>=9UL)
|
|
&& anonym->rxp<339UL) {
|
|
/*0111111x 0 is flag else abort*/
|
|
/*bits modulo 8 ?*/
|
|
/*frame long enough ?*/
|
|
if (anonym->rxcrc==0x9F0BUL) {
|
|
sendkiss(anonym->rxbuf, 339ul, (int32_t)(anonym->rxp-2UL),
|
|
anonym->port16);
|
|
}
|
|
if (anonym->monitor==afskmodem_passall || anonym->rxcrc==0x9F0BUL && anonym->monitor)
|
|
{
|
|
ShowFrame(anonym->rxbuf, 339ul, anonym->rxp-2UL, m,
|
|
chan[anonym->ch].adcmax, anonym->monitor==afskmodem_noinfo);
|
|
anonym->flagc = 0UL;
|
|
anonym->flage = 0UL;
|
|
}
|
|
}
|
|
anonym->rxp = 0UL;
|
|
anonym->rxbitc = 0UL;
|
|
anonym->rxcrc = 0xFFFFUL; /*init crc register*/
|
|
anonym->flagbeg = 1;
|
|
}
|
|
if (d) ++anonym->rxstuffc;
|
|
else anonym->rxstuffc = 0UL;
|
|
}
|
|
/*destuffing*/
|
|
} /* end demodbit() */
|
|
|
|
|
|
static void demod(float u, int32_t m)
|
|
{
|
|
char d;
|
|
struct MPAR * anonym;
|
|
d = u>=0.0f;
|
|
{ /* with */
|
|
struct MPAR * anonym = &modpar[m];
|
|
if (anonym->cbit) {
|
|
demodbit(m, d);
|
|
if (d!=anonym->oldd) {
|
|
if (d==anonym->plld) anonym->baudfine += anonym->pllshift;
|
|
else anonym->baudfine -= anonym->pllshift;
|
|
anonym->oldd = d;
|
|
}
|
|
else if (d!=anonym->plld) {
|
|
anonym->flagc = 0UL;
|
|
anonym->flage = 0UL;
|
|
anonym->flagbeg = 0;
|
|
}
|
|
/*squelch*/
|
|
anonym->sqmed[d] = anonym->sqmed[d]+(u-anonym->sqmed[d])*0.05f;
|
|
anonym->noise = anonym->noise+((float)fabs(u-anonym->sqmed[d])
|
|
-anonym->noise)*0.05f;
|
|
/*squelch*/
|
|
++anonym->flagc;
|
|
}
|
|
else anonym->plld = d;
|
|
anonym->cbit = !anonym->cbit;
|
|
}
|
|
} /* end demod() */
|
|
|
|
|
|
static void Afsk(int32_t m)
|
|
{
|
|
float ff;
|
|
float b;
|
|
float a;
|
|
float d;
|
|
float mid;
|
|
float right;
|
|
struct MPAR * anonym;
|
|
{ /* with */
|
|
struct MPAR * anonym = &modpar[m];
|
|
right = Fir(afin, 0UL, 16UL, chan[anonym->ch].afir, 32ul,
|
|
anonym->afirtab, 512ul);
|
|
if (anonym->left<0.0f!=right<0.0f) {
|
|
d = X2C_DIVR(anonym->left,anonym->left-right);
|
|
a = (float)(uint32_t)X2C_TRUNCC(d*16.0f+0.5f,0UL,
|
|
X2C_max_longcard);
|
|
b = a*0.0625f;
|
|
if ((uint32_t)X2C_TRUNCC(a,0UL,
|
|
X2C_max_longcard)>0UL && (uint32_t)X2C_TRUNCC(a,0UL,
|
|
X2C_max_longcard)<16UL) {
|
|
mid = Fir(afin, 16UL-(uint32_t)X2C_TRUNCC(a,0UL,
|
|
X2C_max_longcard), 16UL, chan[anonym->ch].afir, 32ul,
|
|
anonym->afirtab, 512ul);
|
|
if (anonym->left<0.0f!=mid<0.0f) {
|
|
d = (X2C_DIVR(anonym->left,anonym->left-mid))*b;
|
|
}
|
|
else d = b+(X2C_DIVR(mid,mid-right))*(1.0f-b);
|
|
}
|
|
if (anonym->tcnt+d!=0.0f) {
|
|
anonym->freq = X2C_DIVR(1.0f,anonym->tcnt+d);
|
|
}
|
|
anonym->tcnt = 0.0f-d;
|
|
}
|
|
anonym->tcnt = anonym->tcnt+1.0f;
|
|
anonym->left = right;
|
|
anonym->dfir[anonym->dfin] = anonym->freq-anonym->afskmidfreq;
|
|
anonym->dfin = anonym->dfin+1UL&63UL;
|
|
anonym->baudfine += (int32_t)anonym->demodbaud;
|
|
if (anonym->baudfine>=65536L) {
|
|
anonym->baudfine -= 65536L;
|
|
if (anonym->baudfine<65536L) {
|
|
/* normal alway true */
|
|
ff = Fir(anonym->dfin, (uint32_t)(16L-anonym->baudfine/4096L),
|
|
16UL, anonym->dfir, 64ul, anonym->dfirtab, 1024ul);
|
|
demod(ff, m);
|
|
}
|
|
}
|
|
}
|
|
} /* end Afsk() */
|
|
|
|
|
|
static void Fsk(int32_t m)
|
|
{
|
|
float ff;
|
|
int32_t lim;
|
|
struct MPAR * anonym;
|
|
{ /* with */
|
|
struct MPAR * anonym = &modpar[m];
|
|
lim = (int32_t)anonym->demodbaud;
|
|
for (;;) {
|
|
if (anonym->baudfine>=65536L) {
|
|
anonym->baudfine -= 65536L;
|
|
ff = Fir(afin, (uint32_t)((anonym->baudfine&65535L)/4096L),
|
|
16UL, chan[anonym->ch].afir, 32ul, anonym->afirtab, 512ul);
|
|
demod(ff-(anonym->left+anonym->freq)*0.5f, m);
|
|
/*clamp*/
|
|
if (!anonym->cbit) {
|
|
if (ff>anonym->left) {
|
|
anonym->left = anonym->left+(ff-anonym->left)*1.0f;
|
|
}
|
|
if (ff<anonym->freq) {
|
|
anonym->freq = anonym->freq+(ff-anonym->freq)*1.0f;
|
|
}
|
|
anonym->left = anonym->left*anonym->clamp;
|
|
anonym->freq = anonym->freq*anonym->clamp;
|
|
}
|
|
}
|
|
/*clamp*/
|
|
anonym->baudfine += lim;
|
|
lim = 0L;
|
|
if (anonym->baudfine<131072L) break;
|
|
}
|
|
}
|
|
} /* end Fsk() */
|
|
|
|
/*
|
|
(*pp065*)
|
|
PROCEDURE setppout(fd:INTEGER; mask:SET32):BOOLEAN;
|
|
CONST PORTCFG=40026206H;
|
|
|
|
VAR pc:SET32;
|
|
r:CARDINAL;
|
|
BEGIN
|
|
r:=100;
|
|
LOOP
|
|
pc:=SET32{30};
|
|
IF ioctl(fd, CAST(INTEGER, PORTCFG), ADR(pc))=0 THEN EXIT END;
|
|
DEC(r);
|
|
IF r=0 THEN pc:=SET32{}; EXIT END;
|
|
END;
|
|
pc:=pc*SET32{0..15}+SET32{31}+mask+SHIFT(mask,1);
|
|
RETURN ioctl(fd, CAST(INTEGER, PORTCFG), ADR(pc))=0;
|
|
END setppout;
|
|
|
|
PROCEDURE ppbitset(fd:INTEGER; port:CARDINAL; on:BOOLEAN);
|
|
CONST PARWR=40026207H;
|
|
VAR res:INTEGER;
|
|
BEGIN
|
|
--IO.WrInt(port, 3); IO.WrInt(ORD(on) , 3); IO.WrStrLn("ppout");
|
|
res:=ioctl(fd, CAST(INTEGER, PARWR), CAST(ADDRESS,SET32{port+ORD(NOT on)*8}
|
|
));
|
|
END ppbitset;
|
|
(*pp065*)
|
|
|
|
|
|
|
|
PROCEDURE Ptt;
|
|
VAR lptfd, b:INTEGER;
|
|
map, mask:SET8;
|
|
c:CHANNELS;
|
|
ppmask:SET32;
|
|
BEGIN
|
|
--WrInt(ORD(chan[LEFT].pttstate),2); WrInt(ORD(chan[RIGHT].pttstate),1);
|
|
WrStrLn("=ptts");
|
|
(*tty*)
|
|
IF ttyfn[0]<>0C THEN
|
|
IF ttyfd<0 THEN ttyfd:=open(ttyfn, 0) END;
|
|
IF ttyfd>=0 THEN
|
|
|
|
IF NOT SetStatLine(ttyfd, chan[LEFT].pttstate, chan[RIGHT].pttstate)
|
|
OR closetty THEN
|
|
Close(ttyfd);
|
|
ttyfd:=-1;
|
|
END; (* else keep open for alzheimer usb devices *)
|
|
ELSE WrStrLn("tty port open error") END;
|
|
END;
|
|
(*tty*)
|
|
|
|
IF parporttyp=1 THEN
|
|
(*parport*)
|
|
mask:=SET8{};
|
|
map:=SET8{};
|
|
FOR c:=LEFT TO RIGHT DO
|
|
b:=chan[c].lptpttbit;
|
|
IF b<>0 THEN
|
|
IF chan[c].pttstate=(b>=0) THEN INCL(map, ABS(b)-1) END;
|
|
INCL(mask, ABS(b)-1);
|
|
END;
|
|
END;
|
|
IF mask<>SET8{} THEN
|
|
lptfd:=OpenRW(lptfn);
|
|
IF (lptfd<0) OR (lpt.ppclaim(lptfd)<0)
|
|
THEN WrStrLn("lpt port open error");
|
|
ELSE
|
|
map:=(CAST(SET8, lpt.ppdevrdata(lptfd))-mask) + map;
|
|
lpt.ppdevdata(lptfd, CAST(CHAR, map));
|
|
END;
|
|
IF (lptfd>=0) THEN Close(lptfd) END;
|
|
END;
|
|
(*parport*)
|
|
|
|
ELSIF parporttyp=2 THEN
|
|
(*pp065*)
|
|
lptfd:=OpenRW(lptfn);
|
|
IF lptfd>=0 THEN
|
|
ppmask:=SET32{};
|
|
FOR c:=LEFT TO RIGHT DO
|
|
b:=chan[c].lptpttbit;
|
|
IF b<>0 THEN INCL(ppmask, (ABS(b)-1)*2) END;
|
|
END;
|
|
IF setppout(lptfd, ppmask) THEN
|
|
FOR c:=LEFT TO RIGHT DO
|
|
b:=chan[c].lptpttbit;
|
|
IF b<>0 THEN
|
|
ppbitset(lptfd, ABS(b)-1, chan[c].pttstate=(b>=0));
|
|
END;
|
|
END;
|
|
END;
|
|
Close(lptfd);
|
|
ELSE WrStr(lptfn); WrStrLn(" port open error") END;
|
|
END;
|
|
(*pp065*)
|
|
|
|
|
|
END Ptt;
|
|
*/
|
|
|
|
static void startrandom(uint8_t ch)
|
|
{
|
|
struct CHAN * anonym;
|
|
{ /* with */
|
|
struct CHAN * anonym = &chan[ch];
|
|
anonym->addrandom = 2UL+(uint32_t)X2C_TRUNCC(osic_Random()
|
|
*(double)anonym->persist,0UL,X2C_max_longcard);
|
|
/* store ramdom wait */
|
|
anonym->dcdclock = clock0; /* start txwait after we sent */
|
|
}
|
|
} /* end startrandom() */
|
|
|
|
|
|
static char CheckRandom(int32_t modem)
|
|
{
|
|
uint32_t clk;
|
|
struct MPAR * anonym;
|
|
struct CHAN * anonym0;
|
|
{ /* with */
|
|
struct MPAR * anonym = &modpar[modem];
|
|
{ /* with */
|
|
struct CHAN * anonym0 = &chan[anonym->ch];
|
|
if (anonym0->duplex==afskmodem_shiftdigi) {
|
|
clk = modpar[modem].dcdclockm; /* use dcd of this modulation */
|
|
}
|
|
else clk = anonym0->dcdclock;
|
|
return anonym0->duplex!=afskmodem_fullduplex && (clock0-clk<=anonym0->addrandom || anonym0->duplex==afskmodem_onetx)
|
|
;
|
|
}
|
|
}
|
|
} /* end CheckRandom() */
|
|
|
|
/* (usb) soundcard died */
|
|
|
|
static void repairsound(void)
|
|
{
|
|
/* pttok:=FALSE; */
|
|
ptt(chan[afskmodem_LEFT].hptt, -1L);
|
|
ptt(chan[afskmodem_RIGHT].hptt, -1L);
|
|
if (abortonsounderr) Error("Sounddevice Failure", 20ul);
|
|
osic_Close(soundfd);
|
|
usleep(100000UL);
|
|
/*WrStrLn("openA"); */
|
|
OpenSound();
|
|
} /* end repairsound() */
|
|
|
|
|
|
static void getadc(void)
|
|
{
|
|
short buf[4096];
|
|
int32_t minr;
|
|
int32_t maxr;
|
|
int32_t minl;
|
|
int32_t maxl;
|
|
int32_t sl;
|
|
int32_t m;
|
|
int32_t i;
|
|
int32_t l;
|
|
uint8_t c;
|
|
char ndcd;
|
|
struct MPAR * anonym;
|
|
struct MPAR * anonym0;
|
|
l = read(soundfd, (char *)buf, adcbuflen*adcbytes);
|
|
for (m = 0L; m<=7L; m++) {
|
|
modpar[m].noise = modpar[m].noise*0.99f; /* clear dcd on silence */
|
|
} /* end for */
|
|
if (l<=0L) {
|
|
repairsound();
|
|
return;
|
|
}
|
|
if (debfd>=0L && !deb01) {
|
|
i = write(debfd, (char *)buf, (uint32_t)l);
|
|
}
|
|
l = (int32_t)((uint32_t)l/adcbytes);
|
|
for (c = afskmodem_LEFT;; c++) {
|
|
chan[c].adcmax = chan[c].adcmax*15L>>4;
|
|
if (c==afskmodem_RIGHT) break;
|
|
} /* end for */
|
|
maxl = -32768L;
|
|
maxr = -32768L;
|
|
minl = 32767L;
|
|
minr = 32767L;
|
|
i = 0L;
|
|
while (i<l) {
|
|
sl = (int32_t)buf[i];
|
|
chan[afskmodem_LEFT].afir[afin] = (float)sl;
|
|
if (sl>maxl) maxl = sl;
|
|
if (sl<minl) minl = sl;
|
|
if (maxl-minl>chan[afskmodem_LEFT].adcmax) {
|
|
chan[afskmodem_LEFT].adcmax = maxl-minl;
|
|
}
|
|
if (maxchannels>afskmodem_LEFT) {
|
|
sl = (int32_t)buf[i+1L];
|
|
chan[afskmodem_RIGHT].afir[afin] = (float)sl;
|
|
if (sl>maxr) maxr = sl;
|
|
if (sl<minr) minr = sl;
|
|
if (maxr-minr>chan[afskmodem_RIGHT].adcmax) {
|
|
chan[afskmodem_RIGHT].adcmax = maxr-minr;
|
|
}
|
|
}
|
|
afin = afin+1UL&31UL;
|
|
for (m = 0L; m<=7L; m++) {
|
|
{ /* with */
|
|
struct MPAR * anonym = &modpar[m];
|
|
if ((anonym->configured && chan[anonym->ch]
|
|
.adcmax>=anonym->leveldcd)
|
|
&& (!chan[anonym->ch].pttstate || chan[anonym->ch]
|
|
.duplex && chan[anonym->ch].duplex!=afskmodem_onetx)) {
|
|
/* save cpu and echo reception */
|
|
if (anonym->afsk) Afsk(m);
|
|
else Fsk(m);
|
|
/*
|
|
IF (m=0) & (clock MOD 64=0)
|
|
THEN IO.WrInt(chan[modpar[m].ch].adcmax,6); IO.WrLn; END;
|
|
*/
|
|
if (noiselevel((uint32_t)m)<anonym->squelchdcd) {
|
|
chan[anonym->ch].dcdclock = clock0; /* tx wise dcd */
|
|
anonym->dcdclockm = clock0;
|
|
/* modem wise dcd for shift digi*/
|
|
}
|
|
}
|
|
else anonym->rxp = 0UL;
|
|
}
|
|
} /* end for */
|
|
i += (int32_t)((uint32_t)maxchannels+1UL);
|
|
}
|
|
for (m = 0L; m<=7L; m++) {
|
|
{ /* with */
|
|
struct MPAR * anonym0 = &modpar[m];
|
|
if (anonym0->configured) {
|
|
ndcd = chan[anonym0->ch]
|
|
.adcmax>=anonym0->leveldcd && noiselevel((uint32_t)m)
|
|
<anonym0->squelchdcd;
|
|
if (ndcd) {
|
|
chan[anonym0->ch].dcdclock = clock0; /* tx wise dcd */
|
|
anonym0->dcdclockm = clock0;
|
|
/* modem wise dcd for shift digi*/
|
|
}
|
|
if (ndcd!=anonym0->haddcd) {
|
|
if (ndcd) startrandom(anonym0->ch);
|
|
anonym0->haddcd = ndcd;
|
|
}
|
|
ndcd = CheckRandom(m);
|
|
if (ndcd!=anonym0->haddcdrand) {
|
|
anonym0->haddcdrand = ndcd;
|
|
if (anonym0->dcdmsgs) {
|
|
sendaxudp2((uint32_t)m, 0UL, 0, "", 1ul);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} /* end for */
|
|
} /* end getadc() */
|
|
|
|
|
|
static void txmon(pKISSNEXT pf)
|
|
{
|
|
if (pf && modpar[(uint8_t)pf->port].monitor) {
|
|
ShowFrame(pf->data, 341ul, pf->len,
|
|
(int32_t)(uint32_t)(uint8_t)pf->port, 0L,
|
|
modpar[(uint8_t)pf->port].monitor==afskmodem_noinfo);
|
|
}
|
|
} /* end txmon() */
|
|
|
|
|
|
static float Phasemod(float * uc, float u, float hp)
|
|
{
|
|
float ud;
|
|
ud = u-*uc;
|
|
*uc = *uc+ud*hp;
|
|
return ud;
|
|
} /* end Phasemod() */
|
|
|
|
|
|
static void Free(pKISSNEXT * tb)
|
|
{
|
|
pKISSNEXT ph;
|
|
if (*tb) {
|
|
ph = (*tb)->next;
|
|
(*tb)->next = pTxFree;
|
|
pTxFree = *tb;
|
|
*tb = ph;
|
|
}
|
|
} /* end Free() */
|
|
|
|
|
|
static char frames2tx(int32_t modem)
|
|
{
|
|
char txo;
|
|
char tx;
|
|
tx = 0;
|
|
if (modpar[modem].txbufin) {
|
|
if (modpar[modem].txbufin->time0<=systime) {
|
|
Free(&modpar[modem].txbufin); /* frame too old */
|
|
}
|
|
else tx = 1;
|
|
}
|
|
if (modpar[modem].dcdmsgs) {
|
|
/* axudp2 check if txbuffer run empty*/
|
|
txo = modpar[modem].hadtxdata;
|
|
modpar[modem].hadtxdata = tx;
|
|
if (txo && !tx) {
|
|
sendaxudp2((uint32_t)modem, 0UL, 0, "", 1ul);
|
|
/* send tx ready msg */
|
|
}
|
|
}
|
|
return tx;
|
|
} /* end frames2tx() */
|
|
|
|
|
|
static void sendmodem(void)
|
|
{
|
|
short buf[4096];
|
|
int32_t i;
|
|
float samp;
|
|
uint8_t c;
|
|
struct CHAN * anonym;
|
|
struct CHAN * anonym0;
|
|
struct MPAR * anonym1;
|
|
struct CHAN * anonym2;
|
|
uint8_t tmp;
|
|
int32_t tmp0;
|
|
if (soundbufs>0UL) --soundbufs;
|
|
tmp = maxchannels;
|
|
c = afskmodem_LEFT;
|
|
if (c<=tmp) for (;; c++) {
|
|
{ /* with */
|
|
struct CHAN * anonym = &chan[c];
|
|
if (anonym->pttsoundbufs>0UL) --anonym->pttsoundbufs;
|
|
if (anonym->state==afskmodem_receiv) {
|
|
for (i = 0L; i<=7L; i++) {
|
|
/* has any modem data? */
|
|
/*
|
|
IF modpar[i].txbufin<>NIL THEN
|
|
IF c=modpar[i].ch THEN actmodem:=i END;
|
|
END;
|
|
*/
|
|
if (frames2tx(i) && c==modpar[i].ch) anonym->actmodem = i;
|
|
} /* end for */
|
|
/*
|
|
IF (actmodem<0) OR (modpar[actmodem].txbufin=NIL)
|
|
THEN (* no data to send *)
|
|
*/
|
|
if (anonym->actmodem<0L || !frames2tx(anonym->actmodem)) {
|
|
/* no data to send */
|
|
/*
|
|
IF soundctl.getoutfilled(soundfd)
|
|
<=0 THEN soundctl.pcmsync(soundfd) END;
|
|
IF soundctl.getoutfilled(soundfd)
|
|
>0 THEN IO.WrInt(soundctl.getoutfilled(soundfd),1); IO.WrLn;
|
|
END;
|
|
*/
|
|
if (anonym->pttstate && anonym->pttsoundbufs==0UL) {
|
|
anonym->pttstate = 0;
|
|
ptt(anonym->hptt, 0L);
|
|
/* guess all sound buffers are sent*/
|
|
if (modpar[anonym->actmodem].dcdmsgs) {
|
|
sendaxudp2((uint32_t)anonym->actmodem, 0UL, 0, "",
|
|
1ul);
|
|
}
|
|
}
|
|
}
|
|
else if (anonym->pttstate) {
|
|
/* more data, ptt is on*/
|
|
anonym->state = afskmodem_sendtxdel;
|
|
anonym->tbitc = 0L;
|
|
anonym->tbytec = 0UL;
|
|
txmon(modpar[anonym->actmodem].txbufin);
|
|
}
|
|
else {
|
|
/* data ptt off */
|
|
anonym->tbytec = 0UL;
|
|
anonym->state = afskmodem_slotwait;
|
|
startrandom(c);
|
|
}
|
|
}
|
|
if (anonym->state==afskmodem_slotwait) {
|
|
if (!CheckRandom(anonym->actmodem) || !chan[(uint32_t)
|
|
maxchannels-(uint32_t)c].pttstate) {
|
|
/* onetx: tx locks tx of other channel */
|
|
/*
|
|
IF duplex=shiftdigi THEN
|
|
clk:=modpar[actmodem].dcdclockm;
|
|
(* use dcd of this modulation *)
|
|
ELSE clk:=dcdclock END;
|
|
(* use dcd of latest heard modulation *)
|
|
|
|
IF (duplex=fullduplex) OR (clock-clk > addrandom)
|
|
& ((duplex<>onetx) OR NOT chan[VAL(CHANNELS,
|
|
ORD(maxchannels)-ORD(c))].pttstate)
|
|
THEN (* onetx: tx locks tx of other channel *)
|
|
*/
|
|
if (frames2tx(anonym->actmodem)) {
|
|
txmon(modpar[anonym->actmodem].txbufin);
|
|
chan[c].pttstate = 1; /*WrInt(ORD(c),1); WrStrLn(" ptton");
|
|
*/
|
|
ptt(chan[c].hptt, 1L);
|
|
if (modpar[anonym->actmodem].dcdmsgs) {
|
|
sendaxudp2((uint32_t)anonym->actmodem, 0UL, 0, "",
|
|
1ul);
|
|
}
|
|
chan[c].gmcnt = chan[c].gmqtime;
|
|
anonym->pttsoundbufs = soundbufs+extraaudiodelay;
|
|
anonym->state = afskmodem_sendtxdel;
|
|
anonym->tbitc = 0L;
|
|
anonym->tbytec = 0UL;
|
|
}
|
|
else anonym->state = afskmodem_receiv;
|
|
}
|
|
}
|
|
}
|
|
if (c==tmp) break;
|
|
} /* end for */
|
|
/* WHILE (soundbufs<maxsoundbufs) & ((chan[LEFT].state>=sendtxdel)
|
|
OR (chan[RIGHT].state>=sendtxdel)) DO */
|
|
while (soundbufs<maxsoundbufs && ((badsounddriver || chan[afskmodem_LEFT]
|
|
.state>=afskmodem_sendtxdel)
|
|
|| chan[afskmodem_RIGHT].state>=afskmodem_sendtxdel)) {
|
|
tmp0 = (int32_t)(adcbuflen-1UL);
|
|
i = 0L;
|
|
if (i<=tmp0) for (;; i++) {
|
|
if (maxchannels==afskmodem_RIGHT) c = (uint8_t)(i&1L);
|
|
else c = afskmodem_LEFT;
|
|
{ /* with */
|
|
struct CHAN * anonym0 = &chan[c];
|
|
if (anonym0->state>=afskmodem_sendtxdel) {
|
|
samp = TFIR[anonym0->txbaudgen/512UL][(uint32_t)
|
|
anonym0->tscramb&63UL];
|
|
if (modpar[anonym0->actmodem].afsk) {
|
|
anonym0->dds = anonym0->dds+(uint32_t)
|
|
X2C_TRUNCC(samp*modpar[anonym0->actmodem]
|
|
.afshift+modpar[anonym0->actmodem].afmid,0UL,
|
|
X2C_max_longcard)&32767UL;
|
|
buf[i] = (short)(int32_t)
|
|
X2C_TRUNCI(Phasemod(&anonym0->hipasscap,
|
|
SIN[anonym0->dds]*modpar[anonym0->actmodem].txvolum,
|
|
modpar[anonym0->actmodem].afskhighpass),X2C_min_longint,
|
|
X2C_max_longint);
|
|
}
|
|
else {
|
|
buf[i] = (short)(int32_t)
|
|
X2C_TRUNCI(samp*modpar[anonym0->actmodem].txvolum,
|
|
X2C_min_longint,X2C_max_longint);
|
|
}
|
|
if (anonym0->gmcnt>0UL) {
|
|
buf[i] = 0;
|
|
--anonym0->gmcnt;
|
|
}
|
|
anonym0->txbaudgen = anonym0->txbaudgen+modpar[anonym0->actmodem]
|
|
.txbaud;
|
|
if (anonym0->txbaudgen>=65536UL) {
|
|
anonym0->txbaudgen -= 65536UL;
|
|
/*send next bit */
|
|
if (anonym0->tbitc<=0L) {
|
|
anonym0->tbitc = 8L;
|
|
if (anonym0->state==afskmodem_sendtxdel) {
|
|
if (modpar[anonym0->actmodem].bert>0L) {
|
|
anonym0->tbyte = 255UL;
|
|
modpar[anonym0->actmodem].bert -= 8L;
|
|
}
|
|
else {
|
|
anonym0->tbyte = modpar[anonym0->actmodem]
|
|
.txdelpattern;
|
|
++anonym0->tbytec;
|
|
}
|
|
if (anonym0->tbytec>=modpar[anonym0->actmodem].txdel)
|
|
anonym0->tbyte = 126UL;
|
|
if (anonym0->tbytec>modpar[anonym0->actmodem].txdel) {
|
|
anonym0->state = afskmodem_senddata;
|
|
anonym0->tbytec = 0UL;
|
|
anonym0->txstuffc = 0L;
|
|
}
|
|
}
|
|
if (anonym0->state==afskmodem_sendtxtail) {
|
|
anonym0->tbyte = 126UL;
|
|
++anonym0->tbytec;
|
|
/*next frame*/
|
|
if (modpar[anonym0->actmodem].txbufin) {
|
|
/* same modem */
|
|
anonym0->tbytec = 0UL;
|
|
anonym0->state = afskmodem_senddata;
|
|
anonym0->txstuffc = 0L;
|
|
txmon(modpar[anonym0->actmodem].txbufin);
|
|
}
|
|
else if (anonym0->tbytec>modpar[anonym0->actmodem]
|
|
.txtail) {
|
|
anonym0->state = afskmodem_receiv;
|
|
/* no data for this modem */
|
|
}
|
|
}
|
|
if (anonym0->state==afskmodem_senddata) {
|
|
{ /* with */
|
|
struct MPAR * anonym1 = &modpar[anonym0->actmodem]
|
|
;
|
|
if (anonym1->txbufin==0 || anonym0->tbytec>=anonym1->txbufin->len+2UL)
|
|
{
|
|
/*frame sent*/
|
|
Free(&anonym1->txbufin);
|
|
anonym0->state = afskmodem_sendtxtail;
|
|
anonym0->tbyte = 126UL;
|
|
anonym0->tbytec = 0UL;
|
|
}
|
|
else {
|
|
anonym0->tbyte = (uint32_t)(uint8_t)
|
|
anonym1->txbufin->data[anonym0->tbytec];
|
|
++anonym0->tbytec;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
/*stuff*/
|
|
if ((anonym0->tbyte&1)
|
|
&& anonym0->state==afskmodem_senddata) {
|
|
++anonym0->txstuffc;
|
|
if (anonym0->txstuffc>=5L) {
|
|
anonym0->tbyte += anonym0->tbyte-1UL;
|
|
++anonym0->tbitc;
|
|
anonym0->txstuffc = 0L;
|
|
}
|
|
}
|
|
else anonym0->txstuffc = 0L;
|
|
/*stuff*/
|
|
/* nrzi */
|
|
if (!(anonym0->tbyte&1)) anonym0->tnrzi = !anonym0->tnrzi;
|
|
/*
|
|
IF modpar[actmodem].scramb THEN
|
|
tscramb:=CAST(BITSET, CAST(CARDINAL,
|
|
tscramb)*2+ORD(tnrzi <> ((11 IN tscramb) <> (16 IN tscramb)))
|
|
);
|
|
ELSE tscramb:=CAST(BITSET, CAST(CARDINAL,
|
|
tscramb)*2+ORD(tnrzi)) END;
|
|
*/
|
|
anonym0->tscramb = X2C_LSH(anonym0->tscramb,32,1);
|
|
if (modpar[anonym0->actmodem].scramb) {
|
|
if (anonym0->tnrzi!=(((0x1000UL & anonym0->tscramb)!=0)
|
|
!=((0x20000UL & anonym0->tscramb)!=0))) {
|
|
anonym0->tscramb |= 0x1UL;
|
|
}
|
|
}
|
|
else if (anonym0->tnrzi) anonym0->tscramb |= 0x1UL;
|
|
anonym0->tbyte = anonym0->tbyte>>1;
|
|
--anonym0->tbitc;
|
|
}
|
|
}
|
|
else buf[i] = 0;
|
|
}
|
|
if (i==tmp0) break;
|
|
} /* end for */
|
|
/* WrBin(soundfd, buf, adcbuflen*adcbytes); */
|
|
i = write(soundfd, (char *)buf, adcbuflen*adcbytes);
|
|
for (c = afskmodem_LEFT;; c++) {
|
|
{ /* with */
|
|
struct CHAN * anonym2 = &chan[c];
|
|
if (anonym2->state>=afskmodem_sendtxdel) ++anonym2->pttsoundbufs;
|
|
}
|
|
if (c==afskmodem_RIGHT) break;
|
|
} /* end for */
|
|
++soundbufs;
|
|
}
|
|
} /* end sendmodem() */
|
|
|
|
static void afskmodemcleanup(int32_t);
|
|
|
|
|
|
static void afskmodemcleanup(int32_t signum)
|
|
{
|
|
pttDestroy(chan[afskmodem_LEFT].hptt);
|
|
pttDestroy(chan[afskmodem_RIGHT].hptt);
|
|
osi_WrStr("exit ", 6ul);
|
|
osic_WrINT32((uint32_t)signum, 0UL);
|
|
osi_WrStrLn("!", 2ul);
|
|
X2C_HALT((uint32_t)signum);
|
|
} /* end afskmodemcleanup() */
|
|
|
|
|
|
X2C_STACK_LIMIT(100000l)
|
|
extern int main(int argc, char **argv)
|
|
{
|
|
X2C_BEGIN(&argc,argv,1,4000000l,8000000l);
|
|
if (sizeof(FILENAME)!=1024) X2C_ASSERT(0);
|
|
aprsstr_BEGIN();
|
|
osi_BEGIN();
|
|
signal(SIGTERM, afskmodemcleanup);
|
|
signal(SIGINT, afskmodemcleanup);
|
|
memset((char *)modpar,(char)0,sizeof(struct MPAR [8]));
|
|
Parms();
|
|
Gencrctab();
|
|
initTFIR();
|
|
/*
|
|
tfd:=FIO.Create("/tmp/t.raw");
|
|
*/
|
|
getst = 0UL;
|
|
esc = 0;
|
|
afin = 0UL;
|
|
soundbufs = 0UL;
|
|
ptt(chan[afskmodem_LEFT].hptt, -1L);
|
|
ptt(chan[afskmodem_RIGHT].hptt, -1L);
|
|
for (;;) {
|
|
getadc();
|
|
++clock0;
|
|
if ((clock0&63UL)==0UL) {
|
|
ptt(chan[afskmodem_LEFT].hptt, -1L);
|
|
/* sync ptt to hardware sometime */
|
|
ptt(chan[afskmodem_RIGHT].hptt, -1L);
|
|
systime = osic_time();
|
|
}
|
|
getkiss();
|
|
getudp();
|
|
sendmodem();
|
|
}
|
|
/*
|
|
IO.WrStr("len="); IO.WrCard(txbuf[txp].len, 1); IO.WrStr("cmd=");
|
|
IO.WrHex(ORD(txbuf[txp].cmd), 1);
|
|
|
|
FOR i:=1 TO txbuf[txp].len DO IO.WrHex(ORD(txbuf[txp].data[i-1]), 3) END;
|
|
IO.WrLn;
|
|
*/
|
|
/*
|
|
FIO.Close(pipefd);
|
|
*/
|
|
/*
|
|
FIO.Close(tfd);
|
|
*/
|
|
X2C_EXIT();
|
|
return 0;
|
|
}
|
|
|
|
X2C_MAIN_DEFINITION
|