diff --git a/docs/nmt.html b/docs/nmt.html index 131bb0f..a4de8b5 100644 --- a/docs/nmt.html +++ b/docs/nmt.html @@ -541,22 +541,21 @@ Setup of a base station
Before running the base station, you need to select a network. +The network is defined by the system (NMT-450 or NMT-900) and the Traffic Area (TA). +The NMT-450 is default. To make the phone access the network, it needs to have the same network selected. Check out what networks are available:
-# nmt -Y list -TA Short Country (Provider) ------------------------------------------------------------------------- -5 DK Denmark (Tele Danmark Mobile) -6 SE Sweden (Telia Mobitel) -7 NO Norway (Telenor Mobil) -8 FI Finland (Telecom Finland) -8 IS Iceland (Post & Telecom) -5 FO Faroe Island (Faroese Telecom) -7 EE Estonia (Eesti Mobiiltelefon) +# nmt -N 450 -Y list +TA from TA to YY Code Channels Short Country (Provider) +-------------------------------------------------------------------------------- +DK,1 DK,9 51..59 1-399 Denmark (Tele Danmark Mobile) +SE,1 SE,9 61..69 1-399 Sweden (Telia Mobitel) +NO,1 NO,9 71..79 1-399 Norway (Telenor Mobil) +FI,1 FI,9 81..89 1-399 Finland (Telecom Finland) ...diff --git a/src/nmt/countries.c b/src/nmt/countries.c index c809c91..f2e58fd 100644 --- a/src/nmt/countries.c +++ b/src/nmt/countries.c @@ -32,7 +32,7 @@ struct nmt_frequency { }; /* channel allocation used in scandinavian countries */ -static struct nmt_frequency frq_scandinavia[] = { +static struct nmt_frequency frq_450_scandinavia[] = { { 1, 180, 463.000, 0.025, 1.0, 10.0, 1 }, { 181,200, 462.500, 0.025, 1.0, 10.0, 1 }, { 201,380, 463.0125, 0.025, 1.0, 10.0, 1 }, @@ -40,45 +40,69 @@ static struct nmt_frequency frq_scandinavia[] = { { 0, 0, 0.0, 0.0, 0.0, 0.0, 0 } }; +static struct nmt_frequency frq_900_scandinavia[] = { + { 1, 1000, 935.0125, 0.025, 1.0, 45.0, 0 }, + { 1025,2023, 935.025, 0.025, 1.0, 45.0, 0 }, + { 0, 0, 0.0, 0.0, 0.0, 0.0, 0 } +}; + /* channel allocation used in Netherlands, Luxemburg, Belgium */ -static struct nmt_frequency frq_nl_l_b[] = { +static struct nmt_frequency frq_450_nl_l_b[] = { { 1, 222, 461.310, 0.020, 0.8, 10.0, 0 }, { 0, 0, 0.0, 0.0, 0.0, 0.0, 0 } }; +static struct nmt_frequency frq_900_nl[] = { + { 1, 1000, 935.0125, 0.025, 1.0, 45.0, 0 }, + { 0, 0, 0.0, 0.0, 0.0, 0.0, 0 } +}; + /* channel allocation used in Malaysia */ -static struct nmt_frequency frq_mal[] = { +static struct nmt_frequency frq_450_mal[] = { { 1, 180, 462.000, 0.025, 1.0, 10.0, 0 }, { 0, 0, 0.0, 0.0, 0.0, 0.0, 0 } }; /* channel allocation used in Thailand, Indonesia */ -static struct nmt_frequency frq_t_ri[] = { +static struct nmt_frequency frq_450_t_ri[] = { { 1, 224, 489.000, 0.020, 0.8, 10.0, 0 }, { 0, 0, 0.0, 0.0, 0.0, 0.0, 0 } }; /* channel allocation used in Spain */ -static struct nmt_frequency frq_e[] = { +static struct nmt_frequency frq_450_e[] = { { 1, 180, 464.325, 0.025, 1.0, 10.0, 0 }, { 0, 0, 0.0, 0.0, 0.0, 0.0, 0 } }; /* channel allocation used in Austria */ -static struct nmt_frequency frq_a[] = { +static struct nmt_frequency frq_450_a[] = { { 1, 180, 465.730, -0.020, 0.8, 10.0, 0 }, { 0, 0, 0.0, 0.0, 0.0, 0.0, 0 } }; /* channel allocation used in Czech Republic and Slovakia */ -static struct nmt_frequency frq_cz_sk[] = { +static struct nmt_frequency frq_450_cz_sk[] = { { 1, 222, 465.730, -0.020, 0.8, 10.0, 0 }, { 0, 0, 0.0, 0.0, 0.0, 0.0, 0 } }; +/* channel allocation used in Turkey */ +static struct nmt_frequency frq_900_tr[] = { + { 1, 180, 461.500, 0.025, 1.0, 10.0, 0 }, + { 0, 0, 0.0, 0.0, 0.0, 0.0, 0 } +}; + +/* channel allocation used in France */ +static struct nmt_frequency frq_900_f[] = { + { 1, 540, 430.050, 0.025, 1.0, -10.0, 0 }, + { 0, 0, 0.0, 0.0, 0.0, 0.0, 0 } +}; + /* country selector */ static struct nmt_country { - int tested; + int system; /* 450 or 900 */ + int tested; /* tested with a real phone */ int y; /* country code of traffic area */ int first_ta, last_ta; /* range of used traffic areas */ const char *short_name; @@ -86,47 +110,64 @@ static struct nmt_country { const char *provider_name; struct nmt_frequency *nmt_frequency; /* list of frequency allocations */ } nmt_country[] = { - { 1, 5, 1,9, "DK", "Denmark", "Tele Danmark Mobile", frq_scandinavia }, - { 1, 6, 1,9, "SE", "Sweden", "Telia Mobitel", frq_scandinavia }, - { 1, 7, 1,9, "NO", "Norway", "Telenor Mobil", frq_scandinavia }, - { 1, 8, 1,9, "FI", "Finland", "Telecom Finland", frq_scandinavia }, - { 1, 8, 1,9, "IS", "Iceland", "Post & Telecom", frq_scandinavia }, - { 1, 5, 1,9, "FO", "Faroe Island", "Faroese Telecom", frq_scandinavia }, - { 1, 7, 1,9, "EE", "Estonia", "Eesti Mobiiltelefon", frq_scandinavia }, - { 1, 5, 1,9, "LV", "Latvia", "Latvian Mobile Telephone", frq_scandinavia }, - { 1, 8, 1,9, "LT", "Lithuania", "COMLIET", frq_scandinavia }, - { 1, 6, 1,9, "BY", "Belarus", "Belcel", frq_scandinavia }, - { 1, 5, 1,9, "MO", "OSS/Moscow", "Moscow Cellular Comm.", frq_scandinavia }, - { 1, 6, 1,9, "STP", "OSS/St Petersburg", "Delta Telecom", frq_scandinavia }, - { 1, 6, 1,9, "STP", "OSS/Leningrads Dist.", "Delta Telecom", frq_scandinavia }, - { 1, 7, 1,9, "CAR", "OSS/Carelian Rep.", "Telecom Finland", frq_scandinavia }, - { 1, 5, 1,9, "MUR", "OSS/Murmansk", "Telecom Finland", frq_scandinavia }, - { 1, 5, 1,9, "LED", "OSS/Leningrads Dist.", "Telecom Finland", frq_scandinavia }, - { 1, 5, 1,9, "KAL", "Kaliningrad", "Telecom Finland", frq_scandinavia }, - { 1, 7, 1,9, "PL", "Poland", "CENTERTEL", frq_scandinavia }, - { 1, 6, 1,9, "BG", "Bulgaria", "MOBIFON", frq_scandinavia }, - { 1, 5, 1,9, "RO", "Romania", "Telefonica Romania", frq_scandinavia }, - { 1, 6, 1,9, "UA", "Ukraine", "Ukraine Mobile Comm.", frq_scandinavia }, - { 1, 1, 1,9, "RU1", "", "", frq_scandinavia }, - { 1, 2, 1,9, "RU2", "", "", frq_scandinavia }, - { 1, 3, 1,9, "RU3", "", "", frq_scandinavia }, - { 1, 4, 1,9, "RU4", "", "", frq_scandinavia }, - { 1, 1, 1,9, "NL", "Netherlands", "Royal Dutch Post & Telecom", frq_nl_l_b }, - { 1, 1, 15,15, "L", "Luxemburg", "Enterprise des P&T Luxembourg",frq_nl_l_b }, - { 1, 2, 1,9, "B", "Belgium", "Belgacom Mobile", frq_nl_l_b }, - { 1, 7, 1,9, "CZ", "Czech Republic", "Eurotel Prague", frq_cz_sk }, - { 1, 6, 1,9, "SK", "Slovakia", "Eurotel Bratislava", frq_cz_sk }, + /* 450 */ + { 450, 1, 5, 1,9, "DK", "Denmark", "Tele Danmark Mobile", frq_450_scandinavia }, + { 450, 1, 6, 1,9, "SE", "Sweden", "Telia Mobitel", frq_450_scandinavia }, + { 450, 1, 7, 1,9, "NO", "Norway", "Telenor Mobil", frq_450_scandinavia }, + { 450, 1, 8, 1,9, "FI", "Finland", "Telecom Finland", frq_450_scandinavia }, + { 450, 1, 8, 1,9, "IS", "Iceland", "Post & Telecom", frq_450_scandinavia }, + { 450, 1, 5, 1,9, "FO", "Faroe Island", "Faroese Telecom", frq_450_scandinavia }, + { 450, 1, 7, 1,9, "EE", "Estonia", "Eesti Mobiiltelefon", frq_450_scandinavia }, + { 450, 1, 5, 1,9, "LV", "Latvia", "Latvian Mobile Telephone", frq_450_scandinavia }, + { 450, 1, 8, 1,9, "LT", "Lithuania", "COMLIET", frq_450_scandinavia }, + { 450, 1, 6, 1,9, "BY", "Belarus", "Belcel", frq_450_scandinavia }, + { 450, 1, 5, 1,9, "MO", "OSS/Moscow", "Moscow Cellular Comm.", frq_450_scandinavia }, + { 450, 1, 6, 1,9, "STP", "OSS/St Petersburg", "Delta Telecom", frq_450_scandinavia }, + { 450, 1, 6, 1,9, "STP", "OSS/Leningrads Dist.", "Delta Telecom", frq_450_scandinavia }, + { 450, 1, 7, 1,9, "CAR", "OSS/Carelian Rep.", "Telecom Finland", frq_450_scandinavia }, + { 450, 1, 5, 1,9, "MUR", "OSS/Murmansk", "Telecom Finland", frq_450_scandinavia }, + { 450, 1, 5, 1,9, "LED", "OSS/Leningrads Dist.", "Telecom Finland", frq_450_scandinavia }, + { 450, 1, 5, 1,9, "KAL", "Kaliningrad", "Telecom Finland", frq_450_scandinavia }, + { 450, 1, 7, 1,9, "PL", "Poland", "CENTERTEL", frq_450_scandinavia }, + { 450, 1, 6, 1,9, "BG", "Bulgaria", "MOBIFON", frq_450_scandinavia }, + { 450, 1, 5, 1,9, "RO", "Romania", "Telefonica Romania", frq_450_scandinavia }, + { 450, 1, 6, 1,9, "UA", "Ukraine", "Ukraine Mobile Comm.", frq_450_scandinavia }, + { 450, 1, 1, 1,9, "RU1", "", "", frq_450_scandinavia }, + { 450, 1, 2, 1,9, "RU2", "", "", frq_450_scandinavia }, + { 450, 1, 3, 1,9, "RU3", "", "", frq_450_scandinavia }, + { 450, 1, 4, 1,9, "RU4", "", "", frq_450_scandinavia }, + { 450, 1, 1, 1,9, "NL", "Netherlands", "Royal Dutch Post & Telecom", frq_450_nl_l_b }, + { 450, 1, 1, 15,15, "L", "Luxemburg", "Enterprise des P&T Luxembourg",frq_450_nl_l_b }, + { 450, 1, 2, 1,9, "B", "Belgium", "Belgacom Mobile", frq_450_nl_l_b }, + { 450, 1, 7, 1,9, "CZ", "Czech Republic", "Eurotel Prague", frq_450_cz_sk }, + { 450, 1, 6, 1,9, "SK", "Slovakia", "Eurotel Bratislava", frq_450_cz_sk }, + /* 900 */ + { 900, 1, 1, 1,9, "DK", "Denmark", "Tele Danmark Mobile", frq_900_scandinavia }, + { 900, 1, 2, 1,9, "SE", "Sweden", "Telia Mobitel", frq_900_scandinavia }, + { 900, 1, 3, 1,9, "NO", "Norway", "Telenor Mobil", frq_900_scandinavia }, + { 900, 1, 4, 1,9, "FI", "Finland", "Telecom Finland", frq_900_scandinavia }, /* untested... */ - { 0, 8, 8,8, "MAL", "Malaysia", "Jabatan Telekom Malaysia", frq_mal }, - { 0, 4, 1,9, "T", "Thailand", "Telephone Organization of Thailand",frq_t_ri }, - { 0, 8, 1,9, "E", "Spain", "Telefonica Servicios Moviles", frq_e }, - { 0, 8, 1,1, "RI", "Indonesia", "PT Mobisel", frq_t_ri }, - { 0, 0, 1,3, "A", "Austria", "PTV", frq_a }, - { 0, 9, 1,3, "A2", "Austria 2", "PTV", frq_a }, - { 0, 0, 0,0, NULL, NULL, NULL, NULL } + { 450, 0, 8, 8,8, "MAL", "Malaysia", "Jabatan Telekom Malaysia", frq_450_mal }, + { 450, 0, 4, 1,9, "T", "Thailand", "Telephone Organization of Thailand",frq_450_t_ri }, + { 450, 0, 8, 1,9, "E", "Spain", "Telefonica Servicios Moviles", frq_450_e }, + { 450, 0, 8, 1,1, "RI", "Indonesia", "PT Mobisel", frq_450_t_ri }, + { 450, 0, 0, 1,3, "A", "Austria", "PTV", frq_450_a }, + { 450, 0, 9, 1,3, "A2", "Austria 2", "PTV", frq_450_a }, + { 900, 0, 5, 1,9, "CH", "Switzerland", "PTT", frq_900_scandinavia }, + { 900, 0, 6, 1,15, "NL", "Netherlands", "Royal Dutch Post & Telecom", frq_900_nl }, + { 900, 0, 1, 1,9, "TR", "Turkey", "Turkcell", frq_900_tr }, + { 900, 0, 0, 1,9, "F0", "France (Group 0)", "France Telecom", frq_900_f }, + { 900, 0, 1, 1,9, "F1", "France (Group 1)", "France Telecom", frq_900_f }, + { 900, 0, 2, 1,9, "F2", "France (Group 2)", "France Telecom", frq_900_f }, + { 900, 0, 3, 1,9, "F3", "France (Group 3)", "France Telecom", frq_900_f }, + { 900, 0, 4, 1,9, "F4", "France (Group 4)", "France Telecom", frq_900_f }, + { 900, 0, 5, 1,9, "F5", "France (Group 5)", "France Telecom", frq_900_f }, + { 900, 0, 6, 1,9, "F6", "France (Group 6)", "France Telecom", frq_900_f }, + { 900, 0, 7, 1,9, "F7", "France (Group 7)", "France Telecom", frq_900_f }, + { 0,0, 0, 0,0, NULL, NULL, NULL, NULL } }; -void nmt_country_list(void) +void nmt_country_list(int nmt_system) { int i, j; int ch_from = 0, ch_to = 0; @@ -135,6 +176,8 @@ void nmt_country_list(void) printf("TA from\tTA to\tYY Code\tChannels\tShort\tCountry (Provider)\n"); printf("--------------------------------------------------------------------------------\n"); for (i = 0; nmt_country[i].short_name; i++) { + if (nmt_system != nmt_country[i].system) + continue; printf("%s,%d\t", nmt_country[i].short_name, nmt_country[i].first_ta); if (nmt_country[i].first_ta != nmt_country[i].last_ta) printf("%s,%d", nmt_country[i].short_name, nmt_country[i].last_ta); @@ -155,11 +198,13 @@ void nmt_country_list(void) } } -int nmt_country_by_short_name(const char *short_name) +int nmt_country_by_short_name(int nmt_system, const char *short_name) { int i; for (i = 0; nmt_country[i].short_name; i++) { + if (nmt_system != nmt_country[i].system) + continue; if (!strcasecmp(nmt_country[i].short_name, short_name)) return nmt_country[i].y; } @@ -167,11 +212,13 @@ int nmt_country_by_short_name(const char *short_name) return -1; } -const char *nmt_long_name_by_short_name(const char *short_name) +const char *nmt_long_name_by_short_name(int nmt_system, const char *short_name) { int i; for (i = 0; nmt_country[i].short_name; i++) { + if (nmt_system != nmt_country[i].system) + continue; if (!strcasecmp(nmt_country[i].short_name, short_name)) return nmt_country[i].long_name; } @@ -179,11 +226,13 @@ const char *nmt_long_name_by_short_name(const char *short_name) return NULL; } -int nmt_ta_by_short_name(const char *short_name, int ta) +int nmt_ta_by_short_name(int nmt_system, const char *short_name, int ta) { int i; for (i = 0; nmt_country[i].short_name; i++) { + if (nmt_system != nmt_country[i].system) + continue; if (!strcasecmp(nmt_country[i].short_name, short_name) && ta >= nmt_country[i].first_ta && ta <= nmt_country[i].last_ta) return ta; } @@ -193,12 +242,14 @@ int nmt_ta_by_short_name(const char *short_name, int ta) /* Convert channel number to frequency number of base station. Set 'uplink' to 1 to get frequency of mobile station. */ -double nmt_channel2freq(const char *short_name, int channel, int uplink, double *deviation_factor, int *scandinavia, int *tested) +double nmt_channel2freq(int nmt_system, const char *short_name, int channel, int uplink, double *deviation_factor, int *scandinavia, int *tested) { int i, j; double freq; for (i = 0; nmt_country[i].short_name; i++) { + if (nmt_system != nmt_country[i].system) + continue; if (!strcasecmp(nmt_country[i].short_name, short_name)) { for (j = 0; nmt_country[i].nmt_frequency[j].first_frequency; j++) { if (channel >= nmt_country[i].nmt_frequency[j].first_channel diff --git a/src/nmt/countries.h b/src/nmt/countries.h index b8a7121..adfbdde 100644 --- a/src/nmt/countries.h +++ b/src/nmt/countries.h @@ -1,7 +1,7 @@ -void nmt_country_list(void); -int nmt_country_by_short_name(const char *short_name); -const char *nmt_long_name_by_short_name(const char *short_name); -int nmt_ta_by_short_name(const char *short_name, int ta); -double nmt_channel2freq(const char *short_name, int channel, int uplink, double *deviation_factor, int *scandinavia, int *tested); +void nmt_country_list(int nmt_system); +int nmt_country_by_short_name(int nmt_system, const char *short_name); +const char *nmt_long_name_by_short_name(int nmt_system, const char *short_name); +int nmt_ta_by_short_name(int nmt_system, const char *short_name, int ta); +double nmt_channel2freq(int nmt_system, const char *short_name, int channel, int uplink, double *deviation_factor, int *scandinavia, int *tested); diff --git a/src/nmt/frame.c b/src/nmt/frame.c index 8cad3ca..b64a37c 100644 --- a/src/nmt/frame.c +++ b/src/nmt/frame.c @@ -29,41 +29,116 @@ #include "frame.h" #include "hagelbarger.h" -uint64_t nmt_encode_channel(int channel, int power) +uint64_t nmt_encode_channel(int nmt_system, int channel, int power) { uint64_t value = 0; - if (channel >= 200) { - value |= 0x800; - channel -= 200; + if (nmt_system == 450) { + if (channel >= 200) { + value |= 0x800; + channel -= 200; + } + if (channel >= 100) { + value |= 0x100; + channel -= 100; + } + value |= channel % 10; + value |= (channel / 10) << 4; + value |= power << 9; + } else { + /* interleaved channels are indicated in traffic area */ + if (value > 1000) + value -= 1000; + value |= channel; + /* if channel >= 512, set upper bit */ + if (value & 0x200) + value = value - 0x200 + 0x800; + value |= power << 9; } - if (channel >= 100) { - value |= 0x100; - channel -= 100; - } - value |= channel % 10; - value |= (channel / 10) << 4; - value |= power << 9; return value; } -int nmt_decode_channel(uint64_t value, int *channel, int *power) +int nmt_decode_channel(int nmt_system, uint64_t value, int *channel, int *power) { - if ((value & 0x00f) > 0x009) - return -1; - if ((value & 0x0f0) > 0x090) - return -1; + if (nmt_system == 450) { + if ((value & 0x00f) > 0x009) + return -1; + if ((value & 0x0f0) > 0x090) + return -1; - *channel = (value & 0x00f) + - ((value & 0x0f0) >> 4) * 10 + - ((value & 0x100) >> 8) * 100 + - ((value & 0x800) >> 11) * 200; + *channel = (value & 0x00f) + + ((value & 0x0f0) >> 4) * 10 + + ((value & 0x100) >> 8) * 100 + + ((value & 0x800) >> 11) * 200; + } else { + *channel = (value & 0x1ff) + + ((value & 0x800) >> 2); + } *power = (value & 0x600) >> 9; return 0; } +uint64_t nmt_encode_tc(int nmt_system, int channel, int power) +{ + uint64_t value = 0; + + if (nmt_system == 450) { + if (channel >= 200) { + value |= 0x800; + channel -= 200; + } + if (channel >= 100) { + value |= 0x100; + channel -= 100; + } + value |= channel % 10; + value |= (channel / 10) << 4; + value |= power << 9; + } else { + value = channel; + } + + return value; +} + +static int nmt_decode_tc(int nmt_system, uint64_t value, int *channel, int *power) +{ + if (nmt_system == 450) { + if ((value & 0x00f) > 0x009) + return -1; + if ((value & 0x0f0) > 0x090) + return -1; + + *channel = (value & 0x00f) + + ((value & 0x0f0) >> 4) * 10 + + ((value & 0x100) >> 8) * 100 + + ((value & 0x800) >> 11) * 200; + *power = (value & 0x600) >> 9; + } else { + *channel = value & 0x3ff; + } + + return 0; +} + +uint64_t nmt_encode_traffic_area(int nmt_system, int channel, uint8_t traffic_area) +{ + uint64_t value = 0; + + if (nmt_system == 450) { + value = traffic_area; + } else { + /* upper bit is used for indication of interleaved channel */ + value = traffic_area & 0x7f; + if (channel > 1000) + value |= 0x80; + } + + return value; +} + void nmt_value2digits(uint64_t value, char *digits, int num) { int digit, i; @@ -214,24 +289,30 @@ static struct nmt_frame { } nmt_frame[] = { /* Define Digits Dir. Prefix Nr. Description */ { NMT_MESSAGE_1a, "NNNPYYHHHHHHHHHH", MTX_TO_MS, 12, "1a", "Calling channel indication" }, + { NMT_MESSAGE_1a_a, "NNNPYYHHHHHHHHHH", MTX_TO_MS, 11, "1a'", "Calling channel indication (for MS group A)" }, + { NMT_MESSAGE_1a_b, "NNNPYYHHHHHHHHHH", MTX_TO_MS, 13, "1a''", "Calling channel indication (for MS group B)" }, { NMT_MESSAGE_1b, "NNNPYYHHHHHHHHHH", MTX_TO_MS, 4, "1b", "Combined calling and traffic channel indication" }, { NMT_MESSAGE_2a, "NNNPYYZXXXXXXHHH", MTX_TO_MS, 12, "2a", "Call to mobile subscriber on calling channel" }, { NMT_MESSAGE_2b, "NNNPYYZXXXXXXnnn", MTX_TO_MS, 12, "2b", "Traffic channel allocation on calling channel" }, { NMT_MESSAGE_2c, "NNNPYYZXXXXXXHHH", MTX_TO_MS, 12, "2c", "Queueing information to MS with priority on calling channel" }, { NMT_MESSAGE_2d, "NNNPYYZXXXXXXHHH", MTX_TO_MS, 12, "2d", "Traffic channel scanning order on calling channel" }, + { NMT_MESSAGE_2e, "NNNPYYZXXXXXXHHH", MTX_TO_MS, 4, "2e", "Alternative type of call to MS on combinded CC/TC" }, { NMT_MESSAGE_2f, "NNNPYYZXXXXXXHHH", MTX_TO_MS, 12, "2f", "Queuing information to ordinary MS" }, { NMT_MESSAGE_3a, "NNNPYYZXXXXXXnnn", MTX_TO_MS, 5, "3a", "Traffic channel allocation on traffic channel" }, { NMT_MESSAGE_3b, "NNNPYYZXXXXXXHHH", MTX_TO_MS, 5, "3b", "Identity request on traffic channel" }, { NMT_MESSAGE_3c, "NNNPYYZXXXXXXnnn", MTX_TO_MS, 9, "3c", "Traffic channel allocation on traffic channel, short procedure" }, + { NMT_MESSAGE_3d, "NNNPYYZXXXXXXnnn", MTX_TO_MS, 7, "3d", "Traffic channel allocation on access channel" }, { NMT_MESSAGE_4, "NNNPYYJJJJJJJHHH", MTX_TO_MS, 3, "4", "Free traffic channel indication" }, + { NMT_MESSAGE_4b, "NNNPYYJJJJJJJHHH", MTX_TO_MS, 7, "4b", "Access channel indication" }, { NMT_MESSAGE_5a, "NNNPYYZXXXXXXLLL", MTX_TO_MS, 6, "5a", "Line signal" }, { NMT_MESSAGE_5b, "NNNPYYZXXXXXXLQQ", MTX_TO_MS, 6, "5b", "Line signal: Answer to coin-box" }, { NMT_MESSAGE_6, "JJJPJJJJJJJJJJJJ", MTX_TO_XX, 0, "6", "Idle frame" }, { NMT_MESSAGE_7, "NNNPYYCCCCCCCJJJ", MTX_TO_MS, 8, "7", "Authentication request" }, { NMT_MESSAGE_8, "NNNPYYMHHHHHHHWW", MTX_TO_MS, 1, "8", "A-subscriber number" }, - { NMT_MESSAGE_10a, "NNNPZXXXXXXTJJJJ", MS_TO_MTX, 1, "10a", "Call acknowledgment from MS on calling channel (shortened frame)" }, + { NMT_MESSAGE_10a, "NNNPZXXXXXXTJJJJ", MS_TO_MTX, 1, "10a", "Call acknowledgment from MS on calling channel and access on access channel (shortened frame)" }, { NMT_MESSAGE_10b, "NNNPZXXXXXXTYKKK", MS_TO_MTX, 1, "10b", "Seizure from ordinary MS and identity on traffic channel" }, { NMT_MESSAGE_10c, "NNNPZXXXXXXTYKKK", MS_TO_MTX, 6, "10c", "Seizure and identity from called MS on traffic channel" }, + { NMT_MESSAGE_10d, "NNNPZXXXXXXTJJJJ", MS_TO_MTX, 6, "10c", "Call acknowledgement from MS on the alternative type of call on combined CC/TC (shortened frame)" }, { NMT_MESSAGE_11a, "NNNPZXXXXXXTYKKK", MS_TO_MTX, 14, "11a", "Roaming updating seizure and identity on traffic channel" }, { NMT_MESSAGE_11b, "NNNPZXXXXXXTYKKK", MS_TO_MTX, 15, "11b", "Seizure and call achnowledgment on calling channel from MS with priority (shortened frame)" }, { NMT_MESSAGE_12, "NNNPZXXXXXXTYKKK", MS_TO_MTX, 11, "12", "Seizure from coin-box on traffic channel" }, @@ -288,12 +369,12 @@ static const char *param_hex(uint64_t value, int __attribute__((unused)) ndigits return result; } -static const char *param_channel_no(uint64_t value, int __attribute__((unused)) ndigits, enum nmt_direction __attribute__((unused)) direction) +static const char *param_channel_no_450(uint64_t value, int __attribute__((unused)) ndigits, enum nmt_direction __attribute__((unused)) direction) { static char result[32]; int rc, channel, power; - rc = nmt_decode_channel(value, &channel, &power); + rc = nmt_decode_channel(450, value, &channel, &power); if (rc < 0) sprintf(result, "invalid(%" PRIu64 ")", value); else @@ -302,6 +383,48 @@ static const char *param_channel_no(uint64_t value, int __attribute__((unused)) return result; } +static const char *param_channel_no_900(uint64_t value, int __attribute__((unused)) ndigits, enum nmt_direction __attribute__((unused)) direction) +{ + static char result[32]; + int rc, channel, power; + + rc = nmt_decode_channel(900, value, &channel, &power); + if (rc < 0) + sprintf(result, "invalid(%" PRIu64 ")", value); + else + sprintf(result, "channel=%d power=%d", channel, power); + + return result; +} + +static const char *param_tc_no_450(uint64_t value, int __attribute__((unused)) ndigits, enum nmt_direction __attribute__((unused)) direction) +{ + static char result[32]; + int rc, channel, power; + + rc = nmt_decode_tc(450, value, &channel, &power); + if (rc < 0) + sprintf(result, "invalid(%" PRIu64 ")", value); + else + sprintf(result, "channel=%d power=%d", channel, power); + + return result; +} + +static const char *param_tc_no_900(uint64_t value, int __attribute__((unused)) ndigits, enum nmt_direction __attribute__((unused)) direction) +{ + static char result[32]; + int rc, channel; + + rc = nmt_decode_tc(900, value, &channel, NULL); + if (rc < 0) + sprintf(result, "invalid(%" PRIu64 ")", value); + else + sprintf(result, "channel=%d", channel); + + return result; +} + static const char *param_country(uint64_t value, int __attribute__((unused)) ndigits, enum nmt_direction __attribute__((unused)) direction) { static char result[32]; @@ -310,7 +433,7 @@ static const char *param_country(uint64_t value, int __attribute__((unused)) ndi case 0: return "no additional info"; case 1: - return "Netherlands / Luxemburg / Malaysia"; + return "Netherlands / Luxemburg / Malaysia / Switzerland"; case 2: return "Belgium"; case 4: @@ -347,7 +470,7 @@ static const char *param_number(uint64_t value, int ndigits, enum nmt_direction return result; } -static const char *param_ta(uint64_t value, int ndigits, enum nmt_direction __attribute__((unused)) direction) +static const char *param_ta_450(uint64_t value, int ndigits, enum nmt_direction __attribute__((unused)) direction) { static char result[32]; @@ -357,6 +480,18 @@ static const char *param_ta(uint64_t value, int ndigits, enum nmt_direction __at return result; } +static const char *param_ta_900(uint64_t value, int __attribute__((unused)) ndigits, enum nmt_direction __attribute__((unused)) direction) +{ + static char result[32]; + + if ((value & 0x80)) + sprintf(result, "%" PRIu64 " (Channel No. + 1000)", value & 0x7f); + else + sprintf(result, "%" PRIu64, value); + + return result; +} + static const char *param_line_signal(uint64_t value, int __attribute__((unused)) ndigits, enum nmt_direction direction) { char *desc = "Spare"; @@ -477,34 +612,38 @@ static const char *param_password(uint64_t value, int ndigits, enum nmt_directio } static struct nmt_parameter { + int system; char digit; const char *description; const char *(*decoder)(uint64_t value, int ndigits, enum nmt_direction direction); } nmt_parameter[] = { - { 'N', "Channel No.", param_channel_no }, - { 'n', "TC No.", param_channel_no }, - { 'Y', "Traffic area", param_ta }, - { 'Z', "Mobile subscriber country", param_country }, - { 'X', "Mobile subscriber No.", param_number }, - { 'Q', "Tariff class", param_integer }, - { 'L', "Line signal", param_line_signal }, - { 'S', "Digit signals", param_digit }, - { 'J', "Idle information", param_hex }, - { 'A', "Channel activation", param_hex }, - { 'V', "Management order", param_hex }, - { 'r', "Measurement results", param_hex }, - { 'P', "Prefix", param_integer }, - { 'f', "Supervisory signal", param_supervisory }, - { 'K', "Mobile subscriber password", param_password }, - { 'T', "Area info", param_hex }, - { 'H', "Additional info", param_hex }, - { 'C', "Random challenge", param_hex }, - { 'R', "Signed response", param_hex }, - { 'l', "Limit strength evaluation", param_hex }, - { 'c', "c", param_hex }, - { 'M', "Sequence Number", param_integer }, - { 'W', "Checksum", param_hex }, - { 0, NULL, NULL } + { 450, 'N', "Channel No.", param_channel_no_450 }, + { 900, 'N', "Channel No.", param_channel_no_900 }, + { 450, 'n', "TC No.", param_tc_no_450 }, + { 900, 'n', "TC No.", param_tc_no_900 }, + { 450, 'Y', "Traffic area", param_ta_450 }, + { 900, 'Y', "Traffic area", param_ta_900 }, + { 0, 'Z', "Mobile subscriber country", param_country }, + { 0, 'X', "Mobile subscriber No.", param_number }, + { 0, 'Q', "Tariff class", param_integer }, + { 0, 'L', "Line signal", param_line_signal }, + { 0, 'S', "Digit signals", param_digit }, + { 0, 'J', "Idle information", param_hex }, + { 0, 'A', "Channel activation", param_hex }, + { 0, 'V', "Management order", param_hex }, + { 0, 'r', "Measurement results", param_hex }, + { 0, 'P', "Prefix", param_integer }, + { 0, 'f', "Supervisory signal", param_supervisory }, + { 0, 'K', "Mobile subscriber password", param_password }, + { 0, 'T', "Area info", param_hex }, + { 0, 'H', "Additional info", param_hex }, + { 0, 'C', "Random challenge", param_hex }, + { 0, 'R', "Signed response", param_hex }, + { 0, 'l', "Limit strength evaluation", param_hex }, + { 0, 'c', "c", param_hex }, + { 0, 'M', "Sequence Number", param_integer }, + { 0, 'W', "Checksum", param_hex }, + { 0, 0, NULL, NULL } }; /* Depending on P-value, direction and additional info, frame index (used for @@ -582,7 +721,16 @@ enum nmt_mt decode_frame_mt(const uint8_t *digits, enum nmt_direction direction, return NMT_MESSAGE_21b; return NMT_MESSAGE_4; case 4: - return NMT_MESSAGE_1b; + switch((digits[13] << 8) + (digits[14] << 4) + digits[15]) { + case 0x3f3: + case 0x3f4: + case 0x3f5: + case 0x3f6: + case 0x000: + return NMT_MESSAGE_2e; + default: + return NMT_MESSAGE_1b; + } case 5: if (digits[6] == 15) return NMT_MESSAGE_21c; @@ -601,7 +749,16 @@ enum nmt_mt decode_frame_mt(const uint8_t *digits, enum nmt_direction direction, return NMT_MESSAGE_5b; return NMT_MESSAGE_5a; case 7: - break; + switch((digits[13] << 8) + (digits[14] << 4) + digits[15]) { + case 0x3f3: + case 0x3f4: + case 0x3f5: + case 0x3f6: + case 0x000: + return NMT_MESSAGE_4b; + default: + return NMT_MESSAGE_3d; + } case 8: return NMT_MESSAGE_7; case 9: @@ -609,7 +766,7 @@ enum nmt_mt decode_frame_mt(const uint8_t *digits, enum nmt_direction direction, case 10: return NMT_MESSAGE_30; case 11: - break; + return NMT_MESSAGE_1a_a; case 12: /* no subscriber */ if (digits[6] == 0) @@ -637,7 +794,7 @@ enum nmt_mt decode_frame_mt(const uint8_t *digits, enum nmt_direction direction, return NMT_MESSAGE_2b; } case 13: - break; + return NMT_MESSAGE_1a_b; case 14: if (digits[13] != 15) break; @@ -697,7 +854,7 @@ int init_frame(void) } /* decode 16 digits frame */ -static void disassemble_frame(frame_t *frame, const uint8_t *digits, enum nmt_direction direction, int callack) +static void disassemble_frame(int nmt_system, frame_t *frame, const uint8_t *digits, enum nmt_direction direction, int callack) { enum nmt_mt mt; int i, j, ndigits; @@ -804,6 +961,8 @@ static void disassemble_frame(frame_t *frame, const uint8_t *digits, enum nmt_di } if (debuglevel <= DEBUG_DEBUG) { for (j = 0; nmt_parameter[j].digit; j++) { + if (nmt_parameter[j].system != 0 && nmt_parameter[j].system != nmt_system) + continue; if (nmt_parameter[j].digit == digit) { PDEBUG(DFRAME, DEBUG_DEBUG, " %c: %s\n", digit, nmt_parameter[j].decoder(value, ndigits, direction)); } @@ -823,7 +982,7 @@ static void disassemble_frame(frame_t *frame, const uint8_t *digits, enum nmt_di } /* encode 16 digits frame */ -static void assemble_frame(frame_t *frame, uint8_t *digits, int debug) +static void assemble_frame(int nmt_system, frame_t *frame, uint8_t *digits, int debug) { enum nmt_mt mt; int i, j; @@ -956,6 +1115,8 @@ static void assemble_frame(frame_t *frame, uint8_t *digits, int debug) i++; } for (j = 0; nmt_parameter[j].digit; j++) { + if (nmt_parameter[j].system != 0 && nmt_parameter[j].system != nmt_system) + continue; if (nmt_parameter[j].digit == digit) { PDEBUG(DFRAME, DEBUG_DEBUG, " %c: %s\n", digit, nmt_parameter[j].decoder(value, ndigits, direction)); } @@ -973,13 +1134,13 @@ static void assemble_frame(frame_t *frame, uint8_t *digits, int debug) /* encode frame to bits * debug can be turned on or off */ -const char *encode_frame(frame_t *frame, int debug) +const char *encode_frame(int nmt_system, frame_t *frame, int debug) { uint8_t digits[16], message[9], code[18]; static char bits[166]; int i; - assemble_frame(frame, digits, debug); + assemble_frame(nmt_system, frame, digits, debug); /* hagelbarger code */ message[8] = 0x00; @@ -994,7 +1155,7 @@ const char *encode_frame(frame_t *frame, int debug) } /* decode bits to frame */ -int decode_frame(frame_t *frame, const char *bits, enum nmt_direction direction, int callack) +int decode_frame(int nmt_system, frame_t *frame, const char *bits, enum nmt_direction direction, int callack) { uint8_t digits[16], message[8], code[19]; int i; @@ -1009,7 +1170,7 @@ int decode_frame(frame_t *frame, const char *bits, enum nmt_direction direction, digits[i * 2 + 1] = message[i] & 0x0f; } - disassemble_frame(frame, digits, direction, callack); + disassemble_frame(nmt_system, frame, digits, direction, callack); return 0; } diff --git a/src/nmt/frame.h b/src/nmt/frame.h index 3eb7abc..85b2aa1 100644 --- a/src/nmt/frame.h +++ b/src/nmt/frame.h @@ -1,16 +1,21 @@ enum nmt_mt { NMT_MESSAGE_1a = 0, + NMT_MESSAGE_1a_a, + NMT_MESSAGE_1a_b, NMT_MESSAGE_1b, NMT_MESSAGE_2a, NMT_MESSAGE_2b, NMT_MESSAGE_2c, NMT_MESSAGE_2d, + NMT_MESSAGE_2e, NMT_MESSAGE_2f, NMT_MESSAGE_3a, NMT_MESSAGE_3b, NMT_MESSAGE_3c, + NMT_MESSAGE_3d, NMT_MESSAGE_4, + NMT_MESSAGE_4b, NMT_MESSAGE_5a, NMT_MESSAGE_5b, NMT_MESSAGE_6, @@ -19,6 +24,7 @@ enum nmt_mt { NMT_MESSAGE_10a, NMT_MESSAGE_10b, NMT_MESSAGE_10c, + NMT_MESSAGE_10d, NMT_MESSAGE_11a, NMT_MESSAGE_11b, NMT_MESSAGE_12, @@ -77,8 +83,10 @@ typedef struct frame { int init_frame(void); -uint64_t nmt_encode_channel(int channel, int power); -int nmt_decode_channel(uint64_t value, int *channel, int *power); +uint64_t nmt_encode_channel(int nmt_system, int channel, int power); +int nmt_decode_channel(int nmt_system, uint64_t value, int *channel, int *power); +uint64_t nmt_encode_tc(int nmt_system, int channel, int power); +uint64_t nmt_encode_traffic_area(int nmt_system, int channel, uint8_t traffic_area); void nmt_value2digits(uint64_t value, char *digits, int num); uint64_t nmt_digits2value(const char *digits, int num); char nmt_value2digit(uint64_t value); @@ -86,6 +94,6 @@ uint16_t nmt_encode_area_no(uint8_t area_no); const char *nmt_frame_name(enum nmt_mt mt); -const char *encode_frame(frame_t *frame, int debug); -int decode_frame(frame_t *frame, const char *bits, enum nmt_direction direction, int callack); +const char *encode_frame(int nmt_system, frame_t *frame, int debug); +int decode_frame(int nmt_system, frame_t *frame, const char *bits, enum nmt_direction direction, int callack); diff --git a/src/nmt/main.c b/src/nmt/main.c index cec5266..396f7d0 100644 --- a/src/nmt/main.c +++ b/src/nmt/main.c @@ -44,9 +44,10 @@ static int sms_deliver_fd = -1; /* settings */ +int nmt_system = 450; int num_chan_type = 0; enum nmt_chan_type chan_type[MAX_SENDER] = { CHAN_TYPE_CC_TC }; -int ms_power = 1; /* 1..3 */ +int ms_power = 1; /* 0..3 */ char country[16] = ""; char traffic_area[3] = ""; char area_no = 0; @@ -58,13 +59,19 @@ int send_callerid = 0; void print_help(const char *arg0) { - print_help_common(arg0, "-Y