changeset: 1946:747eed1c4dab tag: bandplan tag: qbase tag: qtip tag: tip user: Sean Burford date: Wed Apr 03 14:56:32 2013 +1100 summary: Add support for band plans (Bug 681) diff -r 4f0521cefe56 -r 747eed1c4dab chirp/bandplan.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/chirp/bandplan.py Wed Apr 03 14:56:32 2013 +1100 @@ -0,0 +1,84 @@ +# Copyright 2013 Sean Burford +# +# 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 3 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. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +from chirp import chirp_common + +class Band(object): + def __init__(self, limits, name, mode=None, step_khz=None, + input_offset=None, output_offset=None, tones=None): + # Apply semantic and chirp limitations to settings. + # memedit applies radio limitations when settings are applied. + try: + assert limits[0] <= limits[1], "Lower freq > upper freq" + if mode is not None: + assert mode in chirp_common.MODES, "Mode %s not one of %s" % ( + mode, chirp_common.MODES) + if step_khz is not None: + assert step_khz in chirp_common.TUNING_STEPS, ( + "step_khz %s not one of %s" % + (step_khz, chirp_common.TUNING_STEPS)) + if tones: + for tone in tones: + assert tone in chirp_common.TONES, ( + "tone %s not one of %s" % (tone, chirp_common.TONES)) + except AssertionError, e: + raise ValueError("%s %s: %s" % (name, limits, e)) + + self.name = name + self.mode = mode + self.step_khz = step_khz + self.tones = tones + self.limits = limits + self.offset = None + self.duplex = "simplex" + if input_offset is not None: + self.offset = input_offset + self.duplex = "rpt TX" + elif output_offset is not None: + self.offset = output_offset + self.duplex = "rpt RX" + + def __eq__(self, other): + return (other.limits[0] == self.limits[0] and + other.limits[1] == self.limits[1]) + + def contains(self, other): + return (other.limits[0] >= self.limits[0] and + other.limits[1] <= self.limits[1]) + + def width(self): + return self.limits[1] - self.limits[0] + + def inverse(self): + """Create an RX/TX shadow of this band using the offset.""" + if not self.offset: + return self + limits = (self.limits[0] + self.offset, self.limits[1] + self.offset) + offset = -1 * self.offset + if self.duplex == "rpt RX": + return Band(limits, self.name, self.mode, self.step_khz, + input_offset=offset, tones=self.tones) + return Band(limits, self.name, self.mode, self.step_khz, + output_offset=offset, tones=self.tones) + + def __repr__(self): + desc = '%s%s%s%s' % ( + self.mode and 'mode: %s ' % (self.mode,) or '', + self.step_khz and 'step_khz: %s ' % (self.step_khz,) or '', + self.offset and 'offset: %s ' % (self.offset,) or '', + self.tones and 'tones: %s ' % (self.tones,) or '') + + return "%s-%s %s %s %s" % ( + self.limits[0], self.limits[1], self.name, self.duplex, desc) diff -r 4f0521cefe56 -r 747eed1c4dab chirp/bandplan_au.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/chirp/bandplan_au.py Wed Apr 03 14:56:32 2013 +1100 @@ -0,0 +1,114 @@ +# Copyright 2013 Sean Burford +# +# 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 3 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. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + + +from chirp import bandplan, bandplan_iaru_r3 + + +SHORTNAME = "australia" + +DESC = { + "name": "Australian Amateur Band Plan", + "updated": "April 2010", + "url": "http://www.wia.org.au/members/bandplans/data/documents/Australian%20Band%20Plans%20100404.pdf", +} + +BANDS_10M = ( + # bandplan.Band((28000000, 29700000), "10 Meter Band"), + bandplan.Band((29520000, 29680000), "FM Simplex and Repeaters", + mode="FM", step_khz=20), + bandplan.Band((29620000, 29680000), "FM Repeaters", input_offset=-100000), +) + +BANDS_6M = ( + # bandplan.Band((50000000, 54000000), "6 Meter Band"), + bandplan.Band((52525000, 53975000), "FM Simplex and Repeaters", + mode="FM", step_khz=25), + bandplan.Band((53550000, 53975000), "FM Repeaters", input_offset=-1000000), +) + +BANDS_2M = ( + bandplan.Band((144000000, 148000000), "2 Meter Band", + tones=(91.5, 123.0, 141.3, 146.2, 85.4)), + bandplan.Band((144400000, 144600000), "Beacons", step_khz=1), + bandplan.Band((146025000, 147975000), "FM Simplex and Repeaters", + mode="FM", step_khz=25), + bandplan.Band((146625000, 147000000), "FM Repeaters Group A", + input_offset=-600000), + bandplan.Band((147025000, 147375000), "FM Repeaters Group B", + input_offset=600000), +) + +BANDS_70CM = ( + bandplan.Band((420000000, 450000000), "70cm Band", + tones=(91.5, 123.0, 141.3, 146.2, 85.4)), + bandplan.Band((432400000, 432600000), "Beacons", step_khz=1), + bandplan.Band((438025000, 439975000), "FM Simplex and Repeaters", + mode="FM", step_khz=25), + bandplan.Band((438025000, 438725000), "FM Repeaters Group A", + input_offset=-5000000), + bandplan.Band((439275000, 439975000), "FM Repeaters Group B", + input_offset=-5000000), +) + +BANDS_23CM = ( + # bandplan.Band((1240000000, 1300000000), "23cm Band"), + bandplan.Band((1273025000, 1273975000), "FM Repeaters", + mode="FM", step_khz=25, input_offset=20000000), + bandplan.Band((1296400000, 1296600000), "Beacons", step_khz=1), + bandplan.Band((1297025000, 1300400000), "General FM Simplex Data", + mode="FM", step_khz=25), +) + +BANDS_13CM = ( + bandplan.Band((2300000000, 2450000000), "13cm Band"), + bandplan.Band((2403400000, 2403600000), "Beacons", step_khz=1), + bandplan.Band((2425000000, 2428000000), "FM Simplex", + mode="FM", step_khz=25), + bandplan.Band((2428025000, 2429000000), "FM Duplex (Voice)", + mode="FM", step_khz=25, input_offset=20000000), + bandplan.Band((2429000000, 2429975000), "FM Duplex (Data)", + mode="FM", step_khz=100, input_offset=20000000), +) + +BANDS_9CM = ( + bandplan.Band((3300000000, 3600000000), "9cm Band"), + bandplan.Band((3320000000, 3340000000), "WB Channel 2: Voice/Data", + step_khz=100), + bandplan.Band((3400400000, 3400600000), "Beacons", step_khz=1), + bandplan.Band((3402000000, 3403000000), "FM Simplex (Voice)", + mode="FM", step_khz=100), + bandplan.Band((3403000000, 3405000000), "FM Simplex (Data)", + mode="FM", step_khz=100), +) + +BANDS_6CM = ( + bandplan.Band((5650000000, 5850000000), "6cm Band"), + bandplan.Band((5760400000, 5760600000), "Beacons", step_khz=1), + bandplan.Band((5700000000, 5720000000), "WB Channel 2: Data", + step_khz=100, input_offset=70000000), + bandplan.Band((5720000000, 5740000000), "WB Channel 3: Voice", + step_khz=100, input_offset=70000000), + bandplan.Band((5762000000, 5763000000), "FM Simplex (Voice)", + mode="FM", step_khz=100), + bandplan.Band((5763000000, 5765000000), "FM Simplex (Data)", + mode="FM", step_khz=100), +) + +BANDS = bandplan_iaru_r3.BANDS_20M + bandplan_iaru_r3.BANDS_17M +BANDS += bandplan_iaru_r3.BANDS_15M + bandplan_iaru_r3.BANDS_12M +BANDS += bandplan_iaru_r3.BANDS_10M + bandplan_iaru_r3.BANDS_6M +BANDS = BANDS_10M + BANDS_6M + BANDS_2M + BANDS_70CM + BANDS_23CM +BANDS = BANDS + BANDS_13CM + BANDS_9CM + BANDS_6CM diff -r 4f0521cefe56 -r 747eed1c4dab chirp/bandplan_iaru_r1.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/chirp/bandplan_iaru_r1.py Wed Apr 03 14:56:32 2013 +1100 @@ -0,0 +1,24 @@ +# Copyright 2013 Sean Burford +# +# 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 3 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. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +SHORTNAME = "iaru_r1" + +DESC = { + "name": "IARU Region 1", + "url": "http://iaru-r1.org/index.php?option=com_content&view=article&id=175&Itemid=127", + "updated": "General Conference Sun City 2011", +} + +BANDS = () diff -r 4f0521cefe56 -r 747eed1c4dab chirp/bandplan_iaru_r2.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/chirp/bandplan_iaru_r2.py Wed Apr 03 14:56:32 2013 +1100 @@ -0,0 +1,145 @@ +# Copyright 2013 Sean Burford +# +# 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 3 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. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +from chirp import bandplan + +SHORTNAME = "iaru_r2" + +DESC = { + "name": "IARU Region 2", + "updated": "October 8, 2010", + "url": "http://www.iaru.org/uploads/1/3/0/7/13073366/r2_band_plan.pdf" +} + +# Bands are broken up like this so that other plans can import bits. + +BANDS_160M = ( + bandplan.Band((1800000, 2000000), "160 Meter Band"), + bandplan.Band((1800000, 1810000), "Digimodes"), + bandplan.Band((1810000, 1830000), "CW", mode="CW"), + bandplan.Band((1830000, 1840000), "CW, priority for DX", mode="CW"), + bandplan.Band((1840000, 1850000), "SSB, priority for DX", mode="LSB"), + bandplan.Band((1850000, 1999000), "All modes", mode="LSB"), + bandplan.Band((1999000, 2000000), "Beacons", mode="CW"), +) + +BANDS_80M = ( + bandplan.Band((3500000, 4000000), "80 Meter Band"), + bandplan.Band((3500000, 3510000), "CW, priority for DX", mode="CW"), + bandplan.Band((3510000, 3560000), "CW, contest preferred", mode="CW"), + bandplan.Band((3560000, 3580000), "CW", mode="CW"), + bandplan.Band((3580000, 3590000), "All narrow band modes, digimodes"), + bandplan.Band((3590000, 3600000), "All modes"), + bandplan.Band((3600000, 3650000), "All modes, SSB contest preferred", + mode="LSB"), + bandplan.Band((3650000, 3700000), "All modes", mode="LSB"), + bandplan.Band((3700000, 3775000), "All modes, SSB contest preferred", + mode="LSB"), + bandplan.Band((3775000, 3800000), "All modes, SSB DX preferred", mode="LSB"), + bandplan.Band((3800000, 4000000), "All modes"), +) + +BANDS_40M = ( + bandplan.Band((7000000, 7300000), "40 Meter Band"), + bandplan.Band((7000000, 7025000), "CW, priority for DX", mode="CW"), + bandplan.Band((7025000, 7035000), "CW", mode="CW"), + bandplan.Band((7035000, 7038000), "All narrow band modes, digimodes"), + bandplan.Band((7038000, 7040000), "All narrow band modes, digimodes"), + bandplan.Band((7040000, 7043000), "All modes, digimodes"), + bandplan.Band((7043000, 7300000), "All modes"), +) + +BANDS_30M = ( + bandplan.Band((10100000, 10150000), "30 Meter Band"), + bandplan.Band((10100000, 10130000), "CW", mode="CW"), + bandplan.Band((10130000, 10140000), "All narrow band digimodes"), + bandplan.Band((10140000, 10150000), "All modes, digimodes, no phone"), +) + +BANDS_20M = ( + bandplan.Band((14000000, 14350000), "20 Meter Band"), + bandplan.Band((14000000, 14025000), "CW, priority for DX", mode="CW"), + bandplan.Band((14025000, 14060000), "CW, contest preferred", mode="CW"), + bandplan.Band((14060000, 14070000), "CW", mode="CW"), + bandplan.Band((14070000, 14089000), "All narrow band modes, digimodes"), + bandplan.Band((14089000, 14099000), "All modes, digimodes"), + bandplan.Band((14099000, 14101000), "IBP, exclusively for beacons", + mode="CW"), + bandplan.Band((14101000, 14112000), "All modes, digimodes"), + bandplan.Band((14112000, 14285000), "All modes, SSB contest preferred", + mode="USB"), + bandplan.Band((14285000, 14300000), "All modes", mode="AM"), + bandplan.Band((14300000, 14350000), "All modes"), +) + +BANDS_17M = ( + bandplan.Band((18068000, 18168000), "17 Meter Band"), + bandplan.Band((18068000, 18095000), "CW", mode="CW"), + bandplan.Band((18095000, 18105000), "All narrow band modes, digimodes"), + bandplan.Band((18105000, 18109000), "All narrow band modes, digimodes"), + bandplan.Band((18109000, 18111000), "IBP, exclusively for beacons", + mode="CW"), + bandplan.Band((18111000, 18120000), "All modes, digimodes"), + bandplan.Band((18120000, 18168000), "All modes"), +) + +BANDS_15M = ( + bandplan.Band((21000000, 21450000), "15 Meter Band"), + bandplan.Band((21000000, 21070000), "CW", mode="CW"), + bandplan.Band((21070000, 21090000), "All narrow band modes, digimodes"), + bandplan.Band((21090000, 21110000), "All narrow band modes, digimodes"), + bandplan.Band((21110000, 21120000), "All modes (exc SSB), digimodes"), + bandplan.Band((21120000, 21149000), "All narrow band modes"), + bandplan.Band((21149000, 21151000), "IBP, exclusively for beacons", + mode="CW"), + bandplan.Band((21151000, 21450000), "All modes", mode="USB"), +) + +BANDS_12M = ( + bandplan.Band((24890000, 24990000), "12 Meter Band"), + bandplan.Band((24890000, 24915000), "CW", mode="CW"), + bandplan.Band((24915000, 24925000), "All narrow band modes, digimodes"), + bandplan.Band((24925000, 24929000), "All narrow band modes, digimodes"), + bandplan.Band((24929000, 24931000), "IBP, exclusively for beacons", + mode="CW"), + bandplan.Band((24931000, 24940000), "All modes, digimodes"), + bandplan.Band((24940000, 24990000), "All modes", mode="USB"), +) + +BANDS_10M = ( + bandplan.Band((28000000, 29520000), "10 Meter Band"), + bandplan.Band((28000000, 28070000), "CW", mode="CW"), + bandplan.Band((28070000, 28120000), "All narrow band modes, digimodes"), + bandplan.Band((28120000, 28150000), "All narrow band modes, digimodes"), + bandplan.Band((28150000, 28190000), "All narrow band modes, digimodes"), + bandplan.Band((28190000, 28199000), "Regional time shared beacons", + mode="CW"), + bandplan.Band((28199000, 28201000), "IBP, exclusively for beacons", + mode="CW"), + bandplan.Band((28201000, 28225000), "Continuous duty beacons", + mode="CW"), + bandplan.Band((28225000, 28300000), "All modes, beacons"), + bandplan.Band((28300000, 28320000), "All modes, digimodes"), + bandplan.Band((28320000, 29000000), "All modes"), + bandplan.Band((29000000, 29200000), "All modes, AM preferred", mode="AM"), + bandplan.Band((29200000, 29300000), "All modes including FM, digimodes"), + bandplan.Band((29300000, 29510000), "Satellite downlink"), + bandplan.Band((29510000, 29520000), "Guard band, no transmission allowed"), + bandplan.Band((29520000, 29700000), "FM", step_khz=10, mode="NFM"), + bandplan.Band((29620000, 29690000), "FM Repeaters", input_offset=-100000), +) + +BANDS = BANDS_160M + BANDS_80M + BANDS_40M + BANDS_30M + BANDS_20M +BANDS = BANDS + BANDS_17M + BANDS_15M + BANDS_12M + BANDS_10M diff -r 4f0521cefe56 -r 747eed1c4dab chirp/bandplan_iaru_r3.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/chirp/bandplan_iaru_r3.py Wed Apr 03 14:56:32 2013 +1100 @@ -0,0 +1,139 @@ +# Copyright 2013 Sean Burford +# +# 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 3 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. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +from chirp import bandplan + +SHORTNAME = "iaru_r3" + +DESC = { + "name": "IARU Region 3", + "updated": "16 October 2009", + "url": "http://www.iaru.org/uploads/1/3/0/7/13073366/r3_band_plan.pdf" +} + +# Bands are broken up like this so that other plans can import bits. + +BANDS_2100M = ( + bandplan.Band((135700, 137800), "137khz Band", mode="CW"), +) + +BANDS_160M = ( + bandplan.Band((1800000, 2000000), "160 Meter Band"), + bandplan.Band((1830000, 1840000), "Digimodes", mode="RTTY"), + bandplan.Band((1840000, 2000000), "Phone"), +) + +BANDS_80M = ( + bandplan.Band((3500000, 3900000), "80 Meter Band"), + bandplan.Band((3500000, 3510000), "CW, priority for DX", mode="CW"), + bandplan.Band((3535000, 3900000), "Phone"), + bandplan.Band((3775000, 3800000), "All modes, SSB DX preferred", mode="LSB"), +) + +BANDS_40M = ( + bandplan.Band((7000000, 7300000), "40 Meter Band"), + bandplan.Band((7000000, 7025000), "CW, priority for DX", mode="CW"), + bandplan.Band((7025000, 7035000), "All narrow band modes, cw", mode="CW"), + bandplan.Band((7035000, 7040000), "All narrow band modes, phone"), + bandplan.Band((7040000, 7300000), "All modes, digimodes"), +) + +BANDS_30M = ( + bandplan.Band((10100000, 10150000), "30 Meter Band"), + bandplan.Band((10100000, 10130000), "CW", mode="CW"), + bandplan.Band((10130000, 10150000), "All narrow band digimodes"), +) + +BANDS_20M = ( + bandplan.Band((14000000, 14350000), "20 Meter Band"), + bandplan.Band((14000000, 14070000), "CW", mode="CW"), + bandplan.Band((14070000, 14099000), "All narrow band modes, digimodes"), + bandplan.Band((14099000, 14101000), "IBP, exclusively for beacons", + mode="CW"), + bandplan.Band((14101000, 14112000), "All narrow band modes, digimodes"), + bandplan.Band((14101000, 14350000), "All modes, digimodes"), +) + +BANDS_17M = ( + bandplan.Band((18068000, 18168000), "17 Meter Band"), + bandplan.Band((18068000, 18100000), "CW", mode="CW"), + bandplan.Band((18100000, 18109000), "All narrow band modes, digimodes"), + bandplan.Band((18109000, 18111000), "IBP, exclusively for beacons", + mode="CW"), + bandplan.Band((18111000, 18168000), "All modes, digimodes"), +) + +BANDS_15M = ( + bandplan.Band((21000000, 21450000), "15 Meter Band"), + bandplan.Band((21000000, 21070000), "CW", mode="CW"), + bandplan.Band((21070000, 21125000), "All narrow band modes, digimodes"), + bandplan.Band((21125000, 21149000), "All narrow band modes, digimodes"), + bandplan.Band((21149000, 21151000), "IBP, exclusively for beacons", + mode="CW"), + bandplan.Band((21151000, 21450000), "All modes", mode="USB"), +) + +BANDS_12M = ( + bandplan.Band((24890000, 24990000), "12 Meter Band"), + bandplan.Band((24890000, 24920000), "CW", mode="CW"), + bandplan.Band((24920000, 24929000), "All narrow band modes, digimodes"), + bandplan.Band((24929000, 24931000), "IBP, exclusively for beacons", + mode="CW"), + bandplan.Band((24931000, 24990000), "All modes, digimodes", mode="USB"), +) + +BANDS_10M = ( + bandplan.Band((28000000, 29700000), "10 Meter Band"), + bandplan.Band((28000000, 28050000), "CW", mode="CW"), + bandplan.Band((28050000, 28150000), "All narrow band modes, digimodes"), + bandplan.Band((28150000, 28190000), "All narrow band modes, digimodes"), + bandplan.Band((28190000, 28199000), "Beacons", mode="CW"), + bandplan.Band((28199000, 28201000), "IBP, exclusively for beacons", + mode="CW"), + bandplan.Band((28201000, 28300000), "Beacons", mode="CW"), + bandplan.Band((28300000, 29300000), "Phone"), + bandplan.Band((29300000, 29510000), "Satellite downlink"), + bandplan.Band((29510000, 29520000), "Guard band, no transmission allowed"), + bandplan.Band((29520000, 29700000), "Wide band", step_khz=10, mode="NFM"), +) + +BANDS_6M = ( + bandplan.Band((50000000, 54000000), "6 Meter Band"), + bandplan.Band((50000000, 50100000), "Beacons", mode="CW"), + bandplan.Band((50100000, 50500000), "Phone and narrow band"), + bandplan.Band((50500000, 54000000), "Wide band"), +) + +BANDS_2M = ( + bandplan.Band((144000000, 148000000), "2 Meter Band"), + bandplan.Band((144000000, 144035000), "Earth Moon Earth"), + bandplan.Band((145800000, 146000000), "Satellite"), +) + +BANDS_70CM = ( + bandplan.Band((430000000, 450000000), "70cm Band"), + bandplan.Band((431900000, 432240000), "Earth Moon Earth"), + bandplan.Band((435000000, 438000000), "Satellite"), +) + +BANDS_23CM = ( + bandplan.Band((1240000000, 1300000000), "23cm Band"), + bandplan.Band((1260000000, 1270000000), "Satellite"), + bandplan.Band((1296000000, 1297000000), "Earth Moon Earth"), +) + +BANDS = BANDS_2100M + BANDS_160M + BANDS_80M + BANDS_40M + BANDS_30M +BANDS = BANDS + BANDS_20M + BANDS_17M + BANDS_15M + BANDS_12M + BANDS_10M +BANDS = BANDS + BANDS_6M + BANDS_2M + BANDS_70CM + BANDS_23CM diff -r 4f0521cefe56 -r 747eed1c4dab chirp/bandplan_na.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/chirp/bandplan_na.py Wed Apr 03 14:56:32 2013 +1100 @@ -0,0 +1,41 @@ +# Copyright 2013 Dan Smith +# +# 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 3 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. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +from chirp import bandplan, bandplan_iaru_r2 + + +SHORTNAME = "north_america" + +DESC = { + "name": "North American Band Plan", +} + +BANDS = bandplan_iaru_r2.BANDS + ( + bandplan.Band((50000000, 54000000), "6 Meter Band"), + bandplan.Band((51620000, 51980000), "Repeaters A", input_offset=-500000), + bandplan.Band((52500000, 52980000), "Repeaters B", input_offset=-500000), + bandplan.Band((53500000, 53980000), "Repeaters C", input_offset=-500000), + bandplan.Band((144000000, 148000000), "2 Meter Band"), + bandplan.Band((145100000, 145500000), "Repeaters A", input_offset=-600000), + bandplan.Band((146600000, 147000000), "Repeaters B", input_offset=-600000), + bandplan.Band((147000000, 147400000), "Repeaters C", input_offset=600000), + bandplan.Band((219000000, 225000000), "220MHz Band"), + bandplan.Band((223850000, 224980000), "Repeaters", input_offset=-1600000), + bandplan.Band((420000000, 450000000), "70cm Band"), + bandplan.Band((440000000, 445000000), "Repeaters A", input_offset=5000000), + bandplan.Band((447000000, 450000000), "Repeaters B", input_offset=-5000000), + bandplan.Band((1240000000, 1300000000), "23cm Band"), + bandplan.Band((1282000000, 1288000000), "Repeaters", input_offset=-12000000), +) diff -r 4f0521cefe56 -r 747eed1c4dab chirp/chirp_common.py --- a/chirp/chirp_common.py Mon Apr 01 21:32:51 2013 -0700 +++ b/chirp/chirp_common.py Wed Apr 03 14:56:32 2013 +1100 @@ -68,58 +68,6 @@ MODES = ["WFM", "FM", "NFM", "AM", "NAM", "DV", "USB", "LSB", "CW", "RTTY", "DIG", "PKT", "NCW", "NCWR", "CWR", "P25", "Auto"] -STD_6M_OFFSETS = [ - (51620000, 51980000, -500000), - (52500000, 52980000, -500000), - (53500000, 53980000, -500000), - ] - -STD_2M_OFFSETS = [ - (145100000, 145500000, -600000), - (146000000, 146400000, 600000), - (146600000, 147000000, -600000), - (147000000, 147400000, 600000), - (147600000, 148000000, -600000), - ] - -STD_220_OFFSETS = [ - (223850000, 224980000, -1600000), - ] - -STD_70CM_OFFSETS = [ - (440000000, 445000000, 5000000), - (447000000, 450000000, -5000000), - ] - -STD_23CM_OFFSETS = [ - (1282000000, 1288000000, -12000000), - ] - -# Standard offsets, indexed by band (wavelength in cm) -STD_OFFSETS = { - 600 : STD_6M_OFFSETS, - 200 : STD_2M_OFFSETS, - 125 : STD_220_OFFSETS, - 70 : STD_70CM_OFFSETS, - 23 : STD_23CM_OFFSETS, - } - -BAND_TO_MHZ = { - 600 : ( 50000000, 54000000 ), - 200 : ( 144000000, 148000000 ), - 125 : ( 219000000, 225000000 ), - 70 : ( 420000000, 450000000 ), - 23 : ( 1240000000, 1300000000 ), -} - -# NB: This only works for some bands, throws an Exception otherwise -def freq_to_band(freq): - """Returns the band (in cm) for a given frequency""" - for band, (lo, hi) in BAND_TO_MHZ.items(): - if int(freq) > lo and int(freq) < hi: - return band - raise Exception("No conversion for frequency %i" % freq) - TONE_MODES = [ "", "Tone", diff -r 4f0521cefe56 -r 747eed1c4dab chirpui/bandplans.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/chirpui/bandplans.py Wed Apr 03 14:56:32 2013 +1100 @@ -0,0 +1,107 @@ +# Copyright 2013 Sean Burford +# +# 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 3 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. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +import gtk +from chirp import bandplan, bandplan_na, bandplan_au +from chirp import bandplan_iaru_r1, bandplan_iaru_r2, bandplan_iaru_r3 +from chirpui import inputdialog + + +class BandPlans(object): + def __init__(self, config): + self._config = config + self.plans = {} + + # Migrate old "automatic repeater offset" setting to + # "North American Amateur Band Plan" + ro = self._config.get("autorpt", "memedit") + if ro is not None: + self._config.set_bool("north_america", ro, "bandplan") + self._config.remove_option("autorpt", "memedit") + # And default new users to North America. + if not self._config.is_defined("north_america", "bandplan"): + self._config.set_bool("north_america", True, "bandplan") + + for plan in (bandplan_na, bandplan_au, bandplan_iaru_r1, + bandplan_iaru_r2, bandplan_iaru_r3): + name = plan.DESC.get("name", plan.SHORTNAME) + self.plans[plan.SHORTNAME] = (name, plan) + + rpt_inputs = [] + for band in plan.BANDS: + # Check for duplicates. + duplicates = [x for x in plan.BANDS if x == band] + if len(duplicates) > 1: + print "Bandplan %s has duplicates %s" % (name, duplicates) + # Add repeater inputs. + rpt_input = band.inverse() + if rpt_input not in plan.BANDS: + rpt_inputs.append(band.inverse()) + plan.bands = list(plan.BANDS) + plan.bands.extend(rpt_inputs) + + def get_defaults_for_frequency(self, freq): + freq = int(freq) + result = bandplan.Band((freq, freq), repr(freq)) + + for shortname, details in self.plans.items(): + if self._config.get_bool(shortname, "bandplan"): + matches = [x for x in details[1].bands if x.contains(result)] + # Add matches to defaults, favoring more specific matches. + matches = sorted(matches, key=lambda x: x.width(), + reverse=True) + for match in matches: + result.mode = match.mode or result.mode + result.step_khz = match.step_khz or result.step_khz + result.offset = match.offset or result.offset + result.duplex = match.duplex or result.duplex + result.tones = match.tones or result.tones + if match.name: + result.name = '/'.join((result.name or '', match.name)) + # Limit ourselves to one band plan match for simplicity. + # Note that if the user selects multiple band plans by editing + # the config file it will work as expected (except where plans + # conflict). + if matches: + break + + return result + + def select_bandplan(self, parent_window): + plans = ["None"] + for shortname, details in self.plans.iteritems(): + if self._config.get_bool(shortname, "bandplan"): + plans.insert(0, details[0]) + else: + plans.append(details[0]) + + d = inputdialog.ChoiceDialog(plans, parent=parent_window, + title="Choose Defaults") + d.label.set_text(_("Band plans define default channel settings for " + "frequencies in a region. Choose a band plan " + "or None for completely manual channel " + "settings.")) + d.label.set_line_wrap(True) + r = d.run() + + if r == gtk.RESPONSE_OK: + selection = d.choice.get_active_text() + for shortname, details in self.plans.iteritems(): + self._config.set_bool(shortname, selection == details[0], + "bandplan") + if selection == details[0]: + print "Selected band plan %s: %s" % (shortname, selection) + + d.destroy() diff -r 4f0521cefe56 -r 747eed1c4dab chirpui/config.py --- a/chirpui/config.py Mon Apr 01 21:32:51 2013 -0700 +++ b/chirpui/config.py Wed Apr 03 14:56:32 2013 +1100 @@ -54,6 +54,12 @@ def is_defined(self, key, section): return self.__config.has_option(section, key) + def remove_option(self, section, key): + self.__config.remove_option(section, key) + + if not self.__config.items(section): + self.__config.remove_section(section) + class ChirpConfigProxy: def __init__(self, config, section="global"): self._config = config @@ -98,6 +104,9 @@ def is_defined(self, key, section=None): return self._config.is_defined(key, section or self._section) + def remove_option(self, key, section): + self._config.remove_option(section, key) + _CONFIG = None def get(section="global"): global _CONFIG diff -r 4f0521cefe56 -r 747eed1c4dab chirpui/mainapp.py --- a/chirpui/mainapp.py Mon Apr 01 21:32:51 2013 -0700 +++ b/chirpui/mainapp.py Wed Apr 03 14:56:32 2013 +1100 @@ -40,6 +40,7 @@ from chirp import CHIRP_VERSION, chirp_common, detect, errors from chirp import icf, ic9x_icf from chirpui import editorset, clone, miscwidgets, config, reporting, fips +from chirpui import bandplans CONF = config.get() @@ -1240,9 +1241,6 @@ conf = config.get() conf.set_bool("no_report", not action.get_active()) - def do_toggle_autorpt(self, action): - CONF.set_bool("autorpt", action.get_active(), "memedit") - def do_toggle_no_smart_tmode(self, action): CONF.set_bool("no_smart_tmode", not action.get_active(), "memedit") @@ -1335,8 +1333,10 @@ self.do_clearq() elif action == "report": self.do_toggle_report(_action) - elif action == "autorpt": - self.do_toggle_autorpt(_action) + elif action == "channel_defaults": + # The memedit thread also has an instance of bandplans. + bp = bandplans.BandPlans(CONF) + bp.select_bandplan(self) elif action == "no_smart_tmode": self.do_toggle_no_smart_tmode(_action) elif action == "developer": @@ -1413,7 +1413,7 @@ - + @@ -1469,6 +1469,7 @@ ('export_chirp', None, _("CHIRP Native File"), None, None, self.mh), ('export_csv', None, _("CSV File"), None, None, self.mh), ('stock', None, _("Import from stock config"), None, None, self.mh), + ('channel_defaults', None, _("Channel defaults"), None, None, self.mh), ('cancelq', gtk.STOCK_STOP, None, "Escape", None, self.mh), ('help', None, _('Help'), None, None, self.mh), ('about', gtk.STOCK_ABOUT, None, None, None, self.mh), @@ -1477,7 +1478,6 @@ conf = config.get() re = not conf.get_bool("no_report"); hu = conf.get_bool("hide_unused", "memedit") - ro = conf.get_bool("autorpt", "memedit") dv = conf.get_bool("developer", "state") st = not conf.get_bool("no_smart_tmode", "memedit") @@ -1485,7 +1485,6 @@ ('report', None, _("Report statistics"), None, None, self.mh, re), ('hide_unused', None, _("Hide Unused Fields"), None, None, self.mh, hu), ('no_smart_tmode', None, _("Smart Tone Modes"), None, None, self.mh, st), - ('autorpt', None, _("Automatic Repeater Offset"), None, None, self.mh, ro), ('developer', None, _("Enable Developer Functions"), None, None, self.mh, dv), ] @@ -1679,10 +1678,6 @@ d.destroy() CONF.set_bool("warned_about_reporting", True) - if not CONF.is_defined("autorpt", "memedit"): - print "autorpt not set et" - CONF.set_bool("autorpt", True, "memedit") - self.update_recent_files() self.update_stock_configs() self.setup_extra_hotkeys() diff -r 4f0521cefe56 -r 747eed1c4dab chirpui/memedit.py --- a/chirpui/memedit.py Mon Apr 01 21:32:51 2013 -0700 +++ b/chirpui/memedit.py Wed Apr 03 14:56:32 2013 +1100 @@ -33,6 +33,7 @@ import os from chirpui import common, shiftdialog, miscwidgets, config, memdetail +from chirpui import bandplans from chirp import chirp_common, errors, directory, import_logic def handle_toggle(_, path, store, col): @@ -125,7 +126,7 @@ iter = self.store.get_iter(path) was_filled, prev = self.store.get(iter, self.col("_filled"), colnum) - def set_offset(path, offset): + def set_offset(offset): if offset > 0: dup = "+" elif offset == 0: @@ -134,17 +135,37 @@ dup = "-" offset *= -1 + if not dup in self.choices[_("Duplex")]: + print "Duplex %s not supported by this radio" % dup + return + if offset: self.store.set(iter, self.col(_("Offset")), offset) self.store.set(iter, self.col(_("Duplex")), dup) def set_ts(ts): - self.store.set(iter, self.col(_("Tune Step")), ts) + if ts in self.choices[_("Tune Step")]: + self.store.set(iter, self.col(_("Tune Step")), ts) + else: + print "Tune step %s not supported by this radio" % ts def get_ts(path): return self.store.get(iter, self.col(_("Tune Step")))[0] + def set_mode(mode): + if mode in self.choices[_("Mode")]: + self.store.set(iter, self.col(_("Mode")), mode) + else: + print "Mode %s not supported by this radio (%s)" % ( + mode, self.choices[_("Mode")]) + + def set_tone(tone): + if tone in self.choices[_("Tone")]: + self.store.set(iter, self.col(_("Tone")), tone) + else: + print "Tone %s not supported by this radio" % tone + try: new = chirp_common.parse_freq(new) except ValueError, e: @@ -155,17 +176,15 @@ set_ts(chirp_common.required_step(new)) is_changed = new != prev if was_filled else True - autorpt_enabled = self._config.get_bool("autorpt") - if new is not None and is_changed and autorpt_enabled: - try: - band = chirp_common.freq_to_band(new) - set_offset(path, 0) - for lo, hi, offset in chirp_common.STD_OFFSETS[band]: - if new > lo and new < hi: - set_offset(path, offset) - break - except Exception, e: - pass + if new is not None and is_changed: + defaults = self.bandplans.get_defaults_for_frequency(new) + set_offset(defaults.offset or 0) + if defaults.step_khz: + set_ts(defaults.step_khz) + if defaults.mode: + set_mode(defaults.mode) + if defaults.tones: + set_tone(defaults.tones[0]) return new @@ -192,11 +211,8 @@ # RX frequency as the default TX frequency self.store.set(iter, self.col("Offset"), freq) else: - band = int(freq / 100000000) - if chirp_common.STD_OFFSETS.has_key(band): - offset = chirp_common.STD_OFFSETS[band][0][2] - else: - offset = 0 + defaults = self.bandplans.get_defaults_for_frequency(freq) + offset = defaults.offset or 0 self.store.set(iter, self.col(_("Offset")), abs(offset)) return new @@ -1227,6 +1243,8 @@ self._config = config.get("memedit") + self.bandplans = bandplans.BandPlans(config.get()) + self.allowed_bands = [144, 440] self.count = 100 self.show_special = self._config.get_bool("show_special")