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