Browse Source

Added storage for pattern and settings

Daniele Lacamera 4 years ago
parent
commit
e3d1ff9c0d
18 changed files with 329 additions and 97 deletions
  1. 2 1
      Makefile
  2. 5 23
      drone.c
  3. 2 4
      drone.h
  4. 13 14
      drums.c
  5. 2 1
      drums.h
  6. 122 0
      flash.c
  7. 10 0
      flash.h
  8. 1 0
      main.c
  9. 2 2
      pot.c
  10. 37 5
      settings.c
  11. 26 2
      settings.h
  12. 38 1
      system.h
  13. 8 1
      target.ld
  14. 1 1
      timer.c
  15. 3 1
      ui.c
  16. 1 4
      ui.h
  17. 49 30
      ui_drone.c
  18. 7 7
      ui_pattern.c

+ 2 - 1
Makefile

@@ -5,7 +5,8 @@ VERSION?=1
 
 OBJS:=startup.o main.o system.o  mem.o led.o \
 	i2c.o display.o font_twisted.o button.o systick.o newlib.o uart.o ui.o timer.o\
-	mutex.o ui_drone.o adc.o spi.o pot.o dac.o sound.o drone.o settings.o ui_pattern.o
+	mutex.o ui_drone.o adc.o spi.o pot.o dac.o sound.o drone.o settings.o ui_pattern.o \
+	flash.o
 
 
 UMX:=lib/unicore-mx/lib/libucmx_stm32f4.a

+ 5 - 23
drone.c

@@ -19,27 +19,6 @@
 
 #define MUTE { 0 , 0 }
 
-static struct drone_slot drone_pattern[MAX_PATTERN_LEN] = {
-    { 28, 10 }, { 28, 20}, {36,20}, {40,20},
-    { 40, 10 }, { 40, 10}, {36, 10}, {32,10},
-    MUTE, MUTE, MUTE, MUTE,
-    MUTE, MUTE, MUTE, MUTE,
-
-    MUTE, MUTE, MUTE, MUTE,
-    MUTE, MUTE, MUTE, MUTE,
-    MUTE, MUTE, MUTE, MUTE,
-    MUTE, MUTE, MUTE, MUTE,
-
-    MUTE, MUTE, MUTE, MUTE,
-    MUTE, MUTE, MUTE, MUTE,
-    MUTE, MUTE, MUTE, MUTE,
-    MUTE, MUTE, MUTE, MUTE,
-
-    MUTE, MUTE, MUTE, MUTE,
-    MUTE, MUTE, MUTE, MUTE,
-    MUTE, MUTE, MUTE, MUTE,
-    MUTE, MUTE, MUTE, MUTE,
-};
 
 void drone_mute(void)
 {
@@ -51,13 +30,17 @@ void drone_mute(void)
 
 void drone_beat(int pattern_pos)
 {
-    struct drone_slot *key = &drone_pattern[pattern_pos];
     static int test_lfo_step = 0;
     static int test_lfo = 0;
     int lfo_depth = 80;
     int lfo_rate = 7;
     int lfo_step = 2;
     int tgt_env;
+    static struct drone_slot *pattern;
+    struct drone_slot *key; 
+    pattern = Settings->drone[Settings->current_pattern].data;
+    key = &pattern[pattern_pos];
+
     if ((key->pitch == 0) && (key->env == 0)) {
         pot_set(0, 99);
         pot_set(1, 0);
@@ -93,7 +76,6 @@ void drone_beat(int pattern_pos)
         tgt_env = 99;
         test_lfo_step = 1;
     }
-
     pot_set(0, key->pitch);
     pot_set(1, tgt_env);
 }

+ 2 - 4
drone.h

@@ -2,11 +2,9 @@
 #ifndef DRONE_H_INCLUDED
 #define DRONE_H_INCLUDED
 #include <stdint.h>
+#include "settings.h"
 
 void drone_mute(void);
+void drone_select_pattern(struct drone_pattern *p);
 
-struct __attribute__((packed)) drone_slot {
-    uint8_t pitch;
-    uint8_t env;
-};
 #endif

+ 13 - 14
drums.c

@@ -17,8 +17,7 @@
 
 #define TRACKS 8
 
-//static uint32_t pattern[MAX_PATTERN_LEN] = { DRUMS_KICK, DRUMS_HIHAT, DRUMS_SNARE, DRUMS_HIHAT, DRUMS_KICK, DRUMS_KICK, DRUMS_SNARE, DRUMS_HIHAT };
-static uint32_t pattern[MAX_PATTERN_LEN] = { DRUMS_KICK, DRUMS_KICK, DRUMS_CLAP, 0,  0, DRUMS_KICK, 0};
+static struct drums_pattern *pattern = NULL;
 static uint32_t pattern_len = 8;
 static uint32_t pattern_pos = 0;
 static unsigned char *dsample[TRACKS] = {};
@@ -26,9 +25,11 @@ static unsigned int dsample_len[TRACKS] = {};
 
 static void beat_cb(uint32_t b)
 {
-    uint32_t key = pattern[pattern_pos];
     int i;
-    drone_beat(pattern_pos);
+    uint32_t key;
+    pattern = &Settings->drums[Settings->current_pattern];
+    //drone_beat(pattern_pos);
+    key = pattern->data[pattern_pos];
     for (i = 0; i < TRACKS; i++) {
         if ((key & (1 << i)) == (1 << i)) {
             if (dsample[i]) {
@@ -40,7 +41,7 @@ static void beat_cb(uint32_t b)
         }
     }
     pattern_pos++;
-    if (pattern_pos >= Settings.pattern_len) {
+    if (pattern_pos >= pattern->len) {
         pattern_pos = 0;
     }
     led_beat((pattern_pos  % 8) + 1);
@@ -82,23 +83,21 @@ void drums_stop(void)
     timer_clear_beat_callback();
 }
 
-void drums_set_pattern_len(int l)
-{
-    Settings.pattern_len = l;
-    timer_set_beat(1);
-}
-
 void drums_set(uint32_t track, int pos)
 {
-    pattern[pos] |= (1 << track);
+    pattern = Settings->drums[Settings->current_pattern].data;
+    pattern->data[pos] |= (1 << track);
 }
 
 void drums_clear(uint32_t track, int pos)
 {
-    pattern[pos] &= ~(1 << track);
+    pattern = Settings->drums[Settings->current_pattern].data;
+    pattern->data[pos] &= ~(1 << track);
 }
 
 int drums_get(uint32_t track, int pos)
 {
-    return (!!(pattern[pos] & (1 << track)));
+    pattern = Settings->drums[Settings->current_pattern].data;
+    return (!!(pattern->data[pos] & (1 << track)));
 }
+

+ 2 - 1
drums.h

@@ -2,14 +2,15 @@
 #define DRUMS_H_INCLUDED
 
 #include <stdint.h>
+#include "settings.h"
 void drums_init(void);
 void drums_start(void);
 void drums_stop(void);
-void drums_set_pattern_len(int l);
 int drums_get(uint32_t track, int pos);
 void drums_set(uint32_t track, int pos);
 void drums_clear(uint32_t track, int pos);
 void drums_oneshot(int track);
+void drums_select_pattern(struct drums_pattern *p);
 
 #define DRUMS_KICK      (1 << 0)
 #define DRUMS_HIHAT     (1 << 1)

+ 122 - 0
flash.c

@@ -0,0 +1,122 @@
+/* stm32f4.c
+ *
+ * Copyright (C) 2020 Danielinux
+ *
+ */
+
+#include <stdint.h>
+#include "system.h"
+
+/* STM32F4 FLASH Geometry */
+#define FLASH_SECTOR_0  0x0000000 /* 16 Kb   */
+#define FLASH_SECTOR_1  0x0004000 /* 16 Kb   */
+#define FLASH_SECTOR_2  0x0008000 /* 16 Kb   */
+#define FLASH_SECTOR_3  0x000C000 /* 16 Kb   */
+#define FLASH_SECTOR_4  0x0010000 /* 64 Kb   */
+#define FLASH_SECTOR_5  0x0020000 /* 128 Kb  */
+#define FLASH_SECTOR_6  0x0040000 /* 128 Kb  */
+#define FLASH_SECTOR_7  0x0060000 /* 128 Kb  */
+#define FLASH_SECTOR_8  0x0080000 /* 128 Kb  */
+#define FLASH_SECTOR_9  0x00A0000 /* 128 Kb  */
+#define FLASH_SECTOR_10 0x00C0000 /* 128 Kb  */
+#define FLASH_SECTOR_11 0x00E0000 /* 128 Kb  */
+#define FLASH_TOP       0x0100000
+
+#define FLASH_SECTORS 12
+const uint32_t flash_sector[FLASH_SECTORS + 1] = {
+    FLASH_SECTOR_0,
+    FLASH_SECTOR_1,
+    FLASH_SECTOR_2,
+    FLASH_SECTOR_3,
+    FLASH_SECTOR_4,
+    FLASH_SECTOR_5,
+    FLASH_SECTOR_6,
+    FLASH_SECTOR_7,
+    FLASH_SECTOR_8,
+    FLASH_SECTOR_9,
+    FLASH_SECTOR_10,
+    FLASH_SECTOR_11,
+    FLASH_TOP
+};
+
+static void flash_wait_complete(void)
+{
+    while ((FLASH_SR & FLASH_SR_BSY) == FLASH_SR_BSY)
+        ;
+}
+
+static void flash_erase_sector(uint32_t sec)
+{
+    uint32_t reg = FLASH_CR & (~(FLASH_CR_SNB_MASK << FLASH_CR_SNB_SHIFT));
+    FLASH_CR = reg | (sec & FLASH_CR_SNB_MASK) << FLASH_CR_SNB_SHIFT;
+    FLASH_CR |= FLASH_CR_SER;
+    FLASH_CR |= FLASH_CR_STRT;
+    flash_wait_complete();
+    FLASH_CR &= ~FLASH_CR_SER;
+    FLASH_CR &= ~(FLASH_CR_SNB_MASK << FLASH_CR_SNB_SHIFT);
+}
+
+static void clear_errors(void)
+{
+    FLASH_SR |= ( FLASH_SR_PGSERR | FLASH_SR_PGPERR | FLASH_SR_PGAERR | FLASH_SR_WRPERR | FLASH_SR_OPERR | FLASH_SR_EOP );
+}
+
+int flash_write(uint32_t address, const uint8_t *data, int len)
+{
+    int i;
+    uint32_t val;
+    flash_wait_complete();
+    clear_errors();
+    /* Set 8-bit write */
+    FLASH_CR &= (~(0x03 << 8));
+    for (i = 0; i < len; i++) {
+        FLASH_CR |= FLASH_CR_PG;
+        *((uint8_t *)(address + i)) = data[i];
+        flash_wait_complete();
+        FLASH_CR &= ~FLASH_CR_PG;
+    }
+    return 0;
+}
+
+void flash_unlock(void)
+{
+    FLASH_CR |= FLASH_CR_LOCK;
+    FLASH_KEYR = FLASH_KEY1;
+    FLASH_KEYR = FLASH_KEY2;
+}
+
+void flash_lock(void)
+{
+    FLASH_CR |= FLASH_CR_LOCK;
+}
+
+
+int flash_erase(uint32_t address, int len)
+{
+    int start = -1, end = -1;
+    uint32_t end_address;
+    int i;
+    if (len == 0)
+        return -1;
+    end_address = address + len - 1;
+
+    if (address < flash_sector[0] || end_address > FLASH_TOP)
+        return -1;
+    for (i = 0; i < FLASH_SECTORS; i++)
+    {
+        if ((address >= flash_sector[i]) && (address < flash_sector[i + 1])) {
+            start = i;
+        }
+        if ((end_address >= flash_sector[i]) && (end_address < flash_sector[i + 1])) {
+            end = i;
+        }
+        if (start > 0 && end > 0)
+            break;
+    }
+    if (start < 0 || end < 0)
+        return -1;
+    for (i = start; i <= end; i++)
+        flash_erase_sector(i);
+    return 0;
+}
+

+ 10 - 0
flash.h

@@ -0,0 +1,10 @@
+#ifndef FLASH_H_INCLUDED
+#define FLASH_H_INCLUDED
+#include <stdint.h>
+
+int flash_write(uint32_t address, const uint8_t *data, int len);
+void flash_unlock(void);
+void flash_lock(void);
+int flash_erase(uint32_t address, int len);
+#endif
+

+ 1 - 0
main.c

@@ -34,6 +34,7 @@ static void bootlevel_0(void)
     uart2_setup(115200, 8, 0, 1);
     systick_enable();
     WFI();
+    settings_load();
     printf("Console on USART2 Enabled.\r\n");
     printf("\r\n=====================\r\n");
     printf("Entering bootlevel 0.\r\n");

+ 2 - 2
pot.c

@@ -109,7 +109,7 @@ void pot_init(void)
 
 void pot_sync(int p)
 {
-    pot_set(p, Settings.levels[p]);
+    pot_set(p, Settings->levels[p]);
 }
 
 
@@ -130,7 +130,7 @@ void pot_set(int p, int val)
     if (val > 100)
         val = 100;
 
-    Settings.levels[p] = val;
+    Settings->levels[p] = val;
 
     off = val - old;
     if (off == 0)

+ 37 - 5
settings.c

@@ -1,7 +1,39 @@
+#include <string.h>
 #include "settings.h"
+#include "flash.h"
 
-struct settings Settings = {
-    .bpm = 125,   
-    .pattern_len = 16,
-    
-};
+
+#define RAM_SETTINGS (0x20012000)
+#define FLASH_SETTINGS (0x0E0000)
+#define SETTINGS_PART_SIZE (0x20000) /* 128 KB */
+
+struct settings *Settings = (struct settings *)(RAM_SETTINGS);
+
+
+
+void settings_save(void)
+{
+    flash_unlock();
+    flash_erase(FLASH_SETTINGS, SETTINGS_PART_SIZE);
+    flash_write(FLASH_SETTINGS, (const void *)(RAM_SETTINGS), sizeof(struct settings));
+    flash_lock();
+}
+
+static void restore_defaults(void)
+{
+    memset(Settings, 0, sizeof(struct settings));
+    Settings->storage_hdr = STORAGE_HDR;
+    Settings->bpm = 125;
+    settings_save();
+}
+
+
+void settings_load(void)
+{
+    struct settings *s = (struct settings *)FLASH_SETTINGS;
+    if (s->storage_hdr != STORAGE_HDR) {
+        restore_defaults();
+        return;
+    } 
+    memcpy((void *)RAM_SETTINGS, (const void *)FLASH_SETTINGS, sizeof(struct settings));
+}

+ 26 - 2
settings.h

@@ -5,14 +5,38 @@
 
 #define MAX_PATTERN_LEN 64
 #define MAX_TRACKS 8
+#define MAX_PATTERNS 32
+
+
+#define STORAGE_HDR (0xDA1EDA1E)
+struct settings;
+extern struct settings *Settings;
+
+
+struct __attribute__((packed)) drone_slot {
+    uint8_t pitch;
+    uint8_t env;
+};
 
 struct settings {
+    uint32_t storage_hdr;
     int levels[NUM_POTS];
 #define master_vol levels[2]
     int bpm;
+    int beatcount;
     int sequencer_on;
-    int pattern_len;
+    int current_pattern;
+    struct drums_pattern {
+        uint32_t len;
+        uint32_t data[MAX_PATTERN_LEN];
+    } drums[MAX_PATTERNS];
+    struct drone_pattern {
+        struct drone_slot data[MAX_PATTERN_LEN];
+    } drone[MAX_PATTERNS];
 };
 
-extern struct settings Settings;
+
+void settings_load(void);
+void settings_save(void);
+
 #endif

+ 38 - 1
system.h

@@ -153,10 +153,47 @@ static inline void nvic_irq_clear(uint8_t n)
 }
 /*** FLASH ***/
 #define FLASH_BASE (0x40023C00)
-#define FLASH_ACR  (*(volatile uint32_t *)(FLASH_BASE + 0x00))
+#define FLASH_ACR           (*(volatile uint32_t *)(FLASH_BASE + 0x00))
+#define FLASH_KEYR          (*(volatile uint32_t *)(FLASH_BASE + 0x04))
+#define FLASH_SR            (*(volatile uint32_t *)(FLASH_BASE + 0x0C))
+#define FLASH_CR            (*(volatile uint32_t *)(FLASH_BASE + 0x10))
 #define FLASH_ACR_ENABLE_DATA_CACHE (1 << 10)
 #define FLASH_ACR_ENABLE_INST_CACHE (1 << 9)
 
+/* Register values */
+#define FLASH_ACR_RESET_DATA_CACHE            (1 << 12)
+#define FLASH_ACR_RESET_INST_CACHE            (1 << 11)
+#define FLASH_ACR_ENABLE_DATA_CACHE           (1 << 10)
+#define FLASH_ACR_ENABLE_INST_CACHE           (1 << 9)
+#define FLASH_ACR_ENABLE_PRFT                 (1 << 8)
+
+#define FLASH_SR_BSY                          (1 << 16)
+#define FLASH_SR_PGSERR                       (1 << 7)
+#define FLASH_SR_PGPERR                       (1 << 6)
+#define FLASH_SR_PGAERR                       (1 << 5)
+#define FLASH_SR_WRPERR                       (1 << 4)
+#define FLASH_SR_OPERR                        (1 << 1)
+#define FLASH_SR_EOP                          (1 << 0)
+
+#define FLASH_CR_LOCK                         (1 << 31)
+#define FLASH_CR_ERRIE                        (1 << 25)
+#define FLASH_CR_EOPIE                        (1 << 24)
+#define FLASH_CR_STRT                         (1 << 16)
+#define FLASH_CR_MER                          (1 << 2)
+#define FLASH_CR_SER                          (1 << 1)
+#define FLASH_CR_PG                           (1 << 0)
+
+#define FLASH_CR_SNB_SHIFT                      3
+#define FLASH_CR_SNB_MASK                      0x1f
+
+#define FLASH_CR_PROGRAM_X8                   (0 << 8)
+#define FLASH_CR_PROGRAM_X16                  (1 << 8)
+#define FLASH_CR_PROGRAM_X32                  (2 << 8)
+#define FLASH_CR_PROGRAM_X64                  (3 << 8)
+
+#define FLASH_KEY1                            (0x45670123)
+#define FLASH_KEY2                            (0xCDEF89AB)
+
 /*** SPI ***/
 #define SPI1 (0x40013000)
 #define SPI1_CR1      (*(volatile uint32_t *)(SPI1))

+ 8 - 1
target.ld

@@ -1,8 +1,9 @@
 MEMORY
 {
     FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 256K - 0x100
-    RAM (rw) : ORIGIN = 0x20001000, LENGTH = 252K
     RAM_S (rw) : ORIGIN = 0x20000000, LENGTH = 4K
+    RAM (rw) : ORIGIN = 0x20001000, LENGTH = 64K
+    RAM_SETTINGS (rw) : ORIGIN = 0x2012000, LENGTH = 60K
 }
 
 SECTIONS
@@ -25,6 +26,7 @@ SECTIONS
 
     _stored_data = .;
 
+
     .data : AT (_stored_data)
     {
         _start_data = .;
@@ -42,6 +44,11 @@ SECTIONS
         _end_bss = .;
         _end = .;
     } > RAM
+    
+    .settings :
+    {
+        *(.settings*)
+    } > RAM_SETTINGS
 
 }
 

+ 1 - 1
timer.c

@@ -27,7 +27,7 @@ int timer_set_bpm(void)
     uint32_t psc = 1;
     uint32_t err = 0;
     uint32_t reg = 0;
-    uint32_t clock = (cpu_freq / (4 * Settings.bpm)) * (S_PER_MINUTE);;
+    uint32_t clock = (cpu_freq / (4 * Settings->bpm)) * (S_PER_MINUTE);;
 
     while (psc < 65535) {
         val = clock / psc;

+ 3 - 1
ui.c

@@ -84,6 +84,7 @@ void ui_menu_autoscroll(void)
     display_scroll(NULL, display_cur_v);
 }
 
+extern struct display_menu MainMenu;
 static void ui_display_menu_refresh(void)
 {
     const struct display_menu *menu = CurrentMenu;
@@ -92,7 +93,8 @@ static void ui_display_menu_refresh(void)
     char txt[16];
     display_scroll(NULL, display_cur_v);
     display_clear(NULL);
-
+    if (menu->render)
+        menu->render(menu);
     for (i = 0; i < menu->entry_n; i++) {
         vline = i + 4;
         if (vline > 7)

+ 1 - 4
ui.h

@@ -24,12 +24,9 @@ struct display_menu {
         int *var;
         const void *arg;
     } entry[MAX_ENTRY];
-
+    void (*render)(struct display_menu *menu);
 };
 
-const struct display_menu MainMenu, MeasureMenu, SignalGenMenu,
-      ExtraMenu;
-
 void ui_display_menu(const struct display_menu *menu);
 void ui_button_press(uint8_t b, int hold);
 

+ 49 - 30
ui_drone.c

@@ -15,6 +15,32 @@
 #define CENTER_Y ((int)(50))
 #define NEUTRAL 2
 
+static void ui_sequencer_action(struct display_menu_entry *e, uint8_t b);
+static void ui_master_action(struct display_menu_entry *e, uint8_t b);
+static void ui_bpm_action(struct display_menu_entry *e, uint8_t b);
+static void ui_pattern_save_action(struct display_menu_entry *e, uint8_t b);
+static void main_menu_prepare(struct display_menu *m);
+extern struct display_menu PatternMenu;
+
+static void ui_submenu_action(struct display_menu_entry *e, uint8_t b)
+{
+    ui_display_menu(e->arg);
+}
+
+struct display_menu MainMenu = {
+    .entry_n = 7,
+    .render = main_menu_prepare,
+    .entry = {  
+        { ENTRY_TYPE_BOOL, "Sequencer", ui_sequencer_action, .min = 0, .max = 0, .step = 0, NULL, .arg = NULL },
+        { ENTRY_TYPE_DEC,  "Volume: ", ui_master_action, 0, 100, 2, NULL, NULL },
+        { ENTRY_TYPE_DEC,  "BPM: ", ui_bpm_action, 30, 300, 1,  NULL, NULL },
+        { ENTRY_TYPE_DEC,  "Pattern    :", NULL, 0, MAX_PATTERNS, 1, NULL, NULL },
+        { ENTRY_TYPE_DEC,  "Pattern Len:", NULL, 8, MAX_PATTERN_LEN, 8, NULL, NULL },
+        { ENTRY_TYPE_TEXT, "Edit Pattern", ui_submenu_action, 0, 0, 0, NULL, &PatternMenu},
+        { ENTRY_TYPE_TEXT, "Save Pattern", ui_pattern_save_action, 0, 0, 0, NULL, NULL},
+    }
+};
+
 struct display_menu *CurrentMenu = &MainMenu;
 
 extern volatile uint32_t jiffies;
@@ -197,6 +223,8 @@ static void ui_bpm_input(uint8_t press, int hold)
             timer_stop();
             timer_set_bpm();
             led_beat(1);
+            settings_save();
+            timer_set_beat(1);
             timer_set_beat(1);
             timer_start();
         }
@@ -207,6 +235,7 @@ static void ui_bpm_input(uint8_t press, int hold)
             timer_stop();
             timer_set_bpm(sys_bpm - 1);
             led_beat(1);
+            settings_save();
             timer_set_beat(1);
             timer_start();
         }
@@ -266,16 +295,6 @@ static void ui_bytebeat(const void *arg)
     set_keepalive(ui_bytebeat_keepalive);
 }
 
-
-
-const struct display_menu PatternMenu = {
-    .entry_n = 1,
-    .entry = {
-        { "TODO!           ", ui_submenu, &MainMenu},
-        { "", NULL, NULL}
-    }
-};
-
 const struct display_menu DroneMenu = {
     .entry_n = 2,
     .entry = {
@@ -295,14 +314,10 @@ const struct display_menu SettingsMenu = {
 
 #endif
 
-static void ui_submenu_action(struct display_menu_entry *e, uint8_t b)
-{
-    ui_display_menu(e->arg);
-}
 
 static void ui_sequencer_action(struct display_menu_entry *e, uint8_t b)
 {
-    if (Settings.sequencer_on) {
+    if (Settings->sequencer_on) {
         timer_set_beat(1);
         timer_start();
     } else {
@@ -326,23 +341,27 @@ static void ui_bpm_action(struct display_menu_entry *e, uint8_t b)
     timer_start();
 }
 
-
-extern void ui_pattern_menu_action(struct display_menu_entry *e, uint8_t b);
-extern struct display_menu PatternMenu;
-const struct display_menu MainMenu = {
-    .entry_n = 5,
-    .entry = {
-        /* TYPE, label, action, min, max, var, arg */
-        { ENTRY_TYPE_BOOL, "Sequencer", ui_sequencer_action, 0, 0, 0, &Settings.sequencer_on, NULL },
-        { ENTRY_TYPE_DEC, "Volume: ", ui_master_action, 0, 100, 2, &Settings.levels[2], NULL },
-        { ENTRY_TYPE_DEC, "BPM: ", ui_bpm_action, 30, 300, 1,  &Settings.bpm, NULL },
-        { ENTRY_TYPE_DEC, "Pattern Len:", NULL, 8, MAX_PATTERN_LEN, 8, &Settings.pattern_len, NULL },
-        { ENTRY_TYPE_TEXT, "Edit Pattern", ui_pattern_menu_action, 0, 0, 0, NULL, &PatternMenu},
-        {0, "", NULL, 0,0,0,NULL,NULL}
-    }
-};
+static void ui_pattern_save_action(struct display_menu_entry *e, uint8_t b)
+{
+    display_clear();
+    display_scroll(NULL, 0);
+    display_text(5, "Saving to FLASH");
+    settings_save();
+    ui_display_menu(&MainMenu);
+}
 
 
+static void main_menu_prepare(struct display_menu *m)
+{
+    if (m != &MainMenu)
+        return;
+    MainMenu.entry[0].var = &Settings->sequencer_on;
+    MainMenu.entry[1].var = &Settings->levels[2];
+    MainMenu.entry[2].var = &Settings->bpm;
+    MainMenu.entry[3].var = &Settings->current_pattern;
+    MainMenu.entry[4].var = &(Settings->drums[Settings->current_pattern].len);
+}
 
 
+extern void ui_pattern_menu_action(struct display_menu_entry *e, uint8_t b);
 

+ 7 - 7
ui_pattern.c

@@ -51,6 +51,7 @@ void ui_pattern_keepalive(void)
     }
 }
 
+extern struct display_menu MainMenu;
 void ui_pattern_menu_return_to_main(struct display_menu_entry *e, uint8_t b)
 {
     display_clear(NULL);
@@ -60,8 +61,10 @@ void ui_pattern_menu_return_to_main(struct display_menu_entry *e, uint8_t b)
     ui_display_menu(&MainMenu);
 }
 
+static void pattern_menu_prepare(struct display_menu *m);
 struct display_menu PatternMenu = {
     .entry_n = 4,
+    .render = pattern_menu_prepare,
     .entry = {
         /* TYPE, label, action, min, max, var, arg */
         { ENTRY_TYPE_DEC, "Track: ", ui_pattern_refresh_action, 0, (MAX_TRACKS - 1), 1, &sel_track, NULL },
@@ -98,16 +101,13 @@ const char instr_txt[MAX_TRACKS][14] = {
     "",
 };
 
-
-
-
-void ui_pattern_menu_action(struct display_menu_entry *e, uint8_t b)
+static void pattern_menu_prepare(struct display_menu *m)
 {
-    PatternMenu.entry[1].max = Settings.pattern_len;
+    if (m != &PatternMenu)
+        return;
+    PatternMenu.entry[1].max = Settings->drums[Settings->current_pattern].len;
     sel_val = drums_get(sel_track, sel_pos - 1);
-    ui_display_menu(e->arg);
     set_keepalive(ui_pattern_keepalive);
     set_input_callback(ui_pattern_input);
-    ui_pattern_refresh_action(e, b);
 }