AMPS: Fixes for multi transceiver support

- Fix channel assignment
- Voice channel sends test tone when idle
- Changed paging timeout
- Minor fix of SCC field in 2 messages
This commit is contained in:
Andreas Eversberg
2016-10-30 09:25:45 +01:00
parent b70f4ecebc
commit 63f39e105b
5 changed files with 121 additions and 41 deletions

View File

@@ -36,8 +36,8 @@
#define SAT_TO1 5.0 /* 5 sec to detect after setup */
#define SAT_TO2 5.0 /* 5 sec lost until abort (specs say 5) */
#define PAGE_TRIES 2 /* how many times to page the phone */
#define PAGE_TO1 5.0 /* max time to wait for paging reply */
#define PAGE_TO2 7.0 /* max time to wait for last paging reply */
#define PAGE_TO1 8.0 /* max time to wait for paging reply */
#define PAGE_TO2 4.0 /* max time to wait for last paging reply */
#define ALERT_TO 60.0 /* max time to wait for answer */
#define RELEASE_TIMER 5.0 /* max time to send release messages */
@@ -297,6 +297,22 @@ const char *chan_type_long_name(enum amps_chan_type chan_type)
return "invalid";
}
static amps_t *search_channel(int channel)
{
sender_t *sender;
amps_t *amps;
for (sender = sender_head; sender; sender = sender->next) {
if (sender->kanal != channel)
continue;
amps = (amps_t *) sender;
if (amps->state == STATE_IDLE)
return amps;
}
return NULL;
}
static amps_t *search_free_vc(void)
{
sender_t *sender;
@@ -306,10 +322,10 @@ static amps_t *search_free_vc(void)
amps = (amps_t *) sender;
if (amps->state != STATE_IDLE)
continue;
/* return first free SpK */
/* return first free voice channel */
if (amps->chan_type == CHAN_TYPE_VC)
return amps;
/* remember OgK/SpK combined channel as second alternative */
/* remember combined voice/control/paging channel as second alternative */
if (amps->chan_type == CHAN_TYPE_CC_PC_VC)
cc_pc_vc = amps;
}
@@ -354,11 +370,17 @@ int amps_create(int channel, enum amps_chan_type chan_type, const char *sounddev
return -EINVAL;
}
/* no paging channel (without control channel) support */
if (chan_type == CHAN_TYPE_PC) {
PDEBUG(DAMPS, DEBUG_ERROR, "Dedicated paging channel currently not supported. Please select CC/PC or CC/PC/VC instead.\n");
return -EINVAL;
}
/* check if there is only one paging channel */
if (chan_type == CHAN_TYPE_PC || chan_type == CHAN_TYPE_CC_PC || chan_type == CHAN_TYPE_CC_PC_VC) {
for (sender = sender_head; sender; sender = sender->next) {
amps = (amps_t *)sender;
if (amps->chan_type == CHAN_TYPE_PC || chan_type == CHAN_TYPE_CC_PC || chan_type == CHAN_TYPE_CC_PC_VC) {
if (amps->chan_type == CHAN_TYPE_PC || amps->chan_type == CHAN_TYPE_CC_PC || amps->chan_type == CHAN_TYPE_CC_PC_VC) {
PDEBUG(DAMPS, DEBUG_ERROR, "Only one paging channel is currently supported. Please check your channel types.\n");
return -EINVAL;
}
@@ -377,11 +399,11 @@ int amps_create(int channel, enum amps_chan_type chan_type, const char *sounddev
/* check if sid machtes channel band */
band = amps_channel2band(channel);
if (band == 'A' && (sid & 1) == 0) {
if (band == 'A' && (sid & 1) == 0 && chan_type != CHAN_TYPE_VC) {
PDEBUG(DAMPS, DEBUG_ERROR, "Channel number %d belongs to system A, but your SID %d is even and belongs to system B. Please give odd SID.\n", channel, sid);
return -EINVAL;
}
if (band == 'B' && (sid & 1) == 1) {
if (band == 'B' && (sid & 1) == 1 && chan_type != CHAN_TYPE_VC) {
PDEBUG(DAMPS, DEBUG_ERROR, "Channel number %d belongs to system B, but your SID %d is odd and belongs to system A. Please give even SID.\n", channel, sid);
return -EINVAL;
}
@@ -479,13 +501,19 @@ static void amps_go_idle(amps_t *amps)
destroy_transaction(amps->trans_list);
}
PDEBUG(DAMPS, DEBUG_INFO, "Entering IDLE state, sending Overhead/Filler frames on %s.\n", chan_type_long_name(amps->chan_type));
if (amps->sender.loopback)
frame_length = 441; /* bits after sync (FOCC) */
else
frame_length = 247; /* bits after sync (RECC) */
amps_new_state(amps, STATE_IDLE);
amps_set_dsp_mode(amps, DSP_MODE_FRAME_RX_FRAME_TX, frame_length);
if (amps->chan_type != CHAN_TYPE_VC) {
PDEBUG(DAMPS, DEBUG_INFO, "Entering IDLE state, sending Overhead/Filler frames on %s.\n", chan_type_long_name(amps->chan_type));
if (amps->sender.loopback)
frame_length = 441; /* bits after sync (FOCC) */
else
frame_length = 247; /* bits after sync (RECC) */
amps_set_dsp_mode(amps, DSP_MODE_FRAME_RX_FRAME_TX, frame_length);
} else {
PDEBUG(DAMPS, DEBUG_INFO, "Entering IDLE state, sending test tone on %s.\n", chan_type_long_name(amps->chan_type));
amps_set_dsp_mode(amps, DSP_MODE_OFF, 0);
}
}
/* Abort connection towards mobile station by sending FOCC/FVC pattern. */
@@ -913,18 +941,18 @@ void transaction_timeout(struct timer *timer)
}
/* assigning voice channel and moving transaction+callref to that channel */
static void assign_voice_channel(transaction_t *trans)
static amps_t *assign_voice_channel(transaction_t *trans)
{
amps_t *amps = trans->amps, *vc;
const char *callerid = amps_min2number(trans->min1, trans->min2);
int callref = ++new_callref;
int rc;
vc = search_free_vc();
vc = search_channel(trans->chan);
if (!vc) {
PDEBUG(DAMPS, DEBUG_NOTICE, "No free channel, rejecting call\n");
PDEBUG(DAMPS, DEBUG_NOTICE, "Channel %d is not free anymore, rejecting call\n", trans->chan);
amps_release(trans, CAUSE_NOCHANNEL);
return;
return NULL;
}
if (vc == amps)
@@ -938,7 +966,7 @@ static void assign_voice_channel(transaction_t *trans)
if (rc < 0) {
PDEBUG(DAMPS, DEBUG_NOTICE, "Call rejected (cause %d), releasing.\n", rc);
amps_release(trans, 0);
return;
return NULL;
}
trans->callref = callref;
}
@@ -950,11 +978,14 @@ static void assign_voice_channel(transaction_t *trans)
link_transaction(trans, vc);
/* flush all other transactions, if any (in case of combined VC + CC) */
amps_flush_other_transactions(vc, trans);
return vc;
}
transaction_t *amps_tx_frame_focc(amps_t *amps)
{
transaction_t *trans;
amps_t *vc;
again:
trans = amps->trans_list;
@@ -981,22 +1012,28 @@ again:
trans_new_state(trans, TRANS_CALL_MO_ASSIGN_SEND);
return trans;
case TRANS_CALL_MO_ASSIGN_SEND:
trans_new_state(trans, TRANS_CALL);
amps_set_dsp_mode(amps, DSP_MODE_AUDIO_RX_AUDIO_TX, 0);
assign_voice_channel(trans);
vc = assign_voice_channel(trans);
if (vc) {
PDEBUG(DAMPS, DEBUG_INFO, "Assignment complete, voice connected\n");
trans_new_state(trans, TRANS_CALL);
amps_set_dsp_mode(vc, DSP_MODE_AUDIO_RX_AUDIO_TX, 0);
}
return NULL;
case TRANS_CALL_MT_ASSIGN:
PDEBUG(DAMPS, DEBUG_INFO, "Assigning channel to call to mobile station\n");
trans_new_state(trans, TRANS_CALL_MT_ASSIGN_SEND);
return trans;
case TRANS_CALL_MT_ASSIGN_SEND:
trans_new_state(trans, TRANS_CALL_MT_ALERT);
trans->chan = 0;
trans->msg_type = 0;
trans->ordq = 0;
trans->order = 1;
amps_set_dsp_mode(amps, DSP_MODE_AUDIO_RX_FRAME_TX, 0);
assign_voice_channel(trans);
vc = assign_voice_channel(trans);
if (vc) {
PDEBUG(DAMPS, DEBUG_INFO, "Assignment complete, next: sending altering on VC\n");
trans->chan = 0;
trans->msg_type = 0;
trans->ordq = 0;
trans->order = 1;
trans_new_state(trans, TRANS_CALL_MT_ALERT);
amps_set_dsp_mode(vc, DSP_MODE_AUDIO_RX_FRAME_TX, 0);
}
return NULL;
case TRANS_PAGE:
PDEBUG(DAMPS, DEBUG_INFO, "Paging the phone\n");
@@ -1022,14 +1059,16 @@ again:
switch (trans->state) {
case TRANS_CALL_RELEASE:
PDEBUG(DAMPS, DEBUG_INFO, "Releasing call to mobile station\n");
PDEBUG(DAMPS, DEBUG_INFO, "Releasing call towards mobile station\n");
trans_new_state(trans, TRANS_CALL_RELEASE_SEND);
return trans;
case TRANS_CALL_RELEASE_SEND:
PDEBUG(DAMPS, DEBUG_INFO, "Release call was sent, destroying call\n");
destroy_transaction(trans);
amps_go_idle(amps);
goto again;
case TRANS_CALL_MT_ALERT:
PDEBUG(DAMPS, DEBUG_INFO, "Sending altering\n");
return trans;
default:
return NULL;

View File

@@ -140,6 +140,8 @@ typedef struct amps {
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 */
double test_phaseshift256; /* how much the phase of sine wave changes per sample */
double test_phase256; /* current phase */
transaction_t *trans_list; /* list of transactions */

View File

@@ -89,6 +89,8 @@
#include "frame.h"
#include "dsp.h"
#define CHAN amps->sender.kanal
/* uncomment this to debug the encoding process */
//#define DEBUG_ENCODER
@@ -124,6 +126,7 @@ static double sat_freq[5] = {
};
static int dsp_sine_sat[256];
static int dsp_sine_test[256];
static uint8_t dsp_sync_check[0x800];
@@ -137,6 +140,7 @@ void dsp_init(void)
for (i = 0; i < 256; i++) {
s = sin((double)i / 256.0 * 2.0 * PI);
dsp_sine_sat[i] = (int)(s * SAT_DEVIATION);
dsp_sine_test[i] = (int)(s * FSK_DEVIATION);
}
/* sync checker */
@@ -245,6 +249,10 @@ int dsp_init_sender(amps_t *amps, int high_pass, int tolerant)
}
sat_reset(amps, "Initial state");
/* test tone */
amps->test_phaseshift256 = 256.0 / ((double)amps->sender.samplerate / 1000.0);
PDEBUG(DDSP, DEBUG_DEBUG, "test_phaseshift256 = %.4f\n", amps->test_phaseshift256);
/* 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) {
@@ -442,6 +450,24 @@ static void sat_encode(amps_t *amps, int16_t *samples, int length)
amps->sat_phase256 = phase;
}
static void test_tone_encode(amps_t *amps, int16_t *samples, int length)
{
double phaseshift, phase;
int i;
phaseshift = amps->test_phaseshift256;
phase = amps->test_phase256;
for (i = 0; i < length; i++) {
*samples++ = dsp_sine_test[((uint8_t)phase) & 0xff];
phase += phaseshift;
if (phase >= 256)
phase -= 256;
}
amps->test_phase256 = phase;
}
/* Provide stream of audio toward radio unit */
void sender_send(sender_t *sender, int16_t *samples, int length)
{
@@ -451,8 +477,8 @@ void sender_send(sender_t *sender, int16_t *samples, int length)
again:
switch (amps->dsp_mode) {
case DSP_MODE_OFF:
/* silence, if transmitter is off */
memset(samples, 0, length * sizeof(*samples));
/* test tone, if transmitter is off */
test_tone_encode(amps, samples, length);
break;
case DSP_MODE_AUDIO_RX_AUDIO_TX:
jitter_load(&amps->sender.audio, samples, length);
@@ -717,9 +743,9 @@ static void sat_decode(amps_t *amps, int16_t *samples, int length)
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);
PDEBUG_CHAN(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, "Signaling Tone level %.2f%% quality %.0f%%\n", result[2] * 32767.0 / FSK_DEVIATION / 0.63662 * 100.0, quality[1] * 100.0);
PDEBUG_CHAN(DDSP, debuglevel, "Signaling 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) {
@@ -727,7 +753,7 @@ static void sat_decode(amps_t *amps, int16_t *samples, int length)
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);
PDEBUG_CHAN(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
@@ -738,7 +764,7 @@ static void sat_decode(amps_t *amps, int16_t *samples, int length)
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");
PDEBUG_CHAN(DDSP, DEBUG_DEBUG, "SAT signal lost.\n");
amps_rx_sat(amps, 0, 0.0);
}
} else
@@ -750,7 +776,7 @@ static void sat_decode(amps_t *amps, int16_t *samples, int length)
if (amps->sig_detect_count == SIG_DETECT_COUNT) {
amps->sig_detected = 1;
amps->sig_detect_count = 0;
PDEBUG(DDSP, DEBUG_DEBUG, "Signaling Tone detected with level=%.0f%%, quality=%.0f%%.\n", result[2] / 0.63662 * 100.0, quality[1] * 100.0);
PDEBUG_CHAN(DDSP, DEBUG_DEBUG, "Signaling Tone detected with level=%.0f%%, quality=%.0f%%.\n", result[2] / 0.63662 * 100.0, quality[1] * 100.0);
amps_rx_signaling_tone(amps, 1, quality[1]);
}
} else
@@ -761,7 +787,7 @@ static void sat_decode(amps_t *amps, int16_t *samples, int length)
if (amps->sig_detect_count == SIG_LOST_COUNT) {
amps->sig_detected = 0;
amps->sig_detect_count = 0;
PDEBUG(DDSP, DEBUG_DEBUG, "Signaling Tone lost.\n");
PDEBUG_CHAN(DDSP, DEBUG_DEBUG, "Signaling Tone lost.\n");
amps_rx_signaling_tone(amps, 0, 0.0);
}
} else
@@ -870,7 +896,7 @@ void sender_receive(sender_t *sender, int16_t *samples, int length)
/* 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);
PDEBUG_CHAN(DDSP, DEBUG_DEBUG, "SAT detector reset: %s.\n", reason);
amps->sat_detected = 0;
amps->sat_detect_count = 0;
amps->sig_detected = 0;
@@ -887,11 +913,24 @@ void amps_set_dsp_mode(amps_t *amps, enum dsp_mode mode, int frame_length)
if (mode == DSP_MODE_FRAME_RX_FRAME_TX) {
/* reset SAT detection */
sat_reset(amps, "Change to FOCC");
PDEBUG_CHAN(DDSP, DEBUG_INFO, "Change mode to FOCC\n");
}
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");
PDEBUG_CHAN(DDSP, DEBUG_INFO, "Change mode from FOCC to FVC\n");
}
if (amps->dsp_mode == DSP_MODE_OFF
&& (mode == DSP_MODE_AUDIO_RX_AUDIO_TX || mode == DSP_MODE_AUDIO_RX_FRAME_TX)) {
/* reset SAT detection */
sat_reset(amps, "Enable FVC");
PDEBUG_CHAN(DDSP, DEBUG_INFO, "Change mode from OFF to FVC\n");
}
if (mode == DSP_MODE_OFF) {
/* reset SAT detection */
sat_reset(amps, "Disable FVC");
PDEBUG_CHAN(DDSP, DEBUG_INFO, "Change mode from FVC to OFF\n");
}
amps->dsp_mode = mode;

View File

@@ -2919,7 +2919,7 @@ static uint64_t amps_encode_word1_extended_address_word_a(uint16_t min2, uint8_t
memset(&frame, 0, sizeof(frame));
frame.ie[AMPS_IE_T1T2] = 2;
frame.ie[AMPS_IE_SCC] = 11;
frame.ie[AMPS_IE_SCC] = 3;
frame.ie[AMPS_IE_MIN2] = min2;
frame.ie[AMPS_IE_EF] = 0;
frame.ie[AMPS_IE_LOCAL_MSG_TYPE] = msg_type;
@@ -2947,7 +2947,7 @@ static uint64_t amps_encode_mobile_station_control_message_word1_a(uint8_t pscc,
memset(&frame, 0, sizeof(frame));
frame.ie[AMPS_IE_T1T2] = 2;
frame.ie[AMPS_IE_SCC] = 11;
frame.ie[AMPS_IE_SCC] = 3;
frame.ie[AMPS_IE_PSCC] = pscc;
frame.ie[AMPS_IE_EF] = 0;
frame.ie[AMPS_IE_LOCAL_MSG_TYPE] = msg_type;

View File

@@ -354,7 +354,7 @@ int main(int argc, char *argv[])
fprintf(stderr, "Failed to create \"Sender\" instance. Quitting!\n");
goto fail;
}
printf("Base station on channel %d ready, please tune transmitter to %.3f MHz and receiver to %.3f MHz.\n", kanal[i], amps_channel2freq(kanal[i], 0), amps_channel2freq(kanal[i], 1));
printf("Base station on channel %d ready (%s), please tune transmitter to %.3f MHz and receiver to %.3f MHz.\n", kanal[i], chan_type_long_name(chan_type[i]), amps_channel2freq(kanal[i], 0), amps_channel2freq(kanal[i], 1));
}
signal(SIGINT,sighandler);