Index: /trunk/FACT++/drive/Camera.cc
===================================================================
--- /trunk/FACT++/drive/Camera.cc	(revision 18618)
+++ /trunk/FACT++/drive/Camera.cc	(revision 18618)
@@ -0,0 +1,187 @@
+/* ======================================================================== *\
+!
+! *
+! * This file is part of MARS, the MAGIC Analysis and Reconstruction
+! * Software. It is distributed to you in the hope that it can be a useful
+! * and timesaving tool in analysing Data of imaging Cerenkov telescopes.
+! * It is distributed WITHOUT ANY WARRANTY.
+! *
+! * Permission to use, copy, modify and distribute this software and its
+! * documentation for any purpose is hereby granted without fee,
+! * provided that the above copyright notice appear in all copies and
+! * that both that copyright notice and this permission notice appear
+! * in supporting documentation. It is provided "as is" without express
+! * or implied warranty.
+! *
+!
+!
+!   Author(s): Thomas Bretz 1/2008 <mailto:tbretz@astro.uni-wuerzburg.de>
+!
+!   Copyright: MAGIC Software Development, 2000-2008
+!
+!
+\* ======================================================================== */
+#include "Camera.h"
+
+#include "MLog.h"
+#include "MLogManip.h"
+
+#include "MVideo.h"
+#include "PixClient.h"
+
+//ClassImp(Camera);
+
+using namespace std;
+
+Camera::Camera(PixClient &client, Int_t nch) : MThread("Camera"), fClient(client), fVideo(0), fNumFrame(0), fChannel(nch)
+{
+    fVideo = new MVideo;
+    fVideo->Open(nch);
+
+    RunThread();
+}
+
+Camera::~Camera()
+{
+    // Shut down the thread
+    CancelThread();
+
+    // Now delete (close) the device
+    delete fVideo;
+}
+
+void Camera::ProcessFrame(unsigned char *img)
+{
+    gettimeofday(&fTime, NULL);
+
+    const Int_t W = fVideo->GetWidth();
+    const Int_t H = fVideo->GetHeight();
+/*
+    const Bool_t crop = W!=768 || H!=576;
+
+    // FIXME: This only works for one RGB24
+    if (!crop)
+    {
+        // FIXME: Grey scale assumed!
+        const unsigned char *end = img + 768*576*depth;
+        char *beg = fImg;
+        while (img < end)
+        {
+            *beg++ = *img;
+            img += depth;
+        }
+    }
+    else
+ */
+    {
+        const Int_t w = TMath::Min(W, 768);
+        const Int_t h = TMath::Min(H, 576);
+
+        memset(fImg, 0, 768*576);
+        for (int y=0; y<h; y++)
+            for (int x=0; x<w; x++)
+            {
+                const Int_t p = (x+y*W)*depth;
+                fImg[x+y*768] = ((UInt_t)img[p]+(UInt_t)img[p+1]+(UInt_t)img[p+2])/3;
+            }
+    }
+
+    fClient.ProcessFrame(fNumFrame-1, (byte*)fImg, &fTime);
+}
+
+Int_t Camera::Thread()
+{
+    fNumSkipped = 0;
+    fNumFrame   = 0;
+
+    if (!fVideo->IsOpen())
+    {
+        gLog << err << "Camera::Thread: ERROR - Device not open." << endl;
+        return kFALSE;
+    }
+
+    gLog << dbg << "Start Camera::Thread at frame " << fNumFrame%fVideo->GetNumBuffers() << endl;
+
+    for (int f=0; f<fVideo->GetNumBuffers(); f++)
+        if (!fVideo->CaptureStart(f))
+            return kFALSE;
+
+    Int_t timeouts = 0;
+    while (1)
+    {
+        // Switch channel if necessary
+        switch (fVideo->SetChannel(fChannel))
+        {
+        case kFALSE:        // Error swucthing channel
+            return kFALSE;
+        case kSKIP:         // No channel switching necessary
+            break;
+        case kTRUE:         // Channel switched (skip filled buffers)
+            for (int f=0; f<fVideo->GetNumBuffers(); f++)
+                if (!fVideo->CaptureWait(fNumFrame+f))
+                    return kFALSE;
+            fNumFrame=0;
+            for (int f=0; f<fVideo->GetNumBuffers(); f++)
+                if (!fVideo->CaptureStart(f))
+                    return kFALSE;
+            break;
+        }
+
+        // Check and wait until capture into the next buffer is finshed
+        unsigned char *img = 0;
+        switch (fVideo->CaptureWait(fNumFrame++, &img))
+        {
+        case kTRUE: // Process frame
+            // If cacellation is requested cancel here
+            TThread::CancelPoint();
+
+            ProcessFrame(img);
+
+            // If cacellation is requested cancel here
+            TThread::CancelPoint();
+
+            // Start to capture into the buffer which has just been processed
+            if (!fVideo->CaptureStart(fNumFrame-1))
+                break;
+
+            timeouts = 0;
+            continue;
+
+        case kFALSE: // Waiting failed
+            break;
+
+        case kSKIP:  // Skip frame
+            fNumFrame--;
+            fNumSkipped++;
+            if (timeouts++<5)
+                continue;
+
+            cout << "ERROR - At least five captured images timed out." << endl;
+            break;
+        }
+
+        break;
+    }
+
+    // Is this necessary?!?
+    //for (int i=0; i<frames-1; i++)
+    //    video.CaptureWait((f+i+1)%frames);
+
+    cout << fNumFrame-1 << " frames processed." << endl;
+    cout << fNumSkipped << " frames skipped." << endl;
+
+    return kTRUE;
+}
+
+//void Camera::Loop(unsigned long nof)
+//{
+//}
+
+void Camera::SetChannel(int chan)
+{
+    fChannel = chan;
+//    CancelThread();
+//    fVideo->SetChannel(chan);
+//    RunThread();
+}
+
Index: /trunk/FACT++/drive/Camera.h
===================================================================
--- /trunk/FACT++/drive/Camera.h	(revision 18618)
+++ /trunk/FACT++/drive/Camera.h	(revision 18618)
@@ -0,0 +1,51 @@
+#ifndef COSY_Camera
+#define COSY_Camera
+
+#ifndef MARS_MThread
+#include "MThread.h"
+#endif
+
+#ifndef COSY_PixGetter
+#include "PixGetter.h"
+#endif
+
+class MVideo;
+class PixClient;
+
+class Camera : public PixGetter, public MThread
+{
+private:
+    //
+    // Geometry
+    //
+    static const int cols  = 768;
+    static const int rows  = 576;
+    static const int depth = 3;
+
+    char fImg[cols*rows];
+    struct timeval fTime;
+
+    PixClient &fClient;
+
+    MVideo *fVideo;
+
+    UInt_t fNumFrame;
+    UInt_t fNumSkipped;
+
+    UInt_t fChannel;
+
+    Int_t Thread();
+    void  ProcessFrame(unsigned char *img);
+
+public:
+    Camera(PixClient &client, Int_t ch=0);
+    virtual ~Camera();
+
+    void SetChannel(int);
+
+    void ExitLoop() { CancelThread(); }
+
+    //ClassDef(Camera, 0)
+};
+
+#endif
Index: /trunk/FACT++/drive/FilterLed.cc
===================================================================
--- /trunk/FACT++/drive/FilterLed.cc	(revision 18618)
+++ /trunk/FACT++/drive/FilterLed.cc	(revision 18618)
@@ -0,0 +1,564 @@
+#include "FilterLed.h"
+
+#include <memory.h>   // memset
+#include <math.h>
+#include <iostream> // cout
+
+#include <TMath.h>
+
+#include "Led.h"
+#include "Leds.h"
+#include "Ring.h"
+
+#include "MGMap.h"
+
+ClassImp(FilterLed);
+
+using namespace std;
+
+class ClusterFinder
+{
+private:
+    byte *fImg;
+
+    UInt_t fW;
+    UInt_t fH;
+
+    Int_t fX0;
+    Int_t fX1;
+
+    Int_t fY0;
+    Int_t fY1;
+
+    UInt_t fLimitingSize;
+
+    UInt_t fCount;
+    Float_t fSumX;
+    Float_t fSumY;
+
+    Float_t FindCluster(Int_t x, Int_t y)
+    {
+        // if edge is touched stop finding cluster
+        if (x<fX0 || x>=fX1 || y<fY0 || y>=fY1)
+            return -1;
+
+        if (fCount>fLimitingSize)
+            return -2;
+
+        // get the value
+        Float_t val = fImg[y*fW+x];
+
+        // if its empty we have found the border of the cluster
+        if (val==0)
+            return 0;
+
+        // mark the point as processed
+        fImg[y*fW+x] = 0;
+
+        fSumX += x*val; // sumx
+        fSumY += y*val; // sumy
+        fCount++;
+
+        Float_t rc[4];
+        rc[0] = FindCluster(x+1, y  );
+        rc[1] = FindCluster(x,   y+1);
+        rc[2] = FindCluster(x-1, y  );
+        rc[3] = FindCluster(x,   y-1);
+
+        for (int i=0; i<4; i++)
+        {
+            if (rc[i]<0) // check if edge is touched
+                return rc[i];
+
+            val += rc[i];
+        }
+
+        return val;
+    }
+
+public:
+    ClusterFinder(byte *img, UInt_t w, UInt_t h) : fImg(0), fLimitingSize(999)
+    {
+        fW = w;
+        fH = h;
+
+        fX0 = 0;
+        fY0 = 0;
+        fX1 = fW;
+        fY1 = fH;
+
+        fImg = new byte[fW*fH];
+
+        memcpy(fImg, img, fW*fH);
+    }
+
+    ~ClusterFinder()
+    {
+        delete [] fImg;
+    }
+    Double_t GetSumX() const { return fSumX; }
+    Double_t GetSumY() const { return fSumY; }
+
+    UInt_t GetCount() const { return fCount; }
+
+    void SetLimitingSize(UInt_t lim) { fLimitingSize=lim; }
+
+    Float_t FindClusterAt(Int_t x, Int_t y)
+    {
+        fCount = 0;
+        fSumX  = 0;
+        fSumY  = 0;
+
+        return FindCluster(x, y);
+    }
+
+    void SetRange(Int_t x0=0, Int_t y0=0, Int_t x1=0, Int_t y1=0)
+    {
+        fX0 = x0;
+        fY0 = y0;
+        fX1 = x1==0?fW:x1;
+        fY1 = y1==0?fH:y1;
+    }
+
+    void FindCluster(Leds &leds, Int_t x0=0, Int_t y0=0, Int_t x1=0, Int_t y1=0)
+    {
+        fX0 = x0;
+        fY0 = y0;
+        fX1 = x1==0?fW:x1;
+        fY1 = y1==0?fH:y1;
+
+        for (Int_t x=fX0; x<fX1; x++)
+            for (Int_t y=fY0; y<fY1; y++)
+            {
+                const byte &b = fImg[y*fW+x];
+                if (b==0)
+                    continue;
+
+                const Float_t mag = FindClusterAt(x, y);
+                if (fCount>999)
+                {
+                    cout << "ERROR - Spot with Size>999 detected..." << endl;
+                    return;
+                }
+
+                if (mag>0 && fCount>6)
+                    leds.Add(fSumX/mag, fSumY/mag, 0, 0, mag);
+            }
+        leds.Compress();
+    }
+};
+
+
+void FilterLed::DrawBox(const int x1, const int y1,
+                        const int x2, const int y2,
+                        const int col) const
+{
+    MGMap::DrawBox(fImg, 768, 576, x1, y1, x2, y2, col);
+}
+
+void FilterLed::MarkPoint(Float_t px, Float_t py, Float_t mag) const
+{
+    const int x = (int)(px+.5);
+    const int y = (int)(py+.5);
+    const int m = (int)(mag);
+
+    DrawBox(x-8, y, x-5, y, m);
+    DrawBox(x, y+5, x, y+8, m);
+    DrawBox(x+5, y, x+8, y, m);
+    DrawBox(x, y-8, x, y-5, m);
+}
+
+void FilterLed::MarkPoint(const Led &led) const
+{
+    /*
+    Int_t M = (int)(log(led.GetMag())*20);
+
+    cout << led.GetMag() << endl;
+
+    if (M>0xff)
+        M=0xff;
+    if (M<0xc0)
+        M=0xc0;
+        */
+
+    const int x = (int)(led.GetX()+.5);
+    const int y = (int)(led.GetY()+.5);
+
+    MarkPoint(x, y, 0xff);
+}
+
+void FilterLed::DrawCircle(float cx, float cy, float r, byte col) const
+{
+    MGMap::DrawCircle(fImg, 768, 576, cx, cy, r, col);
+}
+
+void FilterLed::DrawHexagon(float cx, float cy, float r, byte col) const
+{
+    MGMap::DrawHexagon(fImg, 768, 576, cx, cy, r, col);
+}
+
+void FilterLed::DrawCircle(const Ring &l, byte col) const
+{
+    DrawCircle(l.GetX(), l.GetY(), l.GetR(), col);
+}
+
+void FilterLed::DrawCircle(const Ring &l, double r, byte col) const
+{
+    DrawCircle(l.GetX(), l.GetY(), r, col);
+}
+
+void FilterLed::DrawHexagon(const Ring &l, double r, byte col) const
+{
+    DrawHexagon(l.GetX(), l.GetY(), r, col);
+}
+
+void FilterLed::GetMinMax(const int offset, byte *min, byte *max) const
+{
+    *min = fImg[0];
+    *max = fImg[0];
+
+    byte *s = (byte*)fImg;
+    const byte *e0 = s+fW*fH;
+
+    //
+    // calculate mean value (speed optimized)
+    //
+    while (s<e0)
+    {
+        const byte *e = s+fH-offset;
+        s += offset;
+
+        while (s<e)
+        {
+            if (*s>*max)
+            {
+                *max = *s;
+                if (*max-*min==255)
+                    return;
+            }
+            if (*s<*min)
+            {
+                *min = *s;
+                if (*max-*min==255)
+                    return;
+            }
+            s++;
+        }
+        s+=offset;
+    }
+}
+
+int FilterLed::GetMeanPosition(const int x, const int y,
+                               const int boxx, const int boxy,
+                               float &mx, float &my, unsigned int &sum) const
+{
+    unsigned int sumx=0;
+    unsigned int sumy=0;
+
+    sum=0;
+    for (int dx=x-boxx; dx<x+boxx+1; dx++)
+        for (int dy=y-boxy; dy<y+boxy+1; dy++)
+        {
+            const byte &m = fImg[dy*fW+dx];
+
+            sumx += m*dx;
+            sumy += m*dy;
+            sum  += m;
+        }
+
+    mx = (float)sumx/sum;
+    my = (float)sumy/sum;
+
+    return (int)my*fW + (int)mx;
+}
+
+int FilterLed::GetMeanPosition(const int x, const int y, const int boxx, const int boxy) const
+{
+    float mx, my;
+    unsigned int sum;
+    return GetMeanPosition(x, y, boxx, boxy, mx, my, sum);
+}
+
+int FilterLed::GetMeanPositionBox(const int x, const int y,
+                                  const int boxx, const int boxy,
+                                  float &mx, float &my, unsigned int &sum) const
+{
+    //-------------------------------
+    // Improved algorithm:
+    // 1. Look for the largest five-pixel-cross signal inside the box
+    int x0 = TMath::Max(x-boxx+1,   0);
+    int y0 = TMath::Max(y-boxy+1,   0);
+
+    int x1 = TMath::Min(x+boxx+1-1, fW);
+    int y1 = TMath::Min(y+boxy+1-1, fH);
+
+    int maxx=0;
+    int maxy=0;
+
+    unsigned int max =0;
+    for (int dx=x0; dx<x1; dx++)
+    {
+        for (int dy=y0; dy<y1; dy++)
+        {
+            const unsigned int sumloc =
+                fImg[(dy+0)*fW + (dx-1)] +
+                fImg[(dy+0)*fW + (dx+1)] +
+                fImg[(dy+1)*fW + dx] +
+                fImg[(dy+0)*fW + dx] +
+                fImg[(dy-1)*fW + dx];
+
+            if(sumloc<=max)
+                continue;
+
+            maxx=dx;
+            maxy=dy;
+            max =sumloc;
+	}
+    }
+
+    // 2. Calculate mean position inside a circle around
+    // the highst cross-signal with radius of 6 pixels.
+    ClusterFinder find(fImg, fW, fH);
+    find.SetLimitingSize(9999);
+    find.SetRange(x0, y0, x1, y1);
+
+    const Float_t mag = find.FindClusterAt(maxx, maxy);
+
+    mx = find.GetSumX()/mag;
+    my = find.GetSumY()/mag;
+
+    sum = (int)(mag+0.5);
+
+    return (int)my*fW + (int)mx;
+}
+
+int FilterLed::GetMeanPositionBox(const int x, const int y,
+                                  const int boxx, const int boxy) const
+{
+    float mx, my;
+    unsigned int sum;
+    return GetMeanPositionBox(x, y, boxx, boxy, mx, my, sum);
+}
+
+void FilterLed::ExecuteAndMark(Leds &leds, int xc, int yc) const
+{
+    const Int_t first = leds.GetEntriesFast();
+
+    Execute(leds, xc, yc);
+ 
+    // Mark Stars in image
+    for (int i=first; i<leds.GetEntriesFast(); i++)
+        MarkPoint(leds(i));
+}
+
+
+void FilterLed::ExecuteAndMark(Leds &leds, int xc, int yc, double &bright) const
+{
+    const Int_t first = leds.GetEntriesFast();
+
+    Execute(leds, xc, yc, bright);
+ 
+    // Mark Stars in image
+    for (int i=first; i<leds.GetEntriesFast(); i++)
+        MarkPoint(leds(i));
+}
+
+void FilterLed::Execute(int xc, int yc) const
+{
+    Leds leds;
+    ExecuteAndMark(leds, xc, yc);
+}
+
+void FilterLed::Execute(Leds &leds, int xc, int yc) const
+{
+    double bright;
+    Execute(leds, xc, yc, bright);
+}
+
+void FilterLed::Execute(Leds &leds, int xc, int yc, double &bright) const
+{
+    const int x0 = TMath::Max(xc-fBoxX, 0);
+    const int y0 = TMath::Max(yc-fBoxY, 0);
+    const int x1 = TMath::Min(xc+fBoxX, fW);
+    const int y1 = TMath::Min(yc+fBoxY, fH);
+
+    const int wx = x1-x0;
+    const int hy = y1-y0;
+
+    double sum = 0;
+    double sq  = 0;
+
+    for (int x=x0; x<x1; x++)
+        for (int y=y0; y<y1; y++)
+        {
+            byte &b = fImg[y*fW+x];
+
+            // Skip saturating pixels
+            if (b>0xf0)
+                continue;
+
+            sum += b;
+            sq  += b*b;
+        }
+
+    sum /= wx*hy;
+    sq  /= wx*hy;
+
+    bright=sum;
+
+    
+    // 254 because b<=max and not b<max
+    const double sdev = sqrt(sq-sum*sum);
+    const byte   max  = sum+fCut*sdev>254 ? 254 : (byte)(sum+fCut*sdev);
+
+    //
+    // clean image from noise
+    // (FIXME: A lookup table could accelerate things...
+    //
+    for (int x=x0; x<x1; x++)
+        for (int y=y0; y<y1; y++)
+        {
+            byte &b = fImg[y*fW+x];
+            if (b<=max)
+                b = 0;
+        }
+
+    ClusterFinder find(fImg, fW, fH);
+    find.FindCluster(leds, x0, y0, x1, y1);
+}
+
+void FilterLed::FindStar(Leds &leds, int xc, int yc, bool box) const
+{
+    // fBox: radius of the inner (signal) box
+    // Radius of the outer box is fBox*sqrt(2)
+
+    //
+    // Define inner box in which to search the signal
+    //
+    const int x0 = TMath::Max(xc-fBoxX, 0);
+    const int y0 = TMath::Max(yc-fBoxY, 0);
+    const int x1 = TMath::Min(xc+fBoxX, fW);
+    const int y1 = TMath::Min(yc+fBoxY, fH);
+
+    //
+    // Define outer box (excluding inner box) having almost
+    // the same number of pixels in which the background
+    // is calculated
+    //
+    const double sqrt2 = sqrt(2.);
+
+    const int xa = TMath::Max(xc-TMath::Nint(fBoxX*sqrt2), 0);
+    const int ya = TMath::Max(yc-TMath::Nint(fBoxY*sqrt2), 0);
+    const int xb = TMath::Min(xc+TMath::Nint(fBoxX*sqrt2), fW);
+    const int yb = TMath::Min(yc+TMath::Nint(fBoxY*sqrt2), fH);
+
+    //
+    // Calculate average and sdev for a square
+    // excluding the inner part were we expect
+    // the signal to be.
+    //
+    double sum = 0;
+    double sq  = 0;
+
+    int n=0;
+    for (int x=xa; x<xb; x++)
+        for (int y=ya; y<yb; y++)
+        {
+            if (x>=x0 && x<x1 && y>=y0 && y<y1)
+                continue;
+
+            byte &b = fImg[y*fW+x];
+
+            sum += b;
+            sq  += b*b;
+            n++;
+        }
+
+    sum /= n;
+    sq  /= n;
+
+    // 254 because b<=max and not b<max
+    const double sdev = sqrt(sq-sum*sum);
+    const byte   max  = sum+fCut*sdev>254 ? 254 : (byte)(sum+fCut*sdev);
+
+    //
+    // clean image from noise
+    // (FIXME: A lookup table could accelerate things...
+    //
+    n=0;
+    for (int x=x0; x<x1; x++)
+        for (int y=y0; y<y1; y++)
+        {
+            byte &b = fImg[y*fW+x];
+            if (b<=max)
+                b = 0;
+            else
+                n++;
+        }
+
+    //
+    // Mark the background region
+    //
+    for (int x=xa; x<xb; x+=2)
+    {
+        fImg[ya*fW+x]=0xf0;
+        fImg[yb*fW+x]=0xf0;
+    }
+    for (int y=ya; y<yb; y+=2)
+    {
+        fImg[y*fW+xa]=0xf0;
+        fImg[y*fW+xb]=0xf0;
+    }
+
+    //
+    // Check if any pixel found...
+    //
+    if (n<5)
+        return;
+
+    //
+    // Get the mean position of the star
+    //
+    float mx, my;
+    unsigned int mag;
+    int pos = box ? GetMeanPositionBox(xc, yc, fBoxX-1, fBoxY-1, mx, my, mag)
+        : GetMeanPosition(xc, yc, fBoxX-1, fBoxY-1, mx, my, mag);
+
+    if (pos<0 || pos>=fW*fH || fImg[pos]<sum+fCut*sdev)
+        return;
+
+    //    cout << "Mean=" << sum << "  SDev=" << sdev << "  :  ";
+    //    cout << "Sum/n = " << sum << "/" << n << " = " << (n==0?0:mag/n) << endl;
+
+    leds.Add(mx, my, 0, 0, -2.5*log10((float)mag)+13.7);
+}
+
+void FilterLed::Stretch() const
+{
+    byte min, max;
+    GetMinMax(25, &min, &max);
+
+    if (min==max || max-min>230) // 255/230=1.1
+        return;
+
+    const float scale = 255./(max-min);
+
+    byte *b = fImg;
+    const byte *e = fImg+fW*fH;
+
+    while (b<e)
+    {
+        if (*b<min)
+        {
+            *b++=0;
+            continue;
+        }
+        if (*b>max)
+        {
+            *b++=255;
+            continue;
+        }
+        *b = (byte)((*b-min)*scale);
+        b++;
+    }
+}
Index: /trunk/FACT++/drive/FilterLed.h
===================================================================
--- /trunk/FACT++/drive/FilterLed.h	(revision 18618)
+++ /trunk/FACT++/drive/FilterLed.h	(revision 18618)
@@ -0,0 +1,79 @@
+#ifndef CAOS_FilterLed
+#define CAOS_FilterLed
+
+#ifndef __CINT__
+#include <TROOT.h>
+#endif
+
+typedef unsigned char byte;
+
+class Led;
+class Leds;
+class Ring;
+
+class FilterLed
+{
+    byte *fImg;
+    int fW;
+    int fH;
+    int fBoxX;
+    int fBoxY;
+    float fCut;
+
+    Float_t FindCluster(int &cnt, float *sum, UInt_t x, UInt_t y,
+                        UInt_t x0, UInt_t y0, UInt_t x1, UInt_t y1) const;
+
+    void GetMinMax(const int offset, byte *min, byte *max) const;
+    int  GetMeanPosition(const int x, const int y, const int boxx, const int boxy) const;
+    int  GetMeanPosition(const int x, const int y, const int boxx, const int boxy,
+			 float &mx, float &my, unsigned int &sum) const;
+
+    int  GetMeanPositionBox(const int x, const int y,
+                            const int boxx, const int boxy) const;
+    int  GetMeanPositionBox(const int x, const int y,
+                            const int boxx, const int boxy, float &mx, float &my,
+                            unsigned int &sum) const;
+
+    void DrawBox(const int x1, const int y1,
+                 const int x2, const int y2,
+                 const int col) const;
+
+public:
+    FilterLed(byte *img, int w, int h, double cut=2.5)
+      : fImg(img), fW(w), fH(h), fBoxX(w), fBoxY(h), fCut(cut)
+    {
+    }
+
+    FilterLed(byte *img, int w, int h, int boxx, int boxy, double cut=2.5)
+      : fImg(img), fW(w), fH(h), fBoxX(boxx), fBoxY(boxy), fCut(cut)
+    {
+    }
+    virtual ~FilterLed() { }
+
+    void SetBox(int box)   { fBoxX = fBoxY = box; }
+    void SetBox(int boxx, int boxy)   { fBoxX = boxx; fBoxY = boxy; }
+    void SetCut(float cut) { fCut = cut; } 
+    void FindStar(Leds &leds, int xc, int yc, bool circle=false) const;
+    
+    void Execute(Leds &leds, int xc, int yc, double &bright) const;
+    void Execute(Leds &leds, int xc, int yc) const;
+    void Execute(Leds &leds) const { Execute(leds, fW/2, fH/2); }
+    void ExecuteAndMark(Leds &leds, int xc, int yc) const;
+    void ExecuteAndMark(Leds &leds, int xc, int yc, double &bright) const;
+    void ExecuteAndMark(Leds &leds) const { ExecuteAndMark(leds, fW/2, fH/2); }
+    void Execute(int xc, int yc) const;
+    void Execute() const { Execute(fW/2, fH/2); }
+    void MarkPoint(const Led &led) const;
+    void MarkPoint(Float_t x, Float_t y, Float_t mag) const;
+    void Stretch() const;
+    void DrawCircle(float cx, float cy, float r, byte col=0x40) const;
+    void DrawCircle(float r, byte col=0x40) const { DrawCircle(fW/2, fH/2, r, col); }
+    void DrawCircle(const Ring &c, byte col=0x40) const;
+    void DrawCircle(const Ring &c, double r, byte col) const;
+    void DrawHexagon(float cx, float cy, float r, byte col=0x40) const;
+    void DrawHexagon(const Ring &c, double r, byte col) const;
+
+    ClassDef(FilterLed, 0)
+};
+
+#endif
Index: /trunk/FACT++/drive/Led.cc
===================================================================
--- /trunk/FACT++/drive/Led.cc	(revision 18618)
+++ /trunk/FACT++/drive/Led.cc	(revision 18618)
@@ -0,0 +1,27 @@
+#include "Led.h"
+
+#include <iostream>
+
+#include <TROOT.h>
+#include <TMath.h>
+
+#include "Ring.h"
+#include "MString.h"
+
+ClassImp(Led);
+
+using namespace std;
+
+void Led::CalcPhi(const Ring &ring)
+{
+    fPhi = TMath::ATan2(fY-ring.GetY(), fX-ring.GetX())*180/TMath::Pi();
+}
+
+void Led::Print(Option_t *o) const
+{
+    cout << "Led: ";
+    cout << "x="   << MString::Format("%5.1f", fX)   << "+-" << fDx   << ", ";
+    cout << "y="   << MString::Format("%5.1f", fY)   << "+-" << fDy   << ", ";
+    cout << "phi=" << MString::Format("%6.1f", fPhi) << "+-" << fDphi << ", ";
+    cout << "mag=" << fMag << endl;
+}
Index: /trunk/FACT++/drive/Led.h
===================================================================
--- /trunk/FACT++/drive/Led.h	(revision 18618)
+++ /trunk/FACT++/drive/Led.h	(revision 18618)
@@ -0,0 +1,64 @@
+#ifndef COSY_Led
+#define COSY_Led
+
+#ifndef ROOT_TObject
+#include <TObject.h>
+#endif
+
+class Ring;
+
+class Led : public TObject
+{
+private:
+    Double_t fX;
+    Double_t fY;
+    Double_t fPhi;
+
+    Double_t fDx;
+    Double_t fDy;
+    Double_t fDphi;
+
+    Double_t fMag;
+
+public:
+    Led(Double_t x=0, Double_t y=0, Double_t dx=0, Double_t dy=0, Double_t mag=0) :
+        fX(x), fY(y), fPhi(0), fDx(dx), fDy(dy), fDphi(-1), fMag(mag)
+    {
+    }
+
+    Int_t Compare(const TObject *obj) const
+    {
+        const Led *const l = (Led*)obj;
+
+        if (fPhi<l->fPhi)
+            return -1;
+
+        if (fPhi>l->fPhi)
+            return 1;
+
+        return 0;
+    }
+
+    void SetX(Double_t x)     { fX=x; }
+    void SetY(Double_t y)     { fY=y; }
+
+    Double_t GetX() const    { return fX; }
+    Double_t GetY() const    { return fY; }
+    Double_t GetDx() const   { return fDx; }
+    Double_t GetDy() const   { return fDy; }
+    Double_t GetPhi() const  { return fPhi; }
+    Double_t GetDphi() const { return fDphi; }
+    Double_t GetMag() const  { return fMag; }
+
+    void AddOffset(Double_t dx, Double_t dy) { fX+=dx; fY+=dy; }
+
+    Bool_t IsSortable() const { return kTRUE; }
+
+    void CalcPhi(const Ring &ring);
+
+    void Print(Option_t *o=NULL) const;
+
+    ClassDef(Led, 1)
+};
+
+#endif
Index: /trunk/FACT++/drive/MCaos.cc
===================================================================
--- /trunk/FACT++/drive/MCaos.cc	(revision 18618)
+++ /trunk/FACT++/drive/MCaos.cc	(revision 18618)
@@ -0,0 +1,520 @@
+#include "MCaos.h"
+
+#include <fstream>
+
+#include <TSystem.h>
+#include <TFile.h>
+#include <TTree.h>
+#include <TH1.h>
+#include <TH2.h>
+#include <TGraph.h>
+#include <TCanvas.h>
+
+#include "MLog.h"
+#include "MLogManip.h"
+
+#include "MTime.h"
+#include "MPointing.h"
+
+#include "Led.h"
+#include "Ring.h"
+#include "Rings.h"
+#include "FilterLed.h"
+
+using namespace std;
+
+void MCaos::ReadResources(const char *name)
+{
+    ifstream fin(name);
+    if (!fin)
+    {
+        gLog << err << "ERROR - Cannot open " << name << endl;
+        return;
+    }
+
+    fPositions.Clear();
+
+    gLog << all << " Reading " << name << ":" << endl;
+    gLog << inf << "------------------------------" << endl;
+    while (1)
+    {
+        Double_t px, py, ox, oy;
+        fin >> px >> py >> ox >> oy;
+        if (!fin)
+            break;
+
+        gLog << " Led #" << fPositions.GetEntriesFast() << ":  ";
+        gLog << setw(3) << px << " ";
+        gLog << setw(3) << py << "  (";
+        gLog << setw(3) << ox << ", ";
+        gLog << setw(3) << oy << ")" << endl;
+        AddPosition(px, py, ox, oy);
+    }
+    gLog << all << "Found " << fPositions.GetEntriesFast() << " leds." << endl;
+}
+
+void MCaos::OpenFile()
+{
+    int i=0;
+    char name[100];
+    while (1)
+    {
+        sprintf(name, "data/data%03d.root", i++);
+        if (gSystem->AccessPathName(name, kFileExists))
+            break;
+    }
+
+    if (fFile)
+        delete fFile;
+
+    fFile = new TFile(name, "RECREATE");
+
+    if (!fFile->IsOpen())
+    {
+        delete fFile;
+        fFile = NULL;
+
+        gLog << err << "ERROR - Cannot open file '" << name << "'" << endl;
+    }
+
+    TTree *tree = new TTree("Data", "Real CaOs Data");
+
+    fLeds = new Leds;
+    fEvtTime = 0;
+
+    tree->Branch("Leds", "TClonesArray", &fLeds);
+    tree->Branch("ZenithDist.", &fZenithDist, "fZenithDist/D");
+    tree->Branch("Azimuth.",    &fAzimuth,    "fAzimuth/D");
+    tree->Branch("EvtTime.",    &fEvtTime,    "fEvtTime/D");
+
+    gLog << inf << "Root file '" << name << "' open." << endl;
+}
+
+void MCaos::CloseFile()
+{
+    if (!fFile)
+        return;
+
+    const TString  name = fFile->GetName();
+    const Double_t n    = ((TTree*)fFile->Get("Data"))->GetEntries();
+
+    fFile->Write();
+    delete fFile;
+    fFile = NULL;
+
+    gLog << inf << "Root file closed (n=" << n << ")" << endl;
+
+    if (n<1)
+    {
+        gSystem->Unlink(name);
+        gLog << warn << "Root file deleted - no entries." << endl;
+    }
+}
+
+void MCaos::InitHistograms()
+{
+    if (fHistpr)
+        return;
+
+    Rings r;
+    r.SetMinNumberLeds(fMinNumberLeds);
+    r.CalcRings(fPositions);
+
+    const Ring &c = r.GetCenter();
+
+    Double_t xmin = c.GetX()-50;
+    Double_t xmax = c.GetX()+50;
+
+    Double_t ymin = c.GetY()-50;
+    Double_t ymax = c.GetY()+50;
+
+    Double_t rmin = c.GetR()-50;
+    Double_t rmax = c.GetR()+50;
+
+    Int_t xbin = 1001;
+    Int_t ybin = 1001;
+    Int_t rbin = 1001;
+
+    const Int_t sz = 50;
+    fHistled = new TH2F*[fPositions.GetEntriesFast()];
+    fHistw   = new TH1F*[fPositions.GetEntriesFast()];
+    for (int i=0; i<fPositions.GetEntriesFast(); i++)
+    {
+        TString name  = "LED";
+        TString title = "LED #";
+
+        name += i;
+        title += i;
+
+        const Led &p = fPositions(i);
+        fHistled[i] = new TH2F(name, title,
+                               20*sz+1, p.GetX()-sz, p.GetX()+sz,
+                               20*sz+1, p.GetY()-sz, p.GetY()+sz);
+        fHistled[i]->SetXTitle("x [pix]");
+        fHistled[i]->SetYTitle("counts");
+
+        name = "Angle";
+        title = "Angle of the Led #";
+
+        name += i;
+        title += i;
+
+        fHistw[i] = new TH1F;
+        fHistw[i]->SetNameTitle(name, title);
+        fHistw[i]->SetBins(101, -50.5, 50.5);
+        fHistw[i]->SetXTitle("\\Phi [arcmin]");
+        fHistw[i]->SetYTitle("counts");
+    }
+
+    fHistallw = new TH1F;
+    fHistallw->SetNameTitle("allw","Rotation angel");
+    fHistallw->SetBins(26, -25, 25);
+    fHistallw->SetXTitle("\\phi [arcmin]");
+    fHistallw->SetYTitle("counts");
+
+    fHistprxpry = new TH2F;
+    fHistprxpry->SetNameTitle("prx und pry","x- and y-coordinate of the ring-center");
+    fHistprxpry->SetBins(xbin, xmin, xmax, ybin, ymin, ymax);
+    fHistprxpry->SetXTitle("x [pix]");
+    fHistprxpry->SetYTitle("y [pix]");
+    fHistprxpry->SetZTitle("counts");
+
+    fGraphprx = new TGraph;
+    fGraphprx->SetTitle("time-developement of the x-coordinate of the ring-center");
+
+    fGraphpry = new TGraph;
+    fGraphpry->SetTitle("time-developement of the y-coordinate of the ring-center");
+
+    fGraphw = new TGraph;
+    fGraphw->SetTitle("Time-developement of rotation angle");
+
+    fHistpr = new TH1F("pr","Radius of the ring", rbin, rmin, rmax);
+    fHistpr->SetXTitle("r [pix]");
+    fHistpr->SetYTitle("counts");
+}
+
+void MCaos::DeleteHistograms()
+{
+    TH1F *dummy = fHistpr;
+    fHistpr=NULL;
+
+    if (!dummy)
+        return;
+
+    delete dummy;
+    delete fHistprxpry;
+    delete fHistallw;
+    delete fGraphprx;
+    delete fGraphpry;
+    delete fGraphr;
+
+    for (int i=0; i<6; i++)
+    {
+        delete fHistled[i];
+        delete fHistw[i];
+        delete fGraphw;
+    }
+    delete fHistled;
+    delete fHistw;
+}
+
+void MCaos::ShowHistograms()
+{
+    if (!fHistpr || fHistpr->GetEntries()<1)
+        return;
+
+    TH1 *h;
+
+    TCanvas *c = new TCanvas("cring", "Center of the ring", 800, 800);
+    c->Divide(2,2);
+    c->cd(1);
+    h = (TH1*)fHistprxpry->ProfileX();
+    h->Fit("gaus");
+    h->Draw();
+    h->SetBit(kCanDelete);
+    c->cd(2);
+    h = (TH1*)fHistprxpry->ProfileY();
+    h->Fit("gaus");
+    h->Draw();
+    h->SetBit(kCanDelete);
+    c->cd(3);
+    fHistpr->Fit("gaus");
+    fHistpr->DrawCopy();
+    c->cd(4);
+    fHistprxpry->DrawCopy(/*"surf2"*/);
+    c->Update();
+
+    const Int_t n1 = (Int_t)(TMath::Sqrt(fPositions.GetEntriesFast())+1.0);
+    const Int_t n2 = (Int_t)(TMath::Sqrt(fPositions.GetEntriesFast())+0.5);
+
+    TCanvas *c1 = new TCanvas("cpos", "Led Positions", 800, 600);
+    TCanvas *c2 = new TCanvas("cangle", "Angles of the Leds", 800, 600);
+    c1->Divide(n1, n2);
+    c2->Divide(n1, n2);
+    for (int i=0; i<fPositions.GetEntriesFast(); i++)
+    {
+        c1->cd(i+1);
+        fHistled[i]->DrawCopy();
+        c2->cd(i+1);
+        fHistw[i]->DrawCopy();
+    }
+    c1->Update();
+    c2->Update();
+
+    /*
+    c = new TCanvas("ctime", "Timedevelopement of Center", 800, 800);
+    c->Divide(1,3);
+    c->cd(1);
+    h = fGraphprx->GetHistogram();
+    h->SetXTitle("time [s]");
+    h->SetYTitle("x [pix]");
+    h->DrawCopy();
+    c->SetSelectedPad(NULL);
+    fGraphprx->DrawClone("ALP*")->SetBit(kCanDelete);
+    gPad->Modified();
+    gPad->Update();
+    c->cd(2);
+    h = fGraphpry->GetHistogram();
+    h->SetXTitle("time [s]");
+    h->SetYTitle("y [pix]");
+    h->DrawCopy();
+    //((TPad*)gPad)->SetSelectedPad(NULL);
+    //fGraphpry->DrawClone("ALP*")->SetBit(kCanDelete);
+    c->cd(3);
+    h = fGraphr->GetHistogram();
+    h->SetXTitle("time [s]");
+    h->SetYTitle("r [pix]");
+    h->DrawCopy();
+    //((TPad*)gPad)->SetSelectedPad(NULL);
+    //fGraphr->DrawClone("ALP*")->SetBit(kCanDelete);
+    c->Modified();
+    c->Update();
+    */
+
+    c = new TCanvas("crot", "rotation angle", 800, 600);
+    c->Divide(2,1);
+    c->cd(1);
+    fHistallw->SetXTitle("\\phi [arcmin]");
+    fHistallw->SetYTitle("counts");
+    fHistallw->DrawCopy();
+    /*
+    c->cd(2);
+    h = fGraphw->GetHistogram();
+    h->SetXTitle("time [s]");
+    h->SetYTitle("\\phi [arcmin]");
+    h->DrawCopy();
+    ((TPad*)gPad)->SetSelected(NULL);
+    fGraphw->DrawClone("ALP*")->SetBit(kCanDelete);
+    */
+
+    /* --------------------------------------------------------
+     *  CALCULATE OFFSETS!
+     * --------------------------------------------------------
+     Rings r;
+     r.CalcRings(fPositions);
+
+     const Ring &c = r.GetCenter();
+     */
+}
+
+void MCaos::ResetHistograms()
+{
+    if (!fHistpr)
+        return;
+
+    fHistpr->Reset();
+    fHistprxpry->Reset();
+    fHistallw->Reset();
+    for (int i=0; i<6; i++)
+    {
+        fHistled[i]->Reset();
+        fHistw[i]->Reset();
+    }
+}
+
+Ring MCaos::Run(byte *img, bool printl, bool printr, const ZdAz &pos, const MTime &t)
+{
+    Leds &leds = *fLeds;
+    leds.Clear();
+
+    fNumDetectedLEDs  = 0;
+    fNumDetectedRings = 0;
+
+    /*
+    //the following lines are just to test the new setup
+    static int i=0;
+    i++;
+    i%=2;
+    if (i==0)
+        ReadResources("leds0.txt");
+    else
+        ReadResources("leds1.txt");
+    cout << "LEDs " << i << " " << flush;
+     */
+
+    //          img  width height radius sigma
+    FilterLed f(img, 768, 576, fSizeBox, fSizeBox, fCut);
+
+    Int_t first=0;
+    for (int i=0; i<fPositions.GetEntriesFast(); i++)
+    {
+        // Try to find Led in this area
+        const Led &l0 = fPositions(i);
+        f.Execute(leds, TMath::FloorNint(l0.GetX()), TMath::FloorNint(l0.GetY()));
+
+        fNumDetectedLEDs = leds.GetEntries();
+
+        // Loop over newly found Leds
+        for (int j=first; j<leds.GetEntries(); j++)
+        {
+            Led &l1 = leds(j);
+
+            // Add Offset to Led
+            l1.AddOffset(l0.GetDx(), l0.GetDy());
+
+            // Mark Led in image (FIXME: Move to MStarguider)
+            f.MarkPoint(l1.GetX(), l1.GetY(), l1.GetMag());
+
+            //old
+            /*
+            // Fill values into Histogram
+            if (!fHistpr)
+                continue;
+
+            fHistled[i]->Fill(l1.GetX(), l1.GetY());
+            fHistw[i]->Fill(l1.GetPhi());
+            */
+        }
+        first = leds.GetEntries();
+    }
+
+    Rings rings;
+    rings.SetMinNumberLeds(fMinNumberLeds);
+//    rings.CalcRings(leds, 265, 268); 
+// rwagner
+//    rings.CalcRings(leds, 158, 164);
+    fNumDetectedRings = rings.CalcRings(leds, fMinRadius, fMaxRadius);
+
+    const Ring &center = rings.GetCenter();
+
+//uncommented for testing
+//    center.Print();
+
+    // FIXME!
+    static const MTime t0(t);
+    fEvtTime = t-t0;
+
+    if (fHistpr)
+    {
+        fHistpr->Fill(center.GetR());
+        fHistprxpry->Fill(center.GetX(), center.GetY());
+        fGraphprx->SetPoint(fGraphprx->GetN(), fEvtTime, center.GetX());
+        fGraphpry->SetPoint(fGraphpry->GetN(), fEvtTime, center.GetY());
+
+        //new
+        //-----
+        Double_t sum = 0;
+        for (int j=0; j<leds.GetEntries(); j++)
+        {
+            Led &l1 = leds(j);
+
+            fHistled[j]->Fill(l1.GetX(), l1.GetY());
+            //fHistw[j]->Fill(l1.GetPhi());
+
+            Double_t phi[6] =
+            {
+                0,
+		0,
+		0,
+		0,
+		0,
+		0
+            };
+
+            const Double_t w = (leds(j).GetPhi()-phi[j])*60;
+            sum += w;
+
+            fHistw[j]->Fill(w);
+            sum /= leds.GetEntries();
+        }
+        fGraphw->SetPoint(fGraphw->GetN(), fEvtTime, sum);
+        fHistallw->Fill(sum/leds.GetEntries());
+        //-----
+    }
+
+    /*
+    //test - give number of rings
+    cout << rings.GetEntries() << " " << flush;
+    */
+
+    if (printl)
+        leds.Print();
+    if (printr)
+        rings.Print();
+
+    if (fFile && leds.GetEntries()>0)
+    {
+        fZenithDist = pos.Zd(); //fCosy ? fCosy->GetPointingPos().Zd() : 0
+        fAzimuth    = pos.Az(); //fCosy ? fCosy->GetPointingPos().Az() : 0;
+
+        TTree *t = (TTree*)fFile->Get("Data");
+        t->Fill();
+    }
+
+    return center;
+    /*
+        if (fCaosAnalyse->IsEntryEnabled(IDM_kStopAnalyse))
+        {
+            const Ring &center = rings.GetCenter();
+
+            Double_t phi[6] =
+            {
+                -124.727,
+                 -61.0495,
+                 -16.7907,
+                  49.3119,
+                 139.086
+            };
+
+            Double_t sum = 0;
+            for (int i=0; i<6 && leds.At(i); i++)
+            {
+                const Double_t w = (leds(i).GetPhi()-phi[i])*60;
+
+                sum += w;
+
+                fHistw[i]->Fill(w);
+                fHistv[i]->Fill(leds(i).GetPhi());
+                fGraphw[i]->SetPoint(fGraphw[i]->GetN(), fEvtTime, w);
+            }
+            fHistallw->Fill(sum/5);
+            }
+            */
+}
+
+
+Int_t MCaos::ReadEnv(const TEnv &env, TString prefix, Bool_t print)
+{
+    if (IsEnvDefined(env, prefix, "File", print))
+        ReadResources(GetEnvValue(env, prefix, "File", "ledsxxx.txt"));
+
+    if (IsEnvDefined(env, prefix, "RadiusMin", print))
+        fMinRadius = GetEnvValue(env, prefix, "RadiusMin", fMinRadius);
+
+    if (IsEnvDefined(env, prefix, "RadiusMax", print))
+        fMaxRadius = GetEnvValue(env, prefix, "RadiusMax", fMaxRadius);
+
+    if (IsEnvDefined(env, prefix, "MinNumberLeds", print))
+        fMinNumberLeds = GetEnvValue(env, prefix, "MinNumberLeds", fMinNumberLeds);
+
+    if (IsEnvDefined(env, prefix, "SizeBox", print))
+        fSizeBox = GetEnvValue(env, prefix, "SizeBox", fSizeBox);
+
+    if (IsEnvDefined(env, prefix, "CleaningLevel", print))
+        fCut = GetEnvValue(env, prefix, "CleaningLevel", fCut);
+
+    if (IsEnvDefined(env, prefix, "ArcsecPerPixel", print))
+        fArcsecPerPixel = GetEnvValue(env, prefix, "ArcsecPerPixel", fArcsecPerPixel);
+
+    return kTRUE;
+}
Index: /trunk/FACT++/drive/MCaos.h
===================================================================
--- /trunk/FACT++/drive/MCaos.h	(revision 18618)
+++ /trunk/FACT++/drive/MCaos.h	(revision 18618)
@@ -0,0 +1,109 @@
+#ifndef CAOS_MCaos
+#define CAOS_MCaos
+
+#ifndef MARS_MParContainer
+#include "MParContainer.h"
+#endif
+#ifndef CAOS_Leds
+#include "Leds.h"
+#endif
+#ifndef CAOS_Ring
+#include "Ring.h"
+#endif
+
+#ifndef COSY_PixClient
+#include "PixClient.h" // byte
+#endif
+
+class TFile;
+class TH1F;
+class TH2F;
+class TGraph;
+
+class MTime;
+class ZdAz;
+
+class MCaos : public MParContainer
+{
+private:
+    TFile         *fFile;       // File we may write data to
+
+    Leds           fPositions;
+
+    Leds          *fLeds;
+    Double_t       fEvtTime;
+    Double_t       fZenithDist;
+    Double_t       fAzimuth;
+
+    TH1F          *fHistpr;
+    TH2F         **fHistled;
+    TH1F          *fHistallw;
+    TH1F         **fHistw;
+
+    TH2F          *fHistprxpry;
+
+    TGraph        *fGraphprx;
+    TGraph        *fGraphpry;
+    TGraph        *fGraphw;
+    TGraph        *fGraphr;
+
+    Short_t       fMinNumberLeds;      // minimum number of detected leds required
+    Double_t      fMinRadius;          // minimum radius for cut in ring radius
+    Double_t      fMaxRadius;          // maximum radius for cut in ring radius
+    UShort_t      fSizeBox;            // Size of the search box (side length in units of pixels)
+    Double_t      fCut;                // Cleaning level (sigma above noise)
+    Double_t      fArcsecPerPixel;     // Conversion from arcseconds to pixel
+
+    Int_t fNumDetectedLEDs;
+    Int_t fNumDetectedRings;
+
+public:
+    MCaos(const char *name=0, const char *title=0)
+        : fFile(NULL), fHistpr(NULL), fMinNumberLeds(5),
+        fMinRadius(265), fMaxRadius(268), fSizeBox(19), fCut(3.0)
+    {
+        fLeds = new Leds;
+    }
+
+    ~MCaos()
+    {
+        CloseFile();
+        DeleteHistograms();
+        delete fLeds;
+    }
+
+    void AddPosition(Float_t x, Float_t y, Float_t dx, Float_t dy)
+    {
+        fPositions.Add(x, y, dx, dy);
+    }
+
+    void ReadResources(const char *name="leds.txt");
+
+    void OpenFile();
+    void CloseFile();
+    
+    void SetMinNumberLeds(Short_t n)
+    {
+	fMinNumberLeds = n;
+    }
+
+    void SetMinRadius(Double_t min) { fMinRadius=min; }
+    void SetMaxRadius(Double_t max) { fMaxRadius=max; }
+
+    void InitHistograms();
+    void DeleteHistograms();
+    void ShowHistograms();
+    void ResetHistograms();
+
+    Int_t GetNumDetectedLEDs() const  { return fNumDetectedLEDs; }
+    Int_t GetNumDetectedRings() const { return fNumDetectedRings; }
+
+    Double_t GetArcsecPerPixel() const { return fArcsecPerPixel; }
+
+    Ring Run(byte *img, bool printl, bool printr, const ZdAz &pos, 
+             const MTime &t);
+
+    Int_t ReadEnv(const TEnv &env, TString prefix, Bool_t print=kFALSE);
+};
+
+#endif
Index: /trunk/FACT++/drive/MGImage.cc
===================================================================
--- /trunk/FACT++/drive/MGImage.cc	(revision 18618)
+++ /trunk/FACT++/drive/MGImage.cc	(revision 18618)
@@ -0,0 +1,251 @@
+//
+// This File contains the definition of the MGImage-class
+//
+//   Author: Thomas Bretz
+//   Version: V1.0 (1-8-2000)
+//
+// x11/src/GX11Gui.cxx
+//
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// MGImage
+//
+// If sync-mode is enabled the Redraw function is secured by a mutex (ignore
+// error messages about it comming from root) This has the advantage that
+// if you use a timer for screen update reading and writing the image is
+// synchronized. In this way you don't get flickering half images.
+//
+//////////////////////////////////////////////////////////////////////////////
+#include "MGImage.h"
+
+#include <TGX11.h>
+#include <TMutex.h>
+
+#include "MLog.h"
+#include "MLogManip.h"
+
+ClassImp(MGImage);
+
+using namespace std;
+
+MGImage::MGImage(const TGWindow* p, UInt_t w, UInt_t h, UInt_t options, ULong_t back)
+    : TGFrame(p, w, h, options, back), fWidth(w), fHeight(h)
+{
+    // p = pointer to MainFrame (not owner)
+    // w = width of frame
+    // h = width of frame
+
+    //
+    // Creat drawing semaphore
+    //
+    fMuxPixmap = new TMutex;
+
+    Resize(GetWidth(), GetHeight());
+
+    //
+    // create empty pixmap
+    //
+    fDefGC  = gVirtualX->CreateGC(fId, 0);
+    fImage  = (XImage*)gVirtualX->CreateImage(fWidth, fHeight);
+
+    gLog << all << "Detected Color Depth: " << gVirtualX->GetDepth() << endl;
+}
+
+MGImage::~MGImage()
+{
+    if (fMuxPixmap->Lock()==13)
+        cout << "MGImage::~MGImage - mutex is already locked by this thread" << endl;
+
+    gLog << inf2 << "Deleting MGImage..." << endl;
+
+    gVirtualX->DeleteGC(fDefGC);
+    gVirtualX->DeleteImage((Drawable_t)fImage);
+
+    //cout << fMuxPixmap->UnLock() << endl;
+
+    delete fMuxPixmap;
+
+    gLog << inf2 << "MGImage destroyed." << endl;
+}
+
+void MGImage::DoRedraw()
+{
+    if (TestBit(kSyncMode))
+        while (fMuxPixmap->Lock()==13)
+            usleep(1);
+
+    //    gVirtualX->DrawLine(fId, fDefGC, 0, 0, fWidth+2, 0);
+    //    gVirtualX->DrawLine(fId, fDefGC, 0, 0, 0, fHeight+2);
+    //    gVirtualX->DrawLine(fId, fDefGC, fWidth+2, 0,  fWidth+2, fHeight+2);
+    //    gVirtualX->DrawLine(fId, fDefGC, 0, fHeight+2, fWidth+2, fHeight+2);
+
+    //    if (TestBit(kNeedRedraw))
+    {
+        gVirtualX->PutImage(fId, fDefGC, (Drawable_t)fImage, 0, 0, 0, 0,
+                            fWidth, fHeight);
+        ResetBit(kNeedRedraw);
+    }
+
+    if (TestBit(kSyncMode))
+        if (fMuxPixmap->UnLock()==13)
+            gLog << warn << "MGImage::DoRedraw - tried to unlock mutex locked by other thread." << endl;
+}
+
+void MGImage::DrawImg16(unsigned short *d, char *s, char *e)
+{
+    // d=destination, s=source, e=end
+    // rrrrrggg gggbbbbb
+    //
+    while (s<e)
+    {
+        //         11111100    11111000      11111000
+        // *d++ = (*s&0xfc) | (*s&0xf8)<<5 | (*s&0xf8)<<11;
+
+        //      11111000       11111100       11111000
+        *d++ = (*s&0xf8)<<8 | (*s&0xfc)<<3 | (*s>>3);
+        s++;
+    }
+}
+
+void MGImage::DrawImg24(char *d, char *s, char *e)
+{
+    // d=destination, s=source, e=end
+    // rrrrrrrr gggggggg bbbbbbbb aaaaaaaa
+    //
+    while (s<e)
+    {
+        *d++ = *s;
+        *d++ = *s;
+        *d++ = *s++;
+        d++;
+    }
+}
+
+void MGImage::DrawImg(const byte *buffer)
+{
+    if (TestBit(kSyncMode))
+        while (fMuxPixmap->Lock()==13)
+            usleep(1);
+    else
+    {
+        const Int_t rc = fMuxPixmap->Lock();
+        if (rc==13)
+            cout << "MGImage::DrawImg - mutex is already locked by this thread" << endl;
+        if (rc)
+            return;
+    }
+
+    switch (gVirtualX->GetDepth())
+    {
+    case 8:
+        memcpy(fImage->data, buffer, fWidth*fHeight);
+        break;
+    case 16:
+        DrawImg16((unsigned short*)fImage->data, (char*)buffer, (char*)(buffer+fWidth*fHeight));
+        break;
+    case 24:
+        DrawImg24(fImage->data, (char*)buffer, (char*)(buffer+fWidth*fHeight));
+        break;
+    default:
+        cout << "Sorry, " << gVirtualX->GetDepth() << "bit color depth not yet implemented." << endl;
+    }
+
+    SetBit(kNeedRedraw);
+
+    if (fMuxPixmap->UnLock()==13)
+        cout << "MGImage::DrawImage - tried to unlock mutex locked by other thread." << endl;
+}
+
+void MGImage::DrawColImg16(unsigned short *d, char *s1, char *s2, char *e)
+{
+    // d=destination, s1=source1, s2=source2, e=end
+    // d:  rrrrrggg gggbbbbb
+    // s2:          00rrggbb
+    //
+    while (s1<e)
+    {
+        if (*s2)
+        {    
+            //      00000011   00001100        00110000
+            //*d++ = (*s2&0x3) | (*s2&0xb)<<3 | (*s2&0x30)<<7;
+            *d++ = (*s2&0x3)<<3 | (*s2&0xb)<<6 | (*s2&0x30)<<10;
+        }
+        else
+        {
+            //      11111100     11111000        11111100
+            *d++ = (*s1&0xfc) | (*s1&0xf8)<<5 | (*s1&0xfc)<<11;
+        }
+        s1++;
+        s2++;
+    }
+}
+
+void MGImage::DrawColImg24(char *d, char *s1, char *s2, char *e)
+{
+    // d=destination, s1=source1, s2=source2, e=end
+    while (s1<e)
+    {
+        if (*s2)
+        {
+            *d++ = ((*s2>>4)&0x3)*85;
+            *d++ = ((*s2>>2)&0x3)*85;
+            *d++ = ((*s2++ )&0x3)*85;
+            d++;
+            s1++;
+        }
+        else
+        {
+            *d++ = *s1;
+            *d++ = *s1;
+            *d++ = *s1++;
+            d++;
+            s2++;
+        }
+    }
+}
+
+void MGImage::DrawColImg(const byte *gbuf, const byte *cbuf)
+{
+    if (TestBit(kSyncMode))
+        while (fMuxPixmap->Lock()==13)
+            usleep(1);
+    else
+    {
+        const Int_t rc = fMuxPixmap->Lock();
+        if (rc==13)
+            cout << "MGImage::DrawColImg - mutex is already locked by this thread" << endl;
+        if (rc)
+            return;
+    }
+
+    // FROM libAfterImage:
+    // -------------------
+    //#define ALPHA_TRANSPARENT      	0x00
+    //#define ALPHA_SEMI_TRANSPARENT 	0x7F
+    //#define ALPHA_SOLID            	0xFF
+    // * Lowermost 8 bits - Blue channel
+    // * bits  8 to 15    - Green channel
+    // * bits 16 to 23    - Red channel
+    // * bits 24 to 31    - Alpha channel
+    //#define ARGB32_White    		0xFFFFFFFF
+    //#define ARGB32_Black    		0xFF000000
+
+    // FIXME: This loop depends on the screen color depth
+    switch (gVirtualX->GetDepth())
+    {
+    case 16:
+        DrawColImg16((unsigned short*)fImage->data, (char*)gbuf, (char*)cbuf, (char*)(gbuf+fWidth*fHeight));
+        break;
+    case 24:
+        DrawColImg24(fImage->data, (char*)gbuf, (char*)cbuf, (char*)(gbuf+fWidth*fHeight));
+        break;
+    default:
+        cout << "Sorry, " << gVirtualX->GetDepth() << "bit color depth not yet implemented." << endl;
+    }
+
+    SetBit(kNeedRedraw);
+
+    if (fMuxPixmap->UnLock()==13)
+        cout << "MGImage::DrawColImage - tried to unlock mutex locked by other thread." << endl;
+}
Index: /trunk/FACT++/drive/MGImage.h
===================================================================
--- /trunk/FACT++/drive/MGImage.h	(revision 18618)
+++ /trunk/FACT++/drive/MGImage.h	(revision 18618)
@@ -0,0 +1,59 @@
+#ifndef MGIMAGE_H
+#define MGIMAGE_H
+
+//
+// This File contains the declaration of the MGImage-class
+//
+//   Author: Thomas Bretz
+//   Version: V1.0 (1-8-2000)
+
+#ifndef ROOT_TGFrame
+#include <TGFrame.h>
+#endif
+#ifndef ROOT_TGX11
+#include <TGX11.h>
+#endif
+
+class TMutex;
+
+typedef unsigned char byte;
+
+class MGImage : public TGFrame
+{
+    XImage *fImage;
+
+    GContext_t fDefGC;
+    //Pixmap_t   fPixmap;
+
+    UInt_t fWidth;
+    UInt_t fHeight;
+
+    TMutex *fMuxPixmap; //! test
+
+    enum
+    {
+        kNeedRedraw = BIT(17),
+        kSyncMode   = BIT(18)
+    };
+
+    void DrawImg16(unsigned short *d, char *s, char *e);
+    void DrawImg24(char *d, char *s, char *e);
+    void DrawColImg16(unsigned short *d, char *s1, char *s2, char *e);
+    void DrawColImg24(char *d, char *s1, char *s2, char *e);
+
+public:
+    MGImage(const TGWindow* p, UInt_t w, UInt_t h, UInt_t options = kSunkenFrame, ULong_t back = fgDefaultFrameBackground);
+    ~MGImage();
+
+    void DoRedraw();
+
+    void DrawImg(const byte *buffer);
+    void DrawColImg(const byte *gbuf, const byte *cbuf);
+
+    void EnableSyncMode()  { SetBit(kSyncMode); }
+    void DisableSyncMode() { ResetBit(kSyncMode); }
+
+    ClassDef(MGImage, 0)
+};
+
+#endif // MGIMAGE_H
Index: /trunk/FACT++/drive/MPointing.cc
===================================================================
--- /trunk/FACT++/drive/MPointing.cc	(revision 18618)
+++ /trunk/FACT++/drive/MPointing.cc	(revision 18618)
@@ -0,0 +1,840 @@
+/* ======================================================================== *\
+!
+! *
+! * This file is part of MARS, the MAGIC Analysis and Reconstruction
+! * Software. It is distributed to you in the hope that it can be a useful
+! * and timesaving tool in analysing Data of imaging Cerenkov telescopes.
+! * It is distributed WITHOUT ANY WARRANTY.
+! *
+! * Permission to use, copy, modify and distribute this software and its
+! * documentation for any purpose is hereby granted without fee,
+! * provided that the above copyright notice appear in all copies and
+! * that both that copyright notice and this permission notice appear
+! * in supporting documentation. It is provided "as is" without express
+! * or implied warranty.
+! *
+!
+!
+!   Author(s): Thomas Bretz, 2003 <mailto:tbretz@astro.uni-wuerzburg.de>
+!
+!   Copyright: MAGIC Software Development, 2000-2007
+!
+!
+\* ======================================================================== */
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// MPointing
+// =========
+//
+// This is the class used for the pointing correction done in the MAGIC
+// drive software cosy. NEVER CHANGE IT WITHOUT CONTACTING THE AUTHOR FIRST!
+//
+// Variables/Coefficients
+// ----------------------
+//
+//    Double_t fIe   ; // [rad] Index Error in Elevation
+//    Double_t fIa   ; // [rad] Index Error in Azimuth
+//
+//    Double_t fFlop ; // [rad] Vertical Sag
+//     * do not use if not data: Zd<0
+//
+//    Double_t fNpae ; // [rad] Az-El Nonperpendicularity
+//
+//    Double_t fCa   ; // [rad] Left-Right Collimation Error
+//
+//    Double_t fAn   ; // [rad] Azimuth Axis Misalignment (N-S)
+//    Double_t fAw   ; // [rad] Azimuth Axis Misalignment (E-W)
+//
+//    Double_t fTf   ; // [rad] Tube fluxture (sin)
+//     * same as ecec if no data: Zd<0
+//    Double_t fTx   ; // [rad] Tube fluxture (tan)
+//     * do not use with NPAE if no data: Zd<0
+//
+//    Double_t fNrx  ; // [rad] Nasmyth rotator displacement, horizontan
+//    Double_t fNry  ; // [rad] Nasmyth rotator displacement, vertical
+//
+//    Double_t fCrx  ; // [rad] Alt/Az Coude Displacement (N-S)
+//    Double_t fCry  ; // [rad] Alt/Az Coude Displacement (E-W)
+//
+//    Double_t fEces ; // [rad] Elevation Centering Error (sin)
+//    Double_t fAces ; // [rad] Azimuth Centering Error (sin)
+//    Double_t fEcec ; // [rad] Elevation Centering Error (cos)
+//    Double_t fAcec ; // [rad] Azimuth Centering Error (cos)
+//
+//    Double_t fMagic1;// [rad] MAGIC culmination hysteresis
+//    Double_t fMagic2;// [rad] undefined
+//
+//    Double_t fDx;    // [rad] X-offset in camera (for starguider calibration)
+//    Double_t fDy;    // [rad] Y-offset in camera (for starguider calibration)
+//
+//
+//  Class Version 2:
+//  ----------------
+//    + fPx
+//    + fPy
+//    + fDx
+//    + fDy
+//
+//
+////////////////////////////////////////////////////////////////////////////
+#include "MPointing.h"
+
+#include <fstream>
+
+#include <TMinuit.h>
+
+#include "MLog.h"
+#include "MLogManip.h"
+
+#include "MTime.h"
+
+ClassImp(AltAz);
+ClassImp(ZdAz);
+ClassImp(RaDec);
+ClassImp(MPointing);
+
+using namespace std;
+
+#undef DEBUG
+//#define DEBUG(txt) txt
+#define DEBUG(txt)
+
+void ZdAz::Round()
+{
+    fX = TMath::Nint(fX);
+    fY = TMath::Nint(fY);
+}
+
+void ZdAz::Abs()
+{
+    fX = TMath::Abs(fX);
+    fY = TMath::Abs(fY);
+}
+
+void MPointing::Init(const char *name, const char *title)
+{
+    fName  = name  ? name  : "MPointing";
+    fTitle = title ? title : "Pointing correction model for the MAGIC telescope";
+
+    fCoeff = new Double_t*[kNumPar];
+    fNames = new TString[kNumPar];
+    fDescr = new TString[kNumPar];
+
+    fCoeff[kIA]     = &fIa;      fNames[kIA]     = "IA";
+    fCoeff[kIE]     = &fIe;      fNames[kIE]     = "IE";
+    fCoeff[kFLOP]   = &fFlop;    fNames[kFLOP]   = "FLOP";
+    fCoeff[kAN]     = &fAn;      fNames[kAN]     = "AN";
+    fCoeff[kAW]     = &fAw;      fNames[kAW]     = "AW";
+    fCoeff[kNPAE]   = &fNpae;    fNames[kNPAE]   = "NPAE";
+    fCoeff[kCA]     = &fCa;      fNames[kCA]     = "CA";
+    fCoeff[kTF]     = &fTf;      fNames[kTF]     = "TF";
+    fCoeff[kTX]     = &fTx;      fNames[kTX]     = "TX";
+    fCoeff[kECES]   = &fEces;    fNames[kECES]   = "ECES";
+    fCoeff[kACES]   = &fAces;    fNames[kACES]   = "ACES";
+    fCoeff[kECEC]   = &fEcec;    fNames[kECEC]   = "ECEC";
+    fCoeff[kACEC]   = &fAcec;    fNames[kACEC]   = "ACEC";
+    fCoeff[kNRX]    = &fNrx;     fNames[kNRX]    = "NRX";
+    fCoeff[kNRY]    = &fNry;     fNames[kNRY]    = "NRY";
+    fCoeff[kCRX]    = &fCrx;     fNames[kCRX]    = "CRX";
+    fCoeff[kCRY]    = &fCry;     fNames[kCRY]    = "CRY";
+    fCoeff[kMAGIC1] = &fMagic1;  fNames[kMAGIC1] = "MAGIC1";
+    fCoeff[kMAGIC2] = &fMagic2;  fNames[kMAGIC2] = "MAGIC2";
+    fCoeff[kPX]     = &fPx;      fNames[kPX]     = "PX";
+    fCoeff[kPY]     = &fPy;      fNames[kPY]     = "PY";
+    fCoeff[kDX]     = &fDx;      fNames[kDX]     = "DX";
+    fCoeff[kDY]     = &fDy;      fNames[kDY]     = "DY";
+
+    fDescr[kIA]     =  "Index Error Azimuth";
+    fDescr[kIE]     =  "Index Error Zenith Distance";
+    fDescr[kFLOP]   =  "Vertical Sag";
+    fDescr[kAN]     =  "Azimuth Axis Misalignment (N-S)";
+    fDescr[kAW]     =  "Azimuth Axis Misalignment (E-W)";
+    fDescr[kNPAE]   =  "Az-El Nonperpendicularity";
+    fDescr[kCA]     =  "Left-Right Collimation Error";
+    fDescr[kTF]     =  "Tube fluxture (sin)";
+    fDescr[kTX]     =  "Tube fluxture (tan)";
+    fDescr[kECES]   =  "Elevation Centering Error (sin)";
+    fDescr[kACES]   =  "Azimuth Centering Error (sin)";
+    fDescr[kECEC]   =  "Elevation Centering Error (cos)";
+    fDescr[kACEC]   =  "Azimuth Centering Error (cos)";
+    fDescr[kNRX]    =  "Nasmyth rotator displacement (horizontal)";
+    fDescr[kNRY]    =  "Nasmyth rotator displacement (vertical)";
+    fDescr[kCRX]    =  "Alt/Az Coude Displacement (N-S)";
+    fDescr[kCRY]    =  "Alt/Az Coude Displacement (E-W)";
+    fDescr[kMAGIC1] =  "MAGIC culmination hysteresis";
+    fDescr[kMAGIC2] =  "n/a";
+    fDescr[kPX]     =  "Starguider calibration fixed offset x";
+    fDescr[kPY]     =  "Starguider calibration fixed offset y";
+    fDescr[kDX]     =  "Starguider calibration additional offset dx";
+    fDescr[kDY]     =  "Starguider calibration additional offset dy";
+}
+
+void MPointing::Reset()
+{
+    Clear();
+}
+
+Bool_t MPointing::Load(const char *name)
+{
+    /*
+     ! MMT 1987 July 8
+     ! T   36   7.3622   41.448  -0.0481
+     !   IA        -37.5465    20.80602
+     !   IE        -13.9180     1.25217
+     !   NPAE       +7.0751    26.44763
+     !   CA         -6.9149    32.05358
+     !   AN         +0.5053     1.40956
+     !   AW         -2.2016     1.37480
+     ! END
+     */
+
+    ifstream fin(name);
+    if (!fin)
+    {
+        *fLog << err << "ERROR - Cannot open file '" << name << "'" << endl;
+        return kFALSE;
+    }
+
+    char c;
+    while (fin && fin.get()!='\n');
+    fin >> c;
+
+    if (c!='S' && c!='s')
+    {
+        *fLog << err << "Error: This in not a model correcting the star position (" << c << ")" << endl;
+        return kFALSE;
+    }
+
+    Clear();
+
+    cout << endl;
+
+    Double_t val;
+    fin >> val;
+    *fLog << inf;
+    //*fLog << "Number of observed stars: " << val << endl;
+    fin >> val;
+    //*fLog << "Sky RMS: " << val << "\"" << endl;
+    fin >> val;
+    //*fLog << "Refraction Constant A: " << val << "\"" << endl;
+    fin >> val;
+    //*fLog << "Refraction Constant B: " << val << "\"" << endl;
+
+    *fLog << endl;
+
+    *fLog << "  & = Name            Value                 Sigma " << endl;
+    *fLog << "--------------------------------------------------" << endl;
+
+    while (fin)
+    {
+        TString str;
+        fin >> str;
+        if (!fin)
+        {
+            *fLog << err << "ERROR - Reading file " << name << endl;
+            return kFALSE;
+        }
+
+        str = str.Strip(TString::kBoth);
+
+        if (str=="END")
+            break;
+
+        TString sout;
+
+        if (str[0]=='#')
+            continue;
+
+        if (str[0]=='&')
+        {
+            sout += " & ";
+            str.Remove(0);
+        }
+        else
+            sout += "   ";
+
+        if (str[1]=='=')
+        {
+            sout += "=  ";
+            str.Remove(0);
+        }
+        else
+            sout += "   ";
+
+        fin >> val;
+
+        sout += str;
+        sout += '\t';
+        sout += Form("%11f", val);
+        sout += UTF8::kDeg;
+        sout += "     \t";
+        val *= TMath::DegToRad();
+
+        // Find parameter
+        Int_t n = -1;
+        for (int i=0; i<kNumPar; i++)
+            if (str==fNames[i])
+            {
+                n = i;
+                *fCoeff[i] = val;
+                break;
+            }
+
+        fin >> val;
+        sout += Form("%9f%s", val, UTF8::kDeg);
+
+        if (*fCoeff[n]!=0 || val>0)
+            *fLog << sout << endl;
+
+        if (!fin)
+        {
+            *fLog << err << "ERROR - Reading line " << str << endl;
+            return kFALSE;
+        }
+
+        if (n<0)
+        {
+            *fLog << warn << "WARNING - Parameter " << str << " unknown." << endl;
+            continue;
+        }
+
+        // corresponding error
+        fError[n] = val*TMath::DegToRad();
+    }
+    *fLog << endl;
+
+    fName = name;
+
+    return kTRUE;
+}
+
+Bool_t MPointing::Save(const char *name)
+{
+    /*
+     ! MMT 1987 July 8
+     ! T   36   7.3622   41.448  -0.0481
+     !   IA        -37.5465    20.80602
+     !   IE        -13.9180     1.25217
+     !   NPAE       +7.0751    26.44763
+     !   CA         -6.9149    32.05358
+     !   AN         +0.5053     1.40956
+     !   AW         -2.2016     1.37480
+     ! END
+     */
+
+    ofstream fout(name);
+    if (!fout)
+    {
+        cout << "Error: Cannot open file '" << name << "'" << endl;
+        return kFALSE;
+    }
+
+    MTime t;
+    t.Now();
+
+    fout << "MAGIC1 " << t << endl;
+    fout << "S   00   000000   000000  0000000" << endl;
+    fout << setprecision(8);
+    for (int i=0; i<kNumPar; i++)
+    {
+        fout << " " << setw(6) << GetVarName(i) << " ";
+        fout << setw(13) << *fCoeff[i]*kRad2Deg << "   ";
+        fout << setw(11) << fError[i]*kRad2Deg << endl;
+    }
+    fout << "END" << endl;
+
+    fName = name;
+
+    return kTRUE;
+}
+
+Double_t MPointing::Sign(Double_t val, Double_t alt)
+{
+    // Some pointing corrections are defined as Delta ZA, which
+    // is (P. Wallace) defined [0,90]deg while Alt is defined
+    // [0,180]deg
+    return (TMath::Pi()/2-alt < 0 ? -val : val);
+}
+
+AltAz MPointing::AddOffsets(const AltAz &aa) const
+{
+    // Correct [rad]
+    // zdaz    [rad]
+    AltAz p = aa;
+
+    const AltAz I(fIe, fIa);
+    p += I;
+
+    return p;
+}
+
+ZdAz MPointing::AddOffsets(const ZdAz &zdaz) const
+{
+    AltAz p(TMath::Pi()/2-zdaz.Zd(), zdaz.Az());
+
+    AltAz c = AddOffsets(p);
+
+    return ZdAz(TMath::Pi()/2-c.Alt(), c.Az());
+}
+
+TVector3 MPointing::AddOffsets(const TVector3 &v) const
+{
+    AltAz p(TMath::Pi()/2-v.Theta(), v.Phi());
+    AltAz c = AddOffsets(p);
+
+    TVector3 rc;
+    rc.SetMagThetaPhi(1, TMath::Pi()/2-c.Alt(), c.Az());
+    return rc;
+}
+
+AltAz MPointing::SubtractOffsets(const AltAz &aa) const
+{
+    // Correct [rad]
+    // zdaz    [rad]
+    AltAz p = aa;
+
+    const AltAz I(fIe, fIa);
+    p -= I;
+
+    return p;
+}
+
+ZdAz MPointing::SubtractOffsets(const ZdAz &zdaz) const
+{
+    AltAz p(TMath::Pi()/2-zdaz.Zd(), zdaz.Az());
+
+    AltAz c = SubtractOffsets(p);
+
+    return ZdAz(TMath::Pi()/2-c.Alt(), c.Az());
+}
+
+TVector3 MPointing::SubtractOffsets(const TVector3 &v) const
+{
+    AltAz p(TMath::Pi()/2-v.Theta(), v.Phi());
+    AltAz c = SubtractOffsets(p);
+
+    TVector3 rc;
+    rc.SetMagThetaPhi(1, TMath::Pi()/2-c.Alt(), c.Az());
+    return rc;
+}
+
+AltAz MPointing::CalcAnAw(const AltAz &p, Int_t sign) const
+{
+    // Corrections for AN and AW without approximations
+    // as done by Patrick Wallace. The approximation cannot
+    // be used for MAGIC because the correctioon angle
+    // AW (~1.5deg) is not small enough.
+
+    // Vector in cartesian coordinates
+    TVector3 v1;
+
+    // Set Azimuth and Elevation
+    v1.SetMagThetaPhi(1, TMath::Pi()/2-p.Alt(), p.Az());
+
+
+    TVector3 v2(v1);
+//    cout << sign << endl;
+
+//    cout << "v1: " << v1.Theta()*TMath::RadToDeg() << " " << v1.Phi()*TMath::RadToDeg() << endl;
+
+    // Rotate around the x- and y-axis
+    v1.RotateY(sign*fAn);
+    v1.RotateX(sign*fAw);
+
+//    cout << "v1: " << v1.Theta()*TMath::RadToDeg() << " " << v1.Phi()*TMath::RadToDeg() << endl;
+//    cout << "v2: " << v2.Theta()*TMath::RadToDeg() << " " << v2.Theta()*TMath::RadToDeg() << endl;
+
+   // cout << "dv: " << (v2.Theta()-v1.Theta())*TMath::RadToDeg() << " " << (v2.Phi()-v1.Phi())*TMath::RadToDeg() << endl;
+
+    Double_t dalt = v1.Theta()-v2.Theta();
+    Double_t daz  = v1.Phi()  -v2.Phi();
+
+    //cout << dalt*TMath::RadToDeg() << " " << daz*TMath::RadToDeg() << endl;
+
+    if (daz>TMath::Pi())
+        daz -= TMath::TwoPi();
+    if (daz<-TMath::Pi())
+        daz += TMath::TwoPi();
+
+//    if (daz>TMath::Pi()/2)
+//    {
+//    }
+
+    AltAz d(dalt, daz);
+    return d;
+
+    // Calculate Delta Azimuth and Delta Elevation
+    /*
+    AltAz d(TMath::Pi()/2-v1.Theta(), v1.Phi());
+
+    cout << "p :  " << p.Alt()*TMath::RadToDeg() << " " << p.Az()*TMath::RadToDeg() << endl;
+    cout << "d :  " << d.Alt()*TMath::RadToDeg() << " " << d.Az()*TMath::RadToDeg() << endl;
+    d -= p;
+    cout << "d-p: " << d.Alt()*TMath::RadToDeg() << " " << d.Az()*TMath::RadToDeg() << endl;
+    d *= sign;
+    cout << "d* : " << d.Alt()*TMath::RadToDeg() << " " << d.Az()*TMath::RadToDeg() << endl;
+
+
+    cout << "p2:  " << 90-p.Alt()*TMath::RadToDeg() << " " << p.Az()*TMath::RadToDeg() << endl;
+    cout << "d2:  " << 90-d.Alt()*TMath::RadToDeg() << " " << d.Az()*TMath::RadToDeg() << endl;
+
+    Int_t s1 = 90-d.Alt()*TMath::RadToDeg() < 0 ? -1 : 1;
+    Int_t s2 = 90-p.Alt()*TMath::RadToDeg() < 0 ? -1 : 1;
+
+
+    if (s1 != s2)
+    {
+        //90-d.Alt() <-- -90+d.Alt()
+
+        d.Alt(d.Alt()-TMath::Pi());
+        cout << "Alt-" << endl;
+    }
+    cout << "d': " << 90-d.Alt()*TMath::RadToDeg() << " " << d.Az()*TMath::RadToDeg() << endl;*/
+ /*
+    // Fix 'direction' of output depending on input vector
+    if (TMath::Pi()/2-sign*p.Alt()<0)
+    {
+        d.Alt(d.Alt()-TMath::Pi());
+        cout << "Alt-" << endl;
+    }
+    //if (TMath::Pi()/2-sign*p.Alt()>TMath::Pi())
+    //{
+    //    d.Alt(TMath::Pi()-d.Alt());
+    //    cout << "Alt+" << endl;
+    //}
+
+    // Align correction into [-180,180]
+    while (d.Az()>TMath::Pi())
+    {
+        d.Az(d.Az()-TMath::Pi()*2);
+        cout << "Az-" << endl;
+    }
+    while (d.Az()<-TMath::Pi())
+    {
+        d.Az(d.Az()+TMath::Pi()*2);
+        cout << "Az+" << endl;
+    }
+   */
+    return d;
+}
+
+
+AltAz MPointing::Correct(const AltAz &aa) const
+{
+    // Correct [rad]
+    // zdaz    [rad]
+    AltAz p = aa;
+
+    DEBUG(cout << setprecision(16));
+    DEBUG(cout << "Bend7: " << 90-p.Alt()*180/TMath::Pi() << " " << p.Az()*180/TMath::Pi() << endl);
+
+    const AltAz CRX(-fCrx*sin(p.Az()-p.Alt()),  fCrx*cos(p.Az()-p.Alt())/cos(p.Alt()));
+    const AltAz CRY(-fCry*cos(p.Az()-p.Alt()), -fCry*sin(p.Az()-p.Alt())/cos(p.Alt()));
+    p += CRX;
+    p += CRY;
+
+    DEBUG(cout << "Bend6: " << 90-p.Alt()*180/TMath::Pi() << " " << p.Az()*180/TMath::Pi() << endl);
+
+    const AltAz NRX(fNrx*sin(p.Alt()), -fNrx);
+    const AltAz NRY(fNry*cos(p.Alt()), -fNry*tan(p.Alt()));
+    p += NRX;
+    p += NRY;
+
+    DEBUG(cout << "Bend5: " << 90-p.Alt()*180/TMath::Pi() << " " << p.Az()*180/TMath::Pi() << endl);
+
+    const AltAz CES(-fEces*sin(p.Alt()), -fAces*sin(p.Az()));
+    const AltAz CEC(-fEcec*cos(p.Alt()), -fAcec*cos(p.Az()));
+    p += CES;
+    p += CEC;
+
+    DEBUG(cout << "Bend4: " << 90-p.Alt()*180/TMath::Pi() << " " << p.Az()*180/TMath::Pi() << endl);
+
+    const AltAz TX(Sign(fTx/tan(p.Alt()), p.Alt()), 0);
+    const AltAz TF(Sign(fTf*cos(p.Alt()), p.Alt()), 0);
+    //p += TX;
+    p += TF;
+
+
+    DEBUG(cout << "Bend3: " << 90-p.Alt()*180/TMath::Pi() << " " << p.Az()*180/TMath::Pi() << endl);
+
+    /*
+     //New Corrections for NPAE and CA:
+     TVector3 v(1.,1.,1.); // Vector in cartesian coordinates
+
+     //Set Azimuth and Elevation
+     v.SetPhi(p.Az());
+     v.SetTheta(TMath::Pi()/2-p.Alt());
+     //Rotation Vectors:
+     TVector3 vNpae(             cos(p.Az()),              sin(p.Az()),             0);
+     TVector3   vCa( -cos(p.Az())*cos(p.Alt()), -sin(p.Az())*cos(p.Alt()), sin(p.Alt()));
+     //Rotate around the vectors vNpae and vCa
+     v.Rotate(fNpae, vNpae);
+     v.Rotate(fCa,     vCa);
+
+     p.Az(v.Phi());
+     p.Alt(TMath::Pi()/2-v.Theta());
+     */
+
+    //Old correction terms for Npae and Ca:
+    const AltAz CA(0, -fCa/cos(p.Alt()));
+    p += CA;
+
+    const AltAz NPAE(0, -fNpae*tan(p.Alt()));
+    p += NPAE;
+
+    DEBUG(cout << "Bend2: " << 90-p.Alt()*180/TMath::Pi() << " " << p.Az()*180/TMath::Pi() << endl);
+
+    const AltAz ANAW(CalcAnAw(p, -1));
+    p += ANAW;
+
+    /* Old correction terms for An and Aw:
+     const AltAz AW( fAw*sin(p.Az()), -fAw*cos(p.Az())*tan(p.Alt()));
+     const AltAz AN(-fAn*cos(p.Az()), -fAn*sin(p.Az())*tan(p.Alt()));
+     p += AW;
+     p += AN;
+    */
+
+    DEBUG(cout << "Bend1: " << 90-p.Alt()*180/TMath::Pi() << " " << p.Az()*180/TMath::Pi() << endl);
+
+    const AltAz FLOP(Sign(fFlop, p.Alt()), 0);
+    p += FLOP;
+
+    const AltAz MAGIC1(fMagic1*TMath::Sign(1., sin(p.Az())), 0);
+    p += MAGIC1;
+
+    const AltAz I(fIe, fIa);
+    p += I;
+
+    DEBUG(cout << "Bend0: " << 90-p.Alt()*180/TMath::Pi() << " " << p.Az()*180/TMath::Pi() << endl);
+
+    return p;
+}
+
+AltAz MPointing::CorrectBack(const AltAz &aa) const
+{
+    // Correct [rad]
+    // zdaz    [rad]
+    AltAz p = aa;
+
+    DEBUG(cout << setprecision(16));
+    DEBUG(cout << "Back0: " << 90-p.Alt()*180/TMath::Pi() << " " << p.Az()*180/TMath::Pi() << endl);
+
+    const AltAz I(fIe, fIa);
+    p -= I;
+
+    const AltAz MAGIC1(fMagic1*TMath::Sign(1., sin(p.Az())), 0);
+    p -= MAGIC1;
+
+    //const AltAz MAGIC1(fMagic1*sin(p.Az()), 0);
+    //p -= MAGIC1;
+
+    const AltAz FLOP(Sign(fFlop, p.Alt()), 0);
+    p -= FLOP;
+
+    DEBUG(cout << "Back1: " << 90-p.Alt()*180/TMath::Pi() << " " << p.Az()*180/TMath::Pi() << endl);
+
+    /* Old correction terms for An and Aw:
+     const AltAz AN(-fAn*cos(p.Az()), -fAn*sin(p.Az())*tan(p.Alt()));
+     const AltAz AW( fAw*sin(p.Az()), -fAw*cos(p.Az())*tan(p.Alt()));
+     p -= AN;
+     p -= AW;
+     */
+
+    const AltAz ANAW(CalcAnAw(p, -1));
+    p -= ANAW;
+
+    DEBUG(cout << "Back2: " << 90-p.Alt()*180/TMath::Pi() << " " << p.Az()*180/TMath::Pi() << endl);
+
+    //Old Correction terms for Npae and Ca:
+    const AltAz NPAE(0, -fNpae*tan(p.Alt()));
+    p -= NPAE;
+
+    const AltAz CA(0, -fCa/cos(p.Alt()));
+    p -= CA;
+
+    /*
+     //New Correction term for Npae and Ca:
+     TVector3 v2(1.,1.,1.); // Vector in cartesian coordinates
+     //Set Azimuth and Elevation
+     v2.SetPhi(p.Az());
+     v2.SetTheta(TMath::Pi()/2-p.Alt());
+     //Rotation Vectors:
+     TVector3 vNpae(             cos(p.Az()),              sin(p.Az()),             0);
+     TVector3   vCa( -cos(p.Az())*cos(p.Alt()), -sin(p.Az())*cos(p.Alt()), sin(p.Alt()));
+     //Rotate around the vectors vCa and vNpae
+     v2.Rotate(-fCa,     vCa);
+     v2.Rotate(-fNpae, vNpae);
+
+     p.Az(v2.Phi());
+     p.Alt(TMath::Pi()/2-v2.Theta());
+    */
+
+    DEBUG(cout << "Back3: " << 90-p.Alt()*180/TMath::Pi() << " " << p.Az()*180/TMath::Pi() << endl);
+
+    const AltAz TF(Sign(fTf*cos(p.Alt()), p.Alt()), 0);
+    const AltAz TX(Sign(fTx/tan(p.Alt()), p.Alt()), 0);
+    p -= TF;
+    //p -= TX;
+
+    DEBUG(cout << "Back4: " << 90-p.Alt()*180/TMath::Pi() << " " << p.Az()*180/TMath::Pi() << endl);
+
+    const AltAz CEC(-fEcec*cos(p.Alt()), -fAcec*cos(p.Az()));
+    const AltAz CES(-fEces*sin(p.Alt()), -fAces*sin(p.Az()));
+    p -= CEC;
+    p -= CES;
+
+    DEBUG(cout << "Back5: " << 90-p.Alt()*180/TMath::Pi() << " " << p.Az()*180/TMath::Pi() << endl);
+
+    const AltAz NRY(fNry*cos(p.Alt()), -fNry*tan(p.Alt()));
+    const AltAz NRX(fNrx*sin(p.Alt()), -fNrx);
+    p -= NRY;
+    p -= NRX;
+
+    DEBUG(cout << "Back6: " << 90-p.Alt()*180/TMath::Pi() << " " << p.Az()*180/TMath::Pi() << endl);
+
+    const AltAz CRY(-fCry*cos(p.Az()-p.Alt()), -fCry*sin(p.Az()-p.Alt())/cos(p.Alt()));
+    const AltAz CRX(-fCrx*sin(p.Az()-p.Alt()),  fCrx*cos(p.Az()-p.Alt())/cos(p.Alt()));
+    p -= CRY;
+    p -= CRX;
+
+    DEBUG(cout << "Back7: " << 90-p.Alt()*180/TMath::Pi() << " " << p.Az()*180/TMath::Pi() << endl);
+
+    return p;
+}
+
+ZdAz MPointing::Correct(const ZdAz &zdaz) const
+{
+    // Correct [rad]
+    // zdaz    [rad]
+    AltAz p(TMath::Pi()/2-zdaz.Zd(), zdaz.Az());
+    AltAz c = Correct(p);
+    return ZdAz(TMath::Pi()/2-c.Alt(), c.Az());
+}
+
+TVector3 MPointing::Correct(const TVector3 &v) const
+{
+    // Correct [rad]
+    // zdaz    [rad]
+    AltAz p(TMath::Pi()/2-v.Theta(), v.Phi());
+    AltAz c = Correct(p);
+    TVector3 rc;
+    rc.SetMagThetaPhi(1, TMath::Pi()/2-c.Alt(), c.Az());
+    return rc;
+}
+
+ZdAz MPointing::CorrectBack(const ZdAz &zdaz) const
+{
+    // Correct [rad]
+    // zdaz    [rad]
+    AltAz p(TMath::Pi()/2-zdaz.Zd(), zdaz.Az());
+    AltAz c = CorrectBack(p);
+    return ZdAz(TMath::Pi()/2-c.Alt(), c.Az());
+}
+
+TVector3 MPointing::CorrectBack(const TVector3 &v) const
+{
+    // Correct [rad]
+    // zdaz    [rad]
+    AltAz p(TMath::Pi()/2-v.Theta(), v.Phi());
+    AltAz c = CorrectBack(p);
+    TVector3 rc;
+    rc.SetMagThetaPhi(1, TMath::Pi()/2-c.Alt(), c.Az());
+    return rc;
+}
+
+void MPointing::SetParameters(const Double_t *par, Int_t n)
+{
+    Clear();
+
+    while (n--)
+        *fCoeff[n] = par[n]/kRad2Deg;
+}
+
+void MPointing::GetParameters(Double_t *par, Int_t n) const
+{
+    while (n--)
+        par[n] = *fCoeff[n]*kRad2Deg;
+}
+
+void MPointing::GetError(TArrayD &par) const
+{
+    par = fError;
+    for (int i=0; i<kNumPar; i++)
+        par[i] *= TMath::RadToDeg();
+}
+
+TVector2 MPointing::GetDxy() const
+{
+    return TVector2(fDx, fDy)*TMath::RadToDeg();
+}
+
+Double_t MPointing::GetPx() const
+{
+    return fPx*TMath::RadToDeg();
+}
+
+Double_t MPointing::GetPy() const
+{
+    return fPy*TMath::RadToDeg();
+}
+
+void MPointing::SetMinuitParameters(TMinuit &m, Int_t n) const
+{
+    if (n<0)
+        n = kNumPar;
+
+    Int_t ierflg = 0;
+
+    while (n--)
+        m.mnparm(n, fNames[n], *fCoeff[n]*kRad2Deg,  1, -360, 360, ierflg);
+}
+
+void MPointing::GetMinuitParameters(TMinuit &m, Int_t n)
+{
+    if (n<0 || n>m.GetNumPars())
+        n = m.GetNumPars();
+
+    while (n--)
+    {
+        m.GetParameter(n, *fCoeff[n], fError[n]);
+        *fCoeff[n] /= kRad2Deg;
+        fError[n]  /= kRad2Deg;
+    }
+}
+/*
+void FormatPar(TMinuit &m, Int_t n)
+{
+    Double_t par, err;
+    m.GetParameter(n, par, err);
+
+    int expp = (int)log10(par);
+    int expe = (int)log10(err);
+
+    if (err<2*pow(10, expe))
+        expe--;
+
+    Int_t exp = expe>expp ? expp : expe;
+
+    par = (int)(par/pow(10, exp)) * pow(10, exp);
+    err = (int)(err/pow(10, exp)) * pow(10, exp);
+
+    cout << par << " +- " << err << flush;
+}
+*/
+void MPointing::PrintMinuitParameters(TMinuit &m, Int_t n) const
+{
+    if (n<0)
+        n = m.GetNumPars();
+
+    cout << setprecision(3);
+
+    Double_t par, er;
+
+    while (n--)
+    {
+        m.GetParameter(n, par, er);
+        cout << Form(" %2d %6s: ", n, (const char*)fNames[n]);
+        cout << setw(8) << par << " \xb1 " << setw(6) <<  er << endl;
+    }
+}
Index: /trunk/FACT++/drive/MPointing.h
===================================================================
--- /trunk/FACT++/drive/MPointing.h	(revision 18618)
+++ /trunk/FACT++/drive/MPointing.h	(revision 18618)
@@ -0,0 +1,313 @@
+#ifndef MARS_MPointing
+#define MARS_MPointing
+
+#ifndef ROOT_TArrayD
+#include <TArrayD.h>
+#endif
+
+#ifndef ROOT_TVector2
+#include <TVector2.h>
+#endif
+
+#ifndef ROOT_TVector3
+#include <TVector3.h>
+#endif
+
+#ifndef MARS_MParContainer
+#include "MParContainer.h"
+#endif
+
+// ---------------------------------------------------
+
+#define XY TVector2
+
+inline TVector2 Div(const TVector2 &v1, const TVector2 &v2)
+{
+    return TVector2(v1.X()/v2.X(), v1.Y()/v2.Y());
+}
+inline TVector2 Mul(const TVector2 &v1, const TVector2 &v2)
+{
+    return TVector2(v1.X()*v2.X(), v1.Y()*v2.Y());
+}
+
+inline TVector2 operator-(const TVector2 &v) { return TVector2(-v.X(), -v.Y()); }
+
+class AltAz : public XY
+{
+public:
+    AltAz(double alt=0, double az=0) : XY(alt, az) {}
+
+    double Alt() const { return fX; }
+    double Az()  const { return fY; }
+
+    void operator*=(double c) { fX*=c; fY*=c; }
+    void operator/=(double c) { fX*=c; fY*=c; }
+
+    void Alt(double d) { fX=d; }
+    void Az(double d)  { fY=d; }
+    void operator*=(const XY &c)    { fX*=c.X(); fY*=c.Y(); }
+    void operator/=(const XY &c)    { fX/=c.X(); fY/=c.Y(); }
+    void operator-=(const AltAz &c) { fX-=c.fX; fY-=c.fY; }
+    void operator+=(const AltAz &c) { fX+=c.fX; fY+=c.fY; }
+
+    AltAz operator/(double c) const { return AltAz(fX/c, fY/c); }
+    AltAz operator*(double c) const { return AltAz(fX*c, fY*c); }
+    AltAz operator*(const XY &c) const { return AltAz(fX*c.X(), fY*c.Y()); }
+    AltAz operator/(const XY &c) const { return AltAz(fX/c.X(), fY/c.Y()); }
+    AltAz operator+(const AltAz &c) const { return AltAz(fX+c.fX, fY+c.fY); }
+    AltAz operator-(const AltAz &c) const { return AltAz(fX-c.fX, fY-c.fY); }
+    AltAz operator-() const { return AltAz(-fX, -fY); }
+
+    ClassDef(AltAz, 0)
+};
+
+class ZdAz : public XY
+{
+public:
+    ZdAz(double zd=0, double az=0) : XY(zd, az) {}
+    ZdAz(const ZdAz &c) : XY(c) {}
+
+    void operator*=(double c) { fX*=c; fY*=c; }
+    void operator/=(double c) { fX*=c; fY*=c; }
+
+    double Zd() const { return fX; }
+    double Az() const { return fY; }
+
+    void Zd(double d) { fX=d; }
+    void Az(double d) { fY=d; }
+    void operator*=(const XY &c)   { fX*=c.X(); fY*=c.Y(); }
+    void operator/=(const XY &c)   { fX/=c.X(); fY/=c.Y(); }
+    void operator-=(const ZdAz &c) { fX-=c.fX; fY-=c.fY; }
+    void operator+=(const ZdAz &c) { fX+=c.fX; fY+=c.fY; }
+
+    ZdAz operator/(double c) const { return ZdAz(fX/c, fY/c); }
+    ZdAz operator*(double c) const { return ZdAz(fX*c, fY*c); }
+    ZdAz operator*(const XY &c) const { return ZdAz(fX*c.X(), fY*c.Y()); }
+    ZdAz operator/(const XY &c) const { return ZdAz(fX/c.X(), fY/c.Y()); }
+    ZdAz operator+(const ZdAz &c) const { return ZdAz(fX+c.fX, fY+c.fY); }
+    ZdAz operator-(const ZdAz &c) const { return ZdAz(fX-c.fX, fY-c.fY); }
+    ZdAz operator-() const { return ZdAz(-fX, -fY); }
+
+    // MSlewing only?!?
+    double Ratio() const { return fX/fY; }
+    void Round();
+    void Abs();
+
+    ClassDef(ZdAz, 0)
+};
+
+class RaDec : public XY
+{
+public:
+    RaDec(double ra=0, double dec=0) : XY(ra, dec) {}
+
+    double Ra()  const { return fX; }
+    double Dec() const { return fY; }
+
+    void operator*=(double c) { fX*=c; fY*=c; }
+    void operator/=(double c) { fX*=c; fY*=c; }
+
+    void Ra(double x)  { fX = x; }
+    void Dec(double y) { fY = y; }
+
+    RaDec operator/(double c) const { return RaDec(fX/c, fY/c); }
+    RaDec operator*(double c) const { return RaDec(fX*c, fY*c); }
+    RaDec operator*(const XY &c) const { return RaDec(fX*c.X(), fY*c.Y()); }
+    RaDec operator+(const RaDec &c) const { return RaDec(fX+c.fX, fY+c.fY); }
+    RaDec operator-(const RaDec &c) const { return RaDec(fX-c.fX, fY-c.fY); }
+    RaDec operator-() const { return RaDec(-fX, -fY); }
+
+    ClassDef(RaDec, 0)
+};
+
+// ---------------------------------------------------
+
+class TMinuit;
+
+class MPointing : public MParContainer
+{
+private:
+    enum {
+        kIA,           // [rad] Index Error in Elevation
+        kIE,           // [rad] Index Error in Azimuth
+        kFLOP,         // [rad] Vertical Sag
+        kAN,           // [rad] Az-El Nonperpendicularity
+        kAW,           // [rad] Left-Right Collimation Error
+        kNPAE,         // [rad] Azimuth Axis Misalignment (N-S)
+        kCA,           // [rad] Azimuth Axis Misalignment (E-W)
+        kTF,           // [rad] Tube fluxture (sin)
+        kTX,           // [rad] Tube fluxture (tan)
+        kECES,         // [rad] Nasmyth rotator displacement, horizontal
+        kACES,         // [rad] Nasmyth rotator displacement, vertical
+        kECEC,         // [rad] Alt/Az Coude Displacement (N-S)
+        kACEC,         // [rad] Alt/Az Coude Displacement (E-W)
+        kNRX,          // [rad] Elevation Centering Error (sin)
+        kNRY,          // [rad] Azimuth Centering Error (sin)
+        kCRX,          // [rad] Elevation Centering Error (cos)
+        kCRY,          // [rad] Azimuth Centering Error (cos)
+        kMAGIC1,       // [rad] Magic Term (what is it?)
+        kMAGIC2,       // [rad] Magic Term (what is it?)
+        kPX,           // [rad] Starguider calibration fixed offset x
+        kPY,           // [rad] Starguider calibration fixed offset y
+        kDX,           // [rad] Starguider calibration additional offset dx
+        kDY,           // [rad] Starguider calibration additional offset dy
+        kNumPar   // Number of elements
+    };
+
+
+    Double_t fIe   ; // [rad] Index Error in Elevation
+    Double_t fIa   ; // [rad] Index Error in Azimuth
+    Double_t fFlop ; // [rad] Vertical Sag
+    Double_t fNpae ; // [rad] Az-El Nonperpendicularity
+    Double_t fCa   ; // [rad] Left-Right Collimation Error
+    Double_t fAn   ; // [rad] Azimuth Axis Misalignment (N-S)
+    Double_t fAw   ; // [rad] Azimuth Axis Misalignment (E-W)
+    Double_t fTf   ; // [rad] Tube fluxture (sin)
+    Double_t fTx   ; // [rad] Tube fluxture (tan)
+    Double_t fNrx  ; // [rad] Nasmyth rotator displacement, horizontal
+    Double_t fNry  ; // [rad] Nasmyth rotator displacement, vertical
+    Double_t fCrx  ; // [rad] Alt/Az Coude Displacement (N-S)
+    Double_t fCry  ; // [rad] Alt/Az Coude Displacement (E-W)
+    Double_t fEces ; // [rad] Elevation Centering Error (sin)
+    Double_t fAces ; // [rad] Azimuth Centering Error (sin)
+    Double_t fEcec ; // [rad] Elevation Centering Error (cos)
+    Double_t fAcec ; // [rad] Azimuth Centering Error (cos)
+    Double_t fMagic1; // [rad] Magic Term (what is it?)
+    Double_t fMagic2; // [rad] Magic Term (what is it?)
+
+    Double_t fPx;    // [rad] Starguider calibration fixed offset x
+    Double_t fPy;    // [rad] Starguider calibration fixed offset y
+    Double_t fDx;    // [rad] Starguider calibration additional offset dx
+    Double_t fDy;    // [rad] Starguider calibration additional offset dy
+
+    Double_t **fCoeff; //!
+    TString   *fNames; //!
+    TString   *fDescr; //!
+
+    TArrayD   fError;
+
+    void Init(const char *name=0, const char *title=0);
+
+    void Clear(Option_t *o="")
+    {
+        for (int i=0; i<kNumPar; i++)
+        {
+            *fCoeff[i] = 0;
+            fError[i] = -1;
+        }
+    }
+
+    static Double_t Sign(Double_t val, Double_t alt);
+    AltAz CalcAnAw(const AltAz &p, Int_t sign) const;
+
+public:
+    MPointing() : fError(kNumPar) { Init(); Clear(); }
+    MPointing(const char *name) : fError(kNumPar) { Init(); Clear(); Load(name); }
+    virtual ~MPointing() { delete [] fNames; delete [] fCoeff; delete [] fDescr; }
+
+    Bool_t Load(const char *name);
+    Bool_t Save(const char *name);
+
+    void Reset();
+
+    ZdAz     Correct(const ZdAz &zdaz) const;
+    AltAz    Correct(const AltAz &aaz) const;
+    TVector3 Correct(const TVector3 &v) const;
+
+    ZdAz     CorrectBack(const ZdAz &zdaz) const;
+    AltAz    CorrectBack(const AltAz &aaz) const;
+    TVector3 CorrectBack(const TVector3 &v) const;
+
+    ZdAz     operator()(const ZdAz &zdaz)  const { return Correct(zdaz); }
+    AltAz    operator()(const AltAz &aaz)  const { return Correct(aaz); }
+    TVector3 operator()(const TVector3 &v) const { return Correct(v); }
+
+    ZdAz operator()(const ZdAz &zdaz, void (*fcn)(ZdAz &zdaz, Double_t *par)) const
+    {
+        Double_t par[kNumPar];
+        GetParameters(par);
+        ZdAz za = zdaz;
+        fcn(za, par);
+        return za;
+    }
+
+    AltAz operator()(const AltAz &aaz, void (*fcn)(AltAz &aaz, Double_t *par)) const
+    {
+        Double_t par[kNumPar];
+        GetParameters(par);
+        AltAz aa = aaz;
+        fcn(aa, par);
+        return aa;
+    }
+
+    TVector3 operator()(const TVector3 &aaz, void (*fcn)(TVector3 &aaz, Double_t *par)) const
+    {
+        Double_t par[kNumPar];
+        GetParameters(par);
+        TVector3 v = aaz;
+        fcn(v, par);
+        return v;
+    }
+
+    AltAz    AddOffsets(const AltAz &aa) const;
+    ZdAz     AddOffsets(const ZdAz &zdaz) const;
+    TVector3 AddOffsets(const TVector3 &v) const;
+
+    AltAz    SubtractOffsets(const AltAz &aa) const;
+    ZdAz     SubtractOffsets(const ZdAz &zdaz) const;
+    TVector3 SubtractOffsets(const TVector3 &v) const;
+
+    void SetParameters(const Double_t *par, Int_t n=kNumPar);
+    void GetParameters(Double_t *par, Int_t n=kNumPar) const;
+
+    void SetParameters(const TArrayD &par)
+    {
+        SetParameters(par.GetArray(), par.GetSize());
+    }
+    void GetParameters(TArrayD &par) const
+    {
+        par.Set(kNumPar);
+        GetParameters(par.GetArray());
+    }
+    void GetError(TArrayD &par) const;
+
+    Double_t &operator[](UInt_t i) { return *fCoeff[i]; }
+
+    void SetMinuitParameters(TMinuit &m, Int_t n=-1) const;
+    void GetMinuitParameters(TMinuit &m, Int_t n=-1);
+    void PrintMinuitParameters(TMinuit &m, Int_t n=-1) const;
+
+    const TString &GetVarName(int i) const { return fNames[i]; }
+    const TString &GetDescription(int i) const { return fDescr[i]; }
+
+    /*
+     Double_t GetIe() const { return fIe; }
+     Double_t GetIa() const { return fIa; }
+     Double_t GetCa() const { return fCa; }
+     Double_t GetAn() const { return fAn; }
+     Double_t GetAw() const { return fAw; }
+     Double_t GetNrx() const { return fNrx; }
+     Double_t GetNry() const { return fNry; }
+     Double_t GetCrx() const { return fNrx; }
+     Double_t GetCry() const { return fNry; }
+     Double_t GetEces() const { return fEces; }
+     Double_t GetEcec() const { return fEcec; }
+     Double_t GetAces() const { return fAces; }
+     Double_t GetAcec() const { return fAcec; }
+     Double_t GetNpae() const { return fNpae; }
+     */
+
+    TVector2 GetDxy() const;// { return TVector2(fDx, fDy)*TMath::RadToDeg(); }
+
+    Double_t GetPx() const;// { return fPx*TMath::RadToDeg(); }
+    Double_t GetPy() const;// { return fPy*TMath::RadToDeg(); }
+
+    Bool_t IsPxValid() const { return fError[kPX]>0; }
+    Bool_t IsPyValid() const { return fError[kPY]>0; }
+
+    static const Int_t GetNumPar() { return kNumPar; }
+
+    ClassDef(MPointing, 2) // Pointing Model for MAGIC
+};
+
+#endif
Index: /trunk/FACT++/drive/MStarguider.cc
===================================================================
--- /trunk/FACT++/drive/MStarguider.cc	(revision 18618)
+++ /trunk/FACT++/drive/MStarguider.cc	(revision 18618)
@@ -0,0 +1,2129 @@
+#undef EXPERT
+#define FACT
+
+#include "MStarguider.h"
+
+#include <fstream>    // ifstream
+
+#include <TH2F.h>
+#include <TGraph.h>
+#include <TTimer.h>
+#include <TEnv.h>
+#include <TSystem.h>
+#include <TFile.h> // temp writeout of histos
+//#include <TSocket.h>
+
+#include <TGMenu.h>
+#include <TGLabel.h>
+#include <TGButton.h>
+#include <TGSplitter.h>    // TGHorizontal3DLine
+#include <TGTextEntry.h>
+#include <TGLayout.h>
+#include "MString.h"
+
+#include "MLog.h"
+#include "MLogManip.h"
+
+#include "MAstro.h"
+#include "MString.h"
+
+
+#include "MCosy.h"
+#include "MCaos.h"
+// #include "MStargLeds.h"
+#include "MStargHistograms.h"
+#include "MDriveCom.h"
+
+#include "MGStarg.h" 
+#include "MGNumStars.h"
+
+#include "MGImage.h"
+#include "MGCoordinates.h"
+
+#include "Camera.h"
+#include "PngReader.h"
+
+#include "Led.h"
+#include "Writer.h"
+#include "FilterLed.h"
+#include "MStarList.h"
+#include "CaosFilter.h"
+#include "StarCatalog.h"
+#include "MGeomCamMagic.h"
+#include "MAstroCamera.h"
+
+#include "MGCosy.h"
+
+ClassImp(MStarguider);
+
+using namespace std;
+
+enum {
+    IDM_kFilter,
+    IDM_kFindStar,
+    IDM_kCaosFilter,
+    IDM_kCatalog,
+    IDM_kStarguider,
+    IDM_kStart,
+    IDM_kStop,
+    IDM_kFileType,
+    IDM_kPPM,
+    IDM_kPNG,
+    IDM_kOnce,
+    IDM_kStretch,
+    IDM_kInput,
+    IDM_kChannel1,
+    IDM_kChannel2,
+    IDM_kChannel3,
+    IDM_kContinous,
+    IDM_kRate25ps,
+    IDM_kRate5ps,
+    IDM_kRate1s,
+    IDM_kRate5s,
+    IDM_kRate30s,
+    IDM_kRate1m,
+    IDM_kRate5m,
+    IDM_kSetup,
+    IDM_kLimMag3,
+    IDM_kLimMag4,
+    IDM_kLimMag5,
+    IDM_kLimMag6,
+    IDM_kLimMag7,
+    IDM_kLimMag8,
+    IDM_kLimMag9,
+    IDM_kPixSize,
+    IDM_kAngle,
+    IDM_kCut,
+    IDM_kInterpol250,
+    IDM_kInterpol125,
+    IDM_kInterpol50,
+    IDM_kInterpol25,
+    IDM_kInterpol10,
+    IDM_kInterpol5,
+    IDM_kInterpol2,
+    IDM_kInterpol1,
+    IDM_kCaosPrintRings,
+    IDM_kCaosPrintLeds,
+    IDM_kCaosAnalStart,
+    IDM_kCaosAnalStop,
+    IDM_kCaosWriteStart,
+    IDM_kCaosWriteStop,
+    IDM_kResetHistograms,
+    IDM_kStargAnalysis,
+    IDM_kStargCaosFilter,
+    IDM_kStarguiderMode,
+    IDM_kTpointMode
+
+};
+
+Bool_t MStarguider::HandleTimer(TTimer *t)
+{
+    if (IsMapped())
+    {
+        fImage->DoRedraw();
+        fZoomImage->DoRedraw();
+    }
+
+    if (fCosy && fCosy->GetWin()->IsMapped())
+        fCosy->GetWin()->GetImage()->DoRedraw();
+
+    fGStarg->Update(fPos, fD);   
+    if (fDisplay->IsEntryChecked(IDM_kStarguider))
+        fGNumStars->Update(fNumStarsDetected, fNumStarsCorrelated);
+ 
+    return kTRUE;
+}
+
+#define kZOOM 96
+
+XY MStarguider::GetCoordinates() const
+{
+    return fPZdAz->GetCoordinates();
+}
+
+void MStarguider::InitGui(Int_t channel)
+{
+    fList = new MGList;
+    fList->SetOwner();
+
+    const TGWindow *p=gClient->GetRoot();
+
+    fChannel = new TGPopupMenu(p);
+    fChannel->AddEntry("Starfield Camera", IDM_kChannel1);
+    fChannel->AddEntry("TPoint Camera",    IDM_kChannel2);
+    fChannel->AddEntry("Read from File",   IDM_kChannel3);
+    if (channel<0)
+        fChannel->CheckEntry(IDM_kChannel3);
+    else
+        fChannel->CheckEntry(channel==0?IDM_kChannel1:IDM_kChannel2);
+    fChannel->Associate(this);
+    fList->Add(fChannel);
+
+    fFileType = new TGPopupMenu(p);
+    fFileType->AddEntry("PP&M", IDM_kPPM);
+    fFileType->AddEntry("&PNG", IDM_kPNG);
+    fFileType->CheckEntry(IDM_kPNG);
+    fFileType->Associate(this);
+    fList->Add(fFileType);
+
+    fWriteType = new TGPopupMenu(p);
+    fWriteType->AddEntry("&Once",      IDM_kOnce);
+    fWriteType->AddEntry("&Continous", IDM_kContinous);
+    fWriteType->CheckEntry(IDM_kOnce);
+    fWriteType->Associate(this);
+    fList->Add(fWriteType);
+
+    fWriteRate = new TGPopupMenu(p);
+    fWriteRate->AddEntry("25/s", IDM_kRate25ps);
+    fWriteRate->AddEntry("5/s",  IDM_kRate5ps);
+    fWriteRate->AddEntry("1s",   IDM_kRate1s);
+    fWriteRate->AddEntry("5s",   IDM_kRate5s);
+    fWriteRate->AddEntry("30s",  IDM_kRate30s);
+    fWriteRate->AddEntry("1min", IDM_kRate1m);
+    fWriteRate->AddEntry("5min", IDM_kRate5m);
+    fWriteRate->CheckEntry(IDM_kRate1m);
+    fWriteRate->Associate(this);
+    fList->Add(fWriteRate);
+
+    fWrtRate = 25*60;
+
+    fLimMag = new TGPopupMenu(p);
+    fLimMag->AddEntry("3", IDM_kLimMag3);
+    fLimMag->AddEntry("4", IDM_kLimMag4);
+    fLimMag->AddEntry("5", IDM_kLimMag5);
+    fLimMag->AddEntry("6", IDM_kLimMag6);
+    fLimMag->AddEntry("7", IDM_kLimMag7);
+    fLimMag->AddEntry("8", IDM_kLimMag8);
+    fLimMag->AddEntry("9", IDM_kLimMag9);
+    fLimMag->CheckEntry(IDM_kLimMag9);
+    fLimMag->Associate(this);
+    fList->Add(fLimMag);
+
+    fSao->SetLimitMag(9.0);
+
+    fInterpol = new TGPopupMenu(p);
+    fInterpol->AddEntry("250", IDM_kInterpol250);
+    fInterpol->AddEntry("125", IDM_kInterpol125);
+    fInterpol->AddEntry("50",  IDM_kInterpol50);
+    fInterpol->AddEntry("25",  IDM_kInterpol25);
+    fInterpol->AddEntry("10",  IDM_kInterpol10);
+    fInterpol->AddEntry("5",   IDM_kInterpol5);
+    fInterpol->AddEntry("2",   IDM_kInterpol2);
+    fInterpol->AddEntry("Off", IDM_kInterpol1);
+    fInterpol->Associate(this);
+    fList->Add(fInterpol);
+
+    TString disp=gVirtualX->DisplayName();
+    gLog << all << "Display: " << disp << endl;
+    if (disp.First(':')>=0)
+        disp=disp(0, disp.First(':'));
+
+    if (disp.IsNull() || disp==(TString)"localhost")
+    {
+        fInterpol->CheckEntry(IDM_kInterpol5);
+        fIntRate = 50;
+    }
+    else
+    {
+        fInterpol->CheckEntry(IDM_kInterpol125);
+        fIntRate = 125;
+    }
+
+    fCaosPrint = new TGPopupMenu(p);
+    fCaosPrint->AddEntry("&Leds",  IDM_kCaosPrintLeds);
+    fCaosPrint->AddEntry("&Rings", IDM_kCaosPrintRings);
+    fCaosPrint->Associate(this);
+    fList->Add(fCaosPrint);
+
+    fCaosWrite = new TGPopupMenu(p);
+    fCaosWrite->AddEntry("&Start", IDM_kCaosWriteStart);
+    fCaosWrite->AddEntry("Sto&p",  IDM_kCaosWriteStop);
+    fCaosWrite->DisableEntry(IDM_kCaosWriteStop);
+    fCaosWrite->Associate(this);
+    fList->Add(fCaosWrite);
+
+    fCaosAnalyse = new TGPopupMenu(p);
+    fCaosAnalyse->AddEntry("S&tart Analysis", IDM_kCaosAnalStart);
+    fCaosAnalyse->AddEntry("St&op Analysis",  IDM_kCaosAnalStop);
+    fCaosAnalyse->DisableEntry(IDM_kCaosAnalStop);
+    fCaosAnalyse->Associate(this);
+    fList->Add(fCaosAnalyse);
+
+    fMenu = new TGMenuBar(this, 0, 0, kHorizontalFrame);
+    fDisplay       = fMenu->AddPopup("&Display");
+    fMode          = fMenu->AddPopup("&Mode");
+    fWritePictures = fMenu->AddPopup("&WritePics");
+    fSetup         = fMenu->AddPopup("&Setup");
+    fOperations    = fMenu->AddPopup("&Operations");
+    fMenu->Resize(fMenu->GetDefaultSize());
+    AddFrame(fMenu); 
+
+    //
+    // Create Menu for MStarguider Display
+    //
+    //fDisplay = new MMGPopupMenu(p);
+    fDisplay->AddEntry("&Filter",               IDM_kFilter);
+    fDisplay->AddEntry("Stretch",               IDM_kStretch);
+    fDisplay->AddSeparator();
+    fDisplay->AddEntry("Find &Star",            IDM_kFindStar);
+    fDisplay->AddEntry("C&aos Filter",          IDM_kCaosFilter);
+    fDisplay->AddSeparator();
+    fDisplay->AddEntry("SAO &Catalog",          IDM_kCatalog);
+    fDisplay->AddEntry("Starguider",            IDM_kStarguider);
+    fDisplay->AddEntry("Starguider LED Filter", IDM_kStargCaosFilter);
+    fDisplay->AddSeparator();    
+    if (channel>=0)
+        fDisplay->AddPopup("&Input",   fChannel);
+    fDisplay->CheckEntry(IDM_kStretch);
+    fDisplay->Associate(this);
+
+    fMode->AddEntry("Starguider", IDM_kStarguiderMode);
+    fMode->AddEntry("Tpoint",     IDM_kTpointMode);
+    fMode->Associate(this);
+
+    fWritePictures->AddEntry("&Start",      IDM_kStart);
+    fWritePictures->AddEntry("Sto&p",       IDM_kStop);
+    fWritePictures->AddSeparator();
+    fWritePictures->AddPopup("File &Type",  fFileType);
+    fWritePictures->AddPopup("&Write Type", fWriteType);
+    fWritePictures->AddPopup("Write &Rate", fWriteRate);
+    fWritePictures->DisableEntry(IDM_kStop);
+    fWritePictures->Associate(this);
+
+    fSetup->AddPopup("Lim. &Magnitude",      fLimMag);
+    fSetup->AddPopup("Disp. &Interpolation", fInterpol);
+    fSetup->Associate(this);
+
+    fOperations->AddEntry("Starguider Analysis", IDM_kStargAnalysis);
+    fOperations->DisableEntry(IDM_kStargAnalysis);
+    fOperations->Associate(this);
+
+    fCaOs = new TGPopupMenu(p);
+    fCaOs->AddPopup("&Write",   fCaosWrite);
+    fCaOs->AddPopup("&Print",   fCaosPrint);
+    fCaOs->AddPopup("&Analyse", fCaosAnalyse);
+    fCaOs->Associate(this);
+    fList->Add(fCaOs);
+
+    fGStarg = new MGStarg(this, 235);
+    fGStarg->Move(530,596+5);
+    fList->Add(fGStarg);
+
+    //RA,Dec for catalog
+    fCRaDec = new MGCoordinates(this, kETypeRaDec);
+    fCRaDec->Move(4, fMenu->GetDefaultHeight()+584);
+    AddFrame(fCRaDec);
+
+    //telescope position
+    fCZdAz = new MGCoordinates(this, kETypeZdAz, 2);
+    fCZdAz->Move(240+12+28, fMenu->GetDefaultHeight()+597);
+    AddFrame(fCZdAz);
+
+    //starguider position
+    fPZdAz = new MGCoordinates(this, kETypeZdAz, 2);
+    fPZdAz->Move(240+12+28, fMenu->GetDefaultHeight()+640);
+    AddFrame(fPZdAz);
+
+    //mispointing
+    fDZdAz = new MGCoordinates(this, kETypeZdAz, 2);
+    fDZdAz->Move(240+12+28, fMenu->GetDefaultHeight()+683);
+    AddFrame(fDZdAz);
+
+    fSZdAz = new MGCoordinates(this, kETypeZdAz, 2);
+    fSZdAz->Move(240+12+28, fMenu->GetDefaultHeight()+795);
+    AddFrame(fSZdAz);
+
+    fGNumStars = new MGNumStars(this, 235);
+    fGNumStars->DrawText("Number of stars");
+    fGNumStars->Move(278, fMenu->GetDefaultHeight()+713);
+    fList->Add(fGNumStars);
+
+    fTPoint = new TGTextButton(this, "TPoint");
+    //fTPoint->Move(4, fMenu->GetDefaultHeight()+785);
+    fTPoint->Move(170, fMenu->GetDefaultHeight()+785);
+    fTPoint->AllowStayDown(kTRUE);
+    AddFrame(fTPoint);
+    /*
+     fStargTPoint = new TGTextButton(this, "StargTPoint");
+     fStargTPoint->Move(170, fMenu->GetDefaultHeight()+785);
+     fStargTPoint->AllowStayDown(kTRUE);
+     AddFrame(fStargTPoint);
+    */
+
+    fFps = new TGLabel(this, "---fps");
+    fFps->SetTextJustify(kTextRight);
+    fFps->Move(650-495, fMenu->GetDefaultHeight()+714+23);
+    AddFrame(fFps);
+
+    fPosZoom = new TGLabel(this, "(----, ----) ----.--d/----.--d");
+    fPosZoom->SetTextJustify(kTextLeft);
+    fPosZoom->Move(4, fMenu->GetDefaultHeight()+765);
+    AddFrame(fPosZoom);
+
+    fSkyBright = new TGLabel(this, "Sky Brightness: ---         ");
+    fSkyBright->SetTextJustify(kTextLeft);
+    fSkyBright->Move(4, fMenu->GetDefaultHeight()+785);
+    AddFrame(fSkyBright);
+
+    TGLabel *l = new TGLabel(this, "deg");
+    l->SetTextJustify(kTextLeft);
+    l->Move(606-412, fMenu->GetDefaultHeight()+669);
+    AddFrame(l);
+
+    l = new TGLabel(this, "arcsec/pix");
+    l->SetTextJustify(kTextLeft);
+    l->Move(606-412, fMenu->GetDefaultHeight()+692);
+    AddFrame(l);
+
+    l = new TGLabel(this, "sigma");
+    l->SetTextJustify(kTextLeft);
+    l->Move(606-412, fMenu->GetDefaultHeight()+715);
+    AddFrame(l);
+
+    fCZdAzText = new TGLabel(this, "Zd/Az telescope pointing at");
+    fCZdAzText->SetTextJustify(kTextLeft);
+    fCZdAzText->Move(240+12+20+7, fMenu->GetDefaultHeight()+584-5);
+    AddFrame(fCZdAzText);
+
+    fPZdAzText = new TGLabel(this, "Zd/Az starguider pointing at");
+    fPZdAzText->SetTextJustify(kTextLeft);
+    fPZdAzText->Move(240+12+20+7, fMenu->GetDefaultHeight()+630+20-5-23);
+    AddFrame(fPZdAzText);
+
+    fDZdAzText = new TGLabel(this, "Zd/Az mispointing");
+    fDZdAzText->SetTextJustify(kTextLeft);
+    fDZdAzText->Move(240+12+20+7, fMenu->GetDefaultHeight()+676+2*20-5-46);
+    AddFrame(fDZdAzText);
+
+    // Set input box for rotation angle
+    fAngle = new TGTextEntry(this, "           ", IDM_kAngle);
+    fAngle->SetAlignment(kTextCenterX);
+    fAngle->Move(547-410, fMenu->GetDefaultHeight()+667);
+    AddFrame(fAngle);
+
+    SetRotationAngle(-0.2);
+
+    // Set input box for pixel size
+    fPixSize = new TGTextEntry(this, "           ", IDM_kPixSize);
+    fPixSize->SetAlignment(kTextCenterX);
+    fPixSize->Move(547-410, fMenu->GetDefaultHeight()+690);
+    AddFrame(fPixSize);
+
+    SetPixSize(48.9);
+
+    // Set input box for cleaning cut
+    fCut = new TGTextEntry(this, "           ", IDM_kCut);
+    fCut->SetAlignment(kTextCenterX);
+    fCut->Move(547-410, fMenu->GetDefaultHeight()+713);
+    AddFrame(fCut);
+
+    SetCut(3.0);
+
+    // TGHorizontal3DLine *fLineSep = new TGHorizontal3DLine(this);
+    // AddFrame(fLineSep, new TGLayoutHints (kLHintsNormal | kLHintsExpandX));
+    // fList->Add(fLineSep);
+
+    //
+    // Create Image Display
+    //
+    fZoomImage = new MGImage(this, kZOOM, kZOOM);
+    // fZoomImage->Move(768-kZOOM-2, 700-kZOOM-2);
+    fZoomImage->Move(4, 700-kZOOM-2+85);
+    AddFrame(fZoomImage);
+
+    fImage = new MGImage(this, 768, 576);
+    fImage->Move(0, fMenu->GetDefaultHeight());
+    AddFrame(fImage);
+
+    const Int_t w = 768;
+    const Int_t h = 840;
+    SetWMSizeHints(w, h, w, h, 1, 1);  // set the smallest and biggest size of the Main frame
+
+    //
+    // Make everything visible
+    //
+    SetWindowName("MStarguider Main Window");
+    SetIconName("MStarguider");
+
+    MapSubwindows();
+    fTPoint->UnmapWindow();
+    //fStargTPoint->UnmapWindow();
+    fGStarg->UnmapWindow();
+    fGNumStars->UnmapWindow();
+    fCRaDec->UnmapWindow();
+    fCZdAz->UnmapWindow();
+    fCZdAzText->UnmapWindow();
+    fPZdAz->UnmapWindow();
+    fPZdAzText->UnmapWindow();
+    fDZdAz->UnmapWindow();
+    fDZdAzText->UnmapWindow();
+    fSZdAz->UnmapWindow();
+    fSkyBright->UnmapWindow();
+    MapWindow();
+
+
+    //IconifyWindow();
+
+    //------------------------------------------------------------
+    //    XY xy(3.819444, 24.05333);
+    //    fCRaDec->SetCoordinates(xy);
+    //    fRaDec->Set(xy.X()*360/24, xy.Y());
+    //------------------------------------------------------------
+}
+
+MStarguider::MStarguider(MObservatory::LocationName_t obs, Int_t channel)
+    : TGMainFrame(gClient->GetRoot(), 768, 840), 
+      fNumStarsDetected(0),
+      fNumStarsCorrelated(0),
+      fCosy(NULL),
+      fOutTp(0),
+      fOutStargTp(0),
+//      fOutRq(0),
+      fDx((768-kZOOM)/2),
+      fDy((512-kZOOM)/2),
+      fStatus(MDriveCom::kStandby),
+      fRadius(200),
+      fTPointFromCC(-1),
+      fFindStarCut(3.0), fFindStarBox(70)
+{
+    gLog << warn << " #### FIXME: Make MCaos Thread safe!" << endl;
+
+    // This means that all objects added with AddFrame are deleted
+    // automatically, including all LayoutHints.
+    SetCleanup();
+
+    fSao = new StarCatalog(obs);
+    fRaDec = new RaDec(180, 40);
+
+    fCaos = new MCaos;
+    fStargCaos = new MCaos;
+
+    fStargHistograms = new MStargHistograms();
+
+    InitGui(channel);
+
+    fTimer=new TTimer(this, 1000/25); // 40ms
+    fTimer->TurnOn();
+
+    fTime.Now();
+
+    fTimeFromTp.Clear();
+    fAltAzOffsetFromTp = AltAz(-1000,-1000);
+                                             
+    gVirtualX->GrabButton(fId, kButton2, 0, 0, 0, 0, kTRUE);
+
+    if (channel<0)
+        fGetter = new PngReader(*this);
+    else
+        fGetter = new Camera(*this, channel);
+}
+
+void MStarguider::SetRotationAngle(Double_t angle)
+{
+    fSao->SetRotationAngle(angle);
+
+    TString txt;
+    txt += angle;
+
+    fAngle->SetText(txt);
+}
+
+void MStarguider::SetPixSize(Double_t size)
+{
+    fSao->SetPixSize(size);
+
+    TString txt;
+    txt += size;
+
+    fPixSize->SetText(txt);
+}
+
+void MStarguider::SetCut(Double_t cut)
+{
+    TString txt;
+    txt += cut;
+
+    fCut->SetText(txt);
+}
+
+void MStarguider::SetupEnv(TEnv &env)
+{
+    fCaos->ReadEnv(env, "TPointLeds", kTRUE);
+    fStargCaos->ReadEnv(env, "StarguiderLeds", kTRUE);
+
+    SetRotationAngle(env.GetValue("Starguider.RotationAngle", fSao->GetRotationAngle()));
+    SetCut(env.GetValue("Starguider.CleaningLevel", atof(fCut->GetText())));
+
+    SetPixSize(env.GetValue("StarguiderLeds.ArcsecPerPixel", fSao->GetPixSize()));
+
+    fRadius = env.GetValue("Leds.Radius", fRadius);
+
+    fStarguiderW = env.GetValue("Starguider.Width",  fStarguiderW);
+    fStarguiderH = env.GetValue("Starguider.Height", fStarguiderH);
+    fStarguiderX = env.GetValue("Starguider.X",      fStarguiderX);
+    fStarguiderY = env.GetValue("Starguider.Y",      fStarguiderY);
+
+    fSkyOffsetX = env.GetValue("Starguider.SkyOffsetX", fSkyOffsetX);
+    fSkyOffsetY = env.GetValue("Starguider.SkyOffsetY", fSkyOffsetY);
+
+    fFindStarBox = env.GetValue("FindStar.SizeBox",       fFindStarBox);
+    fFindStarCut = env.GetValue("FindStar.CleaningLevel", fFindStarCut);
+}
+
+MStarguider::~MStarguider()
+{
+    fGetter->ExitLoop();
+    delete fGetter;
+
+    gVirtualX->GrabButton(fId, kButton2, 0, 0, 0, 0, kFALSE);
+
+    fTimer->TurnOff();
+    delete fTimer;
+
+    delete fList;
+
+    delete fCaos;
+    delete fStargCaos;
+    delete fStargHistograms;
+    delete fSao;
+    delete fRaDec;
+
+    if (fOutTp)
+        delete fOutTp;
+
+    if (fOutStargTp)
+        delete fOutStargTp;
+
+//    if (fOutRq)
+//        delete fOutRq;
+
+    gLog << inf2 << "Camera Display destroyed." << endl;
+}
+
+void MStarguider::Layout()
+{
+    // Resize(GetDefaultSize());
+}
+
+void MStarguider::CloseWindow()
+{
+    gLog << inf2 << "EventDisplay::CloseWindow: Exit Application Loop." << endl;
+
+    //fClient.ExitLoop();
+    //    cout << "FIXME: ExitLoop not called!!!!!!" << endl;
+    fGetter->ExitLoop();
+    gSystem->ExitLoop();
+}
+
+void MStarguider::SwitchOff(TGPopupMenu *p, UInt_t id)
+{
+    p->UnCheckEntry(id);
+    p->DisableEntry(id);
+}
+
+void MStarguider::SetChannel()
+{
+    if (fChannel->IsEntryChecked(IDM_kChannel3))
+    {
+        if (dynamic_cast<PngReader*>(fGetter)==0)
+        {
+            delete fGetter;
+            fGetter=new PngReader(*this);
+        }
+    }
+    else
+    {
+        const Int_t ch = fChannel->IsEntryChecked(IDM_kChannel1) ? 0 : 1;
+        if (dynamic_cast<Camera*>(fGetter)==0)
+        {
+            delete fGetter;
+            fGetter = new Camera(*this, ch);
+        }
+        else
+            fGetter->SetChannel(ch);
+    }
+}
+
+void MStarguider::Toggle(TGPopupMenu *p, UInt_t id)
+{
+    if (p->IsEntryChecked(id))
+        p->UnCheckEntry(id);
+    else
+        p->CheckEntry(id);
+}
+
+void MStarguider::ToggleStargAnalysis()
+{
+    if (fOperations->IsEntryChecked(IDM_kStargAnalysis))
+        fStargHistograms->OpenFile();
+    else
+        fStargHistograms->CloseFile();
+}
+
+/*
+void MStarguider::ToggleFindStar()
+{
+    if (fDisplay->IsEntryChecked(IDM_kFindStar) && fCosy)
+    fTPoint->MapWindow();
+    else
+    {
+        fTPoint->UnmapWindow();
+        fTPoint->SetDown(kFALSE);
+    }
+}
+*/
+void MStarguider::ToggleStarguider()
+{
+    if (fDisplay->IsEntryChecked(IDM_kStarguider))
+    {
+        fLastBright = 0xff;
+
+        fChannel->EnableEntry(IDM_kChannel1);
+        fDisplay->DisableEntry(IDM_kFindStar);
+        fDisplay->DisableEntry(IDM_kCaosFilter);
+        fOperations->EnableEntry(IDM_kStargAnalysis);
+
+        //fStargTPoint->MapWindow();
+
+        fPZdAz->MapWindow();
+        fDZdAz->MapWindow();
+        fSkyBright->MapWindow();
+
+        for (int i=IDM_kLimMag3; i<=IDM_kLimMag9; i++)
+            fLimMag->UnCheckEntry(i);
+        fLimMag->CheckEntry(IDM_kLimMag9);
+        fSao->SetLimitMag(9.0);
+
+        for (int i=IDM_kInterpol250; i<=IDM_kInterpol1; i++)
+            fInterpol->UnCheckEntry(i);
+        fInterpol->CheckEntry(IDM_kInterpol125);
+        fIntRate = 125;
+
+        //catalog
+        fDisplay->CheckEntry(IDM_kCatalog);
+        fCRaDec->MapWindow();
+        fCZdAz->MapWindow();
+        fCZdAzText->MapWindow();
+
+        fPZdAz->MapWindow();
+        fPZdAzText->MapWindow();
+        fDZdAz->MapWindow();
+        fDZdAzText->MapWindow();
+
+        fGStarg->MapWindow();
+        fGNumStars->MapWindow();
+
+        SwitchOff(fChannel, IDM_kChannel2);
+        fChannel->CheckEntry(IDM_kChannel1);
+    }
+    else
+    {
+        fStatus = MDriveCom::kStandby;
+
+        //fStargTPoint->UnmapWindow();
+        //fStargTPoint->SetDown(kFALSE);
+
+        fPZdAz->UnmapWindow();
+        fPZdAzText->UnmapWindow();
+        fDZdAz->UnmapWindow();
+        fDZdAzText->UnmapWindow();
+        fSkyBright->UnmapWindow();
+        //catalog
+        fCRaDec->UnmapWindow();
+        fCZdAz->UnmapWindow();
+        fCZdAzText->UnmapWindow();
+        fDisplay->UnCheckEntry(IDM_kCatalog);
+
+        fGStarg->UnmapWindow();
+        fGNumStars->UnmapWindow();
+
+        fChannel->EnableEntry(IDM_kChannel2);
+        fDisplay->EnableEntry(IDM_kFindStar);
+        fDisplay->EnableEntry(IDM_kCaosFilter);
+        fOperations->DisableEntry(IDM_kStargAnalysis);
+    }
+
+    SetChannel();
+    //gSystem->Unlink("tracking_error.txt");
+}
+
+void MStarguider::ToggleCaosFilter()
+{
+    if (fDisplay->IsEntryChecked(IDM_kCaosFilter))
+    {
+        if (!fMode->IsEntryChecked(IDM_kStarguiderMode)
+            && !fMode->IsEntryChecked(IDM_kTpointMode))
+            fMenu->AddPopup("&CaOs", fCaOs, NULL);
+
+        SwitchOff(fDisplay, IDM_kStarguider);
+        SwitchOff(fDisplay, IDM_kStargCaosFilter);
+    }
+    else
+    {
+        fCaosWrite->UnCheckEntry(IDM_kCaosPrintLeds);
+        fCaosWrite->UnCheckEntry(IDM_kCaosPrintRings);
+
+        if (fCaosAnalyse->IsEntryEnabled(IDM_kCaosAnalStop))
+        {
+            fCaosAnalyse->DisableEntry(IDM_kCaosAnalStop);
+            fCaosAnalyse->EnableEntry(IDM_kCaosAnalStart);
+            fCaos->DeleteHistograms();
+        }
+        if (fCaosWrite->IsEntryEnabled(IDM_kCaosWriteStop))
+        {
+            fCaosWrite->DisableEntry(IDM_kCaosWriteStop);
+            fCaosWrite->EnableEntry(IDM_kCaosWriteStart);
+            fCaos->CloseFile();
+        }
+        fMenu->RemovePopup("CaOs");
+
+        fDisplay->EnableEntry(IDM_kStargCaosFilter);
+        fDisplay->EnableEntry(IDM_kStarguider);
+    }
+    fMenu->Resize(fMenu->GetDefaultSize());
+    MapSubwindows(); // maps everything, but we don't want that
+    fTPoint->UnmapWindow();
+    //fStargTPoint->UnmapWindow();
+    fGStarg->UnmapWindow();
+    fGNumStars->UnmapWindow();
+    fCRaDec->UnmapWindow();
+    fCZdAz->UnmapWindow();
+    fCZdAzText->UnmapWindow();
+    fPZdAz->UnmapWindow();
+    fPZdAzText->UnmapWindow();
+    fDZdAz->UnmapWindow();
+    fDZdAzText->UnmapWindow();
+    fSZdAz->UnmapWindow();
+    fSkyBright->UnmapWindow();
+    MapWindow();
+}
+
+Bool_t MStarguider::ProcessMessage(Long_t msg, Long_t mp1, Long_t mp2)
+{
+    switch (GET_MSG(msg))
+    {
+    case kC_TEXTENTRY:
+        if (GET_SUBMSG(msg)==kTE_ENTER)
+            switch (mp1)
+            {
+            case IDM_kPixSize:
+                {
+                    const Float_t pixsize = atof(fPixSize->GetText());
+                    gLog << all << "Pixel Size changed to " << pixsize << "\"/pix" << endl;
+                    fSao->SetPixSize(pixsize);
+                    return kTRUE;
+                }
+            case IDM_kAngle:
+                {
+                    const Float_t angle = atof(fAngle->GetText());
+                    gLog << all << "Rotation Angle changed to " << angle << "deg" << endl;
+                    fSao->SetRotationAngle(angle);
+                    return kTRUE;
+                }
+            case IDM_kCut:
+                {
+                    const Float_t cut = atof(fCut->GetText());
+                    gLog << all << "Starguider cleaning level changed to " << cut << " sigma." << endl;
+                    return kTRUE;
+                }
+            }
+        return kTRUE;
+
+    case kC_COMMAND:
+        switch (GET_SUBMSG(msg))
+        {
+        case kCM_MENU:
+            switch (mp1)
+            {
+            case IDM_kCatalog:
+                Toggle(fDisplay, IDM_kCatalog);
+                if (fDisplay->IsEntryChecked(IDM_kCatalog))
+                {
+                    fCRaDec->MapWindow();
+                    fCZdAz->MapWindow();
+                    fCZdAzText->MapWindow();
+                }
+                else
+                {
+                    fCRaDec->UnmapWindow();
+                    fCZdAz->UnmapWindow();
+                    fCZdAzText->UnmapWindow();
+                }
+                return kTRUE;
+
+            case IDM_kStarguider:
+                Toggle(fDisplay, IDM_kStarguider);
+                ToggleStarguider();
+                return kTRUE;
+
+            case IDM_kStargAnalysis:
+                Toggle(fOperations, IDM_kStargAnalysis);
+                ToggleStargAnalysis();
+                return kTRUE;
+
+            case IDM_kStarguiderMode:
+                Toggle(fMode, IDM_kStarguiderMode);
+
+                if (fMode->IsEntryChecked(IDM_kStarguiderMode))
+                {
+                    //uncheck not needed items
+                    //general
+                    SwitchOff(fDisplay, IDM_kFilter);
+                    SwitchOff(fChannel, IDM_kChannel3);
+                    SwitchOff(fOperations, IDM_kStargAnalysis);
+
+                    //tpoint
+                    SwitchOff(fDisplay, IDM_kFindStar);
+                    SwitchOff(fDisplay, IDM_kCaosFilter);
+                    ToggleCaosFilter();
+                    fMode->UnCheckEntry(IDM_kTpointMode);
+
+                    //enable starguider items
+                    fDisplay->EnableEntry(IDM_kStargCaosFilter);
+                    fDisplay->EnableEntry(IDM_kStarguider);
+                    fDisplay->EnableEntry(IDM_kCatalog);
+
+                    //check needed items
+                    fDisplay->UnCheckEntry(IDM_kStretch);
+                    fDisplay->CheckEntry(IDM_kStargCaosFilter);
+                    fDisplay->CheckEntry(IDM_kStarguider);
+                    ToggleStarguider();
+
+                    fTPoint->MapWindow();
+                }
+                else
+                {
+                    //uncheck
+                    //starguider items
+                    fDisplay->UnCheckEntry(IDM_kStargCaosFilter);
+                    fDisplay->UnCheckEntry(IDM_kStarguider);
+                    fTPoint->UnmapWindow();
+                    ToggleStarguider();
+
+                    //general
+                    fDisplay->UnCheckEntry(IDM_kCatalog);
+                    fDisplay->EnableEntry(IDM_kFilter);
+                    fDisplay->EnableEntry(IDM_kCaosFilter);
+                    fDisplay->EnableEntry(IDM_kFindStar);
+                    fChannel->EnableEntry(IDM_kChannel3);
+                }
+                return kTRUE;
+
+            case IDM_kTpointMode:
+                Toggle(fMode, IDM_kTpointMode);
+
+                if (fMode->IsEntryChecked(IDM_kTpointMode))
+                {
+                    //unchecking not needed items
+                    //general
+                    SwitchOff(fDisplay, IDM_kFilter);
+                    SwitchOff(fChannel, IDM_kChannel3);
+
+                    //from starguider
+                    SwitchOff(fDisplay, IDM_kStargCaosFilter);
+                    SwitchOff(fDisplay, IDM_kCatalog);
+                    SwitchOff(fDisplay, IDM_kStarguider);
+                    ToggleStarguider();
+                    fMode->UnCheckEntry(IDM_kStarguiderMode);
+                    SwitchOff(fOperations, IDM_kStargAnalysis);
+                    ToggleStargAnalysis();
+
+                    //switch camera
+                    SwitchOff(fChannel, IDM_kChannel1);
+                    fChannel->CheckEntry(IDM_kChannel2);
+
+                    SetChannel();
+
+                    //checking needed items
+                    fDisplay->UnCheckEntry(IDM_kStretch);
+                    fDisplay->CheckEntry(IDM_kCaosFilter);
+                    ToggleCaosFilter();
+                    fDisplay->CheckEntry(IDM_kFindStar);
+                    fTPoint->MapWindow();
+                }
+                else
+                {
+                    //enable
+                    //starguider items
+                    fDisplay->EnableEntry(IDM_kStargCaosFilter);
+                    fDisplay->EnableEntry(IDM_kCatalog);
+                    fDisplay->EnableEntry(IDM_kStarguider);
+                    fOperations->EnableEntry(IDM_kStargAnalysis);
+
+                    //general
+                    fDisplay->EnableEntry(IDM_kFilter);
+                    fChannel->EnableEntry(IDM_kChannel1);
+                    fChannel->EnableEntry(IDM_kChannel3);
+
+                    //tpoint
+                    fDisplay->UnCheckEntry(IDM_kCaosFilter);
+                    ToggleCaosFilter();
+                    fDisplay->UnCheckEntry(IDM_kFindStar);
+                    fTPoint->UnmapWindow();
+                }
+                return kTRUE;
+
+            case IDM_kFilter:
+                Toggle(fDisplay, IDM_kFilter);           
+                return kTRUE;
+
+            case IDM_kFindStar:
+                Toggle(fDisplay, IDM_kFindStar);
+                //ToggleFindStar();
+                return kTRUE;
+
+            case IDM_kStretch:
+                Toggle(fDisplay, IDM_kStretch);
+                return kTRUE;
+
+            case IDM_kCaosFilter:
+                Toggle(fDisplay, IDM_kCaosFilter);
+                ToggleCaosFilter();
+                return kTRUE;
+
+            case IDM_kStargCaosFilter:
+		Toggle(fDisplay, IDM_kStargCaosFilter);                
+                if (fDisplay->IsEntryChecked(IDM_kStargCaosFilter))
+                {
+                    SwitchOff(fDisplay, IDM_kCaosFilter);
+                    SwitchOff(fDisplay, IDM_kFindStar);
+                    SwitchOff(fDisplay, IDM_kFilter);
+                }
+                else
+                {
+                    fDisplay->EnableEntry(IDM_kFilter);
+                    fDisplay->EnableEntry(IDM_kFindStar);
+                    fDisplay->EnableEntry(IDM_kCaosFilter);
+                }
+                return kTRUE;
+
+            case IDM_kCaosPrintLeds:
+            case IDM_kCaosPrintRings:
+                Toggle(fCaosPrint, mp1);
+                return kTRUE;
+
+            case IDM_kCaosAnalStart:
+                fCaosAnalyse->DisableEntry(IDM_kCaosAnalStart);
+                fCaosAnalyse->EnableEntry(IDM_kCaosAnalStop);
+                fCaos->InitHistograms();
+                return kTRUE;
+
+            case IDM_kCaosAnalStop:
+                fCaosAnalyse->DisableEntry(IDM_kCaosAnalStop);
+                fCaosAnalyse->EnableEntry(IDM_kCaosAnalStart);
+                fCaos->ShowHistograms();
+                fCaos->DeleteHistograms();
+                return kTRUE;
+
+            case IDM_kCaosWriteStart:
+                fCaosWrite->DisableEntry(IDM_kCaosWriteStart);
+                fCaosWrite->EnableEntry(IDM_kCaosWriteStop);
+                fCaos->OpenFile();
+                return kTRUE;
+
+            case IDM_kCaosWriteStop:
+                fCaosWrite->DisableEntry(IDM_kCaosWriteStop);
+                fCaosWrite->EnableEntry(IDM_kCaosWriteStart);
+                fCaos->CloseFile();
+                return kTRUE;
+
+            case IDM_kStart:
+                fWritePictures->DisableEntry(IDM_kStart);
+                fWritePictures->EnableEntry(IDM_kStop);
+                return kTRUE;
+
+            case IDM_kStop:
+                fWritePictures->DisableEntry(IDM_kStop);
+                fWritePictures->EnableEntry(IDM_kStart);
+                return kTRUE;
+
+            case IDM_kPNG:
+                fFileType->CheckEntry(IDM_kPNG);
+                fFileType->UnCheckEntry(IDM_kPPM);
+                return kTRUE;
+
+            case IDM_kPPM:
+                fFileType->CheckEntry(IDM_kPPM);
+                fFileType->UnCheckEntry(IDM_kPNG);
+                return kTRUE;
+
+            case IDM_kOnce:
+                fWriteType->CheckEntry(IDM_kOnce);
+                fWriteType->UnCheckEntry(IDM_kContinous);
+                return kTRUE;
+
+            case IDM_kContinous:
+                fWriteType->CheckEntry(IDM_kContinous);
+                fWriteType->UnCheckEntry(IDM_kOnce);
+                return kTRUE;
+
+            case IDM_kRate25ps:
+            case IDM_kRate5ps:
+            case IDM_kRate1s:
+            case IDM_kRate5s:
+            case IDM_kRate30s:
+            case IDM_kRate1m:
+            case IDM_kRate5m:
+                for (int i=IDM_kRate25ps; i<=IDM_kRate5m; i++)
+                    if (mp1==i)
+                        fWriteRate->CheckEntry(i);
+                    else
+                        fWriteRate->UnCheckEntry(i);
+                switch (mp1)
+                {
+                case IDM_kRate25ps:
+                    fWrtRate = 1;
+                    return kTRUE;
+                case IDM_kRate5ps:
+                    fWrtRate = 5;
+                    return kTRUE;
+                case IDM_kRate1s:
+                    fWrtRate = 25;
+                    return kTRUE;
+                case IDM_kRate5s:
+                    fWrtRate = 5*25;
+                    return kTRUE;
+                case IDM_kRate30s:
+                    fWrtRate = 30*25;
+                    return kTRUE;
+                case IDM_kRate1m:
+                    fWrtRate = 60*25;
+                    return kTRUE;
+                case IDM_kRate5m:
+                    fWrtRate = 5*60*25;
+                    return kTRUE;
+                }
+                return kTRUE;
+
+            case IDM_kChannel1:
+            case IDM_kChannel2:
+                {
+                    const Int_t ch0 = fChannel->IsEntryChecked(IDM_kChannel1) ? 0 : 1;
+                    const Int_t ch1 = mp1==IDM_kChannel1                      ? 0 : 1;
+
+		    if (ch0==ch1)
+                        return kTRUE;
+
+                    fChannel->CheckEntry  (ch1==0?IDM_kChannel1:IDM_kChannel2);
+                    fChannel->UnCheckEntry(ch1==1?IDM_kChannel1:IDM_kChannel2);
+
+                    SetChannel();
+                }
+                return kTRUE;
+
+            case IDM_kInterpol250:
+            case IDM_kInterpol125:
+            case IDM_kInterpol50:
+            case IDM_kInterpol25:
+            case IDM_kInterpol10:
+            case IDM_kInterpol5:
+            case IDM_kInterpol2:
+            case IDM_kInterpol1:
+                for (int i=IDM_kInterpol250; i<=IDM_kInterpol1; i++)
+                    if (mp1==i)
+                        fInterpol->CheckEntry(i);
+                    else
+                        fInterpol->UnCheckEntry(i);
+                switch (mp1)
+                {
+                case IDM_kInterpol1:
+                    fIntRate = 1;
+                    return kTRUE;
+                case IDM_kInterpol2:
+                    fIntRate = 2;
+                    return kTRUE;
+                case IDM_kInterpol5:
+                    fIntRate = 5;
+                    return kTRUE;
+                case IDM_kInterpol10:
+                    fIntRate = 10;
+                    return kTRUE;
+                case IDM_kInterpol25:
+                    fIntRate = 25;
+                    return kTRUE;
+                case IDM_kInterpol50:
+                    fIntRate = 50;
+                    return kTRUE;
+                case IDM_kInterpol125:
+                    fIntRate = 125;
+                    return kTRUE;
+                case IDM_kInterpol250:
+                    fIntRate = 250;
+                    return kTRUE;
+                }
+                return kTRUE;
+
+            case IDM_kLimMag3:
+            case IDM_kLimMag4:
+            case IDM_kLimMag5:
+            case IDM_kLimMag6:
+            case IDM_kLimMag7:
+            case IDM_kLimMag8:
+            case IDM_kLimMag9:
+                for (int i=IDM_kLimMag3; i<=IDM_kLimMag9; i++)
+                    if (mp1==i)
+                        fLimMag->CheckEntry(i);
+                    else
+                        fLimMag->UnCheckEntry(i);
+
+                fSao->SetLimitMag(mp1-IDM_kLimMag3+3);
+                return kTRUE;
+            }
+            break;
+        }
+        break;
+    }
+
+    return kTRUE;
+}
+
+void MStarguider::SetPointingPosition(RaDec rd)
+{
+    rd.Ra(rd.Ra()*24/360);
+    fCRaDec->SetCoordinates(rd);
+}
+
+ZdAz MStarguider::TrackingError(TArrayF &x, TArrayF &y, TArrayF &mag,
+                                Int_t &num) const
+{
+    num = -1;
+
+    // Width of the final 2D gaussian
+    const Double_t width = 0.8;
+
+    // The binning is made 1.7 sigma (which, in the 1D case, gives the 
+    // highest significance of a gaussian signal)  (1bin equiv 3x3 sigma)
+    const Double_t max =  50;
+    const Int_t    n   = TMath::Nint(2*max/(1.77*1.7*width));
+    //1.77=sqrt(pi) comes from pir=bin
+
+    // Fill a histogram with the dx/dy values from the file
+    TH2F hist("Hist", "dX/dY", n, -max, max, n, -max, max);
+//    hist.SetDirectory(0);
+
+    //
+    // Search for matching Magnitudes
+    //
+    //for (int i=0; i<mag.GetSize(); i++)
+    //{
+    //   if (mag[i]>48-15 && mag[i]<48+15)
+    //        h.Fill(x[i], y[i]);
+    //}
+
+    // fill dx and dy into histogram
+    for (int i=0; i<mag.GetSize(); i++)
+        hist.Fill(x[i], y[i]);
+
+    // Remove all bins which have content of only a single event
+    // including under- and overflow bins
+    for (int i=0; i<hist.GetSize(); i++)
+        if (hist.GetBinContent(i)<1.5)
+            hist.SetBinContent(i, 0);
+
+    // Find the bin containing the maximum
+    Int_t bx, by, bz;
+    hist.GetMaximumBin(bx, by, bz);
+
+    // In the worst case the events are spread through the
+    // bins which are the neighbors of the maximum
+    // Normally neighbors which do not belong to the signal are empty!
+    hist.GetXaxis()->SetRange(bx-1, bx+1); // 3x3bins  ~8x8pix  ~9x9sigma
+    hist.GetYaxis()->SetRange(by-1, by+1); // 3x3bins  ~8x8pix  ~9x9sigma
+
+    // Check whether this region contains events
+    num = TMath::Nint(hist.Integral());
+    if (num<1)
+        return ZdAz();
+
+    // Get Mean for the given axis range
+    Double_t mx = hist.GetMean(1);
+    Double_t my = hist.GetMean(2);
+
+    const Int_t max1 = TMath::Nint(hist.GetBinContent(bx, by));
+
+    // Check if the maximum is unique
+    Int_t bx2, by2, bz2;
+    hist.GetXaxis()->SetRange(-1, 9999);
+    hist.GetYaxis()->SetRange(-1, 9999);
+    hist.SetBinContent(bx, by, 0);
+    hist.GetMaximumBin(bx2, by2, bz2);
+
+    const Int_t max2 = TMath::Nint(hist.GetBinContent(bx2, by2));
+    if (max1==max2 && TMath::Abs(bx2-bx)+TMath::Abs(by2-by)>1)
+        return ZdAz();
+
+    // loop again over the file and fill the histogram again.
+    // to get closer to the correct value
+    Double_t sumx = 0;
+    Double_t sumy = 0;
+             num  = 0;
+    for (int i=0; i<mag.GetSize(); i++)
+    {
+        // only fill values into the histogram which
+        // are inside 2*1.7=3.4 sigma (99.7%)
+        if (TMath::Hypot(x[i]-mx, y[i]-my)>width*3.4)
+            continue;
+
+        sumx += x[i];
+        sumy += y[i];
+        num++;
+    }
+
+    if (num<1)
+        return ZdAz();
+
+    // calc MeanX and MeanY
+    mx = sumx/num;
+    my = sumy/num;
+
+    // loop again to fill the mispointing corrected histograms
+    // and fill another histogram to check the quality of the calculated
+    // mispointing.
+    sumx = 0;
+    sumy = 0;
+    num  = 0;
+    for (int i=0; i<mag.GetSize(); i++)
+    {
+        // only fill values into the histogram which
+        // are inside 1.7=3.4 sigma (92%)
+        // Cut at 1.7 sigma which gives the best background supression
+        if (TMath::Hypot(x[i]-mx, y[i]-my)>width*1.7)
+            continue;
+
+        sumx += x[i];
+        sumy += y[i];
+        num++;
+    }
+
+    if (num<1)
+        return ZdAz(); // FIXME!!!!!!!!!!!!
+
+    // Mispointing
+    mx = sumx/num;
+    my = sumy/num;
+
+#ifdef EXPERT
+    cout << "Offset-XY:    " << mx << " +- " << my << endl;
+#endif
+
+    return fSao->CalcDeltaZdAzFromPix(mx, my)*TMath::RadToDeg();
+/*
+    AltAz pos0 = fSao->CalcAltAzFromPix(768/2,    576/2)*kRad2Deg;
+    AltAz pos1 = fSao->CalcAltAzFromPix(768/2+mx, 576/2+my)*kRad2Deg;
+
+    pos1 -= pos0;
+
+    ZdAz res2 = ZdAz(-pos1.Alt(), pos1.Az());
+
+    return res1;
+*/
+}
+
+Int_t MStarguider::CalcTrackingError(const Leds &leds, MStarList &stars,
+                                     ZdAz &d, const MTime &t, const double &bright,
+                                     Int_t &num, const Ring &center, Int_t numleds, Int_t numrings)
+{
+    // Get tracking coordinates
+    const XY xy = fCRaDec->GetCoordinates();
+
+    num = leds.GetEntries();
+    if (num < 3) //was 1
+    {
+        gLog << warn << "Sorry, less than 3 detected spot in FOV!" << endl;
+        if (fTPoint->IsDown() && fCosy && fCosy->GetDriveCom())
+            fCosy->GetDriveCom()->SendTPoint(false, 'S', fTPointStarMag, fTPointStarName, AltAz(), ZdAz(), xy, 0, 0, t, center, Led(), numleds, numrings, num);    // Report
+        fTPoint->SetDown(kFALSE);
+        return 0;
+    }
+
+    if (stars.GetRealEntries() < 3)
+    {
+        gLog << warn << "Sorry, less than 3 stars in FOV!" << endl;
+        if (fTPoint->IsDown() && fCosy && fCosy->GetDriveCom())
+            fCosy->GetDriveCom()->SendTPoint(false, 'S', fTPointStarMag, fTPointStarName, AltAz(), ZdAz(), xy, 0, 0, t, center, Led(), numleds, numrings, num);    // Report
+        fTPoint->SetDown(kFALSE);
+        return 0;
+    }
+
+    stars.Sort(); // Sort by magnitude
+
+#ifdef EXPERT
+    TString str = "data/tracking_";
+    str += fSao->GetMjd();
+    str += ".txt";
+
+    ofstream fout(str);
+#endif
+
+    TArrayF x, y, mag;
+
+    // FIXME: Is predefined value 3 a good idea?
+    Int_t cnt=0;
+
+    MStar *star=0;
+    MStarListIter NextStar(&stars);
+    while ((star=NextStar()) && cnt<num+5)
+    {
+        TIter NextSp(&leds);
+        Led *spot=NULL;
+        while ((spot=(Led*)NextSp())) 
+	{
+            const XY dpos(spot->GetX()-(768-star->GetX()),
+                          spot->GetY()-star->GetY());
+	    
+            const Int_t idx = x.GetSize();
+
+            x.Set(idx+1);
+            y.Set(idx+1);
+            mag.Set(idx+1);
+
+            x.AddAt(dpos.X(), idx);
+            y.AddAt(dpos.Y(), idx);
+            mag.AddAt(1, idx);
+//            mag.AddAt(log(spot->GetMag())/star->GetMag(), idx);
+/*
+#ifdef EXPERT
+            if (fout)
+            {
+                fout << spot->GetX() << " "
+                    << spot->GetY()  << " "
+                    << -2.5*log(spot->GetMag())  << " "
+                    << star->GetX() << " "
+                    << star->GetY()  << " "
+                    << star->GetMag()  << " ";
+                fout << x[idx] << " " << y[idx] << " " << mag[idx] << endl;
+            }
+#endif
+*/
+        }
+        cnt++;
+    }
+
+    Int_t numcor = 0;
+    d = TrackingError(x, y, mag, numcor);
+    if (numcor<1)
+    {
+        fTPoint->SetDown(kFALSE);
+        if (fTPoint->IsDown() && fCosy && fCosy->GetDriveCom())
+            fCosy->GetDriveCom()->SendTPoint(false, 'S', fTPointStarMag, fTPointStarName, AltAz(), ZdAz(), xy, 0, 0, t, center, Led(), numleds, numrings, num, numcor);    // Report
+        return 0;
+    }
+
+    fDZdAz->SetCoordinates(d);
+
+    //
+    // Current Pointing position
+    //
+    ZdAz cpos = fSao->GetZdAz()-d;
+    fPZdAz->SetCoordinates(cpos);
+
+    // Check StargTPoint data set request
+    if (!fMode->IsEntryChecked(IDM_kStarguiderMode) || !fTPoint->IsDown())
+        return numcor;
+    fTPoint->SetDown(kFALSE);
+
+    // If no file open: open new file
+    if (!fOutStargTp)
+    {
+        // open tpoint file
+        const TString name = MCosy::GetFileName("tpoint", "starg", "txt");
+        gLog << all << "TPoint-Starg File ********* " << name << " ********** " << endl;
+
+        fOutStargTp = new ofstream(name);
+        *fOutStargTp << "Magic Model  STARGTPOINT data file" << endl;
+        *fOutStargTp << ": ALTAZ" << endl;
+        *fOutStargTp << "49 48 0 ";
+        *fOutStargTp << t << endl;
+    }
+
+    const RaDec rd(xy.X()*MAstro::HorToRad(), xy.Y()*TMath::DegToRad());
+
+    // From the star position in the camera we calculate the Alt/Az
+    // position we are currently tracking (real pointing position)
+    fSao->SetMjd(t.GetMjd());
+    AltAz za0 = fSao->CalcAltAz(rd)*kRad2Deg;
+
+    //correction with offset from last tpoint measurement
+    za0 -= fAltAzOffsetFromTp;
+
+    //if the difference between the tpoint and the starguider tpoint
+    //is too big, the starguider tpoint is not stored
+    if ((t.GetMjd()-fTimeFromTp.GetMjd())>0.001) //1min20sec
+    {
+        cout << "     time difference between tpoint and starguider-tpoint > 1m20s" << endl;
+        cout << "     => starguider tpoint hasn't been stored. " << endl;
+        cout << "        Please repeat whole procedure. " << endl;
+        return numcor;
+    }
+
+
+    // Write real pointing position
+    *fOutStargTp << setprecision(7) << za0.Az() << " " << za0.Alt() << " ";
+
+    // Write system pointing position
+    *fOutStargTp << fmod(cpos.Az()+360, 360) << " " << 90-cpos.Zd();
+
+    *fOutStargTp << " " << xy.X() << " " << xy.Y();
+    *fOutStargTp << " " << d.Zd() << " " << d.Az();
+    *fOutStargTp << " " << setprecision(11) << t.GetMjd();
+    *fOutStargTp << " " << setprecision(4) << center.GetMag();
+    *fOutStargTp << " 0";// << star->GetMag();
+    *fOutStargTp << " " << center.GetX() << " " << center.GetY();
+    *fOutStargTp << " 0 0";
+    *fOutStargTp << " " << numleds << " " << numrings;
+    *fOutStargTp << " " << num << " " << numcor << " " << bright;
+    *fOutStargTp << " " << fTPointStarMag << " " << fTPointStarName;
+    *fOutStargTp << endl;
+
+    gLog << all << "Starguider TPoint successfully taken." << endl;
+
+    fTimeFromTp.Clear();
+
+    if (!fCosy)
+        return numcor;
+
+    MDriveCom *com = fCosy->GetDriveCom();
+    if (!com)
+        return numcor;
+
+    com->SendTPoint(true, 'S', fTPointStarMag, fTPointStarName, za0, cpos, xy, d.Zd(), d.Az(), t, center, Led(), numleds, numrings, num, numcor);    // Report
+
+    return numcor;
+}
+
+void MStarguider::FindStar(const FilterLed &f, const FilterLed &f2, const Ring &center, const MTime &t, Int_t numleds, Int_t numrings)
+{
+    // Get tracking coordinates
+    const XY xy = fCRaDec->GetCoordinates();  // [h, deg]
+
+    if (center.GetX()<=0 && center.GetY()<=0)
+    {
+        gLog << warn << "Couldn't determine center of the camera." << endl;
+        if (fTPoint->IsDown() && fCosy && fCosy->GetDriveCom())
+            fCosy->GetDriveCom()->SendTPoint(false, 'T', fTPointStarMag, fTPointStarName, AltAz(), ZdAz(), xy, 0, 0, t, center, Led(), numleds, numrings);    // Report
+        return;
+    }
+
+    // Try to find the star
+    Leds leds;
+    f.FindStar(leds, (Int_t)center.GetX(), (Int_t)center.GetY(), true);
+
+    // Check whether star found
+    Led *star = (Led*)leds.At(0);
+    if (!star)
+    {
+        gLog << warn << "No star found." << endl;
+        if (fTPoint->IsDown() && fCosy && fCosy->GetDriveCom())
+            fCosy->GetDriveCom()->SendTPoint(false, 'T', fTPointStarMag, fTPointStarName, AltAz(), ZdAz(), xy, 0, 0, t, center, Led(), numleds, numrings);    // Report
+        return;
+    }
+
+    cout << "Found star @ " << flush;
+    star->Print();
+    f2.MarkPoint(star->GetX(), star->GetY(), 2<<2);
+
+    const RaDec rd(xy.X()*MAstro::HorToRad(), xy.Y()*TMath::DegToRad());
+
+    // Initialize Star Catalog on the camera plane
+    MGeomCamMagic geom;
+    MAstroCamera ac;
+    ac.SetGeom(geom);
+    ac.SetRadiusFOV(3);
+    ac.SetObservatory(*fSao);
+    ac.SetTime(t);
+    ac.SetRaDec(rd.Ra(), rd.Dec());
+
+    // Convert from Pixel to millimeter (1pix=2.6mm) [deg/pix / deg/mm = mm/pix]
+    // Correct for abberation.
+    const Double_t conv = fCaos->GetArcsecPerPixel()/3600/geom.GetConvMm2Deg()/ 1.0713;
+
+    // Adapt coordinate system (GUIs and humans are counting Y in different directions)
+    const Double_t dx = (star->GetX()-center.GetX())*conv;
+    const Double_t dy = (center.GetY()-star->GetY())*conv;
+
+    // Convert offset from camera plane into local ccordinates
+    Double_t dzd, daz;
+    ac.GetDiffZdAz(dx, dy, dzd, daz);
+
+    ZdAz zdaz(dzd,daz);
+
+    // Check TPoint data set request
+    if (!fMode->IsEntryChecked(IDM_kTpointMode) || !fTPoint->IsDown())
+        return;
+
+    // If no file open: open new file
+    if (!fOutTp)
+    {
+        //
+        // open tpoint file
+        //
+        const TString name = MCosy::GetFileName("tpoint", "tpoint", "txt");
+        cout << "TPoint File ********* " << name << " ********** " << endl;
+
+        fOutTp = new ofstream(name);
+        *fOutTp << "Magic Model  TPOINT data file" << endl;
+        *fOutTp << ": ALTAZ" << endl;
+        *fOutTp << "49 48 0 ";
+        *fOutTp << t << endl;
+        // temp(°C) pressure(mB) height(m) humidity(1) wavelength(microm) troplapserate(K/m)
+    }
+
+    // Output Ra/Dec the drive system thinks that it is currently tracking
+    //cout << "TPoint Star: " << xy.X() << "h " << xy.Y() << "°" << endl;
+
+    // From the star position in the camera we calculate the Alt/Az
+    // position we are currently tracking (real pointing position)
+    fSao->SetMjd(t.GetMjd());
+    AltAz za0 = fSao->CalcAltAz(rd)*kRad2Deg;
+
+    //ZdAz za0 = fSao->GetZdAz();
+    za0 -= AltAz(-dzd, daz);
+    fAltAzOffsetFromTp = AltAz(-dzd, daz);
+    fTimeFromTp=t;
+
+    // From the Shaftencoders we get the current 'pointing' position
+    // as it is seen by the drive system (system pointing position)
+    const ZdAz za1 = fCosy->GetSePos()*360; // [deg]
+
+
+    // Write real pointing position
+    //cout << "     Alt/Az: " << za0.Alt() << "° " << za0.Az() << "°" << endl;
+    *fOutTp << setprecision(7) << za0.Az() << " " << za0.Alt() << " ";
+
+    // Write system pointing position
+    //cout << "     SE-Pos: " << 90-za1.Zd() << "° " << za1.Az() << "°" << endl;
+    *fOutTp << fmod(za1.Az()+360, 360) << " " << 90-za1.Zd();
+
+    *fOutTp << " " << xy.X() << " " << xy.Y();
+    *fOutTp << " " << -dzd << " " << -daz;
+    *fOutTp << " " << setprecision(11) << t.GetMjd();
+    *fOutTp << " " << setprecision(4) << center.GetMag();
+    *fOutTp << " " << star->GetMag();
+    *fOutTp << " " << center.GetX() << " " << center.GetY();
+    *fOutTp << " " << star->GetX() << " " << star->GetY();
+    *fOutTp << " " << numleds << " " << numrings;
+    *fOutTp << " 0 0 0";
+    *fOutTp << " " << fTPointStarMag << " " << fTPointStarName;
+    *fOutTp << endl;
+
+    gLog << all << "TPoint successfully taken." << endl;
+/*
+    MLog &outrep = *fCosy->GetOutRep();
+    if (outrep.Lock("MStarguider::FindStar"))
+    {
+        outrep << "FINDSTAR-REPORT 00 " << MTime(-1) << " " << setprecision(7);
+        outrep << 90-za0.Alt() << " " << za0.Az() << " ";
+        outrep << za1.Zd() << " " << za1.Az() << " ";
+        outrep << xy.X() << " " << xy.Y() << " ";
+        outrep << -dzd << " " << -daz << " ";
+        outrep << star->GetX() << " " << star->GetY() << " ";
+        outrep << center.GetX() << " " << center.GetY() << " ";
+        outrep << dx/conv << " " << dy/conv << " " << star->GetMag();
+        outrep << setprecision(11) << t.GetMjd() << endl;
+        outrep.UnLock("MStarguider::FindStar");
+    }*/
+    
+//    return zdaz;
+
+    if (!fCosy)
+        return;
+
+    MDriveCom *com = fCosy->GetDriveCom();
+    if (!com)
+        return;
+
+    com->SendTPoint(true, 'T', fTPointStarMag, fTPointStarName, za0, za1, xy, -dzd, -daz, t, center, *star, numleds, numrings);    // Report
+}
+
+bool MStarguider::Interpolate(const unsigned long n, byte *img) const
+{
+    if (fIntRate<=1)
+        return true;
+
+    static unsigned short myimg[768*576];
+
+    unsigned short *f = myimg;
+
+    const byte *end = img+768*576;
+
+    if (n%fIntRate)
+    {
+        while (img<end)
+            *f++ += *img++;
+        return false;
+    }
+    else
+    {
+        while (img<end)
+        {
+            *img = (*img + *f)/fIntRate;
+            ++img;
+            *f++ = 0;
+        }
+
+        return true;
+    }
+}
+
+void MStarguider::DrawZoomImage(const byte *img)
+{
+    byte zimg[kZOOM*kZOOM];
+    for (int y=0; y<kZOOM; y++)
+        for (int x=0; x<kZOOM; x++)
+            zimg[x+y*kZOOM] = img[(fDx+(x-kZOOM/2)/2)+(fDy+(y-kZOOM/2)/2)*768];
+
+    fZoomImage->DrawImg(zimg);
+}
+
+void MStarguider::DrawCosyImage(const byte *img)
+{
+    if (!fCosy)
+        return;
+
+    byte simg[(768/2-1)*(576/2-1)];
+    for (int y=0; y<576/2-1; y++)
+        for (int x=0; x<768/2-1; x++)
+            simg[x+y*(768/2-1)] = ((unsigned int)img[2*x+2*y*768]+img[2*x+2*y*768+1]+img[2*x+2*(y+1)*768]+img[2*x+2*(y+1)*768+1])/4;
+
+    fCosy->GetWin()->GetImage()->DrawImg(simg);
+}
+
+void MStarguider::StartTPoint(char *cmd)
+{
+    fTPointStarName = "Dummy";
+    fTPointStarMag  = 0;
+
+    TString str(cmd);
+
+    TObjArray *arr = str.Tokenize(' ');
+
+    if (arr->GetEntries()==2)
+    {
+        fTPointStarName = (*arr)[0]->GetName();
+        fTPointStarMag  = atof((*arr)[1]->GetName());
+    }
+
+    delete arr;
+
+    if (fTPointFromCC<0)
+        fTPointFromCC=0;
+}
+
+void MStarguider::StartStarguider(bool on)
+{
+    // Switch to starguider mode
+    if (on)
+    {
+        cout << " * Switching Starguider mode on" << endl;
+        fMode->UnCheckEntry(IDM_kStarguiderMode);
+        ProcessMessage(MK_MSG(kC_COMMAND, kCM_MENU), IDM_kStarguiderMode, 0);
+    }
+    else
+    {
+        cout << " * Switching Starguider mode off" << endl;
+        fMode->CheckEntry(IDM_kStarguiderMode);
+        ProcessMessage(MK_MSG(kC_COMMAND, kCM_MENU), IDM_kStarguiderMode, 0);
+    }
+}
+
+Int_t MStarguider::GetStarguiderMode() const
+{
+    return fMode->IsEntryChecked(IDM_kStarguiderMode) ? 1 : 2;
+
+}
+
+Bool_t MStarguider::DoTPoint()
+{
+    if (fTPoint->IsDown() && fTPointFromCC<0)
+    {
+        fTPointFromCC = 0;
+        fTPoint->SetDown(kFALSE);
+    }
+
+    if (fTPointFromCC<0)
+        return kTRUE;
+
+    switch (++fTPointFromCC)
+    {
+    case 1:
+        fTimeFromTp.Clear();
+        fNumStarsDetected = 0;
+
+        if (!fMode->IsEntryChecked(IDM_kTpointMode))
+        {
+            cout << " * Switching to TPoint mode" << endl;
+            // Switch to tpoint mode
+            fMode->UnCheckEntry(IDM_kTpointMode);
+            ProcessMessage(MK_MSG(kC_COMMAND, kCM_MENU), IDM_kTpointMode, 0);
+            return kFALSE;
+        }
+        fTPointFromCC++;
+
+    case 2:
+    case 3:
+        cout << " * Waiting one frame" << endl;
+        // Wait one frame
+        return kFALSE;
+
+    case 4:
+        cout << " * Taking TPoint" << endl;
+        fTPoint->SetDown(); // kTRUE
+        return kTRUE;
+
+    case 5:
+        if (!fTimeFromTp) // TPoint failed
+            break;
+#ifdef FACT
+        fTPointFromCC = -1;
+        return kFALSE;
+#else
+        // Switch to starguider mode
+        cout << " * Switching to Starguider mode" << endl;
+        fMode->UnCheckEntry(IDM_kStarguiderMode);
+        ProcessMessage(MK_MSG(kC_COMMAND, kCM_MENU), IDM_kStarguiderMode, 0);
+        return kFALSE;
+#endif
+    case 6:
+    case 7:
+        cout << " * Waiting one frame" << endl;
+        // Wait one frame
+        return kFALSE;
+
+    case 8:
+        cout << " * Taking Starguider TPoint" << endl;
+        fTPoint->SetDown(); // kTRUE
+        return kTRUE;
+
+//    case 9:
+//        cout << " * Send Report" << endl;
+//        return kTRUE;
+
+    case 9:
+        cout << " * Switching to TPoint mode" << endl;
+        // Switch to tpoint mode
+        fMode->UnCheckEntry(IDM_kTpointMode);
+        ProcessMessage(MK_MSG(kC_COMMAND, kCM_MENU), IDM_kTpointMode, 0);
+        fTPointFromCC = -1;
+        return kFALSE;
+    }
+
+    // Send report
+/*
+    if (!fCosy)
+        return kTRUE;
+
+    MDriveCom *com = fCosy->GetDriveCom();
+    if (!com)
+        return kTRUE;
+
+    // nominalaz, nominalel, realaz, realel, nomra, nomdec,
+    // diffaz, diffel, mjd, numleds, artmag
+
+    //fTimeFromTp.Clear();
+    //fStatus==MDriveCom::kMonitoring
+    //fNumStarsDetected   = numstars;
+    //fNumStarsCorrelated = rc;
+    com->SendTPoint(fNumStarsCorrelated>0);
+*/
+    return kTRUE;
+}
+
+void MStarguider::ProcessFrame(const unsigned long n, byte *img, 
+			       struct timeval *tm)
+{
+    static unsigned long n0 = n;
+
+    MTime t(*tm);
+
+    const Double_t d = t-fTime;
+    if (d>1)
+    {
+        const TString txt = MString::Format("%dfps", (int)((n-n0)/d+.5));
+        fFps->SetText(txt);
+        fTime = t;
+        n0 = n;
+    }
+
+    if (!Interpolate(n, img))
+        return;
+
+    byte cimg[768*576];
+    memset(cimg, 0, 768*576);
+
+    FilterLed f(img,   768, 576, 2.5); // 2.5
+    FilterLed f2(cimg, 768, 576); // former color 0xb0
+
+    if (fDisplay->IsEntryChecked(IDM_kStretch))
+        f.Stretch();
+
+    if (!fWritePictures->IsEntryEnabled(IDM_kStart) &&
+        (!(n%fWrtRate) || fWriteType->IsEntryChecked(IDM_kOnce)))
+    {
+
+        if (fFileType->IsEntryChecked(IDM_kPNG))
+            Writer::Png("pix/file", img, tm, fCRaDec->GetCoordinates());
+
+        if (fFileType->IsEntryChecked(IDM_kPPM))
+            Writer::Ppm("pix/file", img, tm, fCRaDec->GetCoordinates());
+	
+        if (fWriteType->IsEntryChecked(IDM_kOnce))
+            ProcessMessage(MK_MSG(kC_COMMAND, kCM_MENU), IDM_kStop, 0);
+    }
+
+    // Visual Filter, whole FOV
+    if (fDisplay->IsEntryChecked(IDM_kFilter))
+        f.Execute();
+
+    if (!DoTPoint())
+        return;
+
+    Int_t numleds = 0;
+    Int_t numrings = 0;
+
+    // Find Center of Camera for Caos and Tpoints
+//    Ring center;//(-1, -1);
+    Ring center(5, 5);//(-1, -1);
+    if (fDisplay->IsEntryChecked(IDM_kCaosFilter))
+    {
+        const bool printl = fCaosPrint->IsEntryChecked(IDM_kCaosPrintLeds);
+        const bool printr = fCaosPrint->IsEntryChecked(IDM_kCaosPrintRings);
+        ZdAz pos;
+        if (fCosy)
+            pos = fCosy->GetPointingPos();
+
+        center = fCaos->Run(img, printl, printr, pos, t);
+
+        numleds  = fCaos->GetNumDetectedLEDs();
+        numrings = fCaos->GetNumDetectedRings();
+    }
+
+    // Find Star at Center---for Tpoint Procedure
+    if (fDisplay->IsEntryChecked(IDM_kFindStar))
+    {
+        // Set search Paremeters (FIXME: Get them from user input!)
+        f.SetCut(fFindStarCut);
+        f.SetBox(fFindStarBox);
+
+        FindStar(f, f2, center, t, numleds, numrings);
+    }
+
+    DrawZoomImage(img);
+    DrawCosyImage(img);
+
+    // Position corresponding to the camera center (53.2, 293.6)
+    Ring sgcenter;//(-1, -1); // Center of camera in SG picture [px]
+
+    // Find Center of Camera in Starfield Camera picture 
+    if (fDisplay->IsEntryChecked(IDM_kStargCaosFilter))
+    {
+        ZdAz pos;
+        if (fCosy)
+            pos = fCosy->GetPointingPos();
+
+        sgcenter = fStargCaos->Run(img, kFALSE, kFALSE, pos, t); // [px]
+
+        numleds  = fStargCaos->GetNumDetectedLEDs();
+        numrings = fStargCaos->GetNumDetectedRings();
+    }
+
+    // we obtain a list of stars in the FOV from the SAO catalog
+    if (fDisplay->IsEntryChecked(IDM_kCatalog))
+    {
+        MTime time(*tm);
+
+        XY xy = fCRaDec->GetCoordinates();  //[h,  deg]
+	fRaDec->Set(xy.X()*15, xy.Y());     //[deg,deg]
+
+	UpdatePosZoom();
+
+	// Always call SetMjd first!
+        fSao->SetPointing(time.GetMjd(), *fRaDec);
+  	fCZdAz->SetCoordinates(fSao->GetZdAz());
+
+    	fSao->SetBox(fStarguiderW, fStarguiderH); // 280 Region of interest around center
+
+        // If center of camera cannot be determined sgcenter is (0,0)
+        const Bool_t centerisvalid = sgcenter.GetX()>0 && sgcenter.GetY()>0;
+
+	// We determine the ideal starfield using camera sagging info
+        // from the LEDs
+        //Please never change this offsets!!!
+        // 53.2 and 293.6 are the "preliminary" camera center
+        // -9 and 28.5 are the offsets of the pointing position in the sky
+        //const XY off(sgcenter.GetX()- 53.2-9,
+        //             sgcenter.GetY()-293.6+28.5);
+
+        // Skycenter
+        const XY off(sgcenter.GetX() + fSkyOffsetX,
+                     sgcenter.GetY() + fSkyOffsetY);
+
+        MStarList stars;
+        if (centerisvalid)
+        {
+            // we obtain stars in the effective star FOV and draw them.
+            // coordinates are video frame coords.
+            fSao->CalcStars(stars, fStarguiderX, fStarguiderY, off.X(), off.Y());
+            fSao->DrawStars(stars, cimg);
+        }
+
+	// There are two corrections to the mispointing
+	// - Sagging of the camera as measured with the LEDs
+	// - Star not ideally centered on MAGIC Camera
+
+	// Next we evaluate the offset given by the LEDs. This we obtain
+        // in Zd/Az and add it to the tracking error.
+	if (fDisplay->IsEntryChecked(IDM_kStarguider))
+        {
+            const Float_t cut = atof(fCut->GetText());
+
+  	    Leds spots;
+            f.SetBox(fStarguiderW, fStarguiderH); // 280
+	    f.SetCut(cut);
+
+            double bright;
+ 	    f.ExecuteAndMark(spots, fStarguiderX, fStarguiderY, bright);
+
+            ULong_t color;
+	    gClient->GetColorByName("Green", color);
+            if (bright> 60)
+                gClient->GetColorByName("Yellow", color);
+            if (bright> 85)
+                gClient->GetColorByName("Orange", color);
+            if (bright> 95)
+                gClient->GetColorByName("Red", color);
+            fSkyBright->SetBackgroundColor(color);
+
+            const MString txt = MString::Format("Sky Brightness: %.1f", bright);
+ 	    fSkyBright->SetText(txt);
+
+            const Bool_t brightnessisvalid = bright<1.75*fLastBright &&
+                bright>30 && bright<110;
+
+            fLastBright = bright;
+
+            Int_t numstars = 0;
+            const Int_t rc = CalcTrackingError(spots, stars, fD, t, bright, numstars, sgcenter, numleds, numrings);
+
+            const Bool_t monitoring = brightnessisvalid && centerisvalid && fNumStarsCorrelated>2;
+
+            fStatus = monitoring ? MDriveCom::kMonitoring : MDriveCom::kError;
+
+            if (fCosy)
+                fPos = fCosy->GetPointingPos();
+
+            if (fOperations->IsEntryChecked(IDM_kStargAnalysis))
+                fStargHistograms->Fill(spots, stars, fD, fSao->GetZdAz(),
+                                       sgcenter, bright, fPos, t);
+
+            fNumStarsDetected   = numstars;
+            fNumStarsCorrelated = rc;
+
+            if (fCosy)
+            {
+                MDriveCom *com = fCosy->GetDriveCom();
+                if (com)
+                    com->SendStargReport(fStatus, fD, fSao->GetZdAz(),
+                                         sgcenter, numstars, rc, bright,
+                                         time.GetMjd(), numleds, numrings);    // Report
+            }
+
+        } //kStarguider
+
+        if (centerisvalid && fNumStarsCorrelated>2)
+        {
+            // Position around which the circles are drawn.
+            const Ring skycenter(off.X(), off.Y());
+
+            f2.DrawCircle(skycenter,   2.0,     0x0a);
+
+            const Double_t ap = fSao->GetPixSize()/3600; //[deg/pix]
+
+            f2.DrawCircle(skycenter,  0.10/ap, 0x0a); //0.1deg
+            f2.DrawHexagon(skycenter, 2.06/ap, 0x0a);
+            f2.DrawHexagon(skycenter, 3.50/ap, 0x0a);
+        }
+
+    } //CalcStars
+
+    if (fTPoint->IsDown())
+        fTPoint->SetDown(kFALSE);
+
+    // Draw Circles around center of Camera
+    if (fDisplay->IsEntryChecked(IDM_kCaosFilter) &&
+        center.GetX()>0 && center.GetY()>0)
+    {
+        f2.DrawCircle(center, 0x0a);
+        f2.DrawCircle(center,   7.0,
+		      fDisplay->IsEntryChecked(IDM_kFindStar)?3:0xb0);
+        f2.DrawCircle(center, 115.0, 0x0a);
+        f2.DrawCircle(center, 230.0, 0x0a);
+        f2.DrawCircle(center, 245.0, 0x0a);
+    }
+
+    if (fDisplay->IsEntryChecked(IDM_kStargCaosFilter) &&
+        sgcenter.GetX()>0 && sgcenter.GetY()>0)
+    {
+        f2.DrawCircle(sgcenter, 0x0a);
+        f2.DrawCircle(sgcenter,   5.0,
+                      fDisplay->IsEntryChecked(IDM_kFindStar)?3:0xb0);
+    }
+
+    if (fDisplay->IsEntryChecked(IDM_kCaosFilter) ||
+        fDisplay->IsEntryChecked(IDM_kCatalog)    ||
+        fDisplay->IsEntryChecked(IDM_kFindStar))
+        fImage->DrawColImg(img, cimg);
+    else
+        fImage->DrawImg(img);
+}
+
+void MStarguider::UpdatePosZoom()
+{
+    MString txt;/*
+    if (fDisplay->IsEntryChecked(IDM_kCatalog))
+    {
+        // FIXME: Necessary?
+        fSao->Now();
+        AltAz aa = fSao->CalcAltAzFromPix(fDx, fDy)*kRad2Deg;
+        if (aa.Az()<0)
+            aa.Az(aa.Az()+360);
+        txt.Form("(%d, %d) %.1fd/%.1fd", fDx, fDy, -aa.Alt(), aa.Az()-180);
+    }
+    else*/
+        txt.Form("(%d, %d)", fDx, fDy);
+    fPosZoom->SetText(txt);
+}
+
+Bool_t MStarguider::HandleDoubleClick(Event_t *event)
+{
+    const Int_t w = fImage->GetWidth();
+    const Int_t h = fImage->GetHeight();
+    const Int_t x = fImage->GetX();
+    const Int_t y = fImage->GetY();
+
+    if (!(event->fX>x && event->fX<x+w && event->fY>y && event->fY<y+h))
+        return kTRUE;
+
+    Int_t dx = event->fX-x;
+    Int_t dy = event->fY-y;
+
+    if (dx<kZOOM/4) dx=kZOOM/4;
+    if (dy<kZOOM/4) dy=kZOOM/4;
+    if (dx>766-kZOOM/4) dx=766-kZOOM/4;
+    if (dy>574-kZOOM/4) dy=574-kZOOM/4;
+
+    fDx = dx;
+    fDy = dy;
+
+    UpdatePosZoom();
+    return kTRUE;
+}
+
+void MStarguider::Print(TString &str, Double_t deg) const
+{
+    Char_t sgn;
+    UShort_t d, m, s;
+
+    MAstro::Deg2Dms(deg, sgn, d, m, s);
+
+    str += MString::Format("%c %03d %02d %03d ", sgn, d, m, s);
+}
Index: /trunk/FACT++/drive/MStarguider.h
===================================================================
--- /trunk/FACT++/drive/MStarguider.h	(revision 18618)
+++ /trunk/FACT++/drive/MStarguider.h	(revision 18618)
@@ -0,0 +1,214 @@
+#ifndef COSY_MStarguider
+#define COSY_MStarguider
+
+#include "PixClient.h"
+#include "MGImage.h"
+
+#include "MPointing.h"
+
+#ifndef MARS_MObservatory
+#include "MObservatory.h"
+#endif
+#ifndef MARS_MTime
+#include "MTime.h"
+#endif
+#ifndef MARS_MGList
+#include "MGList.h"
+#endif
+
+class TArrayF;
+class TGLabel;
+class TGButton;
+class TString;
+//class TSocket;
+
+class TTimer;
+
+class TGMenuBar;
+class TGPopupMenu;
+class TGTextEntry;
+
+class PixGetter;
+
+class MGImage;
+class MGCoordinates;
+
+class StarCatalog;
+class MStarList;
+class MCosy;
+class MCaos;
+// class MStargLeds;
+class MStargHistograms;
+class MGNumStars;
+class MGStarg;
+class FilterLed;
+class Ring;
+
+class Leds;
+#include <TGButton.h>
+class MStarguider : public PixClient, public TGMainFrame
+{
+private:
+    PixGetter     *fGetter;
+
+    MGList        *fList;
+
+    TGMenuBar     *fMenu;
+    MGImage       *fImage;
+    MGImage       *fZoomImage;
+
+    MGStarg       *fGStarg;
+    MGNumStars    *fGNumStars;
+
+    TGPopupMenu   *fDisplay;
+    TGPopupMenu   *fMode;
+    TGPopupMenu   *fWritePictures;
+    TGPopupMenu   *fSetup;
+    TGPopupMenu   *fOperations;
+
+    TGPopupMenu   *fFileType;
+    TGPopupMenu   *fWriteType;
+    TGPopupMenu   *fWriteRate;
+    TGPopupMenu   *fInterpol;
+    TGPopupMenu   *fLimMag;
+    TGPopupMenu   *fChannel;
+
+    TGPopupMenu   *fCaosWrite;
+    TGPopupMenu   *fCaosPrint;
+    TGPopupMenu   *fCaosAnalyse;
+    TGPopupMenu   *fCaOs;
+
+    MGCoordinates *fCRaDec;
+    MGCoordinates *fCZdAz;
+
+    MGCoordinates *fPZdAz;
+    MGCoordinates *fDZdAz;
+    MGCoordinates *fSZdAz;
+
+    TGTextEntry   *fPixSize;
+    TGTextEntry   *fAngle;
+    TGTextEntry   *fCut;
+
+    TGLabel       *fFps;
+    TGLabel       *fPosZoom;
+    TGLabel       *fSkyBright;
+    TGLabel       *fCZdAzText;
+    TGLabel       *fPZdAzText;
+    TGLabel       *fDZdAzText;
+public:
+    TGButton      *fTPoint;
+//    TGButton      *fStargTPoint;
+private:
+    ZdAz          fPos;
+    ZdAz          fD;
+    AltAz         fAltAzOffsetFromTp;
+
+    Int_t          fNumStarsDetected;
+    Int_t          fNumStarsCorrelated;
+
+    StarCatalog   *fSao;
+    MCosy         *fCosy;
+    MCaos         *fCaos;
+    MCaos         *fStargCaos;
+    MStargHistograms *fStargHistograms;
+    
+    RaDec *fRaDec;
+
+    TTimer *fTimer;
+    MTime   fTime;
+    MTime   fTimeFromTp;
+
+    std::ofstream *fOutTp;
+    std::ofstream *fOutStargTp;
+//    ofstream *fOutRq;
+
+    Int_t fDx;
+    Int_t fDy;
+
+    byte fIntRate;
+    int  fWrtRate;
+
+    UInt_t fStatus;
+    Double_t fLastBright;
+
+    Double_t fRadius; // LED radius [cm]
+
+    Int_t fTPointFromCC;
+
+    Int_t fStarguiderW;
+    Int_t fStarguiderH;
+    Int_t fStarguiderX;
+    Int_t fStarguiderY;
+
+    Float_t fSkyOffsetX;  // Offset between camera center and sky position
+    Float_t fSkyOffsetY;  // Offset between camera center and sky position
+
+    Float_t fFindStarCut;
+    Int_t   fFindStarBox;
+
+    TString fTPointStarName;
+    Float_t fTPointStarMag;
+
+    void Toggle(TGPopupMenu *p, UInt_t id);
+    void SwitchOff(TGPopupMenu *p, UInt_t id);
+    void ToggleStargAnalysis();
+//    void ToggleFindStar();
+    void ToggleStarguider();
+    void ToggleCaosFilter();
+    void SetChannel();
+    Int_t CalcTrackingError(const Leds &, MStarList &, ZdAz &, const MTime &, const double &bright, Int_t &num, const Ring &center, Int_t numleds, Int_t numrings);
+    ZdAz TrackingError(TArrayF &alt, TArrayF &az, TArrayF &mag, Int_t &num) const;
+    bool Interpolate(const unsigned long n, byte *img) const;
+    void FindStar(const FilterLed &f, const FilterLed &f2, const Ring &center, const MTime &t, Int_t numleds, Int_t numrings);
+
+    void InitGui(Int_t channel);
+
+    void UpdatePosZoom();
+    void DrawZoomImage(const byte *img);
+    void DrawCosyImage(const byte *img);
+
+    Bool_t HandleTimer(TTimer *t);
+
+    void SetRotationAngle(Double_t angle);
+    void SetPixSize(Double_t size);
+    void SetCut(Double_t cut);
+
+    Bool_t DoTPoint();
+
+public:
+    MStarguider(MObservatory::LocationName_t obs, Int_t channel);
+    virtual ~MStarguider();
+
+    void SetupEnv(TEnv &env);
+
+    void Layout();
+    void CloseWindow();
+
+    Bool_t ProcessMessage(Long_t msg, Long_t parm1, Long_t parm2);
+
+    Bool_t HandleDoubleClick(Event_t *event);
+
+    void SetPointingPosition(RaDec rd);
+    void SetCosy(MCosy *c) { fCosy = c; }
+
+    XY GetCoordinates() const;
+
+    //
+    // Execution of one frame - this function may be overloaded!
+    //
+    void ProcessFrame(const unsigned long n, byte *img, struct timeval *tm);
+
+    void Print(TString &str, Double_t deg) const;
+    void Print(Option_t *o) const { }
+
+    void StartTPoint(char *cmd=0);// { if (fTPointFromCC<0) fTPointFromCC=0; }
+    void StartStarguider(bool on);
+
+    Int_t GetStarguiderMode() const;
+
+    ClassDef(MStarguider, 0)
+};
+
+#endif
+
+
Index: /trunk/FACT++/drive/MThread.cc
===================================================================
--- /trunk/FACT++/drive/MThread.cc	(revision 18618)
+++ /trunk/FACT++/drive/MThread.cc	(revision 18618)
@@ -0,0 +1,102 @@
+/* ======================================================================== *\
+!
+! *
+! * This file is part of MARS, the MAGIC Analysis and Reconstruction
+! * Software. It is distributed to you in the hope that it can be a useful
+! * and timesaving tool in analysing Data of imaging Cerenkov telescopes.
+! * It is distributed WITHOUT ANY WARRANTY.
+! *
+! * Permission to use, copy, modify and distribute this software and its
+! * documentation for any purpose is hereby granted without fee,
+! * provided that the above copyright notice appear in all copies and
+! * that both that copyright notice and this permission notice appear
+! * in supporting documentation. It is provided "as is" without express
+! * or implied warranty.
+! *
+!
+!
+!   Author(s): Thomas Bretz  1/2008 <mailto:tbretz@astro.uni-wuerzburg.de>
+!
+!   Copyright: MAGIC Software Development, 2000-2008
+!
+!
+\* ======================================================================== */
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// MThread
+//
+// Implementing a slightly simplified interface to multi-threading
+// based on TThread
+//
+//////////////////////////////////////////////////////////////////////////////
+#include "MThread.h"
+
+ClassImp(MThread);
+
+using namespace std;
+
+// --------------------------------------------------------------------------
+//
+// Return the thread's state as string
+//
+TString MThread::GetThreadStateStr() const
+{
+    switch (fThread.GetState())
+    {
+    case TThread::kInvalidState:
+        return "Invalid - thread was not created properly";
+    case TThread::kNewState:
+        return "New - thread object exists but hasn't started";
+    case TThread::kRunningState:
+        return "Running - thread is running";
+    case TThread::kTerminatedState:
+        return "Terminated - thread has terminated but storage has not yet been reclaimed (i.e. waiting to be joined)";
+    case TThread::kFinishedState:
+        return "Finished - thread has finished";
+    case TThread::kCancelingState:
+        return "Canceling - thread in process of canceling";
+    case TThread::kCanceledState:
+        return "Canceled - thread has been canceled";
+    case TThread::kDeletingState:
+        return "Deleting - thread in process of deleting";
+    };
+    return "Unknown";
+}
+
+/*
+{
+    TMethodCall call(cl, "Name", 0);
+
+    if (!call.IsValid())
+        return 0;
+
+    //const char    *GetParams() const { return fParams.Data(); }
+    //const char    *GetProto() const { return fProto.Data(); }
+
+    switch (call.ReturnType())
+    {
+    case kLong:
+        break;
+    case kDouble:
+        break;
+    case kString:
+        break;
+    case kOther:
+        break;
+    case kNone:
+        break;
+    }
+
+    // NOTE execute functions are locked by a global mutex!!!
+
+   void     Execute(void *object);
+   void     Execute(void *object, Long_t &retLong);
+   void     Execute(void *object, Double_t &retDouble);
+   void     Execute(void *object, char **retText);
+
+   void     Execute();
+   void     Execute(Long_t &retLong);
+   void     Execute(Double_t &retDouble);
+}
+*/
Index: /trunk/FACT++/drive/MThread.h
===================================================================
--- /trunk/FACT++/drive/MThread.h	(revision 18618)
+++ /trunk/FACT++/drive/MThread.h	(revision 18618)
@@ -0,0 +1,81 @@
+#ifndef MARS_MThread
+#define MARS_MThread
+
+#ifndef ROOT_TThread
+#include <TThread.h>
+#endif
+
+class MThread // We don't want MThread to be derived from TObject
+{
+private:
+    TThread fThread;
+
+    Int_t fNumCleanups;
+
+    virtual void CleanUp() { }
+    static void MapCleanUp(void *arg)
+    {
+        MThread *th = (MThread*)arg;
+        th->CleanUp();
+    }
+
+    virtual Int_t Thread() = 0;
+    static void *MapThread(void *arg)
+    {
+        // GetPriority();     High: -1 - -20, Norm: 0, Low: 1-20
+        // pthread_setschedprio(SelfId(), priority);
+        // 0: ok,
+
+        TThread::CleanUpPush((void*)&MapCleanUp, arg);
+
+        MThread *th = (MThread*)arg;
+        return reinterpret_cast<void*>(th->Thread());
+    }
+
+public:
+    MThread(TThread::EPriority pri = TThread::kNormalPriority) :
+        fThread(MapThread, this, pri), fNumCleanups(0) { }
+    MThread(const char *thname, TThread::EPriority pri = TThread::kNormalPriority) :
+        fThread(thname, MapThread, this, pri), fNumCleanups(0) { }
+    virtual ~MThread() { }
+
+    // Setter: Thread control
+    Int_t RunThread(void *arg = 0) { return fThread.Run(arg); }
+
+    // Send cancel request and wait for cancellation
+    // 13 is returned if thread is not running,
+    // the return code of Join otherwise
+    Int_t CancelThread(void **ret = 0) {
+        const Int_t rc = fThread.Kill();
+        if (rc==13) // Thread not running
+            return rc;
+        return fThread.Join(ret);
+    }
+
+    // Int_t            Kill() { return fThread.Kill(); }
+    // Long_t           Join(void **ret = 0) { return fThread.Join(ret); }
+
+    // void             SetPriority(EPriority pri)
+    // void             Delete(Option_t *option="") { TObject::Delete(option); }
+
+    // Getter
+    TThread::EState  GetThreadState() const { return fThread.GetState(); }
+    TString          GetThreadStateStr() const;
+    Long_t           GetThreadId() const { return fThread.GetId(); }
+    // EPriority        GetPriority() const { return fPriority; }
+
+    Bool_t IsThreadRunning()  const { return fThread.GetState()==TThread::kRunningState; }
+    Bool_t IsThreadCanceled() const { return fThread.GetState()==TThread::kCancelingState; }
+
+    // This is a version of usleep which is a cancel point
+    static void Sleep(UInt_t us)
+    {
+        TThread::SetCancelOn();
+        usleep(us);
+        TThread::SetCancelOff();
+    }
+
+    ClassDef(MThread,0)  // A simplified interface to TThread
+};
+
+#endif
Index: /trunk/FACT++/drive/MVideo.cc
===================================================================
--- /trunk/FACT++/drive/MVideo.cc	(revision 18618)
+++ /trunk/FACT++/drive/MVideo.cc	(revision 18618)
@@ -0,0 +1,1123 @@
+/* ======================================================================== *\
+!
+! *
+! * This file is part of MARS, the MAGIC Analysis and Reconstruction
+! * Software. It is distributed to you in the hope that it can be a useful
+! * and timesaving tool in analysing Data of imaging Cerenkov telescopes.
+! * It is distributed WITHOUT ANY WARRANTY.
+! *
+! * Permission to use, copy, modify and distribute this software and its
+! * documentation for any purpose is hereby granted without fee,
+! * provided that the above copyright notice appear in all copies and
+! * that both that copyright notice and this permission notice appear
+! * in supporting documentation. It is provided "as is" without express
+! * or implied warranty.
+! *
+!
+!
+!   Author(s): Thomas Bretz 1/2008 <mailto:thomas.bretz@epfl.ch>
+!
+!   Copyright: MAGIC Software Development, 2000-2011
+!
+!
+\* ======================================================================== */
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// MVideo
+//
+// Interface to Video4Linux at a simple level
+//
+// V4L2 spcifications from http://v4l2spec.bytesex.org/spec/
+//
+/////////////////////////////////////////////////////////////////////////////
+#include "MVideo.h"
+
+// iostream
+#include <iostream>
+
+// open
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include <unistd.h>    // usleep
+#include <errno.h>     // errno
+#include <sys/mman.h>  // mmap
+#include <sys/ioctl.h> // ioctl
+
+#include <TEnv.h>
+#include <TString.h>
+
+#include "MLog.h"
+#include "MLogManip.h"
+
+#undef DEBUG
+
+using namespace std;
+
+//ClassImp(MVideo);
+
+MVideoCtrl::MVideoCtrl(const v4l2_queryctrl &ctrl)
+{
+    fId      = ctrl.id;
+    fName    = (const char*)ctrl.name;
+    fMinimum = ctrl.minimum;
+    fMaximum = ctrl.maximum;
+    fStep    = ctrl.step;
+    fDefault = ctrl.default_value;
+}
+
+// -------------------------------------------------------------
+//
+// Constructor. Specify the device (e.g. "/dev/video") to be used
+//
+MVideo::MVideo(const char *path) : fPath(path), fFileDesc(-1), fMapBuffer(0)
+{
+    Reset();
+
+    fControls.SetOwner();
+}
+
+// -------------------------------------------------------------
+//
+// Internal function to reset the descriptors of the device
+//
+void MVideo::Reset()
+{
+    fInputs.clear();
+    fStandards.clear();
+
+    memset(&fCaps,    0, sizeof(fCaps));
+    memset(&fChannel, 0, sizeof(fChannel));
+//    memset(&fBuffer,  0, sizeof(fBuffer));
+    memset(&fAbil,    0, sizeof(fAbil));
+
+    fFileDesc = -1;
+    fMapBuffer = 0;
+    fChannel.channel = -1;
+    fAbil.tuner = -1;
+
+    fControls.Delete();
+}
+
+// -------------------------------------------------------------
+//
+// Mapper around ioctl for easier access to the device
+//
+int MVideo::Ioctl(int req, void *opt, bool allowirq, bool force) const
+{
+    if (fFileDesc<0)
+    {
+        gLog << err << "ERROR - Ioctl: Device " << fPath << " not open." << endl;
+        return -1;
+    }
+
+    while (1)
+    {
+        // FIXME: This call is a possible source for a hangup
+        const int rc = ioctl(fFileDesc, req, opt);
+        if (rc==0)
+            return 0;
+
+        if (errno==EINVAL)
+            return 1;
+
+        if (!allowirq && errno==EAGAIN)
+            return -4;
+
+        cout <<"errno="<< errno << endl;
+
+        // errno== 4: Interrupted system call (e.g. by alarm())
+        // errno==16: Device or resource busy
+        if (errno==4 || errno==16)
+        {
+            if (!allowirq && errno==4)
+                return -4;
+
+            gLog << err << "ERROR - MVideo::Ioctl 0x" << hex << req << ": errno=" << dec << errno << " - ";
+            gLog << strerror(errno) << " (rc=" << rc << ")" << endl;
+            usleep(10);
+            continue;
+        }
+
+        if (!force)
+        {
+            gLog << err << "ERROR - MVideo::Ioctl 0x" << hex << req << ": errno=" << dec << errno << " - ";
+            gLog << strerror(errno) << " (rc=" << rc << ")" << endl;
+        }
+        return rc;
+    }
+    return -1;
+}
+
+// -------------------------------------------------------------
+//
+// Read the capabilities of the device
+//
+Bool_t MVideo::GetCapabilities()
+{
+    return Ioctl(VIDIOCGCAP, &fCaps)!=-1;
+}
+
+// -------------------------------------------------------------
+//
+// Read the properties of the device
+//
+Bool_t MVideo::GetProperties()
+{
+    return Ioctl(VIDIOCGPICT, &fProp)!=-1;
+}
+
+// -------------------------------------------------------------
+//
+// Read the video standard
+//
+Bool_t MVideo::GetVideoStandard()
+{
+    return Ioctl(VIDIOC_G_STD, &fVideoStandard)==-1;
+}
+
+// -------------------------------------------------------------
+//
+// Read the abilities of the tuner
+//
+Bool_t MVideo::GetTunerAbilities()
+{
+    fAbil.tuner = 0; // FIXME?
+    return Ioctl(VIDIOCGTUNER, &fAbil)!=-1;
+}
+
+// -------------------------------------------------------------
+//
+// Enumerate (get) all controls from the device and store them
+// as MVideoCtrl in fControls, starting with the id given as
+// argument.
+//
+Bool_t MVideo::EnumerateControls(UInt_t id)
+{
+    struct v4l2_queryctrl qctrl;
+    memset(&qctrl, 0, sizeof(qctrl));
+    qctrl.id = id;
+
+    while (1)
+    {
+        if (Ioctl(VIDIOC_QUERYCTRL, &qctrl, true, true)==-1)
+            break;
+
+        if (qctrl.maximum<=qctrl.minimum)
+            continue;
+
+        fControls.Add(new MVideoCtrl(qctrl));
+
+        qctrl.id++;
+    }
+
+    return kTRUE;
+}
+
+// -------------------------------------------------------------
+//
+// Enumerate (get) all basic and private controls from the
+// device and store them as MVideoCtrl in fControls.
+//
+Bool_t MVideo::EnumerateControls()
+{
+    if (!EnumerateControls(V4L2_CID_BASE))
+        return kFALSE;
+    if (!EnumerateControls(V4L2_CID_PRIVATE_BASE))
+        return kFALSE;
+
+    return kTRUE;
+}
+
+// -------------------------------------------------------------
+//
+// Reset a given control to it's default value as defined
+// by the device.
+//
+Bool_t MVideo::ResetControl(MVideoCtrl &vctrl) const
+{
+    return WriteControl(vctrl, vctrl.fDefault);
+}
+
+// -------------------------------------------------------------
+//
+// Reset all enumereated device controls to their default.
+// The default is defined by the device iteself.
+//
+Bool_t MVideo::ResetControls() const
+{
+    Bool_t rc = kTRUE;
+
+    TIter Next(&fControls);
+    MVideoCtrl *ctrl = 0;
+    while ((ctrl=((MVideoCtrl*)Next())))
+        if (!ResetControl(*ctrl))
+        {
+            gLog << err << "ERROR - Could not reset " << ctrl->fName << "." << endl;
+            rc = kFALSE;
+        }
+
+    return rc;
+}
+
+// -------------------------------------------------------------
+//
+//  Read the value of the given control from the device
+// and store it back into the given MVideoCtrl.
+//
+Bool_t MVideo::ReadControl(MVideoCtrl &vctrl) const
+{
+    struct v4l2_control ctrl = { vctrl.fId, 0 };
+    if (Ioctl(VIDIOC_G_CTRL, &ctrl)==-1)
+        return kFALSE;
+
+    vctrl.fValue = ctrl.value;
+
+    return kTRUE;
+}
+
+// -------------------------------------------------------------
+//
+// Write the given value into the given control of the device.
+// On success the value is stored in the given MVideoCtrl.
+//
+Bool_t MVideo::WriteControl(MVideoCtrl &vctrl, Int_t val) const
+{
+    if (val<vctrl.fMinimum)
+    {
+        gLog << err << "ERROR - Value of " << val << " below minimum of " << vctrl.fMinimum << " for " << vctrl.fName << endl;
+        return kFALSE;
+    }
+
+    if (val>vctrl.fMaximum)
+    {
+        gLog << err << "ERROR - Value of " << val << " above maximum of " << vctrl.fMaximum << " for " << vctrl.fName << endl;
+        return kFALSE;
+    }
+
+    struct v4l2_control ctrl = { vctrl.fId, val };
+    if (Ioctl(VIDIOC_S_CTRL, &ctrl)==-1)
+        return kFALSE;
+
+    vctrl.fValue = val;
+
+    return kTRUE;
+}
+
+// -------------------------------------------------------------
+//
+// Set all controls from a TEnv. Note that all whitespaces
+// and colons in the control names (as defined by the name of
+// the MVideoCtrls stored in fControls) are replaced by
+// underscores.
+//
+Bool_t MVideo::SetControls(TEnv &env) const
+{
+    Bool_t rc = kTRUE;
+
+    TIter Next(&fControls);
+    TObject *o = 0;
+    while ((o=Next()))
+    {
+        if (!env.Defined(o->GetName()))
+            continue;
+
+        TString str = env.GetValue(o->GetName(), "");
+        str = str.Strip(TString::kBoth);
+        str.ReplaceAll(" ", "_");
+        str.ReplaceAll(":", "_");
+        if (str.IsNull())
+            continue;
+
+        MVideoCtrl &ctrl = *static_cast<MVideoCtrl*>(o);
+
+        const Int_t val = str=="default" || str=="def" ?
+            ctrl.fDefault : env.GetValue(o->GetName(), 0);
+
+        if (!WriteControl(ctrl, val))
+            rc = kFALSE;
+    }
+
+    return rc;
+}
+
+template<class S>
+Bool_t MVideo::Enumerate(vector<S> &vec, int request)
+{
+    for (int i=0; ; i++)
+    {
+        S input;
+        input.index = i;
+
+        const int rc = Ioctl(request, &input);
+        if (rc<0)
+            return kFALSE;
+        if (rc==1)
+            return kTRUE;
+
+        vec.push_back(input);
+    }
+
+    return kFALSE;
+}
+
+void MVideo::PrintInputs() const
+{
+    gLog << all;
+    for (vector<v4l2_input>::const_iterator it=fInputs.begin(); it!=fInputs.end(); it++)
+    {
+        gLog << "Input #" << it->index << endl;
+        gLog << " - " << it->name << endl;
+        gLog << " - " << (it->type==V4L2_INPUT_TYPE_CAMERA?"Camera":"Tuner") << endl;
+        gLog << " - TV Standard: " << hex << it->std << dec << endl;
+
+        gLog << " - Status: 0x" << hex << it->status;
+        if (it->status&V4L2_IN_ST_NO_POWER)
+            gLog << " NoPower";
+        if (it->status&V4L2_IN_ST_NO_SIGNAL)
+            gLog << " NoSignal";
+        if (it->status&V4L2_IN_ST_NO_COLOR)
+            gLog << " NoColor";
+        if (it->status&V4L2_IN_ST_NO_H_LOCK)
+            gLog << " NoHLock";
+        if (it->status&V4L2_IN_ST_COLOR_KILL)
+            gLog << " ColorKill";
+        gLog << endl;
+
+        /*
+         TV Standard
+         ===========
+         #define V4L2_STD_PAL_B          ((v4l2_std_id)0x00000001)
+         #define V4L2_STD_PAL_B1         ((v4l2_std_id)0x00000002)
+         #define V4L2_STD_PAL_G          ((v4l2_std_id)0x00000004)
+         #define V4L2_STD_PAL_H          ((v4l2_std_id)0x00000008)
+         #define V4L2_STD_PAL_I          ((v4l2_std_id)0x00000010)
+         #define V4L2_STD_PAL_D          ((v4l2_std_id)0x00000020)
+         #define V4L2_STD_PAL_D1         ((v4l2_std_id)0x00000040)
+         #define V4L2_STD_PAL_K          ((v4l2_std_id)0x00000080)
+
+         #define V4L2_STD_PAL_M          ((v4l2_std_id)0x00000100)
+         #define V4L2_STD_PAL_N          ((v4l2_std_id)0x00000200)
+         #define V4L2_STD_PAL_Nc         ((v4l2_std_id)0x00000400)
+         #define V4L2_STD_PAL_60         ((v4l2_std_id)0x00000800)
+         V4L2_STD_PAL_60 is a hybrid standard with 525 lines, 60 Hz refresh rate, and PAL color modulation with a 4.43 MHz color subcarrier. Some PAL video recorders can play back NTSC tapes in this mode for display on a 50/60 Hz agnostic PAL TV.
+
+         #define V4L2_STD_NTSC_M         ((v4l2_std_id)0x00001000)
+         #define V4L2_STD_NTSC_M_JP      ((v4l2_std_id)0x00002000)
+         #define V4L2_STD_NTSC_443       ((v4l2_std_id)0x00004000)
+         V4L2_STD_NTSC_443 is a hybrid standard with 525 lines, 60 Hz refresh rate, and NTSC color modulation with a 4.43 MHz color subcarrier.
+
+         #define V4L2_STD_NTSC_M_KR      ((v4l2_std_id)0x00008000)
+
+         #define V4L2_STD_SECAM_B        ((v4l2_std_id)0x00010000)
+         #define V4L2_STD_SECAM_D        ((v4l2_std_id)0x00020000)
+         #define V4L2_STD_SECAM_G        ((v4l2_std_id)0x00040000)
+         #define V4L2_STD_SECAM_H        ((v4l2_std_id)0x00080000)
+         #define V4L2_STD_SECAM_K        ((v4l2_std_id)0x00100000)
+         #define V4L2_STD_SECAM_K1       ((v4l2_std_id)0x00200000)
+         #define V4L2_STD_SECAM_L        ((v4l2_std_id)0x00400000)
+         #define V4L2_STD_SECAM_LC       ((v4l2_std_id)0x00800000)
+
+
+         // ATSC/HDTV
+         #define V4L2_STD_ATSC_8_VSB     ((v4l2_std_id)0x01000000)
+         #define V4L2_STD_ATSC_16_VSB    ((v4l2_std_id)0x02000000)
+         V4L2_STD_ATSC_8_VSB and V4L2_STD_ATSC_16_VSB are U.S. terrestrial digital TV standards. Presently the V4L2 API does not support digital TV. See also the Linux DVB API at http://linuxtv.org.
+
+         #define V4L2_STD_PAL_BG   (V4L2_STD_PAL_B   | V4L2_STD_PAL_B1    | V4L2_STD_PAL_G)
+         #define V4L2_STD_B        (V4L2_STD_PAL_B   | V4L2_STD_PAL_B1    | V4L2_STD_SECAM_B)
+         #define V4L2_STD_GH       (V4L2_STD_PAL_G   | V4L2_STD_PAL_H     | V4L2_STD_SECAM_G  | V4L2_STD_SECAM_H)
+         #define V4L2_STD_PAL_DK   (V4L2_STD_PAL_D   | V4L2_STD_PAL_D1    | V4L2_STD_PAL_K)
+         #define V4L2_STD_PAL      (V4L2_STD_PAL_BG  | V4L2_STD_PAL_DK    | V4L2_STD_PAL_H    | V4L2_STD_PAL_I)
+         #define V4L2_STD_NTSC     (V4L2_STD_NTSC_M  | V4L2_STD_NTSC_M_JP | V4L2_STD_NTSC_M_KR)
+         #define V4L2_STD_MN       (V4L2_STD_PAL_M   | V4L2_STD_PAL_N     | V4L2_STD_PAL_Nc   | V4L2_STD_NTSC)
+         #define V4L2_STD_SECAM_DK (V4L2_STD_SECAM_D | V4L2_STD_SECAM_K   | V4L2_STD_SECAM_K1)
+         #define V4L2_STD_DK       (V4L2_STD_PAL_DK  | V4L2_STD_SECAM_DK)
+         #define V4L2_STD_SECAM    (V4L2_STD_SECAM_B | V4L2_STD_SECAM_G   | V4L2_STD_SECAM_H  | V4L2_STD_SECAM_DK | V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC)
+         #define V4L2_STD_525_60   (V4L2_STD_PAL_M   | V4L2_STD_PAL_60    | V4L2_STD_NTSC     | V4L2_STD_NTSC_443)
+         #define V4L2_STD_625_50   (V4L2_STD_PAL     | V4L2_STD_PAL_N     | V4L2_STD_PAL_Nc   | V4L2_STD_SECAM)
+         #define V4L2_STD_UNKNOWN  0
+         #define V4L2_STD_ALL      (V4L2_STD_525_60  | V4L2_STD_625_50)
+         */
+
+         /*
+          Status:
+         =======
+         General
+         V4L2_IN_ST_NO_POWER	0x00000001	Attached device is off.
+         V4L2_IN_ST_NO_SIGNAL	0x00000002
+         V4L2_IN_ST_NO_COLOR	0x00000004	The hardware supports color decoding, but does not detect color modulation in the signal.
+
+         Analog Video
+         V4L2_IN_ST_NO_H_LOCK	0x00000100	No horizontal sync lock.
+         V4L2_IN_ST_COLOR_KILL	0x00000200	A color killer circuit automatically disables color decoding when it detects no color modulation. When this flag is set the color killer is enabled and has shut off color decoding.
+
+         Digital Video
+         V4L2_IN_ST_NO_SYNC	0x00010000	No synchronization lock.
+         V4L2_IN_ST_NO_EQU	0x00020000	No equalizer lock.
+         V4L2_IN_ST_NO_CARRIER	0x00040000	Carrier recovery failed.
+
+         VCR and Set-Top Box
+         V4L2_IN_ST_MACROVISION	0x01000000	Macrovision is an analog copy prevention system mangling the video signal to confuse video recorders. When this flag is set Macrovision has been detected.
+         V4L2_IN_ST_NO_ACCESS	0x02000000	Conditional access denied.
+         V4L2_IN_ST_VTR	        0x04000000	VTR time constant. [?]
+         */
+    }
+}
+
+void MVideo::PrintStandards() const
+{
+    gLog << all;
+    for (vector<v4l2_standard>::const_iterator it=fStandards.begin(); it!=fStandards.end(); it++)
+    {
+        gLog << "Index #" << it->index << endl;
+        gLog << " - TV Standard: " << it->name << hex << "(" << it->id << ")" << dec << endl;
+        gLog << " - FPS: " << it->frameperiod.numerator << "/" << it->frameperiod.denominator << endl;
+        gLog << " - Lines: " << it->framelines << endl;
+    }
+}
+
+// -------------------------------------------------------------
+//
+// Open channel ch of the device
+//
+Bool_t MVideo::Open(Int_t ch)
+{
+    const Bool_t rc = Init(ch);
+    if (!rc)
+        Close();
+    return rc;
+}
+
+// -------------------------------------------------------------
+//
+// Open a channel of the device and retriev all necessary
+// informations from the driver. Initialize the shared
+// memory. Other access methods are not supported yet.
+//
+Bool_t MVideo::Init(Int_t channel)
+{
+    if (IsOpen())
+    {
+        gLog << warn << "WARNING - Device " << fPath << " already open." << endl;
+        return kTRUE;
+    }
+
+    gLog << all << "Opening " << fPath << "... " << flush;
+    do
+    {
+        fFileDesc = open(fPath, O_RDWR|O_NONBLOCK, 0);
+        usleep(1);
+    }
+    while (errno==19 && fFileDesc==-1);
+
+    if (fFileDesc == -1)
+    {
+        gLog << err << "ERROR: " << strerror(errno) << endl;
+        return kFALSE;
+    }
+
+    gLog << "done (" << fFileDesc << ")." << endl;
+
+    // Close device on exit
+    if (fcntl(fFileDesc, F_SETFD, FD_CLOEXEC)<0)
+    {
+        gLog << err << "ERROR - Call to fnctl (F_SETFD, FD_CLOEXEC) failed." << endl;
+        return kFALSE;
+    }
+
+
+
+/*
+    if (!Enumerate(fInputs, VIDIOC_ENUMINPUT))
+    {
+        gLog << err << "ERROR - Could not enumerate inputs." << endl;
+        return kFALSE;
+    }
+    PrintInputs();
+
+    if (!Enumerate(fStandards, VIDIOC_ENUMSTD))
+    {
+        gLog << err << "ERROR - Could not enumerate inputs." << endl;
+        return kFALSE;
+    }
+    PrintStandards();
+   */
+
+    int index = 3;
+    if (Ioctl(VIDIOC_S_INPUT, &index)==-1)
+    {
+        gLog << err << "ERROR - Could not set input." << endl;
+        return kFALSE;
+    }
+
+    //check the input
+    if (Ioctl(VIDIOC_G_INPUT, &index))
+    {
+        gLog << err << "ERROR - Could not get input." << endl;
+        return kFALSE;
+    }
+
+    v4l2_input input;
+    memset(&input, 0, sizeof (input));
+    input.index = index;
+    if (Ioctl(VIDIOC_ENUMINPUT, &input))
+    {
+        gLog << err << "ERROR - Could enum input." << endl;
+        return kFALSE;
+    }
+    gLog << "*** Input: " << input.name << " (" << input.index << ")" << endl;
+
+    v4l2_std_id st = 4;//standard.id;
+    if (Ioctl (VIDIOC_S_STD, &st))
+    {
+        gLog << err << "ERROR - Could not set standard." << endl;
+        return kFALSE;
+    }
+
+    v4l2_capability cap;
+    if (Ioctl(VIDIOC_QUERYCAP, &cap))
+    {
+        gLog << err << "ERROR - Could not get capabilities." << endl;
+        return kFALSE;
+    }
+
+    if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE))
+    {
+        gLog << err << "ERROR - No capture capabaility." << endl;
+        return kFALSE;
+    }
+
+    v4l2_cropcap cropcap;
+    cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+    if (Ioctl(VIDIOC_CROPCAP, &cropcap)==-1)
+    {
+    }
+
+    v4l2_crop crop;
+    crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+    crop.c = cropcap.defrect; /* reset to default */
+
+    if (Ioctl(VIDIOC_S_CROP, &crop))
+    {
+        gLog << err << "Could not reset cropping." << endl;
+        return kFALSE;
+    }
+
+    v4l2_format fmt;
+    fmt.type                = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+    fmt.fmt.pix.width       = 768;
+    fmt.fmt.pix.height      = 576;
+    fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_RGB32;
+
+    if (Ioctl(VIDIOC_S_FMT, &fmt)==-1)
+    {
+        gLog << err << "ERROR - Could not set format." << endl;
+        return kFALSE;
+    }
+    // The image format must be selected before buffers are allocated,
+    // with the VIDIOC_S_FMT ioctl. When no format is selected the driver
+    // may use the last, possibly by another application requested format.
+
+    v4l2_requestbuffers reqbuf;
+    memset (&reqbuf, 0, sizeof (reqbuf));
+
+    reqbuf.type   = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+    reqbuf.memory = V4L2_MEMORY_MMAP;
+    reqbuf.count  = 4;//125;
+
+    if (Ioctl(VIDIOC_REQBUFS, &reqbuf)==-1)
+    {
+        gLog << err << "ERROR - Couldn't setup frame buffers." << endl;
+        return kFALSE;
+    }
+
+    gLog << all << "Allocated " << reqbuf.count << " frame buffers." << endl;
+
+    for (unsigned int i=0; i<reqbuf.count; i++)
+    {
+        v4l2_buffer buffer;
+        memset (&buffer, 0, sizeof (buffer));
+
+        buffer.type   = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	buffer.memory = V4L2_MEMORY_MMAP;
+        buffer.index  = i;
+
+        if (Ioctl(VIDIOC_QUERYBUF, &buffer))
+        {
+            gLog << err << "ERROR - Request of frame buffer " << i << " failed." << endl;
+            return kFALSE;
+        }
+
+        void *ptr = mmap(NULL, buffer.length,
+                         PROT_READ | PROT_WRITE,
+                         MAP_SHARED,
+                         fFileDesc, buffer.m.offset);
+
+        if (MAP_FAILED == ptr)
+        {
+
+            gLog << err << "ERROR - Could not allocate shared memory." << endl;
+            return kFALSE;
+                // If you do not exit here you should unmap() and free()
+                // the buffers mapped so far.
+                //perror ("mmap");
+                //exit (EXIT_FAILURE);
+        }
+
+        fBuffers.push_back(make_pair(buffer, ptr));
+    }
+
+    return kTRUE;
+}
+
+Bool_t MVideo::Start()
+{
+    v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+    if (Ioctl(VIDIOC_STREAMON, &type)==-1)
+    {
+        gLog << err << "ERROR - Couldn't start capturing." << endl;
+        return kFALSE;
+    }
+
+    cout << "*** Stream on" << endl;
+
+    return kTRUE;
+}
+
+// -------------------------------------------------------------
+//
+// Close device. Free the shared memory
+//
+Int_t MVideo::Close()
+{
+    //    if (!IsOpen())
+    //        return kTRUE;
+/*
+    if (Ioctl(VIDIOC_STREAMON, &fBuffers[0])==-1)
+    {
+        gLog << err << "ERROR - Couldn't start capturing." << endl;
+        return kFALSE;
+    }
+*/
+    Bool_t rc = kTRUE;
+
+    gLog << all << "Closing " << fPath << " (" << fFileDesc << ")... " << flush;
+    if (fFileDesc != -1)
+    {
+        if (close(fFileDesc)<0)
+        {
+            gLog << err << "ERROR!" << endl;
+            rc = kFALSE;
+        }
+        fFileDesc = -1;
+    }
+    gLog << "done." << endl;
+
+    // unmap device memory
+    for (vector<pair<v4l2_buffer,void*> >::iterator it=fBuffers.begin(); it!=fBuffers.end(); it++)
+    {
+        munmap(it->second, it->first.length);
+        fBuffers.erase(it);
+    }
+
+    Reset();
+
+    return rc;
+}
+
+// -------------------------------------------------------------
+//
+// Instruct hardware to start capture into framebuffer frame
+//
+Bool_t MVideo::CaptureStart(unsigned int frame) const
+{
+    frame %= fBuffers.size();
+
+//    cout << "*** CaptureStart " << frame << endl;
+
+    if (Ioctl(VIDIOC_QBUF, const_cast<v4l2_buffer*>(&fBuffers[frame].first))==-1)
+    {
+        gLog << err << "ERROR - Couldn't buffer " << frame << "." << endl;
+        return kFALSE;
+    }
+
+//    cout << "*** " << errno << endl;
+
+    return kTRUE;
+
+    /*
+    struct video_mmap gb =
+    {
+        frame,                           // frame
+        fCaps.maxheight, fCaps.maxwidth, // height, width
+        VIDEO_PALETTE_RGB24             // palette
+    };
+
+#ifdef DEBUG
+    gLog << dbg << "CapturStart(" << frame << ")" << endl;
+#endif
+
+    //
+    // capture frame
+    //
+    if (Ioctl(VIDIOCMCAPTURE, &gb) != -1)
+        return kTRUE;
+
+//    if (errno == EAGAIN)
+    gLog << err;
+    gLog << "ERROR - Couldn't start capturing frame " << frame << "." << endl;
+    gLog << "        Maybe your card doesn't support VIDEO_PALETTE_RGB24." << endl;
+    return kFALSE;
+    */
+}
+
+// -------------------------------------------------------------
+//
+// Wait until hardware has finished capture into framebuffer frame
+//
+Int_t MVideo::CaptureWait(unsigned int frame, unsigned char **ptr) const
+{
+    frame %= fBuffers.size();
+
+    if (ptr)
+        *ptr = NULL;
+
+//    const int SYNC_TIMEOUT = 1;
+
+//#ifdef DEBUG
+//    cout << "*** CaptureWait " << frame << endl;
+//#endif
+
+    //alarm(SYNC_TIMEOUT);
+    const Int_t rc = Ioctl(VIDIOC_DQBUF, const_cast<v4l2_buffer*>(&fBuffers[frame].first), false);
+    if (rc==-4)
+    {
+        //cout << "ERROR - Waiting for frame " << frame << " timed out." << endl;
+        return kSKIP;
+    }
+    //alarm(0);
+
+    if (rc==-1)
+    {
+        gLog << err << "ERROR - Waiting for " << frame << " frame failed." << endl;
+        return kFALSE;
+    }
+
+    if (ptr)
+        *ptr = static_cast<unsigned char*>(fBuffers[frame].second);
+
+    return kTRUE;
+}
+
+// -------------------------------------------------------------
+//
+// Change the channel of a priviously opened device
+//
+Int_t MVideo::SetChannel(Int_t chan)
+{
+    return kSKIP;
+
+    if (fChannel.channel==chan)
+        return kSKIP;
+
+    if (chan<0 || chan>=fCaps.channels)
+    {
+        gLog << err << "ERROR - Set channel " << chan << " out of range." << endl;
+        return kFALSE;
+    }
+
+    // Switch to channel
+    struct video_channel ch = { chan, "", 0, 0, 0, 0 };
+    if (Ioctl(VIDIOCSCHAN, &ch)==-1)
+    {
+        gLog << err << "ERROR - Couldn't switch to channel " << chan << "." << endl;
+        gLog << "        You might need a bttv version > 0.5.13" << endl;
+        return kFALSE;
+    }
+
+    // Get information about channel
+    if (Ioctl(VIDIOCGCHAN, &ch)==-1)
+    {
+        gLog << err << "ERROR - Getting information for channel " << chan << " failed." << endl;
+        return kFALSE;
+    }
+
+    memcpy(&fChannel, &ch, sizeof(fChannel));
+
+    gLog << all << "Switched to channel " << chan << endl;
+
+    return kTRUE;
+}
+
+// -------------------------------------------------------------
+//
+// Has the device capture capabilities?
+//
+Bool_t MVideo::CanCapture() const
+{
+    return fCaps.type&VID_TYPE_CAPTURE;
+}
+
+// -------------------------------------------------------------
+//
+// Has a tuner
+//
+Bool_t MVideo::HasTuner() const
+{
+    return fCaps.type&VID_TYPE_TUNER;
+}
+
+// -------------------------------------------------------------
+//
+// Returns the number of frame buffers which can be used
+//
+Int_t MVideo::GetNumBuffers() const
+{
+    return fBuffers.size();
+}
+
+// -------------------------------------------------------------
+//
+// Maximum width of the frame which can be captured
+//
+Int_t MVideo::GetWidth() const
+{
+    return 768;//fCaps.maxwidth;
+}
+
+// -------------------------------------------------------------
+//
+// Maximum height of the frame which can be captured
+//
+Int_t MVideo::GetHeight() const
+{
+    return 576;//fCaps.maxheight;
+}
+
+// -------------------------------------------------------------
+//
+// Return the device type as string
+//
+TString MVideo::GetDevType(int type) const
+{
+    TString rc;
+    if (CanCapture())
+        rc += " capture";
+    if (HasTuner())
+        rc += " tuner";
+    if (type&VID_TYPE_TELETEXT)
+        rc += " teletext";
+    if (type&VID_TYPE_OVERLAY)
+        rc += " overlay";
+    if (type&VID_TYPE_CHROMAKEY)
+        rc += " chromakey";
+    if (type&VID_TYPE_CLIPPING)
+        rc += " clipping";
+    if (type&VID_TYPE_FRAMERAM)
+        rc += " frameram";
+    if (type&VID_TYPE_SCALES)
+        rc += " scales";
+    if (type&VID_TYPE_MONOCHROME)
+        rc += " monochrom";
+    if (type&VID_TYPE_SUBCAPTURE)
+        rc += " subcapature";
+    return rc;
+}
+
+TString MVideo::GetTunerFlags(Int_t flags) const
+{
+    TString rc;
+    if (flags&VIDEO_TUNER_PAL)
+        rc += " PAL";
+    if (flags&VIDEO_TUNER_NTSC)
+        rc += " NTSC";
+    if (flags&VIDEO_TUNER_SECAM)
+        rc += " SECAM";
+    if (flags&VIDEO_TUNER_LOW)
+        rc += " kHz";
+    if (flags&VIDEO_TUNER_NORM)
+        rc += " CanSetNorm";
+    if (flags&VIDEO_TUNER_STEREO_ON)
+        rc += " StereoOn";
+    return rc;
+}
+
+TString MVideo::GetTunerMode(Int_t mode) const
+{
+    switch (mode)
+    {
+    case VIDEO_MODE_PAL:
+        return "PAL";
+    case VIDEO_MODE_NTSC:
+        return "NTSC";
+    case VIDEO_MODE_SECAM:
+        return "SECAM";
+    case VIDEO_MODE_AUTO:
+        return "AUTO";
+    }
+    return "undefined";
+}
+
+// -------------------------------------------------------------
+//
+// Return the channel flags as string
+//
+TString MVideo::GetChannelFlags(Int_t flags) const
+{
+    TString rc = "video";
+    if (flags&VIDEO_VC_TUNER)
+        rc += " tuner";
+    if (flags&VIDEO_VC_AUDIO)
+        rc += " audio";
+//    if (flags&VIDEO_VC_NORM)
+//        rc += " normsetting";
+    return rc;
+}
+
+// -------------------------------------------------------------
+//
+// Return the channel type as string
+//
+TString MVideo::GetChannelType(Int_t type) const
+{
+    if (type&VIDEO_TYPE_TV)
+        return "TV";
+    if (type&VIDEO_TYPE_CAMERA)
+        return "Camera";
+    return "unknown";
+}
+
+// -------------------------------------------------------------
+//
+// Return the palette pal as string
+//
+TString MVideo::GetPalette(Int_t pal) const
+{
+    switch (pal)
+    {
+    case VIDEO_PALETTE_GREY:
+        return "VIDEO_PALETTE_GREY: Linear intensity grey scale";
+    case VIDEO_PALETTE_HI240:
+        return "VIDEO_PALETTE_HI240: BT848 8-bit color cube";
+    case VIDEO_PALETTE_RGB565:
+        return "VIDEO_PALETTE_RGB565: RGB565 packed into 16-bit words";
+    case VIDEO_PALETTE_RGB555:
+        return "VIDEO_PALETTE_RGB555: RGB555 packed into 16-bit words, top bit undefined";
+    case VIDEO_PALETTE_RGB24:
+        return "VIDEO_PALETTE_RGB24: RGB888 packed into 24-bit words";
+    case VIDEO_PALETTE_RGB32:
+        return "VIDEO_PALETTE_RGB32: RGB888 packed into the low three bytes of 32-bit words. Top bits undefined.";
+    case VIDEO_PALETTE_YUV422:
+        return "VIDEO_PALETTE_YUV422: Video style YUV422 - 8-bit packed, 4-bit Y, 2-bits U, 2-bits V";
+    case VIDEO_PALETTE_YUYV:
+        return "VIDEO_PALETTE_YUYV: YUYV";
+    case VIDEO_PALETTE_UYVY:
+        return "VIDEO_PALETTE_UYVY: UYVY";
+    case VIDEO_PALETTE_YUV420:
+        return "VIDEO_PALETTE_YUV420: YUV420";
+    case VIDEO_PALETTE_YUV411:
+        return "VIDEO_PALETTE_YUV411: YUV411";
+    case VIDEO_PALETTE_RAW:
+        return "VIDEO_PALETTE_RAW: Raw capture (Bt848)";
+    case VIDEO_PALETTE_YUV422P:
+        return "VIDEO_PALETTE_YUV422P: YUV 4:2:2 planar";
+    case VIDEO_PALETTE_YUV411P:
+        return "VIDEO_PALETTE_YUV411P: YUV 4:1:1 planar";
+    }
+    return "unknown";
+}
+
+// -------------------------------------------------------------
+//
+// Print informations about the device, the capabilities, the
+// channel and all available information
+//
+void MVideo::Print() const
+{
+    gLog << all << dec;
+
+    gLog << "Device " << fPath << " " << (fFileDesc>0?"open":"closed") << "." << endl;
+
+    if (fFileDesc<=0)
+        return;
+
+    gLog  << " - Name:       " << fCaps.name << endl;
+    gLog  << " - DevType:   "  << GetDevType(fCaps.type) << endl;
+    gLog  << " - Channels:   " << fCaps.channels << endl;
+    gLog  << " - Audios:     " << fCaps.audios << endl;
+    gLog  << " - Size:       ";
+    gLog  << fCaps.minwidth << "x" << fCaps.minheight << " to ";
+    gLog  << fCaps.maxwidth << "x" << fCaps.maxheight << endl;
+    gLog  << endl;
+    if (fChannel.channel>=0)
+    {
+        gLog  << " - Channel:    " << fChannel.channel << " (" << fChannel.name << ")" << endl;
+        gLog  << " - IsA:        " << GetChannelType(fChannel.type) << " with " << GetChannelFlags(fChannel.flags) << " (" << fChannel.flags << ")" << endl;
+        //if (fChannel.flags&VIDEO_VC_NORM)
+        gLog  << " - Norm:       " << fChannel.norm << endl;
+        gLog  << endl;
+    }
+
+    if (fAbil.tuner>=0)
+    {
+        gLog << " - Tuner:           " << fAbil.tuner << endl;
+        gLog << " - Name:            " << fAbil.name << endl;
+ //       gLog << " - Tuner Range:     " << fAbil.rangelow << " - " << fAbil.rangehigh << endl;
+        gLog << " - Tuner flags:    " << GetTunerFlags(fAbil.flags) << " (" << fAbil.flags << ")" << endl;
+        gLog << " - Tuner mode:      " << GetTunerMode(fAbil.mode) << " (" << fAbil.mode << ")" <<endl;
+        gLog << " - Signal Strength: " << fAbil.signal << endl;
+    }
+
+    gLog  << " - Brightness: " << fProp.brightness << endl;
+    gLog  << " - Hue:        " << fProp.hue << endl;
+    gLog  << " - Color:      " << fProp.colour << endl;
+    gLog  << " - Contrast:   " << fProp.contrast << endl;
+    gLog  << " - Whiteness:  " << fProp.whiteness << endl;
+    gLog  << " - Depth:      " << fProp.depth << endl;
+    gLog  << " - Palette:    " << GetPalette(fProp.palette) << " (" << fProp.palette << ")" << endl;
+    gLog  << endl;
+
+//    gLog  << " - BufferSize: 0x" << hex << fBuffer.size << " (" << dec << fBuffer.frames << " frames)" << endl;
+//    gLog  << " - Offsets:   " << hex;
+//    for (int i=0; i<fBuffer.frames; i++)
+//        gLog  << " 0x" << fBuffer.offsets[i];
+//    gLog  << dec << endl;
+
+    gLog << inf2 << "Controls:" << endl;
+    fControls.Print();
+}
+
+/*
+void MVideo::SetPicPar(int bright, int hue, int contrast)
+{
+    struct video_picture pict;
+
+    Ioctl(VIDIOCGPICT, &pict);  // get
+
+    if (contrast != -1)
+        pict.contrast = contrast;
+
+    if (bright != -1)
+        pict.brightness = bright;
+
+    if (hue != -1)
+	pict.hue = hue;
+
+    Ioctl(VIDIOCSPICT, &pict);  //set
+}
+
+void MVideo::GetPicPar(int *bright, int *hue, int *contrast)
+{
+    struct video_picture pict;
+
+    Ioctl(VIDIOCGPICT, &pict);   // get
+
+    *contrast = pict.contrast;
+    *bright   = pict.brightness;
+    *hue      = pict.hue;
+}
+*/
Index: /trunk/FACT++/drive/MVideo.h
===================================================================
--- /trunk/FACT++/drive/MVideo.h	(revision 18618)
+++ /trunk/FACT++/drive/MVideo.h	(revision 18618)
@@ -0,0 +1,140 @@
+#ifndef MARS_MVideo
+#define MARS_MVideo
+
+#ifndef MAGIC_MAGIC
+#include "MAGIC.h"
+#endif
+
+#ifndef __CINT__
+#ifndef __LINUX_VIDEODEV_H
+#include "videodev.h"  // video4linux
+#endif
+#ifndef __LINUX_VIDEODEV2_H
+#include <linux/videodev2.h> // video4linux2
+#endif
+#endif
+
+#include <vector>
+
+struct v4l2_queryctrl;
+struct v4l2_input;
+struct v4l2_standard;
+struct v4l2_buffer;
+
+class TEnv;
+
+class MVideoCtrl : public TObject
+{
+    friend class MVideo;
+private:
+    UInt_t  fId;
+    //enum v4l2_ctrl_type  type;
+    TString fName;
+    Int_t   fMinimum;
+    Int_t   fMaximum;
+    Int_t   fStep;
+    Int_t   fDefault;
+    UInt_t  fFlags;
+
+    UInt_t  fValue;
+
+public:
+    MVideoCtrl(const v4l2_queryctrl &ctrl);
+    const char *GetName() const { return fName; }
+    const char *GetTitle() const { return Form("Range=[%d;%d] Step=%d Def=%d", fMinimum, fMaximum, fStep, fDefault); }
+
+    //ClassDef(MVideoCtrl, 0) // Helper class to enumare device controls
+};
+
+class MVideo
+{
+private:
+    TString fPath; // Device path
+
+    int fFileDesc; // File descriptor
+
+    unsigned char *fMapBuffer;
+
+protected:
+    struct video_capability fCaps;      // Device capabilities
+    struct video_channel    fChannel;   // Channel information
+    //struct video_mbuf       fBuffer;    // Buffer information
+    struct video_picture    fProp;      // Picture properties
+    struct video_tuner      fAbil;      // Tuner abilities
+
+    ULong64_t fVideoStandard;
+
+    std::vector<v4l2_input>      fInputs;
+    std::vector<v4l2_standard>   fStandards;
+    std::vector<std::pair<v4l2_buffer, void*> > fBuffers;
+
+    TList fControls;
+
+private:
+    int Ioctl(int req, void *opt, bool allowirq=true, bool force=false) const;
+
+    void Reset();
+
+    Bool_t EnumerateControls(UInt_t id);
+    Bool_t EnumerateControls();
+    Bool_t GetCapabilities();
+    Bool_t GetProperties();
+    Bool_t GetTunerAbilities();
+    Bool_t GetVideoStandard();
+    Bool_t Init(Int_t channel);
+
+    template<class S>
+        Bool_t Enumerate(std::vector<S> &s, int request);
+
+    void PrintInputs() const;
+    void PrintStandards() const;
+
+    // Conversion functions
+    TString GetDevType(int type) const;
+    TString GetChannelFlags(Int_t flags) const;
+    TString GetChannelType(Int_t type) const;
+    TString GetTunerFlags(Int_t type) const;
+    TString GetTunerMode(Int_t type) const;
+    TString GetPalette(Int_t pal) const;
+
+public:
+    MVideo(const char *path="/dev/video0");
+    virtual ~MVideo() { Close(); }
+
+    // Getter
+    Bool_t IsOpen() const { return fFileDesc>0 && fBuffers.size()>0; }
+    Bool_t CanCapture() const;
+    Bool_t HasTuner() const;
+    Int_t  GetNumBuffers() const;
+
+    Int_t  GetWidth() const;
+    Int_t  GetHeight() const;
+
+    // Control
+    Bool_t Open(Int_t channel=0);
+    Int_t  Close();
+
+    Int_t SetChannel(Int_t chan);
+    Bool_t ReadControl(MVideoCtrl &vctrl) const;
+    Bool_t WriteControl(MVideoCtrl &vctrl, Int_t val) const;
+    Bool_t SetControls(TEnv &env) const;
+    Bool_t ResetControl(MVideoCtrl &vctrl) const;
+    Bool_t ResetControls() const;
+
+    // Image capture
+    Bool_t CaptureStart(unsigned int frame) const;
+    Int_t  CaptureWait(unsigned int frame, unsigned char **ptr=0) const;
+    Bool_t Start();
+
+    // Support
+    void Print() const;
+
+    // hardware features
+    //void SetPicPar(int  bright, int  hue, int  contrast);
+    //void GetPicPar(int *bright, int *hue, int *contrast);
+
+    //ClassDef(MVideo, 0) // Interface to Video4Linux at a simple level
+
+};
+
+#endif
Index: /trunk/FACT++/drive/PixClient.cc
===================================================================
--- /trunk/FACT++/drive/PixClient.cc	(revision 18618)
+++ /trunk/FACT++/drive/PixClient.cc	(revision 18618)
@@ -0,0 +1,12 @@
+#include "PixClient.h"
+
+#include <iostream>
+
+using namespace std;
+
+void PixClient::ProcessFrame(const unsigned long n, byte *img,
+                             struct timeval *tm)
+{
+    cout << "PixClient - Img: " << n << "  " << (void*)img << endl;
+}
+
Index: /trunk/FACT++/drive/PixClient.h
===================================================================
--- /trunk/FACT++/drive/PixClient.h	(revision 18618)
+++ /trunk/FACT++/drive/PixClient.h	(revision 18618)
@@ -0,0 +1,22 @@
+#ifndef COSY_PixClient
+#define COSY_PixClient
+
+#ifdef __CINT__
+struct timeval;
+#else
+#include <unistd.h>
+#include <sys/time.h>
+#endif
+
+
+typedef unsigned char byte;
+
+class PixClient
+{
+public:
+    virtual ~PixClient() { }
+    virtual void ProcessFrame(const unsigned long n,
+                              byte *img, struct timeval *tm);
+};
+
+#endif
Index: /trunk/FACT++/drive/Ring.cc
===================================================================
--- /trunk/FACT++/drive/Ring.cc	(revision 18618)
+++ /trunk/FACT++/drive/Ring.cc	(revision 18618)
@@ -0,0 +1,148 @@
+#include "Ring.h"
+
+#include <iostream>
+
+#include <math.h>
+
+#include "Led.h"
+#include "Leds.h"
+
+#include "Rings.h"
+#include "MString.h"
+
+ClassImp(Ring);
+
+using namespace std;
+
+Ring::Ring(Double_t x, Double_t y) :
+    fX(x), fY(y), fR(0), fPhi(0), fDx(-1), fDy(-1), fDr(-1), fDphi(-1)
+{
+}
+
+bool Ring::CalcCenter(const Leds &leds, Int_t i, Int_t j, Int_t k)
+{
+    if (leds.At(i)==NULL)
+    {
+        cout << "Ring::CalcCenter: Led i=" << i << " is NULL." << endl;
+        return kFALSE;
+    }
+    if (leds.At(j)==NULL)
+    {
+        cout << "Ring::CalcCenter: Led j=" << j << " is NULL." << endl;
+        return kFALSE;
+    }
+    if (leds.At(k)==NULL)
+    {
+        cout << "Ring::CalcCenter: Led k=" << k << " is NULL." << endl;
+        return kFALSE;
+    }
+
+    Double_t h1 = leds(i).GetY()- leds(j).GetY();
+
+    if (h1==0)
+    {
+        Swap(j, k);
+        h1 = leds(i).GetY()- leds(j).GetY();
+        if (h1==0)
+        {
+            cout << "Ring::CalcCenter: h1==0" <<endl;
+            return kFALSE;
+        }
+    }
+
+    Double_t h2 = leds(j).GetY() - leds(k).GetY();
+
+    if (h2==0)
+    {
+        Swap(i, j);
+        h2 = leds(j).GetY() - leds(k).GetY();
+        if (h2==0)
+        {
+            cout << "Ring::CalcCenter: h2==0" << endl;
+            return kFALSE;
+        }
+    }
+
+    const Double_t w1 = leds(i).GetX() - leds(j).GetX();
+    const Double_t w2 = leds(j).GetX() - leds(k).GetX();
+
+    const Double_t m1 = -w1/h1;
+    const Double_t m2 = -w2/h2;
+
+    if (m2-m1==0)
+    {
+        cout << "Ring::CalcCenter: All three points in a row! (m2-m1==0)" << endl;
+        return kFALSE;
+    }
+
+    fX = ((m2*(leds(j).GetX() + leds(k).GetX()) + leds(i).GetY() - leds(k).GetY()       -m1*(leds(i).GetX() + leds(j).GetX()))/(m2-m1)/2);
+    fY = ((m2*(leds(i).GetY() + leds(j).GetY()) +m1*m2*(leds(k).GetX() - leds(i).GetX())-m1*(leds(j).GetY() + leds(k).GetY()))/(m2-m1)/2);
+
+    fR = hypot(fX-leds(i).GetX(), fY-leds(i).GetY());
+
+    fMag = (leds(i).GetMag() + leds(j).GetMag() + leds(k).GetMag())/3;
+
+    return kTRUE;
+}
+
+void Ring::InterpolCenters(const Rings &rings)
+{
+    const int n=rings.GetEntries();
+
+    fX = 0;
+    fY = 0;
+    fR = 0;
+
+    fDx=0;
+    fDy=0;
+    fDr=0;
+
+    fMag=0;
+
+    if (n<1)
+        return;
+
+    for (int i=0; i<n; i++)
+    {
+        const Ring &ring = rings(i);
+
+        fX   += ring.GetX();
+        fY   += ring.GetY();
+        fR   += ring.GetR();
+        fMag += ring.GetMag();
+    }
+
+    fX   /= n;
+    fY   /= n;
+    fR   /= n;
+    fMag /= n;
+
+    if (n<2)
+        return;
+
+    //
+    // deviation of x- and y coordinate and radius
+    //
+    for (int i=0; i<n; i++)
+    {
+        const Ring &ring = rings(i);
+
+        fDx += sqr(ring.GetX()-fX);
+        fDy += sqr(ring.GetY()-fY);
+        fDr += sqr(ring.GetR()-fR);
+    }
+
+    fDx=sqrt(fDx)/n;
+    fDy=sqrt(fDy)/n;
+    fDr=sqrt(fDr)/n;
+}
+
+void Ring::Print(Option_t *o) const
+{
+    cout << "Ring: ";
+    cout << "x="   << MString::Format("%5.1f", fX) << "+-" << MString::Format("%.1f", fDx) << ", ";
+    cout << "y="   << MString::Format("%5.1f", fY) << "+-" << MString::Format("%.1f", fDy) << ", ";
+    cout << "r="   << MString::Format("%5.1f", fR) << "+-" << MString::Format("%.1f", fDr) << ", ";
+    cout << "phi=" << fPhi              << "+-" << fDphi << endl;
+}
+
Index: /trunk/FACT++/drive/Ring.h
===================================================================
--- /trunk/FACT++/drive/Ring.h	(revision 18618)
+++ /trunk/FACT++/drive/Ring.h	(revision 18618)
@@ -0,0 +1,55 @@
+#ifndef COSY_Ring
+#define COSY_Ring
+
+#ifndef ROOT_TObject
+#include <TObject.h>
+#endif
+
+class Leds;
+class Rings;
+
+class Ring : public TObject
+{
+private:
+    Double_t fX;
+    Double_t fY;
+    Double_t fR;
+    Double_t fPhi;
+
+    Double_t fDx;
+    Double_t fDy;
+    Double_t fDr;
+    Double_t fDphi;
+
+    Double_t fMag;
+
+    Double_t sqr(Double_t x) { return x*x; }
+
+    void Swap(int &m, int &n)
+    {
+        int dummy = m;
+        m = n;
+        n = dummy;
+    }
+
+public:
+    Ring(Double_t x=0, Double_t y=0);
+
+    void SetXY(Double_t x=0, Double_t y=0) { fX=x; fY=y; }
+
+    Double_t GetX() const   { return fX; }
+    Double_t GetY() const   { return fY; }
+    Double_t GetR() const   { return fR; }
+    Double_t GetPhi() const { return fPhi; }
+
+    Double_t GetMag() const { return fMag; }
+
+    bool CalcCenter(const Leds &leds, Int_t i, Int_t j, Int_t k);
+    void InterpolCenters(const Rings &rings);
+
+    void Print(Option_t *o=NULL) const;
+
+    ClassDef(Ring, 1)
+};
+
+#endif
Index: /trunk/FACT++/drive/TPointGui.cc
===================================================================
--- /trunk/FACT++/drive/TPointGui.cc	(revision 18618)
+++ /trunk/FACT++/drive/TPointGui.cc	(revision 18618)
@@ -0,0 +1,1336 @@
+#include "TPointGui.h"
+
+#include <fstream>
+#include <stdlib.h>
+
+#include <TGLabel.h>
+#include <TGButton.h>
+#include <TGTextEntry.h>
+
+#include <TView.h>
+#include <TStyle.h>
+#include <TCanvas.h>
+
+#include <TText.h>
+#include <TLine.h>
+#include <TMarker.h>
+#include <TPolyLine.h>
+
+#include <TF1.h>
+#include <TH2.h>
+#include <TMath.h>
+#include <TMinuit.h>
+#include <TProfile.h>
+#include <TGraphErrors.h>
+
+#include "MLog.h"
+#include "MLogManip.h"
+
+#include "MGList.h"
+
+#include "TPointStar.h"
+
+ClassImp(TPointGui);
+
+using namespace std;
+
+TPointGui::TPointGui(const char *fname, const char *mod) : TGMainFrame(gClient->GetRoot(), 750, 435, kHorizontalFrame), fExitLoopOnClose(kFALSE),
+   fAzMin(-180), fAzMax(180), fZdMin(0), fZdMax(90), fMagMin(0), fLimit(0.05)
+{
+    fCoordinates.SetOwner();
+    fOriginal.SetOwner();
+
+    fList = new MGList;
+    fList->SetOwner();
+
+    fFont = gVirtualX->LoadQueryFont("7x13bold");
+
+    TGLayoutHints *hints0 = new TGLayoutHints(kLHintsExpandY, 7, 5, 5, 0);
+    TGLayoutHints *hints1 = new TGLayoutHints(kLHintsExpandX|kLHintsExpandY, 5, 7, 5, 6);
+    fList->Add(hints0);
+    fList->Add(hints1);
+
+    TGGroupFrame *grp1 = new TGGroupFrame(this, "Control", kVerticalFrame);
+    AddFrame(grp1, hints0);
+    fList->Add(grp1);
+
+    TGGroupFrame *grp2 = new TGGroupFrame(this, "Parameters", kHorizontalFrame);
+    AddFrame(grp2, hints1);
+    fList->Add(grp2);
+
+
+    TGLayoutHints *hints4 = new TGLayoutHints(kLHintsExpandX, 5, 5,  3);
+    TGLayoutHints *hints5 = new TGLayoutHints(kLHintsExpandX, 5, 5, 10);
+    AddTextButton(grp1, "Load Pointing Model", kTbLoad,        hints5);
+    AddTextButton(grp1, "Save Pointing Model", kTbSave,        hints4);
+    AddTextButton(grp1, "Fit Parameters",      kTbFit,         hints5);
+    AddTextButton(grp1, "Reset Parameters",    kTbReset,       hints4);
+    AddTextButton(grp1, "Load Stars",          kTbLoadStars,   hints5);
+    AddTextButton(grp1, "Reset Stars",         kTbResetStars,  hints4);
+    AddTextButton(grp1, "Reload Stars",        kTbReloadStars, hints4);
+    fList->Add(hints4);
+    fList->Add(hints5);
+
+
+
+
+
+
+
+    TGHorizontalFrame *comp = new TGHorizontalFrame(grp2, 1, 1);
+    grp2->AddFrame(comp);
+    fList->Add(comp);
+
+    TGLayoutHints *hints3 = new TGLayoutHints(kLHintsLeft|kLHintsTop, 0, 10, 5, 0);
+    fList->Add(hints3);
+
+    TGVerticalFrame *vframe = new TGVerticalFrame(comp, 1, 1);
+
+    for (int i=0; i<MPointing::GetNumPar(); i++)
+        AddCheckButton(vframe, fBending.GetVarName(i), i);
+
+    TGButton *but = (TGButton*)fList->FindWidget(0);
+
+    comp->AddFrame(vframe, hints3);
+    fList->Add(vframe);
+
+    vframe = new TGVerticalFrame(comp, 1, 1);
+    comp->AddFrame(vframe, hints3);
+    fList->Add(vframe);
+
+    hints3 = new TGLayoutHints(kLHintsLeft|kLHintsTop, 0, 10, 5, 0);
+    fList->Add(hints3);
+
+    TGLabel *l = new TGLabel(vframe, "+000.0000");
+    l->SetTextJustify(kTextRight);
+    fList->Add(l);
+    fLabel.Add(l);
+
+    TGLayoutHints *h = new TGLayoutHints(kLHintsCenterY, 0, 0, but->GetHeight()-l->GetHeight());
+    fList->Add(h);
+
+    vframe->AddFrame(l,h);
+
+    for (int i=1; i<MPointing::GetNumPar(); i++)
+        AddLabel(vframe, "+000.0000", h)->SetTextJustify(kTextRight);
+
+    vframe = new TGVerticalFrame(comp, 1, 1);
+    comp->AddFrame(vframe, hints3);
+    fList->Add(vframe);
+
+    for (int i=0; i<MPointing::GetNumPar(); i++)
+        AddLabel(vframe, "\xb1 00.0000\xb0", h)->SetTextJustify(kTextRight);
+
+    hints3 = new TGLayoutHints(kLHintsLeft|kLHintsTop, 0, 20, 5, 0);
+    fList->Add(hints3);
+
+    TGLayoutHints *hreset = new TGLayoutHints(kLHintsLeft|kLHintsTop, 0, 0, 3, 1);
+    fList->Add(hreset);
+
+    TGVerticalFrame *vframe2 = new TGVerticalFrame(comp, 1, 1);
+    comp->AddFrame(vframe2, hints3);
+    fList->Add(vframe2);
+    for (int i=0; i<MPointing::GetNumPar(); i++)
+        AddResetButton(vframe2, i+2*MPointing::GetNumPar(), hreset,
+                       but->GetHeight()-4);
+
+    vframe = new TGVerticalFrame(comp, 1, 1);
+    comp->AddFrame(vframe, hints3);
+    fList->Add(vframe);
+
+    for (int i=0; i<MPointing::GetNumPar(); i++)
+        AddLabel(vframe, fBending.GetDescription(i), h);
+
+    TGLayoutHints *hints6 = new TGLayoutHints(kLHintsExpandX, 5, 5, 4, 6);
+    fList->Add(hints6);
+
+    l = new TGLabel(grp1, "0000000 Data Sets loaded.");
+    grp1->AddFrame(l, hints6);
+    fList->Add(l);
+    fLabel.Add(l);
+
+    l = new TGLabel(grp1, "");
+    l->SetTextJustify(kTextLeft);
+    grp1->AddFrame(l, hints6);
+    fList->Add(l);
+    fLabel.Add(l);
+
+    l = new TGLabel(grp1, "");
+    l->SetTextJustify(kTextLeft);
+    grp1->AddFrame(l, hints6);
+    fList->Add(l);
+    fLabel.Add(l);
+
+    l = new TGLabel(grp1, "");
+    l->SetTextJustify(kTextLeft);
+    grp1->AddFrame(l, hints6);
+    fList->Add(l);
+    fLabel.Add(l);
+
+    // ------------------------------------------------------------------
+
+    TGLayoutHints *hintse1 = new TGLayoutHints(kLHintsExpandX|kLHintsBottom);
+    TGLayoutHints *hintse2 = new TGLayoutHints(kLHintsExpandX, 2, 2);
+    TGLayoutHints *hintse3 = new TGLayoutHints(kLHintsExpandX);
+    TGLayoutHints *hintsl  = new TGLayoutHints(kLHintsExpandX, 1, 0, 5);
+    fList->Add(hintse1);
+    fList->Add(hintse2);
+    fList->Add(hintse3);
+
+    TGHorizontalFrame *entries = new TGHorizontalFrame(grp1, 1, 1);
+    grp1->AddFrame(entries, hintse1);
+    fList->Add(entries);
+
+    TGVerticalFrame *v1 = new TGVerticalFrame(entries);
+    TGVerticalFrame *v2 = new TGVerticalFrame(entries);
+    TGVerticalFrame *v3 = new TGVerticalFrame(entries);
+    entries->AddFrame(v1, hintse2);
+    entries->AddFrame(v2, hintse2);
+    entries->AddFrame(v3, hintse2);
+    fList->Add(v1);
+    fList->Add(v2);
+    fList->Add(v3);
+
+    TGLabel *label1 = new TGLabel(v1, "Az min/°");
+    TGLabel *label2 = new TGLabel(v2, "Az max/°");
+    TGLabel *label3 = new TGLabel(v3, "Mag min");
+    TGLabel *label4 = new TGLabel(v1, "Zd min/°");
+    TGLabel *label5 = new TGLabel(v2, "Zd max/°");
+    TGLabel *label6 = new TGLabel(v3, "Limit/°");
+    label1->SetTextJustify(kTextLeft);
+    label2->SetTextJustify(kTextLeft);
+    label3->SetTextJustify(kTextLeft);
+    label4->SetTextJustify(kTextLeft);
+    label5->SetTextJustify(kTextLeft);
+    label6->SetTextJustify(kTextLeft);
+    fList->Add(label1);
+    fList->Add(label2);
+    fList->Add(label3);
+    fList->Add(label4);
+    fList->Add(label5);
+    fList->Add(label6);
+
+    TGTextEntry *entry1 = new TGTextEntry(v1, Form("%.1f", fAzMin),  kIdAzMin);
+    TGTextEntry *entry2 = new TGTextEntry(v2, Form("%.1f", fAzMax),  kIdAzMax);
+    TGTextEntry *entry3 = new TGTextEntry(v3, Form("%.1f", fMagMin), kIdMagMin);
+    TGTextEntry *entry4 = new TGTextEntry(v1, Form("%.1f", fZdMin),  kIdZdMin);
+    TGTextEntry *entry5 = new TGTextEntry(v2, Form("%.1f", fZdMax),  kIdZdMax);
+    TGTextEntry *entry6 = new TGTextEntry(v3, Form("%.3f", fLimit),  kIdLimit);
+    entry1->SetToolTipText("TPoints with a real star located at Az<Az min are ignored in the fit.");
+    entry2->SetToolTipText("TPoints with a real star located at Az>Az max are ignored in the fit.");
+    entry2->SetToolTipText("TPoints with a artifiical magnitude Mag<Mag min are ignored in the fit.");
+    entry4->SetToolTipText("TPoints with a real star located at Zd<Zd min are ignored in the fit.");
+    entry5->SetToolTipText("TPoints with a real star located at Zd>Zd max are ignored in the fit.");
+    entry6->SetToolTipText("TPoints with an residual after the fit > Limit are output.");
+    entry1->Associate(this);
+    entry2->Associate(this);
+    entry3->Associate(this);
+    entry4->Associate(this);
+    entry5->Associate(this);
+    entry6->Associate(this);
+    v1->AddFrame(label1, hintsl);
+    v1->AddFrame(entry1, hintse3);
+    v1->AddFrame(label4, hintsl);
+    v1->AddFrame(entry4, hintse3);
+    v2->AddFrame(label2, hintsl);
+    v2->AddFrame(entry2, hintse3);
+    v2->AddFrame(label5, hintsl);
+    v2->AddFrame(entry5, hintse3);
+    v3->AddFrame(label3, hintsl);
+    v3->AddFrame(entry3, hintse3);
+    v3->AddFrame(label6, hintsl);
+    v3->AddFrame(entry6, hintse3);
+    fList->Add(entry1);
+    fList->Add(entry2);
+    fList->Add(entry3);
+    fList->Add(entry4);
+    fList->Add(entry5);
+    fList->Add(entry6);
+
+    // ------------------------------------------------------------------
+
+    // FIXME: Move this to the rc-file.
+    ((TGCheckButton*)fList->FindWidget(0))->SetState(kButtonDown);
+    ((TGCheckButton*)fList->FindWidget(1))->SetState(kButtonDown);
+    ((TGCheckButton*)fList->FindWidget(5))->SetState(kButtonDown);
+    ((TGCheckButton*)fList->FindWidget(6))->SetState(kButtonDown);
+    ((TGCheckButton*)fList->FindWidget(9))->SetState(kButtonDown);
+    ((TGCheckButton*)fList->FindWidget(11))->SetState(kButtonDown);
+    ((TGCheckButton*)fList->FindWidget(15))->SetState(kButtonDown);
+    ((TGCheckButton*)fList->FindWidget(16))->SetState(kButtonDown);
+    ((TGCheckButton*)fList->FindWidget(17))->SetState(kButtonDown);
+
+    ((TGCheckButton*)fList->FindWidget(19))->SetState(kButtonDisabled);
+    ((TGCheckButton*)fList->FindWidget(20))->SetState(kButtonDisabled);
+    ((TGCheckButton*)fList->FindWidget(21))->SetState(kButtonDisabled);
+    ((TGCheckButton*)fList->FindWidget(22))->SetState(kButtonDisabled);
+
+    ((TGCheckButton*)fList->FindWidget(19+2*MPointing::GetNumPar()))->SetState(kButtonDisabled);
+    ((TGCheckButton*)fList->FindWidget(20+2*MPointing::GetNumPar()))->SetState(kButtonDisabled);
+    ((TGCheckButton*)fList->FindWidget(21+2*MPointing::GetNumPar()))->SetState(kButtonDisabled);
+    ((TGCheckButton*)fList->FindWidget(22+2*MPointing::GetNumPar()))->SetState(kButtonDisabled);
+
+    SetWindowName("Telesto");
+    SetIconName("Telesto");
+
+    Layout();
+
+    MapSubwindows();
+    MapWindow();
+
+    if (!TString(fname).IsNull())
+        LoadStars(fname);
+    if (!TString(mod).IsNull())
+        fBending.Load(mod);
+
+    DisplayBending();
+    DisplayData();
+}
+
+TPointGui::~TPointGui()
+{
+    if (fFont)
+        gVirtualX->DeleteFont(fFont);
+
+    delete fList;
+
+    if (fExitLoopOnClose)
+        gSystem->ExitLoop();
+}
+
+void TPointGui::Fcn(Int_t &/*npar*/, Double_t */*gin*/, Double_t &f, Double_t *par, Int_t /*iflag*/)
+{
+    f = 0;
+
+    MPointing bend;
+    bend.SetParameters(par); // Set Parameters [deg] to MPointing
+
+    for (int i=0; i<fCoordinates.GetSize(); i++)
+    {
+        TPointStar set = *(TPointStar*)fCoordinates.At(i);
+
+        if (set.GetStarZd()<fZdMin || set.GetStarZd()>fZdMax ||
+            set.GetStarAz()<fAzMin || set.GetStarAz()>fAzMax ||
+            set.GetMag()   <fMagMin)
+            continue;
+
+        set.Adjust(bend);
+
+        Double_t err = 0.01; // [deg] = 0.25SE
+        Double_t res = set.GetResidual();//(&err);
+        res /= err;
+
+        f += res*res;
+    }
+
+    f /= fCoordinates.GetSize();
+}
+
+void TPointGui::fcn(Int_t &npar, Double_t *gin, Double_t &f, Double_t *par, Int_t iflag)
+{
+    ((TPointGui*)gMinuit->GetObjectFit())->Fcn(npar, gin, f, par, iflag);
+}
+
+void TPointGui::AddTextButton(TGCompositeFrame *f, TString txt, Int_t id, TGLayoutHints *h)
+{
+    TGButton *but = new TGTextButton(f, txt, id);
+    but->Associate(this);
+    f->AddFrame(but, h);
+    fList->Add(but);
+
+}
+
+void TPointGui::AddCheckButton(TGCompositeFrame *f, TString txt, Int_t id, TGLayoutHints *h)
+{
+    TGButton *but = new TGCheckButton(f, txt, id);
+    but->Associate(this);
+    f->AddFrame(but, h);
+    fList->Add(but);
+}
+
+void TPointGui::AddResetButton(TGCompositeFrame *f, Int_t id, TGLayoutHints *h, Int_t height)
+{
+    TGPictureButton *but = new TGPictureButton(f, "tpoint/skull.xpm", id);
+    but->SetHeight(height); // Offsets from TGLayout
+    but->SetWidth(height);
+    but->Associate(this);
+    f->AddFrame(but, h);
+    fList->Add(but);
+}
+
+TGLabel *TPointGui::AddLabel(TGCompositeFrame *f, TString txt, TGLayoutHints *h)
+{
+    TGLabel *l = new TGLabel(f, txt/*, TGLabel::GetDefaultGC()(), fFont*/);
+    f->AddFrame(l, h);
+    fList->Add(l);
+    fLabel.Add(l);
+    return l;
+}
+
+void TPointGui::DisplayBending()
+{
+    TArrayD par, err;
+    fBending.GetParameters(par);
+    fBending.GetError(err);
+
+    TGLabel *l;
+
+    for (int i=0; i<MPointing::GetNumPar(); i++)
+    {
+        l = (TGLabel*)fLabel.At(i);
+        l->SetText(Form("%.4f\xb0", par[i]));
+
+        l = (TGLabel*)fLabel.At(MPointing::GetNumPar()+i);
+        l->SetText(Form("\xb1 %8.4f\xb0", err[i]>0?err[i]:0));
+    }
+}
+
+void TPointGui::DisplayData()
+{
+    TGLabel *l = (TGLabel*)fLabel.At(3*MPointing::GetNumPar());
+    l->SetText(Form("%d data sets loaded.", fOriginal.GetSize()));
+}
+
+void TPointGui::DisplayResult(Double_t before, Double_t after, Double_t backw)
+{
+    TGLabel *l1 = (TGLabel*)fLabel.At(3*MPointing::GetNumPar()+1);
+    l1->SetText(Form("Before: %.1f +- %.1f SE", before, 0.));
+
+    TGLabel *l2 = (TGLabel*)fLabel.At(3*MPointing::GetNumPar()+2);
+    l2->SetText(Form("After:  %.1f +- %.1f SE", after, 0.));
+
+    TGLabel *l3 = (TGLabel*)fLabel.At(3*MPointing::GetNumPar()+3);
+    l3->SetText(Form("Backw:  %.1f +- %.1f SE", backw, 0.));
+}
+
+void TPointGui::DrawMarker(TVirtualPad *pad, Double_t r0, Double_t phi0)
+{
+    TView *view = pad->GetView();
+
+    if (!view)
+    {
+        gLog << err << "No View!" << endl;
+        return;
+    }
+
+    TMarker mark0;
+    mark0.SetMarkerStyle(kFullDotLarge);
+    mark0.SetMarkerColor(kBlue);
+
+    r0 /= 90;
+    phi0 *= TMath::DegToRad();
+
+    Double_t x[6] = { r0*cos(phi0), r0*sin(phi0), 0, 0, 0, 0};
+
+    view->WCtoNDC(x, x+3);
+
+    mark0.DrawMarker(-x[3], x[4]);
+}
+
+void TPointGui::DrawPolLine(TVirtualPad *pad, Double_t r0, Double_t phi0, Double_t r1, Double_t phi1)
+{
+    TView *view = pad->GetView();
+
+    if (!view)
+    {
+        gLog << err << "No View!" << endl;
+        return;
+    }
+    /*
+    if (r0<0)
+    {
+        r0 = -r0;
+        phi0 += 180;
+    }
+    if (r1<0)
+    {
+        r1 = -r1;
+        phi1 += 180;
+    }
+
+    phi0 = fmod(phi0+360, 360);
+    phi1 = fmod(phi1+360, 360);
+
+    if (phi1-phi0<-180)
+        phi1+=360;
+    */
+    TLine line;
+    line.SetLineWidth(2);
+    line.SetLineColor(kBlue);
+
+    Double_t p0 = phi0<phi1?phi0:phi1;
+    Double_t p1 = phi0<phi1?phi1:phi0;
+
+    if (phi0>phi1)
+    {
+        Double_t d = r1;
+        r1 = r0;
+        r0 = d;
+    }
+
+    r0 /= 90;
+    r1 /= 90;
+
+    Double_t dr = r1-r0;
+    Double_t dp = p1-p0;
+
+    Double_t x0[3] = { r0*cos(p0*TMath::DegToRad()), r0*sin(p0*TMath::DegToRad()), 0};
+
+    for (double i=p0+10; i<p1+10; i+=10)
+    {
+        if (i>p1)
+            i=p1;
+
+        Double_t r = dr/dp*(i-p0)+r0;
+        Double_t p = TMath::DegToRad()*i;
+
+        Double_t x1[3] = { r*cos(p), r*sin(p), 0};
+
+        Double_t y0[3], y1[3];
+
+        view->WCtoNDC(x0, y0);
+        view->WCtoNDC(x1, y1);
+
+        line.DrawLine(y0[0], y0[1], y1[0], y1[1]);
+
+        x0[0] = x1[0];
+        x0[1] = x1[1];
+    }
+}
+
+void TPointGui::DrawSet(TVirtualPad *pad, TPointStar &set, Float_t scale, Float_t angle)
+{
+    Double_t r0   = set.GetRawZd();
+    Double_t phi0 = set.GetRawAz()-angle;
+    Double_t r1   = set.GetStarZd();
+    Double_t phi1 = set.GetStarAz()-angle;
+
+    if (r0<0)
+    {
+        r0 = -r0;
+        phi0 += 180;
+    }
+    if (r1<0)
+    {
+        r1 = -r1;
+        phi1 += 180;
+    }
+
+    phi0 = fmod(phi0+360, 360);
+    phi1 = fmod(phi1+360, 360);
+
+    if (phi1-phi0<-180)
+        phi1+=360;
+
+    if (scale<0 || scale>1000)
+        scale = -1;
+
+    if (scale>0)
+    {
+        Double_t d = r1-r0;
+        r0 += scale*d;
+        r1 -= scale*d;
+        d = phi1-phi0;
+        phi0 += scale*d;
+        phi1 -= scale*d;
+
+        DrawPolLine(pad, r0, phi0, r1, phi1);
+        DrawMarker(pad,  r0, phi0);
+    }
+    else
+        DrawMarker(pad,  r1, phi1);
+}
+
+void TPointGui::DrawHorizon(TVirtualPad *pad, const char *fname) const
+{
+    TView *view = pad->GetView();
+
+    if (!view)
+    {
+        gLog << err << "No View!" << endl;
+        return;
+    }
+
+    ifstream fin(fname);
+    if (!fin)
+    {
+        gLog << err << "ERROR - " << fname << " not found." << endl;
+        return;
+    }
+
+    TPolyLine poly;
+    poly.SetLineWidth(2);
+    poly.SetLineColor(12);
+    poly.SetLineStyle(8);
+
+    while (1)
+    {
+        TString line;
+        line.ReadLine(fin);
+        if (!fin)
+            break;
+
+        Float_t az, alt;
+        sscanf(line.Data(), "%f %f", &az, &alt);
+
+        Float_t zd = 90-alt;
+
+        az *= TMath::DegToRad();
+        zd /= 90;
+
+        Double_t x[6] = { zd*cos(az), zd*sin(az), 0, 0, 0, 0};
+        view->WCtoNDC(x, x+3);
+        poly.SetNextPoint(-x[3], x[4]);
+    }
+
+    poly.DrawClone()->SetBit(kCanDelete);
+
+}
+
+TString TPointGui::OpenDialog(TString &dir, EFileDialogMode mode)
+{
+    static const char *gOpenTypes[] =
+    {
+        "TPoint files",     "*.txt",
+        "Collection files", "*.col",
+        "Model files",      "*.mod",
+        "All files",        "*",
+        NULL,           NULL
+    };
+
+    //static TString dir("tpoint/");
+
+    TGFileInfo fi; // fFileName and fIniDir deleted in ~TGFileInfo
+
+    fi.fFileTypes = (const char**)gOpenTypes;
+    fi.fIniDir    = StrDup(dir);
+
+    new TGFileDialog(fClient->GetRoot(), this, mode, &fi);
+
+    if (!fi.fFilename)
+        return "";
+
+    dir = fi.fIniDir;
+
+    return fi.fFilename;
+}
+
+void TPointGui::LoadCollection(TString fname)
+{
+    ifstream fin(fname);
+    if (!fin)
+    {
+        gLog << err << "Collection '" << fname << "' not found!" << endl;
+        return;
+    }
+
+    while (1)
+    {
+        TString line;
+        line.ReadLine(fin);
+        if (!fin)
+            break;
+
+        line = line.Strip(TString::kBoth);
+        if (line[0]=='#')
+            continue;
+        if (line.Length()==0)
+            continue;
+
+        if (!line.EndsWith(".txt"))
+        {
+            gLog << warn << "WARNING: " << line << endl;
+            continue;
+        }
+
+        LoadStars(line);
+    }
+}
+
+void TPointGui::LoadStars(TString fname)
+{
+    if (fname.EndsWith(".col"))
+    {
+        LoadCollection(fname);
+        fFileNameStars = fname;
+        SetWindowName(Form("Telesto (%s)", fFileNameStars.Data()));
+        return;
+    }
+
+    const Int_t size = fOriginal.GetSize();
+
+    ifstream fin(fname);
+
+    while (fin && fin.get()!='\n');
+    while (fin && fin.get()!='\n');
+    while (fin && fin.get()!='\n');
+    if (!fin)
+    {
+        gLog << err << "File '" << fname << "' not found!" << endl;
+        return;
+    }
+
+    TPointStar set(fname);
+
+    while (1)
+    {
+        fin >> set;  // Read data from file [deg], it is stored in [rad]
+        if (!fin)
+            break;
+
+//        if (set.GetRawZd()>60)
+//            continue;
+
+        fOriginal.Add(new TPointStar(set));
+    }
+
+    gLog << all << "Found " << fOriginal.GetSize()-size;
+    gLog << " sets of coordinates in " << fname;
+    gLog << " (Total=" << fOriginal.GetSize() << ")" << endl;
+
+    fFileNameStars = fname;
+    SetWindowName(Form("Telesto (%s)", fFileNameStars.Data()));
+}
+
+Float_t TPointGui::GetFloat(Int_t id) const
+{
+    return atof(static_cast<TGTextEntry*>(fList->FindWidget(id))->GetText());
+}
+
+Bool_t TPointGui::ProcessMessage(Long_t msg, Long_t mp1, Long_t)
+{
+    // cout << "Msg: " << hex << GET_MSG(msg) << endl;
+    // cout << "SubMsg: " << hex << GET_SUBMSG(msg) << dec << endl;
+
+    static TString dirmod("tpoint/");
+    static TString dircol("tpoint/");
+
+    switch (GET_MSG(msg))
+    {
+    case kC_COMMAND:
+        switch (GET_SUBMSG(msg))
+        {
+        case kCM_BUTTON:
+            switch (mp1)
+            {
+            case kTbFit:
+                {
+                    Double_t before=0;
+                    Double_t after=0;
+                    Double_t backw=0;
+                    Fit(before, after, backw);
+                    DisplayBending();
+                    DisplayResult(before, after, backw);
+                }
+                return kTRUE;
+            case kTbLoad:
+                fBending.Load(OpenDialog(dirmod));
+                DisplayBending();
+                return kTRUE;
+            case kTbSave:
+                fBending.Save(OpenDialog(dirmod, kFDSave));
+                return kTRUE;
+            case kTbLoadStars:
+                LoadStars(OpenDialog(dircol));
+                DisplayData();
+                return kTRUE;
+            case kTbReset:
+                fBending.Reset();
+                DisplayBending();
+                return kTRUE;
+            case kTbReloadStars:
+                fOriginal.Delete();
+                LoadStars(fFileNameStars); // FIXME: Use TGLabel!
+                DisplayData();
+                return kTRUE;
+            case kTbResetStars:
+                fOriginal.Delete();
+                DisplayData();
+                return kTRUE;
+            }
+
+            // In the default cas a reset button must have been pressed
+            fBending[mp1-2*MPointing::GetNumPar()] = 0;
+            DisplayBending();
+            return kTRUE;
+        }
+        return kTRUE;
+
+    case kC_TEXTENTRY:
+        switch (GET_SUBMSG(msg))
+        {
+        case kTE_TEXTCHANGED:
+            switch (mp1)
+            {
+            case kIdAzMin:
+                fAzMin = GetFloat(kIdAzMin);
+                return kTRUE;
+            case kIdAzMax:
+                fAzMax = GetFloat(kIdAzMax);
+                return kTRUE;
+            case kIdZdMin:
+                fZdMin = GetFloat(kIdZdMin);
+                return kTRUE;
+            case kIdZdMax:
+                fZdMax = GetFloat(kIdZdMax);
+                return kTRUE;
+            case kIdMagMin:
+                fMagMin = GetFloat(kIdMagMin);
+                return kTRUE;
+            case kIdLimit:
+                fLimit = GetFloat(kIdLimit);
+                return kTRUE;
+            }
+            return kTRUE;
+
+        }
+        return kTRUE;
+
+    }
+    return kTRUE;
+}
+
+void TPointGui::Fit(Double_t &before, Double_t &after, Double_t &backw)
+{
+    if (fOriginal.GetSize()==0)
+    {
+        gLog << warn << "Sorry, no input data loaded..." << endl;
+        return;
+    }
+
+    fCoordinates.Delete();
+    for (int i=0; i<fOriginal.GetSize(); i++)
+        fCoordinates.Add(new TPointStar(*(TPointStar*)fOriginal.At(i)));
+
+    gLog << all << "-----------------------------------------------------------------------" << endl;
+
+    gStyle->SetOptStat("emro");
+
+    TH1F hres1("Res1", " Residuals before correction ", fOriginal.GetSize()/3, 0, 0.3);
+    TH1F hres2("Res2", " Residuals after correction ",  fOriginal.GetSize()/3, 0, 0.3);
+    TH1F hres3("Res3", " Residuals after backward correction ",  fOriginal.GetSize()/3, 0, 0.3);
+
+    TProfile proaz ("ProAz",  " \\Delta profile vs. Az",  48, -180, 180);
+    TProfile prozd ("ProZd",  " \\Delta profile vs. Zd",  60,    0, 90);
+    TProfile promag("ProMag", " \\Delta profile vs. Mag", 40,    1,  4);
+
+    hres1.SetXTitle("\\Delta [\\circ]");
+    hres1.SetYTitle("Counts");
+
+    hres2.SetXTitle("\\Delta [\\circ]");
+    hres2.SetYTitle("Counts");
+
+    hres3.SetXTitle("\\Delta [\\circ]");
+    hres3.SetYTitle("Counts");
+
+    TGraph gdaz;
+    TGraph gdzd;
+    TGraph gaz;
+    TGraph gzd;
+    TGraphErrors graz;
+    TGraphErrors grzd;
+    TGraphErrors grmag;
+    TGraph gmaz;
+    TGraph gmzd;
+
+    gdaz.SetTitle(" \\Delta Az vs. Zd ");
+    gdzd.SetTitle(" \\Delta Zd vs. Az ");
+
+    gaz.SetTitle(" \\Delta Az vs. Az ");
+    gzd.SetTitle(" \\Delta Zd vs. Zd ");
+
+    gmaz.SetTitle(" \\Delta Az vs. Mag ");
+    gmzd.SetTitle(" \\Delta Zd vs. Mag ");
+
+    graz.SetTitle(" \\Delta vs. Az ");
+    grzd.SetTitle(" \\Delta vs. Zd ");
+    grmag.SetTitle(" \\Delta vs. Mag ");
+
+    TMinuit minuit(MPointing::GetNumPar());  //initialize TMinuit with a maximum of 5 params
+    minuit.SetObjectFit(this);
+    minuit.SetPrintLevel(-1);
+    minuit.SetFCN(fcn);
+
+    fBending.SetMinuitParameters(minuit, MPointing::GetNumPar()); // Init Parameters [deg]
+
+    for (int i=0; i<MPointing::GetNumPar(); i++)
+    {
+        TGButton *l = (TGButton*)fList->FindWidget(i);
+        minuit.FixParameter(i);
+        if (l->GetState()==kButtonDown)
+            minuit.Release(i);
+    }
+
+    //minuit.Command("SHOW PARAMETERS");
+    //minuit.Command("SHOW LIMITS");
+
+    gLog << inf << endl;
+    gLog << "Starting fit..." << endl;
+    gLog << "For the fit an measurement error in the residual of ";
+    gLog << "0.02deg (=1SE) is assumed." << endl;
+    gLog << endl;
+
+    Int_t ierflg = 0;
+    ierflg = minuit.Migrad();
+    gLog << inf << "Migrad returns " << ierflg << endl;
+    // minuit.Release(2);
+    ierflg = minuit.Migrad();
+    gLog << inf << "Migrad returns " << ierflg << endl << endl;
+
+    //
+    // Get Fit Results
+    //
+    fBending.GetMinuitParameters(minuit);
+    fBending.PrintMinuitParameters(minuit);
+    gLog << endl;
+    //fBending.Save("bending_magic.txt");
+
+
+    //
+    // Make a copy of all list entries
+    //
+    TList list;
+    list.SetOwner();
+    for (int i=0; i<fCoordinates.GetSize(); i++)
+        list.Add(new TPointStar(*(TPointStar*)fCoordinates.At(i)));
+
+    //
+    // Correct for Offsets only
+    //
+    TArrayD par;
+    fBending.GetParameters(par);
+    for (int i=2; i<MPointing::GetNumPar(); i++)
+        par[i]=0;
+
+    MPointing b2;
+    b2.SetParameters(par);
+
+    gLog << all << endl << "Sets with Residual exceeding " << fLimit << "deg:" << endl;
+    gLog << "   StarAz  StarEl      RawAz   RawEl      Mag Residual  Filename" << endl;
+
+    //
+    // Calculate correction and residuals
+    //
+    for (int i=0; i<fCoordinates.GetSize(); i++)
+    {
+        TPointStar orig = *(TPointStar*)fCoordinates.At(i);
+
+        TPointStar &set0 = *(TPointStar*)fCoordinates.At(i);
+
+        ZdAz za(set0.GetStarZdAz());
+        za *=kRad2Deg;
+
+        //
+        // Correct for offsets only
+        //
+        TPointStar set1(set0);
+        set1.Adjust(b2);
+
+        hres1.Fill(set1.GetResidual());
+
+        set0.Adjust(fBending);
+        hres2.Fill(set0.GetResidual());
+
+        Double_t dz = fmod(set0.GetDAz()+720, 360);
+        if (dz>180)
+            dz -= 360;
+
+        Double_t err;
+        Double_t resi = set0.GetResidual(&err);
+
+        gdzd.SetPoint(i, za.Az(), set0.GetDZd());
+        gdaz.SetPoint(i, za.Zd(), dz);
+        graz.SetPoint(i, za.Az(), resi);
+        graz.SetPointError(i, 0, err);
+        grzd.SetPoint(i, za.Zd(), resi);
+        grzd.SetPointError(i, 0, err);
+
+        if (resi>fLimit) // 0.13
+            gLog << all << " " << orig << "  <" << Form("%5.3f", resi) << ">  " << orig.GetName() << endl;
+
+        proaz.Fill(za.Az(), set0.GetResidual(&err));
+        prozd.Fill(za.Zd(), set0.GetResidual(&err));
+        promag.Fill(set0.GetMag(), set0.GetResidual(&err));
+
+        gaz.SetPoint( i, za.Az(), dz);
+        gzd.SetPoint( i, za.Zd(), set0.GetDZd());
+        if (set0.GetMag()>=-20)
+        {
+            grmag.SetPoint(i, set0.GetMag(), set0.GetResidual(&err));
+            grmag.SetPointError(i, 0, err);
+            gmaz.SetPoint( i, set0.GetMag(), dz);
+            gmzd.SetPoint( i, set0.GetMag(), set0.GetDZd());
+        }
+    }
+
+    gLog << "done." << endl << endl;
+
+    //
+    // Check for overflows
+    //
+    const Stat_t ov = hres2.GetBinContent(hres2.GetNbinsX()+1);
+    if (ov>0)
+        gLog << warn << "WARNING: " << ov << " overflows in residuals." << endl;
+
+
+
+    gLog << inf << dec << endl;
+    gLog << "              Number of calls to FCN: " << minuit.fNfcn << endl;
+    gLog << "Minimum value found for FCN (Chi^2?): " << minuit.fAmin << endl;
+    gLog << "                  Fit-Probability(?): " << TMath::Prob(minuit.fAmin/*fOriginal.GetSize()*/, fOriginal.GetSize()-minuit.GetNumFreePars())*100 << "%" << endl;
+    gLog << "                           Chi^2/NDF: " << minuit.fAmin/(fOriginal.GetSize()-minuit.GetNumFreePars()) << endl;
+    //cout << "Prob(?): " << TMath::Prob(fChisquare,ndf);
+
+
+
+    //
+    // Print all data sets for which the backward correction is
+    // twice times worse than the residual gotten from the
+    // bending correction itself
+    //
+    gLog << endl;
+    gLog << "Checking backward correction (raw-->star):" << endl;
+    for (int i=0; i<fCoordinates.GetSize(); i++)
+    {
+        TPointStar set0(*(TPointStar*)list.At(i));
+        TPointStar &set1 = *(TPointStar*)list.At(i);
+
+        set0.AdjustBack(fBending);
+        set1.Adjust(fBending);
+
+        const Double_t res0 = set0.GetResidual();
+        const Double_t res1 = set1.GetResidual();
+        const Double_t diff = TMath::Abs(res0-res1);
+
+        hres3.Fill(res0);
+
+        if (diff<hres2.GetMean()*0.66)
+            continue;
+
+        gLog << "DBack: " << setw(6) << set0.GetStarZd() << " " << setw(7) << set0.GetStarAz() << ":  ";
+        gLog << "ResB="<< setw(7) << res0*60 << "  ResF=" << setw(7) << res1*60 << "  |ResB-ResF|=" << setw(7) << diff*60 << " arcmin" << endl;
+    }
+    gLog << "OK." << endl;
+    gLog << endl;
+
+    const Double_t max1 = TMath::Max(gaz.GetHistogram()->GetMaximum(), gdaz.GetHistogram()->GetMaximum());
+    const Double_t max2 = TMath::Max(gzd.GetHistogram()->GetMaximum(), gdzd.GetHistogram()->GetMaximum());
+    const Double_t max3 = TMath::Max(grzd.GetHistogram()->GetMaximum(), graz.GetHistogram()->GetMaximum());
+
+    const Double_t min1 = TMath::Min(gaz.GetHistogram()->GetMinimum(), gdaz.GetHistogram()->GetMinimum());
+    const Double_t min2 = TMath::Min(gzd.GetHistogram()->GetMinimum(), gdzd.GetHistogram()->GetMinimum());
+    const Double_t min3 = TMath::Min(grzd.GetHistogram()->GetMinimum(), graz.GetHistogram()->GetMinimum());
+
+    const Double_t absmax1 = TMath::Max(max1, TMath::Abs(min1));
+    const Double_t absmax2 = TMath::Max(max2, TMath::Abs(min2));
+    const Double_t absmax3 = TMath::Max(max3, TMath::Abs(min3));
+
+    gaz.SetMaximum(absmax1);
+    gzd.SetMaximum(absmax2);
+    gdaz.SetMaximum(absmax1);
+    gdzd.SetMaximum(absmax2);
+    gmaz.SetMaximum(absmax1);
+    gmzd.SetMaximum(absmax2);
+    graz.SetMaximum(absmax3);
+    grzd.SetMaximum(absmax3);
+    grmag.SetMaximum(absmax3);
+    gaz.SetMinimum(-absmax1);
+    gzd.SetMinimum(-absmax2);
+    gdaz.SetMinimum(-absmax1);
+    gdzd.SetMinimum(-absmax2);
+    gmaz.SetMinimum(-absmax1);
+    gmzd.SetMinimum(-absmax2);
+    graz.SetMinimum(0);
+    grzd.SetMinimum(0);
+    grmag.SetMinimum(0);
+
+    TCanvas *c1;
+
+    if (gROOT->FindObject("CanvGraphs"))
+        c1 = dynamic_cast<TCanvas*>(gROOT->FindObject("CanvGraphs"));
+    else
+        c1=new TCanvas("CanvGraphs", "Graphs");
+
+    gROOT->SetSelectedPad(0);
+    c1->SetSelectedPad(0);
+    c1->SetBorderMode(0);
+    c1->SetFrameBorderMode(0);
+    c1->Clear();
+
+    c1->SetFillColor(kWhite);
+#ifndef PRESENTATION
+    c1->Divide(3,3,1e-10,1e-10);
+#else
+    c1->Divide(2,2,1e-10,1e-10);
+#endif
+    c1->SetFillColor(kWhite);
+
+    TGraph *g=0;
+
+    TLine line;
+    line.SetLineColor(kGreen);
+    line.SetLineWidth(2);
+#ifndef PRESENTATION
+    c1->cd(1);
+    gPad->SetBorderMode(0);
+    gPad->SetFrameBorderMode(0);
+    gPad->SetGridx();
+    gPad->SetGridy();
+    g=(TGraph*)gaz.DrawClone("A*");
+    g->SetBit(kCanDelete);
+    g->GetHistogram()->SetXTitle("Az [\\circ]");
+    g->GetHistogram()->SetYTitle("\\Delta Az [\\circ]");
+
+    line.DrawLine(g->GetXaxis()->GetXmin(),  360./16384, g->GetXaxis()->GetXmax(),  360./16384);
+    line.DrawLine(g->GetXaxis()->GetXmin(), -360./16384, g->GetXaxis()->GetXmax(), -360./16384);
+
+    c1->cd(2);
+    gPad->SetBorderMode(0);
+    gPad->SetFrameBorderMode(0);
+    gPad->SetGridx();
+    gPad->SetGridy();
+    g=(TGraph*)gdaz.DrawClone("A*");
+    g->SetBit(kCanDelete);
+    g->GetHistogram()->SetXTitle("Zd [\\circ]");
+    g->GetHistogram()->SetYTitle("\\Delta Az [\\circ]");
+    line.DrawLine(g->GetXaxis()->GetXmin(),  360./16384, g->GetXaxis()->GetXmax(),  360./16384);
+    line.DrawLine(g->GetXaxis()->GetXmin(), -360./16384, g->GetXaxis()->GetXmax(), -360./16384);
+    cout << "Mean dAz: " << g->GetMean(2) << " \xb1 " << g->GetRMS(2) <<  endl;
+
+    c1->cd(3);
+    gPad->SetBorderMode(0);
+    gPad->SetFrameBorderMode(0);
+    gPad->SetGridx();
+    gPad->SetGridy();
+    if (gmaz.GetN()>0)
+    {
+        g=(TGraph*)gmaz.DrawClone("A*");
+        g->SetBit(kCanDelete);
+        g->GetHistogram()->SetXTitle("Mag");
+        g->GetHistogram()->SetYTitle("\\Delta Az [\\circ]");
+        line.DrawLine(g->GetXaxis()->GetXmin(),  360./16384, g->GetXaxis()->GetXmax(),  360./16384);
+        line.DrawLine(g->GetXaxis()->GetXmin(), -360./16384, g->GetXaxis()->GetXmax(), -360./16384);
+    }
+#endif
+
+#ifndef PRESENTATION
+    c1->cd(4);
+#else
+    c1->cd(1);
+#endif
+    gPad->SetBorderMode(0);
+    gPad->SetFrameBorderMode(0);
+    gPad->SetGridx();
+    gPad->SetGridy();
+    g=(TGraph*)gdzd.DrawClone("A*");
+    g->SetBit(kCanDelete);
+    g->GetHistogram()->SetXTitle("Az [\\circ]");
+    g->GetHistogram()->SetYTitle("\\Delta Zd [\\circ]");
+    line.DrawLine(g->GetXaxis()->GetXmin(),  360./16384, g->GetXaxis()->GetXmax(),  360./16384);
+    line.DrawLine(g->GetXaxis()->GetXmin(), -360./16384, g->GetXaxis()->GetXmax(), -360./16384);
+    cout << "Mean dZd: " << g->GetMean(2) << " \xb1 " << g->GetRMS(2) <<  endl;
+    cout << endl;
+
+#ifndef PRESENTATION
+    c1->cd(5);
+#else
+    c1->cd(2);
+#endif
+    gPad->SetBorderMode(0);
+    gPad->SetFrameBorderMode(0);
+    gPad->SetGridx();
+    gPad->SetGridy();
+    g=(TGraph*)gzd.DrawClone("A*");
+    g->SetBit(kCanDelete);
+    g->GetHistogram()->SetXTitle("Zd [\\circ]");
+    g->GetHistogram()->SetYTitle("\\Delta Zd [\\circ]");
+    line.DrawLine(g->GetXaxis()->GetXmin(),  360./16384, g->GetXaxis()->GetXmax(),  360./16384);
+    line.DrawLine(g->GetXaxis()->GetXmin(), -360./16384, g->GetXaxis()->GetXmax(), -360./16384);
+#ifndef PRESENTATION
+    c1->cd(6);
+    gPad->SetBorderMode(0);
+    gPad->SetFrameBorderMode(0);
+    gPad->SetGridx();
+    gPad->SetGridy();
+    if (gmzd.GetN()>0)
+    {
+        g=(TGraph*)gmzd.DrawClone("A*");
+        g->SetBit(kCanDelete);
+        g->GetHistogram()->SetXTitle("Mag");
+        g->GetHistogram()->SetYTitle("\\Delta Zd [\\circ]");
+        line.DrawLine(g->GetXaxis()->GetXmin(),  360./16384, g->GetXaxis()->GetXmax(),  360./16384);
+        line.DrawLine(g->GetXaxis()->GetXmin(), -360./16384, g->GetXaxis()->GetXmax(), -360./16384);
+    }
+#endif
+
+#ifndef PRESENTATION
+    c1->cd(7);
+#else
+    c1->cd(3);
+#endif
+    gPad->SetBorderMode(0);
+    gPad->SetFrameBorderMode(0);
+    gPad->SetGridx();
+    gPad->SetGridy();
+    g=(TGraph*)graz.DrawClone("AP");
+    g->SetBit(kCanDelete);
+    g->GetHistogram()->SetXTitle("Az [\\circ]");
+    g->GetHistogram()->SetYTitle("\\Delta [\\circ]");
+    line.DrawLine(g->GetXaxis()->GetXmin(),  360./16384, g->GetXaxis()->GetXmax(),  360./16384);
+
+    proaz.SetLineWidth(2);
+    proaz.SetLineColor(kBlue);
+    proaz.SetMarkerColor(kBlue);
+    proaz.DrawCopy("pc hist same");
+
+#ifndef PRESENTATION
+    c1->cd(8);
+#else
+    c1->cd(4);
+#endif
+    gPad->SetBorderMode(0);
+    gPad->SetFrameBorderMode(0);
+    gPad->SetGridx();
+    gPad->SetGridy();
+    g=(TGraph*)grzd.DrawClone("AP");
+    g->SetBit(kCanDelete);
+    g->GetHistogram()->SetXTitle("Zd [\\circ]");
+    g->GetHistogram()->SetYTitle("\\Delta [\\circ]");
+    line.DrawLine(g->GetXaxis()->GetXmin(),  360./16384, g->GetXaxis()->GetXmax(),  360./16384);
+
+    prozd.SetLineWidth(2);
+    prozd.SetLineColor(kBlue);
+    prozd.SetMarkerColor(kBlue);
+    prozd.DrawCopy("pc hist same");
+
+#ifndef PRESENTATION
+    c1->cd(9);
+    gPad->SetBorderMode(0);
+    gPad->SetFrameBorderMode(0);
+    gPad->SetGridx();
+    gPad->SetGridy();
+    if (grmag.GetN()>0)
+    {
+        g=(TGraph*)grmag.DrawClone("AP");
+        g->SetBit(kCanDelete);
+        g->GetHistogram()->SetXTitle("Mag");
+        g->GetHistogram()->SetYTitle("\\Delta [\\circ]");
+        line.DrawLine(g->GetXaxis()->GetXmin(),  360./16384, g->GetXaxis()->GetXmax(),  360./16384);
+    }
+    promag.SetLineWidth(2);
+    promag.SetLineColor(kBlue);
+    promag.SetMarkerColor(kBlue);
+    promag.DrawCopy("pc hist same");
+#endif
+
+    //
+    // Print out the residual before and after correction in several
+    // units
+    //
+    cout << fCoordinates.GetSize() << " data sets." << endl << endl;
+    cout << "Total Spread of Residual:" << endl;
+    cout << "-------------------------" << endl;
+    cout << "before: " << Form("%6.4f", hres1.GetMean()) << " \xb1 " << Form("%6.4f", hres1.GetRMS()) << " deg \t";
+    cout << "before: " << Form("%4.1f", hres1.GetMean()*60) << " \xb1 " << Form("%.1f", hres1.GetRMS()*60) << " arcmin" << endl;
+    cout << "after:  " << Form("%6.4f", hres2.GetMean()) << " \xb1 " << Form("%6.4f", hres2.GetRMS()) << " deg \t";
+    cout << "after:  " << Form("%4.1f", hres2.GetMean()*60) << " \xb1 " << Form("%.1f", hres2.GetRMS()*60) << " arcmin" << endl;
+    cout << "backw:  " << Form("%6.4f", hres3.GetMean()) << " \xb1 " << Form("%6.4f", hres3.GetRMS()) << " deg \t";
+    cout << "backw:  " << Form("%4.1f", hres3.GetMean()*60) << " \xb1 " << Form("%.1f", hres3.GetRMS()*60) << " arcmin" << endl;
+    cout << endl;
+    cout << "before: " << Form("%4.1f", hres1.GetMean()*16348/360) << " \xb1 " << Form("%.1f", hres1.GetRMS()*16384/360) << " SE \t\t";
+    cout << "before: " << Form("%4.1f", hres1.GetMean()*60*60/23.4) << " \xb1 " << Form("%.1f", hres1.GetRMS()*60*60/23.4) << " pix" << endl;
+    cout << "after:  " << Form("%4.1f", hres2.GetMean()*16384/360) << " \xb1 " << Form("%.1f", hres2.GetRMS()*16384/360) << " SE \t\t";
+    cout << "after:  " << Form("%4.1f", hres2.GetMean()*60*60/23.4) << " \xb1 " << Form("%.1f", hres2.GetRMS()*60*60/23.4) << " pix" << endl;
+    cout << "backw:  " << Form("%4.1f", hres3.GetMean()*16384/360) << " \xb1 " << Form("%.1f", hres3.GetRMS()*16384/360) << " SE \t\t";
+    cout << "backw:  " << Form("%4.1f", hres3.GetMean()*60*60/23.4) << " \xb1 " << Form("%.1f", hres3.GetRMS()*60*60/23.4) << " pix" << endl;
+    cout << endl;
+    cout << endl; // ±
+
+
+    before = hres1.GetMean()*16384/360;
+    after  = hres2.GetMean()*16384/360;
+    backw  = hres3.GetMean()*16384/360;
+
+
+    gStyle->SetOptStat(1110);
+    gStyle->SetStatFormat("6.2g");
+
+    if (gROOT->FindObject("CanvResiduals"))
+        c1 = dynamic_cast<TCanvas*>(gROOT->FindObject("CanvResiduals"));
+    else
+        c1=new TCanvas("CanvResiduals", "Residuals", 800, 800);
+
+    gROOT->SetSelectedPad(0);
+    c1->SetSelectedPad(0);
+    c1->Clear();
+    c1->SetFillColor(kWhite);
+
+    c1->Divide(2, 2, 1e-10, 1e-10);
+
+    c1->cd(2);
+    gPad->SetBorderMode(0);
+    gPad->SetFrameBorderMode(0);
+    hres1.SetLineColor(kRed);
+    hres1.DrawCopy();
+
+    gPad->Update();
+
+    line.DrawLine(360./16384, gPad->GetUymin(), 360./16384, gPad->GetUymax());
+
+    c1->cd(4);
+    gPad->SetBorderMode(0);
+    gPad->SetFrameBorderMode(0);
+    hres2.SetLineColor(kBlue);
+    TH1 *h=hres2.DrawCopy();
+    TF1 f("mygaus", "(gaus)", 0, 1);
+    f.SetLineColor(kMagenta/*6*/);
+    f.SetLineWidth(1);
+    f.SetParameter(0, h->GetBinContent(1));
+    f.FixParameter(1, 0);
+    f.SetParameter(2, h->GetRMS());
+    h->Fit("mygaus", "QR");
+    hres3.SetLineColor(kCyan);
+    hres3.SetLineStyle(kDashed);
+    hres3.DrawCopy("same");
+    cout << "Gaus-Fit  Sigma: " << f.GetParameter(2) << "\xb0" << endl;
+    cout << "Fit-Probability: " << f.GetProb()*100 << "%" << endl;
+    cout << "      Chi^2/NDF: " << f.GetChisquare() << "/" << f.GetNDF() << " = " << f.GetChisquare()/f.GetNDF() << endl;
+    gPad->Update();
+    line.DrawLine(360./16384, gPad->GetUymin(), 360./16384, gPad->GetUymax());
+
+    c1->cd(1);
+    gPad->SetBorderMode(0);
+    gPad->SetFrameBorderMode(0);
+    gPad->SetTheta(90);
+    gPad->SetPhi(90);
+    TH2F h2res1("Res2D1", " Dataset positions on the sky ", 36, 0, 360,  8, 0, 90);
+    h2res1.SetBit(TH1::kNoStats);
+    h2res1.DrawCopy("surf1pol");
+    gPad->Modified();
+    gPad->Update();
+    DrawHorizon(gPad);
+    for (int i=0; i<fOriginal.GetSize(); i++)
+        DrawSet(gPad, *(TPointStar*)fOriginal.At(i));//, 10./hres1.GetMean());
+
+    TText text;
+    text.SetTextAlign(22);
+    text.DrawText( 0.00,  0.66, "N");
+    text.DrawText( 0.66,  0.00, "E");
+    text.DrawText( 0.00, -0.66, "S");
+    text.DrawText(-0.66,  0.00, "W");
+
+    c1->cd(3);
+    gPad->SetBorderMode(0);
+    gPad->SetFrameBorderMode(0);
+    gPad->SetTheta(90);
+    gPad->SetPhi(90);
+    h2res1.SetTitle(" Arb. Residuals after correction (scaled) ");
+    h2res1.DrawCopy("surf1pol");
+    gPad->Modified();
+    gPad->Update();
+//        for (int i=0; i<fCoordinates.GetSize(); i++)
+//            DrawSet(gPad, *(Set*)fCoordinates.At(i), 10./hres2.GetMean(), par[0]);
+
+    RaiseWindow();
+}
+
Index: /trunk/FACT++/drive/TPointGui.h
===================================================================
--- /trunk/FACT++/drive/TPointGui.h	(revision 18618)
+++ /trunk/FACT++/drive/TPointGui.h	(revision 18618)
@@ -0,0 +1,98 @@
+#ifndef COSY_TPointGui
+#define COSY_TPointGui
+
+#ifndef ROOT_TGFrame
+#include <TGFrame.h>
+#endif
+
+#ifndef ROOT_TGFileDialog
+#include <TGFileDialog.h>
+#endif
+
+#include "MPointing.h"
+
+class MGList; // To be removed!!!
+class TPointStar;
+
+class TGLabel;
+
+class TPointGui : public TGMainFrame
+{
+private:
+    enum {
+        kTbFit = 1024,
+        kTbLoad,
+        kTbSave,
+        kTbLoadStars,
+        kTbReset,
+        kTbResetStars,
+        kTbReloadStars,
+
+        kIdAzMin,
+        kIdAzMax,
+        kIdZdMin,
+        kIdZdMax,
+        kIdMagMin,
+        kIdLimit,
+    };
+
+    MGList *fList;
+
+    TList fOriginal;
+    TList fCoordinates;
+    TList fLabel;
+
+    MPointing fBending;
+
+    TString fFileNameStars;
+
+    FontStruct_t fFont;
+
+    Bool_t fExitLoopOnClose;
+
+    Float_t fAzMin;
+    Float_t fAzMax;
+    Float_t fZdMin;
+    Float_t fZdMax;
+    Float_t fMagMin;
+
+    Float_t fLimit;
+
+    void Fcn(Int_t &/*npar*/, Double_t */*gin*/, Double_t &f, Double_t *par, Int_t /*iflag*/);
+    static void fcn(Int_t &npar, Double_t *gin, Double_t &f, Double_t *par, Int_t iflag);
+
+    void AddTextButton(TGCompositeFrame *f, TString txt, Int_t id=-1, TGLayoutHints *h=0);
+    void AddCheckButton(TGCompositeFrame *f, TString txt, Int_t id=-1, TGLayoutHints *h=0);
+    void AddResetButton(TGCompositeFrame *f, Int_t id, TGLayoutHints *h, Int_t height);
+    TGLabel *AddLabel(TGCompositeFrame *f, TString txt, TGLayoutHints *h=0);
+
+    void DisplayBending();
+    void DisplayData();
+    void DisplayResult(Double_t before, Double_t after, Double_t backw);
+
+    void DrawMarker(TVirtualPad *pad, Double_t r0, Double_t phi0);
+    void DrawPolLine(TVirtualPad *pad, Double_t r0, Double_t phi0, Double_t r1, Double_t phi1);
+    void DrawSet(TVirtualPad *pad, TPointStar &set, Float_t scale=-1, Float_t angle=0);
+    void DrawHorizon(TVirtualPad *pad, const char *fname="horizon.dat") const;
+
+    TString OpenDialog(TString &dir, EFileDialogMode mode=kFDOpen);
+
+    void LoadCollection(TString fname);
+    void LoadStars(TString fname="tpoint.txt");
+
+    Bool_t ProcessMessage(Long_t msg, Long_t mp1, Long_t);
+
+    void Fit(Double_t &before, Double_t &after, Double_t &backw);
+
+    Float_t GetFloat(Int_t id) const;
+
+public:
+    TPointGui(const char *fname=NULL, const char *mod=NULL);
+    ~TPointGui();
+
+    void SetExitLoopOnClose(Bool_t b=kTRUE) { fExitLoopOnClose=b; }
+
+    ClassDef(TPointGui, 0)
+};
+
+#endif
Index: /trunk/FACT++/drive/TPointStar.cc
===================================================================
--- /trunk/FACT++/drive/TPointStar.cc	(revision 18618)
+++ /trunk/FACT++/drive/TPointStar.cc	(revision 18618)
@@ -0,0 +1,141 @@
+#include "TPointStar.h"
+
+#include <TMath.h>
+
+#include "MLog.h"
+#include "MLogManip.h"
+
+#include "MPointing.h"
+
+ClassImp(TPointStar);
+
+using namespace std;
+
+void TPointStar::Init(const char *name, const char *title)
+{
+    fName  = name  ? name  : "TPointStar";
+    fTitle = title ? title : "A set of TPoints";
+}
+
+TPointStar::TPointStar(Double_t sel, Double_t saz, Double_t rel, Double_t raz) :
+    fStarAz(saz*TMath::DegToRad()),
+    fStarEl(sel*TMath::DegToRad()),
+    fRawAz(raz*TMath::DegToRad()),
+    fRawEl(rel*TMath::DegToRad()), fMag(-25)
+{
+    Init();
+}
+
+Double_t TPointStar::GetDEl() const     { return (fRawEl-fStarEl)*TMath::RadToDeg(); }
+Double_t TPointStar::GetDZd() const     { return -GetDEl(); }
+Double_t TPointStar::GetDAz() const     { return (fRawAz-fStarAz)*TMath::RadToDeg(); }
+Double_t TPointStar::GetStarEl() const  { return fStarEl*TMath::RadToDeg(); }
+Double_t TPointStar::GetStarZd() const  { return 90.-fStarEl*TMath::RadToDeg(); }
+Double_t TPointStar::GetStarAz() const  { return fStarAz*TMath::RadToDeg(); }
+Double_t TPointStar::GetRawEl() const   { return fRawEl*TMath::RadToDeg(); }
+Double_t TPointStar::GetRawAz() const   { return fRawAz*TMath::RadToDeg(); }
+Double_t TPointStar::GetRawZd() const   { return 90.-fRawEl*TMath::RadToDeg(); }
+
+ZdAz  TPointStar::GetStarZdAz() const   { return ZdAz(TMath::Pi()/2-fStarEl, fStarAz); }
+AltAz TPointStar::GetStarAltAz() const  { return AltAz(fStarEl, fStarAz); }
+
+ZdAz  TPointStar::GetRawZdAz() const    { return ZdAz(TMath::Pi()/2-fRawEl, fRawAz); }
+AltAz TPointStar::GetRawAltAz() const   { return AltAz(fRawEl, fRawAz); }
+
+void TPointStar::AdjustEl(Double_t del) { fStarEl += del*TMath::DegToRad(); }
+void TPointStar::AdjustAz(Double_t daz) { fStarAz += daz*TMath::DegToRad(); }
+
+void TPointStar::Adjust(const MPointing &bend)
+{
+    AltAz p = bend(GetStarAltAz());
+    fStarEl = p.Alt();
+    fStarAz = p.Az();
+}
+
+void TPointStar::AdjustBack(const MPointing &bend)
+{
+    AltAz p = bend.CorrectBack(GetRawAltAz());
+    fRawEl = p.Alt();
+    fRawAz = p.Az();
+}
+
+Double_t TPointStar::GetResidual(Double_t *err) const
+{
+    const Double_t del = fRawEl-fStarEl;
+    const Double_t daz = fRawAz-fStarAz;
+
+    const double x = cos(fRawEl) * cos(fStarEl) * cos(fStarAz-fRawAz);
+    const double y = sin(fRawEl) * sin(fStarEl);
+
+    const Double_t d = x + y;
+
+    if (err)
+    {
+        // Error of one pixel in the CCD
+        const Double_t e1 = 32./3600*TMath::DegToRad()   * 0.5;
+
+        // Error of one SE unit
+        const Double_t e2 = 360./16384*TMath::DegToRad() * 0.5;
+
+        const Double_t e11 =  sin(del)+cos(fRawEl)*sin(fStarEl)*(1-cos(daz));
+        const Double_t e12 =  cos(fRawEl)*cos(fStarEl)*sin(daz);
+
+        const Double_t e21 = -sin(del)+sin(fRawEl)*cos(fStarEl)*(1-cos(daz));
+        const Double_t e22 = -cos(fRawEl)*cos(fStarEl)*sin(daz);
+
+        const Double_t err1  = sqrt(1-d*d);
+        const Double_t err2  = (e11*e11 + e12*e12)*e1*e1;
+        const Double_t err3  = (e21*e21 + e22*e22)*e2*e2;
+
+        *err = sqrt(err2+err3)/err1 * TMath::RadToDeg();
+    }
+
+    const Double_t dist = acos(d);
+    return dist * TMath::RadToDeg();
+}
+
+istream &operator>>(istream &fin, TPointStar &set)
+{
+    TString str;
+    do
+    {
+        str.ReadLine(fin);
+        if (!fin)
+            return fin;
+    } while (str[0]=='#');
+
+    Float_t v[4], mag;
+    Int_t n = sscanf(str.Data(), "%f %f %f %f %*f %*f %*f %*f %*f %*f %f", v, v+1, v+2, v+3, &mag);
+    if (n<4)
+    {
+        gLog << err << "Read: ERROR - Not enough numbers" << endl;
+        return fin;
+    }
+    set.fMag = n<5 ? -25 : mag;
+
+    set.fStarAz = v[0]*TMath::DegToRad();
+    set.fStarEl = v[1]*TMath::DegToRad();
+
+    set.fRawAz  = v[2]*TMath::DegToRad();
+    set.fRawEl  = v[3]*TMath::DegToRad();
+
+    if (fin)
+    {
+        Double_t res, err;
+        res = set.GetResidual(&err);
+        gLog << inf << "Read: " << v[0] << " " << v[1] << "  :  " << v[2] << " " << v[3] << "  :  " << v[2]-v[0] << " " << v[3]-v[1] << "  :  " << res << " " << err << " " << err/res << endl;
+    }
+
+    return fin;
+}
+
+ostream &operator<<(ostream &out, TPointStar &set)
+{
+    out << Form("%8.3f", set.fStarAz*TMath::RadToDeg()) << " ";
+    out << Form("%7.3f", set.fStarEl*TMath::RadToDeg()) << "   ";
+    out << Form("%8.3f", set.fRawAz*TMath::RadToDeg()) << " ";
+    out << Form("%7.3f", set.fRawEl*TMath::RadToDeg()) << "   ";
+    out << Form("%6.3f", set.fMag);
+
+    return out;
+}
Index: /trunk/FACT++/drive/TPointStar.h
===================================================================
--- /trunk/FACT++/drive/TPointStar.h	(revision 18618)
+++ /trunk/FACT++/drive/TPointStar.h	(revision 18618)
@@ -0,0 +1,95 @@
+#ifndef COSY_TPointStar
+#define COSY_TPointStar
+
+#ifndef ROOT_TNamed
+#include <TNamed.h>
+#endif
+
+//class istream;
+//class ostream;
+
+class ZdAz;
+class AltAz;
+
+class MPointing;
+
+class TPointStar : public TNamed
+{
+    friend std::istream &operator>>(std::istream &fin,  TPointStar &set);
+    friend std::ostream &operator<<(std::ostream &fout, TPointStar &set);
+private:
+    Double_t fStarAz;
+    Double_t fStarEl;
+
+    Double_t fRawAz;
+    Double_t fRawEl;
+
+    Double_t fMag;
+
+    void Init(const char *name=0, const char *title=0);
+public:
+    TPointStar(const char *name, const char *title=0) { Init(name, title); }
+    TPointStar(Double_t sel=0, Double_t saz=0, Double_t rel=0, Double_t raz=0);
+    TPointStar(const TPointStar &set) : TNamed(set)
+    {
+        fStarAz = set.fStarAz;
+        fStarEl = set.fStarEl;
+        fRawAz  = set.fRawAz;
+        fRawEl  = set.fRawEl;
+        fMag    = set.fMag;
+    }
+
+    Double_t GetMag() const { return fMag; }
+    Double_t GetResidual(Double_t *err=0) const;
+    //Double_t GetResidual() const;
+
+    Double_t GetDEl() const;//     { return (fRawEl-fStarEl)*TMath::RadToDeg(); }
+    Double_t GetDZd() const;//     { return -GetDEl(); }
+    Double_t GetDAz() const;//     { return (fRawAz-fStarAz)*TMath::RadToDeg(); }
+    Double_t GetStarEl() const;//  { return fStarEl*TMath::RadToDeg(); }
+    Double_t GetStarZd() const;//  { return 90.-fStarEl*TMath::RadToDeg(); }
+    Double_t GetStarAz() const;//  { return fStarAz*TMath::RadToDeg(); }
+    Double_t GetRawEl() const;//   { return fRawEl*TMath::RadToDeg(); }
+    Double_t GetRawAz() const;//   { return fRawAz*TMath::RadToDeg(); }
+    Double_t GetRawZd() const;//   { return 90.-fRawEl*TMath::RadToDeg(); }
+
+    ZdAz  GetStarZdAz() const;//   { return ZdAz(TMath::Pi()/2-fStarEl, fStarAz); }
+    AltAz GetStarAltAz() const;//  { return AltAz(fStarEl, fStarAz); }
+
+    ZdAz  GetRawZdAz() const;//    { return ZdAz(TMath::Pi()/2-fRawEl, fRawAz); }
+    AltAz GetRawAltAz() const;//   { return AltAz(fRawEl, fRawAz); }
+
+    void AdjustEl(Double_t del);// { fStarEl += del*TMath::DegToRad(); }
+    void AdjustAz(Double_t daz);// { fStarAz += daz*TMath::DegToRad(); }
+
+    void Adjust(const MPointing &bend);/*
+    {
+        AltAz p = bend(GetStarAltAz());
+        fStarEl = p.Alt();
+        fStarAz = p.Az();
+    }*/
+    void AdjustBack(const MPointing &bend);/*
+    {
+        AltAz p = bend.CorrectBack(GetRawAltAz());
+        fRawEl = p.Alt();
+        fRawAz = p.Az();
+    }*/
+    ClassDef(TPointStar, 1)
+};
+
+/*
+class TPoint : public TPointStar
+{
+public:
+    TPoint(Double_t sel=0, Double_t saz=0, Double_t rel=0, Double_t raz=0)
+        : TPointStar(sel, saz, rel, raz)
+    {
+    }
+    ClassDef(TPoint, 1)
+};
+*/
+
+std::istream &operator>>(std::istream &fin, TPointStar &set);
+std::ostream &operator<<(std::ostream &out, TPointStar &set);
+
+#endif
Index: /trunk/FACT++/drive/Writer.cc
===================================================================
--- /trunk/FACT++/drive/Writer.cc	(revision 18618)
+++ /trunk/FACT++/drive/Writer.cc	(revision 18618)
@@ -0,0 +1,181 @@
+#include "Writer.h"
+
+#include <iostream> // cout
+#include <fstream>  // ofstream
+
+#include <TVector2.h>
+
+#include <stdio.h>    // FILE
+#include <png.h>
+
+#include "MTime.h"
+
+ClassImp(Writer);
+
+using namespace std;
+
+void Writer::Png(const char *fname, const byte *buf,
+                 struct timeval *date, const TVector2 xy)
+{
+    MTime t(*date);
+    TString mjd;
+    mjd += t.GetMjd()-52000;
+    mjd = mjd.Strip(TString::kBoth);
+    if (mjd.Length()<10)
+        mjd.Append('0', 10-mjd.Length());
+
+    TString pos;
+    pos += xy.X();
+    pos = pos.Strip(TString::kBoth);
+    pos +="_";
+    TString posy;
+    posy += xy.Y();
+    posy = posy.Strip(TString::kBoth);
+    pos +=posy;
+
+    TString name = fname;
+    name += "_";
+    name += mjd;
+    name += "_";
+    name += pos;
+    name += ".png";
+
+    cout << "Writing PNG '" << name << "'" << endl;
+
+    //
+    // open file
+    //
+    FILE *fd = fopen(name, "w");
+    if (!fd)
+    {
+        cout << "Warning: Cannot open file for writing." << endl;
+        return;
+    }
+
+    //
+    // allocate memory
+    //
+    png_structp fPng = png_create_write_struct(PNG_LIBPNG_VER_STRING,
+                                               NULL, NULL, NULL);
+
+    if (!fPng)
+    {
+        cout << "Warning: Unable to create PNG structure" << endl;
+        fclose(fd);
+        return;
+    }
+
+
+    png_infop fInfo = png_create_info_struct(fPng);
+
+    if (!fInfo)
+    {
+        cout << "Warning: Unable to create PNG info structure" << endl;
+        png_destroy_write_struct (&fPng, NULL);
+        fclose(fd);
+        return;
+    }
+
+    fInfo->width      = 768;
+    fInfo->height     = 576;
+    fInfo->bit_depth  = 8;
+    fInfo->color_type = PNG_COLOR_TYPE_GRAY;
+
+    //
+    // set jump-back point in case of errors
+    //
+    if (setjmp(fPng->jmpbuf))
+    {
+        cout << "longjmp Warning: PNG encounterd an error!" << endl;
+        png_destroy_write_struct (&fPng, &fInfo);
+        fclose(fd);
+        return;
+    }
+
+    //
+    // connect file to PNG-Structure
+    //
+    png_init_io(fPng, fd);
+
+    // png_set_compression_level (fPng, Z_BEST_COMPRESSION);
+
+    //
+    // Write header
+    //
+    png_write_info (fPng, fInfo);
+
+    //
+    // Write Time Chunks
+    //
+    /*
+    if (date)
+    {
+        char text[36];
+
+        Timer timet(date);
+        sprintf(text, "*** %s ***", timet.GetTimeStr());
+        png_write_chunk(fPng, (png_byte*)"UTC", (png_byte*)text, strlen(text));
+        sprintf(text,"*** %s %s %.1f %i ***", tzname[0], tzname[1], 1.0/3600*timezone, daylight);
+        png_write_chunk(fPng, (png_byte*)"ZONE", (png_byte*)text, strlen(text));
+        }
+        */
+
+    //
+    // Write bitmap data
+    //
+    for (unsigned int y=0; y<768*576; y+=768)
+	png_write_row (fPng, (png_byte*)buf+y);
+
+    //
+    // Write footer
+    //
+    png_write_end (fPng, fInfo);
+
+    //
+    // free memory
+    //
+    png_destroy_write_struct (&fPng, &fInfo);
+
+    fclose(fd);
+}
+
+void Writer::Ppm(const char *fname, const byte *img, struct timeval *date, const TVector2 xy)
+{
+    TString name = fname;
+
+    MTime t(*date);
+
+    TString pos;
+    pos += xy.X();
+    pos = pos.Strip(TString::kBoth);
+    pos +="_";
+    TString posy;
+    posy += xy.Y();
+    posy = posy.Strip(TString::kBoth);
+    pos +=posy;
+
+    name += "_";
+    name += t.GetMjd()-52000;
+    name += "_";
+    name += pos;  
+    name += ".ppm";
+
+    cout << "Writing PPM '" << name << "'" << endl;
+
+    //
+    // open file for writing
+    //
+    ofstream fout(name);
+    if (!fout)
+    {
+        cout << "Warning: Cannot open file for writing." << endl;
+        return;
+    }
+
+    //
+    // write buffer to file
+    //
+    fout << "P6\n768 576\n255\n";
+    for (byte const *buf = img; buf < img+768*576; buf++)
+        fout << *buf << *buf << *buf;
+}
Index: /trunk/FACT++/drive/Writer.h
===================================================================
--- /trunk/FACT++/drive/Writer.h	(revision 18618)
+++ /trunk/FACT++/drive/Writer.h	(revision 18618)
@@ -0,0 +1,28 @@
+#ifndef WRITER_H
+#define WRITER_H
+
+#ifdef __CINT__
+struct timeval;
+#else
+#include <TROOT.h>
+#include <sys/time.h>
+#endif
+
+class TVector2;
+
+typedef unsigned char byte;
+
+class Writer;
+
+class Writer 
+{
+public:
+    virtual ~Writer() { }
+
+    static void Ppm(const char *fname, const byte *img, struct timeval *date, const TVector2 xy);
+    static void Png(const char *fname, const byte *buf, struct timeval *date, const TVector2 xy);
+
+    ClassDef(Writer, 0)
+};
+
+#endif
Index: /trunk/FACT++/drive/telesto.cc
===================================================================
--- /trunk/FACT++/drive/telesto.cc	(revision 18618)
+++ /trunk/FACT++/drive/telesto.cc	(revision 18618)
@@ -0,0 +1,160 @@
+#include <TROOT.h>
+#include <TClass.h>
+#include <TSystem.h>
+#include <TGClient.h>
+#include <TApplication.h>
+#include <TObjectTable.h>
+
+#include "MAGIC.h"
+
+#include "MLog.h"
+#include "MLogManip.h"
+
+//#include "MEnv.h"
+#include "MArgs.h"
+#include "MArray.h"
+#include "MParContainer.h"
+//#include "MDirIter.h"
+
+#include "TPointGui.h"
+//#include "MStatusDisplay.h"
+
+//#include "MSequence.h"
+//#include "MJStar.h"
+
+using namespace std;
+
+static void StartUpMessage()
+{
+    gLog << all << endl;
+
+    //                1         2         3         4         5         6
+    //       123456789012345678901234567890123456789012345678901234567890
+    gLog << "========================================================" << endl;
+    gLog << "                       Telesto - COSY"                    << endl;
+    gLog << "           Telesto - Telescope TPoint organizer"          << endl;
+    gLog << "       Compiled with ROOT v" << ROOT_RELEASE << " on <" << __DATE__ << ">" << endl;
+    gLog << "========================================================" << endl;
+    gLog << endl;
+}
+
+static void Usage()
+{
+    //                1         2         3         4         5         6         7         8
+    //       12345678901234567890123456789012345678901234567890123456789012345678901234567890
+    gLog << all << endl;
+    gLog << "Sorry the usage is:" << endl;
+    gLog << " telestop [file.txt|file.col [pointing.mod]]" << endl << endl;
+    gLog << " Arguments:" << endl;
+    gLog << "   file.txt|file.col         A collection of files or a file with tpoints" << endl;
+    gLog << "   pointing.mod              A pointing model to load at startup" << endl << endl;
+    gLog << " Root Options:" << endl;
+    gLog << "   -b                        Batch mode (no graphical output to screen)" << endl<<endl;
+    gLog << " Options:" << endl;
+    gLog.Usage();
+//    gLog << "   --debug-env=0             Disable debugging setting resources <default>" << endl;
+//    gLog << "   --debug-env[=1]           Display untouched resources after program execution" << endl;
+//    gLog << "   --debug-env=2             Display untouched resources after eventloop setup" << endl;
+//    gLog << "   --debug-env=3             Debug setting resources from resource file and command line" << endl;
+    gLog << "   --debug-mem               Debug memory usage" << endl << endl;
+//    gLog << "   --rc=Name:option          Set or overwrite a resource of the resource file." << endl;
+    gLog << "                             (Note, that this option can be used multiple times." << endl;
+    gLog << endl;
+    gLog << " Output options:" << endl;
+//    gLog << "   -q                        Quit when job is finished" << endl;
+//    gLog << "   -f                        Force overwrite of existing files" << endl;
+    gLog << endl;
+    gLog << "   --version, -V             Show startup message with version number" << endl;
+    gLog << "   -?, -h, --help            This help" << endl << endl;
+    gLog << "Background:" << endl;
+    gLog << " Telesto is a moon of Saturn.  It was discovered by  Smith,  Reitsema," << endl;
+    gLog << " Larson and Fountain in 1980 from ground-based observations,  and  was" << endl;
+    gLog << " provisionally designated S/1980 S 13." << endl;
+    gLog << " In 1983 it was officially named after Telesto  of Greek mythology. It" << endl;
+    gLog << " is also designated as Saturn XIII or Tethys B." << endl;
+    gLog << " Telesto  is  co-orbital  with  Tethys,  residing  in  Tethys' leading" << endl;
+    gLog << " Lagrangian  point  (L4).  This relationship  was  first identified by" << endl;
+    gLog << " Seidelmann et al.   The  moon  Calypso  also  resides  in  the  other" << endl;
+    gLog << " (trailing) lagrangian point of Tethys, 60 deg in the other direction." << endl;
+    gLog << " The  Cassini probe  performed a distant flyby  of Telesto on Oct. 11," << endl;
+    gLog << " 2005.  The resulting  images show  that  its surface  is surprisingly" << endl;
+    gLog << " smooth, devoid of small impact craters." << endl << endl;
+}
+
+int main(int argc, char **argv)
+{
+    if (!MARS::CheckRootVer())
+        return 0xff;
+
+    MLog::RedirectErrorHandler(MLog::kColor);
+
+    //
+    // Evaluate arguments
+    //
+    MArgs arg(argc, argv);
+    gLog.Setup(arg);
+
+    StartUpMessage();
+
+    if (arg.HasOnly("-V") || arg.HasOnly("--version"))
+        return 0;
+
+    if (arg.HasOnly("-?") || arg.HasOnly("-h") || arg.HasOnly("--help"))
+    {
+        Usage();
+        return 2;
+    }
+
+    const Bool_t kDebugMem   = arg.HasOnlyAndRemove("--debug-mem");
+
+    //
+    // check for the right usage of the program (number of arguments)
+    //
+    if (arg.GetNumArguments()>2)
+    {
+        gLog << warn << "WARNING - Wrong number of arguments..." << endl;
+        Usage();
+        return 2;
+    }
+
+    TString fname=arg.GetArgumentStr(0);
+    TString mod  =arg.GetArgumentStr(1);
+
+    //
+    // check for the right usage of the program (number of options)
+    //
+    if (arg.GetNumOptions()>0)
+    {
+        gLog << warn << "WARNING - Unknown commandline options..." << endl;
+        arg.Print("options");
+        gLog << endl;
+        return 2;
+    }
+
+//    MArray::Class()->IgnoreTObjectStreamer();
+//    MParContainer::Class()->IgnoreTObjectStreamer();
+
+    TApplication app("telesto", &argc, argv);
+    if (!gClient || gROOT->IsBatch())
+    {
+        gLog << err << "Bombing... maybe your DISPLAY variable is not set correctly!" << endl;
+        return 1;
+    }
+
+    if (kDebugMem)
+        TObject::SetObjectStat(kTRUE);
+
+    TPointGui *gui = new TPointGui(fname, mod);
+    gui->SetExitLoopOnClose();
+
+    // Wait until the user decides to exit the application
+    app.Run(kFALSE);
+
+    if (TObject::GetObjectStat())
+    {
+        TObject::SetObjectStat(kFALSE);
+        gObjectTable->Print();
+    }
+
+    return 0;
+}
Index: /trunk/FACT++/drive/videodev.h
===================================================================
--- /trunk/FACT++/drive/videodev.h	(revision 18618)
+++ /trunk/FACT++/drive/videodev.h	(revision 18618)
@@ -0,0 +1,283 @@
+#ifndef __LINUX_VIDEODEV_H
+#define __LINUX_VIDEODEV_H
+
+#include <linux/types.h>
+
+/*#ifdef __KERNEL__
+
+#if LINUX_VERSION_CODE >= 0x020100
+#include <linux/poll.h>
+#endif
+
+struct video_device
+{
+	char name[32];
+	int type;
+	int hardware;
+
+	int (*open)(struct video_device *, int mode);
+	void (*close)(struct video_device *);
+	long (*read)(struct video_device *, char *, unsigned long, int noblock);
+	// Do we need a write method ?
+	long (*write)(struct video_device *, const char *, unsigned long, int noblock);
+#if LINUX_VERSION_CODE >= 0x020100
+	unsigned int (*poll)(struct video_device *, struct file *, poll_table *);
+#endif
+	int (*ioctl)(struct video_device *, unsigned int , void *);
+	int (*mmap)(struct video_device *, const char *, unsigned long);
+	int (*initialize)(struct video_device *);	
+	void *priv;		// Used to be 'private' but that upsets C++
+	int busy;
+	int minor;
+};
+
+extern int videodev_init(void);
+#define VIDEO_MAJOR	81
+extern int video_register_device(struct video_device *, int type);
+
+#define VFL_TYPE_GRABBER	0
+#define VFL_TYPE_VBI		1
+#define VFL_TYPE_RADIO		2
+#define VFL_TYPE_VTX		3
+
+extern void video_unregister_device(struct video_device *);
+#endif
+*/
+
+#define VID_TYPE_CAPTURE	1	/* Can capture */
+#define VID_TYPE_TUNER		2	/* Can tune */
+#define VID_TYPE_TELETEXT	4	/* Does teletext */
+#define VID_TYPE_OVERLAY	8	/* Overlay onto frame buffer */
+#define VID_TYPE_CHROMAKEY	16	/* Overlay by chromakey */
+#define VID_TYPE_CLIPPING	32	/* Can clip */
+#define VID_TYPE_FRAMERAM	64	/* Uses the frame buffer memory */
+#define VID_TYPE_SCALES		128	/* Scalable */
+#define VID_TYPE_MONOCHROME	256	/* Monochrome only */
+#define VID_TYPE_SUBCAPTURE	512	/* Can capture subareas of the image */
+
+struct video_capability
+{
+	char name[32];
+	int type;
+	int channels;	/* Num channels */
+	int audios;	/* Num audio devices */
+	int maxwidth;	/* Supported width */
+	int maxheight;	/* And height */
+	int minwidth;	/* Supported width */
+	int minheight;	/* And height */
+};
+
+
+struct video_channel
+{
+	int channel;
+	char name[32];
+	int tuners;
+	__u32  flags;
+#define VIDEO_VC_TUNER		1	/* Channel has a tuner */
+#define VIDEO_VC_AUDIO		2	/* Channel has audio */
+	__u16  type;
+#define VIDEO_TYPE_TV		1
+#define VIDEO_TYPE_CAMERA	2	
+	__u16 norm;			/* Norm set by channel */
+};
+
+struct video_tuner
+{
+	int tuner;
+	char name[32];
+	ulong rangelow, rangehigh;	/* Tuner range */
+	__u32 flags;
+#define VIDEO_TUNER_PAL		1
+#define VIDEO_TUNER_NTSC	2
+#define VIDEO_TUNER_SECAM	4
+#define VIDEO_TUNER_LOW		8	/* Uses KHz not MHz */
+#define VIDEO_TUNER_NORM	16	/* Tuner can set norm */
+#define VIDEO_TUNER_STEREO_ON	128	/* Tuner is seeing stereo */
+	__u16 mode;			/* PAL/NTSC/SECAM/OTHER */
+#define VIDEO_MODE_PAL		0
+#define VIDEO_MODE_NTSC		1
+#define VIDEO_MODE_SECAM	2
+#define VIDEO_MODE_AUTO		3
+	__u16 signal;			/* Signal strength 16bit scale */
+};
+
+struct video_picture
+{
+	__u16	brightness;
+	__u16	hue;
+	__u16	colour;
+	__u16	contrast;
+	__u16	whiteness;	/* Black and white only */
+	__u16	depth;		/* Capture depth */
+	__u16   palette;	/* Palette in use */
+#define VIDEO_PALETTE_GREY	1	/* Linear greyscale */
+#define VIDEO_PALETTE_HI240	2	/* High 240 cube (BT848) */
+#define VIDEO_PALETTE_RGB565	3	/* 565 16 bit RGB */
+#define VIDEO_PALETTE_RGB24	4	/* 24bit RGB */
+#define VIDEO_PALETTE_RGB32	5	/* 32bit RGB */	
+#define VIDEO_PALETTE_RGB555	6	/* 555 15bit RGB */
+#define VIDEO_PALETTE_YUV422	7	/* YUV422 capture */
+#define VIDEO_PALETTE_YUYV	8
+#define VIDEO_PALETTE_UYVY	9	/* The great thing about standards is ... */
+#define VIDEO_PALETTE_YUV420	10
+#define VIDEO_PALETTE_YUV411	11	/* YUV411 capture */
+#define VIDEO_PALETTE_RAW	12	/* RAW capture (BT848) */
+#define VIDEO_PALETTE_YUV422P	13	/* YUV 4:2:2 Planar */
+#define VIDEO_PALETTE_YUV411P	14	/* YUV 4:1:1 Planar */
+#define VIDEO_PALETTE_YUV420P	15	/* YUV 4:2:0 Planar */
+#define VIDEO_PALETTE_YUV410P	16	/* YUV 4:1:0 Planar */
+#define VIDEO_PALETTE_PLANAR	13	/* start of planar entries */
+#define VIDEO_PALETTE_COMPONENT 7	/* start of component entries */
+};
+
+struct video_audio
+{
+	int	audio;		/* Audio channel */
+	__u16	volume;		/* If settable */
+	__u16	bass, treble;
+	__u32	flags;
+#define VIDEO_AUDIO_MUTE	1
+#define VIDEO_AUDIO_MUTABLE	2
+#define VIDEO_AUDIO_VOLUME	4
+#define VIDEO_AUDIO_BASS	8
+#define VIDEO_AUDIO_TREBLE	16	
+	char    name[16];
+#define VIDEO_SOUND_MONO	1
+#define VIDEO_SOUND_STEREO	2
+#define VIDEO_SOUND_LANG1	4
+#define VIDEO_SOUND_LANG2	8
+        __u16   mode;		/* detected audio carriers or one to set */
+        __u16	balance;	/* Stereo balance */
+        __u16	step;		/* Step actual volume uses */
+};
+
+struct video_clip
+{
+	__s32	x,y;
+	__s32	width, height;
+	struct	video_clip *next;	/* For user use/driver use only */
+};
+
+struct video_window
+{
+	__u32	x,y;			/* Position of window */
+	__u32	width,height;		/* Its size */
+	__u32	chromakey;
+	__u32	flags;
+	struct	video_clip *clips;	/* Set only */
+	int	clipcount;
+#define VIDEO_WINDOW_INTERLACE	1
+#define VIDEO_CLIP_BITMAP	-1
+/* bitmap is 1024x625, a '1' bit represents a clipped pixel */
+#define VIDEO_CLIPMAP_SIZE	(128 * 625)
+};
+
+struct video_capture
+{
+	__u32 	x,y;			/* Offsets into image */
+	__u32	width, height;		/* Area to capture */
+	__u16	decimation;		/* Decimation divder */
+	__u16	flags;			/* Flags for capture */
+#define VIDEO_CAPTURE_ODD		0	/* Temporal */
+#define VIDEO_CAPTURE_EVEN		1
+};
+
+struct video_buffer
+{
+	void	*base;
+	int	height,width;
+	int	depth;
+	int	bytesperline;
+};
+
+struct video_mmap
+{
+	unsigned	int frame;		/* Frame (0 - n) for double buffer */
+	int		height,width;
+	unsigned	int format;		/* should be VIDEO_PALETTE_* */
+};
+
+struct video_key
+{
+	__u8	key[8];
+	__u32	flags;
+};
+
+
+#define VIDEO_MAX_FRAME		32
+
+struct video_mbuf
+{
+	int	size;		/* Total memory to map */
+	int	frames;		/* Frames */
+	int	offsets[VIDEO_MAX_FRAME];
+};
+	
+
+#define 	VIDEO_NO_UNIT	(-1)
+
+	
+struct video_unit
+{
+	int 	video;		/* Video minor */
+	int	vbi;		/* VBI minor */
+	int	radio;		/* Radio minor */
+	int	audio;		/* Audio minor */
+	int	teletext;	/* Teletext minor */
+};
+
+#define VIDIOCGCAP		_IOR('v',1,struct video_capability)	/* Get capabilities */
+#define VIDIOCGCHAN		_IOWR('v',2,struct video_channel)	/* Get channel info (sources) */
+#define VIDIOCSCHAN		_IOW('v',3,struct video_channel)	/* Set channel 	*/
+#define VIDIOCGTUNER		_IOWR('v',4,struct video_tuner)		/* Get tuner abilities */
+#define VIDIOCSTUNER		_IOW('v',5,struct video_tuner)		/* Tune the tuner for the current channel */
+#define VIDIOCGPICT		_IOR('v',6,struct video_picture)	/* Get picture properties */
+#define VIDIOCSPICT		_IOW('v',7,struct video_picture)	/* Set picture properties */
+#define VIDIOCCAPTURE		_IOW('v',8,int)				/* Start, end capture */
+#define VIDIOCGWIN		_IOR('v',9, struct video_window)	/* Set the video overlay window */
+#define VIDIOCSWIN		_IOW('v',10, struct video_window)	/* Set the video overlay window - passes clip list for hardware smarts , chromakey etc */
+#define VIDIOCGFBUF		_IOR('v',11, struct video_buffer)	/* Get frame buffer */
+#define VIDIOCSFBUF		_IOW('v',12, struct video_buffer)	/* Set frame buffer - root only */
+#define VIDIOCKEY		_IOR('v',13, struct video_key)		/* Video key event - to dev 255 is to all - cuts capture on all DMA windows with this key (0xFFFFFFFF == all) */
+#define VIDIOCGFREQ		_IOR('v',14, unsigned long)		/* Set tuner */
+#define VIDIOCSFREQ		_IOW('v',15, unsigned long)		/* Set tuner */
+#define VIDIOCGAUDIO		_IOR('v',16, struct video_audio)	/* Get audio info */
+#define VIDIOCSAUDIO		_IOW('v',17, struct video_audio)	/* Audio source, mute etc */
+#define VIDIOCSYNC		_IOW('v',18, int)			/* Sync with mmap grabbing */
+#define VIDIOCMCAPTURE		_IOW('v',19, struct video_mmap)		/* Grab frames */
+#define VIDIOCGMBUF		_IOR('v', 20, struct video_mbuf)	/* Memory map buffer info */
+#define VIDIOCGUNIT		_IOR('v', 21, struct video_unit)	/* Get attached units */
+#define VIDIOCGCAPTURE		_IOR('v',22, struct video_capture)	/* Get frame buffer */
+#define VIDIOCSCAPTURE		_IOW('v',23, struct video_capture)	/* Set frame buffer - root only */
+
+#define BASE_VIDIOCPRIVATE	192		/* 192-255 are private */
+
+
+#define VID_HARDWARE_BT848	1
+#define VID_HARDWARE_QCAM_BW	2
+#define VID_HARDWARE_PMS	3
+#define VID_HARDWARE_QCAM_C	4
+#define VID_HARDWARE_PSEUDO	5
+#define VID_HARDWARE_SAA5249	6
+#define VID_HARDWARE_AZTECH	7
+#define VID_HARDWARE_SF16MI	8
+#define VID_HARDWARE_RTRACK	9
+#define VID_HARDWARE_ZOLTRIX	10
+#define VID_HARDWARE_SAA7146    11
+#define VID_HARDWARE_VIDEUM	12	/* Reserved for Winnov videum */
+#define VID_HARDWARE_RTRACK2	13
+#define VID_HARDWARE_PERMEDIA2	14	/* Reserved for Permedia2 */
+#define VID_HARDWARE_RIVA128	15	/* Reserved for RIVA 128 */
+
+/*
+ *	Initialiser list
+ */
+ 
+struct video_init
+{
+	char *name;
+	int (*init)(struct video_init *);
+};
+
+#endif
