Donnerstag, 28. Februar 2008

Anzeige von Empfangswerten in Neutrino

Um SIG SNR BER auch im Infoviewer anzeigen zu lassen ist nicht viel nötig.

Wenn man sich selbst etwas mit dem Source beschäftigt würde man am einfachsten mal damit anfangen sich den Source des Satfinders anzuschauen.
Die Sourcen sind im CVS zu finden. (apps/tuxbox/tools/satfind)


Einfach ist das ganze aber wenn man sich mal die zapitclient.cpp/h anschaut.
(CVS: apps/dvb/zapit/lib)
Dort ist in der Funktion
void CZapitClient::getFESignal (struct responseFESignal &f) gut zu erkennen wie das funktionieren könnte.

Oder man liest gleich die streaminfo2.cpp/h aus dem Neutrinozweig...

Ok, genug der Verweise. Kommen wir mal zum Punkt.

Verändert werden müssen folgende Dateien: infoviewer.cpp & infoviewer.h

infoviewer.h:
Im private Bereich der Klasse wird folgendes eingefügt.
struct feSignal {
unsigned long sig;
unsigned long ber;
unsigned long snr;
} signal;

void showSatfind();

infoviewer.cpp:

Die in der infoviewer.h vordefinierte Funktion showSatfind() wird wie folgt angelegt.

void CInfoViewer::showSatfind()
{
CZapitClient::responseFESignal s;

g_Zapit->getFESignal(s);


signal.sig = s.sig & 0xFFFF;

signal.snr = s.snr & 0xFFFF;

signal.ber = (s.ber < 0x3FFFF) ? s.ber : 0x3FFFF;

int sx = BoxStartX;
int sy = g_settings.screen_StartY + 150;
int ex = BoxEndX;
int ey = sy + 20;

int fromleft = sx + 137;// Abstand Links
int fromright = ex - 85; // Abstand Rechts

// maximale Breite pro Signal
unsigned int maxbar = ((fromright - fromleft) / 3) - 20;
// maximaler Signalwert
unsigned long maxs = 65000;
// maximaler BER-Wert
unsigned long maxb = 40000;

unsigned int sigbar = ( (long) maxbar * (long) signal.sig ) / (long) maxs;
unsigned int snrbar = ( (long) maxbar * (long) signal.snr ) / (long) maxs;
unsigned int berbar = ( (long) maxbar * (long) signal.ber ) / (long) maxb;

// Manchmal ist BERBAR grösser als MAXBAR! Also hier abfangen!
if (berbar > maxbar)
berbar = maxbar;

}

Jetzt haben wir Werte mit dennen man Boxen zeichnen kann welche die SAT Werte darstellen.

Für jede Anzeige müssen drei Rechtecke gezeichnet werden. Ok, müssen nicht aber sieht besser aus ;)

// Hintergrund
frameBuffer->paintBoxRel(fromleft , ey - 6, maxbar + 2, 8, COL_INFOBAR_PLUS_7);
frameBuffer->paintBoxRel(fromleft + maxbar + 10, ey - 6, maxbar + 2, 8, COL_INFOBAR_PLUS_7);
frameBuffer->paintBoxRel(fromleft + (maxbar * 2) + 20, ey - 6, maxbar + 2, 8, COL_INFOBAR_PLUS_7);

// Balken 100%
frameBuffer->paintBoxRel(fromleft + 1, ey - 5, maxbar, 6, COL_INFOBAR_PLUS_3);
frameBuffer->paintBoxRel(fromleft + maxbar + 11, ey - 5, maxbar, 6, COL_INFOBAR_PLUS_3);
frameBuffer->paintBoxRel(fromleft + (maxbar * 2) + 21, ey - 5, maxbar, 6, COL_INFOBAR_PLUS_3);

// Balken Wertanzeige
frameBuffer->paintBoxRel(fromleft + 1, ey - 5, sigbar, 6, COL_BASIC_GREEN);
frameBuffer->paintBoxRel(fromleft + maxbar + 11, ey - 5, snrbar, 6, COL_BASIC_YELLOW);
frameBuffer->paintBoxRel(fromleft + (maxbar * 2) + 21, ey - 5, berbar, 6, COL_BASIC_RED);

Fertig...

Nunja, wenn man die Funktion nun irgendwo aufruft, dann würde nur der Wert angezeigt der beim Aufruf der Funktion gültig war. Nun ist die Infobar aber per default 6 Sekunden zu sehen.
Warum also nicht auch in der Zeit die Werte aktualisieren.

Dazu bietet sich in der Funktion showTitle() folgender Abschnitt geradezu an:

else if ( ( msg == NeutrinoMessages::EVT_TIMER ) && ( data == sec_timer_id ) )
{

paintTime( show_dot, false );

showRecordIcon(show_dot);

show_dot = !show_dot;

}


Hier wird der Funktionsaufruf einfach eingefügt und die Werte werden jede Sekunde aktualisiert.

So, ich bin nicht der tolle Erklärbar aber mit diesen Info sollte wohl jeder der sich an C Sourcen traut auch etwas mit anfangen können. Die hier angegebenen Koordinaten (sy, sy, ex, ey) sind nur daher geschrieben. Die Anzeige kann also etwas komisch aussehen.
Ein wenig Zeit sollte dann doch jeder selbst investieren.

z.B.: Erweiterung zur Anzeige der Werte in Textform u.s.w...

Gruß

Montag, 11. Februar 2008

Runde Ecken in Neutrino

Wie erstellt man runde Ecken in Neutrino???

Als erstes muss wohl die Framebufferklasse von Neutrino angepasst werden.
Dazu habe ich zwei neue Funktionen integriert.
Eine Funktion dient dazu normale und die andere gefüllte Kreise zu zeichnen.

Die Funktionen für die framebuffer.cpp sind:

void CFrameBuffer::paintCircleFilled(int sx, int sy, int radius, const fb_pixel_t col, int type)
{
if (!getActive())
return;

int F = 1 - radius;
int ddF_x = 0;
int ddF_y = -2*radius;
int x = 0;
int y = radius;
bool paint_extraline = true;

while ( x <>= 0) {
y -= 1;
ddF_y += 2;
F += ddF_y;
}

x += 1;
ddF_x += 2;
F += ddF_x + 1;

switch (type)
{
case 0: // Full Circle
paintHLineRel(sx - x, (sx - (sx - x)) * 2, sy - y, col);
paintHLineRel(sx - y, (sx - (sx - y)) * 2, sy - x, col);
if (paint_extraline) {
paintHLineRel(sx - y, (sx - (sx - y)) * 2, sy + x - 1, col);
paint_extraline = false;
}
paintHLineRel(sx - x, (sx - (sx - x)) * 2, sy + y, col);
paintHLineRel(sx - y, (sx - (sx - y)) * 2, sy + x, col);
break;
case 1: // Left Upper Corner
paintHLineRel(sx - x, sx - (sx - x), sy - y, col);
paintHLineRel(sx - y, sx - (sx - y), sy - x, col);
break;
case 2: // Right Upper Corner
paintHLineRel(sx, (sx + x) - sx, sy - y, col);
paintHLineRel(sx, (sx + y) - sx, sy - x, col);
break;
case 3: // Left Lower Corner
paintHLineRel(sx - x, sx - (sx - x), sy + y, col);
paintHLineRel(sx - y, sx - (sx - y), sy + x, col);
break;
case 4: // Right Lower Corner
paintHLineRel(sx, (sx + x) - sx, sy + y, col);
paintHLineRel(sx, (sx + y) - sx, sy + x, col);
break;
default: ; /* nothing to do for default */
}
}
}

void CFrameBuffer::paintCircle(int sx, int sy, int radius, const fb_pixel_t col, int type)
{
if (!getActive())
return;

int F = 1 - radius;
int ddF_x = 0;
int ddF_y = -2*radius;
int x = 0;
int y = radius;

while ( x <>= 0) {
y -= 1;
ddF_y += 2;
F += ddF_y;
}
x += 1;
ddF_x += 2;
F += ddF_x + 1;

switch (type)
{
case 0: // Full Circle
paintPixel(sx + x, sy + y, col); paintPixel(sx - x, sy + y, col);
paintPixel(sx + x, sy - y, col); paintPixel(sx - x, sy - y, col);
paintPixel(sx + y, sy + x, col); paintPixel(sx - y, sy + x, col);
paintPixel(sx + y, sy - x, col); paintPixel(sx - y, sy - x, col);
break;
case 1: // Left Upper Corner
paintPixel(sx - x, sy - y, col); paintPixel(sx - y, sy - x, col);
break;
case 2: // Right Upper Corner
paintPixel(sx + x, sy - y, col); paintPixel(sx + y, sy - x, col);
break;
case 3: // Left Lower Corner
paintPixel(sx - x, sy + y, col); paintPixel(sx - y, sy + x, col);
break;
case 4: // Right Lower Corner
paintPixel(sx + x, sy + y, col); paintPixel(sx + y, sy + x, col);
break;
default: ; /* nothing to do for default */
}
}
}


Die Einträge für framebuffer.h

void paintCircle(int sx, int sy, int radius, const fb_pixel_t col, int type);
void paintCircleFilled(int sx, int sy, int radius, const fb_pixel_t col, int type);



Kurz eine Erläuterung zu den Funktionen:
int sx = Startpunkt X
int sy = Startpunkt Y
int radius = Radius
const fb_pixel_t col = Farbe (Linie oder gefüllt)
int type = die Form (Viertel / Voll)

als Typ gibt es folgendes Werte:
0 = Voller Kreis
1 = Viertelkreis als Corner Links/Oben
2 = Viertelkreis als Corner Rechts/Oben
3 = Viertelkreis als Corner Links/Unten
4 = Viertelkreis als Corner Rechts/Unten

Beispiel:
frameBuffer->paintCircleFilled(300, 300, 20, COL_INFOBAR_PLUS_7, 0);

Zeichnet einen Kreis mit einem Durchmesser von 40 Pixel mit Mittelpunkt bei 300x - 300y, mit Weiss gefüllt.

Die Vorgehensweise, so wie ich es immer mache, ist:

Rechteck zeichnen
BackgroundBox zeichnen mit Länge/Höhe vom Radius des Viertelkreises.
Viertelkreis (gefüllt) zeichnen.
Fertig! Wir haben eine runde Ecke...

Beispiel:

 frameBuffer->paintBoxRel(100, 100, 250, 250, COL_INFOBAR_PLUS_0);
frameBuffer->paintBackgroundBox(100, 100, 100 + 20, 100 + 20);
frameBuffer->paintCircleFilled(100 + 20, 100 + 20, 20, COL_INFOBAR_PLUS_0, 1);


Gruß