Notice. New forum software under development. It's going to miss a few functions and look a bit ugly for a while, but I'm working on it full time now as the old forum was too unstable. Couple days, all good. If you notice any issues, please contact me.
|
Forum Index : Microcontroller and PC projects : Help me write a function...
Author | Message | ||||
Grogster Admin Group Joined: 31/12/2012 Location: New ZealandPosts: 9308 |
Hi folks. For those of you finished with Christmas day, and want to stretch your little grey cells, I am trying to work out how I can make the following loop into a function, that I can call from the main code. Here is the code which is repeated several times in the main code: [code] do timer=0 flag=0 print @(50,170) "_ " do k$=inkey$ loop until k$<>"" or timer>DEFAULT if timer>9000 then out$="" goto start endif if asc(k$)>=0 and asc(k$)<=7 or asc(k$)>=9 and asc(k$)<=12 then out$="" goto start endif if asc(k$)>=14 and asc(k$)<=31 or asc(k$)>=128 and asc(k$)<=156 then out$="" goto start endif if asc(k$)=13 then If out$="" Then GoTo start lin$=out$ flag=1 endif endif if asc(k$)=8 and len(out$)>=1 then out$=left$(out$,len(out$)-1) else out$=out$ + k$ endif if len(out$)=1 then if asc(out$)=8 then out$="" endif if flag=1 then out$="" exit endif loop [/code] This routine times out and goes back to the main menu, if no key is pressed within ten seconds, or whatever DEFAULT is set to. It also deals with backspace etc, and builds a string with the results of your keypresses, for processing by the following code, when ENTER is pressed. Most of you will easily see what is going on in the code - let me know if anyone does not follow it, and I will explain it some more. What I would like to do, is make this routine a function which I can call from the main code, rather then repeating the code LOTS of times within the main program. IT IS WORKING FINE LIKE THIS, but multipule copies of the code will be gobbling up lots of memory, so to try to streamline the process, the use of a function was suggested by other members. This routine was built on by a couple of other members here aswell as myself - I will post a link to the thread about it, once I find it.... EDIT: Found links. Building a string from keypresses Show cursor during inputs My problem is in trying to understand how I need to "Format" the function, and what I need to pass to it, and how to understand what comes back to the main code. I have read about the FUNCTION command in the manual, but cannot understand it, so I am hoping that others here can prod me in the right direction. Thanks for any help, and merry Christmas. Smoke makes things work. When the smoke gets out, it stops! |
||||
BobD Guru Joined: 07/12/2011 Location: AustraliaPosts: 935 |
First step you could make it into a sub routine. After that you could try for a function if still needed. Put a label (GetMyInput:) on the front of it. Put an End Sub at the bottom of it. Convert each of the GoTo Start into Exit Sub, rinse and debug. At the point where your code used to be use a GoSub GetMyInput (or whatever label you choose). Merry Christmas edit: this post made me into a guru, lol. edit again: Your code for the timeouts is a bit weird. loop until k$<>"" or timer>DEFAULT
if timer>9000 then if DEFAULT > 9000 then you will exit on timeout but if DEFAULT =< 9000 then you will process a timed out null entry. You may end up with some odd results. |
||||
Grogster Admin Group Joined: 31/12/2012 Location: New ZealandPosts: 9308 |
I will try your idea, and study the sub/end sub commands a bit more. I will do more reading. As to the timer>9000 - that is a small bug - thanks for pointing it out. It does not stop the code from running, but that line should be timer>=default - I will correct it. I will upload my experiments here as I go. Merry Christmas, Guru. Smoke makes things work. When the smoke gets out, it stops! |
||||
Grogster Admin Group Joined: 31/12/2012 Location: New ZealandPosts: 9308 |
OK, thanks primarily to BobD for the prod, I have come up with a defined subroutine which appears to work. Before calling the sub, the following code is run: [code] GETIN (50,170,DEFAULT,0) if GIFLAG<>0 then goto start [/code] GETIN is the routine(contraction of GET INPUT), values passed to the subroutine are cursor position X, cursor position Y, Timeout period, show keystrokes or not. The last one is just a 1 or 0 switch - 1=show keystrokes on the screen, 0=hide them. Now, the subroutine follows thus: [code] SUB GETIN (CX,CY,TP,SK) do timer=0 flag=0 giflag=0 if SK=1 then print @(CX,CY) out$ + "_ " else print @(CX,CY) "_ " endif do k$=inkey$ loop until k$<>"" or timer>TP if timer>=TP then out$="" giflag=1 exit sub endif if asc(k$)>=0 and asc(k$)<=7 or asc(k$)>=9 and asc(k$)<=12 then out$="" giflag=1 exit sub endif if asc(k$)>=14 and asc(k$)<=31 or asc(k$)>=128 and asc(k$)<=156 then out$="" giflag=1 exit sub endif if asc(k$)=13 then If out$="" Then exit sub lin$=out$ flag=1 endif endif if asc(k$)=8 and len(out$)>=1 then out$=left$(out$,len(out$)-1) else out$=out$ + k$ endif if len(out$)=1 then if asc(out$)=8 then out$="" endif if flag=1 then out$="" giflag=0 exit endif loop end sub [/code] giflag keeps a track of if the subroutine has exited correctly, or if there has been a timeout or illegal keypress etc. this flag has to be zero when the code returns from the sub. If it is not, then the code jumps back to the main menu. All this seems to be working well. I have only ported this to one test area of the code, but will now port this to the rest of the code - I should save a bit of memory in the process, as this big routine was repeated quite a bit in the code, anywhere I needed keyboard input from the user, so I am hoping this will reduce the memory consumption - I will post back. Current code size is 30976 bytes. Smoke makes things work. When the smoke gets out, it stops! |
||||
BobD Guru Joined: 07/12/2011 Location: AustraliaPosts: 935 |
Graeme, good to see it working. I see I didn't quite get the start of the sub correct. Sorry, I lack a bit of practice and I didn't have time to look it up yesterday. Err, actually I was also having a bit of difficulty reading. The screen kept getting blurred. I don't remember what caused that. Bob |
||||
Grogster Admin Group Joined: 31/12/2012 Location: New ZealandPosts: 9308 |
No worries - I knew what you were getting at. Vodka? Smoke makes things work. When the smoke gets out, it stops! |
||||
Grogster Admin Group Joined: 31/12/2012 Location: New ZealandPosts: 9308 |
Ported code is 19922 bytes - I have saved 11054 bytes - 11k of memory saved by making this a subroutine. Well worth it. Smoke makes things work. When the smoke gets out, it stops! |
||||
BobD Guru Joined: 07/12/2011 Location: AustraliaPosts: 935 |
I'm sticking to my story; I don't remember, lol. |
||||
MicroBlocks Guru Joined: 12/05/2012 Location: ThailandPosts: 2209 |
Here is my interpretation (untested, just wrote it here in a post). It doesn't use any global variables. [code] FUNCTION InputLine$ (ScreenX, ScreenY, AllowedCharacters$, Echo, ExitOnNotAllowedCharacters, MaxLength, Timeout) LOCAL Line$ Line$ = "" timer = 0 do if Echo then print @(ScreenX, ScreenY) Line$ + "_"; else print @(ScreenX, ScreenY) "_"; endif do key$ = inkey$ loop until key$ <> "" or timer > Timeout if timer > Timeout then ' Here you could give Line$ a special value ' that is not available from the keyboard. ' Like Line$ = chr(1) to signal that a timeout occured Line$ = "" exit endif if key$ = chr$(8) then if len(Line$) = 1 then Line$="" if len(Line$) > 1 then Line$ = left(Line$,len(Line$)-1) endif if key$ = chr(13) then exit endif if instr(AllowedCharacters$, key$) = 0 then if ExitOnNotAllowedCharacters then ' Comment the next line if you want to keep ' what was entered until a NotAllowedCharacter occured. ' Or you could use Line$ = chr$(2) to signal that a ' not allowed character occured. Line$ = "" exit end if else if len(Line$) < MaxLength then Line$ = Line$ + key$ endif endif loop InputLine$ = Line$ END FUNCTION [/code] if you use it many times it is better to have the AllowedCharacters$ defined at the start of your program to save on memory requirement. [code] Numbers$ = "0123456789" Text$ = "abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ" Special$ = "!@#$%^&*()_+" SuperSpecial$ = "{}[]|\/?.>,<;:'" + chr$(34) AllowAll$ = Number$ + Text$ + Special$ + SuperSpecial$ [/code] You can then use it wherever in your program like this: [code] Answer$ = InputLine$(10, 8, Numbers$, true, true, 1, 5000) [/code] And if you really want to save memory: [code] FUNCTION InputLine$ (X, Y, A$, E, N, M, T) LOCAL L$ L$ = "" : timer = 0 do if E then print @(X, Y) L$ + "_"; else print @(X, Y) "_"; endif do k$ = inkey$ loop until k$ <> "" or timer > T if timer > T then L$ = "": exit endif if k$ = chr$(8) then if len(L$) = 1 then L$="" if len(L$) > 1 then L$ = left(L$,len(L$)-1) endif if k$ = chr(13) then exit if instr(A$, k$) = 0 then if N then L$ = "" exit end if else if len(L$) < M then L$ = L$ + k$ endif endif loop InputLine$ = L$ END FUNCTION [/code] If you need to test in your program that a timeout occured change the line L$ = "" to L$ = chr$(1). You can then test for it. [code] answer$=InputLine$(10, 8, Numbers$, true, true, 1, 5000) if answer$ = chr$(1) then ' Timeout occured ' do your stuff endif [/code] Microblocks. Build with logic. |
||||
Grogster Admin Group Joined: 31/12/2012 Location: New ZealandPosts: 9308 |
WOW, TZ - you really know how to code. I will have to read that a few times to understand it. Nice work. I will read this a few times to comprehend it. Smoke makes things work. When the smoke gets out, it stops! |
||||
MicroBlocks Guru Joined: 12/05/2012 Location: ThailandPosts: 2209 |
You might want to add [code] timer = 0 [/code] right after the timeout test. This will allow the user time after each keystroke, not a total time to be in the menu. Depends on what you need. Microblocks. Build with logic. |
||||
Grogster Admin Group Joined: 31/12/2012 Location: New ZealandPosts: 9308 |
Thanks, TZ, but it does that already - great minds think alike. Sample from my code above: [code] SUB GETIN (CX,CY,TP,SK) do timer=0 flag=0 giflag=0 if SK=1 then print @(CX,CY) out$ + "_ " else print @(CX,CY) "_ " endif [/code] After every keypress(controlled by the master DO/LOOP), the timer is reset, so as long as the user types SOMETHING, the timer is always being reset. This gives the user practically unlimited time to type, provided that they type something within the default time-out period. EDIT: OH - I think you mean in YOUR version of the code... (add timer=0) Smoke makes things work. When the smoke gets out, it stops! |
||||
James_From_Canb Senior Member Joined: 19/06/2011 Location: AustraliaPosts: 265 |
One more suggestion. There are a fair number of parameters being passed to TZ's function. If I recall correctly it's possible to test for an empty parameter so you could add code at the start of the function (before the Do command) to test for empty parameters and replace them with default values. That would make the calling of the function simpler and neater. BTW. I agree with Grogster. Nice code. James My mind is aglow with whirling, transient nodes of thought careening through a cosmic vapor of invention. Hedley Lamarr, Blazing Saddles (1974) |
||||
Print this page |