<?
include "../mateslib.php";

top("URVC - ovladač kamer SBIG");
start_tbl("URVC - ovladač kamer SBIG");
?>

</center>
</center>
</center>
</center>
<h1>Abstrakt</h1>

Krom řečí o CCD detektorech se zde prezentuje alternativní ovladač CCD kamer
SBIG, včetně některých detailů jeho realizace. Člověka neastronomického asi
nejvíce zaujme část s popisem soft-realtime řešení
driveru. Člověka - astronoma tady nezaujme nic. Někoho,
kdo chce zdrojáky k SBIG kamerám pak zmínka, že
skutečně existují. 
<h1>Úvod</h1>

<p>URVC je program určený na ovládání astronomických CCD detektorů firmy SBIG.
Současné provedení poskytuje uživateli jednoduchou příkazovou řádku,
předpokládám však další postup, který bude spočívat v umožnění standardního
knihovního přístupu k funkcím, případně řešení ve formě jaderného ovladače,
které by eliminovalo nutnost rootích práv.</p>

<p>URVC vychází z existující knihovny pardrv, která není open source a volně
šiřitelná je pouze její zkompilovaná (neslinkrovaná) knihovna pardrv.a.
URVC sice doposud nedosahuje kompletní funkčnosti pardrv, její
nesrovnatelnou výhodou je ovšem dostupnost zdrojových textů a možnost
přizpůsobovat kód v případě potřeby.</p> 

<p>Cílovým přístrojem programu je robotický teleskop BART v Ondřejově.</p>

<h1>Motivace</h1>

<p>Původní motivací pro celou práci bylo umožnit implementaci driveru v
jednočipovém mikropočítači a umožnit přenos dat od teleskopu do počítače po
médiu, které nemá drastickou nevýhodu paralelního portu v totálním zahlcení
počítače I/O operacemi paralelního portu, které zahltí stejně starou
pomalou 286 jako poslední model Pentia šest. V úvahu padá buďto USB nebo
ethernet. Existuje sice možnost připojit kameru k dedikovanému (starému)
počítači, ale to neumožní vytoužené omezení množství datových kabelů
vedoucích na tubus z 50 na 4. (tak to asi dopadne)</p>

<h1>Licence</h1>

<p>URVC vzniklo zpětným inženýrstvím z pardrv, které je pod licencí SBIGu.
Vzniklo proto, že SBIG odmítl vydat specifikaci svého protokolu na
paralelním portu. Technologie je patentovaná. Přestože tedy URVC existuje,
nikdo ho asi nesmí používat. Ze stejného důvodu nesmí nejspíš nikdo číst
tento text. </p>

<center>
<BR>
<img src="st7.jpg"><BR>
Obrázek 1: CCD kamera SBIG
<BR><BR>
</center>

<h1>CCD detektor</h1>

<p>Astronomické CCD kamery od SBIGu jsou opravdu pěkné věcičky, schopnostmi
zdaleka předčí nejen obvykle dostupné vebové kamerky, ale i nejeden
digitální fotoaparát. Čeho se u nich ovšem člověk nedočká je barevná
detekce. Rozlišení největší kamery je 2184x1472, tj. 3M pixely (jak
počítají rozlišení komerčníci). Rozměry ostatních verzí jsou v tabulce:</p>

<center>
<BR>
<table border=1 rowspan=0 colspan=0>
<th>typ</th><th>rozlišení</th><th>vyčtení</th>
<tr><td>st7</td><td>768x512</td><td>13s</td></tr>
<tr><td>st8</td><td>1532x1024</td><td>50s</td></tr>
<tr><td>st9</td><td>512x512</td><td>9s</td></tr>
<tr><td>st10</td><td>2184x1472</td><td>100s</td></tr>
<tr><td>st1001</td><td>1024x1024</td><td>35s</td></tr>
</table><BR>
Tabulka 1: Rozlišení různých detektorů SBIG.
<BR><BR>
</center>

<p>Pro astronomy velmi podstatnou záležitostí je 16 bitová digitalizace obrazu.
Pro srovnání - digitální fotoaparáty používají obvykle 8 bitovou, vebkamerky
většinou 5 bitovou digitalizaci. 16 bitová digitalizace s co nejmenším šumem a
co nejlepší linearitou je důležitá na přesná fotometrická měření, která by s
osmibitovou digitalizací prakticky neměla smysl. Daní za přesný a lineární
převod je pomalá digitalizace, obraz z st9 se zdigitalizuje a vyčte za 9 sekund.
Provozní rychlost A/D převodníku je 30kHz. </p>

<!--p>K vysvětlení vysoké kvantové účinnosti astronomických CCD kamer, kterou se
liší od těch používaných při pozemním fotografování bude zapotřebí
obrázku:</p-->

<p>Nepoužívá se antiblooming, který je na fotografických čipech proto, aby
odvodný kanál mezi pixely odvedl přebytečné elektrony z přeexponovaných
pixelů, které by jinak přetekly do pixelů sousedních a zničily fotografii.
Odvodný kanál totiž jednak přímo zmenšuje vlastní aktivní plochu pixelu asi
o čtvrtinu, jednak se odtokový kanál neaktivuje až když je potřeba -
funguje pořád a odvádí nějaké elektrony i z nepřeexponovaných pixelů - z
plnějších víc než z prázdných - a výsledkem je krom ještě menší účinnosti
navíc nelinearita detekce. V poslední době se navíc v některých případech 
před pixely instaluje matice mikročoček, která směruje světlo z celé plochy
čipu na jeho aktivní část.</p>

<p>Nepoužívají se matice barevných filtrů před pixely k dozažení barevnosti
snímku. Astronomové dosahují barevné detekce (nezbytné při redukci dat)
pomocí předsazených filtrů. </p>

<h1>Paralelní port</h1>

<p>Podpora zařízení připojených na paralelní port v Linuxu, kde jsem ovladač
začal programovat, je dosti rozsáhlá. Umožňuje v userspacu používat
zařízení používat tiskárny a jiná zařízení v režimech IEEE1284. Podle
schopností použitého portu je možné použít všech definovaných režimů (SPP,
EPP, ECP). </p>

<p>Kamery SBIG nepoužívají IEEE protokolů. Protokol kamer se podobá
standardnímu nibble modu (např. paralelní laplink), ale je optimalizovaná
na rychlost vyčítání u starých počítačů. Informace směrem ke kameře se
posílají po 8 datových pinech paralelního portu. Zpět se posílají po
stavových linkách tiskárny. Optimalizace spočívá v hardwarové negaci bitů
tak, aby nebylo nutné na přijímající straně provádět XOR přijatých 4 bitů -
stačí jen potřebný bitový posun.</p>

<p>Protože je protokol nestandardní a protože je zapotřebí prioritního
přístupu na port, nepoužívá se ovladač jádra, ale přímý přístup na I/O
linky PC. </p>

<h1>Přístup na I/O porty</h1>

<p>Linux netrpí svým programům, aby přistupovaly na I/O linky PC. Při troše
snahy se nám sice může podařit do programu zakompilovat instrukce IN a
OUT:</p>

<pre>
#include &lt;sys/io.h&gt;

outb(baseAddress, value);
value = inb(baseaddress + 1) &gt;&gt; 3;
</pre>

<p>inb a outb jsou makra definovaná v uvedeném souboru. V ukázce jsou v
nejobvyklejší používané podobě. Makra sama ovšem stojí za pokochání:
</p>

<pre>
static __inline unsigned char
inb (unsigned short int port)
{
	unsigned char _v;

	__asm__ __volatile__ ("inb %w1,%0":"=a" (_v):"Nd" (port));
	return _v;
}
</pre>

<p>
jedno určitě stačí. Umožní nám poměrně snadno dopsat další potřebné makro -
zákaz a povolení přerušení. Opět jen poloviční ukázka:
</p>

<pre>
static __inline void disable()
{
	__asm__ __volatile__("cli");
}
</pre>

<p>
problém nastane až v okamžiku, kdy se program při svém běhu na nějaké
takové místo dostane: Linux ho samozřejmě okamžitě odstřelí. :) Aby to
neudělal, je potřeba mu to vysvětlit. To se dá udělat dvěma podobnými
způsobyr.</p>

<p>Jednoduchým způsobem je volání</p>

<pre>
ioperm(from_port, num, turn_on);
</pre>

<p>
která umožní procesu pristupovat na _num_ IO linek od portu from_port.  Turn_on
rovno jedné povolení zapne, nule vypne. Pomocí tohoto volání lze přistupovat
jen na porty 0 - 3ffh a neumožňuje povolit zákaz přerušení. Jelikož byla
předmětem řešení také PCI deska s paralelními porty na adresách mimo tento
rozsah, používá nakonec URVC volání iopl(), které navíc procesu umožní zakázat
přerušení
</p>

<pre>
if(iopl(3) < 0)
{
	perror("iopl(3)");
	exit(1);
}
</pre>

<p>iopl() dovolí procesu přistupovat na IO porty v celém rozsahu 65536 portů
bez nutnosti specifikovat rozsah.</p>

<p>Problémem při vyčítání kamery je nutnost zajistit, aby se digitalizovaná
řádka vyčetla najednou. Kamera nemá buffer, takže je zapotřebí zajistit
spojitý tok dat přes paralelní port do paměti počítače. K tomu potřebujeme
provést ještě dvě akce: nastavit si nenulovou statickou prioritu a zamknout
si paměť proti swapování. </p>

<p>Statická priorita je záležitost, která se týká jen real-time programů,
všechny normální programy mají statickou prioritu nulovou a pracují s
prioritou dynamickou (nice). Statickou prioritu můžeme nastavit takto:</p>

<pre>
struct sched_param s;
s.sched_priority = 0x32;

if(sched_setscheduler(0, SCHED_FIFO, &s) < 0)
{
perror("sched_setscheduler(0, FIFO, &(..0x32..) )");
exit(1);
}
</pre>

<p>
Abychom zamezili prodlevám způsobeným načítáním kusu naší paměti ze swapu,
musíme si ji zamknout voláním funkce mlock(). V následujícím útržku
programu si paměť zamykáme všechnu přes mlockall().</p>

<pre>
if(mlockall(1) < 0)
{
perror("mlockall(1)");
exit(1);
}
</pre>

<h1>Komunikační protokol SBIG</h1>

<p>K detektorům SBIG určitě existuje nějaká dokumentace. Já jsem ji nikdy
neviděl a proto zde používané termíny mohou být divné, ve knihovnách se
ovšem vyskytuje spousta literálů, takže některé názvy budou zřejmě v
pořádku.</p>

<p>V dalším můžeme klidně zapomenout na to, že na daném I/O rozsahu visí
paralelní port a můžeme předpokládat, že jsou tam za sebou dva registry, kterými
se přímo ovládá kamera. (Je to pravda jen "skoro", předtím je potřeba uvést
paralelní port do stavu, kdy to tak začne vypadat.)</p>

<p>Všechno nasvědčuje tomu, že kamera má osm čtyřbitových registrů, jejichž
obsah se dá přečíst nebo zapsat pomocí adresování horní polovinou datového
bajtu paralelního portu. Čtený a zapisovaný port zřejmě nejsou identické.
Hodnota posílaná do registru se zapíše do spodních čtyřech bajtů datového
portu, hodnota vyčítaná se objeví na stavových linkách portu.</p>

<b>Programátorský model:</b>

<pre>
base + 0:  write |  reg2 |  reg1 |  reg0 | send3 | send2 | send1 | send0 |
base + 1:  busy  | recv3 | recv2 | recv1 | recv0 |   -   |   -   |   -   |
</pre>

<p>Chceme-li pak poslat nibble do registru kamery, dáme do reg0-2 číslo
registru, do send0-3 posílaná data a na malou chvíli nastavíme bit write na
jedničku. Vyčtení registru se dělá tak, že se do reg0-2 napíše registr a ze
stavového portu se vyčte jeho hodnota. Hodnota je k dispozici teprve když
se vynuluje bit busy. Obvyklý přenos pak vypadá takto:

<center>
<BR>
<table border=1 rowspan=0 colspan=0>
<tr><td>1</td><td>počkám, až busy bude nula</td></tr>
<tr><td>2</td><td>OUT registr &lt;&lt; 4 + hodnota</td></tr>
<tr><td>3</td><td>OUT registr &lt;&lt; 4 + hodnota + 0x80</td></tr>
<tr><td>4</td><td>OUT registr &lt;&lt; 4 + hodnota</td></tr>
<tr><td>5</td><td>počkám, až busy bude nula</td></tr>
<tr><td>6</td><td>...</td></tr>
</table>
<BR>
Tabulka 2: Posílací cyklus
<BR><BR>
</center>

<center>
<BR>
<table border=1 rowspan=0 colspan=0>
<tr><td>1</td><td>počkám, až busy bude nula</td></tr>
<tr><td>2</td><td>OUT registr &lt;&lt; 4</td></tr>
<tr><td>3</td><td>počkám, až busy bude nula</td></tr>
<tr><td>4</td><td>IN registr &lt;&lt; 4 + hodnota + 0x80</td></tr>
<tr><td>5</td><td>...</td></tr>
</table>
<BR>
Tabulka 3: Přijímací cyklus
<BR><BR>
</center>

<p>Zde všude znamená OUT výstup na datový port a IN vstup ze stavového
portu.</p>

<b>Časování:</b>

<p>Zvláštní pozornost při komunikaci s kamerou si zaslouží realizace časování,
tj. správných odstupů řídících impulsů při jejich posílání kameře.</p>

<p>Paralelní port je zařízení překvapivě pomalé. Jeden IN nebo out na paralelní
port mi na většině systémů, které se mi dostaly do ruky, trval od 0.6 do 3
mikrosekund. Na standardním PC paralelním portu trval skoro vždycky kolem 1.3
us. Při takhle dlouhé instrukci (cca 86 taktů 486/66) lze dosahovat řádově
mikrosekundových pulsů sekvencemi OUTů. To je poměrně sympatické, ale pro
extrémně dlouhé nebo extrémně krátké OUTy některých počítačů jsem sekvence musl
upravit. (Já upravil sekvenci, kdežto originální sw od SBIGu prostě přestal
fungovat joj!). U velmi pomalých I/O operací byl problém dosáhnout rychlosti A/D
převodu 30kHz, tj. 120 000 půlbajtů za vteřinu. </p>

<b>Mikropříkazy:</b>

<p>Výše zmíněný "hloupý" způsob komunikace s kamerou je omezen jen na časově
kritické úkoly a několik speciálních akcí. Ostatní diplomacie se řeší přes
tzv. mikropříkazy. Mikropříkazy představují komunikaci na vyšší úrovni.
Umožňují zadat kameře příkaz včetně parametrů a umožňují získání různých
návratových hodnot. Známe dohromady 13 různých mikropříkazů, jeden má dvě
modifikace, architektura umožňuje 16. Mikropříkaz je sekvence nibblů s
následující obecnou strukturou:</p>

<pre>
0xA | 0x5 | kod prikazu | delka | data...
</pre>

<p>A5h je hlavička příkazu a je vždycky stejná. Kódy příkazů jsou v tabulce a
délka je počet následujících _bajtů_ dat, tedy počet půlbajtů lomeno
dvěma.</p>

<center>
<BR>
<table border=1 rowspan=0 colspan=0>
<th>kód</th><th>bajtů tam</th><th>bajtů zpět</th><th>smysl</th>
<tr><td>0</td><td>8</td><td>-</td><td>začátek expozice</td></tr>
<tr><td>1</td><td>2</td><td>-</td><td>konec expozice</td></tr>
<tr><td>2</td><td>6/6</td><td>-</td><td>regulace chlazení (2 varianty)</td></tr>
<tr><td>3</td><td>-</td><td>10</td><td>status chlazení</td></tr>
<tr><td>4</td><td>10</td><td>-</td><td>relé (pointace teleskopu)</td></tr>
<tr><td>5</td><td>10</td><td>-</td><td>pulz (ovládání periferií)</td></tr>
<tr><td>6</td><td>-</td><td>4</td><td>vrať verzi</td></tr>
<tr><td>7</td><td>4</td><td>2/-</td><td>ovládání EEPROM (r/w)</td></tr>
<tr><td>8</td><td>2</td><td>-</td><td>různé (LEDka, větrák, závěrka)</td></tr>
<tr><td>9</td><td>-</td><td>4</td><td>status</td></tr>
<tr><td>a</td><td>4</td><td>-</td><td>test systému</td></tr>
<tr><td>b</td><td>2-255</td><td>2</td><td>přenos bajtů</td></tr>
<tr><td>c</td><td>4</td><td>-</td><td>CCD control</td></tr>
</table><BR>
Tabulka 4: Mikropříkazy
<BR><BR>
</center>

<p>Detaily o posílání mikropříkazů, případně o digitalizaci obrazu viz.
zdrojáky nebo tento dokument časem.</p>

<?
end_tbl();
bottom();
?>
