Kaynağa Gözat

Merge branch 'feature_models' of thomas/drumkit into master

Thomas B 1 ay önce
ebeveyn
işleme
ecc7c9c212

+ 71
- 0
3dprint/actuator.scad Dosyayı Görüntüle

@@ -0,0 +1,71 @@
1
+$fa=1/1;
2
+$fs=1/2;
3
+bissl=1/2;
4
+part="spool";//[spool,cap,hammer,all]
5
+total_length=50;
6
+wall=0.8;
7
+air=0.5;
8
+copper_height=5;
9
+thick_wall=2*wall; //can be specified
10
+iron_d=4;
11
+iron_h=total_length/3; //can be changed, but this seems optimal
12
+spool_h=iron_h; //according to theory, optimum is a little more
13
+iron_travel=iron_h; //may be smaller with heavy beaters or returning springs
14
+extra_hold=iron_h/3;
15
+spool_id=iron_d+2*air;
16
+spool_od=spool_id+2*wall;
17
+cap_od=spool_od+2*copper_height;
18
+slit=15;
19
+hole=3;
20
+hammer_flat=true;
21
+module spool() {
22
+  difference() {
23
+    union() {
24
+      cylinder(d1=spool_od,d2=cap_od,h=thick_wall+iron_travel);
25
+      translate([0,0,iron_travel+thick_wall]) cylinder(d=spool_od,h=spool_h+extra_hold);
26
+    }
27
+    translate([0,0,thick_wall]) cylinder(d=spool_id,h=spool_h+iron_h+bissl+extra_hold);
28
+  }
29
+}
30
+module cap() {
31
+difference() {
32
+union() {
33
+cylinder(d=cap_od,h=thick_wall);
34
+translate([0,0,thick_wall])cylinder(d=spool_od+2*wall+2*air,h=extra_hold);
35
+translate([-cap_od/2,0,0])cube([cap_od,cap_od/2,thick_wall]);
36
+translate([-cap_od/2,cap_od/2,0])cube([cap_od,thick_wall,2*thick_wall+slit]);
37
+translate([-thick_wall/2,0,0])cube([thick_wall,cap_od/2,extra_hold+thick_wall]);
38
+}
39
+translate([0,0,-bissl])cylinder(d=spool_id,h=extra_hold+thick_wall+2*bissl);
40
+cylinder(d=spool_od+2*air,h=extra_hold);
41
+hull() {
42
+translate([cap_od/2-thick_wall-hole/2,cap_od/2+thick_wall/2,2*thick_wall+hole/2])rotate([90,0,0])cylinder (d=hole, h=thick_wall+bissl,center=true);
43
+translate([cap_od/2-thick_wall-hole/2,cap_od/2+thick_wall/2,slit])rotate([90,0,0])cylinder (d=hole, h=thick_wall+bissl,center=true);
44
+}
45
+hull() {
46
+translate([-cap_od/2+thick_wall+hole/2,cap_od/2+thick_wall/2,2*thick_wall+hole/2])rotate([90,0,0])cylinder (d=hole, h=thick_wall+bissl,center=true);
47
+translate([-cap_od/2+thick_wall+hole/2,cap_od/2+thick_wall/2,slit])rotate([90,0,0])cylinder (d=hole, h=thick_wall+bissl,center=true);
48
+}
49
+}
50
+}
51
+echo (cap_od-thick_wall*2-hole);
52
+module hammer() {
53
+if (hammer_flat) {
54
+cylinder(d=cap_od-2*air,h=thick_wall);
55
+translate([0,0,thick_wall]) cylinder(d1=cap_od-2*air,d2=iron_d,h=cap_od/2-iron_d/2-air/2);
56
+}
57
+else {
58
+cylinder(d2=cap_od/2,d1=iron_d,h=cap_od/4-iron_d/4);
59
+translate([0,0,cap_od/4-iron_d/4])cylinder(d=cap_od/2,h=thick_wall);
60
+translate([0,0,cap_od/4-iron_d/4+thick_wall]) cylinder(d1=cap_od/2,d2=iron_d,h=cap_od/4-iron_d/4);
61
+}
62
+translate([0,0,thick_wall+cap_od/2-iron_d/2-air/2]) cylinder(d=iron_d,h=1.5*iron_h);
63
+}
64
+if (part=="all") {
65
+spool();
66
+translate([0,0,spool_h+iron_h+bissl+air+thick_wall])cap();
67
+translate([0,0,total_length])mirror([0,0,1])hammer();
68
+}
69
+if (part=="spool") spool();
70
+if (part=="cap") cap();
71
+if (part=="hammer") hammer();

+ 52
- 0
3dprint/beam.scad Dosyayı Görüntüle

@@ -0,0 +1,52 @@
1
+$fa=1/1;
2
+$fs=1/2;
3
+bissl=1/100;
4
+wall=1.6;//twice nozzle diameter is fine, walls of triangles
5
+hole=3; //hole for mounting thread inserts
6
+hd=10; //horizontal distance between mounting points, depends on mounting hole distance in the actuator
7
+height=40; //dimension of the beam in the direction of tambourine depth
8
+vd=height-wall; //vertical distance between mounting holes
9
+segments=14; //number of mounting points, defines the beam length
10
+radius=1; //rounding of inner corners
11
+thickness=2*wall+hole; //thickness of the beam, keep some material to properly hold the threaded insert on the side
12
+offset=wall/2+hole/2;
13
+difference() {
14
+  linear_extrude(thickness, convexity=4) difference() {
15
+    offset(r=-radius)offset(r=radius)union() {
16
+      for (i=[0:hd:hd*(segments-1)]) translate ([i,0]) {
17
+        for (tr=[[[hd,0],[0,0]],[[-hd/2,vd],[0,0]],[[hd/2,vd],[0,0]],[[hd/2,vd],[-hd/2,vd]]]) hull() { //diagonals
18
+          translate(tr[0])circle(d=wall);
19
+          translate(tr[1]) circle(d=wall);
20
+        }
21
+        for (tr=[[hd/2,vd-offset],[-hd/2,vd-offset],[hd,offset],[0,offset]]) translate(tr)circle(d=2*wall+hole); //big circles
22
+      }
23
+    
24
+      //left vertical wall, not generated by the loop
25
+      for (tr=[[[-hd/2-offset,0],[0,0]],[[-hd/2-offset,0],[-hd/2-offset,vd]],[[-hd/2-offset,vd],[-hd/2,vd]]]) hull() {
26
+        translate(tr[0])circle(d=wall);
27
+        translate(tr[1]) circle(d=wall);
28
+      }
29
+
30
+      //solid triangle to jhold threaded inserts
31
+      hull() for (tr=[[0,0],[-hd/2-offset,0],[-hd/2-offset,vd],[-hd/2,vd]]) translate(tr) circle(d=wall); 
32
+
33
+      //right vertical wall, not generated by the loop
34
+      for (tr=[[[hd*segments+offset,0],[0,0]],
35
+               [[hd*segments+offset,0],[hd*segments+offset,vd]],
36
+               [[hd*segments+offset,vd],[hd*(segments-0.5),vd]],
37
+               [[hd*segments,0],[hd*(segments-0.5),vd]]]) 
38
+        hull() {
39
+          translate(tr[0])circle(d=wall);
40
+          translate(tr[1]) circle(d=wall);
41
+        }
42
+    }
43
+    for (i=[0:segments]) {
44
+      translate([i*hd,offset]) circle(d=hole);
45
+      translate([(i-0.5)*hd,vd-offset]) circle(d=hole);
46
+    }
47
+  }
48
+  //mounting holes for threaded inserts, three just in case, it's better to use the middle one
49
+  translate([-hd/2-offset-wall/2,height/4-wall,thickness/2])rotate([0,90,0])cylinder(d=hole,h=hd-wall);
50
+  translate([-hd/2-offset-wall/2,height/2-wall/2,thickness/2])rotate([0,90,0])cylinder(d=hole,h=hd-wall);
51
+  translate([-hd/2-offset-wall/2,height*3/4,thickness/2])rotate([0,90,0])cylinder(d=hole,h=hd-wall);
52
+}

BIN
3dprint/beam.stl Dosyayı Görüntüle


+ 1
- 0
3dprint/enclosure.scad Dosyayı Görüntüle

@@ -0,0 +1 @@
1
+part="bottom";//[bottom,top]

+ 1
- 2
3dprint/tamb_mount.json Dosyayı Görüntüle

@@ -9,8 +9,7 @@
9 9
             "id_tamb": "239",
10 10
             "lip": "3",
11 11
             "od_tamb": "251",
12
-            "part": "outer",
13
-            "wall": "1.6000000000000001"
12
+            "part": "outer"
14 13
         }
15 14
     }
16 15
 }

+ 10
- 11
3dprint/tamb_mount.scad Dosyayı Görüntüle

@@ -2,15 +2,15 @@ $fa=1/1;
2 2
 $fs=1/2;
3 3
 bissl=1/100;
4 4
 part="inner";//[inner,outer,all_visualize]
5
-od_tamb=251;
6
-id_tamb=239;
7
-wall_tamb=(od_tamb-id_tamb)/2;
8
-hole_tamb=23;
9
-lip=3;
10
-air=1;
11
-hole=3;
12
-wall=1.6;
13
-beam_width=7;
5
+od_tamb=251;//tambourine rim outer diameter
6
+id_tamb=239;//tambourine rim inner diameter
7
+wall_tamb=(od_tamb-id_tamb)/2; //tambourine wall
8
+hole_tamb=23; //holding hole in the rim
9
+lip=3; //extra plastic that hols to the hole
10
+air=1; //wiggle room
11
+hole=3; //diameter for screw hole
12
+beam_width=7; //slit in inner part of mount to hod the beam
13
+wall=1.6;//thinnest part in the mount, namely the slit to tune the beam mounting height
14 14
 module inner_mount() {
15 15
   difference() {
16 16
     union() {
@@ -30,7 +30,6 @@ module inner_mount() {
30 30
     translate([-beam_width/2-air/2,-hole_tamb/2-lip,-bissl]) cube([beam_width+air,hole_tamb+2*lip,lip]);
31 31
   }
32 32
 }
33
-
34 33
 module outer_mount() {
35 34
   difference() {
36 35
     union() {
@@ -54,4 +53,4 @@ if (part=="outer") outer_mount();
54 53
 if (part=="all_visualize") {
55 54
   inner_mount();
56 55
   translate([0,0,wall_tamb+3*lip])rotate([180,0,0])outer_mount();
57
-  }
56
+}

+ 1
- 0
CMakeLists.txt Dosyayı Görüntüle

@@ -30,6 +30,7 @@ pico_sdk_init()
30 30
 add_executable(drumkit)
31 31
 
32 32
 target_sources(drumkit PUBLIC
33
+    src/adc.c
33 34
     src/buttons.c
34 35
     src/encoder.c
35 36
     src/lcd.c

+ 1
- 1
README.md Dosyayı Görüntüle

@@ -53,7 +53,7 @@ It uses the [Pi Pico SDK](https://github.com/raspberrypi/pico-sdk), licensed as
53 53
 
54 54
 The code in `src/encoder.c` is derived from [mathertel/RotaryEncoder](https://github.com/mathertel/RotaryEncoder) and therefore licensed as BSD 3-clause.
55 55
 
56
-The PCB design uses `Mini360_step_down_converter` library from [rayvburn/KiCad](https://github.com/rayvburn/KiCad/tree/master/Mini360_step_down_converter).
56
+~~The PCB design uses `Mini360_step_down_converter` library from [rayvburn/KiCad](https://github.com/rayvburn/KiCad/tree/master/Mini360_step_down_converter).~~
57 57
 
58 58
     This program is free software: you can redistribute it and/or modify
59 59
     it under the terms of the GNU General Public License as published by

+ 25
- 0
include/adc.h Dosyayı Görüntüle

@@ -0,0 +1,25 @@
1
+/*
2
+ * adc.h
3
+ *
4
+ * Copyright (c) 2022 - 2023 Thomas Buck (thomas@xythobuz.de)
5
+ *
6
+ * This program is free software: you can redistribute it and/or modify
7
+ * it under the terms of the GNU General Public License as published by
8
+ * the Free Software Foundation, either version 3 of the License, or
9
+ * (at your option) any later version.
10
+ *
11
+ * This program is distributed in the hope that it will be useful,
12
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
+ * GNU General Public License for more details.
15
+ *
16
+ * See <http://www.gnu.org/licenses/>.
17
+ */
18
+
19
+#ifndef __ADC_H__
20
+#define __ADC_H__
21
+
22
+void bat_init(void);
23
+float bat_get(void);
24
+
25
+#endif // __ADC_H__

+ 0
- 1
include/buttons.h Dosyayı Görüntüle

@@ -35,4 +35,3 @@ void buttons_callback(void (*fp)(enum buttons, bool));
35 35
 void buttons_run(void);
36 36
 
37 37
 #endif // __BUTTONS_H__
38
-

+ 0
- 1
include/encoder.h Dosyayı Görüntüle

@@ -26,4 +26,3 @@ int32_t encoder_pos(void);
26 26
 void encoder_run(void);
27 27
 
28 28
 #endif // __ENCODER_H__
29
-

+ 1
- 0
include/lcd.h Dosyayı Görüntüle

@@ -23,5 +23,6 @@
23 23
 #define LCD_HEIGHT 64
24 24
 
25 25
 void lcd_init(void);
26
+void lcd_draw(const char *mode, const char *val, const char *bat);
26 27
 
27 28
 #endif // __LCD_H__

+ 12
- 0
include/sequence.h Dosyayı Görüntüle

@@ -36,11 +36,23 @@ enum channels {
36 36
 
37 37
 #define CH_GPIO_TIMINGS { 42, 42, 42 } // in milliseconds
38 38
 
39
+#define MAX_BEATS 32
40
+#define MAX_BANKS (MAX_BEATS / NUM_BTNS)
41
+
39 42
 void sequence_init(void);
43
+
40 44
 void sequence_set_bpm(uint32_t new_bpm);
45
+uint32_t sequence_get_bpm(void);
46
+
41 47
 void sequence_set_beats(uint32_t new_beats);
48
+uint32_t sequence_get_beats(void);
49
+
50
+void sequence_set_bank(uint32_t new_bank);
51
+uint32_t sequence_get_bank(void);
52
+
42 53
 void sequence_handle_button_loopstation(enum buttons btn, bool rec);
43 54
 void sequence_handle_button_drummachine(enum buttons btn);
55
+
44 56
 void sequence_run(void);
45 57
 
46 58
 #endif // __SEQUENCE_H__

+ 1
- 0
include/ui.h Dosyayı Görüntüle

@@ -39,5 +39,6 @@ enum machine_modes {
39 39
 
40 40
 void ui_init(void);
41 41
 void ui_encoder(int32_t val);
42
+void ui_run(void);
42 43
 
43 44
 #endif // __UI_H__

+ 47
- 0
src/adc.c Dosyayı Görüntüle

@@ -0,0 +1,47 @@
1
+/*
2
+ * adc.c
3
+ *
4
+ * Copyright (c) 2024 Thomas Buck (thomas@xythobuz.de)
5
+ *
6
+ * This program is free software: you can redistribute it and/or modify
7
+ * it under the terms of the GNU General Public License as published by
8
+ * the Free Software Foundation, either version 3 of the License, or
9
+ * (at your option) any later version.
10
+ *
11
+ * This program is distributed in the hope that it will be useful,
12
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
+ * GNU General Public License for more details.
15
+ *
16
+ * See <http://www.gnu.org/licenses/>.
17
+ */
18
+
19
+#include <stdio.h>
20
+#include "pico/stdlib.h"
21
+#include "hardware/adc.h"
22
+
23
+#include "adc.h"
24
+
25
+#define ADC_NUM 2
26
+#define ADC_PIN (26 + ADC_NUM)
27
+
28
+#define ADC_VREF 3.3
29
+#define ADC_RANGE (1 << 12)
30
+#define ADC_CONVERT (ADC_VREF / (ADC_RANGE - 1))
31
+
32
+#define BAT_R1 10000.0f
33
+#define BAT_R2 18000.0f
34
+
35
+void bat_init(void) {
36
+    adc_init();
37
+    adc_gpio_init( ADC_PIN);
38
+    adc_select_input( ADC_NUM);
39
+}
40
+
41
+float bat_get(void) {
42
+    float v_adc = adc_read() * ADC_CONVERT;
43
+
44
+    // Vadc = Vbat * R2 / (R1 + R2)
45
+    float v_bat = v_adc / (BAT_R2 / (BAT_R1 + BAT_R2));
46
+    return v_bat;
47
+}

+ 4
- 1
src/encoder.c Dosyayı Görüntüle

@@ -22,7 +22,7 @@
22 22
 #define FOUR0 2 // 4 steps, Latch at position 0 (reverse wirings)
23 23
 #define TWO03 3 // 2 steps, Latch at position 0 and 3
24 24
 
25
-#define ENCODER_MODE TWO03
25
+#define ENCODER_MODE FOUR3
26 26
 
27 27
 static const uint gpio_num[2] = {
28 28
     17, 18
@@ -70,6 +70,7 @@ void encoder_run(void) {
70 70
             if (thisState == LATCH3) {
71 71
                 // The hardware has 4 steps with a latch on the input state 3
72 72
                 positionExt = position >> 2;
73
+                positionExt = -positionExt;
73 74
             }
74 75
             break;
75 76
 
@@ -77,6 +78,7 @@ void encoder_run(void) {
77 78
             if (thisState == LATCH0) {
78 79
                 // The hardware has 4 steps with a latch on the input state 0
79 80
                 positionExt = position >> 2;
81
+                positionExt = -positionExt;
80 82
             }
81 83
             break;
82 84
 
@@ -84,6 +86,7 @@ void encoder_run(void) {
84 86
             if ((thisState == LATCH0) || (thisState == LATCH3)) {
85 87
                 // The hardware has 2 steps with a latch on the input state 0 and 3
86 88
                 positionExt = position >> 1;
89
+                positionExt = -positionExt;
87 90
             }
88 91
             break;
89 92
         }

+ 10
- 0
src/lcd.c Dosyayı Görüntüle

@@ -40,4 +40,14 @@ void lcd_init(void) {
40 40
 
41 41
     disp.external_vcc = false;
42 42
     ssd1306_init(&disp, LCD_WIDTH, LCD_HEIGHT, LCD_ADDR, LCD_I2C);
43
+    ssd1306_clear(&disp);
44
+}
45
+
46
+void lcd_draw(const char *mode, const char *val, const char *bat) {
47
+    ssd1306_clear(&disp);
48
+    ssd1306_draw_string(&disp, 0, 0, 2, mode);
49
+    ssd1306_draw_string(&disp, 0, 20, 4, val);
50
+    ssd1306_draw_string(&disp, 0, LCD_HEIGHT - 1 - 10, 1, bat);
51
+
52
+    ssd1306_show(&disp);
43 53
 }

+ 3
- 0
src/main.c Dosyayı Görüntüle

@@ -20,6 +20,7 @@
20 20
 #include "pico/stdlib.h"
21 21
 #include "hardware/watchdog.h"
22 22
 
23
+#include "adc.h"
23 24
 #include "buttons.h"
24 25
 #include "encoder.h"
25 26
 #include "lcd.h"
@@ -34,6 +35,7 @@
34 35
 int main(void) {
35 36
     watchdog_enable(WATCHDOG_PERIOD_MS, 1);
36 37
     stdio_init_all();
38
+    bat_init();
37 39
     buttons_init();
38 40
     encoder_init();
39 41
     lcd_init();
@@ -50,6 +52,7 @@ int main(void) {
50 52
         encoder_run();
51 53
         sequence_run();
52 54
         pulse_run();
55
+        ui_run();
53 56
 
54 57
         int32_t epos = encoder_pos();
55 58
         if (epos != last_epos) {

+ 26
- 1
src/sequence.c Dosyayı Görüntüle

@@ -23,13 +23,13 @@
23 23
 #include "pulse.h"
24 24
 #include "sequence.h"
25 25
 
26
-#define MAX_BEATS 32
27 26
 static const uint32_t channel_times[NUM_CHANNELS] = CH_GPIO_TIMINGS;
28 27
 
29 28
 static uint32_t ms_per_beat = 500;
30 29
 static uint32_t beats = 16;
31 30
 static uint32_t last_t = 0;
32 31
 static uint32_t last_i = 0;
32
+static uint32_t bank = 0;
33 33
 
34 34
 static enum channels sequence[MAX_BEATS] = {0};
35 35
 
@@ -46,8 +46,30 @@ void sequence_set_bpm(uint32_t new_bpm) {
46 46
     ms_per_beat = 60000 / new_bpm;
47 47
 }
48 48
 
49
+uint32_t sequence_get_bpm(void) {
50
+    return 60000 / ms_per_beat;
51
+}
52
+
49 53
 void sequence_set_beats(uint32_t new_beats) {
50 54
     beats = (new_beats <= MAX_BEATS) ? new_beats : MAX_BEATS;
55
+
56
+    uint32_t max_banks_currently = (beats + (NUM_BTNS - 1)) / NUM_BTNS;
57
+    bank = (bank < max_banks_currently) ? bank : max_banks_currently;
58
+}
59
+
60
+uint32_t sequence_get_beats(void) {
61
+    return beats;
62
+}
63
+
64
+void sequence_set_bank(uint32_t new_bank) {
65
+    uint32_t b = (new_bank < MAX_BANKS) ? new_bank : MAX_BANKS;
66
+
67
+    uint32_t max_banks_currently = (beats + (NUM_BTNS - 1)) / NUM_BTNS;
68
+    bank = (b < max_banks_currently) ? b : max_banks_currently;
69
+}
70
+
71
+uint32_t sequence_get_bank(void) {
72
+    return bank;
51 73
 }
52 74
 
53 75
 static void sequence_set(uint32_t beat, enum channels ch, bool value) {
@@ -123,18 +145,21 @@ void sequence_handle_button_drummachine(enum buttons btn) {
123 145
 
124 146
     switch (btn) {
125 147
         case BTN_A: {
148
+            // TODO kick is wrong here
126 149
             bool val = !sequence_get(beat, CH_KICK);
127 150
             sequence_set(beat, CH_KICK, val);
128 151
             break;
129 152
         }
130 153
 
131 154
         case BTN_B: {
155
+            // TODO snare is wrong here
132 156
             bool val = !sequence_get(beat, CH_SNARE);
133 157
             sequence_set(beat, CH_SNARE, val);
134 158
             break;
135 159
         }
136 160
 
137 161
         case BTN_C: {
162
+            // TODO hihat is wrong here
138 163
             bool val = !sequence_get(beat, CH_HIHAT);
139 164
             sequence_set(beat, CH_HIHAT, val);
140 165
             break;

+ 58
- 12
src/ui.c Dosyayı Görüntüle

@@ -17,35 +17,66 @@
17 17
  */
18 18
 
19 19
 #include <stdio.h>
20
+#include <inttypes.h>
20 21
 #include "pico/stdlib.h"
21 22
 
23
+#include "adc.h"
22 24
 #include "buttons.h"
25
+#include "lcd.h"
23 26
 #include "sequence.h"
24 27
 #include "ui.h"
25 28
 
29
+#define REDRAW_MS 2000
30
+
26 31
 static bool rec_held_down = false;
27 32
 static enum ui_modes ui_mode = 0;
28 33
 static enum machine_modes machine_mode = 0;
34
+static uint32_t last_redraw = 0;
29 35
 
30 36
 static void ui_redraw(void) {
37
+    char mode[64] = {0};
38
+    char val[64] = {0};
39
+    char bat[64] = {0};
40
+
31 41
     switch (ui_mode) {
32 42
         case UI_BPM: {
33
-            // TODO
43
+            snprintf(mode, sizeof(mode) - 1, "BPM:");
44
+            snprintf(val, sizeof(val) - 1, "%"PRIu32, sequence_get_bpm());
34 45
             break;
35 46
         }
36 47
 
37 48
         case UI_MODE: {
38
-            // TODO
49
+            snprintf(mode, sizeof(mode) - 1, "Mode:");
50
+            switch (machine_mode) {
51
+                case MODE_LOOPSTATION: {
52
+                    snprintf(val, sizeof(val) - 1, "Loop");
53
+                    break;
54
+                }
55
+
56
+                case MODE_DRUMMACHINE: {
57
+                    snprintf(val, sizeof(val) - 1, "Drum");
58
+                    break;
59
+                }
60
+
61
+                default: {
62
+                    printf("%s: invalid mode: %d\n", __func__, machine_mode);
63
+                    machine_mode = 0;
64
+                    ui_redraw();
65
+                    return;
66
+                }
67
+            }
39 68
             break;
40 69
         }
41 70
 
42 71
         case UI_LENGTH: {
43
-            // TODO
72
+            snprintf(mode, sizeof(mode) - 1, "Length:");
73
+            snprintf(val, sizeof(val) - 1, "%"PRIu32, sequence_get_beats());
44 74
             break;
45 75
         }
46 76
 
47 77
         case UI_BANK: {
48
-            // TODO
78
+            snprintf(mode, sizeof(mode) - 1, "Bank:");
79
+            snprintf(val, sizeof(val) - 1, "%"PRIu32, sequence_get_bank());
49 80
             break;
50 81
         }
51 82
 
@@ -53,9 +84,12 @@ static void ui_redraw(void) {
53 84
             printf("%s: invalid mode: %d\n", __func__, ui_mode);
54 85
             ui_mode = 0;
55 86
             ui_redraw();
56
-            break;
87
+            return;
57 88
         }
58 89
     }
90
+
91
+    snprintf(bat, sizeof(bat) - 1, "Bat: %.2fV", bat_get());
92
+    lcd_draw(mode, val, bat);
59 93
 }
60 94
 
61 95
 static void ui_buttons_loopstation(enum buttons btn, bool val) {
@@ -103,8 +137,10 @@ static void ui_buttons_drummachine(enum buttons btn, bool val) {
103 137
 static void ui_buttons(enum buttons btn, bool val) {
104 138
     switch (btn) {
105 139
         case BTN_CLICK: {
106
-            ui_mode = (ui_mode + 1) % UI_NUM_MODES;
107
-            ui_redraw();
140
+            if (val) {
141
+                ui_mode = (ui_mode + 1) % UI_NUM_MODES;
142
+                ui_redraw();
143
+            }
108 144
             break;
109 145
         }
110 146
 
@@ -139,22 +175,22 @@ void ui_encoder(int32_t val) {
139 175
 
140 176
     switch (ui_mode) {
141 177
         case UI_BPM: {
142
-            // TODO
178
+            sequence_set_bpm(sequence_get_bpm() + val);
143 179
             break;
144 180
         }
145 181
 
146 182
         case UI_MODE: {
147
-            // TODO
183
+            machine_mode = (machine_mode + val) % MACHINE_NUM_MODES;
148 184
             break;
149 185
         }
150 186
 
151 187
         case UI_LENGTH: {
152
-            // TODO
188
+            sequence_set_beats(sequence_get_beats() + val);
153 189
             break;
154 190
         }
155 191
 
156 192
         case UI_BANK: {
157
-            // TODO
193
+            sequence_set_bank(sequence_get_bank() + val);
158 194
             break;
159 195
         }
160 196
 
@@ -162,12 +198,22 @@ void ui_encoder(int32_t val) {
162 198
             printf("%s: invalid mode: %d\n", __func__, ui_mode);
163 199
             ui_mode = 0;
164 200
             ui_encoder(val);
165
-            break;
201
+            return;
166 202
         }
167 203
     }
204
+
205
+    ui_redraw();
168 206
 }
169 207
 
170 208
 void ui_init(void) {
171 209
     buttons_callback(ui_buttons);
172 210
     ui_redraw();
173 211
 }
212
+
213
+void ui_run(void) {
214
+    uint32_t now = to_ms_since_boot(get_absolute_time());
215
+    if (now >= (last_redraw + REDRAW_MS)) {
216
+        ui_redraw();
217
+        last_redraw = now;
218
+    }
219
+}

Loading…
İptal
Kaydet