mirror of
				https://github.com/vdr-projects/vdr.git
				synced 2025-03-01 10:50:46 +00:00 
			
		
		
		
	Initial revision
This commit is contained in:
		
							
								
								
									
										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 | ||||
		Reference in New Issue
	
	Block a user