mirror of
https://github.com/VDR4Arch/vdr.git
synced 2023-10-10 13:36:52 +02:00
Initial revision
This commit is contained in:
commit
4a9d9c5876
37
Makefile
Normal file
37
Makefile
Normal 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
122
README
Normal 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
13
TODO
Normal 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
109
channels.conf
Normal 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
333
config.c
Normal 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
163
config.h
Normal 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
166
dvbapi.c
Normal 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
65
dvbapi.h
Normal 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
298
interface.c
Normal 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
41
interface.h
Normal 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
BIN
keys-pc.conf
Normal file
Binary file not shown.
19
keys.conf
Normal file
19
keys.conf
Normal 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
745
menu.c
Normal 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
21
menu.h
Normal 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
196
osd.c
Normal 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
68
osd.h
Normal 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
119
osm.c
Normal 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
257
remote.c
Normal 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
43
remote.h
Normal 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
9
timers.conf
Normal 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
124
tools.c
Normal 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
54
tools.h
Normal 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
|
Loading…
Reference in New Issue
Block a user