home *** CD-ROM | disk | FTP | other *** search
- UNIT cct; {$project vt }
- { Programmierung des CCT-Chips (Computer Controlled Teletext) SAA5246 }
-
- INTERFACE; FROM vt USES global;
- {$incl "i2c.lib" }
-
- CONST maxerror=9;
- VAR i2c_error: ARRAY[0..maxerror] OF String[30];
- VAR i2c_status: Integer;
- VAR aktspeicher: Integer; { der Speicher, in dem die VT-Uhr läuft }
-
- PROCEDURE display_select(speicher: Byte);
- PROCEDURE TV_display(mode: Byte);
- FUNCTION VTstat: Byte;
- PROCEDURE sperren(speicher: Byte);
- PROCEDURE anfordern(speicher: Byte; page, subpage: Integer; mask: Byte);
- PROCEDURE init_CCT;
- FUNCTION seite_da(speicher: Byte): Boolean;
- PROCEDURE gettime(speicher: Byte; VAR zeit: Str80);
- PROCEDURE gethead(speicher: Byte; VAR head: Str80);
- PROCEDURE getpage(speicher: Byte; seite: p_onepage; ganz: Boolean);
- PROCEDURE add_sp_number(seite: p_onepage);
-
- { ---------------------------------------------------------------------- }
-
- IMPLEMENTATION;
-
- {$opt q,s+,i+ } { keine Laufzeitprüfungen außer Stack und Feldindizes }
-
- CONST SAA5246 = $22;
- PBLF = $20;
- DOCARE = $10;
- NOTHOLD = $08;
- SERMAG = $0800; { C11 }
-
- VAR i2cdata: ARRAY[1..20] OF Byte; { kleiner Puffer für Kommandos }
-
- PROCEDURE send(addr: Byte; anz: Word; buffer: Ptr);
- { Dummy-Prozedur, um den Fehler "keine Library" aufzufangen }
- BEGIN
- IF I2CBase=Nil THEN
- i2c_status := maxerror
- ELSE
- i2c_status := (SendI2C(addr,anz,buffer) SHR 8) AND $FF;
- END;
-
- PROCEDURE receive(addr: Byte; anz: Word; buffer: Ptr);
- BEGIN
- IF I2CBase=Nil THEN
- i2c_status := maxerror
- ELSE
- i2c_status := (ReceiveI2C(addr,anz,buffer) SHR 8) AND $FF;
- END;
-
- PROCEDURE setregister(addr,reg,value: Byte);
- { Häufig benötigter Vorgang: ein einzelnes Register am I²C-Bus beschreiben. }
- BEGIN
- i2cdata[1] := reg; i2cdata[2] := value;
- send(addr,2,^i2cdata);
- END;
-
- FUNCTION getregister(addr,reg: Byte): Byte;
- { Etwas umständlicher, wird auch seltener benötigt: ein einzelnes Register }
- { auslesen. NICHT schleifenweise aufrufen, um mehrere Bytes zu lesen! }
- BEGIN
- send(addr,1,^reg);
- receive(addr,1,^i2cdata);
- getregister := i2cdata[1];
- END;
-
- PROCEDURE display_select{(speicher: Byte)};
- { Einen der 8 Seitenspeicher zur Anzeige auswählen }
- BEGIN
- setregister(SAA5246,4,speicher);
- END;
-
- PROCEDURE TV_display{(mode: Byte)};
- { Art der Anzeige am Fernseher auswählen. }
- BEGIN
- i2cdata[1] := 5;
- CASE mode OF
- 2: { Normalseiten bildfüllend, Schlagzeilen als Boxen }
- BEGIN i2cdata[2] := %11001100; i2cdata[3] := %01001111; END;
- 1: { Normalseiten als Boxen, Schlagzeilen transparent }
- BEGIN i2cdata[2] := %11001111; i2cdata[3] := %00001111; END;
- OTHERWISE { Anzeige aus }
- BEGIN i2cdata[2] := %00000011; i2cdata[3] := %00000011; END;
- END;
- i2cdata[4] := %00000111;
- send(SAA5246,4,^i2cdata);
- END;
-
- FUNCTION VTstat{: Byte};
- { Liest aus dem CCT das Register R11B. Bedeutung: bit0 - Videosignal vorh., }
- { bit1 - Textsignal vorh., bit2-5 - ROM-Version }
- BEGIN
- setregister(SAA5246,0,%00000001); { R11B aktivieren }
- VTstat := getregister(SAA5246,11); { Status lesen }
- setregister(SAA5246,0,%00000000); { R11 aktivieren }
- END;
-
- PROCEDURE sperren{(speicher: Byte)};
- { Seitensuche eines Empfangskreises anhalten, damit nicht evtl. niederpriore }
- { Empfangskreise behindert werden. Die Sperre wird bei Programmierung einer }
- { neuen Seitenanforderung automatisch aufgehoben. }
- BEGIN
- i2cdata[1] := 2;
- i2cdata[2] := speicher*16;
- i2cdata[3] := 0;
- send(SAA5246,3,^i2cdata);
- END;
-
- PROCEDURE anfordern{(speicher: Byte; page, subpage: Integer; mask: Byte)};
- { Einlesen einer Seite in einen Seitenspeicher 0..7 anfordern, Unterseite nur }
- { direkt anfordern, wenn subpage > 0 }
- { <mask> ist eine dreistellige Binärzahl, wo eine '0' steht, wird in der }
- { entsprechenden Ziffer der angeforderten Seitennummer das DOCARE-Bit }
- { gelöscht. }
- VAR lauf: Integer;
- BEGIN
- { Seitenanforderung beschreiben: }
- i2cdata[1] := 2;
- i2cdata[2] := speicher*16;
- i2cdata[3] := ((page SHR 8) AND $7) OR NOTHOLD;
- i2cdata[4] := (page SHR 4) AND $F;
- i2cdata[5] := page AND $F;
- IF page > 0 THEN
- FOR lauf := 3 TO 5 DO
- IF Odd(mask SHR (5-lauf)) THEN
- i2cdata[lauf] := i2cdata[lauf] OR DOCARE;
- i2cdata[6] := (subpage SHR 12) AND $3;
- i2cdata[7] := (subpage SHR 8) AND $F;
- i2cdata[8] := (subpage SHR 4) AND $7
- i2cdata[9] := subpage AND $F;
- IF subpage > 0 THEN
- FOR lauf := 6 TO 9 DO i2cdata[lauf] := i2cdata[lauf] OR DOCARE;
- send(SAA5246,9,^i2cdata);
- END;
-
- PROCEDURE init_CCT;
- VAR i: Byte;
- BEGIN
- { Wichtig in R1: bit5 - ACQ OFF, Decoder-NotAus; bit2 - TCS ON, }
- { RGB-Ausgangssignal wird mit Fernsehbild synchronisiert. }
- setregister(SAA5246,1,%00000100);
- { Seitensuche sperren: }
- FOR i := 0 TO maxactive-1 DO BEGIN
- sperren(i); activejobs[i].pg := 0;
- END;
- { alle Seitenspeicher löschen: }
- FOR i := 0 TO 7 DO BEGIN
- setregister(SAA5246,8,%00001000 OR i); Delay(2);
- { Löschvorgang dauert bis zu 22 ms, darum mal jeweils 40 ms warten. }
- END;
- { R11 aktivieren }
- setregister(SAA5246,0,%00000000);
- { Fernsehdarstellung einschalten }
- display_select(0);
- TV_display(2);
- END;
-
- FUNCTION seite_da{(speicher: Byte): Boolean};
- { Überprüft, ob die für einen Speicher 0..7 angeforderte Seite bereits }
- { eingetroffen ist. Das Statusflag PBLF, das in diesem Fall gelöscht ist, }
- { muß danach wieder gesetzt werden. Das geschieht entweder implizit beim }
- { Programmieren einer neuen Seitenanforderung oder explizit durch }
- { Schreibzugriff, in diesem Programm in getpage(). }
- { Problem: das Statusflag PBLF bezieht sich auf den Empfang der Kopfzeile, }
- { nicht etwa den Empfang der kompletten Seite. Genauer gesagt: für letzteres }
- { existiert überhaupt kein Statusflag! }
- { Nun ist das nicht ganz so tragisch, nach Empfang der Kopfzeile kann man }
- { bereits bedenkenlos die Statuszeile 25 mit Steuerbits und Seitennummer }
- { lesen. Und in vielen Fällen geht es sogar gut, sofort mit dem Einlesen }
- { der gesamten Seite zu beginnen, da sich nämlich maximal 11 Seiten pro }
- { Sekunde über den I²C-Bus schaufeln lassen, während der Videotext selbst }
- { mit ca. 13 Seiten pro Sekunde einrollt: Die noch leere Seite wird }
- { schneller aufgefüllt, als sie ausgelesen werden kann. }
- { Probleme entstehen natürlich, wenn der Empfang der VT-Seite länger als }
- { ca. 1/10 s dauert. Das ist möglich, wenn der Sender nicht alle zur }
- { VT-Übertragung zulässigen Rasterzeilen ausnutzt, oder wenn er gar den }
- { Magazin-gemischten Übertragungsmodus verwendet. Letzteres ist aber an }
- { einem Statusflag (C11) vom Programm aus erkennbar, hm ... }
- BEGIN
- seite_da := False;
- { Byte 9 der Statuszeile (Zeile 25) adressieren ... }
- i2cdata[1] := 8;
- i2cdata[2] := speicher;
- i2cdata[3] := 25; i2cdata[4] := 9;
- send(SAA5246,4,^i2cdata);
- IF i2c_status<>0 THEN Exit;
- { ... und auslesen: }
- receive(SAA5246,1,^i2cdata);
- IF i2c_status<>0 THEN Exit;
- seite_da := (i2cdata[1] AND PBLF)=0;
- END;
-
- PROCEDURE gettime{(speicher: Byte; VAR zeit: Str80)};
- { liest aus einer Speicherseite 0..7 des CCT-Bausteins die Uhrzeit }
- VAR i: Integer;
- BEGIN
- zeit := ' ';
- { Uhrzeit aus der Seite im CCT lesen: Zeile 0, Spalte 32 }
- i2cdata[1] := 8;
- i2cdata[2] := speicher;
- i2cdata[3] := 0; i2cdata[4] := 32;
- send(SAA5246,4,^i2cdata);
- IF i2c_status<>0 THEN Exit;
- { Uhrzeit lesen: }
- receive(SAA5246,8,^i2cdata);
- IF i2c_status<>0 THEN Exit;
- FOR i := 1 TO 8 DO
- IF i2cdata[i] IN [32..127] THEN zeit[i] := Chr(i2cdata[i]);
- END;
-
- PROCEDURE gethead{(speicher: Byte; VAR head: Str80)};
- { liest die 24 Byte Titelzeile zwischen Statusfeld und Uhrzeit }
- VAR i: Integer;
- BEGIN
- head := '';
- { Seitenspeicher addressieren: Zeile 0, Spalte 8 }
- i2cdata[1] := 8;
- i2cdata[2] := speicher;
- i2cdata[3] := 0; i2cdata[4] := 8;
- send(SAA5246,4,^i2cdata);
- IF i2c_status<>0 THEN Exit;
- { Zeile lesen: }
- receive(SAA5246,24,^head);
- IF i2c_status<>0 THEN Exit;
- FOR i := 1 TO 24 DO
- IF NOT (Ord(head[i]) IN [32..127]) THEN head[i] := ' ';
- head[25] := #0;
- END;
-
- PROCEDURE getpage{(speicher: Byte; seite: p_onepage; ganz: Boolean)};
- { Liest eine Speicherseite (0..7) aus dem CCT-Baustein aus und speichert }
- { diese Seite im Amiga. Für <ganz>=false werden nur die Statusinformationen }
- { aus Zeile 25 gelesen. }
- VAR i,h: Integer;
- status: ARRAY [0..9] OF Byte;
- s: str80;
- BEGIN
- seite^.pg := 0; seite^.sp := 0; seite^.cbits := 0;
- { Status aus der Seite im CCT lesen: Zeile 25, Spalte 0 }
- i2cdata[1] := 8;
- i2cdata[2] := speicher;
- i2cdata[3] := 25; i2cdata[4] := 0;
- send(SAA5246,4,^i2cdata);
- IF i2c_status<>0 THEN Exit;
- receive(SAA5246,10,^status);
- IF i2c_status<>0 THEN Exit;
- seite^.pg := (status[0] AND $F) + (status[1] AND $F) SHL 4
- + (status[8] AND $7) SHL 8;
- IF seite^.pg<$100 THEN seite^.pg := seite^.pg + $800;
- seite^.sp := (status[2] AND $F) + (status[3] AND $7) SHL 4
- + (status[4] AND $F) SHL 8 + (status[5] AND $3) SHL 12;
- seite^.cbits := (status[3] AND $08) SHL 1 { C4 }
- + (status[5] AND $0C) SHL 3 { C5, C6 }
- + (status[6] AND $0F) SHL 7 { C7, C8, C9, C10 }
- + (status[7] AND $0F) SHL 11 { C11, C12..C14 }
- IF ganz THEN BEGIN
- seite^.dejavu := False; { als Neuigkeit kennzeichnen }
- { Seite einlesen. Richtigen Speicher, Zeile 0, Spalte 0 adressieren: }
- i2cdata[1] := 8;
- i2cdata[2] := speicher;
- i2cdata[3] := 0; i2cdata[4] := 0;
- send(SAA5246,4,^i2cdata);
- IF i2c_status<>0 THEN Exit;
- { Seite einlesen: }
- receive(SAA5246,960,^seite^.chars);
- IF i2c_status<>0 THEN Exit;
- { aus dem zur Anzeige aktivierten Seitenspeicher die Uhrzeit holen: }
- IF speicher<>aktspeicher THEN BEGIN
- gettime(aktspeicher,s);
- FOR i := 1 TO 8 DO
- seite^.chars[31+i] := Ord(s[i]);
- END;
- END;
- END;
-
- PROCEDURE add_sp_number{(seite: p_onepage)};
- { In den freien Anfang der 1. Zeile die Unterseitennummer eintragen, }
- { greift zwar nicht auf den I²C-Bus zu, gehört aber eng zu getpage() dazu. }
- VAR i: Integer;
- s: str80;
- BEGIN
- s := '('+hexstr(seite^.sp,4)+') ';
- IF (seite^.cbits AND SERMAG)=0 THEN BEGIN { Magazin-gemischte Übertragung, }
- s[1] := '<'; s[6] := '>'; { Modus für den Benutzer erkennbar machen }
- END;
- FOR i := 1 TO 7 DO
- seite^.chars[i] := Ord(s[i]);
- END;
-
- LIBRARY SysBase:
- -414 : PROCEDURE CloseLibrary(A1: Ptr);
- -552 : FUNCTION OpenLibrary(A1: Str; D0: Long): Ptr;
- END;
-
- PROCEDURE retreat;
- BEGIN
- IF I2CBase<>Nil THEN CloseLibrary(I2CBase);
- END;
-
- VAR i: Integer;
-
- BEGIN { Initialisierungsteil }
- aktspeicher := 0;
- AddExitServer(retreat); I2CBase := OpenLibrary('i2c.library',39);
- FOR i := 0 TO maxerror-1 DO
- IF I2CBase<>Nil THEN i2c_error[i] := I2CErrText(i SHL 8)
- ELSE i2c_error[i] := '';
- i2c_error[maxerror] := 'need i2c.library V39+';
- END.
-