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
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.
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))
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!
@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.
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.
You should limit your threads to a single topic.