/*************************************************************************** * __________ __ ___. * Open \______ \ ____ ____ | | _\_ |__ _______ ___ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ * \/ \/ \/ \/ \/ * $Id$ * * Copyright (C) 2003 Pierre Delore * * All files in this archive are subject to the GNU General Public License. * See the file COPYING in the source tree root for full license agreement. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ****************************************************************************/ #include "plugin.h" #include "configfile.h" #ifdef HAVE_LCD_CHARCELLS /* Euro converter for the player */ /* Use: + : Digit +1 - : Digit -1 PLAY : Next digit STOP : Prev digit ON : RESET ON+PLAY : Swap Euro<>Home MENU : Display the Menu Currency -> Allows to choose the currency Exit-> Exit the plugin Notes: I don't use float. I use signed long long (64 bits). A value have 5 digits after the . (123.45 = 12345000) To do: - The Irish currency needs 6 digits after the . to have sufficient precision on big number */ /* Name and path of the config file*/ static const char cfg_filename[] = "euroconverter.cfg"; #define CFGFILE_VERSION 0 /* Current config file version */ #define CFGFILE_MINVERSION 0 /* Minimum config file version to accept */ /* typedef for simplifying usage of long long type */ typedef long long int longlong_t; /*Pattern for the converter*/ static unsigned char pattern_euro[]={0x07, 0x08, 0x1E, 0x10, 0x1E, 0x08, 0x07}; /* € */ static unsigned char pattern_home[]={0x04, 0x0A, 0x11, 0x1F, 0x11, 0x11, 0x1F}; /* Home icon*/ /* 1 euro = ... (remenber 5 digits after the .)*/ static int currency[12]={ 655957, /*FRF France*/ 195583, /*DEM Germany*/ 1376030, /*ATS Austria*/ 4033990, /*BEF Belgium*/ 16638600, /*ESP Spain*/ 594573, /*FIM Finland*/ 78756, /*IEP Ireland*/ 193627000, /*ITL Italy*/ 4033990, /*LUF Luxemburg*/ 220371, /*NLG Netherlands*/ 20048200, /*PTE Portugal*/ 34075100, /*GRD Greece*/ }; /* Number of digit of the currency (for the display) */ static int nb_digit[12]={ 2, /*FRF France*/ 2, /*DEM Germany*/ 2, /*ATS Austria*/ 2, /*BEF Belgium*/ 0, /*ESP Spain*/ 2, /*FIM Finland*/ 2, /*IEP Ireland*/ 0, /*ITL Italy*/ 2, /*LUF Luxemburg*/ 2, /*NLG Netherlands*/ 0, /*PTE Portugal*/ 0 /*GRD Greece*/ }; /* max euro to have home currency */ static longlong_t max_euro[12]={ 99999999000LL, /*FRF France 999 999.99 */ 99999999000LL, /*DEM Germany 999 999.99 */ 99999999000LL, /*ATS Austria 999 999.99 */ 99999999000LL, /*BEF Belgium 999 999.99 */ 99999999000LL, /*ESP Spain 99 999 999 */ 99999999000LL, /*FIM Finland 999 999.99 */ 99999999000LL, /*IEP Ireland 999 999.99 */ 51645690000LL, /*ITL Italy 999 999 999 */ 99999999000LL, /*LUF Luxemburg 999 999.99 */ 99999999000LL, /*NLG Netherlands 999 999.99 */ 99999999000LL, /*PTE Portugal 99 999 999 */ 29347028000LL /*GRD Greece 99 999 999 */ }; /* max home to have euro currency */ /* 92233720300000 Limitation due to the max capacity of long long (2^63)*/ static longlong_t max_curr[12]={ 99999999000LL, /*FRF France 152449.02 */ 99999999000LL, /*DEM Germany 511291.88 */ 99999999000LL, /*ATS Austria 72672.83 */ 99999999000LL, /*BEF Belgium 24789.35 */ 92233720300000LL,/*ESP Spain 5543358.23 */ 99999999000LL, /*FIM Finland 168187.92 */ 9999999900LL, /*IEP Ireland 1269744.51 exact value=1269738.07 */ 92233720300000LL,/*ITL Italy 476347.41 */ 99999999000LL, /*LUF Luxemburg 24789.35 */ 99999999000LL, /*NLG Netherlands 453780.21 */ 92233720300000LL,/*PTE Portugal 4600598.57 */ 92233720300000LL /*GRD Greece 2706777.69 */ }; static unsigned char *abbrev_str[12] = { "...FRF...", /*France*/ "...DEM...", /*Germany*/ "...ATS...", /*Austria*/ "...BEF...", /*Belgium*/ "...ESP...", /*Spain*/ "...FIM...", /*Finland*/ "...IEP...", /*Ireland*/ "...ITL...", /*Italy*/ "...LUF...", /*Luxemburg*/ "...NLG...", /*Netherlands*/ "...PTE...", /*Portugal*/ "...GRD..." /*Greece*/ }; static unsigned char heuro,hhome; /*Handles for the new patterns*/ static struct plugin_api* rb; static char *currency_str[12] = { "France", "Germany", "Austria", "Belgium", "Spain", "Finland", "Ireland", "Italy", "Luxemburg", "Netherlands", "Portugal", "Greece" }; static int country; /*Country selected*/ static int cur_pos; /*Cursor position*/ static longlong_t inc; /* Persistent settings */ static struct configdata config[] = { { TYPE_ENUM, 0, 12, &country, "country", currency_str, NULL } }; /* 64bits*64 bits with 5 digits after the . */ static longlong_t mymul(longlong_t a, longlong_t b) { return((a*b)/100000LL); } /* 64bits/64 bits with 5 digits after the . */ static longlong_t mydiv(longlong_t a, longlong_t b) { return((a*100000LL)/b); } /* 123.45=12345000 split => i=123 f=45000*/ static void split(longlong_t v, longlong_t* i, longlong_t* f) { longlong_t t; t=v/100000LL; (*i)=t; (*f)=(v-(t*100000LL)); } /* result=10^n */ static longlong_t pow10(int n) { int i; longlong_t r; r=1; for (i=0;i=5) add=1; if (n>0) { (*f)=((*f)/(int)pow10(5-n))+add; if ((*f)==100LL) { (*i)+=1; (*f)=0; } } else { (*i)+=add; (*f)=0; } } /* Display the imput and the result pos: false : first line : true : second line */ static void display(longlong_t euro, longlong_t home, bool pos) { char c1,c2; longlong_t i,f; unsigned char str[20]; unsigned char s1[20]; unsigned char s2[20]; if (pos) { /*Edit the second line*/ c1=0x20; rb->strcpy(s1,"%c%c%6d.%02d"); c2=0x81; if (nb_digit[country]==2) rb->strcpy(s2,"%c%c%06d.%02d"); else rb->strcpy(s2,"%c%c%09d"); } else { c1=0x81; rb->strcpy(s1,"%c%c%06d.%02d"); c2=0x20; if (nb_digit[country]==2) rb->strcpy(s2,"%c%c%6d.%02d"); else rb->strcpy(s2,"%c%c%9d"); } rb->lcd_remove_cursor(); /*First line*/ split(euro,&i,&f); if (pos) round(&i,&f,2); rb->snprintf(str,sizeof(str),s1,heuro,c1,(int)i,(int)f); if (!pos) { rb->lcd_puts(0,0,str); rb->lcd_put_cursor(10-cur_pos,0,0x5F); } else rb->lcd_puts_scroll(0,0,str); /*Second line*/ split(home,&i,&f); if (!pos) round(&i,&f,nb_digit[country]); rb->snprintf(str,sizeof(str),s2,hhome,c2,(int)i,(int)f); if (pos) { rb->lcd_puts(0,1,str); rb->lcd_put_cursor(10-cur_pos,1,0x5F); } else rb->lcd_puts_scroll(0,1,str); } /* Show country Abbreviation */ static void show_abbrev(void) { rb->lcd_puts(2,1,abbrev_str[country]); rb->sleep(HZ*3/4); } /* Save the config to disk */ static void save_config(void) { configfile_save(cfg_filename, config, 1, CFGFILE_VERSION); } /* Load the config from disk */ static void load_config(void) { configfile_load(cfg_filename, config, 1, CFGFILE_MINVERSION); } /*Currency choice*/ static void currency_menu(void) { int c=country; rb->lcd_clear_display(); while (true) { rb->lcd_puts(0,0,"Currency:"); rb->lcd_puts(0,1,currency_str[c]); switch (rb->button_get(true)) { case BUTTON_RIGHT|BUTTON_REL: c++; if (c>11) c=0; break; case BUTTON_LEFT|BUTTON_REL: c--; if (c<0) c=11; break; case BUTTON_PLAY|BUTTON_REL: country=c; save_config(); return; break; case BUTTON_STOP|BUTTON_REL: return; } } } /* Display the choice menu. */ static int euro_menu(void) { int c=0; while (true) { rb->lcd_clear_display(); rb->lcd_puts(0,0," Currency"); rb->lcd_puts(0,1," Exit"); rb->lcd_putc(0,c,0x81); switch (rb->button_get(true)) { case BUTTON_RIGHT|BUTTON_REL: c=1; break; case BUTTON_LEFT|BUTTON_REL: c=0; break; case BUTTON_PLAY|BUTTON_REL: if (c==0) currency_menu(); else return 1; break; case BUTTON_STOP|BUTTON_REL: return 0; } } } /* Call when the program end */ static void euro_exit(void *parameter) { (void)parameter; //Restore the old pattern (i don't find another way to do this. An idea?) rb->lcd_unlock_pattern(heuro); rb->lcd_unlock_pattern(hhome); //Clear the screen rb->lcd_clear_display(); } /* this is the plugin entry point */ enum plugin_status plugin_start(struct plugin_api* api, void* parameter) { bool end, pos; longlong_t e,h,old_e,old_h; int button; /* this macro should be called as the first thing you do in the plugin. it test that the api version and model the plugin was compiled for matches the machine it is running on */ TEST_PLUGIN_API(api); /* if you don't use the parameter, you can do like this to avoid the compiler warning about it */ (void)parameter; /* if you are using a global api pointer, don't forget to copy it! otherwise you will get lovely "I04: IllInstr" errors... :-) */ rb = api; /*Get the pattern handle*/ heuro=rb->lcd_get_locked_pattern(); hhome=rb->lcd_get_locked_pattern(); rb->lcd_define_pattern(heuro, pattern_euro); rb->lcd_define_pattern(hhome, pattern_home); h=0; e=0; end=false; pos=false; country=0; cur_pos=3; inc=100000; configfile_init(rb); load_config(); /*Empty the event queue*/ rb->button_clear_queue(); display(e,h,false); show_abbrev(); display(e,h,false); /*Main loop*/ while(end!=true) { button = rb->button_get(true); switch (button) { case BUTTON_MENU|BUTTON_REL: switch (euro_menu()) { case 1: end=true; break; } if (!pos) { if (e>max_euro[country]) e=0; cur_pos=3; } else { if (h>max_curr[country]) h=0; if (nb_digit[country]==2) cur_pos=3; else cur_pos=0; } display(e,h,pos); break; case BUTTON_ON | BUTTON_PLAY: pos=!pos; case BUTTON_ON | BUTTON_REL: e=0; h=0; if (!pos) { cur_pos=3; inc=100000; } else { inc=100000; if (nb_digit[country]==2) cur_pos=3; else cur_pos=0; } show_abbrev(); break; case BUTTON_STOP|BUTTON_REL: cur_pos--; if (!pos) { if (cur_pos<0) cur_pos=0; if (cur_pos==2) cur_pos=1; if (cur_pos>2) inc=pow10(3+cur_pos-1); else inc=pow10(3+cur_pos); } else { if (cur_pos<0) cur_pos=0; if (nb_digit[country]==2) { if (cur_pos==2) cur_pos=1; if (cur_pos>2) inc=pow10(3+cur_pos-1); else inc=pow10(3+cur_pos); } else inc=pow10(5+cur_pos); } break; case BUTTON_PLAY|BUTTON_REL: cur_pos++; if (!pos) { if (cur_pos>8) cur_pos=8; if (cur_pos==2) cur_pos=3; if (cur_pos>2) inc=pow10(3+cur_pos-1); else inc=pow10(3+cur_pos); } else { if (cur_pos>8) cur_pos=8; if (nb_digit[country]==2) { if (cur_pos==2) cur_pos=3; if (cur_pos>2) inc=pow10(3+cur_pos-1); else inc=pow10(3+cur_pos); } else inc=pow10(5+cur_pos); } break; case BUTTON_LEFT|BUTTON_REL: case BUTTON_LEFT|BUTTON_REPEAT: if (!pos) { e-=inc; if (e<0) e=0; } else { h-=inc; if (h<0) h=0; } break; case BUTTON_RIGHT|BUTTON_REL: case BUTTON_RIGHT|BUTTON_REPEAT: old_e=e; old_h=h; if (!pos) { e+=inc; if (e>max_euro[country]) e=old_e; } else { h+=inc; if (h>max_curr[country]) h=old_h; } break; default: if (rb->default_event_handler_ex(button, euro_exit, NULL) == SYS_USB_CONNECTED) return PLUGIN_USB_CONNECTED; break; } /*Display*/ if (!pos) /*Euro>home*/ h=mymul(e,currency[country]); else /*Home>euro*/ e=mydiv(h,currency[country]); display(e,h,pos); } euro_exit(NULL); return PLUGIN_OK; } #endif