Forum: Mikrocontroller und Digitale Elektronik Lookupstr - Bascom


von Manfred S. (Firma: Manfred) (xfred343)


Lesenswert?

Hallo,
hab folgendes Problem in Bascom:
ich möchte den Data-Header auslesen, exakt 7 Bytes, es soll aber mit der 
Variablen i ein beliebiger Header ausgelesen werden.
Kann die Stringlänge beim Lesezugriff beschränkt werden?
1
sub test
2
dim strHeader as string*8
3
i=1
4
strHeader=lookupstr(i,DATEN)
5
strHeader=left(lookupstr(i,DATEN),7) 'geht nicht!
6
print strHeader 'ist 255 Zeichen lang, leider.. und überschreibt vlt. was
7
8
DATEN:
9
DATA "Header1: Das sind bis zu 255 Bytes Daten.."
10
DATA "Head  2: Das sind bis zu 255 Bytes Daten.."
11
DATA "Head 3 : wieder bis zu 255 Bytes.."

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Da wirst Du mit einem temporären Zwischenstring arbeiten müssen. Bascom 
kennt keine komplexen Ausdrücke, und
1
strHeader=left(lookupstr(i,DATEN),7)
ist aus Bascom-Sicht wohl schon komplex.

von Karl (Gast)


Lesenswert?

Ja, eins nach dem anderen:

strHeader=lookupstr(i,DATEN)
strHeader=left(strHeader,7)

von Karl H. (kbuchegg)


Lesenswert?

Hmmm
1
DATEN:
2
DATA "Header1: Das sind bis zu 255 Bytes Daten.."

Sind das jetzt Strings im eigentlichen Sinne, oder doch eher Bytes? Wie 
du schon gesehen hast, sind Strings da anscheinend nicht unbedingt das 
Wahre.

von Manfred S. (Firma: Manfred) (xfred343)


Lesenswert?

Schönen Abend,

danke für das Feedback - also mit reinen Bytes ist es mühsam.
es sind Strings für RTTTL-Klingeltöne, die erste Sequenz ist dabei der 
Name des Liedes:

z.B.
1
Musik:
2
Data "Pac Man :d=4,o=5,b=112:32b,32p,32b6,32p,32f#6,32p,32d#6,32p,32b6,32f#6,16p,16d#6,16p,32c6,32p,32c7,32p,32g6,32p,32e6,32p,32c7,32g6,16p,16e6,16p,32b,32p,32b6,32p,32f#6,32p,32d#6,32p,32b6,32f#6,16p,16d#6,16p,32d#6,32e6,32f6,32p,32f6,32f#6,32g6"
3
Data "Simpsons:d=4,o=5,b=160:c.6,e6,f#6,8a6,g.6,e6,c6,8a,8f#,8f#,8f#,2g"
4
Data "Flintsto:d=4,o=5,b=200:g#,c#,8p,c#6,8a#,g#,c#,8p,g#,8f#,8f,8f,8f#,8g#,c#,d#,2f"

Mit Hilfe von strlookup möchte ich jeweils den Songtitel zu einer 
Songnummer ausgeben.
Hab schon mit loadlabel versucht, aber der liefert mir nur die 
Startadresse von Musik, nicht aber die Adresse zu einer beliebigen 
Songnummer..

So bleibt mir nichts anderes übrig, als die max. 255 Zeichen in eine 
strtemp-Variable (dim strtemp als string*255) zu laden und dann die 
ersten 7 Zeichen abzuschneiden..
dumm eigentlich, aber es dürfte nicht anders gehen.

Bascom ist zwar sehr gut, aber die Pointer vermisse ich immer mehr...

von Karl H. (kbuchegg)


Lesenswert?

Manfred S. schrieb:

>
1
> Musik:
2
> Data "Pac Man
3
> :d=4,o=5,b=112:32b,32p,32b6,32p,32f#6,32p,32d#6,32p,32b6,32f#6,16p,16d#6,16p,32c6,32p,32c7,32p,32g6,32p,32e6,32p,32c7,32g6,16p,16e6,16p,32b,32p,32b6,32p,32f#6,32p,32d#6,32p,32b6,32f#6,16p,16d#6,16p,32d#6,32e6,32f6,32p,32f6,32f#6,32g6"
4
> Data "Simpsons:d=4,o=5,b=160:c.6,e6,f#6,8a6,g.6,e6,c6,8a,8f#,8f#,8f#,2g"
5
> Data
6
> "Flintsto:d=4,o=5,b=200:g#,c#,8p,c#6,8a#,g#,c#,8p,g#,8f#,8f,8f,8f#,8g#,c#,d#,2f"
7
>
>
> Mit Hilfe von strlookup möchte ich jeweils den Songtitel zu einer
> Songnummer ausgeben.

OK.
Was spricht dagegen, pro Song einfach 2 Data-Zeilen zu benutzen?
1
Musik:
2
  Data "Pac Man"
3
  Data "d=4,o=5,b=112:32b,32p,32b6,32p,32f#6,32p,32d#6,32p,32b6,32f#6,16p,16d#6,16p,32c6,32p,32c7,32p,32g6,32p,32e6,32p,32c7,32g6,16p,16e6,16p,32b,32p,32b6,32p,32f#6,32p,32d#6,32p,32b6,32f#6,16p,16d#6,16p,32d#6,32e6,32f6,32p,32f6,32f#6,32g6"
4
  Data "Simpsons"
5
  Data "d=4,o=5,b=160:c.6,e6,f#6,8a6,g.6,e6,c6,8a,8f#,8f#,8f#,2g"
6
  Data "Flintsto"
7
  Data "d=4,o=5,b=200:g#,c#,8p,c#6,8a#,g#,c#,8p,g#,8f#,8f,8f,8f#,8g#,c#,d#,2f"

Der Song mit der Nummer i beginnt dann beim Data mit der Nummer 2*i. 
Wobei unter 2*i der Titel zu finden ist und die Songbeschreibung unter 
2*i+1

(i bei 0 beginnend; weiss nicht, wie das bei BASCOM geregelt ist. 
Schlimmsten Falls muss man dann eben noch einmal 1 dazuzählen, wenn da 
bei 1 angefangen wird zu zählen)

Und wenn ich mir da die Daten so ansehe, dann scheint es da noch eine 
Unterteilung zu geben. -> 3 Data Zeilen pro Song.
1
Musik:
2
  Data "Pac Man"
3
  Data "d=4,o=5,b=112"
4
  Data "32b,32p,32b6,32p,32f#6,32p,32d#6,32p,32b6,32f#6,16p,16d#6,16p,32c6,32p,32c7,32p,32g6,32p,32e6,32p,32c7,32g6,16p,16e6,16p,32b,32p,32b6,32p,32f#6,32p,32d#6,32p,32b6,32f#6,16p,16d#6,16p,32d#6,32e6,32f6,32p,32f6,32f#6,32g6"
5
6
  Data "Simpsons"
7
  Data "d=4,o=5,b=160"
8
  Data "c.6,e6,f#6,8a6,g.6,e6,c6,8a,8f#,8f#,8f#,2g"
9
10
  Data "Flintsto"
11
  Data "d=4,o=5,b=200"
12
  Data "g#,c#,8p,c#6,8a#,g#,c#,8p,g#,8f#,8f,8f,8f#,8g#,c#,d#,2f"

Das lässt sich doch alles aus der Songnummer errechnen, wo die 
jeweiligen Daten dazu anfangen.

von Manfred S. (Firma: Manfred) (xfred343)


Lesenswert?

Guten Morgen,

ja - danke für die Tipps, mein Parser zerlegt den String dann zwar 
ohnedies in die 3 Teile und es ist sicher ein "workaround" mit den 3 
Data-Zeilen, aber ich wollte eine "echte" Lösung:

Zwei Schwächen gibts hier in Bascom:
1) ich kann nicht die Startadresse der Datazeile finden, so quasi ein 
Befehl lookupadr fehlt
2) wenn die Variable kürzer ist als der Data-String, wird einfach der 
nachfolgende Speicher überschrieben.
Da ist schon das Beispiel von Mark aus der Hilfe gefährlich, er nimmt 
zwar Original Idx=0, aber bei Idx=2 "krachts":
1
$hwstack = 32            
2
$swstack = 10
3
$framesize = 40                                             
4
Dim S As String * 4 , Idx As Byte
5
Idx = 2 : S = Lookupstr(idx , Sdata)
6
Print S
7
PRINT IDX 'ist 116!!                                                      
8
End
9
Sdata:
10
Data "This" , "is" , "a test"

Wenn ich für IDX=2 nehme, werden - obwohl S nur mit 4 Byte definiert ist 
- 5 Bytes angezeigt (und die nachfolgende Variable wird überschrieben)
Danach hat Idx den Wert 116 (den Ascii-Code von t = letzter Buchstabe 
von "a test") !!!

Das mag was für Trickprogrammierer sein - aber nix für 
Otto-Normalprogrammierer.

von MWS (Gast)


Lesenswert?

Manfred S. schrieb:
> Das mag was für Trickprogrammierer sein - aber nix für
> Otto-Normalprogrammierer.

Array Overflows sind nichts für Trick-Programmierer, sondern das ist bei 
Null-terminierten Strings so, dass nachfolgende Variablen überschrieben 
werden können.

Die Größeninformation der Variablen ist nur zur Kompilierzeit bekannt. 
Wenn eine Bereichsüberprüfung stattfinden soll, dann muss der User a) 
diese Information dem Code zur Verfügung stellen und b) entsprechenden 
Code zum Schutz vor Bereichsüberprüfung selbst bereitstellen.

Die Verwendung von Lookupstr() um sich durch solche Monsterstrings 
durchzuhangeln ist sowieso maximal ineffektiv.

Statt einen String mit 'ner Riesenzeile zu laden und damit sowohl 'ne 
Menge SRam zu benutzen, als auch eine unnötige Kopieraktion zu haben, 
schreit sowas nach einem Parser, der den Flash Zeichenweise durchgeht.

Es gibt dazu Bascom-Befehle, welche die Adresse des Labels und damit des 
Strings ermitteln können und es gibt Befehle um aus dem Flash zu lesen.
Das ist dann der gewünschte Zeiger.

Effektiveren Zugriff auf die einzelnen Strings könnte man auch über 
einen Label-Index machen.
1
$Regfile = "m32def.dat"
2
$Crystal = 8000000
3
$hwstack = 40
4
$swstack = 16
5
$framesize = 32
6
$baud = 9600
7
8
dim str_ptr as word
9
dim rtd_flash_byte as byte
10
11
restore lbl_linklist
12
13
Do
14
  read str_ptr
15
    if Str_Ptr = 0 then
16
      restore lbl_linklist
17
    else
18
      rtd_flash_byte = cpeek(str_ptr)
19
        while rtd_flash_byte <> 0
20
          print chr(rtd_flash_byte) ;
21
            incr str_ptr
22
              rtd_flash_byte = cpeek(str_ptr)
23
        wend
24
          print
25
Loop
26
end
27
28
lbl_linklist:
29
  adr2 lbl_1
30
  adr2 lbl_2
31
  adr2 lbl_3
32
  adr2 lbl_4
33
  adr2 lbl_5
34
  data 0%
35
36
lbl_1:
37
  data "This"
38
lbl_2:
39
  data "is"
40
lbl_3:
41
  data "my"
42
lbl_4:
43
  data "Hello"
44
lbl_5:
45
  data "World"
Dieser Code läss sich im Simulator ausprobieren.

Und auch Otto-Normalprogrammierer darf seine graue Grütze benutzen, um 
alle Möglichkeiten der jeweiligen Programmiersprache auszunutzen. :D

von Manfred S. (Firma: Manfred) (xfred343)


Lesenswert?

Hallo,

das mit ADR2 ist super!
Das hätte ich schon oft brauchen können, hab dafür immer
"Select-Case und loadlabel" verwendet

Dein Code funktioniert (bis auf das fehlende EndIf ;-))
Hab jetzt eine Sub-daraus gebaut, die einen String beliebiger Länge
ausliest.

Kann man das auch als Funktion mit String-Rückgabe schreiben?
Da scheitere ich noch
1
$regfile = "m32def.dat"
2
$Crystal = 8000000
3
$hwstack = 40
4
$swstack = 40
5
$framesize = 32
6
$baud = 9600
7
Dim Strtxt As String * 20
8
Dim Strtxtbytes(21) As Byte At Strtxt Overlay
9
Declare Sub Slooku pstr(byval Bytpos As Byte , Byref Strtxtbytes(1) As Byte , Byval Bytlen As Byte )
10
Call Slookupstr(2 , Strtxtbytes(1) , 10) '10 Zeichen
11
Print Strtxt
12
Call Slookupstr(3 , Strtxtbytes(1) , 20) '20 Zeichen
13
Print Strtxt
14
End
15
16
Sub Slookupstr(byval Bytpos As Byte , Byref Strtxtbytes(1) As Byte , Byval Bytlen As Byte )
17
Restore Lbl_linklist
18
Local Str_ptr As Word
19
Local I As Byte
20
For I = 0 To Bytpos
21
   Read Str_ptr
22
Next I
23
For I = 1 To Bytlen
24
   Strtxtbytes(i) = Cpeek(str_ptr)
25
   If Strtxtbytes(i) = 0 Then Exit For
26
   Incr Str_ptr
27
Next I
28
Strtxtbytes(i) = 0
29
End Sub
30
31
Lbl_linklist:
32
  adr2 lbl_1
33
  adr2 lbl_2
34
  adr2 lbl_3
35
  adr2 lbl_4
36
  adr2 lbl_5
37
  data 0%
38
39
lbl_1:
40
  data "This"
41
lbl_2:
42
  data "is"
43
lbl_3:
44
  Data "my Data is longer than 10 chars"
45
lbl_4:
46
  Data "Hello this is longer than 20 chars"
47
lbl_5:
48
  data "World"

von MWS (Gast)


Lesenswert?

Manfred S. schrieb:
> Dein Code funktioniert

Ja, wusste ich, da's getestet war.

> (bis auf das fehlende EndIf ;-))

Ging unbeabsichtigt beim Einfügen/Editieren verloren.

> Kann man das auch als Funktion mit String-Rückgabe schreiben?
1
$framesize = 64
2
'...
3
Print Slookupstr(3 , Strtxtbytes(1) , 20)       '20 Zeichen
4
'...
5
function Slookupstr(byval Bytpos As Byte , Strtxtbytes(1) As Byte , Byval Bytlen As Byte ) As String
6
Local loc_str As String * 30
7
Dim chr_val As Byte
8
Local Str_ptr As Word
9
Local I As Byte
10
  Restore Lbl_linklist
11
    For I = 0 To Bytpos
12
      Read Str_ptr
13
    Next I
14
  loc_str = ""
15
    For I = 1 To Bytlen
16
      chr_val = Cpeek(str_ptr) : loc_str = loc_str + Chr(chr_val)
17
        If chr_val = 0 Then Exit For
18
      Incr Str_ptr
19
    Next I
20
  Slookupstr = loc_str
21
End function
Locale Variablen landen im Frame, der muss deshalb groß genug sein, 
$framesize entsprechend anpassen.
Der globale String mit Overlay würde ggf. wirtschaftlicher arbeiten, da 
dort nicht nochmal vom Frame umkopiert werden muss.

von MWS (Gast)


Lesenswert?

Das nun überflüssige Strtxtbytes(1) noch überall entfernen.

von Manfred S. (Firma: Manfred) (xfred343)


Lesenswert?

Hallo, Mahlzeit,

super - ja das klappt -
hab das Ganze noch etwas "verfeiner" - naja zumindest im Simulator 
läufts
(bin selbst überrascht, dass es funktioniert ;-))
Ich weiß jetzt nicht, ob das noch etwas Performance bringt.
1
$regfile = "m32def.dat"
2
$Crystal = 8000000
3
$hwstack = 40
4
$swstack = 40
5
$framesize = 80
6
$baud = 9600
7
Declare Function Fxlookupstr(byval Bytpos As Byte , Byval Bytlen As Byte ) As String * 30
8
Print Fxlookupstr(2 , 10)                                   '10 Zeichen
9
Print Fxlookupstr(3 , 20)                                   '20 Zeichen
10
End
11
12
Function Fxlookupstr(byval Bytpos As Byte , Byval Bytlen As Byte ) As String * 30
13
Restore Lbl_linklist
14
Local Str_ptr As Word
15
Local I As Byte
16
Local Wrdadr As Word
17
Local Byt As Byte
18
For I = 0 To Bytpos
19
   Read Str_ptr
20
Next I
21
Wrdadr = Varptr(fxlookupstr)
22
For I = 1 To Bytlen
23
   Byt = Cpeek(str_ptr)
24
   Out Wrdadr , Byt
25
   Incr Wrdadr
26
   Incr Str_ptr
27
   If Byt = 0 Then Exit Function
28
Next I
29
Out Wrdadr , 0
30
End Function
31
32
Lbl_linklist:
33
  adr2 lbl_1
34
  adr2 lbl_2
35
  adr2 lbl_3
36
  adr2 lbl_4
37
  adr2 lbl_5
38
  data 0%
39
40
lbl_1:
41
  data "This"
42
lbl_2:
43
  data "is"
44
lbl_3:
45
  Data "my Data is longer than 10 chars"
46
lbl_4:
47
  Data "Hello this is longer than 20 chars"
48
lbl_5:
49
  data "World"

von MWS (Gast)


Lesenswert?

Manfred S. schrieb:
> Ich weiß jetzt nicht, ob das noch etwas Performance bringt.

Du sparst die Kopieraktion. Aber so richtig schnell ist's nicht.

Da Du ohne Trickprogrammiererei auskommen willst, ist das dann 
natürlich nix für Dich: :D
1
$regfile = "m32def.dat"
2
$Crystal = 8000000
3
$hwstack = 40
4
$swstack = 40
5
$framesize = 64
6
$baud = 9600
7
8
$external _LookUpStr
9
$external _Lpmbyte
10
Dim idx As Byte
11
Dim lng As Byte
12
Dim lup_str As String * 20
13
14
idx = 2
15
lng = 20
16
17
loadwordadr lbl_block
18
  !LDS  R24,      {idx}
19
  !CLR  R25
20
  !CALL _LookUpStr
21
loadadr lup_str , X
22
  !LDS  R22,      {lng}
23
!loop:
24
  !CALL _Lpmbyte
25
  !BREQ str_end
26
  !ST   X+,       R0
27
  !DEC  R22
28
  !BRNE loop
29
!str_end:
30
  !CLR  R22
31
  !ST   X,        R22
32
33
  Print lup_str
34
35
End
36
37
lbl_block:
38
  data "This"
39
  data "is"
40
  Data "my Data is longer than 10 chars"
41
  Data "Hello this is longer than 20 chars"
42
  data "World"
Das entspricht der normalen Vorgehensweise des Lookupstr(), also sich 
über die Stringendzeichen durchzuhangeln. Schlägt aufgrund des 
Assembleraufbaus natürlich auch eine Indexliste.

Und noch'n Hinweis; die Strings dürfen hier innerhalb des Blocks keine 
weiteren Labels haben, denn dann kann's sein, dass der Compiler auf Word 
aligned und eine 0 einfügt, die dann falsch interpretiert würde.

von Manfred S. (Firma: Manfred) (xfred343)


Lesenswert?

Sorry, bin erst jetzt zum Analysieren gekommen -
muss sagen, einfach genial - jetzt brauch ich auch keine Labels mehr und 
das ist exakt die Funktion, die ich benötigt habe.

Hab mir auch die dazugehörigen Routinen in der mcs.lib angesehen, da 
wird ja Bascom noch viel interessanter.

Der Assembler dieser Harvard-Architektur ist schon genial und viel 
einfacher als bei den Klassikern 6502, 8080 usw. die Pointer sind hier 
schön verständlich..

Ist zwar offtopic:
Wo gibts mehr Infos bzw. gute Tutorials, welche Register Bascom belegt 
und welche frei sind? Da muss ich unbedingt tiefer einsteigen

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.