summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTomasz Moń <desowin@gmail.com>2021-06-23 17:15:36 +0200
committerTomasz Moń <desowin@gmail.com>2021-06-25 16:12:06 +0200
commit373851095386dec79adff7927e9b23020a7fbf30 (patch)
tree291c0471a960c338bf2b73ef1a03b49d1e1e6269
parent635ec5bbbd00bd5b6c0eff7fc459155cd84d5fe1 (diff)
downloadrockbox-373851095386dec79adff7927e9b23020a7fbf30.tar.gz
rockbox-373851095386dec79adff7927e9b23020a7fbf30.zip
Sansa Connect: Implement RTC functionality
Use 32-bit monotime AVR counter for time tracking. Set the time by adding fixed offset to the counter value. Store the offset in rockbox directory to make it persistent between reboots. Do not implement alarm functionality as wakeup is only possible from sleep and not from complete power off. Change-Id: I615c7eb4df8ab0619dcbfcff107bc7051a15aace
-rw-r--r--apps/keymaps/keymap-sansa-connect.c16
-rw-r--r--firmware/export/config.h1
-rw-r--r--firmware/export/config/sansaconnect.h2
-rw-r--r--firmware/target/arm/tms320dm320/sansa-connect/avr-sansaconnect.c182
4 files changed, 176 insertions, 25 deletions
diff --git a/apps/keymaps/keymap-sansa-connect.c b/apps/keymaps/keymap-sansa-connect.c
index 27790d2bfd..6a6d5de955 100644
--- a/apps/keymaps/keymap-sansa-connect.c
+++ b/apps/keymaps/keymap-sansa-connect.c
@@ -73,6 +73,18 @@ static const struct button_mapping button_context_yesno[] = {
73 LAST_ITEM_IN_LIST 73 LAST_ITEM_IN_LIST
74}; /* button_context_yesno */ 74}; /* button_context_yesno */
75 75
76static const struct button_mapping button_context_settings_time[] = {
77 {ACTION_STD_PREV, BUTTON_PREV|BUTTON_REL, BUTTON_PREV},
78 {ACTION_STD_PREVREPEAT, BUTTON_PREV|BUTTON_REPEAT, BUTTON_PREV},
79 {ACTION_STD_NEXT, BUTTON_NEXT|BUTTON_REL, BUTTON_NEXT},
80 {ACTION_STD_NEXTREPEAT, BUTTON_NEXT|BUTTON_REPEAT, BUTTON_NEXT},
81 {ACTION_STD_CANCEL, BUTTON_LEFT|BUTTON_REPEAT, BUTTON_LEFT},
82 {ACTION_STD_OK, BUTTON_SELECT|BUTTON_REL, BUTTON_SELECT},
83 {ACTION_SETTINGS_INC, BUTTON_SCROLL_FWD, BUTTON_NONE},
84 {ACTION_SETTINGS_DEC, BUTTON_SCROLL_BACK, BUTTON_NONE},
85 LAST_ITEM_IN_LIST
86}; /* button_context_settings_time */
87
76static const struct button_mapping button_context_keyboard[] = { 88static const struct button_mapping button_context_keyboard[] = {
77 {ACTION_KBD_LEFT, BUTTON_LEFT, BUTTON_NONE}, 89 {ACTION_KBD_LEFT, BUTTON_LEFT, BUTTON_NONE},
78 {ACTION_KBD_LEFT, BUTTON_LEFT|BUTTON_REPEAT, BUTTON_NONE}, 90 {ACTION_KBD_LEFT, BUTTON_LEFT|BUTTON_REPEAT, BUTTON_NONE},
@@ -113,7 +125,9 @@ const struct button_mapping* get_context_mapping(int context)
113 case CONTEXT_KEYBOARD: 125 case CONTEXT_KEYBOARD:
114 case CONTEXT_MORSE_INPUT: 126 case CONTEXT_MORSE_INPUT:
115 return button_context_keyboard; 127 return button_context_keyboard;
116 128 case CONTEXT_SETTINGS_TIME:
129 return button_context_settings_time;
130
117 case CONTEXT_TREE: 131 case CONTEXT_TREE:
118 case CONTEXT_LIST: 132 case CONTEXT_LIST:
119 case CONTEXT_MAINMENU: 133 case CONTEXT_MAINMENU:
diff --git a/firmware/export/config.h b/firmware/export/config.h
index 623ef8b4ff..fdf3bf420d 100644
--- a/firmware/export/config.h
+++ b/firmware/export/config.h
@@ -348,6 +348,7 @@ Lyre prototype 1 */
348#define RTC_STM41T62 21 /* ST M41T62 */ 348#define RTC_STM41T62 21 /* ST M41T62 */
349#define RTC_JZ4760 22 /* Ingenic Jz4760 */ 349#define RTC_JZ4760 22 /* Ingenic Jz4760 */
350#define RTC_X1000 23 /* Ingenic X1000 */ 350#define RTC_X1000 23 /* Ingenic X1000 */
351#define RTC_CONNECT 24 /* Sansa Connect AVR */
351 352
352/* USB On-the-go */ 353/* USB On-the-go */
353#define USBOTG_M66591 6591 /* M:Robe 500 */ 354#define USBOTG_M66591 6591 /* M:Robe 500 */
diff --git a/firmware/export/config/sansaconnect.h b/firmware/export/config/sansaconnect.h
index 5909d3bf84..5fc91a2794 100644
--- a/firmware/export/config/sansaconnect.h
+++ b/firmware/export/config/sansaconnect.h
@@ -114,7 +114,7 @@
114//#define HW_SAMPR_CAPS SAMPR_CAP_44 | SAMPR_CAP_22 | SAMPR_CAP_11 | SAMPR_CAP_8 114//#define HW_SAMPR_CAPS SAMPR_CAP_44 | SAMPR_CAP_22 | SAMPR_CAP_11 | SAMPR_CAP_8
115 115
116/* define this if you have a real-time clock */ 116/* define this if you have a real-time clock */
117//#define CONFIG_RTC RTC_STM41T62 117#define CONFIG_RTC RTC_CONNECT
118 118
119/* define this if the unit uses a scrollwheel for navigation */ 119/* define this if the unit uses a scrollwheel for navigation */
120#define HAVE_SCROLLWHEEL 120#define HAVE_SCROLLWHEEL
diff --git a/firmware/target/arm/tms320dm320/sansa-connect/avr-sansaconnect.c b/firmware/target/arm/tms320dm320/sansa-connect/avr-sansaconnect.c
index ca76100e8b..66cbb1931b 100644
--- a/firmware/target/arm/tms320dm320/sansa-connect/avr-sansaconnect.c
+++ b/firmware/target/arm/tms320dm320/sansa-connect/avr-sansaconnect.c
@@ -21,7 +21,9 @@
21 21
22#include <stdio.h> 22#include <stdio.h>
23#include "config.h" 23#include "config.h"
24#include "file.h"
24#include "system.h" 25#include "system.h"
26#include "time.h"
25#include "power.h" 27#include "power.h"
26#include "kernel.h" 28#include "kernel.h"
27#include "panic.h" 29#include "panic.h"
@@ -104,15 +106,28 @@
104/* protects spi avr commands from concurrent access */ 106/* protects spi avr commands from concurrent access */
105static struct mutex avr_mtx; 107static struct mutex avr_mtx;
106 108
107/* buttons thread */ 109/* AVR thread events */
108#define BTN_INTERRUPT 1 110#define INPUT_INTERRUPT 1
111#define MONOTIME_OFFSET_UPDATE 2
109static int btn = 0; 112static int btn = 0;
110static bool hold_switch; 113static bool hold_switch;
111#ifndef BOOTLOADER 114static bool input_interrupt_pending;
115/* AVR implements 32-bit counter incremented every second.
116 * The counter value cannot be modified to arbitrary value,
117 * so the epoch offset needs to be stored in a file.
118 */
119#define MONOTIME_OFFSET_FILE ROCKBOX_DIR "/monotime_offset.dat"
120static uint32_t monotime_offset;
121/* Buffer last read monotime value. Reading monotime takes
122 * atleast 700 us so the tick counter is used together with
123 * last read monotime value to return current time.
124 */
125static uint32_t monotime_value;
126static unsigned long monotime_value_tick;
127
112static long avr_stack[DEFAULT_STACK_SIZE/sizeof(long)]; 128static long avr_stack[DEFAULT_STACK_SIZE/sizeof(long)];
113static const char avr_thread_name[] = "avr"; 129static const char avr_thread_name[] = "avr";
114static struct semaphore avr_thread_trigger; 130static struct event_queue avr_queue;
115#endif
116 131
117/* OF bootloader will refuse to start software if low power is set 132/* OF bootloader will refuse to start software if low power is set
118 * Bits 3, 4, 5, 6 and 7 are unknown. 133 * Bits 3, 4, 5, 6 and 7 are unknown.
@@ -133,7 +148,6 @@ static inline uint16_t be2short(uint8_t *buf)
133 148
134#define BUTTON_DIRECT_MASK (BUTTON_LEFT | BUTTON_UP | BUTTON_RIGHT | BUTTON_DOWN | BUTTON_SELECT | BUTTON_VOL_UP | BUTTON_VOL_DOWN | BUTTON_NEXT | BUTTON_PREV) 149#define BUTTON_DIRECT_MASK (BUTTON_LEFT | BUTTON_UP | BUTTON_RIGHT | BUTTON_DOWN | BUTTON_SELECT | BUTTON_VOL_UP | BUTTON_VOL_DOWN | BUTTON_NEXT | BUTTON_PREV)
135 150
136#ifndef BOOTLOADER
137static void handle_wheel(uint8_t wheel) 151static void handle_wheel(uint8_t wheel)
138{ 152{
139 static int key = 0; 153 static int key = 0;
@@ -199,7 +213,6 @@ static void handle_wheel(uint8_t wheel)
199 213
200 prev_key = key; 214 prev_key = key;
201} 215}
202#endif
203 216
204/* buf must be 8-byte state array (reply from avr_hid_get_state() */ 217/* buf must be 8-byte state array (reply from avr_hid_get_state() */
205static void parse_button_state(uint8_t *state) 218static void parse_button_state(uint8_t *state)
@@ -219,26 +232,23 @@ static void parse_button_state(uint8_t *state)
219 232
220 btn = main_btns_state; 233 btn = main_btns_state;
221 234
222#ifndef BOOTLOADER
223 /* check if stored hold_switch state changed (prevents lost changes) */ 235 /* check if stored hold_switch state changed (prevents lost changes) */
224 if ((state[1] & 0x20) /* hold change notification */ || 236 if ((state[1] & 0x20) /* hold change notification */ ||
225 (hold_switch != ((state[1] & 0x02) >> 1))) 237 (hold_switch != ((state[1] & 0x02) >> 1)))
226 { 238 {
227#endif
228 hold_switch = (state[1] & 0x02) >> 1; 239 hold_switch = (state[1] & 0x02) >> 1;
229#ifdef BUTTON_DEBUG 240#ifdef BUTTON_DEBUG
230 dbgprintf("HOLD changed (%d)", hold_switch); 241 dbgprintf("HOLD changed (%d)", hold_switch);
231#endif 242#endif
232#ifndef BOOTLOADER 243#ifndef BOOTLOADER
233 backlight_hold_changed(hold_switch); 244 backlight_hold_changed(hold_switch);
234 }
235#endif 245#endif
236#ifndef BOOTLOADER 246 }
247
237 if ((hold_switch == false) && (state[1] & 0x80)) /* scrollwheel change */ 248 if ((hold_switch == false) && (state[1] & 0x80)) /* scrollwheel change */
238 { 249 {
239 handle_wheel(state[0]); 250 handle_wheel(state[0]);
240 } 251 }
241#endif
242 252
243#ifdef BUTTON_DEBUG 253#ifdef BUTTON_DEBUG
244 if (state[1] & 0x10) /* power button change */ 254 if (state[1] & 0x10) /* power button change */
@@ -496,6 +506,13 @@ static void avr_hid_get_state(void)
496 parse_button_state(state); 506 parse_button_state(state);
497} 507}
498 508
509static uint32_t avr_hid_get_monotime(void)
510{
511 uint8_t tmp[4];
512 avr_execute_command(CMD_MONOTIME, tmp, sizeof(tmp));
513 return (tmp[0]) | (tmp[1] << 8) | (tmp[2] << 16) | (tmp[3] << 24);
514}
515
499static void avr_hid_enable_wheel(void) 516static void avr_hid_enable_wheel(void)
500{ 517{
501 uint8_t enable = 0x01; 518 uint8_t enable = 0x01;
@@ -554,7 +571,6 @@ void avr_hid_power_off(void)
554 avr_hid_sys_ctrl(SYS_CTRL_POWEROFF); 571 avr_hid_sys_ctrl(SYS_CTRL_POWEROFF);
555} 572}
556 573
557#ifndef BOOTLOADER
558static bool avr_state_changed(void) 574static bool avr_state_changed(void)
559{ 575{
560 return (IO_GIO_BITSET0 & 0x1) ? false : true; 576 return (IO_GIO_BITSET0 & 0x1) ? false : true;
@@ -567,6 +583,9 @@ static bool headphones_inserted(void)
567 583
568static void set_audio_output(bool headphones) 584static void set_audio_output(bool headphones)
569{ 585{
586#ifdef BOOTLOADER
587 (void)headphones;
588#else
570 if (headphones) 589 if (headphones)
571 { 590 {
572 /* Stereo output on headphones */ 591 /* Stereo output on headphones */
@@ -579,19 +598,115 @@ static void set_audio_output(bool headphones)
579 aic3x_switch_output(false); 598 aic3x_switch_output(false);
580 avr_hid_set_amp_enable(1); 599 avr_hid_set_amp_enable(1);
581 } 600 }
601#endif
602}
603
604static void read_monotime_offset(void)
605{
606 int fd = open(MONOTIME_OFFSET_FILE, O_RDONLY);
607 if (fd >= 0)
608 {
609 uint32_t offset;
610 if (sizeof(offset) == read(fd, &offset, sizeof(offset)))
611 {
612 monotime_offset = offset;
613 }
614 close(fd);
615 }
616}
617
618static bool write_monotime_offset(void)
619{
620 bool success = false;
621 int fd = open(MONOTIME_OFFSET_FILE, O_WRONLY | O_CREAT | O_TRUNC, 0666);
622 if (fd >= 0)
623 {
624 uint32_t offset = monotime_offset;
625 if (sizeof(monotime_offset) == write(fd, &offset, sizeof(offset)))
626 {
627 success = true;
628 }
629 close(fd);
630 }
631 return success;
632}
633
634static void read_monotime(void)
635{
636 uint32_t value = avr_hid_get_monotime();
637 int flags = disable_irq_save();
638 monotime_value = value;
639 monotime_value_tick = current_tick;
640 restore_irq(flags);
641}
642
643static time_t get_timestamp(void)
644{
645 time_t timestamp;
646 int flags = disable_irq_save();
647 timestamp = monotime_value;
648 timestamp += monotime_offset;
649 timestamp += ((current_tick - monotime_value_tick) / HZ);
650 restore_irq(flags);
651 return timestamp;
652}
653
654void rtc_init(void)
655{
656 /* This is called before disk is mounted */
657}
658
659int rtc_read_datetime(struct tm *tm)
660{
661 time_t time = get_timestamp();
662 gmtime_r(&time, tm);
663 return 1;
664}
665
666int rtc_write_datetime(const struct tm *tm)
667{
668 time_t offset = mktime((struct tm *)tm);
669 int flags = disable_irq_save();
670 offset -= monotime_value;
671 offset -= ((current_tick - monotime_value_tick) / HZ);
672 monotime_offset = offset;
673 restore_irq(flags);
674 queue_post(&avr_queue, MONOTIME_OFFSET_UPDATE, 0);
675 return 1;
582} 676}
583 677
584void avr_thread(void) 678void avr_thread(void)
585{ 679{
680 struct queue_event ev;
586 bool headphones_active_state = headphones_inserted(); 681 bool headphones_active_state = headphones_inserted();
587 bool headphones_state; 682 bool headphones_state;
683 bool disk_access_available = true;
684 bool monotime_offset_update_pending = false;
588 685
589 set_audio_output(headphones_active_state); 686 set_audio_output(headphones_active_state);
687 read_monotime_offset();
688 read_monotime();
590 689
591 while (1) 690 while (1)
592 { 691 {
593 semaphore_wait(&avr_thread_trigger, TIMEOUT_BLOCK); 692 queue_wait(&avr_queue, &ev);
693
694 if (ev.id == SYS_USB_CONNECTED)
695 {
696 /* Allow USB to gain exclusive storage access */
697 usb_acknowledge(SYS_USB_CONNECTED_ACK);
698 disk_access_available = false;
699 }
700 else if (ev.id == SYS_USB_DISCONNECTED)
701 {
702 disk_access_available = true;
703 }
704 else if (ev.id == MONOTIME_OFFSET_UPDATE)
705 {
706 monotime_offset_update_pending = true;
707 }
594 708
709 input_interrupt_pending = false;
595 if (avr_state_changed()) 710 if (avr_state_changed())
596 { 711 {
597 /* Read buttons state */ 712 /* Read buttons state */
@@ -604,6 +719,20 @@ void avr_thread(void)
604 set_audio_output(headphones_state); 719 set_audio_output(headphones_state);
605 headphones_active_state = headphones_state; 720 headphones_active_state = headphones_state;
606 } 721 }
722
723 if (disk_access_available)
724 {
725 if (monotime_offset_update_pending && write_monotime_offset())
726 {
727 monotime_offset_update_pending = false;
728 }
729 }
730
731 /* Update buffered monotime value every hour */
732 if (TIME_AFTER(current_tick, monotime_value_tick + 3600 * HZ))
733 {
734 read_monotime();
735 }
607 } 736 }
608} 737}
609 738
@@ -613,7 +742,11 @@ void GIO0(void)
613 /* Clear interrupt */ 742 /* Clear interrupt */
614 IO_INTC_IRQ1 = (1 << 5); 743 IO_INTC_IRQ1 = (1 << 5);
615 744
616 semaphore_release(&avr_thread_trigger); 745 if (!input_interrupt_pending)
746 {
747 input_interrupt_pending = true;
748 queue_post(&avr_queue, INPUT_INTERRUPT, 0);
749 }
617} 750}
618 751
619void GIO2(void) __attribute__ ((section(".icode"))); 752void GIO2(void) __attribute__ ((section(".icode")));
@@ -622,20 +755,26 @@ void GIO2(void)
622 /* Clear interrupt */ 755 /* Clear interrupt */
623 IO_INTC_IRQ1 = (1 << 7); 756 IO_INTC_IRQ1 = (1 << 7);
624 757
625 semaphore_release(&avr_thread_trigger); 758 /* Prevent event queue overflow by allowing just one pending event */
759 if (!input_interrupt_pending)
760 {
761 input_interrupt_pending = true;
762 queue_post(&avr_queue, INPUT_INTERRUPT, 0);
763 }
626} 764}
627#endif
628 765
629void button_init_device(void) 766void button_init_device(void)
630{ 767{
631 btn = 0; 768 btn = 0;
632 hold_switch = false; 769 hold_switch = false;
633#ifndef BOOTLOADER 770
634 semaphore_init(&avr_thread_trigger, 1, 1); 771 queue_init(&avr_queue, true);
772 input_interrupt_pending = true;
773 queue_post(&avr_queue, INPUT_INTERRUPT, 0);
635 create_thread(avr_thread, avr_stack, sizeof(avr_stack), 0, 774 create_thread(avr_thread, avr_stack, sizeof(avr_stack), 0,
636 avr_thread_name IF_PRIO(, PRIORITY_USER_INTERFACE) 775 avr_thread_name IF_PRIO(, PRIORITY_USER_INTERFACE)
637 IF_COP(, CPU)); 776 IF_COP(, CPU));
638#endif 777
639 IO_GIO_DIR0 |= 0x01; /* Set GIO0 as input */ 778 IO_GIO_DIR0 |= 0x01; /* Set GIO0 as input */
640 779
641 /* Get in sync with AVR */ 780 /* Get in sync with AVR */
@@ -646,7 +785,6 @@ void button_init_device(void)
646 /* Read button status and tell avr we want interrupt on next change */ 785 /* Read button status and tell avr we want interrupt on next change */
647 avr_hid_get_state(); 786 avr_hid_get_state();
648 787
649#ifndef BOOTLOADER
650 IO_GIO_IRQPORT |= 0x05; /* Enable GIO0/GIO2 external interrupt */ 788 IO_GIO_IRQPORT |= 0x05; /* Enable GIO0/GIO2 external interrupt */
651 IO_GIO_INV0 &= ~0x05; /* Clear INV for GIO0/GIO2 */ 789 IO_GIO_INV0 &= ~0x05; /* Clear INV for GIO0/GIO2 */
652 /* falling edge detection on GIO0, any edge on GIO2 */ 790 /* falling edge detection on GIO0, any edge on GIO2 */
@@ -654,7 +792,6 @@ void button_init_device(void)
654 792
655 /* Enable GIO0 and GIO2 interrupts */ 793 /* Enable GIO0 and GIO2 interrupts */
656 IO_INTC_EINT1 |= INTR_EINT1_EXT0 | INTR_EINT1_EXT2; 794 IO_INTC_EINT1 |= INTR_EINT1_EXT0 | INTR_EINT1_EXT2;
657#endif
658} 795}
659 796
660int button_read_device(void) 797int button_read_device(void)
@@ -674,4 +811,3 @@ void lcd_enable(bool on)
674{ 811{
675 (void)on; 812 (void)on;
676} 813}
677