home *** CD-ROM | disk | FTP | other *** search
/ Amiga ISO Collection / AmigaUtilCD2.iso / Misc / VIDEOTEXT.LZX / VTsrc / cct.p < prev    next >
Encoding:
Text File  |  1996-02-28  |  10.5 KB  |  314 lines

  1. UNIT cct; {$project vt }
  2. { Programmierung des CCT-Chips (Computer Controlled Teletext) SAA5246 }
  3.  
  4. INTERFACE; FROM vt USES global;
  5. {$incl "i2c.lib" }
  6.  
  7. CONST maxerror=9;
  8. VAR i2c_error: ARRAY[0..maxerror] OF String[30];
  9. VAR i2c_status: Integer;
  10. VAR aktspeicher: Integer;   { der Speicher, in dem die VT-Uhr läuft }
  11.  
  12. PROCEDURE display_select(speicher: Byte);
  13. PROCEDURE TV_display(mode: Byte);
  14. FUNCTION VTstat: Byte;
  15. PROCEDURE sperren(speicher: Byte);
  16. PROCEDURE anfordern(speicher: Byte; page, subpage: Integer; mask: Byte);
  17. PROCEDURE init_CCT;
  18. FUNCTION seite_da(speicher: Byte): Boolean;
  19. PROCEDURE gettime(speicher: Byte; VAR zeit: Str80);
  20. PROCEDURE gethead(speicher: Byte; VAR head: Str80);
  21. PROCEDURE getpage(speicher: Byte; seite: p_onepage; ganz: Boolean);
  22. PROCEDURE add_sp_number(seite: p_onepage);
  23.  
  24. { ---------------------------------------------------------------------- }
  25.  
  26. IMPLEMENTATION;
  27.  
  28. {$opt q,s+,i+ } { keine Laufzeitprüfungen außer Stack und Feldindizes }
  29.  
  30. CONST SAA5246 = $22;
  31.       PBLF = $20;
  32.       DOCARE =  $10;
  33.       NOTHOLD = $08;
  34.       SERMAG = $0800; { C11 }
  35.  
  36. VAR i2cdata: ARRAY[1..20] OF Byte;    { kleiner Puffer für Kommandos }
  37.  
  38. PROCEDURE send(addr: Byte; anz: Word; buffer: Ptr);
  39. { Dummy-Prozedur, um den Fehler "keine Library" aufzufangen }
  40. BEGIN
  41.   IF I2CBase=Nil THEN
  42.     i2c_status := maxerror
  43.   ELSE
  44.     i2c_status := (SendI2C(addr,anz,buffer) SHR 8) AND $FF;
  45. END;
  46.  
  47. PROCEDURE receive(addr: Byte; anz: Word; buffer: Ptr);
  48. BEGIN
  49.   IF I2CBase=Nil THEN
  50.     i2c_status := maxerror
  51.   ELSE
  52.     i2c_status := (ReceiveI2C(addr,anz,buffer) SHR 8) AND $FF;
  53. END;
  54.  
  55. PROCEDURE setregister(addr,reg,value: Byte);
  56. { Häufig benötigter Vorgang: ein einzelnes Register am I²C-Bus beschreiben. }
  57. BEGIN
  58.   i2cdata[1] := reg; i2cdata[2] := value;
  59.   send(addr,2,^i2cdata);
  60. END;
  61.  
  62. FUNCTION getregister(addr,reg: Byte): Byte;
  63. { Etwas umständlicher, wird auch seltener benötigt: ein einzelnes Register }
  64. { auslesen. NICHT schleifenweise aufrufen, um mehrere Bytes zu lesen! }
  65. BEGIN
  66.   send(addr,1,^reg);
  67.   receive(addr,1,^i2cdata);
  68.   getregister := i2cdata[1];
  69. END;
  70.  
  71. PROCEDURE display_select{(speicher: Byte)};
  72. { Einen der 8 Seitenspeicher zur Anzeige auswählen }
  73. BEGIN
  74.   setregister(SAA5246,4,speicher);
  75. END;
  76.  
  77. PROCEDURE TV_display{(mode: Byte)};
  78. { Art der Anzeige am Fernseher auswählen. }
  79. BEGIN
  80.   i2cdata[1] := 5;
  81.   CASE mode OF
  82.     2: { Normalseiten bildfüllend, Schlagzeilen als Boxen }
  83.       BEGIN  i2cdata[2] := %11001100; i2cdata[3] := %01001111; END;
  84.     1: { Normalseiten als Boxen, Schlagzeilen transparent }
  85.       BEGIN  i2cdata[2] := %11001111; i2cdata[3] := %00001111; END;
  86.     OTHERWISE  { Anzeige aus }
  87.       BEGIN  i2cdata[2] := %00000011; i2cdata[3] := %00000011; END;
  88.   END;
  89.   i2cdata[4] := %00000111;
  90.   send(SAA5246,4,^i2cdata);
  91. END;
  92.  
  93. FUNCTION VTstat{: Byte};
  94. { Liest aus dem CCT das Register R11B. Bedeutung: bit0 - Videosignal vorh., }
  95. { bit1 - Textsignal vorh., bit2-5 - ROM-Version }
  96. BEGIN
  97.   setregister(SAA5246,0,%00000001);   { R11B aktivieren }
  98.   VTstat := getregister(SAA5246,11);    { Status lesen }
  99.   setregister(SAA5246,0,%00000000);   { R11 aktivieren }
  100. END;
  101.  
  102. PROCEDURE sperren{(speicher: Byte)};
  103. { Seitensuche eines Empfangskreises anhalten, damit nicht evtl. niederpriore }
  104. { Empfangskreise behindert werden. Die Sperre wird bei Programmierung einer }
  105. { neuen Seitenanforderung automatisch aufgehoben. }
  106. BEGIN
  107.   i2cdata[1] := 2;
  108.   i2cdata[2] := speicher*16;
  109.   i2cdata[3] := 0;
  110.   send(SAA5246,3,^i2cdata);
  111. END;
  112.  
  113. PROCEDURE anfordern{(speicher: Byte; page, subpage: Integer; mask: Byte)};
  114. { Einlesen einer Seite in einen Seitenspeicher 0..7 anfordern, Unterseite nur }
  115. { direkt anfordern, wenn subpage > 0 }
  116. { <mask> ist eine dreistellige Binärzahl, wo eine '0' steht, wird in der }
  117. { entsprechenden Ziffer der angeforderten Seitennummer das DOCARE-Bit }
  118. { gelöscht. }
  119. VAR lauf: Integer;
  120. BEGIN
  121.   { Seitenanforderung beschreiben: }
  122.   i2cdata[1] := 2;
  123.   i2cdata[2] := speicher*16;
  124.   i2cdata[3] := ((page SHR 8) AND $7) OR NOTHOLD;
  125.   i2cdata[4] := (page SHR 4) AND $F;
  126.   i2cdata[5] := page AND $F;
  127.   IF page > 0 THEN
  128.     FOR lauf := 3 TO 5 DO
  129.       IF Odd(mask SHR (5-lauf)) THEN
  130.         i2cdata[lauf] := i2cdata[lauf] OR DOCARE;
  131.   i2cdata[6] := (subpage SHR 12) AND $3;
  132.   i2cdata[7] := (subpage SHR 8) AND $F;
  133.   i2cdata[8] := (subpage SHR 4) AND $7
  134.   i2cdata[9] := subpage AND $F;
  135.   IF subpage > 0 THEN
  136.     FOR lauf := 6 TO 9 DO  i2cdata[lauf] := i2cdata[lauf] OR DOCARE;
  137.   send(SAA5246,9,^i2cdata);
  138. END;
  139.  
  140. PROCEDURE init_CCT;
  141. VAR i: Byte;
  142. BEGIN
  143.   { Wichtig in R1: bit5 - ACQ OFF, Decoder-NotAus; bit2 - TCS ON, }
  144.   { RGB-Ausgangssignal wird mit Fernsehbild synchronisiert. }
  145.   setregister(SAA5246,1,%00000100);
  146.   { Seitensuche sperren: }
  147.   FOR i := 0 TO maxactive-1 DO BEGIN
  148.     sperren(i); activejobs[i].pg := 0;
  149.   END;
  150.   { alle Seitenspeicher löschen: }
  151.   FOR i := 0 TO 7 DO BEGIN
  152.     setregister(SAA5246,8,%00001000 OR i); Delay(2);
  153.     { Löschvorgang dauert bis zu 22 ms, darum mal jeweils 40 ms warten. }
  154.   END;
  155.   { R11 aktivieren }
  156.   setregister(SAA5246,0,%00000000);
  157.   { Fernsehdarstellung einschalten }
  158.   display_select(0);
  159.   TV_display(2);
  160. END;
  161.  
  162. FUNCTION seite_da{(speicher: Byte): Boolean};
  163. { Überprüft, ob die für einen Speicher 0..7 angeforderte Seite bereits }
  164. { eingetroffen ist. Das Statusflag PBLF, das in diesem Fall gelöscht ist, }
  165. { muß danach wieder gesetzt werden. Das geschieht entweder implizit beim }
  166. { Programmieren einer neuen Seitenanforderung oder explizit durch }
  167. { Schreibzugriff, in diesem Programm in getpage(). }
  168. { Problem: das Statusflag PBLF bezieht sich auf den Empfang der Kopfzeile, }
  169. { nicht etwa den Empfang der kompletten Seite. Genauer gesagt: für letzteres }
  170. { existiert überhaupt kein Statusflag! }
  171. { Nun ist das nicht ganz so tragisch, nach Empfang der Kopfzeile kann man }
  172. { bereits bedenkenlos die Statuszeile 25 mit Steuerbits und Seitennummer }
  173. { lesen. Und in vielen Fällen geht es sogar gut, sofort mit dem Einlesen }
  174. { der gesamten Seite zu beginnen, da sich nämlich maximal 11 Seiten pro }
  175. { Sekunde über den I²C-Bus schaufeln lassen, während der Videotext selbst }
  176. { mit ca. 13 Seiten pro Sekunde einrollt: Die noch leere Seite wird }
  177. { schneller aufgefüllt, als sie ausgelesen werden kann. }
  178. { Probleme entstehen natürlich, wenn der Empfang der VT-Seite länger als }
  179. { ca. 1/10 s dauert. Das ist möglich, wenn der Sender nicht alle zur }
  180. { VT-Übertragung zulässigen Rasterzeilen ausnutzt, oder wenn er gar den }
  181. { Magazin-gemischten Übertragungsmodus verwendet. Letzteres ist aber an }
  182. { einem Statusflag (C11) vom Programm aus erkennbar, hm ... }
  183. BEGIN
  184.   seite_da := False;
  185.   { Byte 9 der Statuszeile (Zeile 25) adressieren ... }
  186.   i2cdata[1] := 8;
  187.   i2cdata[2] := speicher;
  188.   i2cdata[3] := 25; i2cdata[4] := 9;
  189.   send(SAA5246,4,^i2cdata);
  190.   IF i2c_status<>0 THEN Exit;
  191.   { ... und auslesen: }
  192.   receive(SAA5246,1,^i2cdata);
  193.   IF i2c_status<>0 THEN Exit;
  194.   seite_da := (i2cdata[1] AND PBLF)=0;
  195. END;
  196.  
  197. PROCEDURE gettime{(speicher: Byte; VAR zeit: Str80)};
  198. { liest aus einer Speicherseite 0..7 des CCT-Bausteins die Uhrzeit }
  199. VAR i: Integer;
  200. BEGIN
  201.   zeit := '        ';
  202.   { Uhrzeit aus der Seite im CCT lesen: Zeile 0, Spalte 32 }
  203.   i2cdata[1] := 8;
  204.   i2cdata[2] := speicher;
  205.   i2cdata[3] := 0; i2cdata[4] := 32;
  206.   send(SAA5246,4,^i2cdata);
  207.   IF i2c_status<>0 THEN Exit;
  208.   { Uhrzeit lesen: }
  209.   receive(SAA5246,8,^i2cdata);
  210.   IF i2c_status<>0 THEN Exit;
  211.   FOR i := 1 TO 8 DO
  212.     IF i2cdata[i] IN [32..127] THEN zeit[i] := Chr(i2cdata[i]);
  213. END;
  214.  
  215. PROCEDURE gethead{(speicher: Byte; VAR head: Str80)};
  216. { liest die 24 Byte Titelzeile zwischen Statusfeld und Uhrzeit }
  217. VAR i: Integer;
  218. BEGIN
  219.   head := '';
  220.   { Seitenspeicher addressieren: Zeile 0, Spalte 8 }
  221.   i2cdata[1] := 8;
  222.   i2cdata[2] := speicher;
  223.   i2cdata[3] := 0; i2cdata[4] := 8;
  224.   send(SAA5246,4,^i2cdata);
  225.   IF i2c_status<>0 THEN Exit;
  226.   { Zeile lesen: }
  227.   receive(SAA5246,24,^head);
  228.   IF i2c_status<>0 THEN Exit;
  229.   FOR i := 1 TO 24 DO
  230.     IF NOT (Ord(head[i]) IN [32..127]) THEN head[i] := ' ';
  231.   head[25] := #0;
  232. END;
  233.  
  234. PROCEDURE getpage{(speicher: Byte; seite: p_onepage; ganz: Boolean)};
  235. { Liest eine Speicherseite (0..7) aus dem CCT-Baustein aus und speichert }
  236. { diese Seite im Amiga. Für <ganz>=false werden nur die Statusinformationen }
  237. { aus Zeile 25 gelesen. }
  238. VAR i,h: Integer;
  239.     status: ARRAY [0..9] OF Byte;
  240.     s: str80;
  241. BEGIN
  242.   seite^.pg := 0; seite^.sp := 0; seite^.cbits := 0;
  243.   { Status aus der Seite im CCT lesen: Zeile 25, Spalte 0 }
  244.   i2cdata[1] := 8;
  245.   i2cdata[2] := speicher;
  246.   i2cdata[3] := 25; i2cdata[4] := 0;
  247.   send(SAA5246,4,^i2cdata);
  248.   IF i2c_status<>0 THEN Exit;
  249.   receive(SAA5246,10,^status);
  250.   IF i2c_status<>0 THEN Exit;
  251.   seite^.pg := (status[0] AND $F) + (status[1] AND $F) SHL 4
  252.                                   + (status[8] AND $7) SHL 8;
  253.   IF seite^.pg<$100 THEN seite^.pg := seite^.pg + $800;
  254.   seite^.sp := (status[2] AND $F)       + (status[3] AND $7) SHL 4
  255.              + (status[4] AND $F) SHL 8 + (status[5] AND $3) SHL 12;
  256.   seite^.cbits := (status[3] AND $08) SHL 1   { C4 }
  257.                 + (status[5] AND $0C) SHL 3   { C5, C6 }
  258.                 + (status[6] AND $0F) SHL 7   { C7, C8, C9, C10 }
  259.                 + (status[7] AND $0F) SHL 11  { C11, C12..C14 }
  260.   IF ganz THEN BEGIN
  261.     seite^.dejavu := False; { als Neuigkeit kennzeichnen }
  262.     { Seite einlesen. Richtigen Speicher, Zeile 0, Spalte 0 adressieren: }
  263.     i2cdata[1] := 8;
  264.     i2cdata[2] := speicher;
  265.     i2cdata[3] := 0; i2cdata[4] := 0;
  266.     send(SAA5246,4,^i2cdata);
  267.     IF i2c_status<>0 THEN Exit;
  268.     { Seite einlesen: }
  269.     receive(SAA5246,960,^seite^.chars);
  270.     IF i2c_status<>0 THEN Exit;
  271.     { aus dem zur Anzeige aktivierten Seitenspeicher die Uhrzeit holen: }
  272.     IF speicher<>aktspeicher THEN BEGIN
  273.       gettime(aktspeicher,s);
  274.       FOR i := 1 TO 8 DO
  275.         seite^.chars[31+i] := Ord(s[i]);
  276.     END;
  277.   END;
  278. END;
  279.  
  280. PROCEDURE add_sp_number{(seite: p_onepage)};
  281. { In den freien Anfang der 1. Zeile die Unterseitennummer eintragen, }
  282. { greift zwar nicht auf den I²C-Bus zu, gehört aber eng zu getpage() dazu. }
  283. VAR i: Integer;
  284.     s: str80;
  285. BEGIN
  286.   s := '('+hexstr(seite^.sp,4)+') ';
  287.   IF (seite^.cbits AND SERMAG)=0 THEN BEGIN { Magazin-gemischte Übertragung, }
  288.     s[1] := '<'; s[6] := '>';     { Modus für den Benutzer erkennbar machen }
  289.   END;
  290.   FOR i := 1 TO 7 DO
  291.     seite^.chars[i] := Ord(s[i]);
  292. END;
  293.  
  294. LIBRARY SysBase:
  295. -414 : PROCEDURE CloseLibrary(A1: Ptr);
  296. -552 : FUNCTION  OpenLibrary(A1: Str; D0: Long): Ptr;
  297. END;
  298.  
  299. PROCEDURE retreat;
  300. BEGIN
  301.   IF I2CBase<>Nil THEN CloseLibrary(I2CBase);
  302. END;
  303.                
  304. VAR i: Integer;
  305.  
  306. BEGIN  { Initialisierungsteil }
  307.   aktspeicher := 0;
  308.   AddExitServer(retreat); I2CBase := OpenLibrary('i2c.library',39);
  309.   FOR i := 0 TO maxerror-1 DO
  310.     IF I2CBase<>Nil THEN i2c_error[i] := I2CErrText(i SHL 8)
  311.     ELSE i2c_error[i] := '';
  312.   i2c_error[maxerror] := 'need i2c.library V39+';
  313. END.
  314.