AMPS: Caller ID Support

Support for sending caller ID for newer phones.
Currently does not work with older phones, they will abort.
This commit is contained in:
Andreas Eversberg 2017-05-22 18:02:07 +02:00
parent 1a0813069f
commit 4e669ecf79
7 changed files with 237 additions and 72 deletions

View File

@ -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(&amps->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(&amps->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:
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;
}

View File

@ -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);

View File

@ -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;

View File

@ -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(&amps->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;

View File

@ -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_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;

View File

@ -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:

View File

@ -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 */