1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2003 Linus Nielsen Feltzing
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
31 #include "string-extra.h"
44 static int curr_preset
= -1;
46 extern int curr_freq
; /* from radio.c.. naughty but meh */
47 extern int radio_mode
;
48 int snap_freq_to_grid(int freq
);
49 void remember_frequency(void);
50 void talk_freq(int freq
, bool enqueue
);
52 #define MAX_PRESETS 64
53 static bool presets_loaded
= false, presets_changed
= false;
54 static struct fmstation presets
[MAX_PRESETS
];
56 static char filepreset
[MAX_PATH
]; /* preset filename variable */
58 static int num_presets
= 0; /* The number of presets in the preset list */
60 bool yesno_pop(const char* text
); /* radio.c */
62 int radio_current_preset(void)
66 int radio_preset_count(void)
70 const struct fmstation
*radio_get_preset(int preset
)
72 return &presets
[preset
];
75 bool has_presets_changed(void)
77 return presets_changed
;
81 /* Find a matching preset to freq */
82 int find_preset(int freq
)
87 for(i
= 0;i
< MAX_PRESETS
;i
++)
89 if(freq
== presets
[i
].frequency
)
96 /* Return the closest preset encountered in the search direction with
98 int find_closest_preset(int freq
, int direction
)
105 if (direction
== 0) /* direction == 0 isn't really used */
108 for (i
= 0; i
< num_presets
; i
++)
110 int f
= presets
[i
].frequency
;
112 return i
; /* Exact match = stop */
114 /* remember the highest and lowest presets for wraparound */
115 if (f
< presets
[lowpreset
].frequency
)
117 if (f
> presets
[highpreset
].frequency
)
120 /* find the closest preset in the given direction */
121 if (direction
> 0 && f
> freq
)
123 if (closest
< 0 || f
< presets
[closest
].frequency
)
126 else if (direction
< 0 && f
< freq
)
128 if (closest
< 0 || f
> presets
[closest
].frequency
)
135 /* no presets in the given direction */
136 /* wrap around depending on direction */
138 closest
= highpreset
;
146 void next_preset(int direction
)
151 if (curr_preset
== -1)
152 curr_preset
= find_closest_preset(curr_freq
, direction
);
154 curr_preset
= (curr_preset
+ direction
+ num_presets
) % num_presets
;
156 /* Must stay on the current grid for the region */
157 curr_freq
= snap_freq_to_grid(presets
[curr_preset
].frequency
);
159 tuner_set(RADIO_FREQUENCY
, curr_freq
);
160 remember_frequency();
163 void set_current_preset(int preset
)
165 curr_preset
= preset
;
168 /* Speak a preset by number or by spelling its name, depending on settings. */
169 void talk_preset(int preset
, bool fallback
, bool enqueue
)
171 if (global_settings
.talk_file
== 1) /* number */
172 talk_number(preset
+ 1, enqueue
);
175 if(presets
[preset
].name
[0])
176 talk_spell(presets
[preset
].name
, enqueue
);
178 talk_freq(presets
[preset
].frequency
, enqueue
);
183 void radio_save_presets(void)
188 fd
= creat(filepreset
, 0666);
191 for(i
= 0;i
< num_presets
;i
++)
193 fdprintf(fd
, "%d:%s\n", presets
[i
].frequency
, presets
[i
].name
);
197 if(!strncasecmp(FMPRESET_PATH
, filepreset
, strlen(FMPRESET_PATH
)))
198 set_file(filepreset
, global_settings
.fmr_file
, MAX_FILENAME
);
199 presets_changed
= false;
203 splash(HZ
, ID2P(LANG_FM_PRESET_SAVE_FAILED
));
207 void radio_load_presets(char *filename
)
217 memset(presets
, 0, sizeof(presets
));
220 /* No Preset in configuration. */
221 if(filename
[0] == '\0')
223 filepreset
[0] = '\0';
226 /* Temporary preset, loaded until player shuts down. */
227 else if(filename
[0] == '/')
228 strlcpy(filepreset
, filename
, sizeof(filepreset
));
229 /* Preset from default directory. */
231 snprintf(filepreset
, sizeof(filepreset
), "%s/%s.fmr",
232 FMPRESET_PATH
, filename
);
234 fd
= open_utf8(filepreset
, O_RDONLY
);
237 while(!done
&& num_presets
< MAX_PRESETS
)
239 rc
= read_line(fd
, buf
, 128);
242 if(settings_parseline(buf
, &freq
, &name
))
245 if(f
) /* For backwards compatibility */
247 struct fmstation
* const fms
= &presets
[num_presets
];
249 strlcpy(fms
->name
, name
, MAX_FMPRESET_LEN
+1);
259 else /* invalid file name? */
260 filepreset
[0] = '\0';
262 presets_loaded
= num_presets
> 0;
263 presets_changed
= false;
266 const char* radio_get_preset_name(int preset
)
268 if (preset
< num_presets
)
269 return presets
[preset
].name
;
273 int radio_add_preset(void)
275 char buf
[MAX_FMPRESET_LEN
+ 1];
277 if(num_presets
< MAX_PRESETS
)
281 if (!kbd_input(buf
, MAX_FMPRESET_LEN
+ 1))
283 struct fmstation
* const fms
= &presets
[num_presets
];
284 strcpy(fms
->name
, buf
);
285 fms
->frequency
= curr_freq
;
287 presets_changed
= true;
288 presets_loaded
= num_presets
> 0;
294 splash(HZ
, ID2P(LANG_FM_NO_FREE_PRESETS
));
299 /* needed to know which preset we are edit/delete-ing */
300 static int selected_preset
= -1;
301 static int radio_edit_preset(void)
303 char buf
[MAX_FMPRESET_LEN
+ 1];
307 struct fmstation
* const fms
= &presets
[selected_preset
];
309 strcpy(buf
, fms
->name
);
311 if (!kbd_input(buf
, MAX_FMPRESET_LEN
+ 1))
313 strcpy(fms
->name
, buf
);
314 presets_changed
= true;
321 static int radio_delete_preset(void)
325 struct fmstation
* const fms
= &presets
[selected_preset
];
327 if (selected_preset
>= --num_presets
)
328 selected_preset
= num_presets
- 1;
330 memmove(fms
, fms
+ 1, (uintptr_t)(fms
+ num_presets
) -
333 if (curr_preset
>= num_presets
)
337 /* Don't ask to save when all presets are deleted. */
338 presets_changed
= num_presets
> 0;
340 if (!presets_changed
)
342 /* The preset list will be cleared, switch to Scan Mode. */
343 radio_mode
= RADIO_SCAN_MODE
;
345 presets_loaded
= false;
351 int load_preset_list(void)
353 return !rockbox_browse(FMPRESET_PATH
, SHOW_FMR
);
356 int save_preset_list(void)
360 bool bad_file_name
= true;
362 if(!dir_exists(FMPRESET_PATH
)) /* Check if there is preset folder */
363 mkdir(FMPRESET_PATH
);
365 create_numbered_filename(filepreset
, FMPRESET_PATH
, "preset",
366 ".fmr", 2 IF_CNFN_NUM_(, NULL
));
370 if(!kbd_input(filepreset
, sizeof(filepreset
)))
372 /* check the name: max MAX_FILENAME (20) chars */
376 p1
= strrchr(filepreset
, '/');
378 while((p1
) && (*p2
) && (*p2
!= '.'))
380 len
= (int)(p2
-p1
) - 1;
381 if((!p1
) || (len
> MAX_FILENAME
) || (len
== 0))
383 /* no slash, too long or too short */
384 splash(HZ
, ID2P(LANG_INVALID_FILENAME
));
388 /* add correct extension (easier to always write)
389 at this point, p2 points to 0 or the extension dot */
391 strcat(filepreset
,".fmr");
392 bad_file_name
= false;
393 radio_save_presets();
404 splash(HZ
, ID2P(LANG_FM_NO_PRESETS
));
409 int clear_preset_list(void)
411 /* Clear all the preset entries */
412 memset(presets
, 0, sizeof (presets
));
415 presets_loaded
= false;
416 /* The preset list will be cleared switch to Scan Mode. */
417 radio_mode
= RADIO_SCAN_MODE
;
419 presets_changed
= false; /* Don't ask to save when clearing the list. */
424 MENUITEM_FUNCTION(radio_edit_preset_item
, MENU_FUNC_CHECK_RETVAL
,
425 ID2P(LANG_FM_EDIT_PRESET
),
426 radio_edit_preset
, NULL
, NULL
, Icon_NOICON
);
427 MENUITEM_FUNCTION(radio_delete_preset_item
, MENU_FUNC_CHECK_RETVAL
,
428 ID2P(LANG_FM_DELETE_PRESET
),
429 radio_delete_preset
, NULL
, NULL
, Icon_NOICON
);
430 static int radio_preset_callback(int action
,
431 const struct menu_item_ex
*this_item
)
433 if (action
== ACTION_STD_OK
)
434 action
= ACTION_EXIT_AFTER_THIS_MENUITEM
;
438 MAKE_MENU(handle_radio_preset_menu
, ID2P(LANG_PRESET
),
439 radio_preset_callback
, Icon_NOICON
, &radio_edit_preset_item
,
440 &radio_delete_preset_item
);
441 /* present a list of preset stations */
442 static const char* presets_get_name(int selected_item
, void *data
,
443 char *buffer
, size_t buffer_len
)
446 struct fmstation
*p
= &presets
[selected_item
];
449 int freq
= p
->frequency
/ 10000;
450 int frac
= freq
% 100;
452 snprintf(buffer
, buffer_len
,
453 str(LANG_FM_DEFAULT_PRESET_NAME
), freq
, frac
);
457 static int presets_speak_name(int selected_item
, void * data
)
460 talk_preset(selected_item
, true, false);
464 int handle_radio_presets(void)
466 struct gui_synclist lists
;
468 int action
= ACTION_NONE
;
469 #ifdef HAVE_BUTTONBAR
470 struct gui_buttonbar buttonbar
;
473 if(presets_loaded
== false)
476 #ifdef HAVE_BUTTONBAR
477 gui_buttonbar_init(&buttonbar
);
478 gui_buttonbar_set_display(&buttonbar
, &(screens
[SCREEN_MAIN
]) );
479 gui_buttonbar_set(&buttonbar
, str(LANG_FM_BUTTONBAR_ADD
),
480 str(LANG_FM_BUTTONBAR_EXIT
),
481 str(LANG_FM_BUTTONBAR_ACTION
));
482 gui_buttonbar_draw(&buttonbar
);
484 gui_synclist_init(&lists
, presets_get_name
, NULL
, false, 1, NULL
);
485 gui_synclist_set_title(&lists
, str(LANG_PRESET
), NOICON
);
486 gui_synclist_set_icon_callback(&lists
, NULL
);
487 if(global_settings
.talk_file
)
488 gui_synclist_set_voice_callback(&lists
, presets_speak_name
);
489 gui_synclist_set_nb_items(&lists
, num_presets
);
490 gui_synclist_select_item(&lists
, curr_preset
<0 ? 0 : curr_preset
);
491 gui_synclist_speak_item(&lists
);
495 gui_synclist_draw(&lists
);
496 list_do_action(CONTEXT_STD
, TIMEOUT_BLOCK
,
497 &lists
, &action
, LIST_WRAP_UNLESS_HELD
);
500 case ACTION_STD_MENU
:
501 if (radio_add_preset())
503 gui_synclist_set_nb_items(&lists
, num_presets
);
504 gui_synclist_select_item(&lists
, num_presets
- 1);
507 case ACTION_STD_CANCEL
:
511 curr_preset
= gui_synclist_get_sel_pos(&lists
);
512 curr_freq
= presets
[curr_preset
].frequency
;
514 remember_frequency();
518 case ACTION_STD_CONTEXT
:
519 selected_preset
= gui_synclist_get_sel_pos(&lists
);
520 do_menu(&handle_radio_preset_menu
, NULL
, NULL
, false);
521 gui_synclist_set_nb_items(&lists
, num_presets
);
522 gui_synclist_select_item(&lists
, selected_preset
);
523 gui_synclist_speak_item(&lists
);
526 if(default_event_handler(action
) == SYS_USB_CONNECTED
)
534 int scan_presets(void *viewports
)
538 struct viewport
*vp
= (struct viewport
*)viewports
;
541 screens
[i
].set_viewport(vp
?&vp
[i
]:NULL
);
542 if(num_presets
> 0) /* Do that to avoid 2 questions. */
543 do_scan
= yesno_pop(ID2P(LANG_FM_CLEAR_PRESETS
));
547 const struct fm_region_data
* const fmr
=
548 &fm_region_data
[global_settings
.fm_region
];
550 curr_freq
= fmr
->freq_min
;
552 memset(presets
, 0, sizeof(presets
));
554 tuner_set(RADIO_MUTE
, 1);
556 while(curr_freq
<= fmr
->freq_max
)
559 if(num_presets
>= MAX_PRESETS
|| action_userabort(TIMEOUT_NOBLOCK
))
562 freq
= curr_freq
/ 10000;
566 splashf(0, str(LANG_FM_SCANNING
), freq
, frac
);
568 if(tuner_set(RADIO_SCAN_FREQUENCY
, curr_freq
))
571 presets
[num_presets
].name
[0] = '\0';
572 presets
[num_presets
].frequency
= curr_freq
;
576 curr_freq
+= fmr
->freq_step
;
579 if (get_radio_status() == FMRADIO_PLAYING
)
580 tuner_set(RADIO_MUTE
, 0);
582 presets_changed
= true;
586 screens
[i
].clear_viewport();
587 screens
[i
].update_viewport();
592 curr_freq
= presets
[0].frequency
;
593 radio_mode
= RADIO_PRESET_MODE
;
594 presets_loaded
= true;
599 /* Wrap it to beginning or we'll be past end of band */
600 presets_loaded
= false;
608 void presets_save(void)
610 if(filepreset
[0] == '\0')
613 radio_save_presets();
616 #ifdef HAVE_LCD_BITMAP
617 static inline void draw_veritcal_line_mark(struct screen
* screen
,
620 screen
->set_drawmode(DRMODE_COMPLEMENT
);
621 screen
->vline(x
, y
, y
+h
-1);
624 /* draw the preset markers for a track of length "tracklen",
625 between (x,y) and (x+w,y) */
626 void presets_draw_markers(struct screen
*screen
,
627 int x
, int y
, int w
, int h
)
630 const struct fm_region_data
*region_data
=
631 &(fm_region_data
[global_settings
.fm_region
]);
632 int len
= region_data
->freq_max
- region_data
->freq_min
;
633 for (i
=0; i
< radio_preset_count(); i
++)
635 int freq
= radio_get_preset(i
)->frequency
;
636 int diff
= freq
- region_data
->freq_min
;
637 xi
= x
+ (w
* diff
)/len
;
638 draw_veritcal_line_mark(screen
, xi
, y
, h
);