Here is all the code I've written for operating a
2x20 VFD with freevo. Vfdchanges.txt contains all the ammendments I made
to the original freevo/mplayer codes, and recshare.so and parport.so are my
python modules. I have also included the source code for these modules,
which I compiled using SWIG.
I think that a lot of this code could be made more
efficient, but at least it works. I had to use shared memory in a lot of
places, because I didn't know how else to get mplayer and freevo to
communicate with each other. If there's a better way, let me
know! I hope this is useful to someone, and please feel free
to fix it and send me recommendations!
Thanks,
Rob M
|
parport.c
Description: Binary data
parport.so
Description: Binary data
recshare.c
Description: Binary data
recshare.so
Description: Binary data
# Revisions February - March 2003 # Rob MacNeill's additions for a 2x20 VFD or LCD. # (Also included is a small bit of code for deleting unwanted video files)
# All of this code was written for a final school project to turn a PC into # a standalone DVR that can be part of a home entertainment unit. The school # is Camosun College in Victoria, BC, Canada. # # Check out the other students' projects at www.elex.camosun.bc.ca # (There's some pretty cool stuff!) # I used a 2x20 VFD connected directly to the parallel port. The parallel port # pin connections were as follows: # Parallel port Pin VFD Signal # ----------------- ---------- # 1 Enable # 2 - 9 D0 - D7 # 10 - 13 Floating # 14 RD/!WR # 15 Busy (I never used this, but tried to set it up anyway) # 16 Register Select # 17 !Reset # 18 - 25 Gnd # / Serial In - Floating # / !Chip Select - Tied to ground # # I used a VFD set to LCD mode, so most of this code should be transferable to # an LCD. The available character addresses were 0x80-0x93 for the top row, and # 0x94-0xA7. #KNOWN BUGS: #-Intermittent error when forward skip goes past the end of a file. Sometimes # screen clears as it should, then PLAY message reappears. # #-Slight (but noticeable) screen glitch when time display rolls over # from :59 to :00 - not as noticeable with faster hardware. # #-(rec) message stays on screen if recording finishes while MPlayer is active. # Goes away if MPlayer stopped then restarted. # #-mplayer/mencoder can't execute from the command line using this code, # since it is looking for shared memory created by freevo. This is fine for # me since I am only using freevo to execute MPlayer, but this should probably # be fixed eventually. main.py: -------- Line 152: # Also put these at the top of the two mplayer.py's and record_daemon.py import parport # For accessing VFD through Parallel port import recshare # For RecordStatus and PlayStatus Line 209: # setup recshare.creatememory() recshare.putrecstatus(0) recshare.putplaystatus(0) Line 217: # Shutdown Message parport.display(2) time.sleep(1) parport.display(0) Line 357: # This bit is just for fun and isn't necessary. If freevo is # Idle for ~20seconds a message flashes between the top line and the # bottom line until a button is pushed. Right now, the message is just # "SCREENSAVER" - just change it in parport.c. If you want to leave this # out, then you can also leave out all parport.getstatus() and # parport.putstatus() messages in mplayer.py/record_damemon.py. while 1: counter = 0 routine = 0 # Get next command while 1: if recshare.getrecstatus() == 0: counter = counter + 1 if counter > 100: counter = 90 if parport.getstatus() == 0: if routine == 0: parport.display(5) routine = 1 elif routine == 1: parport.display(6) routine = 0 event = osd._cb() Line 422: # This is pretty specific to our project, and probably not useful to anyone # else. We built a 4 to 1 RCA multiplexer board, controlled by a PICf628. # This section toggles the line in status for the VFD between the 4 RCA lines # and the cable input. elif event == rc.TV_VCR: parport.display(0) if line == 0: line = 1 parport.putlinestatus(1) parport.display(31) elif line == 1: line = 2 parport.putlinestatus(2) parport.display(32) elif line == 2: line = 3 parport.putlinestatus(3) parport.display(33) elif line == 3: line = 4 parport.putlinestatus(4) parport.display(34) elif line == 4: line = 0 parport.putlinestatus(0) parport.display(30) -------------------------------------------------------------------------------- /video/mplayer.py ----------------- Line 218: # Top of def play() parport.putstatus(1) recshare.putplaystatus(1) Line 351: # Top of def stop() recshare.putplaystatus(0) parport.putstatus(0) parport.freememory() self.thread.mode = 'stop' self.thread.mode_flag.set() rc.app = None rc.func = None while self.thread.mode == 'stop': time.sleep(0.3) if recshare.getrecstatus() == 1: parport.display(4) Line 365: # There's a whole bunch of stuff here, so I'll just show the complete # Eventhandler. This is all the play mode icons. There are play, pause, stop, # >, >>, >>>, <, <<, <<< (depending on seek speed). def eventhandler(self, event): """ eventhandler for mplayer control. If an event is not bound in this function it will be passed over to the items eventhandler """ if event == rc.STOP or event == rc.SELECT: if self.mode == 'dvdnav': self.thread.app.write('dvdnav 6\n') else: parport.SharedMem(1) parport.display(18) parport.SharedMem(0) self.stop() self.thread.item = None rc.app = None menuwidget.refresh(reload=1) return TRUE if event == rc.EXIT: parport.SharedMem(1) parport.display(18) parport.SharedMem(0) self.stop() self.thread.item = None rc.app = None menuwidget.refresh(reload=1) return TRUE if event == rc.PLAY_END or event == rc.USER_END: self.stop() parport.display(0) rc.app = None return self.item.eventhandler(event) if event == rc.DVD_PROTECTED: self.stop() rc.app = None skin.PopupBox('The DVD is protected, see the docs for more info!') osd.update() time.sleep(5.0) # Forward the event as if it was a regular end of item event = rc.PLAY_END return self.item.eventhandler(event) if event == rc.MENU: if self.mode == 'dvdnav': self.thread.app.write('dvdnav 5\n') return TRUE if event == rc.DISPLAY: self.thread.app.write('osd\n') return TRUE if event == rc.PAUSE or event == rc.PLAY: playswitch = parport.getplayswitch() if event == rc.PAUSE and playswitch == 0: self.thread.app.write('pause\n') parport.SharedMem(1) parport.display(16) parport.SharedMem(0) parport.putplayswitch(1) elif event == rc.PLAY and playswitch == 1: self.thread.app.write('pause\n') parport.SharedMem(1) parport.display(17) parport.SharedMem(0) parport.putplayswitch(0) return TRUE if event == rc.FFWD: self.thread.app.write('seek 10\n') parport.putplayswitch(0) parport.SharedMem(1) parport.display(11) parport.SharedMem(0) time.sleep(2) parport.SharedMem(1) parport.display(17) parport.SharedMem(0) return TRUE if event == rc.UP: self.thread.app.write('seek 600\n') parport.putplayswitch(0) parport.SharedMem(1) parport.display(14) parport.SharedMem(0) time.sleep(2) parport.SharedMem(1) parport.display(17) parport.SharedMem(0) return TRUE if event == rc.REW: self.thread.app.write('seek -10\n') parport.putplayswitch(0) parport.SharedMem(1) parport.display(10) parport.SharedMem(0) time.sleep(2) parport.SharedMem(1) parport.display(17) parport.SharedMem(0) return TRUE if event == rc.DOWN: self.thread.app.write('seek -600\n') parport.putplayswitch(0) parport.SharedMem(1) parport.display(15) parport.SharedMem(0) time.sleep(2) parport.SharedMem(1) parport.display(17) parport.SharedMem(0) return TRUE if event == rc.LEFT: if self.mode == 'dvdnav': self.thread.app.write('dvdnav 3\n') else: self.thread.app.write('seek -60\n') parport.putplayswitch(0) parport.SharedMem(1) parport.display(13) parport.SharedMem(0) time.sleep(2) parport.SharedMem(1) parport.display(17) parport.SharedMem(0) return TRUE if event == rc.RIGHT: if self.mode == 'dvdnav': self.thread.app.write('dvdnav 4\n') else: self.thread.app.write('seek 60\n') parport.putplayswitch(0) parport.SharedMem(1) parport.display(12) parport.SharedMem(0) time.sleep(2) parport.SharedMem(1) parport.display(17) parport.SharedMem(0) return TRUE -------------------------------------------------------------------------------- /tv/mplayer.py -------------- Line 174: # This is all more cable/RCA stuff, and probably not necessary. # (Except for the first line if you're using the Screensaver feature.) parport.putstatus(1) linein = parport.getlinestatus() if linein == 0: mode = "tv" elif linein == 1: mode = "vcr" parport.display(0) parport.display(31) elif linein == 2: mode = "vcr" parport.display(0) parport.display(32) elif linein == 3: mode = "vcr" parport.display(0) parport.display(33) elif linein == 4: mode = "vcr" parport.display(0) parport.display(34) Line 205: # Displays the current channel on the VFD/LCD upon startup of tv application if mode == 'tv': parport.display(0) parport.display(3) parport.display(30) tuner_channel = self.TunerGetChannel() parport.channelchange(tuner_channel) Line 351: # Under def Stop() parport.putstatus(0) Line 369: # Added parport lines to CHUP/CHDN event handler to actively update current # channel display using channel up / channel down buttons # elif event == rc.CHUP or event == rc.CHDOWN: if self.mode == 'vcr': return # Go to the prev/next channel in the list if event == rc.CHUP: self.TunerPrevChannel() tuner_id = config.TV_CHANNELS[self.tuner_chidx][2] parport.channelchange(tuner_id) else: self.TunerNextChannel() tuner_id = config.TV_CHANNELS[self.tuner_chidx][2] parport.channelchange(tuner_id) new_channel = self.TunerGetChannel() self.thread.app.write('tv_set_channel %s\n' % new_channel) -------------------------------------------------------------------------------- record_daemon.py ---------------- Line 123: # Displays a message if something is recording. Message varies depending on # Current status of MPlayer # Should this item be started? if item.check_time(): recshare.putrecstatus(1) if recshare.getplaystatus() == 1: parport.SharedMem(1) # If MPlayer is running, then show small parport.display(35) # (rec) message in bottom right corner parport.SharedMem(0) elif recshare.getplaystatus() == 0: parport.display(4) # Else show large RECORDING message on cmd = item.make_cmd() # Top line log(' Starting item (%s)' % cmd) -------------------------------------------------------------------------------- mplayer.c --------- #include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h> #include "/usr/include/sys/io.h" Line 80: # Setup stuff int isTV; //Added Feb 23, 2003 - status flag for file type (TV or movie) #define BUFSZ 1 //Added Feb26, 2003 to allocate space for shared memory #define BUFSZ2 10 int isrec = 0; int shmid; //Shared Memory ID char *shmbuf; //Contents of Shared Memory -- Flag Variable FILE *fPtr; //File Pointer for sving shmid to a file int shmid2; char *shmbuf2; Line 246: # I don't remember why I put this stuff here rather than with the stuff above. # It probably doesn't matter. char secl=0x30, sech=0x30, minl=0x30, minh=0x30, hour=0x30; int oneshot=0; char *recmsg = "(rec)"; Line 474: # Clears the display when MPlayer is halted if(how) mp_msg(MSGT_CPLAYER,MSGL_INFO,MSGTR_Exiting,mp_gettext(how)); mp_msg(MSGT_CPLAYER,MSGL_DBG2,"max framesize was %d bytes\n",max_framesize); //Start of Rob's Code!!!!!!!!!!!!!!!!!!! int i=0; ioperm(0x378, 3, 1); //Grant Permission to use Parallel Port //HOME CURSOR outb (0x02, 0x378); //Move Cursor to home outb (0x03, 0x37A); //Enable Transfer usleep(1); outb (0x02, 0x37A); //Complete Transfer /*CLEAR FILENAME*/ //Set DDRAM Address outb (0x80, 0x378); // Set DDRAM Address outb (0x03, 0x37A); //Enable Transfer usleep(1); outb (0x02, 0x37A); //Complete Transfer for (i=0;i<20;i++) { outb(0x06, 0x37A); //Enable Register Select outb(0x20, 0x378); //Output Data 1 char at a time outb(0x07, 0x37A); //Enable Transfer usleep(1); outb (0x06, 0x37A); //Complete Transfer } /*CLEAR TIMER*/ //Set DDRAM Address outb (0x02, 0x37A); usleep(1); outb (0x94, 0x378); // Set DDRAM Address outb (0x03, 0x37A); //Enable Transfer usleep(1); outb (0x02, 0x37A); //Complete Transfer for (i=0;i<20;i++) { outb(0x06, 0x37A); //Enable Register Select outb(0x20, 0x378); //Output Data 1 char at a time outb(0x07, 0x37A); //Enable Transfer usleep(1); outb (0x06, 0x37A); //Complete Transfer } ioperm(0x378, 3, 0); //End of Rob's code!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! exit(rc); Line 826: # This is the main section to show the filename on the VFD. If the name is # greater than 20 characters long (entire top line), then last three letters on # the top line are replaced with '...'. I wrote this before I was familiar with # python...Looking back, I think that this should really be rewritten within # /video/mplayer.py. filename = play_tree_iter_get_file(playtree_iter,1); //This is Rob MacNeill's Code!!!!!!!!!!!!!!!!!!! char *TVstring = "TV channel"; isTV = strncmp(filename, TVstring, 10); int i=0; int start=0; int length; int toolong = 0; char *etc = "..."; char *timeinit = "0:00:00 PLAY"; length = strlen(filename); for (i=0;i<length;i++) { if (filename[i] == '/') start=i+1; } if ((length - start) > 20) { toolong = 1; while ((length - start) > 17) { length = length - 1; } } /*!!!!!!CREATE SHARED MEMORY SPACE FOR DISPLAY HANDSHAKE!!!!!*/ if ((shmid = shmget(IPC_PRIVATE, BUFSZ, 0666)) < 0) { perror("shmget"); exit(EXIT_FAILURE); } if ((fPtr = fopen("/tmp/sharedisplay.txt", "w")) == NULL) printf("\nShareDisplay file not opened for writing\n"); else { fprintf(fPtr, "%d", shmid); fclose(fPtr); } /*Attach to shared memory segment*/ if ((shmbuf = shmat(shmid, 0, 0)) < (char *)0) { perror("shmat"); exit(EXIT_FAILURE); } shmbuf[0] = 1; //Set Status to 1: so nothing else can write // to display until info is done /*Detach from shared memory*/ if ((shmdt(shmbuf)) < 0) { perror("shmdt"); exit(EXIT_FAILURE); } //!!!!!!!!!!!!END OF MEMORY HANDSHAKE!!!!!!!!!!!!!!!!!!!! if (isTV != 0) { ioperm(0x378, 3, 1); //Grant Permission to use Parallel Port //CLEAR DISPLAY outb (0x02, 0x37A); outb (0x01, 0x378); //Clear Display outb (0x03, 0x37A); //Enable Transfer usleep(1); outb (0x02, 0x37A); //Complete Transfer //HOME CURSOR outb (0x02, 0x378); //Move Cursor to home outb (0x03, 0x37A); //Enable Transfer usleep(1); outb (0x02, 0x37A); //Complete Transfer //SETUP DISPLAY outb (0x0c, 0x378); //Unblank Display, and Remove Cursors outb (0x03, 0x37A); //Enable Transfer usleep(1); outb (0x02, 0x37A); //Complete Transfer //Cursor Position Controls outb (0x14, 0x378); //Shift Cursor Right outb (0x03, 0x37A); //Enable Transfer usleep(1); outb (0x02, 0x37A); //Complete Transfer //Set DDRAM Address outb (0x80, 0x378); // Set DDRAM Address outb (0x03, 0x37A); //Enable Transfer usleep(1); outb (0x02, 0x37A); //Complete Transfer for (i=start;i<length;i++) { /*OUTPUT FILE NAME*/ outb(0x06, 0x37A); //Enable Register Select outb(filename[i], 0x378); //Output Data 1 char at a time outb(0x07, 0x37A); //Enable Transfer usleep(1); outb (0x06, 0x37A); //Complete Transfer } if (toolong == 1) { for (i=0;i<3;i++) { outb(0x06, 0x37A); //Enable Register Select outb(etc[i], 0x378); //Output Data 1 char at a time outb(0x07, 0x37A); //Enable Transfer usleep(1); outb (0x06, 0x37A); //Complete Transfer } } /*INITIALIZE TIMER DISPLAY TO 0:00:00*/ //Set DDRAM Address outb (0x02, 0x37A); usleep(1); outb (0x94, 0x378); // Set DDRAM Address outb (0x03, 0x37A); //Enable Transfer usleep(1); outb (0x02, 0x37A); //Complete Transfer for (i=0;i<14;i++) { outb(0x06, 0x37A); //Enable Register Select outb(timeinit[i], 0x378); //Output Data 1 char at a time outb(0x07, 0x37A); //Enable Transfer usleep(1); outb (0x06, 0x37A); //Complete Transfer } // START RECORD/PLAY SIMULTANEOUSLY if ((fPtr = fopen("/tmp/recstatus.txt", "r")) == NULL) printf("\nShareDisplay not opened for writing\n"); else { fscanf(fPtr, "%d", &shmid2); fclose(fPtr); } if ((shmbuf2 = shmat(shmid2, 0, 0)) < (char *)0) { perror("shmat"); exit(EXIT_FAILURE); } if (shmbuf2[0] == 1) //If Something is recording { //Set DDRAM Address outb(0x02, 0x37A); usleep(1); outb(0xA3, 0x378); outb(0x03, 0x37A); usleep(1); outb(0x02, 0x37A); for (i=0;i<5;i++) { outb(0x06, 0x37A); outb(recmsg[i], 0x378); outb(0x07, 0x37A); usleep(1); outb(0x06, 0x37A); } } if ((shmdt(shmbuf2)) < 0) { perror("shmdt"); exit(EXIT_FAILURE); } ioperm(0x378, 3, 0); } /*Attach to shared memory segment*/ if ((shmbuf = shmat(shmid, 0, 0)) < (char *)0) { perror("shmat"); exit(EXIT_FAILURE); } shmbuf[0] = 0; //INITIALIZE STATUS TO 0 - NOTHING OPERATING /*Detach from shared memory*/ if ((shmdt(shmbuf)) < 0) { perror("shmdt"); exit(EXIT_FAILURE); } //End of Rob's code!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! } } #ifndef HAVE_NEW_GUI Line 2421: # Code to show current time of file playing. As far as I can see, this code # needs to stay in mplayer.c, but if anyone knows how to move it to freevo # please do so! It really should have been written as a callable function, # since it is used in both the audio and noaudio modes. I'll only show it here # once, but keep in mind it needs to be copied into both play modes! # Note: if you are using a slower computer, you may notice a skip in the video # in 1 minute increments, since the VFD has to update over 2 characters. /*Added by Rob MacNeill Feb 21, 2003 to show time on a Front Panel Display*/ /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/ if (isTV != 0) { /*Attach to shared memory segment*/ if ((shmbuf = shmat(shmid, 0, 0)) < (char *)0) { perror("shmat"); exit(EXIT_FAILURE); } while(shmbuf[0] != 0) { usleep(100); } shmbuf[0] = 1; //TIMER IS OPERATING /*Detach from shared memory*/ if ((shmdt(shmbuf)) < 0) { perror("shmdt"); exit(EXIT_FAILURE); } timeout=v_pts; ioperm(0x378, 3, 1); //Grant Permission to use Parallel Port if (hour != ((timeout/3600)%10) + 0x30) { //Set DDRAM Address hour = ((timeout/3600)%10) + 0x30; outb (0x02, 0x37A); //usleep(1); outb (0x94, 0x378); // Set DDRAM Address outb (0x03, 0x37A); //Enable Transfer usleep(1); outb (0x02, 0x37A); //Complete Transfer //Output Time Character outb(0x06, 0x37A); //Enable Register Select outb(hour, 0x378); //Output Data 1 char at a time outb(0x07, 0x37A); //Enable Transfer usleep(1); outb (0x06, 0x37A); //Complete Transfer } timeout = timeout % 3600; if (minh != (timeout/600) + 0x30) { //Set DDRAM Address minh = (timeout/600) + 0x30; outb (0x02, 0x37A); //usleep(1); outb (0x96, 0x378); // Set DDRAM Address outb (0x03, 0x37A); //Enable Transfer usleep(1); outb (0x02, 0x37A); //Complete Transfer //Output Time Character outb(0x06, 0x37A); //Enable Register Select outb(minh, 0x378); //Output Data 1 char at a time outb(0x07, 0x37A); //Enable Transfer usleep(1); outb (0x06, 0x37A); //Complete Transfer } timeout = timeout % 600; if (minl != (timeout/60) + 0x30) { //Set DDRAM Address minl = (timeout/60) + 0x30; outb (0x02, 0x37A); //usleep(1); outb (0x97, 0x378); // Set DDRAM Address outb (0x03, 0x37A); //Enable Transfer usleep(1); outb (0x02, 0x37A); //Complete Transfer //Output Time Character outb(0x06, 0x37A); //Enable Register Select outb(minl, 0x378); //Output Data 1 char at a time outb(0x07, 0x37A); //Enable Transfer usleep(1); outb (0x06, 0x37A); //Complete Transfer } timeout = timeout % 60; if (sech != (timeout/10) + 0x30) { //Set DDRAM Address sech = (timeout/10) + 0x30; outb (0x02, 0x37A); //usleep(1); outb (0x99, 0x378); // Set DDRAM Address outb (0x03, 0x37A); //Enable Transfer usleep(1); outb (0x02, 0x37A); //Complete Transfer //Output Time Character outb(0x06, 0x37A); //Enable Register Select outb(sech, 0x378); //Output Data 1 char at a time outb(0x07, 0x37A); //Enable Transfer usleep(1); outb (0x06, 0x37A); //Complete Transfer } if (secl != (timeout%10) + 0x30) { //Set DDRAM Address secl = (timeout%10) + 0x30; outb (0x02, 0x37A); //usleep(1); outb (0x9a, 0x378); // Set DDRAM Address outb (0x03, 0x37A); //Enable Transfer usleep(1); outb (0x02, 0x37A); //Complete Transfer //Output Time Character outb(0x06, 0x37A); //Enable Register Select outb(secl, 0x378); //Output Data 1 char at a time outb(0x07, 0x37A); //Enable Transfer usleep(1); outb (0x06, 0x37A); //Complete Transfer } ioperm(0x378, 3, 0); //Grant Permission to use Parallel Port /*Attach to shared memory segment*/ if ((shmbuf = shmat(shmid, 0, 0)) < (char *)0) { perror("shmat"); exit(EXIT_FAILURE); } shmbuf[0] = 0; //TIMER IS FINISHED OPERATING /*Detach from shared memory*/ if ((shmdt(shmbuf)) < 0) { perror("shmdt"); exit(EXIT_FAILURE); } } /*End of Front Panel Display Addition*/ /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/ fflush(stdout); } -------------------------------------------------------------------------------- mencoder.c ---------- #include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h> #include "/usr/include/sys/io.h" #Somewhere at the top: int shmid; //Shared Memory ID char *shmbuf; //Contents of Shared Memory -- Flag Variable FILE *fPtr; //File Pointer for sving shmid to a file Line 1325: # Display procedure for mencoder end. Would like to add code to remove (rec) # message while MPlayer is running. As it is the message will stay until # MPlayer ends. if ((fPtr = fopen("/tmp/playstatus.txt", "r")) == NULL) printf("\nPlaystatus file not opened for writing\n"); else { fscanf(fPtr, "%d", &shmid); fclose(fPtr); } /*Attach to shared memory segment*/ if ((shmbuf = shmat(shmid, 0, 0)) < (char *)0) { perror("shmat"); exit(EXIT_FAILURE); } if (shmbuf[0] == 0) { //If nothing Playing on MPlayer, then Clear Display ioperm(0x378, 3, 1); outb (0x02, 0x37A); outb (0x01, 0x378); outb (0x03, 0x37A); usleep(1); outb (0x02, 0x37A); ioperm(0x378, 3, 0); } // else ... Insert Clear routine for "(rec)" label /*Detach from shared memory*/ if ((shmdt(shmbuf)) < 0) { perror("shmdt"); exit(EXIT_FAILURE); } // NOW CLEAR RECSTATUS FOR FREEVO if ((fPtr = fopen("/tmp/recstatus.txt", "r")) == NULL) printf("Recstatus File not opened for reading"); else { fscanf(fPtr, "%d", &shmid); fclose(fPtr); } if ((shmbuf = shmat(shmid, 0, 0)) < (char *)0) { perror("shmat"); exit(EXIT_FAILURE); } shmbuf[0] = 0; if ((shmdt(shmbuf)) < 0) { perror("shmdt"); exit(EXIT_FAILURE); } //!!!!!!END OF ROB'S CODE!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! return interrupted; } -------------------------------------------------------------------------------- # This is unrelated. Just a little bit of code I added to videoitem.py to delete # unwanted video files. I don't know if someone has already done this or not, but # here it is. I used '8' for delete and confirm and '7' to cancel. videoitem.py ------------ Line 451: def delete(self, arg=None, menuw=None): skin.PopupBox("Do you really want to delete this file?\nPush C to confirm or B to cancel.") self.deleteinit = 1 def deleteconfirm(self, arg=None, menuw=None): file = self.filename os.system ('rm -f %s' % (file)) menuwidget.refresh() skin.PopupBox("File Deleted") self.deleteinit = 0 time.sleep(2) menuwidget.refresh() def canceldelete(self, arg=None, menuw=None): menuwidget.refresh() skin.PopupBox("File Not Deleted") self.deleteinit = 0 time.sleep(2) menuwidget.refresh() # And in the eventhandler... if event == rc.K8 and self.deleteinit == 0: self.delete() return TRUE elif event == rc.K8 and self.deleteinit == 1: self.deleteconfirm() return TRUE if event == rc.K7 and self.deleteinit == 1: self.canceldelete() return TRUE