AMPS: Serveral minor fixes

This commit is contained in:
Andreas Eversberg 2017-05-21 16:40:10 +02:00
parent 76a3484c5c
commit 56024b384b
6 changed files with 75 additions and 37 deletions

View File

@ -95,14 +95,20 @@ enum amps_chan_type amps_channel2type(int channel)
return CHAN_TYPE_VC;
}
char amps_channel2band(int channel)
const char *amps_channel2band(int channel)
{
if (channel >= 991 && channel <= 1023)
return "A''";
if (channel >= 1 && channel <= 333)
return "A";
if (channel >= 334 && channel <= 666)
return 'B';
return "B";
if (channel >= 667 && channel <= 716)
return "A'";
if (channel >= 717 && channel <= 799)
return 'B';
return "B'";
return 'A';
return "<invalid>";
}
static inline int digit2binary(int digit)
@ -227,11 +233,28 @@ const char *amps_scm(uint8_t scm)
{
static char text[64];
sprintf(text, "Class %d / %sontinuous / %d MHz", (scm >> 2) + (scm & 3) + 1, (scm & 4) ? "Disc" : "C", (scm & 8) ? 25 : 20);
sprintf(text, "Class %d / %sontinuous / %d MHz", ((scm & 16) >> 2) + (scm & 3) + 1, (scm & 4) ? "Disc" : "C", (scm & 8) ? 25 : 20);
return text;
}
const char *amps_mpci(uint8_t mpci)
{
switch (mpci) {
case 0:
return "TIA/EIA-553 or IS-54A mobile station";
case 1:
return "TIA/EIA-627 dual-mode mobile station";
case 2:
return "reserved (see TIA/EIA IS-95)";
case 3:
return "EIATIA/EIA-136 dual-mode mobile station";
default:
return "MPCI INVALID, PLEASE FIX!";
}
}
const char *amps_state_name(enum amps_state state)
{
static char invalid[16];
@ -383,10 +406,10 @@ int amps_create(int channel, enum amps_chan_type chan_type, const char *audiodev
amps_t *amps;
int rc;
enum amps_chan_type ct;
char band;
const char *band;
/* check for channel number */
if (channel < 1 || channel > 666) {
if (channel < 1 || (channel > 799 && channel < 991) || channel > 1023) {
PDEBUG(DAMPS, DEBUG_ERROR, "Channel number %d invalid.\n", channel);
return -EINVAL;
}
@ -420,11 +443,11 @@ int amps_create(int channel, enum amps_chan_type chan_type, const char *audiodev
/* check if sid machtes channel band */
band = amps_channel2band(channel);
if (band == 'A' && (sid & 1) == 0 && chan_type != CHAN_TYPE_VC) {
if (band[0] == '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 && chan_type != CHAN_TYPE_VC) {
if (band[0] == '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;
}
@ -434,13 +457,18 @@ int amps_create(int channel, enum amps_chan_type chan_type, const char *audiodev
PDEBUG(DAMPS, DEBUG_NOTICE, "You selected '%s'. This is a hack, but the only way to use control channel and voice channel on one transceiver. Some phones may reject this, but all my phones don't.\n", chan_type_long_name(chan_type));
}
/* check if we selected a voice channel that i outside 20 MHz band */
if (chan_type == CHAN_TYPE_VC && channel > 666) {
PDEBUG(DAMPS, DEBUG_NOTICE, "You selected '%s' on channel #%d. Older phones do not support channels above #666.\n", chan_type_long_name(chan_type), channel);
}
amps = calloc(1, sizeof(amps_t));
if (!amps) {
PDEBUG(DAMPS, DEBUG_ERROR, "No memory!\n");
return -ENOMEM;
}
PDEBUG(DAMPS, DEBUG_DEBUG, "Creating 'AMPS' instance for channel = %d (sample rate %d).\n", channel, samplerate);
PDEBUG(DAMPS, DEBUG_DEBUG, "Creating 'AMPS' instance for channel = %d of band %s (sample rate %d).\n", channel, band, samplerate);
/* init general part of transceiver */
rc = sender_create(&amps->sender, channel, amps_channel2freq(channel, 0), amps_channel2freq(channel, 1), audiodev, use_sdr, samplerate, rx_gain, 0, 0, write_rx_wave, write_tx_wave, read_rx_wave, loopback, 0, PAGING_SIGNAL_NONE);
@ -480,7 +508,7 @@ int amps_create(int channel, enum amps_chan_type chan_type, const char *audiodev
amps_new_state(amps, STATE_BUSY);
#endif
PDEBUG(DAMPS, DEBUG_NOTICE, "Created channel #%d of type '%s' = %s\n", channel, chan_type_short_name(chan_type), chan_type_long_name(chan_type));
PDEBUG(DAMPS, DEBUG_NOTICE, "Created channel #%d (System %s) of type '%s' = %s\n", channel, band, chan_type_short_name(chan_type), chan_type_long_name(chan_type));
return 0;
@ -671,7 +699,7 @@ static void timeout_sat(amps_t *amps, double duration)
}
/* receive message from phone on RECC */
void amps_rx_recc(amps_t *amps, uint8_t scm, uint32_t esn, uint32_t min1, uint16_t min2, uint8_t msg_type, uint8_t ordq, uint8_t order, const char *dialing)
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)
{
amps_t *vc;
transaction_t *trans;
@ -684,7 +712,7 @@ void amps_rx_recc(amps_t *amps, uint8_t scm, uint32_t esn, uint32_t min1, uint16
}
if (order == 13 && (ordq == 0 || ordq == 1 || ordq == 2 || ordq == 3) && msg_type == 0) {
PDEBUG_CHAN(DAMPS, DEBUG_INFO, "Registration %s (ESN = %08x, %s)\n", callerid, esn, amps_scm(scm));
PDEBUG_CHAN(DAMPS, DEBUG_INFO, "Registration %s (ESN = %08x, %s, %s)\n", callerid, esn, amps_scm(scm), amps_mpci(mpci));
trans = create_transaction(amps, TRANS_REGISTER_ACK, min1, min2, msg_type, ordq, order, 0);
if (!trans) {
PDEBUG(DAMPS, DEBUG_ERROR, "Failed to create transaction\n");
@ -692,7 +720,7 @@ void amps_rx_recc(amps_t *amps, uint8_t scm, uint32_t esn, uint32_t min1, uint16
}
} else
if (order == 13 && ordq == 3 && msg_type == 1) {
PDEBUG_CHAN(DAMPS, DEBUG_INFO, "Registration - Power Down %s (ESN = %08x, %s)\n", callerid, esn, amps_scm(scm));
PDEBUG_CHAN(DAMPS, DEBUG_INFO, "Registration - Power Down %s (ESN = %08x, %s, %s)\n", callerid, esn, amps_scm(scm), amps_mpci(mpci));
trans = create_transaction(amps, TRANS_REGISTER_ACK, min1, min2, msg_type, ordq, order, 0);
if (!trans) {
PDEBUG(DAMPS, DEBUG_ERROR, "Failed to create transaction\n");
@ -701,9 +729,9 @@ void amps_rx_recc(amps_t *amps, uint8_t scm, uint32_t esn, uint32_t min1, uint16
} else
if (order == 0 && ordq == 0 && msg_type == 0) {
if (!dialing)
PDEBUG_CHAN(DAMPS, DEBUG_INFO, "Paging reply %s (ESN = %08x, %s)\n", callerid, esn, amps_scm(scm));
PDEBUG_CHAN(DAMPS, DEBUG_INFO, "Paging reply %s (ESN = %08x, %s, %s)\n", callerid, esn, amps_scm(scm), amps_mpci(mpci));
else
PDEBUG_CHAN(DAMPS, DEBUG_INFO, "Call %s -> %s (ESN = %08x, %s)\n", callerid, dialing, esn, amps_scm(scm));
PDEBUG_CHAN(DAMPS, DEBUG_INFO, "Call %s -> %s (ESN = %08x, %s, %s)\n", callerid, dialing, esn, amps_scm(scm), amps_mpci(mpci));
trans = search_transaction_number(amps, min1, min2);
if (!trans && !dialing) {
PDEBUG(DAMPS, DEBUG_NOTICE, "Paging reply, but call is already gone, rejecting call\n");

View File

@ -102,7 +102,8 @@ typedef struct amps {
double fsk_rx_frame_level; /* sum of level of all bits */
double fsk_rx_frame_quality; /* sum of quality of all bits */
/* RECC frame states */
int rx_recc_word_count; /* counts received words */
int rx_recc_nawc; /* counts down received words */
int rx_recc_word_count; /* counts up received words */
uint32_t rx_recc_min1; /* mobile id */
uint16_t rx_recc_min2;
uint8_t rx_recc_msg_type; /* message (3 values) */
@ -110,6 +111,7 @@ typedef struct amps {
uint8_t rx_recc_order;
uint32_t rx_recc_esn;
uint32_t rx_recc_scm;
uint8_t rx_recc_mpci;
char rx_recc_dialing[33]; /* received dial string */
/* FOCC frame states */
int rx_focc_word_count; /* counts received words */
@ -158,7 +160,7 @@ const char *chan_type_short_name(enum amps_chan_type chan_type);
const char *chan_type_long_name(enum amps_chan_type chan_type);
double amps_channel2freq(int channel, int uplink);
enum amps_chan_type amps_channel2type(int channel);
char amps_channel2band(int channel);
const char *amps_channel2band(int channel);
const char *amps_min22number(uint16_t min2);
const char *amps_min12number(uint32_t min1);
void amps_number2min(const char *number, uint32_t *min1, uint16_t *min2);
@ -168,7 +170,7 @@ int amps_create(int channel, enum amps_chan_type chan_type, const char *audiodev
void amps_destroy(sender_t *sender);
void amps_rx_signaling_tone(amps_t *amps, int tone, double quality);
void amps_rx_sat(amps_t *amps, int tone, double quality);
void amps_rx_recc(amps_t *amps, uint8_t scm, uint32_t esn, uint32_t min1, uint16_t min2, uint8_t msg_type, uint8_t ordq, uint8_t order, const char *dialing);
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);
transaction_t *amps_tx_frame_focc(amps_t *amps);
transaction_t *amps_tx_frame_fvc(amps_t *amps);

View File

@ -605,7 +605,7 @@ prepare_frame:
amps->fsk_rx_frame[amps->fsk_rx_frame_count] = '\0';
more = amps_decode_frame(amps, amps->fsk_rx_frame, amps->fsk_rx_frame_count, amps->fsk_rx_frame_level / (double)amps->fsk_rx_frame_count, amps->fsk_rx_frame_quality / amps->fsk_rx_frame_level, (amps->fsk_rx_sync == FSK_SYNC_NEGATIVE));
if (more) {
/* switch to next worda length without DCC included */
/* switch to next word length without DCC included */
amps->fsk_rx_frame_length = 240;
goto prepare_frame;
} else {

View File

@ -1713,21 +1713,21 @@ static const char *ie_cmac(uint64_t value)
{
switch (value) {
case 0:
return "6 dbW";
return "6 dbW (4 Watts)";
case 1:
return "2 dbW";
return "2 dbW (1.6 Watts)";
case 2:
return "-2 dbW";
return "-2 dbW (630 Milliwatts)";
case 3:
return "-6 dbW";
return "-6 dbW (250 Milliwatts)";
case 4:
return "-10 dbW";
return "-10 dbW (100 Milliwatts)";
case 5:
return "-14 dbW";
return "-14 dbW (40 Milliwatts)";
case 6:
return "-18 dbW";
return "-18 dbW (16 Milliwatts)";
}
return "-22";
return "-22 dbW (6.3 Milliwatts)";
}
static const char *ie_cmax(uint64_t value)
@ -2777,7 +2777,7 @@ uint64_t amps_encode_word2_system(uint8_t dcc, uint8_t s, uint8_t e, uint8_t reg
frame.ie[AMPS_IE_E] = e;
frame.ie[AMPS_IE_REGH] = regh;
frame.ie[AMPS_IE_REGR] = regr;
frame.ie[AMPS_IE_DTX] = dtx;
frame.ie[AMPS_IE_DTX_Support] = dtx;
frame.ie[AMPS_IE_N_1] = n_1;
frame.ie[AMPS_IE_RCF] = rcf;
frame.ie[AMPS_IE_CPA] = cpa;
@ -3141,6 +3141,7 @@ static int amps_decode_word_recc(amps_t *amps, uint64_t word, int first)
if (first) {
memset(amps->rx_recc_dialing, 0, sizeof(amps->rx_recc_dialing));
amps->rx_recc_word_count = 0;
amps->rx_recc_nawc = nawc;
if (f == 0) {
PDEBUG_CHAN(DFRAME, DEBUG_NOTICE, "Received first word, but F bit is not set.\n");
return 0;
@ -3150,6 +3151,10 @@ static int amps_decode_word_recc(amps_t *amps, uint64_t word, int first)
PDEBUG_CHAN(DFRAME, DEBUG_NOTICE, "Received additional word, but F bit is set.\n");
return 0;
}
amps->rx_recc_nawc--;
if (amps->rx_recc_nawc != nawc) {
PDEBUG_CHAN(DFRAME, DEBUG_NOTICE, "Received additional word with NAWC missmatch!\n");
}
}
msg_count = amps->rx_recc_word_count;
@ -3159,8 +3164,6 @@ static int amps_decode_word_recc(amps_t *amps, uint64_t word, int first)
return 0;
}
// amps->rx_recc_word[msg_count] = word;
if (msg_count == 0)
w = &abbreviated_address_word;
@ -3210,6 +3213,7 @@ static int amps_decode_word_recc(amps_t *amps, uint64_t word, int first)
amps->rx_recc_ordq = frame->ie[AMPS_IE_ORDQ];
amps->rx_recc_order = frame->ie[AMPS_IE_ORDER];
amps->rx_recc_scm |= frame->ie[AMPS_IE_SCM] << 4;
amps->rx_recc_mpci = frame->ie[AMPS_IE_MPCI];
}
if (amps->rx_recc_word_count == 2 && frame) {
if (amps->si.word2.s)
@ -3258,16 +3262,17 @@ static int amps_decode_word_recc(amps_t *amps, uint64_t word, int first)
amps->rx_recc_dialing[31] = digit2number[frame->ie[AMPS_IE_DIGIT_32]];
}
if (msg_count >= 3 && nawc == 0) {
PDEBUG_CHAN(DFRAME, DEBUG_INFO, "expecting %d more word(s) to come\n", amps->rx_recc_nawc);
if (msg_count >= 3 && amps->rx_recc_nawc == 0) {
/* if no digit messages are present, send NULL as dial string (paging reply) */
amps_rx_recc(amps, amps->rx_recc_scm, amps->rx_recc_esn, amps->rx_recc_min1, amps->rx_recc_min2, amps->rx_recc_msg_type, amps->rx_recc_ordq, amps->rx_recc_order, (msg_count > 3) ? amps->rx_recc_dialing : NULL);
amps_rx_recc(amps, amps->rx_recc_scm, amps->rx_recc_mpci, amps->rx_recc_esn, amps->rx_recc_min1, amps->rx_recc_min2, amps->rx_recc_msg_type, amps->rx_recc_ordq, amps->rx_recc_order, (msg_count > 3) ? amps->rx_recc_dialing : NULL);
}
amps->rx_recc_word_count++;
done:
//printf("left=%d\n", (word >> 44) & 0x7);
if (nawc > 0)
if (amps->rx_recc_nawc > 0)
return 1;
return 0;
@ -3464,7 +3469,7 @@ int amps_encode_frame_fvc(amps_t *amps, char *bits)
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, 0, 0, 0, amps->si.vmac, 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);
} else

View File

@ -74,11 +74,14 @@ void print_help(const char *arg0)
printf(" many second the phone waits before it re-registers.\n");
printf(" -S --sysinfo pureg=0 | pureg=1\n");
printf(" If 1, phone registers on every power on (default = '%d')\n", pureg);
printf(" (Not supported by older phones.)\n");
printf(" -S --sysinfo pdreg=0 | pdreg=1\n");
printf(" If 1, phone de-registers on every power down (default = '%d')\n", pureg);
printf(" (Not supported by older phones.)\n");
printf(" -S --sysinfo locaid=<location area ID > | locaid=-1 to disable\n");
printf(" (default = '%d')\n", locaid);
printf(" If it changes, phone re-registers.\n");
printf(" (Not supported by older phones.)\n");
printf(" -S --sysinfo regh=0 | regh=1\n");
printf(" If 1, phone registers only if System ID matches (default = '%d')\n", regh);
printf(" -S --sysinfo regr=0 | regr=1\n");

View File

@ -70,7 +70,7 @@ void init_sysinfo(amps_si *si, int cmac, int vmac, int dcc, int sid1, int regh,
si->word2.e = 1;
si->word2.regh = regh;
si->word2.regr = regr;
si->word2.dtx = 0;
si->word2.dtx = 0; /* DTX seems not to work with Dynatac 8000 */
si->word2.n_1 = 20;
si->word2.rcf = (bis) ? 0 : 1; /* must be set to ignore B/I bit */
si->word2.cpa = 1; /* must be set for combined CC+PC */