mirror of
https://github.com/dj0abr/SSB_HighSpeed_Modem.git
synced 2024-10-31 15:37:12 -04:00
update
This commit is contained in:
parent
f0fc9622a4
commit
e335d4efbf
Binary file not shown.
Binary file not shown.
@ -2,7 +2,7 @@
|
||||
|
||||
CXXFLAGS = -Wall -O3 -std=c++0x -Wno-write-strings -Wno-narrowing
|
||||
LDFLAGS = -lpthread -lrt -lsndfile -lasound -lm -lbass -lbassflac -lfftw3 -lfftw3_threads -lliquid
|
||||
OBJ = hsmodem.o constellation.o crc16.o frame_packer.o main_helper.o scrambler.o speed.o fec.o audio.o udp.o fft.o liquid_if.o
|
||||
OBJ = hsmodem.o constellation.o crc16.o frame_packer.o main_helper.o scrambler.o speed.o fec.o audio.o udp.o fft.o liquid_if.o symboltracker.o
|
||||
|
||||
default: $(OBJ)
|
||||
g++ $(CXXFLAGS) -o ../LinuxRelease/hsmodem $(OBJ) $(LDFLAGS)
|
||||
|
@ -369,7 +369,7 @@ void setPBvolume(int v)
|
||||
float vf = v;
|
||||
vf /= 100;
|
||||
|
||||
printf("set PB volume to:%d / %f [0..1]\n", v, vf );
|
||||
//printf("set PB volume to:%d / %f [0..1]\n", v, vf );
|
||||
|
||||
selectPBdevice();
|
||||
if (!BASS_SetVolume(vf))
|
||||
@ -383,7 +383,7 @@ void setCAPvolume(int v)
|
||||
float vf = v;
|
||||
vf /= 100;
|
||||
|
||||
printf("set CAP volume to:%d / %f [0..1]\n", v, vf);
|
||||
//printf("set CAP volume to:%d / %f [0..1]\n", v, vf);
|
||||
|
||||
selectCAPdevice();
|
||||
if (!BASS_RecordSetInput(-1,BASS_INPUT_ON,vf))
|
||||
@ -462,7 +462,7 @@ void PB_UNLOCK() { pthread_mutex_unlock(&pb_crit_sec); }
|
||||
|
||||
#define AUDIO_BUFFERMAXTIME 2 // fifo can buffer this time in [s]
|
||||
#define AUDIO_PLAYBACK_BUFLEN (48000 * 10) // space for 10 seconds of samples
|
||||
#define AUDIO_CAPTURE_BUFLEN (48000 * 10)
|
||||
#define AUDIO_CAPTURE_BUFLEN (48000) // space for 1s
|
||||
|
||||
int cap_wridx=0;
|
||||
int cap_rdidx=0;
|
||||
@ -487,6 +487,11 @@ void init_pipes()
|
||||
// overwrite old data if the fifo is full
|
||||
void cap_write_fifo(float sample)
|
||||
{
|
||||
if (((cap_wridx + 1) % AUDIO_CAPTURE_BUFLEN) == cap_rdidx)
|
||||
{
|
||||
printf("cap fifo full\n");
|
||||
}
|
||||
|
||||
CAP_LOCK;
|
||||
cap_buffer[cap_wridx] = sample;
|
||||
if(++cap_wridx >= AUDIO_CAPTURE_BUFLEN) cap_wridx = 0;
|
||||
|
BIN
hsmodem/audio/amsat.flac
Normal file
BIN
hsmodem/audio/amsat.flac
Normal file
Binary file not shown.
@ -157,7 +157,7 @@ void setPBvolume(int v)
|
||||
if (vf < minPBvol) vf = minPBvol;
|
||||
if (vf > maxPBvol) vf = maxPBvol;
|
||||
|
||||
printf("set PB volume to:%d / %f [%f..%f]\n", v, vf, minPBvol, maxPBvol);
|
||||
//printf("set PB volume to:%d / %f [%f..%f]\n", v, vf, minPBvol, maxPBvol);
|
||||
|
||||
selectPBdevice_wasapi();
|
||||
if (!BASS_WASAPI_SetVolume(BASS_WASAPI_CURVE_DB, vf))
|
||||
@ -216,16 +216,55 @@ DWORD CALLBACK PBcallback_wasapi(void* buffer, DWORD length, void* user)
|
||||
free(fdata);
|
||||
return length;
|
||||
}
|
||||
/*
|
||||
#define MCHECK 10
|
||||
void nullChecker(float fv, float *pbuf, DWORD len)
|
||||
{
|
||||
static float farr[MCHECK];
|
||||
static int idx = 0;
|
||||
static int f = 1;
|
||||
static int anz = 0;
|
||||
|
||||
if (f)
|
||||
{
|
||||
f = 0;
|
||||
for (int i = 0; i < MCHECK; i++)
|
||||
farr[i] = 1;
|
||||
}
|
||||
|
||||
farr[idx] = fv;
|
||||
idx++;
|
||||
if (idx == MCHECK) idx = 0;
|
||||
|
||||
float nu = 0;
|
||||
for (int i = 0; i < MCHECK; i++)
|
||||
{
|
||||
nu += farr[i];
|
||||
}
|
||||
|
||||
if (nu == 0)
|
||||
{
|
||||
// how many 00s ar in the current buffer
|
||||
int a = 0;
|
||||
for (unsigned int i = 0; i < len-1; i++)
|
||||
{
|
||||
if (pbuf[i] == 0 && pbuf[i+1] == 0) a++;
|
||||
}
|
||||
printf("=============== null sequence detected: %d len:%d nullanz:%d\n",anz++,len,a);
|
||||
}
|
||||
}
|
||||
*/
|
||||
DWORD CALLBACK CAPcallback_wasapi(void* buffer, DWORD length, void* user)
|
||||
{
|
||||
//printf("CAP callback, len:%d\n",length);
|
||||
//measure_speed_bps(length/sizeof(float)/ WASAPI_CHANNELS);
|
||||
|
||||
float* fbuffer = (float*)buffer;
|
||||
//showbytestringf((char*)"rx: ", fbuffer, 20);
|
||||
//showbytestringf((char*)"rx: ", fbuffer, 10);
|
||||
//printf("%10.6f\n", fbuffer[0]);
|
||||
for (unsigned int i = 0; i < (length / sizeof(float)); i += WASAPI_CHANNELS)
|
||||
{
|
||||
//nullChecker(fbuffer[i],fbuffer, length / sizeof(float));
|
||||
cap_write_fifo(fbuffer[i]);
|
||||
}
|
||||
|
||||
|
@ -32,6 +32,7 @@ uint8_t rx_status = 0;
|
||||
|
||||
int framecounter = 0;
|
||||
int lastframenum = 0;
|
||||
int getPayload_error = 0;
|
||||
|
||||
// header for TX,
|
||||
uint8_t TXheaderbytes[HEADERLEN] = {0x53, 0xe1, 0xa6};
|
||||
@ -95,7 +96,7 @@ uint8_t *Pack(uint8_t *payload, int type, int status, int *plen)
|
||||
// polulate the raw frame
|
||||
|
||||
// make the frame counter
|
||||
if(status & (1<<4))
|
||||
if(status == 0)
|
||||
framecounter = 0; // first block of a stream
|
||||
else
|
||||
framecounter++;
|
||||
@ -131,30 +132,46 @@ uint8_t *Pack(uint8_t *payload, int type, int status, int *plen)
|
||||
return txblock;
|
||||
}
|
||||
|
||||
#ifdef _WIN32_
|
||||
#define MAXHEADERRS 5
|
||||
#endif
|
||||
|
||||
#define MAXHEADERRS 0
|
||||
#ifdef _LINUX_
|
||||
#define MAXHEADERRS 2 // takes less CPU time, important for Rasberry PI
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Header erros will not cause any data errors because the CRC will filter out
|
||||
* false header detects,
|
||||
* but it will cause higher CPU load due to excessive execution of FEC and CRC
|
||||
*/
|
||||
int seekHeadersyms()
|
||||
*/
|
||||
|
||||
int seekHeadersyms(int symnum)
|
||||
{
|
||||
int ret = -1;
|
||||
int errs = 0;
|
||||
|
||||
int exp_hdr = (UDPBLOCKLEN * 8) / bitsPerSymbol; // we expect a new header at this symbol number
|
||||
symnum %= exp_hdr;
|
||||
|
||||
int maxerr = MAXHEADERRS;
|
||||
|
||||
if(constellationSize == 4)
|
||||
{
|
||||
// QPSK
|
||||
for(int tab=0; tab<4; tab++)
|
||||
{
|
||||
int errs = 0;
|
||||
errs = 0;
|
||||
for(int i=0; i<HEADERLEN*8/2; i++)
|
||||
{
|
||||
if(rxbuffer[i] != QPSK_headertab[tab][i])
|
||||
{
|
||||
errs++;
|
||||
}
|
||||
if (errs <= maxerr)
|
||||
{
|
||||
ret = tab;
|
||||
break;
|
||||
}
|
||||
if(errs <= MAXHEADERRS) return tab;
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -162,17 +179,27 @@ int seekHeadersyms()
|
||||
// 8PSK
|
||||
for(int tab=0; tab<8; tab++)
|
||||
{
|
||||
int errs = 0;
|
||||
errs = 0;
|
||||
for(int i=0; i<HEADERLEN*8/3; i++)
|
||||
{
|
||||
if(rxbuffer[i] != _8PSK_headertab[tab][i])
|
||||
{
|
||||
errs++;
|
||||
}
|
||||
}
|
||||
if(errs <= MAXHEADERRS) return tab;
|
||||
if(errs <= maxerr)
|
||||
{
|
||||
ret = tab;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ret != -1)
|
||||
{
|
||||
//printf("header detected at symbol:%d, headererrors:%d\n", symnum,errs);
|
||||
return ret;
|
||||
}
|
||||
|
||||
//if (symnum == 0) printf("header expected at symbol:%d but not found\n", symnum);
|
||||
|
||||
return -1;
|
||||
}
|
||||
@ -184,6 +211,7 @@ uint8_t *unpack_data(uint8_t *rxd, int len)
|
||||
{
|
||||
int framerdy = 0;
|
||||
static uint8_t payload[PAYLOADLEN+10];
|
||||
static int symnum = 0;
|
||||
|
||||
rx_status = 0;
|
||||
// shift all received symbols through rxbuffer
|
||||
@ -196,13 +224,13 @@ uint8_t *unpack_data(uint8_t *rxd, int len)
|
||||
memmove(rxbuffer,rxbuffer+1,frmlen-1);
|
||||
// insert new symbol at the top
|
||||
rxbuffer[frmlen-1] = rxd[sym];
|
||||
symnum++;
|
||||
|
||||
//showbytestring((char*)"rx: ",rxbuffer,30);
|
||||
|
||||
int rotations = seekHeadersyms();
|
||||
int rotations = seekHeadersyms(symnum);
|
||||
if(rotations != -1)
|
||||
{
|
||||
//printf("Header found, rotation: %d\n",rotations);
|
||||
|
||||
// rxbuffer contains all symbols of the received frame
|
||||
// convert to bytes
|
||||
@ -226,6 +254,14 @@ uint8_t *unpack_data(uint8_t *rxd, int len)
|
||||
{
|
||||
memcpy(payload,pl, PAYLOADLEN+10);
|
||||
framerdy = 1;
|
||||
if(symnum != 688)
|
||||
printf("Header found, rotation: %d at symbol no.: %d result: OK\n", rotations, symnum);
|
||||
symnum = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if((symnum % ((UDPBLOCKLEN * 8) / bitsPerSymbol)) == 0)
|
||||
printf("Header found, rotation: %d at symbol no.: %d result: %d\n", rotations, symnum, getPayload_error);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -273,6 +309,7 @@ uint8_t *getPayload(uint8_t *rxb)
|
||||
if(ret == 0)
|
||||
{
|
||||
//printf("fec ERROR\n");
|
||||
getPayload_error = 1;
|
||||
return NULL; // fec impossible
|
||||
}
|
||||
//printf("fec ok\n");
|
||||
@ -285,6 +322,7 @@ uint8_t *getPayload(uint8_t *rxb)
|
||||
if (crc != rxcrc)
|
||||
{
|
||||
//printf("crc ERROR\n");
|
||||
getPayload_error = 2;
|
||||
return NULL; // no data found
|
||||
}
|
||||
//printf("crc OK\n");
|
||||
@ -308,8 +346,8 @@ uint8_t *getPayload(uint8_t *rxb)
|
||||
payload[4] = rx_status; // frame lost information
|
||||
payload[5] = speed >> 8; // measured line speed
|
||||
payload[6] = speed;
|
||||
payload[7] = 0; // free for later use
|
||||
payload[8] = 0;
|
||||
payload[7] = maxLevel; // actual max level on sound capture in %
|
||||
payload[8] = 0; // free for later use
|
||||
payload[9] = 0;
|
||||
|
||||
//printf("Frame no.: %d, type:%d, minfo:%d\n",framenumrx,payload[0],payload[3]);
|
||||
|
@ -91,6 +91,7 @@ int UdpDataPort_fromGR_I_Q = 40137;
|
||||
int speedmode = 2;
|
||||
int bitsPerSymbol = 2; // QPSK=2, 8PSK=3
|
||||
int constellationSize = 4; // QPSK=4, 8PSK=8
|
||||
int psk8mode=0; // 0=APSK8, 1=PSK8
|
||||
|
||||
char localIP[] = { "127.0.0.1" };
|
||||
char ownfilename[] = { "hsmodem" };
|
||||
@ -202,7 +203,7 @@ int main(int argc, char* argv[])
|
||||
//doArraySend();
|
||||
|
||||
if (demodulator() == 0)
|
||||
sleep_ms(100);
|
||||
sleep_ms(10);
|
||||
}
|
||||
printf("stopped: %d\n", keeprunning);
|
||||
|
||||
@ -242,6 +243,14 @@ SPEEDRATE sr[8] = {
|
||||
|
||||
void startModem()
|
||||
{
|
||||
if (speedmode >= 8)
|
||||
{
|
||||
speedmode = speedmode - 4;
|
||||
psk8mode = 1;
|
||||
}
|
||||
else
|
||||
psk8mode = 0;
|
||||
|
||||
bitsPerSymbol = sr[speedmode].bpsym;
|
||||
constellationSize = (1 << bitsPerSymbol); // QPSK=4, 8PSK=8
|
||||
|
||||
@ -394,7 +403,7 @@ void appdata_rxdata(uint8_t* pdata, int len, struct sockaddr_in* rxsock)
|
||||
|
||||
//if (getSending() == 1) return; // already sending (Array sending)
|
||||
|
||||
if (minfo == 0)
|
||||
if (minfo == 0 || minfo == 3)
|
||||
{
|
||||
// this is the first frame of a larger file
|
||||
sendAnnouncement();
|
||||
@ -403,8 +412,8 @@ void appdata_rxdata(uint8_t* pdata, int len, struct sockaddr_in* rxsock)
|
||||
// caprate: samples/s. This are symbols: caprate/txinterpolfactor
|
||||
// and bits: symbols * bitsPerSymbol
|
||||
// and bytes/second: bits/8 = (caprate/txinterpolfactor) * bitsPerSymbol / 8
|
||||
// one frame has 258 bytes, so we need for 5s: 5* ((caprate/txinterpolfactor) * bitsPerSymbol / 8) /258 + 1 frames
|
||||
int numframespreamble = 5 * ((caprate / txinterpolfactor) * bitsPerSymbol / 8) / 258 + 1;
|
||||
// one frame has 258 bytes, so we need for 6s: 6* ((caprate/txinterpolfactor) * bitsPerSymbol / 8) /258 + 1 frames
|
||||
int numframespreamble = 6 * ((caprate / txinterpolfactor) * bitsPerSymbol / 8) / 258 + 1;
|
||||
for (int i = 0; i < numframespreamble; i++)
|
||||
toGR_sendData(pdata + 2, type, minfo);
|
||||
}
|
||||
@ -460,7 +469,7 @@ void GRdata_rxdata(uint8_t* pdata, int len, struct sockaddr_in* rxsock)
|
||||
if (++fnd >= (wt * ws))
|
||||
{
|
||||
fnd = 0;
|
||||
//printf("no signal detected %d, reset RX modem\n", wt);
|
||||
printf("no signal detected %d, reset RX modem\n", wt);
|
||||
resetModem();
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef _WIN32
|
||||
#define _WIN32_
|
||||
@ -60,6 +61,7 @@
|
||||
#include "frameformat.h"
|
||||
#include "fec.h"
|
||||
#include "udp.h"
|
||||
#include "symboltracker.h"
|
||||
|
||||
#define jpg_tempfilename "rxdata.jpg"
|
||||
|
||||
@ -129,6 +131,14 @@ void exit_fft();
|
||||
void showbytestringf(char* title, float* data, int anz);
|
||||
uint16_t* make_waterfall(float fre, int* retlen);
|
||||
|
||||
void km_symtrack_cccf_create(int _ftype,
|
||||
unsigned int _k,
|
||||
unsigned int _m,
|
||||
float _beta,
|
||||
int _ms);
|
||||
void km_symtrack_cccf_reset(int mode);
|
||||
void km_symtrack_cccf_set_bandwidth(float _bw);
|
||||
void km_symtrack_execute(liquid_float_complex _x, liquid_float_complex* _y, unsigned int* _ny, unsigned int* psym_out);
|
||||
|
||||
extern int speedmode;
|
||||
extern int bitsPerSymbol;
|
||||
@ -146,6 +156,8 @@ extern int announcement;
|
||||
extern int ann_running;
|
||||
extern int transmissions;
|
||||
extern int linespeed;
|
||||
extern uint8_t maxLevel;
|
||||
extern int psk8mode;
|
||||
|
||||
#ifdef _LINUX_
|
||||
int isRunning(char* prgname);
|
||||
|
@ -228,6 +228,7 @@
|
||||
<ClInclude Include="frameformat.h" />
|
||||
<ClInclude Include="hsmodem.h" />
|
||||
<ClInclude Include="liquid.h" />
|
||||
<ClInclude Include="symboltracker.h" />
|
||||
<ClInclude Include="udp.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
@ -243,6 +244,7 @@
|
||||
<ClCompile Include="main_helper.cpp" />
|
||||
<ClCompile Include="scrambler.cpp" />
|
||||
<ClCompile Include="speed.cpp" />
|
||||
<ClCompile Include="symboltracker.cpp" />
|
||||
<ClCompile Include="udp.cpp" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
|
@ -54,6 +54,9 @@
|
||||
<ClCompile Include="audio_wasapi.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="symboltracker.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="hsmodem.h">
|
||||
@ -86,5 +89,8 @@
|
||||
<ClInclude Include="bassflac.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="symboltracker.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
@ -51,9 +51,13 @@ modulation_scheme getMod()
|
||||
{
|
||||
if(bitsPerSymbol == 2)
|
||||
return LIQUID_MODEM_QPSK;
|
||||
//return LIQUID_MODEM_APSK4;
|
||||
else
|
||||
{
|
||||
if(psk8mode == 0)
|
||||
return LIQUID_MODEM_APSK8;
|
||||
else
|
||||
return LIQUID_MODEM_PSK8;
|
||||
}
|
||||
}
|
||||
|
||||
// =========== MODULATOR ==================================================
|
||||
@ -209,7 +213,6 @@ void modulator(uint8_t sym_in)
|
||||
|
||||
nco_crcf dnnco = NULL;
|
||||
symtrack_cccf symtrack = NULL;
|
||||
modem demod = NULL;
|
||||
firdecim_crcf decim = NULL;
|
||||
|
||||
// decimator parameters
|
||||
@ -221,8 +224,9 @@ int ftype_st = LIQUID_FIRFILT_RRC;
|
||||
unsigned int k_st = 4; // samples per symbol
|
||||
unsigned int m_st = 7; // filter delay (symbols)
|
||||
float beta_st = beta_excessBW;//0.30f; // filter excess bandwidth factor
|
||||
float bandwidth_st = 0.7f; // loop filter bandwidth
|
||||
float bandwidth_st = 0.9f; // loop filter bandwidth
|
||||
|
||||
uint8_t maxLevel = 0; // maximum level over the last x samples in %
|
||||
|
||||
void init_demodulator()
|
||||
{
|
||||
@ -241,34 +245,23 @@ void init_demodulator()
|
||||
|
||||
// create symbol tracking synchronizer
|
||||
//k_st = txinterpolfactor;
|
||||
symtrack = symtrack_cccf_create(ftype_st,k_st,m_st,beta_st,getMod());
|
||||
symtrack_cccf_set_bandwidth(symtrack,bandwidth_st);
|
||||
|
||||
int ret = symtrack_cccf_set_eq_dd(symtrack);
|
||||
if (ret != LIQUID_OK)
|
||||
{
|
||||
printf("symtrack_cccf_set_eq_dd failed\n");
|
||||
}
|
||||
|
||||
// demodulator
|
||||
demod = modem_create(getMod());
|
||||
printf("RX demodulator running\n");
|
||||
//symtrack = km_symtrack_cccf_create(ftype_st,k_st,m_st,beta_st,getMod());
|
||||
km_symtrack_cccf_create(ftype_st, k_st, m_st, beta_st, getMod());
|
||||
//symtrack_cccf_set_bandwidth(symtrack,bandwidth_st);
|
||||
km_symtrack_cccf_set_bandwidth(bandwidth_st);
|
||||
}
|
||||
|
||||
void close_demodulator()
|
||||
{
|
||||
if(symtrack != NULL) symtrack_cccf_destroy(symtrack);
|
||||
if(demod != NULL) modem_destroy(demod);
|
||||
if(decim != NULL) firdecim_crcf_destroy(decim);
|
||||
symtrack = NULL;
|
||||
demod = NULL;
|
||||
decim = NULL;
|
||||
}
|
||||
|
||||
void resetModem()
|
||||
{
|
||||
//printf("Reset Symtrack\n");
|
||||
symtrack_cccf_reset(symtrack);
|
||||
km_symtrack_cccf_reset(0xff);
|
||||
}
|
||||
|
||||
// called for Audio-Samples (FFT)
|
||||
@ -301,6 +294,34 @@ void make_FFTdata(float f)
|
||||
}
|
||||
}
|
||||
|
||||
#define MCHECK 1000
|
||||
void getMax(float fv)
|
||||
{
|
||||
static float farr[MCHECK];
|
||||
static int idx = 0;
|
||||
static int f = 1;
|
||||
|
||||
if (f)
|
||||
{
|
||||
f = 0;
|
||||
for (int i = 0; i < MCHECK; i++)
|
||||
farr[i] = 1;
|
||||
}
|
||||
|
||||
farr[idx] = fv;
|
||||
idx++;
|
||||
if (idx == MCHECK)
|
||||
{
|
||||
idx = 0;
|
||||
float max = 0;
|
||||
for (int i = 0; i < MCHECK; i++)
|
||||
{
|
||||
if (farr[i] > max) max = farr[i];
|
||||
}
|
||||
maxLevel = (uint8_t)(max*100);
|
||||
//printf("max: %10.6f\n", max);
|
||||
}
|
||||
}
|
||||
|
||||
int demodulator()
|
||||
{
|
||||
@ -314,12 +335,15 @@ static int ccol_idx = 0;
|
||||
int ret = cap_read_fifo(&f);
|
||||
if(ret == 0) return 0;
|
||||
|
||||
|
||||
// input volume
|
||||
#ifdef _WIN32_
|
||||
f *= softwareCAPvolume;
|
||||
#endif
|
||||
|
||||
make_FFTdata(f*120);
|
||||
getMax(f);
|
||||
|
||||
make_FFTdata(f*60);
|
||||
|
||||
// downconvert into baseband
|
||||
// still at soundcard sample rate
|
||||
@ -340,18 +364,21 @@ static int ccol_idx = 0;
|
||||
ccol_idx = 0;
|
||||
|
||||
// we have rxPreInterpolfactor samples in ccol
|
||||
//printf("sc:%10.6f dn:%10.6f j%10.6f ", f, c.real, c.imag);
|
||||
liquid_float_complex y;
|
||||
firdecim_crcf_execute(decim, ccol, &y);
|
||||
|
||||
unsigned int num_symbols_sync;
|
||||
liquid_float_complex syms;
|
||||
symtrack_cccf_execute(symtrack, y, &syms, &num_symbols_sync);
|
||||
//symtrack_cccf_execute(symtrack, y, &syms, &num_symbols_sync);
|
||||
unsigned int nsym_out; // output symbol
|
||||
km_symtrack_execute(y, &syms, &num_symbols_sync,&nsym_out);
|
||||
|
||||
if(num_symbols_sync > 1) printf("symtrack_cccf_execute %d output symbols ???\n",num_symbols_sync);
|
||||
if(num_symbols_sync != 0)
|
||||
{
|
||||
unsigned int sym_out; // output symbol
|
||||
modem_demodulate(demod, syms, &sym_out);
|
||||
sym_out = nsym_out;
|
||||
|
||||
measure_speed_syms(1);
|
||||
|
||||
|
@ -89,7 +89,7 @@ void showbytestringf(char* title, float* data, int anz)
|
||||
{
|
||||
printf("%s. Len %d: ", title, anz);
|
||||
for (int i = 0; i < anz; i++)
|
||||
printf("%.6f ", data[i]);
|
||||
printf("%7.4f ", data[i]);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
|
173
hsmodem/symboltracker.cpp
Executable file
173
hsmodem/symboltracker.cpp
Executable file
@ -0,0 +1,173 @@
|
||||
#include "hsmodem.h"
|
||||
|
||||
SYMTRACK km_symtrack;
|
||||
SYMTRACK* q = &km_symtrack;
|
||||
|
||||
// create km_symtrack object with basic parameters
|
||||
// _ftype : filter type (e.g. LIQUID_FIRFILT_RRC)
|
||||
// _k : samples per symbol
|
||||
// _m : filter delay (symbols)
|
||||
// _beta : filter excess bandwidth
|
||||
// _ms : modulation scheme (e.g. LIQUID_MODEM_QPSK)
|
||||
void km_symtrack_cccf_create(int _ftype,
|
||||
unsigned int _k,
|
||||
unsigned int _m,
|
||||
float _beta,
|
||||
int _ms)
|
||||
{
|
||||
// validate input
|
||||
if (_k < 2)
|
||||
printf((char *)"symtrack_cccf_create(), filter samples/symbol must be at least 2\n");
|
||||
if (_m == 0)
|
||||
printf((char*)"symtrack_cccf_create(), filter delay must be greater than zero\n");
|
||||
if (_beta <= 0.0f || _beta > 1.0f)
|
||||
printf((char*)"symtrack_cccf_create(), filter excess bandwidth must be in [0,1]\n");
|
||||
if (_ms == LIQUID_MODEM_UNKNOWN || _ms >= LIQUID_MODEM_NUM_SCHEMES)
|
||||
printf((char*)"symtrack_cccf_create(), invalid modulation scheme\n");
|
||||
|
||||
// set input parameters
|
||||
q->filter_type = _ftype;
|
||||
q->k = _k;
|
||||
q->m = _m;
|
||||
q->beta = _beta;
|
||||
q->mod_scheme = _ms == LIQUID_MODEM_UNKNOWN ? LIQUID_MODEM_BPSK : _ms;
|
||||
|
||||
// create automatic gain control
|
||||
q->agc = agc_crcf_create();
|
||||
|
||||
// create symbol synchronizer (output rate: 2 samples per symbol)
|
||||
if (q->filter_type == LIQUID_FIRFILT_UNKNOWN)
|
||||
q->symsync = symsync_crcf_create_kaiser(q->k, q->m, 0.9f, 16);
|
||||
else
|
||||
q->symsync = symsync_crcf_create_rnyquist(q->filter_type, q->k, q->m, q->beta, 16);
|
||||
symsync_crcf_set_output_rate(q->symsync, 2);
|
||||
|
||||
// create equalizer as default low-pass filter with integer symbol delay (2 samples/symbol)
|
||||
q->eq_len = 2 * 4 + 1;
|
||||
q->eq = eqlms_cccf_create_lowpass(q->eq_len, 0.45f);
|
||||
q->eq_strategy = q->SYMTRACK_EQ_DD;
|
||||
|
||||
// nco and phase-locked loop
|
||||
q->nco = nco_crcf_create(LIQUID_VCO);
|
||||
|
||||
// demodulator
|
||||
q->demod = modem_create((modulation_scheme)q->mod_scheme);
|
||||
|
||||
// set default bandwidth
|
||||
km_symtrack_cccf_set_bandwidth(0.9f);
|
||||
|
||||
// reset and return main object
|
||||
km_symtrack_cccf_reset(0xff);
|
||||
}
|
||||
|
||||
void km_symtrack_cccf_reset(int mode)
|
||||
{
|
||||
// reset objects
|
||||
if (mode & 1) agc_crcf_reset(q->agc);
|
||||
if (mode & 2) symsync_crcf_reset(q->symsync);
|
||||
if (mode & 4) eqlms_cccf_reset(q->eq);
|
||||
if (mode & 8) nco_crcf_reset(q->nco);
|
||||
if (mode & 0x10) modem_reset(q->demod);
|
||||
|
||||
// reset internal counters
|
||||
q->symsync_index = 0;
|
||||
q->num_syms_rx = 0;
|
||||
}
|
||||
|
||||
void km_symtrack_cccf_set_bandwidth(float _bw)
|
||||
{
|
||||
// validate input
|
||||
if (_bw < 0)
|
||||
printf("symtrack_set_bandwidth(), bandwidth must be in [0,1]\n");
|
||||
|
||||
// set bandwidths accordingly
|
||||
float agc_bandwidth = 0.02f * _bw;
|
||||
float symsync_bandwidth = 0.001f * _bw;
|
||||
float eq_bandwidth = 0.02f * _bw;
|
||||
float pll_bandwidth = 0.001f * _bw;
|
||||
|
||||
// automatic gain control
|
||||
agc_crcf_set_bandwidth(q->agc, agc_bandwidth);
|
||||
|
||||
// symbol timing recovery
|
||||
symsync_crcf_set_lf_bw(q->symsync, symsync_bandwidth);
|
||||
|
||||
// equalizer
|
||||
eqlms_cccf_set_bw(q->eq, eq_bandwidth);
|
||||
|
||||
// phase-locked loop
|
||||
nco_crcf_pll_set_bandwidth(q->nco, pll_bandwidth);
|
||||
}
|
||||
|
||||
#define MX 10
|
||||
|
||||
// execute synchronizer on single input sample
|
||||
// _q : synchronizer object
|
||||
// _x : input data sample
|
||||
// _y : output data array
|
||||
// _ny : number of samples written to output buffer
|
||||
void km_symtrack_execute(liquid_float_complex _x, liquid_float_complex* _y, unsigned int* _ny, unsigned int *psym_out)
|
||||
{
|
||||
liquid_float_complex v; // output sample
|
||||
unsigned int i;
|
||||
unsigned int num_outputs = 0;
|
||||
|
||||
// run sample through automatic gain control
|
||||
agc_crcf_execute(q->agc, _x, &v);
|
||||
|
||||
// symbol synchronizer
|
||||
unsigned int nw = 0;
|
||||
symsync_crcf_execute(q->symsync, &v, 1, q->symsync_buf, &nw);
|
||||
|
||||
// process each output sample
|
||||
for (i = 0; i < nw; i++) {
|
||||
// update phase-locked loop
|
||||
nco_crcf_step(q->nco);
|
||||
nco_crcf_mix_down(q->nco, q->symsync_buf[i], &v);
|
||||
|
||||
// equalizer/decimator
|
||||
eqlms_cccf_push(q->eq, v);
|
||||
|
||||
// decimate result, noting that symsync outputs at exactly 2 samples/symbol
|
||||
q->symsync_index++;
|
||||
if (!(q->symsync_index % 2))
|
||||
continue;
|
||||
|
||||
// increment number of symbols received
|
||||
q->num_syms_rx++;
|
||||
|
||||
// compute equalizer filter output; updating coefficients is dependent upon strategy
|
||||
liquid_float_complex d_hat;
|
||||
eqlms_cccf_execute(q->eq, &d_hat);
|
||||
|
||||
// demodulate result, apply phase correction
|
||||
unsigned int sym_out;
|
||||
modem_demodulate(q->demod, d_hat, &sym_out);
|
||||
*psym_out = sym_out;
|
||||
float phase_error = modem_get_demodulator_phase_error(q->demod);
|
||||
|
||||
// update pll
|
||||
nco_crcf_pll_step(q->nco, phase_error);
|
||||
|
||||
// update equalizer independent of the signal: estimate error
|
||||
// assuming constant modulus signal
|
||||
// TODO: check lock conditions of previous object to determine when to run equalizer
|
||||
liquid_float_complex d_prime;
|
||||
d_prime.real = d_prime.imag = 0;
|
||||
if (q->num_syms_rx > 200)
|
||||
{
|
||||
modem_get_demodulator_sample(q->demod, &d_prime);
|
||||
eqlms_cccf_step(q->eq, d_prime, d_hat);
|
||||
}
|
||||
|
||||
// save result to output
|
||||
_y[num_outputs++] = d_hat;
|
||||
}
|
||||
|
||||
/*float fr = nco_crcf_get_frequency(q->nco);
|
||||
float ph = nco_crcf_get_phase(q->nco);
|
||||
|
||||
printf("%10.6f %10.6f %10.6f %10.6f\n", fr, ph, _x.real, _x.imag);*/
|
||||
|
||||
* _ny = num_outputs;
|
||||
}
|
42
hsmodem/symboltracker.h
Executable file
42
hsmodem/symboltracker.h
Executable file
@ -0,0 +1,42 @@
|
||||
#pragma once
|
||||
|
||||
#include "liquid.h"
|
||||
|
||||
typedef struct _SYMTRACK_ {
|
||||
// parameters
|
||||
int filter_type; // filter type (e.g. LIQUID_FIRFILT_RRC)
|
||||
unsigned int k; // samples/symbol
|
||||
unsigned int m; // filter semi-length
|
||||
float beta; // filter excess bandwidth
|
||||
int mod_scheme; // demodulator
|
||||
|
||||
// automatic gain control
|
||||
agc_crcf agc; // agc object
|
||||
float agc_bandwidth; // agc bandwidth
|
||||
|
||||
// symbol timing recovery
|
||||
symsync_crcf symsync; // symbol timing recovery object
|
||||
float symsync_bandwidth; // symsync loop bandwidth
|
||||
liquid_float_complex symsync_buf[8]; // symsync output buffer
|
||||
unsigned int symsync_index; // symsync output sample index
|
||||
|
||||
// equalizer/decimator
|
||||
eqlms_cccf eq; // equalizer (LMS)
|
||||
unsigned int eq_len; // equalizer length
|
||||
float eq_bandwidth; // equalizer bandwidth
|
||||
enum {
|
||||
SYMTRACK_EQ_CM, // equalizer strategy: constant modulus
|
||||
SYMTRACK_EQ_DD, // equalizer strategy: decision directed
|
||||
SYMTRACK_EQ_OFF, // equalizer strategy: disabled
|
||||
} eq_strategy;
|
||||
|
||||
// nco/phase-locked loop
|
||||
nco_crcf nco; // nco (carrier recovery)
|
||||
float pll_bandwidth; // phase-locked loop bandwidth
|
||||
|
||||
// demodulator
|
||||
modem demod; // linear modem demodulator
|
||||
|
||||
// state and counters
|
||||
unsigned int num_syms_rx; // number of symbols recovered
|
||||
} SYMTRACK;
|
BIN
images/hsmodem_win10_141120.zip
Normal file
BIN
images/hsmodem_win10_141120.zip
Normal file
Binary file not shown.
@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
|
||||
// Input: Byte Array
|
||||
@ -79,8 +78,10 @@ namespace oscardata
|
||||
long filesize = data.Length;// statics.GetFileSize(filename);
|
||||
|
||||
Byte[] fnarr = statics.StringToByteArray(realname);
|
||||
|
||||
// CRC16 over complete file contents is the file ID
|
||||
Crc c = new Crc();
|
||||
UInt16 fncrc = c.crc16_messagecalc(fnarr, fnarr.Length);
|
||||
UInt16 fncrc = c.crc16_messagecalc(data, data.Length);
|
||||
|
||||
// create the file header
|
||||
// 50 bytes ... Filename (or first 50 chars of the filename)
|
||||
@ -151,13 +152,14 @@ namespace oscardata
|
||||
if (txlen <= statics.PayloadLen)
|
||||
{
|
||||
// we just need to send one frame
|
||||
txudp(txdata, txtype, statics.LastFrame);
|
||||
txudp(txdata, txtype, statics.SingleFrame);
|
||||
setSending(false); // transmission complete
|
||||
}
|
||||
else
|
||||
{
|
||||
// additional frame follow
|
||||
// from txdata send one chunk of length statics.PayloadLen
|
||||
// frame is repeated for preamble by hsmodem.cpp
|
||||
Array.Copy(txdata, 0, txarr, 0, statics.PayloadLen);
|
||||
txudp(txarr, txtype, statics.FirstFrame);
|
||||
txpos = statics.PayloadLen;
|
||||
|
101
oscardata/oscardata/Form1.Designer.cs
generated
101
oscardata/oscardata/Form1.Designer.cs
generated
@ -77,6 +77,7 @@
|
||||
this.tb_shutdown = new System.Windows.Forms.TextBox();
|
||||
this.bt_resetmodem = new System.Windows.Forms.Button();
|
||||
this.textBox2 = new System.Windows.Forms.TextBox();
|
||||
this.textBox3 = new System.Windows.Forms.TextBox();
|
||||
this.groupBox3 = new System.Windows.Forms.GroupBox();
|
||||
this.label6 = new System.Windows.Forms.Label();
|
||||
this.label5 = new System.Windows.Forms.Label();
|
||||
@ -100,7 +101,10 @@
|
||||
this.timer_searchmodem = new System.Windows.Forms.Timer(this.components);
|
||||
this.progressBar_fifo = new System.Windows.Forms.ProgressBar();
|
||||
this.label_fifo = new System.Windows.Forms.Label();
|
||||
this.textBox3 = new System.Windows.Forms.TextBox();
|
||||
this.trackBar_maxlevel = new System.Windows.Forms.TrackBar();
|
||||
this.tb_info = new System.Windows.Forms.TextBox();
|
||||
this.label7 = new System.Windows.Forms.Label();
|
||||
this.cb_stampinfo = new System.Windows.Forms.CheckBox();
|
||||
this.statusStrip1.SuspendLayout();
|
||||
this.tabPage1.SuspendLayout();
|
||||
this.tabPage2.SuspendLayout();
|
||||
@ -115,6 +119,7 @@
|
||||
((System.ComponentModel.ISupportInitialize)(this.tb_CAPvol)).BeginInit();
|
||||
((System.ComponentModel.ISupportInitialize)(this.tb_PBvol)).BeginInit();
|
||||
this.groupBox2.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.trackBar_maxlevel)).BeginInit();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// timer_udpTX
|
||||
@ -608,6 +613,18 @@
|
||||
this.textBox2.Text = "in case the RX has sync\r\nproblems, it can be\r\nre-initialized here.";
|
||||
this.textBox2.Visible = false;
|
||||
//
|
||||
// textBox3
|
||||
//
|
||||
this.textBox3.BorderStyle = System.Windows.Forms.BorderStyle.None;
|
||||
this.textBox3.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||
this.textBox3.ForeColor = System.Drawing.Color.Black;
|
||||
this.textBox3.Location = new System.Drawing.Point(15, 46);
|
||||
this.textBox3.Multiline = true;
|
||||
this.textBox3.Name = "textBox3";
|
||||
this.textBox3.Size = new System.Drawing.Size(151, 50);
|
||||
this.textBox3.TabIndex = 12;
|
||||
this.textBox3.Text = "only uncheck if modem runs on a separate PC";
|
||||
//
|
||||
// groupBox3
|
||||
//
|
||||
this.groupBox3.Controls.Add(this.label6);
|
||||
@ -709,6 +726,9 @@
|
||||
//
|
||||
// groupBox2
|
||||
//
|
||||
this.groupBox2.Controls.Add(this.cb_stampinfo);
|
||||
this.groupBox2.Controls.Add(this.tb_info);
|
||||
this.groupBox2.Controls.Add(this.label7);
|
||||
this.groupBox2.Controls.Add(this.textBox5);
|
||||
this.groupBox2.Controls.Add(this.cb_announcement);
|
||||
this.groupBox2.Controls.Add(this.textBox4);
|
||||
@ -786,7 +806,7 @@
|
||||
this.tb_callsign.CharacterCasing = System.Windows.Forms.CharacterCasing.Upper;
|
||||
this.tb_callsign.Location = new System.Drawing.Point(71, 28);
|
||||
this.tb_callsign.Name = "tb_callsign";
|
||||
this.tb_callsign.Size = new System.Drawing.Size(151, 20);
|
||||
this.tb_callsign.Size = new System.Drawing.Size(104, 20);
|
||||
this.tb_callsign.TabIndex = 1;
|
||||
//
|
||||
// label1
|
||||
@ -803,7 +823,7 @@
|
||||
this.cb_stampcall.AutoSize = true;
|
||||
this.cb_stampcall.Checked = true;
|
||||
this.cb_stampcall.CheckState = System.Windows.Forms.CheckState.Checked;
|
||||
this.cb_stampcall.Location = new System.Drawing.Point(71, 67);
|
||||
this.cb_stampcall.Location = new System.Drawing.Point(71, 64);
|
||||
this.cb_stampcall.Name = "cb_stampcall";
|
||||
this.cb_stampcall.Size = new System.Drawing.Size(146, 17);
|
||||
this.cb_stampcall.TabIndex = 2;
|
||||
@ -815,7 +835,7 @@
|
||||
this.cb_savegoodfiles.AutoSize = true;
|
||||
this.cb_savegoodfiles.Checked = true;
|
||||
this.cb_savegoodfiles.CheckState = System.Windows.Forms.CheckState.Checked;
|
||||
this.cb_savegoodfiles.Location = new System.Drawing.Point(71, 90);
|
||||
this.cb_savegoodfiles.Location = new System.Drawing.Point(71, 102);
|
||||
this.cb_savegoodfiles.Name = "cb_savegoodfiles";
|
||||
this.cb_savegoodfiles.Size = new System.Drawing.Size(159, 17);
|
||||
this.cb_savegoodfiles.TabIndex = 3;
|
||||
@ -833,10 +853,14 @@
|
||||
"5500 8APSK BW: 2300 Hz",
|
||||
"6000 8APSK BW: 2500 Hz (QO-100)",
|
||||
"6600 8APSK BW: 2600 Hz",
|
||||
"7200 8APSK BW: 2700 Hz"});
|
||||
this.cb_speed.Location = new System.Drawing.Point(636, 593);
|
||||
"7200 8APSK BW: 2700 Hz",
|
||||
"5500 8PSK BW: 2300 Hz",
|
||||
"6000 8PSK BW: 2500 Hz (QO-100)",
|
||||
"6600 8PSK BW: 2600 Hz",
|
||||
"7200 8PSK BW: 2700 Hz"});
|
||||
this.cb_speed.Location = new System.Drawing.Point(658, 591);
|
||||
this.cb_speed.Name = "cb_speed";
|
||||
this.cb_speed.Size = new System.Drawing.Size(324, 21);
|
||||
this.cb_speed.Size = new System.Drawing.Size(304, 21);
|
||||
this.cb_speed.TabIndex = 11;
|
||||
this.cb_speed.Text = "4410 QPSK BW: 2500 Hz (QO-100)";
|
||||
this.cb_speed.SelectedIndexChanged += new System.EventHandler(this.comboBox1_SelectedIndexChanged);
|
||||
@ -844,7 +868,7 @@
|
||||
// label_speed
|
||||
//
|
||||
this.label_speed.AutoSize = true;
|
||||
this.label_speed.Location = new System.Drawing.Point(545, 596);
|
||||
this.label_speed.Location = new System.Drawing.Point(567, 594);
|
||||
this.label_speed.Name = "label_speed";
|
||||
this.label_speed.Size = new System.Drawing.Size(71, 13);
|
||||
this.label_speed.TabIndex = 12;
|
||||
@ -857,10 +881,10 @@
|
||||
//
|
||||
// progressBar_fifo
|
||||
//
|
||||
this.progressBar_fifo.Location = new System.Drawing.Point(636, 620);
|
||||
this.progressBar_fifo.Location = new System.Drawing.Point(658, 618);
|
||||
this.progressBar_fifo.Maximum = 20;
|
||||
this.progressBar_fifo.Name = "progressBar_fifo";
|
||||
this.progressBar_fifo.Size = new System.Drawing.Size(324, 23);
|
||||
this.progressBar_fifo.Size = new System.Drawing.Size(304, 23);
|
||||
this.progressBar_fifo.Step = 11;
|
||||
this.progressBar_fifo.Style = System.Windows.Forms.ProgressBarStyle.Continuous;
|
||||
this.progressBar_fifo.TabIndex = 13;
|
||||
@ -868,29 +892,59 @@
|
||||
// label_fifo
|
||||
//
|
||||
this.label_fifo.AutoSize = true;
|
||||
this.label_fifo.Location = new System.Drawing.Point(545, 625);
|
||||
this.label_fifo.Location = new System.Drawing.Point(567, 623);
|
||||
this.label_fifo.Name = "label_fifo";
|
||||
this.label_fifo.Size = new System.Drawing.Size(55, 13);
|
||||
this.label_fifo.TabIndex = 14;
|
||||
this.label_fifo.Text = "TX Buffer:";
|
||||
//
|
||||
// textBox3
|
||||
// trackBar_maxlevel
|
||||
//
|
||||
this.textBox3.BorderStyle = System.Windows.Forms.BorderStyle.None;
|
||||
this.textBox3.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||
this.textBox3.ForeColor = System.Drawing.Color.Black;
|
||||
this.textBox3.Location = new System.Drawing.Point(15, 46);
|
||||
this.textBox3.Multiline = true;
|
||||
this.textBox3.Name = "textBox3";
|
||||
this.textBox3.Size = new System.Drawing.Size(151, 50);
|
||||
this.textBox3.TabIndex = 12;
|
||||
this.textBox3.Text = "only uncheck if modem runs on a separate PC";
|
||||
this.trackBar_maxlevel.Location = new System.Drawing.Point(535, 591);
|
||||
this.trackBar_maxlevel.Maximum = 100;
|
||||
this.trackBar_maxlevel.Name = "trackBar_maxlevel";
|
||||
this.trackBar_maxlevel.Orientation = System.Windows.Forms.Orientation.Vertical;
|
||||
this.trackBar_maxlevel.Size = new System.Drawing.Size(45, 75);
|
||||
this.trackBar_maxlevel.TabIndex = 15;
|
||||
this.trackBar_maxlevel.TickFrequency = 10;
|
||||
this.trackBar_maxlevel.TickStyle = System.Windows.Forms.TickStyle.TopLeft;
|
||||
this.trackBar_maxlevel.Value = 50;
|
||||
//
|
||||
// tb_info
|
||||
//
|
||||
this.tb_info.Location = new System.Drawing.Point(243, 28);
|
||||
this.tb_info.Name = "tb_info";
|
||||
this.tb_info.Size = new System.Drawing.Size(413, 20);
|
||||
this.tb_info.TabIndex = 22;
|
||||
this.tb_info.Text = "tnx fer QSO, vy 73";
|
||||
//
|
||||
// label7
|
||||
//
|
||||
this.label7.AutoSize = true;
|
||||
this.label7.Location = new System.Drawing.Point(204, 31);
|
||||
this.label7.Name = "label7";
|
||||
this.label7.Size = new System.Drawing.Size(28, 13);
|
||||
this.label7.TabIndex = 21;
|
||||
this.label7.Text = "Info:";
|
||||
//
|
||||
// cb_stampinfo
|
||||
//
|
||||
this.cb_stampinfo.AutoSize = true;
|
||||
this.cb_stampinfo.Checked = true;
|
||||
this.cb_stampinfo.CheckState = System.Windows.Forms.CheckState.Checked;
|
||||
this.cb_stampinfo.Location = new System.Drawing.Point(71, 82);
|
||||
this.cb_stampinfo.Name = "cb_stampinfo";
|
||||
this.cb_stampinfo.Size = new System.Drawing.Size(128, 17);
|
||||
this.cb_stampinfo.TabIndex = 23;
|
||||
this.cb_stampinfo.Text = "Insert Info into picture";
|
||||
this.cb_stampinfo.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// Form1
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.ClientSize = new System.Drawing.Size(1293, 691);
|
||||
this.Controls.Add(this.trackBar_maxlevel);
|
||||
this.Controls.Add(this.label_fifo);
|
||||
this.Controls.Add(this.progressBar_fifo);
|
||||
this.Controls.Add(this.cb_speed);
|
||||
@ -925,6 +979,7 @@
|
||||
((System.ComponentModel.ISupportInitialize)(this.tb_PBvol)).EndInit();
|
||||
this.groupBox2.ResumeLayout(false);
|
||||
this.groupBox2.PerformLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.trackBar_maxlevel)).EndInit();
|
||||
this.ResumeLayout(false);
|
||||
this.PerformLayout();
|
||||
|
||||
@ -1003,6 +1058,10 @@
|
||||
private System.Windows.Forms.TextBox textBox4;
|
||||
private System.Windows.Forms.TextBox textBox1;
|
||||
private System.Windows.Forms.TextBox textBox3;
|
||||
private System.Windows.Forms.TrackBar trackBar_maxlevel;
|
||||
private System.Windows.Forms.CheckBox cb_stampinfo;
|
||||
private System.Windows.Forms.TextBox tb_info;
|
||||
private System.Windows.Forms.Label label7;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -39,9 +39,9 @@ namespace oscardata
|
||||
Byte frameinfo = (Byte)statics.FirstFrame;
|
||||
String TXfilename;
|
||||
int rxbytecounter = 0;
|
||||
DateTime starttime;
|
||||
String old_tsip = "";
|
||||
bool modemrunning = false;
|
||||
receivefile recfile = new receivefile();
|
||||
|
||||
public Form1()
|
||||
{
|
||||
@ -240,9 +240,7 @@ namespace oscardata
|
||||
// RX timer
|
||||
int rxstat = 0;
|
||||
int speed;
|
||||
int tmpnum = 0;
|
||||
int file_lostframes = 0;
|
||||
int last_fileid = 0;
|
||||
int maxlevel = 0;
|
||||
private void timer_udprx_Tick(object sender, EventArgs e)
|
||||
{
|
||||
while (true)
|
||||
@ -260,383 +258,92 @@ namespace oscardata
|
||||
speed = rxd[5];
|
||||
speed <<= 8;
|
||||
speed += rxd[6];
|
||||
int dummy3 = rxd[7];
|
||||
maxlevel = rxd[7];
|
||||
int dummy4 = rxd[8];
|
||||
int dummy5 = rxd[9];
|
||||
|
||||
if (rxstat == 4)
|
||||
{
|
||||
framelost++;
|
||||
file_lostframes++;
|
||||
}
|
||||
calcBer(rxfrmnum);
|
||||
rxbytecounter += statics.UdpBlocklen;
|
||||
|
||||
if (minfo == statics.FirstFrame)
|
||||
file_lostframes = 0;
|
||||
trackBar_maxlevel.Value = maxlevel;
|
||||
int v1 = 255;
|
||||
int v2 = 220;
|
||||
if (maxlevel < 20 || maxlevel > 70) trackBar_maxlevel.BackColor = Color.FromArgb(v1,v2,v2);
|
||||
else if (maxlevel < 30 || maxlevel > 60) trackBar_maxlevel.BackColor = Color.FromArgb(v1, v1, v2);
|
||||
else trackBar_maxlevel.BackColor = Color.FromArgb(v2, v1, v2);
|
||||
|
||||
Byte[] rxdata = new byte[rxd.Length - 10];
|
||||
Array.Copy(rxd, 10, rxdata, 0, rxd.Length - 10);
|
||||
|
||||
//Console.WriteLine("minfo:" + minfo + " data:" + rxdata[0].ToString("X2") + " " + rxdata[1].ToString("X2"));
|
||||
|
||||
if (minfo == statics.FirstFrame)
|
||||
{
|
||||
rxbytecounter = rxdata.Length;
|
||||
starttime = DateTime.UtcNow;
|
||||
}
|
||||
else
|
||||
{
|
||||
rxbytecounter += rxdata.Length;
|
||||
}
|
||||
TimeSpan ts = DateTime.UtcNow - starttime;
|
||||
ts += new TimeSpan(0, 0, 0, 1);
|
||||
|
||||
// ===== ASCII RX ================================================
|
||||
if (rxtype == statics.AsciiFile)
|
||||
{
|
||||
// if this is the first frame of a file transfer
|
||||
// then read and remove the file info header
|
||||
if (minfo == statics.FirstFrame || minfo == statics.SingleFrame)
|
||||
{
|
||||
//Console.WriteLine("first, single");
|
||||
rxdata = ArraySend.GetAndRemoveHeader(rxdata);
|
||||
if (rxdata == null) return;
|
||||
if (last_fileid == ArraySend.FileID) return; // got first frame for this ID already
|
||||
last_fileid = ArraySend.FileID;
|
||||
}
|
||||
else
|
||||
last_fileid = 0;
|
||||
|
||||
// collect all received data into zip_RXtempfilename
|
||||
Byte[] ba = null;
|
||||
Byte[] nba;
|
||||
try
|
||||
{
|
||||
ba = File.ReadAllBytes(statics.zip_RXtempfilename);
|
||||
}
|
||||
catch { }
|
||||
|
||||
if (ba != null)
|
||||
{
|
||||
//Console.WriteLine("write next");
|
||||
nba = new Byte[ba.Length + rxdata.Length];
|
||||
Array.Copy(ba, nba, ba.Length);
|
||||
Array.Copy(rxdata, 0, nba, ba.Length, rxdata.Length);
|
||||
}
|
||||
else
|
||||
{
|
||||
//Console.WriteLine("write first");
|
||||
nba = new Byte[rxdata.Length];
|
||||
Array.Copy(rxdata, nba, rxdata.Length);
|
||||
}
|
||||
File.WriteAllBytes(statics.zip_RXtempfilename, nba);
|
||||
long filesize = 0;
|
||||
|
||||
// check if transmission is finished
|
||||
if (minfo == statics.LastFrame || minfo == statics.SingleFrame)
|
||||
{
|
||||
// statics.zip_RXtempfilename has the received data, but maybee too long (multiple of payload length)
|
||||
// reduce for the real file length
|
||||
Byte[] fc = File.ReadAllBytes(statics.zip_RXtempfilename);
|
||||
Byte[] fdst = new byte[ArraySend.FileSize];
|
||||
if(fc.Length < ArraySend.FileSize)
|
||||
{
|
||||
Console.WriteLine("len=" + fc.Length + " fz=" + ArraySend.FileSize);
|
||||
return;
|
||||
}
|
||||
Array.Copy(fc, 0, fdst, 0, ArraySend.FileSize);
|
||||
File.WriteAllBytes(statics.zip_RXtempfilename, fdst);
|
||||
|
||||
//Console.WriteLine("size:"+ ArraySend.FileSize.ToString());
|
||||
|
||||
//Console.WriteLine("last");
|
||||
// unzip received data and store result in file: unzipped_RXtempfilename
|
||||
rtb_RXfile.Text = "";
|
||||
ZipStorer zs = new ZipStorer();
|
||||
String fl = zs.unzipFile(statics.zip_RXtempfilename);
|
||||
if (fl != null)
|
||||
{
|
||||
// save file
|
||||
int idx = fl.LastIndexOf('/');
|
||||
if (idx == -1) idx = fl.LastIndexOf('\\');
|
||||
String fdest = fl.Substring(idx + 1);
|
||||
fdest = statics.getHomePath("", fdest);
|
||||
try { File.Delete(fdest); } catch { }
|
||||
File.Move(fl, fdest);
|
||||
filesize = statics.GetFileSize(fdest);
|
||||
|
||||
String serg = File.ReadAllText(fdest);
|
||||
printText(rtb_RXfile, serg);
|
||||
}
|
||||
else
|
||||
printText(rtb_RXfile, "unzip failed");
|
||||
File.Delete(statics.zip_RXtempfilename);
|
||||
}
|
||||
|
||||
int rest = ArraySend.FileSize - rxbytecounter;
|
||||
if (rest < 0) rest = 0;
|
||||
if (rest > 0)
|
||||
label_rxfile.Text = "RX file: " + ArraySend.rxFilename + " " + rest.ToString() + " bytes";
|
||||
else
|
||||
label_rxfile.Text = "RX file: " + ArraySend.rxFilename + " " + filesize + " bytes";
|
||||
|
||||
if (minfo == statics.LastFrame)
|
||||
ShowStatus((int)filesize, (int)ts.TotalSeconds);
|
||||
else
|
||||
ShowStatus(rxbytecounter, (int)ts.TotalSeconds);
|
||||
}
|
||||
|
||||
// ===== HTML File RX ================================================
|
||||
if (rxtype == statics.HTMLFile)
|
||||
{
|
||||
// if this is the first frame of a file transfer
|
||||
// then read and remove the file info header
|
||||
if (minfo == statics.FirstFrame)
|
||||
{
|
||||
rxdata = ArraySend.GetAndRemoveHeader(rxdata);
|
||||
if (last_fileid == ArraySend.FileID) return; // got first frame for this ID already
|
||||
last_fileid = ArraySend.FileID;
|
||||
}
|
||||
else
|
||||
last_fileid = 0;
|
||||
|
||||
Byte[] ba = null;
|
||||
Byte[] nba;
|
||||
try
|
||||
{
|
||||
ba = File.ReadAllBytes(statics.zip_RXtempfilename);
|
||||
}
|
||||
catch { }
|
||||
|
||||
if (ba != null)
|
||||
{
|
||||
nba = new Byte[ba.Length + rxdata.Length];
|
||||
Array.Copy(ba, nba, ba.Length);
|
||||
Array.Copy(rxdata, 0, nba, ba.Length, rxdata.Length);
|
||||
}
|
||||
else
|
||||
{
|
||||
nba = new Byte[rxdata.Length];
|
||||
Array.Copy(rxdata, nba, rxdata.Length);
|
||||
}
|
||||
File.WriteAllBytes(statics.zip_RXtempfilename, nba);
|
||||
long filesize = 0;
|
||||
if (minfo == statics.LastFrame)
|
||||
{
|
||||
// unzip received data
|
||||
rtb_RXfile.Text = "";
|
||||
ZipStorer zs = new ZipStorer();
|
||||
// unzip returns filename+path of unzipped file
|
||||
String fl = zs.unzipFile(statics.zip_RXtempfilename);
|
||||
if (fl != null)
|
||||
{
|
||||
// save file
|
||||
int idx = fl.LastIndexOf('/');
|
||||
if (idx == -1) idx = fl.LastIndexOf('\\');
|
||||
String fdest = fl.Substring(idx + 1);
|
||||
fdest = statics.getHomePath("", fdest);
|
||||
try { File.Delete(fdest); } catch { }
|
||||
File.Move(fl, fdest);
|
||||
filesize = statics.GetFileSize(fdest);
|
||||
|
||||
rxbytecounter = (int)statics.GetFileSize(fdest);
|
||||
String serg = File.ReadAllText(fdest);
|
||||
printText(rtb_RXfile, serg);
|
||||
try
|
||||
{
|
||||
OpenUrl(fdest);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine(ex.ToString());
|
||||
}
|
||||
}
|
||||
else
|
||||
printText(rtb_RXfile, "unzip failed");
|
||||
}
|
||||
|
||||
int rest = ArraySend.FileSize - rxbytecounter;
|
||||
if (rest < 0) rest = 0;
|
||||
if (rest > 0)
|
||||
label_rxfile.Text = "RX file: " + ArraySend.rxFilename + " " + rest.ToString() + " bytes";
|
||||
else
|
||||
label_rxfile.Text = "RX file: " + ArraySend.rxFilename + " " + filesize + " bytes";
|
||||
|
||||
if (minfo == statics.LastFrame)
|
||||
ShowStatus(ArraySend.FileSize, (int)ts.TotalSeconds);
|
||||
else
|
||||
ShowStatus(rxbytecounter, (int)ts.TotalSeconds);
|
||||
}
|
||||
|
||||
// ===== Binary File RX ================================================
|
||||
if (rxtype == statics.BinaryFile)
|
||||
{
|
||||
// if this is the first frame of a file transfer
|
||||
// then read and remove the file info header
|
||||
if (minfo == statics.FirstFrame || minfo == statics.SingleFrame)
|
||||
{
|
||||
//Console.WriteLine("first, single");
|
||||
rxdata = ArraySend.GetAndRemoveHeader(rxdata);
|
||||
if (last_fileid == ArraySend.FileID) return; // got first frame for this ID already
|
||||
last_fileid = ArraySend.FileID;
|
||||
}
|
||||
else
|
||||
last_fileid = 0;
|
||||
|
||||
// collect all received data into zip_RXtempfilename
|
||||
Byte[] ba = null;
|
||||
Byte[] nba;
|
||||
try
|
||||
{
|
||||
ba = File.ReadAllBytes(statics.zip_RXtempfilename);
|
||||
}
|
||||
catch { }
|
||||
|
||||
if (ba != null)
|
||||
{
|
||||
//Console.WriteLine("write next");
|
||||
nba = new Byte[ba.Length + rxdata.Length];
|
||||
Array.Copy(ba, nba, ba.Length);
|
||||
Array.Copy(rxdata, 0, nba, ba.Length, rxdata.Length);
|
||||
}
|
||||
else
|
||||
{
|
||||
//Console.WriteLine("write first");
|
||||
nba = new Byte[rxdata.Length];
|
||||
Array.Copy(rxdata, nba, rxdata.Length);
|
||||
}
|
||||
File.WriteAllBytes(statics.zip_RXtempfilename, nba);
|
||||
long filesize = 0;
|
||||
|
||||
// check if transmission is finished
|
||||
if (minfo == statics.LastFrame || minfo == statics.SingleFrame)
|
||||
{
|
||||
// statics.zip_RXtempfilename has the received data, but maybee too long (multiple of payload length)
|
||||
// reduce for the real file length
|
||||
Byte[] fc = File.ReadAllBytes(statics.zip_RXtempfilename);
|
||||
Byte[] fdst = new byte[ArraySend.FileSize];
|
||||
if (fc.Length < ArraySend.FileSize)
|
||||
{
|
||||
Console.WriteLine("len=" + fc.Length + " fz=" + ArraySend.FileSize);
|
||||
return;
|
||||
}
|
||||
Console.WriteLine("copy final binary file");
|
||||
Array.Copy(fc, 0, fdst, 0, ArraySend.FileSize);
|
||||
File.WriteAllBytes(statics.zip_RXtempfilename, fdst);
|
||||
|
||||
//Console.WriteLine("last");
|
||||
// unzip received data and store result in file: unzipped_RXtempfilename
|
||||
rtb_RXfile.Text = "";
|
||||
ZipStorer zs = new ZipStorer();
|
||||
String fl = zs.unzipFile(statics.zip_RXtempfilename);
|
||||
if (fl != null)
|
||||
{
|
||||
int idx = fl.LastIndexOf('/');
|
||||
if(idx == -1) idx = fl.LastIndexOf('\\');
|
||||
String fdest = fl.Substring(idx + 1);
|
||||
fdest = statics.getHomePath("", fdest);
|
||||
try { File.Delete(fdest); } catch { }
|
||||
File.Move(fl, fdest);
|
||||
filesize = statics.GetFileSize(fdest);
|
||||
//File.WriteAllBytes(fl, nba);
|
||||
printText(rtb_RXfile, "binary file received\r\n");
|
||||
printText(rtb_RXfile, "--------------------\r\n\r\n");
|
||||
printText(rtb_RXfile, "file size : " + filesize + " byte\r\n\r\n");
|
||||
printText(rtb_RXfile, "stored in : " + fdest + "\r\n\r\n");
|
||||
printText(rtb_RXfile, "transmission time : " + ((int)ts.TotalSeconds).ToString() + " seconds" + "\r\n\r\n");
|
||||
printText(rtb_RXfile, "transmission speed: " + ((int)(filesize*8/ts.TotalSeconds)).ToString() + " bit/s" + "\r\n\r\n");
|
||||
}
|
||||
else
|
||||
printText(rtb_RXfile, "unzip failed");
|
||||
File.Delete(statics.zip_RXtempfilename);
|
||||
}
|
||||
|
||||
int rest = ArraySend.FileSize - rxbytecounter;
|
||||
if (rest < 0) rest = 0;
|
||||
if (rest > 0)
|
||||
label_rxfile.Text = "RX file: " + ArraySend.rxFilename + " " + rest.ToString() + " bytes";
|
||||
else
|
||||
label_rxfile.Text = "RX file: " + ArraySend.rxFilename + " " + filesize + " bytes";
|
||||
|
||||
if (minfo == statics.LastFrame)
|
||||
ShowStatus((int)filesize, (int)ts.TotalSeconds);
|
||||
else
|
||||
ShowStatus(rxbytecounter, (int)ts.TotalSeconds);
|
||||
}
|
||||
|
||||
// ===== IMAGE RX ================================================
|
||||
// ========= receive file ==========
|
||||
// handle file receive
|
||||
if (rxtype == statics.Image)
|
||||
{
|
||||
// if this is the first frame of a file transfer
|
||||
// then read and remove the file info header
|
||||
if (minfo == statics.FirstFrame)
|
||||
if (recfile.receive(rxd))
|
||||
{
|
||||
rxdata = ArraySend.GetAndRemoveHeader(rxdata);
|
||||
if (rxdata == null) return;
|
||||
if (recfile.filename != null && recfile.filename.Length > 0 && minfo != statics.FirstFrame)
|
||||
{
|
||||
// reception complete, show stored file
|
||||
Console.WriteLine("load " + recfile.filename);
|
||||
pictureBox_rximage.BackgroundImage = Image.FromFile(recfile.filename);
|
||||
pictureBox_rximage.Invalidate();
|
||||
}
|
||||
|
||||
ih.receive_image(rxdata, minfo);
|
||||
|
||||
// show currect contents of rxtemp.jpg in RX picturebox
|
||||
if (recfile.pbmp != null)
|
||||
{
|
||||
// in case we can display portions of an image return this portion
|
||||
try
|
||||
{
|
||||
String fn = statics.addTmpPath("temp" + tmpnum.ToString() + ".jpg");
|
||||
try
|
||||
{
|
||||
File.Delete(fn);
|
||||
pictureBox_rximage.BackgroundImage = recfile.pbmp;
|
||||
}
|
||||
catch { }
|
||||
tmpnum++;
|
||||
fn = statics.addTmpPath("temp" + tmpnum.ToString() + ".jpg");
|
||||
File.Copy(statics.jpg_tempfilename, fn);
|
||||
|
||||
try
|
||||
{
|
||||
if(statics.GetFileSize(fn) > 1200)
|
||||
pictureBox_rximage.BackgroundImage = Image.FromFile(fn);
|
||||
}
|
||||
catch {
|
||||
}
|
||||
}
|
||||
|
||||
if (minfo == statics.LastFrame)
|
||||
if (rxtype == statics.AsciiFile)
|
||||
{
|
||||
// file is complete, save in RX storage
|
||||
// remove possible path from filename
|
||||
String fname = ArraySend.rxFilename;
|
||||
int idx = fname.IndexOfAny(new char[] {'\\','/' });
|
||||
if (idx != -1)
|
||||
if(recfile.receive(rxd))
|
||||
{
|
||||
try
|
||||
{
|
||||
fname = fname.Substring(idx + 1);
|
||||
} catch{ }
|
||||
}
|
||||
if (!cb_savegoodfiles.Checked || (file_lostframes == 0 && cb_savegoodfiles.Checked))
|
||||
{
|
||||
// add home path and RXstorage path
|
||||
String fnx = statics.getHomePath(statics.RXimageStorage, fname);
|
||||
File.Copy(fn, fnx);
|
||||
// ASCII file received, show in window
|
||||
String serg = File.ReadAllText(recfile.filename);
|
||||
printText(rtb_RXfile, serg);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
|
||||
int rest = ArraySend.FileSize - rxbytecounter;
|
||||
if (rest < 0) rest = 0;
|
||||
if(rest > 0)
|
||||
label_rximage.Text = "RX image: " + ArraySend.rxFilename + " remaining: " + rest.ToString() + " bytes";
|
||||
else
|
||||
label_rximage.Text = "RX image: " + ArraySend.rxFilename;
|
||||
ShowStatus(rxbytecounter, (int)ts.TotalSeconds);
|
||||
if (rxtype == statics.HTMLFile)
|
||||
{
|
||||
if (recfile.receive(rxd))
|
||||
{
|
||||
// HTML file received, show in window
|
||||
String serg = File.ReadAllText(recfile.filename);
|
||||
printText(rtb_RXfile, serg);
|
||||
// and show in browser
|
||||
OpenUrl(recfile.filename);
|
||||
}
|
||||
}
|
||||
|
||||
if (rxtype == statics.BinaryFile)
|
||||
{
|
||||
if (recfile.receive(rxd))
|
||||
{
|
||||
// Binary file received, show statistics in window
|
||||
printText(rtb_RXfile, "binary file received\r\n");
|
||||
printText(rtb_RXfile, "--------------------\r\n\r\n");
|
||||
printText(rtb_RXfile, "transmission time : " + ((int)recfile.runtime.TotalSeconds).ToString() + " seconds" + "\r\n\r\n");
|
||||
printText(rtb_RXfile, "transmission speed: " + ((int)(recfile.filesize * 8 / recfile.runtime.TotalSeconds)).ToString() + " bit/s" + "\r\n\r\n");
|
||||
printText(rtb_RXfile, "file size : " + recfile.filesize + " byte\r\n\r\n");
|
||||
printText(rtb_RXfile, "file name : " + recfile.filename + "\r\n\r\n");
|
||||
}
|
||||
}
|
||||
|
||||
// ===== BER Test ================================================
|
||||
if (rxtype == statics.BERtest)
|
||||
{
|
||||
RXstatus.Text = "BER: " + ber.ToString("E3") + " " + rxframecounter.ToString() + " frames received OK";
|
||||
|
||||
BERcheck(rxdata);
|
||||
BERcheck(rxdata, rxfrmnum,minfo);
|
||||
}
|
||||
|
||||
ShowStatus(rxtype, minfo);
|
||||
}
|
||||
}
|
||||
|
||||
@ -894,18 +601,21 @@ namespace oscardata
|
||||
Image img = new Bitmap(fullfn);
|
||||
String cs = tb_callsign.Text;
|
||||
if (cb_stampcall.Checked == false) cs = "";
|
||||
String inf = tb_info.Text;
|
||||
if (cb_stampinfo.Checked == false) inf = "";
|
||||
if (!checkBox_big.Checked)
|
||||
{
|
||||
img = ih.ResizeImage(img, 320, 240, cs);
|
||||
img = ih.ResizeImage(img, 320, 240, cs, inf);
|
||||
// set quality by reducing the file size and save under default name
|
||||
ih.SaveJpgAtFileSize(img, TXimagefilename, max_size / 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
img = ih.ResizeImage(img, 640, 480, cs);
|
||||
img = ih.ResizeImage(img, 640, 480, cs, inf);
|
||||
// set quality by reducing the file size and save under default name
|
||||
ih.SaveJpgAtFileSize(img, TXimagefilename, max_size);
|
||||
}
|
||||
|
||||
pictureBox_tximage.Load(TXimagefilename);
|
||||
TXRealFileSize = statics.GetFileSize(TXimagefilename);
|
||||
ShowTXstatus();
|
||||
@ -977,11 +687,8 @@ namespace oscardata
|
||||
|
||||
private void button_startBERtest_Click(object sender, EventArgs e)
|
||||
{
|
||||
ber = 0;
|
||||
framelost = 0;
|
||||
totallostframes = 0;
|
||||
last_rxfrmnum = -1;
|
||||
rtb.Text = "";
|
||||
missBlocks = 0;
|
||||
frameinfo = (Byte)statics.FirstFrame;
|
||||
txcommand = statics.BERtest;
|
||||
}
|
||||
@ -991,36 +698,23 @@ namespace oscardata
|
||||
txcommand = statics.noTX;
|
||||
}
|
||||
|
||||
DateTime dt = DateTime.Now;
|
||||
int rxframecounter = 0;
|
||||
int framelost = 0;
|
||||
int last_rxfrmnum = -1;
|
||||
double ber = 0;
|
||||
int totallostframes = 0;
|
||||
|
||||
void calcBer(int rxfrmnum)
|
||||
int lastfrmnum = 0;
|
||||
int missBlocks = 0;
|
||||
private void BERcheck(Byte[] rxdata, int frmnum, int minfo)
|
||||
{
|
||||
if (last_rxfrmnum == -1)
|
||||
{
|
||||
last_rxfrmnum = rxfrmnum;
|
||||
return;
|
||||
}
|
||||
if (minfo == statics.FirstFrame)
|
||||
rxframecounter = 0;
|
||||
|
||||
// calc gap
|
||||
int gap = ((rxfrmnum+1024) - last_rxfrmnum) % 1024;
|
||||
rxframecounter += gap;
|
||||
totallostframes += (gap - 1);
|
||||
if (lastfrmnum == frmnum) return;
|
||||
lastfrmnum = frmnum;
|
||||
|
||||
int totalbits = rxframecounter * 258 * 8;
|
||||
int errorbits = totallostframes * 258 * 8;
|
||||
ber = (double)totallostframes / (double)rxframecounter;
|
||||
rxframecounter++;
|
||||
|
||||
last_rxfrmnum = rxfrmnum;
|
||||
}
|
||||
|
||||
private void BERcheck(Byte[] rxdata)
|
||||
{
|
||||
String line = "RX: " + rxframecounter.ToString().PadLeft(6, ' ') + " ";
|
||||
missBlocks += (frmnum - rxframecounter);
|
||||
if (missBlocks < 0) missBlocks = 0;
|
||||
String line = "RX: " + frmnum.ToString().PadLeft(6, ' ') + " "; // + rxframecounter + " " + missBlocks + " ";
|
||||
rxframecounter = frmnum;
|
||||
|
||||
// print payload (must be printable chars)
|
||||
line += Encoding.UTF8.GetString(rxdata).Substring(0, 50) + " ...";
|
||||
@ -1060,28 +754,72 @@ namespace oscardata
|
||||
|
||||
line += " " + bits.ToString() + " " + sbit + " " + bytes.ToString() + " " + sbyt;
|
||||
|
||||
line += " BER: " + string.Format("{0:#.##E+0}", ber); // ber.ToString("E3");
|
||||
|
||||
line += "\r\n";
|
||||
printText(rtb,line);
|
||||
|
||||
int fl = framelost;
|
||||
if (fl <= 1) fl = 0;
|
||||
String s = "Speed: " + speed.ToString() + " bit/s, Lost Frames: " + fl.ToString();
|
||||
toolStripStatusLabel.Text = s;
|
||||
}
|
||||
|
||||
private void ShowStatus(int rxbytecounter, int totalseconds)
|
||||
int[] blockres = new int[2];
|
||||
private void ShowStatus(int rxtype, int minfo)
|
||||
{
|
||||
int fl = framelost;
|
||||
if (fl <= 1) fl = 0;
|
||||
String s = "Speed: " + speed.ToString() + " bit/s, Lost Frames: " + fl.ToString();
|
||||
toolStripStatusLabel.Text = s;
|
||||
if (minfo == statics.FirstFrame)
|
||||
rxbytecounter = 0;
|
||||
|
||||
int rspeed = 0;
|
||||
if (totalseconds >= 1)
|
||||
rspeed = rxbytecounter * 8 / totalseconds;
|
||||
RXstatus.Text = "received " + rxbytecounter + " byte " + totalseconds + " s, " + rspeed + " bit/s";
|
||||
// calculate speed
|
||||
int fsz = (int)recfile.filesize;
|
||||
if (fsz == 0) fsz = ArraySend.FileSize; // during reception we do not have the final size, use the transmitted size
|
||||
// fsz = real or zipped file size, whatever available
|
||||
// transmitted size in % of zipped file
|
||||
int txsize = 0;
|
||||
if (ArraySend.FileSize > 0)
|
||||
txsize = (recfile.rxbytes * 100) / ArraySend.FileSize;
|
||||
// transmitted size of real filesize
|
||||
int txreal = (fsz * txsize) / 100;
|
||||
// speed
|
||||
int speed_bps = 0;
|
||||
if(recfile.runtime.TotalSeconds > 0)
|
||||
speed_bps = (int)(((double)txreal * 8.0) / recfile.runtime.TotalSeconds);
|
||||
|
||||
// show RX status on top of the RX windows
|
||||
String s = "RX: ";
|
||||
|
||||
recfile.blockstat(blockres);
|
||||
int missingBlocks = blockres[0] - blockres[1];
|
||||
|
||||
if (ArraySend.rxFilename != null && ArraySend.rxFilename.Length > 0)
|
||||
{
|
||||
s += ArraySend.rxFilename + " ";
|
||||
s += recfile.rxbytes / 1000 + " of " + ArraySend.FileSize / 1000 + " kB ";
|
||||
s += Math.Truncate(recfile.runtime.TotalSeconds) + " s, ";
|
||||
s += blockres[1] + " of " + blockres[0] + " blocks OK";
|
||||
}
|
||||
else
|
||||
s += "wait for RX";
|
||||
|
||||
if (rxtype == statics.Image)
|
||||
label_rximage.Text = s;
|
||||
|
||||
if (rxtype == statics.AsciiFile || rxtype == statics.HTMLFile || rxtype == statics.BinaryFile)
|
||||
label_rxfile.Text = s;
|
||||
|
||||
// show speed in status line at the left side
|
||||
toolStripStatusLabel.Text = "Line Speed: " + speed.ToString() + " bps";
|
||||
|
||||
if (missBlocks < 0) missBlocks = 0;
|
||||
if (missingBlocks < 0) missingBlocks = 0;
|
||||
|
||||
// show RX status in the status line
|
||||
if (rxtype == statics.BERtest)
|
||||
RXstatus.Text = "RXed: " + rxbytecounter + " Byte. Missing blocks: " + missBlocks;
|
||||
else
|
||||
{
|
||||
if(fsz > 0)
|
||||
RXstatus.Text = "RXed: " + fsz + " Byte. Missing blocks: " + missingBlocks;
|
||||
else
|
||||
RXstatus.Text = "RXed: " + rxbytecounter + " Byte. Missing blocks: " + missingBlocks;
|
||||
}
|
||||
|
||||
if(speed_bps > 0)
|
||||
RXstatus.Text += " Net Speed:" + speed_bps + " bps";
|
||||
}
|
||||
|
||||
private void button_cancelimg_Click(object sender, EventArgs e)
|
||||
@ -1139,7 +877,10 @@ namespace oscardata
|
||||
label_txfile.Location = new Point(rtb_TXfile.Location.X, ly);
|
||||
label_rxfile.Location = new Point(rtb_RXfile.Location.X, ly);
|
||||
|
||||
label_speed.Location = new Point(panel_txspectrum.Location.X + panel_txspectrum.Size.Width + 20,panel_txspectrum.Location.Y+10);
|
||||
trackBar_maxlevel.Location = new Point(panel_txspectrum.Location.X + panel_txspectrum.Size.Width + 5, panel_txspectrum.Location.Y);
|
||||
trackBar_maxlevel.Size = new Size(20, panel_txspectrum.Size.Height);
|
||||
|
||||
label_speed.Location = new Point(trackBar_maxlevel.Location.X + trackBar_maxlevel.Size.Width + 15,panel_txspectrum.Location.Y+10);
|
||||
cb_speed.Location = new Point(label_speed.Location.X + label_speed.Size.Width + 10, label_speed.Location.Y-5);
|
||||
|
||||
label_fifo.Location = new Point(label_speed.Location.X, label_speed.Location.Y + 35);
|
||||
@ -1207,26 +948,6 @@ namespace oscardata
|
||||
statics.ModemIP = "1.2.3.4";
|
||||
}
|
||||
|
||||
private void bt_file_ascii_Click(object sender, EventArgs e)
|
||||
{
|
||||
OpenFileDialog open = new OpenFileDialog();
|
||||
open.Filter = "Text Files(*.txt*; *.*)|*.txt; *.*";
|
||||
if (open.ShowDialog() == DialogResult.OK)
|
||||
{
|
||||
TXfilename = open.FileName;
|
||||
TXRealFilename = open.SafeFileName;
|
||||
String text = File.ReadAllText(TXfilename);
|
||||
rtb_TXfile.Text = text;
|
||||
txcommand = statics.AsciiFile;
|
||||
// compress file
|
||||
ZipStorer zs = new ZipStorer();
|
||||
zs.zipFile(statics.zip_TXtempfilename,open.SafeFileName,open.FileName);
|
||||
|
||||
TXRealFileSize = statics.GetFileSize(statics.zip_TXtempfilename);
|
||||
ShowTXstatus();
|
||||
}
|
||||
}
|
||||
|
||||
private void bt_file_send_Click(object sender, EventArgs e)
|
||||
{
|
||||
rtb_RXfile.Text = "";
|
||||
@ -1236,36 +957,35 @@ namespace oscardata
|
||||
ArraySend.Send(textarr, (Byte)txcommand, TXfilename, TXRealFilename);
|
||||
}
|
||||
|
||||
private void bt_file_ascii_Click(object sender, EventArgs e)
|
||||
{
|
||||
bt_sendFile("Text Files(*.txt*; *.*)|*.txt; *.*", statics.AsciiFile);
|
||||
}
|
||||
|
||||
private void button2_Click(object sender, EventArgs e)
|
||||
{
|
||||
OpenFileDialog open = new OpenFileDialog();
|
||||
open.Filter = "HTML Files(*.html; *.htm; *.*)|*.html; *.htm; *.*";
|
||||
if (open.ShowDialog() == DialogResult.OK)
|
||||
{
|
||||
TXfilename = open.FileName;
|
||||
TXRealFilename = open.SafeFileName;
|
||||
String text = File.ReadAllText(TXfilename);
|
||||
rtb_TXfile.Text = text;
|
||||
txcommand = statics.HTMLFile;
|
||||
// compress file
|
||||
ZipStorer zs = new ZipStorer();
|
||||
zs.zipFile(statics.zip_TXtempfilename, open.SafeFileName, open.FileName);
|
||||
|
||||
TXRealFileSize = statics.GetFileSize(statics.zip_TXtempfilename);
|
||||
ShowTXstatus();
|
||||
}
|
||||
bt_sendFile("HTML Files(*.html; *.htm; *.*)|*.html; *.htm; *.*", statics.HTMLFile);
|
||||
}
|
||||
|
||||
private void bt_sendBinaryFile_Click(object sender, EventArgs e)
|
||||
{
|
||||
bt_sendFile("All Files(*.*)|*.*", statics.BinaryFile);
|
||||
}
|
||||
|
||||
private void bt_sendFile(String filter, int cmd)
|
||||
{
|
||||
OpenFileDialog open = new OpenFileDialog();
|
||||
open.Filter = "All Files(*.*)|*.*";
|
||||
open.Filter = filter;
|
||||
if (open.ShowDialog() == DialogResult.OK)
|
||||
{
|
||||
txcommand = cmd;
|
||||
TXfilename = open.FileName;
|
||||
TXRealFilename = open.SafeFileName;
|
||||
if (txcommand == statics.BinaryFile)
|
||||
rtb_TXfile.Text = "Binary file " + TXfilename + " loaded";
|
||||
txcommand = statics.BinaryFile;
|
||||
else
|
||||
rtb_TXfile.Text = File.ReadAllText(TXfilename);
|
||||
|
||||
// compress file
|
||||
ZipStorer zs = new ZipStorer();
|
||||
zs.zipFile(statics.zip_TXtempfilename, open.SafeFileName, open.FileName);
|
||||
@ -1277,26 +997,17 @@ namespace oscardata
|
||||
|
||||
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
|
||||
{
|
||||
int idx = cb_speed.SelectedIndex;
|
||||
int real_rate=4000;
|
||||
|
||||
switch (idx)
|
||||
{
|
||||
case 0: real_rate = 3000; break;
|
||||
case 1: real_rate = 3150; break;
|
||||
case 2: real_rate = 3675; break;
|
||||
case 3: real_rate = 4000; break;
|
||||
case 4: real_rate = 4410; break;
|
||||
case 5: real_rate = 4800; break;
|
||||
case 6: real_rate = 5525; break;
|
||||
case 7: real_rate = 6000; break;
|
||||
case 8: real_rate = 6615; break;
|
||||
case 9: real_rate = 7200; break;
|
||||
}
|
||||
|
||||
statics.setDatarate(real_rate);
|
||||
if (cb_speed.Text.Contains("3000")) statics.real_datarate = 3000;
|
||||
if (cb_speed.Text.Contains("4000")) statics.real_datarate = 4000;
|
||||
if (cb_speed.Text.Contains("4410")) statics.real_datarate = 4410;
|
||||
if (cb_speed.Text.Contains("4800")) statics.real_datarate = 4800;
|
||||
if (cb_speed.Text.Contains("5500")) statics.real_datarate = 5500;
|
||||
if (cb_speed.Text.Contains("6000")) statics.real_datarate = 6000;
|
||||
if (cb_speed.Text.Contains("6600")) statics.real_datarate = 6600;
|
||||
if (cb_speed.Text.Contains("7200")) statics.real_datarate = 7200;
|
||||
|
||||
Byte[] txdata = new byte[statics.PayloadLen + 2];
|
||||
int idx = cb_speed.SelectedIndex;
|
||||
txdata[0] = (Byte)statics.ResamplingRate; // BER Test Marker
|
||||
txdata[1] = (Byte)idx;
|
||||
|
||||
@ -1308,7 +1019,6 @@ namespace oscardata
|
||||
button_cancelimg_Click(null, null);
|
||||
}
|
||||
|
||||
|
||||
private void timer_searchmodem_Tick(object sender, EventArgs e)
|
||||
{
|
||||
search_modem();
|
||||
@ -1415,6 +1125,9 @@ namespace oscardata
|
||||
s = ReadString(sr);
|
||||
cb_autostart.Checked = (s == "1");
|
||||
try { cb_announcement.Text = ReadString(sr); } catch { }
|
||||
s = ReadString(sr);
|
||||
try { cb_stampinfo.Checked = (s == "1"); } catch { }
|
||||
try { tb_info.Text = ReadString(sr); } catch { }
|
||||
}
|
||||
}
|
||||
catch
|
||||
@ -1443,7 +1156,8 @@ namespace oscardata
|
||||
sw.WriteLine(tb_CAPvol.Value.ToString());
|
||||
sw.WriteLine(cb_autostart.Checked ? "1" : "0");
|
||||
sw.WriteLine(cb_announcement.Text);
|
||||
|
||||
sw.WriteLine(cb_stampinfo.Checked ? "1" : "0");
|
||||
sw.WriteLine(tb_info.Text);
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
|
Binary file not shown.
@ -54,7 +54,6 @@ namespace oscardata
|
||||
public static int UdpBlocklen = 258; // length of a data block (UDP)
|
||||
public static int PayloadLen = UdpBlocklen - FecLen - 3 - 2 - 2;
|
||||
public static int real_datarate = 6000; // speed in bit/s
|
||||
static int datarate = (real_datarate * 100) / 99; // little bit more to avoid underruns
|
||||
public static String jpg_tempfilename = "rxdata.jpg";
|
||||
public static String zip_TXtempfilename = "TXtemp.zip";
|
||||
public static String zip_RXtempfilename = "RXtemp.zip";
|
||||
@ -67,16 +66,6 @@ namespace oscardata
|
||||
public static String[] AudioCAPdevs;
|
||||
public static int PBfifousage = 0;
|
||||
|
||||
public static void setDatarate(int rate)
|
||||
{
|
||||
real_datarate = rate;
|
||||
datarate = (rate * 100) / 99;
|
||||
}
|
||||
|
||||
public static int getDatarate()
|
||||
{
|
||||
return datarate;
|
||||
}
|
||||
|
||||
public static String[] getOwnIPs()
|
||||
{
|
||||
|
@ -57,7 +57,7 @@ namespace oscardata
|
||||
return 5;
|
||||
}
|
||||
|
||||
public Bitmap ResizeImage(Image image, int width, int height, String callsign)
|
||||
public Bitmap ResizeImage(Image image, int width, int height, String callsign, String info)
|
||||
{
|
||||
// get original size of img
|
||||
int x = image.Width;
|
||||
@ -90,6 +90,19 @@ namespace oscardata
|
||||
g.DrawString(callsign, fnt, Brushes.Blue, 5, 5);
|
||||
}
|
||||
}
|
||||
if (info != "")
|
||||
{
|
||||
using (var fnt = new Font("Verdana", 11.0f))
|
||||
{
|
||||
int ypos = nh - 30;
|
||||
var size = g.MeasureString(info, fnt);
|
||||
var rect = new RectangleF(5, ypos, size.Width, size.Height);
|
||||
SolidBrush opaqueBrush = new SolidBrush(Color.FromArgb(128, 255, 255, 255));
|
||||
|
||||
g.FillRectangle(opaqueBrush, rect);
|
||||
g.DrawString(info, fnt, Brushes.Blue, 5, ypos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return destImage;
|
||||
|
@ -67,6 +67,7 @@
|
||||
<Compile Include="imagehandler.cs" />
|
||||
<Compile Include="Program.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="receivefile.cs" />
|
||||
<Compile Include="udp.cs" />
|
||||
<Compile Include="zip.cs" />
|
||||
<EmbeddedResource Include="Form1.resx">
|
||||
|
533
oscardata/oscardata/receivefile.cs
Executable file
533
oscardata/oscardata/receivefile.cs
Executable file
@ -0,0 +1,533 @@
|
||||
/*
|
||||
* High Speed modem to transfer data in a 2,7kHz SSB channel
|
||||
* =========================================================
|
||||
* Author: DJ0ABR
|
||||
*
|
||||
* (c) DJ0ABR
|
||||
* www.dj0abr.de
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
* File restauration process
|
||||
* =========================
|
||||
* 1) file header is received, get filename and file ID (which is the CRC16 over the complete file contents)
|
||||
* 2) is this file already existing ? yes-> 3)
|
||||
* 3) this file does not exist -> 4)
|
||||
*
|
||||
* 3) file with this name and ID exists is already, cancel reception, show file
|
||||
*
|
||||
* 4) file dows not exist, receive the blocks
|
||||
* 5) a block is missing -> find a previous block-file with this name+ID. If exists, take the block from this file
|
||||
* 6) reception complete, the files is OK -> save the file, delete a block file
|
||||
* 7) reception complete, the files is incomplete -> save the block file for late use
|
||||
*
|
||||
* Filenames:
|
||||
* ----------
|
||||
* transmitter:
|
||||
* the sender takes any filename, but the ID is the C&C16 over the file contents (to identify different files with the same name)
|
||||
*
|
||||
* receiver:
|
||||
* use the filename as transmitted for the good original file
|
||||
* the blockfile's filename is the ID in Ascii-Hex representation, i.e.: ID= 0x45 0xfe ... filename is: 45FE.blk
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
|
||||
namespace oscardata
|
||||
{
|
||||
class receivefile
|
||||
{
|
||||
int rxtype;
|
||||
int rxfrmnum;
|
||||
int minfo;
|
||||
int rxstat;
|
||||
int speed;
|
||||
int maxlevel;
|
||||
int dummy4;
|
||||
int dummy5;
|
||||
Byte[] rxdata = new byte[statics.PayloadLen];
|
||||
|
||||
// file buffer, we have max 2^10=1024 blocks with 219 bytes each = 224.256kB
|
||||
Byte[,] blockbuf = new byte[1024, statics.PayloadLen];
|
||||
bool[] blockvalid = new bool[1024];
|
||||
int blockidx;
|
||||
Byte[] firstblock;
|
||||
|
||||
bool receiving = false;
|
||||
public String filename = null;
|
||||
public String StatusText = "";
|
||||
public long filesize = 0;
|
||||
public Bitmap pbmp = null;
|
||||
DateTime starttime;
|
||||
public TimeSpan runtime;
|
||||
public int rxbytes = 0;
|
||||
bool autoRXnum = false;
|
||||
String blockFilename = "";
|
||||
|
||||
public bool receive(Byte []rxdp)
|
||||
{
|
||||
// read frame header
|
||||
if(!getFrameHeader(rxdp))
|
||||
{
|
||||
// invalid situation
|
||||
blockidx = 0;
|
||||
receiving = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
// receive first frame of a transmission
|
||||
if (minfo == statics.FirstFrame || minfo == statics.SingleFrame)
|
||||
{
|
||||
starttime = DateTime.UtcNow;
|
||||
rxbytes = 0;
|
||||
filesize = 0;
|
||||
filename = "";
|
||||
if (!StartFileRX()) return false; // invalid file
|
||||
|
||||
// check if file already exists
|
||||
if (fileExists())
|
||||
{
|
||||
// exists already, no need to receive
|
||||
filename = makeRXfilename();
|
||||
|
||||
if (rxtype == statics.Image)
|
||||
{
|
||||
try
|
||||
{
|
||||
// show existing image
|
||||
Image img = Image.FromFile(filename);
|
||||
pbmp = new Bitmap(img);
|
||||
}
|
||||
catch { pbmp = null; }
|
||||
}
|
||||
receiving = false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (minfo != statics.FirstFrame)
|
||||
runtime = DateTime.UtcNow - starttime;
|
||||
|
||||
// receive continous frames of a transmission
|
||||
if (minfo == statics.NextFrame)
|
||||
{
|
||||
// there are more frames for this file
|
||||
if(!FileRX())
|
||||
{
|
||||
// invalid situation
|
||||
blockidx = 0;
|
||||
receiving = false;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
rxbytes += statics.PayloadLen;
|
||||
|
||||
// receive last file of a transmission
|
||||
if (minfo == statics.LastFrame || minfo == statics.SingleFrame)
|
||||
{
|
||||
if (!FileRX())
|
||||
{
|
||||
// invalid situation
|
||||
blockidx = 0;
|
||||
receiving = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
// the last block was received ok
|
||||
// save file if all blocks valid
|
||||
SaveFile();
|
||||
blockidx = 0;
|
||||
receiving = false;
|
||||
|
||||
if (rxtype == statics.AsciiFile || rxtype == statics.HTMLFile || rxtype == statics.BinaryFile)
|
||||
{
|
||||
// these file type must be unzipped
|
||||
handleZIPfiles();
|
||||
receiving = false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (rxtype == statics.Image)
|
||||
{
|
||||
// build bitmap from received data
|
||||
pbmp = buildBitmap();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool getFrameHeader(Byte[] rxd)
|
||||
{
|
||||
rxtype = rxd[0];
|
||||
rxfrmnum = rxd[1];
|
||||
rxfrmnum <<= 8;
|
||||
rxfrmnum += rxd[2];
|
||||
minfo = rxd[3];
|
||||
rxstat = rxd[4];
|
||||
speed = rxd[5];
|
||||
speed <<= 8;
|
||||
speed += rxd[6];
|
||||
maxlevel = rxd[7];
|
||||
dummy4 = rxd[8];
|
||||
dummy5 = rxd[9];
|
||||
|
||||
if (rxfrmnum >= 1024) return false;
|
||||
if (!autoRXnum)
|
||||
blockidx = rxfrmnum;
|
||||
|
||||
Array.Copy(rxd, 10, rxdata, 0, rxd.Length - 10);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool StartFileRX()
|
||||
{
|
||||
if (receiving) return true; // already open
|
||||
|
||||
//Console.WriteLine("first block");
|
||||
|
||||
// store first block
|
||||
filename = null;
|
||||
if (rxfrmnum != 0)
|
||||
{
|
||||
Console.WriteLine("blockidx auto increment");
|
||||
autoRXnum = true; // for old compatibility, increment blockidx by ourself
|
||||
}
|
||||
blockidx = 0;
|
||||
if (rxdata.Length > statics.PayloadLen)
|
||||
{
|
||||
Console.WriteLine("wrong payload size: " + rxdata.Length + " expected:" + statics.PayloadLen);
|
||||
return false; // wrong size
|
||||
}
|
||||
|
||||
// read file header
|
||||
ArraySend.rxFilename = "";
|
||||
firstblock = ArraySend.GetAndRemoveHeader(rxdata);
|
||||
if (firstblock == null)
|
||||
{
|
||||
Console.WriteLine("invalid File header");
|
||||
return false; // cannot read header, file is corrupted, ignore
|
||||
}
|
||||
|
||||
// get block filename for this file
|
||||
blockFilename = idToFilename(ArraySend.FileID);
|
||||
|
||||
// init valid blocks table
|
||||
for(int i=0; i<blockvalid.Length; i++)
|
||||
blockvalid[i] = false;
|
||||
|
||||
// insert previously received blocks
|
||||
readBlocks();
|
||||
|
||||
// insert first block
|
||||
for (int i = 0; i < rxdata.Length; i++)
|
||||
blockbuf[blockidx, i] = rxdata[i]; // contains file info header and file data
|
||||
|
||||
// mark first block as valid
|
||||
blockvalid[blockidx] = true;
|
||||
|
||||
receiving = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
String idToFilename(int id)
|
||||
{
|
||||
char hexToChar(Byte h)
|
||||
{
|
||||
if (h >= 0 && h <= 9) return (char)(0x30 + h);
|
||||
return (char)(0x41 + h - 10);
|
||||
}
|
||||
|
||||
Byte b0 = (Byte)((id >> 12) & 0x0f);
|
||||
Byte b1 = (Byte)((id >> 8) & 0x0f);
|
||||
Byte b2 = (Byte)((id >> 4) & 0x0f);
|
||||
Byte b3 = (Byte)(id & 0x0f);
|
||||
|
||||
String s = "";
|
||||
s += hexToChar(b0);
|
||||
s += hexToChar(b1);
|
||||
s += hexToChar(b2);
|
||||
s += hexToChar(b3);
|
||||
s += ".blk";
|
||||
|
||||
return statics.getHomePath("blocks", s);
|
||||
}
|
||||
|
||||
public bool blockstat(int[] result)
|
||||
{
|
||||
if (blockidx == 0) return false;
|
||||
int ok = 0;
|
||||
for (int i = 0; i <= blockidx; i++)
|
||||
{
|
||||
if (blockvalid[i]) ok++;
|
||||
}
|
||||
result[0] = blockidx+1; // +1 because we start with block 0
|
||||
result[1] = ok;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void saveBlocks()
|
||||
{
|
||||
try
|
||||
{
|
||||
using (BinaryWriter writer = new BinaryWriter(File.Open(blockFilename, FileMode.Create)))
|
||||
{
|
||||
for (int i = 0; i <= blockidx; i++)
|
||||
{
|
||||
// first byte of a block: valid/invalid block
|
||||
Byte[] blk = new byte[statics.PayloadLen + 1];
|
||||
for (int j = 0; j < statics.PayloadLen; j++)
|
||||
blk[j + 1] = blockbuf[i, j];
|
||||
|
||||
blk[0] = blockvalid[i] ? (Byte)1 : (Byte)0;
|
||||
|
||||
writer.Write(blk);
|
||||
}
|
||||
writer.Close();
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
void readBlocks()
|
||||
{
|
||||
Byte[] blk = new byte[statics.PayloadLen + 1];
|
||||
int idx = 0;
|
||||
|
||||
try
|
||||
{
|
||||
using (BinaryReader reader = new BinaryReader(File.Open(blockFilename, FileMode.Open)))
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
int ret = reader.Read(blk, 0, statics.PayloadLen + 1);
|
||||
if (ret != statics.PayloadLen + 1) break;
|
||||
|
||||
for (int j = 0; j < statics.PayloadLen; j++)
|
||||
{
|
||||
if (blk[0] == 1)
|
||||
{
|
||||
blockbuf[idx, j] = blk[j + 1];
|
||||
blockvalid[idx] = true;
|
||||
}
|
||||
}
|
||||
idx++;
|
||||
}
|
||||
reader.Close();
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
bool FileRX()
|
||||
{
|
||||
if (!receiving)
|
||||
{
|
||||
Console.WriteLine("next/last block: not receiving, first block missing?");
|
||||
return false;
|
||||
}
|
||||
|
||||
//Console.WriteLine("next/last block");
|
||||
|
||||
// store next block
|
||||
if (rxdata.Length != statics.PayloadLen)
|
||||
{
|
||||
Console.WriteLine("wrong payload size: " + rxdata.Length + " expected:" + statics.PayloadLen);
|
||||
return false; // wrong size
|
||||
}
|
||||
|
||||
if (autoRXnum)
|
||||
{
|
||||
blockidx++;
|
||||
Console.WriteLine("blockidx: do auto increment " + blockidx);
|
||||
}
|
||||
|
||||
for (int i = 0; i < rxdata.Length; i++)
|
||||
blockbuf[blockidx, i] = rxdata[i];
|
||||
|
||||
blockvalid[blockidx] = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// build full path+filename from received filename
|
||||
String makeRXfilename()
|
||||
{
|
||||
String fn = "";
|
||||
// remove possible path from filename
|
||||
String fname = ArraySend.rxFilename;
|
||||
int idx = fname.IndexOfAny(new char[] { '\\', '/' });
|
||||
if (idx != -1)
|
||||
{
|
||||
try
|
||||
{
|
||||
fname = fname.Substring(idx + 1);
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
if (rxtype == statics.Image)
|
||||
fn = statics.getHomePath(statics.RXimageStorage, fname);
|
||||
else
|
||||
fn = statics.getHomePath("", fname);
|
||||
return fn;
|
||||
}
|
||||
|
||||
bool fileExists()
|
||||
{
|
||||
String fn = makeRXfilename();
|
||||
if (!File.Exists(fn)) return false;
|
||||
|
||||
// File exists, but is the ID the same ?
|
||||
Byte[] ba = File.ReadAllBytes(fn);
|
||||
if (ba == null) return false;
|
||||
Crc c = new Crc();
|
||||
int fncrc = c.crc16_messagecalc(ba, ba.Length);
|
||||
if (ArraySend.FileID != fncrc) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SaveFile()
|
||||
{
|
||||
Console.WriteLine("save file");
|
||||
|
||||
// check if all blocks ok
|
||||
for (int i = 0; i <= blockidx; i++)
|
||||
{
|
||||
if (blockvalid[i] == false)
|
||||
{
|
||||
Console.WriteLine("save file: not all blocks ok");
|
||||
// save block file
|
||||
saveBlocks();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// reception was ok, blockfile no more needed, delete it
|
||||
// file is OK, blockfile no more needed, delete it
|
||||
try { File.Delete(blockFilename); } catch { }
|
||||
|
||||
// make filename
|
||||
filename = makeRXfilename();
|
||||
|
||||
Console.WriteLine("save at " + filename);
|
||||
|
||||
using (BinaryWriter writer = new BinaryWriter(File.Open(filename, FileMode.Create)))
|
||||
{
|
||||
for (int i = 0; i <= blockidx; i++)
|
||||
{
|
||||
if (i == 0)
|
||||
writer.Write(firstblock);
|
||||
else
|
||||
{
|
||||
Byte[] blk = new byte[statics.PayloadLen];
|
||||
for (int j = 0; j < statics.PayloadLen; j++)
|
||||
blk[j] = blockbuf[i, j];
|
||||
|
||||
writer.Write(blk);
|
||||
}
|
||||
}
|
||||
writer.Close();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Bitmap buildBitmap()
|
||||
{
|
||||
Bitmap bmp = null;
|
||||
|
||||
using (MemoryStream memStream = new MemoryStream())
|
||||
{
|
||||
for (int i = 0; i <= blockidx; i++)
|
||||
{
|
||||
if (i == 0)
|
||||
memStream.Write(firstblock, 0, firstblock.Length);
|
||||
else
|
||||
{
|
||||
Byte[] blk = new byte[statics.PayloadLen];
|
||||
for (int j = 0; j < statics.PayloadLen; j++)
|
||||
blk[j] = blockbuf[i, j];
|
||||
|
||||
memStream.Write(blk, 0, blk.Length);
|
||||
}
|
||||
}
|
||||
try
|
||||
{
|
||||
// first assign it to an "Image", this checks if the image is valid
|
||||
Image img = Image.FromStream(memStream);
|
||||
bmp = new Bitmap(img);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return bmp;
|
||||
}
|
||||
|
||||
void handleZIPfiles()
|
||||
{
|
||||
if (filename == null)
|
||||
{
|
||||
Console.WriteLine("handleZIPfile: no filename");
|
||||
return;
|
||||
}
|
||||
|
||||
// filename has the received data, but maybe too long (multiple of payload length)
|
||||
// reduce for the real file length
|
||||
Byte[] fc = File.ReadAllBytes(filename);
|
||||
Byte[] fdst = new byte[ArraySend.FileSize];
|
||||
if (fc.Length < ArraySend.FileSize)
|
||||
{
|
||||
Console.WriteLine("file not complete: got len=" + fc.Length + " expected len=" + ArraySend.FileSize);
|
||||
return;
|
||||
}
|
||||
Array.Copy(fc, 0, fdst, 0, ArraySend.FileSize);
|
||||
File.WriteAllBytes(statics.zip_RXtempfilename, fdst); // the received file (still zipped) is here
|
||||
|
||||
// unzip received data and store result in file: unzipped_RXtempfilename
|
||||
ZipStorer zs = new ZipStorer();
|
||||
String fl = zs.unzipFile(statics.zip_RXtempfilename);
|
||||
if (fl != null)
|
||||
{
|
||||
// save file
|
||||
// fl is the filename of the file inside the zip file, so the originally zipped file
|
||||
// remove path to get just the filename
|
||||
int idx = fl.LastIndexOf('/');
|
||||
if (idx == -1) idx = fl.LastIndexOf('\\');
|
||||
String fdest = fl.Substring(idx + 1);
|
||||
fdest = statics.getHomePath("", fdest);
|
||||
// fdest is the file in the oscardata's user home directoty
|
||||
// remove old file with same name
|
||||
try { File.Delete(fdest); } catch { }
|
||||
// move the unzipped file to the final location
|
||||
File.Move(fl, fdest);
|
||||
filesize = statics.GetFileSize(fdest);
|
||||
StatusText = "unzip OK";
|
||||
}
|
||||
else
|
||||
StatusText = "unzip failed";
|
||||
|
||||
File.Delete(statics.zip_RXtempfilename);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user