volatile char menuBack(char key, char first)
{
	if(key == FL_KEY)
		menu.back();

	return FN_CANCEL;
}
volatile char firmwareUpdated(char key, char first)
{
	if(first)
	{
		uint8_t l, c;
		char* text;
		char buf[6];

		lcd.cls();
		menu.setTitle(TEXT("FIRMWARE"));

		lcd.writeStringTiny(13, 10, TEXT("Successfully"));
		lcd.writeStringTiny(25, 16, TEXT("Updated"));

		lcd.writeStringTiny(8, 28, TEXT("Version:"));
		uint32_t version = VERSION;

		l = 0;

		while(version)
		{
			c = (char)(version % 10);
			buf[0] = ((char)(c + '0'));
			buf[1] = 0;
			text = buf;
			l += lcd.measureStringTiny(text) + 1;
			lcd.writeStringTiny(75 - l, 28, text);

			version -= (uint32_t)c;
			version /= 10;
		}
		menu.setBar(TEXT("RETURN"), BLANK_STR);
		lcd.update();
	}

	switch(key)
	{
	   case FL_KEY:
	   case LEFT_KEY:
		   return FN_CANCEL;
	}

	return FN_CONTINUE;
}
volatile char notYet(char key, char first)
{
	if(first)
	{
		lcd.cls();
		lcd.writeString(3, 7, TEXT("Sorry, this  "));
		lcd.writeString(3, 15, TEXT("feature has  "));
		lcd.writeString(3, 23, TEXT("not yet been "));
		lcd.writeString(3, 31, TEXT("implemented  "));
		menu.setTitle(TEXT("Not Yet"));
		menu.setBar(TEXT("RETURN"), BLANK_STR);
		lcd.update();
	}

	if(key)
		return FN_CANCEL;

	return FN_CONTINUE;
}
volatile char memoryFree(char key, char first)
{
	if(first)
	{
		unsigned int mem = hardware_freeMemory();

		lcd.cls();
		lcd.writeString(1, 18, TEXT("Free RAM:"));
		/*char x =*/lcd.writeNumber(55, 18, mem, 'U', 'L');
		//lcd.writeString(55 + x * 6, 18, TEXT("b"));
		menu.setTitle(TEXT("Memory"));
		menu.setBar(TEXT("RETURN"), BLANK_STR);
		lcd.update();
	}

	if(key == FL_KEY)
		return FN_CANCEL;

	return FN_CONTINUE;
}
void Remote::event()
{
	switch(bt.event)
	{
		case BT_EVENT_DISCONNECT:
			connected = 0;
			break;

		case BT_EVENT_CONNECT:
			connected = 1;
			break;

		case BT_EVENT_DATA:
			switch(bt.dataId)
			{
				case REMOTE_STATUS:
					if(bt.dataType == REMOTE_TYPE_REQUEST) send(bt.dataId, REMOTE_TYPE_SEND);
					if(bt.dataType == REMOTE_TYPE_SEND) memcpy(&status, bt.data, bt.dataSize);
					if(bt.dataType == REMOTE_TYPE_SET) memcpy(&status, bt.data, bt.dataSize);
					break;
				case REMOTE_PROGRAM:
					if(bt.dataType == REMOTE_TYPE_REQUEST) send(bt.dataId, REMOTE_TYPE_SEND);
					if(bt.dataType == REMOTE_TYPE_SEND) memcpy(&current, bt.data, bt.dataSize);
					if(bt.dataType == REMOTE_TYPE_SET)
					{
						memcpy((void*)&timer.current, bt.data, bt.dataSize);
						menu.refresh();
					}
					break;
				case REMOTE_BATTERY:
					if(bt.dataType == REMOTE_TYPE_REQUEST) send(bt.dataId, REMOTE_TYPE_SEND);
					if(bt.dataType == REMOTE_TYPE_SEND) memcpy(&battery, bt.data, 1);
					if(bt.dataType == REMOTE_TYPE_SET) memcpy(&battery, bt.data, 1);
					break;
				case REMOTE_START:
					if(bt.dataType == REMOTE_TYPE_REQUEST) send(timer.running ? REMOTE_START : REMOTE_STOP, REMOTE_TYPE_SEND);
					if(bt.dataType == REMOTE_TYPE_SEND) running = 1;
					if(bt.dataType == REMOTE_TYPE_SET) runHandler(FR_KEY, 1);
					break;
				case REMOTE_STOP:
					if(bt.dataType == REMOTE_TYPE_REQUEST) send(timer.running ? REMOTE_START : REMOTE_STOP, REMOTE_TYPE_SEND);
					if(bt.dataType == REMOTE_TYPE_SEND) running = 0;
					if(bt.dataType == REMOTE_TYPE_SET) timerStop(FR_KEY, 1);
					break;
				default:
					return;
			}
			bt.event = BT_EVENT_NULL;
			break;
	}
	requestActive = 0;
}
volatile char shutter_addKeyframe(char key, char first)
{
	if(timer.current.Keyframes < MAX_KEYFRAMES)
	{
		if(timer.current.Keyframes < 1)
			timer.current.Keyframes = 1;

		timer.current.Key[timer.current.Keyframes] = timer.current.Key[timer.current.Keyframes - 1] + 3600;
		timer.current.Bulb[timer.current.Keyframes + 1] = timer.current.Bulb[timer.current.Keyframes];
		timer.current.Keyframes++;
	}

	menu.back();

	return FN_CANCEL;
}
void updateConditions()
{
	if(timerNotRunning != !timer.running) menu.refresh();
	timerNotRunning = !timer.running;
	modeTimelapse = (timer.current.Mode & TIMELAPSE);
	modeHDR = (timer.current.Mode & HDR);
	modeStandard = (!modeHDR && !modeRamp);
	modeRamp = (timer.current.Mode & RAMP);
	modeRampKeyAdd = (modeRamp && (timer.current.Keyframes < MAX_KEYFRAMES));
	modeRampKeyDel = (modeRamp && (timer.current.Keyframes > 1));
	bulb1 = timer.current.Keyframes > 1 && modeRamp;
	bulb2 = timer.current.Keyframes > 2 && modeRamp;
	bulb3 = timer.current.Keyframes > 3 && modeRamp;
	bulb4 = timer.current.Keyframes > 4 && modeRamp;
	showGap = timer.current.Photos != 1 && modeTimelapse;
	showRemoteStart = (remote.connected && !remote.running);	
	clock.sleepOk = timerNotRunning && !timer.cableIsConnected() && bt.state != BT_ST_CONNECTED && sleepOk;
}
void hardware_off(void)
{
    hardware_flashlight(0);
    if(battery_status() == 0)
    {
        //if(timer.cableIsConnected())
        //{
        //    menu.message(STR("Error: Cable"));
        //}
        //else
        //{
            shutter_off();

            // Save the current time-lapse settings to nv-mem
            timer.saveCurrent();

            // If USB is used, detach from the bus
            USB_Detach();

            // Shutdown bluetooth
            bt.disconnect();
            bt.sleep();

            // Disable all interrupts
            cli();

            // Shutdown
            setHigh(POWER_HOLD_PIN);

            FOREVER;
        //}
    } 
    else // Plugged in
    {
        // Charging screen //
        clock.sleeping = 1;
        menu.spawn((void *) batteryStatus);
    }
}
volatile char usbPlug(char key, char first)
{
	static char connected = 0;

	if(first || (PTP_Connected != connected) || (PTP_Ready))
	{
		connected = PTP_Connected;
		char exp_name[7];

		if(PTP_Connected)
		{
			if(PTP_Ready)
			{
				lcd.cls();
				lcd.writeString(3, 7,  PTP_CameraModel);
				if(camera.shutterName(exp_name, camera.shutter))
				{
					lcd.writeString(3, 15, exp_name);
				}
				if(camera.apertureName(exp_name, camera.aperture))
				{
					lcd.writeString(3, 23, TEXT("f"));
					lcd.writeString(3+6, 23, exp_name);
				}
				if(camera.isoName(exp_name, camera.iso))
				{
					lcd.writeString(3, 31, TEXT("ISO"));
					lcd.writeString(3+24, 31, exp_name);
				}
				menu.setTitle(TEXT("Camera Info"));
				menu.setBar(TEXT("RETURN"), TEXT("PHOTO"));
				lcd.update();
				connectUSBcamera = 1;

			}
			else
			{
				lcd.cls();
				lcd.writeString(3, 7,  TEXT(" Connected!  "));
				lcd.writeString(3, 15, TEXT(" Retrieving  "));
				lcd.writeString(3, 23, TEXT("   Device    "));
				lcd.writeString(3, 31, TEXT("   Info...   "));
				menu.setTitle(TEXT("Camera Info"));
				menu.setBar(TEXT("RETURN"), BLANK_STR);
				lcd.update();
				connectUSBcamera = 1;

			}
		}
		else
		{
			lcd.cls();
			lcd.writeString(3, 7, TEXT("Plug camera  "));
			lcd.writeString(3, 15, TEXT("into left USB"));
			lcd.writeString(3, 23, TEXT("port...      "));
			lcd.writeString(3, 31, TEXT("             "));
			menu.setTitle(TEXT("Connect USB"));
			menu.setBar(TEXT("CANCEL"), BLANK_STR);
			lcd.update();
			connectUSBcamera = 1;
		}
	}

	if(key == FL_KEY || key == LEFT_KEY)
	{
		if(!PTP_Connected)
			connectUSBcamera = 0;

		return FN_CANCEL;
	}
	else if(key == FR_KEY)
	{
		if(PTP_Ready) camera.capture();
	}
	else if(key == UP_KEY)
	{
		if(PTP_Ready) camera.isoUp(camera.iso);
	}
	else if(key == DOWN_KEY)
	{
		if(PTP_Ready) camera.isoDown(camera.iso);
	}

	return FN_CONTINUE;
}
Beispiel #10
0
void CASSETTE :: ADDITION(void)
{
	MENU menu ;
	char filename[13], casname[36], ch ;
	int cascode, valid ;
	do
	{
		strcpy(filename,menu.CHOICE_MENU()) ;
		if (!strcmpi(filename,"FAILED"))
			return ;
		cascode = LASTCODE(filename) + 1 ;
		LINES line ;
		line.BOX(10,6,71,21,219) ;
		line.LINE_HOR(11,70,10,196) ;
		gotoxy(72,1) ;
		cout <<"<0>=EXIT" ;
		gotoxy(27,8) ;
		cout <<"ADDITION OF NEW CASSETTES" ;
		gotoxy(20,12) ;
		cout <<"Code # " <<cascode ;
		do
		{
			valid = 1 ;
			gotoxy(5,25) ; clreol() ;
			cout <<"ENTER NAME OF THE CASSETTE" ;
			gotoxy(20,14) ;
			cout <<"                                                   " ;
			gotoxy(20,14) ;
			cout <<"Name : " ;
			gets(casname) ;
			if (casname[0] == '0')
				return ;
			if (strlen(casname) < 1 || strlen(casname) > 35)
			{
				valid = 0 ;
				gotoxy(5,25) ; clreol() ;
				cout <<"\7Enter Correctly (Range: 1..35)" ;
				getch() ;
			}
		} while (!valid) ;
		gotoxy(5,25) ; clreol() ;
		do
		{
			gotoxy(20,17) ;
			cout <<"                           " ;
			gotoxy(20,17) ;
			cout <<"Do you want to save (y/n) " ;
			ch = getche() ;
			ch = toupper(ch) ;
			if (ch == '0')
				return ;
		} while (ch != 'Y' && ch != 'N') ;
		if (ch == 'Y')
		{
			char casstatus='A' ;
			int  ccode=0 ;
			ADD_RECORD(filename,cascode,casname,casstatus,ccode) ;
			cascode++ ;
		}
		do
		{
			gotoxy(20,19) ;
			cout <<"                               " ;
			gotoxy(20,19) ;
			cout <<"Do you want to Add more (y/n) " ;
			ch = getche() ;
			ch = toupper(ch) ;
			if (ch == '0')
				return ;
		} while (ch != 'Y' && ch != 'N') ;
		if (ch == 'N')
			return ;
	} while (ch == 'Y') ;
}
Beispiel #11
0
void CASSETTE :: MODIFICATION(void)
{
	MENU menu ;
	char t1[10], ch, filename[13] ;
	int t2, cascode, valid ;
	strcpy(filename,menu.CHOICE_MENU()) ;
	if (!strcmpi(filename,"FAILED"))
		return ;
	do
	{
		valid = 1 ;
		do
		{
			clrscr() ;
			gotoxy(72,2) ;
			cout <<"<0>=EXIT" ;
			gotoxy(5,5) ;
			cout <<"Enter code of the Cassette or <ENTER> for help " ;
			gets(t1) ;
			t2 = atoi(t1) ;
			cascode = t2 ;
			if (cascode == 0 && strlen(t1) != 0)
				return ;
			if (strlen(t1) == 0)
				DISPLAY_LIST(filename) ;
		} while (strlen(t1) == 0) ;
		if (!FOUND_CODE(filename,cascode))
		{
			valid = 0 ;
			gotoxy(5,20) ;
			cout <<"\7Cassette code not found." ;
			getch() ;
		}
	} while (!valid) ;
	clrscr() ;
	gotoxy(72,1) ;
	cout <<"<0>=EXIT" ;
	DISPLAY_RECORD(filename,cascode) ;
	do
	{
		gotoxy(5,12) ; clreol() ;
		cout <<"Modify Cassette Name (y/n) " ;
		ch = getche() ;
		ch = toupper(ch) ;
		if (ch == '0')
			return ;
	} while (ch != 'Y' && ch != 'N') ;
	if (ch == 'N')
		return ;
	char casname[36] ;
	do
	{
		valid = 1 ;
		gotoxy(5,25) ; clreol() ;
		cout <<"ENTER NAME OF THE CASSETTE" ;
		gotoxy(5,15) ; clreol() ;
		cout <<"Name : " ;
		gets(casname) ;
		if (casname[0] == '0')
			return ;
		if (strlen(casname) < 1 || strlen(casname) > 35)
		{
			valid = 0 ;
			gotoxy(5,25) ; clreol() ;
			cout <<"\7Enter Correctly (Range: 1..35)" ;
			getch() ;
		}
	} while (!valid) ;
	gotoxy(5,25) ; clreol() ;
	do
	{
		gotoxy(5,17) ; clreol() ;
		cout <<"Do you want to save (y/n) " ;
		ch = getche() ;
		ch = toupper(ch) ;
		if (ch == '0')
			return ;
	} while (ch != 'Y' && ch != 'N') ;
	if (ch == 'N')
		return ;
	int recno ;
	recno = RECORDNO(filename,cascode) ;
	fstream file ;
	file.open(filename, ios::out | ios::ate) ;
	strcpy(name,casname) ;
	int location ;
	location = (recno-1) * sizeof(CASSETTE) ;
	file.seekp(location) ;
	file.write((char *) this, sizeof(CASSETTE)) ;
	file.close() ;
	gotoxy(5,20) ;
	cout <<"\7Record Modified" ;
	gotoxy(5,25) ;
	cout <<"Press any key to continue..." ;
	getch() ;
}
Beispiel #12
0
void ISSUE_RETURN :: ISSUE(void)
{
	MENU menu ;
	CUSTOMER cust ;
	CASSETTE cas ;
	char filename[13] ;
	strcpy(filename,menu.CHOICE_MENU()) ;
	if (!strcmpi(filename,"FAILED"))
		return ;
	char t1[10] ;
	int t2, cascode, valid ;
	do
	{
		valid = 1 ;
		do
		{
			clrscr() ;
			gotoxy(72,2) ;
			cout <<"<0>=EXIT" ;
			gotoxy(5,5) ;
			cout <<"Enter code of the Cassette or <ENTER> for help " ;
			gets(t1) ;
			t2 = atoi(t1) ;
			cascode = t2 ;
			if (cascode == 0 && strlen(t1) != 0)
				return ;
			if (strlen(t1) == 0)
				DISPLAY_LIST(filename) ;
		} while (strlen(t1) == 0) ;
		if (!CASSETTE::FOUND_CODE(filename,cascode))
		{
			valid = 0 ;
			gotoxy(5,20) ;
			cout <<"\7Cassette code not found. Kindly choose another." ;
			getch() ;
		}
		if (valid && ISSUED(filename,cascode))
		{
			valid = 0 ;
			gotoxy(5,20) ;
			cout <<"\7Cassette already issued. Kindly choose another." ;
			getch() ;
		}
	} while (!valid) ;
	clrscr() ;
	int ccode ;
	ccode = CUSTOMER::LASTCODE() + 1 ;
	char custname[26], custphone[10] ;
	int d1, m1, y1 ;
	struct date d;
	getdate(&d);
	d1 = d.da_day ;
	m1 = d.da_mon ;
	y1 = d.da_year ;
	gotoxy(5,2) ;
	cout <<"Date: " <<d1 <<"/" <<m1 <<"/" <<y1 ;
	gotoxy(72,2) ;
	cout <<"<0>=EXIT" ;
	CASSETTE::DISPLAY_RECORD(filename,cascode) ;
	gotoxy(5,10) ;
	cout <<"Customer Code # " <<ccode ;
	gotoxy(5,12) ;
	cout <<"Name   : " ;
	gotoxy(5,13) ;
	cout <<"Phone  : " ;
	do
	{
		valid = 1 ;
		gotoxy(5,25) ; clreol() ;
		cout <<"Enter the name of the Customer" ;
		gotoxy(14,12) ; clreol() ;
		gets(custname) ;
		strupr(custname) ;
		if (custname[0] == '0')
			return ;
		if (strlen(custname) < 1 || strlen(custname) > 25)
		{
			valid = 0 ;
			gotoxy(5,25) ; clreol() ;
			cout <<"\7Enter correctly (Range: 1..25)" ;
			getch() ;
		}
	} while (!valid) ;
	do
	{
		valid = 1 ;
		gotoxy(5,25) ; clreol() ;
		cout <<"Enter Phone no. of the Customer" ;
		gotoxy(14,13) ; clreol() ;
		gets(custphone) ;
		if (custphone[0] == '0')
			return ;
		if ((strlen(custphone) < 7 && strlen(custphone) > 0) || (strlen(custphone) > 9))
		{
			valid = 0 ;
			gotoxy(5,25) ; clreol() ;
			cout <<"\7Enter correctly" ;
			getch() ;
		}
	} while (!valid) ;
	gotoxy(5,25) ; clreol() ;
	UPDATE(filename,cascode,ccode,'N') ;
	EXTEND_DATE(d1,m1,y1,5) ;
	d1 = day ;
	m1 = mon ;
	y1 = year ;
	CUSTOMER::ADD_RECORD(ccode,custname,custphone,filename,cascode,d1,m1,y1) ;
	gotoxy(5,17) ;
	cout <<"\7CASSETTE ISSUED" ;
	gotoxy(5,19) ;
	cout <<"Date of Return : " <<d1 <<"/" <<m1 <<"/" <<y1 ;
	gotoxy(5,25) ;
	cout <<"Press any key to continue..." ;
	getch() ;
}
Beispiel #13
0
void main(void)
{
	MENU menu ;
	menu.MAIN_MENU() ;
}
Beispiel #14
0
main (int argc, char **argv, char **envp) {
	register c;

	if (argc > 2) {
		outerr("Usage: deco [dirname]\n",0);
		exit (1);
	}
	outerr("Demos Commander, Copyright (C) 1989-1994 Serge Vakulenko\n",0);
	palette = dflt_palette;
	EnvInit (envp);
	uid = getuid ();
	gid = getgid ();
# ifdef GROUPS
	gidnum = getgroups (sizeof(gidlist)/sizeof(gidlist[0]), (unsigned int *)gidlist);
# endif
	ppid = getppid ();
	user = username (uid);
	group = groupname (gid);
	tty = ttyname (0);
	machine = getmachine ();
#if 0
	sigign();
#else
	signal(SIGTERM, SIG_IGN);
	signal(SIGQUIT, SIG_IGN);
	signal(SIGINT, SIG_IGN);
# ifdef SIGTSTP
	signal(SIGTSTP, SIG_IGN);
# endif
#endif
	init ();
//	inithome ();
	VClear ();
/* init class dir */
	if (argc > 1)
//		chdir (argv [1]);
		left = new dir(argv [1]);
	else
		left = new dir;
	right = new dir;
	left->d.basecol = 0;
	right->d.basecol = 40;
/*-----------*/
	initfile.read();
	if (uid == 0)
		palette.dimfg = 6;
	v.VSetPalette (palette.fg, palette.bg, palette.revfg, palette.revbg,
		palette.boldfg, palette.boldbg, palette.boldrevfg, palette.boldrevbg,
		palette.dimfg, palette.dimbg, palette.dimrevfg, palette.dimrevbg);
	setdir (left, ".");
	setdir (right, ".");
	left->chdir(left->d.cwd);
	cur = left;
	draw.draw(cur, left, right);
	for (;;) {
		if (! cmdreg)
			draw.drawcursor(cur);
//		cmd.drawcmd(cur, &left, &right);
		VSync ();
		c = KeyGet ();
		if (! cmdreg)
			draw.undrawcursor(cur);
		switch (c) {
		case '+':               /* select */
		case '-':               /* unselect */
			if (! cpos && ! cmdreg && ! cur->d.status) {
				if (c == '+')
					tagall ();
				else
					untagall ();
				draw.draw(cur, left, right);
				continue;
			}
		default:
//			if (c>=' ' && c<='~' || c>=0300 && c<=0376) {
//				if (cpos || c!=' ')
//					cmd.inscmd(c);
//				continue;
//			}
			VBeep ();
			continue;
//		case cntrl ('V'):       /* quote next char */
//			cmd.inscmd(quote ());
//			continue;
//		case cntrl ('J'):       /* insert file name */
//			if (! cmdreg && ! cur->status)
//				cmd.namecmd(cur);
//			continue;
//		case cntrl ('G'):
//			cmd.delcmd();
//			continue;
//		case meta ('b'):        /* backspace */
//			if (cpos) {
//				cmd.leftcmd();
//				cmd.delcmd();
//			}
//			continue;
		case cntrl ('O'):       /* set/unset command mode */
		case cntrl ('P'):       /* set/unset command mode */
			switchcmdreg ();
			if (! cmdreg)
				visualwin = 1;
			draw.draw(cur, left, right);
			continue;
		case cntrl ('M'):         /* return */
//			if (command [0]) {
//				cmd.exec(cur, &left, &right, 1, 1);
//				draw.draw(cur, &left, &right);
//				continue;
//			}
			if (cmdreg) {
				cmdreg = 0;
				if (! visualwin) {
					visualwin = 1;
					setdir (cur==left ? right : left, NULL);
					setdir (cur, NULL);
				}
				draw.draw(cur, left, right);
				continue;
			}
			execute ();
			continue;
		case cntrl (']'):       /* redraw screen */
			VRedraw ();
			continue;
//		case cntrl ('B'):        /* history */
//			if (! visualwin)
//				VClearBox (1, 0, LINES-2, 80);
//			cmd.histmenu(cur, &left, &right);
//			draw.draw(cur, &left, &right);
//			continue;
		case meta ('A'):        /* f1 */
			genhelp ();
			draw.draw(cur, left, right);
			continue;
		case meta ('B'):          /* f2 */
			udm.menu();
			draw.draw(cur, left, right);
			continue;
		case meta ('I'):        /* f9 */
			mymenu.runmenu (cur==left ? 'l' : 'r');
			draw.draw(cur, left, right);
			continue;
		case meta ('J'):        /* f0 */
		case cntrl ('C'):       /* quit */
			quit ();
			continue;
		case cntrl ('U'):       /* swap panels */
			swappanels ();
			draw.draw(cur, left, right);
			continue;
		case cntrl ('F'):       /* full screen */
			fullscreen ();
			draw.draw(cur, left, right);
			continue;
		case cntrl ('^'):       /* cd / */
			directory (0, 'r');
			if (! cur->d.status)
				draw.drawdir(cur, 1, left, right);
			continue;
		case cntrl ('\\'):      /* cd $HOME */
			directory (0, 'o');
			if (! cur->d.status)
				draw.drawdir(cur, 1, left, right);
			continue;
//		case cntrl ('Y'):       /* clear line */
//			command [cpos = 0] = 0;
//			continue;
//		case cntrl ('X'):       /* next history */
//			cmd.nextcmd();
//			continue;
//		case cntrl ('E'):       /* prev history */
//			cmd.prevcmd();
//			continue;
//		case cntrl ('S'):       /* char left */
//		case cntrl ('A'):       /* char left */
//			cmd.leftcmd();
//			continue;
//		case cntrl ('D'):       /* char right */
//			cmd.rightcmd();
//			continue;
		case cntrl ('I'):       /* tab */
			if (cmdreg) {}
//				if (command [cpos])
//					cmd.endcmd();
//				else
//					cmd.homecmd();
			else {
				switchpanels ();
				if (fullwin) {
					draw.drawbanners();
					draw.drawdir(cur, 0, left, right);
					break;
				}
			}
			continue;
		case cntrl ('W'):       /* double width */
			if (! cmdreg) {
				setdwid ();
				draw.draw(cur, left, right);
			}
			continue;
//		case meta ('G'):        /* f7 */
//			makedir ();
//			draw.draw(cur, &left, &right);
//			continue;
		case meta ('h'):        /* home */
		case meta ('e'):        /* end */
		case meta ('u'):        /* up */
		case meta ('d'):        /* down */
		case meta ('l'):        /* left */
		case meta ('r'):        /* right */
		case meta ('n'):        /* next page */
		case meta ('p'):        /* prev page */
		case cntrl ('K'):       /* find file */
		case cntrl ('R'):       /* reread catalog */
		case cntrl ('T'):       /* tag file */
		case meta ('C'):        /* f3 */
		case meta ('D'):        /* f4 */
		case meta ('E'):        /* f5 */
		case meta ('F'):        /* f6 */
		case meta ('H'):        /* f8 */
		case cntrl ('L'):       /* status */
			if (cmdreg || cur->d.status) {}
//				docmdreg (c);
			else
				doscrreg (c);
			continue;
		}
	}
}
volatile void Button::poll()
{
    uint8_t i;
    char p;

    for(i = 0; i < NUM_KEYS; i++)
    {
        p = pgm_read_byte(&button_pins[i]);
        
        if(i < 2) 
            p = (getBit(p, FB_PIN) == LOW);
        else 
            p = (getBit(p, B_PIN) == LOW);
        
        if(p)  // key is pressed
        {
            if(button_count[i] < DEBOUNCE_REPEAT_DELAY)
            {
                button_count[i]++;
                
                if(button_count[i] > DEBOUNCE_ON)
                {
                    if(button_status[i] == 0)
                    {
                        button_flag[i] = 1;
                        button_status[i] = 1; //button debounced to 'pressed' status
                        clock.awake(); // keep from sleeping since a button was pressed
                    }

                }
            }
            else
            {
                if(i + 1 == UP_KEY || i + 1 == DOWN_KEY || (verticalRepeat && (i + 1 == LEFT_KEY || i + 1 == RIGHT_KEY)))
                {
                    button_flag[i] = 1;
                    button_status[i] = 1; //button debounced to 'pressed' status
                    button_count[i] = DEBOUNCE_REPEAT_DELAY - DEBOUNCE_REPEAT_SPEED;
                }
                else if(i + 1 == FL_KEY)
                {
                    off_count++;
                    if(off_count > POWER_OFF_TIME)
                    {
                        menu.message(TEXT("Power Off"));
                        menu.task();
                        cli();
                        while(getBit(p, FB_PIN) == LOW) wdt_reset();
                        hardware_off();
                    }
                }
            }

        } 
        else // not pressed
        {
            if(i + 1 == FL_KEY) off_count = 0;
            if(button_count[i] > 0)
            {
                //button_flag[i] = 0;
                if(button_count[i] > DEBOUNCE_MAX) button_count[i] = DEBOUNCE_MAX;
                button_count[i]--;
                
                if(button_count[i] < DEBOUNCE_OFF)
                {
                    button_status[i] = 0;   //button debounced to 'released' status
                }
            }
        }
    }
}
volatile char sysInfo(char key, char first)
{
	if(first)
	{
		lcd.cls();

		char l;
		char* text;
		char buf[6];
		uint16_t val;

		// Lines (Y) = 6, 12, 18, 24, 30
		val = (uint16_t)bt.version();

		text = TEXT("TLP01");
		l = lcd.measureStringTiny(text);
		lcd.writeStringTiny(80 - l, 6 + SY, text);
		lcd.writeStringTiny(3, 6 + SY, TEXT("Model:"));

		if(val > 1)
			text = TEXT("BTLE");
		else
			text = TEXT("KS99");

		l = lcd.measureStringTiny(text);
		lcd.writeStringTiny(80 - l, 12 + SY, text);
		lcd.writeStringTiny(3, 12 + SY, TEXT("Edition:"));

		lcd.writeStringTiny(3, 18 + SY, TEXT("Firmware:"));
		uint32_t version = VERSION;

		char c;

		l = 0;

		while(version)
		{
			c = (char)(version % 10);
			buf[0] = ((char)(c + '0'));
			buf[1] = 0;
			text = buf;
			l += lcd.measureStringTiny(text) + 1;
			lcd.writeStringTiny(80 - l, 18 + SY, text);

			version -= (uint32_t)c;
			version /= 10;
		}

		if(val > 1)
		{
			int_to_str(val, buf);
			text = buf;
			l = lcd.measureStringTiny(text);
			lcd.writeStringTiny(80 - l, 30 + SY, text);
			lcd.writeStringTiny(3, 30 + SY, TEXT("BT FW Version:"));
		}

		menu.setTitle(TEXT("System Info"));
		menu.setBar(TEXT("RETURN"), BLANK_STR);
		lcd.update();
	}

	if(key == FL_KEY || key == LEFT_KEY)
		return FN_CANCEL;

	return FN_CONTINUE;
}
volatile char lightMeter(char key, char first)
{
	static char held = 0;

	if(first)
	{
		lcd.backlight(0);
		hardware_flashlight(0);
	}

	if(!held)
	{
		lcd.cls();

		menu.setTitle(TEXT("Light Meter"));

		if(key == FR_KEY)
		{
			held = 1;
			menu.setBar(TEXT("RETURN"), TEXT("RUN"));
		}
		else
		{
			menu.setBar(TEXT("RETURN"), TEXT("PAUSE"));
		}

		char buf[6] , l;
		uint16_t val;
		char* text;

		val = (uint16_t)hardware_readLight(0);
		int_to_str(val, buf);
		text = buf;
		l = lcd.measureStringTiny(text);
		lcd.writeStringTiny(80 - l, 12 + SY, text);
		lcd.writeStringTiny(3, 12 + SY, TEXT("Level 1:"));

		val = (uint16_t)hardware_readLight(1);
		int_to_str(val, buf);
		text = buf;
		l = lcd.measureStringTiny(text);
		lcd.writeStringTiny(80 - l, 18 + SY, text);
		lcd.writeStringTiny(3, 18 + SY, TEXT("Level 2:"));

		val = (uint16_t)hardware_readLight(2);
		int_to_str(val, buf);
		text = buf;
		l = lcd.measureStringTiny(text);
		lcd.writeStringTiny(80 - l, 24 + SY, text);
		lcd.writeStringTiny(3, 24 + SY, TEXT("Level 3:"));

		lcd.update();
		_delay_ms(10);
	}
	else
	{
		if(key == FR_KEY)
			held = 0;
	}

	if(key == FL_KEY)
	{
		lcd.backlight(255);
		return FN_CANCEL;
	}

	return FN_CONTINUE;
}
volatile char motionTrigger(char key, char first)
{
	uint8_t i;
	uint16_t val;
	static uint16_t lv[3];
	static uint8_t threshold = 2;

	if(key == LEFT_KEY)
	{
		if(threshold > 0) threshold--;
		first = 1;
	}
	if(key == RIGHT_KEY)
	{
		if(threshold < 4) threshold++;
		first = 1;
	}

	if(first)
	{
		sleepOk = 0;
		clock.tare();
		lcd.cls();
		menu.setTitle(TEXT("Motion Sensor"));
		menu.setBar(TEXT("RETURN"), BLANK_STR);

		lcd.drawLine(10, 22, 84-10, 22);
		lcd.drawLine(11, 21, 11, 23);
		lcd.drawLine(84-11, 21, 84-11, 23);
		lcd.drawLine(12, 20, 12, 24);
		lcd.drawLine(84-12, 20, 84-12, 24);
		lcd.drawLine(13, 20, 13, 24);
		lcd.drawLine(84-13, 20, 84-13, 24);
		lcd.setPixel(42, 21);
		lcd.setPixel(42+10, 21);
		lcd.setPixel(42-10, 21);
		lcd.setPixel(42+20, 21);
		lcd.setPixel(42-20, 21);

		i = threshold * 10;
		lcd.drawLine(42-3-20+i, 16, 42+3-20+i, 16);
		lcd.drawLine(42-2-20+i, 17, 42+2-20+i, 17);
		lcd.drawLine(42-1-20+i, 18, 42+1-20+i, 18);
		lcd.setPixel(42-20+i, 19);

		lcd.writeStringTiny(19, 25, TEXT("SENSITIVITY"));

		lcd.update();
		lcd.backlight(0);
		hardware_flashlight(0);
		_delay_ms(50);
		for(i = 0; i < 3; i++)
		{
			lv[i] = (uint16_t)hardware_readLight(i);
		}
	}

	uint8_t thres = 4 - threshold + 2;
	if((4 - threshold) > 2) thres += ((4 - threshold) - 1) * 2;

	for(i = 0; i < 3; i++)
	{
		val = (uint16_t)hardware_readLight(i);
		if(clock.eventMs() > 1000 && val > thres && (val < (lv[i] - thres) || val > (lv[i] + thres)))
		{
			clock.tare();
			shutter_capture();
		}
		lv[i] = val;
	}

	if(key == FL_KEY)
	{
		sleepOk = 1;
		lcd.backlight(255);
		return FN_CANCEL;
	}

	return FN_CONTINUE;
}
volatile char btConnect(char key, char first)
{
	static uint8_t sfirst = 1;
	uint8_t i;
	static uint8_t menuSize;
	static uint8_t menuSelected;
	uint8_t c;
	uint8_t update, menuScroll;
	update = 0;

	if(sfirst)
	{
		menuScroll = 0;
		menuSelected = 0;
		sfirst = 0;

		update = 1;
		if(bt.state != BT_ST_CONNECTED)
		{
			bt.advertise();
			bt.scan();
		}
	}

	switch(key)
	{
		case LEFT_KEY:
		case FL_KEY:
			sfirst = 1;
			if(bt.state != BT_ST_CONNECTED) bt.sleep();
			return FN_CANCEL;

		case FR_KEY:
			if(bt.state == BT_ST_CONNECTED)
			{
				bt.disconnect();
			}
			else
			{
				bt.connect(bt.device[menuSelected].addr);
			}
			break;
	}

	update = 1;
	switch(bt.event)
	{
		case BT_EVENT_DISCOVERY:
			debug(STR("dicovery!\r\n"));
			break;
		case BT_EVENT_SCAN_COMPLETE:
			debug(STR("done!\r\n"));
			if(bt.state != BT_ST_CONNECTED) bt.scan();
			break;
		case BT_EVENT_DISCONNECT:		
			bt.scan();
			break;
		default:
			update = 0;
	}

	bt.event = BT_EVENT_NULL; // clear event so we don't process it twice

	if(first)
	{
		update = 1;
	}

	if(key == UP_KEY && menuSelected > 0)
	{
		menuSelected--;
		update = 1;
	}
	else if(key == DOWN_KEY && menuSelected < menuSize - 1)
	{
		menuSelected++;
		update = 1;
	}

	if(update)
	{
		lcd.cls();

		if(bt.state == BT_ST_CONNECTED)
		{
			menu.setTitle(TEXT("Connect"));
			lcd.writeStringTiny(18, 20, TEXT("Connected!"));
			menu.setBar(TEXT("RETURN"), TEXT("DISCONNECT"));
		}
		else
		{
			if(menuSelected > 2)
				menuScroll = menuSelected - 2;

			menuSize = 0;

			for(i = 0; i < bt.devices; i++)
			{
				if(i >= menuScroll && i <= menuScroll + 4)
				{
					for(c = 0; c < MENU_NAME_LEN - 1; c++) // Write settings item text //
					{
							if(bt.device[i].name[c])
								lcd.writeChar(3 + c * 6, 8 + 9 * (menuSize - menuScroll), bt.device[i].name[c]);
					}
				}
				menuSize++;
			}

			if(bt.devices)
			{
				lcd.drawHighlight(2, 7 + 9 * (menuSelected - menuScroll), 81, 7 + 9 * (menuSelected - menuScroll) + 8);
				menu.setBar(TEXT("RETURN"), TEXT("CONNECT"));
			}
			else
			{
				lcd.writeStringTiny(6, 20, TEXT("No Devices Found"));
				menu.setBar(TEXT("RETURN"), BLANK_STR);
			}

			menu.setTitle(TEXT("Connect"));

			lcd.drawLine(0, 3, 0, 40);
			lcd.drawLine(83, 3, 83, 40);
		}

		lcd.update();
	}

	return FN_CONTINUE;
}
void Remote::event()
{
	switch(bt.event)
	{
		case BT_EVENT_DISCONNECT:
			notify.unWatch(&remote_notify); // stop all active notifications
			//debug(STR("REMOTE::EVENT: Disconnected\r\n"));
			connected = 0;
			break;

		case BT_EVENT_CONNECT:
			connected = 1;
			//debug(STR("REMOTE::EVENT: Connected\r\n"));
			request(REMOTE_MODEL);
			break;

		case BT_EVENT_DATA:
			switch(bt.dataId)
			{
				case REMOTE_STATUS:
					if(bt.dataType == REMOTE_TYPE_REQUEST) send(bt.dataId, REMOTE_TYPE_SEND);
					if(bt.dataType == REMOTE_TYPE_SEND && bt.dataSize == sizeof(timer_status)) memcpy(&status, bt.data, bt.dataSize);
					if(bt.dataType == REMOTE_TYPE_NOTIFY_WATCH) notify.watch(REMOTE_STATUS, (void *)&timer.status, sizeof(timer.status), &remote_notify);
					if(bt.dataType == REMOTE_TYPE_NOTIFY_UNWATCH) notify.unWatch(REMOTE_STATUS, &remote_notify);
					break;
				case REMOTE_PROGRAM:
					if(bt.dataType == REMOTE_TYPE_REQUEST) send(bt.dataId, REMOTE_TYPE_SEND);
					if(bt.dataType == REMOTE_TYPE_SEND && bt.dataSize == sizeof(program)) memcpy(&current, bt.data, bt.dataSize);
					if(bt.dataType == REMOTE_TYPE_SET && bt.dataSize == sizeof(program))
					{
						memcpy((void*)&timer.current, bt.data, bt.dataSize);
						menu.refresh();
					}
					if(bt.dataType == REMOTE_TYPE_NOTIFY_WATCH) notify.watch(REMOTE_PROGRAM, (void *)&timer.current, sizeof(timer.current), &remote_notify);
					if(bt.dataType == REMOTE_TYPE_NOTIFY_UNWATCH) notify.unWatch(REMOTE_PROGRAM, &remote_notify);
					break;
				case REMOTE_BATTERY:
					if(bt.dataType == REMOTE_TYPE_REQUEST) send(bt.dataId, REMOTE_TYPE_SEND);
					if(bt.dataType == REMOTE_TYPE_SEND) memcpy(&battery, bt.data, bt.dataSize);
					if(bt.dataType == REMOTE_TYPE_NOTIFY_WATCH) notify.watch(REMOTE_BATTERY, (void *)&battery_percent, sizeof(battery_percent), &remote_notify);
					if(bt.dataType == REMOTE_TYPE_NOTIFY_UNWATCH) notify.unWatch(REMOTE_BATTERY, &remote_notify);
					break;
				case REMOTE_START:
					if(bt.dataType == REMOTE_TYPE_REQUEST) send(timer.running ? REMOTE_START : REMOTE_STOP, REMOTE_TYPE_SEND);
					if(bt.dataType == REMOTE_TYPE_SEND) running = 1;
					if(bt.dataType == REMOTE_TYPE_SET) runHandler(FR_KEY, 1);
					if(bt.dataType == REMOTE_TYPE_NOTIFY_WATCH) notify.watch(REMOTE_START, (void *)&timer.running, sizeof(timer.running), &remote_notify);
					if(bt.dataType == REMOTE_TYPE_NOTIFY_UNWATCH) notify.unWatch(REMOTE_START, &remote_notify);
					break;
				case REMOTE_STOP:
					if(bt.dataType == REMOTE_TYPE_REQUEST) send(timer.running ? REMOTE_START : REMOTE_STOP, REMOTE_TYPE_SEND);
					if(bt.dataType == REMOTE_TYPE_SEND) running = 0;
					if(bt.dataType == REMOTE_TYPE_SET) timerStop(FR_KEY, 1);
					if(bt.dataType == REMOTE_TYPE_NOTIFY_WATCH) notify.watch(REMOTE_START, (void *)&timer.running, sizeof(timer.running), &remote_notify);
					if(bt.dataType == REMOTE_TYPE_NOTIFY_UNWATCH) notify.unWatch(REMOTE_START, &remote_notify);
					break;
				case REMOTE_BULB_START:
					if(bt.dataType == REMOTE_TYPE_SET) timer.bulbStart();
					break;
				case REMOTE_BULB_END:
					if(bt.dataType == REMOTE_TYPE_SET) timer.bulbEnd();
					break;
				case REMOTE_CAPTURE:
					if(bt.dataType == REMOTE_TYPE_SET) timer.capture();
					break;
				case REMOTE_MODEL:
					if(bt.dataType == REMOTE_TYPE_REQUEST) send(REMOTE_MODEL, REMOTE_TYPE_SEND);
					if(bt.dataType == REMOTE_TYPE_SEND) memcpy(&model, bt.data, bt.dataSize);
					break;
				case REMOTE_FIRMWARE:
				case REMOTE_BT_FW_VERSION:
				case REMOTE_PROTOCOL_VERSION:
					if(bt.dataType == REMOTE_TYPE_REQUEST) send(bt.dataId, REMOTE_TYPE_SEND);
					break;
				case REMOTE_CAMERA_FPS:
					if(bt.dataType == REMOTE_TYPE_REQUEST) send(bt.dataId, REMOTE_TYPE_SEND);
					if(bt.dataType == REMOTE_TYPE_NOTIFY_WATCH) notify.watch(REMOTE_CAMERA_FPS, (void *)&conf.cameraFPS, sizeof(conf.cameraFPS), &remote_notify);
					if(bt.dataType == REMOTE_TYPE_NOTIFY_UNWATCH) notify.unWatch(REMOTE_CAMERA_FPS, &remote_notify);
					break;
				case REMOTE_CAMERA_MAKE:
					if(bt.dataType == REMOTE_TYPE_REQUEST) send(bt.dataId, REMOTE_TYPE_SEND);
					if(bt.dataType == REMOTE_TYPE_NOTIFY_WATCH) notify.watch(REMOTE_CAMERA_MAKE, (void *)&conf.cameraMake, sizeof(conf.cameraMake), &remote_notify);
					if(bt.dataType == REMOTE_TYPE_NOTIFY_UNWATCH) notify.unWatch(REMOTE_CAMERA_MAKE, &remote_notify);
					break;
				case REMOTE_DEBUG:
					if(bt.dataType == REMOTE_TYPE_SEND)
					{
						bt.data[bt.dataSize] = 0;
						debug_remote(bt.data);
					}
					break;
				case REMOTE_ISO:
					if(bt.dataType == REMOTE_TYPE_REQUEST) send(bt.dataId, REMOTE_TYPE_SEND);
					if(bt.dataType == REMOTE_TYPE_SET && bt.dataSize == sizeof(uint8_t))
					{
						uint8_t tmp;
						memcpy((void*)&tmp, bt.data, bt.dataSize);
						camera.setISO(tmp);
					}
					break;
				case REMOTE_APERTURE:
					if(bt.dataType == REMOTE_TYPE_REQUEST) send(bt.dataId, REMOTE_TYPE_SEND);
					if(bt.dataType == REMOTE_TYPE_SET && bt.dataSize == sizeof(uint8_t))
					{
						uint8_t tmp;
						memcpy((void*)&tmp, bt.data, bt.dataSize);
						camera.setAperture(tmp);
					}
					break;
				case REMOTE_SHUTTER:
					if(bt.dataType == REMOTE_TYPE_REQUEST) send(bt.dataId, REMOTE_TYPE_SEND);
					if(bt.dataType == REMOTE_TYPE_SET && bt.dataSize == sizeof(uint8_t))
					{
						uint8_t tmp;
						memcpy((void*)&tmp, bt.data, bt.dataSize);
						camera.setShutter(tmp);
					}
					break;
				case REMOTE_THUMBNAIL:
					if(bt.dataType == REMOTE_TYPE_REQUEST) send(bt.dataId, REMOTE_TYPE_SEND);
					break;
				case REMOTE_VIDEO:
					if(bt.dataType == REMOTE_TYPE_SET && bt.dataSize == sizeof(uint8_t))
					{
						uint8_t tmp;
						memcpy((void*)&tmp, bt.data, bt.dataSize);
						if(tmp) camera.videoStart(); else camera.videoStop();
					}
					if(bt.dataType == REMOTE_TYPE_SEND && bt.dataSize == sizeof(uint8_t))
					{
						uint8_t tmp;
						memcpy((void*)&tmp, bt.data, bt.dataSize);
						if(tmp) recording = true; else recording = false;
					}
					if(bt.dataType == REMOTE_TYPE_REQUEST) send(bt.dataId, REMOTE_TYPE_SEND);
					if(bt.dataType == REMOTE_TYPE_NOTIFY_WATCH) notify.watch(REMOTE_VIDEO, (void *)&camera.recording, sizeof(camera.recording), &remote_notify);
					if(bt.dataType == REMOTE_TYPE_NOTIFY_UNWATCH) notify.unWatch(REMOTE_VIDEO, &remote_notify);
					break;
				case REMOTE_LIVEVIEW:
					if(bt.dataType == REMOTE_TYPE_SET && bt.dataSize == sizeof(uint8_t))
					{
						uint8_t tmp;
						memcpy((void*)&tmp, bt.data, bt.dataSize);
						if(tmp) camera.liveView(tmp);
					}
					if(bt.dataType == REMOTE_TYPE_SEND && bt.dataSize == sizeof(uint8_t))
					{
						uint8_t tmp;
						memcpy((void*)&tmp, bt.data, bt.dataSize);
						if(tmp) modeLiveView = true; else modeLiveView = false;
					}
					if(bt.dataType == REMOTE_TYPE_REQUEST) send(bt.dataId, REMOTE_TYPE_SEND);
					if(bt.dataType == REMOTE_TYPE_NOTIFY_WATCH) notify.watch(REMOTE_LIVEVIEW, (void *)&camera.modeLiveView, sizeof(camera.modeLiveView), &remote_notify);
					if(bt.dataType == REMOTE_TYPE_NOTIFY_UNWATCH) notify.unWatch(REMOTE_LIVEVIEW, &remote_notify);
					break;
				default:
					return;
			}
			bt.event = BT_EVENT_NULL;
			break;
	}
	requestActive = 0;
}
volatile char shutterLagTest(char key, char first)
{
//  static uint8_t cable;
	uint16_t start_lag, end_lag;

	if(first)
	{
//    cable = 0;
		lcd.cls();
		menu.setTitle(TEXT("Shutter Lag Test"));
		menu.setBar(TEXT("Test 1"), TEXT("Test 2 "));
		lcd.update();
	}

	if(key == FL_KEY || key == FR_KEY)
	{
		lcd.eraseBox(10, 18, 80, 38);
		lcd.writeString(10, 18, TEXT("Result:"));

		ENABLE_SHUTTER;
		ENABLE_MIRROR;
		ENABLE_AUX_PORT;

		_delay_ms(100);

		if(key == FR_KEY)
		{
			MIRROR_UP;
			_delay_ms(1000);
		}

		SHUTTER_OPEN;
		clock.tare();

		while(!AUX_INPUT1)
		{
			if(clock.eventMs() >= 1000)
				break;
		}

		start_lag = (uint16_t)clock.eventMs();

		_delay_ms(50);

		SHUTTER_CLOSE;
		clock.tare();

		while(AUX_INPUT1)
		{
			if(clock.eventMs() > 1000)
				break;
		}

		end_lag = (uint16_t)clock.eventMs();

		lcd.writeNumber(56, 18, start_lag, 'U', 'L');
		lcd.writeNumber(56, 28, end_lag, 'U', 'L');

		lcd.update();
	}

	if(key == LEFT_KEY)
		return FN_CANCEL;

	return FN_CONTINUE;
}
volatile char cableRelease(char key, char first)
{
	static char status; //, cable;

	if(first)
	{
		status = 0;
		//cable = 0;
		lcd.cls();
		menu.setTitle(TEXT("Cable Remote"));
		menu.setBar(TEXT("Bulb"), TEXT("Photo"));
		lcd.update();
		timer.half();
	}

	if(key == FL_KEY)
	{
		if(status != 1)
		{
			status = 1;
			lcd.eraseBox(8, 18, 8 + 6 * 11, 26);
			lcd.writeString(8, 18, TEXT("(BULB OPEN)"));
			timer.bulbStart();
			lcd.update();
		} else
		{
			status = 0;
			lcd.eraseBox(8, 18, 8 + 6 * 11, 26);
			timer.bulbEnd();
			lcd.update();
		}
	}
	else if(key == FR_KEY && status != 1)
	{
		status = 0;
		lcd.eraseBox(8, 18, 8 + 6 * 11, 26);
		timer.capture();
		lcd.update();
	}
	else if(key != 0)
	{
		status = 0;
		lcd.eraseBox(8, 18, 8 + 6 * 11, 26);
		timer.half();
		lcd.update();
	}
/*
	if(timer.cableIsConnected())
	{
		if(cable == 0)
		{
			cable = 1;
			lcd.writeStringTiny(6, 28, TEXT("Cable Connected"));
			lcd.update();
		}
	}
	else
	{
		if(cable == 1)
		{
			cable = 0;
			lcd.eraseBox(6, 28, 6 + 15 * 5, 36);
			lcd.update();
		}
	}
*/
	if(key == LEFT_KEY)
	{
		timer.off();
		return FN_CANCEL;
	}
	return FN_CONTINUE;
}
volatile char shutterTest(char key, char first)
{
	static char status, cable;

	if(first)
	{
		status = 0;
		cable = 0;
		lcd.cls();
		menu.setTitle(TEXT("Shutter Test"));
		menu.setBar(TEXT("Half"), TEXT("Full"));
		lcd.update();
	}

	if(key == FL_KEY && status != 1)
	{
		status = 1;
		lcd.eraseBox(20, 18, 20 + 6 * 6, 26);
		lcd.writeString(20, 18, TEXT("(HALF)"));
		timer.half();
		lcd.update();
	}
	else if(key == FR_KEY && status != 2)
	{
		status = 2;
		lcd.eraseBox(20, 18, 20 + 6 * 6, 26);
		lcd.writeString(20, 18, TEXT("(FULL)"));
		timer.full();
		lcd.update();
	}
	else if(key != 0)
	{
		status = 0;
		lcd.eraseBox(20, 18, 20 + 6 * 6, 26);
		timer.off();
		lcd.update();
	}

	if(timer.cableIsConnected())
	{
		if(cable == 0)
		{
			cable = 1;
			lcd.writeStringTiny(6, 28, TEXT("Cable Connected"));
			lcd.update();
		}
	}
	else
	{
		if(cable == 1)
		{
			cable = 0;
			lcd.eraseBox(6, 28, 6 + 15 * 5, 36);
			lcd.update();
		}
	}

	if(key == LEFT_KEY)
		return FN_CANCEL;

	return FN_CONTINUE;
}
volatile char shutter_load(char key, char first)
{
	static char menuSize;
	static char menuSelected;
	static char itemSelected;
	uint8_t c;
	char ch, update, menuScroll;

	update = 0;

	if(first)
	{
		menuScroll = 0;
		update = 1;
	}

	if(key == UP_KEY && menuSelected > 0)
	{
		menuSelected--;
		update = 1;

	}
	else if(key == DOWN_KEY && menuSelected < menuSize - 1)
	{
		menuSelected++;
		update = 1;
	}

	if(update)
	{
		lcd.cls();

		if(menuSelected > 2)
			menuScroll = menuSelected - 2;

		menuSize = 0;
		char i = 0;

		for(char x = 1; x < MAX_STORED; x++)
		{
			i++;
			ch = eeprom_read_byte((uint8_t*)&stored[i - 1].Name[0]);

			if(ch == 0 || ch == 255)
				continue;

			for(c = 0; c < MENU_NAME_LEN - 1; c++) // Write settings item text //
			{
				if(i >= menuScroll && i <= menuScroll + 5)
				{
					ch = eeprom_read_byte((uint8_t*)&stored[i - 1].Name[c]);

					if(ch == 0) break;

					if(ch < 'A' || ch > 'Z')
						ch = ' ';

					lcd.writeChar(3 + c * 6, 8 + 9 * (menuSize - menuScroll), ch);

					if(menuSize == menuSelected)
						itemSelected = i - 1;
				}
			}
			menuSize++;
		}

		lcd.drawHighlight(2, 7 + 9 * (menuSelected - menuScroll), 81, 7 + 9 * (menuSelected - menuScroll) + 8);

		menu.setTitle(TEXT("Load Saved"));
		menu.setBar(TEXT("CANCEL"), TEXT("LOAD"));

		lcd.drawLine(0, 3, 0, 40);
		lcd.drawLine(83, 3, 83, 40);

		lcd.update();
	}

	switch(key)
	{
	   case FL_KEY:
	   case LEFT_KEY:
		   return FN_CANCEL;

	   case FR_KEY:
	   case RIGHT_KEY:
		   timer.load(itemSelected);
		   menu.message(TEXT("Loaded"));
		   menu.back();
		   menu.select(0);
		   return FN_SAVE;
	}

	return FN_CONTINUE;
}
uint8_t Remote::send(uint8_t id, uint8_t type)
{
	switch(id)
	{
		case REMOTE_BATTERY:
			return bt.sendDATA(id, type, (void *) &battery_percent, sizeof(battery_percent));
		case REMOTE_STATUS:
			return bt.sendDATA(id, type, (void *) &timer.status, sizeof(timer.status));
		case REMOTE_PROGRAM:
			return bt.sendDATA(id, type, (void *) &timer.current, sizeof(timer.current));
		case REMOTE_MODEL:
		{
			uint8_t tmp = REMOTE_MODEL_TLP;
			return bt.sendDATA(id, type, (void *) &tmp, sizeof(uint8_t));
		}
		case REMOTE_FIRMWARE:
		{
			unsigned long version = VERSION;
			void *ptr = &version;
			return bt.sendDATA(id, type, ptr, sizeof(version));
		}
		case REMOTE_BT_FW_VERSION:
		{
			uint8_t btVersion = bt.version();
			return bt.sendDATA(id, type, (void *) &btVersion, sizeof(btVersion));
		}
		case REMOTE_PROTOCOL_VERSION:
		{
			unsigned long remoteVersion = REMOTE_VERSION;
			void *ptr = &remoteVersion;
			return bt.sendDATA(id, type, ptr, sizeof(remoteVersion));
		}
		case REMOTE_CAMERA_FPS:
			return bt.sendDATA(id, type, (void *) &conf.cameraFPS, sizeof(conf.cameraFPS));
		case REMOTE_CAMERA_MAKE:
			return bt.sendDATA(id, type, (void *) &conf.cameraMake, sizeof(conf.cameraMake));
		case REMOTE_ISO:
		{
			uint8_t tmp = camera.iso();
			return bt.sendDATA(id, type, (void *) &tmp, sizeof(tmp));
		}
		case REMOTE_APERTURE:
		{
			uint8_t tmp = camera.aperture();
			return bt.sendDATA(id, type, (void *) &tmp, sizeof(tmp));
		}
		case REMOTE_SHUTTER:
		{
			uint8_t tmp = camera.shutter();
			return bt.sendDATA(id, type, (void *) &tmp, sizeof(tmp));
		}
		case REMOTE_VIDEO:
		{
			uint8_t tmp = camera.recording;
			return bt.sendDATA(id, type, (void *) &tmp, sizeof(tmp));
		}
		case REMOTE_LIVEVIEW:
		{
			uint8_t tmp = camera.modeLiveView;
			return bt.sendDATA(id, type, (void *) &tmp, sizeof(tmp));
		}
		case REMOTE_THUMBNAIL:
		{
			menu.message(STR("Busy"));
/*
			uint8_t ret = camera.getCurrentThumbStart();
			if(ret != PTP_RETURN_ERROR)
			{
				bt.sendDATA(REMOTE_THUMBNAIL_SIZE, type, (void *) &PTP_Bytes_Total, sizeof(PTP_Bytes_Total));
				bt.sendDATA(id, type, (void *) PTP_Buffer, PTP_Bytes_Received);
				while(ret == PTP_RETURN_DATA_REMAINING)
				{
					ret = camera.getCurrentThumbContinued();
					bt.sendDATA(id, type, (void *) PTP_Buffer, PTP_Bytes_Received);
				}
			}
*/
			///////////////////////// DEMO Code ////////////////////////////
			PTP_Bytes_Total = sizeof(thm);
			bt.sendDATA(REMOTE_THUMBNAIL_SIZE, type, (void *) &PTP_Bytes_Total, sizeof(PTP_Bytes_Total));
			uint16_t total_sent = 0, i;
			while(total_sent < PTP_Bytes_Total)
			{
				for(i = 0; i < PTP_BUFFER_SIZE; i++)
				{
					PTP_Buffer[i] = pgm_read_byte(&thm[i + total_sent]);
					if(total_sent + i >= PTP_Bytes_Total) break;
				}
				PTP_Bytes_Received = i;
				total_sent += PTP_Bytes_Received;
				if(PTP_Bytes_Received == 0) break;
				bt.sendDATA(id, type, (void *) PTP_Buffer, PTP_Bytes_Received);
				if(total_sent >= PTP_Bytes_Total) break;
			}
			/////////////////////////////////////////////////////////////////
			return 0;
		}
		default:
			return bt.sendDATA(id, type, 0, 0);
	}
	return 0;
}
volatile char batteryStatus(char key, char first)
{
//	uint16_t batt_high = 645;
//	uint16_t batt_low = 540;
	static uint8_t charging;
	char stat = battery_status();

	if(first)
	{
		charging = (stat > 0);
	}

//	unsigned int batt_level = battery_read_raw();

#define BATT_LINES 36

//	uint8_t lines = ((batt_level - batt_low) * BATT_LINES) / (batt_high - batt_low);
	uint8_t lines = (uint8_t)((uint16_t)battery_percent * BATT_LINES / 100);

	if(lines > BATT_LINES - 1 && stat == 1)
		lines = BATT_LINES - 1;

	if(lines > BATT_LINES || stat == 2)
		lines = BATT_LINES;

	lcd.cls();

	char* text;

	text = getChargingStatus();

	char l = lcd.measureStringTiny(text) / 2;

	if(battery_status())
		lcd.writeStringTiny(41 - l, 31, text);

	// Draw Battery Outline //
	lcd.drawLine(20, 15, 60, 15);
	lcd.drawLine(20, 16, 20, 27);
	lcd.drawLine(21, 27, 60, 27);
	lcd.drawLine(60, 16, 60, 19);
	lcd.drawLine(60, 23, 60, 26);
	lcd.drawLine(61, 19, 61, 23);

	// Draw Battery Charge //
	for(uint8_t i = 0; i <= lines; i++)
	{
		lcd.drawLine(22 + i, 17, 22 + i, 25);
	}

	menu.setTitle(TEXT("Battery Status"));
	menu.setBar(TEXT("RETURN"), BLANK_STR);
	lcd.update();

	if(stat == 0 && charging)
	{
		clock.awake();
		return FN_CANCEL; // unplugged
	}
	if(key == FL_KEY)
		return FN_CANCEL;

	return FN_CONTINUE;
}