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"
33 #include "filefuncs.h"
46 static int curr_preset
= -1;
48 extern int curr_freq
; /* from radio.c.. naughty but meh */
49 extern int radio_mode
;
50 int snap_freq_to_grid(int freq
);
51 void remember_frequency(void);
53 #define MAX_PRESETS 64
54 static bool presets_loaded
= false;
55 static bool presets_changed
= false;
56 static struct fmstation presets
[MAX_PRESETS
];
58 static char filepreset
[MAX_PATH
]; /* preset filename variable */
60 static int num_presets
= 0; /* The number of presets in the preset list */
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 presets_have_changed(void)
77 return presets_changed
;
81 /* Find a matching preset to freq */
82 int preset_find(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 static 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 preset_next(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 preset_set_current(int preset
)
165 curr_preset
= preset
;
168 /* Speak a preset by number or by spelling its name, depending on settings. */
169 void preset_talk(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_value_decimal(presets
[preset
].frequency
, UNIT_INT
, 6, enqueue
);
182 void radio_save_presets(void)
187 fd
= creat(filepreset
, 0666);
190 for(i
= 0;i
< num_presets
;i
++)
192 fdprintf(fd
, "%d:%s\n", presets
[i
].frequency
, presets
[i
].name
);
196 if(!strncasecmp(FMPRESET_PATH
, filepreset
, strlen(FMPRESET_PATH
)))
197 set_file(filepreset
, global_settings
.fmr_file
, MAX_FILENAME
);
198 presets_changed
= false;
202 splash(HZ
, ID2P(LANG_FM_PRESET_SAVE_FAILED
));
206 void radio_load_presets(char *filename
)
216 memset(presets
, 0, sizeof(presets
));
219 /* No Preset in configuration. */
220 if(filename
[0] == '\0')
222 filepreset
[0] = '\0';
225 /* Temporary preset, loaded until player shuts down. */
226 else if(filename
[0] == '/')
227 strlcpy(filepreset
, filename
, sizeof(filepreset
));
228 /* Preset from default directory. */
230 snprintf(filepreset
, sizeof(filepreset
), "%s/%s.fmr",
231 FMPRESET_PATH
, filename
);
233 fd
= open_utf8(filepreset
, O_RDONLY
);
236 while(!done
&& num_presets
< MAX_PRESETS
)
238 rc
= read_line(fd
, buf
, 128);
241 if(settings_parseline(buf
, &freq
, &name
))
244 if(f
) /* For backwards compatibility */
246 struct fmstation
* const fms
= &presets
[num_presets
];
248 strlcpy(fms
->name
, name
, MAX_FMPRESET_LEN
+1);
258 else /* invalid file name? */
259 filepreset
[0] = '\0';
261 presets_loaded
= num_presets
> 0;
262 presets_changed
= false;
265 const char* radio_get_preset_name(int preset
)
267 if (preset
< num_presets
)
268 return presets
[preset
].name
;
272 int handle_radio_add_preset(void)
274 char buf
[MAX_FMPRESET_LEN
+ 1];
276 if(num_presets
< MAX_PRESETS
)
280 if (!kbd_input(buf
, MAX_FMPRESET_LEN
+ 1))
282 struct fmstation
* const fms
= &presets
[num_presets
];
283 strcpy(fms
->name
, buf
);
284 fms
->frequency
= curr_freq
;
286 presets_changed
= true;
287 presets_loaded
= num_presets
> 0;
293 splash(HZ
, ID2P(LANG_FM_NO_FREE_PRESETS
));
298 /* needed to know which preset we are edit/delete-ing */
299 static int selected_preset
= -1;
300 static int radio_edit_preset(void)
302 char buf
[MAX_FMPRESET_LEN
+ 1];
306 struct fmstation
* const fms
= &presets
[selected_preset
];
308 strcpy(buf
, fms
->name
);
310 if (!kbd_input(buf
, MAX_FMPRESET_LEN
+ 1))
312 strcpy(fms
->name
, buf
);
313 presets_changed
= true;
320 static int radio_delete_preset(void)
324 struct fmstation
* const fms
= &presets
[selected_preset
];
326 if (selected_preset
>= --num_presets
)
327 selected_preset
= num_presets
- 1;
329 memmove(fms
, fms
+ 1, (uintptr_t)(fms
+ num_presets
) -
332 if (curr_preset
>= num_presets
)
336 /* Don't ask to save when all presets are deleted. */
337 presets_changed
= num_presets
> 0;
339 if (!presets_changed
)
341 /* The preset list will be cleared, switch to Scan Mode. */
342 radio_mode
= RADIO_SCAN_MODE
;
344 presets_loaded
= false;
350 int preset_list_load(void)
352 char selected
[MAX_PATH
];
353 struct browse_context browse
;
354 snprintf(selected
, sizeof(selected
), "%s.%s", global_settings
.fmr_file
, "fmr");
355 browse_context_init(&browse
, SHOW_FMR
, 0,
356 str(LANG_FM_PRESET_LOAD
), NOICON
,
357 FMPRESET_PATH
, selected
);
358 return !rockbox_browse(&browse
);
361 int preset_list_save(void)
365 bool bad_file_name
= true;
367 if(!dir_exists(FMPRESET_PATH
)) /* Check if there is preset folder */
368 mkdir(FMPRESET_PATH
);
370 create_numbered_filename(filepreset
, FMPRESET_PATH
, "preset",
371 ".fmr", 2 IF_CNFN_NUM_(, NULL
));
375 if(!kbd_input(filepreset
, sizeof(filepreset
)))
377 /* check the name: max MAX_FILENAME (20) chars */
381 p1
= strrchr(filepreset
, '/');
383 while((p1
) && (*p2
) && (*p2
!= '.'))
385 len
= (int)(p2
-p1
) - 1;
386 if((!p1
) || (len
> MAX_FILENAME
) || (len
== 0))
388 /* no slash, too long or too short */
389 splash(HZ
, ID2P(LANG_INVALID_FILENAME
));
393 /* add correct extension (easier to always write)
394 at this point, p2 points to 0 or the extension dot */
396 strcat(filepreset
,".fmr");
397 bad_file_name
= false;
398 radio_save_presets();
409 splash(HZ
, ID2P(LANG_FM_NO_PRESETS
));
414 int preset_list_clear(void)
416 /* Clear all the preset entries */
417 memset(presets
, 0, sizeof (presets
));
420 presets_loaded
= false;
421 /* The preset list will be cleared switch to Scan Mode. */
422 radio_mode
= RADIO_SCAN_MODE
;
424 presets_changed
= false; /* Don't ask to save when clearing the list. */
429 MENUITEM_FUNCTION(radio_edit_preset_item
, MENU_FUNC_CHECK_RETVAL
,
430 ID2P(LANG_FM_EDIT_PRESET
),
431 radio_edit_preset
, NULL
, NULL
, Icon_NOICON
);
432 MENUITEM_FUNCTION(radio_delete_preset_item
, MENU_FUNC_CHECK_RETVAL
,
433 ID2P(LANG_FM_DELETE_PRESET
),
434 radio_delete_preset
, NULL
, NULL
, Icon_NOICON
);
435 static int radio_preset_callback(int action
,
436 const struct menu_item_ex
*this_item
)
438 if (action
== ACTION_STD_OK
)
439 action
= ACTION_EXIT_AFTER_THIS_MENUITEM
;
443 MAKE_MENU(handle_radio_preset_menu
, ID2P(LANG_PRESET
),
444 radio_preset_callback
, Icon_NOICON
, &radio_edit_preset_item
,
445 &radio_delete_preset_item
);
446 /* present a list of preset stations */
447 static const char* presets_get_name(int selected_item
, void *data
,
448 char *buffer
, size_t buffer_len
)
451 struct fmstation
*p
= &presets
[selected_item
];
454 int freq
= p
->frequency
/ 10000;
455 int frac
= freq
% 100;
457 snprintf(buffer
, buffer_len
,
458 str(LANG_FM_DEFAULT_PRESET_NAME
), freq
, frac
);
462 static int presets_speak_name(int selected_item
, void * data
)
465 preset_talk(selected_item
, true, false);
469 int handle_radio_presets(void)
471 struct gui_synclist lists
;
473 int action
= ACTION_NONE
;
474 #ifdef HAVE_BUTTONBAR
475 struct gui_buttonbar buttonbar
;
478 if(presets_loaded
== false)
481 #ifdef HAVE_BUTTONBAR
482 gui_buttonbar_init(&buttonbar
);
483 gui_buttonbar_set_display(&buttonbar
, &(screens
[SCREEN_MAIN
]) );
484 gui_buttonbar_set(&buttonbar
, str(LANG_FM_BUTTONBAR_ADD
),
485 str(LANG_FM_BUTTONBAR_EXIT
),
486 str(LANG_FM_BUTTONBAR_ACTION
));
487 gui_buttonbar_draw(&buttonbar
);
489 gui_synclist_init(&lists
, presets_get_name
, NULL
, false, 1, NULL
);
490 gui_synclist_set_title(&lists
, str(LANG_PRESET
), NOICON
);
491 gui_synclist_set_icon_callback(&lists
, NULL
);
492 if(global_settings
.talk_file
)
493 gui_synclist_set_voice_callback(&lists
, presets_speak_name
);
494 gui_synclist_set_nb_items(&lists
, num_presets
);
495 gui_synclist_select_item(&lists
, curr_preset
<0 ? 0 : curr_preset
);
496 gui_synclist_speak_item(&lists
);
500 gui_synclist_draw(&lists
);
501 list_do_action(CONTEXT_STD
, TIMEOUT_BLOCK
,
502 &lists
, &action
, LIST_WRAP_UNLESS_HELD
);
505 case ACTION_STD_MENU
:
506 if (handle_radio_add_preset())
508 gui_synclist_set_nb_items(&lists
, num_presets
);
509 gui_synclist_select_item(&lists
, num_presets
- 1);
512 case ACTION_STD_CANCEL
:
516 curr_preset
= gui_synclist_get_sel_pos(&lists
);
517 curr_freq
= presets
[curr_preset
].frequency
;
519 remember_frequency();
523 case ACTION_STD_CONTEXT
:
524 selected_preset
= gui_synclist_get_sel_pos(&lists
);
525 do_menu(&handle_radio_preset_menu
, NULL
, NULL
, false);
526 gui_synclist_set_nb_items(&lists
, num_presets
);
527 gui_synclist_select_item(&lists
, selected_preset
);
528 gui_synclist_speak_item(&lists
);
531 if(default_event_handler(action
) == SYS_USB_CONNECTED
)
539 int presets_scan(void *viewports
)
543 struct viewport
*vp
= (struct viewport
*)viewports
;
546 screens
[i
].set_viewport(vp
?&vp
[i
]:NULL
);
547 if(num_presets
> 0) /* Do that to avoid 2 questions. */
548 do_scan
= yesno_pop(ID2P(LANG_FM_CLEAR_PRESETS
));
552 const struct fm_region_data
* const fmr
=
553 &fm_region_data
[global_settings
.fm_region
];
555 curr_freq
= fmr
->freq_min
;
557 memset(presets
, 0, sizeof(presets
));
559 tuner_set(RADIO_MUTE
, 1);
561 while(curr_freq
<= fmr
->freq_max
)
564 if(num_presets
>= MAX_PRESETS
|| action_userabort(TIMEOUT_NOBLOCK
))
567 freq
= curr_freq
/ 10000;
571 splashf(0, str(LANG_FM_SCANNING
), freq
, frac
);
573 if(tuner_set(RADIO_SCAN_FREQUENCY
, curr_freq
))
576 presets
[num_presets
].name
[0] = '\0';
577 presets
[num_presets
].frequency
= curr_freq
;
581 curr_freq
+= fmr
->freq_step
;
584 if (get_radio_status() == FMRADIO_PLAYING
)
585 tuner_set(RADIO_MUTE
, 0);
587 presets_changed
= true;
591 screens
[i
].clear_viewport();
592 screens
[i
].update_viewport();
597 curr_freq
= presets
[0].frequency
;
598 radio_mode
= RADIO_PRESET_MODE
;
599 presets_loaded
= true;
604 /* Wrap it to beginning or we'll be past end of band */
605 presets_loaded
= false;
613 void presets_save(void)
615 if(filepreset
[0] == '\0')
618 radio_save_presets();
621 #ifdef HAVE_LCD_BITMAP
622 static inline void draw_vertical_line_mark(struct screen
* screen
,
625 screen
->set_drawmode(DRMODE_COMPLEMENT
);
626 screen
->vline(x
, y
, y
+h
-1);
629 /* draw the preset markers for a track of length "tracklen",
630 between (x,y) and (x+w,y) */
631 void presets_draw_markers(struct screen
*screen
,
632 int x
, int y
, int w
, int h
)
635 const struct fm_region_data
*region_data
=
636 &(fm_region_data
[global_settings
.fm_region
]);
637 int len
= region_data
->freq_max
- region_data
->freq_min
;
638 for (i
=0; i
< radio_preset_count(); i
++)
640 int freq
= radio_get_preset(i
)->frequency
;
641 int diff
= freq
- region_data
->freq_min
;
642 xi
= x
+ (w
* diff
)/len
;
643 draw_vertical_line_mark(screen
, xi
, y
, h
);