Initial revision

This commit is contained in:
Klaus Schmidinger 2000-02-19 13:36:48 +01:00
commit 4a9d9c5876
22 changed files with 3002 additions and 0 deletions

37
Makefile Normal file
View File

@ -0,0 +1,37 @@
#
# Makefile for the On Screen Menu of the Video Disk Recorder
#
# 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 $
OBJS = config.o dvbapi.o interface.o menu.o osd.o remote.o tools.o osm.o
ifdef DEBUG_REMOTE
DEFINES += -DDEBUG_REMOTE
endif
ifdef DEBUG_OSD
DEFINES += -DDEBUG_OSD
endif
%.o: %.c
g++ -g -O2 -Wall -c $(DEFINES) $<
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
remote.o : remote.c remote.h tools.h
tools.o : tools.c tools.h
osm: $(OBJS)
g++ -g -O2 $(OBJS) -lncurses -o osm
clean:
-rm $(OBJS) osm

122
README Normal file
View File

@ -0,0 +1,122 @@
On Screen Menu for the Video Disk Recorder
------------------------------------------
These files contain the source code of an on screen
menu for a video disk recorder based on the DVB driver
of the LinuxTV project (http://linuxtv.org).
For details about the "Video Disk Recorder" project please
refer to http://www.cadsoft.de/people/kls/vdr.
The author can be contacted at kls@cadsoft.de.
Yet another "set-top-box"?
--------------------------
The "set-top-boxes" available from commercial companies all have
one major drawback: they are not "open". This project's goal is
to build an "open" digital satellite receiver and timer controlled
video disk recorder, based upon open standards and freely available
driver software (of course, the hardware still has to be bought).
The on screen menu system is simple, but shall provide all the
possibilites necessary to perform timer controlled recording,
file management and, maybe, even "on disk editing". The menus
of commercial set-top-boxes usually are a lot more fancy than
the ones in this system, but here we have the full source code
and can modify the menus in whatever way desired.
Compiling and running the program:
----------------------------------
Make sure the files from this package are located in a
directory that is "parallel" to the DVB directory of the
driver source for the Siemens DVB-S PCI card (refer to
http://linuxtv.org/dvb/siemens_dvb.html for more information
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.
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.
There are two macros you can use to customize the 'osm' program
at compile time. Adding "DEBUG_REMOTE=1" to the 'make' call
will use the PC's keyboard as input device instead of the "Remote
Control Unit" (see http://www.cadsoft.de/people/kls/vdr/remote.htm).
Adding "DEBUG_OSD=1" will use the PC screen (or current window)
to display texts instead of the DVB card's on-screen display
interface. These modes are useful when testing new menus if you
only have a remote connection to the VDR (which, in my case, is
located in the living room and has neither a monitor nor a keyboard).
Configuration files:
--------------------
There are three configuration files that hold information about
channels, remote control keys and timers. These files are currrently
assumed to be located in the directory from which the 'osm' program
was started (this will become configurable later). The configuration
files can be edited with any text editor, or will be written by the
'osm' program if any changes are made inside the on-screen menus.
The meaning of the data entries may still vary in future releases,
so for the moment please look at the source code (config.c) to see
the meaning of the various fields.
There is no way of adding or deleting channels or timers yet, this
will be implemented later.
Learning the remote control keys:
---------------------------------
The remote control configuration file 'keys.conf' that comes with
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,
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
definitions is optional, but the more keys you define, the more you
will be able to navigate through the menus.
If the program has been built with "DEBUG_REMOTE=1", it will use the
key configuration file 'keys-pc.conf', so that you won't loose data
when switching between normal and debug mode.
Navigating through the On Screen Menus:
---------------------------------------
The "Main" menu can be called up with the "Menu" key of your remote
control unit. The "Up" and "Down" keys are used to select a specific
item. The "Left" and "Right" keys can be used to change options, and
the numeric keys allow direct input of numeric data. The "Ok" key
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.
Textual options, like channel names or recording file names, can be edited
by pressing the "Right" button (which puts brackets around the current
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.
At any point in the menu system, pressing the "Menu" key again will
immediately leave the menu system.
What do you think?
------------------
So, what do you think about this project? Does it make sense? Were you
able to use it? Do you have suggestions on how to improve it?
Please send email to kls@cadsoft.de if you'd like to comment on this.

13
TODO Normal file
View File

@ -0,0 +1,13 @@
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).
* Implement "on-disk editing" to allow "cutting out" of certain
scenes in order to archive them (or, reversely, cut out
commercial breaks).

109
channels.conf Normal file
View File

@ -0,0 +1,109 @@
RTL:12188:h:1:27500:163:104
Sat.1:12552:v:1:22000:163:104
Pro 7:12480:v:1:27500:255:256
RTL2:12188:h:1:27500:166:128
ARD:11837:h:1:27500:101:102
BR3:11837:h:1:27500:201:202
Hessen 3:11837:h:1:27500:301:302
N3:11837:h:1:27500:401:402
SR3:11837:h:1:27500:501:502
WDR:11837:h:1:27500:601:602
BR alpha:11837:h:1:27500:701:702
SWR BW:11837:h:1:27500:801:802
Phoenix:11837:h:1:27500:901:902
ZDF:11954:h:1:27500:110:120
3sat:11954:h:1:27500:210:220
Kinderkanal:11954:h:1:27500:310:320
arte:11954:h:1:27500:360:370
phoenix:11954:h:1:27500:410:420
ORF Sat:11954:h:1:27500:506:507
ZDF Infobox:11954:h:1:27500:610:620
CNN:12168:v:1:27500:165:100
Super RTL:12188:h:1:27500:165:120
VOX:12188:h:1:27500:167:136
DW TV:12363:v:1:27500:305:306
Kabel 1:12480:v:1:27500:511:512
TM3:12480:v:1:27500:767:768
DSF:12480:v:1:27500:1023:1024
HOT:12480:v:1:27500:1279:1280
BloombergTV:12552:v:1:22000:162:99
Sky News:12552:v:1:22000:305:306
KinderNet:12574:h:1:22000:163:92
Alice:12610:v:1:22000:162:96
n-tv:12670:v:1:22000:162:96
Grand Tour.:12670:v:1:22000:289:290
TW1:12692:h:1:22000:166:167
Eins Extra:12722:h:1:22000:101:102
Eins Festival:12722:h:1:22000:201:202
Eins MuXx:12722:h:1:22000:301:302
MDR:12722:h:1:22000:401:402
ORB:12722:h:1:22000:501:502
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
Mosaico:11934:v:1:27500:165:100
Andalucia TV:11934:v:1:27500:166:104
TVC Internacional:11934:v:1:27500:167:108
Nasza TV:11992:h:1:27500:165:98
WishLine test:12012:v:1:27500:163:90
Pro 7 Austria:12051:v:1:27500:161:84
Kabel 1 Schweiz:12051:v:1:27500:162:163
Kabel 1 Austria:12051:v:1:27500:166:167
Pro 7 Schweiz:12051:v:1:27500:289:290
Kiosque:12129:v:1:27500:160:80
KTO:12129:v:1:27500:170:120
TCM:12168:v:1:27500:160:80
Cartoon Network France & Spain:12168:v:1:27500:161:84
TVBS Europe:12168:v:1:27500:162:88
TVBS Europe:12168:v:1:27500:162:89
Travel:12168:v:1:27500:163:92
TCM Espania:12168:v:1:27500:164:96
MTV Spain:12168:v:1:27500:167:112
TCM France:12168:v:1:27500:169:64
RTL2 CH:12188:h:1:27500:164:112
La Cinquieme:12207:v:1:27500:160:80
ARTE:12207:v:1:27500:165:100
Post Filial TV:12226:h:1:27500:255:256
Canal Canaris:12246:v:1:27500:160:80
Canal Canaris:12246:v:1:27500:160:81
Canal Canaris:12246:v:1:27500:160:82
Canal Canaris:12246:v:1:27500:160:83
AB Sat Passion promo:12266:h:1:27500:160:80
AB Channel 1:12266:h:1:27500:161:84
Taquilla 0:12285:v:1:27500:165:100
CSAT:12324:v:1:27500:160:80
Mosaique:12324:v:1:27500:162:88
Mosaique 2:12324:v:1:27500:163:92
Mosaique 3:12324:v:1:27500:164:96
Le Sesame C+:12324:v:1:27500:165:1965
FEED:12344:h:1:27500:163:92
RTM 1:12363:v:1:27500:162:96
ESC 1:12363:v:1:27500:163:104
TV5 Europe:12363:v:1:27500:164:112
TV7 Tunisia:12363:v:1:27500:166:128
ARTE:12363:v:1:27500:167:137
RAI Uno:12363:v:1:27500:289:290
RTP International:12363:v:1:27500:300:301
Fashion TV:12402:v:1:27500:163:92
VideoService:12422:h:1:27500:255:256
Beta Research promo:12422:h:1:27500:1023:1024
Canal Canarias:12441:v:1:27500:160:80
TVC International:12441:v:1:27500:512:660
Fitur:12441:v:1:27500:514:662
Astra Info 1:12552:v:1:22000:164:112
Astra Info 2:12552:v:1:22000:165:120
Astra Vision 1:12552:v:1:22000:168:144
Astra Vision 1:12552:v:1:22000:168:145
Astra Vision 1:12552:v:1:22000:168:146
Astra Vision 1:12552:v:1:22000:168:147
Astra Vision 1:12552:v:1:22000:168:148
Astra Vision 1:12552:v:1:22000:168:149
Astra Vision 1:12552:v:1:22000:168:150
RTL Tele Letzebuerg:12552:v:1:22000:168:144
Astra Mosaic:12552:v:1:22000:175:176
MHP test:12604:h:1:22000:5632:8191
Bloomberg TV Spain:12610:v:1:22000:45:49
Video Italia:12610:v:1:22000:121:122
AC 3 promo:12670:v:1:22000:308:256

333
config.c Normal file
View File

@ -0,0 +1,333 @@
/*
* config.c: Configuration file handling
*
* 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 $
*/
#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 },
};
cKeys::cKeys(void)
{
fileName = NULL;
code = 0;
address = 0;
keys = keyTable;
}
void cKeys::Clear(void)
{
for (tKey *k = keys; k->type != kNone; k++)
k->code = 0;
}
bool cKeys::Load(char *FileName)
{
isyslog(LOG_INFO, "loading %s", FileName);
bool result = false;
if (FileName)
fileName = strdup(FileName);
if (fileName) {
FILE *f = fopen(fileName, "r");
if (f) {
int line = 0;
char buffer[MaxBuffer];
result = true;
while (fgets(buffer, sizeof(buffer), f) > 0) {
line++;
char *Name = buffer;
char *p = strpbrk(Name, " \t");
if (p) {
*p = 0; // terminates 'Name'
while (*++p && isspace(*p))
;
if (*p) {
if (strcasecmp(Name, "Code") == 0)
code = *p;
else if (strcasecmp(Name, "Address") == 0)
address = strtol(p, NULL, 16);
else {
for (tKey *k = keys; k->type != kNone; k++) {
if (strcasecmp(Name, k->name) == 0) {
k->code = strtol(p, NULL, 16);
Name = NULL; // to indicate that we found it
break;
}
}
if (Name) {
fprintf(stderr, "unknown key in %s, line %d\n", fileName, line);
result = false;
break;
}
}
}
continue;
}
fprintf(stderr, "error in %s, line %d\n", fileName, line);
result = false;
break;
}
fclose(f);
}
else
fprintf(stderr, "can't open '%s'\n", fileName);
}
else
fprintf(stderr, "no key configuration file name supplied!\n");
return result;
}
bool cKeys::Save(void)
{
//TODO make backup copies???
bool result = true;
FILE *f = fopen(fileName, "w");
if (f) {
if (fprintf(f, "Code\t%c\nAddress\t%04X\n", code, address) > 0) {
for (tKey *k = keys; k->type != kNone; k++) {
if (fprintf(f, "%s\t%08X\n", k->name, k->code) <= 0) {
result = false;
break;
}
}
}
else
result = false;
fclose(f);
}
else
result = false;
return result;
}
eKeys cKeys::Get(unsigned int Code)
{
if (Code != 0) {
tKey *k;
for (k = keys; k->type != kNone; k++) {
if (k->code == Code)
break;
}
return k->type;
}
return kNone;
}
void cKeys::Set(eKeys Key, unsigned int Code)
{
for (tKey *k = keys; k->type != kNone; k++) {
if (k->type == Key) {
k->code = Code;
break;
}
}
}
// -- cChannel ---------------------------------------------------------------
cChannel::cChannel(void)
{
*name = 0;
}
bool cChannel::Parse(char *s)
{
char *buffer = NULL;
if (7 == sscanf(s, "%a[^:]:%d:%c:%d:%d:%d:%d", &buffer, &frequency, &polarization, &diseqc, &srate, &vpid, &apid)) {
strncpy(name, buffer, MaxChannelName - 1);
name[strlen(buffer)] = 0;
delete buffer;
return true;
}
return false;
}
bool cChannel::Save(FILE *f)
{
return fprintf(f, "%s:%d:%c:%d:%d:%d:%d\n", name, frequency, polarization, diseqc, srate, vpid, apid) > 0;
}
bool cChannel::Switch(void)
{
if (!ChannelLocked) {
isyslog(LOG_INFO, "switching to channel %d", Index() + 1);
CurrentChannel = Index();
Interface.DisplayChannel(CurrentChannel + 1, name);
for (int i = 3; --i;) {
if (DvbSetChannel(frequency, polarization, diseqc, srate, vpid, apid))
return true;
esyslog(LOG_ERR, "retrying");
}
}
Interface.Info("Channel locked (recording)!");
return false;
}
bool cChannel::SwitchTo(int i)
{
cChannel *channel = Channels.Get(i);
return channel && channel->Switch();
}
// -- cTimer -----------------------------------------------------------------
cTimer::cTimer(void)
{
*file = 0;
}
int cTimer::TimeToInt(int t)
{
return (t / 100 * 60 + t % 100) * 60;
}
int cTimer::ParseDay(char *s)
{
char *tail;
int d = strtol(s, &tail, 10);
if (tail && *tail) {
d = 0;
if (tail == s) {
if (strlen(s) == 7) {
for (char *p = s + 6; p >= s; p--) {
d <<= 1;
d |= (*p != '-');
}
d |= 0x80000000;
}
}
}
else if (d < 1 || d > 31)
d = 0;
return d;
}
char *cTimer::PrintDay(int d)
{
static char buffer[8];
if ((d & 0x80000000) != 0) {
char *b = buffer;
char *w = "MTWTFSS";
*b = 0;
while (*w) {
*b++ = (d & 1) ? *w : '-';
d >>= 1;
w++;
}
}
else
sprintf(buffer, "%d", d);
return buffer;
}
bool cTimer::Parse(char *s)
{
char *buffer1 = NULL;
char *buffer2 = NULL;
if (9 == sscanf(s, "%d:%d:%a[^:]:%d:%d:%c:%d:%d:%as", &active, &channel, &buffer1, &start, &stop, &quality, &priority, &lifetime, &buffer2)) {
day = ParseDay(buffer1);
strncpy(file, buffer2, MaxFileName - 1);
file[strlen(buffer2)] = 0;
delete buffer1;
delete buffer2;
return day != 0;
}
return false;
}
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::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;
int begin = TimeToInt(start);
int end = TimeToInt(stop);
bool twoDays = (end < begin);
bool todayMatches = false, yesterdayMatches = false;
if ((day & 0x80000000) != 0) {
if ((day & (1 << weekday)) != 0)
todayMatches = true;
else if (twoDays) {
int yesterday = weekday == 0 ? 6 : weekday - 1;
if ((day & (1 << yesterday)) != 0)
yesterdayMatches = true;
}
}
else if (day == now->tm_mday)
todayMatches = true;
else if (twoDays) {
t -= 86400;
now = localtime(&t);
if (day == now->tm_mday)
yesterdayMatches = true;
}
return (todayMatches && current >= begin && (current <= end || twoDays))
|| (twoDays && yesterdayMatches && current <= end);
}
return false;
}
cTimer *cTimer::GetMatch(void)
{
cTimer *t = (cTimer *)Timers.First();
while (t) {
if (t->Matches())
return t;
t = (cTimer *)t->Next();
}
return NULL;
}
// -- cKeys ------------------------------------------------------------------
cKeys Keys;
// -- cChannels --------------------------------------------------------------
int CurrentChannel = 0;
bool ChannelLocked = false;
cChannels Channels;
// -- cTimers ----------------------------------------------------------------
cTimers Timers;

163
config.h Normal file
View File

@ -0,0 +1,163 @@
/*
* config.h: Configuration file handling
*
* 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 $
*/
#ifndef __CONFIG_H
#define __CONFIG_H
#include <stdio.h>
#include <string.h>
#include "tools.h"
#define MaxBuffer 1000
enum eKeys { // "Up" and "Down" must be the first two keys!
kUp,
kDown,
kMenu,
kOk,
kBack,
kLeft,
kRight,
k0, k1, k2, k3, k4, k5, k6, k7, k8, k9,
kNone
};
struct tKey {
eKeys type;
char *name;
unsigned int code;
};
class cKeys {
private:
char *fileName;
public:
unsigned char code;
unsigned short address;
tKey *keys;
cKeys(void);
void Clear(void);
bool Load(char *FileName = NULL);
bool Save(void);
eKeys Get(unsigned int Code);
void Set(eKeys Key, unsigned int Code);
};
class cChannel : public cListObject {
public:
enum { MaxChannelName = 32 }; // 31 chars + terminating 0!
char name[MaxChannelName];
int frequency; // MHz
char polarization;
int diseqc;
int srate;
int vpid;
int apid;
cChannel(void);
bool Parse(char *s);
bool Save(FILE *f);
bool Switch(void);
static bool SwitchTo(int i);
};
class cTimer : public cListObject {
public:
enum { MaxFileName = 256 };
int active;
int channel;
int day;
int start;
int stop;
//TODO VPS???
char quality;
int priority;
int lifetime;
char file[MaxFileName];
cTimer(void);
bool Parse(char *s);
bool Save(FILE *f);
bool Matches(void);
static cTimer *GetMatch(void);
static int TimeToInt(int t);
static int ParseDay(char *s);
static char *PrintDay(int d);
};
template<class T> class cConfig : public cList<T> {
private:
char *fileName;
void Clear(void)
{
delete fileName;
cList<T>::Clear();
}
public:
bool Load(char *FileName)
{
isyslog(LOG_INFO, "loading %s", FileName);
bool result = true;
Clear();
fileName = strdup(FileName);
FILE *f = fopen(fileName, "r");
if (f) {
int line = 0;
char buffer[MaxBuffer];
while (fgets(buffer, sizeof(buffer), f) > 0) {
line++;
T *l = new T;
if (l->Parse(buffer))
Add(l);
else {
fprintf(stderr, "error in %s, line %d\n", fileName, line);
delete l;
result = false;
break;
}
}
fclose(f);
}
else {
fprintf(stderr, "can't open '%s'\n", fileName);
result = false;
}
return result;
}
bool Save(void)
{
//TODO make backup copies???
bool result = true;
T *l = (T *)First();
FILE *f = fopen(fileName, "w");
if (f) {
while (l) {
if (!l->Save(f)) {
result = false;
break;
}
l = (T *)l->Next();
}
fclose(f);
}
else
result = false;
return result;
}
};
class cChannels : public cConfig<cChannel> {};
class cTimers : public cConfig<cTimer> {};
extern int CurrentChannel;
extern bool ChannelLocked;
extern cChannels Channels;
extern cTimers Timers;
extern cKeys Keys;
#endif //__CONFIG_H

166
dvbapi.c Normal file
View File

@ -0,0 +1,166 @@
/*
* dvbapi.c: Interface to the DVB driver
*
* 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 $
*/
// 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"
#define VIDEODEVICE "/dev/video"
const char *DvbQuality = "LMH"; // Low, Medium, High
bool DvbSetChannel(int FrequencyMHz, char Polarization, int Diseqc, int Srate, int Vpid, int Apid)
{
int v = open(VIDEODEVICE, O_RDWR);
if (v >= 0) {
struct frontend front;
ioctl(v, VIDIOCGFRONTEND, &front);
unsigned int freq = FrequencyMHz;
front.ttk = (freq < 11800UL) ? 0 : 1;
if (freq < 11800UL)
freq -= 9750UL;
else
freq -= 10600UL;
front.freq = freq * 1000000UL;
front.diseqc = Diseqc;
front.srate = Srate * 1000;
front.volt = (Polarization == 'v') ? 0 : 1;
front.video_pid = Vpid;
front.audio_pid = Apid;
front.AFC = 1;
ioctl(v, VIDIOCSFRONTEND, &front);
close(v);
if (front.sync & 0x1F == 0x1F)
return true;
esyslog(LOG_ERR, "channel not sync'ed (front.sync=%X)!", front.sync);
}
else
Interface.Error("can't open VIDEODEVICE");//XXX
return false;
}
// -- cDvbRecorder -----------------------------------------------------------
cDvbRecorder::cDvbRecorder(void)
{
}
cDvbRecorder::~cDvbRecorder()
{
Stop();
}
bool cDvbRecorder::Record(const char *FileName, char Quality)
{
isyslog(LOG_INFO, "record %s (%c)", FileName, Quality);
return true;
// TODO
return false;
}
bool cDvbRecorder::Play(const char *FileName, int Frame)
{
isyslog(LOG_INFO, "play %s (%d)", FileName, Frame);
// TODO
return false;
}
bool cDvbRecorder::FastForward(void)
{
isyslog(LOG_INFO, "fast forward");
// TODO
return false;
}
bool cDvbRecorder::FastRewind(void)
{
isyslog(LOG_INFO, "fast rewind");
// TODO
return false;
}
bool cDvbRecorder::Pause(void)
{
isyslog(LOG_INFO, "pause");
// TODO
return false;
}
void cDvbRecorder::Stop(void)
{
isyslog(LOG_INFO, "stop");
// TODO
}
int cDvbRecorder::Frame(void)
{
isyslog(LOG_INFO, "frame");
// TODO
return 0;
}
// ---------------------------------------------------------------------------
static void DvbOsdCmd(OSD_Command cmd, int color = 0, int x0 = 0, int y0 = 0, int x1 = 0, int y1 = 0, void *data = NULL)
{
int v = open(VIDEODEVICE, O_RDWR);
if (v >= 0) {
struct drawcmd dc;
dc.cmd = cmd;
dc.color = color;
dc.x0 = x0;
dc.y0 = y0;
dc.x1 = x1;
dc.y1 = y1;
dc.data = data;
ioctl(v, VIDIOCSOSDCOMMAND, &dc);
close(v);
}
else
Interface.Error("can't open VIDEODEVICE");//XXX
}
void DvbOsdOpen(int x, int y, 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
}
void DvbOsdClose(void)
{
DvbOsdCmd(OSD_Close);
}
void DvbOsdClear(void)
{
DvbOsdCmd(OSD_Clear);
}
void DvbOsdClrEol(int x, int y)
{
DvbOsdCmd(OSD_FillBlock, 0, x, y * DvbOsdLineHeight, x + 490, (y + 1) * DvbOsdLineHeight);//XXX
}
void DvbOsdText(int x, int y, char *s)
{
DvbOsdCmd(OSD_Text, 1, x, y, 1, 0, s);
}

65
dvbapi.h Normal file
View File

@ -0,0 +1,65 @@
/*
* dvbapi.h: Interface to the DVB driver
*
* 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 $
*/
#ifndef __DVBAPI_H
#define __DVBAPI_H
const int DvbOsdCharWidth = 12; //XXX
const int DvbOsdLineHeight = 25;
extern const char *DvbQuality; // Low, Medium, High
bool DvbSetChannel(int FrequencyMHz, char Polarization, int Diseqc, int Srate, int Vpid, int Apid);
class cDvbRecorder {
public:
cDvbRecorder(void);
~cDvbRecorder();
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.
// Returns true if recording was started successfully.
// If there is already a recording session active, false will be
// returned.
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.
// 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.
bool FastForward(void);
// Runs the current playback session forward at a higher speed.
// TODO allow different fast forward speeds???
bool FastRewind(void);
// Runs the current playback session backwards forward at a higher speed.
// TODO allow different fast rewind speeds???
bool Pause(void);
// Pauses the current recording or playback session, or resumes a paused
// session.
// Returns true if there is actually a recording or playback session
// active that was paused/resumed.
void Stop(void);
// Stops the current recording or playback session.
int Frame(void);
// Returns the number of the current frame in the current recording or
// playback session, which can be used to start playback at a given position.
// The number returned is the actual number of frames counted from the
// beginning of the current file.
// 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);
#endif //__DVBAPI_H

298
interface.c Normal file
View File

@ -0,0 +1,298 @@
/*
* interface.c: Abstract user interface layer
*
* 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 $
*/
#include "interface.h"
#include <ncurses.h>
#include <unistd.h>
#include "dvbapi.h"
#include "remote.h"
#ifndef DEBUG_REMOTE
cRcIo RcIo("/dev/ttyS1");//XXX
#endif
WINDOW *window;
cInterface Interface;
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)
{
#ifndef DEBUG_REMOTE
RcIo.SetCode(Keys.code, Keys.address);
#endif
}
void cInterface::Open(void)
{
if (!open++) {
#ifdef DEBUG_OSD
#else
//TODO
DvbOsdOpen(100, 100, 500, 400);
#endif
}
}
void cInterface::Close(void)
{
if (!--open) {
#ifdef DEBUG_OSD
#else
//TODO
DvbOsdClose();
#endif
}
}
unsigned int cInterface::GetCh(void)
{
#ifdef DEBUG_REMOTE
return getch();
#else
#ifdef DEBUG_OSD
wrefresh(window);//XXX
#endif
unsigned int Command;
return RcIo.GetCommand(&Command) ? Command : 0;
#endif
}
eKeys cInterface::GetKey(void)
{
return Keys.Get(GetCh());
}
void cInterface::Clear(void)
{
if (open) {
#ifdef DEBUG_OSD
wclear(window);
#else
//TODO
DvbOsdClear();
#endif
}
}
void cInterface::SetCols(int *c)
{
for (int i = 0; i < MaxCols; i++) {
cols[i] = *c++;
if (cols[i] == 0)
break;
}
}
void cInterface::Write(int x, int y, char *s)
{
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
}
}
void cInterface::WriteText(int x, int y, 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++;
int col = 0;
for (;;) {
char *t = strchr(s, '\t');
char *p = s;
char buf[1000];
if (t && col < MaxCols && cols[col] > 0) {
unsigned int n = t - s;
if (n >= sizeof(buf))
n = sizeof(buf) - 1;
strncpy(buf, s, n);
buf[n] = 0;
p = buf;
s = t + 1;
}
Write(x, y, p);
if (p == s)
break;
x += cols[col++];
}
}
}
void cInterface::Info(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
Close();
}
void cInterface::Error(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
Close();
}
void cInterface::QueryKeys(void)
{
Keys.Clear();
WriteText(1, 1, "Learning Remote Control Keys");
WriteText(1, 3, "Phase 1: Detecting RC code type");
WriteText(1, 5, "Press any key on the RC unit");
#ifndef DEBUG_REMOTE
unsigned char Code = 0;
unsigned short Address;
#endif
for (;;) {
#ifdef DEBUG_REMOTE
if (GetCh())
break;
#else
//TODO on screen display...
if (RcIo.DetectCode(&Code, &Address)) {
Keys.code = Code;
Keys.address = Address;
WriteText(1, 5, "RC code detected!");
WriteText(1, 6, "Do not press any key...");
RcIo.Flush(3);
WriteText(1, 5, "");
WriteText(1, 6, "");
break;
}
#endif
}
WriteText(1, 3, "Phase 2: Learning specific key codes");
tKey *k = Keys.keys;
while (k->type != kNone) {
char *Prompt;
asprintf(&Prompt, "Press key for '%s'", k->name);
WriteText(1, 5, Prompt);
delete Prompt;
for (;;) {
unsigned int ch = GetCh();
if (ch != 0) {
switch (Keys.Get(ch)) {
case kUp: if (k > Keys.keys) {
k--;
break;
}
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, "");
for (;;) {
eKeys key = GetKey();
if (key == kUp) {
Clear();
return;
}
else if (key == kDown) {
WriteText(1, 6, "");
break;
}
}
break;
}
case kNone: k->code = ch;
k++;
break;
default: break;
}
break;
}
}
if (k > Keys.keys)
WriteText(1, 7, "(press 'Up' to go back)");
else
WriteText(1, 7, "");
if (k > Keys.keys + 1)
WriteText(1, 8, "(press 'Down' to end key definition)");
else
WriteText(1, 8, "");
}
}
void cInterface::LearnKeys(void)
{
isyslog(LOG_INFO, "learning keys");
for (;;) {
Clear();
QueryKeys();
Clear();
WriteText(1, 1, "Learning Remote Control Keys");
WriteText(1, 3, "Phase 3: Saving key codes");
WriteText(1, 5, "Press 'Up' to save, 'Down' to cancel");
for (;;) {
eKeys key = GetKey();
if (key == kUp) {
Keys.Save();
Clear();
return;
}
else if (key == kDown) {
Keys.Load();
Clear();
return;
}
}
}
}
void cInterface::DisplayChannel(int Number, char *Name)
{
//TODO
#ifndef DEBUG_REMOTE
RcIo.Number(Number);
#endif
}

41
interface.h Normal file
View File

@ -0,0 +1,41 @@
/*
* interface.h: Abstract user interface layer
*
* 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 $
*/
#ifndef __INTERFACE_H
#define __INTERFACE_H
#include "config.h"
class cInterface {
public:
enum { MaxCols = 5 };
private:
int open;
int cols[MaxCols];
unsigned int GetCh(void);
void QueryKeys(void);
void Write(int x, int y, char *s);
public:
cInterface(void);
void Init(void);
void Open(void);
void Close(void);
eKeys GetKey(void);
void Clear(void);
void SetCols(int *c);
void WriteText(int x, int y, char *s, bool Current = false);
void Info(char *s);
void Error(char *s);
void LearnKeys(void);
void DisplayChannel(int Number, char *Name);
};
extern cInterface Interface;
#endif //__INTERFACE_H

BIN
keys-pc.conf Normal file

Binary file not shown.

19
keys.conf Normal file
View File

@ -0,0 +1,19 @@
Code B
Address 0000
Up 000047E2
Down 000007E2
Menu 000011E2
Ok 000079E2
Back 00001AE2
Left 000005E2
Right 000045E2
0 00007FE2
1 00003FE2
2 00005FE2
3 00001FE2
4 00006FE2
5 00002FE2
6 00004FE2
7 00000FE2
8 000077E2
9 000037E2

745
menu.c Normal file
View File

@ -0,0 +1,745 @@
/*
* menu.c: The actual menu implementations
*
* 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 $
*/
#include "menu.h"
#include <limits.h>
#include <stdio.h>
#include <string.h>
#include "config.h"
#include "dvbapi.h"
const char *FileNameChars = "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz0123456789/-.# ";//TODO more?
// --- cMenuEditItem ---------------------------------------------------------
class cMenuEditItem : public cOsdItem {
private:
const char *name;
const char *value;
public:
cMenuEditItem(const char *Name);
~cMenuEditItem();
void SetValue(const char *Value);
};
cMenuEditItem::cMenuEditItem(const char *Name)
{
name = strdup(Name);
value = NULL;
}
cMenuEditItem::~cMenuEditItem()
{
delete name;
delete value;
}
void cMenuEditItem::SetValue(const char *Value)
{
delete value;
value = strdup(Value);
char *buffer = NULL;
asprintf(&buffer, "%s:\t%s", name, value);
SetText(buffer, false);
Display();
}
// --- cMenuEditIntItem ------------------------------------------------------
class cMenuEditIntItem : public cMenuEditItem {
protected:
int *value;
int min, max;
virtual void Set(void);
public:
cMenuEditIntItem(const char *Name, int *Value, int Min = 0, int Max = INT_MAX);
virtual eOSStatus ProcessKey(eKeys Key);
};
cMenuEditIntItem::cMenuEditIntItem(const char *Name, int *Value, int Min, int Max)
:cMenuEditItem(Name)
{
value = Value;
min = Min;
max = Max;
Set();
}
void cMenuEditIntItem::Set(void)
{
char buf[16];
snprintf(buf, sizeof(buf), "%d", *value);
SetValue(buf);
}
eOSStatus cMenuEditIntItem::ProcessKey(eKeys Key)
{
eOSStatus status = cMenuEditItem::ProcessKey(Key);
if (status == osUnknown) {
int newValue;
if (k0 <= Key && Key <= k9) {
if (fresh) {
*value = 0;
fresh = false;
}
newValue = *value * 10 + (Key - k0);
}
else if (Key == kLeft) { // TODO might want to increase the delta if repeated quickly?
newValue = *value - 1;
fresh = true;
}
else if (Key == kRight) {
newValue = *value + 1;
fresh = true;
}
else
return status;
if ((!fresh || min <= newValue) && newValue <= max) {
*value = newValue;
Set();
}
status = osContinue;
}
return status;
}
// --- cMenuEditBoolItem -----------------------------------------------------
class cMenuEditBoolItem : public cMenuEditIntItem {
protected:
virtual void Set(void);
public:
cMenuEditBoolItem(const char *Name, int *Value);
};
cMenuEditBoolItem::cMenuEditBoolItem(const char *Name, int *Value)
:cMenuEditIntItem(Name, Value, 0, 1)
{
Set();
}
void cMenuEditBoolItem::Set(void)
{
char buf[16];
snprintf(buf, sizeof(buf), "%s", *value ? "yes" : "no");
SetValue(buf);
}
// --- cMenuEditChanItem -----------------------------------------------------
class cMenuEditChanItem : public cMenuEditIntItem {
protected:
virtual void Set(void);
public:
cMenuEditChanItem(const char *Name, int *Value);
};
cMenuEditChanItem::cMenuEditChanItem(const char *Name, int *Value)
:cMenuEditIntItem(Name, Value, 1, Channels.Count())
{
Set();
}
void cMenuEditChanItem::Set(void)
{
char buf[255];
cChannel *channel = Channels.Get(*value - 1);
if (channel)
snprintf(buf, sizeof(buf), "%d %s", *value, channel->name);
else
*buf = 0;
SetValue(buf);
}
// --- cMenuEditDayItem ------------------------------------------------------
class cMenuEditDayItem : public cMenuEditIntItem {
protected:
static int days[];
int d;
virtual void Set(void);
public:
cMenuEditDayItem(const char *Name, int *Value);
virtual eOSStatus ProcessKey(eKeys Key);
};
int cMenuEditDayItem::days[] ={ cTimer::ParseDay("M------"),
cTimer::ParseDay("-T-----"),
cTimer::ParseDay("--W----"),
cTimer::ParseDay("---T---"),
cTimer::ParseDay("----F--"),
cTimer::ParseDay("-----S-"),
cTimer::ParseDay("------S"),
cTimer::ParseDay("MTWTF--"),
cTimer::ParseDay("MTWTFS-"),
cTimer::ParseDay("MTWTFSS"),
cTimer::ParseDay("-----SS"),
0 };
cMenuEditDayItem::cMenuEditDayItem(const char *Name, int *Value)
:cMenuEditIntItem(Name, Value, -INT_MAX, 31)
{
d = -1;
if (*value < 0) {
int n = 0;
while (days[n]) {
if (days[n] == *value) {
d = n;
break;
}
n++;
}
}
Set();
}
void cMenuEditDayItem::Set(void)
{
SetValue(cTimer::PrintDay(*value));
}
eOSStatus cMenuEditDayItem::ProcessKey(eKeys Key)
{
switch (Key) {
case kLeft: if (d > 0)
*value = days[--d];
else if (d == 0) {
*value = 31;
d = -1;
}
else if (*value == 1) {
d = sizeof(days) / sizeof(int) - 2;
*value = days[d];
}
else
return cMenuEditIntItem::ProcessKey(Key);
Set();
break;
case kRight: if (d >= 0) {
*value = days[++d];
if (*value == 0) {
*value = 1;
d = -1;
}
}
else if (*value == 31) {
d = 0;
*value = days[d];
}
else
return cMenuEditIntItem::ProcessKey(Key);
Set();
break;
default : return cMenuEditIntItem::ProcessKey(Key);
}
return osContinue;
}
// --- cMenuEditTimeItem -----------------------------------------------------
class cMenuEditTimeItem : public cMenuEditItem {
protected:
int *value;
int hh, mm;
int pos;
virtual void Set(void);
public:
cMenuEditTimeItem(const char *Name, int *Value);
virtual eOSStatus ProcessKey(eKeys Key);
};
cMenuEditTimeItem::cMenuEditTimeItem(const char *Name, int *Value)
:cMenuEditItem(Name)
{
value = Value;
hh = *value / 100;
mm = *value % 100;
pos = 0;
Set();
}
void cMenuEditTimeItem::Set(void)
{
char buf[10];
snprintf(buf, sizeof(buf), "%02d:%02d", hh, mm);
SetValue(buf);
}
eOSStatus cMenuEditTimeItem::ProcessKey(eKeys Key)
{
eOSStatus status = cMenuEditItem::ProcessKey(Key);
if (status == osUnknown) {
if (k0 <= Key && Key <= k9) {
if (fresh || pos > 3) {
pos = 0;
fresh = false;
}
int n = Key - k0;
switch (pos) {
case 0: if (n <= 2) {
hh = n * 10;
mm = 0;
pos++;
}
break;
case 1: if (hh + n <= 23) {
hh += n;
pos++;
}
break;
case 2: if (n <= 5) {
mm += n * 10;
pos++;
}
break;
case 3: if (mm + n <= 59) {
mm += n;
pos++;
}
break;
}
}
else if (Key == kLeft) { // TODO might want to increase the delta if repeated quickly?
if (--mm < 0) {
mm = 59;
if (--hh < 0)
hh = 23;
}
fresh = true;
}
else if (Key == kRight) {
if (++mm > 59) {
mm = 0;
if (++hh > 23)
hh = 0;
}
fresh = true;
}
else
return status;
*value = hh * 100 + mm;
Set();
status = osContinue;
}
return status;
}
// --- cMenuEditChrItem ------------------------------------------------------
class cMenuEditChrItem : public cMenuEditItem {
private:
char *value;
const char *allowed;
const char *current;
virtual void Set(void);
public:
cMenuEditChrItem(const char *Name, char *Value, const char *Allowed);
~cMenuEditChrItem();
virtual eOSStatus ProcessKey(eKeys Key);
};
cMenuEditChrItem::cMenuEditChrItem(const char *Name, char *Value, const char *Allowed)
:cMenuEditItem(Name)
{
value = Value;
allowed = strdup(Allowed);
current = strchr(allowed, *Value);
if (!current)
current = allowed;
Set();
}
cMenuEditChrItem::~cMenuEditChrItem()
{
delete allowed;
}
void cMenuEditChrItem::Set(void)
{
char buf[2];
snprintf(buf, sizeof(buf), "%c", *value);
SetValue(buf);
}
eOSStatus cMenuEditChrItem::ProcessKey(eKeys Key)
{
eOSStatus status = cMenuEditItem::ProcessKey(Key);
if (status == osUnknown) {
if (Key == kLeft) {
if (current > allowed)
current--;
}
else if (Key == kRight) {
if (*(current + 1))
current++;
}
else
return status;
*value = *current;
Set();
status = osContinue;
}
return status;
}
// --- cMenuEditStrItem ------------------------------------------------------
class cMenuEditStrItem : public cMenuEditItem {
private:
char *value;
int length;
const char *allowed;
int pos;
virtual void Set(void);
char Inc(char c, bool Up);
public:
cMenuEditStrItem(const char *Name, char *Value, int Length, const char *Allowed);
~cMenuEditStrItem();
virtual eOSStatus ProcessKey(eKeys Key);
};
cMenuEditStrItem::cMenuEditStrItem(const char *Name, char *Value, int Length, const char *Allowed)
:cMenuEditItem(Name)
{
value = Value;
length = Length;
allowed = strdup(Allowed);
pos = -1;
Set();
}
cMenuEditStrItem::~cMenuEditStrItem()
{
delete allowed;
}
void cMenuEditStrItem::Set(void)
{
char buf[1000];
if (pos >= 0) {
strncpy(buf, value, pos);
char *s = value[pos] != ' ' ? value + pos + 1 : "";
snprintf(buf + pos, sizeof(buf) - pos - 2, "[%c]%s", *(value + pos), s);
SetValue(buf);
}
else
SetValue(value);
}
char cMenuEditStrItem::Inc(char c, bool Up)
{
const char *p = strchr(allowed, c);
if (!p)
p = allowed;
if (Up) {
if (!*++p)
p = allowed;
}
else if (--p < allowed)
p = allowed + strlen(allowed) - 1;
return *p;
}
eOSStatus cMenuEditStrItem::ProcessKey(eKeys Key)
{
switch (Key) {
case kLeft: if (pos > 0) {
if (value[pos] == ' ')
value[pos] = 0;
pos--;
}
break;
case kRight: if (pos < length && value[pos] != ' ') {
if (++pos >= int(strlen(value))) {
value[pos] = ' ';
value[pos + 1] = 0;
}
}
break;
case kUp:
case kDown: if (pos >= 0)
value[pos] = Inc(value[pos], Key == kUp);
else
return cMenuEditItem::ProcessKey(Key);
break;
case kOk: if (pos >= 0) {
if (value[pos] == ' ')
value[pos] = 0;
pos = -1;
break;
}
// run into default
default: return cMenuEditItem::ProcessKey(Key);
}
Set();
return osContinue;
}
// --- cMenuEditChannel ------------------------------------------------------
class cMenuEditChannel : public cOsdMenu {
private:
cChannel *channel;
cChannel data;
public:
cMenuEditChannel(int Index);
virtual eOSStatus ProcessKey(eKeys Key);
};
cMenuEditChannel::cMenuEditChannel(int Index)
:cOsdMenu("Edit channel", 14)
{
channel = Channels.Get(Index);
if (channel) {
data = *channel;
Add(new cMenuEditStrItem("Name", data.name, sizeof(data.name), FileNameChars));
Add(new cMenuEditIntItem("Frequency", &data.frequency, 10000, 13000)); //TODO exact limits???
Add(new cMenuEditChrItem("Polarization", &data.polarization, "hv"));
Add(new cMenuEditIntItem("Diseqc", &data.diseqc, 0, 10)); //TODO exact limits???
Add(new cMenuEditIntItem("Srate", &data.srate, 22000, 27500)); //TODO exact limits - toggle???
Add(new cMenuEditIntItem("Vpid", &data.vpid, 0, 10000)); //TODO exact limits???
Add(new cMenuEditIntItem("Apid", &data.apid, 0, 10000)); //TODO exact limits???
}
}
eOSStatus cMenuEditChannel::ProcessKey(eKeys Key)
{
eOSStatus status = cOsdMenu::ProcessKey(Key);
if (status == osUnknown) {
if (Key == kOk) {
if (channel)
*channel = data;
Channels.Save();
status = osBack;
}
}
return status;
}
// --- cMenuChannelItem ------------------------------------------------------
class cMenuChannelItem : public cOsdItem {
private:
int index;
cChannel *channel;
public:
cMenuChannelItem(int Index, cChannel *Channel);
virtual void Set(void);
};
cMenuChannelItem::cMenuChannelItem(int Index, cChannel *Channel)
{
index = Index;
channel = Channel;
Set();
}
void cMenuChannelItem::Set(void)
{
char *buffer = NULL;
asprintf(&buffer, "%d\t%s", index + 1, channel->name); // user visible channel numbers start with '1'
SetText(buffer, false);
}
// --- cMenuChannels ---------------------------------------------------------
class cMenuChannels : public cOsdMenu {
public:
cMenuChannels(void);
virtual eOSStatus ProcessKey(eKeys Key);
};
cMenuChannels::cMenuChannels(void)
:cOsdMenu("Channels", 4)
{
//TODO
int i = 0;
cChannel *channel;
while ((channel = Channels.Get(i)) != NULL) {
Add(new cMenuChannelItem(i, channel), i == CurrentChannel);
i++;
}
}
eOSStatus cMenuChannels::ProcessKey(eKeys Key)
{
eOSStatus status = cOsdMenu::ProcessKey(Key);
if (status == 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;
}
default: break;
}
}
return status;
}
// --- cMenuEditTimer --------------------------------------------------------
class cMenuEditTimer : public cOsdMenu {
private:
cTimer *timer;
cTimer data;
public:
cMenuEditTimer(int Index);
virtual eOSStatus ProcessKey(eKeys Key);
};
cMenuEditTimer::cMenuEditTimer(int Index)
:cOsdMenu("Edit timer", 10)
{
timer = Timers.Get(Index);
if (timer) {
data = *timer;
Add(new cMenuEditBoolItem("Active", &data.active));
Add(new cMenuEditChanItem("Channel", &data.channel));
Add(new cMenuEditDayItem( "Day", &data.day));
Add(new cMenuEditTimeItem("Start", &data.start));
Add(new cMenuEditTimeItem("Stop", &data.stop));
//TODO VPS???
Add(new cMenuEditChrItem( "Quality", &data.quality, DvbQuality));
Add(new cMenuEditIntItem( "Priority", &data.priority, 0, 99));
Add(new cMenuEditIntItem( "Lifetime", &data.lifetime, 0, 99));
Add(new cMenuEditStrItem( "File", data.file, sizeof(data.file), FileNameChars));
}
}
eOSStatus cMenuEditTimer::ProcessKey(eKeys Key)
{
eOSStatus status = cOsdMenu::ProcessKey(Key);
if (status == osUnknown) {
if (Key == kOk) {
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;
}
}
return status;
}
// --- cMenuTimerItem --------------------------------------------------------
class cMenuTimerItem : public cOsdItem {
private:
int index;
cTimer *timer;
public:
cMenuTimerItem(int Index, cTimer *Timer);
virtual void Set(void);
};
cMenuTimerItem::cMenuTimerItem(int Index, cTimer *Timer)
{
index = Index;
timer = Timer;
Set();
}
void cMenuTimerItem::Set(void)
{
char *buffer = NULL;
asprintf(&buffer, "%d\t%c\t%d\t%s\t%02d:%02d\t%02d:%02d", index + 1,
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'
SetText(buffer, false);
}
// --- cMenuTimer ------------------------------------------------------------
class cMenuTimer : public cOsdMenu {
public:
cMenuTimer(void);
virtual eOSStatus ProcessKey(eKeys Key);
};
cMenuTimer::cMenuTimer(void)
:cOsdMenu("Timer", 3, 2, 4, 10, 6)
{
int i = 0;
cTimer *timer;
while ((timer = Timers.Get(i)) != NULL) {
Add(new cMenuTimerItem(i, timer));
i++;
}
}
eOSStatus cMenuTimer::ProcessKey(eKeys Key)
{
eOSStatus status = cOsdMenu::ProcessKey(Key);
if (status == 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();
}
}
default: break;
}
}
return status;
}
// --- cMenuMain -------------------------------------------------------------
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)
{
eOSStatus status = cOsdMenu::ProcessKey(Key);
switch (status) {
case osChannels: return AddSubMenu(new cMenuChannels);
case osTimer: return AddSubMenu(new cMenuTimer);
//TODO Replay
default: break;
}
return status;
}

21
menu.h Normal file
View File

@ -0,0 +1,21 @@
/*
* menu.h: The actual menu implementations
*
* 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 $
*/
#ifndef _MENU_H
#define _MENU_H
#include "osd.h"
class cMenuMain : public cOsdMenu {
public:
cMenuMain(void);
virtual eOSStatus ProcessKey(eKeys Key);
};
#endif //_MENU_H

196
osd.c Normal file
View File

@ -0,0 +1,196 @@
/*
* osd.c: Abstract On Screen Display layer
*
* 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 $
*/
#include "osd.h"
#include <assert.h>
#include <string.h>
// --- cOsdItem --------------------------------------------------------------
cOsdItem::cOsdItem(eOSStatus Status)
{
text = NULL;
offset = -1;
status = Status;
fresh = false;
}
cOsdItem::cOsdItem(char *Text, eOSStatus Status)
{
text = NULL;
offset = -1;
status = Status;
fresh = false;
SetText(Text);
}
cOsdItem::~cOsdItem()
{
delete text;
}
void cOsdItem::SetText(char *Text, bool Copy)
{
delete text;
text = Copy ? strdup(Text) : Text;
}
void cOsdItem::Display(int Offset, bool Current)
{
fresh |= Offset >= 0;
Current |= Offset < 0;
if (Offset >= 0)
offset = Offset;
//TODO current if Offset == -1 ???
if (offset >= 0)
Interface.WriteText(0, offset + 2, text, Current);
}
eOSStatus cOsdItem::ProcessKey(eKeys Key)
{
return Key == kOk ? status : osUnknown;
}
// --- cOsdMenu --------------------------------------------------------------
cOsdMenu::cOsdMenu(char *Title, int c0, int c1, int c2, int c3, int c4)
{
title = strdup(Title);
cols[0] = c0;
cols[1] = c1;
cols[2] = c2;
cols[3] = c3;
cols[4] = c4;
first = count = 0;
current = -1;
subMenu = NULL;
Interface.Open();
}
cOsdMenu::~cOsdMenu()
{
delete title;
delete subMenu;
Interface.Clear();
Interface.Close();
}
void cOsdMenu::Add(cOsdItem *Item, bool Current)
{
cList<cOsdItem>::Add(Item);
count++;
if (Current && current < 0)
current = Item->Index();
}
void cOsdMenu::Display(void)
{
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;
}
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;
}
}
void cOsdMenu::RefreshCurrent(void)
{
cOsdItem *item = Get(current);
if (item)
item->Set();
}
void cOsdMenu::DisplayCurrent(bool Current)
{
cOsdItem *item = Get(current);
if (item)
item->Display(current - first, Current);
}
void cOsdMenu::CursorUp(void)
{
if (current > 0) {
DisplayCurrent(false);
if (--current < first) {
first -= MAXOSDITEMS;
if (first < 0)
first = 0;
Display();
}
else
DisplayCurrent(true);
}
}
void cOsdMenu::CursorDown(void)
{
if (current < count - 1) {
DisplayCurrent(false);
if (++current >= first + MAXOSDITEMS) {
first += MAXOSDITEMS;
if (first > count - MAXOSDITEMS)
first = count - MAXOSDITEMS;
Display();
}
else
DisplayCurrent(true);
}
}
eOSStatus cOsdMenu::AddSubMenu(cOsdMenu *SubMenu)
{
delete subMenu;
subMenu = SubMenu;
subMenu->Display();
return osContinue; // convenience return value (see cMenuMain)
}
eOSStatus cOsdMenu::ProcessKey(eKeys Key)
{
if (subMenu) {
eOSStatus status = subMenu->ProcessKey(Key);
if (status == osBack) {
delete subMenu;
subMenu = NULL;
RefreshCurrent();
Display();
status = osContinue;
}
return status;
}
cOsdItem *item = Get(current);
if (item) {
eOSStatus status = item->ProcessKey(Key);
if (status != osUnknown)
return status;
}
switch (Key) {
case kUp: CursorUp(); break;
case kDown: CursorDown(); break;
case kBack: return osBack;
default: return osUnknown;
}
return osContinue;
}

68
osd.h Normal file
View File

@ -0,0 +1,68 @@
/*
* osd.h: Abstract On Screen Display layer
*
* 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 $
*/
#ifndef __OSD_H
#define __OSD_H
#include "config.h"
#include "interface.h"
#include "tools.h"
#define MAXOSDITEMS 9
enum eOSStatus { osUnknown,
osContinue,
osProcessed,
osChannels,
osTimer,
osRecordings,
osBack,
osEnd,
};
class cOsdItem : public cListObject {
private:
char *text;
int offset;
eOSStatus status;
protected:
bool fresh;
public:
cOsdItem(eOSStatus Status = osUnknown);
cOsdItem(char *Text, eOSStatus Status = 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);
};
class cOsdMenu : public cList<cOsdItem> {
private:
char *title;
int cols[cInterface::MaxCols];
int first, current, count;
cOsdMenu *subMenu;
protected:
void RefreshCurrent(void);
void DisplayCurrent(bool Current);
void CursorUp(void);
void CursorDown(void);
eOSStatus AddSubMenu(cOsdMenu *SubMenu);
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);
};
#endif //__OSD_H

119
osm.c Normal file
View File

@ -0,0 +1,119 @@
/*
* osm.c: On Screen Menu for the Video Disk Recorder
*
* Copyright (C) 2000 Klaus Schmidinger
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
* Or, point your browser to http://www.gnu.org/copyleft/gpl.html
*
* The author can be reached at kls@cadsoft.de
*
* 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 $
*/
#include "config.h"
#include "dvbapi.h"
#include "interface.h"
#include "menu.h"
#include "tools.h"
#ifdef DEBUG_REMOTE
#define KEYS_CONF "keys-pc.conf"
#else
#define KEYS_CONF "keys.conf"
#endif
int main(int argc, char *argv[])
{
openlog("vdr", LOG_PID | LOG_CONS, LOG_USER);
isyslog(LOG_INFO, "started");
Channels.Load("channels.conf");
Timers.Load("timers.conf");
if (!Keys.Load(KEYS_CONF))
Interface.LearnKeys();
Interface.Init();
cChannel::SwitchTo(CurrentChannel);
cMenuMain *Menu = NULL;
cTimer *Timer = NULL;
cDvbRecorder *Recorder = 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) {
// 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;
}
}
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???
}
}
eKeys key = Interface.GetKey();
if (Menu) {
switch (Menu->ProcessKey(key)) {
default: if (key != kMenu)
break;
case osBack:
case osEnd: delete Menu;
Menu = NULL;
break;
}
}
else {
switch (key) {
case kMenu: Menu = new cMenuMain;
Menu->Display();
break;
case kUp:
case kDown: {
int n = CurrentChannel + (key == kUp ? 1 : -1);
cChannel *channel = Channels.Get(n);
if (channel)
channel->Switch();
}
break;
default: break;
}
}
}
closelog();
return 1;
}

257
remote.c Normal file
View File

@ -0,0 +1,257 @@
/*
* remote.c: Interface to the Remote Control Unit
*
* See the main source file 'osm.c' for copyright information and
* how to reach the author.
*
* $Id: remote.c 1.1 2000/02/19 13:36:48 kls Exp $
*/
#include "remote.h"
#include <fcntl.h>
#include <netinet/in.h>
#include <string.h>
#include <sys/types.h>
#include <sys/time.h>
#include <termios.h>
#include <unistd.h>
#include "tools.h"
cRcIo::cRcIo(char *DeviceName)
{
dp = 0;
mode = modeB;
code = 0;
address = 0xFFFF;
t = 0;
firstTime = lastTime = 0;
minDelta = 0;
lastCommand = 0;
if ((f = open(DeviceName, O_RDWR | O_NONBLOCK)) >= 0) {
struct termios t;
if (tcgetattr(f, &t) == 0) {
cfsetspeed(&t, B9600);
cfmakeraw(&t);
if (tcsetattr(f, TCSAFLUSH, &t) == 0)
return;
}
close(f);
}
f = -1;
}
cRcIo::~cRcIo()
{
if (f >= 0)
close(f);
}
int cRcIo::ReceiveByte(bool Wait)
{
// Returns the byte if one was received within 1 second, -1 otherwise
if (f >= 0) {
fd_set set;
struct timeval timeout;
timeout.tv_sec = Wait ? 1 : 0;
timeout.tv_usec = Wait ? 0 : 10000;
FD_ZERO(&set);
FD_SET(f, &set);
if (select(FD_SETSIZE, &set, NULL, NULL, &timeout) > 0) {
if (FD_ISSET(f, &set)) {
unsigned char b;
if (read(f, &b, 1) == 1)
return b;
}
}
}
return -1;
}
bool cRcIo::SendByteHandshake(unsigned char c)
{
if (f >= 0 && write(f, &c, 1) == 1) {
for (int reply = ReceiveByte(); reply >= 0;) {
if (reply == c)
return true;
else if (reply == 'X') {
// skip any incoming RC code - it will come again
for (int i = 6; i--;) {
if (ReceiveByte(false) < 0)
return false;
}
}
else
return false;
}
}
return false;
}
bool cRcIo::SendByte(unsigned char c)
{
for (int retry = 5; retry--;) {
if (SendByteHandshake(c))
return true;
}
return false;
}
void cRcIo::Flush(int WaitSeconds)
{
time_t t0 = time(NULL);
for (;;) {
while (ReceiveByte(false) >= 0)
t0 = time(NULL);
if (time(NULL) - t0 >= WaitSeconds)
break;
}
}
bool cRcIo::SetCode(unsigned char Code, unsigned short Address)
{
code = Code;
address = Address;
minDelta = 200;
return SendCommand(code);
}
bool cRcIo::SetMode(unsigned char Mode)
{
mode = Mode;
return SendCommand(mode);
}
bool cRcIo::GetCommand(unsigned int *Command, unsigned short *Address)
{
#pragma pack(1)
union {
struct {
unsigned short address;
unsigned int command;
} data;
unsigned char raw[6];
} buffer;
#pragma pack()
Flush();
if (Command && ReceiveByte() == 'X') {
for (int i = 0; i < 6; i++) {
int b = ReceiveByte(false);
if (b >= 0)
buffer.raw[i] = b;
else
return false;
}
if (Address)
*Address = ntohs(buffer.data.address); // the PIC sends bytes in "network order"
else if (address != ntohs(buffer.data.address))
return false;
*Command = ntohl(buffer.data.command);
if (code == 'B' && address == 0x0000 && *Command == 0x00004000)
// Well, well, if it isn't the "d-box"...
// This remote control sends the above command before and after
// each keypress - let's just drop this:
return false;
if (*Command == lastCommand) {
// let's have a timeout to avoid getting overrun by commands
int now = time_ms();
int delta = now - lastTime;
if (delta < minDelta)
minDelta = delta; // dynamically adjust to the smallest delta
lastTime = now;
if (delta < minDelta * 1.3) { // if commands come in rapidly...
if (now - firstTime < 250)
return false; // ...repeat function kicks in after 250ms
return true;
}
}
lastTime = firstTime = time_ms();
lastCommand = *Command;
return true;
}
if (time(NULL) - t > 60) {
SendCommand(code); // in case the PIC listens to the wrong code
t = time(NULL);
}
return false;
}
bool cRcIo::SendCommand(unsigned char Cmd)
{
return SendByte(Cmd | 0x80);
}
bool cRcIo::Digit(int n, int v)
{
return SendByte(((n & 0x03) << 5) | (v & 0x0F) | (((dp >> n) & 0x01) << 4));
}
bool cRcIo::Number(int n, bool Hex)
{
if (!Hex) {
char buf[8];
sprintf(buf, "%4d", n & 0xFFFF);
n = 0;
for (char *d = buf; *d; d++) {
if (*d == ' ')
*d = 0xF;
n = (n << 4) | ((*d - '0') & 0x0F);
}
}
for (int i = 0; i < 4; i++) {
if (!Digit(i, n))
return false;
n >>= 4;
}
return SendCommand(mode);
}
bool cRcIo::String(char *s)
{
char *chars = mode == modeH ? "0123456789ABCDEF" : "0123456789-EHLP ";
int n = 0;
for (int i = 0; *s && i < 4; s++, i++) {
n <<= 4;
for (char *c = chars; *c; c++) {
if (*c == *s) {
n |= c - chars;
break;
}
}
}
return Number(n, mode == modeH);
}
bool cRcIo::DetectCode(unsigned char *Code, unsigned short *Address)
{
// Caller should initialize 'Code' to 0 and call DetectCode()
// until it returns true. Whenever DetectCode() returns false
// and 'Code' is not 0, the caller can use 'Code' to display
// a message like "Trying code '%c'". If false is returned and
// 'Code' is 0, all possible codes have been tried and the caller
// can either stop calling DetectCode() (and give some error
// message), or start all over again.
if (*Code < 'A' || *Code > 'D') {
*Code = 'A';
return false;
}
if (*Code <= 'D') {
SetMode(modeH);
char buf[5];
sprintf(buf, "C0D%c", *Code);
String(buf);
SetCode(*Code, 0);
unsigned int Command;
if (GetCommand(&Command, Address))
return true;
if (*Code < 'D') {
(*Code)++;
return false;
}
}
*Code = 0;
return false;
}

43
remote.h Normal file
View File

@ -0,0 +1,43 @@
/*
* remote.h: Interface to the Remote Control Unit
*
* See the main source file 'osm.c' for copyright information and
* how to reach the author.
*
* $Id: remote.h 1.1 2000/02/19 13:36:48 kls Exp $
*/
#ifndef __REMOTE_H
#define __REMOTE_H
#include <stdio.h>
#include <time.h>
class cRcIo {
private:
int f;
unsigned char dp, code, mode;
unsigned short address;
time_t t;
int firstTime, lastTime, minDelta;
unsigned int lastCommand;
bool SendCommand(unsigned char Cmd);
int ReceiveByte(bool Wait = true);
bool SendByteHandshake(unsigned char c);
bool SendByte(unsigned char c);
public:
enum { modeH = 'h', modeB = 'b', modeS = 's' };
cRcIo(char *DeviceName);
~cRcIo();
void Flush(int WaitSeconds = 0);
bool SetCode(unsigned char Code, unsigned short Address);
bool SetMode(unsigned char Mode);
bool GetCommand(unsigned int *Command, unsigned short *Address = NULL);
bool Digit(int n, int v);
bool Number(int n, bool Hex = false);
void Points(unsigned char Dp) { dp = Dp; }
bool String(char *s);
bool DetectCode(unsigned char *Code, unsigned short *Address);
};
#endif //__REMOTE_H

9
timers.conf Normal file
View File

@ -0,0 +1,9 @@
1:2:-----S-:2210:2320:H:99:99:Wochenshow
1:3: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:#

124
tools.c Normal file
View File

@ -0,0 +1,124 @@
/*
* tools.c: Various tools
*
* 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 $
*/
#include "tools.h"
#include <stdlib.h>
#include <sys/time.h>
int time_ms(void)
{
struct timeval t;
if (gettimeofday(&t, NULL) == 0)
return t.tv_sec * 1000 + t.tv_usec / 1000;
return 0;
}
// --- cListObject -----------------------------------------------------------
cListObject::cListObject(void)
{
prev = next = NULL;
}
cListObject::~cListObject()
{
}
void cListObject::Append(cListObject *Object)
{
next = Object;
Object->prev = this;
}
void cListObject::Unlink(void)
{
if (next)
next->prev = prev;
if (prev)
prev->next = next;
}
int cListObject::Index(void)
{
cListObject *p = prev;
int i = 0;
while (p) {
i++;
p = p->prev;
}
return i;
}
// --- cListBase -------------------------------------------------------------
cListBase::cListBase(void)
{
objects = lastObject = NULL;
}
cListBase::~cListBase()
{
Clear();
while (objects) {
cListObject *object = objects->Next();
delete objects;
objects = object;
}
}
void cListBase::Add(cListObject *Object)
{
if (lastObject)
lastObject->Append(Object);
else
objects = Object;
lastObject = Object;
}
void cListBase::Del(cListObject *Object)
{
if (Object == objects)
objects = Object->Next();
if (Object == lastObject)
lastObject = Object->Prev();
Object->Unlink();
delete Object;
}
void cListBase::Clear(void)
{
while (objects) {
cListObject *object = objects->Next();
delete objects;
objects = object;
}
objects = lastObject = NULL;
}
cListObject *cListBase::Get(int Index)
{
cListObject *object = objects;
while (object && Index-- > 0)
object = object->Next();
return object;
}
int cListBase::Count(void)
{
int n = 0;
cListObject *object = objects;
while (object) {
n++;
object = object->Next();
}
return n;
}

54
tools.h Normal file
View File

@ -0,0 +1,54 @@
/*
* tools.h: Various tools
*
* 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 $
*/
#ifndef __TOOLS_H
#define __TOOLS_H
#include <syslog.h>
//TODO
#define dsyslog syslog
#define esyslog syslog
#define isyslog syslog
class cListObject {
private:
cListObject *prev, *next;
public:
cListObject(void);
virtual ~cListObject();
void Append(cListObject *Object);
void Unlink(void);
int Index(void);
cListObject *Prev(void) { return prev; }
cListObject *Next(void) { return next; }
};
class cListBase {
protected:
cListObject *objects, *lastObject;
cListBase(void);
public:
virtual ~cListBase();
void Add(cListObject *Object);
void Del(cListObject *Object);
void Clear(void);
cListObject *Get(int Index);
int Count(void);
};
template<class T> class cList : public cListBase {
public:
T *Get(int Index) { return (T *)cListBase::Get(Index); }
T *First(void) { return (T *)objects; }
};
int time_ms(void);
#endif //__TOOLS_H