AMPS: Caller ID Support
Support for sending caller ID for newer phones. Currently does not work with older phones, they will abort.pull/15/head
parent
1a0813069f
commit
4e669ecf79
143
src/amps/amps.c
143
src/amps/amps.c
|
@ -61,7 +61,9 @@
|
|||
#define PAGE_TRIES 2 /* how many times to page the phone */
|
||||
#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 ALERT_TRIES 3 /* how many times to alert the phone */
|
||||
#define ALERT_TO 0.3 /* max time to wait for alert confirm */
|
||||
#define ANSWER_TO 60.0 /* max time to wait for answer */
|
||||
#define RELEASE_TIMER 5.0 /* max time to send release messages */
|
||||
|
||||
/* Convert channel number to frequency number of base station.
|
||||
|
@ -502,7 +504,7 @@ static amps_t *search_pc(void)
|
|||
}
|
||||
|
||||
/* Create transceiver instance and link to a list. */
|
||||
int amps_create(const char *kanal, enum amps_chan_type chan_type, const char *device, int use_sdr, int samplerate, double rx_gain, double tx_gain, int pre_emphasis, int de_emphasis, const char *write_rx_wave, const char *write_tx_wave, const char *read_rx_wave, const char *read_tx_wave, amps_si *si, uint16_t sid, uint8_t sat, int polarity, int tolerant, int loopback)
|
||||
int amps_create(const char *kanal, enum amps_chan_type chan_type, const char *device, int use_sdr, int samplerate, double rx_gain, double tx_gain, int pre_emphasis, int de_emphasis, const char *write_rx_wave, const char *write_tx_wave, const char *read_rx_wave, const char *read_tx_wave, amps_si *si, uint16_t sid, uint8_t sat, int polarity, int send_callerid, int tolerant, int loopback)
|
||||
{
|
||||
sender_t *sender;
|
||||
amps_t *amps;
|
||||
|
@ -582,12 +584,12 @@ int amps_create(const char *kanal, enum amps_chan_type chan_type, const char *de
|
|||
amps->chan_type = chan_type;
|
||||
memcpy(&s->si, si, sizeof(amps->si));
|
||||
amps->sat = sat;
|
||||
|
||||
amps->send_callerid = send_callerid;
|
||||
if (polarity < 0)
|
||||
amps->flip_polarity = 1;
|
||||
|
||||
amps->pre_emphasis = pre_emphasis;
|
||||
amps->de_emphasis = de_emphasis;
|
||||
|
||||
/* the AMPS uses a frequency rage of 300..3000 Hz, but we still use the default low pass filter, which is not too far above */
|
||||
rc = init_emphasis(&s->estate, samplerate, CUT_OFF_EMPHASIS_DEFAULT, CUT_OFF_HIGHPASS_DEFAULT, CUT_OFF_LOWPASS_DEFAULT);
|
||||
if (rc < 0)
|
||||
|
@ -688,14 +690,13 @@ static void amps_release(transaction_t *trans, uint8_t cause)
|
|||
trans->callref = 0;
|
||||
}
|
||||
/* change DSP mode to transmit release */
|
||||
if (amps->dsp_mode == DSP_MODE_AUDIO_RX_AUDIO_TX || amps->dsp_mode == DSP_MODE_OFF)
|
||||
if (amps->dsp_mode == DSP_MODE_AUDIO_RX_AUDIO_TX || amps->dsp_mode == DSP_MODE_AUDIO_RX_SILENCE_TX || amps->dsp_mode == DSP_MODE_OFF)
|
||||
amps_set_dsp_mode(amps, DSP_MODE_AUDIO_RX_FRAME_TX, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* receive signaling
|
||||
*/
|
||||
|
||||
void amps_rx_signaling_tone(amps_t *amps, int tone, double quality)
|
||||
{
|
||||
transaction_t *trans = amps->trans_list;
|
||||
|
@ -710,6 +711,7 @@ void amps_rx_signaling_tone(amps_t *amps, int tone, double quality)
|
|||
PDEBUG_CHAN(DAMPS, DEBUG_INFO, "Lost Signaling Tone signal\n");
|
||||
|
||||
switch (trans->state) {
|
||||
case TRANS_CALL_MO_ASSIGN_CONFIRM: // should not happen
|
||||
case TRANS_CALL:
|
||||
if (!tone)
|
||||
break;
|
||||
|
@ -723,16 +725,19 @@ void amps_rx_signaling_tone(amps_t *amps, int tone, double quality)
|
|||
destroy_transaction(trans);
|
||||
amps_go_idle(amps);
|
||||
break;
|
||||
case TRANS_CALL_MT_ALERT:
|
||||
case TRANS_CALL_MT_ASSIGN_CONFIRM: // should not happen
|
||||
case TRANS_CALL_MT_ALERT: // should not happen
|
||||
case TRANS_CALL_MT_ALERT_SEND: // should not happen
|
||||
case TRANS_CALL_MT_ALERT_CONFIRM:
|
||||
if (tone) {
|
||||
timer_stop(&trans->timer);
|
||||
call_up_alerting(trans->callref);
|
||||
amps_set_dsp_mode(amps, DSP_MODE_AUDIO_RX_AUDIO_TX, 0);
|
||||
trans_new_state(trans, TRANS_CALL_MT_ALERT_SEND);
|
||||
timer_start(&trans->timer, ALERT_TO);
|
||||
trans_new_state(trans, TRANS_CALL_MT_ANSWER_WAIT);
|
||||
timer_start(&trans->timer, ANSWER_TO);
|
||||
}
|
||||
break;
|
||||
case TRANS_CALL_MT_ALERT_SEND:
|
||||
case TRANS_CALL_MT_ANSWER_WAIT:
|
||||
if (!tone) {
|
||||
timer_stop(&trans->timer);
|
||||
if (!trans->sat_detected)
|
||||
|
@ -753,13 +758,20 @@ void amps_rx_sat(amps_t *amps, int tone, double quality)
|
|||
PDEBUG_CHAN(DAMPS, DEBUG_ERROR, "SAT signal without transaction, please fix!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* irgnoring SAT loss on release */
|
||||
if (trans->state == TRANS_CALL_RELEASE
|
||||
|| trans->state == TRANS_CALL_RELEASE_SEND)
|
||||
return;
|
||||
if (trans->state != TRANS_CALL
|
||||
|
||||
/* only SAT with these states */
|
||||
if (trans->state != TRANS_CALL_MO_ASSIGN_CONFIRM
|
||||
&& trans->state != TRANS_CALL_MT_ASSIGN_CONFIRM
|
||||
&& trans->state != TRANS_CALL_MT_ALERT
|
||||
&& trans->state != TRANS_CALL_MT_ALERT_SEND) {
|
||||
&& trans->state != TRANS_CALL_MT_ALERT_SEND
|
||||
&& trans->state != TRANS_CALL_MT_ALERT_CONFIRM
|
||||
&& trans->state != TRANS_CALL_MT_ANSWER_WAIT
|
||||
&& trans->state != TRANS_CALL) {
|
||||
PDEBUG_CHAN(DAMPS, DEBUG_ERROR, "SAT signal without active call, please fix!\n");
|
||||
return;
|
||||
}
|
||||
|
@ -772,9 +784,26 @@ void amps_rx_sat(amps_t *amps, int tone, double quality)
|
|||
trans->sat_detected = 0;
|
||||
}
|
||||
|
||||
/* no SAT during alerting */
|
||||
/* initial SAT received */
|
||||
if (tone && trans->state == TRANS_CALL_MO_ASSIGN_CONFIRM) {
|
||||
PDEBUG_CHAN(DAMPS, DEBUG_INFO, "Confirm from mobile (SAT) received\n");
|
||||
timer_stop(&trans->timer);
|
||||
trans_new_state(trans, TRANS_CALL);
|
||||
amps_set_dsp_mode(amps, DSP_MODE_AUDIO_RX_AUDIO_TX, 0);
|
||||
}
|
||||
if (tone && trans->state == TRANS_CALL_MT_ASSIGN_CONFIRM) {
|
||||
PDEBUG_CHAN(DAMPS, DEBUG_INFO, "Confirm from mobile (SAT) received\n");
|
||||
timer_stop(&trans->timer);
|
||||
trans->alert_retry = 1;
|
||||
trans_new_state(trans, TRANS_CALL_MT_ALERT);
|
||||
amps_set_dsp_mode(amps, DSP_MODE_AUDIO_RX_FRAME_TX, 0);
|
||||
}
|
||||
|
||||
/* no SAT timeout handling during alerting */
|
||||
if (trans->state == TRANS_CALL_MT_ALERT
|
||||
|| trans->state == TRANS_CALL_MT_ALERT_SEND)
|
||||
|| trans->state == TRANS_CALL_MT_ALERT_SEND
|
||||
|| trans->state == TRANS_CALL_MT_ALERT_CONFIRM
|
||||
|| trans->state == TRANS_CALL_MT_ANSWER_WAIT)
|
||||
return;
|
||||
|
||||
if (tone) {
|
||||
|
@ -790,20 +819,6 @@ void amps_rx_sat(amps_t *amps, int tone, double quality)
|
|||
return;
|
||||
}
|
||||
|
||||
static void timeout_sat(amps_t *amps, double duration)
|
||||
{
|
||||
if (!amps->trans_list) {
|
||||
PDEBUG_CHAN(DAMPS, DEBUG_ERROR, "SAT timeout, but no transaction, please fix!\n");
|
||||
return;
|
||||
}
|
||||
if (duration == SAT_TO1)
|
||||
PDEBUG_CHAN(DAMPS, DEBUG_NOTICE, "Timeout after %.0f seconds not receiving SAT signal.\n", duration);
|
||||
else
|
||||
PDEBUG_CHAN(DAMPS, DEBUG_NOTICE, "Timeout after %.0f seconds loosing SAT signal.\n", duration);
|
||||
PDEBUG_CHAN(DAMPS, DEBUG_INFO, "Release call towards network.\n");
|
||||
amps_release(amps->trans_list, CAUSE_TEMPFAIL);
|
||||
}
|
||||
|
||||
/* receive message from phone on RECC */
|
||||
void amps_rx_recc(amps_t *amps, uint8_t scm, uint8_t mpci, uint32_t esn, uint32_t min1, uint16_t min2, uint8_t msg_type, uint8_t ordq, uint8_t order, const char *dialing)
|
||||
{
|
||||
|
@ -950,6 +965,11 @@ int call_down_setup(int callref, const char __attribute__((unused)) *caller_id,
|
|||
}
|
||||
trans->callref = callref;
|
||||
trans->page_retry = 1;
|
||||
if (caller_type == TYPE_INTERNATIONAL) {
|
||||
trans->caller_id[0] = '+';
|
||||
strncpy(trans->caller_id + 1, caller_id, sizeof(trans->caller_id) - 2);
|
||||
} else
|
||||
strncpy(trans->caller_id, caller_id, sizeof(trans->caller_id) - 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -988,8 +1008,11 @@ void call_down_disconnect(int callref, int cause)
|
|||
switch (amps->dsp_mode) {
|
||||
case DSP_MODE_AUDIO_RX_AUDIO_TX:
|
||||
case DSP_MODE_AUDIO_RX_FRAME_TX:
|
||||
if (trans->state == TRANS_CALL_MT_ALERT
|
||||
|| trans->state == TRANS_CALL_MT_ALERT_SEND) {
|
||||
if (trans->state == TRANS_CALL_MT_ASSIGN_CONFIRM
|
||||
|| trans->state == TRANS_CALL_MT_ALERT
|
||||
|| trans->state == TRANS_CALL_MT_ALERT_SEND
|
||||
|| trans->state == TRANS_CALL_MT_ALERT_CONFIRM
|
||||
|| trans->state == TRANS_CALL_MT_ANSWER_WAIT) {
|
||||
PDEBUG_CHAN(DAMPS, DEBUG_INFO, "Call control disconnect on voice channel while alerting, releasing towards mobile station.\n");
|
||||
amps_release(trans, cause);
|
||||
}
|
||||
|
@ -1028,6 +1051,7 @@ void call_down_release(int callref, int cause)
|
|||
trans->callref = 0;
|
||||
|
||||
switch (amps->dsp_mode) {
|
||||
case DSP_MODE_AUDIO_RX_SILENCE_TX:
|
||||
case DSP_MODE_AUDIO_RX_AUDIO_TX:
|
||||
case DSP_MODE_AUDIO_RX_FRAME_TX:
|
||||
PDEBUG_CHAN(DAMPS, DEBUG_INFO, "Call control releases on voice channel, releasing towards mobile station.\n");
|
||||
|
@ -1071,8 +1095,16 @@ void transaction_timeout(struct timer *timer)
|
|||
amps_t *amps = trans->amps;
|
||||
|
||||
switch (trans->state) {
|
||||
case TRANS_CALL_MO_ASSIGN_CONFIRM:
|
||||
case TRANS_CALL_MT_ASSIGN_CONFIRM:
|
||||
PDEBUG_CHAN(DAMPS, DEBUG_NOTICE, "Timeout after %.0f seconds not receiving initial SAT signal.\n", timer->duration);
|
||||
PDEBUG_CHAN(DAMPS, DEBUG_INFO, "Release call towards network.\n");
|
||||
amps_release(amps->trans_list, CAUSE_TEMPFAIL);
|
||||
break;
|
||||
case TRANS_CALL:
|
||||
timeout_sat(amps, timer->duration);
|
||||
PDEBUG_CHAN(DAMPS, DEBUG_NOTICE, "Timeout after %.0f seconds loosing SAT signal.\n", timer->duration);
|
||||
PDEBUG_CHAN(DAMPS, DEBUG_INFO, "Release call towards network.\n");
|
||||
amps_release(amps->trans_list, CAUSE_TEMPFAIL);
|
||||
break;
|
||||
case TRANS_CALL_RELEASE:
|
||||
case TRANS_CALL_RELEASE_SEND:
|
||||
|
@ -1080,10 +1112,18 @@ void transaction_timeout(struct timer *timer)
|
|||
destroy_transaction(trans);
|
||||
amps_go_idle(amps);
|
||||
break;
|
||||
case TRANS_CALL_MT_ALERT:
|
||||
amps_release(trans, CAUSE_TEMPFAIL);
|
||||
break;
|
||||
case TRANS_CALL_MT_ALERT_SEND:
|
||||
case TRANS_CALL_MT_ALERT_CONFIRM:
|
||||
if (trans->alert_retry++ == ALERT_TRIES) {
|
||||
PDEBUG_CHAN(DAMPS, DEBUG_NOTICE, "Phone does not respond to alert order, destroying transaction\n");
|
||||
amps_release(trans, CAUSE_TEMPFAIL);
|
||||
} else {
|
||||
PDEBUG_CHAN(DAMPS, DEBUG_NOTICE, "Phone does not respond to alert order, retrying\n");
|
||||
trans_new_state(trans, TRANS_CALL_MT_ALERT);
|
||||
amps_set_dsp_mode(amps, DSP_MODE_AUDIO_RX_FRAME_TX, 0);
|
||||
}
|
||||
break;
|
||||
case TRANS_CALL_MT_ANSWER_WAIT:
|
||||
PDEBUG_CHAN(DAMPS, DEBUG_NOTICE, "Alerting timeout, destroying transaction\n");
|
||||
amps_release(trans, CAUSE_NOANSWER);
|
||||
break;
|
||||
|
@ -1173,8 +1213,9 @@ again:
|
|||
vc = assign_voice_channel(trans);
|
||||
if (vc) {
|
||||
PDEBUG_CHAN(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);
|
||||
/* timer and other things are processed at assign_voice_channel() */
|
||||
trans_new_state(trans, TRANS_CALL_MO_ASSIGN_CONFIRM);
|
||||
amps_set_dsp_mode(vc, DSP_MODE_AUDIO_RX_SILENCE_TX, 0);
|
||||
}
|
||||
return NULL;
|
||||
case TRANS_CALL_MT_ASSIGN:
|
||||
|
@ -1184,13 +1225,10 @@ again:
|
|||
case TRANS_CALL_MT_ASSIGN_SEND:
|
||||
vc = assign_voice_channel(trans);
|
||||
if (vc) {
|
||||
PDEBUG_CHAN(DAMPS, DEBUG_INFO, "Assignment complete, next: sending alerting 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);
|
||||
PDEBUG_CHAN(DAMPS, DEBUG_INFO, "Assignment complete, waiting for SAT on VC\n");
|
||||
/* timer and other things are processed at assign_voice_channel() */
|
||||
trans_new_state(trans, TRANS_CALL_MT_ASSIGN_CONFIRM);
|
||||
amps_set_dsp_mode(vc, DSP_MODE_AUDIO_RX_SILENCE_TX, 0);
|
||||
}
|
||||
return NULL;
|
||||
case TRANS_PAGE:
|
||||
|
@ -1223,8 +1261,25 @@ transaction_t *amps_tx_frame_fvc(amps_t *amps)
|
|||
PDEBUG_CHAN(DAMPS, DEBUG_INFO, "Release call was sent, continue sending release\n");
|
||||
return trans;
|
||||
case TRANS_CALL_MT_ALERT:
|
||||
PDEBUG_CHAN(DAMPS, DEBUG_INFO, "Sending alerting\n");
|
||||
trans->chan = 0;
|
||||
trans->msg_type = 0;
|
||||
trans->ordq = 0;
|
||||
// "Alert with caller ID" causes older phones to interrupt the connection for some reason, therefore we don't use order 17 when no caller ID is set
|
||||
if (amps->send_callerid && trans->alert_retry == 1 && !trans->caller_id) {
|
||||
PDEBUG_CHAN(DAMPS, DEBUG_INFO, "Sending alerting with caller ID\n");
|
||||
trans->order = 17;
|
||||
} else {
|
||||
PDEBUG_CHAN(DAMPS, DEBUG_INFO, "Sending alerting\n");
|
||||
trans->order = 1;
|
||||
}
|
||||
trans_new_state(trans, TRANS_CALL_MT_ALERT_SEND);
|
||||
return trans;
|
||||
case TRANS_CALL_MT_ALERT_SEND:
|
||||
PDEBUG_CHAN(DAMPS, DEBUG_INFO, "Alerting was sent, continue waiting for ST or timeout\n");
|
||||
timer_start(&trans->timer, ALERT_TO);
|
||||
amps_set_dsp_mode(amps, DSP_MODE_AUDIO_RX_SILENCE_TX, 0);
|
||||
trans_new_state(trans, TRANS_CALL_MT_ALERT_CONFIRM);
|
||||
return NULL;
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ 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_AUDIO_RX_SILENCE_TX, /* stream audio, send silence */
|
||||
DSP_MODE_FRAME_RX_FRAME_TX, /* send and decode frames */
|
||||
};
|
||||
|
||||
|
@ -56,6 +57,7 @@ struct amps {
|
|||
|
||||
/* system info */
|
||||
amps_si si;
|
||||
int send_callerid; /* if set, caller ID is transmitted */
|
||||
|
||||
/* cell nr selection */
|
||||
int cell_auto; /* if set, cell_nr is selected automatically */
|
||||
|
@ -140,6 +142,12 @@ struct amps {
|
|||
uint8_t tx_fvc_msg_type; /* message (3 values) */
|
||||
uint8_t tx_fvc_ordq;
|
||||
uint8_t tx_fvc_order;
|
||||
char tx_fvc_callerid[34]; /* caller ID */
|
||||
int tx_fvc_callerid_present;/* presentation of caller ID */
|
||||
int tx_fvc_callerid_screen; /* screening of caller ID */
|
||||
int tx_fvc_callerid_signal; /* signal to send in conjunction with caller ID */
|
||||
int tx_fvc_word_count; /* counts transmitted words in a muli word message */
|
||||
int tx_fvc_word_repeat; /* counts repeats of mulit word message */
|
||||
/* SAT tone */
|
||||
int sat; /* use SAT tone 0..2 */
|
||||
int sat_samples; /* number of samples in buffer for supervisory detection */
|
||||
|
@ -175,7 +183,7 @@ 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(const char *kanal, enum amps_chan_type chan_type, const char *device, int use_sdr, int samplerate, double rx_gain, double tx_gain, int pre_emphasis, int de_emphasis, const char *write_rx_wave, const char *write_tx_wave, const char *read_rx_wave, const char *read_tx_wave, amps_si *si, uint16_t sid, uint8_t sat, int polarity, int tolerant, int loopback);
|
||||
int amps_create(const char *kanal, enum amps_chan_type chan_type, const char *device, int use_sdr, int samplerate, double rx_gain, double tx_gain, int pre_emphasis, int de_emphasis, const char *write_rx_wave, const char *write_tx_wave, const char *read_rx_wave, const char *read_tx_wave, amps_si *si, uint16_t sid, uint8_t sat, int polarity, int send_callerid, int tolerant, int loopback);
|
||||
void amps_destroy(sender_t *sender);
|
||||
void amps_go_idle(amps_t *amps);
|
||||
void amps_rx_signaling_tone(amps_t *amps, int tone, double quality);
|
||||
|
|
|
@ -38,7 +38,10 @@
|
|||
int num_chan_type = 0;
|
||||
enum amps_chan_type chan_type[MAX_SENDER] = { CHAN_TYPE_CC_PC_VC };
|
||||
const char *flip_polarity = "";
|
||||
int ms_power = 4, dtx = 0, dcc = 0, scc = 0, sid = 0, regh = 1, regr = 1, pureg = 0, pdreg = 0, locaid = -1, regincr = 300, bis = 0;
|
||||
int ms_power = 4;
|
||||
int dtx = 0;
|
||||
int send_callerid = 0;
|
||||
int dcc = 0, scc = 0, sid = 0, regh = 1, regr = 1, pureg = 0, pdreg = 0, locaid = -1, regincr = 300, bis = 0;
|
||||
int tolerant = 0;
|
||||
|
||||
void print_help(const char *arg0)
|
||||
|
@ -63,6 +66,12 @@ void print_help(const char *arg0)
|
|||
printf(" Give DTX parameter for Discontinuous Transmission. (default = '%d')\n", dtx);
|
||||
printf(" 0 = disable DTX; 1 = reserved;\n");
|
||||
printf(" 2 = 8 dB attenuation in low state; 3 = transmitter off\n");
|
||||
printf(" -I --caller-id 1 | 0\n");
|
||||
printf(" If set, the caller ID is sent while ringing the phone. (default = '%d')\n", send_callerid);
|
||||
printf(" Note that this does not work as documented in the specs. If the phone\n");
|
||||
printf(" does not support caller ID, it will abort connection on receiving\n");
|
||||
printf(" caller ID for some unknown reason. Therefore use caller ID only with\n");
|
||||
printf(" phones that support it.\n");
|
||||
if (!tacs) {
|
||||
printf(" -S --sysinfo sid=<System ID> | sid=list\n");
|
||||
printf(" Give system ID of cell broadcast\n");
|
||||
|
@ -110,6 +119,7 @@ static void add_options(void)
|
|||
option_add('F', "flip-polarity", 1);
|
||||
option_add('P', "ms-power", 1);
|
||||
option_add('D', "dtx", 1);
|
||||
option_add('I', "caller-id", 1);
|
||||
option_add('S', "sysinfo", 1);
|
||||
option_add('O', "tolerant", 0);
|
||||
}
|
||||
|
@ -156,6 +166,9 @@ static int handle_options(int short_option, int argi, char **argv)
|
|||
if (dtx < 0)
|
||||
dtx = 0;
|
||||
break;
|
||||
case 'I':
|
||||
send_callerid = atoi(argv[argi]);
|
||||
break;
|
||||
case 'S':
|
||||
p = strchr(argv[argi], '=');
|
||||
if (!p) {
|
||||
|
@ -384,7 +397,7 @@ int main_amps_tacs(const char *name, int argc, char *argv[])
|
|||
amps_si si;
|
||||
|
||||
init_sysinfo(&si, ms_power, ms_power, dtx, dcc, sid >> 1, regh, regr, pureg, pdreg, locaid, regincr, bis);
|
||||
rc = amps_create(kanal[i], chan_type[i], dsp_device[i], use_sdr, dsp_samplerate, rx_gain, tx_gain, do_pre_emphasis, do_de_emphasis, write_rx_wave, write_tx_wave, read_rx_wave, read_tx_wave, &si, sid, scc, polarity, tolerant, loopback);
|
||||
rc = amps_create(kanal[i], chan_type[i], dsp_device[i], use_sdr, dsp_samplerate, rx_gain, tx_gain, do_pre_emphasis, do_de_emphasis, write_rx_wave, write_tx_wave, read_rx_wave, read_tx_wave, &si, sid, scc, polarity, send_callerid, tolerant, loopback);
|
||||
if (rc < 0) {
|
||||
fprintf(stderr, "Failed to create \"Sender\" instance. Quitting!\n");
|
||||
goto fail;
|
||||
|
|
|
@ -399,8 +399,8 @@ again:
|
|||
rc = amps_encode_frame_fvc(amps, amps->fsk_tx_frame);
|
||||
else
|
||||
rc = amps_encode_frame_focc(amps, amps->fsk_tx_frame);
|
||||
/* check if we have not bit string (change to tx audio)
|
||||
* we may not store fsk_tx_buffer_pos, because is was reset on a mode achange */
|
||||
/* check if we have no bit string (change to tx audio / silence)
|
||||
* we may not store fsk_tx_buffer_pos, because is was reset on a mode change */
|
||||
if (rc)
|
||||
return count;
|
||||
amps->fsk_tx_frame_pos = 0;
|
||||
|
@ -487,7 +487,13 @@ again:
|
|||
/* pre-emphasis */
|
||||
if (amps->pre_emphasis)
|
||||
pre_emphasis(&s->estate, samples, length);
|
||||
/* encode sat */
|
||||
/* encode SAT during call */
|
||||
sat_encode(amps, samples, length);
|
||||
break;
|
||||
case DSP_MODE_AUDIO_RX_SILENCE_TX:
|
||||
memset(power, 1, length);
|
||||
memset(samples, 0, sizeof(*samples) * length);
|
||||
/* encode SAT while waiting for alert response or answer */
|
||||
sat_encode(amps, samples, length);
|
||||
break;
|
||||
case DSP_MODE_AUDIO_RX_FRAME_TX:
|
||||
|
@ -496,6 +502,7 @@ again:
|
|||
* stopped, process again for rest of stream. */
|
||||
count = fsk_frame(amps, samples, length);
|
||||
memset(power, 1, count);
|
||||
// no SAT during frame transmission, according to specs
|
||||
samples += count;
|
||||
power += count;
|
||||
length -= count;
|
||||
|
@ -894,6 +901,7 @@ void sender_receive(sender_t *sender, sample_t *samples, int length, double __at
|
|||
break;
|
||||
case DSP_MODE_AUDIO_RX_AUDIO_TX:
|
||||
case DSP_MODE_AUDIO_RX_FRAME_TX:
|
||||
case DSP_MODE_AUDIO_RX_SILENCE_TX:
|
||||
sender_receive_audio(amps, samples, length);
|
||||
break;
|
||||
}
|
||||
|
@ -923,13 +931,13 @@ void amps_set_dsp_mode(amps_t *amps, enum dsp_mode mode, int frame_length)
|
|||
amps->tx_focc_debugged = 0;
|
||||
}
|
||||
if (amps->dsp_mode == DSP_MODE_FRAME_RX_FRAME_TX
|
||||
&& (mode == DSP_MODE_AUDIO_RX_AUDIO_TX || mode == DSP_MODE_AUDIO_RX_FRAME_TX)) {
|
||||
&& (mode == DSP_MODE_AUDIO_RX_AUDIO_TX || mode == DSP_MODE_AUDIO_RX_FRAME_TX || mode == DSP_MODE_AUDIO_RX_SILENCE_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)) {
|
||||
&& (mode == DSP_MODE_AUDIO_RX_AUDIO_TX || mode == DSP_MODE_AUDIO_RX_FRAME_TX || mode == DSP_MODE_AUDIO_RX_SILENCE_TX)) {
|
||||
/* reset SAT detection */
|
||||
sat_reset(amps, "Enable FVC");
|
||||
PDEBUG_CHAN(DDSP, DEBUG_INFO, "Change mode from OFF to FVC\n");
|
||||
|
@ -940,6 +948,8 @@ void amps_set_dsp_mode(amps_t *amps, enum dsp_mode mode, int frame_length)
|
|||
PDEBUG_CHAN(DDSP, DEBUG_INFO, "Change mode from FVC to OFF\n");
|
||||
}
|
||||
|
||||
PDEBUG_CHAN(DDSP, DEBUG_DEBUG, "Reset FSK frame transmitter, due to setting dsp mode.\n");
|
||||
|
||||
amps->dsp_mode = mode;
|
||||
if (frame_length)
|
||||
amps->fsk_rx_frame_length = frame_length;
|
||||
|
|
|
@ -3020,6 +3020,37 @@ static uint64_t amps_encode_mobile_station_control_message_word1_b(uint8_t scc,
|
|||
return amps_encode_word(&frame, &mobile_station_control_message_word1_b, 1);
|
||||
}
|
||||
|
||||
static uint64_t amps_encode_word2_first_alert_with_info_word(uint8_t rl_w, uint8_t signal, uint8_t cpn_rl, uint8_t pi, uint8_t si)
|
||||
{
|
||||
frame_t frame;
|
||||
|
||||
memset(&frame, 0, sizeof(frame));
|
||||
frame.ie[AMPS_IE_T1T2] = 1;
|
||||
frame.ie[AMPS_IE_RL_W] = rl_w;
|
||||
frame.ie[AMPS_IE_SIGNAL] = signal;
|
||||
frame.ie[AMPS_IE_CPN_RL] = cpn_rl;
|
||||
frame.ie[AMPS_IE_PI] = pi;
|
||||
frame.ie[AMPS_IE_SI] = si;
|
||||
return amps_encode_word(&frame, &word2_first_alert_with_info_word, 1);
|
||||
}
|
||||
|
||||
static uint64_t amps_encode_wordn_n_minus_1th_alert_with_info_word(const char *character)
|
||||
{
|
||||
frame_t frame;
|
||||
|
||||
memset(&frame, 0, sizeof(frame));
|
||||
frame.ie[AMPS_IE_T1T2] = 1;
|
||||
if (character[0]) {
|
||||
frame.ie[AMPS_IE_CHARACTER_1] = character[0];
|
||||
if (character[1]) {
|
||||
frame.ie[AMPS_IE_CHARACTER_2] = character[1];
|
||||
if (character[2])
|
||||
frame.ie[AMPS_IE_CHARACTER_3] = character[2];
|
||||
}
|
||||
}
|
||||
return amps_encode_word(&frame, &wordn_n_minus_1th_alert_with_info_word, 1);
|
||||
}
|
||||
|
||||
/* decoder function of a word */
|
||||
static frame_t *amps_decode_word(uint64_t word, struct def_word *w)
|
||||
{
|
||||
|
@ -3346,7 +3377,7 @@ static void amps_encode_focc_bits(uint64_t word_a, uint64_t word_b, char *bits)
|
|||
|
||||
memcpy(bits + 0, dotting, 10);
|
||||
bits[10] = 'i';
|
||||
strcpy(bits + 11, sync_word);
|
||||
memcpy(bits + 11, sync_word, 11);
|
||||
bits[22] = 'i';
|
||||
k = 23;
|
||||
for (i = 0; i < 5; i++) {
|
||||
|
@ -3366,22 +3397,22 @@ static void amps_encode_focc_bits(uint64_t word_a, uint64_t word_b, char *bits)
|
|||
|
||||
if (k != 463)
|
||||
abort();
|
||||
bits[463] = '\0';
|
||||
bits[k] = '\0';
|
||||
|
||||
#ifdef BIT_DEBUGGING
|
||||
if (debuglevel == DEBUG_DEBUG) {
|
||||
char text[64];
|
||||
|
||||
strncpy(text, bits, 23);
|
||||
text[23] = '\0';
|
||||
#ifdef BIT_DEBUGGING
|
||||
PDEBUG(DFRAME, DEBUG_INFO, "TX FOCC: %s\n", text);
|
||||
for (i = 0; i < 10; i++) {
|
||||
strncpy(text, bits + 23 + i * 44, 44);
|
||||
text[44] = '\0';
|
||||
PDEBUG(DFRAME, DEBUG_DEBUG, " word %c - %s\n", (i & 1) ? 'b' : 'a', text);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void amps_encode_fvc_bits(uint64_t word_a, char *bits)
|
||||
|
@ -3398,15 +3429,15 @@ static void amps_encode_fvc_bits(uint64_t word_a, char *bits)
|
|||
memcpy(bits + k, dotting, 37);
|
||||
k += 37;
|
||||
}
|
||||
strcpy(bits + k, sync_word);
|
||||
memcpy(bits + k, sync_word, 11);
|
||||
k += 11;
|
||||
for (j = 39; j >= 0; j--)
|
||||
bits[k++] = ((word_a >> j) & 1) + '0';
|
||||
}
|
||||
|
||||
if (k != 1032)
|
||||
abort();
|
||||
|
||||
bits[1032] = '\0';
|
||||
bits[k] = '\0';
|
||||
|
||||
#ifdef BIT_DEBUGGING
|
||||
if (debuglevel == DEBUG_DEBUG) {
|
||||
|
@ -3502,7 +3533,16 @@ int amps_encode_frame_fvc(amps_t *amps, char *bits)
|
|||
amps->tx_fvc_ordq = trans->ordq;
|
||||
amps->tx_fvc_order = trans->order;
|
||||
amps->tx_fvc_chan = trans->chan;
|
||||
strncpy(amps->tx_fvc_callerid, trans->caller_id, sizeof(amps->tx_fvc_callerid) - 1);
|
||||
amps->tx_fvc_callerid_signal = 1;
|
||||
amps->tx_fvc_callerid_screen = 3;
|
||||
if (trans->caller_id[0])
|
||||
amps->tx_fvc_callerid_present = 0;
|
||||
else
|
||||
amps->tx_fvc_callerid_signal = 1;
|
||||
amps->tx_fvc_send = 1;
|
||||
amps->tx_fvc_word_count = 0;
|
||||
amps->tx_fvc_word_repeat = 0;
|
||||
}
|
||||
/* on change of dsp mode */
|
||||
if (amps->dsp_mode != DSP_MODE_AUDIO_RX_FRAME_TX)
|
||||
|
@ -3511,11 +3551,32 @@ int amps_encode_frame_fvc(amps_t *amps, char *bits)
|
|||
|
||||
/* send scheduled mobile control message */
|
||||
if (amps->tx_fvc_send) {
|
||||
amps->tx_fvc_send = 0;
|
||||
if (amps->tx_fvc_chan)
|
||||
word = amps_encode_mobile_station_control_message_word1_b(amps->sat, amps->sat, (amps->si.word2.dtx) ? 1 : 0, 0, 0, amps->si.vmac, amps->tx_fvc_chan);
|
||||
else
|
||||
word = amps_encode_mobile_station_control_message_word1_a(amps->sat, amps->tx_fvc_msg_type, amps->tx_fvc_ordq, amps->tx_fvc_order);
|
||||
if (amps->tx_fvc_word_count == 0) {
|
||||
if (amps->tx_fvc_chan)
|
||||
word = amps_encode_mobile_station_control_message_word1_b(amps->sat, amps->sat, (amps->si.word2.dtx) ? 1 : 0, 0, 0, amps->si.vmac, amps->tx_fvc_chan);
|
||||
else
|
||||
word = amps_encode_mobile_station_control_message_word1_a(amps->sat, amps->tx_fvc_msg_type, amps->tx_fvc_ordq, amps->tx_fvc_order);
|
||||
/* done, if we don't have ALERTING with info */
|
||||
if (amps->tx_fvc_order != 17)
|
||||
amps->tx_fvc_send = 0;
|
||||
} else if (amps->tx_fvc_word_count == 1) {
|
||||
int cpn_rl, rl_w;
|
||||
/* number of characters */
|
||||
cpn_rl = strlen(amps->tx_fvc_callerid);
|
||||
/* number of frames that are required to hold number of characters */
|
||||
rl_w = (cpn_rl + 2) / 3;
|
||||
word = amps_encode_word2_first_alert_with_info_word(rl_w, amps->tx_fvc_callerid_signal, cpn_rl, amps->tx_fvc_callerid_present, amps->tx_fvc_callerid_screen);
|
||||
if (cpn_rl == 0)
|
||||
amps->tx_fvc_send = 0;
|
||||
} else {
|
||||
const char *callerid;
|
||||
/* chunk of caller ID */
|
||||
callerid = amps->tx_fvc_callerid + (amps->tx_fvc_word_count - 2) * 3;
|
||||
word = amps_encode_wordn_n_minus_1th_alert_with_info_word(callerid);
|
||||
if (strlen(callerid) <= 3)
|
||||
amps->tx_fvc_send = 0;
|
||||
}
|
||||
amps->tx_fvc_word_count++;
|
||||
} else
|
||||
return 1;
|
||||
|
||||
|
|
|
@ -37,17 +37,25 @@ static const char *trans_state_name(int state)
|
|||
case TRANS_REGISTER_ACK_SEND:
|
||||
return "REGISTER ACK SEND";
|
||||
case TRANS_CALL_MO_ASSIGN:
|
||||
return "CALL ASSIGN MOBILE ORIGINATING";
|
||||
return "MO CALL ASSIGNMENT";
|
||||
case TRANS_CALL_MO_ASSIGN_SEND:
|
||||
return "CALL ASSIGN MOBILE ORIGINATING SEND";
|
||||
return "MO CALL ASSIGNMENT SENDING";
|
||||
case TRANS_CALL_MO_ASSIGN_CONFIRM:
|
||||
return "MO CALL ASSIGNMENT WAIT CONFIRM";
|
||||
case TRANS_CALL_MT_ASSIGN:
|
||||
return "CALL ASSIGN MOBILE TERMINATING";
|
||||
return "MT CALL ASSIGNMENT";
|
||||
case TRANS_CALL_MT_ASSIGN_SEND:
|
||||
return "CALL ASSIGN MOBILE TERMINATING SEND";
|
||||
return "MT CALL ASSIGNMENT SENDING";
|
||||
case TRANS_CALL_MT_ASSIGN_CONFIRM:
|
||||
return "MT CALL ASSIGNMENT WAIT CONFIRM";
|
||||
case TRANS_CALL_MT_ALERT:
|
||||
return "CALL ALERT MOBILE TERMINATING";
|
||||
return "MT CALL ALERT";
|
||||
case TRANS_CALL_MT_ALERT_SEND:
|
||||
return "CALL ALERT MOBILE TERMINATING SEND";
|
||||
return "MT CALL ALERT SENDING";
|
||||
case TRANS_CALL_MT_ALERT_CONFIRM:
|
||||
return "MT CALL ALERT WAIT CONFIRM";
|
||||
case TRANS_CALL_MT_ANSWER_WAIT:
|
||||
return "MT CALL ANSWER WAIT";
|
||||
case TRANS_CALL_REJECT:
|
||||
return "CALL REJECT";
|
||||
case TRANS_CALL_REJECT_SEND:
|
||||
|
@ -79,11 +87,15 @@ const char *trans_short_state_name(int state)
|
|||
return "REGISTER";
|
||||
case TRANS_CALL_MO_ASSIGN:
|
||||
case TRANS_CALL_MO_ASSIGN_SEND:
|
||||
case TRANS_CALL_MO_ASSIGN_CONFIRM:
|
||||
case TRANS_CALL_MT_ASSIGN:
|
||||
case TRANS_CALL_MT_ASSIGN_SEND:
|
||||
case TRANS_CALL_MT_ASSIGN_CONFIRM:
|
||||
return "ASSIGN";
|
||||
case TRANS_CALL_MT_ALERT:
|
||||
case TRANS_CALL_MT_ALERT_SEND:
|
||||
case TRANS_CALL_MT_ALERT_CONFIRM:
|
||||
case TRANS_CALL_MT_ANSWER_WAIT:
|
||||
return "ALERT";
|
||||
case TRANS_CALL_REJECT:
|
||||
case TRANS_CALL_REJECT_SEND:
|
||||
|
|
|
@ -5,10 +5,14 @@ enum amps_trans_state {
|
|||
TRANS_REGISTER_ACK_SEND, /* attach request received, sending ack */
|
||||
TRANS_CALL_MO_ASSIGN, /* assigning channel, waiting to send */
|
||||
TRANS_CALL_MO_ASSIGN_SEND, /* assigning channel, sending assignment */
|
||||
TRANS_CALL_MO_ASSIGN_CONFIRM, /* assignment sent, waiting for confirm (SAT) */
|
||||
TRANS_CALL_MT_ASSIGN, /* assigning channel, waiting to send */
|
||||
TRANS_CALL_MT_ASSIGN_SEND, /* assigning channel, sending assignment */
|
||||
TRANS_CALL_MT_ALERT, /* ringing the phone, sending alert order until signaling tone is received */
|
||||
TRANS_CALL_MT_ALERT_SEND, /* ringing the phone, signaling tone is received */
|
||||
TRANS_CALL_MT_ASSIGN_CONFIRM, /* assignment sent, waiting for confirm (SAT) */
|
||||
TRANS_CALL_MT_ALERT, /* ringing the phone, waiting to send alert */
|
||||
TRANS_CALL_MT_ALERT_SEND, /* ringing the phone, sending alert */
|
||||
TRANS_CALL_MT_ALERT_CONFIRM, /* ringing the phone, signaling tone is received */
|
||||
TRANS_CALL_MT_ANSWER_WAIT, /* ringing the phone, waiting for the phone to answer */
|
||||
TRANS_CALL_REJECT, /* rejecting channel, waiting to send */
|
||||
TRANS_CALL_REJECT_SEND, /* rejecting channel, sending reject */
|
||||
TRANS_CALL, /* active call */
|
||||
|
@ -31,6 +35,8 @@ typedef struct transaction {
|
|||
uint8_t ordq;
|
||||
uint8_t order;
|
||||
uint16_t chan; /* channel to assign */
|
||||
int alert_retry; /* current number of alter order (re)try */
|
||||
char caller_id[33]; /* id of calling phone */
|
||||
char dialing[33]; /* number dialed by the phone */
|
||||
enum amps_trans_state state; /* state of transaction */
|
||||
struct timer timer; /* for varous timeouts */
|
||||
|
|
Loading…
Reference in New Issue