/* RF Channel utilities */ /* (C) 2010 by Sylvain Munaut * * 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 2 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. * */ #include #include #include /* * Hopping sequence generation * * The algorithm is explained in GSM 05.02 Section 6.2.3 * * if HSN = 0 (cyclic hopping) then: * MAI, integer (0 .. N-1) : * MAI = (FN + MAIO) modulo N * * else: * M, integer (0 .. 152) : * M = T2 + RNTABLE((HSN xor T1R) + T3) * * S, integer (0 .. N-1) : * M' = M modulo (2 ^ NBIN) * T' = T3 modulo (2 ^ NBIN) * * if M' < N then: * S = M' * else: * S = (M'+T') modulo N * * MAI, integer (0 .. N-1) : * MAI = (S + MAIO) modulo N */ static uint8_t rn_table[114] = { 48, 98, 63, 1, 36, 95, 78, 102, 94, 73, 0, 64, 25, 81, 76, 59, 124, 23, 104, 100, 101, 47, 118, 85, 18, 56, 96, 86, 54, 2, 80, 34, 127, 13, 6, 89, 57, 103, 12, 74, 55, 111, 75, 38, 109, 71, 112, 29, 11, 88, 87, 19, 3, 68, 110, 26, 33, 31, 8, 45, 82, 58, 40, 107, 32, 5, 106, 92, 62, 67, 77, 108, 122, 37, 60, 66, 121, 42, 51, 126, 117, 114, 4, 90, 43, 52, 53, 113, 120, 72, 16, 49, 7, 79, 119, 61, 22, 84, 9, 97, 91, 15, 21, 24, 46, 39, 93, 105, 65, 70, 125, 99, 17, 123, }; static int pow_nbin_mask(int n) { int x; x = (n ) | (n >> 1) | (n >> 2) | (n >> 3) | (n >> 4) | (n >> 5) | (n >> 6); return x; } /*! Hopping sequence generator. * \param[in] t GSM time (frame number) * \param[in] hsn Hopping Sequence Number * \param[in] maio Mobile Allocation Index OFfset * \param[in] n number of entries in mobile allocation (arfcn table) * \param[in] arfcn_tbl Array of ARFCN representing the mobile allocation * \returns ARFCN to use for given input parameters at time 't' or MAI if arfcn_tbl == NULL */ static int16_t rfch_hop_seq_gen(const struct gsm_time *t, uint8_t hsn, uint8_t maio, uint8_t n, const uint16_t *arfcn_tbl) { int mai; if (!hsn) { /* cyclic hopping */ mai = (t->fn + maio) % n; } else { /* pseudo random hopping */ int m, mp, tp, s, pnm; pnm = pow_nbin_mask(n); m = t->t2 + rn_table[(hsn ^ (t->t1 & 63)) + t->t3]; mp = m & pnm; if (mp < n) s = mp; else { tp = t->t3 & pnm; s = (mp + tp) % n; } mai = (s + maio) % n; } return arfcn_tbl ? arfcn_tbl[mai] : mai; } /*! Get RF Channel parameters at a given GSM time (frame number) * \param[in] t GSM time for which to obtain parameters * \param[out] arfcn_p ARFCN to use at time t * \oaram[out] tsc_p Training sequence to use at time t * \param[out] tn_p Timeslot Number to use at time t */ void rfch_get_params(const struct gsm_time *t, uint16_t *arfcn_p, uint8_t *tsc_p, uint8_t *tn_p) { if (l1s.dedicated.type == GSM_DCHAN_NONE) { /* Serving cell only */ if (arfcn_p) *arfcn_p = l1s.serving_cell.arfcn; if (tsc_p) *tsc_p = l1s.serving_cell.bsic & 0x7; if (tn_p) *tn_p = 0; } else { /* Dedicated channel */ if (arfcn_p) { if (l1s.dedicated.h) { *arfcn_p = rfch_hop_seq_gen(t, l1s.dedicated.h1.hsn, l1s.dedicated.h1.maio, l1s.dedicated.h1.n, l1s.dedicated.h1.ma); } else { *arfcn_p = l1s.dedicated.h0.arfcn; } } if (tsc_p) *tsc_p = l1s.dedicated.tsc; if (tn_p) *tn_p = l1s.dedicated.tn; } }