<html>
  <head>
    <meta content="text/html; charset=UTF-8" http-equiv="Content-Type">
  </head>
  <body bgcolor="#FFFFFF" text="#000000">
    Thanks for your reply!<br>
    <br>
    <div class="moz-cite-prefix">On 2013-02-19 10:14, Tom Hayward wrote:<br>
    </div>
    <blockquote
cite="mid:CAFXO5Z28Wb22jQWp+YHHOQvLLHHrTZ__cOaRR5RUeksSsDH91A@mail.gmail.com"
      type="cite">...
      <pre wrap="">
A new file is a change to Chirp. After adding the new file, Chirp is
not the same as it was before. But that's not the point here...</pre>
    </blockquote>
    <br>
    I understand that.  In CVS, to add a new file, I do "cvs add
    &lt;filename".  I presume in Mercurial I do "hg add chirp\id51py"
    (which I did), which would be added to the repository by a commit. 
    However, if I do the commit, Chirp's web site seems to imply that
    creates a fork that creates problems, so I haven't done that.<br>
    <br>
    <br>
    <blockquote
cite="mid:CAFXO5Z28Wb22jQWp+YHHOQvLLHHrTZ__cOaRR5RUeksSsDH91A@mail.gmail.com"
      type="cite">... "hg status -mar" does nothing to attribute the
      changes to you, or
      label them with an appropriate commit message.</blockquote>
    <br>
    I understand that "hg status -mar" is the same as "cvs upd";  ie,
    just lists the files that have changed or been added, and will be
    committed on the next commit.<br>
    <br>
    <br>
    <blockquote
cite="mid:CAFXO5Z28Wb22jQWp+YHHOQvLLHHrTZ__cOaRR5RUeksSsDH91A@mail.gmail.com"
      type="cite"> Our goal here isn't
      just to add new lines of code, but to document who added them and
      why,
      so that future readers of the code can ask "what was the guy who
      wrote
      this thinking??" and have both the explanation (commit message)
      and
      name/email of the guy who wrote it. If we find that your change
      introduces a regression, we are also easily able to search for
      commit
      messages containing "id?1" and revert each as needed until the
      regression disappears.
      <blockquote type="cite">
        <pre wrap="">hg diff:
</pre>
      </blockquote>
      <pre wrap="">
For this all to work, you must use a different command, "hg qnew ..."
to create your patch. You will be prompted to enter a commit message,
and when you export it ("hg export tip") your name and email address
will be automatically be added to the header. The commands to
accomplish this are all listed here:

<a class="moz-txt-link-freetext" href="http://chirp.danplanet.com/projects/chirp/wiki/DevelopersProcess#Soft-committing-a-Change">http://chirp.danplanet.com/projects/chirp/wiki/DevelopersProcess#Soft-committing-a-Change</a></pre>
    </blockquote>
    <br>
    So far, I've been sent that link THREE TIMES.  Each time I have read
    it IN DETAIL.  I don't want to start an argument here, BUT IT IS FAR
    FROM CLEAR.  The Mercurial website documentation is poorer;  I had
    to Google to find the format of the configuration file (named
    ".hg/hgrc", not ".hg/config" as the Chirp website indicates).  Note
    that I have worked with several source control systems over the
    forty years I've been developing, so I have a bit of a clue.<br>
    <br>
    EG:<br>
    <br>
    <ol>
      <li>The first time I ran "hg export tip", it showed changes (by
        Dan) to files that I hadn't touched.  What's that about?<br>
      </li>
      <li>Subsequent invocations return my changes to two files.  These
        two files need to be two separate patches (two separate bug #s).</li>
      <li>What the hell is "tip" ???<br>
      </li>
      <li>OK, I did "hg qnew -l chirp\id51.py -ef &lt;comment&gt;". 
        Then I removed it with "hg qpop".  Somewhere in these few steps
        my changes (including all of id51.py) were <b>deleted</b>.   Is
        that what you mean by "minimal learning curve" below? 
        Fortunately (that means having some experience with the batch of
        new SCM packages out there), I had a complete backup elsewhere.</li>
      <li>I just now decided to have multiple backups of my changes. 
        Perhaps I'll use CVS internally ...<br>
      </li>
      <li>Another "hg qpop" also removed a "patch" named "help";  I'll
        let you guess as to how that got there (grin).<br>
      </li>
    </ol>
    <br>
    <blockquote
cite="mid:CAFXO5Z28Wb22jQWp+YHHOQvLLHHrTZ__cOaRR5RUeksSsDH91A@mail.gmail.com"
      type="cite">
      <pre wrap="">When using "hg q.." commands, your changes are not permanent. You can
send a work-in-progress patch (see Sending a Change), ask some
questions, modify your code, then use "hg qref" to update the patch.

A little bit of record keeping is necessary for managing a large
codebase, and I think you'll find the learning curve for hg mq is
minimal and saves you effort in the long run.

Tom KD7LXL
</pre>
    </blockquote>
    <br>
    <b>&lt;rant&gt;</b><br>
    <br>
    So far this has been all downhill.  I've spent <b>far more time</b>
    screwing around with the submission process, that I did to create
    id51.py (and make proposed changes to id31.py).  I don't
    have/need/want an ID-31A.  I have an ID-51A, and the free Icom CS-51
    software is sufficient for my needs (including the import of some
    250 memories via .CSV files).  Frankly, it's less buggy as well.<br>
    <br>
    I thought, "Chirp lacks ID-51 support, and I have one;  let's see if
    I can help".  That's my sole motivation.  Just as changing DStarCom
    to open source so that Chirp could use some of that code, was to
    help (see Dan's blog on my code).  The changes I have to id31.py are
    because (having cloned id51.py from it) I think there are errors in
    the memory layout, and it seems reasonable to help fix that as well.<br>
    <br>
    We're all volunteers here, and I don't expect anyone to jump through
    hoops for me.  On the other hand, I'm retired, and have plenty of
    spare time to contribute to useful efforts.  Of course, I have MANY
    choices for how I spend that time (that includes being paid to fly
    small airplanes in wonderful weather), and screwing around with yet
    another inadequately documented tool is not high on my list.<br>
    <br>
    I don't know if you have read the book "Psychology of Computer
    Programming" by Gerald Weinberg.  Written in 1972, it's considered a
    classic.  He reported that back then, someone was inventing a new
    computer language about once a week.  This industry is filled with
    people that "have to" create new ("vanity") languages or tools, with
    very marginal additional utility (or worse) between them.  Remember
    "BitKeeper"?  That was the SCM rage a couple years ago.  No one
    these days counts the productivity cost of learning new tools (for
    Microsoft, that means new versions of productive software, with the
    main change being useless changes to the GUI) that are not
    adequately documented.<br>
    <br>
    <b>&lt;/rant&gt;</b><br>
    <br>
    So, I'll try once more:<br>
    <br>
       hg qnew -l chirp\id51.py -ef "[id51] Add support for Icom ID-51"<br>
    <br>
    I'm supposed to enter the bug # (553), but "qnew" won't take a "#"
    on the command line, and up pops a NotePad window with the changed
    file (??? I just closed it).  So, no info on that.  What follows is
    the output from the next command. I sure don't see my comment
    (above), and I sure thought that almost all of the lines would be
    prefixed by a "+".  So,, my guess is that this will be unacceptable
    as well.  I'm sure not going to submit any changes to id31.py until
    I've sorted this out.<br>
    <br>
       hg export tip<br>
    <br>
    # HG changeset patch<br>
    # User Dean Gibson <a class="moz-txt-link-rfc2396E" href="mailto:data@ae7q.net">&lt;data@ae7q.net&gt;</a><br>
    # Date 1361307603 28800<br>
    # Node ID b94ce8ef429fb5bf5750d96341c6d38354837b57<br>
    # Parent  5528bdcdc34e5966d5b7f0dbb6859f700b5f9366<br>
    # Copyright 2012 Dan Smith <a class="moz-txt-link-rfc2396E" href="mailto:dsmith@danplanet.com">&lt;dsmith@danplanet.com&gt;</a><br>
    #<br>
    # This program is free software: you can redistribute it and/or
    modify<br>
    # it under the terms of the GNU General Public License as published
    by<br>
    # the Free Software Foundation, either version 3 of the License, or<br>
    # (at your option) any later version.<br>
    #<br>
    # This program is distributed in the hope that it will be useful,<br>
    # but WITHOUT ANY WARRANTY; without even the implied warranty of<br>
    # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the<br>
    # GNU General Public License for more details.<br>
    #<br>
    # You should have received a copy of the GNU General Public License<br>
    # along with this program.  If not, see
    <a class="moz-txt-link-rfc2396E" href="http://www.gnu.org/licenses/">&lt;http://www.gnu.org/licenses/&gt;</a>.<br>
    <br>
    from chirp import directory, icf, bitwise, chirp_common<br>
    <br>
    MEM_FORMAT = """<br>
    struct {<br>
      u24 freq;<br>
      u16 offset;<br>
      u16 rtone:6,<br>
          ctone:6,<br>
          unknown2:1,<br>
          mode:3;<br>
      u8 dtcs;<br>
      u8 tune_step:4,<br>
         unknown5:4;<br>
      u8 unknown4;<br>
      u8 tmode:4,<br>
         duplex:2,<br>
         dtcs_polarity:2;<br>
      char name[16];<br>
      u8 unknown13;<br>
      u8 urcall[7];<br>
      u8 rpt1call[7];<br>
      u8 rpt2call[7];<br>
    } memory[500];<br>
    <br>
    #seekto 0x6A40;<br>
    u8 used_flags[70];<br>
    <br>
    #seekto 0x6A86;<br>
    u8 skip_flags[69];<br>
    <br>
    #seekto 0x6ACB;<br>
    u8 pskp_flags[69];<br>
    <br>
    #seekto 0x6B40;<br>
    struct {<br>
      u8 bank;<br>
      u8 index;<br>
    } banks[500];<br>
    <br>
    #seekto 0x6FD0;<br>
    struct {<br>
      char name[16];<br>
    } bank_names[26];<br>
    <br>
    #seekto 0xA8C0;<br>
    struct {<br>
      u24 freq;<br>
      u16 offset;<br>
      u8 unknown1[3];<br>
      u8 call[7];<br>
      char name[16];<br>
      char subname[8];<br>
      u8 unknown3[10];<br>
    } repeaters[700];<br>
    <br>
    #seekto 0x1384E;<br>
    struct {<br>
      u8 call[7];<br>
    } rptcall[700];<br>
    <br>
    #seekto 0x14E60;<br>
    struct {<br>
      char call[8];<br>
      char tag[4];<br>
    } mycall[6];<br>
    <br>
    #seekto 0x14EA8;<br>
    struct {<br>
      char call[8];<br>
    } urcall[200];<br>
    <br>
    """<br>
    <br>
    MODES = [ "FM", "NFM", "AM", "DV" ]<br>
    MODE_INDEX = [ 0, 1, 3, 5 ]<br>
    TMODES = ["", "Tone", "TSQL", "TSQL", "DTCS", "DTCS", "TSQL-R",
    "DTCS-R"]<br>
    DUPLEX = ["", "-", "+"]<br>
    DTCS_POLARITY = ["NN", "NR", "RN", "RR"]<br>
    TUNING_STEPS = [5.0, 6.25, 0, 0, 10.0, 12.5, 15.0, 20.0, 25.0, 30.0,
    50.0,<br>
                    100.0, 125.0, 200.0]<br>
    <br>
    def _decode_call(_call):<br>
        # Why Icom, why?<br>
        call = ""<br>
        shift = 1<br>
        acc = 0<br>
        for val in _call:<br>
            mask = (1 &lt;&lt; (shift)) - 1<br>
            call += chr((val &gt;&gt; shift) | acc)<br>
            acc = (val &amp; mask) &lt;&lt; (7 - shift)<br>
            shift += 1<br>
        call += chr(acc)<br>
        return call<br>
    <br>
    def _encode_call(call):<br>
        _call = [0x00] * 7<br>
        for i in range(0, 7):<br>
            val = ord(call[i]) &lt;&lt; (i + 1)<br>
            if i &gt; 0:<br>
                _call[i-1] |= (val &amp; 0xFF00) &gt;&gt; 8<br>
            _call[i] = val<br>
        _call[6] |= (ord(call[7]) &amp; 0x7F)<br>
    <br>
        return _call<br>
    <br>
    def _get_freq(_mem):<br>
        freq = int(_mem.freq)<br>
        offs = int(_mem.offset)<br>
    <br>
        if freq &amp; 0x00200000:<br>
            mult = 6250<br>
        else:<br>
            mult = 5000<br>
    <br>
        freq &amp;= 0x0003FFFF<br>
    <br>
        return (freq * mult), (offs * mult)<br>
    <br>
    def _set_freq(_mem, freq, offset):<br>
        if chirp_common.is_fractional_step(freq):<br>
            mult = 6250<br>
            flag = 0x00200000<br>
        else:<br>
            mult = 5000<br>
            flag = 0x00000000<br>
    <br>
        _mem.freq = (freq / mult) | flag<br>
        _mem.offset = (offset / mult)<br>
    <br>
    class ID51Bank(icf.IcomBank):<br>
        """A ID-51 Bank"""<br>
        def get_name(self):<br>
            _banks = self._model._radio._memobj.bank_names<br>
            return str(_banks[self.index].name).rstrip()<br>
    <br>
        def set_name(self, name):<br>
            _banks = self._model._radio._memobj.bank_names<br>
            _banks[self.index].name = str(name).ljust(16)[:16]<br>
    <br>
    @directory.register<br>
    class ID51Radio(icf.IcomCloneModeRadio,
    chirp_common.IcomDstarSupport):<br>
        """Icom ID-51"""<br>
        MODEL = "ID-51A"<br>
    <br>
        _memsize = 0x1FB40<br>
        _model = "\x33\x90\x00\x01"<br>
        _endframe = "Icom Inc\x2E\x44\x41"<br>
        _num_banks = 26<br>
        _bank_class = ID51Bank<br>
        _can_hispeed = True<br>
    <br>
        _ranges = [(0x00000, 0x1FB40, 32)]<br>
    <br>
        def _get_bank(self, loc):<br>
            _bank = self._memobj.banks[loc]<br>
            if _bank.bank == 0xFF:<br>
                return None<br>
            else:<br>
                return _bank.bank<br>
    <br>
        def _set_bank(self, loc, bank):<br>
            _bank = self._memobj.banks[loc]<br>
            if bank is None:<br>
                _bank.bank = 0xFF<br>
            else:<br>
                _bank.bank = bank<br>
    <br>
        def _get_bank_index(self, loc):<br>
            _bank = self._memobj.banks[loc]<br>
            return _bank.index<br>
    <br>
        def _set_bank_index(self, loc, index):<br>
            _bank = self._memobj.banks[loc]<br>
            _bank.index = index<br>
    <br>
        def get_features(self):<br>
            rf = chirp_common.RadioFeatures()<br>
            rf.memory_bounds = (0, 499)<br>
            rf.valid_bands = [(108000000, 174000000), (400000000,
    479000000)]<br>
            rf.has_settings = True<br>
            rf.has_ctone = True<br>
            rf.has_bank_index = True<br>
            rf.has_bank_names = True<br>
            rf.valid_tmodes = list(TMODES)<br>
            rf.valid_tuning_steps = sorted(list(TUNING_STEPS))<br>
            rf.valid_modes = list(MODES)<br>
            rf.valid_skips = ["", "S", "P"]<br>
            rf.valid_characters = chirp_common.CHARSET_ASCII<br>
            rf.valid_name_length = 16<br>
            return rf<br>
    <br>
        def process_mmap(self):<br>
            self._memobj = bitwise.parse(MEM_FORMAT, self._mmap)<br>
    <br>
        def get_raw_memory(self, number):<br>
            return repr(self._memobj.memory[number])<br>
    <br>
        def get_memory(self, number):<br>
            _mem = self._memobj.memory[number]<br>
            _usd = self._memobj.used_flags[number / 8]<br>
            _skp = self._memobj.skip_flags[number / 8]<br>
            _psk = self._memobj.pskp_flags[number / 8]<br>
    <br>
            bit = (1 &lt;&lt; (number % 8))<br>
    <br>
            if MODES[MODE_INDEX.index(_mem.mode)] == "DV":<br>
                mem = chirp_common.DVMemory()<br>
            else:<br>
                mem = chirp_common.Memory()<br>
            mem.number = number<br>
    <br>
            if _usd &amp; bit:<br>
                mem.empty = True<br>
                return mem<br>
    <br>
            mem.freq, mem.offset = _get_freq(_mem)<br>
            mem.name = str(_mem.name).rstrip()<br>
            mem.rtone = chirp_common.TONES[_mem.rtone]<br>
            mem.ctone = chirp_common.TONES[_mem.ctone]<br>
            mem.tmode = TMODES[_mem.tmode]<br>
            mem.duplex = DUPLEX[_mem.duplex]<br>
            mem.dtcs = chirp_common.DTCS_CODES[_mem.dtcs]<br>
            mem.dtcs_polarity = DTCS_POLARITY[_mem.dtcs_polarity]<br>
            mem.tuning_step = TUNING_STEPS[_mem.tune_step]<br>
            mem.mode = MODES[MODE_INDEX.index(_mem.mode)]<br>
    <br>
            if mem.mode == "DV":<br>
                mem.dv_urcall = _decode_call(_mem.urcall).rstrip()<br>
                mem.dv_rpt1call = _decode_call(_mem.rpt1call).rstrip()<br>
                mem.dv_rpt2call = _decode_call(_mem.rpt2call).rstrip()<br>
    <br>
            if _psk &amp; bit:<br>
                mem.skip = "P"<br>
            if _skp &amp; bit:<br>
                mem.skip = "S"<br>
    <br>
            return mem<br>
    <br>
        def set_memory(self, memory):<br>
            _mem = self._memobj.memory[memory.number]<br>
            _usd = self._memobj.used_flags[memory.number / 8]<br>
            _skp = self._memobj.skip_flags[memory.number / 8]<br>
            _psk = self._memobj.pskp_flags[memory.number / 8]<br>
    <br>
            bit = (1 &lt;&lt; (memory.number % 8))<br>
    <br>
            if memory.empty:<br>
                _usd |= bit<br>
                self._set_bank(memory.number, None)<br>
                return<br>
    <br>
            _usd &amp;= ~bit<br>
    <br>
            _set_freq(_mem, memory.freq, memory.offset)<br>
            _mem.name = memory.name.ljust(16)[:16]<br>
            _mem.rtone = chirp_common.TONES.index(memory.rtone)<br>
            _mem.ctone = chirp_common.TONES.index(memory.ctone)<br>
            _mem.tmode = TMODES.index(memory.tmode)<br>
            _mem.duplex = DUPLEX.index(memory.duplex)<br>
            _mem.dtcs = chirp_common.DTCS_CODES.index(memory.dtcs)<br>
            _mem.dtcs_polarity =
    DTCS_POLARITY.index(memory.dtcs_polarity)<br>
            _mem.tune_step = TUNING_STEPS.index(memory.tuning_step)<br>
            _mem.mode = MODE_INDEX[MODES.index(memory.mode)]<br>
    <br>
            if isinstance(memory, chirp_common.DVMemory):<br>
                _mem.urcall = _encode_call(memory.dv_urcall.ljust(8))<br>
                _mem.rpt1call =
    _encode_call(memory.dv_rpt1call.ljust(8))<br>
                _mem.rpt2call =
    _encode_call(memory.dv_rpt2call.ljust(8))<br>
            elif memory.mode == "DV":<br>
                raise Exception("BUG")<br>
    <br>
            if memory.skip == "S":<br>
                _skp |=  bit<br>
                _psk &amp;= ~bit<br>
            elif memory.skip == "P":<br>
                _skp &amp;= ~bit<br>
                _psk |=  bit<br>
            else:<br>
                _skp &amp;= ~bit<br>
                _psk &amp;= ~bit<br>
    <br>
        def get_urcall_list(self):<br>
            calls = []<br>
            for i in range(0, 200):<br>
                call = str(self._memobj.urcall[i].call)<br>
                if call == "CALLSIGN":<br>
                    call = ""<br>
                calls.append(call)<br>
            return calls<br>
    <br>
        def get_mycall_list(self):<br>
            calls = []<br>
            for i in range(0, 6):<br>
                calls.append(str(self._memobj.mycall[i].call))<br>
            return calls<br>
    <br>
        def get_repeater_call_list(self):<br>
            calls = []<br>
            for rptcall in self._memobj.rptcall:<br>
                call = _decode_call(rptcall.call)<br>
                if call.rstrip() and not call == "CALLSIGN":<br>
                    calls.append(call)<br>
            for repeater in self._memobj.repeaters:<br>
                call = _decode_call(repeater.call)<br>
                if call == "CALLSIGN":<br>
                    call = ""<br>
                calls.append(call.rstrip())<br>
            return calls<br>
    <br>
  </body>
</html>