Menu uses colors; support for RGYB buttons; fixed DEBUG_REMOTE; Add, Del and Move for channels and timers; basic record/play file handling

This commit is contained in:
Klaus Schmidinger 2000-03-11 11:22:37 +01:00
parent 4a9d9c5876
commit 571686d909
23 changed files with 1378 additions and 366 deletions

12
HISTORY Normal file
View File

@ -0,0 +1,12 @@
Video Disk Recorder OSM Revision History
----------------------------------------
2000-02-19: Version 0.01 (Initial revision).
2000-03-11: Version 0.02
- Fixed compilation with only DEBUG_REMOTE=1.
- Menus now use colors.
- Support for "Red", "Green", "Yellow", "Blue" buttons.
- Channels and Timers can now be added, deleted and moved.
- Basic record/play file handling support (no actual record/playback yet).

View File

@ -4,9 +4,9 @@
# See the main source file 'osm.c' for copyright information and
# how to reach the author.
#
# $Id: Makefile 1.1 2000/02/19 13:36:48 kls Exp $
# $Id: Makefile 1.2 2000/03/05 13:51:57 kls Exp $
OBJS = config.o dvbapi.o interface.o menu.o osd.o remote.o tools.o osm.o
OBJS = config.o dvbapi.o interface.o menu.o osd.o recording.o remote.o tools.o osm.o
ifdef DEBUG_REMOTE
DEFINES += -DDEBUG_REMOTE
@ -24,9 +24,10 @@ all: osm
config.o : config.c config.h dvbapi.h interface.h tools.h
dvbapi.o : dvbapi.c config.h dvbapi.h interface.h tools.h
interface.o: interface.c config.h dvbapi.h interface.h remote.h tools.h
menu.o : menu.c config.h dvbapi.h interface.h menu.h osd.h tools.h
osd.o : osd.c config.h interface.h osd.h tools.h
osm.o : osm.c config.h dvbapi.h interface.h menu.h osd.h tools.h
menu.o : menu.c config.h dvbapi.h interface.h menu.h osd.h recording.h tools.h
osd.o : osd.c config.h dvbapi.h interface.h osd.h tools.h
osm.o : osm.c config.h dvbapi.h interface.h menu.h osd.h recording.h tools.h
recording.o: recording.c config.h dvbapi.h interface.h recording.h tools.h
remote.o : remote.c remote.h tools.h
tools.o : tools.c tools.h

36
README
View File

@ -36,10 +36,34 @@ about that driver). For example, if the DVB driver was
extracted into the directory /home/kls/vdr/DVB, then this
package should be extracted into /home/kls/vdr/OSM.
In order for the menu colors to work correctly you may want
to replace the function RGB2YUV() in DVB/driver/dvb.c with
static u32 RGB2YUV(u16 R, u16 G, u16 B)
{
u16 y, u, v;
u16 Y, Cr, Cb;
y = R * 77 + G * 150 + B * 29; // Luma=0.299R+0.587G+0.114B 0..65535
u = 2048+B * 8 -(y>>5); // Cr 0..4095
v = 2048+R * 8 -(y>>5); // Cb 0..4095
Y = y >> 8;
Cb= u >> 4;
Cr= v >> 4;
return Cr|(Cb<<16)|(Y<<8);
}
(this may no longer be necessary with driver versions after 0.03c).
After extracting the package, change into the OSM directory
and type 'make'. This should produce an executable file
named 'osm', which can be run after the DVB driver has been
installed.
installed. There may be several warnings about "implicit declaration
of function `int asprintf(...)'" during the compilation, which I was
unable to avoid (anybody know how to avoid them?). Just ignore them,
the program will work, anyway.
There are two macros you can use to customize the 'osm' program
at compile time. Adding "DEBUG_REMOTE=1" to the 'make' call
@ -75,10 +99,10 @@ this package contains the codes for the "d-box" remote control unit.
If you want to use a different remote control unit, simply delete
the file 'keys.conf' and restart the 'osm' program. The program will
then start a key learning session in which it first attempts to determine
the basic data tranfer mode and timing of your remote control unit,
the basic data transfer mode and timing of your remote control unit,
and then will ask you to press one key after the other so that it can
learn the various key codes. You will at least need to provide an "Up"
and a "Down" key, so that you can switch channels. The rest os the key
and a "Down" key, so that you can switch channels. The rest of the key
definitions is optional, but the more keys you define, the more you
will be able to navigate through the menus.
@ -97,9 +121,6 @@ confirms any changes (or switches to a channel in the "Channels" menu).
The "Back" key goes back one level in the menu structure, discarding
any changes that might have been made in the current menu.
In the "Channels" menu, the current channel can be edited by pressing
the "Right" key.
In the "Timers" menu, the current timer can be enabled or disabled with
the "Right" or "Left" key, respectively (enabled timers are marked with ">").
"Ok" here opens the "Edit timer" menu.
@ -110,6 +131,9 @@ character as in "[R]TL"), selecting the desired character position with
"Left" and "Right", and changing the character with the "Up" and "Down"
keys. "Ok" then confirms the changes.
The "Red", "Green", "Yellow" and "Blue" buttons have special meanings
in the various menus and are listed at the bottom of the on-screen-display.
At any point in the menu system, pressing the "Menu" key again will
immediately leave the menu system.

5
TODO
View File

@ -1,13 +1,12 @@
TODO list for the Video Disk Recorder project
---------------------------------------------
* Implement a way to add and delete channels and timers.
* Implement recording to disk and playback from disk.
* Implement disk file management (delete old/viewed files to make
room for new recordings if necessary).
* Make it work with two DVB-S PCI cards to allow simultaneous
recording of one programme, while replaying another programme
(or maybe the same one, but time delayed).
Maybe we can do this with only a single card, if the card
driver/firmware allows simultaneuos record/playback?
* Implement "on-disk editing" to allow "cutting out" of certain
scenes in order to archive them (or, reversely, cut out
commercial breaks).

View File

@ -42,7 +42,7 @@ B1:12722:h:1:22000:601:602
ARD Online-Kanal:12722:h:1:22000:8191:701
Premiere World Promo:11798:h:1:27500:255:256
TV Niepokalanow:11876:h:1:27500:305:321
test card:11876:h:1:27500:306:322
test card:11798:h:1:27500:511:512
Mosaico:11934:v:1:27500:165:100
Andalucia TV:11934:v:1:27500:166:104
TVC Internacional:11934:v:1:27500:167:108

118
config.c
View File

@ -4,37 +4,40 @@
* See the main source file 'osm.c' for copyright information and
* how to reach the author.
*
* $Id: config.c 1.1 2000/02/19 13:36:48 kls Exp $
* $Id: config.c 1.2 2000/03/05 16:14:27 kls Exp $
*/
#include "config.h"
#include <ctype.h>
#include <stdlib.h>
#include <time.h>
#include "dvbapi.h"
#include "interface.h"
// -- cKeys ------------------------------------------------------------------
tKey keyTable[] = { // "Up" and "Down" must be the first two keys!
{ kUp, "Up", 0 },
{ kDown, "Down", 0 },
{ kMenu, "Menu", 0 },
{ kOk, "Ok", 0 },
{ kBack, "Back", 0 },
{ kLeft, "Left", 0 },
{ kRight, "Right", 0 },
{ k0, "0", 0 },
{ k1, "1", 0 },
{ k2, "2", 0 },
{ k3, "3", 0 },
{ k4, "4", 0 },
{ k5, "5", 0 },
{ k6, "6", 0 },
{ k7, "7", 0 },
{ k8, "8", 0 },
{ k9, "9", 0 },
{ kNone, "", 0 },
{ kUp, "Up", 0 },
{ kDown, "Down", 0 },
{ kMenu, "Menu", 0 },
{ kOk, "Ok", 0 },
{ kBack, "Back", 0 },
{ kLeft, "Left", 0 },
{ kRight, "Right", 0 },
{ k0, "0", 0 },
{ k1, "1", 0 },
{ k2, "2", 0 },
{ k3, "3", 0 },
{ k4, "4", 0 },
{ k5, "5", 0 },
{ k6, "6", 0 },
{ k7, "7", 0 },
{ k8, "8", 0 },
{ k9, "9", 0 },
{ kRed, "Red", 0 },
{ kGreen, "Green", 0 },
{ kYellow, "Yellow", 0 },
{ kBlue, "Blue", 0 },
{ kNone, "", 0 },
};
cKeys::cKeys(void)
@ -160,6 +163,17 @@ cChannel::cChannel(void)
*name = 0;
}
cChannel::cChannel(const cChannel *Channel)
{
strcpy(name, Channel ? Channel->name : "Pro7");
frequency = Channel ? Channel->frequency : 12480;
polarization = Channel ? Channel->polarization : 'v';
diseqc = Channel ? Channel->diseqc : 1;
srate = Channel ? Channel->srate : 27500;
vpid = Channel ? Channel->vpid : 255;
apid = Channel ? Channel->apid : 256;
}
bool cChannel::Parse(char *s)
{
char *buffer = NULL;
@ -203,6 +217,17 @@ bool cChannel::SwitchTo(int i)
cTimer::cTimer(void)
{
startTime = stopTime = 0;
recording = false;
active = 1;
channel = CurrentChannel + 1;
day = 1; //XXX today!
start = 0; //XXX now!
stop = 0; //XXX now + 2h!
//TODO VPS???
quality = 'H';
priority = 99;
lifetime = 99;
*file = 0;
}
@ -211,6 +236,13 @@ int cTimer::TimeToInt(int t)
return (t / 100 * 60 + t % 100) * 60;
}
time_t cTimer::Day(time_t t)
{
struct tm d = *localtime(&t);
d.tm_hour = d.tm_min = d.tm_sec = 0;
return mktime(&d);
}
int cTimer::ParseDay(char *s)
{
char *tail;
@ -270,13 +302,17 @@ bool cTimer::Save(FILE *f)
return fprintf(f, "%d:%d:%s:%d:%d:%c:%d:%d:%s\n", active, channel, PrintDay(day), start, stop, quality, priority, lifetime, file) > 0;
}
bool cTimer::IsSingleEvent(void)
{
return (day & 0x80000000) == 0;
}
bool cTimer::Matches(void)
{
if (active) {
time_t t = time(NULL);
struct tm *now = localtime(&t);
int weekday = now->tm_wday == 0 ? 6 : now->tm_wday - 1; // we start with monday==0!
int current = (now->tm_hour * 60 + now->tm_min) * 60 + now->tm_sec;
struct tm now = *localtime(&t);
int weekday = now.tm_wday == 0 ? 6 : now.tm_wday - 1; // we start with monday==0!
int begin = TimeToInt(start);
int end = TimeToInt(stop);
bool twoDays = (end < begin);
@ -291,20 +327,44 @@ bool cTimer::Matches(void)
yesterdayMatches = true;
}
}
else if (day == now->tm_mday)
else if (day == now.tm_mday)
todayMatches = true;
else if (twoDays) {
t -= 86400;
now = localtime(&t);
if (day == now->tm_mday)
time_t ty = t - SECSINDAY;
if (day == localtime(&ty)->tm_mday)
yesterdayMatches = true;
}
return (todayMatches && current >= begin && (current <= end || twoDays))
|| (twoDays && yesterdayMatches && current <= end);
if (todayMatches || (twoDays && yesterdayMatches)) {
startTime = Day(t - (yesterdayMatches ? SECSINDAY : 0)) + begin;
stopTime = startTime + (twoDays ? SECSINDAY - begin + end : end - begin);
}
else
startTime = stopTime = 0;
return startTime <= t && t <= stopTime;
}
return false;
}
time_t cTimer::StartTime(void)
{
if (!startTime)
Matches();
return startTime;
}
time_t cTimer::StopTime(void)
{
if (!stopTime)
Matches();
return stopTime;
}
void cTimer::SetRecording(bool Recording)
{
recording = Recording;
isyslog(LOG_INFO, "timer %d %s", Index() + 1, recording ? "start" : "stop");
}
cTimer *cTimer::GetMatch(void)
{
cTimer *t = (cTimer *)Timers.First();

View File

@ -4,7 +4,7 @@
* See the main source file 'osm.c' for copyright information and
* how to reach the author.
*
* $Id: config.h 1.1 2000/02/19 13:36:48 kls Exp $
* $Id: config.h 1.2 2000/03/05 14:58:23 kls Exp $
*/
#ifndef __CONFIG_H
@ -12,6 +12,7 @@
#include <stdio.h>
#include <string.h>
#include <time.h>
#include "tools.h"
#define MaxBuffer 1000
@ -25,6 +26,10 @@ enum eKeys { // "Up" and "Down" must be the first two keys!
kLeft,
kRight,
k0, k1, k2, k3, k4, k5, k6, k7, k8, k9,
kRed,
kGreen,
kYellow,
kBlue,
kNone
};
@ -60,6 +65,7 @@ public:
int vpid;
int apid;
cChannel(void);
cChannel(const cChannel *Channel);
bool Parse(char *s);
bool Save(FILE *f);
bool Switch(void);
@ -67,8 +73,11 @@ public:
};
class cTimer : public cListObject {
private:
time_t startTime, stopTime;
public:
enum { MaxFileName = 256 };
bool recording;
int active;
int channel;
int day;
@ -82,9 +91,14 @@ public:
cTimer(void);
bool Parse(char *s);
bool Save(FILE *f);
bool IsSingleEvent(void);
bool Matches(void);
time_t StartTime(void);
time_t StopTime(void);
void SetRecording(bool Recording);
static cTimer *GetMatch(void);
static int TimeToInt(int t);
static time_t Day(time_t t);
static int ParseDay(char *s);
static char *PrintDay(int d);
};

168
dvbapi.c
View File

@ -4,20 +4,14 @@
* See the main source file 'osm.c' for copyright information and
* how to reach the author.
*
* $Id: dvbapi.c 1.1 2000/02/19 13:36:48 kls Exp $
* $Id: dvbapi.c 1.2 2000/03/11 10:39:09 kls Exp $
*/
// FIXME: these should be defined in ../DVB/driver/dvb.h!!!
typedef unsigned int u32;
typedef unsigned short u16;
typedef unsigned char u8;
#include "dvbapi.h"
#include <fcntl.h>
#include <stdio.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include "../DVB/driver/dvb.h"
#include "interface.h"
#include "tools.h"
@ -60,6 +54,7 @@ bool DvbSetChannel(int FrequencyMHz, char Polarization, int Diseqc, int Srate, i
cDvbRecorder::cDvbRecorder(void)
{
recording = false;
}
cDvbRecorder::~cDvbRecorder()
@ -67,18 +62,41 @@ cDvbRecorder::~cDvbRecorder()
Stop();
}
bool cDvbRecorder::Recording(void)
{
return recording;
}
bool cDvbRecorder::Record(const char *FileName, char Quality)
{
isyslog(LOG_INFO, "record %s (%c)", FileName, Quality);
return true;
if (MakeDirs(FileName)) {
FILE *f = fopen(FileName, "a");
if (f) {
fprintf(f, "%s, %c\n", FileName, Quality);
fclose(f);
recording = true;
// TODO
Interface.Error("Recording not yet implemented!");
return true;
}
else {
Interface.Error("Can't write to file!");
return false;
}
}
// TODO
return false;
}
bool cDvbRecorder::Play(const char *FileName, int Frame)
{
isyslog(LOG_INFO, "play %s (%d)", FileName, Frame);
// TODO
if (!recording) {
isyslog(LOG_INFO, "play %s (%d)", FileName, Frame);
// TODO
Interface.Error("Playback not yet implemented!");
return true;
}
return false;
}
@ -106,6 +124,7 @@ bool cDvbRecorder::Pause(void)
void cDvbRecorder::Stop(void)
{
isyslog(LOG_INFO, "stop");
recording = false;
// TODO
}
@ -116,9 +135,57 @@ int cDvbRecorder::Frame(void)
return 0;
}
// ---------------------------------------------------------------------------
// --- cDvbOsd ---------------------------------------------------------------
static void DvbOsdCmd(OSD_Command cmd, int color = 0, int x0 = 0, int y0 = 0, int x1 = 0, int y1 = 0, void *data = NULL)
cDvbOsd::cDvbOsd(void)
{
cols = rows = 0;
#ifdef DEBUG_OSD
memset(&colorPairs, 0, sizeof(colorPairs));
initscr();
start_color();
keypad(stdscr, TRUE);
nonl();
cbreak();
noecho();
timeout(1000);
leaveok(stdscr, TRUE);
window = stdscr;
#endif
#ifdef DEBUG_REMOTE
initscr();
keypad(stdscr, TRUE);
nonl();
cbreak();
noecho();
timeout(1000);
#endif
}
cDvbOsd::~cDvbOsd()
{
Close();
}
#ifdef DEBUG_OSD
void cDvbOsd::SetColor(eDvbColor colorFg, eDvbColor colorBg)
{
int color = (colorBg << 16) | colorFg | 0x80000000;
for (int i = 0; i < MaxColorPairs; i++) {
if (!colorPairs[i]) {
colorPairs[i] = color;
init_pair(i + 1, colorFg, colorBg);
wattrset(window, COLOR_PAIR(i + 1));
break;
}
else if (color == colorPairs[i]) {
wattrset(window, COLOR_PAIR(i + 1));
break;
}
}
}
#else
void cDvbOsd::Cmd(OSD_Command cmd, int color, int x0, int y0, int x1, int y1, const void *data)
{
int v = open(VIDEODEVICE, O_RDWR);
@ -130,37 +197,88 @@ static void DvbOsdCmd(OSD_Command cmd, int color = 0, int x0 = 0, int y0 = 0, in
dc.y0 = y0;
dc.x1 = x1;
dc.y1 = y1;
dc.data = data;
dc.data = (void *)data;
ioctl(v, VIDIOCSOSDCOMMAND, &dc);
close(v);
}
else
Interface.Error("can't open VIDEODEVICE");//XXX
}
#endif
void DvbOsdOpen(int x, int y, int w, int h)
void cDvbOsd::Open(int w, int h)
{
DvbOsdCmd(OSD_Open, 1, x, y, x + w - 1, y + h - 1);
DvbOsdCmd(OSD_SetColor, 0, 0, 0, 0, 127); // background 50% gray
DvbOsdCmd(OSD_SetColor, 1, 255, 255, 255, 255); // text white
cols = w;
rows = h;
#ifdef DEBUG_OSD
//XXX size...
#define B2C(b) (((b) * 1000) / 255)
#define SETCOLOR(n, r, g, b, o) init_color(n, B2C(r), B2C(g), B2C(b))
#else
w *= charWidth;
h *= lineHeight;
int x = (720 - w) / 2; //TODO PAL vs. NTSC???
int y = (576 - h) / 2;
Cmd(OSD_Open, 4, x, y, x + w - 1, y + h - 1);
#define SETCOLOR(n, r, g, b, o) Cmd(OSD_SetColor, n, r, g, b, o)
#endif
SETCOLOR(clrBackground, 0x00, 0x00, 0x00, 127); // background 50% gray
SETCOLOR(clrBlack, 0x00, 0x00, 0x00, 255);
SETCOLOR(clrRed, 0xFC, 0x14, 0x14, 255);
SETCOLOR(clrGreen, 0x24, 0xFC, 0x24, 255);
SETCOLOR(clrYellow, 0xFC, 0xC0, 0x24, 255);
SETCOLOR(clrBlue, 0x00, 0x00, 0xFC, 255);
SETCOLOR(clrCyan, 0x00, 0xFC, 0xFC, 255);
SETCOLOR(clrMagenta, 0xB0, 0x00, 0xFC, 255);
SETCOLOR(clrWhite, 0xFC, 0xFC, 0xFC, 255);
}
void DvbOsdClose(void)
void cDvbOsd::Close(void)
{
DvbOsdCmd(OSD_Close);
#ifndef DEBUG_OSD
Cmd(OSD_Close);
#endif
}
void DvbOsdClear(void)
void cDvbOsd::Clear(void)
{
DvbOsdCmd(OSD_Clear);
#ifdef DEBUG_OSD
SetColor(clrBackground, clrBackground);
Fill(0, 0, cols, rows, clrBackground);
#else
Cmd(OSD_Clear);
#endif
}
void DvbOsdClrEol(int x, int y)
void cDvbOsd::Fill(int x, int y, int w, int h, eDvbColor color)
{
DvbOsdCmd(OSD_FillBlock, 0, x, y * DvbOsdLineHeight, x + 490, (y + 1) * DvbOsdLineHeight);//XXX
if (x < 0) x = cols + x;
if (y < 0) y = rows + y;
#ifdef DEBUG_OSD
SetColor(color, color);
for (int r = 0; r < h; r++) {
wmove(window, y + r, x); // ncurses wants 'y' before 'x'!
whline(window, ' ', w);
}
#else
Cmd(OSD_FillBlock, color, x * charWidth, y * lineHeight, (x + w) * charWidth - 1, (y + h) * lineHeight - 1);
#endif
}
void DvbOsdText(int x, int y, char *s)
void cDvbOsd::ClrEol(int x, int y, eDvbColor color)
{
DvbOsdCmd(OSD_Text, 1, x, y, 1, 0, s);
Fill(x, y, cols - x, 1, color);
}
void cDvbOsd::Text(int x, int y, const char *s, eDvbColor colorFg, eDvbColor colorBg)
{
if (x < 0) x = cols + x;
if (y < 0) y = rows + y;
#ifdef DEBUG_OSD
SetColor(colorFg, colorBg);
wmove(window, y, x); // ncurses wants 'y' before 'x'!
waddstr(window, s);
#else
Cmd(OSD_Text, (int(colorBg) << 16) | colorFg, x * charWidth, y * lineHeight, 1, 0, s);
#endif
}

View File

@ -4,23 +4,51 @@
* See the main source file 'osm.c' for copyright information and
* how to reach the author.
*
* $Id: dvbapi.h 1.1 2000/02/19 13:36:48 kls Exp $
* $Id: dvbapi.h 1.2 2000/03/06 19:47:20 kls Exp $
*/
#ifndef __DVBAPI_H
#define __DVBAPI_H
const int DvbOsdCharWidth = 12; //XXX
const int DvbOsdLineHeight = 25;
// FIXME: these should be defined in ../DVB/driver/dvb.h!!!
typedef unsigned int u32;
typedef unsigned short u16;
typedef unsigned char u8;
#if defined(DEBUG_OSD) || defined(DEBUG_REMOTE)
#include <ncurses.h>
#endif
#include "../DVB/driver/dvb.h"
enum eDvbColor { clrBackground,
#ifndef DEBUG_OSD
clrOBSOLETE, //FIXME apparently color '1' can't be used as FgColor with e.g. clrRed as BgColor???
clrBlack,
#else
clrBlack = clrBackground,
#endif
clrRed,
clrGreen,
clrYellow,
clrBlue,
clrMagenta,
clrCyan,
clrWhite,
};
extern const char *DvbQuality; // Low, Medium, High
bool DvbSetChannel(int FrequencyMHz, char Polarization, int Diseqc, int Srate, int Vpid, int Apid);
class cDvbRecorder {
private:
bool recording;
public:
cDvbRecorder(void);
~cDvbRecorder();
bool Recording(void);
// Returns true if this recorder is currently recording, false if it
// is playing back or does nothing.
bool Record(const char *FileName, char Quality);
// Starts recording the current channel into the given file, with the
// given quality level. Any existing file will be overwritten.
@ -30,8 +58,9 @@ public:
bool Play(const char *FileName, int Frame = 0);
// Starts playback of the given file, at the optional Frame (default
// is the beginning of the file). If Frame is beyond the last recorded
// frame in the file, or if it is negative, playback will be positioned
// to the last frame in the file and will do an implicit Pause() there.
// frame in the file (or if it is negative), playback will be positioned
// to the last frame in the file (or the frame with the absolute value of
// Frame) and will do an implicit Pause() there.
// If there is already a playback session active, it will be stopped
// and the new file or frame (which may be in the same file) will
// be played back.
@ -56,10 +85,29 @@ public:
// The very first frame has the number 1.
};
void DvbOsdOpen(int x, int y, int w, int h);
void DvbOsdClose(void);
void DvbOsdClear(void);
void DvbOsdClrEol(int x, int y);
void DvbOsdText(int x, int y, char *s);
class cDvbOsd {
private:
enum { charWidth = 12, // average character width
lineHeight = 27 // smallest text height
};
#ifdef DEBUG_OSD
WINDOW *window;
enum { MaxColorPairs = 16 };
int colorPairs[MaxColorPairs];
void SetColor(eDvbColor colorFg, eDvbColor colorBg = clrBackground);
#else
void Cmd(OSD_Command cmd, int color = 0, int x0 = 0, int y0 = 0, int x1 = 0, int y1 = 0, const void *data = NULL);
#endif
int cols, rows;
public:
cDvbOsd(void);
~cDvbOsd();
void Open(int w, int h);
void Close(void);
void Clear(void);
void Fill(int x, int y, int w, int h, eDvbColor color = clrBackground);
void ClrEol(int x, int y, eDvbColor color = clrBackground);
void Text(int x, int y, const char *s, eDvbColor colorFg = clrWhite, eDvbColor colorBg = clrBackground);
};
#endif //__DVBAPI_H

View File

@ -4,20 +4,21 @@
* See the main source file 'osm.c' for copyright information and
* how to reach the author.
*
* $Id: interface.c 1.1 2000/02/19 13:36:48 kls Exp $
* $Id: interface.c 1.2 2000/03/06 19:45:03 kls Exp $
*/
#include "interface.h"
#include <ncurses.h>
#include <unistd.h>
#include "dvbapi.h"
#include "remote.h"
#define MenuLines 15
#define MenuColumns 40
#ifndef DEBUG_REMOTE
cRcIo RcIo("/dev/ttyS1");//XXX
#endif
WINDOW *window;
cDvbOsd DvbOsd; //XXX member of cInterface???
cInterface Interface;
@ -25,16 +26,6 @@ cInterface::cInterface(void)
{
open = 0;
cols[0] = 0;
#ifdef DEBUG_OSD
initscr();
keypad(stdscr, TRUE);
nonl();
cbreak();
noecho();
leaveok(stdscr, TRUE);
window = stdscr;
#else
#endif
}
void cInterface::Init(void)
@ -46,24 +37,14 @@ void cInterface::Init(void)
void cInterface::Open(void)
{
if (!open++) {
#ifdef DEBUG_OSD
#else
//TODO
DvbOsdOpen(100, 100, 500, 400);
#endif
}
if (!open++)
DvbOsd.Open(MenuColumns, MenuLines);
}
void cInterface::Close(void)
{
if (!--open) {
#ifdef DEBUG_OSD
#else
//TODO
DvbOsdClose();
#endif
}
if (!--open)
DvbOsd.Close();
}
unsigned int cInterface::GetCh(void)
@ -71,9 +52,9 @@ unsigned int cInterface::GetCh(void)
#ifdef DEBUG_REMOTE
return getch();
#else
#ifdef DEBUG_OSD
wrefresh(window);//XXX
#endif
//XXX #ifdef DEBUG_OSD
//XXX wrefresh(window);//XXX
//XXX #endif
unsigned int Command;
return RcIo.GetCommand(&Command) ? Command : 0;
#endif
@ -84,16 +65,28 @@ eKeys cInterface::GetKey(void)
return Keys.Get(GetCh());
}
eKeys cInterface::Wait(int Seconds)
{
int t0 = time_ms();
while (time_ms() - t0 < Seconds * 1000) {
eKeys Key = GetKey();
if (Key != kNone)
return Key;
}
return kNone;
}
void cInterface::Clear(void)
{
if (open) {
#ifdef DEBUG_OSD
wclear(window);
#else
//TODO
DvbOsdClear();
#endif
}
if (open)
DvbOsd.Clear();
}
void cInterface::ClearEol(int x, int y, eDvbColor Color)
{
if (open)
DvbOsd.ClrEol(x, y, Color);
}
void cInterface::SetCols(int *c)
@ -105,34 +98,22 @@ void cInterface::SetCols(int *c)
}
}
void cInterface::Write(int x, int y, char *s)
void cInterface::Write(int x, int y, const char *s, eDvbColor FgColor, eDvbColor BgColor)
{
if (open) {
#ifdef DEBUG_OSD
wmove(window, y, x); // ncurses wants 'y' before 'x'!
waddstr(window, s);
#else
DvbOsdText(x * DvbOsdCharWidth, y * DvbOsdLineHeight, s);
#endif
}
if (open)
DvbOsd.Text(x, y, s, FgColor, BgColor);
}
void cInterface::WriteText(int x, int y, char *s, bool Current)
void cInterface::WriteText(int x, int y, const char *s, bool Current)
{
if (open) {
#ifdef DEBUG_OSD
wmove(window, y, x); // ncurses wants 'y' before 'x'!
wclrtoeol(window);//XXX
#else
//TODO
DvbOsdClrEol(x * DvbOsdCharWidth, y);//XXX
#endif
Write(x, y, Current ? "*" : " ");
x++;
eDvbColor FgColor = Current ? clrBlack : clrWhite;
eDvbColor BgColor = Current ? clrCyan : clrBackground;
ClearEol(x, y, BgColor);
int col = 0;
for (;;) {
char *t = strchr(s, '\t');
char *p = s;
const char *t = strchr(s, '\t');
const char *p = s;
char buf[1000];
if (t && col < MaxCols && cols[col] > 0) {
unsigned int n = t - s;
@ -143,7 +124,7 @@ void cInterface::WriteText(int x, int y, char *s, bool Current)
p = buf;
s = t + 1;
}
Write(x, y, p);
Write(x, y, p, FgColor, BgColor);
if (p == s)
break;
x += cols[col++];
@ -151,38 +132,74 @@ void cInterface::WriteText(int x, int y, char *s, bool Current)
}
}
void cInterface::Info(char *s)
void cInterface::Title(const char *s)
{
int x = (MenuColumns - strlen(s)) / 2;
if (x < 0)
x = 0;
ClearEol(0, 0, clrCyan);
Write(x, 0, s, clrBlack, clrCyan);
}
void cInterface::Status(const char *s, eDvbColor FgColor, eDvbColor BgColor)
{
ClearEol(0, -3, s ? BgColor : clrBackground);
if (s)
Write(0, -3, s, FgColor, BgColor);
}
void cInterface::Info(const char *s)
{
Open();
isyslog(LOG_ERR, s);
WriteText(0, 11, s);//TODO
#ifdef DEBUG_OSD
wrefresh(window);//XXX
#endif
sleep(1);
WriteText(0, 11, "");//TODO
#ifdef DEBUG_OSD
wrefresh(window);//XXX
#endif
isyslog(LOG_INFO, s);
Status(s, clrWhite, clrGreen);
Wait();
Status(NULL);
Close();
}
void cInterface::Error(char *s)
void cInterface::Error(const char *s)
{
Open();
esyslog(LOG_ERR, s);
WriteText(0, 12, s);//TODO
#ifdef DEBUG_OSD
wrefresh(window);//XXX
#endif
sleep(1);
WriteText(0, 12, "");//TODO
#ifdef DEBUG_OSD
wrefresh(window);//XXX
#endif
Status(s, clrWhite, clrRed);
Wait();
Status(NULL);
Close();
}
bool cInterface::Confirm(const char *s)
{
Open();
isyslog(LOG_INFO, "confirm: %s", s);
Status(s, clrBlack, clrGreen);
bool result = Wait(10) == kOk;
Status(NULL);
Close();
isyslog(LOG_INFO, "%sconfirmed", result ? "" : "not ");
return result;
}
void cInterface::HelpButton(int Index, const char *Text, eDvbColor FgColor, eDvbColor BgColor)
{
if (open && Text) {
const int w = MenuColumns / 4;
int l = (w - strlen(Text)) / 2;
if (l < 0)
l = 0;
DvbOsd.Fill(Index * w, -1, w, 1, BgColor);
DvbOsd.Text(Index * w + l, -1, Text, FgColor, BgColor);
}
}
void cInterface::Help(const char *Red, const char *Green, const char *Yellow, const char *Blue)
{
HelpButton(0, Red, clrBlack, clrRed);
HelpButton(1, Green, clrBlack, clrGreen);
HelpButton(2, Yellow, clrBlack, clrYellow);
HelpButton(3, Blue, clrWhite, clrBlue);
}
void cInterface::QueryKeys(void)
{
Keys.Clear();
@ -205,8 +222,8 @@ void cInterface::QueryKeys(void)
WriteText(1, 5, "RC code detected!");
WriteText(1, 6, "Do not press any key...");
RcIo.Flush(3);
WriteText(1, 5, "");
WriteText(1, 6, "");
ClearEol(0, 5);
ClearEol(0, 6);
break;
}
#endif
@ -229,8 +246,8 @@ void cInterface::QueryKeys(void)
case kDown: if (k > Keys.keys + 1) {
WriteText(1, 5, "Press 'Up' to confirm");
WriteText(1, 6, "Press 'Down' to continue");
WriteText(1, 7, "");
WriteText(1, 8, "");
ClearEol(0, 7);
ClearEol(0, 8);
for (;;) {
eKeys key = GetKey();
if (key == kUp) {
@ -238,7 +255,7 @@ void cInterface::QueryKeys(void)
return;
}
else if (key == kDown) {
WriteText(1, 6, "");
ClearEol(0, 6);
break;
}
}
@ -255,17 +272,18 @@ void cInterface::QueryKeys(void)
if (k > Keys.keys)
WriteText(1, 7, "(press 'Up' to go back)");
else
WriteText(1, 7, "");
ClearEol(0, 7);
if (k > Keys.keys + 1)
WriteText(1, 8, "(press 'Down' to end key definition)");
else
WriteText(1, 8, "");
ClearEol(0, 8);
}
}
void cInterface::LearnKeys(void)
{
isyslog(LOG_INFO, "learning keys");
Open();
for (;;) {
Clear();
QueryKeys();
@ -277,19 +295,19 @@ void cInterface::LearnKeys(void)
eKeys key = GetKey();
if (key == kUp) {
Keys.Save();
Clear();
Close();
return;
}
else if (key == kDown) {
Keys.Load();
Clear();
Close();
return;
}
}
}
}
void cInterface::DisplayChannel(int Number, char *Name)
void cInterface::DisplayChannel(int Number, const char *Name)
{
//TODO
#ifndef DEBUG_REMOTE

View File

@ -4,13 +4,14 @@
* See the main source file 'osm.c' for copyright information and
* how to reach the author.
*
* $Id: interface.h 1.1 2000/02/19 13:36:48 kls Exp $
* $Id: interface.h 1.2 2000/02/27 14:54:02 kls Exp $
*/
#ifndef __INTERFACE_H
#define __INTERFACE_H
#include "config.h"
#include "dvbapi.h"
class cInterface {
public:
@ -20,7 +21,8 @@ private:
int cols[MaxCols];
unsigned int GetCh(void);
void QueryKeys(void);
void Write(int x, int y, char *s);
void HelpButton(int Index, const char *Text, eDvbColor FgColor, eDvbColor BgColor);
eKeys Wait(int Seconds = 1);
public:
cInterface(void);
void Init(void);
@ -28,12 +30,18 @@ public:
void Close(void);
eKeys GetKey(void);
void Clear(void);
void ClearEol(int x, int y, eDvbColor Color = clrBackground);
void SetCols(int *c);
void WriteText(int x, int y, char *s, bool Current = false);
void Info(char *s);
void Error(char *s);
void Write(int x, int y, const char *s, eDvbColor FgColor = clrWhite, eDvbColor BgColor = clrBackground);
void WriteText(int x, int y, const char *s, bool Current = false);
void Title(const char *s);
void Status(const char *s, eDvbColor FgColor = clrBlack, eDvbColor BgColor = clrCyan);
void Info(const char *s);
void Error(const char *s);
bool Confirm(const char *s);
void Help(const char *Red, const char *Green = NULL, const char *Yellow = NULL, const char *Blue = NULL);
void LearnKeys(void);
void DisplayChannel(int Number, char *Name);
void DisplayChannel(int Number, const char *Name);
};
extern cInterface Interface;

Binary file not shown.

View File

@ -17,3 +17,7 @@ Right 000045E2
7 00000FE2
8 000077E2
9 000037E2
Red 000025E2
Green 00002AE2
Yellow 00005AE2
Blue 00000000

454
menu.c
View File

@ -4,7 +4,7 @@
* See the main source file 'osm.c' for copyright information and
* how to reach the author.
*
* $Id: menu.c 1.1 2000/02/19 13:36:48 kls Exp $
* $Id: menu.c 1.2 2000/03/05 15:37:31 kls Exp $
*/
#include "menu.h"
@ -13,8 +13,9 @@
#include <string.h>
#include "config.h"
#include "dvbapi.h"
#include "recording.h"
const char *FileNameChars = "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz0123456789/-.# ";//TODO more?
const char *FileNameChars = "aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ0123456789-.# ";
// --- cMenuEditItem ---------------------------------------------------------
@ -59,7 +60,7 @@ protected:
virtual void Set(void);
public:
cMenuEditIntItem(const char *Name, int *Value, int Min = 0, int Max = INT_MAX);
virtual eOSStatus ProcessKey(eKeys Key);
virtual eOSState ProcessKey(eKeys Key);
};
cMenuEditIntItem::cMenuEditIntItem(const char *Name, int *Value, int Min, int Max)
@ -78,11 +79,11 @@ void cMenuEditIntItem::Set(void)
SetValue(buf);
}
eOSStatus cMenuEditIntItem::ProcessKey(eKeys Key)
eOSState cMenuEditIntItem::ProcessKey(eKeys Key)
{
eOSStatus status = cMenuEditItem::ProcessKey(Key);
eOSState state = cMenuEditItem::ProcessKey(Key);
if (status == osUnknown) {
if (state == osUnknown) {
int newValue;
if (k0 <= Key && Key <= k9) {
if (fresh) {
@ -100,14 +101,14 @@ eOSStatus cMenuEditIntItem::ProcessKey(eKeys Key)
fresh = true;
}
else
return status;
return state;
if ((!fresh || min <= newValue) && newValue <= max) {
*value = newValue;
Set();
}
status = osContinue;
state = osContinue;
}
return status;
return state;
}
// --- cMenuEditBoolItem -----------------------------------------------------
@ -167,7 +168,7 @@ protected:
virtual void Set(void);
public:
cMenuEditDayItem(const char *Name, int *Value);
virtual eOSStatus ProcessKey(eKeys Key);
virtual eOSState ProcessKey(eKeys Key);
};
int cMenuEditDayItem::days[] ={ cTimer::ParseDay("M------"),
@ -205,7 +206,7 @@ void cMenuEditDayItem::Set(void)
SetValue(cTimer::PrintDay(*value));
}
eOSStatus cMenuEditDayItem::ProcessKey(eKeys Key)
eOSState cMenuEditDayItem::ProcessKey(eKeys Key)
{
switch (Key) {
case kLeft: if (d > 0)
@ -252,7 +253,7 @@ protected:
virtual void Set(void);
public:
cMenuEditTimeItem(const char *Name, int *Value);
virtual eOSStatus ProcessKey(eKeys Key);
virtual eOSState ProcessKey(eKeys Key);
};
cMenuEditTimeItem::cMenuEditTimeItem(const char *Name, int *Value)
@ -272,11 +273,11 @@ void cMenuEditTimeItem::Set(void)
SetValue(buf);
}
eOSStatus cMenuEditTimeItem::ProcessKey(eKeys Key)
eOSState cMenuEditTimeItem::ProcessKey(eKeys Key)
{
eOSStatus status = cMenuEditItem::ProcessKey(Key);
eOSState state = cMenuEditItem::ProcessKey(Key);
if (status == osUnknown) {
if (state == osUnknown) {
if (k0 <= Key && Key <= k9) {
if (fresh || pos > 3) {
pos = 0;
@ -324,12 +325,12 @@ eOSStatus cMenuEditTimeItem::ProcessKey(eKeys Key)
fresh = true;
}
else
return status;
return state;
*value = hh * 100 + mm;
Set();
status = osContinue;
state = osContinue;
}
return status;
return state;
}
// --- cMenuEditChrItem ------------------------------------------------------
@ -343,7 +344,7 @@ private:
public:
cMenuEditChrItem(const char *Name, char *Value, const char *Allowed);
~cMenuEditChrItem();
virtual eOSStatus ProcessKey(eKeys Key);
virtual eOSState ProcessKey(eKeys Key);
};
cMenuEditChrItem::cMenuEditChrItem(const char *Name, char *Value, const char *Allowed)
@ -369,11 +370,11 @@ void cMenuEditChrItem::Set(void)
SetValue(buf);
}
eOSStatus cMenuEditChrItem::ProcessKey(eKeys Key)
eOSState cMenuEditChrItem::ProcessKey(eKeys Key)
{
eOSStatus status = cMenuEditItem::ProcessKey(Key);
eOSState state = cMenuEditItem::ProcessKey(Key);
if (status == osUnknown) {
if (state == osUnknown) {
if (Key == kLeft) {
if (current > allowed)
current--;
@ -383,12 +384,12 @@ eOSStatus cMenuEditChrItem::ProcessKey(eKeys Key)
current++;
}
else
return status;
return state;
*value = *current;
Set();
status = osContinue;
state = osContinue;
}
return status;
return state;
}
// --- cMenuEditStrItem ------------------------------------------------------
@ -404,7 +405,7 @@ private:
public:
cMenuEditStrItem(const char *Name, char *Value, int Length, const char *Allowed);
~cMenuEditStrItem();
virtual eOSStatus ProcessKey(eKeys Key);
virtual eOSState ProcessKey(eKeys Key);
};
cMenuEditStrItem::cMenuEditStrItem(const char *Name, char *Value, int Length, const char *Allowed)
@ -449,7 +450,7 @@ char cMenuEditStrItem::Inc(char c, bool Up)
return *p;
}
eOSStatus cMenuEditStrItem::ProcessKey(eKeys Key)
eOSState cMenuEditStrItem::ProcessKey(eKeys Key)
{
switch (Key) {
case kLeft: if (pos > 0) {
@ -492,11 +493,11 @@ private:
cChannel data;
public:
cMenuEditChannel(int Index);
virtual eOSStatus ProcessKey(eKeys Key);
virtual eOSState ProcessKey(eKeys Key);
};
cMenuEditChannel::cMenuEditChannel(int Index)
:cOsdMenu("Edit channel", 14)
:cOsdMenu("Edit Channel", 14)
{
channel = Channels.Get(Index);
if (channel) {
@ -511,19 +512,19 @@ cMenuEditChannel::cMenuEditChannel(int Index)
}
}
eOSStatus cMenuEditChannel::ProcessKey(eKeys Key)
eOSState cMenuEditChannel::ProcessKey(eKeys Key)
{
eOSStatus status = cOsdMenu::ProcessKey(Key);
eOSState state = cOsdMenu::ProcessKey(Key);
if (status == osUnknown) {
if (state == osUnknown) {
if (Key == kOk) {
if (channel)
*channel = data;
Channels.Save();
status = osBack;
state = osBack;
}
}
return status;
return state;
}
// --- cMenuChannelItem ------------------------------------------------------
@ -535,6 +536,7 @@ private:
public:
cMenuChannelItem(int Index, cChannel *Channel);
virtual void Set(void);
void SetIndex(int Index);
};
cMenuChannelItem::cMenuChannelItem(int Index, cChannel *Channel)
@ -551,12 +553,24 @@ void cMenuChannelItem::Set(void)
SetText(buffer, false);
}
void cMenuChannelItem::SetIndex(int Index)
{
index = Index;
Set();
}
// --- cMenuChannels ---------------------------------------------------------
class cMenuChannels : public cOsdMenu {
protected:
eOSState Switch(void);
eOSState Edit(void);
eOSState New(void);
eOSState Del(void);
virtual void Move(int From, int To);
public:
cMenuChannels(void);
virtual eOSStatus ProcessKey(eKeys Key);
virtual eOSState ProcessKey(eKeys Key);
};
cMenuChannels::cMenuChannels(void)
@ -570,26 +584,124 @@ cMenuChannels::cMenuChannels(void)
Add(new cMenuChannelItem(i, channel), i == CurrentChannel);
i++;
}
SetHelp("Edit", "New", "Delete", "Mark");
}
eOSStatus cMenuChannels::ProcessKey(eKeys Key)
eOSState cMenuChannels::Switch(void)
{
eOSStatus status = cOsdMenu::ProcessKey(Key);
cChannel *ch = Channels.Get(Current());
if (ch)
ch->Switch();
return osEnd;
}
if (status == osUnknown) {
eOSState cMenuChannels::Edit(void)
{
if (HasSubMenu() || Count() == 0)
return osContinue;
isyslog(LOG_INFO, "editing timer %d", Current() + 1);
return AddSubMenu(new cMenuEditChannel(Current()));
}
eOSState cMenuChannels::New(void)
{
if (HasSubMenu())
return osContinue;
cChannel *channel = new cChannel(Channels.Get(Current()));
Channels.Add(channel);
Add(new cMenuChannelItem(channel->Index()/*XXX*/, channel), true);
Channels.Save();
isyslog(LOG_INFO, "channel %d added", channel->Index() + 1);
return AddSubMenu(new cMenuEditChannel(Current()));
}
eOSState cMenuChannels::Del(void)
{
if (Count() > 0) {
int Index = Current();
// Check if there is a timer using this channel:
for (cTimer *ti = Timers.First(); ti; ti = (cTimer *)ti->Next()) {
if (ti->channel == Index + 1) {
Interface.Error("Channel is being used by a timer!");
return osContinue;
}
}
if (Interface.Confirm("Delete Channel?")) {
// Move and renumber the channels:
Channels.Del(Channels.Get(Index));
cOsdMenu::Del(Index);
int i = 0;
for (cMenuChannelItem *ci = (cMenuChannelItem *)First(); ci; ci = (cMenuChannelItem *)ci->Next())
ci->SetIndex(i++);
Channels.Save();
isyslog(LOG_INFO, "channel %d deleted", Index + 1);
// Fix the timers:
bool TimersModified = false;
Index++; // user visible channel numbers start with '1'
for (cTimer *ti = Timers.First(); ti; ti = (cTimer *)ti->Next()) {
int OldChannel = ti->channel;
if (ti->channel > Index)
ti->channel--;
if (ti->channel != OldChannel) {
TimersModified = true;
isyslog(LOG_INFO, "timer %d: channel changed from %d to %d", ti->Index() + 1, OldChannel, ti->channel);
}
}
if (TimersModified)
Timers.Save();
Display();
}
}
return osContinue;
}
void cMenuChannels::Move(int From, int To)
{
// Move and renumber the channels:
Channels.Move(From, To);
cOsdMenu::Move(From, To);
int i = 0;
for (cMenuChannelItem *ci = (cMenuChannelItem *)First(); ci; ci = (cMenuChannelItem *)ci->Next())
ci->SetIndex(i++);
Channels.Save();
isyslog(LOG_INFO, "channel %d moved to %d", From + 1, To + 1);
// Fix the timers:
bool TimersModified = false;
From++; // user visible channel numbers start with '1'
To++;
for (cTimer *ti = Timers.First(); ti; ti = (cTimer *)ti->Next()) {
int OldChannel = ti->channel;
if (ti->channel == From)
ti->channel = To;
else if (ti->channel > From && ti->channel <= To)
ti->channel--;
else if (ti->channel < From && ti->channel >= To)
ti->channel++;
if (ti->channel != OldChannel) {
TimersModified = true;
isyslog(LOG_INFO, "timer %d: channel changed from %d to %d", ti->Index() + 1, OldChannel, ti->channel);
}
}
if (TimersModified)
Timers.Save();
Display();
}
eOSState cMenuChannels::ProcessKey(eKeys Key)
{
eOSState state = cOsdMenu::ProcessKey(Key);
if (state == osUnknown) {
switch (Key) {
//TODO need to block this if we are already editing a channel!
case kRight: return AddSubMenu(new cMenuEditChannel(Current()));
case kOk: {
cChannel *ch = Channels.Get(Current());
if (ch)
ch->Switch();
return osEnd;
}
case kOk: return Switch();
case kRed: return Edit();
case kGreen: return New();
case kYellow: return Del();
case kBlue: Mark(); break;
default: break;
}
}
return status;
return state;
}
// --- cMenuEditTimer --------------------------------------------------------
@ -600,11 +712,11 @@ private:
cTimer data;
public:
cMenuEditTimer(int Index);
virtual eOSStatus ProcessKey(eKeys Key);
virtual eOSState ProcessKey(eKeys Key);
};
cMenuEditTimer::cMenuEditTimer(int Index)
:cOsdMenu("Edit timer", 10)
:cOsdMenu("Edit Timer", 10)
{
timer = Timers.Get(Index);
if (timer) {
@ -622,21 +734,23 @@ cMenuEditTimer::cMenuEditTimer(int Index)
}
}
eOSStatus cMenuEditTimer::ProcessKey(eKeys Key)
eOSState cMenuEditTimer::ProcessKey(eKeys Key)
{
eOSStatus status = cOsdMenu::ProcessKey(Key);
eOSState state = cOsdMenu::ProcessKey(Key);
if (status == osUnknown) {
if (state == osUnknown) {
if (Key == kOk) {
if (!*data.file)
strcpy(data.file, "unnamed");
if (timer && memcmp(timer, &data, sizeof(data)) != 0) {
*timer = data;
Timers.Save();
isyslog(LOG_INFO, "timer %d modified (%s)", timer->Index() + 1, timer->active ? "active" : "inactive");
}
status = osBack;
state = osBack;
}
}
return status;
return state;
}
// --- cMenuTimerItem --------------------------------------------------------
@ -660,27 +774,34 @@ cMenuTimerItem::cMenuTimerItem(int Index, cTimer *Timer)
void cMenuTimerItem::Set(void)
{
char *buffer = NULL;
asprintf(&buffer, "%d\t%c\t%d\t%s\t%02d:%02d\t%02d:%02d", index + 1,
asprintf(&buffer, "%c\t%d\t%s\t%02d:%02d\t%02d:%02d\t%s",
timer->active ? '>' : ' ',
timer->channel,
timer->PrintDay(timer->day),
timer->start / 100,
timer->start % 100,
timer->stop / 100,
timer->stop % 100); // user visible timer numbers start with '1'
timer->stop % 100,
timer->file);
SetText(buffer, false);
}
// --- cMenuTimer ------------------------------------------------------------
// --- cMenuTimers -----------------------------------------------------------
class cMenuTimer : public cOsdMenu {
class cMenuTimers : public cOsdMenu {
private:
eOSState Activate(bool On);
eOSState Edit(void);
eOSState New(void);
eOSState Del(void);
virtual void Move(int From, int To);
public:
cMenuTimer(void);
virtual eOSStatus ProcessKey(eKeys Key);
cMenuTimers(void);
virtual eOSState ProcessKey(eKeys Key);
};
cMenuTimer::cMenuTimer(void)
:cOsdMenu("Timer", 3, 2, 4, 10, 6)
cMenuTimers::cMenuTimers(void)
:cOsdMenu("Timer", 2, 4, 10, 6, 6)
{
int i = 0;
cTimer *timer;
@ -689,34 +810,190 @@ cMenuTimer::cMenuTimer(void)
Add(new cMenuTimerItem(i, timer));
i++;
}
SetHelp("Edit", "New", "Delete", "Mark");
}
eOSStatus cMenuTimer::ProcessKey(eKeys Key)
eOSState cMenuTimers::Activate(bool On)
{
eOSStatus status = cOsdMenu::ProcessKey(Key);
cTimer *timer = Timers.Get(Current());
if (timer && timer->active != On) {
timer->active = On;
RefreshCurrent();
DisplayCurrent(true);
isyslog(LOG_INFO, "timer %d %sactivated", timer->Index() + 1, timer->active ? "" : "de");
Timers.Save();
}
return osContinue;
}
if (status == osUnknown) {
eOSState cMenuTimers::Edit(void)
{
if (HasSubMenu() || Count() == 0)
return osContinue;
isyslog(LOG_INFO, "editing timer %d", Current() + 1);
return AddSubMenu(new cMenuEditTimer(Current()));
}
eOSState cMenuTimers::New(void)
{
if (HasSubMenu())
return osContinue;
cTimer *timer = new cTimer;
Timers.Add(timer);
Add(new cMenuTimerItem(timer->Index()/*XXX*/, timer), true);
Timers.Save();
isyslog(LOG_INFO, "timer %d added", timer->Index() + 1);
return AddSubMenu(new cMenuEditTimer(Current()));
}
eOSState cMenuTimers::Del(void)
{
// Check if this timer is active:
int Index = Current();
cTimer *ti = Timers.Get(Index);
if (ti) {
if (!ti->recording) {
if (Interface.Confirm("Delete Timer?")) {
Timers.Del(Timers.Get(Index));
cOsdMenu::Del(Index);
Timers.Save();
Display();
isyslog(LOG_INFO, "timer %d deleted", Index + 1);
}
}
else
Interface.Error("Timer is recording!");
}
return osContinue;
}
void cMenuTimers::Move(int From, int To)
{
Timers.Move(From, To);
cOsdMenu::Move(From, To);
Timers.Save();
Display();
isyslog(LOG_INFO, "timer %d moved to %d", From + 1, To + 1);
}
eOSState cMenuTimers::ProcessKey(eKeys Key)
{
eOSState state = cOsdMenu::ProcessKey(Key);
if (state == osUnknown) {
switch (Key) {
//TODO need to block this if we are already editing a channel!
case kOk: return AddSubMenu(new cMenuEditTimer(Current()));
//TODO new timer
//TODO delete timer
case kLeft:
case kRight:
{
cTimer *timer = Timers.Get(Current());
if (timer) {
timer->active = (Key == kRight);
isyslog(LOG_INFO, "timer %d %sactivated", timer->Index() + 1, timer->active ? "" : "de");
RefreshCurrent();
DisplayCurrent(true);
Timers.Save();
}
}
case kRight: return Activate(Key == kRight);
case kOk:
case kRed: return Edit();
case kGreen: return New();
case kYellow: return Del();
case kBlue: Mark(); break;
default: break;
}
}
return status;
return state;
}
// --- cMenuRecordingItem ----------------------------------------------------
class cMenuRecordingItem : public cOsdItem {
public:
cRecording *recording;
cMenuRecordingItem(cRecording *Recording);
virtual void Set(void);
};
cMenuRecordingItem::cMenuRecordingItem(cRecording *Recording)
{
recording = Recording;
Set();
}
void cMenuRecordingItem::Set(void)
{
char *buffer = NULL;
struct tm *t = localtime(&recording->start);
asprintf(&buffer, "%02d.%02d.%04d\t%02d:%02d\t%s",
t->tm_mday,
t->tm_mon + 1,
t->tm_year + 1900,
t->tm_hour,
t->tm_min,
recording->name);
SetText(buffer, false);
}
// --- cMenuRecordings -------------------------------------------------------
class cMenuRecordings : public cOsdMenu {
private:
cRecordings Recordings;
eOSState Play(void);
eOSState Del(void);
public:
cMenuRecordings(void);
virtual eOSState ProcessKey(eKeys Key);
};
cMenuRecordings::cMenuRecordings(void)
:cOsdMenu("Recordings", 11, 6)
{
if (Recordings.Load()) {
cRecording *recording = Recordings.First();
while (recording) {
Add(new cMenuRecordingItem(recording));
recording = Recordings.Next(recording);
}
}
SetHelp("Play", NULL/*XXX"Resume"*/, "Delete");
}
eOSState cMenuRecordings::Play(void)
{
cMenuRecordingItem *ri = (cMenuRecordingItem *)Get(Current());
if (ri) {
//XXX what if this recording's file is currently in use???
if (ri->recording->Play())
return osEnd;
}
return osContinue;
}
eOSState cMenuRecordings::Del(void)
{
cMenuRecordingItem *ri = (cMenuRecordingItem *)Get(Current());
if (ri) {
//XXX what if this recording's file is currently in use???
//XXX if (!ti->recording) {
if (Interface.Confirm("Delete Recording?")) {
if (ri->recording->Delete()) {
cOsdMenu::Del(Current());
Display();
}
else
Interface.Error("Error while deleting recording!");
}
//XXX }
//XXX else
//XXX Interface.Error("Timer is recording!");
}
return osContinue;
}
eOSState cMenuRecordings::ProcessKey(eKeys Key)
{
eOSState state = cOsdMenu::ProcessKey(Key);
if (state == osUnknown) {
switch (Key) {
case kOk:
case kRed: return Play();
case kYellow: return Del();
default: break;
}
}
return state;
}
// --- cMenuMain -------------------------------------------------------------
@ -724,22 +1001,21 @@ eOSStatus cMenuTimer::ProcessKey(eKeys Key)
cMenuMain::cMenuMain(void)
:cOsdMenu("Main")
{
//TODO
Add(new cOsdItem("Channels", osChannels));
Add(new cOsdItem("Timer", osTimer));
Add(new cOsdItem("Recordings", osRecordings));
}
eOSStatus cMenuMain::ProcessKey(eKeys Key)
eOSState cMenuMain::ProcessKey(eKeys Key)
{
eOSStatus status = cOsdMenu::ProcessKey(Key);
eOSState state = cOsdMenu::ProcessKey(Key);
switch (status) {
case osChannels: return AddSubMenu(new cMenuChannels);
case osTimer: return AddSubMenu(new cMenuTimer);
//TODO Replay
switch (state) {
case osChannels: return AddSubMenu(new cMenuChannels);
case osTimer: return AddSubMenu(new cMenuTimers);
case osRecordings: return AddSubMenu(new cMenuRecordings);
default: break;
}
return status;
return state;
}

4
menu.h
View File

@ -4,7 +4,7 @@
* See the main source file 'osm.c' for copyright information and
* how to reach the author.
*
* $Id: menu.h 1.1 2000/02/19 13:36:48 kls Exp $
* $Id: menu.h 1.2 2000/03/05 10:57:27 kls Exp $
*/
#ifndef _MENU_H
@ -15,7 +15,7 @@
class cMenuMain : public cOsdMenu {
public:
cMenuMain(void);
virtual eOSStatus ProcessKey(eKeys Key);
virtual eOSState ProcessKey(eKeys Key);
};
#endif //_MENU_H

131
osd.c
View File

@ -4,7 +4,7 @@
* See the main source file 'osm.c' for copyright information and
* how to reach the author.
*
* $Id: osd.c 1.1 2000/02/19 13:36:48 kls Exp $
* $Id: osd.c 1.2 2000/02/27 17:23:07 kls Exp $
*/
#include "osd.h"
@ -13,19 +13,19 @@
// --- cOsdItem --------------------------------------------------------------
cOsdItem::cOsdItem(eOSStatus Status)
cOsdItem::cOsdItem(eOSState State)
{
text = NULL;
offset = -1;
status = Status;
state = State;
fresh = false;
}
cOsdItem::cOsdItem(char *Text, eOSStatus Status)
cOsdItem::cOsdItem(char *Text, eOSState State)
{
text = NULL;
offset = -1;
status = Status;
state = State;
fresh = false;
SetText(Text);
}
@ -52,24 +52,27 @@ void cOsdItem::Display(int Offset, bool Current)
Interface.WriteText(0, offset + 2, text, Current);
}
eOSStatus cOsdItem::ProcessKey(eKeys Key)
eOSState cOsdItem::ProcessKey(eKeys Key)
{
return Key == kOk ? status : osUnknown;
return Key == kOk ? state : osUnknown;
}
// --- cOsdMenu --------------------------------------------------------------
cOsdMenu::cOsdMenu(char *Title, int c0, int c1, int c2, int c3, int c4)
{
visible = false;
title = strdup(Title);
cols[0] = c0;
cols[1] = c1;
cols[2] = c2;
cols[3] = c3;
cols[4] = c4;
first = count = 0;
current = -1;
first = 0;
current = marked = -1;
subMenu = NULL;
helpRed = helpGreen = helpYellow = helpBlue = NULL;
status = NULL;
Interface.Open();
}
@ -77,40 +80,72 @@ cOsdMenu::~cOsdMenu()
{
delete title;
delete subMenu;
delete status;
Interface.Clear();
Interface.Close();
}
void cOsdMenu::SetStatus(const char *s)
{
delete status;
status = s ? strdup(s) : NULL;
if (visible)
Interface.Status(status);
}
void cOsdMenu::SetHelp(const char *Red, const char *Green, const char *Yellow, const char *Blue)
{
// strings are NOT copied - must be constants!!!
helpRed = Red;
helpGreen = Green;
helpYellow = Yellow;
helpBlue = Blue;
}
void cOsdMenu::Del(int Index)
{
cList<cOsdItem>::Del(Get(Index));
if (current == Count())
current--;
if (Index == first && first > 0)
first--;
}
void cOsdMenu::Add(cOsdItem *Item, bool Current)
{
cList<cOsdItem>::Add(Item);
count++;
if (Current && current < 0)
if (Current)
current = Item->Index();
}
void cOsdMenu::Display(void)
{
visible = true;
Interface.Clear();
Interface.SetCols(cols);
Interface.WriteText(0, 0, title);
if (current < 0 && count)
current = 0; // just for safety - there HAS to be a current item!
int n = 0;
if (current - first >= MAXOSDITEMS) {
first = current - MAXOSDITEMS / 2;
if (first + MAXOSDITEMS > count)
first = count - MAXOSDITEMS;
if (first < 0)
first = 0;
Interface.Title(title);
Interface.Help(helpRed, helpGreen, helpYellow, helpBlue);
int count = Count();
if (count > 0) {
if (current < 0)
current = 0; // just for safety - there HAS to be a current item!
int n = 0;
if (current - first >= MAXOSDITEMS) {
first = current - MAXOSDITEMS / 2;
if (first + MAXOSDITEMS > count)
first = count - MAXOSDITEMS;
if (first < 0)
first = 0;
}
for (int i = first; i < count; i++) {
cOsdItem *item = Get(i);
if (item)
item->Display(i - first, i == current);
if (++n == MAXOSDITEMS) //TODO get this from Interface!!!
break;
}
}
for (int i = first; i < count; i++) {
cOsdItem *item = Get(i);
if (item)
item->Display(i - first, i == current);
if (++n == MAXOSDITEMS) //TODO get this from Interface!!!
break;
}
Interface.Status(status);
}
void cOsdMenu::RefreshCurrent(void)
@ -144,6 +179,7 @@ void cOsdMenu::CursorUp(void)
void cOsdMenu::CursorDown(void)
{
int count = Count();
if (current < count - 1) {
DisplayCurrent(false);
if (++current >= first + MAXOSDITEMS) {
@ -157,7 +193,15 @@ void cOsdMenu::CursorDown(void)
}
}
eOSStatus cOsdMenu::AddSubMenu(cOsdMenu *SubMenu)
void cOsdMenu::Mark(void)
{
if (Count() && marked < 0) {
marked = current;
SetStatus("Up/Dn for new location - OK to move");
}
}
eOSState cOsdMenu::AddSubMenu(cOsdMenu *SubMenu)
{
delete subMenu;
subMenu = SubMenu;
@ -165,31 +209,40 @@ eOSStatus cOsdMenu::AddSubMenu(cOsdMenu *SubMenu)
return osContinue; // convenience return value (see cMenuMain)
}
eOSStatus cOsdMenu::ProcessKey(eKeys Key)
eOSState cOsdMenu::ProcessKey(eKeys Key)
{
if (subMenu) {
eOSStatus status = subMenu->ProcessKey(Key);
if (status == osBack) {
eOSState state = subMenu->ProcessKey(Key);
if (state == osBack) {
delete subMenu;
subMenu = NULL;
RefreshCurrent();
Display();
status = osContinue;
state = osContinue;
}
return status;
return state;
}
cOsdItem *item = Get(current);
if (item) {
eOSStatus status = item->ProcessKey(Key);
if (status != osUnknown)
return status;
if (marked < 0 && item) {
eOSState state = item->ProcessKey(Key);
if (state != osUnknown)
return state;
}
switch (Key) {
case kUp: CursorUp(); break;
case kDown: CursorDown(); break;
case kBack: return osBack;
default: return osUnknown;
case kOk: if (marked >= 0) {
SetStatus(NULL);
if (marked != current)
Move(marked, current);
marked = -1;
break;
}
// else run into default
default: if (marked < 0)
return osUnknown;
}
return osContinue;
}

42
osd.h
View File

@ -4,7 +4,7 @@
* See the main source file 'osm.c' for copyright information and
* how to reach the author.
*
* $Id: osd.h 1.1 2000/02/19 13:36:48 kls Exp $
* $Id: osd.h 1.2 2000/03/05 11:33:11 kls Exp $
*/
#ifndef __OSD_H
@ -16,53 +16,61 @@
#define MAXOSDITEMS 9
enum eOSStatus { osUnknown,
osContinue,
osProcessed,
osChannels,
osTimer,
osRecordings,
osBack,
osEnd,
};
enum eOSState { osUnknown,
osContinue,
osProcessed,
osChannels,
osTimer,
osRecordings,
osBack,
osEnd,
};
class cOsdItem : public cListObject {
private:
char *text;
int offset;
eOSStatus status;
eOSState state;
protected:
bool fresh;
public:
cOsdItem(eOSStatus Status = osUnknown);
cOsdItem(char *Text, eOSStatus Status = osUnknown);
cOsdItem(eOSState State = osUnknown);
cOsdItem(char *Text, eOSState State = osUnknown);
virtual ~cOsdItem();
void SetText(char *Text, bool Copy = true);
char *Text(void) { return text; }
void Display(int Offset = -1, bool Current = false);
virtual void Set(void) {}
virtual eOSStatus ProcessKey(eKeys Key);
virtual eOSState ProcessKey(eKeys Key);
};
class cOsdMenu : public cList<cOsdItem> {
private:
char *title;
int cols[cInterface::MaxCols];
int first, current, count;
int first, current, marked;
cOsdMenu *subMenu;
const char *helpRed, *helpGreen, *helpYellow, *helpBlue;
const char *status;
protected:
bool visible;
void RefreshCurrent(void);
void DisplayCurrent(bool Current);
void CursorUp(void);
void CursorDown(void);
eOSStatus AddSubMenu(cOsdMenu *SubMenu);
void Mark(void);
eOSState AddSubMenu(cOsdMenu *SubMenu);
bool HasSubMenu(void) { return subMenu; }
void SetStatus(const char *s);
void SetHelp(const char *Red, const char *Green = NULL, const char *Yellow = NULL, const char *Blue = NULL);
virtual void Del(int Index);
public:
cOsdMenu(char *Title, int c0 = 0, int c1 = 0, int c2 = 0, int c3 = 0, int c4 = 0);
virtual ~cOsdMenu();
int Current(void) { return current; }
void Add(cOsdItem *Item, bool Current = false);
void Display(void);
virtual eOSStatus ProcessKey(eKeys Key);
virtual eOSState ProcessKey(eKeys Key);
};
#endif //__OSD_H

57
osm.c
View File

@ -22,13 +22,13 @@
*
* The project's page is at http://www.cadsoft.de/people/kls/vdr
*
* $Id: osm.c 1.1 2000/02/19 13:36:48 kls Exp $
* $Id: osm.c 1.2 2000/03/05 17:18:15 kls Exp $
*/
#include "config.h"
#include "dvbapi.h"
#include "interface.h"
#include "menu.h"
#include "recording.h"
#include "tools.h"
#ifdef DEBUG_REMOTE
@ -52,39 +52,39 @@ int main(int argc, char *argv[])
cMenuMain *Menu = NULL;
cTimer *Timer = NULL;
cDvbRecorder *Recorder = NULL;
cRecording *Recording = NULL;
for (;;) {
//TODO check for free disk space and delete files if necessary/possible
// in case there is an ongoing recording
if (!Timer && (Timer = cTimer::GetMatch()) != NULL) {
AssertFreeDiskSpace();
if (!Recording && !Timer && (Timer = cTimer::GetMatch()) != NULL) {
DELETENULL(Menu);
// make sure the timer won't be deleted:
Timer->SetRecording(true);
// switch to channel:
isyslog(LOG_INFO, "timer %d start", Timer->Index() + 1);
delete Menu;
Menu = NULL;
cChannel::SwitchTo(Timer->channel - 1);
ChannelLocked = true;
// start recording:
delete Recorder;
Recorder = new cDvbRecorder;
//TODO special filename handling!!!
if (!Recorder->Record(Timer->file, Timer->quality)) {
delete Recorder;
Recorder = NULL;
}
Recording = new cRecording(Timer);
if (!Recording->Record())
DELETENULL(Recording);
}
if (Timer) {
if (!Timer->Matches()) {
// stop recording:
if (Recorder)
Recorder->Stop();
// end timer:
ChannelLocked = false;
isyslog(LOG_INFO, "timer %d stop", Timer->Index() + 1);
Timer = NULL;
//TODO switch back to the previous channel???
//TODO clear single event timer???
if (Timer && !Timer->Matches()) {
// stop recording:
if (Recording) {
Recording->Stop();
DELETENULL(Recording);
}
// release channel and timer:
ChannelLocked = false;
Timer->SetRecording(false);
// clear single event timer:
if (Timer->IsSingleEvent()) {
DELETENULL(Menu); // must make sure no menu uses it
isyslog(LOG_INFO, "deleting timer %d", Timer->Index() + 1);
Timers.Del(Timer);
Timers.Save();
}
Timer = NULL;
}
eKeys key = Interface.GetKey();
if (Menu) {
@ -92,8 +92,7 @@ int main(int argc, char *argv[])
default: if (key != kMenu)
break;
case osBack:
case osEnd: delete Menu;
Menu = NULL;
case osEnd: DELETENULL(Menu);
break;
}
}

238
recording.c Normal file
View File

@ -0,0 +1,238 @@
/*
* recording.h: Recording file handling
*
* See the main source file 'osm.c' for copyright information and
* how to reach the author.
*
* $Id: recording.c 1.1 2000/03/05 17:16:22 kls Exp $
*/
#include "recording.h"
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include "interface.h"
#include "tools.h"
#define RECEXT ".rec"
#define DELEXT ".del"
#define DATAFORMAT "%4d-%02d-%02d.%02d:%02d.%c.%02d.%02d" RECEXT
#define NAMEFORMAT "%s/%s/" DATAFORMAT
#define FINDCMD "find %s -type f -name '%s'"
#define DFCMD "df -m %s"
#define MINDISKSPACE 1024 // MB
const char *BaseDir = "/video";//XXX
cDvbRecorder *Recorder = NULL;
static bool LowDiskSpace(void)
{
//TODO Find a simpler way to determine the amount of free disk space!
bool result = true;
char *cmd = NULL;
asprintf(&cmd, DFCMD, BaseDir);
FILE *p = popen(cmd, "r");
if (p) {
char *s;
while ((s = readline(p)) != NULL) {
if (*s == '/') {
int available;
sscanf(s, "%*s %*d %*d %d", &available);
result = available < MINDISKSPACE;
break;
}
}
pclose(p);
}
else
esyslog(LOG_ERR, "ERROR: can't open pipe for cmd '%s'", cmd);
delete cmd;
return result;
}
void AssertFreeDiskSpace(void)
{
// With every call to this function we try to actually remove
// a file, or mark a file for removal ("delete" it), so that
// it will get removed during the next call.
if (Recorder && Recorder->Recording() && LowDiskSpace()) {
// Remove the oldest file that has been "deleted":
cRecordings Recordings;
if (Recordings.Load(true)) {
cRecording *r = Recordings.First();
cRecording *r0 = r;
while (r) {
if (r->start < r0->start)
r0 = r;
r = Recordings.Next(r);
}
if (r0 && r0->Remove())
return;
}
// No "deleted" files to remove, so let's see if we can delete a recording:
if (Recordings.Load(false)) {
cRecording *r = Recordings.First();
cRecording *r0 = NULL;
while (r) {
if ((time(NULL) - r->start) / SECSINDAY > r->lifetime) {
if (r0) {
if (r->priority < r0->priority)
r0 = r;
}
else
r0 = r;
}
r = Recordings.Next(r);
}
if (r0 && r0->Delete())
return;
}
// Unable to free disk space, but there's nothing we can do about that...
//TODO maybe a log entry - but make sure it doesn't come too often
}
}
// --- cRecording ------------------------------------------------------------
cRecording::cRecording(const char *Name, time_t Start, char Quality, int Priority, int LifeTime)
{
fileName = NULL;
name = strdup(Name);
start = Start;
quality = Quality;
priority = Priority;
lifetime = LifeTime;
}
cRecording::cRecording(cTimer *Timer)
{
fileName = NULL;
name = strdup(Timer->file);
start = Timer->StartTime();
quality = Timer->quality;
priority = Timer->priority;
lifetime = Timer->lifetime;
}
cRecording::cRecording(const char *FileName)
{
fileName = strdup(FileName);
FileName += strlen(BaseDir) + 1;
char *p = strrchr(FileName, '/');
name = NULL;
if (p) {
time_t now = time(NULL);
struct tm t = *localtime(&now); // this initializes the time zone in 't'
if (8 == sscanf(p + 1, DATAFORMAT, &t.tm_year, &t.tm_mon, &t.tm_mday, &t.tm_hour, &t.tm_min, &quality, &priority, &lifetime)) {
t.tm_year -= 1900;
t.tm_mon--;
t.tm_sec = 0;
start = mktime(&t);
name = new char[p - FileName + 1];
strncpy(name, FileName, p - FileName);
name[p - FileName] = 0;
}
}
}
cRecording::~cRecording()
{
delete fileName;
delete name;
}
const char *cRecording::FileName(void)
{
if (!fileName) {
struct tm *t = localtime(&start);
asprintf(&fileName, NAMEFORMAT, BaseDir, name, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, quality, priority, lifetime);
}
return fileName;
}
bool cRecording::Delete(void)
{
bool result = true;
char *NewName = strdup(FileName());
char *ext = strrchr(NewName, '.');
if (strcmp(ext, RECEXT) == 0) {
strncpy(ext, DELEXT, strlen(ext));
isyslog(LOG_INFO, "deleting recording %s", FileName());
if (rename(FileName(), NewName) == -1) {
esyslog(LOG_ERR, "ERROR: %s", strerror(errno));
result = false;
}
}
delete NewName;
return result;
}
bool cRecording::Remove(void)
{
bool result = true;
isyslog(LOG_INFO, "removing recording %s", FileName());
if (remove(FileName()) == -1) {
esyslog(LOG_ERR, "ERROR: %s", strerror(errno));
result = false;
}
return result;
}
bool cRecording::AssertRecorder(void)
{
if (!Recorder || !Recorder->Recording()) {
if (!Recorder)
Recorder = new cDvbRecorder;
return true;
}
Interface.Error("Recorder is in use!");
return false;
}
bool cRecording::Record(void)
{
return AssertRecorder() && Recorder->Record(FileName(), quality);
}
bool cRecording::Play(void)
{
return AssertRecorder() && Recorder->Play(FileName());
}
void cRecording::Stop(void)
{
if (Recorder)
Recorder->Stop();
}
// --- cRecordings -----------------------------------------------------------
bool cRecordings::Load(bool Deleted)
{
Clear();
bool result = false;
char *cmd = NULL;
asprintf(&cmd, FINDCMD, BaseDir, Deleted ? "*" DELEXT : "*" RECEXT);
FILE *p = popen(cmd, "r");
if (p) {
char *s;
while ((s = readline(p)) != NULL) {
cRecording *r = new cRecording(s);
if (r->name)
Add(r);
else
delete r;
}
pclose(p);
result = Count() > 0;
}
else
Interface.Error("Error while opening pipe!");
delete cmd;
return result;
}

56
recording.h Normal file
View File

@ -0,0 +1,56 @@
/*
* recording.h: Recording file handling
*
* See the main source file 'osm.c' for copyright information and
* how to reach the author.
*
* $Id: recording.h 1.1 2000/03/05 15:57:27 kls Exp $
*/
#ifndef __RECORDING_H
#define __RECORDING_H
#include <time.h>
#include "config.h"
#include "dvbapi.h"
#include "tools.h"
extern cDvbRecorder *Recorder;
void AssertFreeDiskSpace(void);
class cRecording : public cListObject {
private:
bool AssertRecorder(void);
public:
char *name;
char *fileName;
time_t start;
char quality;
int priority;
int lifetime;
cRecording(const char *Name, time_t Start, char Quality, int Priority, int LifeTime);
cRecording(cTimer *Timer);
cRecording(const char *FileName);
~cRecording();
const char *FileName(void);
bool Delete(void);
// Changes the file name so that it will no longer be visible in the OSM
// Returns false in case of error
bool Remove(void);
// Actually removes the file from the disk
// Returns false in case of error
bool Record(void);
// Starts recording of the file
bool Play(void);
// Starts playback of the file
void Stop(void);
// Stops recording or playback of the file
};
class cRecordings : public cList<cRecording> {
public:
bool Load(bool Deleted = false);
};
#endif //__RECORDING_H

View File

@ -1,9 +1,6 @@
1:2:-----S-:2210:2320:H:99:99:Wochenshow
1:3:M------:2125:2205:H:99:99:Neues
1:2:-----S-:2205:2320:H:99:99:Wochenshow
0:15:M------:2125:2205:H:99:99:Neues
1:15:MTWTF--:1828:1901:M:10:5:nano
1:2:-----S-:1737:1827:H:99:99:kls/StarTrek/DS9
1:3:M------:2110:2230:H:99:99:SevenDays
1:3:---T---:2215:2300:H:99:99:SwItch
0:1:1:0:0:H:99:99:#
0:1:1:0:0:H:99:99:#
0:1:1:0:0:L:0:5:#
1:3:---T---:2215:2300:H:99:99:Switch
1:14:------S:2210:2255:H:99:99:Olli

71
tools.c
View File

@ -4,13 +4,30 @@
* See the main source file 'osm.c' for copyright information and
* how to reach the author.
*
* $Id: tools.c 1.1 2000/02/19 13:36:48 kls Exp $
* $Id: tools.c 1.2 2000/03/05 14:33:58 kls Exp $
*/
#include "tools.h"
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/time.h>
#define MaxBuffer 1000
char *readline(FILE *f)
{
static char buffer[MaxBuffer];
if (fgets(buffer, sizeof(buffer), f) > 0) {
int l = strlen(buffer) - 1;
if (l >= 0 && buffer[l] == '\n')
buffer[l] = 0;
return buffer;
}
return NULL;
}
int time_ms(void)
{
struct timeval t;
@ -19,6 +36,30 @@ int time_ms(void)
return 0;
}
bool MakeDirs(const char *FileName)
{
bool result = true;
char *s = strdup(FileName);
char *p = s;
if (*p == '/')
p++;
while ((p = strchr(p, '/')) != NULL) {
*p = 0;
struct stat fs;
if (stat(s, &fs) != 0 || !S_ISDIR(fs.st_mode)) {
isyslog(LOG_INFO, "creating directory %s", s);
if (mkdir(s, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) == -1) {
esyslog(LOG_ERR, "ERROR while creating directory %s: %s", s, strerror(errno));
result = false;
break;
}
}
*p++ = '/';
}
delete s;
return result;
}
// --- cListObject -----------------------------------------------------------
cListObject::cListObject(void)
@ -42,6 +83,7 @@ void cListObject::Unlink(void)
next->prev = prev;
if (prev)
prev->next = next;
next = prev = NULL;
}
int cListObject::Index(void)
@ -92,6 +134,33 @@ void cListBase::Del(cListObject *Object)
delete Object;
}
void cListBase::Move(int From, int To)
{
Move(Get(From), Get(To));
}
void cListBase::Move(cListObject *From, cListObject *To)
{
if (From && To) {
if (From->Index() < To->Index())
To = To->Next();
if (From == objects)
objects = From->Next();
if (From == lastObject)
lastObject = From->Prev();
From->Unlink();
if (To) {
if (To->Prev())
To->Prev()->Append(From);
From->Append(To);
}
else
lastObject->Append(From);
if (!From->Prev())
objects = From;
}
}
void cListBase::Clear(void)
{
while (objects) {

16
tools.h
View File

@ -4,12 +4,13 @@
* See the main source file 'osm.c' for copyright information and
* how to reach the author.
*
* $Id: tools.h 1.1 2000/02/19 13:36:48 kls Exp $
* $Id: tools.h 1.2 2000/03/05 16:14:05 kls Exp $
*/
#ifndef __TOOLS_H
#define __TOOLS_H
#include <stdio.h>
#include <syslog.h>
//TODO
@ -17,6 +18,14 @@
#define esyslog syslog
#define isyslog syslog
#define SECSINDAY 86400
#define DELETENULL(p) (delete (p), p = NULL)
char *readline(FILE *f);
int time_ms(void);
bool MakeDirs(const char *FileName);
class cListObject {
private:
cListObject *prev, *next;
@ -38,6 +47,8 @@ public:
virtual ~cListBase();
void Add(cListObject *Object);
void Del(cListObject *Object);
void Move(int From, int To);
void Move(cListObject *From, cListObject *To);
void Clear(void);
cListObject *Get(int Index);
int Count(void);
@ -47,8 +58,7 @@ template<class T> class cList : public cListBase {
public:
T *Get(int Index) { return (T *)cListBase::Get(Index); }
T *First(void) { return (T *)objects; }
T *Next(T *object) { return (T *)object->Next(); }
};
int time_ms(void);
#endif //__TOOLS_H