Help with sample code for a NooB
iQuit
Posts: 78
Just starting with the Propeller; coming over from the BS2 side.
I was wondering if this code could be implemented any better; it does work in its current state. I've tried several versions, and this is my best shot at it.
Any criticism would be appreciated. But go easy, it's my first time.
Data input comes from a phone connected to a 8870 IC on pins 0..3. (DTMF decoder)
Odd thing to note, the case shown in the code works, but if I change it to...
case Count
0: if Num <> Pin_1
Reset
.
.
.
Other: Count += 1
it doesn't work
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
"She may not be very pretty now, but she was somebody's baby once." Bugs Bunny
Post Edited (iQuit) : 4/20/2010 10:30:54 PM GMT
I was wondering if this code could be implemented any better; it does work in its current state. I've tried several versions, and this is my best shot at it.
Any criticism would be appreciated. But go easy, it's my first time.
Data input comes from a phone connected to a 8870 IC on pins 0..3. (DTMF decoder)
CON Pin_1 = 1 'Pin code to enter, then #, which = 12 Pin_2 = 2 'to unLock system. Out of order entry Resets Count Pin_3 = 3 'variable to zero. Pin_4 = 4 VAR byte Num, Lock, Count PUB Initiate DIRa[noparse][[/noparse]0..4]~ DIRa~~ 'LED on this pin to show success Reset PUB Reset 'initial setup to Lock system Lock := 1 Count := 0 Scan PUB Scan repeat if INa 'goes high when data is available at 8870 IC output Check waitcnt(clkfreq/100 + cnt) PUB Check Num := INa[noparse][[/noparse]3..0] case Num 11: Reset 'star * 12: checkPIN 'pound # case Count 0: if Num == Pin_1 Count += 1 1: if Num == Pin_2 Count += 1 2: if Num == Pin_3 Count += 1 3: if Num == Pin_4 Count += 1 Other: Reset Scan PRI checkPIN if Lock == 1 AND Count == 4 unLock Reset PRI unLock Lock := 0 Count := 0 OUTa~~ waitcnt(clkfreq*2 + cnt) 'make LED light for 2 seconds OUTa~ Reset
Odd thing to note, the case shown in the code works, but if I change it to...
case Count
0: if Num <> Pin_1
Reset
.
.
.
Other: Count += 1
it doesn't work
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
"She may not be very pretty now, but she was somebody's baby once." Bugs Bunny
Post Edited (iQuit) : 4/20/2010 10:30:54 PM GMT
Comments
In Scan you call Check and in Check you call Scan ....
In Check you call Reset and reset calls Scan and Scan calls Check .....
that's not a good idea!!!!! You will sooner or later have a stack overflow! This program looks like you were used to do GOTO driven programming before ;o) When you do Scan for example you 'call' the function, which means that a return address is stored on the stack. When the function is done it will return to this address and continue from there, if you allow it to. The important thing here is, that the stack-pointer will be cleaned up again. If you never return the stack will grow unless it wraps around the 32kByte RAM limit and starts from the beginning. And that's where your program will start doing nasty things or hang ;o)
I thought that there might be some issue with the call stack; and yes, you're correct, having programmed the BS2, I'm used to the Goto
command. Also, the clock settings were left out for brevity.
This begs the question, How does one think in terms of the flow of Spin? For example...
does this work?
PUB Main
dosomething
dosomething else
PUB MethodA
domore
etc.
PUB MethodB
yetMoreStuff
If Main never calls either MethodA, or MethodB, they never will execute, right?
And if conditions change within another method, causing direction change, does the flow have to return to each previous method in reverse
order and then finish the remainder of its code? (that one was a little long)
@ magIO2
You say, " When you do Scan for example you 'call' the function, which means that a return address is stored on the stack. When the function is done it will return to this address and continue from there, if you allow it to."
The part about continue from there, if you allow it to. I had a feeling that I was manhandling the flow of the program, but I sometimes need it to go one way only
if certain conditions exist, without going back and continuing the rest of the code in the previous method. How do I do that?
I will get this stuff, eventually. My main problem, I think, is that I don't fully understand the proper flow of spin. Is there a good statement that can explain
how to look at this stuff in a way that results in good programming techniques?
Thank you.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
"She may not be very pretty now, but she was somebody's baby once." Bugs Bunny
Scan -> Check -> Scan -> Check -> Scan -> Check -> Scan -> Check ->·Scan -> Check -> CheckPIN -> unLock -> Reset -> go back to the beginning
all done by gotos which don't exist in SPIN.
If you have a look at the Scan -> Check sequence .. that's already coded in the repeat loop
Scan -> Check which then returns to·the end of Scan which is in the repeat, so the Scan starts again
Scan -> Check with·return
Scan -> Check with return
Scan -> Check with return
Scan -> Check -> CheckPIN -> unLock -> Reset wich will go back the whole call stack to Scan
To your question about changing the flow: You can change the flow in the caller by using return values which are then checked by if or case statements. If return value equals A, then do this, if return value·equals B then do that, if it equals C do this AND that ....
A common way to do this for a while and something else if a special condition is met is programming a state-machine.
The state tells the program what to do and the state can be changed if a condition is met.
I think I understand. Here is what I've done to tighten up the code even further. I'll try it tonight to verify that it works. And thanks for your assistance.
It is greatly appreciated.
NEW REVISED:
Thanks for the fix concerning the large font issue.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
"She may not be very pretty now, but she was somebody's baby once." Bugs Bunny
Post Edited (iQuit) : 4/20/2010 10:27:51 PM GMT
And you should put code in a code section. Then indentation will not be lost. It's the # button above the text-input in case you did a 'Post Reply'. If you use "Quick Reply" you can use [noparse][[/noparse] code ] [noparse][[/noparse] /code ]-tags (but without spaces then)
One of the commands could be to re-lock the system. If a wrong number gets input, Count gets reset to zero. And Count also gets reset to zero after a successful unlock.
Does it matter where the waitcnt() is located in the scan repeat loop? Before or after the if?
I plan on making this an object that will run in another cog, so most of the methods are PRI. Please feel free to critique.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
"She may not be very pretty now, but she was somebody's baby once." Bugs Bunny
To make it an object your Scan also needs to return somewhen. Or do you want the PIN object to run in it's own COG the whole time? In which system will this object be used?
Maybe it's also a good idea to have a timeout version. If the user does not enter the PIN in time you return to the calling function, which then can denies access to the PIN protected function and locks the system if the PIN was not given or correctly given 3 times ... erase the whole EEPROM ;o)
Yes, a better name would be good. When I get closer to that, I'll think of one. Still haven't decided if this will be a separate object, but I do want to have
this run in a separate cog. Or, is that the same thing? Something like "Phone Handler.spin"
I'm thinking that the top object will start this when the phone rings, start a timer, and wait for input commands. The top object will stop the cog if Lock hasn't
been cleared after some time, say a minute. The top object will also be able to initiate a phone call, start this object, and wait for the PIN to clear the Lock,
and then wait for a command, or beep etc.
I'm still working out the details--this is fun stuff!
What if I were to use the following in place of the Scan method shown above?
Since this is the only thing that the cog will be doing, what could it hurt? The only fear is that it might lock up. If I were to put a stop method in this object,
and called it from the top object, would this object see it while in this waitpeq state?
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
"She may not be very pretty now, but she was somebody's baby once." Bugs Bunny
·
This won't work!
You have to do the cognew inside of the Init.
The question is: What will your 'top object' do while waiting for the pin-object to release the lock? Really wait or has it other tasks? If it's really waiting, there is no need to start an additional COG! You only need to change the Scan function a bit so that it will return after releasing the lock OR after a timeout.
Doing a waitpeq is fine if you have it running in a different COG. But what's the repeat at the end good for? It will keep the COG running even if it's done with it's job.
Waitpeq will halt the COG until the condition is met. So, it won't see anything going on. If your 'top object' calls a stop method, this will run in the same COG as the 'top object' and not in the pin-COG. Stop will then do a COGSTOP with the ID of the pin-COG and the pin-COG will be stopped whatever it's doing. It's not like giving a message 'Could you please stop if possible' ... it's a·forced stop, no chance for the COG to avoid it.
The top object will be monitoring other things while the phone handler object is doing its thing; getting a PIN and receiving commands. It will pass these along
to the top object, or perform the functions itself. The top object will start a timer along with the cog to run phone handler. If, after about a minute, the phone
handler object hasn't sent the unlock signal, it will do something. Perhaps hang up the phone and try again?
I see that I don't need the repeat now. Silly me. I'm pretty sure that this will run in another cog.
Glad to hear that I can stop the running cog from the top object.
Thank you for all of your help. I'm just getting started with the propeller and can use it. This is a great resource.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
"She may not be very pretty now, but she was somebody's baby once." Bugs Bunny
Post Edited (iQuit) : 4/21/2010 7:16:09 PM GMT