aboutsummaryrefslogtreecommitdiff
path: root/keyboards/lily58/keymaps
diff options
context:
space:
mode:
authordruotoni <89318351+druotoni@users.noreply.github.com>2022-01-13 20:00:35 +0100
committerGitHub <noreply@github.com>2022-01-13 11:00:35 -0800
commitb3c0548ed3cdb31c47d1a9e06c446c0804d6e1b6 (patch)
tree87ba1062ffd5d3c77e7ea95fe537d32c3337da94 /keyboards/lily58/keymaps
parent8a6da095d22d66c0ba36ce8731c9d821ca4262e9 (diff)
downloadqmk_firmware-b3c0548ed3cdb31c47d1a9e06c446c0804d6e1b6.tar.gz
qmk_firmware-b3c0548ed3cdb31c47d1a9e06c446c0804d6e1b6.zip
[Keymap] Lily58 : HELL0 NAVI. Interface (#15469)
Co-authored-by: Drashna Jaelre <drashna@live.com> Co-authored-by: Joel Challis <git@zvecr.com>
Diffstat (limited to 'keyboards/lily58/keymaps')
-rw-r--r--keyboards/lily58/keymaps/druotoni/boot.c309
-rw-r--r--keyboards/lily58/keymaps/druotoni/boot.h9
-rw-r--r--keyboards/lily58/keymaps/druotoni/burst.c252
-rw-r--r--keyboards/lily58/keymaps/druotoni/burst.h24
-rw-r--r--keyboards/lily58/keymaps/druotoni/config.h55
-rw-r--r--keyboards/lily58/keymaps/druotoni/draw_helper.c768
-rw-r--r--keyboards/lily58/keymaps/druotoni/draw_helper.h47
-rw-r--r--keyboards/lily58/keymaps/druotoni/fast_random.c17
-rw-r--r--keyboards/lily58/keymaps/druotoni/fast_random.h7
-rw-r--r--keyboards/lily58/keymaps/druotoni/gui_state.c71
-rw-r--r--keyboards/lily58/keymaps/druotoni/gui_state.h18
-rw-r--r--keyboards/lily58/keymaps/druotoni/keymap.c253
-rw-r--r--keyboards/lily58/keymaps/druotoni/layer_frame.c105
-rw-r--r--keyboards/lily58/keymaps/druotoni/layer_frame.h15
-rw-r--r--keyboards/lily58/keymaps/druotoni/navi_font.c139
-rw-r--r--keyboards/lily58/keymaps/druotoni/navi_logo.c117
-rw-r--r--keyboards/lily58/keymaps/druotoni/navi_logo.h7
-rw-r--r--keyboards/lily58/keymaps/druotoni/readme.md133
-rw-r--r--keyboards/lily58/keymaps/druotoni/ring.c494
-rw-r--r--keyboards/lily58/keymaps/druotoni/ring.h11
-rw-r--r--keyboards/lily58/keymaps/druotoni/rules.mk28
21 files changed, 2879 insertions, 0 deletions
diff --git a/keyboards/lily58/keymaps/druotoni/boot.c b/keyboards/lily58/keymaps/druotoni/boot.c
new file mode 100644
index 000000000..ba46f8e36
--- /dev/null
+++ b/keyboards/lily58/keymaps/druotoni/boot.c
@@ -0,0 +1,309 @@
1// Copyright 2021 Nicolas Druoton (druotoni)
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include QMK_KEYBOARD_H
5
6#include "boot.h"
7#include "fast_random.h"
8#include "draw_helper.h"
9#include "gui_state.h"
10
11// boot
12#define ANIM_BOOT_FRAME_DURATION 8
13uint16_t anim_boot_timer = 0;
14uint8_t anim_boot_current_frame = 0;
15
16#define NAVI_DURATION 55
17
18// terminal stuff
19#define TERMINAL_DURATION 25
20#define TERMINAL_LINE_NUMBER 19
21#define TERMINAL_LINE_MAX 14
22
23#define LILY_DURATION 50
24
25// halt
26#define ANIM_HALT_FRAME_DURATION 55
27uint16_t anim_halt_timer = 0;
28
29void reset_boot(void) {
30 // frame zero
31 anim_boot_current_frame = 0;
32}
33
34static void draw_lily_key(uint8_t x, uint8_t y, uint8_t *key_number, unsigned long key_state, uint8_t color) {
35 uint8_t v = *key_number;
36 unsigned long mask = 1;
37 mask = mask << v;
38
39 // ligth the key according to the mask
40 if (((key_state & mask) == mask)) {
41 color = !color;
42 }
43
44 draw_rectangle_fill(x, y, 3, 3, color);
45 *key_number = v + 1;
46}
47
48static void draw_lily_key_row(uint8_t x, uint8_t y, int w, uint8_t *key_number, unsigned long key_state, uint8_t color) {
49 // row of rectangle
50 for (uint8_t i = 0; i < w; i++) {
51 draw_lily_key(x + (i * 4), y, key_number, key_state, color);
52 }
53}
54
55static void draw_lily_render(unsigned long key_state) {
56 // different orientation base on side
57#if IS_LEFT
58
59 uint8_t x = 0;
60 uint8_t y = 56;
61 uint8_t x_ref = 10 + x;
62 uint8_t y_ref = 2 + y;
63 uint8_t i_key_number = 0;
64
65 for (uint8_t i = 0; i < 4; i++) {
66 draw_lily_key_row(x_ref, y_ref + (i * 4), 4, &i_key_number, key_state, true);
67 draw_lily_key_row(x_ref - 8, y_ref + 2 + (i * 4), 2, &i_key_number, key_state, true);
68 }
69
70 draw_lily_key_row(x_ref + 2, y_ref + (4 * 4), 3, &i_key_number, key_state, true);
71
72 uint8_t x_side = x_ref + (4 * 4);
73
74 draw_lily_key(x_side, y_ref + (2 * 4) + 2, &i_key_number, key_state, true);
75 draw_lily_key(x_side, y_ref + (4 * 4), &i_key_number, key_state, true);
76
77 // screen
78 draw_rectangle(x_side, y_ref, 4, 8, true);
79
80 // frame
81 drawline_hr(x + 1, y + 2, 8, true);
82 oled_write_pixel(x + 8, y + 1, true);
83 drawline_hr(x + 8, y, 23, true);
84
85 drawline_hr(x + 1, y + 20, 10, true);
86 oled_write_pixel(x + 10, y + 21, true);
87 drawline_hr(x + 10, y + 22, 16, true);
88
89 drawline_vb(x, y + 3, 17, true);
90 drawline_vb(x + 31, y + 1, 20, true);
91 oled_write_pixel(x + 30, y + 21, true);
92 oled_write_pixel(x + 29, y + 22, true);
93 oled_write_pixel(x + 28, y + 23, true);
94 oled_write_pixel(x + 27, y + 24, true);
95 oled_write_pixel(x + 26, y + 23, true);
96#endif
97
98#if IS_RIGHT
99 uint8_t i_key_number = 0;
100
101 for (uint8_t i = 0; i < 4; i++) {
102 draw_lily_key_row(7, 58 + (i * 4), 4, &i_key_number, key_state, true);
103 draw_lily_key_row(23, 60 + (i * 4), 2, &i_key_number, key_state, true);
104 }
105
106 draw_lily_key_row(9, 74, 3, &i_key_number, key_state, true);
107
108 draw_lily_key(3, 68, &i_key_number, key_state, true);
109 draw_lily_key(3, 74, &i_key_number, key_state, true);
110
111 // screen
112 draw_rectangle(2, 58, 4, 8, true);
113
114 // frame
115 drawline_hr(23, 58, 8, true);
116 oled_write_pixel(23, 57, true);
117 drawline_hr(1, 56, 23, true);
118
119 drawline_hr(21, 76, 10, true);
120 oled_write_pixel(21, 77, true);
121 drawline_hr(6, 78, 16, true);
122
123 drawline_vb(31, 59, 17, true);
124 drawline_vb(0, 57, 20, true);
125 oled_write_pixel(1, 77, true);
126 oled_write_pixel(2, 78, true);
127 oled_write_pixel(3, 79, true);
128 oled_write_pixel(4, 80, true);
129 oled_write_pixel(5, 79, true);
130#endif
131}
132
133static void draw_lily(uint8_t f) {
134 // frame for the events
135 uint8_t tres_stroke = 10;
136 uint8_t tres_boom = 30;
137 uint8_t y_start = 56;
138
139 if (f == 0 || f == tres_stroke || f == tres_boom) {
140 // clean screen
141 oled_clear();
142 }
143
144 // simple lily58 with all the keys
145 if (f < tres_stroke) {
146 draw_lily_render(0);
147 }
148
149 // increase number of random keys pressed
150 if (f >= tres_stroke && f < tres_boom) {
151 int inter_f = interpo_pourcent(tres_stroke, tres_boom, f);
152
153 unsigned long key_state = fastrand_long();
154 for (int r = 100 - inter_f; r > 0; r = r - 10) {
155 key_state &= fastrand_long();
156 }
157 draw_lily_render(key_state);
158 }
159
160 // statir explosion
161 if (f >= tres_boom) {
162 oled_clear();
163 uint8_t density = (f - tres_boom);
164 if (density > 4) density = 4;
165 draw_static(0, y_start - 8, 32, 32, true, density);
166 }
167}
168
169static void draw_startup_navi(uint8_t f) {
170 // text
171 oled_write_cursor(0, 5, "HELL0", false);
172 oled_write_cursor(0, 7, "NAVI.", false);
173
174 // prompt
175 if ((f % 8) > 4) {
176 oled_write_cursor(0, 12, "> ", false);
177 } else {
178 oled_write_cursor(0, 12, ">_", false);
179 }
180
181 // frame threshold
182 uint8_t tres_shell = 15;
183 uint8_t tres_load = 35;
184
185 // rand text to init display
186 if (f > tres_shell) {
187 int inter_f = interpo_pourcent(tres_shell, tres_load, f);
188
189 draw_random_char(1, 12, 'i', 60 + inter_f, 0);
190 draw_random_char(2, 12, 'n', 20 + inter_f, 0);
191 draw_random_char(3, 12, 'i', inter_f, 0);
192 draw_random_char(4, 12, 't', 20 + inter_f, 0);
193 }
194
195 // loading propress bar
196 if (f > tres_load) {
197 int inter_f = interpo_pourcent(tres_load, 50, f);
198
199 // ease
200 float fv = inter_f / 100.00;
201 fv = fv * fv * fv * fv;
202 inter_f = fv * 100;
203
204 draw_rectangle(0, (15 * 8), 32, 8, 1);
205 draw_progress(0 + 3, (15 * 8) + 3, 26, 2, inter_f, 0, 1);
206 }
207}
208
209// text dispayed on terminal
210static char *boot_ref[TERMINAL_LINE_NUMBER] = {"LT:", "RT:", "M :", " ", "cnx:", "A0:", "B0:", " ", "0x40", "0x60", "0x85", "0x0F", " ", "> run", "x ", "y ", " 100%", " ", "> key"};
211
212// prompt style for char in the font
213char scan_font[5] = {'>', 1, 1, 1, 1};
214
215static char *get_terminal_line(uint8_t i) {
216 // display text
217 if (i < TERMINAL_LINE_NUMBER) {
218 return boot_ref[i];
219 }
220
221 // blank line every 3 lines
222 if (i % 3 == 0) {
223 return " ";
224 }
225
226 // display consecutive chars in the font
227 i = (i - TERMINAL_LINE_NUMBER) * 4;
228
229 scan_font[1] = i;
230 scan_font[2] = i + 1;
231 scan_font[3] = i + 2;
232 scan_font[4] = i + 3;
233
234 return scan_font;
235}
236
237static void draw_startup_terminal(uint8_t f) {
238 // ease for printing on screen
239 f = f * 2;
240 f += (f / 5);
241
242 // scroll text
243 uint8_t i_start = 0;
244 uint8_t i_nb_char = f;
245
246 if (f > TERMINAL_LINE_MAX) {
247 i_start = f - TERMINAL_LINE_MAX;
248 i_nb_char = TERMINAL_LINE_MAX;
249 }
250
251 // display lines
252 oled_clear();
253 for (uint8_t i = 0; i < i_nb_char; i++) {
254 char *s = get_terminal_line(i + i_start);
255 oled_write_cursor(0, i, s, false);
256 }
257}
258
259bool render_boot(void) {
260 // end of the boot sequence
261 if (anim_boot_current_frame >= NAVI_DURATION + TERMINAL_DURATION + LILY_DURATION) {
262 anim_boot_current_frame = 0;
263 oled_clear();
264 return true;
265 }
266
267 if (timer_elapsed(anim_boot_timer) > ANIM_BOOT_FRAME_DURATION) {
268 anim_boot_timer = timer_read();
269 if (anim_boot_current_frame < NAVI_DURATION) {
270 // 55 frames
271 draw_startup_navi(anim_boot_current_frame);
272 } else {
273 if (anim_boot_current_frame >= NAVI_DURATION && anim_boot_current_frame < NAVI_DURATION + TERMINAL_DURATION) {
274 // 25
275 draw_startup_terminal(anim_boot_current_frame - NAVI_DURATION);
276 } else {
277 if (anim_boot_current_frame >= NAVI_DURATION + TERMINAL_DURATION) {
278 // 25
279 draw_lily(anim_boot_current_frame - NAVI_DURATION - TERMINAL_DURATION);
280 }
281 }
282 }
283
284 anim_boot_current_frame++;
285 }
286 return false;
287}
288
289void render_halt(void) {
290 if (timer_elapsed(anim_halt_timer) > ANIM_HALT_FRAME_DURATION) {
291 anim_halt_timer = timer_read();
292
293 // comb glitch for all the screen
294 draw_glitch_comb(0, 0, 32, 128, 3, true);
295
296 // random moving blocks of pixels
297 for (uint8_t i = 0; i < 6; i++) {
298 int r = fastrand();
299 int rr = fastrand();
300 uint8_t x = 4 + r % 28;
301 uint8_t y = rr % 128;
302
303 uint8_t w = 7 + r % 20;
304 uint8_t h = 3 + rr % 10;
305 int s = (fastrand() % 20) - 10;
306 move_block(x, y, w, h, s);
307 }
308 }
309}
diff --git a/keyboards/lily58/keymaps/druotoni/boot.h b/keyboards/lily58/keymaps/druotoni/boot.h
new file mode 100644
index 000000000..7897e1792
--- /dev/null
+++ b/keyboards/lily58/keymaps/druotoni/boot.h
@@ -0,0 +1,9 @@
1// Copyright 2021 Nicolas Druoton (druotoni)
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6bool render_boot(void);
7void render_halt(void);
8
9void reset_boot(void); \ No newline at end of file
diff --git a/keyboards/lily58/keymaps/druotoni/burst.c b/keyboards/lily58/keymaps/druotoni/burst.c
new file mode 100644
index 000000000..6dd6579e7
--- /dev/null
+++ b/keyboards/lily58/keymaps/druotoni/burst.c
@@ -0,0 +1,252 @@
1// Copyright 2021 Nicolas Druoton (druotoni)
2// Copyright 2020 Richard Sutherland (rich@brickbots.com)
3// SPDX-License-Identifier: GPL-2.0-or-later
4
5#include QMK_KEYBOARD_H
6
7#include "gui_state.h"
8#include "fast_random.h"
9#include "burst.h"
10#include "draw_helper.h"
11
12// burst stuff
13static int current_burst = 0;
14static uint16_t burst_timer = 0;
15
16// WPM stuff
17static int current_wpm = 0;
18static uint16_t wpm_timer = 0;
19
20// This smoothing is 40 keystrokes
21static const float wpm_smoothing = WPM_SMOOTHING;
22
23// store values
24uint8_t burst_scope[SIZE_SCOPE] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
25uint8_t wpm_scope[SIZE_SCOPE] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
26
27// current max wpm
28int max_wpm = MAX_WPM_INIT;
29
30// scope animation stuff
31#define ANIM_SCOPE_FRAME_DURATION 40
32#define ANIM_SLEEP_SCOPE_FRAME_NUMBER 10
33
34uint16_t anim_scope_timer = 0;
35uint16_t anim_scope_idle_timer = 0;
36uint16_t anim_sleep_scope_timer = 0;
37
38uint8_t anim_sleep_scope_duration[ANIM_SLEEP_SCOPE_FRAME_NUMBER] = {30, 30, 30, 30, 20, 20, 30, 30, 32, 35};
39uint8_t current_sleep_scope_frame = 0;
40uint8_t sleep_scope_frame_destination = ANIM_SLEEP_SCOPE_FRAME_NUMBER - 1;
41
42// glitch animation
43int current_glitch_scope_time = 150;
44uint32_t glitch_scope_timer = 0;
45uint8_t current_glitch_scope_index = 0;
46
47static void update_wpm(void) {
48 if (wpm_timer > 0) {
49 current_wpm += ((60000 / timer_elapsed(wpm_timer) / WPM_ESTIMATED_WORD_SIZE) - current_wpm) * wpm_smoothing;
50 if (current_wpm > LIMIT_MAX_WPM) {
51 current_wpm = LIMIT_MAX_WPM;
52 }
53 }
54 wpm_timer = timer_read();
55}
56
57void update_scope(void) {
58 update_wpm();
59
60 uint16_t temps_ecoule = timer_elapsed(burst_timer);
61
62 if (temps_ecoule > BURST_FENETRE) {
63 // 1er frappe après longtemps
64 current_burst = 40;
65 } else {
66 int time_pourcent = ((100 * (temps_ecoule)) / (BURST_FENETRE));
67 current_burst = 100 - time_pourcent;
68 }
69 burst_timer = timer_read();
70}
71
72static void update_scope_array(void) {
73 // shift array
74 for (uint8_t i = 0; i < SIZE_SCOPE - 1; i++) {
75 burst_scope[i] = burst_scope[i + 1];
76 wpm_scope[i] = wpm_scope[i + 1];
77 }
78
79 int burst = current_burst;
80 int wpm = current_wpm;
81
82 // compute max wpm
83 max_wpm = (wpm == 0) ? MAX_WPM_INIT : ((wpm > max_wpm) ? wpm : max_wpm);
84
85 // current wpm ratio VS max
86 wpm = (100 * wpm) / max_wpm;
87 if (wpm > 100) wpm = 100;
88
89 // update last slot of the arrays
90 burst_scope[SIZE_SCOPE - 1] = burst;
91 wpm_scope[SIZE_SCOPE - 1] = wpm;
92
93 // apply decay to burst chart
94 uint8_t pBaisse = 0;
95 for (uint8_t i = 0; i < SIZE_SCOPE - (SIZE_SCOPE / 4); i++) {
96 pBaisse = 2 + ((SIZE_SCOPE - 1 - i)) / 2;
97 burst_scope[i] -= ((burst_scope[i] * pBaisse) / 100);
98 }
99}
100
101static void RenderScopeBlack(void) {
102 // clean central zone
103 draw_rectangle_fill(3, 82, 28, 120, false);
104
105 // redraw some parts of the frame
106 drawline_hr(1, SCOPE_Y_BOTTOM, 32, 1);
107 drawline_vt(0, SCOPE_Y_BOTTOM - 1, 42, 1);
108 drawline_vt(31, SCOPE_Y_BOTTOM - 1, 47, 1);
109}
110
111static void render_scope_white(void) {
112 static const char PROGMEM raw_logo[] = {
113 240, 8, 4, 226, 241, 248, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 0, 0, 255, 255, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 255, 127, 128, 128, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 128, 128, 127,
114 };
115 oled_write_raw_P_cursor(0, 10, raw_logo, sizeof(raw_logo));
116}
117
118static void render_scope_chart(void) {
119 // clean the frame
120 render_scope_white();
121
122 uint8_t y_offset = SCOPE_Y_BOTTOM - 3;
123
124 for (uint8_t i = 0; i < SIZE_SCOPE; i++) {
125 // offset
126 uint8_t x = 3 + i;
127
128 // new black vertical line for burst
129 uint8_t iCurrentBurst = burst_scope[i];
130 drawline_vt(x, y_offset, (iCurrentBurst * 4) / 10, 0);
131
132 // new black point for wpm, white if it's on the burst line
133 uint8_t iCurrentWpm = wpm_scope[i];
134 uint8_t yWpm = y_offset - ((iCurrentWpm * 4) / 10);
135 oled_write_pixel(x, yWpm, !(iCurrentWpm > iCurrentBurst));
136 }
137}
138
139void reset_scope(void) {
140 // scope need wakeup
141 anim_sleep_scope_timer = timer_read();
142 current_sleep_scope_frame = ANIM_SLEEP_SCOPE_FRAME_NUMBER - 1;
143
144 sleep_scope_frame_destination = 0;
145}
146
147static void render_glitch_square(void) {
148 if (timer_elapsed(anim_scope_idle_timer) > 60) {
149 anim_scope_idle_timer = timer_read();
150 RenderScopeBlack();
151
152 uint8_t color = 0;
153 uint8_t size = 0;
154 for (uint8_t i = 0; i < 4; i++) {
155 size = 4 + (fastrand() % 6);
156
157 draw_gradient(3 + (fastrand() % 19), 85 + (fastrand() % 20), size, size, 255, 255, 4);
158
159 size = (fastrand() % 6);
160 color = 100 + (fastrand() % 100);
161 draw_gradient(3 + (fastrand() % 19), 100 + (fastrand() % 20), size, size, color, color, 4);
162 }
163 }
164}
165
166void render_scope_idle(void) {
167 uint8_t glitch_prob = get_glitch_probability();
168 get_glitch_index(&glitch_scope_timer, &current_glitch_scope_time, &current_glitch_scope_index, 150, 350, glitch_prob, 2);
169
170 switch (current_glitch_scope_index) {
171 case 0:
172 RenderScopeBlack();
173 return;
174 case 1:
175 render_glitch_square();
176 return;
177 }
178}
179
180static void RenderScopeSleep(void) {
181 if (current_sleep_scope_frame == sleep_scope_frame_destination) {
182 // animation finished
183 render_scope_idle();
184 return;
185 }
186
187 if (timer_elapsed(anim_sleep_scope_timer) > anim_sleep_scope_duration[current_sleep_scope_frame]) {
188 anim_sleep_scope_timer = timer_read();
189
190 // clean scope
191 RenderScopeBlack();
192
193 // render animation
194 render_tv_animation(current_sleep_scope_frame, 3, 80, 25, 48);
195
196 // update frame number
197 if (sleep_scope_frame_destination > current_sleep_scope_frame) {
198 current_sleep_scope_frame++;
199 } else {
200 current_sleep_scope_frame--;
201 }
202 }
203}
204
205void render_scope(gui_state_t t) {
206 if (timer_elapsed(anim_scope_timer) > ANIM_SCOPE_FRAME_DURATION) {
207 anim_scope_timer = timer_read();
208
209 // shift arrays
210 update_scope_array();
211
212 // oled_set_cursor(0, 10);
213
214 if (t == _WAKINGUP) {
215 RenderScopeSleep();
216 return;
217 }
218
219 if (t == _IDLE) {
220 sleep_scope_frame_destination = ANIM_SLEEP_SCOPE_FRAME_NUMBER - 1;
221 RenderScopeSleep();
222 return;
223 }
224
225 render_scope_chart();
226 }
227}
228
229static void decay_burst(void) {
230 uint16_t temps_ecoule = timer_elapsed(burst_timer);
231
232 int poucentageEcoule = 100;
233
234 if (temps_ecoule <= BURST_FENETRE * 4) {
235 poucentageEcoule = ((100 * (temps_ecoule)) / (BURST_FENETRE * 4));
236 }
237
238 current_burst = current_burst - poucentageEcoule;
239 if (current_burst <= 0) current_burst = 0;
240}
241
242static void decay_wpm(void) {
243 if (timer_elapsed(wpm_timer) > 1000) {
244 wpm_timer = timer_read();
245 current_wpm += (-current_wpm) * wpm_smoothing;
246 }
247}
248
249void decay_scope(void) {
250 decay_burst();
251 decay_wpm();
252}
diff --git a/keyboards/lily58/keymaps/druotoni/burst.h b/keyboards/lily58/keymaps/druotoni/burst.h
new file mode 100644
index 000000000..8bc815350
--- /dev/null
+++ b/keyboards/lily58/keymaps/druotoni/burst.h
@@ -0,0 +1,24 @@
1// Copyright 2021 Nicolas Druoton (druotoni)
2// Copyright 2020 Richard Sutherland (rich@brickbots.com)
3// SPDX-License-Identifier: GPL-2.0-or-later
4
5#pragma once
6
7// burst
8#define MAX_WPM_INIT 40
9#define BURST_FENETRE 500
10
11// wpm
12#define LIMIT_MAX_WPM 150
13#define WPM_ESTIMATED_WORD_SIZE 5
14#define WPM_SMOOTHING 0.0487
15
16// scope
17#define SIZE_SCOPE 26
18#define SCOPE_Y_BOTTOM 127
19
20void update_scope(void);
21void render_scope(gui_state_t t);
22
23void reset_scope(void);
24void decay_scope(void);
diff --git a/keyboards/lily58/keymaps/druotoni/config.h b/keyboards/lily58/keymaps/druotoni/config.h
new file mode 100644
index 000000000..37124fcaa
--- /dev/null
+++ b/keyboards/lily58/keymaps/druotoni/config.h
@@ -0,0 +1,55 @@
1// Copyright 2021 Nicolas Druoton (druotoni)
2// Copyright 2012 Jun Wako <wakojun@gmail.com>
3// Copyright 2015 Jack Humbert
4// SPDX-License-Identifier: GPL-2.0-or-later
5
6#pragma once
7
8#define MASTER_LEFT
9#define OLED_DRIVER_ENABLE
10
11// tapping toggle for my layers
12#define TAPPING_TOGGLE 2
13
14// choose IS_LEFT or IS_RIGHT for compilation and flash firmware
15#define IS_LEFT 1
16//#define IS_RIGHT 1
17
18// logo glitch
19#define WITH_GLITCH
20// boot sequence
21#define WITH_BOOT
22
23// custom transport for displaying on both side
24#define SPLIT_TRANSACTION_IDS_USER USER_SYNC_A
25
26// custom font
27#ifdef OLED_FONT_H
28# undef OLED_FONT_H
29#endif
30#define OLED_FONT_H "navi_font.c"
31#undef OLED_FONT_END
32#define OLED_FONT_END 125
33
34// more space
35#define NO_ACTION_MACRO
36#define NO_ACTION_FUNCTION
37#define NO_ACTION_ONESHOT
38#define DISABLE_LEADER
39
40// ???
41#undef LOCKING_SUPPORT_ENABLE
42#undef LOCKING_RESYNC_ENABLE
43
44// small layer state
45#define LAYER_STATE_8BIT
46
47// no debug or trace
48#ifndef NO_DEBUG
49# define NO_DEBUG
50#endif
51#if !defined(NO_PRINT) && !defined(CONSOLE_ENABLE)
52# define NO_PRINT
53#endif
54
55
diff --git a/keyboards/lily58/keymaps/druotoni/draw_helper.c b/keyboards/lily58/keymaps/druotoni/draw_helper.c
new file mode 100644
index 000000000..c6761d725
--- /dev/null
+++ b/keyboards/lily58/keymaps/druotoni/draw_helper.c
@@ -0,0 +1,768 @@
1// Copyright 2021 Nicolas Druoton (druotoni)
2// Copyright 2021 ugfx
3// SPDX-License-Identifier: GPL-2.0-or-later
4
5#include QMK_KEYBOARD_H
6
7#include "draw_helper.h"
8#include "fast_random.h"
9
10void drawline(uint8_t x, uint8_t y, uint8_t width, bool bHorizontal, bool bPositiveDirection, bool color) {
11 if (width <= 0) return;
12 uint8_t yPlus = 0;
13 uint8_t yMois = 0;
14 uint8_t nbtour = 0;
15
16 if (!bPositiveDirection) {
17 if (bHorizontal) {
18 x -= width;
19 } else {
20 y -= width;
21 }
22 }
23
24 yMois = (width / 2) - 1 + (width % 2);
25
26 yPlus = (width / 2);
27 nbtour = (width / 4) + 1;
28
29 bool bWhite = color;
30
31 if (bHorizontal) {
32 for (uint8_t i = 0; i < nbtour; i++) {
33 oled_write_pixel(x + yPlus + i, y, bWhite);
34 oled_write_pixel(x + yMois - i, y, bWhite);
35
36 oled_write_pixel(x + i, y, bWhite);
37 oled_write_pixel(x + width - 1 - i, y, bWhite);
38 }
39 } else {
40 for (uint8_t i = 0; i < nbtour; i++) {
41 oled_write_pixel(x, y + yPlus + i, bWhite);
42 oled_write_pixel(x, y + yMois - i, bWhite);
43
44 oled_write_pixel(x, y + i, bWhite);
45
46 oled_write_pixel(x, y + width - 1 - i, bWhite);
47 }
48 }
49}
50
51void drawline_vb(uint8_t x, uint8_t y, uint8_t width, bool color) { drawline(x, y, width, false, true, color); }
52
53void drawline_vt(uint8_t x, uint8_t y, uint8_t width, bool color) { drawline(x, y, width, false, false, color); }
54
55void drawline_hr(uint8_t x, uint8_t y, uint8_t width, bool color) { drawline(x, y, width, true, true, color); }
56
57void drawline_hl(uint8_t x, uint8_t y, uint8_t width, bool color) { drawline(x, y, width, true, false, color); }
58
59void draw_rectangle(uint8_t x, uint8_t y, uint8_t width, uint8_t heigth, bool color) {
60 drawline_hr(x, y, width, color);
61 drawline_hr(x, y + heigth - 1, width, color);
62 drawline_vb(x, y, heigth, color);
63 drawline_vb(x + width - 1, y, heigth, color);
64}
65
66void draw_rectangle_fill(uint8_t x, uint8_t y, uint8_t width, uint8_t heigth, bool color) {
67 for (uint8_t i = 0; i < heigth; i++) {
68 drawline_hr(x, y + i, width, color);
69 }
70}
71
72void drawline_hr_heigth(uint8_t x, uint8_t y, uint8_t width, uint8_t heigth, bool color) {
73 for (int i = 0; i < heigth; i++) {
74 drawline_hr(x, y - i, width, color);
75 drawline_hr(x, y + i, width, color);
76 }
77}
78
79void drawline_point_hr(short x, short y, short x1, bool color) {
80 if (y < 0 || y > 127) return;
81
82 if (x1 < x) {
83 short iTemp = x;
84 x = x1;
85 x1 = iTemp;
86 }
87
88 if (x1 > 31) x1 = 31;
89 if (x < 0) x = 0;
90 if (x > 31) x = 31;
91
92 drawline(x, y, x1 - x, true, true, color);
93}
94
95void flip_flap_x(short px, short py, uint8_t val, bool color) {
96 oled_write_pixel(px + val, py, color);
97 oled_write_pixel(px - val, py, color);
98}
99
100void draw_circle(uint8_t x, uint8_t y, uint8_t radius, bool color) {
101 short a, b, P;
102
103 // Calculate intermediates
104 a = 1;
105 b = radius;
106 P = 4 - radius;
107
108 short py, px;
109
110 // Away we go using Bresenham's circle algorithm
111 // Optimized to prevent double drawing
112 px = x;
113 py = y + b;
114 oled_write_pixel(px, py, color);
115 px = x;
116 py = y - b;
117 oled_write_pixel(px, py, color);
118
119 flip_flap_x(x, y, b, color);
120
121 do {
122 flip_flap_x(x, y + b, a, color);
123 flip_flap_x(x, y - b, a, color);
124 flip_flap_x(x, y + a, b, color);
125 flip_flap_x(x, y - a, b, color);
126
127 if (P < 0)
128 P += 3 + 2 * a++;
129 else
130 P += 5 + 2 * (a++ - b--);
131 } while (a < b);
132
133 flip_flap_x(x, y + b, a, color);
134 flip_flap_x(x, y - b, a, color);
135}
136
137void draw_ellipse(uint8_t x, uint8_t y, uint8_t a, uint8_t b, bool color) {
138 int dx, dy;
139 int a2, b2;
140 int err, e2;
141
142 // short py, px;
143 // Calculate intermediates
144 dx = 0;
145 dy = b;
146 a2 = a * a;
147 b2 = b * b;
148 err = b2 - (2 * b - 1) * a2;
149
150 // Away we go using Bresenham's ellipse algorithm
151 do {
152 flip_flap_x(x, y + dy, dx, color);
153 flip_flap_x(x, y - dy, dx, color);
154
155 e2 = 2 * err;
156 if (e2 < (2 * dx + 1) * b2) {
157 dx++;
158 err += (2 * dx + 1) * b2;
159 }
160 if (e2 > -(2 * dy - 1) * a2) {
161 dy--;
162 err -= (2 * dy - 1) * a2;
163 }
164 } while (dy >= 0);
165}
166
167void draw_ellipse_fill(uint8_t x, uint8_t y, uint8_t a, uint8_t b, bool color) { return; }
168// void draw_ellipse_fill(uint8_t x, uint8_t y, uint8_t a, uint8_t b, uint8_t color) {
169// int dx, dy;
170// int a2, b2;
171// int err, e2;
172
173// // Calculate intermediates
174// dx = 0;
175// dy = b;
176// a2 = a * a;
177// b2 = b * b;
178// err = b2 - (2 * b - 1) * a2;
179
180// short py, px, px1;
181
182// // Away we go using Bresenham's ellipse algorithm
183// // This is optimized to prevent overdrawing by drawing a line only when a y is about to change value
184// do {
185// e2 = 2 * err;
186// if (e2 < (2 * dx + 1) * b2) {
187// dx++;
188// err += (2 * dx + 1) * b2;
189// }
190// if (e2 > -(2 * dy - 1) * a2) {
191// py = y + dy;
192// px = x - dx;
193// px1 = x + dx;
194// drawline_point_hr(px, py, px1, color);
195// if (y) {
196// py = y - dy;
197// px = x - dx;
198// px1 = x + dx;
199// drawline_point_hr(px, py, px1, color);
200// }
201// dy--;
202// err -= (2 * dy - 1) * a2;
203// }
204// } while (dy >= 0);
205// }
206
207bool test_limit(short x, short y) { return !(y < 0 || y > 127 || x < 0 || x > 31); }
208
209void flip_flap_y_point(short px, short py, short px1, uint8_t val, bool color) {
210 // firmware size optimisation : one fonction for 2 lines of code
211 drawline_point_hr(px, py + val, px1, color);
212 drawline_point_hr(px, py - val, px1, color);
213}
214
215void draw_fill_circle(short x, short y, uint8_t radius, bool color) {
216 short a, b, P;
217
218 // Calculate intermediates
219 a = 1;
220 b = radius;
221 P = 4 - radius;
222
223 // Away we go using Bresenham's circle algorithm
224 // This is optimized to prevent overdrawing by drawing a line only when a variable is about to change value
225 short py, px, px1;
226
227 py = y;
228 px = x - b;
229 px1 = x + b;
230 drawline_point_hr(px, py, px1, color);
231
232 py = y + b;
233 px = x;
234 if (test_limit(px, py)) oled_write_pixel(px, py, color);
235 py = y - b;
236 px = x;
237 if (test_limit(px, py)) oled_write_pixel(px, py, color);
238 do {
239 flip_flap_y_point(x - b, y, x + b, a, color);
240
241 if (P < 0) {
242 P += 3 + 2 * a++;
243 } else {
244 flip_flap_y_point(x - a, y, x + a, b, color);
245
246 P += 5 + 2 * (a++ - b--);
247 }
248 } while (a < b);
249
250 flip_flap_y_point(x - b, y, x + b, a, color);
251}
252
253bool apres_moitie(int a, int b) { return (a > b / 2); }
254bool arrive_moitie(int a, int b) { return (a > b / 2); }
255bool avant_moitie(int a, int b) { return (a <= b / 2 && !apres_moitie(a, b)); }
256
257void draw_arc_sector(uint8_t x, uint8_t y, uint8_t radius, unsigned char sectors, unsigned char half, bool color) {
258 short a, b, P;
259 short py, px;
260 // Calculate intermediates
261 a = 1; // x in many explanations
262 b = radius; // y in many explanations
263 P = 4 - radius;
264
265 if (half != 2) {
266 // Away we go using Bresenham's circle algorithm
267 // Optimized to prevent double drawing
268 if (sectors & 0x06) {
269 px = x;
270 py = y - b;
271 oled_write_pixel(px, py, color);
272 } // Upper upper
273 if (sectors & 0x60) {
274 px = x;
275 py = y + b;
276 oled_write_pixel(px, py, color);
277 } // Lower lower
278 if (sectors & 0x81) {
279 px = x + b;
280 py = y;
281 oled_write_pixel(px, py, color);
282 } // Right right
283 if (sectors & 0x18) {
284 px = x - b;
285 py = y;
286 oled_write_pixel(px, py, color);
287 } // Left left
288 }
289
290 bool dessiner = false;
291
292 do {
293 if (half == 1 && arrive_moitie(a, b)) break;
294
295 if (half == 2 && avant_moitie(a, b)) {
296 dessiner = false;
297 } else {
298 dessiner = true;
299 }
300
301 if (dessiner) {
302 if (sectors & 0x01) {
303 px = x + b;
304 py = y - a;
305 oled_write_pixel(px, py, color);
306 } // Upper right right
307 if (sectors & 0x02) {
308 px = x + a;
309 py = y - b;
310 oled_write_pixel(px, py, color);
311 } // Upper upper right
312 if (sectors & 0x04) {
313 px = x - a;
314 py = y - b;
315 oled_write_pixel(px, py, color);
316 } // Upper upper left
317 if (sectors & 0x08) {
318 px = x - b;
319 py = y - a;
320 oled_write_pixel(px, py, color);
321 } // Upper left left
322 if (sectors & 0x10) {
323 px = x - b;
324 py = y + a;
325 oled_write_pixel(px, py, color);
326 } // Lower left left
327 if (sectors & 0x20) {
328 px = x - a;
329 py = y + b;
330 oled_write_pixel(px, py, color);
331 } // Lower lower left
332 if (sectors & 0x40) {
333 px = x + a;
334 py = y + b;
335 oled_write_pixel(px, py, color);
336 } // Lower lower right
337 if (sectors & 0x80) {
338 px = x + b;
339 py = y + a;
340 oled_write_pixel(px, py, color);
341 } // Lower right right
342 }
343
344 if (P < 0)
345 P += 3 + 2 * a++;
346 else
347 P += 5 + 2 * (a++ - b--);
348 } while (a < b);
349
350 if (half != 1) {
351 if (sectors & 0xC0) {
352 px = x + a;
353 py = y + b;
354 oled_write_pixel(px, py, color);
355 } // Lower right
356 if (sectors & 0x03) {
357 px = x + a;
358 py = y - b;
359 oled_write_pixel(px, py, color);
360 } // Upper right
361 if (sectors & 0x30) {
362 px = x - a;
363 py = y + b;
364 oled_write_pixel(px, py, color);
365 } // Lower left
366 if (sectors & 0x0C) {
367 px = x - a;
368 py = y - b;
369 oled_write_pixel(px, py, color);
370 } // Upper left
371 }
372}
373
374void draw_static(uint8_t x, uint8_t y, uint8_t width, uint8_t heigth, int color, uint8_t density) {
375 unsigned long rx = fastrand_long();
376 unsigned long ry = fastrand_long();
377 unsigned long maskx = 1;
378 unsigned long masky = 1;
379 unsigned long mask_base = 1;
380
381 // more 1 in the octet
382 for (int r = 0; r < density; r++) {
383 rx &= fastrand_long();
384 ry &= fastrand_long();
385 }
386
387 color = ((rx >> 1) % 2) == 0;
388
389 for (uint8_t i = 0; i < width; i++) {
390 for (uint8_t j = 0; j < heigth; j++) {
391 // new mask based on ij loop
392 maskx = (mask_base << i);
393 masky = (mask_base << j);
394
395 // logic AND with the masks
396 if (((rx & maskx) == maskx) && ((ry & masky) == masky)) {
397 oled_write_pixel(x + i, y + j, color);
398 }
399 }
400 }
401}
402
403void copy_pixel(int from, int shift, unsigned char mask) {
404 if (shift == 0) return;
405
406 // pixel cluster from
407 char c_from = get_oled_char(from);
408 char extract = c_from & mask;
409
410 // pixel cluster shift
411 char c_from_shift = get_oled_char(from + shift);
412 c_from_shift &= ~(mask);
413 c_from_shift |= extract;
414 oled_write_raw_byte(c_from_shift, from + shift);
415
416 // fill blank with black
417 c_from &= ~(mask);
418 oled_write_raw_byte(c_from, from);
419}
420
421void draw_glitch_comb(uint8_t x, uint8_t y, uint8_t width, uint16_t height, uint8_t iSize, bool odd) {
422 // work only on row
423 uint16_t y_start = (y / 8) * 32;
424 uint8_t nb_h = height / 8;
425
426 uint8_t w_max = width;
427 uint16_t index = y_start + x;
428
429 // shift pair even pixel
430 int mask_1 = 85;
431 int mask_2 = 170;
432
433 if (!odd) {
434 // shift odd pixel
435 mask_1 = 170;
436 mask_2 = 85;
437 }
438
439 // wobble
440 uint16_t pos = 0;
441 for (uint16_t j = 0; j < nb_h; j++) {
442 // next line
443 index = (y_start + x) + (j * 32);
444
445 for (uint16_t i = 0; i < w_max; i++) {
446 if (i + iSize < w_max) {
447 pos = index + i;
448 copy_pixel(pos + iSize, iSize * -1, mask_1);
449 }
450
451 if (w_max - 1 - i - iSize >= 0) {
452 pos = (index + w_max - 1) - i;
453 copy_pixel(pos - iSize, iSize, mask_2);
454 }
455 }
456 }
457}
458
459void draw_random_char(uint8_t column, uint8_t row, char final_char, int value, uint8_t style) {
460 if (value < 0) return;
461
462 char c = final_char;
463
464 if (value < 100) {
465 c = ((fastrand() % 15) + 1);
466 }
467
468 oled_set_cursor(column, row);
469 oled_write_char(c, false);
470}
471
472void get_glitch_index_new(uint16_t *glitch_timer, uint8_t *current_glitch_scope_time, uint8_t *glitch_index, uint8_t min_time, uint16_t max_time, uint8_t glitch_probobility, uint8_t glitch_frame_number) {
473 if (timer_elapsed(*glitch_timer) > *current_glitch_scope_time) {
474 // end of the last glitch period
475 *glitch_timer = timer_read();
476
477 // new random glich period
478 *current_glitch_scope_time = min_time + fastrand() % (max_time - min_time);
479
480 bool bGenerateGlitch = (fastrand() % 100) < glitch_probobility;
481 if (!bGenerateGlitch) {
482 // no glitch
483 *glitch_index = 0;
484 return;
485 }
486
487 // get a new glitch index
488 *glitch_index = fastrand() % glitch_frame_number;
489 }
490}
491
492uint8_t get_glitch_frame_index(uint8_t glitch_probobility, uint8_t glitch_frame_number) {
493 bool bGenerateGlitch = (fastrand() % 100) < glitch_probobility;
494 if (!bGenerateGlitch) {
495 // no glitch
496 return 0;
497 }
498
499 // get a new glitch index
500 return fastrand() % glitch_frame_number;
501}
502
503uint8_t get_glitch_duration(uint8_t min_time, uint16_t max_time) { return min_time + fastrand() % (max_time - min_time); }
504
505void get_glitch_index(uint32_t *glitch_timer, int *current_glitch_scope_time, uint8_t *glitch_index, uint8_t min_time, uint16_t max_time, uint8_t glitch_probobility, uint8_t glitch_frame_number) {
506 if (timer_elapsed32(*glitch_timer) > *current_glitch_scope_time) {
507 // end of the last glitch period
508 *glitch_timer = timer_read32();
509
510 // new random glich period
511 *current_glitch_scope_time = min_time + fastrand() % (max_time - min_time);
512
513 bool bGenerateGlitch = (fastrand() % 100) < glitch_probobility;
514 if (!bGenerateGlitch) {
515 // no glitch
516 *glitch_index = 0;
517 return;
518 }
519
520 // get a new glitch index
521 *glitch_index = fastrand() % glitch_frame_number;
522 }
523}
524
525void draw_progress(uint8_t x, uint8_t y, uint8_t width, uint8_t heigth, int value, uint8_t style, bool color) {
526 if (value > 100) {
527 value = 100;
528 }
529 int lenght = (width * value) / 100;
530 for (uint8_t i = 0; i < lenght; i++) {
531 switch (style) {
532 case 0:
533 drawline_vb(x + i, y, heigth - 1, color);
534 break;
535
536 // case 1:
537 // drawline_vb(x + i, y + 1, heigth - 3, ((i % 3) < 2));
538 // break;
539 // case 2:
540 // // . . . . .
541 // drawline_vb(x + i, y + 3, 2, ((i % 2) == 0));
542 // break;
543 }
544 }
545}
546
547void oled_write_raw_P_cursor(uint8_t col, uint8_t line, const char *data, uint16_t size) {
548 // raw_P at cursor position
549 oled_set_cursor(col, line);
550 oled_write_raw_P(data, size);
551}
552
553void oled_write_cursor(uint8_t col, uint8_t line, const char *data, bool invert) {
554 // write at cursor position
555 oled_set_cursor(col, line);
556 oled_write(data, invert);
557}
558
559void draw_label(const char *data, uint8_t len, uint8_t row, int value) {
560 if (value < 0) return;
561 if (row >= 16 || row < 0) return;
562 oled_write_cursor(0, row, data, false);
563}
564
565void draw_box(const char *data, uint8_t len, uint8_t row, long value, uint8_t style) {
566 if (value < 0) return;
567 if (row >= 16 || row < 0) return;
568
569 oled_write_cursor(0, row, data, false);
570
571 uint8_t y = row * 8;
572
573 uint8_t x = 6 * len;
574 uint8_t w = 32 - x;
575
576 if (value < 0) value = 0;
577 if (value > 100) value = 100;
578 draw_progress(x, y, w, 7, value, style, 1);
579}
580
581char get_oled_char(uint16_t start_index) {
582 oled_buffer_reader_t reader;
583 reader = oled_read_raw(start_index);
584 return *reader.current_element;
585}
586
587static int get_index_first_block(uint8_t y) { return ((y / 8) * 32); }
588
589void move_block(uint8_t x, uint8_t y, uint8_t width, uint8_t heigth, int shift) {
590 // clip
591 if (x >= 31) return;
592 if (y >= 127) return;
593
594 int max_screen = 32 - 1;
595 if ((width + x) > max_screen + 1) width = max_screen + 1 - x;
596
597 if (width <= 1) return;
598
599 if ((heigth + y) > 127) heigth = 127 - y;
600 if (heigth <= 1) return;
601
602 // [-32 & +32]
603 if (shift > max_screen) shift = max_screen;
604 if (shift < -1 * max_screen) shift = -1 * max_screen;
605
606 if ((width + x + shift) > max_screen) width = width - shift;
607
608 int pixelTop = 8 - (y % 8);
609 int pixelBottom = (y + heigth) % 8;
610
611 unsigned char cMastTop = ~((unsigned)255 >> (pixelTop));
612 unsigned char cMastBottom = ~((unsigned)255 << (pixelBottom));
613
614 int indexFirstBloc = get_index_first_block(y) + x;
615 int indexFirstBlocFull = get_index_first_block(y + pixelTop) + x;
616 int indexFirstBlocEnd = get_index_first_block(y + heigth) + x;
617
618 int nbBlockHeigth = (heigth - pixelTop - pixelBottom) / 8;
619
620 if (nbBlockHeigth < 0) {
621 // just single row
622 nbBlockHeigth = 0;
623 cMastBottom = 0;
624 }
625
626 if (shift < 0) {
627 for (uint16_t i = 0; i < width; i++) {
628 copy_pixel(indexFirstBloc + i, shift, cMastTop);
629 copy_pixel(indexFirstBlocEnd + i, shift, cMastBottom);
630
631 for (uint16_t j = 0; j < nbBlockHeigth; j++) {
632 copy_pixel(indexFirstBlocFull + i + (j * 32), shift, 255);
633 }
634 }
635
636 } else {
637 for (int i = width - 1; i >= 0; i--) {
638 copy_pixel(indexFirstBloc + i, shift, cMastTop);
639 copy_pixel(indexFirstBlocEnd + i, shift, cMastBottom);
640
641 for (uint16_t j = 0; j < nbBlockHeigth; j++) {
642 copy_pixel(indexFirstBlocFull + i + (j * 32), shift, 255);
643 }
644 }
645 }
646}
647
648int interpo_pourcent(int min, int max, int v) {
649 // interpolation
650 float x0 = min;
651 float x1 = max;
652 float y0 = 0;
653 float y1 = 100;
654 float xp = v;
655 float yp = y0 + ((y1 - y0) / (x1 - x0)) * (xp - x0);
656
657 return (int)yp;
658}
659
660uint8_t BAYER_PATTERN_4[4][4] = {{15, 135, 45, 165}, {195, 75, 225, 105}, {60, 180, 30, 150}, {240, 120, 210, 90}};
661
662void draw_gradient(uint8_t x, uint8_t y, uint8_t width, uint8_t heigth, uint8_t color_start, uint8_t color_end, uint8_t tres) {
663 bool invert = color_start > color_end;
664
665 if (invert) {
666 color_start = 255 - color_start;
667 color_end = 255 - color_end;
668 }
669
670 int step = (100 / tres);
671 int step_minus = (100 / (tres - 1));
672 int distance = color_end - color_start;
673
674 for (uint8_t i = 0; i < width; i++) {
675 int position = interpo_pourcent(0, width, i);
676
677 float color = position;
678 color = ((int)(color / step)) * step_minus;
679
680 color = color_start + ((distance * color) / 100);
681
682 for (uint8_t j = 0; j < heigth; j++) {
683 uint8_t m = BAYER_PATTERN_4[i % 4][j % 4];
684 unsigned char color_d = (color > m) ? !invert : invert;
685
686 oled_write_pixel(x + i, y + j, color_d);
687 }
688 }
689}
690
691void render_tv_animation(uint8_t frame_number, uint8_t x, uint8_t y, uint8_t width, uint8_t heigth) {
692 uint8_t xCenter = x + (width / 2);
693 uint8_t yCenter = y + (heigth / 2);
694
695 switch (frame_number) {
696 case 0:
697 // a fond : allume
698 drawline_hr_heigth(x, yCenter, width, 17, true);
699 break;
700
701 case 1:
702 drawline_hr_heigth(x, yCenter, width, 12, true);
703 draw_ellipse_fill(xCenter, yCenter, 7, 15, true);
704 break;
705
706 case 2:
707 drawline_hr_heigth(x, yCenter, width, 5, true);
708 draw_ellipse_fill(xCenter, yCenter, 5, 8, true);
709 break;
710
711 case 3:
712 drawline_hr_heigth(x, yCenter, width, 3, true);
713 draw_ellipse_fill(xCenter, yCenter, 3, 4, true);
714 break;
715
716 case 4:
717 drawline_hr_heigth(x, yCenter, width, 2, true);
718 draw_fill_circle(xCenter, yCenter, 3, true);
719 break;
720
721 case 5:
722 // central line
723 drawline_hr(x, yCenter, width, true);
724 draw_fill_circle(xCenter, yCenter, 2, true);
725 break;
726
727 case 6:
728 // cross
729 drawline_hr(xCenter, yCenter + 1, 2, true);
730 drawline_hr(xCenter, yCenter - 1, 2, true);
731
732 // central line
733 drawline_hr(x, yCenter, width, true);
734 break;
735
736 case 7:
737 // cross
738 drawline_hr(xCenter, yCenter + 1, 2, true);
739 drawline_hr(xCenter, yCenter - 1, 2, true);
740 // central line
741 drawline_hr(xCenter - 8, yCenter, 18, true);
742 // static
743 oled_write_pixel(xCenter - 11, yCenter, true);
744 oled_write_pixel(xCenter + 12, yCenter, true);
745 break;
746
747 case 8:
748 // cross
749 drawline_hr(xCenter, yCenter + 1, 2, true);
750 drawline_hr(xCenter, yCenter - 1, 2, true);
751 // central line
752 drawline_hr(xCenter - 2, yCenter, 4, true);
753 // static
754 drawline_hr(xCenter - 7, yCenter, 2, true);
755 drawline_hr(xCenter + 6, yCenter, 3, true);
756
757 // oled_write_pixel(xCenter - 11, yCenter, true);
758 oled_write_pixel(xCenter - 9, yCenter, true);
759 oled_write_pixel(xCenter + 12, yCenter, true);
760 oled_write_pixel(xCenter + 14, yCenter, true);
761 break;
762
763 case 9:
764 // central line
765 drawline_hr(xCenter, yCenter, 2, true);
766 break;
767 }
768} \ No newline at end of file
diff --git a/keyboards/lily58/keymaps/druotoni/draw_helper.h b/keyboards/lily58/keymaps/druotoni/draw_helper.h
new file mode 100644
index 000000000..991ab0d0a
--- /dev/null
+++ b/keyboards/lily58/keymaps/druotoni/draw_helper.h
@@ -0,0 +1,47 @@
1// Copyright 2021 Nicolas Druoton (druotoni)
2// Copyright 2021 ugfx
3// SPDX-License-Identifier: GPL-2.0-or-later
4
5#pragma once
6
7// line
8void drawline_vb(uint8_t x, uint8_t y, uint8_t width, bool color);
9void drawline_vt(uint8_t x, uint8_t y, uint8_t width, bool color);
10void drawline_hr(uint8_t x, uint8_t y, uint8_t width, bool color);
11void drawline_hl(uint8_t x, uint8_t y, uint8_t width, bool color);
12void drawline_hr_heigth(uint8_t x, uint8_t y, uint8_t width, uint8_t heigth, bool color);
13
14// rectangle
15void draw_rectangle(uint8_t x, uint8_t y, uint8_t width, uint8_t heigth, bool color);
16void draw_rectangle_fill(uint8_t x, uint8_t y, uint8_t width, uint8_t heigth, bool color);
17void draw_gradient(uint8_t x, uint8_t y, uint8_t width, uint8_t heigth, uint8_t color_start, uint8_t color_end, uint8_t tres);
18
19// circle
20void draw_fill_circle(short x, short y, uint8_t radius, bool color);
21void draw_circle(uint8_t x, uint8_t y, uint8_t radius, bool color);
22void draw_ellipse(uint8_t x, uint8_t y, uint8_t a, uint8_t b, bool color);
23void draw_ellipse_fill(uint8_t x, uint8_t y, uint8_t a, uint8_t b, bool color);
24void draw_arc_sector(uint8_t x, uint8_t y, uint8_t radius, unsigned char sectors, unsigned char half, bool color);
25void draw_static(uint8_t x, uint8_t y, uint8_t width, uint8_t heigth, int color, uint8_t density);
26
27// text
28void draw_random_char(uint8_t column, uint8_t row, char final_char, int value, uint8_t style);
29void draw_label(const char *data, uint8_t len, uint8_t row, int value);
30void draw_box(const char *data, uint8_t len, uint8_t row, long value, uint8_t style);
31void draw_progress(uint8_t x, uint8_t y, uint8_t width, uint8_t heigth, int value, uint8_t style, bool color);
32
33// oled drivers stuff
34char get_oled_char(uint16_t start_index);
35void oled_write_cursor(uint8_t col, uint8_t line, const char *data, bool invert);
36void oled_write_raw_P_cursor(uint8_t col, uint8_t line, const char *data, uint16_t size);
37
38// pixel manipulation
39void copy_pixel(int from, int shift, unsigned char mask);
40void move_block(uint8_t x, uint8_t y, uint8_t width, uint8_t heigth, int shift);
41void draw_glitch_comb(uint8_t x, uint8_t y, uint8_t width, uint16_t height, uint8_t iSize, bool odd);
42
43// misc
44void render_tv_animation(uint8_t frame_number, uint8_t x, uint8_t y, uint8_t width, uint8_t heigth);
45int interpo_pourcent(int min, int max, int v);
46void get_glitch_index(uint32_t *glitch_timer, int *current_glitch_scope_time, uint8_t *glitch_index, uint8_t min_time, uint16_t max_time, uint8_t glitch_probobility, uint8_t glitch_frame_number);
47void get_glitch_index_new(uint16_t *glitch_timer, uint8_t *current_glitch_scope_time, uint8_t *glitch_index, uint8_t min_time, uint16_t max_time, uint8_t glitch_probobility, uint8_t glitch_frame_number);
diff --git a/keyboards/lily58/keymaps/druotoni/fast_random.c b/keyboards/lily58/keymaps/druotoni/fast_random.c
new file mode 100644
index 000000000..3028b57ac
--- /dev/null
+++ b/keyboards/lily58/keymaps/druotoni/fast_random.c
@@ -0,0 +1,17 @@
1// Copyright 2021 Nicolas Druoton (druotoni)
2// SPDX-License-Identifier: GPL-2.0-or-later
3#include "fast_random.h"
4
5// seed for random
6static unsigned long g_seed = 0;
7
8int fastrand(void) {
9 // todo : try with random16();
10 g_seed = (214013 * g_seed + 2531011);
11 return (g_seed >> 16) & 0x7FFF;
12}
13
14unsigned long fastrand_long(void) {
15 g_seed = (214013 * g_seed + 2531011);
16 return g_seed;
17}
diff --git a/keyboards/lily58/keymaps/druotoni/fast_random.h b/keyboards/lily58/keymaps/druotoni/fast_random.h
new file mode 100644
index 000000000..fe8c4a40a
--- /dev/null
+++ b/keyboards/lily58/keymaps/druotoni/fast_random.h
@@ -0,0 +1,7 @@
1// Copyright 2021 Nicolas Druoton (druotoni)
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6int fastrand(void);
7unsigned long fastrand_long(void); \ No newline at end of file
diff --git a/keyboards/lily58/keymaps/druotoni/gui_state.c b/keyboards/lily58/keymaps/druotoni/gui_state.c
new file mode 100644
index 000000000..d86e67ec7
--- /dev/null
+++ b/keyboards/lily58/keymaps/druotoni/gui_state.c
@@ -0,0 +1,71 @@
1// Copyright 2021 Nicolas Druoton (druotoni)
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include QMK_KEYBOARD_H
5
6#include "gui_state.h"
7#include "draw_helper.h"
8
9// timer for the gui state
10uint32_t global_sleep_timer = 0;
11uint32_t global_waking_up_timer = 0;
12uint32_t global_booting_timer = 0;
13
14// timers test for states
15#ifdef WITH_BOOT
16static bool IsBooting(void) { return (timer_elapsed32(global_booting_timer) < BOOTING_TIME_TRESHOLD); }
17#else
18static bool IsBooting(void) { return false; }
19#endif
20
21// state test
22static bool IsWakingUp(void) { return (timer_elapsed32(global_waking_up_timer) < WAKING_UP_TIME_TRESHOLD); }
23static bool IsIdle(void) { return (timer_elapsed32(global_sleep_timer) > IDLE_TIME_TRESHOLD && timer_elapsed32(global_sleep_timer) < HALTING_TIME_TRESHOLD); }
24static bool IsSleep(void) { return (timer_elapsed32(global_sleep_timer) >= SLEEP_TIME_TRESHOLD); }
25static bool IsHalting(void) { return (timer_elapsed32(global_sleep_timer) >= HALTING_TIME_TRESHOLD && timer_elapsed32(global_sleep_timer) < SLEEP_TIME_TRESHOLD); }
26
27gui_state_t get_gui_state(void) {
28 // get gui states by testing timers
29 if (IsBooting()) return _BOOTING;
30 if (IsWakingUp()) return _WAKINGUP;
31 if (IsIdle()) return _IDLE;
32 if (IsHalting()) return _HALTING;
33 if (IsSleep()) return _SLEEP;
34
35 return _UP;
36}
37
38void update_gui_state(void) {
39 // what to do when a key is pressed
40 gui_state_t t = get_gui_state();
41
42#ifdef WITH_BOOT
43 if (t == _SLEEP) {
44 // booting
45 global_booting_timer = timer_read32();
46 }
47
48 if (t == _BOOTING) {
49 // cancel booting
50 global_booting_timer = 1000000;
51 }
52#else
53 if (t == _SLEEP) {
54 // waking up
55 global_waking_up_timer = timer_read32();
56 }
57#endif
58
59 if (t == _IDLE || t == _HALTING || t == _BOOTING) {
60 // waking up
61 global_waking_up_timer = timer_read32();
62 }
63
64 // no sleep
65 global_sleep_timer = timer_read32();
66}
67
68uint8_t get_glitch_probability(void) {
69 // more gliches could occur when halting time is near
70 return interpo_pourcent(IDLE_TIME_TRESHOLD, HALTING_TIME_TRESHOLD, timer_elapsed32(global_sleep_timer));
71}
diff --git a/keyboards/lily58/keymaps/druotoni/gui_state.h b/keyboards/lily58/keymaps/druotoni/gui_state.h
new file mode 100644
index 000000000..190e02d30
--- /dev/null
+++ b/keyboards/lily58/keymaps/druotoni/gui_state.h
@@ -0,0 +1,18 @@
1// Copyright 2021 Nicolas Druoton (druotoni)
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6// states timing
7#define BOOTING_TIME_TRESHOLD 7000
8#define WAKING_UP_TIME_TRESHOLD 300
9#define IDLE_TIME_TRESHOLD 4000
10#define HALTING_TIME_TRESHOLD IDLE_TIME_TRESHOLD + 6000
11#define SLEEP_TIME_TRESHOLD HALTING_TIME_TRESHOLD + 8000
12
13typedef uint8_t gui_state_t;
14enum gui_state { _WAKINGUP = 0, _IDLE, _SLEEP, _UP, _BOOTING, _HALTING };
15
16gui_state_t get_gui_state(void);
17void update_gui_state(void);
18uint8_t get_glitch_probability(void); \ No newline at end of file
diff --git a/keyboards/lily58/keymaps/druotoni/keymap.c b/keyboards/lily58/keymaps/druotoni/keymap.c
new file mode 100644
index 000000000..2db32047e
--- /dev/null
+++ b/keyboards/lily58/keymaps/druotoni/keymap.c
@@ -0,0 +1,253 @@
1// Copyright 2021 Nicolas Druoton (druotoni)
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include QMK_KEYBOARD_H
5#include "keymap_french.h"
6#include "transactions.h"
7
8// global
9#include "gui_state.h"
10#include "boot.h"
11#include "navi_logo.h"
12
13#include "draw_helper.h"
14#include "fast_random.h"
15
16// left side
17#include "layer_frame.h"
18#include "burst.h"
19
20// right side
21#include "ring.h"
22
23// clang-format off
24const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
25/* QWERTY
26* ,-----------------------------------------. ,-----------------------------------------.
27* | ESC | 1 | 2 | 3 | 4 | 5 | | 6 | 7 | 8 | 9 | 0 | DEL |
28* |------+------+------+------+------+------| |------+------+------+------+------+------|
29* | Tab | Q | W | E | R | T | | Y | U | I | O | P | ^ |
30* |------+------+------+------+------+------| |------+------+------+------+------+------|
31* |LShift| A | S | D | F | G |-------. ,-------| H | J | K | L | ; |RShift|
32* |------+------+------+------+------+------| " | | ) |------+------+------+------+------+------|
33* |LCTRL | Z | X | C | V | B |-------| |-------| N | M | , | . | / | $ |
34* `-----------------------------------------/ / \ \-----------------------------------------'
35* | LAlt | SPE | Space| / NAV / \Enter \ |BackSP| ] | RGUI |
36* | | | |/ / \ \ | | | |
37* `----------------------------' '------''--------------------'
38*/
39 [_QWERTY] = LAYOUT(
40 KC_ESC, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_DELETE,
41 KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, FR_CIRC,
42 KC_LSFT, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_RSFT,
43 KC_LCTRL, KC_Z, KC_X, KC_C, KC_V, KC_B, S(KC_Z), FR_RPRN, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH, KC_QUOT,
44 KC_LALT, TT(_RAISE), KC_SPC, TT(_LOWER), KC_ENT, KC_BSPC, KC_RBRC, KC_RGUI
45 ),
46
47 /* LOWER
48* ,---------------------------------------------. ,------------------------------------------------.
49* | ESC | F1 | F2 | F3 | F4 | F5 | | F6 | F7 | F8 | F9 | F10 | DEL |
50* |------+-------+-------+------+-------+-------| |--------+--------+--------+-------+------+------|
51* | RST | F11 | F12 | DEL | paste | copy | | home | pg up | print | redo | w | |
52* |------+-------+-------+------+-------+-------| |--------+--------+--------+-------+------+------|
53* | | all | | SAV | undo | BackSP|-------. ,-------| left | down | up | right | | |
54* |------+-------+-------+------+-------+-------| enter| | |--------+--------+--------+-------+------+------|
55* | F9 | F11 | F10 | F5 | TAB | cut |-------| |-------| end | pg dw | | | | |
56* `---------------------------------------------/ / \ \-----------------------------------------------'
57* | | SPE | | / / \ \ | | MENU | |
58* | | | |/ / \ \ | | | |
59* `--------------------------------' '-------''--------------------'
60*/
61 [_LOWER] = LAYOUT(
62 KC_ESC, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, KC_DELETE,
63 RESET, KC_F11, KC_F12, KC_DELETE, RCTL(FR_V), RCTL(FR_C), KC_HOME, KC_PGUP, KC_PSCR, RCTL(FR_Y), RCTL(KC_RIGHT), _______,
64 _______,RCTL(FR_A), _______,RCTL(FR_S), RCTL(FR_Z), KC_BSPC, KC_LEFT, KC_DOWN, KC_UP, KC_RIGHT, _______, _______,
65 KC_F9, KC_F11, KC_F10, KC_F5, LALT(KC_TAB), RCTL(FR_X), KC_ENT, _______, KC_END, KC_PGDN, _______, _______, _______, _______,
66 _______,TT(_RAISE), _______, _______, _______, _______, KC_APP, _______),
67
68/* RAISE
69* ,-----------------------------------------. ,-------------------------------------------.
70* | | | | | | | | | | / | * | - | RGB TOG|
71* |------+------+------+------+------+------| |------+------+------+------+-----+--------|
72* | ` | [ | ] | | | | | ^ | 7 | 8 | 9 | + | RGB HUI|
73* |------+------+------+------+------+------| |------+------+------+------+-----+--------|
74* | | @ | | | & | € | # |-------. ,-------| $ | 4 | 5 | 6 | | |
75* |------+------+------+------+------+------| | | |------+------+------+------+-----+--------|
76* | F7 | F8 | F9 | F10 | # | F12 |-------| |-------| | 1 | 2 | 3 | | |
77* `-----------------------------------------/ / \ \------------------------------------------'
78* | | | | / / \ \ | | 0 | . |
79* | | | |/ / \ \ | | | |
80* `----------------------------' '------''---------------------'
81*/
82 [_RAISE] = LAYOUT(
83 _______, _______, _______, _______, _______, _______, _______, _______, KC_PSLS, KC_PAST, KC_PMNS, RGB_TOG,
84 KC_GRV, FR_LBRC, FR_RBRC, _______, _______, _______, FR_EQL, KC_KP_7, KC_KP_8, KC_KP_9, KC_PPLS, RGB_HUI,
85 _______, FR_AT, FR_PIPE, ALGR(KC_1), FR_EURO, FR_HASH, S(FR_EQL), KC_KP_4, KC_KP_5, KC_KP_6, _______, _______,
86 KC_F7, KC_F8, KC_F9, KC_F10, FR_HASH, KC_F12, _______, _______, _______, KC_KP_1, KC_KP_2, KC_KP_3, _______, _______,
87 _______, _______, _______, _______, _______, _______, KC_KP_0, KC_KP_DOT)
88};
89// clang-format on
90
91// sync transport
92typedef struct _sync_keycode_t {
93 uint16_t keycode;
94} sync_keycode_t;
95
96// force rigth side to update
97bool b_sync_need_send = false;
98
99// last keycode typed
100sync_keycode_t last_keycode;
101
102oled_rotation_t oled_init_user(oled_rotation_t rotation) {
103 // vertical orientation
104 return OLED_ROTATION_270;
105}
106
107void render(gui_state_t t) {
108 // logo
109 render_logo(t);
110
111#if IS_LEFT
112 // left side
113 render_layer_frame(t);
114 render_gears();
115
116 decay_scope();
117 render_scope(t);
118#endif
119
120#if IS_RIGHT
121 // right side
122 render_circle(t);
123#endif
124}
125
126void update(uint16_t keycode) {
127#if IS_LEFT
128 update_scope();
129#endif
130
131#if IS_RIGHT
132 update_circle(keycode);
133#endif
134}
135
136void reset(void) {
137#if IS_LEFT
138 reset_scope();
139#endif
140
141#if IS_RIGHT
142 reset_ring();
143#endif
144}
145
146void set_wackingup_mode_clean(void) {
147 oled_clear();
148 reset();
149}
150
151bool oled_task_user(void) {
152 gui_state_t t = get_gui_state();
153
154 // in sleep mode => turn display off
155 if (t == _SLEEP) {
156 oled_off();
157 return false;
158 }
159
160 // not in sleep mode => screen is on
161 oled_on();
162
163#ifdef WITH_BOOT
164 // in booting mode => display booting animation
165 if (t == _BOOTING) {
166 bool boot_finished = render_boot();
167 if (boot_finished) {
168 // end of the boot : wacking up
169 set_wackingup_mode_clean();
170 update_gui_state();
171 }
172 return false;
173 }
174#endif
175
176 // in halting mode => display booting animation
177 if (t == _HALTING) {
178 render_halt();
179 return false;
180 }
181
182 render(t);
183 return false;
184}
185
186void process_key(uint16_t keycode) {
187 // update screen with the new key
188 update(keycode);
189
190 gui_state_t t = get_gui_state();
191
192 if (t == _IDLE) {
193 // wake up animation
194 reset();
195 }
196
197 if (t == _BOOTING || t == _HALTING) {
198 // cancel booting or halting : waking_up
199 set_wackingup_mode_clean();
200 }
201
202 if (t == _SLEEP) {
203 // boot sequence
204 set_wackingup_mode_clean();
205 reset_boot();
206 }
207
208 update_gui_state();
209}
210
211void user_sync_a_slave_handler(uint8_t in_buflen, const void* in_data, uint8_t out_buflen, void* out_data) {
212 const sync_keycode_t* m2s = (const sync_keycode_t*)in_data;
213 // get the last char typed on left side and update the right side
214 process_key(m2s->keycode);
215}
216
217void keyboard_post_init_user(void) {
218 // callback for tranport sync data
219 transaction_register_rpc(USER_SYNC_A, user_sync_a_slave_handler);
220}
221
222void housekeeping_task_user(void) {
223 // only for master side
224 if (!is_keyboard_master()) return;
225
226 // only if a new char was typed
227 if (!b_sync_need_send) return;
228
229 // send the char to the slave side : sync is done
230 if (transaction_rpc_send(USER_SYNC_A, sizeof(last_keycode), &last_keycode)) {
231 b_sync_need_send = false;
232 }
233}
234
235bool process_record_user(uint16_t keycode, keyrecord_t* record) {
236 if (record->event.pressed) {
237 // master : store keycode to sent to the other side to be process_key
238 last_keycode.keycode = keycode;
239 b_sync_need_send = true;
240
241 // gui process the input
242 process_key(keycode);
243 }
244 return true;
245}
246
247#if IS_LEFT
248layer_state_t layer_state_set_user(layer_state_t state) {
249 // update the frame with the layer name
250 update_layer_frame(state);
251 return state;
252}
253#endif
diff --git a/keyboards/lily58/keymaps/druotoni/layer_frame.c b/keyboards/lily58/keymaps/druotoni/layer_frame.c
new file mode 100644
index 000000000..6f7ae1a25
--- /dev/null
+++ b/keyboards/lily58/keymaps/druotoni/layer_frame.c
@@ -0,0 +1,105 @@
1// Copyright 2021 Nicolas Druoton (druotoni)
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include QMK_KEYBOARD_H
5
6#include "gui_state.h"
7#include "layer_frame.h"
8#include "draw_helper.h"
9
10#define ANIM_LAYER_FRAME_DURATION 2
11#define ANIM_LAYER_FRAME_MAX 7
12
13// current layer
14uint8_t current_layer = _QWERTY;
15
16// layer animation stuff
17uint16_t anim_layer_frame_timer = 0;
18uint8_t current_layer_frame = ANIM_LAYER_FRAME_MAX;
19uint8_t layer_frame_destination = ANIM_LAYER_FRAME_MAX;
20
21// layer name for display
22const char* layer_name;
23static const char* layer_ref[3] = {LAYER_NAME_0, LAYER_NAME_1, LAYER_NAME_2};
24
25void update_layer_frame(layer_state_t state) {
26 // reset timer
27 anim_layer_frame_timer = timer_read();
28
29 // direction for animation base on layer selected
30 current_layer = get_highest_layer(state);
31 if (current_layer == _QWERTY) {
32 layer_frame_destination = 0;
33 } else {
34 layer_frame_destination = ANIM_LAYER_FRAME_MAX;
35 }
36}
37
38static void draw_black_screen(void) {
39 // clean frame center
40 draw_rectangle_fill(3, 42, 26, 20, false);
41 drawline_hr(17, 62, 12, false);
42}
43
44void render_gears(void) {
45 // 64 bytes, 8x8 font, 8 characters, 32x16 image, 4 columns, 2 rows
46 static const char PROGMEM raw_logo[] = {
47 0, 6, 6, 54, 118, 96, 230, 192, 192, 128, 0, 0, 0, 0, 0, 1, 2, 2, 2, 2, 2, 2, 18, 226, 2, 18, 226, 2, 18, 226, 2, 1, 0, 0, 0, 0, 0, 128, 128, 128, 185, 187, 187, 131, 128, 184, 128, 128, 128, 128, 128, 128, 128, 128, 128, 191, 128, 128, 191, 128, 128, 191, 128, 0,
48 };
49
50 // extra line for complete the gui
51 oled_write_raw_P_cursor(0, 8, raw_logo, sizeof(raw_logo));
52}
53
54void render_layer_frame(gui_state_t t) {
55 // 96 bytes, 8x8 font, 12 characters, 32x24 image, 4 columns, 3 rows
56 static const char PROGMEM raw_logo[] = {
57 62, 1, 0, 56, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 124, 248, 241, 226, 4, 8, 240, 0, 28, 28, 28, 0, 0, 127, 4, 8, 16, 127, 0, 124, 18, 17, 18, 124, 0, 31, 32, 64, 32, 31, 0, 0, 0, 0, 255, 255, 0, 0, 255, 62, 64, 64, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 142, 30, 62, 126, 126, 70, 70, 126, 70, 70, 126, 70, 70, 127, 127, 0, 0, 255,
58 };
59 oled_write_raw_P_cursor(0, 5, raw_logo, sizeof(raw_logo));
60
61 // extra line for complete the gui
62 drawline_hr(2, 39, 25, 1);
63
64 if (current_layer_frame != layer_frame_destination) {
65 if (timer_elapsed(anim_layer_frame_timer) > ANIM_LAYER_FRAME_DURATION) {
66 anim_layer_frame_timer = timer_read();
67
68 if (layer_frame_destination > current_layer_frame) {
69 current_layer_frame++;
70 } else {
71 current_layer_frame--;
72 }
73 }
74
75 // black screen
76 draw_black_screen();
77
78 // gradient animation on layer selection
79 draw_gradient(3, 42, current_layer_frame * 4, 10, 0, 255, 7);
80 draw_gradient(3 + (27 - current_layer_frame * 4), 57, current_layer_frame * 4, 6, 255, 0, 7);
81
82 drawline_hr(3, 46, 22, false);
83 drawline_hr(3, 47, 23, false);
84
85 draw_rectangle_fill(3, 55, 24, 2, false);
86 draw_rectangle_fill(24, 48, 3, 7, false);
87
88 draw_rectangle_fill(3, 60, 12, 2, false);
89 oled_write_pixel(15, 61, false);
90 drawline_hr(14, 62, 3, false);
91 drawline_hr(14, 62, 3, false);
92 drawline_hr(3, 62, 11, true);
93 }
94
95 // get current layer name
96 layer_name = layer_ref[current_layer];
97
98 // gui on pause : no layer name on screen
99 if (t == _IDLE || t == _SLEEP || t == _WAKINGUP) {
100 layer_name = " ";
101 }
102
103 // display layer name in the frame
104 oled_write_cursor(1, 6, layer_name, false);
105}
diff --git a/keyboards/lily58/keymaps/druotoni/layer_frame.h b/keyboards/lily58/keymaps/druotoni/layer_frame.h
new file mode 100644
index 000000000..abbd94839
--- /dev/null
+++ b/keyboards/lily58/keymaps/druotoni/layer_frame.h
@@ -0,0 +1,15 @@
1// Copyright 2021 Nicolas Druoton (druotoni)
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6// layer name : must be 3 chars
7#define LAYER_NAME_0 "ABC"
8#define LAYER_NAME_1 "NAV"
9#define LAYER_NAME_2 "SPE"
10
11enum layer_number { _QWERTY = 0, _LOWER, _RAISE };
12
13void render_gears(void);
14void render_layer_frame(gui_state_t t);
15void update_layer_frame(layer_state_t state); \ No newline at end of file
diff --git a/keyboards/lily58/keymaps/druotoni/navi_font.c b/keyboards/lily58/keymaps/druotoni/navi_font.c
new file mode 100644
index 000000000..2412256e6
--- /dev/null
+++ b/keyboards/lily58/keymaps/druotoni/navi_font.c
@@ -0,0 +1,139 @@
1// Copyright 2021 Nicolas Druoton (druotoni)
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4// This is the 'classic' fixed-space bitmap font for Adafruit_GFX since 1.0.
5// See gfxfont.h for newer custom bitmap font info.
6
7#include "progmem.h"
8
9// Standard ASCII 5x7 font
10const unsigned char font[] PROGMEM = {
11 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
12 0x42, 0x3A, 0x12, 0x12, 0x0E, 0x00,
13 0x0C, 0x44, 0x47, 0x24, 0x1C, 0x00,
14 0x24, 0x24, 0x14, 0x7F, 0x04, 0x00,
15 0x42, 0x3F, 0x02, 0x22, 0x1E, 0x00,
16 0x0A, 0x0A, 0x7F, 0x0A, 0x0A, 0x00,
17 0x02, 0x47, 0x42, 0x22, 0x1F, 0x00,
18 0x21, 0x15, 0x09, 0x15, 0x63, 0x00,
19 0x44, 0x44, 0x3F, 0x04, 0x04, 0x00,
20 0x22, 0x1A, 0x02, 0x7F, 0x12, 0x00,
21 0x22, 0x22, 0x12, 0x0A, 0x06, 0x00,
22 0x08, 0x47, 0x42, 0x22, 0x1E, 0x00,
23 0x10, 0x52, 0x54, 0x30, 0x16, 0x00,
24 0x40, 0x3A, 0x02, 0x3E, 0x42, 0x00,
25 0x5E, 0x52, 0x52, 0x52, 0x5E, 0x00,
26 0x04, 0x27, 0x44, 0x44, 0x3C, 0x00,
27 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
28 0x77, 0x00, 0x77, 0x00, 0x77, 0x00,
29 0x14, 0x22, 0x7F, 0x22, 0x14, 0x00,
30 0x5F, 0x5F, 0x00, 0x5F, 0x5F, 0x00,
31 0x06, 0x09, 0x7F, 0x01, 0x7F, 0x00,
32 0x00, 0x66, 0x89, 0x95, 0x6A, 0x00,
33 0x60, 0x60, 0x60, 0x60, 0x60, 0x00,
34 0x94, 0xA2, 0xFF, 0xA2, 0x94, 0x00,
35 0x08, 0x04, 0x7E, 0x04, 0x08, 0x00,
36 0x10, 0x20, 0x7E, 0x20, 0x10, 0x00,
37 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
38 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
39 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
40 0x00, 0x1C, 0x1C, 0x1C, 0x00, 0x00,
41 0x00, 0x08, 0x1C, 0x08, 0x00, 0x00,
42 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
43 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
44 0x00, 0x00, 0x5F, 0x00, 0x00, 0x00,
45 0x00, 0x07, 0x00, 0x07, 0x00, 0x00,
46 0x14, 0x7F, 0x14, 0x7F, 0x14, 0x00,
47 0x24, 0x2A, 0x7F, 0x2A, 0x12, 0x00,
48 0x23, 0x13, 0x08, 0x64, 0x62, 0x00,
49 0x36, 0x49, 0x56, 0x20, 0x50, 0x00,
50 0x00, 0x08, 0x07, 0x03, 0x00, 0x00,
51 0x00, 0x1C, 0x22, 0x41, 0x00, 0x00,
52 0x00, 0x41, 0x22, 0x1C, 0x00, 0x00,
53 0x2A, 0x1C, 0x7F, 0x1C, 0x2A, 0x00,
54 0x08, 0x08, 0x3E, 0x08, 0x08, 0x00,
55 0x00, 0x80, 0x70, 0x30, 0x00, 0x00,
56 0x08, 0x08, 0x08, 0x08, 0x08, 0x00,
57 0x00, 0x00, 0x60, 0x60, 0x00, 0x00,
58 0x20, 0x10, 0x08, 0x04, 0x02, 0x00,
59 0x3E, 0x51, 0x49, 0x45, 0x3E, 0x00,
60 0x00, 0x42, 0x7F, 0x40, 0x00, 0x00,
61 0x72, 0x49, 0x49, 0x49, 0x46, 0x00,
62 0x21, 0x41, 0x49, 0x4D, 0x33, 0x00,
63 0x18, 0x14, 0x12, 0x7F, 0x10, 0x00,
64 0x27, 0x45, 0x45, 0x45, 0x39, 0x00,
65 0x3C, 0x4A, 0x49, 0x49, 0x31, 0x00,
66 0x41, 0x21, 0x11, 0x09, 0x07, 0x00,
67 0x36, 0x49, 0x49, 0x49, 0x36, 0x00,
68 0x46, 0x49, 0x49, 0x29, 0x1E, 0x00,
69 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,
70 0x00, 0x40, 0x34, 0x00, 0x00, 0x00,
71 0x00, 0x08, 0x14, 0x22, 0x41, 0x00,
72 0x14, 0x14, 0x14, 0x14, 0x14, 0x00,
73 0x00, 0x41, 0x22, 0x14, 0x08, 0x00,
74 0x02, 0x01, 0x59, 0x09, 0x06, 0x00,
75 0x3E, 0x41, 0x5D, 0x59, 0x4E, 0x00,
76 0x7C, 0x12, 0x11, 0x12, 0x7C, 0x00,
77 0x7F, 0x49, 0x49, 0x49, 0x36, 0x00,
78 0x3E, 0x41, 0x41, 0x41, 0x22, 0x00,
79 0x7F, 0x41, 0x41, 0x41, 0x3E, 0x00,
80 0x7F, 0x49, 0x49, 0x49, 0x41, 0x00,
81 0x7F, 0x09, 0x09, 0x09, 0x01, 0x00,
82 0x3E, 0x41, 0x41, 0x51, 0x73, 0x00,
83 0x7F, 0x08, 0x08, 0x08, 0x7F, 0x00,
84 0x00, 0x41, 0x7F, 0x41, 0x00, 0x00,
85 0x20, 0x40, 0x41, 0x3F, 0x01, 0x00,
86 0x7F, 0x08, 0x14, 0x22, 0x41, 0x00,
87 0x7F, 0x40, 0x40, 0x40, 0x40, 0x00,
88 0x7F, 0x02, 0x1C, 0x02, 0x7F, 0x00,
89 0x7F, 0x04, 0x08, 0x10, 0x7F, 0x00,
90 0x3E, 0x41, 0x41, 0x41, 0x3E, 0x00,
91 0x7F, 0x09, 0x09, 0x09, 0x06, 0x00,
92 0x3E, 0x41, 0x51, 0x21, 0x5E, 0x00,
93 0x7F, 0x09, 0x19, 0x29, 0x46, 0x00,
94 0x26, 0x49, 0x49, 0x49, 0x32, 0x00,
95 0x03, 0x01, 0x7F, 0x01, 0x03, 0x00,
96 0x3F, 0x40, 0x40, 0x40, 0x3F, 0x00,
97 0x1F, 0x20, 0x40, 0x20, 0x1F, 0x00,
98 0x3F, 0x40, 0x38, 0x40, 0x3F, 0x00,
99 0x63, 0x14, 0x08, 0x14, 0x63, 0x00,
100 0x03, 0x04, 0x78, 0x04, 0x03, 0x00,
101 0x61, 0x59, 0x49, 0x4D, 0x43, 0x00,
102 0x00, 0x7F, 0x41, 0x41, 0x41, 0x00,
103 0x02, 0x04, 0x08, 0x10, 0x20, 0x00,
104 0x00, 0x41, 0x41, 0x41, 0x7F, 0x00,
105 0x04, 0x02, 0x01, 0x02, 0x04, 0x00,
106 0x40, 0x40, 0x40, 0x40, 0x40, 0x00,
107 0x00, 0x03, 0x07, 0x08, 0x00, 0x00,
108 0x20, 0x54, 0x54, 0x78, 0x40, 0x00,
109 0x7F, 0x28, 0x44, 0x44, 0x38, 0x00,
110 0x38, 0x44, 0x44, 0x44, 0x28, 0x00,
111 0x38, 0x44, 0x44, 0x28, 0x7F, 0x00,
112 0x38, 0x54, 0x54, 0x54, 0x18, 0x00,
113 0x00, 0x08, 0x7E, 0x09, 0x02, 0x00,
114 0x18, 0x24, 0x24, 0x1C, 0x78, 0x00,
115 0x7F, 0x08, 0x04, 0x04, 0x78, 0x00,
116 0x00, 0x44, 0x7D, 0x40, 0x00, 0x00,
117 0x20, 0x40, 0x40, 0x3D, 0x00, 0x00,
118 0x7F, 0x10, 0x28, 0x44, 0x00, 0x00,
119 0x00, 0x41, 0x7F, 0x40, 0x00, 0x00,
120 0x7C, 0x04, 0x78, 0x04, 0x78, 0x00,
121 0x7C, 0x08, 0x04, 0x04, 0x78, 0x00,
122 0x38, 0x44, 0x44, 0x44, 0x38, 0x00,
123 0x7C, 0x18, 0x24, 0x24, 0x18, 0x00,
124 0x18, 0x24, 0x24, 0x18, 0x7C, 0x00,
125 0x7C, 0x08, 0x04, 0x04, 0x08, 0x00,
126 0x48, 0x54, 0x54, 0x54, 0x24, 0x00,
127 0x04, 0x04, 0x3F, 0x44, 0x24, 0x00,
128 0x3C, 0x40, 0x40, 0x20, 0x7C, 0x00,
129 0x1C, 0x20, 0x40, 0x20, 0x1C, 0x00,
130 0x3C, 0x40, 0x30, 0x40, 0x3C, 0x00,
131 0x44, 0x28, 0x10, 0x28, 0x44, 0x00,
132 0x4C, 0x90, 0x90, 0x90, 0x7C, 0x00,
133 0x44, 0x64, 0x54, 0x4C, 0x44, 0x00,
134 0x00, 0x08, 0x36, 0x41, 0x00, 0x00,
135 0x00, 0x00, 0x77, 0x00, 0x00, 0x00,
136 0x00, 0x41, 0x36, 0x08, 0x00, 0x00,
137 0x02, 0x01, 0x02, 0x04, 0x02, 0x00,
138 0x3C, 0x26, 0x23, 0x26, 0x3C, 0x00
139};
diff --git a/keyboards/lily58/keymaps/druotoni/navi_logo.c b/keyboards/lily58/keymaps/druotoni/navi_logo.c
new file mode 100644
index 000000000..6041aa5eb
--- /dev/null
+++ b/keyboards/lily58/keymaps/druotoni/navi_logo.c
@@ -0,0 +1,117 @@
1// Copyright 2021 Nicolas Druoton (druotoni)
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include QMK_KEYBOARD_H
5
6#include "gui_state.h"
7#include "navi_logo.h"
8#include "fast_random.h"
9#include "draw_helper.h"
10
11#define LOGO_SIZE 128
12
13// glitch stuff
14#define GLITCH_FRAME_NUMBER 11
15
16uint8_t current_glitch_index = 0;
17int current_glitch_time = 150;
18uint32_t glitch_timer = 0;
19
20static void render_logo_clean(void) {
21 // your logo here
22 static const char PROGMEM raw_logo[] = {
23 0, 0, 0, 0, 0, 0, 128, 128, 0, 0, 128, 128, 192, 192, 204, 222, 222, 204, 192, 192, 128, 0, 0, 0, 128, 128, 0, 0, 0, 0, 0, 0, 192, 240, 248, 28, 14, 7, 3, 249, 252, 255, 15, 7, 3, 225, 241, 241, 241, 241, 225, 3, 7, 15, 255, 252, 249, 3, 7, 14, 28, 248, 240, 192, 192, 227, 231, 206, 28, 56, 112, 99, 15, 31, 60, 120, 240, 225, 227, 3, 3, 227, 225, 240, 120, 60, 31, 15, 103, 112, 56, 28, 206, 231, 227, 192, 0, 1, 1, 0, 0, 0, 56, 120, 96, 192, 192, 192, 96, 127, 63, 0, 0, 63, 127, 96, 192, 192, 192, 96, 120, 56, 0, 0, 0, 1, 1, 0,
24 };
25 oled_write_raw_P(raw_logo, sizeof(raw_logo));
26}
27
28void render_glitch_bar(uint8_t x, uint8_t y, uint8_t width, uint8_t height, uint8_t iProb) {
29 // random horizontal scanlines
30 for (uint8_t i = 0; i < height; i++) {
31 bool bGenerateGlitch = (fastrand() % 100) < iProb;
32
33 if (bGenerateGlitch) {
34 drawline_hr(x, y + i, width, true);
35 }
36 }
37}
38
39void render_misc_glitch(uint8_t algo) {
40 char c = 0;
41 switch (algo) {
42 case 7:
43 // invert
44 for (uint8_t i = 0; i < LOGO_SIZE; i++) {
45 c = get_oled_char(i);
46 oled_write_raw_byte(~(c), i);
47 }
48 break;
49
50 case 8:
51 // wobble
52 for (uint8_t i = 0; i < LOGO_SIZE; i++) {
53 if (i < LOGO_SIZE - 1) {
54 copy_pixel(i + 1, -1, 85);
55
56 copy_pixel(LOGO_SIZE - 1 - 1 - i, 1, 170);
57 }
58 }
59 break;
60 }
61}
62
63static void render_logo_glitch(void) {
64#ifdef WITH_GLITCH
65 // get a random glitch index
66 uint8_t glitch_prob = get_glitch_probability();
67 get_glitch_index(&glitch_timer, &current_glitch_time, &current_glitch_index, 0, 150, glitch_prob, GLITCH_FRAME_NUMBER);
68
69 // no glitch
70 if (current_glitch_index <= 3) {
71 render_logo_clean();
72 return;
73 }
74
75 // glitch time !
76 switch (current_glitch_index) {
77 case 4:
78 move_block(1, 11, 24, 3, 5);
79 move_block(2, 19, 14, 3, 4);
80 move_block(9, 22, 7, 4, 4);
81 return;
82
83 case 5:
84 move_block(6, 25, 20, 7, 4);
85 move_block(0, 8, 32, 8, 7);
86 return;
87 case 6:
88 move_block(3, 7, 27, 4, -3);
89 move_block(13, 23, 19, 4, -4);
90 return;
91
92 case 7:
93 case 8:
94 render_misc_glitch(current_glitch_index);
95 return;
96
97 case 9:
98 render_glitch_bar(0, 0, 32, 32, 25);
99 return;
100
101 case 10:
102 draw_static(0, 0, 32, 32, true, 0);
103 return;
104 }
105#endif
106}
107
108void render_logo(gui_state_t t) {
109 if (t == _IDLE) {
110 // on idle : glitch time !
111 render_logo_glitch();
112 return;
113 }
114
115 // standart logo
116 render_logo_clean();
117}
diff --git a/keyboards/lily58/keymaps/druotoni/navi_logo.h b/keyboards/lily58/keymaps/druotoni/navi_logo.h
new file mode 100644
index 000000000..3504568e5
--- /dev/null
+++ b/keyboards/lily58/keymaps/druotoni/navi_logo.h
@@ -0,0 +1,7 @@
1// Copyright 2021 Nicolas Druoton (druotoni)
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6void render_logo(gui_state_t t);
7
diff --git a/keyboards/lily58/keymaps/druotoni/readme.md b/keyboards/lily58/keymaps/druotoni/readme.md
new file mode 100644
index 000000000..c6d47da5d
--- /dev/null
+++ b/keyboards/lily58/keymaps/druotoni/readme.md
@@ -0,0 +1,133 @@
1# HELL0 NAVI. Interface
2
3HELL0 NAVI. Interface is a GUI based en [Serial Experiments Lain](https://en.wikipedia.org/wiki/Serial_Experiments_Lain). Turn your [Lily58](https://github.com/kata0510/Lily58) keyboard into a Navi computer with its own Copland OS.
4
5
6Ready to dive into the Wired ?
7
8
9HELL0 NAVI provides interactive animations for both sides :
10- a scope on left side for burst, WPM and active layer
11- a ring on right side for the last key stroke
12
13
14
15
16
17
18
19## Typing animation
20
21The scope displays your burst time on a chart. The WPM is represented by an horizontal line.
22
23The ring display the last letter in the upper frame. Each time you enter a key, the Navi searches into the circular database and locks the position. A special animation is displayed when Enter, Backspce or Escape are struck.
24
25<img src="https://imgur.com/Yf7D6UN.gif" height="400" >
26
27## Startup animation
28
29Your Navi boots when it leaves the sleep mode. The animation can be canceled by typing.
30
31
32
33<img src="https://imgur.com/EXU92Ev.gif" height="400" >
34
35
36
37## Waking up animation
38
39After a period of inactivity, the scope and the ring turn off and the Navi runs in Idle mode. A new key stroke wakes them up.
40
41
42<img src="https://imgur.com/9GWa7rR.gif" height="400" >
43
44
45## Idle animation
46
47The Copland OS is still in beta test. After a while, some visual glitches will occur.
48
49
50<img src="https://imgur.com/eKZ7qgC.gif" height="400" >
51
52
53
54## Shutdown animation
55The Navi runs in sleep mode after 10 seconds in Idle mode. A nice (and difficul to render in a gif) animation is run. The OLED display turns off.
56
57# How to build & flash
58
59You need to flash each side with a specific version based on config.h configuration.
60
61 ## Left side (master)
62
63IS_RIGHT needs to be commented in config.h
64```
65#define IS_LEFT 1
66//#define IS_RIGHT 1
67```
68Connect the left side and flash
69
70 ## Right side (slave)
71
72Comment IS_LEFT and uncomment IS_RIGHT in config.h
73```
74//#define IS_LEFT 1
75#define IS_RIGHT 1
76```
77Connect the right side and flash
78
79# Customization
80
81## Logo
82Logo can be change in navi_logo.c.
83The new logo must be 32x32 pixels.
84```
85static void render_logo_clean(void) {
86 // your logo here
87 static const char PROGMEM logo_raw[] = {
88 0, 0, 0, 0, 0, 0, 128, 128, 0, 0, 128, 128, 192, 192, 204, 222, 222, 204, 192, 192, 128, 0, 0, 0, 128, 128, 0, 0,
89 0, 0, 0, 0, 192, 240, 248, 28, 14, 7, 3, 249, 252, 255, 15, 7, 3, 225, 241, 241, 241, 241, 225, 3, 7, 15, 255, 252,
90 249, 3, 7, 14, 28, 248, 240, 192, 192, 227, 231, 206, 28, 56, 112, 99, 15, 31, 60, 120, 240, 225, 227, 3, 3, 227,
91 225, 240, 120, 60, 31, 15, 103, 112, 56, 28, 206, 231, 227, 192, 0, 1, 1, 0, 0, 0, 56, 120, 96, 192, 192, 192,
92 96, 127, 63, 0, 0, 63, 127, 96, 192, 192, 192, 96, 120, 56, 0, 0, 0, 1, 1, 0,
93 };
94 oled_write_raw_P(logo_raw, sizeof(logo_raw));
95}
96```
97## Layer names
98
99The current version handle 3 differents layers. Names can be changed in layer_frame.h.
100```
101// layer name : must be 3 chars
102#define LAYER_NAME_0 "ABC"
103#define LAYER_NAME_1 "NAV"
104#define LAYER_NAME_2 "SPE"
105```
106
107## Timing
108
109You can tweak states timing in gui_state.h.
110```
111// states timing
112#define BOOTING_TIME_TRESHOLD 7000
113#define WAKING_UP_TIME_TRESHOLD 300
114#define IDLE_TIME_TRESHOLD 4000
115#define HALTING_TIME_TRESHOLD IDLE_TIME_TRESHOLD + 6000
116#define SLEEP_TIME_TRESHOLD HALTING_TIME_TRESHOLD + 8000
117```
118
119## Need space ?
120Boot and gliches can be commented in config.h
121```
122// states timing
123// logo glitch
124//#define WITH_GLITCH
125// boot sequence
126//#define WITH_BOOT
127```
128
129![My Navi](https://imgur.com/eYkgoZJ.png)
130> Keyboard : https://github.com/kata0510/Lily58
131>
132> Case : https://github.com/BoardSodie/Lily58-Acrylic-Case
133
diff --git a/keyboards/lily58/keymaps/druotoni/ring.c b/keyboards/lily58/keymaps/druotoni/ring.c
new file mode 100644
index 000000000..e3b747287
--- /dev/null
+++ b/keyboards/lily58/keymaps/druotoni/ring.c
@@ -0,0 +1,494 @@
1// Copyright 2021 Nicolas Druoton (druotoni)
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include QMK_KEYBOARD_H
5#include "gui_state.h"
6#include "ring.h"
7
8#include "fast_random.h"
9#include "draw_helper.h"
10
11char tListeTotal[SIZE_ARRAY_1] = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P'};
12char tListeTotal2[SIZE_ARRAY_1] = {'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', ',', '.', '/', '1', '2', '3'};
13
14static char tRefArc[SIZE_ARRAY_1] = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P'};
15static char tRefArc2[SIZE_ARRAY_1] = {'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', ',', '.', '/', '1', '2', '3'};
16
17// ring target and previous char
18char c_target = 'A';
19char c_target2 = 'Q';
20char c_last = ' ';
21char c_previous = ' ';
22
23static const char PROGMEM code_to_name[60] = {' ', ' ', ' ', ' ', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', 'R', 'E', 'B', 'T', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ';', '\'', ' ', ',', '.', '/', ' ', ' ', ' '};
24
25// main circle
26#define CIRCLE_ANIM_FRAME_DURATION 40
27uint16_t circle_timer = 0;
28
29// special animation for special keys
30#define ANIM_CENTER_FRAME_NUMBER 5
31#define ANIM_CENTER_FRAME_DURATION 40
32uint16_t anim_center_timer = 0;
33uint8_t anim_center_current_frame = 0;
34
35// sleep animation
36#define ANIM_SLEEP_RING_FRAME_NUMBER 9
37#define ANIM_SLEEP_RING_FRAME_DURATION 20
38uint16_t anim_sleep_ring_timer = 0;
39uint8_t current_sleep_ring_frame = 0;
40uint8_t sleep_ring_frame_destination = ANIM_SLEEP_RING_FRAME_NUMBER - 1;
41
42// glitch animation
43uint16_t anim_ring_idle_timer = 0;
44int current_glitch_ring_time = 150;
45uint32_t glitch_ring_timer = 0;
46uint8_t current_glitch_ring_index = 0;
47
48// central frame keylog animation
49#define ANIM_KEYLOG_FRAME_NUMBER 8
50#define ANIM_KEYLOG_FRAME_DURATION 20
51uint8_t anim_keylog_current_frame = 0;
52uint16_t anim_keylog_timer = 0;
53
54static const char PROGMEM raw_ring_sleep[4][64] = {{
55 192, 32, 16, 8, 4, 4, 4, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 4, 4, 4, 8, 16, 32, 192, 3, 4, 8, 16, 32, 32, 32, 64, 64, 64, 64, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 64, 64, 64, 64, 32, 32, 32, 16, 8, 4, 3,
56 },
57
58 {
59 128, 64, 32, 32, 16, 16, 16, 16, 16, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 16, 16, 16, 16, 16, 32, 32, 64, 128, 0, 1, 2, 2, 4, 4, 4, 4, 4, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 4, 4, 4, 4, 4, 2, 2, 1, 0,
60 },
61
62 {
63 248, 192, 128, 128, 128, 128, 128, 128, 128, 0, 0, 128, 0, 0, 0, 0, 0, 0, 0, 0, 128, 0, 0, 128, 128, 128, 128, 128, 128, 128, 192, 248, 15, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 15,
64 },
65
66 {
67 255, 240, 128, 128, 0, 128, 128, 0, 0, 128, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 0, 0, 128, 128, 0, 128, 128, 248, 255, 255, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 255,
68 }};
69
70static const char PROGMEM raw_circle[4][128] = {{
71 0, 0, 0, 192, 32, 16, 8, 8, 4, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 4, 8, 8, 16, 32, 192, 0, 0, 0, 240, 14, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 129, 238, 240, 15, 112, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 192, 240, 255, 127, 15, 0, 0, 0, 3, 4, 8, 16, 16, 32, 64, 64, 64, 128, 128, 192, 192, 224, 224, 224, 240, 112, 120, 124, 60, 30, 30, 15, 7, 3, 0, 0, 0,
72 },
73 {
74 0, 0, 0, 192, 32, 16, 8, 8, 4, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 4, 8, 8, 48, 224, 192, 0, 0, 0, 240, 14, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 255, 255, 254, 240, 15, 112, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 192, 224, 240, 248, 248, 254, 255, 255, 127, 15, 0, 0, 0, 3, 7, 15, 31, 30, 62, 126, 126, 126, 254, 254, 254, 254, 254, 255, 255, 255, 127, 127, 127, 63, 31, 31, 15, 7, 3, 0, 0, 0,
75 },
76 {
77 0, 0, 0, 192, 32, 16, 8, 8, 4, 2, 2, 2, 1, 1, 1, 1, 3, 15, 255, 255, 254, 254, 254, 252, 248, 248, 240, 224, 192, 0, 0, 0, 240, 14, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 192, 240, 248, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 254, 240, 15, 126, 252, 248, 248, 248, 248, 248, 252, 252, 254, 254, 255, 255, 255, 255, 255, 255, 255, 127, 63, 31, 15, 7, 7, 3, 3, 3, 7, 143, 127, 15, 0, 0, 0, 3, 7, 15, 31, 31, 63, 127, 127, 127, 255, 255, 255, 255, 255, 255, 195, 128, 64, 64, 64, 32, 16, 16, 8, 4, 3, 0, 0, 0,
78 },
79 {
80 0, 0, 0, 192, 224, 240, 248, 248, 124, 62, 30, 14, 15, 7, 7, 3, 3, 3, 1, 1, 2, 2, 2, 4, 8, 8, 16, 32, 192, 0, 0, 0, 240, 254, 255, 31, 15, 3, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 14, 240, 15, 115, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 112, 15, 0, 0, 0, 3, 4, 8, 16, 16, 32, 64, 64, 64, 128, 128, 128, 128, 128, 128, 128, 128, 64, 64, 64, 32, 16, 16, 8, 4, 3, 0, 0, 0,
81 }};
82
83static const char PROGMEM raw_bottom[] = {
84 127, 192, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 192, 127,
85};
86
87static const char PROGMEM raw_middle[] = {
88 240, 8, 4, 226, 241, 248, 124, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 56, 0, 1, 62, 255, 0, 0, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 28, 28, 28, 0, 255, 0, 0, 127, 127, 70, 70, 126, 70, 70, 126, 70, 70, 126, 126, 62, 30, 142, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 64, 64, 62, 1, 2, 114, 114, 2, 2, 114, 114, 2, 2, 114, 114, 2, 2, 2, 2, 1, 0, 0, 0, 128, 64, 64, 64, 64, 64, 64, 64, 64, 64, 128, 0, 0, 128, 131, 131, 132, 136, 179, 131, 132, 184, 131, 131, 188, 128, 128, 128, 128, 128, 128, 128, 143, 144, 149, 144, 149, 144, 149, 144, 149, 144, 143, 0,
89};
90
91static void rotate_right(char str[]) {
92 uint8_t iSize = SIZE_ARRAY_1;
93 char cFist = str[0];
94
95 // rotate array to the right
96 for (uint8_t i = 0; i < iSize - 1; i++) {
97 str[i] = str[i + 1];
98 }
99 str[iSize - 1] = cFist;
100}
101
102static void rotate_left(char str[]) {
103 uint8_t iSize = SIZE_ARRAY_1;
104 char cLast = str[iSize - 1];
105
106 // rotate array to the left
107 for (uint8_t i = iSize - 1; i > 0; i--) {
108 str[i] = str[i - 1];
109 }
110 str[0] = cLast;
111}
112
113static signed char GetPosition(char c, char tListe[]) {
114 uint8_t iSize = SIZE_ARRAY_1;
115
116 // find position of c in the array
117 for (uint8_t i = 0; i < iSize; i++) {
118 if (tListe[i] == c) return i;
119 }
120
121 // not found
122 return -1;
123}
124
125static signed char GetDistance(char cNew, char tListe[]) {
126 signed char iPositionNew = GetPosition(cNew, tListe);
127 if (iPositionNew == -1) {
128 // not found
129 return 0;
130 }
131
132 return iPositionNew - CURSOR_1;
133}
134
135static bool TesterEstDansListe(char c, char tListe[]) {
136 // char in the list ?
137 return GetPosition(c, tListe) != -1;
138}
139
140static void SmartRotation(char c, char tListe[]) {
141 signed char i = GetDistance(c, tListe);
142 if (i == 0) return;
143
144 // rotate in the shorter way
145 if (i < 0) {
146 rotate_left(tListe);
147 return;
148 }
149
150 if (i > 0) {
151 rotate_right(tListe);
152 return;
153 }
154}
155
156static void update_list(char cNouveau, char tListe[]) {
157 signed char iDistance = GetDistance(cNouveau, tListe);
158 if (iDistance != 0) {
159 // the new char is in the list : rotation
160 SmartRotation(cNouveau, tListe);
161 }
162}
163
164static void draw_arc_sector_16(uint8_t x, uint8_t y, uint8_t radius, int position, bool color) {
165 unsigned int s = 1;
166 s = s << (position / 2);
167
168 if (position % 4 == 0 || position % 4 == 3) {
169 draw_arc_sector(x, y, radius, s, 1, color);
170 } else {
171 draw_arc_sector(x, y, radius, s, 2, color);
172 }
173}
174
175static void render_set(uint8_t x, uint8_t y, uint8_t r, int p, bool color) {
176 // 2 pixels arc sector
177 draw_arc_sector_16(x, y, r, p, color);
178 draw_arc_sector_16(x, y, r - 1, p, color);
179}
180
181static void draw_letter_circle(char t[], char tRef[], char ct, uint8_t x, uint8_t y, uint8_t r, bool invert) {
182 char c = t[CURSOR_1];
183
184 signed char p = GetPosition(c, tRef);
185 signed char pt = GetPosition(ct, tRef);
186
187 if (!invert) {
188 draw_fill_circle(x, y, r, false);
189 draw_circle(x, y, r, false);
190 draw_circle(x, y, r - 1, false);
191 draw_circle(x, y, r - 2, false);
192 draw_circle(x, y, r - 4, true);
193 draw_circle(x, y, r - 5, true);
194 }
195
196 int pafter = (pt + 1) % SIZE_ARRAY_1;
197 int pbefore = (pt + SIZE_ARRAY_1 - 1) % SIZE_ARRAY_1;
198 render_set(x, y, r, pt, true);
199 render_set(x, y, r, pafter, true);
200 render_set(x, y, r, pbefore, true);
201
202 pafter = (pt + 2) % SIZE_ARRAY_1;
203 pbefore = (pt + SIZE_ARRAY_1 - 2) % SIZE_ARRAY_1;
204 render_set(x, y, r, pafter, true);
205 render_set(x, y, r, pbefore, true);
206
207 r -= 4;
208
209 pafter = (p + 1) % SIZE_ARRAY_1;
210 pbefore = (p + SIZE_ARRAY_1 - 1) % SIZE_ARRAY_1;
211
212 render_set(x, y, r, p, false);
213 render_set(x, y, r, pafter, false);
214 render_set(x, y, r, pbefore, false);
215
216 draw_circle(x, y, r - 6, true);
217}
218
219static void draw_center_circle_frame(uint8_t x, uint8_t y, uint8_t r, uint8_t f) {
220 draw_fill_circle(x, y, r, 0);
221 draw_circle(x, y, r, 0);
222
223 if (f == 0) {
224 draw_circle(x, y, r, 1);
225 } else {
226 // animation
227 oled_write_raw_P_cursor(0, 11, raw_circle[f - 1], sizeof(raw_circle[f - 1]));
228 }
229}
230
231static void render_anim_center_circle(uint8_t x, uint8_t y, uint8_t r) {
232 if (anim_center_current_frame == ANIM_CENTER_FRAME_NUMBER) {
233 // last frame : no animation
234 return;
235 }
236
237 if (timer_elapsed(anim_center_timer) > ANIM_CENTER_FRAME_DURATION) {
238 anim_center_timer = timer_read();
239
240 draw_center_circle_frame(x, y, r, anim_center_current_frame);
241
242 anim_center_current_frame++;
243 }
244}
245
246static void write_char(char c) {
247 // write keylog char in the frame then offset to center
248 oled_set_cursor(2, 6);
249 oled_write_char(c, false);
250 move_block(12, 48, 6, 8, 2);
251}
252
253static void render_keylog(gui_state_t t) {
254 if (anim_keylog_current_frame != ANIM_KEYLOG_FRAME_NUMBER) {
255 if (timer_elapsed(anim_keylog_timer) > ANIM_KEYLOG_FRAME_DURATION) {
256 // update frame number
257 anim_keylog_timer = timer_read();
258 anim_keylog_current_frame++;
259 }
260
261 // clean frame
262 draw_rectangle_fill(7, 46, 21, 11, false);
263
264 // comb motion to merge current and previous
265 if (anim_keylog_current_frame < ANIM_KEYLOG_FRAME_NUMBER / 2) {
266 // expand the previous char
267 write_char(c_previous);
268 draw_glitch_comb(9, 6 * 8, 18, 8, anim_keylog_current_frame + 1, true);
269 } else {
270 // shrink the current char
271 write_char(c_last);
272 draw_glitch_comb(9, 6 * 8, 18, 8, ANIM_KEYLOG_FRAME_NUMBER - anim_keylog_current_frame, false);
273 }
274
275 return;
276 }
277
278 write_char(c_last);
279}
280
281void reset_ring(void) {
282 // need to open
283 anim_sleep_ring_timer = timer_read();
284 current_sleep_ring_frame = ANIM_SLEEP_RING_FRAME_NUMBER - 1;
285 sleep_ring_frame_destination = 0;
286}
287
288static void render_tv_circle(uint8_t x, uint8_t y, uint8_t r, uint8_t f) {
289 // raw image
290 if (f == 2 || f == 3) {
291 oled_write_raw_P_cursor(0, 12, raw_ring_sleep[f - 2], sizeof(raw_ring_sleep[f - 2]));
292 return;
293 }
294
295 // raw image
296 if (f == 5 || f == 6) {
297 oled_write_raw_P_cursor(0, 12, raw_ring_sleep[f - 3], sizeof(raw_ring_sleep[f - 3]));
298 return;
299 }
300
301 // other frames : lighter to draw than using raw image
302 switch (f) {
303 case 1:
304 draw_circle(x, y, r, 1);
305 break;
306
307 case 4:
308 drawline_hr(1, y, 12, 1);
309 drawline_hr(19, y, 12, 1);
310 drawline_vb(0, y - 1, 3, true);
311 drawline_vb(31, y - 1, 3, true);
312 break;
313
314 case 7:
315
316 oled_write_pixel(1, y, true);
317 oled_write_pixel(3, y, true);
318 oled_write_pixel(28, y, true);
319 oled_write_pixel(30, y, true);
320
321 drawline_vb(0, y - 12, 26, true);
322 drawline_vb(31, y - 12, 26, true);
323 break;
324
325 case 8:
326 drawline_vb(0, 88, 32, true);
327 drawline_vb(31, 88, 32, true);
328 break;
329 }
330}
331
332static void render_circle_white(void) {
333 // top
334 oled_write_raw_P_cursor(0, 5, raw_middle, sizeof(raw_middle));
335 drawline_hr(5, 39, 25, 1);
336
337 // clean center
338 draw_rectangle_fill(0, 80, 32, 40, false);
339
340 // bottom
341 drawline_vb(0, 80, 8, 1);
342 drawline_vb(31, 80, 8, 1);
343 oled_write_pixel(1, 80, true);
344 oled_write_pixel(30, 80, true);
345
346 oled_write_raw_P_cursor(0, 15, raw_bottom, sizeof(raw_bottom));
347}
348
349static void render_ring_clean_close(void) {
350 render_circle_white();
351 drawline_vb(0, 88, 32, true);
352 drawline_vb(31, 88, 32, true);
353}
354
355static void render_glitch_square(void) {
356 if (timer_elapsed(anim_ring_idle_timer) > 60) {
357 anim_ring_idle_timer = timer_read();
358
359 render_ring_clean_close();
360
361 uint8_t size = 0;
362 for (uint8_t i = 0; i < 4; i++) {
363 size = 4 + (fastrand() % 6);
364 draw_rectangle_fill(3 + (fastrand() % 19), 85 + (fastrand() % 20), size, size, true);
365
366 size = (fastrand() % 6);
367 draw_rectangle_fill(3 + (fastrand() % 19), 100 + (fastrand() % 20), size, size, true);
368 }
369 }
370}
371
372static void render_ring_idle(void) {
373 uint8_t glitch_prob = get_glitch_probability();
374 get_glitch_index(&glitch_ring_timer, &current_glitch_ring_time, &current_glitch_ring_index, 150, 350, glitch_prob, 2);
375
376 switch (current_glitch_ring_index) {
377 case 0:
378 // no glitch
379 render_ring_clean_close();
380 return;
381 case 1:
382 // square gliches
383 render_glitch_square();
384 return;
385 }
386}
387
388static void render_ring_sleep(void) {
389 if (current_sleep_ring_frame == sleep_ring_frame_destination) {
390 // no more animation needes : render the idle animation
391 render_ring_idle();
392 return;
393 }
394
395 // display wacking up / sleep animation
396 if (timer_elapsed(anim_sleep_ring_timer) > ANIM_SLEEP_RING_FRAME_DURATION) {
397 anim_sleep_ring_timer = timer_read();
398
399 // clean + new frame
400 render_circle_white();
401 render_tv_circle(15, 103, 11, current_sleep_ring_frame);
402
403 // update frame number
404 if (sleep_ring_frame_destination > current_sleep_ring_frame) {
405 current_sleep_ring_frame++;
406 } else {
407 current_sleep_ring_frame--;
408 }
409 }
410}
411
412static void render_circle_middle(void) {
413 // clean
414 render_circle_white();
415
416 // center special animation
417 if (anim_center_current_frame < ANIM_CENTER_FRAME_NUMBER) {
418 render_anim_center_circle(15, 103, 15 - 4);
419 return;
420 }
421
422 // ring render
423 if (anim_center_current_frame == ANIM_CENTER_FRAME_NUMBER) {
424 draw_letter_circle(tListeTotal, tRefArc, c_target, 15, 103, 15, false);
425 draw_letter_circle(tListeTotal2, tRefArc2, c_target2, 15, 103, 15, true);
426 }
427}
428
429void render_circle(gui_state_t t) {
430 if (timer_elapsed(circle_timer) > CIRCLE_ANIM_FRAME_DURATION) {
431 // new frame
432 circle_timer = timer_read();
433
434 // shift rings
435 update_list(c_target, tListeTotal);
436 update_list(c_target2, tListeTotal2);
437
438 // waking up animation
439 if (t == _WAKINGUP) {
440 render_ring_sleep();
441 return;
442 }
443
444 // idle animation
445 if (t == _IDLE) {
446 sleep_ring_frame_destination = ANIM_SLEEP_RING_FRAME_NUMBER - 1;
447 render_ring_sleep();
448 return;
449 }
450
451 // render on display
452 render_circle_middle();
453 render_keylog(t);
454 }
455}
456
457void update_circle(uint16_t keycode) {
458 // special animation for special keys
459 if (keycode == KC_ESC || keycode == KC_SPACE || keycode == KC_ENTER) {
460 anim_center_timer = timer_read();
461 anim_center_current_frame = 0;
462 return;
463 }
464
465 // cancel special animation on a new key
466 anim_center_current_frame = ANIM_CENTER_FRAME_NUMBER;
467
468 // out of scope key
469 if (keycode >= 60) {
470 return;
471 }
472
473 // keycode to char
474 char c = pgm_read_byte(&code_to_name[keycode]);
475
476 // stock previous char
477 c_previous = c_last;
478 c_last = c;
479
480 // start keylog animation
481 anim_keylog_current_frame = 0;
482
483 // update target in ring #1 position
484 if (TesterEstDansListe(c, tListeTotal)) {
485 c_target = c;
486 return;
487 }
488
489 // update target in #2 position
490 if (TesterEstDansListe(c, tListeTotal2)) {
491 c_target2 = c;
492 return;
493 }
494}
diff --git a/keyboards/lily58/keymaps/druotoni/ring.h b/keyboards/lily58/keymaps/druotoni/ring.h
new file mode 100644
index 000000000..9ce4520e6
--- /dev/null
+++ b/keyboards/lily58/keymaps/druotoni/ring.h
@@ -0,0 +1,11 @@
1// Copyright 2021 Nicolas Druoton (druotoni)
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#define SIZE_ARRAY_1 16
7#define CURSOR_1 9
8
9void update_circle(uint16_t);
10void render_circle(gui_state_t t);
11void reset_ring(void);
diff --git a/keyboards/lily58/keymaps/druotoni/rules.mk b/keyboards/lily58/keymaps/druotoni/rules.mk
new file mode 100644
index 000000000..c07761108
--- /dev/null
+++ b/keyboards/lily58/keymaps/druotoni/rules.mk
@@ -0,0 +1,28 @@
1# Build Options
2# change to "no" to disable the options, or define them in the Makefile in
3# the appropriate keymap folder that will get included automatically
4#
5RGBLIGHT_ENABLE = yes # Enable WS2812 RGB underlight.
6
7# Bootloader selection
8BOOTLOADER = atmel-dfu
9
10# Do not enable SLEEP_LED_ENABLE. it uses the same timer as BACKLIGHT_ENABLE
11SLEEP_LED_ENABLE = no # Breathing sleep LED during USB suspend
12# EXTRAFLAGS += -flto
13LTO_ENABLE = yes
14SPACE_CADET_ENABLE = no
15GRAVE_ESC_ENABLE = no
16MAGIC_ENABLE = no
17
18# If you want to change the display of OLED, you need to change here
19SRC += ./lib/rgb_state_reader.c \
20 ./burst.c \
21 ./navi_logo.c \
22 ./gui_state.c \
23 ./fast_random.c \
24 ./layer_frame.c \
25 ./ring.c \
26 ./boot.c \
27 ./draw_helper.c \
28