blob: 185918ef98ba04c83568c48b6f4220fd03666a70 [file] [log] [blame]
Holger Freyther76c95692009-02-17 20:31:30 +00001/*
2 * (C) 2008 by Daniel Willmann <daniel@totalueberwachung.de>
3 * (C) 2009 by Holger Hans Peter Freyther <zecke@selfish.org>
Harald Welte7e310b12009-03-30 20:56:32 +00004 * (C) 2009 by Harald Welte <laforge@gnumonks.org>
Holger Freyther76c95692009-02-17 20:31:30 +00005 *
6 * All Rights Reserved
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 *
22 */
23
Harald Welte66b6a8d2009-08-09 14:45:18 +020024#include <openbsc/gsm_data.h>
Holger Freyther76c95692009-02-17 20:31:30 +000025#include <openbsc/gsm_utils.h>
Harald Welte12247c62009-05-21 07:23:02 +000026#include <stdlib.h>
Holger Freytherce668962009-02-17 23:42:45 +000027#include <string.h>
Harald Welte66b6a8d2009-08-09 14:45:18 +020028#include <errno.h>
Holger Freyther76c95692009-02-17 20:31:30 +000029
Holger Freytherce668962009-02-17 23:42:45 +000030/* GSM 03.38 6.2.1 Charachter packing */
Harald Welte7e310b12009-03-30 20:56:32 +000031int gsm_7bit_decode(char *text, const u_int8_t *user_data, u_int8_t length)
Holger Freyther76c95692009-02-17 20:31:30 +000032{
33 u_int8_t d_off = 0, b_off = 0;
34 u_int8_t i;
Holger Freyther76c95692009-02-17 20:31:30 +000035
36 for (i=0;i<length;i++) {
37 text[i] = ((user_data[d_off] + (user_data[d_off+1]<<8)) & (0x7f<<b_off))>>b_off;
38 b_off += 7;
39 if (b_off >= 8) {
40 d_off += 1;
41 b_off -= 8;
42 }
43 }
Holger Freyther62f47772009-02-17 20:31:35 +000044 text[i] = '\0';
Harald Welte7e310b12009-03-30 20:56:32 +000045 return 0;
Holger Freyther76c95692009-02-17 20:31:30 +000046}
Holger Freytherce668962009-02-17 23:42:45 +000047
48/* GSM 03.38 6.2.1 Charachter packing */
Harald Welte7e310b12009-03-30 20:56:32 +000049int gsm_7bit_encode(u_int8_t *result, const char *data)
Holger Freytherce668962009-02-17 23:42:45 +000050{
51 int i;
52 u_int8_t d_off = 0, b_off = 0;
53 const int length = strlen(data);
Harald Welte7e310b12009-03-30 20:56:32 +000054 int out_length = (length * 8)/7;
Harald Welte93d93032009-03-30 09:11:45 +000055
Harald Welte7e310b12009-03-30 20:56:32 +000056 memset(result, 0, out_length);
Holger Freytherce668962009-02-17 23:42:45 +000057
58 for (i = 0; i < length; ++i) {
59 u_int8_t first = (data[i] & 0x7f) << b_off;
Holger Freyther3b1f3d02009-02-23 01:47:15 +000060 u_int8_t second = (data[i] & 0x7f) >> (8 - b_off);
61
Holger Freytherce668962009-02-17 23:42:45 +000062 result[d_off] |= first;
Holger Freyther59da07b2009-02-23 00:50:38 +000063 if (second != 0)
64 result[d_off + 1] = second;
Holger Freytherce668962009-02-17 23:42:45 +000065
66 b_off += 7;
67
68 if (b_off >= 8) {
69 d_off += 1;
70 b_off -= 8;
71 }
72 }
73
Harald Welte7e310b12009-03-30 20:56:32 +000074 return out_length;
Holger Freytherce668962009-02-17 23:42:45 +000075}
Harald Welte66b6a8d2009-08-09 14:45:18 +020076
77/* determine power control level for given dBm value, as indicated
78 * by the tables in chapter 4.1.1 of GSM TS 05.05 */
79int ms_pwr_ctl_lvl(enum gsm_band band, unsigned int dbm)
80{
81 switch (band) {
82 case GSM_BAND_400:
83 case GSM_BAND_900:
84 case GSM_BAND_850:
85 if (dbm >= 39)
86 return 0;
87 else if (dbm < 5)
88 return 19;
89 else
90 return 2 + ((39 - dbm) / 2);
91 break;
92 case GSM_BAND_1800:
93 if (dbm >= 36)
94 return 29;
95 else if (dbm >= 34)
96 return 30;
97 else if (dbm >= 32)
98 return 31;
99 else
100 return (30 - dbm) / 2;
101 break;
102 case GSM_BAND_1900:
103 if (dbm >= 33)
104 return 30;
105 else if (dbm >= 32)
106 return 31;
107 else
108 return (30 - dbm) / 2;
109 break;
110 }
111 return -EINVAL;
112}
113
114int ms_pwr_dbm(enum gsm_band band, u_int8_t lvl)
115{
116 lvl &= 0x1f;
117
118 switch (band) {
119 case GSM_BAND_400:
120 case GSM_BAND_900:
121 case GSM_BAND_850:
122 if (lvl < 2)
123 return 39;
124 else if (lvl < 20)
125 return 39 - ((lvl - 2) * 2) ;
126 else
127 return 5;
128 break;
129 case GSM_BAND_1800:
130 if (lvl < 16)
131 return 30 - (lvl * 2);
132 else if (lvl < 29)
133 return 0;
134 else
135 return 36 - ((lvl - 29) * 2);
136 break;
137 case GSM_BAND_1900:
138 if (lvl < 16)
139 return 30 - (lvl * 2);
140 else if (lvl < 30)
141 return -EINVAL;
142 else
143 return 33 - (lvl - 30);
144 break;
145 }
146 return -EINVAL;
147}
148
149