Home
JAQForum Ver 20.06
Log In or Join  
Active Topics
Local Time 05:15 06 May 2024 Privacy Policy
Jump to

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 : Micromite Firmware Update V5.04.04

     Page 2 of 2    
Author Message
CaptainBoing

Guru

Joined: 07/09/2016
Location: United Kingdom
Posts: 1985
Posted: 01:24am 23 Jun 2017
Copy link to clipboard 
Print this post

  Andrew_G said   Geoff and CaptainBoing,
I've been looking at your Field functions above. Is it me or do they have a problem picking the last field as in "E" the following real NMEA (0183) sentence (and all the last fields - because the last delimiter is "*" not ",")?
(It is still important to get the last field - in this case the E is for East of the prime meridian.)

$GPRMC,034600,A,3747.3072,S,14502.7606,E,000.0,097.2,081016,011.6,E*6A

Can you see a way of neatly picking the E (OK - it could be the character(s) between the last "," and the "*" but there has to be a neater way?)


To fix your problem you need to split the string twice (because you have two delimiters (, and *) so first I would break the string into the main components (on the ,) and for the last you need to split it on the *

Geoff's code above is a good fit but it is specific to your needs.

SPLIT is more aimed at general use.

This is a classic example of two adages:
1. horses for courses.
2. You can have it small and slow or big and fast.

This last point is the eternal challenge in writing algorithms. i.e. do I calculate a Sine from a polynomial or look it up in a table. The first is small code but takes time to run through the loops required, the last is a few steps but requires a huge data table. It is always a trade-off

I have a screen dump (including the test prog) at the end of this so you can play but the way I see it here are the for/against for both methods:

FIELD$:
Cons. code runs each time you extract a part, Many parts = many calls. Doesn't tell you how many fields are in the string - you need to know beforehand. Doesn't permit long delimiters (e.g CRLF) but easy to fix.
Pros. Small memory overhead ,no array = "cheaper" on RAM. Preserves the original string. May still end up in the firmware

SPLIT:
Cons. Potentially large memory overhead, maximum would be 129*256 bytes =32k+ worst case. Destroys the original string (easily fixed).
Pros. single call required to extract multiple elements. Quick for many elements. Tells you how many are in the string.

For the string you supplied, SPLIT used 4K of RAM(!) but it was around 3x quicker - see point 2 above as an aside here, this is not entirely a fair impression as Geoff's code has not been optimized for speed and SPLIT has. That said, With a 3 field string, split was 36mS and FIELD$ was 46mS (remember this is at 5MHz to make the delays show)
I did a version without the print (the console time will make things look bad). The single call to SPLIT took 107mS and twelve calls to FIELD$ took 365mS.

This absolutely must not be seen as a "my code's better than your code" bun fight - it really is just down to the differences and trade-offs in two different approaches to the same problem - also Geoff's version does cater for two different delimiters where as in this specific case, SPLIT would require to to pick apart SP$(12) (you could get SPLIT to do it but it would destroy your previous split as SP$() is re-used)

If FIELD$ does make it into the firmware (so not interpreted), I will probably never use SPLIT again.

Make your own mind up - here's my screen output


> cpu 5
> ? mm.ver
5.0404
> ? mm.device$
Micromite MkII
> list all

Dim a$
Dim n,x As integer

a$="$GPRMC,034600,A,3747.3072,S,14502.7606,E,000.0,097.2,081016,011.6,E*6A"

Timer=0
x=split(a$,",")

For n=1 To x
Print sp$(n)
Next

Print Timer;"mS"

a$="$GPRMC,034600,A,3747.3072,S,14502.7606,E,000.0,097.2,081016,011.6,E*6A"

Timer=0

For n=1 To 12
Print Field$(a$,n,",")
Next

Print Timer;"mS"

Function Split(a$,b$) ' returns the number of dimensions in SP$ always starts from 1 regardless of OPTION BASE
Local INTEGER z,n,m
On ERROR SKIP 1' if SP$ doesn't exist, next line will cause an error
Erase SP$
z=1:n=0
Do 'count instances of delimiter for DIM SP$()
z=Instr(z,a$,b$)
If z=0 Then
If n=0 Then ' no delimeters
Dim SP$(1):SP$(1)=a$:Split=1:Exit Function ' early bath
Else
Exit Do
End If
Else
n=n+1:z=z+Len(b$)
End If
Loop

m=n+1:n=1
Dim SP$(m)
Do
z=Instr(1,a$,b$)
If z=0 Then
SP$(m)=a$:Exit Do
Else
SP$(n)=Left$(a$,z-1):a$=Mid$(a$,z+Len(b$)):n=n+1
End If
Loop
Split=m
End Function


'------------------------------------------------------------------------------
' Geoff's Message Field$ Routine (with one amendment)
'------------------------------------------------------------------------------

Function Field$(s$, n, delim$)
Local Integer i, StartIdx = 1, EndIdx

' get the start of the field in StartIdx
For i = 2 To n
StartIdx = Instr(StartIdx, s$, delim$) + 1
If StartIdx = 1 Or StartIdx > Len(s$) Then Exit Function
Next i

' get the end of the field in EndIdx and extract the field
EndIdx = Instr(StartIdx, s$, delim$)
If EndIdx = 0 Then EndIdx = Len(s$)+1 ' makes it smaller than 255
Field$ = Mid$(s$, StartIdx, EndIdx - StartIdx)

End Function
> RUN
$GPRMC
034600
A
3747.3072
S
14502.7606
E
000.0
097.2
081016
011.6
E*6A
128mS
$GPRMC
034600
A
3747.3072
S
14502.7606
E
000.0
097.2
081016
011.6
E*6A
364mS
> memory
Flash:
2K ( 3%) Program (76 lines)
1K ( 1%) 2 Saved Variables (40 bytes)
57K (96%) Free

RAM:
4K ( 7%) 4 Variables
0K ( 0%) General
46K (93%) Free
>

Edited by CaptainBoing 2017-06-24
 
Andrew_G
Guru

Joined: 18/10/2016
Location: Australia
Posts: 842
Posted: 02:39pm 23 Jun 2017
Copy link to clipboard 
Print this post

Hi Captain Boing. Thanks for that. I was "less than precise than normal" in that my comment about missing the last field was directed at the Field function by Geoff (that you modified slightly). I have not tried the Split function as I am dealing with NMEA sentences and I know how many fields there are in each.
You are right that it is (always|usually?) horses for courses.
One of the beaut things about this forum is that people can exchange ideas without being defensive - in my 6+ months here I've not seen one example.

Cheers,
Andrew
 
led-bloon

Senior Member

Joined: 21/12/2014
Location: Australia
Posts: 203
Posted: 03:53pm 23 Jun 2017
Copy link to clipboard 
Print this post

One point with Geoff's FIELD$ code, I bring up for discussion,
especially if it were to be re-introduced into MMBasic.
FIELD$ should return ALL characters between delimiters.

My view is that the "trim leading and trailing spaces" code
at the bottom should not exist in the function.
The coder should be responsible for removing unwanted
white space if and when required.

Miss you George
 
Geoffg

Guru

Joined: 06/06/2011
Location: Australia
Posts: 3165
Posted: 05:28pm 23 Jun 2017
Copy link to clipboard 
Print this post

Yep, I fully agree. I debated it with myself before putting it in but should have left the Trim$() function as separate.

Geoff
Geoff Graham - http://geoffg.net
 
CaptainBoing

Guru

Joined: 07/09/2016
Location: United Kingdom
Posts: 1985
Posted: 11:27pm 23 Jun 2017
Copy link to clipboard 
Print this post

  led-bloon said  
FIELD$ should return ALL characters between delimiters.

yes this is really important. If the firmware starts hiding stuff trying to be helpful (with the best intentions), it can still bite you in the rear.

One famous one in VB was forcing the password for the MSFTP ActiveX object into lower case caused a few WTF moments when first discovered in the early 90's
 
     Page 2 of 2    
Print this page


To reply to this topic, you need to log in.

© JAQ Software 2024