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"
45 static int curr_preset
= -1;
47 extern int curr_freq
; /* from radio.c.. naughty but meh */
48 extern int radio_mode
;
49 int snap_freq_to_grid(int freq
);
50 void remember_frequency(void);
51 void talk_freq(int freq
, bool enqueue
);
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 bool yesno_pop(const char* text
); /* radio.c */
64 int radio_current_preset(void)
68 int radio_preset_count(void)
72 const struct fmstation
*radio_get_preset(int preset
)
74 return &presets
[preset
];
77 bool presets_have_changed(void)
79 return presets_changed
;
83 /* Find a matching preset to freq */
84 int preset_find(int freq
)
89 for(i
= 0;i
< MAX_PRESETS
;i
++)
91 if(freq
== presets
[i
].frequency
)
98 /* Return the closest preset encountered in the search direction with
100 static int find_closest_preset(int freq
, int direction
)
107 if (direction
== 0) /* direction == 0 isn't really used */
110 for (i
= 0; i
< num_presets
; i
++)
112 int f
= presets
[i
].frequency
;
114 return i
; /* Exact match = stop */
116 /* remember the highest and lowest presets for wraparound */
117 if (f
< presets
[lowpreset
].frequency
)
119 if (f
> presets
[highpreset
].frequency
)
122 /* find the closest preset in the given direction */
123 if (direction
> 0 && f
> freq
)
125 if (closest
< 0 || f
< presets
[closest
].frequency
)
128 else if (direction
< 0 && f
< freq
)
130 if (closest
< 0 || f
> presets
[closest
].frequency
)
137 /* no presets in the given direction */
138 /* wrap around depending on direction */
140 closest
= highpreset
;
148 void preset_next(int direction
)
153 if (curr_preset
== -1)
154 curr_preset
= find_closest_preset(curr_freq
, direction
);
156 curr_preset
= (curr_preset
+ direction
+ num_presets
) % num_presets
;
158 /* Must stay on the current grid for the region */
159 curr_freq
= snap_freq_to_grid(presets
[curr_preset
].frequency
);
161 tuner_set(RADIO_FREQUENCY
, curr_freq
);
162 remember_frequency();
165 void preset_set_current(int preset
)
167 curr_preset
= preset
;
170 /* Speak a preset by number or by spelling its name, depending on settings. */
171 void preset_talk(int preset
, bool fallback
, bool enqueue
)
173 if (global_settings
.talk_file
== 1) /* number */
174 talk_number(preset
+ 1, enqueue
);
177 if(presets
[preset
].name
[0])
178 talk_spell(presets
[preset
].name
, enqueue
);
180 talk_freq(presets
[preset
].frequency
, enqueue
);
185 void radio_save_presets(void)
190 fd
= creat(filepreset
, 0666);
193 for(i
= 0;i
< num_presets
;i
++)
195 fdprintf(fd
, "%d:%s\n", presets
[i
].frequency
, presets
[i
].name
);
199 if(!strncasecmp(FMPRESET_PATH
, filepreset
, strlen(FMPRESET_PATH
)))
200 set_file(filepreset
, global_settings
.fmr_file
, MAX_FILENAME
);
201 presets_changed
= false;
205 splash(HZ
, ID2P(LANG_FM_PRESET_SAVE_FAILED
));
209 void radio_load_presets(char *filename
)
219 memset(presets
, 0, sizeof(presets
));
222 /* No Preset in configuration. */
223 if(filename
[0] == '\0')
225 filepreset
[0] = '\0';
228 /* Temporary preset, loaded until player shuts down. */
229 else if(filename
[0] == '/')
230 strlcpy(filepreset
, filename
, sizeof(filepreset
));
231 /* Preset from default directory. */
233 snprintf(filepreset
, sizeof(filepreset
), "%s/%s.fmr",
234 FMPRESET_PATH
, filename
);
236 fd
= open_utf8(filepreset
, O_RDONLY
);
239 while(!done
&& num_presets
< MAX_PRESETS
)
241 rc
= read_line(fd
, buf
, 128);
244 if(settings_parseline(buf
, &freq
, &name
))
247 if(f
) /* For backwards compatibility */
249 struct fmstation
* const fms
= &presets
[num_presets
];
251 strlcpy(fms
->name
, name
, MAX_FMPRESET_LEN
+1);
261 else /* invalid file name? */
262 filepreset
[0] = '\0';
264 presets_loaded
= num_presets
> 0;
265 presets_changed
= false;
268 const char* radio_get_preset_name(int preset
)
270 if (preset
< num_presets
)
271 return presets
[preset
].name
;
275 int handle_radio_add_preset(void)
277 char buf
[MAX_FMPRESET_LEN
+ 1];
279 if(num_presets
< MAX_PRESETS
)
283 if (!kbd_input(buf
, MAX_FMPRESET_LEN
+ 1))
285 struct fmstation
* const fms
= &presets
[num_presets
];
286 strcpy(fms
->name
, buf
);
287 fms
->frequency
= curr_freq
;
289 presets_changed
= true;
290 presets_loaded
= num_presets
> 0;
296 splash(HZ
, ID2P(LANG_FM_NO_FREE_PRESETS
));
301 /* needed to know which preset we are edit/delete-ing */
302 static int selected_preset
= -1;
303 static int radio_edit_preset(void)
305 char buf
[MAX_FMPRESET_LEN
+ 1];
309 struct fmstation
* const fms
= &presets
[selected_preset
];
311 strcpy(buf
, fms
->name
);
313 if (!kbd_input(buf
, MAX_FMPRESET_LEN
+ 1))
315 strcpy(fms
->name
, buf
);
316 presets_changed
= true;
323 static int radio_delete_preset(void)
327 struct fmstation
* const fms
= &presets
[selected_preset
];
329 if (selected_preset
>= --num_presets
)
330 selected_preset
= num_presets
- 1;
332 memmove(fms
, fms
+ 1, (uintptr_t)(fms
+ num_presets
) -
335 if (curr_preset
>= num_presets
)
339 /* Don't ask to save when all presets are deleted. */
340 presets_changed
= num_presets
> 0;
342 if (!presets_changed
)
344 /* The preset list will be cleared, switch to Scan Mode. */
345 radio_mode
= RADIO_SCAN_MODE
;
347 presets_loaded
= false;
353 int preset_list_load(void)
355 return !rockbox_browse(FMPRESET_PATH
, SHOW_FMR
);
358 int preset_list_save(void)
362 bool bad_file_name
= true;
364 if(!dir_exists(FMPRESET_PATH
)) /* Check if there is preset folder */
365 mkdir(FMPRESET_PATH
);
367 create_numbered_filename(filepreset
, FMPRESET_PATH
, "preset",
368 ".fmr", 2 IF_CNFN_NUM_(, NULL
));
372 if(!kbd_input(filepreset
, sizeof(filepreset
)))
374 /* check the name: max MAX_FILENAME (20) chars */
378 p1
= strrchr(filepreset
, '/');
380 while((p1
) && (*p2
) && (*p2
!= '.'))
382 len
= (int)(p2
-p1
) - 1;
383 if((!p1
) || (len
> MAX_FILENAME
) || (len
== 0))
385 /* no slash, too long or too short */
386 splash(HZ
, ID2P(LANG_INVALID_FILENAME
));
390 /* add correct extension (easier to always write)
391 at this point, p2 points to 0 or the extension dot */
393 strcat(filepreset
,".fmr");
394 bad_file_name
= false;
395 radio_save_presets();
406 splash(HZ
, ID2P(LANG_FM_NO_PRESETS
));
411 int preset_list_clear(void)
413 /* Clear all the preset entries */
414 memset(presets
, 0, sizeof (presets
));
417 presets_loaded
= false;
418 /* The preset list will be cleared switch to Scan Mode. */
419 radio_mode
= RADIO_SCAN_MODE
;
421 presets_changed
= false; /* Don't ask to save when clearing the list. */
426 MENUITEM_FUNCTION(radio_edit_preset_item
, MENU_FUNC_CHECK_RETVAL
,
427 ID2P(LANG_FM_EDIT_PRESET
),
428 radio_edit_preset
, NULL
, NULL
, Icon_NOICON
);
429 MENUITEM_FUNCTION(radio_delete_preset_item
, MENU_FUNC_CHECK_RETVAL
,
430 ID2P(LANG_FM_DELETE_PRESET
),
431 radio_delete_preset
, NULL
, NULL
, Icon_NOICON
);
432 static int radio_preset_callback(int action
,
433 const struct menu_item_ex
*this_item
)
435 if (action
== ACTION_STD_OK
)
436 action
= ACTION_EXIT_AFTER_THIS_MENUITEM
;
440 MAKE_MENU(handle_radio_preset_menu
, ID2P(LANG_PRESET
),
441 radio_preset_callback
, Icon_NOICON
, &radio_edit_preset_item
,
442 &radio_delete_preset_item
);
443 /* present a list of preset stations */
444 static const char* presets_get_name(int selected_item
, void *data
,
445 char *buffer
, size_t buffer_len
)
448 struct fmstation
*p
= &presets
[selected_item
];
451 int freq
= p
->frequency
/ 10000;
452 int frac
= freq
% 100;
454 snprintf(buffer
, buffer_len
,
455 str(LANG_FM_DEFAULT_PRESET_NAME
), freq
, frac
);
459 static int presets_speak_name(int selected_item
, void * data
)
462 preset_talk(selected_item
, true, false);
466 int handle_radio_presets(void)
468 struct gui_synclist lists
;
470 int action
= ACTION_NONE
;
471 #ifdef HAVE_BUTTONBAR
472 struct gui_buttonbar buttonbar
;
475 if(presets_loaded
== false)
478 #ifdef HAVE_BUTTONBAR
479 gui_buttonbar_init(&buttonbar
);
480 gui_buttonbar_set_display(&buttonbar
, &(screens
[SCREEN_MAIN
]) );
481 gui_buttonbar_set(&buttonbar
, str(LANG_FM_BUTTONBAR_ADD
),
482 str(LANG_FM_BUTTONBAR_EXIT
),
483 str(LANG_FM_BUTTONBAR_ACTION
));
484 gui_buttonbar_draw(&buttonbar
);
486 gui_synclist_init(&lists
, presets_get_name
, NULL
, false, 1, NULL
);
487 gui_synclist_set_title(&lists
, str(LANG_PRESET
), NOICON
);
488 gui_synclist_set_icon_callback(&lists
, NULL
);
489 if(global_settings
.talk_file
)
490 gui_synclist_set_voice_callback(&lists
, presets_speak_name
);
491 gui_synclist_set_nb_items(&lists
, num_presets
);
492 gui_synclist_select_item(&lists
, curr_preset
<0 ? 0 : curr_preset
);
493 gui_synclist_speak_item(&lists
);
497 gui_synclist_draw(&lists
);
498 list_do_action(CONTEXT_STD
, TIMEOUT_BLOCK
,
499 &lists
, &action
, LIST_WRAP_UNLESS_HELD
);
502 case ACTION_STD_MENU
:
503 if (handle_radio_add_preset())
505 gui_synclist_set_nb_items(&lists
, num_presets
);
506 gui_synclist_select_item(&lists
, num_presets
- 1);
509 case ACTION_STD_CANCEL
:
513 curr_preset
= gui_synclist_get_sel_pos(&lists
);
514 curr_freq
= presets
[curr_preset
].frequency
;
516 remember_frequency();
520 case ACTION_STD_CONTEXT
:
521 selected_preset
= gui_synclist_get_sel_pos(&lists
);
522 do_menu(&handle_radio_preset_menu
, NULL
, NULL
, false);
523 gui_synclist_set_nb_items(&lists
, num_presets
);
524 gui_synclist_select_item(&lists
, selected_preset
);
525 gui_synclist_speak_item(&lists
);
528 if(default_event_handler(action
) == SYS_USB_CONNECTED
)
536 int presets_scan(void *viewports
)
540 struct viewport
*vp
= (struct viewport
*)viewports
;
543 screens
[i
].set_viewport(vp
?&vp
[i
]:NULL
);
544 if(num_presets
> 0) /* Do that to avoid 2 questions. */
545 do_scan
= yesno_pop(ID2P(LANG_FM_CLEAR_PRESETS
));
549 const struct fm_region_data
* const fmr
=
550 &fm_region_data
[global_settings
.fm_region
];
552 curr_freq
= fmr
->freq_min
;
554 memset(presets
, 0, sizeof(presets
));
556 tuner_set(RADIO_MUTE
, 1);
558 while(curr_freq
<= fmr
->freq_max
)
561 if(num_presets
>= MAX_PRESETS
|| action_userabort(TIMEOUT_NOBLOCK
))
564 freq
= curr_freq
/ 10000;
568 splashf(0, str(LANG_FM_SCANNING
), freq
, frac
);
570 if(tuner_set(RADIO_SCAN_FREQUENCY
, curr_freq
))
573 presets
[num_presets
].name
[0] = '\0';
574 presets
[num_presets
].frequency
= curr_freq
;
578 curr_freq
+= fmr
->freq_step
;
581 if (get_radio_status() == FMRADIO_PLAYING
)
582 tuner_set(RADIO_MUTE
, 0);
584 presets_changed
= true;
588 screens
[i
].clear_viewport();
589 screens
[i
].update_viewport();
594 curr_freq
= presets
[0].frequency
;
595 radio_mode
= RADIO_PRESET_MODE
;
596 presets_loaded
= true;
601 /* Wrap it to beginning or we'll be past end of band */
602 presets_loaded
= false;
610 void presets_save(void)
612 if(filepreset
[0] == '\0')
615 radio_save_presets();
618 #ifdef HAVE_LCD_BITMAP
619 static inline void draw_vertical_line_mark(struct screen
* screen
,
622 screen
->set_drawmode(DRMODE_COMPLEMENT
);
623 screen
->vline(x
, y
, y
+h
-1);
626 /* draw the preset markers for a track of length "tracklen",
627 between (x,y) and (x+w,y) */
628 void presets_draw_markers(struct screen
*screen
,
629 int x
, int y
, int w
, int h
)
632 const struct fm_region_data
*region_data
=
633 &(fm_region_data
[global_settings
.fm_region
]);
634 int len
= region_data
->freq_max
- region_data
->freq_min
;
635 for (i
=0; i
< radio_preset_count(); i
++)
637 int freq
= radio_get_preset(i
)->frequency
;
638 int diff
= freq
- region_data
->freq_min
;
639 xi
= x
+ (w
* diff
)/len
;
640 draw_vertical_line_mark(screen
, xi
, y
, h
);