Project

General

Profile

Bug #9758 » baofeng_common.py

mert akça, 02/19/2022 03:18 PM

 
1
# Copyright 2016:
2
# * Jim Unroe KC9HI, <rock.unroe@gmail.com>
3
#
4
# This program is free software: you can redistribute it and/or modify
5
# it under the terms of the GNU General Public License as published by
6
# the Free Software Foundation, either version 2 of the License, or
7
# (at your option) any later version.
8
#
9
# This program is distributed in the hope that it will be useful,
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
# GNU General Public License for more details.
13
#
14
# You should have received a copy of the GNU General Public License
15
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
16

    
17
"""common functions for Baofeng (or similar) handheld radios"""
18

    
19
import time
20
import struct
21
import logging
22
from chirp import chirp_common, directory, memmap
23
from chirp import bitwise, errors, util
24
from chirp.settings import RadioSettingGroup, RadioSetting, \
25
    RadioSettingValueBoolean, RadioSettingValueList
26

    
27
LOG = logging.getLogger(__name__)
28

    
29
STIMEOUT = 1.5
30

    
31

    
32
def _clean_buffer(radio):
33
    radio.pipe.timeout = 0.005
34
    junk = radio.pipe.read(256)
35
    radio.pipe.timeout = STIMEOUT
36
    if junk:
37
        LOG.debug("Got %i bytes of junk before starting" % len(junk))
38

    
39

    
40
def _rawrecv(radio, amount):
41
    """Raw read from the radio device"""
42
    data = ""
43
    try:
44
        data = radio.pipe.read(amount)
45
    except:
46
        msg = "Generic error reading data from radio; check your cable."
47
        raise errors.RadioError(msg)
48

    
49
    if len(data) != amount:
50
        msg = "Error reading data from radio: not the amount of data we want."
51
        raise errors.RadioError(msg)
52

    
53
    return data
54

    
55

    
56
def _rawsend(radio, data):
57
    """Raw send to the radio device"""
58
    try:
59
        radio.pipe.write(data)
60
    except:
61
        raise errors.RadioError("Error sending data to radio")
62

    
63

    
64
def _make_frame(cmd, addr, length, data=""):
65
    """Pack the info in the headder format"""
66
    frame = struct.pack(">BHB", ord(cmd), addr, length)
67
    # add the data if set
68
    if len(data) != 0:
69
        frame += data
70
    # return the data
71
    return frame
72

    
73

    
74
def _recv(radio, addr, length):
75
    """Get data from the radio """
76
    # read 4 bytes of header
77
    hdr = _rawrecv(radio, 4)
78

    
79
    # read data
80
    data = _rawrecv(radio, length)
81

    
82
    # DEBUG
83
    LOG.info("Response:")
84
    LOG.debug(util.hexprint(hdr + data))
85

    
86
    c, a, l = struct.unpack(">BHB", hdr)
87
    if a != addr or l != length or c != ord("X"):
88
        LOG.error("Invalid answer for block 0x%04x:" % addr)
89
        LOG.debug("CMD: %s  ADDR: %04x  SIZE: %02x" % (c, a, l))
90
        raise errors.RadioError("Unknown response from the radio")
91

    
92
    return data
93

    
94

    
95
def _get_radio_firmware_version(radio):
96
    msg = struct.pack(">BHB", ord("S"), radio._fw_ver_start,
97
                      radio._recv_block_size)
98
    radio.pipe.write(msg)
99
    block = _recv(radio, radio._fw_ver_start, radio._recv_block_size)
100
    _rawsend(radio, "\x06")
101
    time.sleep(0.05)
102
    version = block[0:16]
103
    return version
104

    
105

    
106
def _image_ident_from_data(data, start, stop):
107
    return data[start:stop]
108

    
109

    
110
def _get_image_firmware_version(radio):
111
    return _image_ident_from_data(radio.get_mmap(), radio._fw_ver_start,
112
                                  radio._fw_ver_start + 0x10)
113

    
114

    
115
def _do_ident(radio, magic):
116
    """Put the radio in PROGRAM mode"""
117
    #  set the serial discipline
118
    radio.pipe.baudrate = 9600
119
    radio.pipe.parity = "N"
120
    radio.pipe.timeout = STIMEOUT
121

    
122
    # flush input buffer
123
    _clean_buffer(radio)
124

    
125
    # send request to enter program mode
126
    _rawsend(radio, magic)
127

    
128
    ack = _rawrecv(radio, 1)
129
    if ack != "\x06":
130
        if ack:
131
            LOG.debug(repr(ack))
132
        raise errors.RadioError("Radio did not respond")
133

    
134
    _rawsend(radio, "\x02")
135

    
136
    # Ok, get the response
137
    ident = _rawrecv(radio, radio._magic_response_length)
138

    
139
    # check if response is OK
140
    if not ident.startswith("\xaa") or not ident.endswith("\xdd"):
141
        # bad response
142
        msg = "Unexpected response, got this:"
143
        msg += util.hexprint(ident)
144
        LOG.debug(msg)
145
        raise errors.RadioError("Unexpected response from radio.")
146

    
147
    # DEBUG
148
    LOG.info("Valid response, got this:")
149
    LOG.debug(util.hexprint(ident))
150

    
151
    _rawsend(radio, "\x06")
152
    ack = _rawrecv(radio, 1)
153
    if ack != "\x06":
154
        if ack:
155
            LOG.debug(repr(ack))
156
        raise errors.RadioError("Radio refused clone")
157

    
158
    return ident
159

    
160

    
161
def _ident_radio(radio):
162
    for magic in radio._magic:
163
        error = None
164
        try:
165
            data = _do_ident(radio, magic)
166
            return data
167
        except errors.RadioError, e:
168
            print e
169
            error = e
170
            time.sleep(2)
171
    if error:
172
        raise error
173
    raise errors.RadioError("Radio did not respond")
174

    
175

    
176
def _download(radio):
177
    """Get the memory map"""
178
    # put radio in program mode
179
    ident = _ident_radio(radio)
180

    
181
    # identify radio
182
    radio_ident = _get_radio_firmware_version(radio)
183
    LOG.info("Radio firmware version:")
184
    LOG.debug(util.hexprint(radio_ident))
185

    
186
    if radio_ident == "\xFF" * 16:
187
        ident += radio.MODEL.ljust(8)
188
    elif radio.MODEL in ("GMRS-V1", "MURS-V1"):
189
        # check if radio_ident is OK
190
        if not radio_ident[:7] in radio._fileid:
191
            msg = "Incorrect model ID, got this:\n\n"
192
            msg += util.hexprint(radio_ident)
193
            LOG.debug(msg)
194
            raise errors.RadioError("Incorrect 'Model' selected.")
195

    
196
    # UI progress
197
    status = chirp_common.Status()
198
    status.cur = 0
199
    status.max = radio._mem_size / radio._recv_block_size
200
    status.msg = "Cloning from radio..."
201
    radio.status_fn(status)
202

    
203
    data = ""
204
    for addr in range(0, radio._mem_size, radio._recv_block_size):
205
        frame = _make_frame("S", addr, radio._recv_block_size)
206
        # DEBUG
207
        LOG.info("Request sent:")
208
        LOG.debug(util.hexprint(frame))
209

    
210
        # sending the read request
211
        _rawsend(radio, frame)
212

    
213
        if radio._ack_block:
214
            ack = _rawrecv(radio, 1)
215
            if ack != "\x06":
216
                raise errors.RadioError(
217
                    "Radio refused to send block 0x%04x" % addr)
218

    
219
        # now we read
220
        d = _recv(radio, addr, radio._recv_block_size)
221

    
222
        _rawsend(radio, "\x06")
223
        time.sleep(0.05)
224

    
225
        # aggregate the data
226
        data += d
227

    
228
        # UI Update
229
        status.cur = addr / radio._recv_block_size
230
        status.msg = "Cloning from radio..."
231
        radio.status_fn(status)
232

    
233
    data += ident
234

    
235
    return data
236

    
237

    
238
def _upload(radio):
239
    """Upload procedure"""
240
    # put radio in program mode
241
    _ident_radio(radio)
242

    
243
    # identify radio
244
    radio_ident = _get_radio_firmware_version(radio)
245
    LOG.info("Radio firmware version:")
246
    LOG.debug(util.hexprint(radio_ident))
247
    # identify image
248
    image_ident = _get_image_firmware_version(radio)
249
    LOG.info("Image firmware version:")
250
    LOG.debug(util.hexprint(image_ident))
251

    
252
    if radio.MODEL in ("GMRS-V1", "MURS-V1"):
253
        # check if radio_ident is OK
254
        if radio_ident != image_ident:
255
            msg = "Incorrect model ID, got this:\n\n"
256
            msg += util.hexprint(radio_ident)
257
            LOG.debug(msg)
258
            raise errors.RadioError("Image not supported by radio")
259

    
260
    if radio_ident != "0xFF" * 16 and image_ident == radio_ident:
261
        _ranges = radio._ranges
262
    else:
263
        _ranges = [(0x0000, 0x0DF0),
264
                   (0x0E00, 0x1800)]
265

    
266
    # UI progress
267
    status = chirp_common.Status()
268
    status.cur = 0
269
    status.max = radio._mem_size / radio._send_block_size
270
    status.msg = "Cloning to radio..."
271
    radio.status_fn(status)
272

    
273
    # the fun start here
274
    for start, end in _ranges:
275
        for addr in range(start, end, radio._send_block_size):
276
            # sending the data
277
            data = radio.get_mmap()[addr:addr + radio._send_block_size]
278

    
279
            frame = _make_frame("X", addr, radio._send_block_size, data)
280

    
281
            _rawsend(radio, frame)
282
            time.sleep(0.05)
283

    
284
            # receiving the response
285
            ack = _rawrecv(radio, 1)
286
            if ack != "\x06":
287
                msg = "Bad ack writing block 0x%04x" % addr
288
                raise errors.RadioError(msg)
289

    
290
            # UI Update
291
            status.cur = addr / radio._send_block_size
292
            status.msg = "Cloning to radio..."
293
            radio.status_fn(status)
294

    
295

    
296
def _split(rf, f1, f2):
297
    """Returns False if the two freqs are in the same band (no split)
298
    or True otherwise"""
299

    
300
    # determine if the two freqs are in the same band
301
    for low, high in rf.valid_bands:
302
        if f1 >= low and f1 <= high and \
303
                f2 >= low and f2 <= high:
304
            # if the two freqs are on the same Band this is not a split
305
            return False
306

    
307
    # if you get here is because the freq pairs are split
308
    return True
309

    
310

    
311
class BaofengCommonHT(chirp_common.CloneModeRadio,
312
                      chirp_common.ExperimentalRadio):
313
    """Baofeng HT Sytle Radios"""
314
    VENDOR = "Baofeng"
315
    MODEL = ""
316
    IDENT = ""
317

    
318
    GMRS_FREQS1 = [462.5625, 462.5875, 462.6125, 462.6375, 462.6625,
319
                   462.6875, 462.7125]
320
    GMRS_FREQS2 = [467.5625, 467.5875, 467.6125, 467.6375, 467.6625,
321
                   467.6875, 467.7125]
322
    GMRS_FREQS3 = [462.5500, 462.5750, 462.6000, 462.6250, 462.6500,
323
                   462.6750, 462.7000, 462.7250]
324
    GMRS_FREQS = GMRS_FREQS1 + GMRS_FREQS2 + GMRS_FREQS3 * 2
325

    
326
    def sync_in(self):
327
        """Download from radio"""
328
        try:
329
            data = _download(self)
330
        except errors.RadioError:
331
            # Pass through any real errors we raise
332
            raise
333
        except:
334
            # If anything unexpected happens, make sure we raise
335
            # a RadioError and log the problem
336
            LOG.exception('Unexpected error during download')
337
            raise errors.RadioError('Unexpected error communicating '
338
                                    'with the radio')
339
        self._mmap = memmap.MemoryMap(data)
340
        self.process_mmap()
341

    
342
    def sync_out(self):
343
        """Upload to radio"""
344
        try:
345
            _upload(self)
346
        except errors.RadioError:
347
            raise
348
        except Exception, e:
349
            # If anything unexpected happens, make sure we raise
350
            # a RadioError and log the problem
351
            LOG.exception('Unexpected error during upload')
352
            raise errors.RadioError('Unexpected error communicating '
353
                                    'with the radio')
354

    
355
    def get_features(self):
356
        """Get the radio's features"""
357

    
358
        rf = chirp_common.RadioFeatures()
359
        rf.has_settings = True
360
        rf.has_bank = False
361
        rf.has_tuning_step = False
362
        rf.can_odd_split = True
363
        rf.has_name = True
364
        rf.has_offset = True
365
        rf.has_mode = True
366
        rf.has_dtcs = True
367
        rf.has_rx_dtcs = True
368
        rf.has_dtcs_polarity = True
369
        rf.has_ctone = True
370
        rf.has_cross = True
371
        rf.valid_modes = self.MODES
372
        rf.valid_characters = self.VALID_CHARS
373
        rf.valid_name_length = self.LENGTH_NAME
374
        rf.valid_duplexes = ["", "-", "+", "split", "off"]
375
        rf.valid_tmodes = ['', 'Tone', 'TSQL', 'DTCS', 'Cross']
376
        rf.valid_cross_modes = [
377
            "Tone->Tone",
378
            "DTCS->",
379
            "->DTCS",
380
            "Tone->DTCS",
381
            "DTCS->Tone",
382
            "->Tone",
383
            "DTCS->DTCS"]
384
        rf.valid_skips = self.SKIP_VALUES
385
        rf.valid_dtcs_codes = self.DTCS_CODES
386
        rf.memory_bounds = (0, 127)
387
        rf.valid_power_levels = self.POWER_LEVELS
388
        rf.valid_bands = self.VALID_BANDS
389
        rf.valid_tuning_steps = [2.5, 5.0, 6.25, 8.33, 10.0, 12.5, 20.0, 25.0, 50.0]
390

    
391
        return rf
392

    
393
    def _is_txinh(self, _mem):
394
        raw_tx = ""
395
        for i in range(0, 4):
396
            raw_tx += _mem.txfreq[i].get_raw()
397
        return raw_tx == "\xFF\xFF\xFF\xFF"
398

    
399
    def get_memory(self, number):
400
        _mem = self._memobj.memory[number]
401
        _nam = self._memobj.names[number]
402

    
403
        mem = chirp_common.Memory()
404
        mem.number = number
405

    
406
        if _mem.get_raw()[0] == "\xff":
407
            mem.empty = True
408
            return mem
409

    
410
        mem.freq = int(_mem.rxfreq) * 10
411

    
412
        if self._is_txinh(_mem):
413
            # TX freq not set
414
            mem.duplex = "off"
415
            mem.offset = 0
416
        else:
417
            # TX freq set
418
            offset = (int(_mem.txfreq) * 10) - mem.freq
419
            if offset != 0:
420
                if _split(self.get_features(), mem.freq, int(
421
                          _mem.txfreq) * 10):
422
                    mem.duplex = "split"
423
                    mem.offset = int(_mem.txfreq) * 10
424
                elif offset < 0:
425
                    mem.offset = abs(offset)
426
                    mem.duplex = "-"
427
                elif offset > 0:
428
                    mem.offset = offset
429
                    mem.duplex = "+"
430
            else:
431
                mem.offset = 0
432

    
433
        for char in _nam.name:
434
            if str(char) == "\xFF":
435
                char = " "  # The OEM software may have 0xFF mid-name
436
            mem.name += str(char)
437
        mem.name = mem.name.rstrip()
438

    
439
        dtcs_pol = ["N", "N"]
440

    
441
        if _mem.txtone in [0, 0xFFFF]:
442
            txmode = ""
443
        elif _mem.txtone >= 0x0258:
444
            txmode = "Tone"
445
            mem.rtone = int(_mem.txtone) / 10.0
446
        elif _mem.txtone <= 0x0258:
447
            txmode = "DTCS"
448
            if _mem.txtone > 0x69:
449
                index = _mem.txtone - 0x6A
450
                dtcs_pol[0] = "R"
451
            else:
452
                index = _mem.txtone - 1
453
            mem.dtcs = self.DTCS_CODES[index]
454
        else:
455
            LOG.warn("Bug: txtone is %04x" % _mem.txtone)
456

    
457
        if _mem.rxtone in [0, 0xFFFF]:
458
            rxmode = ""
459
        elif _mem.rxtone >= 0x0258:
460
            rxmode = "Tone"
461
            mem.ctone = int(_mem.rxtone) / 10.0
462
        elif _mem.rxtone <= 0x0258:
463
            rxmode = "DTCS"
464
            if _mem.rxtone >= 0x6A:
465
                index = _mem.rxtone - 0x6A
466
                dtcs_pol[1] = "R"
467
            else:
468
                index = _mem.rxtone - 1
469
            mem.rx_dtcs = self.DTCS_CODES[index]
470
        else:
471
            LOG.warn("Bug: rxtone is %04x" % _mem.rxtone)
472

    
473
        if txmode == "Tone" and not rxmode:
474
            mem.tmode = "Tone"
475
        elif txmode == rxmode and txmode == "Tone" and mem.rtone == mem.ctone:
476
            mem.tmode = "TSQL"
477
        elif txmode == rxmode and txmode == "DTCS" and mem.dtcs == mem.rx_dtcs:
478
            mem.tmode = "DTCS"
479
        elif rxmode or txmode:
480
            mem.tmode = "Cross"
481
            mem.cross_mode = "%s->%s" % (txmode, rxmode)
482

    
483
        mem.dtcs_polarity = "".join(dtcs_pol)
484

    
485
        if not _mem.scan:
486
            mem.skip = "S"
487

    
488
        levels = self.POWER_LEVELS
489
        try:
490
            mem.power = levels[_mem.lowpower]
491
        except IndexError:
492
            LOG.error("Radio reported invalid power level %s (in %s)" %
493
                      (_mem.power, levels))
494
            mem.power = levels[0]
495

    
496
        mem.mode = _mem.wide and "FM" or "NFM"
497

    
498
        mem.extra = RadioSettingGroup("Extra", "extra")
499

    
500
        rs = RadioSetting("bcl", "BCL",
501
                          RadioSettingValueBoolean(_mem.bcl))
502
        mem.extra.append(rs)
503

    
504
        rs = RadioSetting("pttid", "PTT ID",
505
                          RadioSettingValueList(self.PTTID_LIST,
506
                                                self.PTTID_LIST[_mem.pttid]))
507
        mem.extra.append(rs)
508

    
509
        rs = RadioSetting("scode", "S-CODE",
510
                          RadioSettingValueList(self.SCODE_LIST,
511
                                                self.SCODE_LIST[_mem.scode]))
512
        mem.extra.append(rs)
513

    
514
        return mem
515

    
516
    def set_memory(self, mem):
517
        _mem = self._memobj.memory[mem.number]
518
        _nam = self._memobj.names[mem.number]
519

    
520
        if mem.empty:
521
            _mem.set_raw("\xff" * 16)
522
            _nam.set_raw("\xff" * 16)
523
            return
524

    
525
        _mem.set_raw("\x00" * 16)
526

    
527
        if self._gmrs:
528
            if mem.number >= 1 and mem.number <= 30:
529
                GMRS_FREQ = int(self.GMRS_FREQS[mem.number - 1] * 1000000)
530
                mem.freq = GMRS_FREQ
531
                if mem.number <= 22:
532
                    mem.duplex = ''
533
                    mem.offset = 0
534
                    if mem.number >= 8 and mem.number <= 14:
535
                        mem.mode = "NFM"
536
                        mem.power = self.POWER_LEVELS[2]
537
                if mem.number > 22:
538
                    mem.duplex = '+'
539
                    mem.offset = 5000000
540
            elif float(mem.freq) / 1000000 in self.GMRS_FREQS:
541
                if float(mem.freq) / 1000000 in self.GMRS_FREQS2:
542
                    mem.offset = 0
543
                    mem.mode = "NFM"
544
                    mem.power = self.POWER_LEVELS[2]
545
                if float(mem.freq) / 1000000 in self.GMRS_FREQS3:
546
                    if mem.duplex == '+':
547
                        mem.offset = 5000000
548
                    else:
549
                        mem.offset = 0
550
            else:
551
                mem.duplex = 'off'
552
                mem.offset = 0
553

    
554
        _mem.rxfreq = mem.freq / 10
555

    
556
        if mem.duplex == "off":
557
            for i in range(0, 4):
558
                _mem.txfreq[i].set_raw("\xFF")
559
        elif mem.duplex == "split":
560
            _mem.txfreq = mem.offset / 10
561
        elif mem.duplex == "+":
562
            _mem.txfreq = (mem.freq + mem.offset) / 10
563
        elif mem.duplex == "-":
564
            _mem.txfreq = (mem.freq - mem.offset) / 10
565
        else:
566
            _mem.txfreq = mem.freq / 10
567

    
568
        _namelength = self.get_features().valid_name_length
569
        for i in range(_namelength):
570
            try:
571
                _nam.name[i] = mem.name[i]
572
            except IndexError:
573
                _nam.name[i] = "\xFF"
574

    
575
        rxmode = txmode = ""
576
        if mem.tmode == "Tone":
577
            _mem.txtone = int(mem.rtone * 10)
578
            _mem.rxtone = 0
579
        elif mem.tmode == "TSQL":
580
            _mem.txtone = int(mem.ctone * 10)
581
            _mem.rxtone = int(mem.ctone * 10)
582
        elif mem.tmode == "DTCS":
583
            rxmode = txmode = "DTCS"
584
            _mem.txtone = self.DTCS_CODES.index(mem.dtcs) + 1
585
            _mem.rxtone = self.DTCS_CODES.index(mem.dtcs) + 1
586
        elif mem.tmode == "Cross":
587
            txmode, rxmode = mem.cross_mode.split("->", 1)
588
            if txmode == "Tone":
589
                _mem.txtone = int(mem.rtone * 10)
590
            elif txmode == "DTCS":
591
                _mem.txtone = self.DTCS_CODES.index(mem.dtcs) + 1
592
            else:
593
                _mem.txtone = 0
594
            if rxmode == "Tone":
595
                _mem.rxtone = int(mem.ctone * 10)
596
            elif rxmode == "DTCS":
597
                _mem.rxtone = self.DTCS_CODES.index(mem.rx_dtcs) + 1
598
            else:
599
                _mem.rxtone = 0
600
        else:
601
            _mem.rxtone = 0
602
            _mem.txtone = 0
603

    
604
        if txmode == "DTCS" and mem.dtcs_polarity[0] == "R":
605
            _mem.txtone += 0x69
606
        if rxmode == "DTCS" and mem.dtcs_polarity[1] == "R":
607
            _mem.rxtone += 0x69
608

    
609
        _mem.scan = mem.skip != "S"
610
        _mem.wide = mem.mode == "FM"
611

    
612
        if mem.power:
613
            _mem.lowpower = self.POWER_LEVELS.index(mem.power)
614
        else:
615
            _mem.lowpower = 0
616

    
617
        # extra settings
618
        if len(mem.extra) > 0:
619
            # there are setting, parse
620
            for setting in mem.extra:
621
                setattr(_mem, setting.get_name(), setting.value)
622
        else:
623
            # there are no extra settings, load defaults
624
            _mem.bcl = 0
625
            _mem.pttid = 0
626
            _mem.scode = 0
627

    
628
    def set_settings(self, settings):
629
        _settings = self._memobj.settings
630
        _mem = self._memobj
631
        for element in settings:
632
            if not isinstance(element, RadioSetting):
633
                if element.get_name() == "fm_preset":
634
                    self._set_fm_preset(element)
635
                else:
636
                    self.set_settings(element)
637
                    continue
638
            else:
639
                try:
640
                    name = element.get_name()
641
                    if "." in name:
642
                        bits = name.split(".")
643
                        obj = self._memobj
644
                        for bit in bits[:-1]:
645
                            if "/" in bit:
646
                                bit, index = bit.split("/", 1)
647
                                index = int(index)
648
                                obj = getattr(obj, bit)[index]
649
                            else:
650
                                obj = getattr(obj, bit)
651
                        setting = bits[-1]
652
                    else:
653
                        obj = _settings
654
                        setting = element.get_name()
655

    
656
                    if element.has_apply_callback():
657
                        LOG.debug("Using apply callback")
658
                        element.run_apply_callback()
659
                    elif element.value.get_mutable():
660
                        LOG.debug("Setting %s = %s" % (setting, element.value))
661
                        setattr(obj, setting, element.value)
662
                except Exception, e:
663
                    LOG.debug(element.get_name())
664
                    raise
665

    
666
    def _set_fm_preset(self, settings):
667
        for element in settings:
668
            try:
669
                val = element.value
670
                if self._memobj.fm_presets <= 108.0 * 10 - 650:
671
                    value = int(val.get_value() * 10 - 650)
672
                else:
673
                    value = int(val.get_value() * 10)
674
                LOG.debug("Setting fm_presets = %s" % (value))
675
                self._memobj.fm_presets = value
676
            except Exception, e:
677
                LOG.debug(element.get_name())
678
                raise
    (1-1/1)