Implementation of Advanced Mobile Phone Service (AMPS)

This commit is contained in:
Andreas Eversberg 2016-05-01 19:51:56 +02:00
parent 7d5d3da8d3
commit d2c4ca4fa9
33 changed files with 36778 additions and 16 deletions

1
.gitignore vendored
View File

@ -24,5 +24,6 @@ src/anetz/anetz
src/bnetz/bnetz
src/cnetz/cnetz
src/nmt/nmt
src/amps/amps
src/test/test_compander
src/test/test_emphasis

1
README
View File

@ -7,6 +7,7 @@ and from mobile phone. Currently supported networks:
* B-Netz (ATF-1)
* C-Netz
* NMT 450 (Nordic Mobile Telephone)
* AMPS (Advanced Mobile Phone System)
USE AT YOUR OWN RISK!

View File

@ -33,6 +33,7 @@ AC_OUTPUT(
src/bnetz/Makefile
src/cnetz/Makefile
src/nmt/Makefile
src/amps/Makefile
src/test/Makefile
src/Makefile
Makefile)

View File

@ -1,3 +1,3 @@
AUTOMAKE_OPTIONS = foreign
SUBDIRS = common anetz bnetz cnetz nmt test
SUBDIRS = common anetz bnetz cnetz nmt amps test

25
src/amps/Makefile.am Normal file
View File

@ -0,0 +1,25 @@
AM_CPPFLAGS = -Wall -g $(all_includes)
bin_PROGRAMS = \
amps
amps_SOURCES = \
amps.c \
transaction.c \
frame.c \
dsp.c \
sysinfo.c \
image.c \
tones.c \
noanswer.c \
outoforder.c \
invalidnumber.c \
congestion.c \
stations.c \
main.c
amps_LDADD = \
$(COMMON_LA) \
$(top_builddir)/src/common/libcommon.a \
$(ALSA_LIBS) \
-lm

1061
src/amps/amps.c Normal file

File diff suppressed because it is too large Load Diff

160
src/amps/amps.h Normal file
View File

@ -0,0 +1,160 @@
#include "../common/sender.h"
#include "../common/compander.h"
#include "sysinfo.h"
#include "transaction.h"
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_FRAME_RX_FRAME_TX, /* send and decode frames */
};
enum amps_chan_type {
CHAN_TYPE_CC, /* control channel */
CHAN_TYPE_PC, /* paging channel */
CHAN_TYPE_CC_PC, /* combined CC + PC */
CHAN_TYPE_VC, /* voice channel */
CHAN_TYPE_CC_PC_VC, /* combined CC + PC + TC */
};
enum amps_state {
STATE_NULL, /* power off state */
STATE_IDLE, /* channel is not in use */
STATE_BUSY, /* channel busy (call) */
};
enum fsk_rx_sync {
FSK_SYNC_NONE, /* we are not in sync and wait for valid dotting sequence */
FSK_SYNC_DOTTING, /* we received a valid dotting sequence and check for sync sequence */
FSK_SYNC_POSITIVE, /* we have valid sync and read all the bits of the frame */
FSK_SYNC_NEGATIVE, /* as above, but negative sync (high frequency deviation detected as low signal) */
};
#define FSK_MAX_BITS 1032 /* maximum number of bits to process */
typedef struct amps {
sender_t sender;
compander_t cstate;
int pre_emphasis; /* use pre_emphasis by this instance */
int de_emphasis; /* use de_emphasis by this instance */
emphasis_t estate;
/* sender's states */
enum amps_chan_type chan_type;
enum amps_state state;
int page_retry; /* current number of paging (re)try */
/* system info */
amps_si si;
/* cell nr selection */
int cell_auto; /* if set, cell_nr is selected automatically */
/* dsp states */
enum dsp_mode dsp_mode; /* current mode: audio, durable tone 0 or 1, paging */
int flip_polarity; /* 1 = flip */
int16_t fsk_deviation; /* deviation of FSK signal on sound card */
int16_t fsk_ramp_up[256]; /* samples of upward ramp shape */
int16_t fsk_ramp_down[256]; /* samples of downward ramp shape */
double fsk_bitduration; /* duration of one bit in samples */
double fsk_bitstep; /* fraction of one bit each sample */
/* tx bits generation */
int16_t *fsk_tx_buffer; /* tx buffer for one data block */
int fsk_tx_buffer_size; /* size of tx buffer (in samples) */
int fsk_tx_buffer_length; /* usage of buffer (in samples) */
int fsk_tx_buffer_pos; /* current position sending buffer */
double fsk_tx_phase; /* current bit position */
char fsk_tx_last_bit; /* save last bit of frame (for next frame's ramp) */
/* high-pass filter to remove DC offset from RX signal */
double highpass_factor; /* high pass filter factor */
double highpass_x_last; /* last input value */
double highpass_y_last; /* last output value */
/* rx detection of bits and sync */
int16_t fsk_rx_last_sample; /* last sample (for level change detection) */
double fsk_rx_elapsed; /* bit duration since last level change */
enum fsk_rx_sync fsk_rx_sync; /* sync state */
uint16_t fsk_rx_sync_register; /* shift register to detect sync word */
/* the dotting buffer stores the elapsed samples, so we can calculate
* an average time of zero-crossings during dotting sequence.
* this buffer wrapps every 256 values */
double fsk_rx_dotting_elapsed[256]; /* dotting buffer with elapsed samples since last zero-crossing */
uint8_t fsk_rx_dotting_pos; /* position of next value in dotting buffer */
int fsk_rx_dotting_life; /* counter to expire when no sync was found after dotting */
double fsk_rx_dotting_average; /* last average slope position of dotting sequnece. */
/* the ex buffer holds the duration of one bit, and wrapps every
* bit. */
double fsk_rx_bitcount; /* counts the bit. if it reaches or exceeds 1, the bit is complete and the next bit starts */
int16_t *fsk_rx_buffer; /* rx buffer for one bit */
int fsk_rx_buffer_length; /* length of rx buffer */
int fsk_rx_buffer_pos; /* current position in buffer */
/* the rx bufffer received one frame until rx length */
char fsk_rx_frame[FSK_MAX_BITS + 1]; /* +1 because 0-termination */
int fsk_rx_frame_length; /* length of expected frame */
int fsk_rx_frame_count; /* count number of received bit */
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 */
uint32_t rx_recc_min1; /* mobile id */
uint16_t rx_recc_min2;
uint8_t rx_recc_msg_type; /* message (3 values) */
uint8_t rx_recc_ordq;
uint8_t rx_recc_order;
uint32_t rx_recc_esn;
uint32_t rx_recc_scm;
char rx_recc_dialing[33]; /* received dial string */
/* FOCC frame states */
int rx_focc_word_count; /* counts received words */
int tx_focc_frame_count; /* used to schedule system informations */
int tx_focc_send; /* if set, send message words */
uint32_t tx_focc_min1; /* mobile id */
uint16_t tx_focc_min2;
int tx_focc_chan; /* channel to assign for voice call */
uint8_t tx_focc_msg_type; /* message (3 values) */
uint8_t tx_focc_ordq;
uint8_t tx_focc_order;
int tx_focc_word_count; /* counts transmitted words in a muli word message */
int tx_focc_word_repeat; /* countrs repeats of mulit word message */
/* FVC frame states */
int tx_fvc_send; /* if set, send message words */
int tx_fvc_chan; /* channel to assign for voice call */
uint8_t tx_fvc_msg_type; /* message (3 values) */
uint8_t tx_fvc_ordq;
uint8_t tx_fvc_order;
/* SAT tone */
int sat; /* use SAT tone 0..2 */
int sat_samples; /* number of samples in buffer for supervisory detection */
int sat_coeff[5]; /* coefficient for SAT signal decoding */
int16_t *sat_filter_spl; /* array with sample buffer for supervisory detection */
int sat_filter_pos; /* current sample position in filter_spl */
double sat_phaseshift256[3]; /* how much the phase of sine wave changes per sample */
double sat_phase256; /* current phase */
int sat_detected; /* current detection state flag */
int sat_detect_count; /* current number of consecutive detections/losses */
int sig_detected; /* current detection state flag */
int sig_detect_count; /* current number of consecutive detections/losses */
transaction_t *trans_list; /* list of transactions */
} amps_t;
void amps_channel_list(void);
int amps_channel_by_short_name(const char *short_name);
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_min22number(uint16_t min2);
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(int channel, enum amps_chan_type chan_type, const char *sounddev, int samplerate, int cross_channels, double rx_gain, int pre_emphasis, int de_emphasis, const char *write_wave, const char *read_wave, amps_si *si, uint16_t sid, uint8_t sat, int polarity, int loopback);
void amps_destroy(sender_t *sender);
void amps_rx_signalling_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);
transaction_t *amps_tx_frame_focc(amps_t *amps);
transaction_t *amps_tx_frame_fvc(amps_t *amps);

6645
src/amps/congestion.c Normal file

File diff suppressed because it is too large Load Diff

3
src/amps/congestion.h Normal file
View File

@ -0,0 +1,3 @@
void init_congestion(void);

866
src/amps/dsp.c Normal file
View File

@ -0,0 +1,866 @@
/* AMPS audio processing
*
* (C) 2016 by Andreas Eversberg <jolly@eversberg.eu>
* All Rights Reserved
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* How does FSK decoding work:
* ---------------------------
*
* AMPS modulates the carrier frequency. If it is 8 kHz above, it is high level,
* if it is 8 kHz below, it is low level. The bits are coded using Manchester
* code. A 1 is coded by low level, followed by a hight level. A 0 is coded by
* a high level, followed by a low level. This will cause at least one level
* change within each bit. Also the level changes between equal bits, see
* Manchester coding. The bit rate is 10 KHz.
*
* In order to detect and demodulate a frame, the dotting sequnce is searched.
* The dotting sequnece are alternate bits: 101010101... The duration of a
* level change within the dotting sequnene ist 100uS. If all offsets of 8
* level changes lay within +-50% of the expected time, the dotting sequence is
* valid. Now the next 12 bits will be searched for sync sequnece. If better
* dotting-offsets are found, the counter for searching the sync sequence is
* reset, so the next 12 bits will be searched for sync too. If no sync was
* detected, the state changes to search for next dotting sequence.
*
* The average level change offsets of the dotting sequence is used to set the
* window for the first bit. When all samples for the window are received, a
* raise in level is detected as 1, fall in level is detected as 0. This is done
* by substracting the average sample value of the left side of the window by
* the average sample value of the right side. After the bit has been detected,
* the samples for the next window will be received and detected.
*
* As soon as a sync pattern is detected, the polarity of the pattern is used
* to decode the following frame bits with correct polarity. During reception
* of the frame bits, no sync and no dotting sequnece is searched or detected.
*
* After reception of the bit, the bits are re-assembled, parity checked and
* decoded. Then the process hunts for next dotting sequence.
*/
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <math.h>
#include "../common/debug.h"
#include "../common/timer.h"
#include "../common/call.h"
#include "../common/goertzel.h"
#include "amps.h"
#include "frame.h"
#include "dsp.h"
/* uncomment this to debug the encoding process */
//#define DEBUG_ENCODER
/* uncomment this to debug the decoding process */
//#define DEBUG_DECODER
#define PI M_PI
#define FSK_DEVIATION 32767.0 /* +-8 KHz */
#define SAT_DEVIATION 8192.0 /* +-2 KHz */
#define TX_AUDIO_0dBm0 45000 /* works quite well */
#define BITRATE 10000
#define SIG_TONE_CROSSINGS 2000 /* 2000 crossings are 100ms @ 10 KHz */
#define SIG_TONE_MINBITS 950 /* minimum bit durations to detect signalling tone (1000 is perfect for 100 ms) */
#define SIG_TONE_MAXBITS 1050 /* as above, maximum bits */
#define SAT_DURATION 0.100 /* duration of SAT signal measurement */
#define SAT_QUALITY 0.85 /* quality needed to detect sat */
#define SAT_DETECT_COUNT 3 /* number of measures to detect SAT signal */
#define SAT_LOST_COUNT 3 /* number of measures to loose SAT signal */
#define SIG_DETECT_COUNT 3 /* number of measures to detect Signalling Tone */
#define SIG_LOST_COUNT 2 /* number of measures to loose Signalling Tone */
#define CUT_OFF_HIGHPASS 300.0 /* cut off frequency for high pass filter to remove dc level from sound card / sample */
#define BEST_QUALITY 0.68 /* Best possible RX quality */
static int16_t ramp_up[256], ramp_down[256];
static double sat_freq[5] = {
5970.0,
6000.0,
6030.0,
5800.0, /* noise level to check against */
10000.0, /* signalling tone */
};
static int dsp_sine_sat[256];
/* global init for FSK */
void dsp_init(void)
{
int i;
double s;
PDEBUG(DDSP, DEBUG_DEBUG, "Generating sine table for SAT signal.\n");
for (i = 0; i < 256; i++) {
s = sin((double)i / 256.0 * 2.0 * PI);
dsp_sine_sat[i] = (int)(s * SAT_DEVIATION);
}
}
static void dsp_init_ramp(amps_t *amps)
{
double c;
int i;
PDEBUG(DDSP, DEBUG_DEBUG, "Generating smooth ramp table.\n");
for (i = 0; i < 256; i++) {
c = cos((double)i / 256.0 * PI);
#if 0
if (c < 0)
c = -sqrt(-c);
else
c = sqrt(c);
#endif
ramp_down[i] = (int)(c * (double)amps->fsk_deviation);
ramp_up[i] = -ramp_down[i];
}
}
static void sat_reset(amps_t *amps, const char *reason);
/* Init FSK of transceiver */
int dsp_init_sender(amps_t *amps, int high_pass)
{
double coeff;
int16_t *spl;
int i;
int rc;
double RC, dt;
/* attack (3ms) and recovery time (13.5ms) according to amps specs */
init_compander(&amps->cstate, 8000, 3.0, 13.5, TX_AUDIO_0dBm0);
PDEBUG(DDSP, DEBUG_DEBUG, "Init DSP for transceiver.\n");
if (amps->sender.samplerate < 96000) {
PDEBUG(DDSP, DEBUG_ERROR, "Sample rate must be at least 96000 Hz to process FSK and SAT signals.\n");
return -EINVAL;
}
amps->fsk_bitduration = (double)amps->sender.samplerate / (double)BITRATE;
amps->fsk_bitstep = 1.0 / amps->fsk_bitduration;
PDEBUG(DDSP, DEBUG_DEBUG, "Use %.4f samples for full bit duration @ %d.\n", amps->fsk_bitduration, amps->sender.samplerate);
amps->fsk_tx_buffer_size = amps->fsk_bitduration * (double)FSK_MAX_BITS + 10; /* 10 extra to avoid overflow due to routing */
amps->fsk_tx_buffer = calloc(sizeof(int16_t), amps->fsk_tx_buffer_size);
if (!amps->fsk_tx_buffer) {
PDEBUG(DDSP, DEBUG_DEBUG, "No memory!\n");
rc = -ENOMEM;
goto error;
}
amps->fsk_rx_buffer_length = ceil(amps->fsk_bitduration); /* buffer holds one bit (rounded up) */
amps->fsk_rx_buffer = calloc(sizeof(int16_t), amps->fsk_rx_buffer_length);
if (!amps->fsk_rx_buffer) {
PDEBUG(DDSP, DEBUG_DEBUG, "No memory!\n");
rc = -ENOMEM;
goto error;
}
/* create devation and ramp */
amps->fsk_deviation = FSK_DEVIATION; /* be sure not to overflow 32767 */
dsp_init_ramp(amps);
/* allocate ring buffer for SAT signal detection */
amps->sat_samples = (int)((double)amps->sender.samplerate * SAT_DURATION + 0.5);
spl = calloc(1, amps->sat_samples * sizeof(*spl));
if (!spl) {
PDEBUG(DDSP, DEBUG_ERROR, "No memory!\n");
return -ENOMEM;
}
amps->sat_filter_spl = spl;
/* count SAT tones */
for (i = 0; i < 5; i++) {
coeff = 2.0 * cos(2.0 * PI * sat_freq[i] / (double)amps->sender.samplerate);
amps->sat_coeff[i] = coeff * 32768.0;
PDEBUG(DDSP, DEBUG_DEBUG, "sat_coeff[%d] = %d\n", i, (int)amps->sat_coeff[i]);
if (i < 3) {
amps->sat_phaseshift256[i] = 256.0 / ((double)amps->sender.samplerate / sat_freq[i]);
PDEBUG(DDSP, DEBUG_DEBUG, "sat_phaseshift256[%d] = %.4f\n", i, amps->sat_phaseshift256[i]);
}
}
sat_reset(amps, "Initial state");
/* use this filter to remove dc level for 0-crossing detection
* if we have de-emphasis, we don't need it, so high_pass is not set. */
if (high_pass) {
RC = 1.0 / (CUT_OFF_HIGHPASS * 2.0 *3.14);
dt = 1.0 / amps->sender.samplerate;
amps->highpass_factor = RC / (RC + dt);
}
return 0;
error:
dsp_cleanup_sender(amps);
return rc;
}
/* Cleanup transceiver instance. */
void dsp_cleanup_sender(amps_t *amps)
{
PDEBUG(DDSP, DEBUG_DEBUG, "Cleanup DSP for treansceiver.\n");
if (amps->fsk_tx_buffer)
free(amps->fsk_tx_buffer);
if (amps->fsk_rx_buffer)
free(amps->fsk_rx_buffer);
if (amps->sat_filter_spl) {
free(amps->sat_filter_spl);
amps->sat_filter_spl = NULL;
}
#if 0
if (amps->frame_spl) {
free(amps->frame_spl);
amps->frame_spl = NULL;
}
#endif
}
static int fsk_encode(amps_t *amps, const char *bits)
{
int16_t *spl;
double phase, bitstep, deviation;
int count;
char last;
if (strlen(bits) > FSK_MAX_BITS) {
fprintf(stderr, "FSK buffer too small\n");
abort();
}
deviation = amps->fsk_deviation;
spl = amps->fsk_tx_buffer;
phase = amps->fsk_tx_phase;
last = amps->fsk_tx_last_bit;
bitstep = amps->fsk_bitstep * 256.0 * 2.0; /* half bit ramp */
//printf("%s\n", bits);
while (*bits) {
//printf("%d %d\n", (*bits) & 1, last & 1);
if (((*bits) & 1)) {
if ((last & 1)) {
/* last bit was 1, this bit is 1, so we ramp down first */
do {
*spl++ = ramp_down[(int)phase];
phase += bitstep;
} while (phase < 256.0);
phase -= 256.0;
} else {
/* last bit was 0, this bit is 1, so we stay down first */
do {
*spl++ = -deviation;
phase += bitstep;
} while (phase < 256.0);
phase -= 256.0;
}
/* ramp up */
do {
*spl++ = ramp_up[(int)phase];
phase += bitstep;
} while (phase < 256.0);
phase -= 256.0;
} else {
if ((last & 1)) {
/* last bit was 1, this bit is 0, so we stay up first */
do {
*spl++ = deviation;
phase += bitstep;
} while (phase < 256.0);
phase -= 256.0;
} else {
/* last bit was 0, this bit is 0, so we ramp up first */
do {
*spl++ = ramp_up[(int)phase];
phase += bitstep;
} while (phase < 256.0);
phase -= 256.0;
}
/* ramp up */
do {
*spl++ = ramp_down[(int)phase];
phase += bitstep;
} while (phase < 256.0);
phase -= 256.0;
}
last = *bits;
bits++;
}
/* depending on the number of samples, return the number */
count = ((uintptr_t)spl - (uintptr_t)amps->fsk_tx_buffer) / sizeof(*spl);
amps->fsk_tx_last_bit = last;
amps->fsk_tx_phase = phase;
amps->fsk_tx_buffer_length = count;
return count;
}
int fsk_frame(amps_t *amps, int16_t *samples, int length)
{
int count = 0, pos, copy, i;
int16_t *spl;
const char *bits;
again:
/* there must be length, otherwise we would skip blocks */
if (count == length)
return count;
pos = amps->fsk_tx_buffer_pos;
spl = amps->fsk_tx_buffer + pos;
/* start new frame, so we generate one */
if (pos == 0) {
if (amps->dsp_mode == DSP_MODE_AUDIO_RX_FRAME_TX)
bits = amps_encode_frame_fvc(amps);
else
bits = amps_encode_frame_focc(amps);
if (!bits)
return 0;
fsk_encode(amps, bits);
}
copy = amps->fsk_tx_buffer_length - pos;
if (length - count < copy)
copy = length - count;
//printf("pos=%d length=%d copy=%d\n", pos, length, copy);
for (i = 0; i < copy; i++) {
#ifdef DEBUG_ENCODER
puts(debug_amplitude((double)(*spl) / 32767.0));
#endif
*samples++ = *spl++;
}
pos += copy;
count += copy;
if (pos ==amps->fsk_tx_buffer_length) {
amps->fsk_tx_buffer_pos = 0;
goto again;
}
amps->fsk_tx_buffer_pos = pos;
return count;
}
/* Generate audio stream with SAT signal. Keep phase for next call of function. */
static void sat_encode(amps_t *amps, int16_t *samples, int length)
{
double phaseshift, phase;
int32_t sample;
int i;
phaseshift = amps->sat_phaseshift256[amps->sat];
phase = amps->sat_phase256;
for (i = 0; i < length; i++) {
sample = *samples;
sample += dsp_sine_sat[((uint8_t)phase) & 0xff];
if (sample > 32767)
sample = 32767;
else if (sample < -32767)
sample = -32767;
*samples++ = sample;
phase += phaseshift;
if (phase >= 256)
phase -= 256;
}
amps->sat_phase256 = phase;
}
/* Provide stream of audio toward radio unit */
void sender_send(sender_t *sender, int16_t *samples, int length)
{
amps_t *amps = (amps_t *) sender;
int count;
again:
switch (amps->dsp_mode) {
case DSP_MODE_OFF:
off:
/* silence, if transmitter is off */
memset(samples, 0, length * sizeof(*samples));
break;
case DSP_MODE_AUDIO_RX_AUDIO_TX:
audio:
jitter_load(&amps->sender.audio, samples, length);
/* pre-emphasis */
if (amps->pre_emphasis)
pre_emphasis(&amps->estate, samples, length);
/* encode sat */
sat_encode(amps, samples, length);
break;
case DSP_MODE_AUDIO_RX_FRAME_TX:
case DSP_MODE_FRAME_RX_FRAME_TX:
/* Encode frame into audio stream. If frames have
* stopped, process again for rest of stream. */
count = fsk_frame(amps, samples, length);
#if 0
/* special case: add SAT signal to frame at loop test */
if (amps->sender.loopback)
sat_encode(amps, samples, length);
#endif
/* count == 0: no frame, this should not happen */
if (count == 0)
goto off;
/* * also if the mode changed to audio during processing */
if (amps->dsp_mode == DSP_MODE_AUDIO_RX_AUDIO_TX)
goto audio;
samples += count;
length -= count;
goto again;
break;
}
}
void fsk_rx_bit(amps_t *amps, int16_t *spl, int len, int pos)
{
int i, ii;
int32_t first, second;
int bit;
int32_t max = -32768, min = 32767;
/* decode one bit. substact the first half from the second half.
* the result shows the direction of the bit change: 1 == positive.
*/
ii = len >> 1;
second = first = 0;
for (i = 0; i < ii; i++) {
if (--pos < 0)
pos = len - 1;
//printf("second %d: %d\n", pos, spl[pos]);
second += spl[pos];
if (spl[pos] > max)
max = spl[pos];
if (spl[pos] < min)
min = spl[pos];
}
second /= ii;
for (i = 0; i < ii; i++) {
if (--pos < 0)
pos = len - 1;
//printf("first %d: %d\n", pos, spl[pos]);
first += spl[pos];
if (spl[pos] > max)
max = spl[pos];
if (spl[pos] < min)
min = spl[pos];
}
first /= ii;
//printf("first = %d second = %d\n", first, second);
/* get bit */
if (second > first)
bit = 1;
else
bit = 0;
#ifdef DEBUG_DECODER
if (amps->fsk_rx_sync != FSK_SYNC_POSITIVE && amps->fsk_rx_sync != FSK_SYNC_NEGATIVE)
printf("Decoded bit as %d (dotting life = %d)\n", bit, amps->fsk_rx_dotting_life);
else
printf("Decoded bit as %d\n", bit);
#endif
if (amps->fsk_rx_sync != FSK_SYNC_POSITIVE && amps->fsk_rx_sync != FSK_SYNC_NEGATIVE) {
amps->fsk_rx_sync_register = (amps->fsk_rx_sync_register << 1) | bit;
/* check if we received a sync */
if ((amps->fsk_rx_sync_register & 0x7ff) == 0x712) {
#ifdef DEBUG_DECODER
printf("Sync word detected (positive)\n");
#endif
amps->fsk_rx_sync = FSK_SYNC_POSITIVE;
prepare_frame:
amps->fsk_rx_frame_count = 0;
amps->fsk_rx_frame_quality = 0.0;
amps->fsk_rx_frame_level = 0.0;
amps->fsk_rx_sync_register = 0x555;
return;
}
if ((amps->fsk_rx_sync_register & 0x7ff) == 0x0ed) {
#ifdef DEBUG_DECODER
printf("Sync word detected (negative)\n");
#endif
amps->fsk_rx_sync = FSK_SYNC_NEGATIVE;
goto prepare_frame;
return;
}
/* if no sync, count down the dotting life counter */
if (--amps->fsk_rx_dotting_life == 0) {
#ifdef DEBUG_DECODER
printf("No Sync detected after dotting\n");
#endif
amps->fsk_rx_sync = FSK_SYNC_NONE;
return;
}
return;
}
/* count level and quality */
amps->fsk_rx_frame_level += (double)(max - min) / (double)FSK_DEVIATION / 2.0;
if (bit)
amps->fsk_rx_frame_quality += (double)(second - first) / (double)FSK_DEVIATION / 2.0 / BEST_QUALITY;
else
amps->fsk_rx_frame_quality += (double)(first - second) / (double)FSK_DEVIATION / 2.0 / BEST_QUALITY;
/* invert bit if negative sync was detected */
if (amps->fsk_rx_sync == FSK_SYNC_NEGATIVE)
bit = 1 - bit;
/* read next bit. after all bits, we reset to FSK_SYNC_NONE */
amps->fsk_rx_frame[amps->fsk_rx_frame_count++] = bit + '0';
if (amps->fsk_rx_frame_count > FSK_MAX_BITS) {
fprintf(stderr, "our fsk_tx_count (%d) is larger than our max bits we can handle, please fix!\n", amps->fsk_rx_frame_count);
abort();
}
if (amps->fsk_rx_frame_count == amps->fsk_rx_frame_length) {
int more;
/* a complete frame was received, so we process it */
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 */
amps->fsk_rx_frame_length = 240;
goto prepare_frame;
} else {
/* switch back to first word length with DCC included */
if (amps->fsk_rx_frame_length == 240)
amps->fsk_rx_frame_length = 247;
amps->fsk_rx_sync = FSK_SYNC_NONE;
}
}
}
void fsk_rx_dotting(amps_t *amps, double _elapsed, int dir)
{
uint8_t pos = amps->fsk_rx_dotting_pos++;
double average, elapsed, offset;
int i;
#ifdef DEBUG_DECODER
printf("Level change detected\n");
#endif
/* store into dotting list */
amps->fsk_rx_dotting_elapsed[pos++] = _elapsed;
/* check quality of dotting sequence.
* in case this is not a dotting sequence, noise or speech, the quality
* should be bad.
* count (only) 7 'elapsed' values between 8 zero-crossings.
* calculate the average relative to the current position.
*/
average = 0.0;
elapsed = 0.0;
for (i = 1; i < 8; i++) {
elapsed += amps->fsk_rx_dotting_elapsed[--pos];
offset = elapsed - (double)i;
if (offset >= 0.5 || offset <= -0.5) {
#ifdef DEBUG_DECODER
// printf("offset %.3f (last but %d) not within -0.5 .. 0.5 bit position, detecting no dotting.\n", offset, i - 1);
#endif
return;
}
average += offset;
}
average /= (double)i;
amps->fsk_rx_dotting_life = 12;
/* if we are already found dotting, we detect better dotting.
* this happens, if dotting was falsely detected due to noise.
* then the real dotting causes a reastart of hunting for sync sequence.
*/
if (amps->fsk_rx_sync == FSK_SYNC_NONE || fabs(average) < amps->fsk_rx_dotting_average) {
#ifdef DEBUG_DECODER
printf("Found (better) dotting sequence (average = %.3f)\n", average);
#endif
amps->fsk_rx_sync = FSK_SYNC_DOTTING;
amps->fsk_rx_dotting_average = fabs(average);
amps->fsk_rx_bitcount = 0.5 + average;
}
}
/* decode frame */
void sender_receive_frame(amps_t *amps, int16_t *samples, int length)
{
int16_t *spl, last_sample;
int len, pos;
double bitstep, elapsed;
int i;
bitstep = amps->fsk_bitstep;
spl = amps->fsk_rx_buffer;
pos = amps->fsk_rx_buffer_pos;
len = amps->fsk_rx_buffer_length;
last_sample = amps->fsk_rx_last_sample;
elapsed = amps->fsk_rx_elapsed;
for (i = 0; i < length; i++) {
#ifdef DEBUG_DECODER
puts(debug_amplitude((double)samples[i] / (double)FSK_DEVIATION));
#endif
/* push sample to detection window and shift */
spl[pos++] = samples[i];
if (pos == len)
pos = 0;
if (amps->fsk_rx_sync != FSK_SYNC_POSITIVE && amps->fsk_rx_sync != FSK_SYNC_NEGATIVE) {
/* check for change in polarity */
if (last_sample <= 0) {
if (samples[i] > 0) {
fsk_rx_dotting(amps, elapsed, 1);
elapsed = 0.0;
}
} else {
if (samples[i] <= 0) {
fsk_rx_dotting(amps, elapsed, 0);
elapsed = 0.0;
}
}
}
last_sample = samples[i];
elapsed += bitstep;
// printf("%.4f\n", bitcount);
if (amps->fsk_rx_sync != FSK_SYNC_NONE) {
amps->fsk_rx_bitcount += bitstep;
if (amps->fsk_rx_bitcount >= 1.0) {
amps->fsk_rx_bitcount -= 1.0;
fsk_rx_bit(amps, spl, len, pos);
}
}
}
amps->fsk_rx_last_sample = last_sample;
amps->fsk_rx_elapsed = elapsed;
amps->fsk_rx_buffer_pos = pos;
}
/* decode signalling tone */
/* compare supervisory signal against noise floor on 5800 Hz */
static void sat_decode(amps_t *amps, int16_t *samples, int length)
{
int coeff[3];
double result[3], quality[2];
coeff[0] = amps->sat_coeff[amps->sat];
coeff[1] = amps->sat_coeff[3]; /* noise floor detection */
coeff[2] = amps->sat_coeff[4]; /* signalling tone */
audio_goertzel(samples, length, 0, coeff, result, 3);
quality[0] = (result[0] - result[1]) / result[0];
if (quality[0] < 0)
quality[0] = 0;
quality[1] = (result[2] - result[1]) / result[2];
if (quality[1] < 0)
quality[1] = 0;
PDEBUG(DDSP, DEBUG_NOTICE, "SAT level %.2f%% quality %.0f%%\n", result[0] * 32767.0 / SAT_DEVIATION / 0.63662 * 100.0, quality[0] * 100.0);
if (amps->sender.loopback || debuglevel == DEBUG_DEBUG) {
PDEBUG(DDSP, debuglevel, "Signalling Tone level %.2f%% quality %.0f%%\n", result[2] * 32767.0 / FSK_DEVIATION / 0.63662 * 100.0, quality[1] * 100.0);
}
if (quality[0] > SAT_QUALITY) {
if (amps->sat_detected == 0) {
amps->sat_detect_count++;
if (amps->sat_detect_count == SAT_DETECT_COUNT) {
amps->sat_detected = 1;
amps->sat_detect_count = 0;
PDEBUG(DDSP, DEBUG_DEBUG, "SAT signal detected with level=%.0f%%, quality=%.0f%%.\n", result[0] / 0.63662 * 100.0, quality[0] * 100.0);
amps_rx_sat(amps, 1, quality[0]);
}
} else
amps->sat_detect_count = 0;
} else {
if (amps->sat_detected == 1) {
amps->sat_detect_count++;
if (amps->sat_detect_count == SAT_LOST_COUNT) {
amps->sat_detected = 0;
amps->sat_detect_count = 0;
PDEBUG(DDSP, DEBUG_DEBUG, "SAT signal lost.\n");
amps_rx_sat(amps, 0, 0.0);
}
} else
amps->sat_detect_count = 0;
}
if (quality[1] > 0.8) {
if (amps->sig_detected == 0) {
amps->sig_detect_count++;
if (amps->sig_detect_count == SIG_DETECT_COUNT) {
amps->sig_detected = 1;
amps->sig_detect_count = 0;
PDEBUG(DDSP, DEBUG_DEBUG, "Signalling Tone detected with level=%.0f%%, quality=%.0f%%.\n", result[2] / 0.63662 * 100.0, quality[1] * 100.0);
amps_rx_signalling_tone(amps, 1, quality[1]);
}
} else
amps->sig_detect_count = 0;
} else {
if (amps->sig_detected == 1) {
amps->sig_detect_count++;
if (amps->sig_detect_count == SIG_LOST_COUNT) {
amps->sig_detected = 0;
amps->sig_detect_count = 0;
PDEBUG(DDSP, DEBUG_DEBUG, "Signalling Tone lost.\n");
amps_rx_signalling_tone(amps, 0, 0.0);
}
} else
amps->sig_detect_count = 0;
}
}
/* decode signalling/audio */
/* Count SIG_TONE_CROSSINGS of zero crossings, then check if the elapsed bit
* time is between SIG_TONE_MINBITS and SIG_TONE_MAXBITS. If it is, the
* frequency is close to the singalling tone, so it is detected
*/
void sender_receive_audio(amps_t *amps, int16_t *samples, int length)
{
transaction_t *trans = amps->trans_list;
int16_t *spl;
int max, pos;
int i;
/* SAT detection */
max = amps->sat_samples;
spl = amps->sat_filter_spl;
pos = amps->sat_filter_pos;
for (i = 0; i < length; i++) {
spl[pos++] = samples[i];
if (pos == max) {
pos = 0;
sat_decode(amps, spl, max);
}
}
amps->sat_filter_pos = pos;
/* receive audio, but only if call established and SAT detected */
if ((amps->dsp_mode == DSP_MODE_AUDIO_RX_AUDIO_TX || amps->dsp_mode == DSP_MODE_AUDIO_RX_FRAME_TX)
&& amps->sender.callref && trans && trans->sat_detected) {
int16_t down[length]; /* more than enough */
int pos, count;
int16_t *spl;
int i;
/* de-emphasis */
if (amps->de_emphasis)
de_emphasis(&amps->estate, samples, length);
/* downsample */
count = samplerate_downsample(&amps->sender.srstate, samples, length, down);
expand_audio(&amps->cstate, down, count);
spl = amps->sender.rxbuf;
pos = amps->sender.rxbuf_pos;
for (i = 0; i < count; i++) {
spl[pos++] = down[i];
if (pos == 160) {
call_tx_audio(amps->sender.callref, spl, 160);
pos = 0;
}
}
amps->sender.rxbuf_pos = pos;
} else
amps->sender.rxbuf_pos = 0;
}
/* Process received audio stream from radio unit. */
void sender_receive(sender_t *sender, int16_t *samples, int length)
{
amps_t *amps = (amps_t *) sender;
double x, y, x_last, y_last, factor;
int32_t value;
int i;
/* high pass filter to remove 0-level
* if factor is not set, we should already have 0-level. */
factor = amps->highpass_factor;
if (factor) {
x_last = amps->highpass_x_last;
y_last = amps->highpass_y_last;
for (i = 0; i < length; i++) {
x = (double)samples[i];
y = factor * (y_last + x - x_last);
x_last = x;
y_last = y;
value = (int32_t)(y + 0.5);
if (value < -32768.0)
value = -32768.0;
else if (value > 32767)
value = 32767;
samples[i] = value;
}
amps->highpass_x_last = x_last;
amps->highpass_y_last = y_last;
}
switch (amps->dsp_mode) {
case DSP_MODE_OFF:
break;
case DSP_MODE_FRAME_RX_FRAME_TX:
sender_receive_frame(amps, samples, length);
break;
case DSP_MODE_AUDIO_RX_AUDIO_TX:
case DSP_MODE_AUDIO_RX_FRAME_TX:
sender_receive_audio(amps, samples, length);
break;
}
}
/* Reset SAT detection states, so ongoing tone will be detected again. */
static void sat_reset(amps_t *amps, const char *reason)
{
PDEBUG(DDSP, DEBUG_DEBUG, "SAT detector reset: %s.\n", reason);
amps->sat_detected = 0;
amps->sat_detect_count = 0;
amps->sig_detected = 0;
amps->sig_detect_count = 0;
}
void amps_set_dsp_mode(amps_t *amps, enum dsp_mode mode, int frame_length)
{
#if 0
/* reset telegramm */
if (mode == DSP_MODE_FRAME && amps->dsp_mode != mode)
amps->frame = 0;
#endif
if (mode == DSP_MODE_FRAME_RX_FRAME_TX) {
/* reset SAT detection */
sat_reset(amps, "Change to FOCC");
}
if (amps->dsp_mode == DSP_MODE_FRAME_RX_FRAME_TX
&& (mode == DSP_MODE_AUDIO_RX_AUDIO_TX || mode == DSP_MODE_AUDIO_RX_FRAME_TX)) {
/* reset SAT detection */
sat_reset(amps, "Change from FOCC to FVC");
}
amps->dsp_mode = mode;
if (frame_length)
amps->fsk_rx_frame_length = frame_length;
/* reset detection process */
amps->fsk_rx_sync = FSK_SYNC_NONE;
amps->fsk_rx_sync_register = 0x555;
/* reset transmitter */
amps->fsk_tx_buffer_pos = 0;
}

6
src/amps/dsp.h Normal file
View File

@ -0,0 +1,6 @@
void dsp_init(void);
int dsp_init_sender(amps_t *amps, int high_pass);
void dsp_cleanup_sender(amps_t *amps);
void amps_set_dsp_mode(amps_t *amps, enum dsp_mode mode, int frame_length);

3671
src/amps/frame.c Normal file

File diff suppressed because it is too large Load Diff

225
src/amps/frame.h Normal file
View File

@ -0,0 +1,225 @@
enum amps_ie {
AMPS_IE_010111,
AMPS_IE_1,
AMPS_IE_11,
AMPS_IE_1111,
AMPS_IE_ACT,
AMPS_IE_AUTH,
AMPS_IE_AUTHBS,
AMPS_IE_AUTHR,
AMPS_IE_AUTHU,
AMPS_IE_Acked_Data,
AMPS_IE_Async_Data,
AMPS_IE_BIS,
AMPS_IE_BSCAP,
AMPS_IE_BSPC,
AMPS_IE_CHAN,
AMPS_IE_CHANPOS,
AMPS_IE_CHARACTER_1,
AMPS_IE_CHARACTER_2,
AMPS_IE_CHARACTER_3,
AMPS_IE_CMAC,
AMPS_IE_CMAX_1,
AMPS_IE_COUNT,
AMPS_IE_CPA,
AMPS_IE_CPN_RL,
AMPS_IE_CRC,
AMPS_IE_CRI_E11,
AMPS_IE_CRI_E12,
AMPS_IE_CRI_E13,
AMPS_IE_CRI_E14,
AMPS_IE_CRI_E21,
AMPS_IE_CRI_E22,
AMPS_IE_CRI_E23,
AMPS_IE_CRI_E24,
AMPS_IE_CRI_E31,
AMPS_IE_CRI_E32,
AMPS_IE_CRI_E33,
AMPS_IE_CRI_E34,
AMPS_IE_CRI_E41,
AMPS_IE_CRI_E42,
AMPS_IE_CRI_E43,
AMPS_IE_CRI_E44,
AMPS_IE_CRI_E51,
AMPS_IE_CRI_E52,
AMPS_IE_CRI_E53,
AMPS_IE_CRI_E54,
AMPS_IE_CRI_E61,
AMPS_IE_CRI_E62,
AMPS_IE_CRI_E63,
AMPS_IE_CRI_E64,
AMPS_IE_CRI_E71,
AMPS_IE_CRI_E72,
AMPS_IE_CRI_E73,
AMPS_IE_CRI_E74,
AMPS_IE_CRI_E81,
AMPS_IE_CRI_E82,
AMPS_IE_CRI_E83,
AMPS_IE_CRI_E84,
AMPS_IE_DCC,
AMPS_IE_DIGIT_1,
AMPS_IE_DIGIT_10,
AMPS_IE_DIGIT_11,
AMPS_IE_DIGIT_12,
AMPS_IE_DIGIT_13,
AMPS_IE_DIGIT_14,
AMPS_IE_DIGIT_15,
AMPS_IE_DIGIT_16,
AMPS_IE_DIGIT_17,
AMPS_IE_DIGIT_18,
AMPS_IE_DIGIT_19,
AMPS_IE_DIGIT_2,
AMPS_IE_DIGIT_20,
AMPS_IE_DIGIT_21,
AMPS_IE_DIGIT_22,
AMPS_IE_DIGIT_23,
AMPS_IE_DIGIT_24,
AMPS_IE_DIGIT_25,
AMPS_IE_DIGIT_26,
AMPS_IE_DIGIT_27,
AMPS_IE_DIGIT_28,
AMPS_IE_DIGIT_29,
AMPS_IE_DIGIT_3,
AMPS_IE_DIGIT_30,
AMPS_IE_DIGIT_31,
AMPS_IE_DIGIT_32,
AMPS_IE_DIGIT_4,
AMPS_IE_DIGIT_5,
AMPS_IE_DIGIT_6,
AMPS_IE_DIGIT_7,
AMPS_IE_DIGIT_8,
AMPS_IE_DIGIT_9,
AMPS_IE_DMAC,
AMPS_IE_DTX,
AMPS_IE_DTX_Support,
AMPS_IE_DVCC,
AMPS_IE_Data_Part,
AMPS_IE_Data_Privacy,
AMPS_IE_E,
AMPS_IE_EC,
AMPS_IE_EF,
AMPS_IE_END,
AMPS_IE_EP,
AMPS_IE_ER,
AMPS_IE_ESN,
AMPS_IE_F,
AMPS_IE_G3_Fax,
AMPS_IE_HDVCC,
AMPS_IE_Hyperband,
AMPS_IE_LOCAID,
AMPS_IE_LOCAL_CONTROL,
AMPS_IE_LOCAL_MSG_TYPE,
AMPS_IE_LREG,
AMPS_IE_LT,
AMPS_IE_MAXBUSY_OTHER,
AMPS_IE_MAXBUSY_PGR,
AMPS_IE_MAXSZTR_OTHER,
AMPS_IE_MAXSZTR_PGR,
AMPS_IE_MEM,
AMPS_IE_MIN1,
AMPS_IE_MIN2,
AMPS_IE_MPCI,
AMPS_IE_MSCAP,
AMPS_IE_MSPC,
AMPS_IE_N_1,
AMPS_IE_NAWC ,
AMPS_IE_NEWACC,
AMPS_IE_NULL,
AMPS_IE_OHD,
AMPS_IE_OLC_0,
AMPS_IE_OLC_1,
AMPS_IE_OLC_10,
AMPS_IE_OLC_11,
AMPS_IE_OLC_12,
AMPS_IE_OLC_13,
AMPS_IE_OLC_14,
AMPS_IE_OLC_15,
AMPS_IE_OLC_2,
AMPS_IE_OLC_3,
AMPS_IE_OLC_4,
AMPS_IE_OLC_5,
AMPS_IE_OLC_6,
AMPS_IE_OLC_7,
AMPS_IE_OLC_8,
AMPS_IE_OLC_9,
AMPS_IE_ORDER,
AMPS_IE_ORDQ,
AMPS_IE_P,
AMPS_IE_PCI,
AMPS_IE_PCI_HOME,
AMPS_IE_PCI_ROAM,
AMPS_IE_PDREG,
AMPS_IE_PI,
AMPS_IE_PM,
AMPS_IE_PM_D,
AMPS_IE_PSCC,
AMPS_IE_PUREG,
AMPS_IE_PVI,
AMPS_IE_RAND1_A,
AMPS_IE_RAND1_B,
AMPS_IE_RANDBS,
AMPS_IE_RANDC,
AMPS_IE_RANDSSD_1,
AMPS_IE_RANDSSD_2,
AMPS_IE_RANDSSD_3,
AMPS_IE_RANDU,
AMPS_IE_RCF,
AMPS_IE_REGH,
AMPS_IE_REGID,
AMPS_IE_REGINCR,
AMPS_IE_REGR,
AMPS_IE_RLP,
AMPS_IE_RL_W,
AMPS_IE_RSVD,
AMPS_IE_S,
AMPS_IE_SAP,
AMPS_IE_SBI,
AMPS_IE_SCC,
AMPS_IE_SCM,
AMPS_IE_SDCC1,
AMPS_IE_SDCC2,
AMPS_IE_SI,
AMPS_IE_SID1,
AMPS_IE_SIGNAL,
AMPS_IE_Service_Code,
AMPS_IE_T,
AMPS_IE_T1T2,
AMPS_IE_TA,
AMPS_IE_TCI1,
AMPS_IE_TCI21,
AMPS_IE_TCI22,
AMPS_IE_TCI23,
AMPS_IE_TCI24,
AMPS_IE_TCI31,
AMPS_IE_TCI32,
AMPS_IE_TCI33,
AMPS_IE_TCI34,
AMPS_IE_TCI41,
AMPS_IE_TCI42,
AMPS_IE_TCI43,
AMPS_IE_TCI44,
AMPS_IE_TCI5,
AMPS_IE_VMAC,
AMPS_IE_WFOM,
AMPS_IE_NUM
};
typedef struct amps_frame {
enum amps_ie ie[AMPS_IE_NUM];
} frame_t;
void init_frame(void);
uint64_t amps_encode_word1_system(uint8_t dcc, uint16_t sid1, uint8_t ep, uint8_t auth, uint8_t pci, uint8_t nawc);
uint64_t amps_encode_word2_system(uint8_t dcc, uint8_t s, uint8_t e, uint8_t regh, uint8_t regr, uint8_t dtx, uint8_t n_1, uint8_t rcf, uint8_t cpa, uint8_t cmax_1, uint8_t end);
uint64_t amps_encode_registration_id(uint8_t dcc, uint32_t regid, uint8_t end);
uint64_t amps_encode_registration_increment(uint8_t dcc, uint16_t regincr, uint8_t end);
uint64_t amps_encode_location_area(uint8_t dcc, uint8_t pureg, uint8_t pdreg, uint8_t lreg, uint16_t locaid, uint8_t end);
uint64_t amps_encode_new_access_channel_set(uint8_t dcc, uint16_t newacc, uint8_t end);
uint64_t amps_encode_overload_control(uint8_t dcc, uint8_t *olc, uint8_t end);
uint64_t amps_encode_access_type(uint8_t dcc, uint8_t bis, uint8_t pci_home, uint8_t pci_roam, uint8_t bspc, uint8_t bscap, uint8_t end);
uint64_t amps_encode_access_attempt(uint8_t dcc, uint8_t maxbusy_pgr, uint8_t maxsztr_pgr, uint8_t maxbusy_other, uint8_t maxsztr_other, uint8_t end);
const char *amps_encode_frame_focc(amps_t *amps);
const char *amps_encode_frame_fvc(amps_t *amps);
int amps_decode_frame(amps_t *amps, const char *bits, int count, double level, double quality, int negative);

73
src/amps/image.c Normal file
View File

@ -0,0 +1,73 @@
#include <stdio.h>
#include <string.h>
#include "image.h"
const char *image[] = {
"",
" @R| |",
" @Y| @R/|===|\\",
" @Y-=@wO@Y=- @R/ |\\ /| \\ @w~",
" @Y| @wAMPS @R/ | X | \\ @w~",
" @R/ |===| \\",
" @R/ | |\\ \\",
" @R/ /| | \\ \\ @w~",
" @R|--| / / |===| \\ \\",
" @R/|\\/|\\ / / | | \\ \\",
" @R/ |--| \\ / / | | \\ \\",
" @R/ | |\\ \\ / / |===| \\ \\",
"@g__ @R/ /|--| \\ \\ / / | | \\ \\",
"@g \\_ @R/ / | | \\ \\ / / | | \\ \\",
"@g \\ @R/ / | | \\ \\______/ / | | \\| \\|",
"@g \\@R=========================================================================",
"@g \\_______@R|/\\|@g______ _@G***@g_@G*@g__@G**@g_@G***@g___@G**@g_@G*@g_@R| X | @R|MMMM|",
"@g \\__ @R|\\/|@g \\______/@G* ** * * * ** * @R|/ \\|@g______@y________@R|MMMM|",
"@y _____@g \\_@R|/\\|@G * * * * ** * * * * * * @R|\\ /|@G*@y____/ ~ ~ ~ ~",
"@y/ ~ ~\\@b_______@RI@b__@RI@b_________@G*@b______@G*@b_@G*@b___@G*@b__@G*@b___@G*@b__@G*@b_@G*@b_@R| X |@y/ ~ ~ _________",
"@y_______\\@b _ _ _ _ _ _ _ _ _ _ @R|/@y_@R\\@y/ ~ ______/",
"@b _ _ _ _ _ _ _ @y_/~ ~ ____/ ~ ~ ~",
"@b_ @y_@b _ _ _ _ _ @y/_____/ ~ ____________",
"@y__/~\\______________@b _ _ _ _ @y_/ ~ ~ __________/ ~ ~ ~",
"@y ~ ~ ~ \\____________________________/ / ~ ~ ~ ~ ~",
"@w",
NULL
};
void print_image(void)
{
int i, j;
for (i = 0; image[i]; i++) {
for (j = 0; j < strlen(image[i]); j++) {
if (image[i][j] == '@') {
j++;
switch(image[i][j]) {
case 'R': /* bright red */
printf("\033[1;31m");
break;
case 'g': /* gray */
printf("\033[0;37m");
break;
case 'G': /* green */
printf("\033[0;32m");
break;
case 'w': /* white */
printf("\033[1;37m");
break;
case 'b': /* blue */
printf("\033[0;34m");
break;
case 'y': /* yellow */
printf("\033[0;33m");
break;
case 'Y': /* bright yellow */
printf("\033[1;33m");
break;
}
} else
printf("%c", image[i][j]);
}
printf("\n");
}
printf("\033[0;39m");
}

3
src/amps/image.h Normal file
View File

@ -0,0 +1,3 @@
void print_image(void);

7222
src/amps/invalidnumber.c Normal file

File diff suppressed because it is too large Load Diff

3
src/amps/invalidnumber.h Normal file
View File

@ -0,0 +1,3 @@
void init_invalidnumber(void);

379
src/amps/main.c Normal file
View File

@ -0,0 +1,379 @@
/* AMPS main
*
* (C) 2016 by Andreas Eversberg <jolly@eversberg.eu>
* All Rights Reserved
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <stdint.h>
#include <getopt.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <sched.h>
#include "../common/main.h"
#include "../common/debug.h"
#include "../common/timer.h"
#include "../common/call.h"
#include "../common/mncc_sock.h"
#include "amps.h"
#include "dsp.h"
#include "frame.h"
#include "image.h"
#include "tones.h"
#include "noanswer.h"
#include "outoforder.h"
#include "invalidnumber.h"
#include "congestion.h"
#include "stations.h"
/* settings */
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, dcc = 0, scc = 0, sid = 40, regh = 1, regr = 1, pureg = 1, pdreg = 1, locaid = -1, regincr = 300;
void print_help(const char *arg0)
{
print_help_common(arg0, "-E -e -F yes | no ");
/* - - */
printf(" -t --channel-type <channel type> | list\n");
printf(" Give channel type, use 'list' to get a list. (default = '%s')\n", chan_type_short_name(chan_type[0]));
printf(" -F --flip-polarity no | yes\n");
printf(" Flip polarity of transmitted FSK signal. If yes, the sound card\n");
printf(" generates a negative signal rather than a positive one. Be sure that\n");
printf(" a positive signal causes a positive deviation on your transmitter.\n");
printf(" If the phone shows 'NoSrv', try the other way.\n");
printf(" -P --ms-power <power level>\n");
printf(" Give power level of the mobile station 0..7. (default = '%d')\n", ms_power);
printf(" 0 = 4 W; 1 = 1.6 W; 2 = 630 mW; 3 = 250 mW;\n");
printf(" 4 = 100 mW; 5 = 40 mW; 6 = 16 mW; 7 = 6.3 mW\n");
printf(" -S --sysinfo sid=<System ID> | sid=list\n");
printf(" Give system ID of cell broadcast (default = '%d')\n", sid);
printf(" If it changes, phone re-registers. Use 'sid=list' to get a full list.\n");
printf(" -S --sysinfo dcc=<digital color code>\n");
printf(" Give digital color code 0..3 (default = '%d')\n", dcc);
printf(" -S --sysinfo scc=<SAT color code>\n");
printf(" Give supervisor tone color code 0..2 (default = '%d')\n", scc);
printf(" -S --sysinfo regincr\n");
printf(" Amount to add to REGID after successful registration (default = '%d')\n", regincr);
printf(" Since REGID is incremented every second, this value define after how\n");
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(" -S --sysinfo pdreg=0 | pdreg=1\n");
printf(" If 1, phone de-registers on every power down (default = '%d')\n", pureg);
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(" -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");
printf(" If 1, phone registers only if System ID is different (default = '%d')\n", regr);
printf("\nstation-id: Give 10 digit station-id, you don't need to enter it for every\n");
printf(" start of this program.\n");
}
static int handle_options(int argc, char **argv)
{
const char *p;
int skip_args = 0;
int rc;
static struct option long_options_special[] = {
{"channel-type", 1, 0, 't'},
{"flip-polarity", 1, 0, 'F'},
{"ms-power", 1, 0, 'P'},
{"sysinfo", 1, 0, 'S'},
{0, 0, 0, 0}
};
set_options_common("t:F:P:S:", long_options_special);
while (1) {
int option_index = 0, c;
c = getopt_long(argc, argv, optstring, long_options, &option_index);
if (c == -1)
break;
switch (c) {
case 't':
if (!strcmp(optarg, "list")) {
amps_channel_list();
exit(0);
}
rc = amps_channel_by_short_name(optarg);
if (rc < 0) {
fprintf(stderr, "Error, channel type '%s' unknown. Please use '-t list' to get a list. I suggest to use the default.\n", optarg);
exit(0);
}
OPT_ARRAY(num_chan_type, chan_type, rc)
skip_args += 2;
break;
case 'F':
if (!strcasecmp(optarg, "no"))
flip_polarity = "no";
else if (!strcasecmp(optarg, "yes"))
flip_polarity = "yes";
else {
fprintf(stderr, "Given polarity '%s' is illegal, see help!\n", optarg);
exit(0);
}
skip_args += 2;
break;
case 'P':
ms_power = atoi(optarg);
if (ms_power > 3)
ms_power = 3;
if (ms_power < 0)
ms_power = 0;
skip_args += 2;
break;
case 'S':
p = strchr(optarg, '=');
if (!p) {
fprintf(stderr, "Given sysinfo parameter '%s' requires '=' character to set value, see help!\n", optarg);
exit(0);
}
p++;
if (!strncasecmp(optarg, "sid=", 4)) {
if (!strcasecmp(p, "list")) {
list_stations();
exit(0);
}
sid = atoi(p);
if (sid > 32767)
sid = 32767;
if (sid < 0)
sid = 0;
} else
if (!strncasecmp(optarg, "dcc=", 4)) {
dcc = atoi(p);
if (dcc > 3)
dcc = 3;
if (dcc < 0)
dcc = 0;
} else
if (!strncasecmp(optarg, "scc=", 4)) {
scc = atoi(p);
if (scc > 2)
scc = 2;
if (scc < 0)
scc = 0;
} else
if (!strncasecmp(optarg, "regincr=", 4)) {
regincr = atoi(p);
} else
if (!strncasecmp(optarg, "pureg=", 4)) {
pureg = atoi(p) & 1;
} else
if (!strncasecmp(optarg, "pdreg=", 4)) {
pdreg = atoi(p) & 1;
} else
if (!strncasecmp(optarg, "locaid=", 4)) {
locaid = atoi(p);
if (locaid > 4095)
locaid = 4095;
} else
if (!strncasecmp(optarg, "regh=", 4)) {
regh = atoi(p) & 1;
} else
if (!strncasecmp(optarg, "regr=", 4)) {
regr = atoi(p) & 1;
} else {
fprintf(stderr, "Given sysinfo parameter '%s' unknown, see help!\n", optarg);
exit(0);
}
skip_args += 2;
break;
default:
opt_switch_common(c, argv[0], &skip_args);
}
}
free(long_options);
return skip_args;
}
int main(int argc, char *argv[])
{
int rc;
int skip_args;
const char *station_id = "";
int polarity;
int i;
/* override default */
samplerate = 96000;
/* init common tones */
init_tones();
init_noanswer();
init_outoforder();
init_invalidnumber();
init_congestion();
skip_args = handle_options(argc, argv);
argc -= skip_args;
argv += skip_args;
if (argc > 1) {
station_id = argv[1];
if (strlen(station_id) != 10) {
printf("Given station ID '%s' does not have 10 digits\n", station_id);
return 0;
}
}
if (!num_kanal) {
printf("No channel (\"Kanal\") is specified, I suggest channel 334.\n\n");
print_help(argv[-skip_args]);
return 0;
}
if (num_kanal == 1 && num_sounddev == 0)
num_sounddev = 1; /* use defualt */
if (num_kanal != num_sounddev) {
fprintf(stdout, "You need to specify as many sound devices as you have channels.\n");
exit(0);
}
if (num_kanal == 1 && num_chan_type == 0)
num_chan_type = 1; /* use defualt */
if (num_kanal != num_chan_type) {
fprintf(stdout, "You need to specify as many channel types as you have channels.\n");
exit(0);
}
if (!loopback)
print_image();
sid_stations(sid);
/* init functions */
if (use_mncc_sock) {
rc = mncc_init("/tmp/bsc_mncc");
if (rc < 0) {
fprintf(stderr, "Failed to setup MNCC socket. Quitting!\n");
return -1;
}
}
dsp_init();
init_frame();
rc = call_init(station_id, call_sounddev, samplerate, latency, 10, loopback);
if (rc < 0) {
fprintf(stderr, "Failed to create call control instance. Quitting!\n");
goto fail;
}
/* check for mandatory CC */
for (i = 0; i < num_kanal; i++) {
if (chan_type[i] == CHAN_TYPE_CC || chan_type[i] == CHAN_TYPE_CC_PC || chan_type[i] == CHAN_TYPE_CC_PC_VC)
break;
}
if (i == num_kanal) {
fprintf(stderr, "You must define at least one CC (control) or combined channel type. Quitting!\n");
goto fail;
}
/* check for mandatory PC */
for (i = 0; i < num_kanal; i++) {
if (chan_type[i] == CHAN_TYPE_CC_PC || chan_type[i] == CHAN_TYPE_CC_PC_VC)
break;
}
if (i == num_kanal) {
fprintf(stderr, "You must define at least one PC (paging) or combined channel type. Quitting!\n");
goto fail;
}
/* check for mandatory VC */
for (i = 0; i < num_kanal; i++) {
if (chan_type[i] == CHAN_TYPE_VC || chan_type[i] == CHAN_TYPE_CC_PC_VC)
break;
}
if (i == num_kanal)
fprintf(stderr, "You did not define any VC (voice) channel. You will not be able to make any call.\n");
if (!do_pre_emphasis || !do_de_emphasis) {
fprintf(stderr, "*******************************************************************************\n");
fprintf(stderr, "I strongly suggest to let me do pre- and de-emphasis (options -E -e)!\n");
fprintf(stderr, "Use a transmitter/receiver without emphasis and let me do that!\n");
fprintf(stderr, "Because carrier FSK signalling does not use emphasis, I like to control\n");
fprintf(stderr, "emphasis by myself for best results.\n");
fprintf(stderr, "*******************************************************************************\n");
}
if (!strcmp(flip_polarity, "no"))
polarity = 1; /* positive */
else if (!strcmp(flip_polarity, "yes"))
polarity = -1; /* negative */
else {
fprintf(stderr, "You must define, if the the TX deviation polarity has to be flipped. (-F yes | no) See help.\n");
exit(0);
}
/* create transceiver instance */
for (i = 0; i < num_kanal; i++) {
amps_si si;
init_sysinfo(&si, ms_power, ms_power, dcc, sid >> 1, regh, regr, pureg, pdreg, locaid, regincr);
rc = amps_create(kanal[i], chan_type[i], sounddev[i], samplerate, cross_channels, rx_gain, do_pre_emphasis, do_de_emphasis, write_wave, read_wave, &si, sid, scc, polarity, loopback);
if (rc < 0) {
fprintf(stderr, "Failed to create \"Sender\" instance. Quitting!\n");
goto fail;
}
printf("Base station on channel %d ready, please tune transmitter to %.3f MHz and receiver to %.3f MHz.\n", kanal[i], amps_channel2freq(kanal[i], 0), amps_channel2freq(kanal[i], 1));
}
signal(SIGINT,sighandler);
signal(SIGHUP,sighandler);
signal(SIGTERM,sighandler);
signal(SIGPIPE,sighandler);
if (rt_prio > 0) {
struct sched_param schedp;
int rc;
memset(&schedp, 0, sizeof(schedp));
schedp.sched_priority = rt_prio;
rc = sched_setscheduler(0, SCHED_RR, &schedp);
if (rc)
fprintf(stderr, "Error setting SCHED_RR with prio %d\n", rt_prio);
}
main_loop(&quit, latency);
if (rt_prio > 0) {
struct sched_param schedp;
memset(&schedp, 0, sizeof(schedp));
schedp.sched_priority = 0;
sched_setscheduler(0, SCHED_OTHER, &schedp);
}
fail:
/* cleanup functions */
call_cleanup();
if (use_mncc_sock)
mncc_exit();
/* destroy transceiver instance */
while (sender_head)
amps_destroy(sender_head);
return 0;
}

5105
src/amps/noanswer.c Normal file

File diff suppressed because it is too large Load Diff

3
src/amps/noanswer.h Normal file
View File

@ -0,0 +1,3 @@
void init_noanswer(void);

8182
src/amps/outoforder.c Normal file

File diff suppressed because it is too large Load Diff

3
src/amps/outoforder.h Normal file
View File

@ -0,0 +1,3 @@
void init_outoforder(void);

738
src/amps/stations.c Normal file
View File

@ -0,0 +1,738 @@
#include <stdio.h>
#include "stations.h"
/*
1: the SID, system Identification number
2: the BID, the billing identification number, or 0= if same as the SID
3: a City in the area of the service (multiple cities may be listed)
4: the Postal Code for the State or Province of the City in column 3 (Note: BH was used for Bahamas.)
5: the telephone company name
6: a customer service number for the area indicated by columns 3 and 4
7: the clearing house that handles roamers' billing records
*/
static struct amps_stations {
int sid, bid;
const char *city, *state, *company, *customer_service, *clearing_house;
} amps_stations[] = {
{ 1, 0, "Chicago", "IL", "Cellular One", "800 235 5663", "GTEDS" },
{ 2, 0, "Los Angles", "CA", "Pactel Cellular", "714 553 6100", "GTEDS" },
{ 2, 0, "Palm Springs", "CA", "Pactel Cellular", "714 553 6100", "GTEDS" },
{ 3, 0, "Buffalo", "NY", "Buffalo Telephone Company", "716 854 5076", "BANK/IL" },
{ 4, 0, "San Diego", "CA", "Pactel Cellular", "619 535 6464", "GTEDS" },
{ 5, 0, "Milwaukee", "WI", "Cellular One", "414 783 5500", "APPEX" },
{ 6, 0, "Seattle", "WA", "US West Cellular", "800 626 6611", "GTEDS" },
{ 6, 0, "Tacoma", "WA", "US West Cellular", "800 626 6611", "GTEDS" },
{ 7, 0, "Boston", "MA", "Cellular One", "617 890 1555", "(Boston)" },
{ 8, 0, "Allentown", "PA", "Bell Atlantic Mobile", "800 922 0204", "GTEDS" },
{ 8, 0, "Philadelphia", "PA", "Bell Atlantic Mobile", "800 953 2200", "GTEDS" },
{ 8, 0, "Reading", "PA", "Bell Atlantic Mobile", "800 922 0204", "GTEDS" },
{ 8, 0, "Trenton", "NJ", "Bell Atlantic Mobile", "800 922 0204", "GTEDS" },
{ 8, 0, "Wilmington", "DE", "Bell Atlantic Mobile", "800 922 0204", "GTEDS" },
{ 12, 0, "Beaumont", "TX", "GTE Mobile", "800 347 5665", "GTEDS" },
{ 12, 0, "Bryan", "TX", "GTE Mobile", "800 347 5665", "GTEDS" },
{ 12, 0, "College Station", "TX", "GTE Mobile", "800 347 5665", "GTEDS" },
{ 12, 0, "Galveston", "TX", "GTE Mobile", "800 347 5665", "GTEDS" },
{ 12, 0, "Houston", "TX", "GTE Mobile", "800 347 5665", "GTEDS" },
{ 12, 0, "Port Arthur", "TX", "GTE Mobile", "800 347 5665", "GTEDS" },
{ 13, 0, "Baltimore", "MD", "Cellular One", "301 220 0060", "(Baltimore)" },
{ 13, 0, "Washington", "DC", "Cellular One", "301 220 0060", "(Baltimore)" },
{ 15, 0, "Cleveland", "OH", "Cellular One", "216 351 1414", "Commonwealth" },
{ 15, 0, "Elyria", "OH", "Cellular One", "216 351 1414", "Commonwealth" },
{ 15, 0, "Lorain", "OH", "Cellular One", "216 351 1414", "Commonwealth" },
{ 17, 0, "St. Louis", "MO", "Cybertel Cellular", "314 423 6500", "GTEDS" },
{ 18, 0, "Alexandria", "VA", "Bell Atlantic Mobile", "800 922 0204", "GTEDS" },
{ 18, 0, "Baltimore", "MD", "Bell Atlantic Mobile", "800 922 0204", "GTEDS" },
{ 18, 30016, "Frederick", "MD", "Bell Atlantic Mobile", "", "GTEDS" },
{ 18, 0, "Silver Spring", "MD", "Bell Atlantic Mobile", "800 922 0204", "GTEDS" },
{ 18, 0, "Washington", "DC", "Bell Atlantic Mobile", "800 922 0204", "GTEDS" },
{ 19, 0, "Indianapolis", "IN", "Cellular One", "317 252 5367", "CBIS" },
{ 20, 0, "Chicago", "IL", "Ameritech Mobile", "800 221 0994", "GTEDS" },
{ 21, 0, "Detroit", "MI", "Cellular One", "313 737 5123", "APPEX" },
{ 21, 0, "Flint", "MI", "Cellular One", "313 239 6661", "APPEX" },
{ 21, 0, "Grand Rapids", "MI", "Cellular One", "616 451 3523", "APPEX" },
{ 21, 0, "Lansing", "MI", "Cellular One", "517 323 9462", "APPEX" },
{ 21, 0, "Lima", "OH", "Cellular One", "419 234 1091", "APPEX" },
{ 21, 0, "Muskegon", "WI", "Cellular One", "517 323 9492", "APPEX" },
{ 21, 0, "Saginaw", "MI", "Cellular One", "517 323 9462", "APPEX" },
{ 21, 0, "Toledo", "OH", "Cellular One", "419 243 1091", "APPEX" },
{ 22, 0, "Brooklyn", "NY", "Nynex Mobile Com", "800 227 1069", "Nynex" },
{ 22, 0, "Congers", "NY", "Nynex Mobile Com", "800 227 1069", "Nynex" },
{ 22, 0, "Freehold", "NJ", "Nynex Mobile Com", "800 227 1069", "Nynex" },
{ 22, 0, "Hackensack", "NJ", "Nynex Mobile Com", "800 227 1069", "Nynex" },
{ 22, 0, "Madison", "NJ", "Nynex Mobile Com", "800 227 1069", "Nynex" },
{ 22, 0, "Morristown", "NJ", "Nynex Mobile Com", "800 227 1069", "Nynex" },
{ 22, 0, "Nassau County", "NY", "Nynex Mobile Com", "800 227 1069", "Nynex" },
{ 22, 0, "New Brunswick", "NJ", "Nynex Mobile Com", "800 227 1069", "Nynex" },
{ 22, 0, "Newark", "NJ", "Nynex Mobile Com", "800 227 1069", "Nynex" },
{ 22, 0, "Paterson", "NJ", "Nynex Mobile Com", "800 227 1069", "Nynex" },
{ 22, 0, "Pleasantville", "NY", "Nynex Mobile Com", "800 227 1069", "Nynex" },
{ 22, 0, "Rahway", "NY", "Nynex Mobile Com", "800 227 1069", "Nynex" },
{ 22, 0, "Suffolk County", "NY", "Nynex Mobile Com", "800 227 1069", "Nynex" },
{ 22, 0, "White Plains", "NY", "Nynex Mobile Com", "800 227 1069", "Nynex" },
{ 22, 0, "World Trade Center", "NY", "Nynex Mobile Com", "800 227 1069", "Nynex" },
{ 23, 0, "Minneapolis", "MN", "Cellular One", "612 867 2273", "APPEX" },
{ 24, 0, "Miami", "FL", "Bell South Mobile", "800 351 2400", "GTEDS" },
{ 24, 0, "West Palm Beach", "FL", "Bell South Mobile", "305 577 4975", "GTEDS" },
{ 25, 0, "New York", "NY", "Metro One", "201 587 8000", "APPEX" },
{ 26, 0, "Minneapolis", "MN", "US West Cellular", "800 626 6611", "GTEDS" },
{ 27, 0, "Los Angles", "CA", "LA Cellular Telephone Co.", "213 721 8722", "APPEX" },
{ 27, 0, "Oxnard", "CA", "Cellular One", "805 987 0955", "APPEX" },
{ 28, 0, "Auburn", "MA", "Nynex Mobile Com", "", "Nynex" },
{ 28, 0, "Boston", "MA", "Nynex Mobile Com", "", "Nynex" },
{ 28, 0, "Brockton", "MA", "Nynex Mobile Com", "", "Nynex" },
{ 28, 0, "Framington", "MA", "Nynex Mobile Com", "", "Nynex" },
{ 28, 0, "Lawrence", "MA", "Nynex Mobile Com", "", "Nynex" },
{ 28, 0, "Lowell", "MA", "Nynex Mobile Com", "", "Nynex" },
{ 28, 0, "Lynn", "MA", "Nynex Mobile Com", "", "Nynex" },
{ 28, 0, "New Bedford", "MA", "Nynex Mobile Com", "", "Nynex" },
{ 28, 0, "Providence", "RI", "Nynex Mobile Com", "", "Nynex" },
{ 28, 0, "Worchester", "MA", "Nynex Mobile Com", "", "Nynex" },
{ 29, 0, "Philadelphia", "PA", "Metrophone", "800 327 9666", "APPEX" },
{ 30, 0, "Portland", "OR", "GTE Mobile", "800 366 5665", "GTEDS" },
{ 30, 0, "Salem", "OR", "GTE Mobile", "800 366 5665", "GTEDS" },
{ 31, 30015, "Napa", "CA", "Cellular One", "800 331 4322", "APPEX" },
{ 31, 30017, "Santa Cruz", "CA", "Cellular One", "415 344 1999", "GTEDS" },
{ 31, 0, "Oakland", "CA", "Cellular One", "415 344 1999", "APPEX" },
{ 31, 0, "San Francisco", "CA", "Cellular One", "415 344 1999", "GTEDS" },
{ 31, 0, "San Jose", "CA", "Cellular One", "415 344 1999", "GTEDS" },
{ 31, 0, "San Rosa", "CA", "Cellular One", "800 331 4322", "GTEDS" },
{ 31, 0, "Vallejo", "CA", "Cellular One", "800 331 4322", "GTEDS" },
{ 32, 0, "Pittsburgh", "PA", "Bell Atlantic Mobile", "800 922 0204", "GTEDS" },
{ 32, 30020, "Altoona", "PA", "Bell Atlantic Mobile", "814 944 3011", "GTEDS" },
{ 32, 30022, "Charleston", "WV", "Bell Atlantic Mobile", "304 925 4000", "GTEDS" },
{ 32, 30024, "Huntington", "WV", "Bell Atlantic Mobile", "304 525 4101", "GTEDS" },
{ 32, 30026, "Johnstown", "PA", "Bell Atlantic Mobile", "814 467 5521", "GTEDS" },
{ 32, 30030, "Parkesburg", "PA", "Bell Atlantic Mobile", "800 922 0204", "GTEDS" },
{ 32, 30034, "State College", "PA", "Bell Atlantic Mobile", "814 231 3900", "GTEDS" },
{ 32, 30032, "Steubenville", "OH", "Bell Atlantic Mobile", "614 282 6202", "GTEDS" },
{ 32, 30032, "Weirton", "WV", "Bell Atlantic Mobile", "614 282 6202", "GTEDS" },
{ 32, 30028, "Wheeling", "WV", "Bell Atlantic Mobile", "614 695 9611", "GTEDS" },
{ 33, 0, "Dallas", "TX", "Metrocell Cellular", "214 263 4921", "APPEX" },
{ 33, 0, "Ft. Worth", "TX", "Metrocell Cellular", "214 263 4921", "APPEX" },
{ 33, 0, "Denton", "TX", "Metrocell Cellular", "214 263 4921", "APPEX" },
{ 34, 0, "Athens", "GA", "Bell South Mobile", "800 351 2400", "GTEDS" },
{ 34, 0, "Atlanta", "GA", "Bell South Mobile", "800 351 2400", "GTEDS" },
{ 35, 0, "Houston", "TX", "Houston Cellular Telephone", "713 688 8020", "APPEX" },
{ 36, 0, "New Orleans", "LA", "Bell South Mobile", "800 351 2400", "GTEDS" },
{ 37, 0, "Ft. Lauderdale", "FL", "McCaw Cellular", "407 655 1948", "APPEX" },
{ 37, 0, "Miami", "FL", "Cellular One", "305 792 2355", "APPEX" },
{ 37, 0, "Stuart", "FL", "Cellular One", "407 833 1111", "APPEX" },
{ 37, 0, "West Palm Beach", "FL", "Cellular One", "407 833 1111", "APPEX" },
{ 38, 0, "Ft. Worth", "TX", "Southwestern Bell Mobile", "800 331 0500", "GTEDS" },
{ 38, 0, "Dallas", "TX", "Southwestern Bell Mobile", "800 331 0500", "GTEDS" },
{ 38, 0, "Denison", "TX", "Southwestern Bell Mobile", "800 331 0500", "GTEDS" },
{ 38, 0, "Sherman", "TX", "Southwestern Bell Mobile", "800 331 0500", "GTEDS" },
{ 39, 0, "Johnstown", "PA", "Cellular One", "814 242 0100", "APPEX" },
{ 39, 0, "Pittsburgh", "PA", "Cellular One", "412 471 3922", "APPEX" },
{ 39, 30059, "Wheeling", "WV", "Cellular One", "304 281 0100", "APPEX" },
{ 40, 0, "Salinas", "CA", "GTE Mobile", "800 366 5665", "GTEDS" },
{ 40, 0, "San Francisco", "CA", "GTE Mobile", "800 366 5665", "GTEDS" },
{ 40, 0, "San Jose", "CA", "GTE Mobile", "800 366 5665", "GTEDS" },
{ 40, 0, "San Rosa", "CA", "GTE Mobile", "800 366 5665", "GTEDS" },
{ 40, 30002, "Santa Barbara", "CA", "GTE Mobile", "800 366 5665", "GTEDS" },
{ 41, 0, "Athens", "GA", "Pactel Cellular", "404 449 3900", "GTEDS" },
{ 41, 0, "Atlanta", "GA", "Pactel Cellular", "404 449 3900", "GTEDS" },
{ 42, 0, "Brandenton", "FL", "GTE Mobile", "813 221 1662", "GTEDS" },
{ 42, 0, "Ft. Meyers", "FL", "GTE Mobile", "800 877 5665", "GTEDS" },
{ 42, 0, "Lakeland", "FL", "GTE Mobile", "800 877 5665", "GTEDS" },
{ 42, 0, "Sarasota", "FL", "GTE Mobile", "800 877 5665", "GTEDS" },
{ 42, 0, "Tampa", "FL", "GTE Mobile", "800 877 5665", "GTEDS" },
{ 42, 0, "Venice", "FL", "GTE Mobile", "800 877 5665", "GTEDS" },
{ 42, 0, "Winter Haven", "FL", "GTE Mobile", "800 877 5665", "GTEDS" },
{ 43, 0, "San Diego", "CA", "US West Cellular", "800 626 6611", "GTEDS" },
{ 45, 0, "Colorado Springs", "CO", "Cellular One", "303 831 1200", "APPEX" },
{ 45, 0, "Denver", "CO", "Cellular One", "303 831 1200", "APPEX" },
{ 45, 0, "Ft. Collins", "CO", "Cellular One", "303 831 1200", "APPEX" },
{ 45, 0, "Greely", "CO", "Cellular One", "303 831 1200", "APPEX" },
{ 46, 0, "St. Louis", "MO", "Southwestern Bell Mobile", "314 542 9999", "GTEDS" },
{ 47, 0, "Bellingham", "WA", "Cellular One", "206 285 2273", "APPEX" },
{ 47, 0, "Bremerton", "WA", "Cellular One", "206 285 2273", "APPEX" },
{ 47, 0, "Olympia", "WA", "Cellular One", "206 285 2273", "APPEX" },
{ 47, 0, "Seattle", "WA", "Cellular One", "206 285 2273", "APPEX" },
{ 47, 0, "Tacoma", "WA", "Cellular One", "206 285 2273", "APPEX" },
{ 48, 0, "Phoenix", "AZ", "US West Cellular", "800 626 6611", "GTEDS" },
{ 51, 0, "Cincinnati", "OH", "Cellular One", "513 733 5515", "Commonwealth" },
{ 51, 0, "Hamilton", "OH", "Cellular One", "513 733 5515", "Commonwealth" },
{ 52, 0, "Kansas City", "KS", "Southwestern Bell Mobile", "913 894 1600", "GTEDS" },
{ 52, 0, "Kansas City", "MO", "Southwestern Bell Mobile", "913 894 1600", "GTEDS" },
{ 52, 0, "Lawrence", "KS", "Southwestern Bell Mobile", "913 894 1600", "GTEDS" },
{ 52, 0, "St. Joseph", "MO", "Southwestern Bell Mobile", "913 894 1600", "GTEDS" },
{ 52, 0, "Topeka", "KS", "Southwestern Bell Mobile", "913 894 1600", "GTEDS" },
{ 53, 0, "Phoenix", "AZ", "Metro Mobile", "602 731 6000", "APPEX" },
{ 53, 30053, "Tuscon", "AZ", "Metro Mobile", "602 628 9541", "APPEX" },
{ 54, 0, "Akron", "OH", "GTE Mobile", "800 669 5665", "GTEDS" },
{ 54, 0, "Canton", "OH", "GTE Mobile", "800 669 5665", "GTEDS" },
{ 54, 0, "Cleveland", "OH", "GTE Mobile", "800 669 5665", "GTEDS" },
{ 54, 0, "Elyria", "OH", "GTE Mobile", "800 669 5665", "GTEDS" },
{ 54, 0, "Erie", "PA", "GTE Mobile", "800 669 5665", "GTEDS" },
{ 54, 0, "Lorain", "OH", "GTE Mobile", "800 669 5665", "GTEDS" },
{ 56, 0, "Buffalo", "NY", "Nynex Mobile Com", "", "Nynex" },
{ 57, 0, "New Orleans", "LA", "Cellular One", "504 830 5400", "GTEDS" },
{ 58, 0, "Denver", "CO", "US West Cellular", "800 626 6611", "GTEDS" },
{ 59, 30057, "Kansas City", "KS", "Cellular One", "913 432 3141", "APPEX" },
{ 59, 30057, "Kansas City", "MO", "Cellular One", "913 432 3141", "APPEX" },
{ 59, 0, "Lawrence", "KS", "Cellular One", "913 842 0577", "APPEX" },
{ 59, 0, "Topeka", "KS", "Cellular One", "913 234 4984", "APPEX" },
{ 60, 0, "Honolulu", "HI", "GTE Mobile", "808 941 9934", "GTEDS" },
{ 61, 0, "Eugene", "OR", "Cellular One", "503 345 1818", "APPEX" },
{ 61, 0, "Medford", "OR", "Cellular One", "503 944 5555", "APPEX" },
{ 61, 0, "Portland", "OR", "Cellular One", "503 228 1717", "APPEX" },
{ 61, 0, "Salem", "OR", "Cellular One", "503 364 3335", "APPEX" },
{ 62, 0, "Memphis", "TN", "Bell South Mobile", "800 351 2400", "GTEDS" },
{ 63, 0, "Albany", "NY", "Cellular One", "518 465 7300", "BANK/IL" },
{ 64, 0, "Las Vegas", "NV", "Centel Cellular", "702 365 6500", "GTEDS" },
{ 65, 0, "Louisville", "KY", "Cellular One", "502 582 2355", "APPEX" },
{ 68, 0, "Orlando", "FL", "Bell South Mobile", "305 577 4975", "GTEDS" },
{ 69, 0, "Durham", "NC", "Cellular One", "919 481 1181", "GTEDS" },
{ 69, 0, "Raleigh", "NC", "Cellular One", "919 481 1181", "GTEDS" },
{ 70, 0, "Wichita", "KS", "Southwestern Bell Mobile", "316 687 2355", "GTEDS" },
{ 71, 0, "Richmond", "VA", "Cellular One", "804 288 3805", "GTEDS" },
{ 73, 0, "Akron", "OH", "Cellular One", "216 867 3900", "Commonwealth" },
{ 73, 0, "Canton", "OH", "Cellular One", "216 867 3900", "Commonwealth" },
{ 74, 0, "Bristol", "TX", "Centel Cellular", "", "GTEDS" },
{ 74, 0, "Johnson City", "TN", "Centel Cellular", "", "GTEDS" },
{ 74, 0, "Kingsport", "TN", "Centel Cellular", "", "GTEDS" },
{ 75, 0, "Jacksonville", "FL", "Cellular One", "904 731 2355", "APPEX" },
{ 76, 0, "Louisville", "KY", "Bell South Mobile", "800 351 2400", "GTEDS" },
{ 77, 0, "Syracuse", "NY", "Cellular One", "315 446 0400", "Cell-T" },
{ 78, 0, "Albany", "NY", "Nynex Mobile Com", "", "Nynex" },
{ 79, 0, "Albuquerque", "NM", "Metro Mobile", "505 266 9000", "APPEX" },
{ 80, 0, "Anderson", "IN", "GTE Mobile", "800 669 3001", "GTEDS" },
{ 80, 0, "Bloomington", "IN", "GTE Mobile", "800 669 3001", "GTEDS" },
{ 80, 0, "Ft. Wayne", "IN", "GTE Mobile", "800 669 3001", "GTEDS" },
{ 80, 0, "Indianapolis", "IN", "GTE Mobile", "800 669 3001", "GTEDS" },
{ 80, 0, "Kokomo", "IN", "GTE Mobile", "800 669 3001", "GTEDS" },
{ 80, 0, "Lafayette", "IN", "GTE Mobile", "800 669 3001", "GTEDS" },
{ 80, 0, "Muncie", "IN", "GTE Mobile", "800 669 3001", "GTEDS" },
{ 80, 0, "Terre Haute", "IN", "GTE Mobile", "800 669 3001", "GTEDS" },
{ 81, 0, "Mobile", "AL", "Gulf Coast Cellular", "205 343 9700", "Cell-T" },
{ 83, 0, "Newport News", "VA", "Centel Cellular", "804 473 9600", "GTEDS" },
{ 83, 0, "Norfolk", "VA", "Centel Cellular", "804 473 9600", "GTEDS" },
{ 83, 0, "Virginia Beach", "VA", "Centel Cellular", "804 473 9600", "GTEDS" },
{ 84, 0, "Aiken", "GA", "Cellular Phone of", "404 738 2355", "GTEDS" },
{ 84, 0, "Augusta", "GA", "Cellular Phone of", "404 738 2355", "GTEDS" },
{ 85, 0, "Baton Rouge", "LA", "Cellular One", "504 291 9703", "GTEDS" },
{ 86, 0, "Syracuse", "NY", "Nynex Mobile Com", "", "Nynex" },
{ 88, 0, "SNET", "CT", "SNET Cellular", "203 553 7594", "GTEDS" },
{ 88, 30006, "Springfield", "MA", "SNET Cellular", "203 553 7594", "GTEDS" },
{ 89, 0, "Sharon", "PA", "Cellular One", "412 866 5000", "APPEX" },
{ 89, 0, "Warren", "OH", "Cellular One", "216 565 5000", "APPEX" },
{ 89, 0, "Youngstown", "OH", "Cellular One", "216 565 5000", "APPEX" },
{ 91, 0, "Provo", "UT", "Cellular One", "801 359 2273", "APPEX" },
{ 91, 0, "Salt Lake City", "UT", "Cellular One", "801 359 2273", "APPEX" },
{ 92, 0, "El Paso", "TX", "Contel Cellular", "800 792 8400", "GTEDS" },
{ 92, 0, "Las Cruces", "NM", "Contel Cellular", "800 792 8400", "GTEDS" },
{ 93, 0, "Knoxville", "TN", "Cellular One", "615 584 2355", "APPEX" },
{ 94, 0, "Salt Lake City", "UT", "US West Cellular", "800 626 6611", "GTEDS" },
{ 95, 0, "Greensboro", "NC", "Cellular One", "919 668 3600", "GTEDS" },
{ 96, 0, "Harrisburg", "PA", "Centel Cellular", "717 545 3300", "GTEDS" },
{ 96, 0, "Lancaster", "PA", "Centel Cellular", "717 545 3300", "GTEDS" },
{ 96, 0, "York", "PA", "Centel Cellular", "717 545 3300", "GTEDS" },
{ 97, 30097, "El Paso", "TX", "Metro Mobile", "915 532 5559", "APPEX" },
{ 97, 30097, "Las Cruces", "NM", "Metro Mobile", "505 526 2233", "APPEX" },
{ 98, 0, "Anniston", "AL", "Bell South Mobile", "800 351 2400", "GTEDS" },
{ 98, 0, "Birmingham", "AL", "Bell South Mobile", "800 351 2400", "GTEDS" },
{ 98, 0, "Tuscaloosa", "AL", "Bell South Mobile", "800 351 2400", "GTEDS" },
{ 100, 0, "Fayetteville", "NC", "Centel Cellular", "919 833 7494", "GTEDS" },
{ 103, 0, "Allentown", "PA", "Cellular One", "215 434 2355", "GTEDS" },
{ 103, 30023, "Reading", "PA", "Cellular One", "215 434 2355", "GTEDS" },
{ 103, 0, "York", "PA", "Cellular One", "717 579 2355", "GTEDS" },
{ 104, 0, "Knoxville", "TN", "US Cellular", "615 584 9500", "GTEDS" },
{ 105, 0, "NE PA", "PA", "Cellular One", "717 434 2355", "GTEDS" },
{ 106, 0, "Baton Rouge", "LA", "Bell South Mobile", "800 351 2400", "GTEDS" },
{ 107, 0, "Austin", "TX", "Cellular One", "512 388 6777", "APPEX" },
{ 110, 0, "Albuquerque", "NM", "US West Cellular", "800 626 6611", "GTEDS" },
{ 111, 0, "Tulsa", "OK", "Cellular One", "918 584 7722", "APPEX" },
{ 112, 0, "Sacramemto", "CA", "Pactel Cellular", "916 520 0645", "GTEDS" },
{ 113, 30043, "Anniston", "AL", "Cellular One", "205 942 2355", "APPEX" },
{ 113, 0, "Birmingham", "AL", "Cellular One", "205 942 2355", "APPEX" },
{ 113, 30025, "Florence", "AL", "Cellular One", "205 942 2355", "APPEX" },
{ 113, 30029, "Gadsden", "AL", "Cellular One", "205 942 2355", "APPEX" },
{ 114, 0, "Charlotte", "NC", "Alltel Mobile", "704 529 0001", "GTEDS" },
{ 116, 0, "Anderson", "SC", "Centel Cellular", "803 297 8860", "GTEDS" },
{ 116, 0, "Greenville", "SC", "Centel Cellular", "803 297 8860", "GTEDS" },
{ 116, 0, "Spartanburg", "SC", "Centel Cellular", "803 297 8860", "GTEDS" },
{ 117, 0, "Rochester", "NY", "Genesse Telephone", "716 232 6600", "BANK/IL" },
{ 118, 0, "Clarksville", "TN", "Bell South Mobile", "800 351 2400", "GTEDS" },
{ 118, 0, "Nashville", "TN", "Bell South Mobile", "800 351 2400", "GTEDS" },
{ 119, 0, "Bridgeport", "CT", "Metro Mobile", "203 852 9292", "APPEX" },
{ 119, 0, "Danbury", "CT", "Metro Mobile", "203 852 9292", "APPEX" },
{ 119, 30119, "Fairfield County", "CT", "Metro Mobile", "203 852 9292", "APPEX" },
{ 119, 0, "Hartford", "CT", "Metro Mobile", "203 688 3737", "APPEX" },
{ 119, 0, "New Bedford", "MA", "Metro Mobile", "401 272 3800", "APPEX" },
{ 119, 0, "New Haven", "CT", "Metro Mobile", "203 852 9292", "APPEX" },
{ 119, 0, "North Bedford", "CT", "Metro Mobile", "203 852 9292", "APPEX" },
{ 119, 0, "Norwalk", "CT", "Metro Mobile", "203 852 9292", "APPEX" },
{ 119, 0, "Norwich", "CT", "Metro Mobile", "203 688 3737", "APPEX" },
{ 119, 0, "Pittsfield", "MA", "Metro Mobile", "203 688 3737", "APPEX" },
{ 119, 0, "Providence", "RI", "Metro Mobile", "401 272 3800", "APPEX" },
{ 119, 31119, "Springfield", "MA", "Metro Mobile", "203 688 3737", "APPEX" },
{ 119, 0, "Waterbury", "CT", "Metro Mobile", "203 852 9292", "APPEX" },
{ 120, 0, "Mobile", "AL", "Contel Cellular", "800 792 8400", "GTEDS" },
{ 120, 0, "Pensacola", "FL", "Contel Cellular", "800 792 8400", "GTEDS" },
{ 122, 0, "San Antonio", "TX", "Southwestern Bell Mobile", "512 646 9955", "GTEDS" },
{ 123, 0, "Wilmington", "DE", "Cellular One", "302 737 3333", "APPEX" },
{ 126, 0, "Sharon", "PA", "Centel Cellular", "216 758 4502", "GTEDS" },
{ 126, 0, "Warren", "OH", "Centel Cellular", "216 758 4502", "GTEDS" },
{ 126, 0, "Youngstown", "OH", "Centel Cellular", "216 758 4502", "GTEDS" },
{ 127, 0, "Charleston", "SC", "Cellular One", "803 763 6363", "GTEDS" },
{ 129, 0, "Sacramemto", "CA", "Cellular One", "916 923 2400", "APPEX" },
{ 129, 0, "Yuba City", "CA", "Cellular One", "916 923 2400", "APPEX" },
{ 130, 0, "Toledo", "OH", "Centel Cellular", "419 893 1077", "GTEDS" },
{ 131, 0, "Abilene", "TX", "Cellular One", "", "GTEDS" },
{ 133, 0, "Columbus", "OH", "Cellular One", "614 846 7317", "Commonwealth" },
{ 136, 0, "Jacksonville", "FL", "Bell South Mobile", "305 577 4975", "GTEDS" },
{ 137, 0, "Omaha", "NE", "US West Cellular", "800 626 6611", "GTEDS" },
{ 139, 0, "Anderson", "SC", "Metro Mobile", "803 234 7954", "APPEX" },
{ 139, 30139, "Charlotte", "NC", "Metro Mobile", "704 552 5185", "APPEX" },
{ 139, 31139, "Greenville", "SC", "Metro Mobile", "803 234 7954", "APPEX" },
{ 140, 0, "Tuscon", "AZ", "US West Cellular", "800 626 6611", "GTEDS" },
{ 142, 0, "Greensboro", "NC", "Centel Cellular", "919 299 3333", "GTEDS" },
{ 142, 0, "Winston-Salem", "NC", "Centel Cellular", "919 299 3333", "GTEDS" },
{ 143, 0, "Memphis", "TN", "Cellular One", "901 683 2355", "APPEX" },
{ 144, 0, "Burlington", "NC", "Centel Cellular", "919 833 7494", "GTEDS" },
{ 144, 0, "Durham", "NC", "Centel Cellular", "919 833 7494", "GTEDS" },
{ 144, 0, "Raleigh", "NC", "Centel Cellular", "919 833 7494", "GTEDS" },
{ 146, 0, "Oklahoma City", "OK", "Southwestern Bell Mobile", "405 720 2212", "GTEDS" },
{ 148, 0, "Chattanooga", "TN", "Bell South Mobile", "800 351 2400", "GTEDS" },
{ 149, 0, "Bristol", "TX", "Cellular One", "615 349 4500", "APPEX" },
{ 149, 0, "Johnson City", "TN", "Cellular One", "615 349 4500", "APPEX" },
{ 149, 0, "Kingsport", "TN", "Cellular One", "615 349 4500", "APPEX" },
{ 150, 0, "Des Moines", "IA", "US West Cellular", "800 626 6611", "GTEDS" },
{ 151, 0, "San Antonio", "TX", "Cellular One", "512 349 2600", "APPEX" },
{ 152, 0, "Omaha", "NE", "Centel Cellular", "402 330 6500", "GTEDS" },
{ 153, 0, "Fresno", "CA", "Cellular One", "209 438 8888", "APPEX" },
{ 153, 0, "Visilia", "CA", "Cellular One", "209 738 0999", "APPEX" },
{ 156, 0, "Charleston", "SC", "Centel Cellular", "803 767 1340", "GTEDS" },
{ 159, 0, "Harrisburg", "PA", "Cellular One", "717 579 2355", "GTEDS" },
{ 159, 30011, "Lancaster", "PA", "Cellular One", "717 579 2355", "GTEDS" },
{ 159, 30013, "York", "PA", "Cellular One", "717 579 2355", "GTEDS" },
{ 160, 0, "Jackson", "MS", "Alltel Mobile", "601 354 1212", "GTEDS" },
{ 161, 0, "Chattanooga", "TN", "Cellular One", "615 892 2355", "APPEX" },
{ 162, 0, "Fresno", "CA", "Contel Cellular", "800 792 8400", "GTEDS" },
{ 162, 0, "Visilia", "CA", "Contel Cellular", "800 792 8400", "GTEDS" },
{ 163, 0, "Dayton", "OH", "Cellular One", "513 477 1999", "GTEDS" },
{ 163, 0, "Springfield", "OH", "Cellular One", "513 434 2355", "Commonwealth" },
{ 164, 0, "Austin", "TX", "GTE Mobile", "800 347 5665", "GTEDS" },
{ 165, 0, "Wichita", "KS", "Cellular One", "316 686 8811", "APPEX" },
{ 166, 0, "Tulsa", "OK", "US Cellular", "918 665 0101", "GTEDS" },
{ 167, 0, "Honolulu", "HI", "Honolulu Cellular", "808 545 4755", "APPEX" },
{ 168, 0, "Newport News", "VA", "Contel Cellular", "800 792 8400", "GTEDS" },
{ 168, 0, "Norfolk", "VA", "Contel Cellular", "800 792 8400", "GTEDS" },
{ 169, 0, "Oklahoma City", "OK", "Cellular One", "405 843 9113", "APPEX" },
{ 170, 0, "Petersburg", "VA", "Contel Cellular", "800 792 8400", "GTEDS" },
{ 170, 0, "Richmond", "VA", "Contel Cellular", "800 792 8400", "GTEDS" },
{ 171, 0, "Gulf of Mexico", "XX", "Petrocomm", "800 257 3876", "GTEDS" },
{ 173, 0, "Long Branch", "NJ", "Cellular One", "800 227 9222", "APPEX" },
{ 173, 0, "New Brunswick", "NJ", "Cellular One", "800 227 9222", "APPEX" },
{ 175, 0, "Brandenton", "FL", "Cellular One", "813 221 1662", "APPEX" },
{ 175, 0, "Lakeland", "FL", "Cellular One", "813 221 1662", "APPEX" },
{ 175, 0, "Melbourne", "FL", "Cellular One", "407 258 7100", "APPEX" },
{ 175, 0, "Orlando", "FL", "Cellular One", "407 425 2355", "APPEX" },
{ 175, 0, "Sarasota", "FL", "Cellular One", "813 221 1662", "APPEX" },
{ 175, 0, "Tampa", "FL", "Cellular One", "813 221 1662", "APPEX" },
{ 179, 0, "Clarksville", "TN", "Cellular One", "615 645 2200", "APPEX" },
{ 179, 0, "Mt. Juliet", "TN", "Cellular One", "615 269 2273", "APPEX" },
{ 179, 0, "Nashville", "TN", "Cellular One", "615 269 2273", "APPEX" },
{ 180, 0, "Colorado Springs", "CO", "US West Cellular", "800 626 6611", "GTEDS" },
{ 181, 0, "Augusta", "GA", "Cellular One", "404 868 0086", "GTEDS" },
{ 182, 0, "Columbia", "SC", "Bell South Mobile", "800 351 2400", "GTEDS" },
{ 183, 0, "Bakersfield", "CA", "Bakersfield Cellular", "805 327 8700", "Cell-T" },
{ 184, 0, "Corpus Christi", "TX", "Southwestern Bell Mobile", "512 854 5678", "GTEDS" },
{ 185, 0, "Beaumont", "TX", "Cellular One", "409 898 8000", "Cell-T" },
{ 186, 0, "Davenport", "IA", "Contel Cellular", "800 792 8400", "GTEDS" },
{ 186, 0, "Bettendorf", "IA", "Contel Cellular", "800 792 8400", "GTEDS" },
{ 186, 0, "Rock Island", "IL", "Contel Cellular", "800 792 8400", "GTEDS" },
{ 186, 0, "Moline", "IL", "Contel Cellular", "800 792 8400", "GTEDS" },
{ 188, 0, "Lansing", "MI", "Century Cellunet", "517 393 0311", "GTEDS" },
{ 189, 0, "Columbia", "SC", "Metro Mobile", "803 731 8300", "APPEX" },
{ 190, 0, "Evansville", "IN", "Contel Cellular", "800 792 8400", "GTEDS" },
{ 190, 0, "Henderson", "KY", "Contel Cellular", "800 792 8400", "GTEDS" },
{ 190, 0, "Owensboro", "KY", "Contel Cellular", "800 792 8400", "GTEDS" },
{ 191, 0, "Corpus Christi", "TX", "Cellular One", "512 937 8243", "APPEX" },
{ 193, 0, "Davenport", "IA", "Cellular One", "319 388 8000", "GTEDS" },
{ 193, 0, "Bettendorf", "IA", "Cellular One", "319 388 8000", "GTEDS" },
{ 193, 0, "Rock Island", "IL", "Cellular One", "319 388 8000", "GTEDS" },
{ 193, 0, "Moline", "IL", "Cellular One", "319 388 8000", "GTEDS" },
{ 194, 0, "Gulf of Mexico", "XX", "Coastel Cellular", "800 822 8400", "GTEDS" },
{ 195, 0, "Des Moines", "IA", "Cellular One", "515 223 6611", "GTEDS" },
{ 197, 0, "Evansville", "IN", "Cellular One", "812 464 5111", "GTEDS" },
{ 198, 0, "Huntsville", "AL", "Bell South Mobile", "800 351 2400", "GTEDS" },
{ 199, 0, "Ft. Wayne", "IN", "Cellular One", "219 484 2500", "CBIS" },
{ 203, 0, "Huntsville", "AL", "Cellular One", "205 830 6633", "APPEX" },
{ 204, 0, "Albany", "GA", "Alltel Mobile", "912 888 8200", "GTEDS" },
{ 206, 0, "Georgetown", "KY", "Bell South Mobile", "800 351 2400", "GTEDS" },
{ 206, 0, "Lexington", "KY", "Bell South Mobile", "800 351 2400", "GTEDS" },
{ 208, 0, "Little Rock", "AR", "Alltel Mobile", "501 666 6688", "GTEDS" },
{ 211, 0, "Las Vegas", "NV", "Cellular One", "702 732 2240", "APPEX" },
{ 212, 0, "Alexandria", "LA", "US Cellular", "318 445 2065", "GTEDS" },
{ 213, 0, "Lexington", "KY", "Cellular One", "606 223 3700", "APPEX" },
{ 214, 0, "Peoria", "IL", "Centel Cellular", "309 693 3800", "GTEDS" },
{ 215, 0, "Little Rock", "AR", "Cellular One", "501 225 2355", "APPEX" },
{ 215, 0, "Pine Bluff", "AR", "Cellular One", "501 221 1771", "APPEX" },
{ 216, 0, "Saginaw", "MI", "Century Cellunet", "517 792 1556", "GTEDS" },
{ 217, 30039, "Appleton", "WI", "Cellular One", "414 738 0110", "APPEX" },
{ 217, 30041, "Beloit", "WI", "Cellular One", "608 751 2273", "APPEX" },
{ 217, 30031, "Green Bay", "WI", "Cellular One", "414 496 2273", "APPEX" },
{ 217, 30041, "Janesville", "WI", "Cellular One", "608 751 2273", "APPEX" },
{ 217, 30035, "Kenosha", "WI", "Cellular One", "414 652 2022", "APPEX" },
{ 217, 0, "Madison", "WI", "Cellular One", "608 271 2273", "APPEX" },
{ 217, 0, "Oshkosh", "WI", "Cellular One", "414 738 0110", "APPEX" },
{ 217, 30037, "Racine", "WI", "Cellular One", "414 939 2273", "APPEX" },
{ 217, 30033, "Rockford", "IL", "Cellular One", "815 494 2273", "APPEX" },
{ 220, 0, "Shreveport", "LA", "Century Cellunet", "318 687 8502", "GTEDS" },
{ 221, 0, "Peoria", "IL", "US Cellular", "309 685 1234", "GTEDS" },
{ 222, 0, "Spokane", "WA", "US West Cellular", "800 626 6611", "GTEDS" },
{ 224, 0, "Modesto", "CA", "Pactel Cellular", "916 520 0645", "GTEDS" },
{ 224, 0, "Stockton", "CA", "Pactel Cellular", "916 520 0645", "GTEDS" },
{ 226, 0, "Rome", "NY", "Avantage Cellular", "315 797 2041", "GTEDS" },
{ 226, 0, "Utica", "NY", "Avantage Cellular", "315 797 2041", "GTEDS" },
{ 228, 0, "Bakersfield", "CA", "Contel Cellular", "800 792 8400", "GTEDS" },
{ 229, 0, "Longview", "TX", "Cellular One", "318 636 9888", "APPEX" },
{ 229, 0, "Marshall", "TX", "Cellular One", "318 636 9888", "APPEX" },
{ 229, 0, "Shreveport", "LA", "Cellular One", "318 636 9888", "APPEX" },
{ 229, 0, "Texarkana", "TX", "Cellular One", "318 636 9888", "APPEX" },
{ 231, 0, "Spokane", "WA", "Cellular One", "509 838 2273", "APPEX" },
{ 233, 0, "Modesto", "CA", "Cellular One", "209 572 1004", "APPEX" },
{ 233, 0, "Stockton", "CA", "Cellular One", "209 476 1500", "APPEX" },
{ 235, 0, "Rome", "NY", "Cellular One", "315 768 4400", "Cell-T" },
{ 235, 0, "Utica", "NY", "Cellular One", "315 768 4400", "Cell-T" },
{ 240, 0, "Appleton", "WI", "Cellulink", "414 735 9707", "GTEDS" },
{ 240, 0, "Oshkosh", "WI", "Cellulink", "414 735 9797", "GTEDS" },
{ 241, 0, "Albany", "GA", "Cellular One", "912 888 8228", "APPEX" },
{ 244, 0, "Grand Rapids", "MI", "Century Cellunet", "616 940 0985", "GTEDS" },
{ 246, 0, "Asheville", "NC", "US Cellular", "704 258 0000", "GTEDS" },
{ 247, 0, "Altoona", "PA", "Cellular One", "814 946 4535", "GTEDS" },
{ 249, 0, "Amarillo", "TX", "Cellular One", "806 374 1900", "Cell-T" },
{ 250, 0, "Atlantic City", "NJ", "Bell Atlantic Mobile", "800 922 0204", "GTEDS" },
{ 250, 0, "Vineland", "NJ", "Bell Atlantic Mobile", "800 922 0204", "GTEDS" },
{ 251, 0, "Anchorage", "AK", "Cellular One", "907 561 1122", "APPEX" },
{ 255, 0, "Anniston", "AL", "Cellular One", "205 942 2355", "Cell-T" },
{ 256, 0, "Battle Creek", "MI", "Century Cellunet", "616 342 6655", "GTEDS" },
{ 258, 0, "Bellingham", "WA", "US West Cellular", "800 626 6611", "GTEDS" },
{ 260, 0, "Benton Harbor", "MI", "Century Cellunet", "616 342 6655", "GTEDS" },
{ 264, 0, "Gulfport", "MS", "Cellular South", "", "GTEDS" },
{ 266, 0, "Binghamton", "NY", "Contel Cellular", "800 792 8400", "GTEDS" },
{ 266, 0, "Elmira", "NY", "Contel Cellular", "800 792 8400", "GTEDS" },
{ 267, 0, "Atlantic City", "NJ", "Cellular One", "", "APPEX" },
{ 268, 0, "Bismark", "ND", "US West Cellular", "800 626 6611", "GTEDS" },
{ 269, 0, "Asheville", "NC", "Cellular One", "", "Cell-T" },
{ 271, 0, "Bangor", "ME", "US Cellular", "207 942 0700", "GTEDS" },
{ 272, 0, "Boise", "ID", "US West Cellular", "800 626 6611", "GTEDS" },
{ 276, 0, "Bremerton", "WA", "Cellular One", "800 626 6611", "GTEDS" },
{ 277, 0, "Benton Harbor", "MI", "Cellular One", "616 982 9900", "Cincin" },
{ 278, 0, "Brownsville", "TX", "Southwestern Bell Mobile", "512 541 6200", "GTEDS" },
{ 278, 0, "Harlingen", "TX", "Southwestern Bell Mobile", "512 428 6200", "GTEDS" },
{ 278, 0, "McAllen", "TX", "Southwestern Bell Mobile", "512 380 6200", "GTEDS" },
{ 279, 0, "Billings", "MT", "Cellular One", "406 652 0466", "GTEDS" },
{ 281, 0, "Biloxi", "MS", "Cellular One", "", "GTEDS" },
{ 283, 30007, "Binghamton", "NY", "Cellular One", "607 771 8000", "APPEX" },
{ 283, 30009, "Elmira", "NY", "Cellular One", "607 737 1000", "APPEX" },
{ 284, 0, "Casper", "WY", "US West Cellular", "800 626 6611", "GTEDS" },
{ 285, 0, "Bismark", "ND", "Cellular One", "701 224 1616", "GTEDS" },
{ 286, 0, "Cedar Rapids", "IA", "Centel Cellular", "319 366 5700", "GTEDS" },
{ 286, 0, "Iowa City", "IA", "Centel Cellular", "319 366 5700", "GTEDS" },
{ 287, 0, "Bloomington", "IN", "Cellular One", "502 528 2355", "APPEX" },
{ 289, 0, "Boise", "ID", "Cellular One", "208 345 2355", "GTEDS" },
{ 292, 0, "Charlottesville", "VA", "Centel Cellular", "804 973 9100", "GTEDS" },
{ 294, 0, "Chico", "CA", "Pactel Cellular", "916 920 0645", "GTEDS" },
{ 294, 0, "Redding", "CA", "Pactel Cellular", "916 920 0645", "GTEDS" },
{ 297, 0, "Bryan", "TX", "Cellular One", "409 696 2264", "APPEX" },
{ 297, 0, "College Station", "TX", "Cellular One", "512 338 6777", "GTEDS" },
{ 298, 0, "Columbia", "MO", "US Cellular", "314 474 0400", "GTEDS" },
{ 299, 0, "Burlington", "NC", "Gencell", "800 888 7868", "GTEDS" },
{ 300, 0, "Burlington", "VT", "Contel Cellular", "800 792 8400", "GTEDS" },
{ 301, 0, "Casper", "WY", "Cellular One", "307 235 0110", "GTEDS" },
{ 302, 0, "Columbus", "GA", "Public Service Cellular", "912 841 4117", "GTEDS" },
{ 303, 0, "Cedar Rapids", "IA", "US Cellular", "319 365 1000", "GTEDS" },
{ 304, 0, "Cumberland", "MD", "Gencell", "800 888 7868", "GTEDS" },
{ 306, 0, "Danville", "VA", "Centel Cellular", "804 791 3100", "GTEDS" },
{ 307, 0, "Charleston", "WV", "Cellular One", "304 345 2355", "GTEDS" },
{ 307, 30047, "Huntington", "WV", "Cellular One", "304 345 2355", "GTEDS" },
{ 308, 0, "Daytona Beach", "FL", "Bell South Mobile", "305 577 4975", "GTEDS" },
{ 308, 0, "New Smyrna", "FL", "Bell South Mobile", "800 351 2400", "GTEDS" },
{ 312, 0, "Dothan", "AL", "Graceba Cellular", "205 793 9148", "GTEDS" },
{ 314, 0, "Dubuque", "IA", "Centel Cellular", "319 580 0010", "GTEDS" },
{ 316, 0, "Duluth", "MN", "US West Cellular", "800 626 6611", "GTEDS" },
{ 318, 0, "Eau Claire", "WI", "Cellulink", "715 835 7370", "GTEDS" },
{ 319, 0, "Columbus", "GA", "Cellular One", "404 596 9041", "APPEX" },
{ 321, 0, "Cumberland", "MD", "Cellular One", "814 946 4535", "GTEDS" },
{ 323, 0, "Danville", "VA", "Cellular One", "804 791 3453", "GTEDS" },
{ 324, 0, "Enid", "OK", "Enid Cellular", "405 375 4111", "GTEDS" },
{ 325, 0, "Daytona Beach", "FL", "Cellular One", "904 257 2355", "APPEX" },
{ 328, 0, "Eugene", "OR", "US West Cellular", "800 626 6611", "GTEDS" },
{ 329, 0, "Dothan", "AL", "Cellular One", "205 671 4111", "Cell-T" },
{ 330, 0, "Fargo", "ND", "US West Cellular", "800 626 6611", "GTEDS" },
{ 331, 0, "Dubuque", "IA", "US Cellular", "", "GTEDS" },
{ 333, 0, "Duluth", "MN", "Cellular One", "218 727 4700", "GTEDS" },
{ 334, 0, "Muscle Shoals", "LA", "Shoals Cellular", "205 383 5111", "GTEDS" },
{ 336, 0, "Ft. Collins", "CO", "US West Cellular", "800 626 6611", "GTEDS" },
{ 336, 0, "Loveland", "CO", "US West Cellular", "800 626 6611", "GTEDS" },
{ 340, 0, "Ft. Pierce", "FL", "US Cellular", "305 287 7888", "GTEDS" },
{ 342, 0, "Fayetteville", "AR", "Contel Cellular", "800 792 8400", "GTEDS" },
{ 342, 0, "Ft. Smith", "AR", "Contel Cellular", "800 792 8400", "GTEDS" },
{ 342, 0, "Rogers", "AR", "Contel Cellular", "800 792 8400", "GTEDS" },
{ 343, 0, "Erie", "PA", "Cellular One", "814 881 0100", "APPEX" },
{ 344, 0, "Ft. Walton Beach", "FL", "Centel Cellular", "904 664 2000", "GTEDS" },
{ 348, 0, "Gainesville", "FL", "Alltel Cellular", "904 374 8500", "GTEDS" },
{ 348, 0, "Ocala", "FL", "Alltel Mobile", "904 237 1100", "GTEDS" },
{ 349, 0, "Fayetteville", "NC", "Cellular One", "919 483 1181", "GTEDS" },
{ 350, 0, "Florence", "SC", "Bell South Mobile", "800 351 2400", "GTEDS" },
{ 355, 0, "Ft. Meyers", "FL", "Cellular One", "813 936 4534", "APPEX" },
{ 356, 0, "Grand Forks", "ND", "US West Cellular", "800 626 6611", "GTEDS" },
{ 357, 0, "Ft. Pierce", "FL", "Cellular One", "407 833 1111", "APPEX" },
{ 358, 0, "Great Falls", "MT", "US West Cellular", "800 626 6611", "GTEDS" },
{ 359, 0, "Ft. Smith", "AR", "Cellular One", "501 783 4600", "GTEDS" },
{ 360, 0, "Greely", "CO", "US West Cellular", "800 626 6611", "GTEDS" },
{ 361, 0, "Ft. Walton Beach", "FL", "Cellular One", "904 433 7300", "GTEDS" },
{ 361, 30021, "Pensacola", "FL", "Cellular One", "904 433 7300", "GTEDS" },
{ 362, 0, "Green Bay", "WI", "Cellcom", "414 494 2355", "GTEDS" },
{ 364, 0, "Hagerstown", "MD", "Bell Atlantic Mobile", "800 922 0204", "GTEDS" },
{ 365, 0, "Gainesville", "FL", "Centel Cellular", "904 374 8100", "GTEDS" },
{ 368, 0, "Hickory", "NC", "Centel Cellular", "704 327 4000", "GTEDS" },
{ 370, 0, "Houma", "LA", "Mobiletel", "504 798 7894", "GTEDS" },
{ 370, 0, "Thibodaux", "LA", "Mobiletel", "504 798 7894", "GTEDS" },
{ 370, 0, "Larose", "LA", "Mobiletel", "504 798 7894", "GTEDS" },
{ 370, 0, "Leeville", "LA", "Mobiletel", "504 798 7894", "GTEDS" },
{ 373, 0, "Great Falls", "MT", "Cellular One", "406 727 2355", "GTEDS" },
{ 374, 0, "Jackson", "MI", "Century Cellunet", "517 393 0311", "GTEDS" },
{ 376, 0, "Jacksonville", "NC", "Centel Cellular", "919 833 7494", "GTEDS" },
{ 377, 0, "Florence", "SC", "Cellular One", "803 664 2898", "GTEDS" },
{ 381, 0, "Hagerstown", "MD", "Cellular One", "301 331 2355", "GTEDS" },
{ 384, 0, "Joplin", "MO", "US Cellular", "417 624 2255", "GTEDS" },
{ 385, 0, "Hickory", "NC", "Cellcom", "704 322 7557", "APPEX" },
{ 386, 0, "Kalamazoo", "MI", "Century Cellunet", "616 342 6655", "GTEDS" },
{ 387, 0, "Houma", "LA", "Cellular One", "504 686 0220", "GTEDS" },
{ 387, 0, "Thibodaux", "LA", "Cellular One", "504 686 0220", "GTEDS" },
{ 389, 0, "Iowa City", "IA", "Allcell Cellular", "319 351 5888", "CBIS" },
{ 392, 0, "Killeen", "TX", "Centel Cellular", "817 771 0077", "GTEDS" },
{ 392, 0, "Temple", "TX", "Centel Cellular", "817 771 0077", "GTEDS" },
{ 393, 0, "Jacksonville", "NC", "Cellular One", "919 455 9300", "C-Tech" },
{ 396, 0, "La Crosse", "WI", "Century Cellunet", "608 788 8000", "GTEDS" },
{ 400, 0, "Lake Charles", "LA", "Mercury Cellular", "318 433 6298", "Lake Charles" },
{ 401, 0, "Joplin", "MO", "Cellular One", "417 862 6611", "APPEX" },
{ 402, 0, "Laredo", "TX", "Laredo Cellular", "512 722 2333", "GTEDS" },
{ 403, 0, "Kalamazoo", "MI", "Cellular One", "616 388 8066", "CBIS" },
{ 408, 0, "Lawton", "OK", "US Cellular", "405 355 3535", "GTEDS" },
{ 409, 0, "Killeen", "TX", "Cellular One", "817 526 6800", "APPEX" },
{ 409, 0, "Temple", "TX", "Cellular One", "817 526 6800", "APPEX" },
{ 412, 0, "Lima", "OH", "Centel Cellular", "419 893 1077", "GTEDS" },
{ 413, 0, "La Crosse", "WI", "US Cellular", "608 781 2600", "GTEDS" },
{ 414, 0, "Lafayette", "LA", "Bell South Mobile", "305 577 4975", "GTEDS" },
{ 415, 0, "Lafayette", "IN", "McCaw Cellular", "502 582 2273", "GTEDS" },
{ 416, 0, "Lincoln", "NE", "Lincoln Telephone Cellular", "402 486 7266", "GTEDS" },
{ 417, 0, "Lake Charles", "LA", "Celltelco", "318 279 6532", "GTEDS" },
{ 418, 0, "Longview", "TX", "Centel Cellular", "214 561 5575", "GTEDS" },
{ 418, 0, "Marshall", "TX", "Centel Cellular", "214 561 5575", "GTEDS" },
{ 418, 0, "Tyler", "TX", "Centel Cellular", "214 561 5575", "GTEDS" },
{ 422, 0, "Abilene", "TX", "Southwestern Bell Mobile", "915 698 7626", "GTEDS" },
{ 422, 0, "Amarillo", "TX", "Southwestern Bell Mobile", "806 353 7447", "GTEDS" },
{ 422, 0, "Lubbock", "TX", "Southwestern Bell Mobile", "806 791 0011", "GTEDS" },
{ 422, 0, "Midland", "TX", "Southwestern Bell Mobile", "915 563 4611", "GTEDS" },
{ 422, 0, "Odessa", "TX", "Southwestern Bell Mobile", "915 563 4611", "GTEDS" },
{ 424, 0, "Lynchburg", "VA", "Centel Cellular", "804 528 3500", "GTEDS" },
{ 426, 0, "Macon", "GA", "Bell South Mobile", "800 351 2400", "GTEDS" },
{ 427, 0, "Auburn", "ME", "US Cellular", "207 782 8010", "GTEDS" },
{ 427, 0, "Lewiston", "ME", "US Cellular", "207 782 8010", "GTEDS" },
{ 428, 0, "Manchester", "NH", "Contel Cellular", "800 792 8400", "GTEDS" },
{ 428, 0, "Nashua", "NH", "Contel Cellular", "800 792 8400", "GTEDS" },
{ 430, 0, "Mansfield", "OH", "Centel Cellular", "419 893 1077", "GTEDS" },
{ 431, 0, "Lafayette", "LA", "Cellular One", "318 984 1777", "APPEX" },
{ 436, 0, "Medford", "OR", "US Cellular", "", "GTEDS" },
{ 439, 0, "Lubbock", "TX", "Cellular One", "806 797 2355", "GTEDS" },
{ 440, 0, "Monroe", "LA", "Century Cellunet", "318 325 3600", "GTEDS" },
{ 443, 0, "Macon", "GA", "Cellular One", "912 742 2355", "GTEDS" },
{ 443, 0, "Warner Robins", "GA", "Cellular One", "", "GTEDS" },
{ 444, 0, "Montgomery", "AL", "Alltel Mobile", "800 255 8351", "GTEDS" },
{ 445, 0, "Manchester", "NH", "US Cellular", "603 624 8000", "GTEDS" },
{ 447, 0, "Mansfield", "OH", "Cellular One", "419 564 5000", "Commonwealth" },
{ 448, 0, "Muskegon", "WI", "Century Cellunet", "616 940 0985", "GTEDS" },
{ 451, 0, "Jackson", "MS", "Cellular One", "512 686 2355", "Cell-T" },
{ 451, 0, "McAllen", "TX", "Cellular One", "512 686 2355", "Cell-T" },
{ 456, 0, "Olympia", "WA", "US West Cellular", "800 626 6611", "GTEDS" },
{ 462, 0, "Palm Springs", "FL", "Centel Cellular", "904 785 7000", "GTEDS" },
{ 462, 0, "Panama City", "FL", "Centel Cellular", "904 785 7000", "GTEDS" },
{ 465, 0, "Montgomery", "AL", "Montgomery Cellular", "205 265 2355", "GTEDS" },
{ 467, 0, "Muncie", "IN", "Cellular One", "502 582 2355", "APPEX" },
{ 473, 0, "Ocala", "FL", "Cellular One", "407 425 2355", "GTEDS" },
{ 475, 0, "Odessa", "TX", "Cellular One", "806 797 2355", "GTEDS" },
{ 476, 0, "Melbourne", "FL", "Bell South Mobile", "800 351 2400", "GTEDS" },
{ 478, 30018, "Pine Bluff", "AK", "Pine Bluff Cellular", "501 536 4200", "GTEDS" },
{ 479, 0, "Orange County", "NY", "Cellular One", "914 564 4447", "GTEDS" },
{ 480, 0, "Pittsfield", "NY", "Nynex Mobile Com", "", "Nynex" },
{ 481, 0, "Owensboro", "KY", "US Cellular", "502 685 5111", "GTEDS" },
{ 483, 0, "Palm Springs", "FL", "Palmer Comm", "904 769 2269", "GTEDS" },
{ 484, 0, "Biddeford", "ME", "Star Cellular", "800 346 9172", "GTEDS" },
{ 484, 0, "Dover", "NH", "Star Cellular", "800 346 9172", "GTEDS" },
{ 484, 0, "Portsmouth", "NH", "Star Cellular", "800 346 9172", "GTEDS" },
{ 484, 0, "Saco", "ME", "Star Cellular", "800 346 9172", "GTEDS" },
{ 486, 0, "Orange County", "NY", "Nynex Mobile Com", "", "Nynex" },
{ 486, 0, "Poughkeepsie", "NY", "Nynex Mobile Com", "", "Nynex" },
{ 488, 0, "Provo", "UT", "US West Cellular", "800 626 6611", "GTEDS" },
{ 494, 0, "Rapid City", "SD", "Contel Cellular", "800 792 8400", "GTEDS" },
{ 498, 0, "Reno", "NV", "Pactel Cellular", "916 920 0645", "GTEDS" },
{ 499, 0, "Portland", "ME", "Cellular One", "207 772 9805", "GTEDS" },
{ 500, 0, "Richland", "WA", "US Cellular", "", "GTEDS" },
{ 501, 0, "Portsmouth", "NH", "Cellular One", "617 890 1555", "(Boston)" },
{ 502, 0, "Roanke", "VA", "Contel Cellular", "800 792 8400", "GTEDS" },
{ 503, 0, "Poughkeepsie", "NY", "US Cellular", "914 297 3444", "GTEDS" },
{ 504, 0, "Rochester", "MN", "US Cellular", "507 388 3000", "GTEDS" },
{ 506, 0, "Rockford", "IL", "Contel Cellular", "800 792 8400", "GTEDS" },
{ 510, 0, "San Angelo", "TX", "West Central Cellular", "915 944 9016", "GTEDS" },
{ 511, 0, "Rapid City", "SD", "Cellular One", "", "GTEDS" },
{ 513, 0, "Redding", "CA", "Cellular One", "916 923 2222", "APPEX" },
{ 515, 0, "Reno", "NV", "Cellular One", "702 322 5511", "APPEX" },
{ 519, 0, "Roanke", "VA", "Cellular One", "703 345 0808", "Cell-T" },
{ 520, 0, "Savannah", "GA", "Savannah Cellular", "912 356 5224", "GTEDS" },
{ 521, 0, "Rochester", "MN", "Cellular One", "507 254 2273", "APPEX" },
{ 527, 0, "Monterey", "CA", "Cellular One", "408 754 8888", "APPEX" },
{ 527, 0, "Salinas", "CA", "Cellular One", "408 647 8888", "APPEX" },
{ 530, 0, "Elkhart", "IN", "Centel Cellular", "219 288 2355", "GTEDS" },
{ 530, 0, "South Bend", "IN", "Centel Cellular", "219 288 2355", "GTEDS" },
{ 531, 0, "Santa Barbara", "CA", "Santa Barbara Cellular", "800 722 7464", "Cell-T" },
{ 534, 0, "St. Cloud", "MN", "US Cellular", "612 252 9000", "GTEDS" },
{ 539, 0, "Savannah", "GA", "Cellular One", "912 352 3456", "GTEDS" },
{ 540, 0, "Sioux Falls", "SD", "US West Cellular", "800 626 6611", "GTEDS" },
{ 544, 0, "Talahassee", "FL", "Centel Cellular", "904 668 2200", "GTEDS" },
{ 545, 0, "Denison", "TX", "Metrocell Cellular", "214 263 4921", "APPEX" },
{ 545, 0, "Sherman", "TX", "Metrocell Cellular", "214 263 4921", "APPEX" },
{ 546, 0, "Springfield", "MO", "Alltel Mobile", "417 882 2020", "GTEDS" },
{ 547, 0, "Sioux City", "IA", "Centel Cellular", "712 274 2494", "" },
{ 549, 0, "South Bend", "IN", "Cellular One", "219 289 0933", "Micro-T" },
{ 550, 0, "Texarkana", "TX", "Century Cellunet", "214 793 0500", "GTEDS" },
{ 551, 30045, "Bloomington", "IL", "Cellular One", "217 744 3000", "APPEX" },
{ 551, 30005, "Champaign", "IL", "Cellular One", "217 744 3000", "APPEX" },
{ 551, 30003, "Decatur", "IL", "Cellular One", "217 744 3000", "APPEX" },
{ 551, 30001, "Springfield", "IL", "Cellular One", "217 744 3000", "APPEX" },
{ 551, 30005, "Urbana", "IL", "Cellular One", "217 744 3000", "APPEX" },
{ 555, 0, "Sioux Falls", "SD", "Cellular One", "605 336 0520", "Cell-T" },
{ 557, 0, "St. Joseph", "MO", "Cellular One", "816 232 6158", "APPEX" },
{ 561, 30019, "State College", "PA", "Cellular One", "717 579 2355", "GTEDS" },
{ 562, 0, "Victoria", "TX", "GTE Mobile", "800 347 5665", "GTEDS" },
{ 565, 0, "Talahassee", "FL", "Cellular One", "904 386 8999", "APPEX" },
{ 566, 0, "Waco", "TX", "Centel Cellular", "817 771 0077", "GTEDS" },
{ 567, 0, "Terre Haute", "IN", "Cellular One", "502 582 2355", "APPEX" },
{ 568, 0, "Waterloo", "IA", "Centel Cellular", "319 236 0400", "GTEDS" },
{ 570, 0, "Wausau", "WI", "US Cellular", "715 842 4200", "GTEDS" },
{ 574, 0, "Wichita Falls", "TX", "US Cellular", "817 696 5500", "GTEDS" },
{ 575, 0, "Trenton", "NJ", "Cellular One", "800 227 9222", "APPEX" },
{ 576, 0, "Williamsport", "PA", "US Cellular", "707 321 9500", "GTEDS" },
{ 577, 30027, "Tuscaloosa", "AL", "Cellular One", "205 942 2355", "APPEX" },
{ 578, 0, "Wilmington", "NC", "Centel Cellular", "919 833 7494", "GTEDS" },
{ 579, 0, "Tyler", "TX", "Cellular One", "214 561 2355", "GTEDS" },
{ 580, 0, "Yakima", "WA", "US Cellular", "509 248 3000", "GTEDS" },
{ 581, 0, "Victoria", "TX", "Cellular One", "512 573 1100", "Cell-T" },
{ 583, 0, "Vineland", "NJ", "Cellular One", "609 272 0900", "GTEDS" },
{ 587, 0, "Waco", "TX", "Cellular One", "817 776 3933", "APPEX" },
{ 589, 0, "Waterloo", "IA", "Cellular One", "319 234 4000", "GTEDS" },
{ 591, 0, "Wausau", "WI", "Cellular One", "715 842 7900", "GTEDS" },
{ 595, 0, "Wichita Falls", "TX", "Cellular One", "817 691 9100", "Cell-T" },
{ 599, 0, "Wilmington", "NC", "Cellular One", "919 799 5000", "GTEDS" },
{ 601, 0, "Yakima", "WA", "Cellular One", "509 454 2663", "APPEX" },
{ 607, 0, "Fayetteville", "AR", "Cellular One", "501 783 4600", "Cell-T" },
{ 1161, 0, "Hawaii", "HI", "US Cellular", "", "GTEDS" },
{ 1177, 0, "Lasalle", "IL", "Cellular One", "815 224 4470", "GTEDS" },
{ 1216, 0, "Batavia", "IA", "US Cellular", "515 662 7000", "GTEDS" },
{ 1704, 0, "Gainesville", "TX", "Southwestern Bell Mobile", "214 988 8484", "GTEDS" },
{ 1774, 0, "North Sound", "WA", "US West", "800 238 7848", "GTEDS" },
{ 1784, 0, "Longview", "WA", "US Cellular", "", "GTEDS" },
{ 16384, 0, "Calgary", "AB", "AGT Cellular", "403 248 2355", "GTEDS" },
{ 16384, 0, "Lethbridge", "AB", "AGT Cellular", "403 248 2355", "GTEDS" },
{ 16384, 0, "Medicine Hat", "AB", "AGT Cellular", "403 248 2355", "GTEDS" },
{ 16387, 0, "Calgary", "AB", "Cantel, Inc.", "403 266 1300", "GTEDS" },
{ 16389, 0, "Chicoutimi", "QU", "Cantel, Inc.", "514 340 9220", "GTEDS" },
{ 16390, 0, "Amherst", "NS", "MT&T Cellular", "902 421 2355", "GTEDS" },
{ 16390, 0, "Bridgewater", "NS", "MT&T Cellular", "902 421 2355", "GTEDS" },
{ 16390, 0, "Chester", "NS", "MT&T Cellular", "902 421 2355", "GTEDS" },
{ 16390, 0, "Halifax", "NS", "MT&T Cellular", "902 421 2355", "GTEDS" },
{ 16390, 0, "Hantsport", "NS", "MT&T Cellular", "902 421 2355", "GTEDS" },
{ 16390, 0, "Kentville", "NS", "MT&T Cellular", "902 421 2355", "GTEDS" },
{ 16390, 0, "Moncton", "NB", "MT&T Cellular", "902 421 2355", "GTEDS" },
{ 16390, 0, "Sydney", "NS", "MT&T Cellular", "902 421 2355", "GTEDS" },
{ 16390, 0, "Truro", "NS", "MT&T Cellular", "902 421 2355", "GTEDS" },
{ 16390, 0, "Windsor", "NS", "MT&T Cellular", "902 421 2355", "GTEDS" },
{ 16391, 0, "Edmonton", "AB", "Cantel, Inc.", "416 440 1300", "GTEDS" },
{ 16393, 0, "Halifax", "NS", "Cantel, Inc.", "416 440 1300", "GTEDS" },
{ 16395, 0, "Hamilton", "ON", "Cantel, Inc.", "416 440 1300", "GTEDS" },
{ 16397, 0, "Hespler", "ON", "Cantel, Inc.", "416 440 1300", "GTEDS" },
{ 16397, 0, "Kitchener", "ON", "Cantel, Inc.", "416 440 1300", "GTEDS" },
{ 16399, 0, "London", "ON", "Cantel, Inc.", "416 440 1300", "GTEDS" },
{ 16401, 0, "Montreal", "QU", "Cantel, Inc.", "514 340 9220", "GTEDS" },
{ 16403, 0, "Oshawa", "ON", "Cantel, Inc.", "416 440 1300", "GTEDS" },
{ 16405, 0, "Ottawa", "ON", "Cantel, Inc.", "514 340 9220", "GTEDS" },
{ 16407, 0, "Quebec City", "QU", "Cantel, Inc.", "514 340 9220", "GTEDS" },
{ 16408, 0, "Bathurst", "NB", "MT&T Cellular", "", "GTEDS" },
{ 16408, 0, "Newcastle", "NB", "MT&T Cellular", "", "GTEDS" },
{ 16409, 0, "Regina", "SK", "Cantel, Inc.", "403 266 1300", "GTEDS" },
{ 16411, 0, "St. John", "NB", "Cantel, Inc.", "416 440 1300", "GTEDS" },
{ 16413, 0, "Saskatoon", "SK", "Cantel, Inc.", "403 266 1300", "GTEDS" },
{ 16415, 0, "St. Catharines", "ON", "Cantel, Inc.", "416 440 1300", "GTEDS" },
{ 16419, 0, "Sudbury", "ON", "Cantel, Inc.", "416 440 1300", "GTEDS" },
{ 16423, 0, "Newmarket", "ON", "Cantel, Inc.", "416 440 1300", "GTEDS" },
{ 16423, 0, "Toronto", "ON", "Cantel, Inc.", "416", ":GTEDS" },
{ 16425, 0, "Abbotsford", "BC", "Cantel, Inc.", "604 687 1440", "GTEDS" },
{ 16427, 0, "Vancouver", "BC", "Cantel, Inc.", "604 687 1440", "GTEDS" },
{ 16428, 0, "Winnipeg", "MB", "MTS Cellular", "204 941 7910", "GTEDS" },
{ 16431, 0, "Windsor", "ON", "Cantel, Inc.", "416 440 1300", "GTEDS" },
{ 16431, 0, "Winnipeg", "MB", "Cantel, Inc.", "403 266 1300", "GTEDS" },
{ 16433, 0, "Trois Rivieres", "QU", "Cantel, Inc.", "416 440 1300", "GTEDS" },
{ 16435, 0, "Barrie", "ON", "Cantel, Inc.", "416 440 1300", "GTEDS" },
{ 16437, 0, "Brantford", "ON", "Cantel, Inc.", "416 440 1300", "GTEDS" },
{ 16439, 0, "Sherbrooke", "QU", "Cantel, Inc.", "514 340 9220", "GTEDS" },
{ 16441, 0, "Peterborough", "ON", "Cantel, Inc.", "416 440 1300", "GTEDS" },
{ 16443, 0, "Kingston", "ON", "Cantel, Inc.", "416 440 1300", "GTEDS" },
{ 16445, 0, "Red Deer", "AB", "Cantel, Inc.", "403 266 1300", "GTEDS" },
{ 16447, 0, "Nanaimo", "BC", "Cantel, Inc.", "604 687 1440", "GTEDS" },
{ 16449, 0, "Belleville", "ON", "Cantel, Inc.", "416 440 1300", "GTEDS" },
{ 16451, 0, "Cornwall", "ON", "Cantel, Inc.", "514 340 9220", "GTEDS" },
{ 16453, 0, "Portage", "AB", "Cantel, Inc.", "403 266 1300", "GTEDS" },
{ 16455, 0, "Selkirk", "AB", "Cantel, Inc.", "403 266 1300", "GTEDS" },
{ 16457, 0, "Chatham", "ON", "Cantel, Inc.", "416 440 1300", "GTEDS" },
{ 16459, 0, "Sarnia", "ON", "Cantel, Inc.", "416 440 1300", "GTEDS" },
{ 16461, 0, "Chiliwack", "BC", "Cantel, Inc.", "604 687 1440", "GTEDS" },
{ 16463, 0, "Whistler", "BC", "Cantel, Inc.", "604 687 1440", "GTEDS" },
{ 16465, 0, "Steinbach", "MB", "Cantel, Inc.", "403 266 1300", "GTEDS" },
{ 16467, 0, "Moncton", "NB", "Cantel, Inc.", "416 440 1300", "GTEDS" },
{ 16469, 0, "Fredericton", "NB", "Cantel, Inc.", "", "GTEDS" },
{ 16471, 0, "Brandon", "MB", "Cantel, Inc.", "403 266 1300", "GTEDS" },
{ 16473, 0, "Lethbridge", "AB", "Cantel, Inc.", "403 266 1300", "GTEDS" },
{ 16475, 0, "Truro", "NS", "Cantel, Inc.", "416 440 1300", "GTEDS" },
{ 16477, 0, "Collingwood", "ON", "Cantel, Inc.", "", "GTEDS" },
{ 16481, 0, "St. Marie", "QU", "Cantel, Inc.", "514 340 9220", "GTEDS" },
{ 16485, 0, "Coburg", "ON", "Cantel, Inc.", "415 440 1300", "GTEDS" },
{ 16485, 0, "Newtonville", "ON", "Cantel, Inc.", "415 440 1300", "GTEDS" },
{ 16487, 0, "Brockville", "QU", "Cantel, Inc.", "514 340 9220", "GTEDS" },
{ 16491, 0, "Ponoka", "AB", "Cantel, Inc.", "604 687 1440", "GTEDS" },
{ 16493, 0, "Bowden", "QU", "Cantel, Inc.", "604 687 1440", "GTEDS" },
{ 16509, 0, "Orillia", "ON", "Cantel, Inc.", "416 440 1300", "GTEDS" },
{ 16521, 0, "Kelowna", "BC", "Cantel, Inc.", "", "GTEDS" },
{ 16525, 0, "Penticton", "BC", "Cantel, Inc.", "", "GTEDS" },
{ 16527, 0, "Kamloops", "BC", "Cantel, Inc.", "", "GTEDS" },
{ 16531, 0, "Canmore", "ON", "Cantel, Inc.", "", "GTEDS" },
{ 32752, 0, "Nassau", "Bahamas","Batelco", "809 322 4848", "GTEDS" },
{ 0, 0, NULL, NULL, NULL, NULL, NULL }
};
void list_stations(void)
{
int i;
for (i = 0; amps_stations[i].city; i++) {
printf("SID: %d City: %s, %s (%s)\n", amps_stations[i].sid, amps_stations[i].city, amps_stations[i].state, amps_stations[i].company);
}
}
void sid_stations(int sid)
{
int i, first = 1;
for (i = 0; amps_stations[i].city; i++) {
if (sid == amps_stations[i].sid) {
if (first)
printf("Selected System ID (SID) %d belongs to:\n", amps_stations[i].sid);
first = 0;
printf("\t%s, %s (%s)\n", amps_stations[i].city, amps_stations[i].state, amps_stations[i].company);
}
}
}

4
src/amps/stations.h Normal file
View File

@ -0,0 +1,4 @@
void list_stations(void);
void sid_stations(int sid);

185
src/amps/sysinfo.c Normal file
View File

@ -0,0 +1,185 @@
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include "../common/timer.h"
#include "amps.h"
#include "frame.h"
static struct sysinfo_reg_incr default_reg_incr = {
450,
};
static struct sysinfo_loc_area default_loc_area = {
0,
0,
0,
0,
};
static struct sysinfo_new_acc default_new_acc = {
0,
};
static struct sysinfo_overload default_overload = {
{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
};
static struct sysinfo_acc_type default_acc_type = {
1,
0,
0,
0,
0,
};
static struct sysinfo_acc_attempt default_acc_attempt = {
10,
10,
10,
10,
};
void init_sysinfo(amps_si *si, int cmac, int vmac, int dcc, int sid1, int regh, int regr, int pureg, int pdreg, int locaid, int regincr)
{
int i;
memset(si, 0, sizeof(*si));
/* all words */
si->dcc = dcc;
/* VC assginment */
si->vmac = vmac;
/* filler */
si->filler.cmac = cmac;
si->filler.sdcc1 = 0;
si->filler.sdcc2 = 0;
si->filler.wfom = 1; /* must be set to ignore B/I bit */
/* Word 1 */
si->word1.sid1 = sid1;
si->word1.ep = 1; /* shall be 0 */
si->word1.auth = 0;
si->word1.pci = 0;
/* Word 2 */
si->word2.s = 1;
si->word2.e = 1;
si->word2.regh = regh;
si->word2.regr = regr;
si->word2.dtx = 0;
si->word2.n_1 = 20;
si->word2.rcf = 1; /* must be set to ignore B/I bit */
si->word2.cpa = 1; /* must be set for combined CC+PC */
si->word2.cmax_1 = 20;
/* registration increment */
si->reg_incr.regincr = regincr;
/* location area */
si->loc_area.pureg = pureg;
si->loc_area.pdreg = pdreg;
if (locaid >= 0) {
si->loc_area.lreg = 1;
si->loc_area.locaid = locaid;
}
/* new access channel set */
si->new_acc.newacc = 0;
/* overload control */
for (i = 0; i < 16; i++)
si->overload.olc[i] = 1;
/* Acces Tyoe */
/* 'bis' must be 0, so the phone does not wait for busy bit.
* We cannot respond with B/I fast enough due to processing delay.
* So we don't set the B/I bit to busy on reception of message.
* The access type message (including this 'bis') must also be included.
*/
si->acc_type.bis = 0; /* must be clear to ignore B/I bit */
si->acc_type.pci_home = 0; /* if set, bscap must allso be set */
si->acc_type.pci_roam = 0; /* if set, bscap must allso be set */
si->acc_type.bspc = 0;
si->acc_type.bscap = 0;
/* access attempt parameters */
si->acc_attempt.maxbusy_pgr = 10;
si->acc_attempt.maxsztr_pgr = 10;
si->acc_attempt.maxbusy_other = 10;
si->acc_attempt.maxsztr_other = 10;
/* registration ID */
si->reg_id.regid = 1000;
}
void prepare_sysinfo(amps_si *si)
{
int i = 0;
si->type[i++] = SYSINFO_WORD1;
si->type[i++] = SYSINFO_WORD2;
si->type[i++] = SYSINFO_REG_ID;
/* include only messages that differ from default */
if (!!memcmp(&si->reg_incr, &default_reg_incr, sizeof(si->reg_incr)))
si->type[i++] = SYSINFO_REG_INCR;
if (!!memcmp(&si->loc_area, &default_loc_area, sizeof(si->loc_area)))
si->type[i++] = SYSINFO_LOC_AREA;
if (!!memcmp(&si->new_acc, &default_new_acc, sizeof(si->new_acc)))
si->type[i++] = SYSINFO_NEW_ACC;
if (!!memcmp(&si->overload, &default_overload, sizeof(si->overload)))
si->type[i++] = SYSINFO_OVERLOAD;
if (!!memcmp(&si->acc_type, &default_acc_type, sizeof(si->acc_type)))
si->type[i++] = SYSINFO_ACC_TYPE;
if (!!memcmp(&si->acc_attempt, &default_acc_attempt, sizeof(si->acc_attempt)))
si->type[i++] = SYSINFO_ACC_ATTEMPT;
si->num = i; /* train is running */
si->count = 0; /* first message in train */
if (i > sizeof(si->type) / sizeof(si->type[0])) {
fprintf(stderr, "si type array overflow, pleas fix!\n");
abort();
}
}
uint64_t get_sysinfo(amps_si *si)
{
int count, nawc, end = 0;
time_t ti = time(NULL);
count = si->count;
if (++si->count == si->num) {
end = 1;
si->num = 0; /* train is over */
}
switch (si->type[count]) {
case SYSINFO_WORD1:
nawc = si->num - 1;
return amps_encode_word1_system(si->dcc, si->word1.sid1, si->word1.ep, si->word1.auth, si->word1.pci, nawc);
case SYSINFO_WORD2:
return amps_encode_word2_system(si->dcc, si->word2.s, si->word2.e, si->word2.regh, si->word2.regr, si->word2.dtx, si->word2.n_1, si->word2.rcf, si->word2.cpa, si->word2.cmax_1, end);
case SYSINFO_REG_ID:
/* use time stamp to generate regid */
si->reg_id.regid = ti & 0xfffff;
return amps_encode_registration_id(si->dcc, si->reg_id.regid, end);
case SYSINFO_REG_INCR:
return amps_encode_registration_increment(si->dcc, si->reg_incr.regincr, end);
case SYSINFO_LOC_AREA:
return amps_encode_location_area(si->dcc, si->loc_area.pureg, si->loc_area.pdreg, si->loc_area.lreg, si->loc_area.locaid, end);
case SYSINFO_NEW_ACC:
return amps_encode_new_access_channel_set(si->dcc, si->new_acc.newacc, end);
case SYSINFO_OVERLOAD:
return amps_encode_overload_control(si->dcc, si->overload.olc, end);
case SYSINFO_ACC_TYPE:
return amps_encode_access_type(si->dcc, si->acc_type.bis, si->acc_type.pci_home, si->acc_type.pci_roam, si->acc_type.bspc, si->acc_type.bscap, end);
case SYSINFO_ACC_ATTEMPT:
return amps_encode_access_attempt(si->dcc, si->acc_attempt.maxbusy_pgr, si->acc_attempt.maxsztr_pgr, si->acc_attempt.maxbusy_other, si->acc_attempt.maxsztr_other, end);
}
fprintf(stderr, "get_sysinfo unknown type, please fix!\n");
abort();
}

114
src/amps/sysinfo.h Normal file
View File

@ -0,0 +1,114 @@
/* filler */
struct sysinfo_filler {
uint8_t cmac;
uint8_t sdcc1;
uint8_t sdcc2;
uint8_t wfom;
};
enum amps_sysinfo_type {
SYSINFO_WORD1,
SYSINFO_WORD2,
SYSINFO_REG_ID,
SYSINFO_REG_INCR,
SYSINFO_LOC_AREA,
SYSINFO_NEW_ACC,
SYSINFO_OVERLOAD,
SYSINFO_ACC_TYPE,
SYSINFO_ACC_ATTEMPT,
};
/* Word 1 */
struct sysinfo_word1 {
uint16_t sid1;
uint8_t ep;
uint8_t auth;
uint8_t pci;
};
/* Word 2 */
struct sysinfo_word2 {
uint8_t s;
uint8_t e;
uint8_t regh;
uint8_t regr;
uint8_t dtx;
uint8_t n_1;
uint8_t rcf;
uint8_t cpa;
uint8_t cmax_1;
};
/* registration increment */
struct sysinfo_reg_incr {
uint16_t regincr;
};
/* location area */
struct sysinfo_loc_area {
uint8_t pureg;
uint8_t pdreg;
uint8_t lreg;
uint16_t locaid;
};
/* new access channel set */
struct sysinfo_new_acc {
uint16_t newacc;
};
/* overload control */
struct sysinfo_overload {
uint8_t olc[16];
};
/* Acces Tyoe */
struct sysinfo_acc_type {
uint8_t bis;
uint8_t pci_home;
uint8_t pci_roam;
uint8_t bspc;
uint8_t bscap;
};
/* access attempt parameters */
struct sysinfo_acc_attempt {
uint8_t maxbusy_pgr;
uint8_t maxsztr_pgr;
uint8_t maxbusy_other;
uint8_t maxsztr_other;
};
/* registration ID */
struct sysinfo_reg_id {
uint32_t regid;
};
typedef struct system_information {
/* all words */
uint8_t dcc;
/* VC assginment */
uint8_t vmac;
/* broadcast */
struct sysinfo_filler filler;
struct sysinfo_word1 word1;
struct sysinfo_word2 word2;
struct sysinfo_reg_incr reg_incr;
struct sysinfo_loc_area loc_area;
struct sysinfo_new_acc new_acc;
struct sysinfo_overload overload;
struct sysinfo_acc_type acc_type;
struct sysinfo_acc_attempt acc_attempt;
struct sysinfo_reg_id reg_id;
/* tx state */
enum amps_sysinfo_type type[16]; /* list of messages in train */
int num; /* number of messages in train */
int count; /* count message train */
} amps_si;
void init_sysinfo(amps_si *si, int cmac, int vmac, int dcc, int sid1, int regh, int regr, int pureg, int pdreg, int locaid, int regincr);
void prepare_sysinfo(amps_si *si);
uint64_t get_sysinfo(amps_si *si);

1790
src/amps/tones.c Normal file

File diff suppressed because it is too large Load Diff

3
src/amps/tones.h Normal file
View File

@ -0,0 +1,3 @@
void init_tones(void);

192
src/amps/transaction.c Normal file
View File

@ -0,0 +1,192 @@
/* C-Netz transaction handling
*
* (C) 2016 by Andreas Eversberg <jolly@eversberg.eu>
* All Rights Reserved
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include "../common/debug.h"
#include "../common/timer.h"
#include "amps.h"
//#include "database.h"
static const char *trans_state_name(int state)
{
switch (state) {
case 0:
return "IDLE";
case TRANS_REGISTER_ACK:
return "REGISTER ACK";
case TRANS_REGISTER_ACK_SEND:
return "REGISTER ACK SEND";
case TRANS_CALL_MO_ASSIGN:
return "CALL ASSIGN MOBILE ORIGINATING";
case TRANS_CALL_MO_ASSIGN_SEND:
return "CALL ASSIGN MOBILE ORIGINATING SEND";
case TRANS_CALL_MT_ASSIGN:
return "CALL ASSIGN MOBILE TERMINATING";
case TRANS_CALL_MT_ASSIGN_SEND:
return "CALL ASSIGN MOBILE TERMINATING SEND";
case TRANS_CALL_MT_ALERT:
return "CALL ALERT MOBILE TERMINATING";
case TRANS_CALL_REJECT:
return "CALL REJECT";
case TRANS_CALL_REJECT_SEND:
return "CALL REJECT SEND";
case TRANS_CALL:
return "CALL";
case TRANS_CALL_RELEASE:
return "CALL RELEASE";
case TRANS_CALL_RELEASE_SEND:
return "CALL RELEASE SEND";
case TRANS_PAGE:
return "PAGE";
case TRANS_PAGE_SEND:
return "PAGE SEND";
case TRANS_PAGE_REPLY:
return "PAGE REPLY";
default:
return "<invald transaction state>";
}
}
/* create transaction */
transaction_t *create_transaction(amps_t *amps, enum amps_trans_state state, uint32_t min1, uint16_t min2, uint8_t msg_type, uint8_t ordq, uint8_t order, uint16_t chan)
{
transaction_t *trans;
/* search transaction for this subsriber */
trans = search_transaction_number(amps, min1, min2);
if (trans) {
const char *number = amps_min2number(trans->min1, trans->min2);
PDEBUG(DTRANS, DEBUG_NOTICE, "Found alredy pending transaction for subscriber '%s', deleting!\n", number);
destroy_transaction(trans);
}
trans = calloc(1, sizeof(*trans));
if (!trans) {
PDEBUG(DTRANS, DEBUG_ERROR, "No memory!\n");
return NULL;
}
timer_init(&trans->timer, transaction_timeout, trans);
trans_new_state(trans, state);
trans->min1 = min1;
trans->min2 = min2;
trans->msg_type = msg_type;
trans->ordq = ordq;
trans->order = order;
trans->chan = chan;
const char *number = amps_min2number(trans->min1, trans->min2);
PDEBUG(DTRANS, DEBUG_INFO, "Created transaction '%s' for subscriber '%s'\n", number, trans_state_name(state));
link_transaction(trans, amps);
/* update database: now busy */
// update_db(amps, min1, min2, 1, 0);
return trans;
}
/* destroy transaction */
void destroy_transaction(transaction_t *trans)
{
/* update database: now idle */
// update_db(trans->amps, trans->min1, trans->min2, 0, trans->ma_failed);
unlink_transaction(trans);
const char *number = amps_min2number(trans->min1, trans->min2);
PDEBUG(DTRANS, DEBUG_INFO, "Destroying transaction for subscriber '%s'\n", number);
timer_exit(&trans->timer);
trans_new_state(trans, 0);
free(trans);
}
/* link transaction to list */
void link_transaction(transaction_t *trans, amps_t *amps)
{
transaction_t **transp;
/* attach to end of list, so first transaction is served first */
trans->amps = amps;
transp = &amps->trans_list;
while (*transp)
transp = &((*transp)->next);
*transp = trans;
}
/* unlink transaction from list */
void unlink_transaction(transaction_t *trans)
{
transaction_t **transp;
/* unlink */
transp = &trans->amps->trans_list;
while (*transp && *transp != trans)
transp = &((*transp)->next);
if (!(*transp)) {
PDEBUG(DTRANS, DEBUG_ERROR, "Transaction not in list, please fix!!\n");
abort();
}
*transp = trans->next;
trans->amps = NULL;
}
transaction_t *search_transaction_number(amps_t *amps, uint32_t min1, uint16_t min2)
{
transaction_t *trans = amps->trans_list;
while (trans) {
if (trans->min1 == min1
&& trans->min2 == min2) {
const char *number = amps_min2number(trans->min1, trans->min2);
PDEBUG(DTRANS, DEBUG_DEBUG, "Found transaction for subscriber '%s'\n", number);
return trans;
}
trans = trans->next;
}
return NULL;
}
void trans_new_state(transaction_t *trans, int state)
{
PDEBUG(DTRANS, DEBUG_INFO, "Transaction state %s -> %s\n", trans_state_name(trans->state), trans_state_name(state));
trans->state = state;
}
void amps_flush_other_transactions(amps_t *amps, transaction_t *trans)
{
/* flush after this very trans */
while (trans->next) {
PDEBUG(DTRANS, DEBUG_NOTICE, "Kicking other pending transaction\n");
destroy_transaction(trans);
}
/* flush before this very trans */
while (amps->trans_list != trans) {
PDEBUG(DTRANS, DEBUG_NOTICE, "Kicking other pending transaction\n");
destroy_transaction(amps->trans_list);
}
}

48
src/amps/transaction.h Normal file
View File

@ -0,0 +1,48 @@
typedef struct amps amps_t;
enum amps_trans_state {
TRANS_NULL = 0,
TRANS_REGISTER_ACK, /* attach request received, waiting to ack */
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_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 signalling tone is received */
TRANS_CALL_MT_ALERT_SEND, /* ringing the phone, signalling tone is received */
TRANS_CALL_REJECT, /* rejecting channel, waiting to send */
TRANS_CALL_REJECT_SEND, /* rejecting channel, sending reject */
TRANS_CALL, /* active call */
TRANS_CALL_RELEASE, /* release call towards phone, waiting to send */
TRANS_CALL_RELEASE_SEND, /* release call towards phone, sending release */
TRANS_PAGE, /* paging phone, waiting to send */
TRANS_PAGE_SEND, /* paging phone, sending page order */
TRANS_PAGE_REPLY, /* waitring for paging reply */
};
typedef struct transaction {
struct transaction *next; /* pointer to next node in list */
amps_t *amps; /* pointer to amps instance */
uint32_t min1; /* current station ID (2 values) */
uint16_t min2;
uint8_t msg_type; /* message type (3 values) */
uint8_t ordq;
uint8_t order;
uint16_t chan; /* channel to assign */
char dialing[33]; /* number dialed by the phone */
enum amps_trans_state state; /* state of transaction */
struct timer timer; /* for varous timeouts */
int sat_detected; /* state if we detected SAT */
} transaction_t;
transaction_t *create_transaction(amps_t *amps, enum amps_trans_state trans_state, uint32_t min1, uint16_t min2, uint8_t msg_type, uint8_t ordq, uint8_t order, uint16_t chan);
void destroy_transaction(transaction_t *trans);
void link_transaction(transaction_t *trans, amps_t *amps);
void unlink_transaction(transaction_t *trans);
transaction_t *search_transaction(amps_t *amps, uint32_t state_mask);
transaction_t *search_transaction_number(amps_t *amps, uint32_t min1, uint16_t min2);
void trans_new_state(transaction_t *trans, int state);
void amps_flush_other_transactions(amps_t *amps, transaction_t *trans);
void transaction_timeout(struct timer *timer);

View File

@ -34,17 +34,26 @@ extern int use_mncc_sock;
extern int send_patterns;
/* stream patterns/announcements */
int16_t *outoforder_spl = NULL;
int16_t *ringback_spl = NULL;
int16_t *hangup_spl = NULL;
int16_t *busy_spl = NULL;
int16_t *noanswer_spl = NULL;
int16_t *outoforder_spl = NULL;
int16_t *invalidnumber_spl = NULL;
int16_t *congestion_spl = NULL;
int outoforder_size = 0;
int ringback_size = 0;
int hangup_size = 0;
int busy_size = 0;
int noanswer_size = 0;
int outoforder_size = 0;
int invalidnumber_size = 0;
int congestion_size = 0;
int outoforder_max = 0;
int ringback_max = 0;
int hangup_max = 0;
int busy_max = 0;
int noanswer_max = 0;
int outoforder_max = 0;
int invalidnumber_max = 0;
int congestion_max = 0;
enum call_state {
@ -59,9 +68,12 @@ enum call_state {
enum audio_pattern {
PATTERN_NONE = 0,
PATTERN_RINGBACK,
PATTERN_HANGUP,
PATTERN_BUSY,
PATTERN_CONGESTION,
PATTERN_NOANSWER,
PATTERN_OUTOFORDER,
PATTERN_INVALIDNUMBER,
PATTERN_CONGESTION,
};
void get_pattern(const int16_t **spl, int *size, int *max, enum audio_pattern pattern)
@ -76,16 +88,26 @@ void get_pattern(const int16_t **spl, int *size, int *max, enum audio_pattern pa
*size = ringback_size;
*max = ringback_max;
break;
case PATTERN_HANGUP:
if (!hangup_spl)
goto no_hangup;
*spl = hangup_spl;
*size = hangup_size;
*max = hangup_max;
break;
case PATTERN_BUSY:
no_hangup:
no_noanswer:
*spl = busy_spl;
*size = busy_size;
*max = busy_max;
break;
case PATTERN_CONGESTION:
no_outoforder:
*spl = congestion_spl;
*size = congestion_size;
*max = congestion_max;
case PATTERN_NOANSWER:
if (!noanswer_spl)
goto no_noanswer;
*spl = noanswer_spl;
*size = noanswer_size;
*max = noanswer_max;
break;
case PATTERN_OUTOFORDER:
if (!outoforder_spl)
@ -94,6 +116,20 @@ no_outoforder:
*size = outoforder_size;
*max = outoforder_max;
break;
case PATTERN_INVALIDNUMBER:
if (!invalidnumber_spl)
goto no_invalidnumber;
*spl = invalidnumber_spl;
*size = invalidnumber_size;
*max = invalidnumber_max;
break;
case PATTERN_CONGESTION:
no_outoforder:
no_invalidnumber:
*spl = congestion_spl;
*size = congestion_size;
*max = congestion_max;
break;
default:
;
}
@ -150,14 +186,26 @@ static enum audio_pattern cause2pattern(int cause)
int pattern;
switch (cause) {
case CAUSE_NORMAL:
pattern = PATTERN_HANGUP;
break;
case CAUSE_BUSY:
pattern = PATTERN_BUSY;
break;
case CAUSE_NOANSWER:
pattern = PATTERN_NOANSWER;
break;
case CAUSE_OUTOFORDER:
pattern = PATTERN_OUTOFORDER;
break;
default:
case CAUSE_INVALNUMBER:
pattern = PATTERN_INVALIDNUMBER;
break;
case CAUSE_NOCHANNEL:
pattern = PATTERN_CONGESTION;
break;
default:
pattern = PATTERN_HANGUP;
}
return pattern;

View File

@ -44,6 +44,7 @@ struct debug_cat {
{ "bnetz", "\033[1;34m" },
{ "cnetz", "\033[1;34m" },
{ "nmt", "\033[1;34m" },
{ "amps", "\033[1;34m" },
{ "frame", "\033[0;36m" },
{ "call", "\033[1;37m" },
{ "mncc", "\033[1;32m" },

View File

@ -11,11 +11,12 @@
#define DBNETZ 4
#define DCNETZ 5
#define DNMT 6
#define DFRAME 7
#define DCALL 8
#define DMNCC 9
#define DDB 10
#define DTRANS 11
#define DAMPS 7
#define DFRAME 8
#define DCALL 9
#define DMNCC 10
#define DDB 11
#define DTRANS 12
#define PDEBUG(cat, level, fmt, arg...) _printdebug(__FILE__, __FUNCTION__, __LINE__, cat, level, fmt, ## arg)
void _printdebug(const char *file, const char *function, int line, int cat, int level, const char *fmt, ...);