Another approach for Basic is to always trap aborts from Spin programs. The caller would have to look at the return code to determine if there was an error.
As far as I understand the Spin abort, it cancels all instruction after the abort was called and pops the stack correctly until it finds a '\'. then it returns the long value give when calling abort.
What I sort of miss is a flag telling me that the result is a abort and not a normal return.
@ersmith syntax with try..catch...end could maybe provide this.
As far as I understand the Spin abort, it cancels all instruction after the abort was called and pops the stack correctly until it finds a '\'. then it returns the long value give when calling abort.
That was my understanding, so I just assumed we would loose the mission! The last thing we would want is to have to re work spin methods so that we can use them in a class. We will have see how Eric deals with it.
I think the issue, for a user of fastspin(basic) will be is to learn how to keep the code size down.
I think the issue, for a user of fastspin(basic) will be is to learn how to keep the code size down.
Interesting, does that mean that you will have to re-write Spin Objects? For somebody like myself, I have not used Spin, in a very long time, I would find it very difficult to deal with fsrw26.spin, in terms of code reduction.
It will also be very interesting to see how far Eric can reduce the size of Spin Objects. Or, the other option, writing the driver code in fastspin(BASIC), not sure if that was the intent of fastspin(BASIC).
The abort mechanism in Spin has a flaw I always struggle with, and that is the problem to distinguish between a regular return code and a abort situation.
Yes, that is an annoyance with abort. One way around this in Spin is to "bury" the functions that might abort in a non-aborting function, like:
pri dofile
x := popen(xxx)
y := pwrite(xxx)
z := pclose(xxx)
return $eae1e0ff
pub main
r := \dofile
if (r == $eae1e0ff)
'' everything OK
else
'' r contains the abort code
That was how I initially planned to implement try/catch in BASIC (having the compiler automatically doing this transformation). But that still means you need one magic value that can't be returned, and I think there's another approach I can use that would avoid this.
the try catch syntax would allow to separate this (if possible?)
try
x = fsrw.popen(xxx)
catch err
print "got error code", err
end
so that x just get changed if NO abort happened?
Mike
Right that's definitely an advantage of try/catch, and I'm going to try to implement it.
The one catch is that we'll only be able to return integers from abort (no strings or floats). Or rather, if you do want to return a string or float you'll have to use explicit casts. Spin doesn't have types so it's never an issue there.
I think the issue, for a user of fastspin(basic) will be is to learn how to keep the code size down.
Interesting, does that mean that you will have to re-write Spin Objects?
No. For now it just means that we can't use large functions with large Spin objects, and/or have to use tricks like disabling fcache to get things to fit.
The root of the problem is the LMM code that fastspin generates, which can be 4 times larger than Spin bytecodes. I think the long term solution is to have a mode where fastspin can generate compressed instructions (like PropGCC CMM) or perhaps even Spin bytecodes. That's going to take a while to get going though.
The following function compiles Ok.
I can live with the abort issue for now, if need be I can modify the fsrw.spin file so that I can
continue testing fastspin(basic)
'''
function wrfile(file_name$, text$, len) 'TODO Use ser class for input in leu of INPUT$ so that I can count string length at the input stage
dim x as long
mode= asc("w")
x = sd.popen(file_name,mode)
if ( x= -1) then
print( "error..cannot open file")
else
sd.pwrite(text,LEN)
sd.pclose()
end if
end function
'''
The abort mechanism in Spin has a flaw I always struggle with, and that is the problem to distinguish between a regular return code and a abort situation.
Yes, that is an annoyance with abort. One way around this in Spin is to "bury" the functions that might abort in a non-aborting function, like:
pri dofile
x := popen(xxx)
y := pwrite(xxx)
z := pclose(xxx)
return $eae1e0ff
pub main
r := \dofile
if (r == $eae1e0ff)
'' everything OK
else
'' r contains the abort code
That was how I initially planned to implement try/catch in BASIC (having the compiler automatically doing this transformation). But that still means you need one magic value that can't be returned, and I think there's another approach I can use that would avoid this.
the try catch syntax would allow to separate this (if possible?)
try
x = fsrw.popen(xxx)
catch err
print "got error code", err
end
so that x just get changed if NO abort happened?
Mike
Right that's definitely an advantage of try/catch, and I'm going to try to implement it.
The one catch is that we'll only be able to return integers from abort (no strings or floats). Or rather, if you do want to return a string or float you'll have to use explicit casts. Spin doesn't have types so it's never an issue there.
My usual way there is to abort with a negated string address, so return of less then zero is a error and its abs value is the address of the error-string.
I guess your integer is long enough to hold a address of a string?
The one catch is that we'll only be able to return integers from abort (no strings or floats). Or rather, if you do want to return a string or float you'll have to use explicit casts. Spin doesn't have types so it's never an issue there.
My usual way there is to abort with a negated string address, so return of less then zero is a error and its abs value is the address of the error-string.
I guess your integer is long enough to hold a address of a string?
Yes, integers can hold addresses.
I could also make throw/catch work with type ANY, which you'd then assign to an appropriately typed variable (integer, string, float, or whatever). This would let you throw string messages. You'll have to be very careful when working with other people's objects though to know what kind of error value they are throwing!
Are there major differences in keywords between Propbasic and this basic?
Yes. This BASIC is more like Visual BASIC or FreeBASIC. An LED blink program in fastspin BASIC looks like:
' pin for the LED
const LED = 16
' set the LED pin as an output
direction(LED) = output
' put a message on the serial port
print "Blinking LED on pin "; LED
do
high LED
pausems 500
low LED
pausems 500
loop
sub high(pin)
output(pin) = 1
end sub
sub low(pin)
output(pin) = 0
end sub
In general I don't want to make any breaking changes to fastspin now (just adding new features) but there is one thing that I think needs to change. Right now variables in for loops are declared automatically, which is convenient; but they are made as member variables of the object containing the for loop, which is quite inefficient and not usually what you want. I'm planning to change this so that the default is to create a local variable.
This shouldn't make any difference if you always explicitly declare all variables with "dim" or "var", but it will make things better for lazy programmers like me .
I see you've implemented try/catch. Are you planning on adding "finally" as well? I did try/catch with advsys2 but haven't done "finally" yet.
With the primitive exceptions that fastspin BASIC has right now I think "finally" is redundant. The catch block always catches exceptions, so the code after the try block will always execute. So "finally" would be a dummy like "if (1)". If we had more sophisticated exception handlers that automatically passed exceptions they didn't handle up to the parent then "finally" would be useful.
I see you've implemented try/catch. Are you planning on adding "finally" as well? I did try/catch with advsys2 but haven't done "finally" yet.
With the primitive exceptions that fastspin BASIC has right now I think "finally" is redundant. The catch block always catches exceptions, so the code after the try block will always execute. So "finally" would be a dummy like "if (1)". If we had more sophisticated exception handlers that automatically passed exceptions they didn't handle up to the parent then "finally" would be useful.
Or am I missing something?
Eric
Ah, that's an interesting point. I started out expecting to implement a more sophisticated "catch" but ended up having it always every exception. In that case, as you suggest, "finally" is not necessary. I guess I can take that off my TODO list!
I think users (like me) would like to see a built in function *len*
Oh, definitely! That should have been in there already, and I'll make sure it's added to the next release.
In the meantime you actually can call the Spin "strsize" function from BASIC. I'd say that's a temporary work-around (I'm not sure all the Spin function names will always be available from BASIC) but it'll get you going until "len" is there (both functions do the same thing).
I've updated the compiler to 3.9.6, and new releases of fastspin and spin2gui are available now. The main new features are improvements to COG memory usage, try/catch, LEN, and anonymous functions (lambdas). You shouldn't need to use --fcache=0 any more to compile even fairly complicated programs.
Also, although the open/print/close code has been in for a while it's been difficult to use with large programs because of the COG memory issue. Since that's fixed, you can now hook up Spin objects to the BASIC I/O functions. For example I have a program below for reading and writing files on an SD card using "print" and "input$". The only caveat is that writing data and then immediately reading it back doesn't seem to work right. The data is being written to the card (if I run a "read only" version of the program it prints it, and I can see it on my PC) but something about opening a file for write, closing it, and then opening the same file for read is not working right. I don't know if that's a fastspin bug, an fsrw bug, or just a misunderstanding on my part of how fsrw works.
The "open SendRecvDevice as #n" notation works for any object; you just need to provide 3 pointers to the "send a character", "receive a character", and "close" functions. The basic.md file has a bit more information under OPEN.
' for some reason doing both a read and a write fails??
' but doing just one or the other is OK
#define TRY_WRITE
'#define TRY_READ
const HEAPSIZE=2048 ' may not be necessary, but we're doing a lot of memory allocation under the hood
' the Spin SD card class
dim fsrw as class using "fsrw.spin"
' our pin usage
const D0=22, CLK=23, DI=24, CS=25
' open a file on the SD card
sub openfile(n as integer, name as string, mode as string)
dim r
r = fsrw.popen(name, asc(mode))
if r < 0 then
throw r
end if
open SendRecvDevice(@fsrw.pputc, @fsrw.pgetc, @fsrw.pclose) as #n
end sub
dim err
dim s$
dim cycles as uinteger
try
fsrw.mount_explicit(D0, CLK, DI, CS)
print "done mount"
#ifdef TRY_WRITE
pausems 500
print "testing write"
openfile(2, "hello.txt", "w")
print #2, "Hello from the propeller"
cycles = getcnt()
print #2, "When this was written, cycles = "; cycles
print #2, "See you!"
close #2
#endif
#ifdef TRY_READ
pausems 500
' try reading it back
print "testing read"
openfile(3, "hello.txt", "r")
s$ = input$(80, 3)
if s$ then
print "read back:"
print s$
else
print "got end of file"
endif
close #3
#endif
print "all done"
catch err
print "caught error: "; err
end try
Have you done any performance comparisons with PropBASIC?
Not directly, no -- the two have very different syntaxes so any code for one has to be ported to the other. I have tested fft-bench with fastspin (as Spin code) and since the compiler is the same the benchmark numbers should be very close. On that test fastspin does the FFT in 68 ms, PropBASIC LMM does it in 690 ms, and regular Spin in 1465 ms
Have you done any performance comparisons with PropBASIC?
Not directly, no -- the two have very different syntaxes so any code for one has to be ported to the other. I have tested fft-bench with fastspin (as Spin code) and since the compiler is the same the benchmark numbers should be very close. On that test fastspin does the FFT in 68 ms, PropBASIC LMM does it in 690 ms, and regular Spin in 1465 ms
Yeah, I know the syntax is different. That's good since PropBASIC will appeal to BASIC Stamp users since it is similar to pBASIC and fastBASIC will appeal to people familiar with PC-based BASIC dialects like FreeBASIC.
Is there a compiled version for the MacOS (of fastspin and spin2gui)? I know I should be able to compile it from source, but I just get a variety of errors and it's taking too much time and effort.
I downloaded the new spin2gui, and I tried the program below. Now, it seems to be coming up with some errors. On the previous versions of spin2gui the program below seemed to have run as expected.
The error refers to an unknown symbol Dhtnn_object_dhtnn_read_tmp003, not sure where this is located. Is this something that fastspin(BASIC) is doing?
Ray
rem test_temp.bas
' October 13, 2018
' Test of the CM2302 module on the WX Activity Board
dim cm2302 as class using "DHTnn_Object.spin"
let mscycles = clkfreq / 1000
sub pausems(ms)
waitcnt(getcnt() + ms * mscycles)
end sub
dim temp#,humid#,misc#
cm2302.StartDHTnn(8,22,@temp#,@humid#,@misc#)
do
cm2302.DHTnn_Read()
print "Temp ";(9.0/5.0)*temp# + 32.0;" Humid ";humid#
pausems 3000
loop
test_temp.bas
|-DHTnn_Object.spin
|-|-FloatMath.spin
test_temp.pasm
Done.
G:/fastspin/programs/test_temp/test_temp.pasm(719) error: Unknown symbol Dhtnn_object_dhtnn_read_tmp003_
G:/fastspin/programs/test_temp/test_temp.pasm(771) error: Unknown symbol Dhtnn_object_dhtnn_read_tmp003_
child process exited abnormally
Is there a compiled version for the MacOS (of fastspin and spin2gui)? I know I should be able to compile it from source, but I just get a variety of errors and it's taking too much time and effort.
Here is spin2cpp compiled to run on the Mac. It sounds like you don't have to compile spin2gui. You just have to get the source code from GitHub, open a command prompt, and cd to the top-level directory and type "wish spin2gui.tcl".
I downloaded the new spin2gui, and I tried the program below. Now, it seems to be coming up with some errors. On the previous versions of spin2gui the program below seemed to have run as expected.
The error refers to an unknown symbol Dhtnn_object_dhtnn_read_tmp003, not sure where this is located. Is this something that fastspin(BASIC) is doing?
Yes, it sounds like some of the new code for removing unused COG variables is broken. I'll try to track that down. Thanks for the bug report.
Here is a zip file that I believe contains everything you need to run spin2gui on the Mac. You should start the GUI from a command line prompt by setting your current directory to "spin2gui" and typing "wish spin2gui.tcl".
Here is a zip file that I believe contains everything you need to run spin2gui on the Mac. You should start the GUI from a command line prompt by setting your current directory to "spin2gui" and typing "wish spin2gui.tcl".
unzip spin2gui
cd spin2gui
wish spin2gui.tcl
FYI, I tried this today and ran the "blink1.bas" sample program. It worked fine on the ActivityBoard WX after I changed the PIN number to 26. I only tried a serial download.
Comments
What I sort of miss is a flag telling me that the result is a abort and not a normal return.
@ersmith syntax with try..catch...end could maybe provide this.
Mike
That was my understanding, so I just assumed we would loose the mission! The last thing we would want is to have to re work spin methods so that we can use them in a class. We will have see how Eric deals with it.
I think the issue, for a user of fastspin(basic) will be is to learn how to keep the code size down.
Ron
It will also be very interesting to see how far Eric can reduce the size of Spin Objects. Or, the other option, writing the driver code in fastspin(BASIC), not sure if that was the intent of fastspin(BASIC).
Ray
Right that's definitely an advantage of try/catch, and I'm going to try to implement it.
The one catch is that we'll only be able to return integers from abort (no strings or floats). Or rather, if you do want to return a string or float you'll have to use explicit casts. Spin doesn't have types so it's never an issue there.
The root of the problem is the LMM code that fastspin generates, which can be 4 times larger than Spin bytecodes. I think the long term solution is to have a mode where fastspin can generate compressed instructions (like PropGCC CMM) or perhaps even Spin bytecodes. That's going to take a while to get going though.
The following function compiles Ok.
I can live with the abort issue for now, if need be I can modify the fsrw.spin file so that I can
continue testing fastspin(basic)
Ron
My usual way there is to abort with a negated string address, so return of less then zero is a error and its abs value is the address of the error-string.
I guess your integer is long enough to hold a address of a string?
Mike
Yes, integers can hold addresses.
I could also make throw/catch work with type ANY, which you'd then assign to an appropriately typed variable (integer, string, float, or whatever). This would let you throw string messages. You'll have to be very careful when working with other people's objects though to know what kind of error value they are throwing!
Yes. This BASIC is more like Visual BASIC or FreeBASIC. An LED blink program in fastspin BASIC looks like:
I have the same question but you were faster.
This shouldn't make any difference if you always explicitly declare all variables with "dim" or "var", but it will make things better for lazy programmers like me .
Eric
With the primitive exceptions that fastspin BASIC has right now I think "finally" is redundant. The catch block always catches exceptions, so the code after the try block will always execute. So "finally" would be a dummy like "if (1)". If we had more sophisticated exception handlers that automatically passed exceptions they didn't handle up to the parent then "finally" would be useful.
Or am I missing something?
Eric
I think users (like me) would like to see a built in function *len*
So instead of …...........sd.pwrite(file name, text$, len)
Then I can then do .............sd.pwrite(file_name, text$) and then add the line
lx= len(text$) inside the function.
Is it on your TODO list ?
BTW Thanks for the update on the try/catch
Ron
Oh, definitely! That should have been in there already, and I'll make sure it's added to the next release.
In the meantime you actually can call the Spin "strsize" function from BASIC. I'd say that's a temporary work-around (I'm not sure all the Spin function names will always be available from BASIC) but it'll get you going until "len" is there (both functions do the same thing).
Also, although the open/print/close code has been in for a while it's been difficult to use with large programs because of the COG memory issue. Since that's fixed, you can now hook up Spin objects to the BASIC I/O functions. For example I have a program below for reading and writing files on an SD card using "print" and "input$". The only caveat is that writing data and then immediately reading it back doesn't seem to work right. The data is being written to the card (if I run a "read only" version of the program it prints it, and I can see it on my PC) but something about opening a file for write, closing it, and then opening the same file for read is not working right. I don't know if that's a fastspin bug, an fsrw bug, or just a misunderstanding on my part of how fsrw works.
The "open SendRecvDevice as #n" notation works for any object; you just need to provide 3 pointers to the "send a character", "receive a character", and "close" functions. The basic.md file has a bit more information under OPEN.
Not directly, no -- the two have very different syntaxes so any code for one has to be ported to the other. I have tested fft-bench with fastspin (as Spin code) and since the compiler is the same the benchmark numbers should be very close. On that test fastspin does the FFT in 68 ms, PropBASIC LMM does it in 690 ms, and regular Spin in 1465 ms
The error refers to an unknown symbol Dhtnn_object_dhtnn_read_tmp003, not sure where this is located. Is this something that fastspin(BASIC) is doing?
Ray
Yes, it sounds like some of the new code for removing unused COG variables is broken. I'll try to track that down. Thanks for the bug report.