Wednesday, 7 January 2009
Navigation: Home Galleries
Its All about Dybra
#!/usr/bin/python
import time, thread, os, string, termios, TERMIOS, tty, select
from Tkinter import *
from SimpleDialog import SimpleDialog

# This software is freeware and may be used for any purpose free of
# charge.  There is no warranty of any kind, expressed or implied, and
# the author accepts no liability for any loss or damage that may result
# from the use of this software.  No support is available.  You are
# entirely on your own.

class QVrec:
    """
    This class just looks after the serial character interface
    to the camera in record mode.
    """
    def __init__(self,dummy=0,device='/dev/ttyS0'):
        self.dummy = dummy
        if not dummy:
            self.p = open(device, 'w+b', 0)
            self.fd = self.p.fileno()
            self.rawtty()

    def rawtty(self):
        termios.tcflush(self.fd,TERMIOS.TCIOFLUSH)
        tty.setraw(self.fd, TERMIOS.TCSANOW)

    def write(self,data):
        if self.dummy:
            print 'To camera:', data
        else:
            self.p.write(data)
            termios.tcdrain(self.fd)

    def write_pair(self, A, a, timeout=0.02):
        self.write(A)
        self.sleep(timeout)
        self.write(a)
        self.sleep(0.02)

    def sleep(self,duration):
        # Use select to get a more accurate sleep than sleep()
        select.select([],[],[],duration)

    def focus_lock(self):
        self.write_pair('A','a',1.0)

    def shutter(self):
        self.write_pair('B', 'b', 4.0)

    def zoom_start(self,direction):
        if direction < 0:
            self.write('C')
        else:
            self.write('D')
        self.sleep(0.02) # just to be safe

    def zoom_end(self,direction):
        if direction < 0:
            self.write('c')
        else:
            self.write('d')
        self.sleep(0.02) # just to be safe

    def menu(self):
        self.write_pair('E','e')

    def up(self):
        self.write_pair('F','f')

    def left(self):
        self.write_pair('G','g')

    def right(self):
        self.write_pair('H','h')

    def set(self):
        self.write_pair('I', 'i')

    def down(self):
        self.write_pair('J','j')

    def flash(self):
        self.write_pair('K', 'k')

    def focus_set(self):
        self.write_pair('L', 'l', 1.0)

    def usb(self):
        self.write_pair('M', 'm', 4.0)

    def mode(self):
        self.write_pair('N', 'n')

    def disp(self):
        self.write_pair('O', 'o')

    def preview(self):
        self.write_pair('Q', 'q', 4.0)

    def self_timer(self):
        self.write_pair('P','p')

class StatusBar(Frame):
    def __init__(self,parent):
        Frame.__init__(self,parent)
        self.label = Label(self, bd=1, relief=SUNKEN, anchor=W)
        self.label.pack(fill=X)

    def set(self, format, *args):
        self.label.config(text=(format % args))
        self.label.update_idletasks() # Hangs on win32

    def clear(self):
        self.label.config(text="")
        self.label.update_idletasks()

class QVTk:
    """
    The GUI
    """
    def __init__(self,top=None):
        if top:
            self.top = top
        else:
            self.top = Tk(baseName="QV", className="QV")

        self.loadrc()

        # Topmost menu bar
        menubar = Frame(self.top)
        Button(menubar,text='Quit',
               command=self.quit).pack(side=LEFT)
        Button(menubar,text='Help',
               command=self.help).pack(side=RIGHT)
        menubar.pack(side=TOP,fill=X,pady=5)

        # Device and directory info
        sdframe = Frame(self.top)
        Label(sdframe,text='Serial:').pack(side=LEFT)
        self.sentry = Entry(sdframe,width=15,)
        self.sentry.insert(0,self.serial_device)
        self.sentry.bind("<Return>",self.serialget)
        self.sentry.bind("<Leave>",self.serialget)
        self.sentry.pack(side=LEFT,fill=X,expand=1)
        sdframe.pack(side=TOP,fill=X)

        dframe = Frame(self.top)
        Label(dframe,text='Download:').pack(side=LEFT)
        self.dentry = Entry(dframe)
        self.dentry.insert(0,self.diskpath)
        self.dentry.bind("<Return>",self.diskpathget)
        self.dentry.bind("<Leave>",self.diskpathget)
        self.dentry.pack(side=LEFT,fill=X,expand=1)
        dframe.pack(side=TOP,fill=X)

        cframe = Frame(self.top)
        Label(cframe,text='Mount:').pack(side=LEFT)
        self.centry = Entry(cframe)
        self.centry.insert(0,self.campath)
        self.centry.bind("<Return>",self.campathget)
        self.centry.bind("<Leave>",self.campathget)
        self.centry.pack(side=LEFT,fill=X,expand=1)
        cframe.pack(side=TOP,fill=X)

        # Other menubar
        menubar = Frame(self.top)
        Button(menubar,text='Index',
               command=self.make_index).pack(side=RIGHT)
        Button(menubar,text='Sync',
               command=self.synchronize).pack(side=RIGHT)
        Button(menubar,text='Unmount',
               command=self.unmount).pack(side=RIGHT)
        Button(menubar,text='Mount',
               command=self.mount).pack(side=RIGHT)
        Button(menubar,text='USB',
               command=self.usb).pack(side=RIGHT)
        menubar.pack(side=TOP,pady=5)

        # Frame for camera controls
        clabel = Label(self.top,text='Controls',bd=1,relief=SUNKEN,bg='grey')
        clabel.pack(fill=X)
        cframe = Frame(self.top)

        # Frame for menu, arrows, set
        qframe = Frame(cframe)
        # Up/down/left/right keys for menu traversal, etc.
        Button(qframe, text='Menu', command=self.menu).pack(side=TOP)
        arrows = self.make_arrows(qframe)
        arrows.pack(side=TOP)
        Button(qframe, text='Set', command=self.set).pack(side=TOP)
        qframe.pack(side=LEFT)

        # Menu, mode, flash, self timer buttons.
        mframe = Frame(cframe,bg='grey',border=1,relief=RIDGE)
        Button(mframe, text='Mode', command=self.mode).pack(side=TOP,fill=X)
        Button(mframe, text='Flash', command=self.flash).pack(side=TOP,fill=X)
        Button(mframe, text='Timer', command=self.timer).pack(side=TOP,fill=X)
        Button(mframe, text='Disp', command=self.disp).pack(side=TOP,fill=X)
        Button(mframe, text='Preview', command=self.prev).pack(side=TOP,fill=X)
        mframe.pack(side=LEFT,padx=10)

        # Zoom, Focus, Take Pic.
        pframe = Frame(cframe)

        zframe = Frame(pframe,border=0)
        Label(zframe,text='Zoom',justify=LEFT,border=0).pack(side=LEFT,fill=X)
        zoomin = Button(zframe,text='In')
        zoomin.bind("<Button-1>", self.zoomin_start)
        zoomin.bind("<ButtonRelease-1>", self.zoomin_stop)
        zoomin.pack(side=LEFT,padx=5)
        zoomout = Button(zframe,text='Out')
        zoomout.bind("<Button-1>", self.zoomout_start)
        zoomout.bind("<ButtonRelease-1>", self.zoomout_stop)
        zoomout.pack(side=LEFT)
        zframe.pack(side=TOP)

        fframe = Frame(pframe,border=0)
        Label(fframe,text='Focus',justify=LEFT,border=0).pack(side=LEFT,fill=X)
        Button(fframe,text='Set',command=self.focus_set).pack(side=LEFT,padx=5)
        Button(fframe,text='Lock',command=self.focus_lock).pack(side=LEFT)
        fframe.pack(side=TOP,pady=10)
        Button(pframe,text='Take Picture',border=4,
               command=self.take_picture).pack(side=TOP,fill=X)
        pframe.pack(side=LEFT)

        cframe.pack(side=TOP,fill=BOTH, pady=5)

        # Frame for time lapse controls
        Label(self.top,text='Time lapse',bd=1,relief=SUNKEN,bg='grey').\
                                  pack(side=TOP,fill=X,pady=5)

        tlframe = Frame(self.top)

        vframe = Frame(tlframe,border=0)
        Label(vframe,text='Pictures', border=0).pack(side=LEFT,padx=0)
        self.pics_entry = Entry(vframe,width=6)
        self.pics_entry.bind("<Return>",self.pics_get)
        self.pics_entry.bind("<Leave>",self.pics_get)
        self.pics_set(999)
        self.pics_entry.pack(side=LEFT,padx=5)

        Label(vframe,text='Interval (s)', border=0).pack(side=LEFT,padx=5)
        self.secs_entry = Entry(vframe,width=6)
        self.secs_entry.bind("<Return>",self.secs_get)
        self.secs_entry.bind("<Leave>",self.secs_get)
        self.secs_set(60)
        self.secs_entry.pack(side=LEFT,padx=5)

        Label(vframe,text='Delay (h)', border=0).pack(side=LEFT,padx=5)
        self.delay_entry = Entry(vframe,width=6)
        self.delay_entry.bind("<Return>",self.delay_get)
        self.delay_entry.bind("<Leave>",self.delay_get)
        self.delay_set(0)
        self.delay_entry.pack(side=LEFT,padx=5)
        vframe.pack(side=TOP,fill=X)

        vframe = Frame(tlframe,border=0)
        self.secs_next = Label(vframe,text='Time to next 0.0s',width=22,bd=1)
        self.secs_next.pack(side=LEFT,padx=0)
        self.taken = 0
        self.taken_label = Label(vframe, width=15, text='Inactive: 0')
        self.taken_label.pack(side=LEFT,fill=X,expand=YES)
        vframe.pack(side=TOP,fill=X)

        bframe = Frame(tlframe,border=0)
        self.start = Button(bframe, text='Start', command=self.start)
        self.start.pack(side=LEFT)
        self.pause = Button(bframe, text='Pause', command=self.pause,
                            state=DISABLED)
        self.pause.pack(side=LEFT,padx=5)
        self.cancel = Button(bframe, text='Cancel', command=self.cancel,
                             state=DISABLED)
        self.cancel.pack(side=LEFT)
        bframe.pack(side=TOP,fill=X)

        tlframe.pack(side=TOP,fill=X)

        # Status bar at the bottom
        self.status = StatusBar(self.top)
        self.status.pack(side=TOP,fill=X)

        # Finally, connect to the camera
        try:
            self.qv = QVrec(device=self.serial_device,dummy=0)
        except:
            self.update_status("Failed to open " + self.serial_device)
        if not top:
            self.top.mainloop()

    def loadrc(self):
        self.campath = "/mnt/camera"
        self.diskpath = os.environ['HOME'] + '/Desktop/qv3000'
        self.serial_device = '/dev/ttyS0'
        self.browser = "netscape"
        self.rcfile = os.environ['HOME'] + "/" + '.qvrc'
        if os.path.exists(self.rcfile):
            for line in open(self.rcfile,"r").readlines():
                key,value = string.split(line)
                exec("self."+key+" = '"+value+"'")
        else:
            self.saverc()

    def saverc(self):
        rc = open(self.rcfile,"w")
        rc.write("campath " + self.campath + "\n")
        rc.write("diskpath " + self.diskpath + "\n")
        rc.write("serial_device " + self.serial_device + "\n")
        rc.write("browser " + self.browser + "\n")
        rc.close()

    def make_arrows(self,parent):
        arrows = Frame(parent,border=1,bg='grey', relief=RIDGE)

        row1 = Frame(arrows,border=0,bg='grey')
        row1.pack(side=TOP,fill=X)
        row2 = Frame(arrows,border=0,bg='grey')
        row2.pack(side=TOP,fill=X)
        row3 = Frame(arrows,border=0,bg='grey')
        row3.pack(side=TOP,fill=X)

        Label(row1,text='',bg='grey').pack(side=LEFT, fill=X, expand=YES)
        Button(row1,text='Up',command=self.up).pack(side=LEFT)
        Label(row1,text='',bg='grey').pack(side=LEFT, fill=X, expand=YES)

        Button(row2,text='Left',command=self.left).pack(side=LEFT)
        Label(row2,text='',bg='grey').pack(side=LEFT, fill=X, expand=YES)
        Button(row2,text='Right',command=self.right).pack(side=RIGHT)

        Label(row3,text='',bg='grey').pack(side=LEFT, fill=X, expand=YES)
        Button(row3,text='Down',command=self.down).pack(side=LEFT)
        Label(row3,text='',bg='grey').pack(side=RIGHT, fill=X, expand=YES)

        return arrows

    def serialget(self,event):
        prev = self.serial_device
        self.serial_device = self.sentry.get()
        self.status.clear()
        if prev != self.serial_device:
            if not os.path.exists(self.serial_device):
                self.update_status(self.serial_device + ' does not exist')
                self.serial_device = prev
                self.sentry.delete(0,END)
                self.sentry.insert(0,self.serial_device)
            else:
                try:
                    self.qv = QVrec(device=self.serial_device)
                    self.update_status('Changed serial device to ' +
                                       self.serial_device)
                    self.saverc()
                except:
                    self.update_status("Failed to open " + self.serial_device)
                    self.serial_device = prev
                    self.sentry.delete(0,END)
                    self.sentry.insert(0,self.serial_device)
                    self.qv = QVrec(device=self.serial_device)

    def diskpathget(self,event):
        prev = self.diskpath
        self.diskpath = self.dentry.get()
        self.status.clear()
        if prev != self.diskpath:
            self.update_status('New download directory ' + self.diskpath)
            self.saverc()

    def campathget(self,event):
        prev = self.campath
        self.campath = self.centry.get()
        self.status.clear()
        if prev != self.campath:
            self.update_status('Mount point ' + self.campath)
            self.saverc()

    def quit(self):
        self.top.quit()

    def mounted(self):
        return os.path.exists(self.campath+"/dcim")

    def usb(self):
        self.qv.usb()
        self.update_status("Toggled USB mode")

    def mount(self):
        '''
        Try to mount the camera switching into USB mode if necessary
        '''
        if self.mounted():
            self.update_status("Already mounted " + self.campath)
            return
        mount_command = "mount "+self.campath+" 2>1 1>/dev/null"
        if os.system(mount_command) == 0:
            self.update_status("Mounted "+self.campath)
            return
        self.usb()
        if os.system(mount_command) == 0:
            self.update_status("Mounted "+self.campath)
            return
        self.update_status("Failed to mount the camera")

    def unmount(self):
        '''
        Unmount the camera and switch out of USB mode if necessary
        '''
        if self.mounted():
            if os.system("umount "+self.campath+" 2>1 1>/dev/null") == 0:
                self.update_status("Unmounted "+self.campath)
                self.usb()
            else:
                self.update_status("Failed to unmount "+self.campath)
        else:
            self.update_status("Not mounted "+self.campath)

    def synchronize(self):
        # Sync the contents of the camera with the disk copy
        # Relies on depth first traversal by walk which is kinda
        # broken by empty directories but it works nevertheless
        if not self.mounted():
            self.mount()
        if not os.path.exists(self.diskpath):
            try:
                os.makedirs(self.diskpath)
                os.makedirs(self.diskpath+"/dcim")
                os.makedirs(self.diskpath+"/tiff")
            except:
                self.update_status("Failed to make " + self.diskpath)
                return
        camfiles = []
        os.path.walk(self.campath,
                     lambda arg,dir,nam: arg.append([dir,nam]),
                     camfiles)
        base = len(self.campath)
        total = 0
        for dir,names in camfiles:
            for name in names:
                diskdir = self.diskpath + dir[base:]
                if not os.path.exists(diskdir):
                    os.makedirs(diskdir)
                diskfile = diskdir + "/" + name
                camfile  = self.campath  + dir[base:] + "/" + name
                if not os.path.exists(diskfile):
                    self.update_status("Synchronizing "+camfile)
                    try:
                        data = open(camfile,"rb").read()
                        total = total + len(data)/1024
                        open(diskfile,"wb").write(data)
                    except:
                        self.update_status("Failed synchronizing "+camfile)
                        time.sleep(1)
        self.unmount()
        self.update_status("Synchronized %d kbyte" % total)

    def update_status(self,msg):
        self.status.set("%s",msg)

    def menu(self):
        ''' Press and release the camera MENU button '''
        self.qv.menu()
        self.update_status('Camera menu')

    def mode(self):
        ''' Press and release the camera MODE button '''
        self.qv.mode()
        self.update_status('Camera mode')

    def flash(self):
        ''' Press and release the camera FLASH button '''
        self.qv.flash()
        self.update_status('Camera flash')

    def timer(self):
        ''' Press and release the camera self-TIMER button '''
        self.qv.self_timer()
        self.update_status('Camera self-timer')

    def disp(self):
        ''' Press and release the camera DISP button '''
        self.qv.disp()
        self.update_status('Camera display')

    def prev(self):
        ''' Press and release the camera Preview button '''
        self.qv.preview()
        self.update_status('Camera preview')

    def set(self):
        ''' Press and release the camera SET button '''
        self.qv.set()
        self.update_status('Camera set')

    def zoomin_start(self,event):
        ''' Start ZOOMing IN '''
        self.qv.zoom_start(1)
        self.update_status('Zooming in ...')

    def zoomin_stop(self,event):
        ''' Stop ZOOMing IN '''
        self.qv.zoom_end(1)
        self.update_status('Zoom in finished')

    def zoomout_start(self,event):
        ''' Start ZOOMing OUT '''
        self.qv.zoom_start(-1)
        self.update_status('Zooming out ...')

    def zoomout_stop(self,event):
        ''' Stop ZOOMing OUT '''
        self.qv.zoom_end(-1)
        self.update_status('Zoom out finished')

    def focus_set(self):
        ''' Half-press and release the camera shutter to SET FOCUS '''
        self.qv.focus_set()
        self.update_status('Camera focus set')

    def focus_lock(self):
        ''' Half-press and hold the camera shutter to set and LOCK FOCUS '''
        self.qv.focus_lock()
        self.update_status('Camera focus locked')

    def take_picture(self):
        ''' Press the camera shutter to TAKE a PICTURE '''
        self.update_status('Taking picture ...')
        self.qv.shutter()
        self.update_status('Picture taken')

    def up(self):
        ''' Press and release the camera UP arrow button '''
        self.qv.up()
        self.update_status('Camera up arrow')

    def down(self):
        ''' Press and release the camera DOWN arrow button '''
        self.qv.down()
        self.update_status('Camera down arrow')

    def left(self):
        ''' Press and release the camera LEFT arrow button '''
        self.qv.left()
        self.update_status('Camera left arrow')

    def right(self):
        ''' Press and release the camera RIGHT arrow button '''
        self.qv.right()
        self.update_status('Camera right arrow')

    def update_taken(self,msg):
        self.taken_label.config(text=((msg+': %d pics') % self.taken))

    def sleep_until(self,target):
        '''
        Sleep until the current time is >= target checking every second
        to see if this thread should exit.
        '''
        while 1:
            rem = target - time.time()
            if rem <= 0.5:
                break
            self.secs_next.config(text=("Time to next %.1fs" % rem))
            time.sleep(min(1,rem))
            if self.kill_time_lapse_thread:
                thread.exit()
            self.update_status('Sleeping')
        self.secs_next.config(text=("%8.1fs" % 0.0))

    def do_time_lapse(self):
        self.sleep_until(time.time()+self.delay*3600)
        start = next = time.time() # Start timing from when picture taken
        self.taken = 0
        while self.taken < self.pics:
            self.sleep_until(next)
            next = next + self.secs
            if self.pause_time_lapse:
                self.update_status('Not taking scheduled picture due to pause')
            else:
                self.take_picture()
                self.taken = self.taken + 1
                self.update_taken('Active')
        self.update_taken('Finished')
        self.start.config(state=NORMAL)
        self.pause.config(state=DISABLED)
        self.cancel.config(state=DISABLED)
        self.pause.config(text='Pause')

    def start(self):
        ''' Start a sequence of time lapse pictures '''
        self.taken = 0
        self.pause_time_lapse = 0
        self.kill_time_lapse_thread = 0
        self.start.config(state=DISABLED)
        self.pause.config(state=NORMAL)
        self.cancel.config(state=NORMAL)
        thread.start_new_thread(self.do_time_lapse,())
        self.update_status('Time lapse started')

    def pause(self):
        if self.pause_time_lapse:
            self.pause_time_lapse = 0
            self.update_taken('Active')
            self.update_status('Time lapse continued')
            self.pause.config(text='Pause')
        else:
            self.pause_time_lapse = 1
            self.update_taken('Paused')
            self.update_status('Time lapse paused')
            self.pause.config(text='Continue')

    def cancel(self):
        self.kill_time_lapse_thread = 1
        self.update_status('Time lapse being cancelled ...')
        time.sleep(5)  # Wait for the thread to see the flag
        self.update_taken('Cancelled')
        self.update_status('Time lapse has been cancelled')
        self.start.config(state=NORMAL)
        self.pause.config(state=DISABLED)
        self.cancel.config(state=DISABLED)
        self.pause.config(text='Pause')

    def secs_set(self,value):
        self.secs = value
        self.secs_entry.delete(0,END)
        self.secs_entry.insert(0,`value`)

    def delay_set(self,value):
        self.delay = value
        self.delay_entry.delete(0,END)
        self.delay_entry.insert(0,`value`)

    def pics_set(self,value):
        self.pics = value
        self.pics_entry.delete(0,END)
        self.pics_entry.insert(0,`value`)

    def secs_get(self,event):
        prev = self.secs
        s = self.secs_entry.get()
        try:
            self.secs = int(s)
            if prev != self.secs:
                self.update_status(
                    'set time-lapse interval to %ds' % self.secs)
        except ValueError:
            self.secs_set(prev)
            self.update_status('ValueError: interval must be an integer')

        if (self.secs < 4) or (self.secs > 864000):
            self.secs_set(prev)
            self.update_status('ValueError: interval must be in range 4s - 10days')

    def delay_get(self,event):
        prev = self.delay
        h = self.delay_entry.get()
        try:
            self.delay = float(h)
            if prev != self.delay:
                self.update_status(
                    'set delay to %.2f hours' % self.delay)
        except ValueError:
            self.delay_set(prev)
            self.update_status('Specify delay in hours (floating point)')

        if (self.delay < 0):
            self.delay_set(prev)
            self.update_status('ValueError: delay must be positive')

    def pics_get(self,event):
        prev = self.pics
        s = self.pics_entry.get()
        try:
            self.pics = int(s)
            if prev != self.pics:
                self.update_status(
                    'set #pics for time-lapse to %d' % self.pics)
        except ValueError:
            self.pics_set(prev)
            self.update_status('ValueError: #pics must be an integer')

        if (self.pics < 1) or (self.pics > 2500):
            self.pics_set(prev)
            self.update_status('ValueError: #pics must be in range 1 - 2500')

    def make_index(self):
        fromdir = self.diskpath+"/dcim"
        todir = self.diskpath+"/thumbs"
        indexpath = self.diskpath+"/index.html"

        if os.system("mkdir -p " + todir):
            self.update_status("Failed to make " + todir)
            return
        find = command = 'find ' + fromdir + \
               r' \( -name "*.jpg" -o -name "*.JPG"  \) | grep -v preview'
        title = "Contents of " + fromdir
        index = open(indexpath,"w")
        index.write("<html>\n<head><title>"+title+"</title></head><body>\n")
        index.write("<table border=1>\n<tr>")

        npic = 0
        npic_per_row = 6
        names = [""]*npic_per_row
        for file in os.popen(command,'r').readlines():
            fromfile = file[:-1]
            dir  = os.path.dirname(fromfile)
            base = os.path.basename(fromfile)
            dirnum = string.split(fromfile,"/")[-2]
            tofile = todir + '/' + dirnum + "_" + base
            if not os.path.exists(tofile):
                self.update_status(fromfile)
                os.system("convert "+fromfile+" -sample 128x128 " + tofile)
            index.write('<td>' +
                        '<a href="'+fromfile+'">' +
                        '<img src="'+tofile+'">' +
                        '</a>' +
                        '</td>\n')
            names[npic%npic_per_row] = dirnum + "/" + base
            if (npic%npic_per_row) == (npic_per_row-1):
                index.write("</tr><tr>\n")
                for name in names:
                    index.write('<td>'+name+'</td>')
                index.write("</tr><tr>\n")
                names = [""]*npic_per_row
            npic = npic + 1

        index.write('</tr></table>\n')
        index.write("</body></html>\n")
        self.update_status("Index generated")
        os.system("netscape "+indexpath+" 2>1 1>/dev/null &")


    def help(self):
        text = """
        Version 1.0

        Use with your camera in record mode and connected by one or both of:
        -  the serial cable - for time lapse
        -  the USB cable - for mounting and/or synchronization
        To use USB get the 2.4.* kernel patch at http://www.harald-schreiber.de.
        You need read/write access to the serial device (as root do 'chmod a+rw
        /dev/ttyS0' or whatever your device is).  So that users can mount
        the camera make a mount point (/mnt/camera) and put this in /etc/fstab

        /dev/sda1  /mnt/camera  vfat  rw,noauto,user  0 0

        If you have other SCSI devices, you can find out what number the camera
        is by using dmesg after connecting it to the computer.  On my laptop,
        USB does not work after putting it to sleep -- I have to reboot.

        Defaults are saved in $HOME/.qvrc

        Quit - Immediately terminate
        Help - This text
        USB - Toggle USB mode on the camera
        Mount - Mount the camera, switching into USB mode if necessary
        Umount - Umount the camera and switch out of USB mode
        Sync - Copy new files from camera to disk, switching in and out of USB
        mode, and mount/unmount camera as necessary.  Note that switching in/out
        of USB resets the camera to defaults so, although you can run synch
        during a time lapse (by pausing), you will lose zoom and other settings.
        Index - Make thumbnails, index file, and launch browser
        Serial - Path to serial device (saved in .qvrc)
        Download - Directory for downloads (saved in .qvrc)
        Mount - Mount point for camera (saved in .qvrc)
        Controls - should be familar from your camera
        Time lapse:
        Pictures - The number of pictures to take
        Interval - Time between pictures in seconds.  10s minimum.
        Delay - Time in hours until start of sequence (e.g., 1.5 hours = 90 minutes)
        Start - Starts a time lapse sequence
        Pause - Keeps timing but does not actually take the pictures
        Cancel - Aborts the sequence.
        """
        SimpleDialog(self.top, text=text, buttons=['OK']).go()

    def __del__(self):
        pass

if __name__ == "__main__":
    QVTk()

  Last modified: Fri, 3 December 2004 (03:01:39 PM)