parent
7d5d3da8d3
commit
d2c4ca4fa9
@ -1,3 +1,3 @@ |
||||
AUTOMAKE_OPTIONS = foreign
|
||||
SUBDIRS = common anetz bnetz cnetz nmt test
|
||||
SUBDIRS = common anetz bnetz cnetz nmt amps test
|
||||
|
||||
|
@ -0,0 +1,25 @@ |
||||
AM_CPPFLAGS = -Wall -g $(all_includes)
|
||||
|
||||
bin_PROGRAMS = \
|
||||
amps
|
||||
|
||||
amps_SOURCES = \
|
||||
amps.c \
|
||||
transaction.c \
|
||||
frame.c \
|
||||
dsp.c \
|
||||
sysinfo.c \
|
||||
image.c \
|
||||
tones.c \
|
||||
noanswer.c \
|
||||
outoforder.c \
|
||||
invalidnumber.c \
|
||||
congestion.c \
|
||||
stations.c \
|
||||
main.c
|
||||
amps_LDADD = \
|
||||
$(COMMON_LA) \
|
||||
$(top_builddir)/src/common/libcommon.a \
|
||||
$(ALSA_LIBS) \
|
||||
-lm
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,160 @@ |
||||
#include "../common/sender.h" |
||||
#include "../common/compander.h" |
||||
#include "sysinfo.h" |
||||
#include "transaction.h" |
||||
|
||||
enum dsp_mode { |
||||
DSP_MODE_OFF, /* channel not active (VC) */ |
||||
DSP_MODE_AUDIO_RX_AUDIO_TX, /* stream audio */ |
||||
DSP_MODE_AUDIO_RX_FRAME_TX, /* stream audio, send frames */ |
||||
DSP_MODE_FRAME_RX_FRAME_TX, /* send and decode frames */ |
||||
}; |
||||
|
||||
enum amps_chan_type { |
||||
CHAN_TYPE_CC, /* control channel */ |
||||
CHAN_TYPE_PC, /* paging channel */ |
||||
CHAN_TYPE_CC_PC, /* combined CC + PC */ |
||||
CHAN_TYPE_VC, /* voice channel */ |
||||
CHAN_TYPE_CC_PC_VC, /* combined CC + PC + TC */ |
||||
}; |
||||
|
||||
enum amps_state { |
||||
STATE_NULL, /* power off state */ |
||||
STATE_IDLE, /* channel is not in use */ |
||||
STATE_BUSY, /* channel busy (call) */ |
||||
}; |
||||
|
||||
enum fsk_rx_sync { |
||||
FSK_SYNC_NONE, /* we are not in sync and wait for valid dotting sequence */ |
||||
FSK_SYNC_DOTTING, /* we received a valid dotting sequence and check for sync sequence */ |
||||
FSK_SYNC_POSITIVE, /* we have valid sync and read all the bits of the frame */ |
||||
FSK_SYNC_NEGATIVE, /* as above, but negative sync (high frequency deviation detected as low signal) */ |
||||
}; |
||||
|
||||
#define FSK_MAX_BITS 1032 /* maximum number of bits to process */ |
||||
|
||||
typedef struct amps { |
||||
sender_t sender; |
||||
compander_t cstate; |
||||
int pre_emphasis; /* use pre_emphasis by this instance */ |
||||
int de_emphasis; /* use de_emphasis by this instance */ |
||||
emphasis_t estate; |
||||
|
||||
/* sender's states */ |
||||
enum amps_chan_type chan_type; |
||||
enum amps_state state; |
||||
int page_retry; /* current number of paging (re)try */ |
||||
|
||||
/* system info */ |
||||
amps_si si; |
||||
|
||||
/* cell nr selection */ |
||||
int cell_auto; /* if set, cell_nr is selected automatically */ |
||||
|
||||
/* dsp states */ |
||||
enum dsp_mode dsp_mode; /* current mode: audio, durable tone 0 or 1, paging */ |
||||
int flip_polarity; /* 1 = flip */ |
||||
int16_t fsk_deviation; /* deviation of FSK signal on sound card */ |
||||
int16_t fsk_ramp_up[256]; /* samples of upward ramp shape */ |
||||
int16_t fsk_ramp_down[256]; /* samples of downward ramp shape */ |
||||
double fsk_bitduration; /* duration of one bit in samples */ |
||||
double fsk_bitstep; /* fraction of one bit each sample */ |
||||
/* tx bits generation */ |
||||
int16_t *fsk_tx_buffer; /* tx buffer for one data block */ |
||||
int fsk_tx_buffer_size; /* size of tx buffer (in samples) */ |
||||
int fsk_tx_buffer_length; /* usage of buffer (in samples) */ |
||||
int fsk_tx_buffer_pos; /* current position sending buffer */ |
||||
double fsk_tx_phase; /* current bit position */ |
||||
char fsk_tx_last_bit; /* save last bit of frame (for next frame's ramp) */ |
||||
/* high-pass filter to remove DC offset from RX signal */ |
||||
double highpass_factor; /* high pass filter factor */ |
||||
double highpass_x_last; /* last input value */ |
||||
double highpass_y_last; /* last output value */ |
||||
/* rx detection of bits and sync */ |
||||
int16_t fsk_rx_last_sample; /* last sample (for level change detection) */ |
||||
double fsk_rx_elapsed; /* bit duration since last level change */ |
||||
enum fsk_rx_sync fsk_rx_sync; /* sync state */ |
||||
uint16_t fsk_rx_sync_register; /* shift register to detect sync word */ |
||||
/* the dotting buffer stores the elapsed samples, so we can calculate
|
||||
* an average time of zero-crossings during dotting sequence. |
||||
* this buffer wrapps every 256 values */ |
||||
double fsk_rx_dotting_elapsed[256]; /* dotting buffer with elapsed samples since last zero-crossing */ |
||||
uint8_t fsk_rx_dotting_pos; /* position of next value in dotting buffer */ |
||||
int fsk_rx_dotting_life; /* counter to expire when no sync was found after dotting */ |
||||
double fsk_rx_dotting_average; /* last average slope position of dotting sequnece. */ |
||||
/* the ex buffer holds the duration of one bit, and wrapps every
|
||||
* bit. */ |
||||
double fsk_rx_bitcount; /* counts the bit. if it reaches or exceeds 1, the bit is complete and the next bit starts */ |
||||
int16_t *fsk_rx_buffer; /* rx buffer for one bit */ |
||||
int fsk_rx_buffer_length; /* length of rx buffer */ |
||||
int fsk_rx_buffer_pos; /* current position in buffer */ |
||||
/* the rx bufffer received one frame until rx length */ |
||||
char fsk_rx_frame[FSK_MAX_BITS + 1]; /* +1 because 0-termination */ |
||||
int fsk_rx_frame_length; /* length of expected frame */ |
||||
int fsk_rx_frame_count; /* count number of received bit */ |
||||
double fsk_rx_frame_level; /* sum of level of all bits */ |
||||
double fsk_rx_frame_quality; /* sum of quality of all bits */ |
||||
/* RECC frame states */ |
||||
int rx_recc_word_count; /* counts received words */ |
||||
uint32_t rx_recc_min1; /* mobile id */ |
||||
uint16_t rx_recc_min2; |
||||
uint8_t rx_recc_msg_type; /* message (3 values) */ |
||||
uint8_t rx_recc_ordq; |
||||
uint8_t rx_recc_order; |
||||
uint32_t rx_recc_esn; |
||||
uint32_t rx_recc_scm; |
||||
char rx_recc_dialing[33]; /* received dial string */ |
||||
/* FOCC frame states */ |
||||
int rx_focc_word_count; /* counts received words */ |
||||
int tx_focc_frame_count; /* used to schedule system informations */ |
||||
int tx_focc_send; /* if set, send message words */ |
||||
uint32_t tx_focc_min1; /* mobile id */ |
||||
uint16_t tx_focc_min2; |
||||
int tx_focc_chan; /* channel to assign for voice call */ |
||||
uint8_t tx_focc_msg_type; /* message (3 values) */ |
||||
uint8_t tx_focc_ordq; |
||||
uint8_t tx_focc_order; |
||||
int tx_focc_word_count; /* counts transmitted words in a muli word message */ |
||||
int tx_focc_word_repeat; /* countrs repeats of mulit word message */ |
||||
/* FVC frame states */ |
||||
int tx_fvc_send; /* if set, send message words */ |
||||
int tx_fvc_chan; /* channel to assign for voice call */ |
||||
uint8_t tx_fvc_msg_type; /* message (3 values) */ |
||||
uint8_t tx_fvc_ordq; |
||||
uint8_t tx_fvc_order; |
||||
/* SAT tone */ |
||||
int sat; /* use SAT tone 0..2 */ |
||||
int sat_samples; /* number of samples in buffer for supervisory detection */ |
||||
int sat_coeff[5]; /* coefficient for SAT signal decoding */ |
||||
int16_t *sat_filter_spl; /* array with sample buffer for supervisory detection */ |
||||
int sat_filter_pos; /* current sample position in filter_spl */ |
||||
double sat_phaseshift256[3]; /* how much the phase of sine wave changes per sample */ |
||||
double sat_phase256; /* current phase */ |
||||
int sat_detected; /* current detection state flag */ |
||||
int sat_detect_count; /* current number of consecutive detections/losses */ |
||||
int sig_detected; /* current detection state flag */ |
||||
int sig_detect_count; /* current number of consecutive detections/losses */ |
||||
|
||||
transaction_t *trans_list; /* list of transactions */ |
||||
} amps_t; |
||||
|
||||
void amps_channel_list(void); |
||||
int amps_channel_by_short_name(const char *short_name); |
||||
const char *chan_type_short_name(enum amps_chan_type chan_type); |
||||
const char *chan_type_long_name(enum amps_chan_type chan_type); |
||||
double amps_channel2freq(int channel, int uplink); |
||||
enum amps_chan_type amps_channel2type(int channel); |
||||
char amps_channel2band(int channel); |
||||
const char *amps_min22number(uint16_t min2); |
||||
const char *amps_min12number(uint32_t min1); |
||||
void amps_number2min(const char *number, uint32_t *min1, uint16_t *min2); |
||||
const char *amps_min2number(uint32_t min1, uint16_t min2); |
||||
const char *amps_scm(uint8_t scm); |
||||
int amps_create(int channel, enum amps_chan_type chan_type, const char *sounddev, int samplerate, int cross_channels, double rx_gain, int pre_emphasis, int de_emphasis, const char *write_wave, const char *read_wave, amps_si *si, uint16_t sid, uint8_t sat, int polarity, int loopback); |
||||
void amps_destroy(sender_t *sender); |
||||
void amps_rx_signalling_tone(amps_t *amps, int tone, double quality); |
||||
void amps_rx_sat(amps_t *amps, int tone, double quality); |
||||
void amps_rx_recc(amps_t *amps, uint8_t scm, uint32_t esn, uint32_t min1, uint16_t min2, uint8_t msg_type, uint8_t ordq, uint8_t order, const char *dialing); |
||||
transaction_t *amps_tx_frame_focc(amps_t *amps); |
||||
transaction_t *amps_tx_frame_fvc(amps_t *amps); |
||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,3 @@ |
||||
|
||||
void init_congestion(void); |
||||
|
@ -0,0 +1,866 @@ |
||||
/* AMPS audio processing
|
||||
* |
||||
* (C) 2016 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/>.
|
||||
*/ |
||||
|
||||
/* How does FSK decoding work:
|
||||
* --------------------------- |
||||
* |
||||
* AMPS modulates the carrier frequency. If it is 8 kHz above, it is high level, |
||||
* if it is 8 kHz below, it is low level. The bits are coded using Manchester |
||||
* code. A 1 is coded by low level, followed by a hight level. A 0 is coded by |
||||
* a high level, followed by a low level. This will cause at least one level |
||||
* change within each bit. Also the level changes between equal bits, see |
||||
* Manchester coding. The bit rate is 10 KHz. |
||||
* |
||||
* In order to detect and demodulate a frame, the dotting sequnce is searched. |
||||
* The dotting sequnece are alternate bits: 101010101... The duration of a |
||||
* level change within the dotting sequnene ist 100uS. If all offsets of 8 |
||||
* level changes lay within +-50% of the expected time, the dotting sequence is |
||||
* valid. Now the next 12 bits will be searched for sync sequnece. If better |
||||
* dotting-offsets are found, the counter for searching the sync sequence is |
||||
* reset, so the next 12 bits will be searched for sync too. If no sync was |
||||
* detected, the state changes to search for next dotting sequence. |
||||
* |
||||
* The average level change offsets of the dotting sequence is used to set the |
||||
* window for the first bit. When all samples for the window are received, a |
||||
* raise in level is detected as 1, fall in level is detected as 0. This is done |
||||
* by substracting the average sample value of the left side of the window by |
||||
* the average sample value of the right side. After the bit has been detected, |
||||
* the samples for the next window will be received and detected. |
||||
* |
||||
* As soon as a sync pattern is detected, the polarity of the pattern is used |
||||
* to decode the following frame bits with correct polarity. During reception |
||||
* of the frame bits, no sync and no dotting sequnece is searched or detected. |
||||
* |
||||
* After reception of the bit, the bits are re-assembled, parity checked and |
||||
* decoded. Then the process hunts for next dotting sequence.
|
||||
*/ |
||||
|
||||
#include <stdio.h> |
||||
#include <stdint.h> |
||||
#include <stdlib.h> |
||||
#include <string.h> |
||||
#include <errno.h> |
||||
#include <math.h> |
||||
#include "../common/debug.h" |
||||
#include "../common/timer.h" |
||||
#include "../common/call.h" |
||||
#include "../common/goertzel.h" |
||||
#include "amps.h" |
||||
#include "frame.h" |
||||
#include "dsp.h" |
||||
|
||||
/* uncomment this to debug the encoding process */ |
||||
//#define DEBUG_ENCODER
|
||||
|
||||
/* uncomment this to debug the decoding process */ |
||||
//#define DEBUG_DECODER
|
||||
|
||||
#define PI M_PI |
||||
|
||||
#define FSK_DEVIATION 32767.0 /* +-8 KHz */ |
||||
#define SAT_DEVIATION 8192.0 /* +-2 KHz */ |
||||
#define TX_AUDIO_0dBm0 45000 /* works quite well */ |
||||
#define BITRATE 10000 |
||||
#define SIG_TONE_CROSSINGS 2000 /* 2000 crossings are 100ms @ 10 KHz */ |
||||
#define SIG_TONE_MINBITS 950 /* minimum bit durations to detect signalling tone (1000 is perfect for 100 ms) */ |
||||
#define SIG_TONE_MAXBITS 1050 /* as above, maximum bits */ |
||||
#define SAT_DURATION 0.100 /* duration of SAT signal measurement */ |
||||
#define SAT_QUALITY 0.85 /* quality needed to detect sat */ |
||||
#define SAT_DETECT_COUNT 3 /* number of measures to detect SAT signal */ |
||||
#define SAT_LOST_COUNT 3 /* number of measures to loose SAT signal */ |
||||
#define SIG_DETECT_COUNT 3 /* number of measures to detect Signalling Tone */ |
||||
#define SIG_LOST_COUNT 2 /* number of measures to loose Signalling Tone */ |
||||
#define CUT_OFF_HIGHPASS 300.0 /* cut off frequency for high pass filter to remove dc level from sound card / sample */ |
||||
#define BEST_QUALITY 0.68 /* Best possible RX quality */ |
||||
|
||||
static int16_t ramp_up[256], ramp_down[256]; |
||||
|
||||
static double sat_freq[5] = { |
||||
5970.0, |
||||
6000.0, |
||||
6030.0, |
||||
5800.0, /* noise level to check against */ |
||||
10000.0, /* signalling tone */ |
||||
}; |
||||
|
||||
static int dsp_sine_sat[256]; |
||||
|
||||
/* global init for FSK */ |
||||
void dsp_init(void) |
||||
{ |
||||
int i; |
||||
double s; |
||||
|
||||
PDEBUG(DDSP, DEBUG_DEBUG, "Generating sine table for SAT signal.\n"); |
||||
for (i = 0; i < 256; i++) { |
||||
s = sin((double)i / 256.0 * 2.0 * PI); |
||||
dsp_sine_sat[i] = (int)(s * SAT_DEVIATION); |
||||
} |
||||
} |
||||
|
||||
static void dsp_init_ramp(amps_t *amps) |
||||
{ |
||||
double c; |
||||
int i; |
||||
|
||||
PDEBUG(DDSP, DEBUG_DEBUG, "Generating smooth ramp table.\n"); |
||||
for (i = 0; i < 256; i++) { |
||||
c = cos((double)i / 256.0 * PI); |
||||
#if 0 |
||||
if (c < 0) |
||||
c = -sqrt(-c); |
||||
else |
||||
c = sqrt(c); |
||||
#endif |
||||
ramp_down[i] = (int)(c * (double)amps->fsk_deviation); |
||||
ramp_up[i] = -ramp_down[i]; |
||||
} |
||||
} |
||||
|
||||
static void sat_reset(amps_t *amps, const char *reason); |
||||
|
||||
/* Init FSK of transceiver */ |
||||
int dsp_init_sender(amps_t *amps, int high_pass) |
||||
{ |
||||
double coeff; |
||||
int16_t *spl; |
||||
int i; |
||||
int rc; |
||||
double RC, dt; |
||||
|
||||
/* attack (3ms) and recovery time (13.5ms) according to amps specs */ |
||||
init_compander(&s->cstate, 8000, 3.0, 13.5, TX_AUDIO_0dBm0); |
||||
|
||||
PDEBUG(DDSP, DEBUG_DEBUG, "Init DSP for transceiver.\n"); |
||||
|
||||
if (amps->sender.samplerate < 96000) { |
||||
PDEBUG(DDSP, DEBUG_ERROR, "Sample rate must be at least 96000 Hz to process FSK and SAT signals.\n"); |
||||
return -EINVAL; |
||||
} |
||||
|
||||
amps->fsk_bitduration = (double)amps->sender.samplerate / (double)BITRATE; |
||||
amps->fsk_bitstep = 1.0 / amps->fsk_bitduration; |
||||
PDEBUG(DDSP, DEBUG_DEBUG, "Use %.4f samples for full bit duration @ %d.\n", amps->fsk_bitduration, amps->sender.samplerate); |
||||
|
||||
amps->fsk_tx_buffer_size = amps->fsk_bitduration * (double)FSK_MAX_BITS + 10; /* 10 extra to avoid overflow due to routing */ |
||||
amps->fsk_tx_buffer = calloc(sizeof(int16_t), amps->fsk_tx_buffer_size); |
||||
if (!amps->fsk_tx_buffer) { |
||||
PDEBUG(DDSP, DEBUG_DEBUG, "No memory!\n"); |
||||
rc = -ENOMEM; |
||||
goto error; |
||||
} |
||||
|
||||
amps->fsk_rx_buffer_length = ceil(amps->fsk_bitduration); /* buffer holds one bit (rounded up) */ |
||||
amps->fsk_rx_buffer = calloc(sizeof(int16_t), amps->fsk_rx_buffer_length); |
||||
if (!amps->fsk_rx_buffer) { |
||||
PDEBUG(DDSP, DEBUG_DEBUG, "No memory!\n"); |
||||
rc = -ENOMEM; |
||||
goto error; |
||||
} |
||||
|
||||
/* create devation and ramp */ |
||||
amps->fsk_deviation = FSK_DEVIATION; /* be sure not to overflow 32767 */ |
||||
dsp_init_ramp(amps); |
||||
|
||||
/* allocate ring buffer for SAT signal detection */ |
||||
amps->sat_samples = (int)((double)amps->sender.samplerate * SAT_DURATION + 0.5); |
||||
spl = calloc(1, amps->sat_samples * sizeof(*spl)); |
||||
if (!spl) { |
||||
PDEBUG(DDSP, DEBUG_ERROR, "No memory!\n"); |
||||
return -ENOMEM; |
||||
} |
||||
amps->sat_filter_spl = spl; |
||||
|
||||
/* count SAT tones */ |
||||
for (i = 0; i < 5; i++) { |
||||
coeff = 2.0 * cos(2.0 * PI * sat_freq[i] / (double)amps->sender.samplerate); |
||||
amps->sat_coeff[i] = coeff * 32768.0; |
||||
PDEBUG(DDSP, DEBUG_DEBUG, "sat_coeff[%d] = %d\n", i, (int)amps->sat_coeff[i]); |
||||
|
||||
if (i < 3) { |
||||
amps->sat_phaseshift256[i] = 256.0 / ((double)amps->sender.samplerate / sat_freq[i]); |
||||
PDEBUG(DDSP, DEBUG_DEBUG, "sat_phaseshift256[%d] = %.4f\n", i, amps->sat_phaseshift256[i]); |
||||
} |
||||
} |
||||
sat_reset(amps, "Initial state"); |
||||
|
||||
/* use this filter to remove dc level for 0-crossing detection
|
||||
* if we have de-emphasis, we don't need it, so high_pass is not set. */ |
||||
if (high_pass) { |
||||
RC = 1.0 / (CUT_OFF_HIGHPASS * 2.0 *3.14); |
||||
dt = 1.0 / amps->sender.samplerate; |
||||
amps->highpass_factor = RC / (RC + dt); |
||||
} |
||||
|
||||
return 0; |
||||
|
||||
error: |
||||
dsp_cleanup_sender(amps); |
||||
|
||||
return rc; |
||||
} |
||||
|
||||
/* Cleanup transceiver instance. */ |
||||
void dsp_cleanup_sender(amps_t *amps) |
||||
{ |
||||
PDEBUG(DDSP, DEBUG_DEBUG, "Cleanup DSP for treansceiver.\n"); |
||||
|
||||
if (amps->fsk_tx_buffer) |
||||
free(amps->fsk_tx_buffer); |
||||
if (amps->fsk_rx_buffer) |
||||
free(amps->fsk_rx_buffer); |
||||
if (amps->sat_filter_spl) { |
||||
free(amps->sat_filter_spl); |
||||
amps->sat_filter_spl = NULL; |
||||
} |
||||
#if 0 |
||||
if (amps->frame_spl) { |
||||
free(amps->frame_spl); |
||||
amps->frame_spl = NULL; |
||||
} |
||||
#endif |
||||
} |
||||
|
||||
static int fsk_encode(amps_t *amps, const char *bits) |
||||
{ |
||||
int16_t *spl; |
||||
double phase, bitstep, deviation; |
||||
int count; |
||||
char last; |
||||
|
||||
if (strlen(bits) > FSK_MAX_BITS) { |
||||
fprintf(stderr, "FSK buffer too small\n"); |
||||
abort(); |
||||
} |
||||
|
||||
deviation = amps->fsk_deviation; |
||||
spl = amps->fsk_tx_buffer; |
||||
phase = amps->fsk_tx_phase; |
||||
last = amps->fsk_tx_last_bit; |
||||
bitstep = amps->fsk_bitstep * 256.0 * 2.0; /* half bit ramp */ |
||||
|
||||
//printf("%s\n", bits);
|
||||
while (*bits) { |
||||
//printf("%d %d\n", (*bits) & 1, last & 1);
|
||||
if (((*bits) & 1)) { |
||||
if ((last & 1)) { |
||||
/* last bit was 1, this bit is 1, so we ramp down first */ |
||||
do { |
||||
*spl++ = ramp_down[(int)phase]; |
||||
phase += bitstep; |
||||
} while (phase < 256.0); |
||||
phase -= 256.0; |
||||
} else { |
||||
/* last bit was 0, this bit is 1, so we stay down first */ |
||||
do { |
||||
*spl++ = -deviation; |
||||
phase += bitstep; |
||||
} while (phase < 256.0); |
||||
phase -= 256.0; |
||||
} |
||||
/* ramp up */ |
||||
do { |
||||
*spl++ = ramp_up[(int)phase]; |
||||
phase += bitstep; |
||||
} while (phase < 256.0); |
||||
phase -= 256.0; |
||||
} else { |
||||
if ((last & 1)) { |
||||
/* last bit was 1, this bit is 0, so we stay up first */ |
||||
do { |
||||
*spl++ = deviation; |
||||
phase += bitstep; |
||||
} while (phase < 256.0); |
||||
phase -= 256.0; |
||||
} else { |
||||
/* last bit was 0, this bit is 0, so we ramp up first */ |
||||
do { |
||||
*spl++ = ramp_up[(int)phase]; |
||||
phase += bitstep; |
||||
} while (phase < 256.0); |
||||
phase -= 256.0; |
||||
} |
||||
/* ramp up */ |
||||
do { |
||||
*spl++ = ramp_down[(int)phase]; |
||||
phase += bitstep; |
||||
} while (phase < 256.0); |
||||
phase -= 256.0; |
||||
} |
||||
last = *bits; |
||||
bits++; |
||||
} |
||||
|
||||
/* depending on the number of samples, return the number */ |
||||
count = ((uintptr_t)spl - (uintptr_t)amps->fsk_tx_buffer) / sizeof(*spl); |
||||
|
||||
amps->fsk_tx_last_bit = last; |
||||
amps->fsk_tx_phase = phase; |
||||
amps->fsk_tx_buffer_length = count; |
||||
|
||||
return count; |
||||
} |
||||
|
||||
int fsk_frame(amps_t *amps, int16_t *samples, int length) |
||||
{ |
||||
int count = 0, pos, copy, i; |
||||
int16_t *spl; |
||||
const char *bits; |
||||
|
||||
again: |
||||
/* there must be length, otherwise we would skip blocks */ |
||||
if (count == length) |
||||
return count; |
||||
|
||||
pos = amps->fsk_tx_buffer_pos; |
||||
spl = amps->fsk_tx_buffer + pos; |
||||
|
||||
/* start new frame, so we generate one */ |
||||
if (pos == 0) { |
||||
if (amps->dsp_mode == DSP_MODE_AUDIO_RX_FRAME_TX) |
||||
bits = amps_encode_frame_fvc(amps); |
||||
else |
||||
bits = amps_encode_frame_focc(amps); |
||||
if (!bits) |
||||
return 0; |
||||
fsk_encode(amps, bits); |
||||
} |
||||
|
||||
copy = amps->fsk_tx_buffer_length - pos; |
||||
if (length - count < copy) |
||||
copy = length - count; |
||||
//printf("pos=%d length=%d copy=%d\n", pos, length, copy);
|
||||
for (i = 0; i < copy; i++) { |
||||
#ifdef DEBUG_ENCODER |
||||
puts(debug_amplitude((double)(*spl) / 32767.0)); |
||||
#endif |
||||
*samples++ = *spl++; |
||||
} |
||||
pos += copy; |
||||
count += copy; |
||||
if (pos ==amps->fsk_tx_buffer_length) { |
||||
amps->fsk_tx_buffer_pos = 0; |
||||
goto again; |
||||
} |
||||
|
||||
amps->fsk_tx_buffer_pos = pos; |
||||
|
||||
return count; |
||||
} |
||||
|
||||
/* Generate audio stream with SAT signal. Keep phase for next call of function. */ |
||||
static void sat_encode(amps_t *amps, int16_t *samples, int length) |
||||
{ |
||||
double phaseshift, phase; |
||||
int32_t sample; |
||||
int i; |
||||
|
||||
phaseshift = amps->sat_phaseshift256[amps->sat]; |
||||
phase = amps->sat_phase256; |
||||
|
||||
for (i = 0; i < length; i++) { |
||||
sample = *samples; |
||||
sample += dsp_sine_sat[((uint8_t)phase) & 0xff]; |
||||
if (sample > 32767) |
||||
sample = 32767; |
||||
else if (sample < -32767) |
||||
sample = -32767; |
||||
*samples++ = sample; |
||||
phase += phaseshift; |
||||
if (phase >= 256) |
||||
phase -= 256; |
||||
} |
||||
|
||||
amps->sat_phase256 = phase; |
||||
} |
||||
|
||||
/* Provide stream of audio toward radio unit */ |
||||
void sender_send(sender_t *sender, int16_t *samples, int length) |
||||
{ |
||||
amps_t *amps = (amps_t *) sender; |
||||
int count; |
||||
|
||||
again: |
||||
switch (amps->dsp_mode) { |
||||
case DSP_MODE_OFF: |
||||
off: |
||||
/* silence, if transmitter is off */ |
||||
memset(samples, 0, length * sizeof(*samples)); |
||||
break; |
||||
case DSP_MODE_AUDIO_RX_AUDIO_TX: |
||||
audio: |
||||
jitter_load(&s->sender.audio, samples, length); |
||||
/* pre-emphasis */ |
||||
if (amps->pre_emphasis) |
||||
pre_emphasis(&s->estate, samples, length); |
||||
/* encode sat */ |
||||
sat_encode(amps, samples, length); |
||||
break; |
||||
case DSP_MODE_AUDIO_RX_FRAME_TX: |
||||
case DSP_MODE_FRAME_RX_FRAME_TX: |
||||
/* Encode frame into audio stream. If frames have
|
||||
* stopped, process again for rest of stream. */ |
||||
count = fsk_frame(amps, samples, length); |
||||
#if 0 |
||||
/* special case: add SAT signal to frame at loop test */ |
||||
if (amps->sender.loopback) |
||||
sat_encode(amps, samples, length); |
||||
#endif |
||||
/* count == 0: no frame, this should not happen */ |
||||
if (count == 0) |
||||
goto off; |
||||
/* * also if the mode changed to audio during processing */ |
||||
if (amps->dsp_mode == DSP_MODE_AUDIO_RX_AUDIO_TX) |
||||
goto audio; |
||||
samples += count; |
||||
length -= count; |
||||
goto again; |
||||
break; |
||||
} |
||||
} |
||||
|
||||
void fsk_rx_bit(amps_t *amps, int16_t *spl, int len, int pos) |
||||
{ |
||||
int i, ii; |
||||
int32_t first, second; |
||||
int bit; |
||||
int32_t max = -32768, min = 32767; |
||||
|
||||
/* decode one bit. substact the first half from the second half.
|
||||
* the result shows the direction of the bit change: 1 == positive. |
||||
*/ |
||||
ii = len >> 1; |
||||
second = first = 0; |
||||
for (i = 0; i < ii; i++) { |
||||
if (--pos < 0) |
||||
pos = len - 1; |
||||
//printf("second %d: %d\n", pos, spl[pos]);
|
||||
second += spl[pos]; |
||||
if (spl[pos] > max) |
||||
max = spl[pos]; |
||||
if (spl[pos] < min) |
||||
min = spl[pos]; |
||||
} |
||||
second /= ii; |
||||
for (i = 0; i < ii; i++) { |
||||
if (--pos < 0) |
||||
pos = len - 1; |
||||
//printf("first %d: %d\n", pos, spl[pos]);
|
||||
first += spl[pos]; |
||||
if (spl[pos] > max) |
||||
max = spl[pos]; |
||||
if (spl[pos] < min) |
||||
min = spl[pos]; |
||||
} |
||||
first /= ii; |
||||
//printf("first = %d second = %d\n", first, second);
|
||||
/* get bit */ |
||||
if (second > first) |
||||
bit = 1; |
||||
else |
||||
bit = 0; |
||||
#ifdef DEBUG_DECODER |
||||
if (amps->fsk_rx_sync != FSK_SYNC_POSITIVE && amps->fsk_rx_sync != FSK_SYNC_NEGATIVE) |
||||
printf("Decoded bit as %d (dotting life = %d)\n", bit, amps->fsk_rx_dotting_life); |
||||
else |
||||
printf("Decoded bit as %d\n", bit); |
||||
#endif |
||||
|
||||
if (amps->fsk_rx_sync != FSK_SYNC_POSITIVE && amps->fsk_rx_sync != FSK_SYNC_NEGATIVE) { |
||||
amps->fsk_rx_sync_register = (amps->fsk_rx_sync_register << 1) | bit; |
||||
/* check if we received a sync */ |
||||
if ((amps->fsk_rx_sync_register & 0x7ff) == 0x712) { |
||||
#ifdef DEBUG_DECODER |
||||
printf("Sync word detected (positive)\n"); |
||||
#endif |
||||
amps->fsk_rx_sync = FSK_SYNC_POSITIVE; |
||||
prepare_frame: |
||||
amps->fsk_rx_frame_count = 0; |
||||
amps->fsk_rx_frame_quality = 0.0; |
||||
amps->fsk_rx_frame_level = 0.0; |
||||
amps->fsk_rx_sync_register = 0x555; |
||||
return; |
||||
} |
||||
if ((amps->fsk_rx_sync_register & 0x7ff) == 0x0ed) { |
||||
#ifdef DEBUG_DECODER |
||||
printf("Sync word detected (negative)\n"); |
||||
#endif |
||||
amps->fsk_rx_sync = FSK_SYNC_NEGATIVE; |
||||
goto prepare_frame; |
||||
return; |
||||
} |
||||
/* if no sync, count down the dotting life counter */ |
||||
if (--amps->fsk_rx_dotting_life == 0) { |
||||
#ifdef DEBUG_DECODER |
||||
printf("No Sync detected after dotting\n"); |
||||
#endif |
||||
amps->fsk_rx_sync = FSK_SYNC_NONE; |
||||
return; |
||||
} |
||||
return; |
||||
} |
||||
|
||||
/* count level and quality */ |
||||
amps->fsk_rx_frame_level += (double)(max - min) / (double)FSK_DEVIATION / 2.0; |
||||
if (bit) |
||||
amps->fsk_rx_frame_quality += (double)(second - first) / (double)FSK_DEVIATION / 2.0 / BEST_QUALITY; |
||||
else |
||||
amps->fsk_rx_frame_quality += (double)(first - second) / (double)FSK_DEVIATION / 2.0 / BEST_QUALITY; |
||||
|
||||
/* invert bit if negative sync was detected */ |
||||
if (amps->fsk_rx_sync == FSK_SYNC_NEGATIVE) |
||||
bit = 1 - bit; |
||||
|
||||
/* read next bit. after all bits, we reset to FSK_SYNC_NONE */ |
||||
amps->fsk_rx_frame[amps->fsk_rx_frame_count++] = bit + '0'; |
||||
if (amps->fsk_rx_frame_count > FSK_MAX_BITS) { |
||||
fprintf(stderr, "our fsk_tx_count (%d) is larger than our max bits we can handle, please fix!\n", amps->fsk_rx_frame_count); |
||||
abort(); |
||||
} |
||||
if (amps->fsk_rx_frame_count == amps->fsk_rx_frame_length) { |
||||
int more; |
||||
|
||||
/* a complete frame was received, so we process it */ |
||||
amps->fsk_rx_frame[amps->fsk_rx_frame_count] = '\0'; |
||||
more = amps_decode_frame(amps, amps->fsk_rx_frame, amps->fsk_rx_frame_count, amps->fsk_rx_frame_level / (double)amps->fsk_rx_frame_count, amps->fsk_rx_frame_quality / amps->fsk_rx_frame_level, (amps->fsk_rx_sync == FSK_SYNC_NEGATIVE)); |
||||
if (more) { |
||||
/* switch to next worda length without DCC included */ |
||||
amps->fsk_rx_frame_length = 240; |
||||
goto prepare_frame; |
||||
} else { |
||||
/* switch back to first word length with DCC included */ |
||||
if (amps->fsk_rx_frame_length == 240) |
||||
amps->fsk_rx_frame_length = 247; |
||||
amps->fsk_rx_sync = FSK_SYNC_NONE; |
||||
} |
||||
} |
||||
} |
||||
|
||||
void fsk_rx_dotting(amps_t *amps, double _elapsed, int dir) |
||||
{ |
||||
uint8_t pos = amps->fsk_rx_dotting_pos++; |
||||
double average, elapsed, offset; |
||||
int i; |
||||
|
||||
#ifdef DEBUG_DECODER |
||||
printf("Level change detected\n"); |
||||
#endif |
||||
/* store into dotting list */ |
||||
amps->fsk_rx_dotting_elapsed[pos++] = _elapsed; |
||||
|
||||
/* check quality of dotting sequence.
|
||||
* in case this is not a dotting sequence, noise or speech, the quality |
||||
* should be bad. |
||||
* count (only) 7 'elapsed' values between 8 zero-crossings. |
||||
* calculate the average relative to the current position. |
||||
*/ |
||||
average = 0.0; |
||||
elapsed = 0.0; |
||||
for (i = 1; i < 8; i++) { |
||||
elapsed += amps->fsk_rx_dotting_elapsed[--pos]; |
||||
offset = elapsed - (double)i; |
||||
if (offset >= 0.5 || offset <= -0.5) { |
||||
#ifdef DEBUG_DECODER |
||||
// printf("offset %.3f (last but %d) not within -0.5 .. 0.5 bit position, detecting no dotting.\n", offset, i - 1);
|
||||
#endif |
||||
return; |
||||
} |
||||
average += offset; |
||||
} |
||||
average /= (double)i; |
||||
|
||||
amps->fsk_rx_dotting_life = 12; |
||||
|
||||
/* if we are already found dotting, we detect better dotting.
|
||||
* this happens, if dotting was falsely detected due to noise. |
||||
* then the real dotting causes a reastart of hunting for sync sequence. |
||||
*/ |
||||
if (amps->fsk_rx_sync == FSK_SYNC_NONE || fabs(average) < amps->fsk_rx_dotting_average) { |
||||
#ifdef DEBUG_DECODER |
||||
printf("Found (better) dotting sequence (average = %.3f)\n", average); |
||||
#endif |
||||
amps->fsk_rx_sync = FSK_SYNC_DOTTING; |
||||
amps->fsk_rx_dotting_average = fabs(average); |
||||
amps->fsk_rx_bitcount = 0.5 + average; |
||||
} |
||||
} |
||||
|
||||
/* decode frame */ |
||||
void sender_receive_frame(amps_t *amps, int16_t *samples, int length) |
||||
{ |
||||
int16_t *spl, last_sample; |
||||
int len, pos; |
||||
double bitstep, elapsed; |
||||
int i; |
||||
|
||||
bitstep = amps->fsk_bitstep; |
||||
spl = amps->fsk_rx_buffer; |
||||
pos = amps->fsk_rx_buffer_pos; |
||||
len = amps->fsk_rx_buffer_length; |
||||
last_sample = amps->fsk_rx_last_sample; |
||||
elapsed = amps->fsk_rx_elapsed; |
||||
|
||||
for (i = 0; i < length; i++) { |
||||
#ifdef DEBUG_DECODER |
||||
puts(debug_amplitude((double)samples[i] / (double)FSK_DEVIATION)); |
||||
#endif |
||||
/* push sample to detection window and shift */ |
||||
spl[pos++] = samples[i]; |
||||
if (pos == len) |
||||
pos = 0; |
||||
if (amps->fsk_rx_sync != FSK_SYNC_POSITIVE && amps->fsk_rx_sync != FSK_SYNC_NEGATIVE) { |
||||
/* check for change in polarity */ |
||||
if (last_sample <= 0) { |
||||
if (samples[i] > 0) { |
||||
fsk_rx_dotting(amps, elapsed, 1); |
||||
elapsed = 0.0; |
||||
} |
||||
} else { |
||||
if (samples[i] <= 0) { |
||||
fsk_rx_dotting(amps, elapsed, 0); |
||||
elapsed = 0.0; |
||||
} |
||||
} |
||||
} |
||||
last_sample = samples[i]; |
||||
elapsed += bitstep; |
||||
// printf("%.4f\n", bitcount);
|
||||
if (amps->fsk_rx_sync != FSK_SYNC_NONE) { |
||||
amps->fsk_rx_bitcount += bitstep; |
||||
if (amps->fsk_rx_bitcount >= 1.0) { |
||||
amps->fsk_rx_bitcount -= 1.0; |
||||
fsk_rx_bit(amps, spl, len, pos); |
||||
} |
||||
} |
||||
} |
||||
|
||||
amps->fsk_rx_last_sample = last_sample; |
||||
amps->fsk_rx_elapsed = elapsed; |
||||
amps->fsk_rx_buffer_pos = pos; |
||||
} |
||||
|
||||
|
||||
/* decode signalling tone */ |
||||
/* compare supervisory signal against noise floor on 5800 Hz */ |
||||
static void sat_decode(amps_t *amps, int16_t *samples, int length) |
||||
{ |
||||
int coeff[3]; |
||||
double result[3], quality[2]; |
||||
|
||||
coeff[0] = amps->sat_coeff[amps->sat]; |
||||
coeff[1] = amps->sat_coeff[3]; /* noise floor detection */ |
||||
coeff[2] = amps->sat_coeff[4]; /* signalling tone */ |
||||
audio_goertzel(samples, length, 0, coeff, result, 3); |
||||
|
||||
quality[0] = (result[0] - result[1]) / result[0]; |
||||
if (quality[0] < 0) |
||||
quality[0] = 0; |
||||
quality[1] = (result[2] - result[1]) / result[2]; |
||||
if (quality[1] < 0) |
||||
quality[1] = 0; |
||||
|
||||
PDEBUG(DDSP, DEBUG_NOTICE, "SAT level %.2f%% quality %.0f%%\n", result[0] * 32767.0 / SAT_DEVIATION / 0.63662 * 100.0, quality[0] * 100.0); |
||||
if (amps->sender.loopback || debuglevel == DEBUG_DEBUG) { |
||||
PDEBUG(DDSP, debuglevel, "Signalling Tone level %.2f%% quality %.0f%%\n", result[2] * 32767.0 / FSK_DEVIATION / 0.63662 * 100.0, quality[1] * 100.0); |
||||
} |
||||
if (quality[0] > SAT_QUALITY) { |
||||
if (amps->sat_detected == 0) { |
||||
amps->sat_detect_count++; |
||||
if (amps->sat_detect_count == SAT_DETECT_COUNT) { |
||||
amps->sat_detected = 1; |
||||
amps->sat_detect_count = 0; |
||||
PDEBUG(DDSP, DEBUG_DEBUG, "SAT signal detected with level=%.0f%%, quality=%.0f%%.\n", result[0] / 0.63662 * 100.0, quality[0] * 100.0); |
||||
amps_rx_sat(amps, 1, quality[0]); |
||||
} |
||||
} else |
||||
amps->sat_detect_count = 0; |
||||
} else { |
||||
if (amps->sat_detected == 1) { |
||||
amps->sat_detect_count++; |
||||
if (amps->sat_detect_count == SAT_LOST_COUNT) { |
||||
amps->sat_detected = 0; |
||||
amps->sat_detect_count = 0; |
||||
PDEBUG(DDSP, DEBUG_DEBUG, "SAT signal lost.\n"); |
||||
amps_rx_sat(amps, 0, 0.0); |
||||
} |
||||
} else |
||||
amps->sat_detect_count = 0; |
||||
} |
||||
if (quality[1] > 0.8) { |
||||
if (amps->sig_detected == 0) { |
||||
amps->sig_detect_count++; |
||||
if (amps->sig_detect_count == SIG_DETECT_COUNT) { |
||||
amps->sig_detected = 1; |
||||
amps->sig_detect_count = 0; |
||||
PDEBUG(DDSP, DEBUG_DEBUG, "Signalling Tone detected with level=%.0f%%, quality=%.0f%%.\n", result[2] / 0.63662 * 100.0, quality[1] * 100.0); |
||||
amps_rx_signalling_tone(amps, 1, quality[1]); |
||||
} |
||||
} else |
||||
amps->sig_detect_count = 0; |
||||
} else { |
||||
if (amps->sig_detected == 1) { |
||||
amps->sig_detect_count++; |
||||
if (amps->sig_detect_count == SIG_LOST_COUNT) { |
||||
amps->sig_detected = 0; |
||||
amps->sig_detect_count = 0; |
||||
PDEBUG(DDSP, DEBUG_DEBUG, "Signalling Tone lost.\n"); |
||||
amps_rx_signalling_tone(amps, 0, 0.0); |
||||
} |
||||
} else |
||||
amps->sig_detect_count = 0; |
||||
} |
||||
} |
||||
|
||||
/* decode signalling/audio */ |
||||
/* Count SIG_TONE_CROSSINGS of zero crossings, then check if the elapsed bit
|
||||
* time is between SIG_TONE_MINBITS and SIG_TONE_MAXBITS. If it is, the |
||||
* frequency is close to the singalling tone, so it is detected |
||||
*/ |
||||
void sender_receive_audio(amps_t *amps, int16_t *samples, int length) |
||||
{ |
||||
transaction_t *trans = amps->trans_list; |
||||
int16_t *spl; |
||||
int max, pos; |
||||
int i; |
||||
|
||||
/* SAT detection */ |
||||
|
||||
max = amps->sat_samples; |
||||
spl = amps->sat_filter_spl; |
||||
pos = amps->sat_filter_pos; |
||||
for (i = 0; i < length; i++) { |
||||
spl[pos++] = samples[i]; |
||||
if (pos == max) { |
||||
pos = 0; |
||||
sat_decode(amps, spl, max); |
||||
} |
||||
} |
||||
amps->sat_filter_pos = pos; |
||||
|
||||
/* receive audio, but only if call established and SAT detected */ |
||||
|
||||
if ((amps->dsp_mode == DSP_MODE_AUDIO_RX_AUDIO_TX || amps->dsp_mode == DSP_MODE_AUDIO_RX_FRAME_TX) |
||||
&& amps->sender.callref && trans && trans->sat_detected) { |
||||
int16_t down[length]; /* more than enough */ |
||||
int pos, count; |
||||
int16_t *spl; |
||||
int i; |
||||
|
||||
/* de-emphasis */ |
||||
if (amps->de_emphasis) |
||||
de_emphasis(&s->estate, samples, length); |
||||
/* downsample */ |
||||
count = samplerate_downsample(&s->sender.srstate, samples, length, down); |
||||
expand_audio(&s->cstate, down, count); |
||||
spl = amps->sender.rxbuf; |
||||
pos = amps->sender.rxbuf_pos; |
||||
for (i = 0; i < count; i++) { |
||||
spl[pos++] = down[i]; |
||||
if (pos == 160) { |
||||
call_tx_audio(amps->sender.callref, spl, 160); |
||||
pos = 0; |
||||
} |
||||
} |
||||
amps->sender.rxbuf_pos = pos; |
||||
} else |
||||
amps->sender.rxbuf_pos = 0; |
||||
} |
||||
|
||||
/* Process received audio stream from radio unit. */ |
||||
void sender_receive(sender_t *sender, int16_t *samples, int length) |
||||
{ |
||||
amps_t *amps = (amps_t *) sender; |
||||
double x, y, x_last, y_last, factor; |
||||
int32_t value; |
||||
int i; |
||||
|
||||
/* high pass filter to remove 0-level
|
||||
* if factor is not set, we should already have 0-level. */ |
||||
factor = amps->highpass_factor; |
||||
if (factor) { |
||||
x_last = amps->highpass_x_last; |
||||
y_last = amps->highpass_y_last; |
||||
for (i = 0; i < length; i++) { |
||||
x = (double)samples[i]; |
||||
y = factor * (y_last + x - x_last); |
||||
x_last = x; |
||||
y_last = y; |
||||
value = (int32_t)(y + 0.5); |
||||
if (value < -32768.0) |
||||
value = -32768.0; |
||||
else if (value > 32767) |
||||
value = 32767; |
||||
samples[i] = value; |
||||
} |
||||
amps->highpass_x_last = x_last; |
||||
amps->highpass_y_last = y_last; |
||||
} |
||||
|
||||
switch (amps->dsp_mode) { |
||||
case DSP_MODE_OFF: |
||||
break; |
||||
case DSP_MODE_FRAME_RX_FRAME_TX: |
||||
sender_receive_frame(amps, samples, length); |
||||
break; |
||||
case DSP_MODE_AUDIO_RX_AUDIO_TX: |
||||
case DSP_MODE_AUDIO_RX_FRAME_TX: |
||||
sender_receive_audio(amps, samples, length); |
||||
break; |
||||
} |
||||
} |
||||
|
||||
/* Reset SAT detection states, so ongoing tone will be detected again. */ |
||||
static void sat_reset(amps_t *amps, const char *reason) |
||||
{ |
||||
PDEBUG(DDSP, DEBUG_DEBUG, "SAT detector reset: %s.\n", reason); |
||||
amps->sat_detected = 0; |
||||
amps->sat_detect_count = 0; |
||||
amps->sig_detected = 0; |
||||
amps->sig_detect_count = 0; |
||||
} |
||||
|
||||
void amps_set_dsp_mode(amps_t *amps, enum dsp_mode mode, int frame_length) |
||||
{ |
||||
#if 0 |
||||
/* reset telegramm */ |
||||
if (mode == DSP_MODE_FRAME && amps->dsp_mode != mode) |
||||
amps->frame = 0; |
||||
#endif |
||||
if (mode == DSP_MODE_FRAME_RX_FRAME_TX) { |
||||
/* reset SAT detection */ |
||||
sat_reset(amps, "Change to FOCC"); |
||||
} |
||||
if (amps->dsp_mode == DSP_MODE_FRAME_RX_FRAME_TX |
||||
&& (mode == DSP_MODE_AUDIO_RX_AUDIO_TX || mode == DSP_MODE_AUDIO_RX_FRAME_TX)) { |
||||
/* reset SAT detection */ |
||||
sat_reset(amps, "Change from FOCC to FVC"); |
||||
} |
||||
|
||||
amps->dsp_mode = mode; |
||||
if (frame_length) |
||||
amps->fsk_rx_frame_length = frame_length; |
||||
|
||||
/* reset detection process */ |
||||
amps->fsk_rx_sync = FSK_SYNC_NONE; |
||||
amps->fsk_rx_sync_register = 0x555; |
||||
|
||||
/* reset transmitter */ |
||||
amps->fsk_tx_buffer_pos = 0; |
||||
} |
||||
|
@ -0,0 +1,6 @@ |
||||
|
||||
void dsp_init(void); |
||||
int dsp_init_sender(amps_t *amps, int high_pass); |
||||
void dsp_cleanup_sender(amps_t *amps); |
||||
void amps_set_dsp_mode(amps_t *amps, enum dsp_mode mode, int frame_length); |
||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,225 @@ |
||||
|
||||
enum amps_ie { |
||||
AMPS_IE_010111, |
||||
AMPS_IE_1, |
||||
AMPS_IE_11, |
||||
AMPS_IE_1111, |
||||
AMPS_IE_ACT, |
||||
AMPS_IE_AUTH, |
||||
AMPS_IE_AUTHBS, |
||||
AMPS_IE_AUTHR, |
||||
AMPS_IE_AUTHU, |
||||
AMPS_IE_Acked_Data, |
||||
AMPS_IE_Async_Data, |
||||
AMPS_IE_BIS, |
||||
AMPS_IE_BSCAP, |
||||
AMPS_IE_BSPC, |
||||
AMPS_IE_CHAN, |
||||
AMPS_IE_CHANPOS, |
||||
AMPS_IE_CHARACTER_1, |
||||
AMPS_IE_CHARACTER_2, |
||||
AMPS_IE_CHARACTER_3, |
||||
AMPS_IE_CMAC, |
||||
AMPS_IE_CMAX_1, |
||||
AMPS_IE_COUNT, |
||||
AMPS_IE_CPA, |
||||
AMPS_IE_CPN_RL, |
||||
AMPS_IE_CRC, |
||||
AMPS_IE_CRI_E11, |
||||
AMPS_IE_CRI_E12, |
||||
AMPS_IE_CRI_E13, |
||||
AMPS_IE_CRI_E14, |
||||
AMPS_IE_CRI_E21, |
||||
AMPS_IE_CRI_E22, |
||||
AMPS_IE_CRI_E23, |
||||
AMPS_IE_CRI_E24, |
||||
AMPS_IE_CRI_E31, |
||||
AMPS_IE_CRI_E32, |
||||
AMPS_IE_CRI_E33, |
||||
AMPS_IE_CRI_E34, |
||||
AMPS_IE_CRI_E41, |
||||
AMPS_IE_CRI_E42, |
||||
AMPS_IE_CRI_E43, |
||||
AMPS_IE_CRI_E44, |
||||
AMPS_IE_CRI_E51, |
||||
AMPS_IE_CRI_E52, |
||||
AMPS_IE_CRI_E53, |
||||
AMPS_IE_CRI_E54, |
||||
AMPS_IE_CRI_E61, |
||||
AMPS_IE_CRI_E62, |
||||
AMPS_IE_CRI_E63, |
||||
AMPS_IE_CRI_E64, |
||||
AMPS_IE_CRI_E71, |
||||
AMPS_IE_CRI_E72, |
||||
AMPS_IE_CRI_E73, |
||||
AMPS_IE_CRI_E74, |
||||
AMPS_IE_CRI_E81, |
||||
AMPS_IE_CRI_E82, |
||||
AMPS_IE_CRI_E83, |
||||
AMPS_IE_CRI_E84, |
||||
AMPS_IE_DCC, |
||||
AMPS_IE_DIGIT_1, |
||||
AMPS_IE_DIGIT_10, |
||||
AMPS_IE_DIGIT_11, |
||||
AMPS_IE_DIGIT_12, |
||||
AMPS_IE_DIGIT_13, |
||||
AMPS_IE_DIGIT_14, |
||||
AMPS_IE_DIGIT_15, |
||||
AMPS_IE_DIGIT_16, |
||||
AMPS_IE_DIGIT_17, |
||||
AMPS_IE_DIGIT_18, |
||||
AMPS_IE_DIGIT_19, |
||||
AMPS_IE_DIGIT_2, |
||||
AMPS_IE_DIGIT_20, |
||||
AMPS_IE_DIGIT_21, |
||||
AMPS_IE_DIGIT_22, |
||||
AMPS_IE_DIGIT_23, |
||||
AMPS_IE_DIGIT_24, |
||||
AMPS_IE_DIGIT_25, |
||||
AMPS_IE_DIGIT_26, |
||||
AMPS_IE_DIGIT_27, |
||||
AMPS_IE_DIGIT_28, |
||||
AMPS_IE_DIGIT_29, |
||||
AMPS_IE_DIGIT_3, |
||||
AMPS_IE_DIGIT_30, |
||||
AMPS_IE_DIGIT_31, |
||||
AMPS_IE_DIGIT_32, |
||||
AMPS_IE_DIGIT_4, |
||||
AMPS_IE_DIGIT_5, |
||||
AMPS_IE_DIGIT_6, |
||||
AMPS_IE_DIGIT_7, |
||||
AMPS_IE_DIGIT_8, |
||||
AMPS_IE_DIGIT_9, |
||||
AMPS_IE_DMAC, |
||||
AMPS_IE_DTX, |
||||
AMPS_IE_DTX_Support, |
||||
AMPS_IE_DVCC, |
||||
AMPS_IE_Data_Part, |
||||
AMPS_IE_Data_Privacy, |
||||
AMPS_IE_E, |
||||
AMPS_IE_EC, |
||||
AMPS_IE_EF, |
||||
AMPS_IE_END, |
||||
AMPS_IE_EP, |
||||
AMPS_IE_ER, |
||||
AMPS_IE_ESN, |
||||
AMPS_IE_F, |
||||
AMPS_IE_G3_Fax, |
||||
AMPS_IE_HDVCC, |
||||
AMPS_IE_Hyperband, |
||||
AMPS_IE_LOCAID, |
||||
AMPS_IE_LOCAL_CONTROL, |
||||
AMPS_IE_LOCAL_MSG_TYPE, |
||||
AMPS_IE_LREG, |
||||
AMPS_IE_LT, |
||||
AMPS_IE_MAXBUSY_OTHER, |
||||
AMPS_IE_MAXBUSY_PGR, |
||||
AMPS_IE_MAXSZTR_OTHER, |
||||
AMPS_IE_MAXSZTR_PGR, |
||||
AMPS_IE_MEM, |
||||
AMPS_IE_MIN1, |
||||
AMPS_IE_MIN2, |
||||
AMPS_IE_MPCI, |
||||
AMPS_IE_MSCAP, |
||||
AMPS_IE_MSPC, |
||||
AMPS_IE_N_1, |
||||
AMPS_IE_NAWC , |
||||
AMPS_IE_NEWACC, |
||||
AMPS_IE_NULL, |
||||
AMPS_IE_OHD, |
||||
AMPS_IE_OLC_0, |
||||
AMPS_IE_OLC_1, |
||||
AMPS_IE_OLC_10, |
||||
AMPS_IE_OLC_11, |
||||
AMPS_IE_OLC_12, |
||||
AMPS_IE_OLC_13, |
||||
AMPS_IE_OLC_14, |
||||
AMPS_IE_OLC_15, |
||||
AMPS_IE_OLC_2, |
||||
AMPS_IE_OLC_3, |
||||
AMPS_IE_OLC_4, |
||||
AMPS_IE_OLC_5, |
||||
AMPS_IE_OLC_6, |
||||
AMPS_IE_OLC_7, |
||||
AMPS_IE_OLC_8, |
||||
AMPS_IE_OLC_9, |
||||
AMPS_IE_ORDER, |
||||
AMPS_IE_ORDQ, |
||||
AMPS_IE_P, |
||||
AMPS_IE_PCI, |
||||
AMPS_IE_PCI_HOME, |
||||
AMPS_IE_PCI_ROAM, |
||||
AMPS_IE_PDREG, |
||||
AMPS_IE_PI, |
||||
AMPS_IE_PM, |
||||
AMPS_IE_PM_D, |
||||
AMPS_IE_PSCC, |
||||
AMPS_IE_PUREG, |
||||
AMPS_IE_PVI, |
||||
AMPS_IE_RAND1_A, |
||||
AMPS_IE_RAND1_B, |
||||
AMPS_IE_RANDBS, |
||||
AMPS_IE_RANDC, |
||||
AMPS_IE_RANDSSD_1, |
||||
AMPS_IE_RANDSSD_2, |
||||
AMPS_IE_RANDSSD_3, |
||||
AMPS_IE_RANDU, |
||||
AMPS_IE_RCF, |
||||
AMPS_IE_REGH, |
||||
AMPS_IE_REGID, |
||||
AMPS_IE_REGINCR, |
||||
AMPS_IE_REGR, |
||||
AMPS_IE_RLP, |
||||
AMPS_IE_RL_W, |
||||
AMPS_IE_RSVD, |
||||
AMPS_IE_S, |
||||
AMPS_IE_SAP, |
||||
AMPS_IE_SBI, |
||||
AMPS_IE_SCC, |
||||
AMPS_IE_SCM, |
||||
AMPS_IE_SDCC1, |
||||
AMPS_IE_SDCC2, |
||||
AMPS_IE_SI, |
||||
AMPS_IE_SID1, |
||||
AMPS_IE_SIGNAL, |
||||
AMPS_IE_Service_Code, |
||||
AMPS_IE_T, |
||||
AMPS_IE_T1T2, |
||||
AMPS_IE_TA, |
||||
AMPS_IE_TCI1, |
||||
AMPS_IE_TCI21, |
||||
AMPS_IE_TCI22, |
||||
AMPS_IE_TCI23, |
||||
AMPS_IE_TCI24, |
||||
AMPS_IE_TCI31, |
||||
AMPS_IE_TCI32, |
||||
AMPS_IE_TCI33, |
||||
AMPS_IE_TCI34, |
||||
AMPS_IE_TCI41, |
||||
AMPS_IE_TCI42, |
||||
AMPS_IE_TCI43, |
||||
AMPS_IE_TCI44, |
||||
AMPS_IE_TCI5, |
||||
AMPS_IE_VMAC, |
||||
AMPS_IE_WFOM, |
||||
AMPS_IE_NUM |
||||
}; |
||||
|
||||
typedef struct amps_frame { |
||||
enum amps_ie ie[AMPS_IE_NUM]; |
||||
} frame_t; |
||||
|
||||
void init_frame(void); |
||||
uint64_t amps_encode_word1_system(uint8_t dcc, uint16_t sid1, uint8_t ep, uint8_t auth, uint8_t pci, uint8_t nawc); |
||||
uint64_t amps_encode_word2_system(uint8_t dcc, uint8_t s, uint8_t e, uint8_t regh, uint8_t regr, uint8_t dtx, uint8_t n_1, uint8_t rcf, uint8_t cpa, uint8_t cmax_1, uint8_t end); |
||||
uint64_t amps_encode_registration_id(uint8_t dcc, uint32_t regid, uint8_t end); |
||||
uint64_t amps_encode_registration_increment(uint8_t dcc, uint16_t regincr, uint8_t end); |
||||
uint64_t amps_encode_location_area(uint8_t dcc, uint8_t pureg, uint8_t pdreg, uint8_t lreg, uint16_t locaid, uint8_t end); |
||||
uint64_t amps_encode_new_access_channel_set(uint8_t dcc, uint16_t newacc, uint8_t end); |
||||
uint64_t amps_encode_overload_control(uint8_t dcc, uint8_t *olc, uint8_t end); |
||||
uint64_t amps_encode_access_type(uint8_t dcc, uint8_t bis, uint8_t pci_home, uint8_t pci_roam, uint8_t bspc, uint8_t bscap, uint8_t end); |
||||
uint64_t amps_encode_access_attempt(uint8_t dcc, uint8_t maxbusy_pgr, uint8_t maxsztr_pgr, uint8_t maxbusy_other, uint8_t maxsztr_other, uint8_t end); |
||||
const char *amps_encode_frame_focc(amps_t *amps); |
||||
const char *amps_encode_frame_fvc(amps_t *amps); |
||||
int amps_decode_frame(amps_t *amps, const char *bits, int count, double level, double quality, int negative); |
||||
|
@ -0,0 +1,73 @@ |
||||
#include <stdio.h> |
||||
#include <string.h> |
||||
#include "image.h" |
||||
|
||||
const char *image[] = { |
||||
"", |
||||
" @R| |", |
||||
" @Y| @R/|===|\\", |
||||
" @Y-=@wO@Y=- @R/ |\\ /| \\ @w~", |
||||
" @Y| @wAMPS @R/ | X | \\ @w~", |
||||
" @R/ |===| \\", |
||||
" @R/ | |\\ \\", |
||||
" @R/ /| | \\ \\ @w~", |
||||
" @R|--| / / |===| \\ \\", |
||||
" @R/|\\/|\\ / / | | \\ \\", |
||||
" @R/ |--| \\ / / | | \\ \\", |
||||
" @R/ | |\\ \\ / / |===| \\ \\", |
||||
"@g__ @R/ /|--| \\ \\ / / | | \\ \\", |
||||
"@g \\_ @R/ / | | \\ \\ / / | | \\ \\", |
||||
"@g \\ @R/ / | | \\ \\______/ / | | \\| \\|", |
||||
"@g \\@R=========================================================================", |
||||
"@g \\_______@R|/\\|@g______ _@G***@g_@G*@g__@G**@g_@G***@g___@G**@g_@G*@g_@R| X | @R|MMMM|", |
||||
"@g \\__ @R|\\/|@g \\______/@G* ** * * * ** * @R|/ \\|@g______@y________@R|MMMM|", |
||||
"@y _____@g \\_@R|/\\|@G * * * * ** * * * * * * @R|\\ /|@G*@y____/ ~ ~ ~ ~", |
||||
"@y/ ~ ~\\@b_______@RI@b__@RI@b_________@G*@b______@G*@b_@G*@b___@G*@b__@G*@b___@G*@b__@G*@b_@G*@b_@R| X |@y/ ~ ~ _________", |
||||
"@y_______\\@b _ _ _ _ _ _ _ _ _ _ @R|/@y_@R\\@y/ ~ ______/", |
||||
"@b _ _ _ _ _ _ _ @y_/~ ~ ____/ ~ ~ ~", |
||||
"@b_ @y_@b _ _ _ _ _ @y/_____/ ~ ____________", |
||||
"@y__/~\\______________@b _ _ _ _ @y_/ ~ ~ __________/ ~ ~ ~", |
||||
"@y ~ ~ ~ \\____________________________/ / ~ ~ ~ ~ ~", |
||||
"@w", |
||||
NULL |
||||
}; |
||||
|
||||
void print_image(void) |
||||
{ |
||||
int i, j; |
||||
|
||||
for (i = 0; image[i]; i++) { |
||||
for (j = 0; j < strlen(image[i]); j++) { |
||||
if (image[i][j] == '@') { |
||||
j++; |
||||