From 4e669ecf796b2bda8f212e6e6aa1c1725a00116c Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Mon, 22 May 2017 18:02:07 +0200 Subject: [PATCH] AMPS: Caller ID Support Support for sending caller ID for newer phones. Currently does not work with older phones, they will abort. --- src/amps/amps.c | 143 ++++++++++++++++++++++++++------------ src/amps/amps.h | 10 ++- src/amps/amps_tacs_main.c | 17 ++++- src/amps/dsp.c | 20 ++++-- src/amps/frame.c | 85 ++++++++++++++++++---- src/amps/transaction.c | 24 +++++-- src/amps/transaction.h | 10 ++- 7 files changed, 237 insertions(+), 72 deletions(-) diff --git a/src/amps/amps.c b/src/amps/amps.c index f6f80df..875c993 100644 --- a/src/amps/amps.c +++ b/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; } diff --git a/src/amps/amps.h b/src/amps/amps.h index ccf879e..0a85df2 100644 --- a/src/amps/amps.h +++ b/src/amps/amps.h @@ -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); diff --git a/src/amps/amps_tacs_main.c b/src/amps/amps_tacs_main.c index fe9cc02..3863f1d 100644 --- a/src/amps/amps_tacs_main.c +++ b/src/amps/amps_tacs_main.c @@ -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= | 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; diff --git a/src/amps/dsp.c b/src/amps/dsp.c index e59a318..445c2c3 100644 --- a/src/amps/dsp.c +++ b/src/amps/dsp.c @@ -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; diff --git a/src/amps/frame.c b/src/amps/frame.c index a99c0c6..e89f3d5 100644 --- a/src/amps/frame.c +++ b/src/amps/frame.c @@ -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; diff --git a/src/amps/transaction.c b/src/amps/transaction.c index 2d25313..f8a4aee 100644 --- a/src/amps/transaction.c +++ b/src/amps/transaction.c @@ -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: diff --git a/src/amps/transaction.h b/src/amps/transaction.h index 2f3c00d..6cd6441 100644 --- a/src/amps/transaction.h +++ b/src/amps/transaction.h @@ -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 */