Shop OBEX P1 Docs P2 Docs Learn Events
Possible to load a spin1 object in a spin2 top level object? — Parallax Forums

Possible to load a spin1 object in a spin2 top level object?

Getting started with the Prop2. I used the Prop1 extensively maybe 10 years ago, but this is a re-learn for me. Have read through the relevant documentation so far (I think), but I don't see any comments about how to load a spin1 object in a spin2 object (or at least a comment saying its not possible).

I'm trying to hook up a Parallax Ping Sonar to the Prop2, and I can only find a Prop1 Object for it in the Object Exchange. When I try to load it, I get "cannot find object ping.spin2" error.

If this is not possible, is there any "porting" guides that I can reference? I tried copying the Prop1 version of the Ping object as a Spin2 file, but it looks like there is an error regarding waitpne

Thanks!

Comments

  • JonnyMacJonnyMac Posts: 9,243
    edited 2025-03-13 00:35

    The simple answer is no -- unless your object uses very simple Spin and every method has parameters. In Spin2, methods w/o parameters must have empty parenthesis, and all return values must be declared. I've attached my Spin2 object for the P2 to get you started.

    It's always going to be a game of catch-up comparing the P2 to the P1. In the P1, Spin was fixed and embedded in the silicon. This is not the case with Spin2; the interpreter is downloaded with the compiled program -- what these means is that Chip can (and does) add features to Spin2. There are plenty of us who've ported lots of P1 code to the P2, so ask questions. It won't take long for you to get the hang of the P2 and enjoy the great new features.

  • JonnyMacJonnyMac Posts: 9,243
    edited 2025-03-13 00:42

    This is an old thread but the little python utility I wrote might help
    -- https://forums.parallax.com/discussion/174523/from-spin1-to-spin2#latest

    This is the latest I found on my computer

    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    #
    #  p2_hints.py
    #  -- updated 08 AUG 2022
    #
    #  Copyright 2022 JonnyMac <jon.mcphalen@gmail.com>
    #
    #  Contributors:
    #  -- add your name to this list before re-posting
    #
    #  Use:
    #  -- python p2_hints_1v8.py INFILE
    #
    #  Terms: MIT license
    #
    
    import sys
    
    p1p2_changes = {
        "**"           : "sca/scas",
        "^^"           : "sqrt",
        "||"           : "abs",
        "~>"           : "sar",
        "~~"           : "signx (!)",
        "~"            : "signx (!)",
        "?"            : "?? (pre)",
        "|<"           : "decod",
        ">|"           : "encod (!)",
        "<-"           : "rol",
        "->"           : "ror",
        "><"           : "rev (!)",
        "=>"           : ">=",
        "=<"           : "<=",
        "or"           : "||",
        "and"          : "&&",
        "ina["         : "pinread",
        "outa"         : "pinwrite",
        "dira"         : "N/A (set by pin functions)",
        "ctra"         : "Smart pin or code",
        "frqa"         : "Smart pin or code",
        "phsa"         : "Smart pin or code",
        "ctrb"         : "Smart pin or code",
        "frqb"         : "Smart pin or code",
        "phsb"         : "Smart pin or code",
        "waitcnt"      : "waitct",
        "cnt"          : "getct()",
        "cognew"       : "coginit/cogspin",
        "reboot"       : "hubset($1000_0000)",
        "waitpeq"      : "pinread + code",
        "waitpne"      : "pinread + code",
        "waitvid"      : "new code",
        "chipver"      : "N/A",
        "constant"     : "N/A",
        "string("      : "@ (optional)",
    
        # JM common libraries/calls
        # -- put class file names in double quotes inside single quotes
        #    * process normally ignores quoted text
    
        '"jm_time_80"' : "usually not needed",
        "time.pause"   : "waitms",
        "io.high"      : "pinhigh",
        "io.low"       : "pinlow",
        "io.toggle"    : "pintoggle",
        '"jm_prng"'    : '"jm_random"',
        "prng.seed"    : "not needed for xrandom()"
    }
    
    
    def char_count(c, s):
        """
        Count and return occurances of char c in string s
        """
        count = 0
        for char in s:
            if (char == c):
                count += 1
    
        return count
    
    
    def is_odd(n):
        return True if (n % 2 == 1) else False
    
    
    def in_quotes(i, s):
        """
        Returns True if position i of string s is in quotes
        """
        qs = s.rfind('"', 0, i)
        qe = s.find('"', i)
        qc = char_count('"', s[0:i])
    
        if qs >= 0 and qe >= 0:
            if (i > qs) and (i < qe) and is_odd(qc):
                return True
    
        return False
    
    
    def in_block(i, s):
        """
        Returns True if position i of string s is in single-line block comment
        """
        bs = s.rfind('{', 0, i-1)
        be = s.find('}', i+1)
    
        if (bs >= 0) and (be >= 0):
            if (i > bs) and (i < be) and not in_quotes(i, s):
                return True
    
        return False
    
    
    def in_comment(i, s):
        """
        Returns True if postion i of string s is in an end-of-line comment
        -- does not work for single-line block comments
        """
        cs = s.rfind("'")
    
        if (cs >= 0) and (i > cs) and not in_quotes(i, s):
            return True
        else:
            return False
    
    
    def is_clear(i, s):
        """
        Returns True if position i of string s is not in quotes or comment
        """
        if in_quotes(i, s):
            return False
        elif in_block(i, s):
            return False
        elif in_comment(i, s):
            return False
        else:
            return True
    
    
    def find_p1_tokens(s):
        """
        Returns list of column/token_index pairs in string s
        """
        tokenslist = list()
        s = s.lower()
        scancol = 0
        while scancol < len(s):
            for tkn in p1p2_changes:
                chk = s[scancol:scancol+len(tkn)]
                if (chk == tkn) and is_clear(scancol, s):
                    tokenslist.append([scancol, tkn])
                    scancol += len(tkn)
                    break
            else:
                scancol += 1
    
        return tokenslist
    
    
    def make_showme(tokens):
        """
        Returns string of ^ symbols to point to tokens in source line
        """
        s = "----  "
        pos = 0
        for ts in tokens:
            loc = ts[0]
            if (loc > pos):
                s = s + " " * (loc-pos)
            s = s + "^"
            pos = loc+1
    
        return s
    
    
    def process_file(infile):
        fixlines = 0
        fixes = 0
    
        print(f'Processing {infile}\n')
        try:
            fin = open(infile, 'r')
        except:
            print('-- Error opening input file')
            return -2  
    
        linenum = 0
        for line in fin:
            line = line.rstrip()
            linenum += 1
            tokens = find_p1_tokens(line)
            found = len(tokens)
            if (found > 0):
                fixlines += 1
                fixes += found
                s = make_showme(tokens)
                print(f'{linenum:04d}  {line} \n{s}')
                for x in range(0, found):
                    pos, p1t = tokens[x]
                    pos += 1
                    p2h = p1p2_changes[p1t]
                    print(f'      * Col {pos:03d}  (p1) {p1t:<16}  (p2) {p2h}')
                print()
    
        fin.close()
    
        s1 = 'suggestion' + 's' if (fixes != 1) else ''
        s2 = 'line' + 's' if (fixlines != 1) else ''
        print(f'Done. {fixes} {s1} in {fixlines} {s2}.')
    
        return 0
    
    
    def main(args):   
        if len(args) != 2:
            print(f"Use: python {args[0]} INFILE")
            return -1
    
        return process_file(args[1])
    
    
    if __name__ == '__main__':
        sys.exit(main(sys.argv))
    
  • ersmithersmith Posts: 6,147

    There's also FlexProp, which does let you compile Spin1 for P2 (and mix & match Spin1 and Spin2). However, it cannot translate assembly language from P1 ASM to P2 ASM, so you'll still need to do some porting.

  • Awesome answers, thanks so much!

  • David GitzDavid Gitz Posts: 7
    edited 2025-03-18 02:57

    @JonnyMac Digging through your ping driver code a bit. Trying to make sure I understand what's going on.
    I believe the code:

    pinstart(pin, p_high_ticks, 0, 0) 
    ...
    rdpin(pin)
    

    is designed to take advantage of the SmartPin modes available on the Propeller 2? But technically similiar logic could be done like in the Propeller 1 object:

    timeout := getms() + 25                                       ' start time-out timing (25ms)
     cnt1 := cnt
      repeat
        if (getms() > timeout)                                      ' if > 25ms, abort
          return 0
      until pinread(pin)                                            ' wait for end of pulse
      cnt2 := cnt
      return ((cnt2-cnt1) / (clkfreq / 1_000_000)) >> 1             
    

    Is this just a design choice to use the SmartPin mode, or is there performance improvements because of your method?

    If this is better to post in a different thread let me know.

  • JonnyMacJonnyMac Posts: 9,243
    edited 2025-03-19 17:17

    You're misreading the P2 code and your P1 code won't work -- you're mixing P2 things into it. This is the P1 equivalent of what my P2 code is doing -- without the ability to return as soon as the pulse is done.

    pub ticks(pin) : usecs 
    
    '' Return Ping sensor response in microseconds
    
      dira[pin] := 1                                                ' trigger the Ping
      outa[pin] := 1
      outa[pin] := 0
      dira[pin] := 0
    
      ctra := %01000 << 26 | pin                                    ' prep CTRA for 0-1-0 pulse measure
      frqa := 1
      phsa := 0
    
      waitcnt(cnt + (clkfreq / 40))                                 ' wait 25ms
    
      usecs := (phsa / (clkfreq / 1_000_000)) >> 1                  ' return microseconds
    
      ctra := 0                                                     ' clear counter
    

    Note that I write code that goes into products that my employer sells, so I have greater restraints than the Parallax demo code has. For example, I'm not using waitpeq or waitpne. Why? Because a broken wire or sensor could cause the code to hang forever; there is no escaping waitpxx without a state change.

    If this is better to post in a different thread let me know.

    You should limit your threads to a single topic.

Sign In or Register to comment.