mirror of
https://github.com/VDR4Arch/vdr.git
synced 2023-10-10 13:36:52 +02:00
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:
parent
4a9d9c5876
commit
571686d909
12
HISTORY
Normal file
12
HISTORY
Normal 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).
|
11
Makefile
11
Makefile
@ -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
36
README
@ -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
5
TODO
@ -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).
|
||||
|
@ -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
118
config.c
@ -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();
|
||||
|
16
config.h
16
config.h
@ -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
168
dvbapi.c
@ -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
|
||||
}
|
||||
|
70
dvbapi.h
70
dvbapi.h
@ -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
|
||||
|
202
interface.c
202
interface.c
@ -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
|
||||
|
20
interface.h
20
interface.h
@ -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;
|
||||
|
BIN
keys-pc.conf
BIN
keys-pc.conf
Binary file not shown.
@ -17,3 +17,7 @@ Right 000045E2
|
||||
7 00000FE2
|
||||
8 000077E2
|
||||
9 000037E2
|
||||
Red 000025E2
|
||||
Green 00002AE2
|
||||
Yellow 00005AE2
|
||||
Blue 00000000
|
||||
|
454
menu.c
454
menu.c
@ -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
4
menu.h
@ -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
131
osd.c
@ -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
42
osd.h
@ -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
57
osm.c
@ -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
238
recording.c
Normal 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
56
recording.h
Normal 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
|
11
timers.conf
11
timers.conf
@ -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
71
tools.c
@ -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
16
tools.h
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user