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