Holger Hans Peter Freyther | 3a96d28 | 2016-04-29 21:24:48 +0200 | [diff] [blame] | 1 | #!/usr/bin/python2 |
Harald Welte | eea18a6 | 2016-04-29 15:18:35 +0200 | [diff] [blame] | 2 | |
| 3 | mod_license = """ |
| 4 | /* |
| 5 | * Copyright (C) 2011-2016 Sylvain Munaut <tnt@246tNt.com> |
| 6 | * Copyright (C) 2016 sysmocom s.f.m.c. GmbH |
| 7 | * |
| 8 | * All Rights Reserved |
| 9 | * |
| 10 | * This program is free software; you can redistribute it and/or modify |
| 11 | * it under the terms of the GNU General Public License as published by |
| 12 | * the Free Software Foundation; either version 3 of the License, or |
| 13 | * (at your option) any later version. |
| 14 | * |
| 15 | * This program is distributed in the hope that it will be useful, |
| 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 18 | * GNU General Public License for more details. |
| 19 | * |
| 20 | * You should have received a copy of the GNU General Public License along |
| 21 | * with this program; if not, write to the Free Software Foundation, Inc., |
| 22 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
| 23 | */ |
| 24 | """ |
| 25 | |
Vadim Yanitskiy | 2c71794 | 2017-01-13 02:23:01 +0700 | [diff] [blame] | 26 | import sys, os, math, argparse |
Vadim Yanitskiy | f9c2c56 | 2016-11-01 22:19:28 +0700 | [diff] [blame] | 27 | from functools import reduce |
Vadim Yanitskiy | 15492bc | 2016-11-10 17:10:42 +0700 | [diff] [blame] | 28 | import conv_codes_gsm |
Harald Welte | eea18a6 | 2016-04-29 15:18:35 +0200 | [diff] [blame] | 29 | |
| 30 | class ConvolutionalCode(object): |
| 31 | |
Vadim Yanitskiy | e31cf80 | 2016-09-07 21:51:25 +0700 | [diff] [blame] | 32 | def __init__(self, block_len, polys, name, |
Vadim Yanitskiy | e9a90ee | 2017-01-13 03:43:58 +0700 | [diff] [blame] | 33 | description = None, puncture = [], term_type = None, |
| 34 | vec_in = None, vec_out = None): |
Harald Welte | eea18a6 | 2016-04-29 15:18:35 +0200 | [diff] [blame] | 35 | # Save simple params |
| 36 | self.block_len = block_len |
| 37 | self.k = 1 |
| 38 | self.puncture = puncture |
| 39 | self.rate_inv = len(polys) |
Vadim Yanitskiy | a6b5216 | 2016-09-08 22:06:07 +0700 | [diff] [blame] | 40 | self.term_type = term_type |
Vadim Yanitskiy | e9a90ee | 2017-01-13 03:43:58 +0700 | [diff] [blame] | 41 | self.vec_in = vec_in |
| 42 | self.vec_out = vec_out |
Harald Welte | eea18a6 | 2016-04-29 15:18:35 +0200 | [diff] [blame] | 43 | |
| 44 | # Infos |
| 45 | self.name = name |
| 46 | self.description = description |
| 47 | |
Vadim Yanitskiy | 84fc2ce | 2016-09-08 20:30:36 +0700 | [diff] [blame] | 48 | # Handle polynomials (and check for recursion) |
Harald Welte | eea18a6 | 2016-04-29 15:18:35 +0200 | [diff] [blame] | 49 | self.polys = [(1, 1) if x[0] == x[1] else x for x in polys] |
| 50 | |
| 51 | # Determine the polynomial degree |
| 52 | for (x, y) in polys: |
| 53 | self.k = max(self.k, int(math.floor(math.log(max(x, y), 2)))) |
| 54 | self.k = self.k + 1 |
| 55 | |
| 56 | self.poly_divider = 1 |
| 57 | rp = [x[1] for x in self.polys if x[1] != 1] |
| 58 | if rp: |
| 59 | if not all([x == rp[0] for x in rp]): |
Vadim Yanitskiy | 84fc2ce | 2016-09-08 20:30:36 +0700 | [diff] [blame] | 60 | raise ValueError("Bad polynomials: " |
| 61 | "Can't have multiple different divider polynomials!") |
Vadim Yanitskiy | e31cf80 | 2016-09-07 21:51:25 +0700 | [diff] [blame] | 62 | |
Harald Welte | eea18a6 | 2016-04-29 15:18:35 +0200 | [diff] [blame] | 63 | if not all([x[0] == 1 for x in polys if x[1] == 1]): |
Vadim Yanitskiy | 84fc2ce | 2016-09-08 20:30:36 +0700 | [diff] [blame] | 64 | raise ValueError("Bad polynomials: " |
Vadim Yanitskiy | e31cf80 | 2016-09-07 21:51:25 +0700 | [diff] [blame] | 65 | "Can't have a '1' divider with a non '1' dividend " |
| 66 | "in a recursive code") |
| 67 | |
Harald Welte | eea18a6 | 2016-04-29 15:18:35 +0200 | [diff] [blame] | 68 | self.poly_divider = rp[0] |
| 69 | |
| 70 | @property |
| 71 | def recursive(self): |
| 72 | return self.poly_divider != 1 |
| 73 | |
| 74 | @property |
| 75 | def _state_mask(self): |
| 76 | return (1 << (self.k - 1)) - 1 |
| 77 | |
| 78 | def next_state(self, state, bit): |
| 79 | nb = combine( |
| 80 | (state << 1) | bit, |
| 81 | self.poly_divider, |
| 82 | self.k, |
| 83 | ) |
| 84 | return ((state << 1) | nb) & self._state_mask |
| 85 | |
| 86 | def next_term_state(self, state): |
| 87 | return (state << 1) & self._state_mask |
| 88 | |
| 89 | def next_output(self, state, bit, ns = None): |
| 90 | # Next state bit |
| 91 | if ns is None: |
| 92 | ns = self.next_state(state, bit) |
| 93 | |
| 94 | src = (ns & 1) | (state << 1) |
| 95 | |
Vadim Yanitskiy | 84fc2ce | 2016-09-08 20:30:36 +0700 | [diff] [blame] | 96 | # Scan polynomials |
Harald Welte | eea18a6 | 2016-04-29 15:18:35 +0200 | [diff] [blame] | 97 | rv = [] |
| 98 | for p_n, p_d in self.polys: |
| 99 | if self.recursive and p_d == 1: |
Vadim Yanitskiy | e31cf80 | 2016-09-07 21:51:25 +0700 | [diff] [blame] | 100 | # No choice ... (systematic output in recursive case) |
| 101 | o = bit |
Harald Welte | eea18a6 | 2016-04-29 15:18:35 +0200 | [diff] [blame] | 102 | else: |
| 103 | o = combine(src, p_n, self.k) |
| 104 | rv.append(o) |
| 105 | |
| 106 | return rv |
| 107 | |
| 108 | def next_term_output(self, state, ns = None): |
| 109 | # Next state bit |
| 110 | if ns is None: |
| 111 | ns = self.next_term_state(state) |
| 112 | |
| 113 | src = (ns & 1) | (state << 1) |
| 114 | |
Vadim Yanitskiy | 84fc2ce | 2016-09-08 20:30:36 +0700 | [diff] [blame] | 115 | # Scan polynomials |
Harald Welte | eea18a6 | 2016-04-29 15:18:35 +0200 | [diff] [blame] | 116 | rv = [] |
| 117 | for p_n, p_d in self.polys: |
| 118 | if self.recursive and p_d == 1: |
| 119 | # Systematic output are replaced when in 'termination' mode |
| 120 | o = combine(src, self.poly_divider, self.k) |
| 121 | else: |
| 122 | o = combine(src, p_n, self.k) |
| 123 | rv.append(o) |
| 124 | |
| 125 | return rv |
| 126 | |
| 127 | def next(self, state, bit): |
| 128 | ns = self.next_state(state, bit) |
| 129 | nb = self.next_output(state, bit, ns = ns) |
| 130 | return ns, nb |
| 131 | |
| 132 | def next_term(self, state): |
| 133 | ns = self.next_term_state(state) |
| 134 | nb = self.next_term_output(state, ns = ns) |
| 135 | return ns, nb |
| 136 | |
Vadim Yanitskiy | e31cf80 | 2016-09-07 21:51:25 +0700 | [diff] [blame] | 137 | def _print_term(self, fi, num_states, pack = False): |
Vadim Yanitskiy | 6908fa7 | 2016-09-07 22:34:53 +0700 | [diff] [blame] | 138 | items = [] |
| 139 | |
Harald Welte | eea18a6 | 2016-04-29 15:18:35 +0200 | [diff] [blame] | 140 | for state in range(num_states): |
Vadim Yanitskiy | e31cf80 | 2016-09-07 21:51:25 +0700 | [diff] [blame] | 141 | if pack: |
| 142 | x = pack(self.next_term_output(state)) |
| 143 | else: |
| 144 | x = self.next_term_state(state) |
| 145 | |
Vadim Yanitskiy | 6908fa7 | 2016-09-07 22:34:53 +0700 | [diff] [blame] | 146 | items.append(x) |
| 147 | |
| 148 | # Up to 12 numbers should be placed per line |
| 149 | print_formatted(items, "%3d, ", 12, fi) |
Harald Welte | eea18a6 | 2016-04-29 15:18:35 +0200 | [diff] [blame] | 150 | |
| 151 | def _print_x(self, fi, num_states, pack = False): |
Vadim Yanitskiy | 6908fa7 | 2016-09-07 22:34:53 +0700 | [diff] [blame] | 152 | items = [] |
| 153 | |
Harald Welte | eea18a6 | 2016-04-29 15:18:35 +0200 | [diff] [blame] | 154 | for state in range(num_states): |
Vadim Yanitskiy | e31cf80 | 2016-09-07 21:51:25 +0700 | [diff] [blame] | 155 | if pack: |
| 156 | x0 = pack(self.next_output(state, 0)) |
| 157 | x1 = pack(self.next_output(state, 1)) |
| 158 | else: |
| 159 | x0 = self.next_state(state, 0) |
| 160 | x1 = self.next_state(state, 1) |
| 161 | |
Vadim Yanitskiy | 6908fa7 | 2016-09-07 22:34:53 +0700 | [diff] [blame] | 162 | items.append((x0, x1)) |
| 163 | |
| 164 | # Up to 4 blocks should be placed per line |
| 165 | print_formatted(items, "{ %2d, %2d }, ", 4, fi) |
| 166 | |
| 167 | def _print_puncture(self, fi): |
| 168 | # Up to 12 numbers should be placed per line |
| 169 | print_formatted(self.puncture, "%3d, ", 12, fi) |
Harald Welte | eea18a6 | 2016-04-29 15:18:35 +0200 | [diff] [blame] | 170 | |
Vadim Yanitskiy | 804c4c7 | 2017-01-13 15:04:37 +0700 | [diff] [blame] | 171 | def print_description(self, fi, brief = False): |
| 172 | if brief is True: |
| 173 | fi.write("/*! \\brief ") |
| 174 | fi.write("structure describing %s\n" |
| 175 | % self.description[0]) |
| 176 | for line in self.description[1:]: |
| 177 | fi.write(" * %s\n" % line) |
| 178 | else: |
| 179 | fi.write("/**\n") |
| 180 | for line in self.description: |
| 181 | fi.write(" * %s\n" % line) |
| 182 | |
| 183 | fi.write(" */\n") |
| 184 | |
Vadim Yanitskiy | 6431add | 2016-10-29 00:00:57 +0700 | [diff] [blame] | 185 | def print_state_and_output(self, fi): |
Vadim Yanitskiy | e31cf80 | 2016-09-07 21:51:25 +0700 | [diff] [blame] | 186 | pack = lambda n: \ |
| 187 | sum([x << (self.rate_inv - i - 1) for i, x in enumerate(n)]) |
Harald Welte | eea18a6 | 2016-04-29 15:18:35 +0200 | [diff] [blame] | 188 | num_states = 1 << (self.k - 1) |
Vadim Yanitskiy | e31cf80 | 2016-09-07 21:51:25 +0700 | [diff] [blame] | 189 | |
Vadim Yanitskiy | 45ebc52 | 2016-10-27 02:19:37 +0700 | [diff] [blame] | 190 | fi.write("static const uint8_t %s_state[][2] = {\n" % self.name) |
Harald Welte | eea18a6 | 2016-04-29 15:18:35 +0200 | [diff] [blame] | 191 | self._print_x(fi, num_states) |
Vadim Yanitskiy | 45ebc52 | 2016-10-27 02:19:37 +0700 | [diff] [blame] | 192 | fi.write("};\n\n") |
| 193 | |
| 194 | fi.write("static const uint8_t %s_output[][2] = {\n" % self.name) |
Harald Welte | eea18a6 | 2016-04-29 15:18:35 +0200 | [diff] [blame] | 195 | self._print_x(fi, num_states, pack) |
Vadim Yanitskiy | 45ebc52 | 2016-10-27 02:19:37 +0700 | [diff] [blame] | 196 | fi.write("};\n\n") |
Harald Welte | eea18a6 | 2016-04-29 15:18:35 +0200 | [diff] [blame] | 197 | |
| 198 | if self.recursive: |
Vadim Yanitskiy | 45ebc52 | 2016-10-27 02:19:37 +0700 | [diff] [blame] | 199 | fi.write("static const uint8_t %s_term_state[] = {\n" % self.name) |
Harald Welte | eea18a6 | 2016-04-29 15:18:35 +0200 | [diff] [blame] | 200 | self._print_term(fi, num_states) |
Vadim Yanitskiy | 45ebc52 | 2016-10-27 02:19:37 +0700 | [diff] [blame] | 201 | fi.write("};\n\n") |
Vadim Yanitskiy | e31cf80 | 2016-09-07 21:51:25 +0700 | [diff] [blame] | 202 | |
Vadim Yanitskiy | 45ebc52 | 2016-10-27 02:19:37 +0700 | [diff] [blame] | 203 | fi.write("static const uint8_t %s_term_output[] = {\n" % self.name) |
Harald Welte | eea18a6 | 2016-04-29 15:18:35 +0200 | [diff] [blame] | 204 | self._print_term(fi, num_states, pack) |
Vadim Yanitskiy | 45ebc52 | 2016-10-27 02:19:37 +0700 | [diff] [blame] | 205 | fi.write("};\n\n") |
Harald Welte | eea18a6 | 2016-04-29 15:18:35 +0200 | [diff] [blame] | 206 | |
Vadim Yanitskiy | 6431add | 2016-10-29 00:00:57 +0700 | [diff] [blame] | 207 | def gen_tables(self, pref, fi, shared_tables = None): |
| 208 | # Do not print shared tables |
| 209 | if shared_tables is None: |
| 210 | self.print_state_and_output(fi) |
| 211 | table_pref = self.name |
| 212 | else: |
| 213 | table_pref = shared_tables |
| 214 | |
Harald Welte | eea18a6 | 2016-04-29 15:18:35 +0200 | [diff] [blame] | 215 | if len(self.puncture): |
Vadim Yanitskiy | 45ebc52 | 2016-10-27 02:19:37 +0700 | [diff] [blame] | 216 | fi.write("static const int %s_puncture[] = {\n" % self.name) |
Vadim Yanitskiy | 6908fa7 | 2016-09-07 22:34:53 +0700 | [diff] [blame] | 217 | self._print_puncture(fi) |
Vadim Yanitskiy | 45ebc52 | 2016-10-27 02:19:37 +0700 | [diff] [blame] | 218 | fi.write("};\n\n") |
Harald Welte | eea18a6 | 2016-04-29 15:18:35 +0200 | [diff] [blame] | 219 | |
Vadim Yanitskiy | e31cf80 | 2016-09-07 21:51:25 +0700 | [diff] [blame] | 220 | # Write description as a multi-line comment |
| 221 | if self.description is not None: |
Vadim Yanitskiy | 804c4c7 | 2017-01-13 15:04:37 +0700 | [diff] [blame] | 222 | self.print_description(fi) |
Vadim Yanitskiy | e31cf80 | 2016-09-07 21:51:25 +0700 | [diff] [blame] | 223 | |
| 224 | # Print a final convolutional code definition |
Vadim Yanitskiy | 45ebc52 | 2016-10-27 02:19:37 +0700 | [diff] [blame] | 225 | fi.write("const struct osmo_conv_code %s_%s = {\n" % (pref, self.name)) |
| 226 | fi.write("\t.N = %d,\n" % self.rate_inv) |
| 227 | fi.write("\t.K = %d,\n" % self.k) |
| 228 | fi.write("\t.len = %d,\n" % self.block_len) |
Vadim Yanitskiy | 6431add | 2016-10-29 00:00:57 +0700 | [diff] [blame] | 229 | fi.write("\t.next_output = %s_output,\n" % table_pref) |
| 230 | fi.write("\t.next_state = %s_state,\n" % table_pref) |
Vadim Yanitskiy | 45ebc52 | 2016-10-27 02:19:37 +0700 | [diff] [blame] | 231 | |
Vadim Yanitskiy | a6b5216 | 2016-09-08 22:06:07 +0700 | [diff] [blame] | 232 | if self.term_type is not None: |
Vadim Yanitskiy | 45ebc52 | 2016-10-27 02:19:37 +0700 | [diff] [blame] | 233 | fi.write("\t.term = %s,\n" % self.term_type) |
| 234 | |
Harald Welte | eea18a6 | 2016-04-29 15:18:35 +0200 | [diff] [blame] | 235 | if self.recursive: |
Vadim Yanitskiy | 6431add | 2016-10-29 00:00:57 +0700 | [diff] [blame] | 236 | fi.write("\t.next_term_output = %s_term_output,\n" % table_pref) |
| 237 | fi.write("\t.next_term_state = %s_term_state,\n" % table_pref) |
Vadim Yanitskiy | 45ebc52 | 2016-10-27 02:19:37 +0700 | [diff] [blame] | 238 | |
Harald Welte | eea18a6 | 2016-04-29 15:18:35 +0200 | [diff] [blame] | 239 | if len(self.puncture): |
Vadim Yanitskiy | 45ebc52 | 2016-10-27 02:19:37 +0700 | [diff] [blame] | 240 | fi.write("\t.puncture = %s_puncture,\n" % self.name) |
| 241 | fi.write("};\n\n") |
Harald Welte | eea18a6 | 2016-04-29 15:18:35 +0200 | [diff] [blame] | 242 | |
Vadim Yanitskiy | e9a90ee | 2017-01-13 03:43:58 +0700 | [diff] [blame] | 243 | def calc_out_len(self): |
| 244 | out_len = self.block_len * self.rate_inv |
| 245 | |
| 246 | # By default CONV_TERM_FLUSH |
| 247 | if self.term_type is None: |
| 248 | out_len += self.rate_inv * (self.k - 1) |
| 249 | |
| 250 | if len(self.puncture): |
| 251 | out_len -= len(self.puncture) - 1 |
| 252 | |
| 253 | return out_len |
| 254 | |
| 255 | def gen_test_vector(self, fi, prefix): |
| 256 | code_name = "%s_%s" % (prefix, self.name) |
| 257 | |
| 258 | fi.write("\t{\n") |
| 259 | fi.write("\t\t.name = \"%s\",\n" % code_name) |
| 260 | fi.write("\t\t.code = &%s,\n" % code_name) |
| 261 | |
| 262 | fi.write("\t\t.in_len = %d,\n" % self.block_len) |
| 263 | fi.write("\t\t.out_len = %d,\n" % self.calc_out_len()) |
| 264 | |
| 265 | # Print pre computed vectors if preset |
| 266 | if self.vec_in is not None and self.vec_out is not None: |
| 267 | fi.write("\t\t.has_vec = 1,\n") |
| 268 | fi.write("\t\t.vec_in = {\n") |
| 269 | print_formatted(self.vec_in, "0x%02x, ", 8, fi, indent = "\t\t\t") |
| 270 | fi.write("\t\t},\n") |
| 271 | fi.write("\t\t.vec_out = {\n") |
| 272 | print_formatted(self.vec_out, "0x%02x, ", 8, fi, indent = "\t\t\t") |
| 273 | fi.write("\t\t},\n") |
| 274 | else: |
| 275 | fi.write("\t\t.has_vec = 0,\n") |
| 276 | fi.write("\t\t.vec_in = { },\n") |
| 277 | fi.write("\t\t.vec_out = { },\n") |
| 278 | |
| 279 | fi.write("\t},\n") |
| 280 | |
Harald Welte | eea18a6 | 2016-04-29 15:18:35 +0200 | [diff] [blame] | 281 | poly = lambda *args: sum([(1 << x) for x in args]) |
| 282 | |
| 283 | def combine(src, sel, nb): |
| 284 | x = src & sel |
| 285 | fn_xor = lambda x, y: x ^ y |
| 286 | return reduce(fn_xor, [(x >> n) & 1 for n in range(nb)]) |
| 287 | |
Vadim Yanitskiy | 6908fa7 | 2016-09-07 22:34:53 +0700 | [diff] [blame] | 288 | def print_formatted(items, format, count, fi): |
| 289 | counter = 0 |
| 290 | |
| 291 | # Print initial indent |
| 292 | fi.write("\t") |
| 293 | |
| 294 | for item in items: |
| 295 | if counter > 0 and counter % count == 0: |
| 296 | fi.write("\n\t") |
| 297 | |
| 298 | fi.write(format % item) |
| 299 | counter += 1 |
| 300 | |
| 301 | fi.write("\n") |
| 302 | |
Vadim Yanitskiy | 15492bc | 2016-11-10 17:10:42 +0700 | [diff] [blame] | 303 | def print_shared(fi, shared_polys): |
Vadim Yanitskiy | 6431add | 2016-10-29 00:00:57 +0700 | [diff] [blame] | 304 | for (name, polys) in shared_polys.items(): |
| 305 | # HACK |
| 306 | code = ConvolutionalCode(0, polys, name = name) |
| 307 | code.print_state_and_output(fi) |
| 308 | |
Vadim Yanitskiy | 2c71794 | 2017-01-13 02:23:01 +0700 | [diff] [blame] | 309 | def generate_codes(codes, path, prefix, name): |
Vadim Yanitskiy | d2d9760 | 2016-09-07 22:18:10 +0700 | [diff] [blame] | 310 | # Open a new file for writing |
Vadim Yanitskiy | 2c71794 | 2017-01-13 02:23:01 +0700 | [diff] [blame] | 311 | f = open(os.path.join(path, name), 'w') |
Vadim Yanitskiy | 45ebc52 | 2016-10-27 02:19:37 +0700 | [diff] [blame] | 312 | f.write(mod_license + "\n") |
| 313 | f.write("#include <stdint.h>\n") |
| 314 | f.write("#include <osmocom/core/conv.h>\n\n") |
Vadim Yanitskiy | 15492bc | 2016-11-10 17:10:42 +0700 | [diff] [blame] | 315 | |
Vadim Yanitskiy | 2c71794 | 2017-01-13 02:23:01 +0700 | [diff] [blame] | 316 | sys.stderr.write("Generating convolutional codes...\n") |
| 317 | |
Vadim Yanitskiy | 15492bc | 2016-11-10 17:10:42 +0700 | [diff] [blame] | 318 | # Print shared tables first |
| 319 | if hasattr(codes, "shared_polys"): |
| 320 | print_shared(f, codes.shared_polys) |
Harald Welte | eea18a6 | 2016-04-29 15:18:35 +0200 | [diff] [blame] | 321 | |
Vadim Yanitskiy | d2d9760 | 2016-09-07 22:18:10 +0700 | [diff] [blame] | 322 | # Generate the tables one by one |
Vadim Yanitskiy | 15492bc | 2016-11-10 17:10:42 +0700 | [diff] [blame] | 323 | for code in codes.conv_codes: |
Vadim Yanitskiy | 45ebc52 | 2016-10-27 02:19:37 +0700 | [diff] [blame] | 324 | sys.stderr.write("Generate '%s' definition\n" % code.name) |
Vadim Yanitskiy | 6431add | 2016-10-29 00:00:57 +0700 | [diff] [blame] | 325 | |
| 326 | # Check whether shared polynomials are used |
| 327 | shared = None |
Vadim Yanitskiy | 15492bc | 2016-11-10 17:10:42 +0700 | [diff] [blame] | 328 | if hasattr(codes, "shared_polys"): |
| 329 | for (name, polys) in codes.shared_polys.items(): |
| 330 | if code.polys == polys: |
| 331 | shared = name |
| 332 | break |
Vadim Yanitskiy | 6431add | 2016-10-29 00:00:57 +0700 | [diff] [blame] | 333 | |
| 334 | code.gen_tables(prefix, f, shared_tables = shared) |
Vadim Yanitskiy | d2d9760 | 2016-09-07 22:18:10 +0700 | [diff] [blame] | 335 | |
Vadim Yanitskiy | e9a90ee | 2017-01-13 03:43:58 +0700 | [diff] [blame] | 336 | def generate_vectors(codes, path, prefix, name, inc = None): |
| 337 | # Open a new file for writing |
| 338 | f = open(os.path.join(path, name), 'w') |
| 339 | f.write(mod_license + "\n") |
| 340 | |
| 341 | # Print includes |
| 342 | if inc is not None: |
| 343 | for item in inc: |
| 344 | f.write("%s\n" % item) |
| 345 | f.write("#include <osmocom/core/conv.h>\n") |
| 346 | f.write("#include \"conv.h\"\n\n") |
| 347 | |
| 348 | sys.stderr.write("Generating test vectors...\n") |
| 349 | |
| 350 | vec_count = len(codes.conv_codes) |
| 351 | f.write("const int %s_vectors_len = %d;\n\n" |
| 352 | % (prefix, vec_count)) |
| 353 | |
| 354 | f.write("const struct conv_test_vector %s_vectors[%d] = {\n" |
| 355 | % (prefix, vec_count)) |
| 356 | |
| 357 | # Generate the vectors one by one |
| 358 | for code in codes.conv_codes: |
| 359 | sys.stderr.write("Generate '%s' test vector\n" % code.name) |
| 360 | code.gen_test_vector(f, prefix) |
| 361 | |
| 362 | f.write("};\n") |
| 363 | |
Vadim Yanitskiy | 804c4c7 | 2017-01-13 15:04:37 +0700 | [diff] [blame] | 364 | def generate_header(codes, path, prefix, name, description = None): |
| 365 | # Open a new file for writing |
| 366 | f = open(os.path.join(path, name), 'w') |
| 367 | |
| 368 | # Print license and includes |
| 369 | f.write(mod_license + "\n") |
| 370 | f.write("#pragma once\n\n") |
| 371 | f.write("#include <stdint.h>\n") |
| 372 | f.write("#include <osmocom/core/conv.h>\n\n") |
| 373 | |
| 374 | # Print general file description if preset |
| 375 | if description is not None: |
| 376 | f.write("/*! \\file %s.h\n" % prefix) |
| 377 | f.write(" * %s\n" % description) |
| 378 | f.write(" */\n\n") |
| 379 | |
| 380 | sys.stderr.write("Generating header file...\n") |
| 381 | |
| 382 | # Generate declarations one by one |
| 383 | for code in codes.conv_codes: |
| 384 | sys.stderr.write("Generate '%s' declaration\n" % code.name) |
| 385 | code.print_description(f, True) |
| 386 | f.write("extern const struct osmo_conv_code %s_%s;\n\n" |
| 387 | % (prefix, code.name)) |
| 388 | |
Vadim Yanitskiy | 2c71794 | 2017-01-13 02:23:01 +0700 | [diff] [blame] | 389 | def parse_argv(): |
| 390 | parser = argparse.ArgumentParser() |
| 391 | |
| 392 | # Positional arguments |
| 393 | parser.add_argument("action", |
| 394 | help = "what to generate", |
Vadim Yanitskiy | 804c4c7 | 2017-01-13 15:04:37 +0700 | [diff] [blame] | 395 | choices = ["gen_codes", "gen_vectors", "gen_header"]) |
Vadim Yanitskiy | 2c71794 | 2017-01-13 02:23:01 +0700 | [diff] [blame] | 396 | parser.add_argument("family", |
| 397 | help = "convolutional code family", |
| 398 | choices = ["gsm"]) |
| 399 | |
| 400 | # Optional arguments |
| 401 | parser.add_argument("-p", "--prefix", |
| 402 | help = "internal naming prefix") |
| 403 | parser.add_argument("-n", "--target-name", |
| 404 | help = "target name for generated file") |
| 405 | parser.add_argument("-P", "--target-path", |
| 406 | help = "target path for generated file") |
| 407 | |
| 408 | return parser.parse_args() |
| 409 | |
Vadim Yanitskiy | 15492bc | 2016-11-10 17:10:42 +0700 | [diff] [blame] | 410 | if __name__ == '__main__': |
Vadim Yanitskiy | 2c71794 | 2017-01-13 02:23:01 +0700 | [diff] [blame] | 411 | # Parse and verify arguments |
| 412 | argv = parse_argv() |
| 413 | path = argv.target_path or os.getcwd() |
Vadim Yanitskiy | e9a90ee | 2017-01-13 03:43:58 +0700 | [diff] [blame] | 414 | inc = None |
Vadim Yanitskiy | 15492bc | 2016-11-10 17:10:42 +0700 | [diff] [blame] | 415 | |
Vadim Yanitskiy | 2c71794 | 2017-01-13 02:23:01 +0700 | [diff] [blame] | 416 | # Determine convolutional code family |
| 417 | if argv.family == "gsm": |
| 418 | codes = conv_codes_gsm |
| 419 | prefix = argv.prefix or "gsm0503" |
Vadim Yanitskiy | e9a90ee | 2017-01-13 03:43:58 +0700 | [diff] [blame] | 420 | inc = [ "#include <osmocom/gsm/gsm0503.h>" ] |
Vadim Yanitskiy | 15492bc | 2016-11-10 17:10:42 +0700 | [diff] [blame] | 421 | |
Vadim Yanitskiy | 2c71794 | 2017-01-13 02:23:01 +0700 | [diff] [blame] | 422 | # What to generate? |
| 423 | if argv.action == "gen_codes": |
| 424 | name = argv.target_name or prefix + "_conv.c" |
| 425 | generate_codes(codes, path, prefix, name) |
Vadim Yanitskiy | e9a90ee | 2017-01-13 03:43:58 +0700 | [diff] [blame] | 426 | elif argv.action == "gen_vectors": |
| 427 | name = argv.target_name or prefix + "_test_vectors.c" |
| 428 | generate_vectors(codes, path, prefix, name, inc) |
Vadim Yanitskiy | 804c4c7 | 2017-01-13 15:04:37 +0700 | [diff] [blame] | 429 | elif argv.action == "gen_header": |
| 430 | name = argv.target_name or prefix + ".h" |
| 431 | generate_header(codes, path, prefix, name) |
Vadim Yanitskiy | 15492bc | 2016-11-10 17:10:42 +0700 | [diff] [blame] | 432 | |
Vadim Yanitskiy | 45ebc52 | 2016-10-27 02:19:37 +0700 | [diff] [blame] | 433 | sys.stderr.write("Generation complete.\n") |