Implemented actual record/replay; support for CICAM

This commit is contained in:
Klaus Schmidinger 2000-04-15 17:38:11 +02:00
parent 571686d909
commit 735093b8fa
22 changed files with 1944 additions and 567 deletions

23
BUGS Normal file
View File

@ -0,0 +1,23 @@
Video Disk Recorder - Known Bugs
--------------------------------
* Sometimes picture and sound drift apart.
Presumably this is a problem in the card driver or firmware?
* When the on-screen display is activated during recording,
the video data stream gets corrupted, which results in a
distorted picture when replaying such a recording.
I assume this is a problem in the driver of firmware.
There is no such problem in replay mode.
* After a replay session the screen may go blank.
Haven't figured out yet how to ensure that it switches back to
the current channel.
* Every now and then the on-screen display shows nothing but
"noise". If that occurs, I have to stop the 'osm' program
and do a 'make reload' for the card driver. After that it
works fine again.
Presumably this is a problem in the card driver or firmware?
Or could it be a problem with the hardware?
Does anybody else observe this?

View File

@ -10,3 +10,11 @@ Video Disk Recorder OSM Revision History
- Support for "Red", "Green", "Yellow", "Blue" buttons. - Support for "Red", "Green", "Yellow", "Blue" buttons.
- Channels and Timers can now be added, deleted and moved. - Channels and Timers can now be added, deleted and moved.
- Basic record/play file handling support (no actual record/playback yet). - Basic record/play file handling support (no actual record/playback yet).
2000-04-15: Version 0.03
- Actual record/replay now works.
- Dropped the idea of different "recording qualities" (a 36GB harddisk is
able to store some 18 hours in full quality, so we don't really need that).
- Termination signals are now caught and the program cleans up before exiting.
- Support for CICAM.

39
MANUAL Normal file
View File

@ -0,0 +1,39 @@
Video Disk Recorder User's Manual
---------------------------------
* Selecting a Channel
You can select a channel either by pressing the "Up" or "Down" key (while
no On Screen Menu is displayed), or browsing through the channel list in
the menu and pressing "Ok" on the desired channel.
* Instant Recording
You can start recording the current channel by pressing the "Record"
button. This will create a timer event named "instant" that start
at the current time and records for two hours.
If you want to modify the recording time you need to edit the timer.
Stop instant recording by disabling or deleting the timer.
* Replaying a Recording
All recordings are listed in the "Recordings" menu. Browse through the
list with the "Up" and "Down" button and press "Ok" (or the "Red" button)
to start playback.
* Replay Control
- "Begin" Positions to beginning of the recording and starts playback
from there.
- "Pause" Halts playback at the current frame. Press again to continue
playback.
- "Stop" Stops playback and stores the current position, so that
playback can be resumed later at that point.
- "Search" Runs playback forward or backward at a higher speed. Press
again to resume normal speed.
- "Skip" Skips about 60 seconds forward or backward.
* Programming the Timer
Use the "Timer" menu to maintain your list of timer controlled recordings.

72
README
View File

@ -36,34 +36,13 @@ about that driver). For example, if the DVB driver was
extracted into the directory /home/kls/vdr/DVB, then this extracted into the directory /home/kls/vdr/DVB, then this
package should be extracted into /home/kls/vdr/OSM. package should be extracted into /home/kls/vdr/OSM.
In order for the menu colors to work correctly you may want This program requires the card driver version 0.04 or higher
to replace the function RGB2YUV() in DVB/driver/dvb.c with to work properly.
static u32 RGB2YUV(u16 R, u16 G, u16 B)
{
u16 y, u, v;
u16 Y, Cr, Cb;
y = R * 77 + G * 150 + B * 29; // Luma=0.299R+0.587G+0.114B 0..65535
u = 2048+B * 8 -(y>>5); // Cr 0..4095
v = 2048+R * 8 -(y>>5); // Cb 0..4095
Y = y >> 8;
Cb= u >> 4;
Cr= v >> 4;
return Cr|(Cb<<16)|(Y<<8);
}
(this may no longer be necessary with driver versions after 0.03c).
After extracting the package, change into the OSM directory After extracting the package, change into the OSM directory
and type 'make'. This should produce an executable file and type 'make'. This should produce an executable file
named 'osm', which can be run after the DVB driver has been named 'osm', which can be run after the DVB driver has been
installed. There may be several warnings about "implicit declaration installed.
of function `int asprintf(...)'" during the compilation, which I was
unable to avoid (anybody know how to avoid them?). Just ignore them,
the program will work, anyway.
There are two macros you can use to customize the 'osm' program There are two macros you can use to customize the 'osm' program
at compile time. Adding "DEBUG_REMOTE=1" to the 'make' call at compile time. Adding "DEBUG_REMOTE=1" to the 'make' call
@ -88,28 +67,43 @@ 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 so for the moment please look at the source code (config.c) to see
the meaning of the various fields. 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: Learning the remote control keys:
--------------------------------- ---------------------------------
The remote control configuration file 'keys.conf' that comes with There is no default 'keys.conf' file, so if you compile the program
this package contains the codes for the "d-box" remote control unit. without 'DEBUG_REMOTE=1' you will have to go through a "teach-in"
If you want to use a different remote control unit, simply delete session that allows the program to learn your remote control codes.
the file 'keys.conf' and restart the 'osm' program. The program will It will first attempt to determine the basic data transfer mode and
then start a key learning session in which it first attempts to determine timing of your remote control unit, and then will ask you to press one
the basic data transfer mode and timing of your remote control unit, key after the other so that it can learn the various key codes. You will
and then will ask you to press one key after the other so that it can at least need to provide an "Up" and a "Down" key, so that you can switch
learn the various key codes. You will at least need to provide an "Up" channels. The rest of the key definitions is optional, but the more keys
and a "Down" key, so that you can switch channels. The rest of the key you define, the more you will be able to navigate through the menus and
definitions is optional, but the more keys you define, the more you control recording/replaying.
will be able to navigate through the menus.
If the program has been built with "DEBUG_REMOTE=1", it will use the 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 key configuration file 'keys-pc.conf', so that you won't loose data
when switching between normal and debug mode. when switching between normal and debug mode.
The default PC key assignments are:
Up, Down, Left, Right Crsr keys in numeric block
Menu '5' in numeric block
Ok Enter
Back Backspace
0..9 '0'..'9' in top row
Red, Green, Yellow, Blue 'F1'..'F4'
Record 'r'
Pause 'p'
Stop 's'
Begin 'B'
SearchForward 'f'
SearchBack 'b'
SkipForward 'PgDn' in numeric block
SkipBack 'PgUp' in numeric block
If you prefer different key assignments, simply delete the file
'keys-pc.conf' and restart 'osm' to get into learning mode.
Navigating through the On Screen Menus: Navigating through the On Screen Menus:
--------------------------------------- ---------------------------------------

6
TODO
View File

@ -1,7 +1,7 @@
TODO list for the Video Disk Recorder project TODO list for the Video Disk Recorder project
--------------------------------------------- ---------------------------------------------
* Implement recording to disk and playback from disk. * Channel select via numeric keys.
* Make it work with two DVB-S PCI cards to allow simultaneous * Make it work with two DVB-S PCI cards to allow simultaneous
recording of one programme, while replaying another programme recording of one programme, while replaying another programme
(or maybe the same one, but time delayed). (or maybe the same one, but time delayed).
@ -10,3 +10,7 @@ TODO list for the Video Disk Recorder project
* Implement "on-disk editing" to allow "cutting out" of certain * Implement "on-disk editing" to allow "cutting out" of certain
scenes in order to archive them (or, reversely, cut out scenes in order to archive them (or, reversely, cut out
commercial breaks). commercial breaks).
* Implement on-screen display of replay progress (progress bar
and/or time index).
* Implement channel scanning.
* Better support for encrypted channels.

View File

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

View File

@ -4,7 +4,7 @@
* See the main source file 'osm.c' for copyright information and * See the main source file 'osm.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: config.c 1.2 2000/03/05 16:14:27 kls Exp $ * $Id: config.c 1.3 2000/04/15 12:48:00 kls Exp $
*/ */
#include "config.h" #include "config.h"
@ -16,28 +16,36 @@
// -- cKeys ------------------------------------------------------------------ // -- cKeys ------------------------------------------------------------------
tKey keyTable[] = { // "Up" and "Down" must be the first two keys! tKey keyTable[] = { // "Up" and "Down" must be the first two keys!
{ kUp, "Up", 0 }, { kUp, "Up", 0 },
{ kDown, "Down", 0 }, { kDown, "Down", 0 },
{ kMenu, "Menu", 0 }, { kMenu, "Menu", 0 },
{ kOk, "Ok", 0 }, { kOk, "Ok", 0 },
{ kBack, "Back", 0 }, { kBack, "Back", 0 },
{ kLeft, "Left", 0 }, { kLeft, "Left", 0 },
{ kRight, "Right", 0 }, { kRight, "Right", 0 },
{ k0, "0", 0 }, { k0, "0", 0 },
{ k1, "1", 0 }, { k1, "1", 0 },
{ k2, "2", 0 }, { k2, "2", 0 },
{ k3, "3", 0 }, { k3, "3", 0 },
{ k4, "4", 0 }, { k4, "4", 0 },
{ k5, "5", 0 }, { k5, "5", 0 },
{ k6, "6", 0 }, { k6, "6", 0 },
{ k7, "7", 0 }, { k7, "7", 0 },
{ k8, "8", 0 }, { k8, "8", 0 },
{ k9, "9", 0 }, { k9, "9", 0 },
{ kRed, "Red", 0 }, { kRed, "Red", 0 },
{ kGreen, "Green", 0 }, { kGreen, "Green", 0 },
{ kYellow, "Yellow", 0 }, { kYellow, "Yellow", 0 },
{ kBlue, "Blue", 0 }, { kBlue, "Blue", 0 },
{ kNone, "", 0 }, { kRecord, "Record", 0 },
{ kPause, "Pause", 0 },
{ kStop, "Stop", 0 },
{ kBegin, "Begin", 0 },
{ kSearchForward, "SearchForward", 0 },
{ kSearchBack, "SearchBack", 0 },
{ kSkipForward, "SkipForward", 0 },
{ kSkipBack, "SkipBack", 0 },
{ kNone, "", 0 },
}; };
cKeys::cKeys(void) cKeys::cKeys(void)
@ -88,7 +96,7 @@ bool cKeys::Load(char *FileName)
} }
} }
if (Name) { if (Name) {
fprintf(stderr, "unknown key in %s, line %d\n", fileName, line); esyslog(LOG_ERR, "unknown key in %s, line %d\n", fileName, line);
result = false; result = false;
break; break;
} }
@ -96,17 +104,17 @@ bool cKeys::Load(char *FileName)
} }
continue; continue;
} }
fprintf(stderr, "error in %s, line %d\n", fileName, line); esyslog(LOG_ERR, "error in %s, line %d\n", fileName, line);
result = false; result = false;
break; break;
} }
fclose(f); fclose(f);
} }
else else
fprintf(stderr, "can't open '%s'\n", fileName); esyslog(LOG_ERR, "can't open '%s'\n", fileName);
} }
else else
fprintf(stderr, "no key configuration file name supplied!\n"); esyslog(LOG_ERR, "no key configuration file name supplied!\n");
return result; return result;
} }
@ -172,12 +180,14 @@ cChannel::cChannel(const cChannel *Channel)
srate = Channel ? Channel->srate : 27500; srate = Channel ? Channel->srate : 27500;
vpid = Channel ? Channel->vpid : 255; vpid = Channel ? Channel->vpid : 255;
apid = Channel ? Channel->apid : 256; apid = Channel ? Channel->apid : 256;
ca = Channel ? Channel->ca : 0;
pnr = Channel ? Channel->pnr : 0;
} }
bool cChannel::Parse(char *s) bool cChannel::Parse(char *s)
{ {
char *buffer = NULL; char *buffer = NULL;
if (7 == sscanf(s, "%a[^:]:%d:%c:%d:%d:%d:%d", &buffer, &frequency, &polarization, &diseqc, &srate, &vpid, &apid)) { if (9 == sscanf(s, "%a[^:]:%d:%c:%d:%d:%d:%d:%d:%d", &buffer, &frequency, &polarization, &diseqc, &srate, &vpid, &apid, &ca, &pnr)) {
strncpy(name, buffer, MaxChannelName - 1); strncpy(name, buffer, MaxChannelName - 1);
name[strlen(buffer)] = 0; name[strlen(buffer)] = 0;
delete buffer; delete buffer;
@ -188,20 +198,21 @@ bool cChannel::Parse(char *s)
bool cChannel::Save(FILE *f) bool cChannel::Save(FILE *f)
{ {
return fprintf(f, "%s:%d:%c:%d:%d:%d:%d\n", name, frequency, polarization, diseqc, srate, vpid, apid) > 0; return fprintf(f, "%s:%d:%c:%d:%d:%d:%d:%d:%d\n", name, frequency, polarization, diseqc, srate, vpid, apid, ca, pnr) > 0;
} }
bool cChannel::Switch(void) bool cChannel::Switch(void)
{ {
if (!ChannelLocked) { if (!DvbApi.Recording()) {
isyslog(LOG_INFO, "switching to channel %d", Index() + 1); isyslog(LOG_INFO, "switching to channel %d", Index() + 1);
CurrentChannel = Index(); CurrentChannel = Index();
Interface.DisplayChannel(CurrentChannel + 1, name); Interface.DisplayChannel(CurrentChannel + 1, name);
for (int i = 3; --i;) { for (int i = 3; --i;) {
if (DvbSetChannel(frequency, polarization, diseqc, srate, vpid, apid)) if (DvbApi.SetChannel(frequency, polarization, diseqc, srate, vpid, apid, ca, pnr))
return true; return true;
esyslog(LOG_ERR, "retrying"); esyslog(LOG_ERR, "retrying");
} }
return false;
} }
Interface.Info("Channel locked (recording)!"); Interface.Info("Channel locked (recording)!");
return false; return false;
@ -215,20 +226,23 @@ bool cChannel::SwitchTo(int i)
// -- cTimer ----------------------------------------------------------------- // -- cTimer -----------------------------------------------------------------
cTimer::cTimer(void) cTimer::cTimer(bool Instant)
{ {
startTime = stopTime = 0; startTime = stopTime = 0;
recording = false; recording = false;
active = 1; active = Instant;
channel = CurrentChannel + 1; channel = CurrentChannel + 1;
day = 1; //XXX today! time_t t = time(NULL);
start = 0; //XXX now! struct tm *now = localtime(&t);
stop = 0; //XXX now + 2h! day = now->tm_mday;
start = now->tm_hour * 100 + now->tm_min;
stop = start + 200; // "instant recording" records 2 hours by default
if (stop >= 2400)
stop -= 2400;
//TODO VPS??? //TODO VPS???
quality = 'H';
priority = 99; priority = 99;
lifetime = 99; lifetime = 99;
*file = 0; strcpy(file, Instant ? "instant" : "");
} }
int cTimer::TimeToInt(int t) int cTimer::TimeToInt(int t)
@ -286,7 +300,7 @@ bool cTimer::Parse(char *s)
{ {
char *buffer1 = NULL; char *buffer1 = NULL;
char *buffer2 = 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)) { if (8 == sscanf(s, "%d:%d:%a[^:]:%d:%d:%d:%d:%as", &active, &channel, &buffer1, &start, &stop, &priority, &lifetime, &buffer2)) {
day = ParseDay(buffer1); day = ParseDay(buffer1);
strncpy(file, buffer2, MaxFileName - 1); strncpy(file, buffer2, MaxFileName - 1);
file[strlen(buffer2)] = 0; file[strlen(buffer2)] = 0;
@ -299,7 +313,7 @@ bool cTimer::Parse(char *s)
bool cTimer::Save(FILE *f) 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; return fprintf(f, "%d:%d:%s:%d:%d:%d:%d:%s\n", active, channel, PrintDay(day), start, stop, priority, lifetime, file) > 0;
} }
bool cTimer::IsSingleEvent(void) bool cTimer::IsSingleEvent(void)
@ -383,7 +397,6 @@ cKeys Keys;
// -- cChannels -------------------------------------------------------------- // -- cChannels --------------------------------------------------------------
int CurrentChannel = 0; int CurrentChannel = 0;
bool ChannelLocked = false;
cChannels Channels; cChannels Channels;

View File

@ -4,12 +4,13 @@
* See the main source file 'osm.c' for copyright information and * See the main source file 'osm.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: config.h 1.2 2000/03/05 14:58:23 kls Exp $ * $Id: config.h 1.3 2000/04/15 12:44:23 kls Exp $
*/ */
#ifndef __CONFIG_H #ifndef __CONFIG_H
#define __CONFIG_H #define __CONFIG_H
#define _GNU_SOURCE
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <time.h> #include <time.h>
@ -30,6 +31,14 @@ enum eKeys { // "Up" and "Down" must be the first two keys!
kGreen, kGreen,
kYellow, kYellow,
kBlue, kBlue,
kRecord,
kPause,
kStop,
kBegin,
kSearchForward,
kSearchBack,
kSkipForward,
kSkipBack,
kNone kNone
}; };
@ -64,6 +73,8 @@ public:
int srate; int srate;
int vpid; int vpid;
int apid; int apid;
int ca;
int pnr;
cChannel(void); cChannel(void);
cChannel(const cChannel *Channel); cChannel(const cChannel *Channel);
bool Parse(char *s); bool Parse(char *s);
@ -84,11 +95,10 @@ public:
int start; int start;
int stop; int stop;
//TODO VPS??? //TODO VPS???
char quality;
int priority; int priority;
int lifetime; int lifetime;
char file[MaxFileName]; char file[MaxFileName];
cTimer(void); cTimer(bool Instant = false);
bool Parse(char *s); bool Parse(char *s);
bool Save(FILE *f); bool Save(FILE *f);
bool IsSingleEvent(void); bool IsSingleEvent(void);
@ -128,7 +138,7 @@ public:
if (l->Parse(buffer)) if (l->Parse(buffer))
Add(l); Add(l);
else { else {
fprintf(stderr, "error in %s, line %d\n", fileName, line); esyslog(LOG_ERR, "error in %s, line %d\n", fileName, line);
delete l; delete l;
result = false; result = false;
break; break;
@ -137,7 +147,7 @@ public:
fclose(f); fclose(f);
} }
else { else {
fprintf(stderr, "can't open '%s'\n", fileName); esyslog(LOG_ERR, "can't open '%s'\n", fileName);
result = false; result = false;
} }
return result; return result;
@ -168,7 +178,6 @@ class cChannels : public cConfig<cChannel> {};
class cTimers : public cConfig<cTimer> {}; class cTimers : public cConfig<cTimer> {};
extern int CurrentChannel; extern int CurrentChannel;
extern bool ChannelLocked;
extern cChannels Channels; extern cChannels Channels;
extern cTimers Timers; extern cTimers Timers;

1420
dvbapi.c

File diff suppressed because it is too large Load Diff

121
dvbapi.h
View File

@ -4,20 +4,21 @@
* See the main source file 'osm.c' for copyright information and * See the main source file 'osm.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: dvbapi.h 1.2 2000/03/06 19:47:20 kls Exp $ * $Id: dvbapi.h 1.3 2000/04/15 13:36:10 kls Exp $
*/ */
#ifndef __DVBAPI_H #ifndef __DVBAPI_H
#define __DVBAPI_H #define __DVBAPI_H
// FIXME: these should be defined in ../DVB/driver/dvb.h!!! // FIXME: these should be defined in ../DVB/driver/dvb.h!!!
typedef unsigned int u32; typedef unsigned int __u32;
typedef unsigned short u16; typedef unsigned short __u16;
typedef unsigned char u8; typedef unsigned char __u8;
#if defined(DEBUG_OSD) || defined(DEBUG_REMOTE) #if defined(DEBUG_OSD) || defined(DEBUG_REMOTE)
#include <ncurses.h> #include <ncurses.h>
#endif #endif
#include <stdio.h>
#include "../DVB/driver/dvb.h" #include "../DVB/driver/dvb.h"
enum eDvbColor { clrBackground, enum eDvbColor { clrBackground,
@ -36,56 +37,15 @@ enum eDvbColor { clrBackground,
clrWhite, clrWhite,
}; };
extern const char *DvbQuality; // Low, Medium, High class cDvbApi {
bool DvbSetChannel(int FrequencyMHz, char Polarization, int Diseqc, int Srate, int Vpid, int Apid);
class cDvbRecorder {
private: private:
bool recording; int videoDev;
public: public:
cDvbRecorder(void); cDvbApi(void);
~cDvbRecorder(); ~cDvbApi();
bool Recording(void);
// Returns true if this recorder is currently recording, false if it // On Screen Display facilities
// is playing back or does nothing.
bool Record(const char *FileName, char Quality);
// Starts recording the current channel into the given file, with the
// given quality level. Any existing file will be overwritten.
// 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 (or the frame with the absolute value of
// Frame) and will do an implicit Pause() there.
// If there is already a playback session active, it will be stopped
// and the new file or frame (which may be in the same file) will
// be played back.
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.
};
class cDvbOsd {
private: private:
enum { charWidth = 12, // average character width enum { charWidth = 12, // average character width
lineHeight = 27 // smallest text height lineHeight = 27 // smallest text height
@ -95,19 +55,70 @@ private:
enum { MaxColorPairs = 16 }; enum { MaxColorPairs = 16 };
int colorPairs[MaxColorPairs]; int colorPairs[MaxColorPairs];
void SetColor(eDvbColor colorFg, eDvbColor colorBg = clrBackground); void SetColor(eDvbColor colorFg, eDvbColor colorBg = clrBackground);
#else
void Cmd(OSD_Command cmd, int color = 0, int x0 = 0, int y0 = 0, int x1 = 0, int y1 = 0, const void *data = NULL);
#endif #endif
int cols, rows; int cols, rows;
void Cmd(OSD_Command cmd, int color = 0, int x0 = 0, int y0 = 0, int x1 = 0, int y1 = 0, const void *data = NULL);
public: public:
cDvbOsd(void);
~cDvbOsd();
void Open(int w, int h); void Open(int w, int h);
void Close(void); void Close(void);
void Clear(void); void Clear(void);
void Fill(int x, int y, int w, int h, eDvbColor color = clrBackground); void Fill(int x, int y, int w, int h, eDvbColor color = clrBackground);
void ClrEol(int x, int y, eDvbColor color = clrBackground); void ClrEol(int x, int y, eDvbColor color = clrBackground);
void Text(int x, int y, const char *s, eDvbColor colorFg = clrWhite, eDvbColor colorBg = clrBackground); void Text(int x, int y, const char *s, eDvbColor colorFg = clrWhite, eDvbColor colorBg = clrBackground);
// Channel facilities
bool SetChannel(int FrequencyMHz, char Polarization, int Diseqc, int Srate, int Vpid, int Apid, int Ca, int Pnr);
// Record/Replay facilities
private:
enum { dvbStop = 1, // let's not have 0 as a command
dvbPauseReplay,
dvbFastForward,
dvbFastRewind,
dvbSkip,
};
bool isMainProcess;
pid_t pidRecord, pidReplay;
int fromRecord, toRecord;
int fromReplay, toReplay;
void SetReplayMode(int Mode);
void KillProcess(pid_t pid);
public:
bool Recording(void);
// Returns true if we are currently recording.
bool Replaying(void);
// Returns true if we are currently replaying.
bool StartRecord(const char *FileName);
// Starts recording the current channel into the given file.
// In order to be able to record longer movies,
// a numerical suffix will be appended to the file name. The inital
// value of that suffix will be larger than any existing file under
// the given name, thus allowing an interrupted recording to continue
// gracefully.
// Returns true if recording was started successfully.
// If there is already a recording session active, false will be
// returned.
void StopRecord(void);
// Stops the current recording session (if any).
bool StartReplay(const char *FileName);
// Starts replaying the given file.
// If there is already a replay session active, it will be stopped
// and the new file will be played back.
void StopReplay(void);
// Stops the current replay session (if any).
void PauseReplay(void);
// Pauses the current replay session, or resumes a paused session.
void FastForward(void);
// Runs the current replay session forward at a higher speed.
void FastRewind(void);
// Runs the current replay session backwards at a higher speed.
void Skip(int Seconds);
// Skips the given number of seconds in the current replay session.
// The sign of 'Seconds' determines the direction in which to skip.
// Use a very large negative value to go all the way back to the
// beginning of the recording.
}; };
#endif //__DVBAPI_H #endif //__DVBAPI_H

View File

@ -4,7 +4,7 @@
* See the main source file 'osm.c' for copyright information and * See the main source file 'osm.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: interface.c 1.2 2000/03/06 19:45:03 kls Exp $ * $Id: interface.c 1.3 2000/04/15 17:38:11 kls Exp $
*/ */
#include "interface.h" #include "interface.h"
@ -15,10 +15,10 @@
#define MenuColumns 40 #define MenuColumns 40
#ifndef DEBUG_REMOTE #ifndef DEBUG_REMOTE
cRcIo RcIo("/dev/ttyS1");//XXX cRcIo RcIo("/dev/ttyS1");
#endif #endif
cDvbOsd DvbOsd; //XXX member of cInterface??? cDvbApi DvbApi; //XXX member of cInterface???
cInterface Interface; cInterface Interface;
@ -38,19 +38,22 @@ void cInterface::Init(void)
void cInterface::Open(void) void cInterface::Open(void)
{ {
if (!open++) if (!open++)
DvbOsd.Open(MenuColumns, MenuLines); DvbApi.Open(MenuColumns, MenuLines);
} }
void cInterface::Close(void) void cInterface::Close(void)
{ {
if (open == 1)
Clear();
if (!--open) if (!--open)
DvbOsd.Close(); DvbApi.Close();
} }
unsigned int cInterface::GetCh(void) unsigned int cInterface::GetCh(void)
{ {
#ifdef DEBUG_REMOTE #ifdef DEBUG_REMOTE
return getch(); int c = getch();
return (c > 0) ? c : 0;
#else #else
//XXX #ifdef DEBUG_OSD //XXX #ifdef DEBUG_OSD
//XXX wrefresh(window);//XXX //XXX wrefresh(window);//XXX
@ -80,13 +83,13 @@ eKeys cInterface::Wait(int Seconds)
void cInterface::Clear(void) void cInterface::Clear(void)
{ {
if (open) if (open)
DvbOsd.Clear(); DvbApi.Clear();
} }
void cInterface::ClearEol(int x, int y, eDvbColor Color) void cInterface::ClearEol(int x, int y, eDvbColor Color)
{ {
if (open) if (open)
DvbOsd.ClrEol(x, y, Color); DvbApi.ClrEol(x, y, Color);
} }
void cInterface::SetCols(int *c) void cInterface::SetCols(int *c)
@ -101,7 +104,7 @@ void cInterface::SetCols(int *c)
void cInterface::Write(int x, int y, const char *s, eDvbColor FgColor, eDvbColor BgColor) void cInterface::Write(int x, int y, const char *s, eDvbColor FgColor, eDvbColor BgColor)
{ {
if (open) if (open)
DvbOsd.Text(x, y, s, FgColor, BgColor); DvbApi.Text(x, y, s, FgColor, BgColor);
} }
void cInterface::WriteText(int x, int y, const char *s, bool Current) void cInterface::WriteText(int x, int y, const char *s, bool Current)
@ -187,8 +190,8 @@ void cInterface::HelpButton(int Index, const char *Text, eDvbColor FgColor, eDvb
int l = (w - strlen(Text)) / 2; int l = (w - strlen(Text)) / 2;
if (l < 0) if (l < 0)
l = 0; l = 0;
DvbOsd.Fill(Index * w, -1, w, 1, BgColor); DvbApi.Fill(Index * w, -1, w, 1, BgColor);
DvbOsd.Text(Index * w + l, -1, Text, FgColor, BgColor); DvbApi.Text(Index * w + l, -1, Text, FgColor, BgColor);
} }
} }

View File

@ -4,7 +4,7 @@
* See the main source file 'osm.c' for copyright information and * See the main source file 'osm.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: interface.h 1.2 2000/02/27 14:54:02 kls Exp $ * $Id: interface.h 1.3 2000/03/19 14:03:28 kls Exp $
*/ */
#ifndef __INTERFACE_H #ifndef __INTERFACE_H
@ -45,5 +45,6 @@ public:
}; };
extern cInterface Interface; extern cInterface Interface;
extern cDvbApi DvbApi; //XXX member of cInterface???
#endif //__INTERFACE_H #endif //__INTERFACE_H

Binary file not shown.

View File

@ -1,23 +0,0 @@
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
Red 000025E2
Green 00002AE2
Yellow 00005AE2
Blue 00000000

29
menu.c
View File

@ -4,7 +4,7 @@
* See the main source file 'osm.c' for copyright information and * See the main source file 'osm.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: menu.c 1.2 2000/03/05 15:37:31 kls Exp $ * $Id: menu.c 1.3 2000/04/15 15:07:36 kls Exp $
*/ */
#include "menu.h" #include "menu.h"
@ -502,13 +502,15 @@ cMenuEditChannel::cMenuEditChannel(int Index)
channel = Channels.Get(Index); channel = Channels.Get(Index);
if (channel) { if (channel) {
data = *channel; data = *channel;
Add(new cMenuEditStrItem("Name", data.name, sizeof(data.name), FileNameChars)); Add(new cMenuEditStrItem( "Name", data.name, sizeof(data.name), FileNameChars));
Add(new cMenuEditIntItem("Frequency", &data.frequency, 10000, 13000)); //TODO exact limits??? Add(new cMenuEditIntItem( "Frequency", &data.frequency, 10000, 13000)); //TODO exact limits???
Add(new cMenuEditChrItem("Polarization", &data.polarization, "hv")); Add(new cMenuEditChrItem( "Polarization", &data.polarization, "hv"));
Add(new cMenuEditIntItem("Diseqc", &data.diseqc, 0, 10)); //TODO exact limits??? 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( "Srate", &data.srate, 22000, 27500)); //TODO exact limits - toggle???
Add(new cMenuEditIntItem("Vpid", &data.vpid, 0, 10000)); //TODO exact limits??? Add(new cMenuEditIntItem( "Vpid", &data.vpid, 0, 10000)); //TODO exact limits???
Add(new cMenuEditIntItem("Apid", &data.apid, 0, 10000)); //TODO exact limits??? Add(new cMenuEditIntItem( "Apid", &data.apid, 0, 10000)); //TODO exact limits???
Add(new cMenuEditBoolItem("CA", &data.ca));
Add(new cMenuEditIntItem( "Pnr", &data.pnr, 0, 10000)); //TODO exact limits???
} }
} }
@ -599,7 +601,7 @@ eOSState cMenuChannels::Edit(void)
{ {
if (HasSubMenu() || Count() == 0) if (HasSubMenu() || Count() == 0)
return osContinue; return osContinue;
isyslog(LOG_INFO, "editing timer %d", Current() + 1); isyslog(LOG_INFO, "editing channel %d", Current() + 1);
return AddSubMenu(new cMenuEditChannel(Current())); return AddSubMenu(new cMenuEditChannel(Current()));
} }
@ -711,23 +713,24 @@ private:
cTimer *timer; cTimer *timer;
cTimer data; cTimer data;
public: public:
cMenuEditTimer(int Index); cMenuEditTimer(int Index, bool New = false);
virtual eOSState ProcessKey(eKeys Key); virtual eOSState ProcessKey(eKeys Key);
}; };
cMenuEditTimer::cMenuEditTimer(int Index) cMenuEditTimer::cMenuEditTimer(int Index, bool New)
:cOsdMenu("Edit Timer", 10) :cOsdMenu("Edit Timer", 10)
{ {
timer = Timers.Get(Index); timer = Timers.Get(Index);
if (timer) { if (timer) {
data = *timer; data = *timer;
if (New)
data.active = 1;
Add(new cMenuEditBoolItem("Active", &data.active)); Add(new cMenuEditBoolItem("Active", &data.active));
Add(new cMenuEditChanItem("Channel", &data.channel)); Add(new cMenuEditChanItem("Channel", &data.channel));
Add(new cMenuEditDayItem( "Day", &data.day)); Add(new cMenuEditDayItem( "Day", &data.day));
Add(new cMenuEditTimeItem("Start", &data.start)); Add(new cMenuEditTimeItem("Start", &data.start));
Add(new cMenuEditTimeItem("Stop", &data.stop)); Add(new cMenuEditTimeItem("Stop", &data.stop));
//TODO VPS??? //TODO VPS???
Add(new cMenuEditChrItem( "Quality", &data.quality, DvbQuality));
Add(new cMenuEditIntItem( "Priority", &data.priority, 0, 99)); Add(new cMenuEditIntItem( "Priority", &data.priority, 0, 99));
Add(new cMenuEditIntItem( "Lifetime", &data.lifetime, 0, 99)); Add(new cMenuEditIntItem( "Lifetime", &data.lifetime, 0, 99));
Add(new cMenuEditStrItem( "File", data.file, sizeof(data.file), FileNameChars)); Add(new cMenuEditStrItem( "File", data.file, sizeof(data.file), FileNameChars));
@ -843,7 +846,7 @@ eOSState cMenuTimers::New(void)
Add(new cMenuTimerItem(timer->Index()/*XXX*/, timer), true); Add(new cMenuTimerItem(timer->Index()/*XXX*/, timer), true);
Timers.Save(); Timers.Save();
isyslog(LOG_INFO, "timer %d added", timer->Index() + 1); isyslog(LOG_INFO, "timer %d added", timer->Index() + 1);
return AddSubMenu(new cMenuEditTimer(Current())); return AddSubMenu(new cMenuEditTimer(Current(), true));
} }
eOSState cMenuTimers::Del(void) eOSState cMenuTimers::Del(void)

150
osm.c
View File

@ -22,9 +22,10 @@
* *
* The project's page is at http://www.cadsoft.de/people/kls/vdr * The project's page is at http://www.cadsoft.de/people/kls/vdr
* *
* $Id: osm.c 1.2 2000/03/05 17:18:15 kls Exp $ * $Id: osm.c 1.3 2000/04/15 14:04:21 kls Exp $
*/ */
#include <signal.h>
#include "config.h" #include "config.h"
#include "interface.h" #include "interface.h"
#include "menu.h" #include "menu.h"
@ -37,6 +38,13 @@
#define KEYS_CONF "keys.conf" #define KEYS_CONF "keys.conf"
#endif #endif
static int Interrupted = 0;
void SignalHandler(int signum)
{
Interrupted = signum;
}
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
openlog("vdr", LOG_PID | LOG_CONS, LOG_USER); openlog("vdr", LOG_PID | LOG_CONS, LOG_USER);
@ -50,69 +58,93 @@ int main(int argc, char *argv[])
cChannel::SwitchTo(CurrentChannel); cChannel::SwitchTo(CurrentChannel);
if (signal(SIGHUP, SignalHandler) == SIG_IGN) signal(SIGHUP, SIG_IGN);
if (signal(SIGINT, SignalHandler) == SIG_IGN) signal(SIGINT, SIG_IGN);
if (signal(SIGTERM, SignalHandler) == SIG_IGN) signal(SIGTERM, SIG_IGN);
cMenuMain *Menu = NULL; cMenuMain *Menu = NULL;
cTimer *Timer = NULL; cTimer *Timer = NULL;
cRecording *Recording = NULL; cRecording *Recording = NULL;
for (;;) { while (!Interrupted) {
AssertFreeDiskSpace(); AssertFreeDiskSpace();
if (!Recording && !Timer && (Timer = cTimer::GetMatch()) != NULL) { if (!Recording && !Timer && (Timer = cTimer::GetMatch()) != NULL) {
DELETENULL(Menu); DELETENULL(Menu);
// make sure the timer won't be deleted: // make sure the timer won't be deleted:
Timer->SetRecording(true); Timer->SetRecording(true);
// switch to channel: // switch to channel:
cChannel::SwitchTo(Timer->channel - 1); cChannel::SwitchTo(Timer->channel - 1);
ChannelLocked = true; // start recording:
// start recording: Recording = new cRecording(Timer);
Recording = new cRecording(Timer); if (!Recording->Record())
if (!Recording->Record()) DELETENULL(Recording);
DELETENULL(Recording);
}
if (Timer && !Timer->Matches()) {
// stop recording:
if (Recording) {
Recording->Stop();
DELETENULL(Recording);
}
// release channel and timer:
ChannelLocked = false;
Timer->SetRecording(false);
// clear single event timer:
if (Timer->IsSingleEvent()) {
DELETENULL(Menu); // must make sure no menu uses it
isyslog(LOG_INFO, "deleting timer %d", Timer->Index() + 1);
Timers.Del(Timer);
Timers.Save();
}
Timer = NULL;
}
eKeys key = Interface.GetKey();
if (Menu) {
switch (Menu->ProcessKey(key)) {
default: if (key != kMenu)
break;
case osBack:
case osEnd: DELETENULL(Menu);
break;
} }
} if (Timer && !Timer->Matches()) {
else { // stop recording:
switch (key) { if (Recording) {
case kMenu: Menu = new cMenuMain; Recording->Stop();
Menu->Display(); DELETENULL(Recording);
break; }
case kUp: // release timer:
case kDown: { Timer->SetRecording(false);
int n = CurrentChannel + (key == kUp ? 1 : -1); // clear single event timer:
cChannel *channel = Channels.Get(n); if (Timer->IsSingleEvent()) {
if (channel) DELETENULL(Menu); // must make sure no menu uses it
channel->Switch(); isyslog(LOG_INFO, "deleting timer %d", Timer->Index() + 1);
} Timers.Del(Timer);
break; Timers.Save();
default: break; }
Timer = NULL;
} }
} eKeys key = Interface.GetKey();
} if (Menu) {
switch (Menu->ProcessKey(key)) {
default: if (key != kMenu)
break;
case osBack:
case osEnd: DELETENULL(Menu);
break;
}
}
else {
switch (key) {
// Record/Replay Control:
case kBegin: DvbApi.Skip(-INT_MAX); break;
case kRecord: if (!DvbApi.Recording()) {
cTimer *timer = new cTimer(true);
Timers.Add(timer);
Timers.Save();
}
else
Interface.Error("Already recording!");
break;
case kPause: DvbApi.PauseReplay(); break;
case kStop: DvbApi.StopReplay(); break;
case kSearchBack: DvbApi.FastRewind(); break;
case kSearchForward: DvbApi.FastForward(); break;
case kSkipBack: DvbApi.Skip(-60); break;
case kSkipForward: DvbApi.Skip(60); break;
// Menu Control:
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;
}
}
}
isyslog(LOG_INFO, "caught signal %d", Interrupted);
DvbApi.StopRecord();
DvbApi.StopReplay();
//TODO kill any remaining sub-processes!
isyslog(LOG_INFO, "exiting", Interrupted);
closelog(); closelog();
return 1; return 0;
} }

View File

@ -4,9 +4,10 @@
* See the main source file 'osm.c' for copyright information and * See the main source file 'osm.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: recording.c 1.1 2000/03/05 17:16:22 kls Exp $ * $Id: recording.c 1.2 2000/04/15 13:29:02 kls Exp $
*/ */
#define _GNU_SOURCE
#include "recording.h" #include "recording.h"
#include <errno.h> #include <errno.h>
#include <stdio.h> #include <stdio.h>
@ -16,17 +17,17 @@
#define RECEXT ".rec" #define RECEXT ".rec"
#define DELEXT ".del" #define DELEXT ".del"
#define DATAFORMAT "%4d-%02d-%02d.%02d:%02d.%c.%02d.%02d" RECEXT #define DATAFORMAT "%4d-%02d-%02d.%02d:%02d.%02d.%02d" RECEXT
#define NAMEFORMAT "%s/%s/" DATAFORMAT #define NAMEFORMAT "%s/%s/" DATAFORMAT
#define FINDCMD "find %s -type f -name '%s'" #define FINDCMD "find %s -type d -name '%s'"
#define DFCMD "df -m %s" #define DFCMD "df -m %s"
#define MINDISKSPACE 1024 // MB #define MINDISKSPACE 1024 // MB
const char *BaseDir = "/video";//XXX #define DISKCHECKDELTA 300 // seconds between checks for free disk space
cDvbRecorder *Recorder = NULL; const char *BaseDir = "/video";
static bool LowDiskSpace(void) static bool LowDiskSpace(void)
{ {
@ -58,51 +59,54 @@ void AssertFreeDiskSpace(void)
// With every call to this function we try to actually remove // With every call to this function we try to actually remove
// a file, or mark a file for removal ("delete" it), so that // a file, or mark a file for removal ("delete" it), so that
// it will get removed during the next call. // it will get removed during the next call.
if (Recorder && Recorder->Recording() && LowDiskSpace()) { static time_t LastFreeDiskCheck = 0;
// Remove the oldest file that has been "deleted": if (time(NULL) - LastFreeDiskCheck > DISKCHECKDELTA) {
cRecordings Recordings; LastFreeDiskCheck = time(NULL);
if (Recordings.Load(true)) { if (DvbApi.Recording() && LowDiskSpace()) {
cRecording *r = Recordings.First(); // Remove the oldest file that has been "deleted":
cRecording *r0 = r; cRecordings Recordings;
while (r) { if (Recordings.Load(true)) {
if (r->start < r0->start) cRecording *r = Recordings.First();
r0 = r; cRecording *r0 = r;
r = Recordings.Next(r); while (r) {
} if (r->start < r0->start)
if (r0 && r0->Remove()) r0 = r;
return; r = Recordings.Next(r);
} }
// No "deleted" files to remove, so let's see if we can delete a recording: if (r0 && r0->Remove())
if (Recordings.Load(false)) { return;
cRecording *r = Recordings.First(); }
cRecording *r0 = NULL; // No "deleted" files to remove, so let's see if we can delete a recording:
while (r) { if (Recordings.Load(false)) {
if ((time(NULL) - r->start) / SECSINDAY > r->lifetime) { cRecording *r = Recordings.First();
if (r0) { cRecording *r0 = NULL;
if (r->priority < r0->priority) while (r) {
if ((time(NULL) - r->start) / SECSINDAY > r->lifetime) {
if (r0) {
if (r->priority < r0->priority)
r0 = r;
}
else
r0 = r; r0 = r;
} }
else r = Recordings.Next(r);
r0 = r;
} }
r = Recordings.Next(r); if (r0 && r0->Delete())
} return;
if (r0 && r0->Delete()) }
return; // Unable to free disk space, but there's nothing we can do about that...
esyslog(LOG_ERR, "low disk space, but no recordings to delete");
} }
// Unable to free disk space, but there's nothing we can do about that...
//TODO maybe a log entry - but make sure it doesn't come too often
} }
} }
// --- cRecording ------------------------------------------------------------ // --- cRecording ------------------------------------------------------------
cRecording::cRecording(const char *Name, time_t Start, char Quality, int Priority, int LifeTime) cRecording::cRecording(const char *Name, time_t Start, int Priority, int LifeTime)
{ {
fileName = NULL; fileName = NULL;
name = strdup(Name); name = strdup(Name);
start = Start; start = Start;
quality = Quality;
priority = Priority; priority = Priority;
lifetime = LifeTime; lifetime = LifeTime;
} }
@ -112,7 +116,6 @@ cRecording::cRecording(cTimer *Timer)
fileName = NULL; fileName = NULL;
name = strdup(Timer->file); name = strdup(Timer->file);
start = Timer->StartTime(); start = Timer->StartTime();
quality = Timer->quality;
priority = Timer->priority; priority = Timer->priority;
lifetime = Timer->lifetime; lifetime = Timer->lifetime;
} }
@ -127,7 +130,7 @@ cRecording::cRecording(const char *FileName)
if (p) { if (p) {
time_t now = time(NULL); time_t now = time(NULL);
struct tm t = *localtime(&now); // this initializes the time zone in 't' struct tm t = *localtime(&now); // this initializes the time zone in 't'
if (8 == sscanf(p + 1, DATAFORMAT, &t.tm_year, &t.tm_mon, &t.tm_mday, &t.tm_hour, &t.tm_min, &quality, &priority, &lifetime)) { if (7 == sscanf(p + 1, DATAFORMAT, &t.tm_year, &t.tm_mon, &t.tm_mday, &t.tm_hour, &t.tm_min, &priority, &lifetime)) {
t.tm_year -= 1900; t.tm_year -= 1900;
t.tm_mon--; t.tm_mon--;
t.tm_sec = 0; t.tm_sec = 0;
@ -149,7 +152,7 @@ const char *cRecording::FileName(void)
{ {
if (!fileName) { if (!fileName) {
struct tm *t = localtime(&start); struct tm *t = localtime(&start);
asprintf(&fileName, NAMEFORMAT, BaseDir, name, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, quality, priority, lifetime); asprintf(&fileName, NAMEFORMAT, BaseDir, name, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, priority, lifetime);
} }
return fileName; return fileName;
} }
@ -163,7 +166,7 @@ bool cRecording::Delete(void)
strncpy(ext, DELEXT, strlen(ext)); strncpy(ext, DELEXT, strlen(ext));
isyslog(LOG_INFO, "deleting recording %s", FileName()); isyslog(LOG_INFO, "deleting recording %s", FileName());
if (rename(FileName(), NewName) == -1) { if (rename(FileName(), NewName) == -1) {
esyslog(LOG_ERR, "ERROR: %s", strerror(errno)); esyslog(LOG_ERR, "ERROR: %s: %s", FileName(), strerror(errno));
result = false; result = false;
} }
} }
@ -173,40 +176,23 @@ bool cRecording::Delete(void)
bool cRecording::Remove(void) bool cRecording::Remove(void)
{ {
bool result = true;
isyslog(LOG_INFO, "removing recording %s", FileName()); isyslog(LOG_INFO, "removing recording %s", FileName());
if (remove(FileName()) == -1) { return RemoveFileOrDir(FileName());
esyslog(LOG_ERR, "ERROR: %s", strerror(errno));
result = false;
}
return result;
}
bool cRecording::AssertRecorder(void)
{
if (!Recorder || !Recorder->Recording()) {
if (!Recorder)
Recorder = new cDvbRecorder;
return true;
}
Interface.Error("Recorder is in use!");
return false;
} }
bool cRecording::Record(void) bool cRecording::Record(void)
{ {
return AssertRecorder() && Recorder->Record(FileName(), quality); return DvbApi.StartRecord(FileName());
} }
bool cRecording::Play(void) bool cRecording::Play(void)
{ {
return AssertRecorder() && Recorder->Play(FileName()); return DvbApi.StartReplay(FileName());
} }
void cRecording::Stop(void) void cRecording::Stop(void)
{ {
if (Recorder) DvbApi.StopRecord();
Recorder->Stop();
} }
// --- cRecordings ----------------------------------------------------------- // --- cRecordings -----------------------------------------------------------

View File

@ -4,7 +4,7 @@
* See the main source file 'osm.c' for copyright information and * See the main source file 'osm.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: recording.h 1.1 2000/03/05 15:57:27 kls Exp $ * $Id: recording.h 1.2 2000/04/14 15:12:42 kls Exp $
*/ */
#ifndef __RECORDING_H #ifndef __RECORDING_H
@ -15,21 +15,16 @@
#include "dvbapi.h" #include "dvbapi.h"
#include "tools.h" #include "tools.h"
extern cDvbRecorder *Recorder;
void AssertFreeDiskSpace(void); void AssertFreeDiskSpace(void);
class cRecording : public cListObject { class cRecording : public cListObject {
private:
bool AssertRecorder(void);
public: public:
char *name; char *name;
char *fileName; char *fileName;
time_t start; time_t start;
char quality;
int priority; int priority;
int lifetime; int lifetime;
cRecording(const char *Name, time_t Start, char Quality, int Priority, int LifeTime); cRecording(const char *Name, time_t Start, int Priority, int LifeTime);
cRecording(cTimer *Timer); cRecording(cTimer *Timer);
cRecording(const char *FileName); cRecording(const char *FileName);
~cRecording(); ~cRecording();

View File

@ -4,7 +4,7 @@
* See the main source file 'osm.c' for copyright information and * See the main source file 'osm.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: remote.c 1.1 2000/02/19 13:36:48 kls Exp $ * $Id: remote.c 1.2 2000/04/15 16:00:51 kls Exp $
*/ */
#include "remote.h" #include "remote.h"
@ -221,7 +221,7 @@ bool cRcIo::String(char *s)
} }
} }
} }
return Number(n, mode == modeH); return Number(n, true);
} }
bool cRcIo::DetectCode(unsigned char *Code, unsigned short *Address) bool cRcIo::DetectCode(unsigned char *Code, unsigned short *Address)
@ -244,8 +244,11 @@ bool cRcIo::DetectCode(unsigned char *Code, unsigned short *Address)
String(buf); String(buf);
SetCode(*Code, 0); SetCode(*Code, 0);
unsigned int Command; unsigned int Command;
if (GetCommand(&Command, Address)) if (GetCommand(&Command, Address)) {
SetMode(modeB);
String("----");
return true; return true;
}
if (*Code < 'D') { if (*Code < 'D') {
(*Code)++; (*Code)++;
return false; return false;

View File

@ -1,6 +1,9 @@
1:2:-----S-:2205:2320:H:99:99:Wochenshow 1:15:MTWTF--:1828:1901:10:5:nano
0:15:M------:2125:2205:H:99:99:Neues 1:3:M------:2110:2230:99:10:SevenDays
1:15:MTWTF--:1828:1901:M:10:5:nano 1:10:-T-----:2058:2150:99:10:Quarks
1:3:M------:2110:2230:H:99:99:SevenDays 1:3:---T---:2158:2300:99:10:Switch
1:3:---T---:2215:2300:H:99:99:Switch 1:2:----F--:2110:2155:99:10:Anke
1:14:------S:2210:2255:H:99:99:Olli 1:1:----F--:2210:2325:99:10:7Tage7Koepfe
1:15:-----S-:1358:1435:99:7:Neues
1:1:-----S-:1445:1600:99:10:Hammerman
1:2:-----S-:2205:2320:99:10:Wochenshow

91
tools.c
View File

@ -4,18 +4,46 @@
* See the main source file 'osm.c' for copyright information and * See the main source file 'osm.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: tools.c 1.2 2000/03/05 14:33:58 kls Exp $ * $Id: tools.c 1.3 2000/04/15 15:10:05 kls Exp $
*/ */
#define _GNU_SOURCE
#include "tools.h" #include "tools.h"
#include <dirent.h>
#include <errno.h> #include <errno.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/time.h> #include <sys/time.h>
#include <unistd.h>
#define MaxBuffer 1000 #define MaxBuffer 1000
int SysLogLevel = 3;
void writechar(int filedes, char c)
{
write(filedes, &c, sizeof(c));
}
void writeint(int filedes, int n)
{
write(filedes, &n, sizeof(n));
}
char readchar(int filedes)
{
char c;
read(filedes, &c, 1);
return c;
}
bool readint(int filedes, int &n)
{
//XXX timeout!!
return read(filedes, &n, sizeof(n));
}
char *readline(FILE *f) char *readline(FILE *f)
{ {
static char buffer[MaxBuffer]; static char buffer[MaxBuffer];
@ -30,36 +58,83 @@ char *readline(FILE *f)
int time_ms(void) int time_ms(void)
{ {
static time_t t0 = 0;
struct timeval t; struct timeval t;
if (gettimeofday(&t, NULL) == 0) if (gettimeofday(&t, NULL) == 0) {
return t.tv_sec * 1000 + t.tv_usec / 1000; if (t0 == 0)
t0 = t.tv_sec; // this avoids an overflow (we only work with deltas)
return (t.tv_sec - t0) * 1000 + t.tv_usec / 1000;
}
return 0; return 0;
} }
bool MakeDirs(const char *FileName) void delay_ms(int ms)
{
int t0 = time_ms();
while (time_ms() - t0 < ms)
;
}
bool MakeDirs(const char *FileName, bool IsDirectory)
{ {
bool result = true; bool result = true;
char *s = strdup(FileName); char *s = strdup(FileName);
char *p = s; char *p = s;
if (*p == '/') if (*p == '/')
p++; p++;
while ((p = strchr(p, '/')) != NULL) { while ((p = strchr(p, '/')) != NULL || IsDirectory) {
*p = 0; if (p)
*p = 0;
struct stat fs; struct stat fs;
if (stat(s, &fs) != 0 || !S_ISDIR(fs.st_mode)) { if (stat(s, &fs) != 0 || !S_ISDIR(fs.st_mode)) {
isyslog(LOG_INFO, "creating directory %s", s); isyslog(LOG_INFO, "creating directory %s", s);
if (mkdir(s, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) == -1) { if (mkdir(s, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) == -1) {
esyslog(LOG_ERR, "ERROR while creating directory %s: %s", s, strerror(errno)); esyslog(LOG_ERR, "ERROR: %s: %s", s, strerror(errno));
result = false; result = false;
break; break;
} }
} }
*p++ = '/'; if (p)
*p++ = '/';
else
break;
} }
delete s; delete s;
return result; return result;
} }
bool RemoveFileOrDir(const char *FileName)
{
struct stat st;
if (stat(FileName, &st) == 0) {
if (S_ISDIR(st.st_mode)) {
DIR *d = opendir(FileName);
if (d) {
struct dirent *e;
while ((e = readdir(d)) != NULL) {
if (strcmp(e->d_name, ".") && strcmp(e->d_name, "..")) {
char *buffer;
asprintf(&buffer, "%s/%s", FileName, e->d_name);
if (remove(buffer) < 0)
esyslog(LOG_ERR, "ERROR: %s: %s", buffer, strerror(errno));
delete buffer;
}
}
closedir(d);
}
else {
esyslog(LOG_ERR, "ERROR: %s: %s", FileName, strerror(errno));
return false;
}
}
if (remove(FileName) == 0)
return true;
}
else
esyslog(LOG_ERR, "ERROR: %s: %s", FileName, strerror(errno));
return false;
}
// --- cListObject ----------------------------------------------------------- // --- cListObject -----------------------------------------------------------
cListObject::cListObject(void) cListObject::cListObject(void)

24
tools.h
View File

@ -4,7 +4,7 @@
* See the main source file 'osm.c' for copyright information and * See the main source file 'osm.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: tools.h 1.2 2000/03/05 16:14:05 kls Exp $ * $Id: tools.h 1.3 2000/04/15 15:09:47 kls Exp $
*/ */
#ifndef __TOOLS_H #ifndef __TOOLS_H
@ -13,18 +13,28 @@
#include <stdio.h> #include <stdio.h>
#include <syslog.h> #include <syslog.h>
//TODO extern int SysLogLevel;
#define dsyslog syslog
#define esyslog syslog #define esyslog if (SysLogLevel > 0) syslog
#define isyslog syslog #define isyslog if (SysLogLevel > 1) syslog
#define dsyslog if (SysLogLevel > 2) syslog
#define LOG_ERROR esyslog(LOG_ERR, "ERROR (%s,%d): %s", __FILE__, __LINE__, strerror(errno))
#define LOG_ERROR_STR(s) esyslog(LOG_ERR, "ERROR: %s: %s", s, strerror(errno));
#define SECSINDAY 86400 #define SECSINDAY 86400
#define DELETENULL(p) (delete (p), p = NULL) #define DELETENULL(p) (delete (p), p = NULL)
void writechar(int filedes, char c);
void writeint(int filedes, int n);
char readchar(int filedes);
bool readint(int filedes, int &n);
char *readline(FILE *f); char *readline(FILE *f);
int time_ms(void); int time_ms(void);
bool MakeDirs(const char *FileName); void delay_ms(int ms);
bool MakeDirs(const char *FileName, bool IsDirectory = false);
bool RemoveFileOrDir(const char *FileName);
class cListObject { class cListObject {
private: private:
@ -47,7 +57,7 @@ public:
virtual ~cListBase(); virtual ~cListBase();
void Add(cListObject *Object); void Add(cListObject *Object);
void Del(cListObject *Object); void Del(cListObject *Object);
void Move(int From, int To); virtual void Move(int From, int To);
void Move(cListObject *From, cListObject *To); void Move(cListObject *From, cListObject *To);
void Clear(void); void Clear(void);
cListObject *Get(int Index); cListObject *Get(int Index);