parent
5070bc70bd
commit
6a18c924fb
@ -0,0 +1,9 @@ |
||||
AM_CPPFLAGS = -Wall -Wextra -g $(all_includes)
|
||||
|
||||
noinst_LIBRARIES = libv27.a
|
||||
|
||||
libv27_a_SOURCES = \
|
||||
scrambler.c \
|
||||
psk.c \
|
||||
modem.c
|
||||
|
@ -0,0 +1,89 @@ |
||||
/* V27 Modem
|
||||
* |
||||
* (C) 2020 by Andreas Eversberg <jolly@eversberg.eu> |
||||
* All Rights Reserved |
||||
* |
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
#include <stdio.h> |
||||
#include <stdint.h> |
||||
#include <string.h> |
||||
#include "../libdebug/debug.h" |
||||
#include "../libsample/sample.h" |
||||
#include "modem.h" |
||||
|
||||
static int psk_send_bit(void *inst) |
||||
{ |
||||
v27modem_t *modem = (v27modem_t *)inst; |
||||
uint8_t bit; |
||||
|
||||
bit = modem->send_bit(modem->inst); |
||||
bit = v27_scrambler_bit(&modem->scrambler, bit); |
||||
|
||||
return bit; |
||||
} |
||||
|
||||
static void psk_receive_bit(void *inst, int bit) |
||||
{ |
||||
v27modem_t *modem = (v27modem_t *)inst; |
||||
|
||||
bit = v27_scrambler_bit(&modem->descrambler, bit); |
||||
modem->receive_bit(modem->inst, bit); |
||||
} |
||||
|
||||
/* init psk */ |
||||
int v27_modem_init(v27modem_t *modem, void *inst, int (*send_bit)(void *inst), void (*receive_bit)(void *inst, int bit), int samplerate, int bis) |
||||
{ |
||||
int rc = 0; |
||||
|
||||
memset(modem, 0, sizeof(*modem)); |
||||
|
||||
modem->send_bit = send_bit; |
||||
modem->receive_bit = receive_bit; |
||||
modem->inst = inst; |
||||
|
||||
/* V.27bis/ter with 4800 bps */ |
||||
rc = psk_mod_init(&modem->psk_mod, modem, psk_send_bit, samplerate, 1600.0); |
||||
if (rc) |
||||
goto error; |
||||
rc = psk_demod_init(&modem->psk_demod, modem, psk_receive_bit, samplerate, 1600.0); |
||||
if (rc) |
||||
goto error; |
||||
v27_scrambler_init(&modem->scrambler, bis, 0); |
||||
v27_scrambler_init(&modem->descrambler, bis, 1); |
||||
|
||||
return 0; |
||||
|
||||
error: |
||||
v27_modem_exit(modem); |
||||
return rc; |
||||
} |
||||
|
||||
void v27_modem_exit(v27modem_t *modem) |
||||
{ |
||||
psk_mod_exit(&modem->psk_mod); |
||||
psk_demod_exit(&modem->psk_demod); |
||||
} |
||||
|
||||
void v27_modem_send(v27modem_t *modem, sample_t *sample, int length) |
||||
{ |
||||
psk_mod(&modem->psk_mod, sample, length); |
||||
} |
||||
|
||||
void v27_modem_receive(v27modem_t *modem, sample_t *sample, int length) |
||||
{ |
||||
psk_demod(&modem->psk_demod, sample, length); |
||||
} |
||||
|
@ -0,0 +1,18 @@ |
||||
#include "psk.h" |
||||
#include "scrambler.h" |
||||
|
||||
typedef struct v27modem { |
||||
int (*send_bit)(void *inst); |
||||
void (*receive_bit)(void *inst, int bit); |
||||
void *inst; |
||||
|
||||
v27scrambler_t scrambler, descrambler; |
||||
psk_mod_t psk_mod; |
||||
psk_demod_t psk_demod; |
||||
} v27modem_t; |
||||
|
||||
int v27_modem_init(v27modem_t *modem, void *inst, int (*send_bit)(void *inst), void (*receive_bit)(void *inst, int bit), int samplerate, int bis); |
||||
void v27_modem_exit(v27modem_t *modem); |
||||
void v27_modem_send(v27modem_t *modem, sample_t *sample, int length); |
||||
void v27_modem_receive(v27modem_t *modem, sample_t *sample, int length); |
||||
|
@ -0,0 +1,459 @@ |
||||
/* Jolly's Version of PSK
|
||||
* |
||||
* (C) 2020 by Andreas Eversberg <jolly@eversberg.eu> |
||||
* All Rights Reserved |
||||
* |
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
#include <stdio.h> |
||||
#include <stdint.h> |
||||
#include <unistd.h> |
||||
#include <string.h> |
||||
#include <errno.h> |
||||
#include <math.h> |
||||
#include "../libdebug/debug.h" |
||||
#include "../libsample/sample.h" |
||||
#include "psk.h" |
||||
|
||||
/* bits to phase change */ |
||||
double phase_change8[8] = { |
||||
2.0 * M_PI * 1.0 / 8.0, |
||||
2.0 * M_PI * 0.0 / 8.0, |
||||
2.0 * M_PI * 2.0 / 8.0, |
||||
2.0 * M_PI * 3.0 / 8.0, |
||||
2.0 * M_PI * 6.0 / 8.0, |
||||
2.0 * M_PI * 7.0 / 8.0, |
||||
2.0 * M_PI * 5.0 / 8.0, |
||||
2.0 * M_PI * 4.0 / 8.0, |
||||
}; |
||||
|
||||
/* phase change to bits */ |
||||
uint8_t phase2bits[8] = { 1, 0, 2, 3, 7, 6, 4, 5 }; |
||||
|
||||
/* debug decoder */ |
||||
//#define DEBUG_DECODER
|
||||
|
||||
/* use SIT original encoder */ |
||||
//#define SIT_ENCODER
|
||||
|
||||
/* may be different for testing purpose */ |
||||
#define TX_CARRIER 1800.0 |
||||
#define RX_CARRIER 1800.0 |
||||
|
||||
#ifdef SIT_ENCODER |
||||
static int8_t symbols_int[8][30] = { |
||||
{ 0xff, 0xfd, 0x00, 0x02, 0xfe, 0x02, 0x0d, 0x05, 0xf9, 0x05, 0x02, 0xd2, 0xc9, 0x23, 0x64, 0x23, |
||||
0xc9, 0xd2, 0x02, 0x05, 0xf9, 0x05, 0x0d, 0x02, 0xfe, 0x02, 0x00, 0xfd, 0xff, 0x00 }, |
||||
{ 0xfe, 0xff, 0x03, 0x02, 0xff, 0x07, 0x0a, 0xfa, 0xf7, 0x03, 0xef, 0xd0, 0xfe, 0x56, 0x47, 0xdb, |
||||
0xb4, 0xef, 0x14, 0x03, 0xff, 0x0e, 0x09, 0xfc, 0xfe, 0x01, 0xfd, 0xfd, 0x00, 0x00 }, |
||||
{ 0xff, 0x01, 0x04, 0x01, 0x01, 0x08, 0x00, 0xf2, 0xfa, 0x00, 0xe6, 0xea, 0x34, 0x57, 0x00, 0xa9, |
||||
0xcc, 0x16, 0x1a, 0x00, 0x06, 0x0e, 0x00, 0xf8, 0xff, 0xff, 0xfc, 0xff, 0x01, 0x00 }, |
||||
{ 0x00, 0x03, 0x03, 0xff, 0x02, 0x04, 0xf7, 0xf2, 0x01, 0xfd, 0xec, 0x11, 0x4c, 0x25, 0xb9, 0xaa, |
||||
0x02, 0x30, 0x11, 0xfd, 0x09, 0x06, 0xf6, 0xf9, 0x01, 0xfe, 0xfd, 0x01, 0x02, 0x00 }, |
||||
{ 0x01, 0x03, 0x00, 0xfe, 0x02, 0xfe, 0xf3, 0xfb, 0x07, 0xfb, 0xfe, 0x2e, 0x37, 0xdd, 0x9c, 0xdd, |
||||
0x37, 0x2e, 0xfe, 0xfb, 0x07, 0xfb, 0xf3, 0xfe, 0x02, 0xfe, 0x00, 0x03, 0x01, 0x00 }, |
||||
{ 0x02, 0x01, 0xfd, 0xfe, 0x01, 0xf9, 0xf6, 0x06, 0x09, 0xfd, 0x11, 0x30, 0x02, 0xaa, 0xb9, 0x25, |
||||
0x4c, 0x11, 0xec, 0xfd, 0x01, 0xf2, 0xf7, 0x04, 0x02, 0xff, 0x03, 0x03, 0x00, 0x00 }, |
||||
{ 0x01, 0xff, 0xfc, 0xff, 0xff, 0xf8, 0x00, 0x0e, 0x06, 0x00, 0x1a, 0x16, 0xcc, 0xa9, 0x00, 0x57, |
||||
0x34, 0xea, 0xe6, 0x00, 0xfa, 0xf2, 0x00, 0x08, 0x01, 0x01, 0x04, 0x01, 0xff, 0x00 }, |
||||
{ 0x00, 0xfd, 0xfd, 0x01, 0xfe, 0xfc, 0x09, 0x0e, 0xff, 0x03, 0x14, 0xef, 0xb4, 0xdb, 0x47, 0x56, |
||||
0xfe, 0xd0, 0xef, 0x03, 0xf7, 0xfa, 0x0a, 0x07, 0xff, 0x02, 0x03, 0xff, 0xfe, 0x00 }, |
||||
}; |
||||
|
||||
static sample_t symbols[8][150]; |
||||
|
||||
/* indexes are rotated by 45 degrees, because the phase change during one symbol is 360+45 degrees */ |
||||
static int bits2index[8] = { 2, 1, 3, 4, 7, 0, 6, 5 }; |
||||
#endif |
||||
|
||||
/* init psk */ |
||||
int psk_mod_init(psk_mod_t *psk, void *inst, int (*send_bit)(void *inst), int samplerate, double symbolrate) |
||||
{ |
||||
double cutoff, transitionband; |
||||
|
||||
memset(psk, 0, sizeof(*psk)); |
||||
|
||||
psk->send_bit = send_bit; |
||||
psk->inst = inst; |
||||
|
||||
#ifdef SIT_ENCODER |
||||
int i, j, s; |
||||
sample_t spl; |
||||
|
||||
if (samplerate != 48000) { |
||||
PDEBUG(DDSP, DEBUG_NOTICE, "Sampling rate for PSK encoder must be exactly 48000 Hz!\n"); |
||||
return -EINVAL; |
||||
} |
||||
if (symbolrate != 1600) { |
||||
PDEBUG(DDSP, DEBUG_NOTICE, "Symbol rate for PSK encoder must be exactly 1600 Hz!\n"); |
||||
return -EINVAL; |
||||
} |
||||
|
||||
cutoff = 3300.0; |
||||
transitionband = 200; |
||||
psk->lp[0] = fir_lowpass_init((double)samplerate, cutoff, transitionband); |
||||
PDEBUG(DDSP, DEBUG_DEBUG, "Cut off frequency is at %.1f Hz and %.1f Hz.\n", TX_CARRIER + cutoff, TX_CARRIER - cutoff); |
||||
|
||||
/* interpolate symbol table from 9600 Hz to 48000 Hz */ |
||||
for (i = 0; i < 8; i++) { |
||||
for (j = 0, s = 0; j < 30; j++) { |
||||
spl = (double)symbols_int[i][j] / 128.0; |
||||
symbols[i][s++] = spl; |
||||
symbols[i][s++] = spl; |
||||
symbols[i][s++] = spl; |
||||
symbols[i][s++] = spl; |
||||
symbols[i][s++] = spl; |
||||
} |
||||
} |
||||
#else |
||||
if (samplerate < 48000) { |
||||
PDEBUG(DDSP, DEBUG_NOTICE, "Sampling rate for PSK encoder must be 48000 Hz minimum!\n"); |
||||
return -EINVAL; |
||||
} |
||||
|
||||
/* fixme: make correct filter */ |
||||
cutoff = RX_CARRIER - 100; |
||||
transitionband = 200; |
||||
psk->lp[0] = fir_lowpass_init((double)samplerate, cutoff, transitionband); |
||||
psk->lp[1] = fir_lowpass_init((double)samplerate, cutoff, transitionband); |
||||
PDEBUG(DDSP, DEBUG_DEBUG, "Cut off frequency is at %.1f Hz and %.1f Hz.\n", TX_CARRIER + cutoff, TX_CARRIER - cutoff); |
||||
|
||||
psk->symbols_per_sample = symbolrate / (double)samplerate; |
||||
PDEBUG(DDSP, DEBUG_DEBUG, "Symbol duration of %.4f symbols per sample @ %d.\n", psk->symbols_per_sample, samplerate); |
||||
|
||||
psk->carrier_phaseshift = 2.0 * M_PI * TX_CARRIER / (double)samplerate; |
||||
PDEBUG(DDSP, DEBUG_DEBUG, "Carrier phase shift of %.4f per sample @ %d.\n", psk->carrier_phaseshift, samplerate); |
||||
#endif |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
void psk_mod_exit(psk_mod_t *psk) |
||||
{ |
||||
if (psk->lp[0]) { |
||||
fir_exit(psk->lp[0]); |
||||
psk->lp[0] = NULL; |
||||
} |
||||
if (psk->lp[1]) { |
||||
fir_exit(psk->lp[1]); |
||||
psk->lp[1] = NULL; |
||||
} |
||||
} |
||||
|
||||
void psk_mod(psk_mod_t *psk, sample_t *sample, int length) |
||||
{ |
||||
uint8_t bits; |
||||
int s; |
||||
#ifdef SIT_ENCODER |
||||
int index; |
||||
|
||||
for (s = 0; s < length; s++) { |
||||
if (psk->spl_count == 0) { |
||||
bits = (psk->send_bit(psk->inst) & 1) << 2; |
||||
bits |= (psk->send_bit(psk->inst) & 1) << 1; |
||||
bits |= (psk->send_bit(psk->inst) & 1); |
||||
|
||||
#ifdef DEBUG_DECODER |
||||
static int nextbit = 0; |
||||
if (++nextbit == 8) |
||||
nextbit = 0; |
||||
bits = nextbit; |
||||
#endif |
||||
|
||||
index = psk->sym_list[psk->sym_count]; |
||||
psk->sym_count = (psk->sym_count + 1) % 5; |
||||
psk->sym_list[psk->sym_count] = (index + bits2index[bits]) & 7; |
||||
} |
||||
|
||||
sample[s] = symbols[psk->sym_list[psk->sym_count]][psk->spl_count]; |
||||
sample[s] += symbols[psk->sym_list[(psk->sym_count + 4) % 5]][30 + psk->spl_count]; |
||||
sample[s] += symbols[psk->sym_list[(psk->sym_count + 3) % 5]][60 + psk->spl_count]; |
||||
sample[s] += symbols[psk->sym_list[(psk->sym_count + 2) % 5]][90 + psk->spl_count]; |
||||
sample[s] += symbols[psk->sym_list[(psk->sym_count + 1) % 5]][120 + psk->spl_count]; |
||||
|
||||
if (++psk->spl_count == 30) |
||||
psk->spl_count = 0; |
||||
} |
||||
fir_process(psk->lp[0], sample, length); |
||||
#else |
||||
sample_t I[length], Q[length]; |
||||
|
||||
/* count symbol and get new bits for next symbol */ |
||||
for (s = 0; s < length; s++) { |
||||
psk->symbol_pos += psk->symbols_per_sample; |
||||
if (psk->symbol_pos >= 1.0) { |
||||
psk->symbol_pos -= 1.0; |
||||
/* get tree bits */ |
||||
bits = (psk->send_bit(psk->inst) & 1) << 2; |
||||
bits |= (psk->send_bit(psk->inst) & 1) << 1; |
||||
bits |= (psk->send_bit(psk->inst) & 1); |
||||
|
||||
#ifdef DEBUG_DECODER |
||||
static int nextbit = 0; |
||||
if (++nextbit == 8) |
||||
nextbit = 0; |
||||
bits = nextbit; |
||||
#endif |
||||
|
||||
/* change phase_shift */ |
||||
psk->phase_shift += phase_change8[bits]; |
||||
if (psk->phase_shift > M_PI) |
||||
psk->phase_shift -= 2.0 * M_PI; |
||||
} |
||||
|
||||
I[s] = cos(psk->phase_shift); |
||||
Q[s] = sin(psk->phase_shift); |
||||
} |
||||
|
||||
/* filter phase_shift to limit bandwidth */ |
||||
fir_process(psk->lp[0], I, length); |
||||
fir_process(psk->lp[1], Q, length); |
||||
|
||||
/* modulate with carrier frequency */ |
||||
for (s = 0; s < length; s++) { |
||||
/* compensate overshooting of filter */ |
||||
*sample++ = (I[s] * cos(psk->carrier_phase) - Q[s] * sin(psk->carrier_phase)) * 0.7; |
||||
psk->carrier_phase += psk->carrier_phaseshift; |
||||
if (psk->carrier_phase >= 2.0 * M_PI) |
||||
psk->carrier_phase -= 2.0 * M_PI; |
||||
} |
||||
#endif |
||||
} |
||||
|
||||
int psk_demod_init(psk_demod_t *psk, void *inst, void (*receive_bit)(void *inst, int bit), int samplerate, double symbolrate) |
||||
{ |
||||
double cutoff, transitionband; |
||||
|
||||
if (samplerate < 48000) { |
||||
PDEBUG(DDSP, DEBUG_NOTICE, "Sampling rate for PSK decoder must be 48000 Hz minimum!\n"); |
||||
return -EINVAL; |
||||
} |
||||
|
||||
memset(psk, 0, sizeof(*psk)); |
||||
|
||||
psk->receive_bit = receive_bit; |
||||
psk->inst = inst; |
||||
|
||||
/* fixme: make correct filter */ |
||||
// cutoff = symbolrate / 2.0 * 1.5;
|
||||
cutoff = RX_CARRIER - 100; |
||||
transitionband = 200; |
||||
psk->lp[0] = fir_lowpass_init((double)samplerate, cutoff, transitionband); |
||||
psk->lp[1] = fir_lowpass_init((double)samplerate, cutoff, transitionband); |
||||
iir_lowpass_init(&psk->lp_error[0], 50.0, samplerate, 2); |
||||
iir_lowpass_init(&psk->lp_error[1], 50.0, samplerate, 2); |
||||
iir_bandpass_init(&psk->lp_clock, symbolrate, samplerate, 40); |
||||
psk->sample_delay = (int)floor((double)samplerate / symbolrate * 0.25); /* percent of sine duration behind zero crossing */ |
||||
PDEBUG(DDSP, DEBUG_DEBUG, "Cut off frequency is at %.1f Hz and %.1f Hz.\n", RX_CARRIER + cutoff, RX_CARRIER - cutoff); |
||||
|
||||
psk->carrier_phaseshift = 2.0 * M_PI * -RX_CARRIER / (double)samplerate; |
||||
PDEBUG(DDSP, DEBUG_DEBUG, "Carrier phase shift of %.4f per sample @ %d.\n", psk->carrier_phaseshift, samplerate); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
void psk_demod_exit(psk_demod_t *psk) |
||||
{ |
||||
if (psk->lp[0]) { |
||||
fir_exit(psk->lp[0]); |
||||
psk->lp[0] = NULL; |
||||
} |
||||
if (psk->lp[1]) { |
||||
fir_exit(psk->lp[1]); |
||||
psk->lp[1] = NULL; |
||||
} |
||||
} |
||||
|
||||
#ifdef DEBUG_DECODER |
||||
static void debug_phase(double phase, double amplitude, double error, double amplitude2) |
||||
{ |
||||
int x, y, xx = 100, yy = 50; |
||||
char buffer[yy][xx + 1]; |
||||
double p; |
||||
int i; |
||||
|
||||
if (amplitude > 1.0) |
||||
amplitude = 1.0; |
||||
if (amplitude < -0.0) |
||||
amplitude = -0.0; |
||||
if (amplitude2 > 0.5) |
||||
amplitude2 = 0.5; |
||||
if (amplitude2 < -0.5) |
||||
amplitude2 = -0.5; |
||||
amplitude2 += 0.5; |
||||
|
||||
/* clear (EOL) and fill spaces with border */ |
||||
memset(buffer, '\0', sizeof(buffer)); |
||||
memset(buffer[0], '#', xx); |
||||
for (y = 1; y < yy - 1; y++) { |
||||
memset(buffer[y], ' ', xx); |
||||
buffer[y][0] = '|'; |
||||
buffer[y][xx - 1] = '|'; |
||||
} |
||||
memset(buffer[yy - 1], '-', xx); |
||||
buffer[0][0] = '+'; |
||||
buffer[0][xx - 1] = '+'; |
||||
buffer[yy - 1][0] = '+'; |
||||
buffer[yy - 1][xx - 1] = '+'; |
||||
|
||||
/* plot target angles on buffer */ |
||||
for (i = 0, p = 0.0; i < 8; i++, p = p + M_PI / 4.0) { |
||||
y = -(sin(p + error) * (double)yy / 1.1) + (double)yy; |
||||
x = (cos(p + error) * (double)xx / 2.2) + (double)xx / 2.0; |
||||
buffer[y >> 1][x] = '0' + i; |
||||
} |
||||
|
||||
/* plot angle on buffer */ |
||||
y = -(amplitude * 1.1 * sin(phase) * (double)yy / 1.1) + (double)yy; |
||||
x = (amplitude * 1.1 * cos(phase) * (double)xx / 2.2) + (double)xx / 2.0; |
||||
if ((y & 1)) |
||||
buffer[y >> 1][x] = '.'; |
||||
else |
||||
buffer[y >> 1][x] = '\''; |
||||
|
||||
/* plot amplitude on buffer */ |
||||
y = -(amplitude * (double)yy * 2.0 / 1.1) + (double)yy * 2.0 / 1.1; |
||||
if ((y & 1)) |
||||
buffer[y >> 1][1] = '.'; |
||||
else |
||||
buffer[y >> 1][1] = '\''; |
||||
y = -(amplitude2 * (double)yy * 2.0 / 1.1) + (double)yy * 2.0 / 1.1; |
||||
if ((y & 1)) |
||||
buffer[y >> 1][2] = '.'; |
||||
else |
||||
buffer[y >> 1][2] = '\''; |
||||
|
||||
/* display on screen */ |
||||
for (y = 0; y < yy; y++) |
||||
printf("%s\n", buffer[y]); |
||||
} |
||||
#endif |
||||
|
||||
void psk_demod(psk_demod_t *psk, sample_t *sample, int length) |
||||
{ |
||||
sample_t I[length], Q[length], i; |
||||
sample_t Ip[length], Qp[length]; |
||||
double phases[length]; |
||||
sample_t amplitudes[length], amplitudes2[length]; |
||||
double phaseshift, phase, phase_error, angle_error; |
||||
uint16_t phase_error_int, offset; |
||||
int s, ss; |
||||
uint8_t sector, rotation, bits; |
||||
|
||||
/* demodulate phase from carrier */ |
||||
phaseshift = psk->carrier_phaseshift; |
||||
phase = psk->carrier_phase; |
||||
for (s = 0, ss = 0; s < length; s++) { |
||||
phase += phaseshift; |
||||
i = sample[ss++]; |
||||
if (phase < 0) |
||||
phase += 2.0 * M_PI; |
||||
else if (phase >= 2.0 * M_PI) |
||||
phase -= 2.0 * M_PI; |
||||
I[s] = i * cos(phase); |
||||
Q[s] = i * sin(phase); |
||||
} |
||||
psk->carrier_phase = phase; |
||||
fir_process(psk->lp[0], I, length); |
||||
fir_process(psk->lp[1], Q, length); |
||||
|
||||
/* get phase error */ |
||||
for (s = 0, ss = 0; s < length; s++) { |
||||
phases[s] = atan2(Q[s], I[s]); |
||||
amplitudes[s] = sqrt(Q[s] * Q[s] + I[s] * I[s]) * 2.0; |
||||
amplitudes2[s] = amplitudes[s]; |
||||
Ip[s] = amplitudes[s] * cos(phases[s] * 8.0) * 2.0; |
||||
Qp[s] = amplitudes[s] * sin(phases[s] * 8.0) * 2.0; |
||||
} |
||||
iir_process(&psk->lp_error[0], Ip, length); |
||||
iir_process(&psk->lp_error[1], Qp, length); |
||||
|
||||
/* filter amplitude to get symbol clock */ |
||||
/* NOTE: the filter biases the amplitude, so that we have positive and negative peaks.
|
||||
positive peak is the sample point */ |
||||
iir_process(&psk->lp_clock, amplitudes2, length); |
||||
|
||||
for (s = 0; s < length; s++) { |
||||
/* calculate change of phase error angle within one sample */ |
||||
phase_error_int = (int)floor(atan2(Qp[s], Ip[s]) / (2.0 * M_PI) * 65536.0); |
||||
offset = phase_error_int - psk->last_phase_error; |
||||
psk->last_phase_error = phase_error_int; |
||||
|
||||
/* apply change to current phase error value */ |
||||
psk->phase_error += (int16_t)offset; |
||||
if (psk->phase_error >= 65536 * 8) |
||||
psk->phase_error -= 65536 * 8; |
||||
if (psk->phase_error < 0) |
||||
psk->phase_error += 65536 * 8; |
||||
|
||||
phase_error = (double)psk->phase_error / 65536.0 * (2.0 * M_PI) / 8.0; |
||||
|
||||
/* if we have reached a zero crossing of the amplitude signal, wait for sample point */ |
||||
if (psk->sample_timer && --psk->sample_timer == 0) { |
||||
/* sample point reached */ |
||||
phase = fmod(phases[s] - phase_error + 4.0 * M_PI, 2.0 * M_PI); |
||||
if (phase < 2.0 * M_PI / 16.0 * 1.0) |
||||
sector = 0; |
||||
else if (phase < 2.0 * M_PI / 16.0 * 3.0) |
||||
sector = 1; |
||||
else if (phase < 2.0 * M_PI / 16.0 * 5.0) |
||||
sector = 2; |
||||
else if (phase < 2.0 * M_PI / 16.0 * 7.0) |
||||
sector = 3; |
||||
else if (phase < 2.0 * M_PI / 16.0 * 9.0) |
||||
sector = 4; |
||||
else if (phase < 2.0 * M_PI / 16.0 * 11.0) |
||||
sector = 5; |
||||
else if (phase < 2.0 * M_PI / 16.0 * 13.0) |
||||
sector = 6; |
||||
else if (phase < 2.0 * M_PI / 16.0 * 15.0) |
||||
sector = 7; |
||||
else |
||||
sector = 0; |
||||
angle_error = fmod(phase / 2.0 / M_PI * 8.0, 1.0); |
||||
if (angle_error > 0.5) |
||||
angle_error -= 1.0; |
||||
|
||||
rotation = (sector - psk->last_sector) & 7; // might be negative, so we use AND!
|
||||
bits = phase2bits[rotation]; |
||||
#ifdef DEBUG_DECODER |
||||
printf("sector=%d last_sector=%d rotation=%d bits=%d angle_error=%.2f\n", sector, psk->last_sector, rotation, bits, angle_error); |
||||
#endif |
||||
psk->last_sector = sector; |
||||
/* report bits */ |
||||
#ifndef DEBUG_DECODER |
||||
psk->receive_bit(psk->inst, bits >> 2); |
||||
psk->receive_bit(psk->inst, (bits >> 1) & 1); |
||||
psk->receive_bit(psk->inst, bits & 1); |
||||
#endif |
||||
} |
||||
if (psk->last_amplitude <= 0.0 && amplitudes2[s] > 0.0) |
||||
psk->sample_timer = psk->sample_delay; |
||||
psk->last_amplitude = amplitudes2[s]; |
||||
|
||||
#ifdef DEBUG_DECODER |
||||
static int when = 0; |
||||
if (++when > 10000) { |
||||
printf("\0337\033[H"); |
||||
/* display amplitude between 0.0 and 1.0, aplitude2 between -0.5 and 0.5 */ |
||||
debug_phase(phases[s], amplitudes[s], phase_error, amplitudes2[s]); |
||||
printf("phase2 = %.4f offset = %d, error = %d (error & 0xffff = %d)\n", phase_error, offset, psk->phase_error, psk->phase_error & 0xffff); |
||||
printf("\033[0;39m\0338"); fflush(stdout); |
||||
usleep(50000); |
||||
} |
||||
#endif |
||||
} |
||||
} |
||||
|
@ -0,0 +1,48 @@ |
||||
#include "../libfilter/iir_filter.h" |
||||
#include "../libfilter/fir_filter.h" |
||||
|
||||
typedef struct psk_mod { |
||||
int (*send_bit)(void *inst); |
||||
void *inst; |
||||
|
||||
double symbol_pos; /* current position in symbol */ |
||||
double symbols_per_sample; /* change of position per sample */ |
||||
double phase_shift; /* carrier phase shift */ |
||||
double carrier_phase; /* current carrier phase */ |
||||
double carrier_phaseshift; /* shift of phase per sample */ |
||||
|
||||
fir_filter_t *lp[2]; /* filter for limiting spectrum */ |
||||
|
||||
int spl_count; /* SIT: counter for 30 samples (symbol duration) */ |
||||
int sym_list[5]; /* SIT: list of 5 symbols */ |
||||
int sym_count; /* SIT: current list index */ |
||||
} psk_mod_t; |
||||
|
||||
typedef struct psk_demod { |
||||
void (*receive_bit)(void *inst, int bit); |
||||
void *inst; |
||||
|
||||
double carrier_phase; /* current carrier phase */ |
||||
double carrier_phaseshift; /* shift of phase per sample */ |
||||
|
||||
fir_filter_t *lp[2]; /* filter for limiting spectrum */ |
||||
iir_filter_t lp_error[2]; /* filter for phase correction */ |
||||
iir_filter_t lp_clock; /* filter for symbol clock */ |
||||
|
||||
uint16_t last_phase_error; /* error phase of last sample */ |
||||
int32_t phase_error; /* current phase error */ |
||||
|
||||
sample_t last_amplitude; /* clock amplitude of last sample */ |
||||
int sample_delay; /* delay of quarter symbol length in samples */ |
||||
int sample_timer; /* counter to wait for the symbol's sample point */ |
||||
|
||||
uint8_t last_sector; /* sector of last symbol */ |
||||
} psk_demod_t; |
||||
|
||||
int psk_mod_init(psk_mod_t *psk, void *inst, int (*send_bit)(void *inst), int samplerate, double symbolrate); |
||||
void psk_mod_exit(psk_mod_t *psk); |
||||
void psk_mod(psk_mod_t *psk, sample_t *sample, int length); |
||||
int psk_demod_init(psk_demod_t *psk, void *inst, void (*receive_bit)(void *inst, int bit), int samplerate, double symbolrate); |
||||
void psk_demod_exit(psk_demod_t *psk); |
||||
void psk_demod(psk_demod_t *psk, sample_t *sample, int length); |
||||
|
@ -0,0 +1,163 @@ |
||||
/* V.27(bis) Scrambler / Descrambler
|
||||
* |
||||
* (C) 2020 by Andreas Eversberg <jolly@eversberg.eu> |
||||
* All Rights Reserved |
||||
* |
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
/* Based on orignal Scrambler code from SIT-Rom:
|
||||
|
||||
r6 already has input bit at position 0. |
||||
r6 (low) and r7 (high) are the shift register. |
||||
The register is shifed during process, so that compare at 00BE and |
||||
00C5 refers to the already shifted register and not to the original |
||||
position. |
||||
|
||||
00A4 L00A4: |
||||
00A4 : FE mov a,r6 |
||||
00A5 : ED AF djnz r5,L00AF |
||||
00A7 : D3 01 xrl a,#001H |
||||
00A9 : BD 22 mov r5,#022H |
||||
00AB L00AB: |
||||
00AB : D2 B3 jb6 L00B3 |
||||
00AD : 04 B5 jmp L00B5 |
||||
; |
||||
00AF L00AF: |
||||
00AF : 00 nop |
||||
00B0 : 00 nop |
||||
00B1 : 04 AB jmp L00AB |
||||
; |
||||
00B3 L00B3: |
||||
00B3 : D3 01 xrl a,#001H |
||||
00B5 L00B5: |
||||
00B5 : F2 B9 jb7 L00B9 |
||||
00B7 : 04 BB jmp L00BB |
||||
; |
||||
00B9 L00B9: |
||||
00B9 : D3 01 xrl a,#001H |
||||
00BB L00BB: |
||||
00BB : 97 clr c |
||||
00BC : F7 rlc a |
||||
00BD : AE mov r6,a |
||||
00BE : 32 CB jb1 L00CB |
||||
00C0 : FF mov a,r7 |
||||
00C1 : F7 rlc a |
||||
00C2 : AF mov r7,a |
||||
00C3 : 37 cpl a |
||||
00C4 : 00 nop |
||||
00C5 L00C5: |
||||
00C5 : 53 26 anl a,#026H |
||||
00C7 : C6 D0 jz L00D0 |
||||
00C9 : 04 D2 jmp L00D2 |
||||
; |
||||
00CB L00CB: |
||||
00CB : FF mov a,r7 |
||||
00CC : F7 rlc a |
||||
00CD : AF mov r7,a |
||||
00CE : 04 C5 jmp L00C5 |
||||
;
|
||||
00D0 00D0: |
||||
00D0 : BD 22 mov r5,#022H |
||||
00D2 00D2: |
||||
00D2 : 83 ret |
||||
|
||||
*/ |
||||
|
||||
#include <stdio.h> |
||||
#include <stdint.h> |
||||
#include <string.h> |
||||
#include "scrambler.h" |
||||
|
||||
#define GUARD_COUNT 34 |
||||
|
||||
/* init scrambler */ |
||||
void v27_scrambler_init(v27scrambler_t *scram, int bis, int descramble) |
||||
{ |
||||
memset(scram, 0, sizeof(*scram)); |
||||
|
||||
scram->descramble = descramble; |
||||
|
||||
/* set bits 9 and 12 (and 8 for V.27bis) */ |
||||
if (bis) |
||||
scram->resetmask = 0x1300; |
||||
else |
||||
scram->resetmask = 0x1200; |
||||
|
||||
/* guard counter */ |
||||
scram->counter = GUARD_COUNT; |
||||
} |
||||
|
||||
/* scramble/descramble one bit */ |
||||
uint8_t v27_scrambler_bit(v27scrambler_t *scram, uint8_t in) |
||||
{ |
||||
uint8_t bit0 = in & 1; |
||||
uint16_t shift = scram->shift; |
||||
|
||||
|
||||
/* the descrambler stores the input bit */ |
||||
if (scram->descramble) { |
||||
/* put bit 0 into shift register and shift */ |
||||
shift |= bit0; |
||||
scram->shift = shift << 1; |
||||
} |
||||
|
||||
/* process guaard counter */ |
||||
if (--scram->counter == 0) { |
||||
/* restart counter */ |
||||
scram->counter = GUARD_COUNT; |
||||
/* invert this time */ |
||||
bit0 ^= 1; |
||||
} |
||||
|
||||
/* xor bit 0 with bits 6 and 7: polynome 1 + x^-6 + x^-7 */ |
||||
bit0 ^= ((shift >> 6) & 1); |
||||
bit0 ^= ((shift >> 7) & 1); |
||||
|
||||
/* the scrambler stores the output bit */ |
||||
if (!scram->descramble) { |
||||
/* put bit 0 into shift register and shift */ |
||||
shift |= bit0; |
||||
scram->shift = shift << 1; |
||||
} |
||||
|
||||
/* check if bits (8),9,12 are repitions of bit 0 in shift register (prior shift) */ |
||||
if (!(shift & 1)) |
||||
shift ^= ~0; |
||||
if (!(shift & scram->resetmask)) { |
||||
/* any repetition is not true, reset counter */ |
||||
scram->counter = GUARD_COUNT; |
||||
} |
||||
|
||||
return bit0; |
||||
} |
||||
|
||||
/* scramble/descramble block of bytes (LSB first) */ |
||||
void v27_scrambler_block(v27scrambler_t *scram, uint8_t *data, int len) |
||||
{ |
||||
int i, j; |
||||
uint8_t in, out = 0; |
||||
|
||||
for (i = 0; i < len; i++) { |
||||
in = data[i]; |
||||
for (j = 0; j < 8; j++) { |
||||
out >>= 1; |
||||
// Note: 'in' will be masked to bit 0 only
|
||||
out |= v27_scrambler_bit(scram, in) << 7; |
||||
in >>= 1; |
||||
} |
||||
data[i] = out; |
||||
} |
||||
} |
||||
|
@ -0,0 +1,13 @@ |
||||
|
||||
typedef struct v27scrambler { |
||||
int descramble; /* set if we descramble */ |
||||
|
||||
uint16_t shift; /* shift register to hold 13 bits */ |
||||
int counter; /* counter to guard against repetitions */ |
||||
uint16_t resetmask; /* bit mask for repition check */ |
||||
} v27scrambler_t; |
||||
|
||||
void v27_scrambler_init(v27scrambler_t *scram, int bis, int descramble); |
||||
uint8_t v27_scrambler_bit(v27scrambler_t *scram, uint8_t in); |
||||
void v27_scrambler_block(v27scrambler_t *scram, uint8_t *data, int len); |
||||
|
@ -0,0 +1,133 @@ |
||||
#include "stdio.h" |
||||
#include "stdint.h" |
||||
#include "string.h" |
||||
#include "../libv27/scrambler.h" |
||||
|
||||
static int show_bin(uint8_t *data1, uint8_t *data2, int len) |
||||
{ |
||||
int i, j, error = 0;; |
||||
uint8_t bit1, bit2; |
||||
|
||||
for (i = 0; i < len; i++) { |
||||
printf("."); |
||||
for (j = 0; j < 8; j++) { |
||||
bit1 = (data1[i] >> j) & 1; |
||||
bit2 = (data2[i] >> j) & 1; |
||||
if (bit1 == bit2) |
||||
printf("%d", bit1); |
||||
else { |
||||
printf("X"); |
||||
error++; |
||||
} |
||||
} |
||||
} |
||||
|
||||
printf("\n"); |
||||
|
||||
return error; |
||||
} |
||||
|
||||
static int check_repetition(uint8_t *data, int len, int repeat, int start) |
||||
{ |
||||
int i; |
||||
uint8_t b1, b2; |
||||
|
||||
for (i = start; i < (len * 8 - repeat); i++) { |
||||
b1 = (data[i >> 3] >> (i & 7)) & 1; |
||||
b2 = (data[(i+repeat) >> 3] >> ((i+repeat) & 7)) & 1; |
||||
if (b1 != b2) |
||||
return i - start + repeat; |
||||
} |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
int main(void) |
||||
{ |
||||
v27scrambler_t scram, descram; |
||||
|
||||
char message[] = "Jolly Roger~~~~"; |
||||
int len = strlen(message); |
||||
uint8_t data[len]; |
||||
int ret; |
||||
|
||||
printf("Message: %s\n", message); |
||||
|
||||
memcpy(data, message, len); |
||||
show_bin(data, (uint8_t *)message, len); |
||||
|
||||
v27_scrambler_init(&scram, 1, 0); |
||||
v27_scrambler_block(&scram, data, len); |
||||
|
||||
printf("Scrambled:\n"); |
||||
show_bin(data, data, len); |
||||
|
||||
v27_scrambler_init(&descram, 1, 1); |
||||
v27_scrambler_block(&descram, data, len); |
||||
|
||||
printf("Descramble without corruption?\n"); |
||||
|
||||
ret = show_bin(data, (uint8_t *)message, len); |
||||
if (ret) { |
||||
printf("Descrambling failed!\n"); |
||||
return 1; |
||||
} |
||||
printf("Yes!\n"); |
||||
|
||||
printf("\n"); |
||||
|
||||
v27_scrambler_init(&scram, 1, 0); |
||||
v27_scrambler_block(&scram, data, len); |
||||
|
||||
data[0] = 'B'; |
||||
data[1] = 'U'; |
||||
data[2] = 'G'; |
||||
|
||||
v27_scrambler_init(&descram, 1, 1); |
||||
v27_scrambler_block(&descram, data, len); |
||||
|
||||
printf("Descramble with 3 bytes corruption: (should fix itself after 4 bytes)\n"); |
||||
|
||||
show_bin(data, (uint8_t *)message, len); |
||||
|
||||
printf("\n"); |
||||
|
||||
printf("Descramble a scrambled sequence of 8 bit repetitions with V.27: 01111110\n"); |
||||
|
||||
memset(data, 0x7e, len); |
||||
|
||||
v27_scrambler_init(&descram, 0, 1); |
||||
v27_scrambler_block(&descram, data, len); |
||||
|
||||
show_bin(data, (uint8_t *)data, len); |
||||
|
||||
/* note at position 6 we have no more change towards 8 bit offset */ |
||||
ret = check_repetition(data, len, 8, 6); |
||||
if (ret) { |
||||
printf("Theres is a change of repetition after %d bits after start %d, please fix!\n", ret, 6); |
||||
return 1; |
||||
} |
||||
printf("Repetition not detected, good!\n"); |
||||
|
||||
printf("\n"); |
||||
|
||||
printf("Descramble a scrambled sequence of 8 bit repetitions with V.27bis/ter: 01111110\n"); |
||||
|
||||
memset(data, 0x7e, len); |
||||
|
||||
v27_scrambler_init(&descram, 1, 1); |
||||
v27_scrambler_block(&descram, data, len); |
||||
|
||||
show_bin(data, (uint8_t *)data, len); |
||||
|
||||
/* note at position 6 we have no more change towards 8 bit offset */ |
||||
ret = check_repetition(data, len, 8, 6); |
||||
if (ret != 34) { |
||||
printf("Theres is NO change of repetition after 34 bits, but after %d bits, which should not happen!\n", ret); |
||||
return 1; |
||||
} |
||||
printf("Repetition detected after %d bits from start %d, good!\n", ret, 6); |
||||
|
||||
return 0; |
||||
} |
||||
|
Loading…
Reference in new issue