new regulatory database scheme, flags are per-rule now
authorJohannes Berg <johannes@sipsolutions.net>
Mon, 26 May 2008 13:04:29 +0000 (15:04 +0200)
committerJohannes Berg <johannes@sipsolutions.net>
Mon, 26 May 2008 13:04:29 +0000 (15:04 +0200)
db.txt
db2bin.py
dbparse.py
dump.c
regdb.h
web/Regulatory.py

diff --git a/db.txt b/db.txt
index 3659772..6c72653 100644 (file)
--- a/db.txt
+++ b/db.txt
 ############
 # First: band definitions
 
-band WORLD: 2432 - 2442 @ 20, OFDM, CCK
+band WORLD: 2432 - 2442 @ 20
 
-band FCCA-1: 2412 - 2462 @ 20, OFDM, CCK
-band FCCA-2: 2437 - 2437 @ 40, OFDM, CCK
-band FCCA-3: 2442 - 2462 @ 20, OFDM, CCK
+band FCCA-1: 2412 - 2462 @ 20
+band FCCA-2: 2437 - 2437 @ 40
+band FCCA-3: 2442 - 2462 @ 20
 
 # ETSIC also uses FCCA-1/-2
-band ETSIC: 2442 - 2472 @ 20, OFDM, CCK
+band ETSIC: 2442 - 2472 @ 20
 
-band MKKA-1: 2412 - 2472 @ 20, OFDM, CCK
-band MKKA-2: 2484 - 2484 @ 20, CCK
+band MKKA-1: 2412 - 2472 @ 20
+band MKKA-2: 2484 - 2484 @ 20
 
 # 5 GHz ranges follow
 
-band APL1: 5745 - 5825 @ 20, OFDM
-band APL2: 5745 - 5805 @ 20, OFDM
+band APL1: 5745 - 5825 @ 20
+band APL2: 5745 - 5805 @ 20
 
-band APL3-1: 5280 - 5320 @ 20, OFDM
-band APL3-2: 5745 - 5805 @ 20, OFDM
+band APL3-1: 5280 - 5320 @ 20
+band APL3-2: 5745 - 5805 @ 20
 
 # DMN_APL4 --- DMN_ETSI2 uses only the first frequency range
 # DMN_ETS5 uses the same freq range as DMN_ETSI2 so we can combine these two
-band APL4-1: 5180 - 5240 @ 20, OFDM
-band APL4-2: 5745 - 5825 @ 20, OFDM
+band APL4-1: 5180 - 5240 @ 20
+band APL4-2: 5745 - 5825 @ 20
 
 # DMN_ETSI1 -- DMN_ETSI3 and DMN_ETSI4 uses the first freq range of DMN_ETSI1
 # DMN_ETSI4 overlaps with ETSI3 so we deleted it
-band ETSI1: 5180 - 5320 @ 20, OFDM
-band ETSI2: 5500 - 5700 @ 20, OFDM
-
-band ETSI6-1: 5180 - 5280 @ 20, OFDM
-band ETSI6-2: 5500 - 5700 @ 20, OFDM
-
-band FCC1-1: 5180 - 5200 @ 20, OFDM
-band FCC1-2: 5210 - 5210 @ 40, OFDM
-band FCC1-3: 5220 - 5240 @ 20, OFDM
-band FCC1-4: 5250 - 5250 @ 40, OFDM
-band FCC1-5: 5260 - 5280 @ 20, OFDM
-band FCC1-6: 5290 - 5290 @ 40, OFDM
-band FCC1-7: 5300 - 5320 @ 20, OFDM
-band FCC1-8: 5745 - 5745 @ 20, OFDM
-band FCC1-9: 5760 - 5760 @ 40, OFDM
-band FCC1-10: 5765 - 5785 @ 20, OFDM
-band FCC1-11: 5800 - 5800 @ 40, OFDM
-band FCC1-12: 5805 - 5825 @ 20, OFDM
+band ETSI1: 5180 - 5320 @ 20
+band ETSI2: 5500 - 5700 @ 20
+
+band ETSI6-1: 5180 - 5280 @ 20
+band ETSI6-2: 5500 - 5700 @ 20
+
+band FCC1-1: 5180 - 5200 @ 20
+band FCC1-2: 5210 - 5210 @ 40
+band FCC1-3: 5220 - 5240 @ 20
+band FCC1-4: 5250 - 5250 @ 40
+band FCC1-5: 5260 - 5280 @ 20
+band FCC1-6: 5290 - 5290 @ 40
+band FCC1-7: 5300 - 5320 @ 20
+band FCC1-8: 5745 - 5745 @ 20
+band FCC1-9: 5760 - 5760 @ 40
+band FCC1-10: 5765 - 5785 @ 20
+band FCC1-11: 5800 - 5800 @ 40
+band FCC1-12: 5805 - 5825 @ 20
 
 # FCC3 is FCC1 + this
-band FCC3: 5500 - 5700 @ 20, OFDM
+band FCC3: 5500 - 5700 @ 20
 
 # MKK1
-band MKK1: 5170 - 5230 @ 20, OFDM
+band MKK1: 5170 - 5230 @ 20
 
 # MKK2 is MKK1 + this
-band MKK2: 5040 - 5080 @ 20, OFDM
+band MKK2: 5040 - 5080 @ 20
 
 
 ############
 # Second: power definitions
 
-# OI is the identifier we use for outdoor+indoor which is usually a space
-power DEFAULT: OI, 6, 30, 30, 36, 255
+power DEFAULT: 6, 30, 100 mW
 
 ############
 # Finally, country definitions
 
 country 00:
-       # power definition is the same as DEFAULT, just to
-       # illustrate inlining it...
-       WORLD, (OI, 6, 30, 30, 36, 255)
+       WORLD, DEFAULT
 
 country 01:
-       (2412 - 2732 @ 40, OFDM, CCK), DEFAULT
+       (2412 - 2732 @ 40), DEFAULT
 
 country 02:
-       (5005 - 6100 @ 40, OFDM, CCK), DEFAULT
+       (5005 - 6100 @ 40), DEFAULT
 
 country 03:
-       (2412 - 2732 @ 40, OFDM, CCK), DEFAULT
-       (5005 - 6100 @ 40, OFDM, CCK), DEFAULT
+       (2412 - 2732 @ 40), DEFAULT
+       (5005 - 6100 @ 40), DEFAULT
 
 country BR, BZ:
        FCCA-1, DEFAULT
@@ -160,13 +157,9 @@ country CY, DK, EE, ES, FI, GB, IE, IS, IT, LT, LU, LN, NO, PL, PT, SE, SI, UK,
 # downloaded from http://www.bundesnetzagentur.de/media/archive/13358.pdf
 country DE:
        # entries 279004 and 280006
-       # TODO: max EIRP: 100 mW
-       (2400 - 2483.5 @ 40, OFDM, CCK), (OI, 0, 0, 0, 0, 0)
+       (2400 - 2483.5 @ 40), (0, 0, 100 mW)
        # entry 303005
-       # TODO: max EIRP: 200 mW
-       # TODO: maximum power spectrum density: 0.25 mW/25 kHz
-       # TODO: DFS required
-       (5150 - 5250 @ 40, OFDM, CCK), (I, 0, 0, 0, 0, 0) 
+       (5150 - 5250 @ 40), (0, 0, 200 mW), NO-OUTDOOR, DFS
 
 country CH, HU, LI, AT:
        ETSI1, DEFAULT
@@ -179,7 +172,7 @@ country CZ, F2, HR, SK, TN, TR, AM, AZ, BE, GE, MC, TT:
 
 country BG:
        MKKA-1, DEFAULT
-       MKKA-2, DEFAULT
+       MKKA-2, DEFAULT, NO-OFDM
        MKK1, DEFAULT
 
 country JP:
@@ -190,7 +183,7 @@ country JP:
 
 country J2:
        MKKA-1, DEFAULT
-       MKKA-2, DEFAULT
+       MKKA-2, DEFAULT, NO-OFDM
        MKK1, DEFAULT
        MKK2, DEFAULT
 
index cda80bd..41e2083 100755 (executable)
--- a/db2bin.py
+++ b/db2bin.py
@@ -45,16 +45,18 @@ class PTR(object):
 
 p = DBParser()
 countries = p.parse(file('db.txt'))
-power = {}
-bands = {}
+power = []
+bands = []
 for c in countries.itervalues():
-    for b, p in c.permissions:
-        bands[b] = b
-        power[p] = p
+    for perm in c.permissions:
+        if not perm.freqband in bands:
+            bands.append(perm.freqband)
+        if not perm.power in power:
+            power.append(perm.power)
 rules = create_rules(countries)
-rules.sort(cmp=lambda x, y: cmp(bands[x[0]], bands[y[0]]))
+rules.sort(cmp=lambda x, y: cmp(x.freqband, y.freqband))
 collections = create_collections(countries)
-collections.sort(cmp=lambda x, y: cmp(bands[x[0][0]], bands[y[0][0]]))
+collections.sort(cmp=lambda x, y: cmp(x[0].freqband, y[0].freqband))
 
 output = StringIO()
 
@@ -67,33 +69,27 @@ be32(output, len(countries))
 siglen = PTR(output)
 
 power_rules = {}
-pi = [(i, p) for i, p in power.iteritems()]
-pi.sort(cmp=lambda x, y: cmp(x[1], y[1]))
-for power_rule_id, pr in pi:
-    environ = pr.environment
-    pr = [int(v * 100) for v in (pr.max_ant_gain, pr.max_ir_ptmp, pr.max_ir_ptp,
-                                 pr.max_eirp_ptmp, pr.max_eirp_ptp)]
-    power_rules[power_rule_id] = output.tell()
+for pr in power:
+    power_rules[pr] = output.tell()
+    pr = [int(v * 100.0) for v in (pr.max_ant_gain, pr.max_ir, pr.max_eirp)]
     # struct regdb_file_power_rule
-    output.write(struct.pack('>cxxxIIIII', str(environ), *pr))
+    output.write(struct.pack('>III', *pr))
 
 freq_ranges = {}
-bi = [(f, i) for f, i in bands.iteritems()]
-bi.sort(cmp=lambda x, y: cmp(x[1], y[1]))
-for freq_range_id, fr in bands.iteritems():
-    freq_ranges[freq_range_id] = output.tell()
-    fl = fr.flags
-    fr = [int(f * 1000) for f in (fr.start, fr.end, fr.maxbw)]
+for fr in bands:
+    freq_ranges[fr] = output.tell()
+    fr = [int(f * 1000.0) for f in (fr.start, fr.end, fr.maxbw)]
     # struct regdb_file_freq_range
-    output.write(struct.pack('>IIIII', fr[0], fr[1], fr[2], fl, 0))
+    output.write(struct.pack('>III', *fr))
 
 
 reg_rules = {}
 for reg_rule in rules:
-    freq_range_id, power_rule_id = reg_rule
+    freq_range, power_rule = reg_rule.freqband, reg_rule.power
     reg_rules[reg_rule] = output.tell()
     # struct regdb_file_reg_rule
-    output.write(struct.pack('>II', freq_ranges[freq_range_id], power_rules[power_rule_id]))
+    output.write(struct.pack('>III', freq_ranges[freq_range], power_rules[power_rule],
+                             reg_rule.flags))
 
 
 reg_rules_collections = {}
@@ -103,7 +99,7 @@ for coll in collections:
     # struct regdb_file_reg_rules_collection
     coll = list(coll)
     be32(output, len(coll))
-    coll.sort(cmp=lambda x, y: cmp(bands[x[0]], bands[y[0]]))
+    coll.sort(cmp=lambda x, y: cmp(x.freqband, y.freqband))
     for regrule in coll:
         be32(output, reg_rules[regrule])
 
index 28ea032..85eda45 100644 (file)
@@ -1,18 +1,22 @@
 #!/usr/bin/env python
 
-import sys
-
-band_flags = {
-    'CCK': 1,
-    'OFDM': 2,
+import sys, math
+
+flag_definitions = {
+    'NO-CCK':          1<<0,
+    'NO-OFDM':         1<<1,
+    'NO-INDOOR':       1<<2,
+    'NO-OUTDOOR':      1<<3,
+    'DFS':             1<<4,
+    'PTP-ONLY':                1<<5,
+    'PTMP-ONLY':       1<<6,
 }
 
 class FreqBand(object):
-    def __init__(self, start, end, bw, flags, comments=None):
+    def __init__(self, start, end, bw, comments=None):
         self.start = start
         self.end = end
         self.maxbw = bw
-        self.flags = flags
         self.comments = comments or []
 
     def __cmp__(self, other):
@@ -20,30 +24,21 @@ class FreqBand(object):
         o = other
         if not isinstance(o, FreqBand):
             return False
-        return cmp((s.start, s.end, s.maxbw, s.flags), (o.start, o.end, o.maxbw, o.flags))
+        return cmp((s.start, s.end, s.maxbw), (o.start, o.end, o.maxbw))
 
     def __hash__(self):
         s = self
-        return hash((s.start, s.end, s.maxbw, s.flags))
+        return hash((s.start, s.end, s.maxbw))
 
     def __str__(self):
-        flags = []
-        for f, v in band_flags.iteritems():
-            if self.flags & v:
-                flags.append(f)
-        return '<FreqBand %.3f - %.3f @ %.3f%s>' % (
-                  self.start, self.end, self.maxbw, ', '.join(flags))
+        return '<FreqBand %.3f - %.3f @ %.3f>' % (
+                  self.start, self.end, self.maxbw)
 
 class PowerRestriction(object):
-    def __init__(self, environment, max_ant_gain, max_ir_ptmp,
-                 max_ir_ptp, max_eirp_ptmp, max_eirp_ptp,
-                 comments = None):
-        self.environment = environment
+    def __init__(self, max_ant_gain, max_ir, max_eirp, comments = None):
         self.max_ant_gain = max_ant_gain
-        self.max_ir_ptmp = max_ir_ptmp
-        self.max_ir_ptp = max_ir_ptp
-        self.max_eirp_ptmp = max_eirp_ptmp
-        self.max_eirp_ptp = max_eirp_ptp
+        self.max_ir = max_ir
+        self.max_eirp = max_eirp
         self.comments = comments or []
 
     def __cmp__(self, other):
@@ -51,33 +46,57 @@ class PowerRestriction(object):
         o = other
         if not isinstance(o, PowerRestriction):
             return False
-        return cmp((s.environment, s.max_ant_gain, s.max_ir_ptmp,
-                    s.max_ir_ptp, s.max_eirp_ptmp, s.max_eirp_ptp),
-                   (o.environment, o.max_ant_gain, o.max_ir_ptmp,
-                    o.max_ir_ptp, o.max_eirp_ptmp, o.max_eirp_ptp))
+        return cmp((s.max_ant_gain, s.max_ir, s.max_eirp),
+                   (o.max_ant_gain, o.max_ir, o.max_eirp))
 
     def __str__(self):
         return '<PowerRestriction ...>'
 
     def __hash__(self):
         s = self
-        return hash((s.environment, s.max_ant_gain, s.max_ir_ptmp,
-                     s.max_ir_ptp, s.max_eirp_ptmp, s.max_eirp_ptp))
+        return hash((s.max_ant_gain, s.max_ir, s.max_eirp))
+
+class FlagError(Exception):
+    def __init__(self, flag):
+        self.flag = flag
+
+class Permission(object):
+    def __init__(self, freqband, power, flags):
+        assert isinstance(freqband, FreqBand)
+        assert isinstance(power, PowerRestriction)
+        self.freqband = freqband
+        self.power = power
+        self.flags = 0
+        for flag in flags:
+            if not flag in flag_definitions:
+                raise FlagError(flag)
+            self.flags |= flag_definitions[flag]
+        self.textflags = flags
+
+    def _as_tuple(self):
+        return (self.freqband, self.power, self.flags)
+
+    def __cmp__(self, other):
+        if not isinstance(other, Permission):
+            return False
+        return cmp(self._as_tuple(), other._as_tuple())
+
+    def __hash__(self):
+        return hash(self._as_tuple())
 
 class Country(object):
     def __init__(self, permissions=None, comments=None):
-        # tuple of (freqband, powerrestriction)
         self._permissions = permissions or []
         self.comments = comments or []
 
-    def add(self, band, power):
-        assert isinstance(band, FreqBand)
-        assert isinstance(power, PowerRestriction)
-        self._permissions.append((band, power))
+    def add(self, perm):
+        assert isinstance(perm, Permission)
+        self._permissions.append(perm)
         self._permissions.sort()
 
-    def __contains__(self, tup):
-        return tup in self._permissions
+    def __contains__(self, perm):
+        assert isinstance(perm, Permission)
+        return perm in self._permissions
 
     def __str__(self):
         r = ['(%s, %s)' % (str(b), str(p)) for b, p in self._permissions]
@@ -102,17 +121,8 @@ class DBParser(object):
         sys.stderr.write("Warning (line %d): %s\n" % (self._lineno, txt))
 
     def _parse_band_def(self, bname, banddef, dupwarn=True):
-        line = banddef
-        try:
-            freqs, line = line.split(',', 1)
-        except ValueError:
-            freqs = line
-            line = ''
-
-        flags = [f.upper() for f in line.split(',') if f]
-
         try:
-            freqs, bw = freqs.split('@')
+            freqs, bw = banddef.split('@')
             bw = float(bw)
         except ValueError:
             bw = 20.0
@@ -124,13 +134,7 @@ class DBParser(object):
         except ValueError:
             self._syntax_error("band must have frequency range")
 
-        fl = 0
-        for f in flags:
-            if not f in band_flags:
-                self._syntax_error("Invalid band flag")
-            fl |= band_flags[f]
-
-        b = FreqBand(start, end, bw, fl, comments=self._comments)
+        b = FreqBand(start, end, bw, comments=self._comments)
         self._comments = []
         self._banddup[bname] = bname
         if b in self._bandrev:
@@ -150,6 +154,9 @@ class DBParser(object):
         except ValueError:
             self._syntax_error("band name must be followed by colon")
 
+        if bname in flag_definitions:
+            self._syntax_error("Invalid band name")
+
         self._parse_band_def(bname, line)
 
     def _parse_power(self, line):
@@ -160,31 +167,29 @@ class DBParser(object):
         except ValueError:
             self._syntax_error("power name must be followed by colon")
 
+        if pname in flag_definitions:
+            self._syntax_error("Invalid power name")
+
         self._parse_power_def(pname, line)
 
     def _parse_power_def(self, pname, line, dupwarn=True):
         try:
-            (environ,
-             max_ant_gain,
-             max_ir_ptmp,
-             max_ir_ptp,
-             max_eirp_ptmp,
-             max_eirp_ptp) = line.split(',')
+            (max_ant_gain,
+             max_ir,
+             max_eirp) = line.split(',')
             max_ant_gain = float(max_ant_gain)
-            max_ir_ptmp = float(max_ir_ptmp)
-            max_ir_ptp = float(max_ir_ptp)
-            max_eirp_ptmp = float(max_eirp_ptmp)
-            max_eirp_ptp = float(max_eirp_ptp)
+            def conv_pwr(pwr):
+                if pwr.endswith('mW'):
+                    pwr = float(pwr[:-2])
+                    return 10.0 * math.log10(pwr)
+                else:
+                    return float(pwr)
+            max_ir = conv_pwr(max_ir)
+            max_eirp = conv_pwr(max_eirp)
         except ValueError:
             self._syntax_error("invalid power data")
 
-        if environ == 'OI':
-            environ = ' '
-        if not environ in ('I', 'O', ' '):
-            self._syntax_error("Invalid environment specifier")
-
-        p = PowerRestriction(environ, max_ant_gain, max_ir_ptmp,
-                             max_ir_ptp, max_eirp_ptmp, max_eirp_ptp,
+        p = PowerRestriction(max_ant_gain, max_ir, max_eirp,
                              comments=self._comments)
         self._comments = []
         self._powerdup[pname] = pname
@@ -216,27 +221,40 @@ class DBParser(object):
     def _parse_country_item(self, line):
         if line[0] == '(':
             try:
-                band, pname = line[1:].split('),')
+                band, line = line[1:].split('),', 1)
                 bname = 'UNNAMED %d' % self._lineno
                 self._parse_band_def(bname, band, dupwarn=False)
             except:
                 self._syntax_error("Badly parenthesised band definition")
         else:
             try:
-                bname, pname = line.split(',', 1)
+                bname, line = line.split(',', 1)
                 if not bname:
                     self._syntax_error("country definition must have band")
-                if not pname:
+                if not line:
                     self._syntax_error("country definition must have power")
             except ValueError:
                 self._syntax_error("country definition must have band and power")
 
-        if pname[0] == '(':
-            if not pname[-1] == ')':
-                self._syntax_error("Badly parenthesised power definition")
-            power = pname[1:-1]
+        if line[0] == '(':
+            items = line.split('),', 1)
+            if len(items) == 1:
+                pname = items[0]
+                line = ''
+                if not pname[-1] == ')':
+                    self._syntax_error("Badly parenthesised power definition")
+                pname = pname[:-1]
+                flags = []
+            else:
+                pname = items[0]
+                flags = items[1].split(',')
+            power = pname[1:]
             pname = 'UNNAMED %d' % self._lineno
             self._parse_power_def(pname, power, dupwarn=False)
+        else:
+            line = line.split(',')
+            pname = line[0]
+            flags = line[1:]
 
         if not bname in self._bands:
             self._syntax_error("band does not exist")
@@ -249,11 +267,15 @@ class DBParser(object):
         pname = self._powerdup[pname]
         b = self._bands[bname]
         p = self._power[pname]
-        if (b, p) in self._current_country:
+        try:
+            perm = Permission(b, p, flags)
+        except FlagError, e:
+            self._syntax_error("Invalid flag '%s'" % e.flag)
+        if perm in self._current_country:
             self._warn('Rule "%s, %s" added to "%s" twice' % (
                           bname, pname, self._current_country_name))
         else:
-            self._current_country.add(b, p)
+            self._current_country.add(perm)
 
     def parse(self, f):
         self._current_country = None
diff --git a/dump.c b/dump.c
index 4e22d3c..c207467 100644 (file)
--- a/dump.c
+++ b/dump.c
@@ -41,35 +41,39 @@ static void print_reg_rule(__u8 *db, int dblen, __be32 ruleptr)
        struct regdb_file_reg_rule *rule;
        struct regdb_file_freq_range *freq;
        struct regdb_file_power_rule *power;
-       char *ofdm = "", *cck = "", env[3] = { 'O', 'I', '\0' };
+       __u32 flags;
 
        rule = get_file_ptr(db, dblen, sizeof(*rule), ruleptr);
        freq = get_file_ptr(db, dblen, sizeof(*freq), rule->freq_range_ptr);
        power = get_file_ptr(db, dblen, sizeof(*power), rule->power_rule_ptr);
 
-       if (ntohl(freq->modulation_cap) & 2)
-               ofdm = ", OFDM";
-       if (ntohl(freq->modulation_cap) & 1)
-               cck = ", CCK";
-
-       printf("\t(%.3f - %.3f @ %.3f%s%s), ",
-              (float)ntohl(freq->start_freq)/1000.0,
-              (float)ntohl(freq->end_freq)/1000.0,
-              (float)ntohl(freq->max_bandwidth)/1000.0,
-              cck, ofdm);
-
-       if (power->environment_cap != ' ') {
-               env[0] = power->environment_cap;
-               env[1] = '\0';
-       }
-
-       printf("(%s, %.3f, %.3f, %.3f, %.3f, %.3f)\n",
-              env,
-              (float)ntohl(power->max_antenna_gain/100.0),
-              (float)ntohl(power->max_ir_ptmp/100.0),
-              (float)ntohl(power->max_ir_ptp/100.0),
-              (float)ntohl(power->max_eirp_ptmp/100.0),
-              (float)ntohl(power->max_eirp_ptp)/100.0);
+       printf("\t(%.3f - %.3f @ %.3f), ",
+              ((float)ntohl(freq->start_freq))/1000.0,
+              ((float)ntohl(freq->end_freq))/1000.0,
+              ((float)ntohl(freq->max_bandwidth))/1000.0);
+
+       printf("(%.3f, %.3f, %.3f)",
+              ((float)ntohl(power->max_antenna_gain)/100.0),
+              ((float)ntohl(power->max_ir)/100.0),
+              ((float)ntohl(power->max_eirp)/100.0));
+
+       flags = ntohl(rule->flags);
+       if (flags & RRF_NO_OFDM)
+               printf(", NO-OFDM");
+       if (flags & RRF_NO_CCK)
+               printf(", NO-CCK");
+       if (flags & RRF_NO_INDOOR)
+               printf(", NO-INDOOR");
+       if (flags & RRF_NO_OUTDOOR)
+               printf(", NO-OUTDOOR");
+       if (flags & RRF_DFS)
+               printf(", DFS");
+       if (flags & RRF_PTP_ONLY)
+               printf(", PTP-ONLY");
+       if (flags & RRF_PTMP_ONLY)
+               printf(", PTMP-ONLY");
+
+       printf("\n");
 }
 
 int main(int argc, char **argv)
diff --git a/regdb.h b/regdb.h
index 3c7983f..a5b9ac1 100644 (file)
--- a/regdb.h
+++ b/regdb.h
@@ -38,30 +38,35 @@ struct regdb_file_header {
        __be32  signature_length;
 };
 
-struct regdb_file_reg_rule {
-       /* pointers (offsets) into the file */
-       __be32  freq_range_ptr;
-       __be32  power_rule_ptr;
-};
-
 struct regdb_file_freq_range {
        __be32  start_freq,
                end_freq,
-               max_bandwidth,
-               modulation_cap,
-               misc_restrictions;
+               max_bandwidth;
 };
 
 struct regdb_file_power_rule {
-       __u8    environment_cap;
-       __u8    PAD[3];
        /* antenna gain is in mBi (100 * dBi) */
        __be32  max_antenna_gain;
        /* these are in mBm (100 * dBm) */
-       __be32  max_ir_ptmp,
-               max_ir_ptp,
-               max_eirp_ptmp,
-               max_eirp_ptp;
+       __be32  max_ir, max_eirp;
+};
+
+enum reg_rule_flags {
+       RRF_NO_OFDM     = 1<<0,
+       RRF_NO_CCK      = 1<<1,
+       RRF_NO_INDOOR   = 1<<2,
+       RRF_NO_OUTDOOR  = 1<<3,
+       RRF_DFS         = 1<<4,
+       RRF_PTP_ONLY    = 1<<5,
+       RRF_PTMP_ONLY   = 1<<6,
+};
+
+struct regdb_file_reg_rule {
+       /* pointers (offsets) into the file */
+       __be32  freq_range_ptr,
+               power_rule_ptr;
+       /* rule flags */
+       __be32 flags;
 };
 
 struct regdb_file_reg_rules_collection {
index a001672..1d09c4c 100644 (file)
@@ -7,7 +7,7 @@
 """
 
 import codecs
-from dbparse import DBParser, band_flags
+from dbparse import DBParser, flag_definitions
 
 Dependencies = ["time"]
 
@@ -49,64 +49,37 @@ def _country(macro, countries, code):
             f.text('Flags'),
           f.strong(0), f.table_cell(0),
           f.table_cell(1), f.strong(1),
-            f.text('Environment'),
-          f.strong(0), f.table_cell(0),
-          f.table_cell(1), f.strong(1),
             f.text('Max antenna gain (dBi)'),
           f.strong(0), f.table_cell(0),
           f.table_cell(1), f.strong(1),
-            f.text('Max IR PTMP (dBm)'),
-          f.strong(0), f.table_cell(0),
-          f.table_cell(1), f.strong(1),
-            f.text('Max IR PTP (dBm)'),
-          f.strong(0), f.table_cell(0),
-          f.table_cell(1), f.strong(1),
-            f.text('Max EIRP PTMP (dBm)'),
+            f.text('Max IR (dBm)'),
           f.strong(0), f.table_cell(0),
           f.table_cell(1), f.strong(1),
-            f.text('Max EIRP PTP (dBm)'),
+            f.text('Max EIRP (dBm)'),
           f.strong(0), f.table_cell(0),
         f.table_row(0),
     ])
 
-    for b, p in country.permissions:
-        flags = []
-        for flag, val in band_flags.iteritems():
-            if b.flags & val:
-                flags.append(flag)
-        e = {
-            'O': 'Outdoor',
-            'I': 'Indoor',
-            ' ': 'Out- & Indoor'
-        }[p.environment]
+    for perm in country.permissions:
         result.extend([
             f.table_row(1),
               f.table_cell(1),
-                f.text('%.3f - %.3f' % (b.start, b.end)),
-              f.table_cell(0),
-              f.table_cell(1),
-                f.text('%.3f' % (b.maxbw,)),
-              f.table_cell(0),
-              f.table_cell(1),
-                f.text(', '.join(flags)),
-              f.table_cell(0),
-              f.table_cell(1),
-                f.text(e),
+                f.text('%.3f - %.3f' % (perm.freqband.start, perm.freqband.end)),
               f.table_cell(0),
               f.table_cell(1),
-                f.text('%.3f' % p.max_ant_gain),
+                f.text('%.3f' % (perm.freqband.maxbw,)),
               f.table_cell(0),
               f.table_cell(1),
-                f.text('%.3f' % p.max_ir_ptmp),
+                f.text(', '.join(perm.textflags)),
               f.table_cell(0),
               f.table_cell(1),
-                f.text('%.3f' % p.max_ir_ptp),
+                f.text('%.3f' % perm.power.max_ant_gain),
               f.table_cell(0),
               f.table_cell(1),
-                f.text('%.3f' % p.max_eirp_ptmp),
+                f.text('%.3f' % perm.power.max_ir),
               f.table_cell(0),
               f.table_cell(1),
-                f.text('%.3f' % p.max_eirp_ptp),
+                f.text('%.3f' % perm.power.max_eirp),
               f.table_cell(0),
             f.table_row(0),
         ])