diff --git a/boot.c b/boot.c new file mode 100644 index 0000000..ba46f8e --- /dev/null +++ b/boot.c @@ -0,0 +1,309 @@ +// Copyright 2021 Nicolas Druoton (druotoni) +// SPDX-License-Identifier: GPL-2.0-or-later + +#include QMK_KEYBOARD_H + +#include "boot.h" +#include "fast_random.h" +#include "draw_helper.h" +#include "gui_state.h" + +// boot +#define ANIM_BOOT_FRAME_DURATION 8 +uint16_t anim_boot_timer = 0; +uint8_t anim_boot_current_frame = 0; + +#define NAVI_DURATION 55 + +// terminal stuff +#define TERMINAL_DURATION 25 +#define TERMINAL_LINE_NUMBER 19 +#define TERMINAL_LINE_MAX 14 + +#define LILY_DURATION 50 + +// halt +#define ANIM_HALT_FRAME_DURATION 55 +uint16_t anim_halt_timer = 0; + +void reset_boot(void) { + // frame zero + anim_boot_current_frame = 0; +} + +static void draw_lily_key(uint8_t x, uint8_t y, uint8_t *key_number, unsigned long key_state, uint8_t color) { + uint8_t v = *key_number; + unsigned long mask = 1; + mask = mask << v; + + // ligth the key according to the mask + if (((key_state & mask) == mask)) { + color = !color; + } + + draw_rectangle_fill(x, y, 3, 3, color); + *key_number = v + 1; +} + +static void draw_lily_key_row(uint8_t x, uint8_t y, int w, uint8_t *key_number, unsigned long key_state, uint8_t color) { + // row of rectangle + for (uint8_t i = 0; i < w; i++) { + draw_lily_key(x + (i * 4), y, key_number, key_state, color); + } +} + +static void draw_lily_render(unsigned long key_state) { + // different orientation base on side +#if IS_LEFT + + uint8_t x = 0; + uint8_t y = 56; + uint8_t x_ref = 10 + x; + uint8_t y_ref = 2 + y; + uint8_t i_key_number = 0; + + for (uint8_t i = 0; i < 4; i++) { + draw_lily_key_row(x_ref, y_ref + (i * 4), 4, &i_key_number, key_state, true); + draw_lily_key_row(x_ref - 8, y_ref + 2 + (i * 4), 2, &i_key_number, key_state, true); + } + + draw_lily_key_row(x_ref + 2, y_ref + (4 * 4), 3, &i_key_number, key_state, true); + + uint8_t x_side = x_ref + (4 * 4); + + draw_lily_key(x_side, y_ref + (2 * 4) + 2, &i_key_number, key_state, true); + draw_lily_key(x_side, y_ref + (4 * 4), &i_key_number, key_state, true); + + // screen + draw_rectangle(x_side, y_ref, 4, 8, true); + + // frame + drawline_hr(x + 1, y + 2, 8, true); + oled_write_pixel(x + 8, y + 1, true); + drawline_hr(x + 8, y, 23, true); + + drawline_hr(x + 1, y + 20, 10, true); + oled_write_pixel(x + 10, y + 21, true); + drawline_hr(x + 10, y + 22, 16, true); + + drawline_vb(x, y + 3, 17, true); + drawline_vb(x + 31, y + 1, 20, true); + oled_write_pixel(x + 30, y + 21, true); + oled_write_pixel(x + 29, y + 22, true); + oled_write_pixel(x + 28, y + 23, true); + oled_write_pixel(x + 27, y + 24, true); + oled_write_pixel(x + 26, y + 23, true); +#endif + +#if IS_RIGHT + uint8_t i_key_number = 0; + + for (uint8_t i = 0; i < 4; i++) { + draw_lily_key_row(7, 58 + (i * 4), 4, &i_key_number, key_state, true); + draw_lily_key_row(23, 60 + (i * 4), 2, &i_key_number, key_state, true); + } + + draw_lily_key_row(9, 74, 3, &i_key_number, key_state, true); + + draw_lily_key(3, 68, &i_key_number, key_state, true); + draw_lily_key(3, 74, &i_key_number, key_state, true); + + // screen + draw_rectangle(2, 58, 4, 8, true); + + // frame + drawline_hr(23, 58, 8, true); + oled_write_pixel(23, 57, true); + drawline_hr(1, 56, 23, true); + + drawline_hr(21, 76, 10, true); + oled_write_pixel(21, 77, true); + drawline_hr(6, 78, 16, true); + + drawline_vb(31, 59, 17, true); + drawline_vb(0, 57, 20, true); + oled_write_pixel(1, 77, true); + oled_write_pixel(2, 78, true); + oled_write_pixel(3, 79, true); + oled_write_pixel(4, 80, true); + oled_write_pixel(5, 79, true); +#endif +} + +static void draw_lily(uint8_t f) { + // frame for the events + uint8_t tres_stroke = 10; + uint8_t tres_boom = 30; + uint8_t y_start = 56; + + if (f == 0 || f == tres_stroke || f == tres_boom) { + // clean screen + oled_clear(); + } + + // simple lily58 with all the keys + if (f < tres_stroke) { + draw_lily_render(0); + } + + // increase number of random keys pressed + if (f >= tres_stroke && f < tres_boom) { + int inter_f = interpo_pourcent(tres_stroke, tres_boom, f); + + unsigned long key_state = fastrand_long(); + for (int r = 100 - inter_f; r > 0; r = r - 10) { + key_state &= fastrand_long(); + } + draw_lily_render(key_state); + } + + // statir explosion + if (f >= tres_boom) { + oled_clear(); + uint8_t density = (f - tres_boom); + if (density > 4) density = 4; + draw_static(0, y_start - 8, 32, 32, true, density); + } +} + +static void draw_startup_navi(uint8_t f) { + // text + oled_write_cursor(0, 5, "HELL0", false); + oled_write_cursor(0, 7, "NAVI.", false); + + // prompt + if ((f % 8) > 4) { + oled_write_cursor(0, 12, "> ", false); + } else { + oled_write_cursor(0, 12, ">_", false); + } + + // frame threshold + uint8_t tres_shell = 15; + uint8_t tres_load = 35; + + // rand text to init display + if (f > tres_shell) { + int inter_f = interpo_pourcent(tres_shell, tres_load, f); + + draw_random_char(1, 12, 'i', 60 + inter_f, 0); + draw_random_char(2, 12, 'n', 20 + inter_f, 0); + draw_random_char(3, 12, 'i', inter_f, 0); + draw_random_char(4, 12, 't', 20 + inter_f, 0); + } + + // loading propress bar + if (f > tres_load) { + int inter_f = interpo_pourcent(tres_load, 50, f); + + // ease + float fv = inter_f / 100.00; + fv = fv * fv * fv * fv; + inter_f = fv * 100; + + draw_rectangle(0, (15 * 8), 32, 8, 1); + draw_progress(0 + 3, (15 * 8) + 3, 26, 2, inter_f, 0, 1); + } +} + +// text dispayed on terminal +static char *boot_ref[TERMINAL_LINE_NUMBER] = {"LT:", "RT:", "M :", " ", "cnx:", "A0:", "B0:", " ", "0x40", "0x60", "0x85", "0x0F", " ", "> run", "x ", "y ", " 100%", " ", "> key"}; + +// prompt style for char in the font +char scan_font[5] = {'>', 1, 1, 1, 1}; + +static char *get_terminal_line(uint8_t i) { + // display text + if (i < TERMINAL_LINE_NUMBER) { + return boot_ref[i]; + } + + // blank line every 3 lines + if (i % 3 == 0) { + return " "; + } + + // display consecutive chars in the font + i = (i - TERMINAL_LINE_NUMBER) * 4; + + scan_font[1] = i; + scan_font[2] = i + 1; + scan_font[3] = i + 2; + scan_font[4] = i + 3; + + return scan_font; +} + +static void draw_startup_terminal(uint8_t f) { + // ease for printing on screen + f = f * 2; + f += (f / 5); + + // scroll text + uint8_t i_start = 0; + uint8_t i_nb_char = f; + + if (f > TERMINAL_LINE_MAX) { + i_start = f - TERMINAL_LINE_MAX; + i_nb_char = TERMINAL_LINE_MAX; + } + + // display lines + oled_clear(); + for (uint8_t i = 0; i < i_nb_char; i++) { + char *s = get_terminal_line(i + i_start); + oled_write_cursor(0, i, s, false); + } +} + +bool render_boot(void) { + // end of the boot sequence + if (anim_boot_current_frame >= NAVI_DURATION + TERMINAL_DURATION + LILY_DURATION) { + anim_boot_current_frame = 0; + oled_clear(); + return true; + } + + if (timer_elapsed(anim_boot_timer) > ANIM_BOOT_FRAME_DURATION) { + anim_boot_timer = timer_read(); + if (anim_boot_current_frame < NAVI_DURATION) { + // 55 frames + draw_startup_navi(anim_boot_current_frame); + } else { + if (anim_boot_current_frame >= NAVI_DURATION && anim_boot_current_frame < NAVI_DURATION + TERMINAL_DURATION) { + // 25 + draw_startup_terminal(anim_boot_current_frame - NAVI_DURATION); + } else { + if (anim_boot_current_frame >= NAVI_DURATION + TERMINAL_DURATION) { + // 25 + draw_lily(anim_boot_current_frame - NAVI_DURATION - TERMINAL_DURATION); + } + } + } + + anim_boot_current_frame++; + } + return false; +} + +void render_halt(void) { + if (timer_elapsed(anim_halt_timer) > ANIM_HALT_FRAME_DURATION) { + anim_halt_timer = timer_read(); + + // comb glitch for all the screen + draw_glitch_comb(0, 0, 32, 128, 3, true); + + // random moving blocks of pixels + for (uint8_t i = 0; i < 6; i++) { + int r = fastrand(); + int rr = fastrand(); + uint8_t x = 4 + r % 28; + uint8_t y = rr % 128; + + uint8_t w = 7 + r % 20; + uint8_t h = 3 + rr % 10; + int s = (fastrand() % 20) - 10; + move_block(x, y, w, h, s); + } + } +} diff --git a/boot.h b/boot.h new file mode 100644 index 0000000..7897e17 --- /dev/null +++ b/boot.h @@ -0,0 +1,9 @@ +// Copyright 2021 Nicolas Druoton (druotoni) +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +bool render_boot(void); +void render_halt(void); + +void reset_boot(void); \ No newline at end of file diff --git a/burst.c b/burst.c new file mode 100644 index 0000000..6dd6579 --- /dev/null +++ b/burst.c @@ -0,0 +1,252 @@ +// Copyright 2021 Nicolas Druoton (druotoni) +// Copyright 2020 Richard Sutherland (rich@brickbots.com) +// SPDX-License-Identifier: GPL-2.0-or-later + +#include QMK_KEYBOARD_H + +#include "gui_state.h" +#include "fast_random.h" +#include "burst.h" +#include "draw_helper.h" + +// burst stuff +static int current_burst = 0; +static uint16_t burst_timer = 0; + +// WPM stuff +static int current_wpm = 0; +static uint16_t wpm_timer = 0; + +// This smoothing is 40 keystrokes +static const float wpm_smoothing = WPM_SMOOTHING; + +// store values +uint8_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}; +uint8_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}; + +// current max wpm +int max_wpm = MAX_WPM_INIT; + +// scope animation stuff +#define ANIM_SCOPE_FRAME_DURATION 40 +#define ANIM_SLEEP_SCOPE_FRAME_NUMBER 10 + +uint16_t anim_scope_timer = 0; +uint16_t anim_scope_idle_timer = 0; +uint16_t anim_sleep_scope_timer = 0; + +uint8_t anim_sleep_scope_duration[ANIM_SLEEP_SCOPE_FRAME_NUMBER] = {30, 30, 30, 30, 20, 20, 30, 30, 32, 35}; +uint8_t current_sleep_scope_frame = 0; +uint8_t sleep_scope_frame_destination = ANIM_SLEEP_SCOPE_FRAME_NUMBER - 1; + +// glitch animation +int current_glitch_scope_time = 150; +uint32_t glitch_scope_timer = 0; +uint8_t current_glitch_scope_index = 0; + +static void update_wpm(void) { + if (wpm_timer > 0) { + current_wpm += ((60000 / timer_elapsed(wpm_timer) / WPM_ESTIMATED_WORD_SIZE) - current_wpm) * wpm_smoothing; + if (current_wpm > LIMIT_MAX_WPM) { + current_wpm = LIMIT_MAX_WPM; + } + } + wpm_timer = timer_read(); +} + +void update_scope(void) { + update_wpm(); + + uint16_t temps_ecoule = timer_elapsed(burst_timer); + + if (temps_ecoule > BURST_FENETRE) { + // 1er frappe après longtemps + current_burst = 40; + } else { + int time_pourcent = ((100 * (temps_ecoule)) / (BURST_FENETRE)); + current_burst = 100 - time_pourcent; + } + burst_timer = timer_read(); +} + +static void update_scope_array(void) { + // shift array + for (uint8_t i = 0; i < SIZE_SCOPE - 1; i++) { + burst_scope[i] = burst_scope[i + 1]; + wpm_scope[i] = wpm_scope[i + 1]; + } + + int burst = current_burst; + int wpm = current_wpm; + + // compute max wpm + max_wpm = (wpm == 0) ? MAX_WPM_INIT : ((wpm > max_wpm) ? wpm : max_wpm); + + // current wpm ratio VS max + wpm = (100 * wpm) / max_wpm; + if (wpm > 100) wpm = 100; + + // update last slot of the arrays + burst_scope[SIZE_SCOPE - 1] = burst; + wpm_scope[SIZE_SCOPE - 1] = wpm; + + // apply decay to burst chart + uint8_t pBaisse = 0; + for (uint8_t i = 0; i < SIZE_SCOPE - (SIZE_SCOPE / 4); i++) { + pBaisse = 2 + ((SIZE_SCOPE - 1 - i)) / 2; + burst_scope[i] -= ((burst_scope[i] * pBaisse) / 100); + } +} + +static void RenderScopeBlack(void) { + // clean central zone + draw_rectangle_fill(3, 82, 28, 120, false); + + // redraw some parts of the frame + drawline_hr(1, SCOPE_Y_BOTTOM, 32, 1); + drawline_vt(0, SCOPE_Y_BOTTOM - 1, 42, 1); + drawline_vt(31, SCOPE_Y_BOTTOM - 1, 47, 1); +} + +static void render_scope_white(void) { + static const char PROGMEM raw_logo[] = { + 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, + }; + oled_write_raw_P_cursor(0, 10, raw_logo, sizeof(raw_logo)); +} + +static void render_scope_chart(void) { + // clean the frame + render_scope_white(); + + uint8_t y_offset = SCOPE_Y_BOTTOM - 3; + + for (uint8_t i = 0; i < SIZE_SCOPE; i++) { + // offset + uint8_t x = 3 + i; + + // new black vertical line for burst + uint8_t iCurrentBurst = burst_scope[i]; + drawline_vt(x, y_offset, (iCurrentBurst * 4) / 10, 0); + + // new black point for wpm, white if it's on the burst line + uint8_t iCurrentWpm = wpm_scope[i]; + uint8_t yWpm = y_offset - ((iCurrentWpm * 4) / 10); + oled_write_pixel(x, yWpm, !(iCurrentWpm > iCurrentBurst)); + } +} + +void reset_scope(void) { + // scope need wakeup + anim_sleep_scope_timer = timer_read(); + current_sleep_scope_frame = ANIM_SLEEP_SCOPE_FRAME_NUMBER - 1; + + sleep_scope_frame_destination = 0; +} + +static void render_glitch_square(void) { + if (timer_elapsed(anim_scope_idle_timer) > 60) { + anim_scope_idle_timer = timer_read(); + RenderScopeBlack(); + + uint8_t color = 0; + uint8_t size = 0; + for (uint8_t i = 0; i < 4; i++) { + size = 4 + (fastrand() % 6); + + draw_gradient(3 + (fastrand() % 19), 85 + (fastrand() % 20), size, size, 255, 255, 4); + + size = (fastrand() % 6); + color = 100 + (fastrand() % 100); + draw_gradient(3 + (fastrand() % 19), 100 + (fastrand() % 20), size, size, color, color, 4); + } + } +} + +void render_scope_idle(void) { + uint8_t glitch_prob = get_glitch_probability(); + get_glitch_index(&glitch_scope_timer, ¤t_glitch_scope_time, ¤t_glitch_scope_index, 150, 350, glitch_prob, 2); + + switch (current_glitch_scope_index) { + case 0: + RenderScopeBlack(); + return; + case 1: + render_glitch_square(); + return; + } +} + +static void RenderScopeSleep(void) { + if (current_sleep_scope_frame == sleep_scope_frame_destination) { + // animation finished + render_scope_idle(); + return; + } + + if (timer_elapsed(anim_sleep_scope_timer) > anim_sleep_scope_duration[current_sleep_scope_frame]) { + anim_sleep_scope_timer = timer_read(); + + // clean scope + RenderScopeBlack(); + + // render animation + render_tv_animation(current_sleep_scope_frame, 3, 80, 25, 48); + + // update frame number + if (sleep_scope_frame_destination > current_sleep_scope_frame) { + current_sleep_scope_frame++; + } else { + current_sleep_scope_frame--; + } + } +} + +void render_scope(gui_state_t t) { + if (timer_elapsed(anim_scope_timer) > ANIM_SCOPE_FRAME_DURATION) { + anim_scope_timer = timer_read(); + + // shift arrays + update_scope_array(); + + // oled_set_cursor(0, 10); + + if (t == _WAKINGUP) { + RenderScopeSleep(); + return; + } + + if (t == _IDLE) { + sleep_scope_frame_destination = ANIM_SLEEP_SCOPE_FRAME_NUMBER - 1; + RenderScopeSleep(); + return; + } + + render_scope_chart(); + } +} + +static void decay_burst(void) { + uint16_t temps_ecoule = timer_elapsed(burst_timer); + + int poucentageEcoule = 100; + + if (temps_ecoule <= BURST_FENETRE * 4) { + poucentageEcoule = ((100 * (temps_ecoule)) / (BURST_FENETRE * 4)); + } + + current_burst = current_burst - poucentageEcoule; + if (current_burst <= 0) current_burst = 0; +} + +static void decay_wpm(void) { + if (timer_elapsed(wpm_timer) > 1000) { + wpm_timer = timer_read(); + current_wpm += (-current_wpm) * wpm_smoothing; + } +} + +void decay_scope(void) { + decay_burst(); + decay_wpm(); +} diff --git a/burst.h b/burst.h new file mode 100644 index 0000000..8bc8153 --- /dev/null +++ b/burst.h @@ -0,0 +1,24 @@ +// Copyright 2021 Nicolas Druoton (druotoni) +// Copyright 2020 Richard Sutherland (rich@brickbots.com) +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +// burst +#define MAX_WPM_INIT 40 +#define BURST_FENETRE 500 + +// wpm +#define LIMIT_MAX_WPM 150 +#define WPM_ESTIMATED_WORD_SIZE 5 +#define WPM_SMOOTHING 0.0487 + +// scope +#define SIZE_SCOPE 26 +#define SCOPE_Y_BOTTOM 127 + +void update_scope(void); +void render_scope(gui_state_t t); + +void reset_scope(void); +void decay_scope(void); diff --git a/config.h b/config.h index a41c975..c198df9 100644 --- a/config.h +++ b/config.h @@ -1,37 +1,53 @@ -/* -This is the c configuration file for the keymap - -Copyright 2012 Jun Wako -Copyright 2015 Jack Humbert - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . -*/ +// Copyright 2021 Nicolas Druoton (druotoni) +// Copyright 2012 Jun Wako +// Copyright 2015 Jack Humbert +// SPDX-License-Identifier: GPL-2.0-or-later #pragma once +#define MASTER_LEFT +#define OLED_DRIVER_ENABLE + +// tapping toggle for my layers +#define TAPPING_TOGGLE 2 + +// choose IS_LEFT or IS_RIGHT for compilation and flash firmware +#define IS_LEFT 1 +//#define IS_RIGHT 1 + +// logo glitch +#define WITH_GLITCH +// boot sequence +#define WITH_BOOT + +// custom transport for displaying on both side +#define SPLIT_TRANSACTION_IDS_USER USER_SYNC_A + +// custom font +#ifdef OLED_FONT_H +#undef OLED_FONT_H +#endif +#define OLED_FONT_H "navi_font.c" +#undef OLED_FONT_END +#define OLED_FONT_END 125 + +// more space #define NO_ACTION_MACRO #define NO_ACTION_FUNCTION -#define DISABLE_LEADER -#define MASTER_LEFT -#define EE_HANDS -#define SPLIT_USB_DETECT - -#define TAPPING_FORCE_HOLD -#define TAPPING_TERM 100 - #define NO_ACTION_ONESHOT +#define DISABLE_LEADER -#define SPLIT_LAYER_STATE_ENABLE -#define SPLIT_WPM_ENABLE -#define SPLIT_OLED_ENABLE +// ??? +#undef LOCKING_SUPPORT_ENABLE +#undef LOCKING_RESYNC_ENABLE + +// small layer state +#define LAYER_STATE_8BIT + +// no debug or trace +#ifndef NO_DEBUG +#define NO_DEBUG +#endif +#if !defined(NO_PRINT) && !defined(CONSOLE_ENABLE) +#define NO_PRINT +#endif diff --git a/draw_helper.c b/draw_helper.c new file mode 100644 index 0000000..c6761d7 --- /dev/null +++ b/draw_helper.c @@ -0,0 +1,768 @@ +// Copyright 2021 Nicolas Druoton (druotoni) +// Copyright 2021 ugfx +// SPDX-License-Identifier: GPL-2.0-or-later + +#include QMK_KEYBOARD_H + +#include "draw_helper.h" +#include "fast_random.h" + +void drawline(uint8_t x, uint8_t y, uint8_t width, bool bHorizontal, bool bPositiveDirection, bool color) { + if (width <= 0) return; + uint8_t yPlus = 0; + uint8_t yMois = 0; + uint8_t nbtour = 0; + + if (!bPositiveDirection) { + if (bHorizontal) { + x -= width; + } else { + y -= width; + } + } + + yMois = (width / 2) - 1 + (width % 2); + + yPlus = (width / 2); + nbtour = (width / 4) + 1; + + bool bWhite = color; + + if (bHorizontal) { + for (uint8_t i = 0; i < nbtour; i++) { + oled_write_pixel(x + yPlus + i, y, bWhite); + oled_write_pixel(x + yMois - i, y, bWhite); + + oled_write_pixel(x + i, y, bWhite); + oled_write_pixel(x + width - 1 - i, y, bWhite); + } + } else { + for (uint8_t i = 0; i < nbtour; i++) { + oled_write_pixel(x, y + yPlus + i, bWhite); + oled_write_pixel(x, y + yMois - i, bWhite); + + oled_write_pixel(x, y + i, bWhite); + + oled_write_pixel(x, y + width - 1 - i, bWhite); + } + } +} + +void drawline_vb(uint8_t x, uint8_t y, uint8_t width, bool color) { drawline(x, y, width, false, true, color); } + +void drawline_vt(uint8_t x, uint8_t y, uint8_t width, bool color) { drawline(x, y, width, false, false, color); } + +void drawline_hr(uint8_t x, uint8_t y, uint8_t width, bool color) { drawline(x, y, width, true, true, color); } + +void drawline_hl(uint8_t x, uint8_t y, uint8_t width, bool color) { drawline(x, y, width, true, false, color); } + +void draw_rectangle(uint8_t x, uint8_t y, uint8_t width, uint8_t heigth, bool color) { + drawline_hr(x, y, width, color); + drawline_hr(x, y + heigth - 1, width, color); + drawline_vb(x, y, heigth, color); + drawline_vb(x + width - 1, y, heigth, color); +} + +void draw_rectangle_fill(uint8_t x, uint8_t y, uint8_t width, uint8_t heigth, bool color) { + for (uint8_t i = 0; i < heigth; i++) { + drawline_hr(x, y + i, width, color); + } +} + +void drawline_hr_heigth(uint8_t x, uint8_t y, uint8_t width, uint8_t heigth, bool color) { + for (int i = 0; i < heigth; i++) { + drawline_hr(x, y - i, width, color); + drawline_hr(x, y + i, width, color); + } +} + +void drawline_point_hr(short x, short y, short x1, bool color) { + if (y < 0 || y > 127) return; + + if (x1 < x) { + short iTemp = x; + x = x1; + x1 = iTemp; + } + + if (x1 > 31) x1 = 31; + if (x < 0) x = 0; + if (x > 31) x = 31; + + drawline(x, y, x1 - x, true, true, color); +} + +void flip_flap_x(short px, short py, uint8_t val, bool color) { + oled_write_pixel(px + val, py, color); + oled_write_pixel(px - val, py, color); +} + +void draw_circle(uint8_t x, uint8_t y, uint8_t radius, bool color) { + short a, b, P; + + // Calculate intermediates + a = 1; + b = radius; + P = 4 - radius; + + short py, px; + + // Away we go using Bresenham's circle algorithm + // Optimized to prevent double drawing + px = x; + py = y + b; + oled_write_pixel(px, py, color); + px = x; + py = y - b; + oled_write_pixel(px, py, color); + + flip_flap_x(x, y, b, color); + + do { + flip_flap_x(x, y + b, a, color); + flip_flap_x(x, y - b, a, color); + flip_flap_x(x, y + a, b, color); + flip_flap_x(x, y - a, b, color); + + if (P < 0) + P += 3 + 2 * a++; + else + P += 5 + 2 * (a++ - b--); + } while (a < b); + + flip_flap_x(x, y + b, a, color); + flip_flap_x(x, y - b, a, color); +} + +void draw_ellipse(uint8_t x, uint8_t y, uint8_t a, uint8_t b, bool color) { + int dx, dy; + int a2, b2; + int err, e2; + + // short py, px; + // Calculate intermediates + dx = 0; + dy = b; + a2 = a * a; + b2 = b * b; + err = b2 - (2 * b - 1) * a2; + + // Away we go using Bresenham's ellipse algorithm + do { + flip_flap_x(x, y + dy, dx, color); + flip_flap_x(x, y - dy, dx, color); + + e2 = 2 * err; + if (e2 < (2 * dx + 1) * b2) { + dx++; + err += (2 * dx + 1) * b2; + } + if (e2 > -(2 * dy - 1) * a2) { + dy--; + err -= (2 * dy - 1) * a2; + } + } while (dy >= 0); +} + +void draw_ellipse_fill(uint8_t x, uint8_t y, uint8_t a, uint8_t b, bool color) { return; } +// void draw_ellipse_fill(uint8_t x, uint8_t y, uint8_t a, uint8_t b, uint8_t color) { +// int dx, dy; +// int a2, b2; +// int err, e2; + +// // Calculate intermediates +// dx = 0; +// dy = b; +// a2 = a * a; +// b2 = b * b; +// err = b2 - (2 * b - 1) * a2; + +// short py, px, px1; + +// // Away we go using Bresenham's ellipse algorithm +// // This is optimized to prevent overdrawing by drawing a line only when a y is about to change value +// do { +// e2 = 2 * err; +// if (e2 < (2 * dx + 1) * b2) { +// dx++; +// err += (2 * dx + 1) * b2; +// } +// if (e2 > -(2 * dy - 1) * a2) { +// py = y + dy; +// px = x - dx; +// px1 = x + dx; +// drawline_point_hr(px, py, px1, color); +// if (y) { +// py = y - dy; +// px = x - dx; +// px1 = x + dx; +// drawline_point_hr(px, py, px1, color); +// } +// dy--; +// err -= (2 * dy - 1) * a2; +// } +// } while (dy >= 0); +// } + +bool test_limit(short x, short y) { return !(y < 0 || y > 127 || x < 0 || x > 31); } + +void flip_flap_y_point(short px, short py, short px1, uint8_t val, bool color) { + // firmware size optimisation : one fonction for 2 lines of code + drawline_point_hr(px, py + val, px1, color); + drawline_point_hr(px, py - val, px1, color); +} + +void draw_fill_circle(short x, short y, uint8_t radius, bool color) { + short a, b, P; + + // Calculate intermediates + a = 1; + b = radius; + P = 4 - radius; + + // Away we go using Bresenham's circle algorithm + // This is optimized to prevent overdrawing by drawing a line only when a variable is about to change value + short py, px, px1; + + py = y; + px = x - b; + px1 = x + b; + drawline_point_hr(px, py, px1, color); + + py = y + b; + px = x; + if (test_limit(px, py)) oled_write_pixel(px, py, color); + py = y - b; + px = x; + if (test_limit(px, py)) oled_write_pixel(px, py, color); + do { + flip_flap_y_point(x - b, y, x + b, a, color); + + if (P < 0) { + P += 3 + 2 * a++; + } else { + flip_flap_y_point(x - a, y, x + a, b, color); + + P += 5 + 2 * (a++ - b--); + } + } while (a < b); + + flip_flap_y_point(x - b, y, x + b, a, color); +} + +bool apres_moitie(int a, int b) { return (a > b / 2); } +bool arrive_moitie(int a, int b) { return (a > b / 2); } +bool avant_moitie(int a, int b) { return (a <= b / 2 && !apres_moitie(a, b)); } + +void draw_arc_sector(uint8_t x, uint8_t y, uint8_t radius, unsigned char sectors, unsigned char half, bool color) { + short a, b, P; + short py, px; + // Calculate intermediates + a = 1; // x in many explanations + b = radius; // y in many explanations + P = 4 - radius; + + if (half != 2) { + // Away we go using Bresenham's circle algorithm + // Optimized to prevent double drawing + if (sectors & 0x06) { + px = x; + py = y - b; + oled_write_pixel(px, py, color); + } // Upper upper + if (sectors & 0x60) { + px = x; + py = y + b; + oled_write_pixel(px, py, color); + } // Lower lower + if (sectors & 0x81) { + px = x + b; + py = y; + oled_write_pixel(px, py, color); + } // Right right + if (sectors & 0x18) { + px = x - b; + py = y; + oled_write_pixel(px, py, color); + } // Left left + } + + bool dessiner = false; + + do { + if (half == 1 && arrive_moitie(a, b)) break; + + if (half == 2 && avant_moitie(a, b)) { + dessiner = false; + } else { + dessiner = true; + } + + if (dessiner) { + if (sectors & 0x01) { + px = x + b; + py = y - a; + oled_write_pixel(px, py, color); + } // Upper right right + if (sectors & 0x02) { + px = x + a; + py = y - b; + oled_write_pixel(px, py, color); + } // Upper upper right + if (sectors & 0x04) { + px = x - a; + py = y - b; + oled_write_pixel(px, py, color); + } // Upper upper left + if (sectors & 0x08) { + px = x - b; + py = y - a; + oled_write_pixel(px, py, color); + } // Upper left left + if (sectors & 0x10) { + px = x - b; + py = y + a; + oled_write_pixel(px, py, color); + } // Lower left left + if (sectors & 0x20) { + px = x - a; + py = y + b; + oled_write_pixel(px, py, color); + } // Lower lower left + if (sectors & 0x40) { + px = x + a; + py = y + b; + oled_write_pixel(px, py, color); + } // Lower lower right + if (sectors & 0x80) { + px = x + b; + py = y + a; + oled_write_pixel(px, py, color); + } // Lower right right + } + + if (P < 0) + P += 3 + 2 * a++; + else + P += 5 + 2 * (a++ - b--); + } while (a < b); + + if (half != 1) { + if (sectors & 0xC0) { + px = x + a; + py = y + b; + oled_write_pixel(px, py, color); + } // Lower right + if (sectors & 0x03) { + px = x + a; + py = y - b; + oled_write_pixel(px, py, color); + } // Upper right + if (sectors & 0x30) { + px = x - a; + py = y + b; + oled_write_pixel(px, py, color); + } // Lower left + if (sectors & 0x0C) { + px = x - a; + py = y - b; + oled_write_pixel(px, py, color); + } // Upper left + } +} + +void draw_static(uint8_t x, uint8_t y, uint8_t width, uint8_t heigth, int color, uint8_t density) { + unsigned long rx = fastrand_long(); + unsigned long ry = fastrand_long(); + unsigned long maskx = 1; + unsigned long masky = 1; + unsigned long mask_base = 1; + + // more 1 in the octet + for (int r = 0; r < density; r++) { + rx &= fastrand_long(); + ry &= fastrand_long(); + } + + color = ((rx >> 1) % 2) == 0; + + for (uint8_t i = 0; i < width; i++) { + for (uint8_t j = 0; j < heigth; j++) { + // new mask based on ij loop + maskx = (mask_base << i); + masky = (mask_base << j); + + // logic AND with the masks + if (((rx & maskx) == maskx) && ((ry & masky) == masky)) { + oled_write_pixel(x + i, y + j, color); + } + } + } +} + +void copy_pixel(int from, int shift, unsigned char mask) { + if (shift == 0) return; + + // pixel cluster from + char c_from = get_oled_char(from); + char extract = c_from & mask; + + // pixel cluster shift + char c_from_shift = get_oled_char(from + shift); + c_from_shift &= ~(mask); + c_from_shift |= extract; + oled_write_raw_byte(c_from_shift, from + shift); + + // fill blank with black + c_from &= ~(mask); + oled_write_raw_byte(c_from, from); +} + +void draw_glitch_comb(uint8_t x, uint8_t y, uint8_t width, uint16_t height, uint8_t iSize, bool odd) { + // work only on row + uint16_t y_start = (y / 8) * 32; + uint8_t nb_h = height / 8; + + uint8_t w_max = width; + uint16_t index = y_start + x; + + // shift pair even pixel + int mask_1 = 85; + int mask_2 = 170; + + if (!odd) { + // shift odd pixel + mask_1 = 170; + mask_2 = 85; + } + + // wobble + uint16_t pos = 0; + for (uint16_t j = 0; j < nb_h; j++) { + // next line + index = (y_start + x) + (j * 32); + + for (uint16_t i = 0; i < w_max; i++) { + if (i + iSize < w_max) { + pos = index + i; + copy_pixel(pos + iSize, iSize * -1, mask_1); + } + + if (w_max - 1 - i - iSize >= 0) { + pos = (index + w_max - 1) - i; + copy_pixel(pos - iSize, iSize, mask_2); + } + } + } +} + +void draw_random_char(uint8_t column, uint8_t row, char final_char, int value, uint8_t style) { + if (value < 0) return; + + char c = final_char; + + if (value < 100) { + c = ((fastrand() % 15) + 1); + } + + oled_set_cursor(column, row); + oled_write_char(c, false); +} + +void 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) { + if (timer_elapsed(*glitch_timer) > *current_glitch_scope_time) { + // end of the last glitch period + *glitch_timer = timer_read(); + + // new random glich period + *current_glitch_scope_time = min_time + fastrand() % (max_time - min_time); + + bool bGenerateGlitch = (fastrand() % 100) < glitch_probobility; + if (!bGenerateGlitch) { + // no glitch + *glitch_index = 0; + return; + } + + // get a new glitch index + *glitch_index = fastrand() % glitch_frame_number; + } +} + +uint8_t get_glitch_frame_index(uint8_t glitch_probobility, uint8_t glitch_frame_number) { + bool bGenerateGlitch = (fastrand() % 100) < glitch_probobility; + if (!bGenerateGlitch) { + // no glitch + return 0; + } + + // get a new glitch index + return fastrand() % glitch_frame_number; +} + +uint8_t get_glitch_duration(uint8_t min_time, uint16_t max_time) { return min_time + fastrand() % (max_time - min_time); } + +void 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) { + if (timer_elapsed32(*glitch_timer) > *current_glitch_scope_time) { + // end of the last glitch period + *glitch_timer = timer_read32(); + + // new random glich period + *current_glitch_scope_time = min_time + fastrand() % (max_time - min_time); + + bool bGenerateGlitch = (fastrand() % 100) < glitch_probobility; + if (!bGenerateGlitch) { + // no glitch + *glitch_index = 0; + return; + } + + // get a new glitch index + *glitch_index = fastrand() % glitch_frame_number; + } +} + +void draw_progress(uint8_t x, uint8_t y, uint8_t width, uint8_t heigth, int value, uint8_t style, bool color) { + if (value > 100) { + value = 100; + } + int lenght = (width * value) / 100; + for (uint8_t i = 0; i < lenght; i++) { + switch (style) { + case 0: + drawline_vb(x + i, y, heigth - 1, color); + break; + + // case 1: + // drawline_vb(x + i, y + 1, heigth - 3, ((i % 3) < 2)); + // break; + // case 2: + // // . . . . . + // drawline_vb(x + i, y + 3, 2, ((i % 2) == 0)); + // break; + } + } +} + +void oled_write_raw_P_cursor(uint8_t col, uint8_t line, const char *data, uint16_t size) { + // raw_P at cursor position + oled_set_cursor(col, line); + oled_write_raw_P(data, size); +} + +void oled_write_cursor(uint8_t col, uint8_t line, const char *data, bool invert) { + // write at cursor position + oled_set_cursor(col, line); + oled_write(data, invert); +} + +void draw_label(const char *data, uint8_t len, uint8_t row, int value) { + if (value < 0) return; + if (row >= 16 || row < 0) return; + oled_write_cursor(0, row, data, false); +} + +void draw_box(const char *data, uint8_t len, uint8_t row, long value, uint8_t style) { + if (value < 0) return; + if (row >= 16 || row < 0) return; + + oled_write_cursor(0, row, data, false); + + uint8_t y = row * 8; + + uint8_t x = 6 * len; + uint8_t w = 32 - x; + + if (value < 0) value = 0; + if (value > 100) value = 100; + draw_progress(x, y, w, 7, value, style, 1); +} + +char get_oled_char(uint16_t start_index) { + oled_buffer_reader_t reader; + reader = oled_read_raw(start_index); + return *reader.current_element; +} + +static int get_index_first_block(uint8_t y) { return ((y / 8) * 32); } + +void move_block(uint8_t x, uint8_t y, uint8_t width, uint8_t heigth, int shift) { + // clip + if (x >= 31) return; + if (y >= 127) return; + + int max_screen = 32 - 1; + if ((width + x) > max_screen + 1) width = max_screen + 1 - x; + + if (width <= 1) return; + + if ((heigth + y) > 127) heigth = 127 - y; + if (heigth <= 1) return; + + // [-32 & +32] + if (shift > max_screen) shift = max_screen; + if (shift < -1 * max_screen) shift = -1 * max_screen; + + if ((width + x + shift) > max_screen) width = width - shift; + + int pixelTop = 8 - (y % 8); + int pixelBottom = (y + heigth) % 8; + + unsigned char cMastTop = ~((unsigned)255 >> (pixelTop)); + unsigned char cMastBottom = ~((unsigned)255 << (pixelBottom)); + + int indexFirstBloc = get_index_first_block(y) + x; + int indexFirstBlocFull = get_index_first_block(y + pixelTop) + x; + int indexFirstBlocEnd = get_index_first_block(y + heigth) + x; + + int nbBlockHeigth = (heigth - pixelTop - pixelBottom) / 8; + + if (nbBlockHeigth < 0) { + // just single row + nbBlockHeigth = 0; + cMastBottom = 0; + } + + if (shift < 0) { + for (uint16_t i = 0; i < width; i++) { + copy_pixel(indexFirstBloc + i, shift, cMastTop); + copy_pixel(indexFirstBlocEnd + i, shift, cMastBottom); + + for (uint16_t j = 0; j < nbBlockHeigth; j++) { + copy_pixel(indexFirstBlocFull + i + (j * 32), shift, 255); + } + } + + } else { + for (int i = width - 1; i >= 0; i--) { + copy_pixel(indexFirstBloc + i, shift, cMastTop); + copy_pixel(indexFirstBlocEnd + i, shift, cMastBottom); + + for (uint16_t j = 0; j < nbBlockHeigth; j++) { + copy_pixel(indexFirstBlocFull + i + (j * 32), shift, 255); + } + } + } +} + +int interpo_pourcent(int min, int max, int v) { + // interpolation + float x0 = min; + float x1 = max; + float y0 = 0; + float y1 = 100; + float xp = v; + float yp = y0 + ((y1 - y0) / (x1 - x0)) * (xp - x0); + + return (int)yp; +} + +uint8_t BAYER_PATTERN_4[4][4] = {{15, 135, 45, 165}, {195, 75, 225, 105}, {60, 180, 30, 150}, {240, 120, 210, 90}}; + +void 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) { + bool invert = color_start > color_end; + + if (invert) { + color_start = 255 - color_start; + color_end = 255 - color_end; + } + + int step = (100 / tres); + int step_minus = (100 / (tres - 1)); + int distance = color_end - color_start; + + for (uint8_t i = 0; i < width; i++) { + int position = interpo_pourcent(0, width, i); + + float color = position; + color = ((int)(color / step)) * step_minus; + + color = color_start + ((distance * color) / 100); + + for (uint8_t j = 0; j < heigth; j++) { + uint8_t m = BAYER_PATTERN_4[i % 4][j % 4]; + unsigned char color_d = (color > m) ? !invert : invert; + + oled_write_pixel(x + i, y + j, color_d); + } + } +} + +void render_tv_animation(uint8_t frame_number, uint8_t x, uint8_t y, uint8_t width, uint8_t heigth) { + uint8_t xCenter = x + (width / 2); + uint8_t yCenter = y + (heigth / 2); + + switch (frame_number) { + case 0: + // a fond : allume + drawline_hr_heigth(x, yCenter, width, 17, true); + break; + + case 1: + drawline_hr_heigth(x, yCenter, width, 12, true); + draw_ellipse_fill(xCenter, yCenter, 7, 15, true); + break; + + case 2: + drawline_hr_heigth(x, yCenter, width, 5, true); + draw_ellipse_fill(xCenter, yCenter, 5, 8, true); + break; + + case 3: + drawline_hr_heigth(x, yCenter, width, 3, true); + draw_ellipse_fill(xCenter, yCenter, 3, 4, true); + break; + + case 4: + drawline_hr_heigth(x, yCenter, width, 2, true); + draw_fill_circle(xCenter, yCenter, 3, true); + break; + + case 5: + // central line + drawline_hr(x, yCenter, width, true); + draw_fill_circle(xCenter, yCenter, 2, true); + break; + + case 6: + // cross + drawline_hr(xCenter, yCenter + 1, 2, true); + drawline_hr(xCenter, yCenter - 1, 2, true); + + // central line + drawline_hr(x, yCenter, width, true); + break; + + case 7: + // cross + drawline_hr(xCenter, yCenter + 1, 2, true); + drawline_hr(xCenter, yCenter - 1, 2, true); + // central line + drawline_hr(xCenter - 8, yCenter, 18, true); + // static + oled_write_pixel(xCenter - 11, yCenter, true); + oled_write_pixel(xCenter + 12, yCenter, true); + break; + + case 8: + // cross + drawline_hr(xCenter, yCenter + 1, 2, true); + drawline_hr(xCenter, yCenter - 1, 2, true); + // central line + drawline_hr(xCenter - 2, yCenter, 4, true); + // static + drawline_hr(xCenter - 7, yCenter, 2, true); + drawline_hr(xCenter + 6, yCenter, 3, true); + + // oled_write_pixel(xCenter - 11, yCenter, true); + oled_write_pixel(xCenter - 9, yCenter, true); + oled_write_pixel(xCenter + 12, yCenter, true); + oled_write_pixel(xCenter + 14, yCenter, true); + break; + + case 9: + // central line + drawline_hr(xCenter, yCenter, 2, true); + break; + } +} \ No newline at end of file diff --git a/draw_helper.h b/draw_helper.h new file mode 100644 index 0000000..991ab0d --- /dev/null +++ b/draw_helper.h @@ -0,0 +1,47 @@ +// Copyright 2021 Nicolas Druoton (druotoni) +// Copyright 2021 ugfx +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +// line +void drawline_vb(uint8_t x, uint8_t y, uint8_t width, bool color); +void drawline_vt(uint8_t x, uint8_t y, uint8_t width, bool color); +void drawline_hr(uint8_t x, uint8_t y, uint8_t width, bool color); +void drawline_hl(uint8_t x, uint8_t y, uint8_t width, bool color); +void drawline_hr_heigth(uint8_t x, uint8_t y, uint8_t width, uint8_t heigth, bool color); + +// rectangle +void draw_rectangle(uint8_t x, uint8_t y, uint8_t width, uint8_t heigth, bool color); +void draw_rectangle_fill(uint8_t x, uint8_t y, uint8_t width, uint8_t heigth, bool color); +void 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); + +// circle +void draw_fill_circle(short x, short y, uint8_t radius, bool color); +void draw_circle(uint8_t x, uint8_t y, uint8_t radius, bool color); +void draw_ellipse(uint8_t x, uint8_t y, uint8_t a, uint8_t b, bool color); +void draw_ellipse_fill(uint8_t x, uint8_t y, uint8_t a, uint8_t b, bool color); +void draw_arc_sector(uint8_t x, uint8_t y, uint8_t radius, unsigned char sectors, unsigned char half, bool color); +void draw_static(uint8_t x, uint8_t y, uint8_t width, uint8_t heigth, int color, uint8_t density); + +// text +void draw_random_char(uint8_t column, uint8_t row, char final_char, int value, uint8_t style); +void draw_label(const char *data, uint8_t len, uint8_t row, int value); +void draw_box(const char *data, uint8_t len, uint8_t row, long value, uint8_t style); +void draw_progress(uint8_t x, uint8_t y, uint8_t width, uint8_t heigth, int value, uint8_t style, bool color); + +// oled drivers stuff +char get_oled_char(uint16_t start_index); +void oled_write_cursor(uint8_t col, uint8_t line, const char *data, bool invert); +void oled_write_raw_P_cursor(uint8_t col, uint8_t line, const char *data, uint16_t size); + +// pixel manipulation +void copy_pixel(int from, int shift, unsigned char mask); +void move_block(uint8_t x, uint8_t y, uint8_t width, uint8_t heigth, int shift); +void draw_glitch_comb(uint8_t x, uint8_t y, uint8_t width, uint16_t height, uint8_t iSize, bool odd); + +// misc +void render_tv_animation(uint8_t frame_number, uint8_t x, uint8_t y, uint8_t width, uint8_t heigth); +int interpo_pourcent(int min, int max, int v); +void 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); +void 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/fast_random.c b/fast_random.c new file mode 100644 index 0000000..3028b57 --- /dev/null +++ b/fast_random.c @@ -0,0 +1,17 @@ +// Copyright 2021 Nicolas Druoton (druotoni) +// SPDX-License-Identifier: GPL-2.0-or-later +#include "fast_random.h" + +// seed for random +static unsigned long g_seed = 0; + +int fastrand(void) { + // todo : try with random16(); + g_seed = (214013 * g_seed + 2531011); + return (g_seed >> 16) & 0x7FFF; +} + +unsigned long fastrand_long(void) { + g_seed = (214013 * g_seed + 2531011); + return g_seed; +} diff --git a/fast_random.h b/fast_random.h new file mode 100644 index 0000000..fe8c4a4 --- /dev/null +++ b/fast_random.h @@ -0,0 +1,7 @@ +// Copyright 2021 Nicolas Druoton (druotoni) +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +int fastrand(void); +unsigned long fastrand_long(void); \ No newline at end of file diff --git a/gui_state.c b/gui_state.c new file mode 100644 index 0000000..d86e67e --- /dev/null +++ b/gui_state.c @@ -0,0 +1,71 @@ +// Copyright 2021 Nicolas Druoton (druotoni) +// SPDX-License-Identifier: GPL-2.0-or-later + +#include QMK_KEYBOARD_H + +#include "gui_state.h" +#include "draw_helper.h" + +// timer for the gui state +uint32_t global_sleep_timer = 0; +uint32_t global_waking_up_timer = 0; +uint32_t global_booting_timer = 0; + +// timers test for states +#ifdef WITH_BOOT +static bool IsBooting(void) { return (timer_elapsed32(global_booting_timer) < BOOTING_TIME_TRESHOLD); } +#else +static bool IsBooting(void) { return false; } +#endif + +// state test +static bool IsWakingUp(void) { return (timer_elapsed32(global_waking_up_timer) < WAKING_UP_TIME_TRESHOLD); } +static bool IsIdle(void) { return (timer_elapsed32(global_sleep_timer) > IDLE_TIME_TRESHOLD && timer_elapsed32(global_sleep_timer) < HALTING_TIME_TRESHOLD); } +static bool IsSleep(void) { return (timer_elapsed32(global_sleep_timer) >= SLEEP_TIME_TRESHOLD); } +static bool IsHalting(void) { return (timer_elapsed32(global_sleep_timer) >= HALTING_TIME_TRESHOLD && timer_elapsed32(global_sleep_timer) < SLEEP_TIME_TRESHOLD); } + +gui_state_t get_gui_state(void) { + // get gui states by testing timers + if (IsBooting()) return _BOOTING; + if (IsWakingUp()) return _WAKINGUP; + if (IsIdle()) return _IDLE; + if (IsHalting()) return _HALTING; + if (IsSleep()) return _SLEEP; + + return _UP; +} + +void update_gui_state(void) { + // what to do when a key is pressed + gui_state_t t = get_gui_state(); + +#ifdef WITH_BOOT + if (t == _SLEEP) { + // booting + global_booting_timer = timer_read32(); + } + + if (t == _BOOTING) { + // cancel booting + global_booting_timer = 1000000; + } +#else + if (t == _SLEEP) { + // waking up + global_waking_up_timer = timer_read32(); + } +#endif + + if (t == _IDLE || t == _HALTING || t == _BOOTING) { + // waking up + global_waking_up_timer = timer_read32(); + } + + // no sleep + global_sleep_timer = timer_read32(); +} + +uint8_t get_glitch_probability(void) { + // more gliches could occur when halting time is near + return interpo_pourcent(IDLE_TIME_TRESHOLD, HALTING_TIME_TRESHOLD, timer_elapsed32(global_sleep_timer)); +} diff --git a/gui_state.h b/gui_state.h new file mode 100644 index 0000000..190e02d --- /dev/null +++ b/gui_state.h @@ -0,0 +1,18 @@ +// Copyright 2021 Nicolas Druoton (druotoni) +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +// states timing +#define BOOTING_TIME_TRESHOLD 7000 +#define WAKING_UP_TIME_TRESHOLD 300 +#define IDLE_TIME_TRESHOLD 4000 +#define HALTING_TIME_TRESHOLD IDLE_TIME_TRESHOLD + 6000 +#define SLEEP_TIME_TRESHOLD HALTING_TIME_TRESHOLD + 8000 + +typedef uint8_t gui_state_t; +enum gui_state { _WAKINGUP = 0, _IDLE, _SLEEP, _UP, _BOOTING, _HALTING }; + +gui_state_t get_gui_state(void); +void update_gui_state(void); +uint8_t get_glitch_probability(void); \ No newline at end of file diff --git a/keymap.c b/keymap.c index e984326..31b5b53 100644 --- a/keymap.c +++ b/keymap.c @@ -1,143 +1,193 @@ +// Copyright 2021 Nicolas Druoton (druotoni) +// SPDX-License-Identifier: GPL-2.0-or-later + #include QMK_KEYBOARD_H +#include "transactions.h" -// this is for oled bongo cat -char wpm_str[16]; +// global +#include "boot.h" +#include "gui_state.h" +#include "navi_logo.h" -enum layer_number { - _QWERTY = 0, - _LOWER, - _RAISE, - _BLANK, -}; +#include "draw_helper.h" +#include "fast_random.h" +// left side +#include "burst.h" +#include "layer_frame.h" + +// right side +#include "ring.h" + +// clang-format off const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {[0] = LAYOUT(KC_GESC, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_BSPC, KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_QUOT, KC_LSFT, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_ENT, KC_LCTL, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_LBRC, KC_RBRC, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH, KC_BSLS, KC_LGUI, KC_LAPO, MO(1), KC_SPC, KC_SPC, MO(2), KC_RAPC, KC_RCTL), [1] = LAYOUT(KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_GRV, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_TRNS, KC_BRID, KC_BRIU, KC_MPRV, KC_MNXT, KC_NO, KC_LEFT, KC_DOWN, KC_UP, KC_RGHT, KC_NO, KC_NO, KC_TRNS, KC_VOLD, KC_VOLU, KC_MUTE, KC_MSTP, KC_LPRN, KC_NO, KC_NO, KC_RPRN, KC_EQL, KC_MINS, KC_NO, KC_DEL, KC_BSLS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_NO, KC_TRNS, KC_TRNS), [2] = LAYOUT(KC_TRNS, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, KC_TRNS, KC_TRNS, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_F11, KC_F12, KC_TRNS, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_LEFT, KC_DOWN, KC_UP, KC_RGHT, KC_NO, KC_TRNS, KC_TRNS, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS)}; +// clang-format on -layer_state_t layer_state_set_user(layer_state_t state) { - return update_tri_layer_state(state, _LOWER, _RAISE, _BLANK); -} +// sync transport +typedef struct _sync_keycode_t { + uint16_t keycode; +} sync_keycode_t; -// SSD1306 OLED update loop, make sure to enable OLED_DRIVER_ENABLE=yes in -// rules.mk -#ifdef OLED_ENABLE +// force rigth side to update +bool b_sync_need_send = false; + +// last keycode typed +sync_keycode_t last_keycode; oled_rotation_t oled_init_user(oled_rotation_t rotation) { - if (!is_keyboard_master()) return OLED_ROTATION_180; // flips the display 180 degrees if offhand - return rotation; + // vertical orientation + return OLED_ROTATION_270; } -// When you add source files to SRC in rules.mk, you can use functions. -const char *read_layer_state(void); +void render(gui_state_t t) { + // logo + render_logo(t); -// WPM-responsive animation stuff here -# define IDLE_FRAMES 5 -# define IDLE_SPEED 40 // below this wpm value your animation will idle +#if IS_LEFT + // left side + render_layer_frame(t); + render_gears(); -// #define PREP_FRAMES 1 // uncomment if >1 + decay_scope(); + render_scope(t); +#endif -# define TAP_FRAMES 2 -# define TAP_SPEED 40 // above this wpm value typing animation to trigger +#if IS_RIGHT + // right side + render_circle(t); +#endif +} -# define ANIM_FRAME_DURATION 200 // how long each frame lasts in ms -# define SLEEP_TIMER 60000 // should sleep after this period of 0 wpm, needs -// fixing -# define ANIM_SIZE \ - 640 // number of bytes in array, minimize for adequate firmware size, max is - // 1024 +void update(uint16_t keycode) { +#if IS_LEFT + update_scope(); +#endif -uint32_t anim_timer = 0; -uint32_t anim_sleep = 0; -uint8_t current_idle_frame = 0; -uint8_t current_tap_frame = 0; +#if IS_RIGHT + update_circle(keycode); +#endif +} -static void render_anim(void) { - // Idle animation - static const char PROGMEM idle[IDLE_FRAMES][ANIM_SIZE] = {{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, 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, 0, 0, 128, 64, 64, 32, 32, 32, 32, 16, 16, 16, 16, 16, 8, 8, 4, 4, 4, 8, 48, 64, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24, 100, 130, 2, 2, 2, 2, 2, 1, 0, 0, 0, 0, 128, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 0, 48, 48, 0, 192, 193, 193, 194, 4, 8, 16, 32, 64, 128, 0, 0, 0, 128, 128, 128, 128, 64, 64, 64, 64, 32, 32, 32, 32, 16, 16, 16, 16, 8, 8, 8, 8, 8, 4, 4, 4, 4, 4, 2, 2, 2, 2, 1, 1, 1, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 192, 56, 4, 3, 0, 0, 0, 0, 0, 0, 0, 12, 12, 12, 13, 1, 0, 64, 160, 33, 34, 18, 17, 17, 17, 9, 8, 8, 8, 8, 4, 4, 8, 8, 16, 16, 16, 16, 16, 17, 15, 1, 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, 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, 128, 128, 128, 128, 64, 64, 64, 64, 64, 32, 32, 32, 32, 32, 16, 16, 16, 16, 16, 8, 8, 8, 8, 8, 4, 4, 4, 4, 4, 2, 3, 2, 2, 1, 1, 1, 1, 1, 1, 2, 2, 4, 4, 8, 8, 8, 8, 8, 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, 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, 0, 0, 0, 0, 0}, +void reset(void) { +#if IS_LEFT + reset_scope(); +#endif - {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, 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, 0, 0, 128, 64, 64, 32, 32, 32, 32, 16, 16, 16, 16, 16, 8, 8, 4, 4, 4, 8, 48, 64, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24, 100, 130, 2, 2, 2, 2, 2, 1, 0, 0, 0, 0, 128, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 0, 48, 48, 0, 192, 193, 193, 194, 4, 8, 16, 32, 64, 128, 0, 0, 0, 128, 128, 128, 128, 64, 64, 64, 64, 32, 32, 32, 32, 16, 16, 16, 16, 8, 8, 8, 8, 8, 4, 4, 4, 4, 4, 2, 2, 2, 2, 1, 1, 1, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 192, 56, 4, 3, 0, 0, 0, 0, 0, 0, 0, 12, 12, 12, 13, 1, 0, 64, 160, 33, 34, 18, 17, 17, 17, 9, 8, 8, 8, 8, 4, 4, 8, 8, 16, 16, 16, 16, 16, 17, 15, 1, 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, 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, 128, 128, 128, 128, 64, 64, 64, 64, 64, 32, 32, 32, 32, 32, 16, 16, 16, 16, 16, 8, 8, 8, 8, 8, 4, 4, 4, 4, 4, 2, 3, 2, 2, 1, 1, 1, 1, 1, 1, 2, 2, 4, 4, 8, 8, 8, 8, 8, 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, 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, 0, 0, 0, 0, 0}, +#if IS_RIGHT + reset_ring(); +#endif +} - {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, 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, 0, 0, 0, 128, 128, 64, 64, 64, 64, 32, 32, 32, 32, 16, 8, 4, 2, 2, 4, 24, 96, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 60, 194, 1, 1, 2, 2, 4, 4, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 96, 96, 0, 129, 130, 130, 132, 8, 16, 32, 64, 128, 0, 0, 0, 0, 128, 128, 128, 128, 64, 64, 64, 64, 32, 32, 32, 32, 16, 16, 16, 16, 8, 8, 8, 8, 8, 4, 4, 4, 4, 4, 2, 2, 2, 2, 1, 1, 1, 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, 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, 25, 6, 0, 0, 0, 0, 0, 0, 0, 24, 24, 24, 27, 3, 0, 64, 160, 34, 36, 20, 18, 18, 18, 11, 8, 8, 8, 8, 5, 5, 9, 9, 16, 16, 16, 16, 16, 17, 15, 1, 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, 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, 128, 128, 128, 128, 64, 64, 64, 64, 64, 32, 32, 32, 32, 32, 16, 16, 16, 16, 16, 8, 8, 8, 8, 8, 4, 4, 4, 4, 4, 2, 3, 2, 2, 1, 1, 1, 1, 1, 1, 2, 2, 4, 4, 8, 8, 8, 8, 8, 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, 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, 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, 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, 128, 128, 0, 0, 0, 0, 0, 128, 64, 64, 32, 32, 32, 32, 16, 16, 16, 16, 8, 4, 2, 1, 1, 2, 12, 48, 64, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 225, 0, 0, 1, 1, 2, 2, 1, 0, 0, 0, 0, 128, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 0, 48, 48, 0, 192, 193, 193, 194, 4, 8, 16, 32, 64, 128, 0, 0, 0, 128, 128, 128, 128, 64, 64, 64, 64, 32, 32, 32, 32, 16, 16, 16, 16, 8, 8, 8, 8, 8, 4, 4, 4, 4, 4, 2, 2, 2, 2, 1, 1, 1, 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, 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, 12, 3, 0, 0, 0, 0, 0, 0, 0, 12, 12, 12, 13, 1, 0, 64, 160, 33, 34, 18, 17, 17, 17, 9, 8, 8, 8, 8, 4, 4, 8, 8, 16, 16, 16, 16, 16, 17, 15, 1, 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, 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, 128, 128, 128, 128, 64, 64, 64, 64, 64, 32, 32, 32, 32, 32, 16, 16, 16, 16, 16, 8, 8, 8, 8, 8, 4, 4, 4, 4, 4, 2, 3, 2, 2, 1, 1, 1, 1, 1, 1, 2, 2, 4, 4, 8, 8, 8, 8, 8, 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, 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, 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, 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, 0, 0, 0, 0, 0, 0, 0, 128, 64, 64, 32, 32, 32, 32, 16, 16, 16, 16, 8, 8, 4, 2, 2, 2, 4, 56, 64, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 28, 226, 1, 1, 2, 2, 2, 2, 1, 0, 0, 0, 0, 128, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 0, 48, 48, 0, 192, 193, 193, 194, 4, 8, 16, 32, 64, 128, 0, 0, 0, 128, 128, 128, 128, 64, 64, 64, 64, 32, 32, 32, 32, 16, 16, 16, 16, 8, 8, 8, 8, 8, 4, 4, 4, 4, 4, 2, 2, 2, 2, 1, 1, 1, 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, 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, 12, 3, 0, 0, 0, 0, 0, 0, 0, 12, 12, 12, 13, 1, 0, 64, 160, 33, 34, 18, 17, 17, 17, 9, 8, 8, 8, 8, 4, 4, 8, 8, 16, 16, 16, 16, 16, 17, 15, 1, 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, 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, 128, 128, 128, 128, 64, 64, 64, 64, 64, 32, 32, 32, 32, 32, 16, 16, 16, 16, 16, 8, 8, 8, 8, 8, 4, 4, 4, 4, 4, 2, 3, 2, 2, 1, 1, 1, 1, 1, 1, 2, 2, 4, 4, 8, 8, 8, 8, 8, 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, 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, 0, 0, 0, 0, 0}}; - - // Prep animation - static const char PROGMEM prep[][ANIM_SIZE] = { - - {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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 0, 0, 0, 0, 0, 128, 64, 64, 32, 32, 32, 32, 16, 16, 16, 16, 8, 4, 2, 1, 1, 2, 12, 48, 64, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 225, 0, 0, 1, 1, 2, 2, 129, 128, 128, 0, 0, 128, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 0, 48, 48, 0, 0, 1, 225, 26, 6, 9, 49, 53, 1, 138, 124, 0, 0, 128, 128, 128, 128, 64, 64, 64, 64, 32, 32, 32, 32, 16, 16, 16, 16, 8, 8, 8, 8, 8, 4, 4, 4, 4, 4, 2, 2, 2, 2, 1, 1, 1, 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, 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, 12, 3, 0, 0, 24, 6, 5, 152, 153, 132, 195, 124, 65, 65, 64, 64, 32, 33, 34, 18, 17, 17, 17, 9, 8, 8, 8, 8, 4, 4, 4, 4, 4, 4, 2, 2, 2, 1, 1, 1, 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, 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, 128, 128, 128, 128, 64, 64, 64, 64, 64, 32, 32, 32, 32, 32, 16, 16, 16, 16, 16, 8, 8, 8, 8, 8, 4, 4, 4, 4, 4, 2, 3, 2, 2, 1, 1, 1, 1, 1, 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, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} - - }; - - // Typing animation - static const char PROGMEM tap[TAP_FRAMES][ANIM_SIZE] = { - - {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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 0, 0, 0, 0, 0, 128, 64, 64, 32, 32, 32, 32, 16, 16, 16, 16, 8, 4, 2, 1, 1, 2, 12, 48, 64, 128, 0, 0, 0, 0, 0, 0, 0, 248, 248, 248, 248, 0, 0, 0, 0, 0, 128, 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, 0, 0, 128, 128, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 225, 0, 0, 1, 1, 2, 2, 129, 128, 128, 0, 0, 128, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 0, 48, 48, 0, 0, 1, 1, 2, 4, 8, 16, 32, 67, 135, 7, 1, 0, 184, 188, 190, 159, 95, 95, 79, 76, 32, 32, 32, 32, 16, 16, 16, 16, 8, 8, 8, 8, 8, 4, 4, 4, 4, 4, 2, 2, 2, 2, 1, 1, 1, 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, 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, 12, 3, 0, 0, 24, 6, 5, 152, 153, 132, 67, 124, 65, 65, 64, 64, 32, 33, 34, 18, 17, 17, 17, 9, 8, 8, 8, 8, 4, 4, 8, 8, 16, 16, 16, 16, 16, 17, 15, 1, 61, 124, 252, 252, 252, 252, 252, 60, 12, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128, 128, 64, 64, 64, 64, 64, 32, 32, 32, 32, 32, 16, 16, 16, 16, 16, 8, 8, 8, 8, 8, 4, 4, 4, 4, 4, 2, 3, 2, 2, 1, 1, 1, 1, 1, 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, 0, 0, 0, 0, 0, 0, 0, 0, 1, 3, 3, 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, 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, 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, 128, 128, 0, 0, 0, 0, 0, 128, 64, 64, 32, 32, 32, 32, 16, 16, 16, 16, 8, 4, 2, 1, 1, 2, 12, 48, 64, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 225, 0, 0, 1, 1, 2, 2, 1, 0, 0, 0, 0, 128, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 0, 48, 48, 0, 0, 1, 225, 26, 6, 9, 49, 53, 1, 138, 124, 0, 0, 128, 128, 128, 128, 64, 64, 64, 64, 32, 32, 32, 32, 16, 16, 16, 16, 8, 8, 8, 8, 8, 4, 4, 4, 4, 4, 2, 2, 2, 2, 1, 1, 1, 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, 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, 12, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 64, 160, 33, 34, 18, 17, 17, 17, 9, 8, 8, 8, 8, 4, 4, 4, 4, 4, 4, 2, 2, 2, 1, 1, 1, 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, 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, 128, 128, 128, 128, 64, 64, 64, 64, 64, 32, 32, 32, 32, 32, 16, 16, 16, 16, 16, 8, 8, 8, 8, 8, 4, 4, 4, 4, 4, 2, 3, 122, 122, 121, 121, 121, 121, 57, 49, 2, 2, 4, 4, 8, 8, 8, 136, 136, 135, 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, 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, 0, 0, 0, 0, 0, 0} - - }; - - // assumes 1 frame prep stage - void animation_phase(void) { - if (get_current_wpm() <= IDLE_SPEED) { - current_idle_frame = (current_idle_frame + 1) % IDLE_FRAMES; - oled_clear(); - oled_write_raw_P(idle[abs((IDLE_FRAMES - 1) - current_idle_frame)], ANIM_SIZE); - } - if (get_current_wpm() > IDLE_SPEED && get_current_wpm() < TAP_SPEED) { - oled_clear(); - // oled_write_raw_P(prep[abs((PREP_FRAMES-1)-current_prep_frame)], ANIM_SIZE); // uncomment if IDLE_FRAMES >1 - oled_write_raw_P(prep[0], ANIM_SIZE); // remove if IDLE_FRAMES >1 - } - if (get_current_wpm() >= TAP_SPEED) { - current_tap_frame = (current_tap_frame + 1) % TAP_FRAMES; - oled_clear(); - oled_write_raw_P(tap[abs((TAP_FRAMES - 1) - current_tap_frame)], ANIM_SIZE); - } - } - if (get_current_wpm() != 0) { - if (timer_elapsed(anim_timer) > ANIM_FRAME_DURATION) { - anim_timer = timer_read(); - animation_phase(); - } - anim_sleep = timer_read(); - } else { - if (timer_elapsed(anim_timer) > ANIM_FRAME_DURATION) { - anim_timer = timer_read(); - animation_phase(); - } - if (timer_elapsed(anim_sleep) > SLEEP_TIMER) { - // oled_off(); - } - } +void set_wackingup_mode_clean(void) { + oled_clear(); + reset(); } bool oled_task_user(void) { - if (is_keyboard_master()) { - oled_set_cursor(0, 1); - uint8_t n = get_current_wpm(); - char wpm_counter[4]; - wpm_counter[3] = '\0'; - wpm_counter[2] = '0' + n % 10; - wpm_counter[1] = (n /= 10) % 10 ? '0' + (n) % 10 : (n / 10) % 10 ? '0' : ' '; - wpm_counter[0] = n / 10 ? '0' + n / 10 : ' '; - oled_write_P(PSTR("WPM: "), false); - oled_write(wpm_counter, false); - oled_set_cursor(0, 3); - { oled_write_ln(read_layer_state(), false); } - } else { - render_anim(); + gui_state_t t = get_gui_state(); + + // in sleep mode => turn display off + if (t == _SLEEP) { + oled_off(); + return false; + } + + // not in sleep mode => screen is on + oled_on(); + +#ifdef WITH_BOOT + // in booting mode => display booting animation + if (t == _BOOTING) { + bool boot_finished = render_boot(); + if (boot_finished) { + // end of the boot : wacking up + set_wackingup_mode_clean(); + update_gui_state(); } return false; + } +#endif + + // in halting mode => display booting animation + if (t == _HALTING) { + render_halt(); + return false; + } + + render(t); + return false; } -#endif // OLED_DRIVER_ENABLE + +void process_key(uint16_t keycode) { + // update screen with the new key + update(keycode); + + gui_state_t t = get_gui_state(); + + if (t == _IDLE) { + // wake up animation + reset(); + } + + if (t == _BOOTING || t == _HALTING) { + // cancel booting or halting : waking_up + set_wackingup_mode_clean(); + } + + if (t == _SLEEP) { + // boot sequence + set_wackingup_mode_clean(); + reset_boot(); + } + + update_gui_state(); +} + +void user_sync_a_slave_handler(uint8_t in_buflen, const void *in_data, + uint8_t out_buflen, void *out_data) { + const sync_keycode_t *m2s = (const sync_keycode_t *)in_data; + // get the last char typed on left side and update the right side + process_key(m2s->keycode); +} + +void keyboard_post_init_user(void) { + // callback for tranport sync data + transaction_register_rpc(USER_SYNC_A, user_sync_a_slave_handler); +} + +void housekeeping_task_user(void) { + // only for master side + if (!is_keyboard_master()) + return; + + // only if a new char was typed + if (!b_sync_need_send) + return; + + // send the char to the slave side : sync is done + if (transaction_rpc_send(USER_SYNC_A, sizeof(last_keycode), &last_keycode)) { + b_sync_need_send = false; + } +} + +bool process_record_user(uint16_t keycode, keyrecord_t *record) { + if (record->event.pressed) { + // master : store keycode to sent to the other side to be process_key + last_keycode.keycode = keycode; + b_sync_need_send = true; + + // gui process the input + process_key(keycode); + } + return true; +} + +#if IS_LEFT +layer_state_t layer_state_set_user(layer_state_t state) { + // update the frame with the layer name + update_layer_frame(state); + return state; +} +#endif diff --git a/layer_frame.c b/layer_frame.c new file mode 100644 index 0000000..6f7ae1a --- /dev/null +++ b/layer_frame.c @@ -0,0 +1,105 @@ +// Copyright 2021 Nicolas Druoton (druotoni) +// SPDX-License-Identifier: GPL-2.0-or-later + +#include QMK_KEYBOARD_H + +#include "gui_state.h" +#include "layer_frame.h" +#include "draw_helper.h" + +#define ANIM_LAYER_FRAME_DURATION 2 +#define ANIM_LAYER_FRAME_MAX 7 + +// current layer +uint8_t current_layer = _QWERTY; + +// layer animation stuff +uint16_t anim_layer_frame_timer = 0; +uint8_t current_layer_frame = ANIM_LAYER_FRAME_MAX; +uint8_t layer_frame_destination = ANIM_LAYER_FRAME_MAX; + +// layer name for display +const char* layer_name; +static const char* layer_ref[3] = {LAYER_NAME_0, LAYER_NAME_1, LAYER_NAME_2}; + +void update_layer_frame(layer_state_t state) { + // reset timer + anim_layer_frame_timer = timer_read(); + + // direction for animation base on layer selected + current_layer = get_highest_layer(state); + if (current_layer == _QWERTY) { + layer_frame_destination = 0; + } else { + layer_frame_destination = ANIM_LAYER_FRAME_MAX; + } +} + +static void draw_black_screen(void) { + // clean frame center + draw_rectangle_fill(3, 42, 26, 20, false); + drawline_hr(17, 62, 12, false); +} + +void render_gears(void) { + // 64 bytes, 8x8 font, 8 characters, 32x16 image, 4 columns, 2 rows + static const char PROGMEM raw_logo[] = { + 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, + }; + + // extra line for complete the gui + oled_write_raw_P_cursor(0, 8, raw_logo, sizeof(raw_logo)); +} + +void render_layer_frame(gui_state_t t) { + // 96 bytes, 8x8 font, 12 characters, 32x24 image, 4 columns, 3 rows + static const char PROGMEM raw_logo[] = { + 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, + }; + oled_write_raw_P_cursor(0, 5, raw_logo, sizeof(raw_logo)); + + // extra line for complete the gui + drawline_hr(2, 39, 25, 1); + + if (current_layer_frame != layer_frame_destination) { + if (timer_elapsed(anim_layer_frame_timer) > ANIM_LAYER_FRAME_DURATION) { + anim_layer_frame_timer = timer_read(); + + if (layer_frame_destination > current_layer_frame) { + current_layer_frame++; + } else { + current_layer_frame--; + } + } + + // black screen + draw_black_screen(); + + // gradient animation on layer selection + draw_gradient(3, 42, current_layer_frame * 4, 10, 0, 255, 7); + draw_gradient(3 + (27 - current_layer_frame * 4), 57, current_layer_frame * 4, 6, 255, 0, 7); + + drawline_hr(3, 46, 22, false); + drawline_hr(3, 47, 23, false); + + draw_rectangle_fill(3, 55, 24, 2, false); + draw_rectangle_fill(24, 48, 3, 7, false); + + draw_rectangle_fill(3, 60, 12, 2, false); + oled_write_pixel(15, 61, false); + drawline_hr(14, 62, 3, false); + drawline_hr(14, 62, 3, false); + drawline_hr(3, 62, 11, true); + } + + // get current layer name + layer_name = layer_ref[current_layer]; + + // gui on pause : no layer name on screen + if (t == _IDLE || t == _SLEEP || t == _WAKINGUP) { + layer_name = " "; + } + + // display layer name in the frame + oled_write_cursor(1, 6, layer_name, false); +} diff --git a/layer_frame.h b/layer_frame.h new file mode 100644 index 0000000..f86ff3f --- /dev/null +++ b/layer_frame.h @@ -0,0 +1,15 @@ +// Copyright 2021 Nicolas Druoton (druotoni) +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +// layer name : must be 3 chars +#define LAYER_NAME_0 "ABC" +#define LAYER_NAME_1 "NAV" +#define LAYER_NAME_2 "SPE" + +enum layer_number { _QWERTY = 0, _LOWER, _RAISE }; + +void render_gears(void); +void render_layer_frame(gui_state_t t); +void update_layer_frame(layer_state_t state); diff --git a/lily58_rev1_lily58minh.hex b/lily58_rev1_lily58minh.hex deleted file mode 100644 index 831fb20..0000000 --- a/lily58_rev1_lily58minh.hex +++ /dev/null @@ -1,1634 +0,0 @@ -:100000000C94E70C0C942E0D0C942E0D0C94CE2C0D -:100010000C942E0D0C942E0D0C942E0D0C942E0D74 -:100020000C942E0D0C942E0D0C947A1B0C94361BF4 -:100030000C9417270C942E0D0C942E0D0C942E0D51 -:100040000C942E0D0C942E0D0C942E0D0C942E0D44 -:100050000C942E0D0C94511C0C942E0D0C942E0D02 -:100060000C942E0D0C942E0D0C942E0D0C942E0D24 -:100070000C942E0D0C942E0D0C942E0D0C942E0D14 -:100080000C942E0D0C942E0D0C942E0D0C942E0D04 -:100090000C942E0D0C942E0D0C942E0D0C942E0DF4 -:1000A0000C942E0D0C942E0D0C942E0D00000000BF -:1000B0000000000000000000000000000000000040 -:1000C0000000000000000000000000000000000030 -:1000D0000000000000000000000000000000000020 -:1000E0000000000000000000000000000000808010 -:1000F00080404020201008040204081010202040F6 -:1001000040808000000000000000000000000000AF -:1001100000000000000000000000000000000000DF -:1001200000000000000000000000000000000000CF -:1001300000000000000000000000000000000000BF -:1001400000000000000000000000000000000000AF -:100150000000000000000000000000000000003F60 -:10016000C1010102020404040402020101010000B1 -:10017000000000008000004080804000003030001F -:10018000000000010264180412C2CA2488F08080B2 -:10019000404040402020202010101010080808087F -:1001A0000404040402020202010101010000000033 -:1001B000000000000000000000000000000000003F -:1001C000000000000000000000000000000000002F -:1001D0000000000000000000000000000000E01827 -:1001E0000601000000000000000000000080838382 -:1001F000404040402021212010101010080808081D -:1002000004040404020202020101010100000000D2 -:1002100000000000000000000000000000000000DE -:1002200000000000000000000000000000000000CE -:1002300000000000000000000000000000000000BE -:1002400000000000000000000000000080808080AE -:10025000404040402020202010101010080F0808B7 -:1002600004040404020408101020204040414224E9 -:1002700098C088888C9C1C1E0E06000000000000A0 -:10028000000000000000000000000000000000006E -:10029000000000000000000000000000000000005E -:1002A000000000000000000000000000000000004E -:1002B000000000000000000000000000000000003E -:1002C000000000000000000000000000000000002E -:1002D000000000000000000000000000000000001E -:1002E000000000000000000000000000000000000E -:1002F00000000000000000000000000000000000FE -:1003000000000000000000000000000000000000ED -:1003100000000000000000000000000000000000DD -:1003200000000000000000000000000000000000CD -:1003300000000000000000000000000000000000BD -:1003400000000000000000000000000000000000AD -:10035000000000000000000000000000000000009D -:10036000000000000000000000008080804040206D -:100370002010080402040810102020404080800053 -:10038000000000000000000000000000000000006D -:10039000000000000000000000000000000000005D -:1003A000000000000000000000000000000000004D -:1003B000000000000000000000000000000000003D -:1003C000000000000000000000000000000000002D -:1003D00000000000000000000000003FC101010219 -:1003E0000204844444428201010100000000000034 -:1003F000800000408080400000303000000000019C -:100400000204040808102040808080804040404062 -:1004100020202020101010100808080804040404EC -:1004200002020202010101010000000000000000C0 -:1004300000000000000000000000000000000000BC -:1004400000000000000000000000000000000000AC -:1004500000000000000000000000E018060100009D -:100460000C03000218190005FE80838340404040C1 -:10047000202121201010101008080808040404048A -:100480000408304080800000018698600000000071 -:10049000000000000000000000000000000000005C -:1004A000000000000000000000000000000000004C -:1004B000000000000000000000000000000000003C -:1004C000000000000000000080808080404040402C -:1004D0002020202010101010080F08080404040425 -:1004E0000202020201010101000000000000000000 -:1004F0000000000000000000000000060F0F0703CE -:100500000361F0F8FC600101013C78F8F070000034 -:1005100000000000000000000000000000000000DB -:1005200000000000000000000000000000000000CB -:1005300000000000000000000000000000000000BB -:1005400000000000000000000000000000000000AB -:10055000000000000000000000000000000000009B -:10056000000000000000000000000000000000008B -:10057000000000000000000000000000000000007B -:10058000000000000000000000000000000000006B -:10059000000000000000000000000000000000005B -:1005A000000000000000000000000000000000004B -:1005B000000000000000000000000000000000003B -:1005C000000000000000000000000000000000002B -:1005D000000000000000000000000000000000001B -:1005E000000000808040404020202020201804028D -:1005F000010204081020204040808000000000001C -:1006000000000000000000000000000000000000EA -:1006100000000000000000000000000000000000DA -:1006200000000000000000000000000000000000CA -:1006300000000000000000000000000000000000BA -:1006400000000000000000000000000000000000AA -:10065000000000000000003FC10101020204040488 -:1006600004020201000000000000000080000040C1 -:1006700080804000003030000000000102040408C7 -:100680000810204080808080404040402020202072 -:1006900010101010080808080404040402020202E2 -:1006A0000101010100000000000000000000000046 -:1006B000000000000000000000000000000000003A -:1006C000000000000000000000000000000000002A -:1006D000000000000000E01806010000000000001B -:1006E0000000000000808383404040402021212002 -:1006F000101010100808080804040404040830400E -:10070000808000000186986000000000000000006A -:1007100000000000000000000000000000000000D9 -:1007200000000000000000000000000000000000C9 -:1007300000000000000000000000000000000000B9 -:100740000000000080808080404040402020202029 -:1007500010101010080F0808040404040204081004 -:1007600010202040404142241800000000000000FA -:100770000000000000000000000000000000000079 -:100780000000010101000000000000000000000066 -:100790000000000000000000000000000000000059 -:1007A0000000000000000000000000000000000049 -:1007B0000000000000000000000000000000000039 -:1007C0000000000000000000000000000000000029 -:1007D0000000000000000000000000000000000019 -:1007E0000000000000000000000000000000000009 -:1007F00000000000000000000000000000000000F9 -:1008000000000000000000000000000000000000E8 -:1008100000000000000000000000000000000000D8 -:1008200000000000000000000000000000000000C8 -:1008300000000000000000000000000000000000B8 -:1008400000000000000000000000000000000000A8 -:100850000000000000000000000000000000000098 -:10086000000080804040402010080402010204087B -:100870001020408080000000000000000000000008 -:100880000000000000000000000000000000000068 -:100890000000000000000000000000000000000058 -:1008A0000000000000000000000000000000000048 -:1008B0000000000000000000000000000000000038 -:1008C0000000000000000000000000000000000028 -:1008D0000000003FC10101020204040404020201FD -:1008E0000101000000000000000000800000800006 -:1008F000006060000001020404080810102020407D -:100900008080808040404040202020201010101027 -:10091000080808080404040402020202010101019B -:1009200000000000000000000000000000000000C7 -:1009300000000000000000000000000000000000B7 -:1009400000000000000000000000000000000000A7 -:100950000000C0300C030000000000000000000098 -:100960000080868640404040212222201111101034 -:1009700008080808040404040408304080800000CB -:1009800001869860000000000000000000000000E8 -:100990000000000000000000000000000000000057 -:1009A0000000000000000000000000000000000047 -:1009B0000000000000000000000000000000000037 -:1009C0008080808040404040202020201010101067 -:1009D000080F080804040404020408101020204032 -:1009E0004041422418000000000000000000000008 -:1009F00000000000000000000000000000000101F5 -:100A000001000000000000000000000000000000E5 -:100A100000000000000000000000000000000000D6 -:100A200000000000000000000000000000000000C6 -:100A300000000000000000000000000000000000B6 -:100A400000000000000000000000000000000000A6 -:100A50000000000000000000000000000000000096 -:100A60000000000000000000000000000000000086 -:100A70000000000000000000000000000000000076 -:100A80000000000000000000000000000000000066 -:100A90000000000000000000000000000000000056 -:100AA0000000000000000000000000000000000046 -:100AB0000000000000000000000000000000000036 -:100AC0000000000000000000000000000000000026 -:100AD0000000000000000000000000000000808016 -:100AE00080804040201008040204081020408080CC -:100AF00000000000000000000000000000000000F6 -:100B000000000000000000000000000000000000E5 -:100B100000000000000000000000000000000000D5 -:100B200000000000000000000000000000000000C5 -:100B300000000000000000000000000000000000B5 -:100B40000000000000000000000000000000007E27 -:100B500082020204040808080804040201010000DB -:100B600000000000000000800000800000606000C5 -:100B700001010204040808101020204080808080B9 -:100B80004040404020202020101010100808080885 -:100B90000404040402020202010101010000000039 -:100BA0000000000000000000000000000000000045 -:100BB0000000000000000000000000000000000035 -:100BC0000000000000000000000000000000C03035 -:100BD0000C0300000000000000000000008086867A -:100BE000404040402122222011111010080808081E -:100BF00004040404040830408080000001869860EA -:100C000000000000000000000000000000000000E4 -:100C100000000000000000000000000000000000D4 -:100C200000000000000000000000000000000000C4 -:100C300000000000000000000000000080808080B4 -:100C4000404040402020202010101010080F0808BD -:100C500004040404020408101020204040414224EF -:100C6000180000000000000000000000000000006C -:100C70000000000000000000000001010100000071 -:100C80000000000000000000000000000000000064 -:100C90000000000000000000000000000000000054 -:100CA0000000000000000000000000000000000044 -:100CB0000000000000000000000000000000000034 -:100CC0000000000000000000000000000000000024 -:100CD0000000000000000000000000000000000014 -:100CE0000000000000000000000000000000000004 -:100CF00000000000000000000000000000000000F4 -:100D000000000000000000000000000000000000E3 -:100D100000000000000000000000000000000000D3 -:100D200000000000000000000000000000000000C3 -:100D300000000000000000000000000000000000B3 -:100D400000000000000000000000000000000000A3 -:100D50000000000000000000000080808080404013 -:100D600020100804020408102040808000000000C9 -:100D70000000000000000000000000000000000073 -:100D80000000000000000000000000000000000063 -:100D90000000000000000000000000000000000053 -:100DA0000000000000000000000000000000000043 -:100DB0000000000000000000000000000000000033 -:100DC000000000000000000000001C34C404040403 -:100DD00008080808080404020101000000000000DF -:100DE000800000408080400000303000010102029D -:100DF0000404040808102040808080804040404067 -:100E000020202020101010100808080804040404F2 -:100E100002020202010101010000000000000000C6 -:100E200000000000000000000000000000000000C2 -:100E300000000000000000000000000000000000B2 -:100E400000000000000000000000E01806010000A3 -:100E5000000000000000000000808383404040400C -:100E60002021212010101010080808080404040490 -:100E70000408304080800000018698600000000077 -:100E80000000000000000000000000000000000062 -:100E90000000000000000000000000000000000052 -:100EA0000000000000000000000000000000000042 -:100EB0000000000000000000808080804040404032 -:100EC0002020202010101010080F0808040404042B -:100ED0000204081010202040404142241800000065 -:100EE0000000000000000000000000000000000002 -:100EF00000000000000001010100000000000000EF -:100F000000000000000000000000000000000000E1 -:100F100000000000000000000000000000000000D1 -:100F200000000000000000000000000000000000C1 -:100F300000000000000000000000000000000000B1 -:100F400000000000000000000000000000000000A1 -:100F50000000000000000000000000000000000091 -:100F60000000000000000000000000000000000081 -:100F70000000000000000000000000000000000071 -:100F80000000000000000000000000000000000061 -:100F90000000000000000000000000000000000051 -:100FA0000000000000000000000000000000000041 -:100FB0000000000000000000000000000000000031 -:100FC0000000000000000000000000000000000021 -:100FD0000000008080404040202020202018040293 -:100FE0000102040810202040408080000000000022 -:100FF00000000000000000000000000000000000F1 -:1010000000000000000000000000000000000000E0 -:1010100000000000000000000000000000000000D0 -:1010200000000000000000000000000000000000C0 -:1010300000000000000000000000000000000000B0 -:101040000000000000060D31C1010101020202048E -:1010500004020201000000000000000080000040C7 -:1010600080804000003030000000000102040408CD -:101070000810204080808080404040402020202078 -:1010800010101010080808080404040402020202E8 -:10109000010101010000000000000000000000004C -:1010A0000000000000000000000000000000000040 -:1010B0000000000000000000000000000000000030 -:1010C000000000000000E018060100000000000021 -:1010D0000000000000808383404040402021212008 -:1010E0001010101008080808040404040408304014 -:1010F0008080000001869860000000000000000071 -:1011000000000000000000000000000000000000DF -:1011100000000000000000000000000000000000CF -:1011200000000000000000000000000000000000BF -:10113000000000008080808040404040202020202F -:1011400010101010080F080804040404020408100A -:101150001020204040414224180000000000000000 -:10116000000000000000000000000000000000007F -:10117000000001010100000000000000000000006C -:10118000000000000000000000000000000000005F -:10119000000000000000000000000000000000004F -:1011A000000000000000000000000000000000003F -:1011B000000000000000000000000000000000002F -:1011C000000000000000000000000000000000001F -:1011D000000000000000000000000000000000000F -:1011E00000000000000000000000000000000000FF -:1011F00000000000000000000000000000000000EF -:1012000000000000000000000000000000000000DE -:10121000165C1E001F002000210022002B0014007D -:101220001A00080015001700E1000400160007006E -:1012300009000A00E0001D001B000600190005005F -:101240000000E300F65C01512C002F002A0027006B -:1012500026002500240023003400130012000C0097 -:1012600018001C00280033000F000E000D000B00BA -:101270003100380037003600100011000000E40093 -:10128000F75C02512C003000010001000100010058 -:101290000100010001003500000000000000000016 -:1012A0000100BE00BD00AC00AB0000000100AA00C0 -:1012B000A900A800AD002602000001000100010005 -:1012C0000100000001000100010001000100010017 -:1012D000000000000000000000000000000000000E -:1012E0004F0052005100500031004C0000002D0012 -:1012F0002E00270200000100010000000100000094 -:1013000001003A003B003C003D003E0001000000AF -:1013100000000000000000000100000000000000CC -:1013200000000000010000000000000000000000BC -:101330000000010001000100010000000100430065 -:101340004200410040003F00450044000000000012 -:1013500000000000010000004F005200510050004A -:10136000000000000000000000000000000001007C -:10137000010001000100000000DA0281FFD9F1DB69 -:1013800020A4A62EAF00A0C000A1C800AED580A8A2 -:101390001FD300408D14200020202020202020007A -:1013A000434150530000AF00AE05010980A1018503 -:1013B0000319012AB700150126B7009501751081A0 -:1013C00000C0050C0901A101850419012AA002151C -:1013D0000126A002950175108100C005010906A132 -:1013E00001050719E029E715002501950875018118 -:1013F000029501750881010507190029FF150026CE -:10140000FF00950675088100050819012905950555 -:1014100075019102950175039101C009023B00021B -:101420000100A0FA090400000103010100092111D3 -:101430000100012240000705810308000A09040198 -:101440000001030000000921110100012232000700 -:1014500005820320000A1201000200000008D804DF -:101460002DEB0001010200010E034C0069006C002D -:10147000790035003800000010036C0069006C0032 -:10148000690075006D00730000000403090400008A -:10149000000000003E5B4F5B3E003E6B4F6B3E002A -:1014A0001C3E7C3E1C00183C7E3C18001C577D579F -:1014B0001C001C5E7F5E1C0000183C180000FFE74B -:1014C000C3E7FF00001824180000FFE7DBE7FF0078 -:1014D00030483A060E00262979292600407F050566 -:1014E0000700407F05253F005A3CE73C5A007F3EFD -:1014F0001C1C0800081C1C3E7F0014227F221400C4 -:101500005F5F005F5F0006097F017F0000668995CD -:101510006A0060606060600094A2FFA2940008040A -:101520007E04080010207E20100008082A1C0800F5 -:10153000081C2A0808001E10101010000C1E0C1E9B -:101540000C0030383E383000060E3E0E060000001B -:101550000000000000005F0000000007000700001E -:10156000147F147F1400242A7F2A12002313086496 -:101570006200364956205000000807030000001C96 -:10158000224100000041221C00002A1C7F1C2A006E -:1015900008083E08080000807030000008080808AD -:1015A00008000000606000002010080402003E51A6 -:1015B00049453E0000427F400000724949494600CB -:1015C0002141494D33001814127F1000274545452D -:1015D00039003C4A49493100412111090700364987 -:1015E00049493600464949291E0000001400000000 -:1015F00000403400000000081422410014141414A8 -:1016000014000041221408000201590906003E415D -:101610005D594E007C1211127C007F494949360009 -:101620003E41414122007F4141413E007F494949BD -:1016300041007F09090901003E41415173007F08C3 -:1016400008087F0000417F4100002040413F010029 -:101650007F08142241007F40404040007F021C026E -:101660007F007F0408107F003E4141413E007F091A -:10167000090906003E4151215E007F0919294600F3 -:1016800026494949320003017F0103003F404040A1 -:101690003F001F2040201F003F4038403F006314A0 -:1016A000081463000304780403006159494D4300A2 -:1016B000007F4141410002040810200000414141E7 -:1016C0007F0004020102040040404040400000034B -:1016D000070800002054547840007F284444380014 -:1016E000384444442800384444287F003854545433 -:1016F000180000087E0902001824241C78007F08C6 -:101700000404780000447D4000002040403D00007B -:101710007F102844000000417F4000007C047804D2 -:1017200078007C08040478003844444438007C186D -:1017300024241800182424187C007C0804040800C1 -:1017400048545454240004043F4424003C404020A6 -:101750007C001C2040201C003C4030403C004428C1 -:10176000102844004C9090907C004464544C4400F9 -:1017700000083641000000007700000000413608F4 -:1017800000000201020402003C2623263C00000067 -:1017900000000080808080000000000080E0701861 -:1017A0000C1830E080000010F8901030783010B83D -:1017B000FC3810000000000000F8FCF800000000F9 -:1017C0000000000000000000001C9C1C0000000045 -:1017D000F8FCF80000000000001CFCF8C00000004D -:1017E00000000080E0F87C1C000000F0FCFCFC1C09 -:1017F0001C1C1C1C1C1C1C000000000000C0F0F87D -:10180000381C1C1C1C1C1C3CF8F0E000E0F0F0F044 -:10181000E0ECEEF7F37020007C7C7C7E007E7E7E28 -:101820007F7F7F000080C0E07E5B4F5BFEC00000DA -:10183000C000DCD7DEDEDED7DC00C0000000000028 -:101840000000000000000000000000000000000098 -:101850000000000FBCE0818181838382870C1830F7 -:1018600060C000001FFE90B9FFBB91983C18111397 -:101870003F1100000000000000FFFFFF000000001B -:10188000000000000000000000FFFFFF000000005B -:10189000FFFFFF0000000000000000030F7FF8E0E2 -:1018A00080F0FC3F0F0100000000003F3F3F1C1C88 -:1018B0001C1C1C3C78F8F0E08000000000C3E7FF2F -:1018C0007E3C3878787070F8FFDF87000F1F3F7F0D -:1018D0007F7F7F7F3F1E0C001F1F1F3F003F3F3F4A -:1018E0007F7F7F00307B7F7830202030787F3B0007 -:1018F00003000F7F0F0F0F7F0F0003000000000099 -:101900000000000000000000000000000000183C83 -:1019100024666341C18180808080808081C1416272 -:10192000386C4CC68181808080808081C143623662 -:101930001C1800000000000000FFFFFFC0C0C0C076 -:10194000C0C0C0C0C0800000007FFF7F000000005A -:101950007FFFFFC080000000E0E0C0C0C0E0F97F72 -:101960001F0700000000000000000070F0E0E0C071 -:10197000C0C0C0E0F0F87F3F0F0000000F3F7FF9CC -:10198000E0E0C0C0C0C0C0E0F97F3F1F0000000021 -:101990000000000000000000000000000000000047 -:1019A0000000000000000000000000000000000037 -:1019B0000000000000000000000000000000000027 -:1019C00000000000000000000000000000001124E2 -:1019D0001FBECFEFDAE0DEBFCDBF04B603FE27C0E7 -:1019E0008091E9059091EA05A091EB05B091EC0595 -:1019F0008730904BA740B04BD1F41092E90510927C -:101A0000EA051092EB051092EC0514BE84B7877FAF -:101A100084BF0FB6F894A895809160008861809388 -:101A20006000109260000FBEE0E0F8E3099512E05C -:101A3000A0E0B1E0E0ECF4E602C005900D92A43421 -:101A4000B107D9F725E0A4E4B2E001C01D92A93E98 -:101A5000B207E1F70E943E270C943A320C94000042 -:101A6000CF93DF934091E7055091E805475E5340DF -:101A70009A0124583D4F21303240C0F020E032E03E -:101A8000241B350B6091E5037091E603FC01CA014C -:101A9000240F351FC1E0D0E08217930750F07093F8 -:101AA000E6036093E503DF91CF9108952CE732E0E0 -:101AB000E9CF4491DC01A951BC4F5C91451781F0FD -:101AC0004C93AC01A5E056954795AA95E1F7DE0148 -:101AD00002C0AA0FBB1F4A95E2F7AD016A2B752B16 -:101AE00001963196D9CFFC01AC014B5F5F4F8FEF70 -:101AF00091E32191822728E030E087FF09C0880F19 -:101B0000892721503109C9F7E417F50791F708959E -:101B1000880FF7CFE8EDF0E080818E7F8083109210 -:101B2000E2001092DA001092E100A0EEB0E08C9199 -:101B300081608C9380818F77808319BCA7EDB0E0A2 -:101B40008C918E7F8C9380818F7E80831092C403D2 -:101B500008952091E4003091E50095E6A9012091D7 -:101B6000EC00822F817020FF06C08091E80080FF8A -:101B700006C080E008952091E80022FD1AC08091FF -:101B8000D103882389F0853089F08091EB0085FDB1 -:101B90000FC02091E4003091E50042175307F9F29D -:101BA0009150E1F684E0089582E0089583E008957D -:101BB00081E00895EF92FF920F931F93CF937C01E2 -:101BC0008B010E94A90DC82F811117C08091E800D8 -:101BD00085FD0BC08091E8008E778093E8000E941D -:101BE000A90D882399F3C82F08C0F70181917F01BF -:101BF0008093F1000150110949F78C2FCF911F916B -:101C00000F91FF90EF9008958091D30387FF13C049 -:101C10008091E80082FF06C08091E8008B77809376 -:101C2000E80004C08091D1038111F2CF0895809122 -:101C3000D1038823D9F38091E80080FFF8CF809109 -:101C4000E8008E77ECCF982F9093E900242F762F21 -:101C500050E0891731F07091EC002091ED00509127 -:101C6000F00021FD07C09F5F973071F78093E90076 -:101C700081E008953091EB003E7F3093EB0030918E -:101C8000ED003D7F3093ED003091EB0031603093FB -:101C9000EB007093EC002093ED005093F000209146 -:101CA000EE0027FDE0CF80E00895CF92DF92EF9223 -:101CB000FF920F931F93CF93DF93C8EDD0E08881FD -:101CC0008F7E8883E7EDF0E080818160808384E00F -:101CD00082BF81E08093C40388818E7F888302EE77 -:101CE00010E0F80110821092DA0081EEC82ED12C9B -:101CF000F601108288818F77888388818068888345 -:101D000088818F7D888319BC1092D1031092D203F1 -:101D10001092D0031092CF0390EEE92EF12CF70130 -:101D200080818B7F808388818160888342E060E04E -:101D300080E00E94230EF60180818E7F8083F8016F -:101D4000808181608083808188608083F7018081C9 -:101D50008E7F8083888180618883DF91CF911F91FE -:101D60000F91FF90EF90DF90CF900895FC0180914C -:101D7000D9039091DA0386179707A0F061157105D2 -:101D800029F49091E8009E779093E80090E0611527 -:101D9000710551F4911108C08091E80082FF34C0B0 -:101DA00080E00895BC01F2CF8091D1038823C1F176 -:101DB0008530C1F18091E80083FD30C08091E8005A -:101DC00082FDEACF8091E80080FFE1CF8091F300AF -:101DD0002091F200382F6115710519F02830310576 -:101DE00058F091E02830310509F090E02091E800AA -:101DF0002E772093E800CBCF81918093F100615042 -:101E000071092F5F3F4FE7CF8091D103882341F0C5 -:101E1000853041F08091E80083FFBECF81E00895D6 -:101E200082E0089583E0089508958091C60308959F -:101E3000CF92DF92EF92FF922FB7F894C090BD033C -:101E4000D090BE03E090BF03F090C0032FBFA70166 -:101E50009601261B370B480B590BCA01B901FF909D -:101E6000EF90DF90CF9008952FB7F8946091BD0365 -:101E70007091BE038091BF039091C0032FBF08955E -:101E80009C01FC0132969FEF80E04191461751F092 -:101E90009F3F19F4411101C0982F8F5F8630A9F739 -:101EA0009F3F09F40895290F311D97FD3A95F901D7 -:101EB000628308952091BA033091BB032817390734 -:101EC00071F09093BB038093BA03E091B803F09153 -:101ED000B903309721F00084F185E02D099408952D -:101EE0002091B6033091B7032817390771F090930A -:101EF000B7038093B603E091B803F091B90330972C -:101F000021F00680F781E02D0994089580E008957E -:101F100078940895F894E82FE295EF70F0E031A1FD -:101F2000282F2F7081E090E001C0880F2A95EAF7F2 -:101F3000982F9095932391A392A1892B82A30C941F -:101F4000880F90910C0392FF06C0282F287128302B -:101F5000F9F4877F846093FF06C0282F2871283109 -:101F6000F1F4877E846120910D0320FF06C0382F95 -:101F700038713830D9F4877F816021FF06C0282F5F -:101F800028712831D1F4877E816194FD877E089580 -:101F9000282F24712430F9F68B7F8860DCCF282F1E -:101FA0002471243101F78B7E8861DDCF382F3171A8 -:101FB000313019F78E7F8860E0CF282F21712131D1 -:101FC00021F78E7E8861E1CFCF93DF93EC018238D9 -:101FD0009105A9F1D8F58133910509F496C048F52A -:101FE0008932910509F48AC08A9709F495C0C11510 -:101FF00022E5D20708F0B6C0C11531E5D30708F0D5 -:1020000026C1C83ED10508F09CC0C03ED10560F590 -:10201000C83AD10508F087C0C53AD10508F0EFC02D -:10202000C130D10509F12097F9F0C430D105E0F4B1 -:1020300040C08533910509F45AC0C997C1F6809113 -:102040000C03837089F0C0EED0E00EC0833E910592 -:1020500099F170F4803E910501F1823E910539F6C7 -:1020600080910C0382FD21C0CE01DF91CF910895B4 -:10207000863E910561F1873E910571F1843E91059F -:1020800009F0B5CF80910D0381FFEECF80910C0355 -:10209000C7EED0E084FD0DC0E7CF80910C0380FD3A -:1020A00007C190910D0390FFDFCFC3EED0E084FF16 -:1020B000DBCFD0E0C0E0D8CF80910C0382FDFBC025 -:1020C00090910D0390FDBFCF84FFCECFF2CF8091D2 -:1020D0000C0383FDDDCFC8CF80910C0383FDEEC0E0 -:1020E00090910D0391FFF0CFC4EED0E0BDCF809171 -:1020F0000C0385FFB9CFC9E2D0E0B6CF80910C03C5 -:1021000085FFB2CFC5E3D0E0AFCF80910C0386FF4F -:10211000ABCFCAE2D0E0A8CF80910C0386FFA4CF5A -:10212000C1E3D0E0A1CFCF3BD10518F6C85AD0E02B -:10213000CC0FDD1FC550DE4F0990D881C02DD4646F -:1021400093CFC11540E5D40708F064C0C11580E401 -:10215000D80708F05CC0CE019A9581159F4108F41C -:1021600083CFA7CFC11536E5D30718F5C11545E5CF -:10217000D40708F084C0C11584E5D80708F07AC0F8 -:102180009C2F969596959E0123703327C115D345B4 -:1021900008F462C0C1E0D0E002C0CC0FDD1F2A9578 -:1021A000E2F730E2939FC0011124C82BD92BDA68E3 -:1021B0005BCFC1158AE5D80778F4C11599E5D90731 -:1021C00008F068C0C11528E5D20708F472CFDC2FEB -:1021D000CC27C06FD06A48CFCE019056811590426F -:1021E00008F067CF8D2F8F710E94A10F90E0982F7C -:1021F000882788279F719C012C2BE90149C0C55A6B -:10220000D0E0C850DE4FC881D0E0D0642DCFDF7061 -:10221000D06A2ACFCE01E4E096958795EA95E1F75A -:1022200083702C2F26952695237040E2249F9001E1 -:102230001124382B8C2F8370C1E0D0E002C0CC0F6A -:10224000DD1F8A95E2F7C22BD32BDC680DCFDC2F84 -:10225000CC27C16FD06A08CFC1E0D0E002C0CC0F5C -:10226000DD1F2A95E2F720E2929FC0011124C82BBE -:10227000D92BEBCFDC2FCC27C46FD06AF5CE8C2FB7 -:102280000E94A10FC82FD0E0DC2FCC27CC27DF7114 -:10229000D062EACE8C2F8F700E94A10F34E0D695C9 -:1022A000C7953A95E1F7CF709C2FEC01D069DCCE51 -:1022B000C9E3D0E0D9CEC2EED0E0D6CEC6EED0E0B3 -:1022C000D3CE8091B80281111092B8020895809106 -:1022D000B7029091B602892B9091B502892B809319 -:1022E00046029091B802992391F0892B809346027F -:1022F00020E088E492E0FC013191CF0131112F5FA1 -:10230000F2E08E349F07B9F721110E946111E0912C -:10231000B803F091B903309731F00280F381E02DDA -:1023200086E492E0099408958091B302909182022C -:10233000981301C008958F5F8770FACFAF92BF9254 -:10234000CF92DF92EF92FF920F931F93CF93DF9381 -:10235000C0903C03D0903D03E0903E03F0903F03DB -:102360004091F7025091F8026091F9027091FA02DF -:10237000C42AD52AE62AF72ACFE1D0E0082F10E0B8 -:1023800026E0929F000D111D11249CE3A92EBC2E66 -:10239000D701C6010C2E04C0B695A79597958795D1 -:1023A0000A94D2F780FD0FC0219788F7B12C8B2DAE -:1023B000DF91CF911F910F91FF90EF90DF90CF9021 -:1023C000BF90AF900895AC9EF001AD9EF00D11242A -:1023D000E00FF11FEE0FFF1FE05FFD4E859194911E -:1023E0000E94E40F019701F3E2CFCF93DF93EC015A -:1023F0000E949E11EC2FF0E096E0D99FE00DF11DB8 -:1024000011249CE3899FE00DF11D1124EE0FFF1FA5 -:10241000E05FFD4E85919491DF91CF910C94E40F94 -:10242000E92FEE0FE90FEE0F8E0F982F977086951C -:102430008695869525E0829FF0011124EC5AFD4F88 -:1024400050E040E080E0219130E0092E02C0369556 -:1024500027950A94E2F721703327042E01C0220F3A -:102460000A94EAF7822B4F5F5F4F4530510559F7C9 -:102470000895E92FEE0FE90FEE0F8E0F982F97704A -:1024800041E001C0440F9A95EAF7869586958695B6 -:1024900095E0899FF0011124EC5AFD4F30E020E0D7 -:1024A00070E05191DF011197CB01022E02C0969589 -:1024B00087950A94E2F78170819585278423852783 -:1024C0008C932F5F3F4F2530310559F70895FC015C -:1024D000808191810E94F511292F2F7092959F7014 -:1024E00092509E3078F4E92FF0E0E45CFD4C0C94BF -:1024F0009B2E803F19F020F4883E20F481E008955F -:10250000843FE1F380E00895883EC0F3813FD1F736 -:10251000F5CF822F869586958695089590E080E088 -:102520000E94700F90E080E00E945A0F1092B60255 -:102530001092B5020C9467110F931F938B019C01AD -:102540000670112722273327063011052105310592 -:1025500069F4686060933C0370933D0380933E038D -:1025600090933F031F910F910C948E12677FF2CFCF -:102570000F931F9341E050E060E070E004C0440F0F -:10258000551F661F771F8A95D2F7CB01BA01609558 -:1025900070958095909500913C0310913D0320919A -:1025A0003E0330913F0360237123822393231F91C5 -:1025B0000F910C949C129091B40280958923809382 -:1025C000B402282F277039F4282F082E000C330B63 -:1025D0009217130621F490910D0392FF07C0859581 -:1025E000859585950E94B8121092B40208950F93B4 -:1025F0001F9341E050E060E070E004C0440F551FBD -:10260000661F771F8A95D2F780913C0390913D0316 -:10261000A0913E03B0913F038A019B01082B192B27 -:102620002A2B3B2BC901B8011F910F910C949C12CE -:102630006093F7027093F8028093F9029093FA0284 -:102640000C948E12882341F080959091B7028923D3 -:102650008093B7020C9467110895882339F0909104 -:10266000B702982B9093B7020C94671108958823B2 -:10267000B1F19CEF980F913A70F4E8E4F2E0919197 -:10268000891303C0DF0111971C9242E0EE34F40776 -:10269000B1F70C94671190E2980F983088F4877026 -:1026A00021E030E0A90102C0440F551F8A95E2F7EE -:1026B000CA0180959091B70289238093B702E9CF30 -:1026C0009BE5980F933020F490E080E00C94700F1D -:1026D000885A873120F490E080E00C945A0F0895D6 -:1026E000CF93C82F882309F44EC08CEF8C0F813A0A -:1026F000F8F4E8E4F2E08EE492E0DF012D91C217F5 -:1027000059F08A179B07D1F76C2F86E492E00E945C -:10271000400FCF910C9467112191C21303C0DF01C8 -:1027200011971C928E179F07B9F70E946711ECCF83 -:1027300080E28C0F883068F4C77021E030E001C07F -:10274000220FCA95EAF78091B702822B8093B702D5 -:10275000E0CFEBE5EC0FE33040F4F0E0E850FE4F63 -:10276000808190E0CF910C94700FC85AC73158F413 -:10277000EC2FF0E0EE0FFF1FE550FE4F80819181BE -:10278000CF910C945A0FCF910895CF93C0917503B8 -:10279000C932D0F080914F0290E001968170992764 -:1027A00080934F0221E030E0281B390B4CE752E0C8 -:1027B000249FC001259F900D349F900D11248455B6 -:1027C0009F4FCF910C94300D8091500290E0019674 -:1027D00065E070E00E94682E8093500224E030E0B3 -:1027E000281B390B4CE752E0249FC001259F900D18 -:1027F000349F900D11248C559A4F0E94300DC83291 -:1028000049F2CF910895CF92DF92EF92FF920F930A -:102810001F93CF93DF936C017B0164E670E088E740 -:102820000E94252BEC0197FD12C010E000E0F6019C -:10283000E00FF11F849164E670E00E949F2BEC0191 -:10284000892B29F40F5F1F4F0E151F0581F70E947A -:10285000222CCE01DF91CF911F910F91FF90EF902D -:10286000DF90CF9008958091B4039091B5039111BA -:1028700003C091E089270895882369F062E070E041 -:1028800087EA93E10E940314892B19F08091B40325 -:1028900008951092B4038091B403EBCFCF93C0910D -:1028A000B4038091B5038823D1F00E94340F605A9D -:1028B00075418F4F9F4F6093B0037093B103809326 -:1028C000B2039093B303C11108C062E070E085EADF -:1028D00093E10E940314892B29F0C091B4038C2F3B -:1028E000CF91089581E08093B403F7CF1092B7029F -:1028F000E8E4F2E086E0DF011D928A95E9F70C94A6 -:102900008E121F93CF93DF93CDB7DEB7AA970FB682 -:10291000F894DEBF0FBECDBF83ED93E02091F100B0 -:10292000FC012193CF01F3E08B3D9F07B9F7809124 -:10293000D403833009F46FC0B8F4813009F446C081 -:10294000823009F4B0C08091E80083FF7BC280919F -:10295000D3039091D4039A3008F074C2E92FF0E0C9 -:10296000E65BFD4C0C949B2E8A3009F48BC08B30B7 -:1029700009F46EC0893039F78091D303813219F799 -:102980008091D7039091D8030297E8F68091E800F0 -:10299000877F8093E8008091E80082FF37C09091A4 -:1029A000F3008091F200029729F48091F1008B7F6F -:1029B000813021F48091F1008093C6038091E8007A -:1029C0008B778093E8000E94040EBDCF8091D303E3 -:1029D000813A09F0B8CF8091E800877F8093E800C2 -:1029E0008091D7039091D803892B61F468E087EC3C -:1029F00093E070E00E94B60E8091E8008B778093A0 -:102A0000E800A1CF60E090E080E0F3CF8091D103B7 -:102A10008111C1CF98CF8091D303813A09F093CF30 -:102A20008091D7039091D803892B09F08CCF8091A6 -:102A3000E800877F8093E8008091E80080FFFCCF6A -:102A4000809159018093F1008091E8008E77B9CF91 -:102A50008091D303813209F076CF8091D703909192 -:102A6000D803892B09F06FCF8091E800877F80938E -:102A7000E8000E94040E8091D503809359010E94C2 -:102A8000761461CF8091D303813209F05CCF8091BD -:102A9000E800877F8093E8000E94040E8091D603AF -:102AA0008093C50350CF8091D303813A09F04BCF77 -:102AB0008091E800877F8093E8008091E80080FFA4 -:102AC000FCCF8091C503BECF803899F0823809F0E1 -:102AD000B9C18091D7038F70873008F0B3C180935C -:102AE000E9008091EB0085FB882780F91092E900CE -:102AF00006C08091CF039091D00391118260909194 -:102B0000E800977F9093E8008093F1001092F10025 -:102B10008091E8008E7792C1882309F480C18230C9 -:102B200009F090C18091D503811183C18091D703B1 -:102B30008F702FEF280F263008F084C18093E900B2 -:102B40002091EB0020FF75C1933031F48091EB00B0 -:102B500080628093EB006DC19091EB009061909347 -:102B6000EB0021E030E001C0220F8A95EAF72093C4 -:102B7000EA001092EA008091EB008860EACF8111B0 -:102B800061C11091D5031F778091E3008078812B7C -:102B90008093E3008091E800877F8093E8000E94A3 -:102BA000040E8091E80080FFFCCF8091E3008068F4 -:102BB0008093E30082E0111183E08093D10342C14E -:102BC0008058823008F03EC18091D5039091D603A1 -:102BD0008C3D23E09207A1F583E08A838AE2898312 -:102BE0004FB7F894DE01139620E03EE051E2E32F68 -:102BF000F0E050935700E49120FF03C0E295EF709E -:102C00003F5FEF708E2F90E0EA30C0F0C7968D9353 -:102C10009D932F5F243159F74FBF8091E800877F44 -:102C20008093E8006AE270E0CE0101960E94B60E41 -:102C30008091E8008B778093E80004C1C096E7CFCD -:102C40004091D7035091D803292F332723303105E2 -:102C500009F444C078F52130310509F46FC08BE3E5 -:102C600090E0EBE1F4E12230310509F0EBC0209176 -:102C7000E800277F2093E8002091D9033091DA0300 -:102C80008217930708F49C0140E02115310509F0F3 -:102C900064C0411162C08091E80082FDC9CF80917B -:102CA000D103882329F2853019F28091E80083FF4F -:102CB000F2CFBECF21323105A9F12232310509F020 -:102CC000C1C04115510509F443C04130510509F017 -:102CD000B9C082E390E0E9EAF3E1C9CF99278130F6 -:102CE0009105C1F0009759F0029709F0ABC0E8E6F2 -:102CF000F4E1E4918E2F90E0E8E6F4E107C0EAE821 -:102D0000F4E1E4918E2F90E0EAE8F4E1009709F411 -:102D100099C0ADCFE8E7F4E1E4918E2F90E0E8E7C9 -:102D2000F4E1F4CF4115510571F04130510509F03E -:102D300089C089E090E0E6E4F4E199CF82E190E097 -:102D4000E6E5F4E194CF89E090E0EDE2F4E18FCFA5 -:102D500080E490E0EBEDF3E18ACF8091D10388230A -:102D600009F466CF853009F463CF8091E80083FDD4 -:102D70005FCF8091E80082FD8ECF8091E80080FFD8 -:102D800084CF9091F3008091F2002115310519F064 -:102D90008830910550F041E0089709F040E08091BB -:102DA000E8008E778093E80070CF44914093F10063 -:102DB0003196215031090196E8CF803809F042C0A0 -:102DC0008091E800877F8093E8008091D203809310 -:102DD000F1009ECE811136C01091D503123090F5CE -:102DE0008091E800877F8093E8001093D2030E94CF -:102DF000040E112311F084E005C08091E30087FDEB -:102E0000FACF81E08093D10342E061EC81E00E943F -:102E1000230E42E261EC82E00E94230E13C08091F7 -:102E2000D503813079F481E0933009F080E080931C -:102E3000D0031092E9008091E800877F8093E8003A -:102E40000E94040E8091E80083FF0AC08091E80090 -:102E5000877F8093E8008091EB0080628093EB0095 -:102E6000AA960FB6F894DEBF0FBECDBFDF91CF910B -:102E70001F910895CF93DF93682F81E06A3019F096 -:102E80006D3029F480E0DF91CF910C94BB178091D5 -:102E9000E7059091E80526E0FC01AFEDB3E0019075 -:102EA0000D922A95E1F7603E08F45AC026E0FC0135 -:102EB00011922A95E9F7C091E705D091E80546E01F -:102EC00050E0BE018FED93E00E94192F9E01275E16 -:102ED0003340892B41F1C90145E0969587954A9584 -:102EE000E1F741E050E0BA0102C0660F771F8A9512 -:102EF000E2F7CB016091E5037091E603862B972BF7 -:102F0000B9016B5F7F4FE5E076956795EA95E1F74C -:102F100002C0440F551F6A95E2F7842B952B9093BE -:102F2000E6038093E5032A5F3F4F4091DE03642F61 -:102F300070E0C9010E94482E481B463010F4240F4F -:102F4000311D211572E0370710F030E020E02951E3 -:102F50003C4F3093E8052093E705DF91CF9108952A -:102F6000F6E06F9FB001112462577B4E46E050E0BF -:102F70000E94102FA0CFCF93382FE091E705F0915A -:102F8000E805E75EF3402091DE03622F70E0CF0199 -:102F90000E94482E281B822F332361F066E00E9496 -:102FA0005C2EC82FC15010F4CF91089580E20E948A -:102FB0003A17F8CF9F01280F311D2115324018F024 -:102FC00080E0F0E0E0E08E0F9F2F911D89519C4F33 -:102FD0009093E8058093E705E7CF0F931F93CF9376 -:102FE000DF93EC01FC0101900020E9F78F01015013 -:102FF0001109C017D10728F0DF91CF911F910F91D0 -:10300000089589910E943A17F4CF9091D10394309A -:1030100031F58093C1037093C3036093C20382E0D0 -:103020008093E9008FEF9091E800815095FD06C0F4 -:1030300095ED9A95F1F700008111F5CF8091E800A8 -:1030400085FF0DC050E040E063E070E081EC93E06C -:103050000E94DA0D8091E8008E778093E800089551 -:10306000BC0184E00C940518BC0183E00C940518A5 -:10307000CF93DF93EC0181E08093E9008FEF909193 -:10308000E800815095FD06C095ED9A95F1F7000096 -:103090008111F5CF8091E80085FF14C050E040E039 -:1030A00068E070E0CE010E94DA0D8091E8008E7732 -:1030B0008093E80088E0FE01A7ECB3E001900D9258 -:1030C0008A95E1F7DF91CF9108959F92AF92BF92D9 -:1030D000CF92DF92EF92FF920F931F93CF93DF93E4 -:1030E0007C015B016A018091070301E010E08A30F6 -:1030F00010F40AE010E0C1E0D0E0F894B501C70197 -:10310000F6010995982E0E94880F911004C021960F -:103110000C171D076CF4892DDF91CF911F910F9132 -:10312000FF90EF90DF90CF90BF90AF909F90089569 -:10313000CC9F9001CD9F300D300D112490E080E0A8 -:1031400045E34A95F1F70000019682179307C1F70E -:10315000D4CF8091D102811110C08091D8008061BC -:103160008093D8008AE18A95F1F700C08091D90058 -:1031700080FF0AC081E08093D10281E09091D1026A -:10318000913009F080E0089582E08093D1020E949E -:103190008A0D1092D103F1CF0E94A918882351F013 -:1031A000E091B803F091B903309721F00190F081DC -:1031B000E02D099480E00895CF9384E090E00E9490 -:1031C000F831C82F82E290E00E94F831982F8C2FBE -:1031D000CF910895BF92CF92DF92EF92FF920F931B -:1031E0001F93CF93DF93B82EEB01F42E6901688112 -:1031F00079818A819B810E94180F6436710581054F -:10320000910510F4FF2019F1EB2C0B2C000CFF089A -:103210008B2D9AE08902F0011124EF5FFE4F83812C -:10322000948185529D4F428150E00417150708F4A0 -:10323000A801B6010E94262FC7010E94942D892B58 -:1032400089F40E94340F688379838A839B8381E0A9 -:10325000DF91CF911F910F91FF90EF90DF90CF9072 -:10326000BF90089580E0F4CF0F931F93CF93DF9327 -:103270000F92CDB7DEB78091B40389832091EE021F -:1032800090E041E02817190609F440E001E010E061 -:103290009E012F5F3F4F63E073E086E00E94EA18D3 -:1032A0000F90DF91CF911F910F9108950F931F936E -:1032B000CF93DF930F92CDB7DEB7809175038983EB -:1032C00041E09091ED02981301C040E001E010E070 -:1032D0009E012F5F3F4F6FEF72E085E00E94EA187A -:1032E0000F90DF91CF911F910F9108950F931F932E -:1032F00041E00091E5021091E6022091E702309151 -:10330000E80280913C0390913D03A0913E03B0916F -:103310003F03081719072A073B0709F440E004E0B8 -:1033200010E02CE333E06BEF72E083E00E94EA18D8 -:10333000882301F141E00091E9021091EA02209115 -:10334000EB023091EC028091F7029091F802A0918B -:10335000F902B091FA02081719072A073B0709F486 -:1033600040E004E010E027EF32E063EF72E084E039 -:103370000E94EA181F910F9108950F931F93CF9306 -:10338000DF9300D000D0CDB7DEB76091EF0270912F -:10339000F0028091F1029091F2020E94180F6436BF -:1033A00071058105910588F10E94A918882379F19A -:1033B0000E94340F6E5F7F4F8F4F9F4F69837A83D8 -:1033C0008B839C83809118019091190185529D4FA8 -:1033D0004091170150E04530510510F044E050E0B5 -:1033E000BE016F5F7F4F0E94262F82E090E00E9417 -:1033F000942D892BD9F40E94340F6093EF027093BF -:10340000F0028093F1029093F20281E010C00E94DA -:10341000340F009108031091090320910A033091A1 -:103420000B03600F711F821F931FC4CF80E00F90AA -:103430000F900F900F90DF91CF911F910F910895F2 -:103440000F931F93CF93DF9300D000D000D0CDB760 -:10345000DEB78B0190E080E00E94942D892B09F06B -:1034600071C04091060150E04115510511F041E055 -:1034700050E0609107017091080165527D4FCE01C7 -:1034800006960E94262F6091D7027091D8028091F3 -:10349000D9029091DA020E94180F643671058105F5 -:1034A000910540F48CED92E00E94730D9E81891786 -:1034B00009F455C081E090E00E94942D892BA1F081 -:1034C00080E095E0E2EDF2E0D80101900D929A954E -:1034D000E1F726960FB6F894DEBF0FBECDBFDF91A1 -:1034E000CF911F910F9108954091100150E0463007 -:1034F000510510F045E050E060911101709112010A -:1035000065527D4FCE0101960E94262F8CED92E0F0 -:103510000E94730D9E818913D3CF0E94340F609354 -:10352000D7027093D8028093D9029093DA0285E093 -:10353000FE013196A2EDB2E001900D928A95E1F77D -:1035400081E0BFCF80E095E0ECEDF2E0DE01119686 -:1035500001900D929A95E1F78111E9CFB2CF81E008 -:10356000F2CF69EE7EEF90E080E00E94243260E0CE -:1035700082E090E00E94063260E083E090E00E94EA -:1035800006321092F7021092F8021092F90210928D -:10359000FA0260E084E090E00E94063260E082E29D -:1035A00090E00E94063260E085E090E00E940632E2 -:1035B00060E086E090E00E9406326FEF87E090E0E6 -:1035C0000E94063240E050E0BA0188E090E00E949C -:1035D000183260E08DE090E00E94063240E050E05A -:1035E000BA0188E190E00E94183260E087E190E043 -:1035F0000E94063240E050E0BA018CE190E00E9467 -:10360000183270E060E080E290E00E94243240E0F6 -:1036100050E0BA0188E190E00E94183240E050E0AA -:10362000BA018FE090E00E94183240E050E0BA0109 -:1036300083E190E00C941832CF93C0910D03C2FB4C -:10364000992790F9981781F080FBC2F9C0930D0378 -:1036500060910C0384E090E00E9406326C2F82E2BD -:1036600090E0CF910C940632CF9108951F920F9263 -:103670000FB60F9211242F933F934F935F936F9345 -:103680007F938F939F93AF93BF93CF93DF93EF93EA -:10369000FF93D091E900DF708091EC00C82FC170DA -:1036A00080FDC0E81092E9008091F000877F809350 -:1036B000F00078940E9481141092E9008091F0004B -:1036C00088608093F000CD2BCF70C093E900FF910C -:1036D000EF91DF91CF91BF91AF919F918F917F91AA -:1036E0006F915F914F913F912F910F900FBE0F906F -:1036F0001F9018951F920F920FB60F9211242F93BF -:103700003F934F935F936F937F938F939F93AF9369 -:10371000BF93EF93FF938091E10082FF09C08091F6 -:10372000E20082FF05C08091E1008B7F8093E10081 -:103730008091DA0080FF24C08091D80080FF20C0F3 -:103740008091DA008E7F8093DA008091D90080FF2B -:103750009BC080E189BD82E189BD09B400FEFDCF37 -:1037600081E08093D1038091C403811109C00E943C -:103770008A0D0E94550E8091E20084608093E200E1 -:103780008091E10080FF17C08091E20080FF13C0AC -:103790008091E2008E7F8093E2008091E200806160 -:1037A0008093E2008091D80080628093D80019BC99 -:1037B00085E08093D1038091E10084FF29C080914E -:1037C000E20084FF25C080E189BD82E189BD89B521 -:1037D000982F917080FFFBCF8091D8008F7D8093D0 -:1037E000D8008091E1008F7E8093E1008091E2001B -:1037F0008F7E8093E2008091E20081608093E200FE -:103800008091D203882309F445C084E08093D103DA -:103810008091E10083FF27C08091E20083FF23C0F5 -:103820008091E100877F8093E10082E08093D10363 -:103830001092D2038091E1008E7F8093E10080910D -:10384000E2008E7F8093E2008091E20080618093AD -:10385000E20042E060E080E00E94230E8091F000F0 -:1038600088608093F000FF91EF91BF91AF919F919D -:103870008F917F916F915F914F913F912F910F9019 -:103880000FBE0F901F90189519BC1092D103109283 -:10389000C40376CF8091E30087FD93E09093D1033A -:1038A000B7CF78941F921FB61F9211248F939F93C6 -:1038B000AF93BF938091BD039091BE03A091BF03CE -:1038C000B091C0030196A11DB11D8093BD039093DB -:1038D000BE03A093BF03B093C003BF91AF919F916C -:1038E0008F911F901FBE1F9018959C014FB7F894A1 -:1038F0008091BD039091BE03A091BF03B091C0031E -:103900004FBF821B930B08952FB7F8948091BD038E -:103910009091BE03A091BF03B091C0032FBF089543 -:103920000F931F93CF93DF93C62FD42F022FFC0149 -:1039300082818823A1F06093DD030E94841C909310 -:10394000DC038093DB03C77081E001C0880FCA9558 -:10395000EAF7DF91CF911F910F910C942D13809175 -:10396000DD03681338C08091DB039091DC030E9473 -:10397000751C8436910578F510E21D0FCD17B9F04E -:1039800080E28C0F883040F4C77081E001C0880F5E -:10399000CA95EAF70E942213183048F481E09D2F5F -:1039A000977001C0880F9A95EAF70E942D13802F17 -:1039B0000E947013802F0E943713183098F4D7702C -:1039C00081E001C0880FDA95EAF7DF91CF911F916E -:1039D0000F910C942213C77081E001C0880FCA9523 -:1039E000EAF7F3CFDF91CF911F910F9108954F9296 -:1039F0005F926F927F928F929F92AF92BF92CF927F -:103A0000DF92EF92FF920F931F93CF93DF9300D03B -:103A100000D00F92CDB7DEB77C01FC018381948189 -:103A2000892B39F01081D180812F8D218F3F09F0B2 -:103A3000C9C40F900F900F900F900F90DF91CF910E -:103A40001F910F91FF90EF90DF90CF90BF90AF90BC -:103A50009F908F907F906F905F904F9008950E94FD -:103A60009E11082F682F89819A810E943912E12FB7 -:103A7000F0E026E0D29EE00DF11D11243CE3039F0F -:103A8000E00DF11D1124EE0FFF1FE05FFD4E0591CB -:103A90001491F7018281882309F45DC0C801905612 -:103AA0008115F0E29F0750F0905E811520E19207AA -:103AB00028F0915C81159F4108F08BC0C8019927BF -:103AC0009C01245031092432310518F08B970E9750 -:103AD00040F4E091BE02F0E0ED53FD4F80818F5F36 -:103AE000808380E2D82E0C33110520F4F801E454D1 -:103AF000FE4FD0801F92DF921F930F93F7018081BA -:103B00001F928F9381811F928F938AE591E09F93FB -:103B10008F931F9288E18F9380E493E09F938F931C -:103B20000E94362F0FB6F894DEBF0FBECDBF809136 -:103B3000510290915202449709F454C0809151026D -:103B400090915202FC01E85AFC4FD082019690936A -:103B5000520280935102043F3CE5130709F4ACC0C4 -:103B600008F04EC0093D9CE5190709F4A1C00A3DC3 -:103B7000ECE51E0709F4ACC0083DFCE51F0709F0A1 -:103B80004EC026E241EE61EEC7010E94901C80917A -:103B9000B402877009F44DCFF7018281882309F4BC -:103BA00048CF82E00F900F900F900F900F90DF9111 -:103BB000CF911F910F91FF90EF90DF90CF90BF902A -:103BC000AF909F908F907F906F905F904F900C94EC -:103BD000DB1290E080E00F3F110511F008F070CF8C -:103BE000C8016ECF1092520210925102E8E5F3E044 -:103BF0008CE693E020E221938E179F07E1F79ECF9A -:103C0000063F2CE5120709F45FC008F459C027E20B -:103C100045EE66EE073F8CE5180709F4B5CFF701CE -:103C20008281882309F4DFC31092DD030230FCE5B2 -:103C30001F0708F42EC106312CE5120730F0C80129 -:103C40008B5F9C45099708F024C10E94DC18909373 -:103C50000D0380930C0300313CE5130709F4E8C021 -:103C600008F076C008309CE5190709F4D7C008F0C1 -:103C700045C00430FCE51F0709F4C8C060F50230F8 -:103C80003CE5130709F4B8C003301C4509F4BAC079 -:103C900060910C0310910D0384E090E00E940632C5 -:103CA000612F82E290E00E9406320E9476146FCF6C -:103CB00027E245EE65EE68CF26E241EE60EE64CF86 -:103CC00027E245EE64EE60CF26E241EE62EE5CCF85 -:103CD00028E241E0EFCF80910C03806106309CE543 -:103CE000190709F48CC080910C03886007301C45CB -:103CF00008F485C080910C03806281C080910C0320 -:103D00008D7F0C30FCE51F0709F479C070F48091B9 -:103D10000C038C600A303CE5130709F470C008F40A -:103D200081C080910C038E7F6AC080910C03877FD5 -:103D30000E309CE5190709F462C080910C038B7F5B -:103D40000F301C4508F45BC080910C038F7E57C078 -:103D50000C3FFCE51F0709F45DC030F503313CE57D -:103D6000130709F46DC078F401319CE5190709F4D3 -:103D700063C002311C4509F08BCF0E9476148091FC -:103D80000C038F773CC00531FCE51F0709F460C0C8 -:103D900008F474C080910D0381600B3F1C4509F04D -:103DA00077CF80930D0374CF01158DE5180709F4C3 -:103DB0004BC088F480910D038D7F0E3FECE51E070C -:103DC00081F380910D038E7F0F3F1C4550F380914E -:103DD0000D038360E6CF02302DE5120709F457C0CA -:103DE00008F442C060E003301D4509F051CF8EE079 -:103DF00090E00E9406324CCF80910C03816080934A -:103E00000C0346CF80910C038260F9CF80910C03A4 -:103E10008460F5CF80910D038260C3CF80910C0345 -:103E20008064EDCF0E94761480910C038068E7CF08 -:103E300080910C038F7DE3CF80910C038F7BDFCFCC -:103E400080910C03837FDBCF80910D038C7FA9CF02 -:103E500080910C0382FB992790F921E0922790FB37 -:103E600082F990FB83F9CBCF80910D03982F909529 -:103E700091708E7F892B90FB81F993CF0E947614ED -:103E800090910C03892F97FB87F98058B8CF61E098 -:103E9000AECF06319CE5190709F0BBC28091B7028D -:103EA0008A7A91E009F490E09093530269E28111DB -:103EB00065E386E492E00E94400F0E94671167CE9E -:103EC00085E399C20E947614EFEFF4E32CE0E15011 -:103ED000F0402040E1F700C0000087E797E79093AB -:103EE00001088093000888E19AE00FB6F894A8953D -:103EF000809360000FBE90936000FFCF81E0A9C265 -:103F000080E0A7C2812F902F0E941012D82EB4C239 -:103F1000212F2F70A22E107F19F0A29430EFA32230 -:103F2000DD20C9F0AA2069F080E2800F883010F00F -:103F300081100BC08091B702A82AA092B7020E94FC -:103F40006711802F0E94701318C08091B602A82AB2 -:103F5000A092B602F4CF802F0E943713AA2069F0F6 -:103F6000A094005E083010F0811045C08091B70227 -:103F7000A822A092B7020E946711EB2DE850FF0B18 -:103F8000349710F40E94CC18CC20A9F08091B40290 -:103F900080FD11C0F70112828595859585950E9457 -:103FA000F712C7010E94F71C8091B4028595859590 -:103FB00085950E94B81285E0F701DE011196019007 -:103FC0000D928A95E1F789819A810E9410129A8157 -:103FD000E981F0E026E0929FE00DF11D11243CE321 -:103FE000839FE00DF11D1124EE0FFF1FE05FFD4EDA -:103FF000859194911ECD8091B602A822A092B6021E -:10400000BACF312F3F70932E107F103219F0929457 -:1040100020EF9222882071F081E0881681F1DD2066 -:10402000D9F1AA2091F1F701858180FF8ACF8F70A5 -:1040300085832BC0DD20B1F09091B802892D892BAA -:10404000A11003C00E942D1398CFE1E0AE12FACF69 -:1040500020910D0322FD91CF981709F48ECF809304 -:10406000B8028BCFA11006C00E946111892D0E9459 -:10407000221383CFF1E0AF1609F47FCFF5CFDD2017 -:1040800031F025E02A1508F478CF892DDBCF34E014 -:104090003A1508F472CFEACFAA2041F3F9E38F1260 -:1040A0008AC12FEF37EE83E0215030408040E1F7A6 -:1040B00000C0000080C1812F86958695837061F0D5 -:1040C000813009F05ACFC8019370D11002C090E03E -:1040D00080E00E945A0F51CFC8019370D11002C0E6 -:1040E00090E080E00E94700F48CF812F837009F02C -:1040F00066C0D11042CF802F829586958770880F39 -:10410000880F602F6F70462E512C712C612C082E59 -:1041100004C0440C551C661C771C0A94D2F740E07E -:1041200050E0BA0104FF0FC04FE050E060E070E0E3 -:1041300004C0440F551F661F771F8A95D2F740951C -:10414000509560957095812F869586958370823005 -:1041500019F1D8F40091F7021091F8022091F902B8 -:104160003091FA02813069F044295529662977296E -:10417000CB01BA0160237123822393230E94181379 -:10418000FCCE402A512A622A732ACB01BA01642943 -:10419000752986299729F2CF442955296629772937 -:1041A0000091F7021091F8022091F9023091FA0281 -:1041B000CB01BA016027712782279327DFCF86952D -:1041C000DD2011F0812F8170882309F4D6CE802F55 -:1041D000829586958770880F880F602F6F70462EA6 -:1041E000512C712C612C082E04C0440C551C661CEB -:1041F000771C0A94D2F740E050E0BA0104FF0FC0E8 -:104200004FE050E060E070E004C0440F551F661FAF -:10421000771F8A95D2F74095509560957095812FBC -:10422000869586958370823019F1D8F400913C030D -:1042300010913D0320913E0330913F03813069F09E -:104240004429552966297729CB01BA0160237123B6 -:10425000822393230E949C1290CE402A512A622AE4 -:10426000732ACB01BA016429752986299729F2CFCF -:10427000442955296629772900913C0310913D0373 -:1042800020913E0330913F03CB01BA016027712793 -:1042900082279327DFCF1F70DD2029F0812F0E9416 -:1042A000F712802FCFCE802F0E942213812F0E94E1 -:1042B000B81263CE802F92EF891609F454C0981576 -:1042C00078F0E0EF8E1639F1F1EF8F1609F443C064 -:1042D000DD2009F46BC0A11034CE812F8F7140C056 -:1042E00023EF821609F444C034EF8312F1CFDD20AE -:1042F00009F451C01F71812F0E94F71280910D03A4 -:1043000082FD07C0E8E01E9FC001112483608093F6 -:10431000B402812F25C0DD20C9F084E08A1508F49D -:104320002CCE1F7161E070E080E090E004C0660F69 -:10433000771F881F991F1A95D2F700913C0310919F -:104340003D0320913E0330913F03A0CF95E09A15A5 -:1043500008F413CEE6CF812F8F71DD2009F4A7CFAB -:104360000E94F7120ACE812F8F71DD20C9F39FCFF3 -:1043700060E070E0CB01DD2009F46CCF1F7161E0DB -:1043800070E080E090E004C0660F771F881F991FDF -:104390001A95D2F75FCF81E00E94DB12F1E0FA15A7 -:1043A00008F0EBCD82E00E94DB12E7CDAA2039F0C5 -:1043B000893309F476CE802F0E943713DECD812F0A -:1043C0008F7175CF85E0DE01119601900D928A956F -:1043D000E1F7F701228189819A81211140CB0E9466 -:1043E0001012082F44CB06311C45A9F580915302C9 -:1043F000811166CD89E2E8E4F2E02EE432E09191A9 -:10440000891303C0DF0111971C922E173F07B9F7DC -:1044100054CD0B352DE5120709F470CD58F4011574 -:104420008CE5180709F44ECD0F3D1C45A1F40E9400 -:10443000B11AADCB0C35EDE51E0709F461CD0D3594 -:104440001D4549F480910D0382FB882780F991E096 -:1044500089270E941C1BF70182811081018188231A -:1044600009F450CD812F902F0E949E11D82E682FD5 -:10447000812F902F0E943912E12FF0E026E0029F59 -:10448000E00DF11D11243CE3D39EE00DF11D11243C -:10449000EE0FFF1FE05FFD4E859194910E94E40FA7 -:1044A0008C01882EF701D280A580A2946FE0A6220D -:1044B0008091B4028770A1F0CD2CDD2091F0812F86 -:1044C000807F803421F080E2800F883048F082E0E5 -:1044D0000E94DB128091B4028770CC24C3948111B6 -:1044E000C12CB12EB2944FE0B422FBE0FB1508F4CE -:1044F00044CDEB2DF0E0EC5AFD4C0C949B2E1F9319 -:10450000CF93DF9380918102807FA9F480917E0216 -:10451000882389F08091B302D091820260917C025D -:1045200070917D02A0917F02B0918002C62FC723B7 -:1045300016E0D81304C0DF91CF911F91089590E049 -:10454000109711F0CF3F19F401968770F2CF189FA2 -:104550009001199F300D1124F901ED57FD4F418154 -:104560004713F2CF40814613EFCF42814111ECCF88 -:10457000438154814A1B5B0B4436510528F78091D7 -:1045800081028F70806180938102F901E857FD4FAD -:1045900080818F70806180838CE792E00E94F71C9D -:1045A000DF91CF911F910C949411AF92BF92CF9253 -:1045B000DF92EF92FF920F931F93CF93DF93CDB7CC -:1045C000DEB761970FB6F894DEBF0FBECDBF8C018A -:1045D00085E0F801DE011D9601900D928A95E1F7C4 -:1045E000F801E2808CE7A82E82E0B82E60917F026D -:1045F000709180026115710509F422C190917C02CD -:1046000040917D02892F84238F3F09F419C12081B5 -:104610003181C380D480F0907E02F601E61BF70B57 -:10462000FF2009F4F4C080918102582F507FE436B6 -:10463000F10508F0B7C0511177C0FE2C431321C01B -:1046400092131FC0E1101DC08F70806180938102A2 -:10465000C5010E94F71C80918102F80185838F2D8E -:1046600061960FB6F894DEBF0FBECDBFDF91CF913C -:104670001F910F91FF90EF90DF90CF90BF90AF9080 -:104680000895CD2829F0822F83238F3F09F0F3C0AE -:1046900080E0F82FF170DF2E80FF3CC08091B302E4 -:1046A0004091820256E0841315C02D873E878D8588 -:1046B0009E850E94F511292F22952F702230F0F04F -:1046C000243018F59F70F1F0F8019581907FD1F4B6 -:1046D000D12C1EC090E0589FF001599FF00D11247D -:1046E000ED57FD4F6181361306C06081261303C06C -:1046F0006281E6120FC001968770D5CF9F7011F0CE -:10470000882331F3805E883018F3C8010E94F71CBB -:10471000FD2CA5CFEE2009F4A2CF8091810281600B -:1047200080938102F12C9BCF431312C0921310C0CF -:10473000E1100EC0F8018583C8010E94F71C86E0D5 -:10474000F801ACE7B2E001900D928A95E1F787CFCE -:10475000C8010E946712882309F1EE20F9F08091C8 -:104760008102803270F020917C0230917D02388786 -:104770002F831986DB86CA868C87CE0107960E9416 -:10478000F71C86E0F801ACE7B2E001900D928A9543 -:10479000E1F70E947F22FF24F39461CFC8010E94B9 -:1047A000F71CF9CF51110AC08CE792E00E94F71C68 -:1047B00086E0F50111928A95E9F7B4CF43130FC053 -:1047C00092130DC0E1100BC0F8018583C8010E944F -:1047D000F71C86E0F50111928A95E9F740CFC801F0 -:1047E0000E9467128823D1F2EE20C1F280918102EB -:1047F000803238F220917C0230917D023A83298305 -:104800001B82DD82CC828E83CE010196B8CFE43646 -:10481000F105F8F6FE2CEE2009F2431303C09217BF -:1048200009F48DCFC8010E9467128111AACF80912F -:104830008102816080938102C8010E94F71C0FCF22 -:10484000EE2009F4ABCFC8010E946712F82E88232E -:1048500009F4A4CF86E0F801ACE7B2E001900D9234 -:104860008A95E1F780917C0290917D020E94F5117A -:104870000E947F22F4CE81E08E250BCF1F93CF9331 -:10488000DF93CDB7DEB767970FB6F894DEBF0FBEE4 -:10489000CDBF4B8B5C8B6D8B7E8B8F8B61111092A0 -:1048A000B6021A8A198A85E0FE017396DE011D960A -:1048B00001900D928A95E1F786E0FE013D96DE01BA -:1048C000179601900D928A95E1F7CE0107960E9406 -:1048D000D522882389F016E08091B302909182025C -:1048E000891349C067960FB6F894DEBF0FBECDBFDF -:1048F000DF91CF911F91089586E0FE013796DE018A -:10490000119601900D928A95E1F78A859B85892BF6 -:1049100011F38F81988589238F3FE9F220918202DC -:1049200030E0C9010196877099274091B30248177A -:10493000190671F40E947614109282021092B3024A -:1049400086E0ECE7F2E0DF011D928A95E9F7C3CF3C -:1049500096E0929FD001939FB00D1124AD57BD4FAB -:10496000FE01319601900D929A95E1F780938202B3 -:104970000E949411B0CF819FC00111248D579D4F8B -:104980000E94D522882309F4ADCF8091B30290E034 -:104990000196877099278093B3029ECF9F92AF9222 -:1049A000BF92CF92DF92EF92FF920F931F93CF931C -:1049B000DF93CDB7DEB72F970FB6F894DEBF0FBEEB -:1049C000CDBF8E010F5F1F4F8AE0D8011D928A95DF -:1049D000E9F78BE2C82E82E0D82EF12CE12CAA2434 -:1049E000A394B12CF60181916F018F3F09F44AC065 -:1049F000F894E82FE295EF70F0E021A18F70A50107 -:104A000002C0440F551F8A95E2F7CA01922F982BD6 -:104A100091A392A18095892382A30E94880F00C050 -:104A2000E5E3F2E030E020E0912C41914F3F09F4C2 -:104A30007EC0A42FA295AF70B0E090968C9190E0CC -:104A40004F7002C0959587954A95E2F780FD6FC03B -:104A50008A2D022E01C0880F0A94EAF7982A2F5F48 -:104A60003F4F2630310509F7F601319780818F3F9E -:104A700011F00E948A0F50EA5A95F1F7F801EE0DF5 -:104A8000FF1D90828FEFE81AF80A95E0E916F1040D -:104A900009F0A8CF4AE050E0B8018EE093E00E9410 -:104AA000192F7C01892B41F08AE0F801AEE0B3E0D8 -:104AB00001900D928A95E1F710911903E114F10428 -:104AC000C1F181E08093BB020E94841C9093BA02E2 -:104AD0008093B9028091B9029091BA020E94751C2C -:104AE000059778F0AEE0B3E0E12FF0E0E65EFC4F32 -:104AF00083E193E02D9121938A179B07D9F71092B8 -:104B0000BB0281E090E0EF28C1F02F960FB6F89439 -:104B1000DEBF0FBECDBFDF91CF911F910F91FF90F0 -:104B2000EF90DF90CF90BF90AF909F90089580E07E -:104B300095CF8091BB028111CDCF0E94A918B82ECC -:104B4000E0911903882309F4F5C08E01055F1F4F1A -:104B500085E0D8011D928A95E9F7F0E09F01265E75 -:104B60003C4F790180910703AE01405F5F4F6A01BE -:104B70008A3008F0ADC040E25AE1B801C7010E9496 -:104B80006518882309F4BBC04DEB59E1B801C70192 -:104B90000E946518882309F4B2C046E759E1B801BC -:104BA000C7010E946518882309F4A9C046E559E1A8 -:104BB000B801C7010E946518882309F4A0C044E326 -:104BC00059E1B801C7010E946518882309F497C00C -:104BD00010920703E0911803F0E0AF01465E5C4FCE -:104BE000D801F12CFA019191AF018D91981731F014 -:104BF0009F0121503109F9018083FB2CCA16DB0685 -:104C000089F7C090C3020C2C000CDD081091000144 -:104C1000A12EB12C81E090E08A159B050CF480C098 -:104C20008091C1029091C2020E94751C853FF1E003 -:104C30009F07BCF1809175038093C00220E63AEE95 -:104C4000D6010E94A12E44EC59E0A49E9001A59E9D -:104C5000300DB49E300D1124032E000C440B550B67 -:104C60000E947C2E2093BF028091BE0290E00196AC -:104C70006AE070E00E94682E8093BE028D539D4FC3 -:104C8000DC011C92912F1A3008F099E09F5F9093FD -:104C900000010E94841C9093C2028093C10290E0A4 -:104CA00080E02091C0024091BF02421B550B489FFB -:104CB000B001499F700D589F700D1124CB0164EF16 -:104CC00071E00E94682E260F209375038F2D1DCF53 -:104CD0008091BC029091BD020E94751C843F91405E -:104CE00008F049CFA0911803B0E0A65EBC4FF801D0 -:104CF0001D921192CE16DF06D9F7FB2C82CF809140 -:104D000007038F3F31F08F5F809307038A3008F4E9 -:104D100061CF0E94841C9093BD028093BC02E2CFBD -:104D2000FC01ED53FD4F2081C20ED11C27FDDA940A -:104D3000019672CFF0E0E65EFC4FF89485E0ACEDB2 -:104D4000B2E001900D928A95E1F78CED92E00E941D -:104D5000730D8093DB020E94880FF894C090E102EB -:104D6000D090E202E090E302F090E4028091CD0264 -:104D70009091CE02A091CF02B091D002C816D90670 -:104D8000EA06FB06D1F0C092CD02D092CE02E092AC -:104D9000CF02F092D0020E94A91881110EC00E9489 -:104DA000340FC61AD70AE80AF90AC0920803D0924B -:104DB0000903E0920A03F0920B030E94880FF89413 -:104DC0008091E5029091E602A091E702B091E8029D -:104DD00080933C0390933D03A0933E03B0933F0325 -:104DE0008091E9029091EA02A091EB02B091EC026D -:104DF0008093F7029093F802A093F902B093FA021D -:104E00000E94880FF8948091ED02809375030E94B0 -:104E1000880FF8948091EE02882331F00E944E149E -:104E20000E94880F80E071CE0E943314F9CF1F9248 -:104E30001FB61F9211248F939F93AF93BF938091BE -:104E4000BC03811113C08091BD039091BE03A0915A -:104E5000BF03B091C0034196A11DB11D8093BD0356 -:104E60009093BE03A093BF03B093C003BF91AF91D3 -:104E70009F918F911F901FBE1F901895CDB7DEB7E1 -:104E80002C970FB6F894DEBF0FBECDBF84B7877FD7 -:104E900084BF0FB6F894A8958091600088618093D4 -:104EA0006000109260000FBE80E890E00FB6F894AA -:104EB00080936100909361000FBE85B7806885BFC5 -:104EC00085B7806885BF86E89FE090934502809310 -:104ED00044020E948A0D0E94550E8091E200846077 -:104EE0008093E20078948091D1038823A1F01091FF -:104EF000E9001F709091EC00892F817090FD80E88F -:104F0000182B1092E9008091E80083FD0E94811423 -:104F10001F701093E90082E084BD93E095BD9AEF85 -:104F200097BD80936E0010920803109209031092AF -:104F30000A0310920B030E94A918809347010E9454 -:104F4000A91881110E94872C809147018091470107 -:104F500095E0811190E09093190385E0891B80937F -:104F600018030BE212E0D8018D918D018F3F11F0F3 -:104F70000E948A0FB2E000331B07A9F705E312E095 -:104F8000F80181918F018F3F11F00E948A0FF2E0AA -:104F90000B331F07A9F7EEE0F3E0AAE1B3E01192AB -:104FA0001D9223E0E831F207D1F790E080E00E9403 -:104FB0000032893E9E4F11F00E94B11A82E090E0CB -:104FC0000E94F8318093A5030E94DC1890930D0392 -:104FD00080930C0383E090E00E94F831682F70E02A -:104FE00090E080E00E9418130E94A918811102C06D -:104FF0000E948A2C0E94A9188111D0C082E080935F -:10500000A00380E88093DE030E941F2B6DE070E018 -:105010008BE893E10E940314892BE9F58091A003AA -:1050200063E070E081FDBCC088E893E10E94031456 -:10503000892B89F56DE070E088E793E10E94031405 -:10504000892B49F50E94340F605A75418F4F9F4F4D -:105050006093B0037093B1038093B2039093B30352 -:10506000E7EEF3E080E092E0DF019C011D92215029 -:105070003040E1F7F093E805E093E7058FEF9FEF0D -:105080009093E6038093E50381E08093B5038093DA -:10509000B4031092A10388E491E09093B903809344 -:1050A000B80358E1852E912C8091D10312E185300F -:1050B00009F4AFC00E94CE24D82E81110E94340F73 -:1050C000E6EAF3E0AAE1B3E010E000E0B02EED90F4 -:1050D00081918E1509F4ACC08E25C12CFF24F39468 -:1050E000982F9F2109F49FC00E94A918882399F046 -:1050F000C982BA82EF2081E009F480E08B830E94AC -:10510000841C8160782F9D838C8349815A816B81B7 -:105110008D810E943E24F801EA55FC4F8081F826DB -:10512000F0828091B503882351F18091A203909180 -:10513000A3030E94751CC29708F091C02091E5035B -:105140003091E6032115310509F090C18091B40337 -:105150008823A9F00E94340F0091B0031091B1038D -:105160002091B2033091B303601B710B820B930B40 -:105170006F3F7F4F8F4F9F4710F40E943314D11021 -:105180000E944E140E94CC189091A403891709F430 -:105190008BCF0E94CC188093A40386CF80E02FCFC2 -:1051A00085E893E143CF8091D103843011F11092CF -:1051B000BC0330E40FB6F894A895809260000FBE4F -:1051C0003093600083B7817F846083BF83B7816041 -:1051D00083BF7894889583B78E7F83BF0FB6F8948A -:1051E000A8958091600088618093600010926000B3 -:1051F0000FBE8091D003882361F00E94CE24EAE1A3 -:10520000F3E08191811104C284E293E08E179F073D -:10521000C1F78091D103853009F4C5CF0E9476147F -:105220000E94CC1847CFC394FF0C96E0C91258CF08 -:105230000F5F1F4F0A30110509F048CF8FEF8E83A3 -:105240008F8318860E94841C8160782F9A878987B3 -:105250004E815F8168858A850E943E2462CF0E94CC -:10526000841C9093A3038093A20387EE93E0909312 -:10527000E8058093E7050E94A918882309F462C015 -:1052800080913C0390913D03A0913E03B0913F0378 -:1052900084309105A105B10509F451C010F50097BE -:1052A000A105B10559F167E871E082309105A105CA -:1052B000B10531F1BF93AF939F938F9382EA91E051 -:1052C0009F938F931F9288E18F9384E293E09F9343 -:1052D0008F930E94362F0FB6F894DEBF0FBECDBF5E -:1052E00013C088309105A105B10529F08E309105D4 -:1052F000A105B105F9F664E971E002C06BE671E061 -:1053000084E293E00E942F2F84E293E00E94ED1745 -:1053100081E00E94BB1780E493E00E94ED1781E0DA -:105320000E94BB1788E593E00E94ED1781E00E9480 -:10533000BB178091B503882309F408CFFFCE6AE735 -:1053400071E0DECF80917503882309F460C00E946C -:105350004E14609171037091720380917303909168 -:1053600074030E94180F693C71058105910560F076 -:105370000E94340F609371037093720380937303E0 -:10538000909374030E94C5130E94340F60936D03C1 -:1053900070936E0380936F039093700387EE93E096 -:1053A0009093E8058093E705809175031F928F9392 -:1053B00083EB91E09F938F9386E793E09F938F9386 -:1053C0000E94662F86E793E00E94ED170E94CC189A -:1053D0002091DE0330E029513C4F3093E8052093C3 -:1053E000E7050F900F900F900F900F900F9008E926 -:1053F00013E181FF02C000EA13E1F80184918823E0 -:1054000009F497CF0E943A170F5F1F4FF6CF6091B4 -:105410006D0370916E0380916F03909170030E94F1 -:10542000180F61367A4E8105910518F00E943314E9 -:10543000B5CF609171037091720380917303909165 -:1054400074030E94180F693C71058105910508F4E9 -:10545000A5CF0E94340F6093710370937203809301 -:105460007303909374030E94C51398CF8091A10396 -:1054700061E070E081116ACE082F10E07B01082EF8 -:1054800002C0EE0CFF1C0A94E2F7A9014E215F2135 -:10549000452B09F447C09091A00390FD45C082952B -:1054A000880F80768093540198013695279536951C -:1054B000279520935701815E8093550110925801E2 -:1054C00024E630E047E050E062E571E088E70E94C2 -:1054D000CE2B892B09F03ACEA80125E0440F551FA9 -:1054E0002A95E1F78091A00380FD2CC049515C4FC3 -:1054F00004E610E020E230E060E488E70E94F52B4B -:10550000892B09F023CE0E944E14E094F0948091F0 -:10551000E5039091E603E822F922F092E603E09297 -:10552000E50314CE8F5FA8CF880F880F880F809374 -:10553000540110925701895F8093550183E0809355 -:105540005801BECFE0E8F3E080E2DF011D928A95CA -:10555000E9F7EFE3F2E0FC87EB870BE312E093E47B -:10556000292E92E0392EAB85BC852D91BC87AB8767 -:10557000F80141908F01440E552E511CC2018951F2 -:105580009C4F2C01E22FF0E0E058FC4F30E020E08F -:1055900087E0682E621ACC24C394022E01C0CC0C82 -:1055A0000A94EAF7520190E0D5018D915D018C21BA -:1055B000662D691B6770762E062E000C770BB82FB0 -:1055C00001C0BB0F7A94EAF77B2E71956195710942 -:1055D0006770772701C086956A95EAF7782A8081F7 -:1055E000782A70829F5F9830F9F62F5F3F4F31968F -:1055F0002830310569F6EB85FC852E163F0609F04B -:10560000B2CF04E610E020E230E040E853E074CF8F -:1056100020E129BD19BD09B400FEFDCF8091D8005D -:105620008F7D8093D8008091E00082608093E000BD -:105630008091E00081FDFCCF0E947614EACD1092AB -:10564000B9008CE08093B80008959F92AF92BF920A -:10565000CF92DF92EF92FF920F931F93CF93DF933E -:10566000B82EEB010E94841C6C01EE24E394F12C13 -:10567000C431D10560F025E0E22EF12CCF3FDC07EC -:1056800031F0CE0164E170E00E94482E7B0184EA93 -:10569000A82E94E8992E1092BC00A092BC000E9403 -:1056A000841C8C018091BC0087FF0DC08091B900E3 -:1056B000887F883039F18091B900887F803111F17D -:1056C0000FEF1FEF09C00E94841C801B910B8E15E9 -:1056D0009F0540F30EEF1FEFCF3FDC07E1F2C6015D -:1056E0000E94751C8C179D07B0F2C801DF91CF9105 -:1056F0001F910F91FF90EF90DF90CF90BF90AF90F0 -:105700009F900895B092BB009092BC000E94841CB0 -:105710008C018091BC0087FF0AC08091B900887F0E -:10572000883111F0803461F610E000E0DECF0E9495 -:10573000841C801B910B8E159F0558F3CBCF0F93C4 -:105740001F93CF93DF93EB018093BB0084E880939A -:10575000BC000E94841C8C018091BC0087FF11C09A -:105760002091B900287F81E090E0283211F490E088 -:1057700080E0919581959109DF91CF911F910F91D3 -:105780000895CF3FDC0741F30E94841C801B910BDE -:105790008C179D0708F38EEF9FEFEECFCF92DF922D -:1057A000EF92FF920F931F93CF93DF936B018A01C8 -:1057B0007901B9010E94252BE6010C0D1D1DC017B2 -:1057C000D10761F424E92093BC00DF91CF911F91B0 -:1057D0000F91FF90EF90DF90CF90089597FDF2CF5B -:1057E000B70189910E949F2BEACFCF92DF92EF926F -:1057F000FF920F931F93CF93DF93C62F6A01790116 -:10580000B8010E94252B97FD0CC0B8018C2F0E9477 -:105810009F2BE601EC0CFD1CCE15DF0511F097FF68 -:105820000CC024E92093BC00DF91CF911F910F9110 -:10583000FF90EF90DF90CF900895B80189910E947A -:105840009F2BEACF84E98093BC0008958EE14A9BA8 -:1058500002C08150E1F74A9BFECF08955A9880E23A -:105860008A95F1F75A9A0895FC013BE03A95F1F7D1 -:1058700098E020E080E031E040E14A95F1F7880FC0 -:105880004A9B02C08160232742E04A95F1F700005D -:1058900040E14A95F1F7915079F790E19A95F1F747 -:1058A00099B132E03A95F1F7000040E14A95F1F7FD -:1058B00092FB992790F992272081920F9083089567 -:1058C000EF92FF920F931F93CF93DF930F92CDB779 -:1058D000DEB719828C017C01E60EF11C0E151F0546 -:1058E00061F481E09981911180E00F90DF91CF9177 -:1058F0001F910F91FF90EF9008950E94262CCE01EA -:1059000001960E94342CF80181938F01E7CF529ABF -:105910005A9A089552985A9AEA9AE9E6F0E08081F4 -:105920008F7C808308956150770B91E001C0990FBF -:105930006A95EAF720E031E0911108C0222391F046 -:105940005A9A80E28A95F1F75A980895492F482388 -:1059500039F05A9A232740E24A95F1F79695ECCF11 -:105960005A98F9CF5A98EDCFFF920F931F93CF9388 -:10597000DF93EC018C01060F111DC017D10731F424 -:10598000DF91CF911F910F91FF900895F9900E94A0 -:105990002E2C68E08F2D0E94932CEFCF1F920F9238 -:1059A0000FB60F921124EF92FF920F931F932F9334 -:1059B0003F934F935F936F937F938F939F93AF9397 -:1059C000BF93EF93FF93CF93DF930F92CDB7DEB7E3 -:1059D00019820E94262CCE0101960E94342CA82FF9 -:1059E000A695A695A695282F229525709A2F957095 -:1059F000290F922F937026952695920F98279770CE -:105A00008981982B09F075C0A83008F072C080E138 -:105A10008A95F1F75A9A529AB2E0BA95F1F700C016 -:105A20005A98EA2EF12CEAE0AE9FD0011124AF5F24 -:105A3000BE4F1896ED91FC9119973097B1F0609197 -:105A4000290270912A0216962D913C911797260FE4 -:105A5000371F13968D919C911497680F791F159697 -:105A60004C91159712968C9109958AE08E9DF001C4 -:105A70008F9DF00D1124EF5FFE4F6581662351F07D -:105A80002091290230912A0286819781820F931FEB -:105A90000E94B42C0E942E2CF0E1FA95F1F75A984E -:105AA00052985A9A80E18A95F1F78AE08E9D80019A -:105AB0008F9D100D11240F5F1E4FD80112966C910F -:105AC0001297662371F12091290230912A021396D0 -:105AD0008D919C91820F931F0E94602CD801ED91B3 -:105AE000FC91882311F088E001C082E080830E944D -:105AF000262C0F90DF91CF91FF91EF91BF91AF9145 -:105B00009F918F917F916F915F914F913F912F91D5 -:105B10001F910F91FF90EF900F900FBE0F901F906D -:105B20001895ED91FC91DFCF0F931F93CF93DF93E7 -:105B3000EC0108970CF0A9C08AE08C9FF0018D9FC2 -:105B4000F00D1124EF5FFE4F80819181892B09F4C4 -:105B50009CC0F894529A5A9885E08A95F1F7000013 -:105B60008C2F869585709C2F9570890F982F937038 -:105B700086958695890F8E0193E0000F111F9A95E7 -:105B8000E1F7082B0E942E2C00C068E0802F0E94B5 -:105B9000932CA0E1AA95F1F752985A9A4A9B27C0F4 -:105BA00087E090E04A9925C08AE08C9F80018D9F14 -:105BB000100D11240F5F1E4FF80165816623A1F1BE -:105BC0002091290230912A0286819781820F931FAA -:105BD0000E94602C811128C0529A5A9AD801ED91E6 -:105BE000FC9182E08083789482E090E016C000C04F -:105BF000D5CF0197B9F4529A5A9A8AE08C9FF00156 -:105C00008D9FF00D1124EF5FFE4F0190F081E02D8C -:105C100081E08083789481E090E0DF91CF911F91C3 -:105C20000F91089500C0BECF0E94262CB0E2BA9515 -:105C3000F1F75A98529AE0E1EA95F1F78AE08C9FE1 -:105C4000F0018D9FF00D1124EF5FFE4F62816623FE -:105C500051F02091290230912A0283819481820F90 -:105C6000931F0E94B42C0E942E2C8AE08C9FF0017E -:105C70008D9FF00D1124EF5FFE4F0190F081E02D1C -:105C80001082789490E080E0C8CF84E090E0C5CFA7 -:105C9000AA1BBB1B51E107C0AA1FBB1FA617B70752 -:105CA00010F0A61BB70B881F991F5A95A9F780956E -:105CB0009095BC01CD010895991B79E004C0991F0E -:105CC000961708F0961B881F7A95C9F78095089556 -:105CD00097FB072E16F4009407D077FD09D00E9499 -:105CE000482E07FC05D03EF4909581959F4F08956E -:105CF000709561957F4F0895052E97FB1EF40094D3 -:105D00000E94932E57FD07D00E94A82E07FC03D0B7 -:105D10004EF40C94932E50954095309521953F4F1D -:105D20004F4F5F4F089590958095709561957F4F87 -:105D30008F4F9F4F0895EE0FFF1F0590F491E02DB8 -:105D400009940E94CA2EB7FF0895821B930B0895F1 -:105D5000A1E21A2EAA1BBB1BFD010DC0AA1FBB1F6F -:105D6000EE1FFF1FA217B307E407F50720F0A21BE1 -:105D7000B30BE40BF50B661F771F881F991F1A944E -:105D800069F760957095809590959B01AC01BD0178 -:105D9000CF010895A29FB001B39FC001A39F700DD2 -:105DA000811D1124911DB29F700D811D1124911D23 -:105DB00008952F923F924F925F926F927F928F92AF -:105DC0009F92AF92BF92CF92DF92EF92FF920F938A -:105DD0001F93CF93DF93CDB7DEB7CA1BDB0B0FB694 -:105DE000F894DEBF0FBECDBF09942A883988488851 -:105DF0005F846E847D848C849B84AA84B984C884E7 -:105E0000DF80EE80FD800C811B81AA81B981CE0FDD -:105E1000D11D0FB6F894DEBF0FBECDBFED010895C2 -:105E2000FB01DC0102C005900D9241505040D8F7B3 -:105E30000895FB01DC0104C08D910190801921F4CB -:105E400041505040C8F7881B990B0895FB01DC01B5 -:105E500002C001900D9241505040D8F70895FB01C7 -:105E6000DC0101900D920020E1F70895AEE0B0E072 -:105E7000ECE3FFE20C94E72E0D891E898F89988D43 -:105E800026E02C831A83098397FF02C080E090E804 -:105E900001979E838D83AE01455E5F4F698D7A8D3C -:105EA000CE0101960E94892F4D815E8157FD0AC067 -:105EB0002F813885421753070CF49A01020F131FE4 -:105EC000F80110822E96E4E00C94032FAEE0B0E0CF -:105ED000ECE6FFE20C94E72E0D891E8986E08C83A8 -:105EE0001A8309838FEF9FE79E838D83AE01475E00 -:105EF0005F4F6F89788DCE0101960E94892F2F8187 -:105F00003885020F131FF80110822E96E4E00C94DE -:105F1000032FABE0B0E0EFE8FFE20C94D92E7C0158 -:105F20003B018A01FC0117821682838181FFB9C17E -:105F30009AE0292ECE0101965C01F7019381F301CD -:105F400093FD859193FF81913F01882309F446C118 -:105F5000853239F493FD859193FF81913F0185321C -:105F600029F4B70190E00E946A31E7CF912C412CCF -:105F7000512CFFE1F51538F08B3209F188F48032AD -:105F800001F1833221F157FC3AC020ED280F2A306D -:105F900040F556FE1FC0929C200D1124922E06C083 -:105FA0008D3291F0803379F7689450F8F30193FDC6 -:105FB000859193FF81913F018111DBCF20C06894CF -:105FC00051F8689452F8F2CF689453F8EFCF689480 -:105FD00054F8ECCF429C200D1124422E689455F8C1 -:105FE000E5CF8E3229F456FCF9C0689456F8DECF1E -:105FF0008C3619F4689457F8D9CF8836B9F2982FAF -:106000009F7D95549330C0F08336A1F18337C1F161 -:10601000833509F05BC0F801C190D1908F01692DE3 -:1060200070E056FC02C06FEF7FEFC6010E94543152 -:106030004C01689457F80AC00C5F1F4F2FE3298367 -:1060400088248394912C6501E89457F853FC04C08C -:106050004814190409F018F5342C8114910431F511 -:10606000332009F46ACFB70180E290E00E946A31E0 -:106070003A94F6CFF801808189830E5F1F4FE0CFFD -:10608000F801C190D1908F01692D70E056FC02C0DB -:106090006FEF7FEFC6010E945F314C01D5CFB70192 -:1060A00080E290E00E946A314A94D2CFF60157FC18 -:1060B000859157FE81916F01B70190E00E946A318E -:1060C00031103A94F1E08F1A9108C7CF843619F055 -:1060D000893609F074C0F80157FE6AC06191719168 -:1060E000819191918F01252D2F76D22E97FF09C096 -:1060F00090958095709561957F4F8F4F9F4F6894D5 -:10610000D7F82AE030E0A5010E949A31C82ECA18BB -:106110008C2C5D2CD6FE0CC0E89450F8C91440F4C9 -:10612000D4FE05C0D2FC03C0FD2DFE7E5F2E892C5F -:1061300054FE8FC0FE01EC0DF11D8081803309F00B -:1061400081C0252D297E522E852D8870382E53FC36 -:106150008FC050FE89C09C2C841418F44C0C942CD5 -:10616000981854FE8BC0B70180E390E00E946A311A -:1061700052FE09C088E790E051FE02C088E590E039 -:10618000B7010E946A31C91408F484C0CA94D12CA2 -:106190009FEFC91AD90ACA0CDB1CF60182916F0164 -:1061A000B70190E00E946A31AC14BD04B1F758CF3A -:1061B00061917191072E000C880B990B93CFD52C10 -:1061C000E894D4F82AE030E0853739F1952D997FAD -:1061D000D92E8F3601F148F48835A9F0F701868170 -:1061E00097812B96E2E10C94F52E803749F08837A1 -:1061F000A9F7D4FE02C06894D2F820E130E00DC0C7 -:106200006894D4F8F6CF54FE03C0E92FE660DE2E82 -:1062100020E132E002C028E030E0F801D7FE0DC0F6 -:1062200061917191819191918F01A5010E949A31A3 -:10623000C82ECA18E894D7F86BCF6191719190E09D -:1062400080E0F2CF52FC02C083947ECF839483948B -:106250007BCF852D867809F477CFF6CFB70180E222 -:1062600090E00E946A3183948414C0F3312C79CF7A -:10627000342C3818841408F474CFF8CF852D867820 -:1062800009F481CF8BE251FE80E257FC8DE2B70129 -:1062900090E077CFB70180E390E00E946A319A9452 -:1062A00072CF8FEF9FEF9DCFFC0105906150704042 -:1062B0000110D8F7809590958E0F9F1F0895FC01CF -:1062C0006150704001900110D8F7809590958E0F25 -:1062D0009F1F08950F931F93CF93DF93182F092FBC -:1062E000EB018B8181FD09C01FEF0FEF812F902FF4 -:1062F000DF91CF911F910F91089582FF14C02E81DD -:106300003F818C819D81281739073CF4E881F98110 -:10631000CF0101969983888310838E819F81019696 -:106320009F838E83E3CFE885F985812F0995892B9B -:10633000A1F3DACFFA01AA27283051F1203181F1F7 -:10634000E8946F936E7F6E5F7F4F8F4F9F4FAF4F7D -:10635000B1E03ED0B4E03CD0670F781F891F9A1F90 -:10636000A11D680F791F8A1F911DA11D6A0F711D44 -:10637000811D911DA11D20D009F468943F912AE050 -:10638000269F11243019305D3193DEF6CF01089538 -:10639000462F4770405D4193B3E00FD0C9F7F6CF69 -:1063A000462F4F70405D4A3318F0495D31FD405231 -:1063B000419302D0A9F7EACFB4E0A69597958795C7 -:1063C00077956795BA95C9F70097610571050895A6 -:1063D0009B01AC010A2E0694579547953795279552 -:1063E000BA95C9F7620F731F841F951FA01D0895EA -:1063F000F999FECF92BD81BDF89A992780B508958D -:10640000A8E1B0E042E050E00C942C32262FF9993C -:10641000FECF92BD81BDF89A019700B4021639F003 -:106420001FBA20BD0FB6F894FA9AF99A0FBE0895D4 -:106430000396272F0E9407320E940632252F0E94C2 -:106440000732242F0C9407320196272F0E9407321F -:106450000C940632DC01CB01FC01F999FECF06C099 -:10646000F2BDE1BDF89A319600B40D924150504012 -:10647000B8F70895F894FFCF791279128212821238 -:106480008412821282128212791279128912821275 -:106490008212891264158C1522178C152217BF15CC -:1064A000E0152217DD16EA16881F881F012001203B -:1064B0005B20BD1FBD1FBD1F75204B215A215A21D6 -:1064C000014E0200000001000000004E020000002A -:1064D00005010000004E0204060000000000004E0E -:1064E00002040A0000000000004E02040E0000003A -:1064F0000000004E0201120000000000004E0201E8 -:106500001300000000000001150F3818140F341894 -:1065100030180021007F2200030125647825642CB7 -:10652000206B253264203A202563004C6179657226 -:106530003A2044656661756C74004C617965723A05 -:10654000205261697365004C617965723A204C6F25 -:10655000776572004C617965723A2041646A75739F -:1065600074004C617965723A20556E6465662D251C -:106570006C640057504D3A253033640020202020B1 -:106580006162636465666768696A6B6C6D6E6F7083 -:106590007172737475767778797A3132333435362F -:1065A0003738393052454254202020202020203BCB -:1065B00027202C2E2F202020818283E200E900EA70 -:1065C00000B500B600B700CD008301CC008A01926F -:1065D0000194012102230224022502260227022A15 -:1065E00002B300B4006F007000DB026697C634355A -:1065F0000000000000F6F73133323600081018189A -:04660000100800007E -:00000001FF diff --git a/navi_font.c b/navi_font.c new file mode 100644 index 0000000..2412256 --- /dev/null +++ b/navi_font.c @@ -0,0 +1,139 @@ +// Copyright 2021 Nicolas Druoton (druotoni) +// SPDX-License-Identifier: GPL-2.0-or-later + +// This is the 'classic' fixed-space bitmap font for Adafruit_GFX since 1.0. +// See gfxfont.h for newer custom bitmap font info. + +#include "progmem.h" + +// Standard ASCII 5x7 font +const unsigned char font[] PROGMEM = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x42, 0x3A, 0x12, 0x12, 0x0E, 0x00, + 0x0C, 0x44, 0x47, 0x24, 0x1C, 0x00, + 0x24, 0x24, 0x14, 0x7F, 0x04, 0x00, + 0x42, 0x3F, 0x02, 0x22, 0x1E, 0x00, + 0x0A, 0x0A, 0x7F, 0x0A, 0x0A, 0x00, + 0x02, 0x47, 0x42, 0x22, 0x1F, 0x00, + 0x21, 0x15, 0x09, 0x15, 0x63, 0x00, + 0x44, 0x44, 0x3F, 0x04, 0x04, 0x00, + 0x22, 0x1A, 0x02, 0x7F, 0x12, 0x00, + 0x22, 0x22, 0x12, 0x0A, 0x06, 0x00, + 0x08, 0x47, 0x42, 0x22, 0x1E, 0x00, + 0x10, 0x52, 0x54, 0x30, 0x16, 0x00, + 0x40, 0x3A, 0x02, 0x3E, 0x42, 0x00, + 0x5E, 0x52, 0x52, 0x52, 0x5E, 0x00, + 0x04, 0x27, 0x44, 0x44, 0x3C, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x77, 0x00, 0x77, 0x00, 0x77, 0x00, + 0x14, 0x22, 0x7F, 0x22, 0x14, 0x00, + 0x5F, 0x5F, 0x00, 0x5F, 0x5F, 0x00, + 0x06, 0x09, 0x7F, 0x01, 0x7F, 0x00, + 0x00, 0x66, 0x89, 0x95, 0x6A, 0x00, + 0x60, 0x60, 0x60, 0x60, 0x60, 0x00, + 0x94, 0xA2, 0xFF, 0xA2, 0x94, 0x00, + 0x08, 0x04, 0x7E, 0x04, 0x08, 0x00, + 0x10, 0x20, 0x7E, 0x20, 0x10, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x1C, 0x1C, 0x1C, 0x00, 0x00, + 0x00, 0x08, 0x1C, 0x08, 0x00, 0x00, + 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x5F, 0x00, 0x00, 0x00, + 0x00, 0x07, 0x00, 0x07, 0x00, 0x00, + 0x14, 0x7F, 0x14, 0x7F, 0x14, 0x00, + 0x24, 0x2A, 0x7F, 0x2A, 0x12, 0x00, + 0x23, 0x13, 0x08, 0x64, 0x62, 0x00, + 0x36, 0x49, 0x56, 0x20, 0x50, 0x00, + 0x00, 0x08, 0x07, 0x03, 0x00, 0x00, + 0x00, 0x1C, 0x22, 0x41, 0x00, 0x00, + 0x00, 0x41, 0x22, 0x1C, 0x00, 0x00, + 0x2A, 0x1C, 0x7F, 0x1C, 0x2A, 0x00, + 0x08, 0x08, 0x3E, 0x08, 0x08, 0x00, + 0x00, 0x80, 0x70, 0x30, 0x00, 0x00, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, + 0x00, 0x00, 0x60, 0x60, 0x00, 0x00, + 0x20, 0x10, 0x08, 0x04, 0x02, 0x00, + 0x3E, 0x51, 0x49, 0x45, 0x3E, 0x00, + 0x00, 0x42, 0x7F, 0x40, 0x00, 0x00, + 0x72, 0x49, 0x49, 0x49, 0x46, 0x00, + 0x21, 0x41, 0x49, 0x4D, 0x33, 0x00, + 0x18, 0x14, 0x12, 0x7F, 0x10, 0x00, + 0x27, 0x45, 0x45, 0x45, 0x39, 0x00, + 0x3C, 0x4A, 0x49, 0x49, 0x31, 0x00, + 0x41, 0x21, 0x11, 0x09, 0x07, 0x00, + 0x36, 0x49, 0x49, 0x49, 0x36, 0x00, + 0x46, 0x49, 0x49, 0x29, 0x1E, 0x00, + 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x00, 0x40, 0x34, 0x00, 0x00, 0x00, + 0x00, 0x08, 0x14, 0x22, 0x41, 0x00, + 0x14, 0x14, 0x14, 0x14, 0x14, 0x00, + 0x00, 0x41, 0x22, 0x14, 0x08, 0x00, + 0x02, 0x01, 0x59, 0x09, 0x06, 0x00, + 0x3E, 0x41, 0x5D, 0x59, 0x4E, 0x00, + 0x7C, 0x12, 0x11, 0x12, 0x7C, 0x00, + 0x7F, 0x49, 0x49, 0x49, 0x36, 0x00, + 0x3E, 0x41, 0x41, 0x41, 0x22, 0x00, + 0x7F, 0x41, 0x41, 0x41, 0x3E, 0x00, + 0x7F, 0x49, 0x49, 0x49, 0x41, 0x00, + 0x7F, 0x09, 0x09, 0x09, 0x01, 0x00, + 0x3E, 0x41, 0x41, 0x51, 0x73, 0x00, + 0x7F, 0x08, 0x08, 0x08, 0x7F, 0x00, + 0x00, 0x41, 0x7F, 0x41, 0x00, 0x00, + 0x20, 0x40, 0x41, 0x3F, 0x01, 0x00, + 0x7F, 0x08, 0x14, 0x22, 0x41, 0x00, + 0x7F, 0x40, 0x40, 0x40, 0x40, 0x00, + 0x7F, 0x02, 0x1C, 0x02, 0x7F, 0x00, + 0x7F, 0x04, 0x08, 0x10, 0x7F, 0x00, + 0x3E, 0x41, 0x41, 0x41, 0x3E, 0x00, + 0x7F, 0x09, 0x09, 0x09, 0x06, 0x00, + 0x3E, 0x41, 0x51, 0x21, 0x5E, 0x00, + 0x7F, 0x09, 0x19, 0x29, 0x46, 0x00, + 0x26, 0x49, 0x49, 0x49, 0x32, 0x00, + 0x03, 0x01, 0x7F, 0x01, 0x03, 0x00, + 0x3F, 0x40, 0x40, 0x40, 0x3F, 0x00, + 0x1F, 0x20, 0x40, 0x20, 0x1F, 0x00, + 0x3F, 0x40, 0x38, 0x40, 0x3F, 0x00, + 0x63, 0x14, 0x08, 0x14, 0x63, 0x00, + 0x03, 0x04, 0x78, 0x04, 0x03, 0x00, + 0x61, 0x59, 0x49, 0x4D, 0x43, 0x00, + 0x00, 0x7F, 0x41, 0x41, 0x41, 0x00, + 0x02, 0x04, 0x08, 0x10, 0x20, 0x00, + 0x00, 0x41, 0x41, 0x41, 0x7F, 0x00, + 0x04, 0x02, 0x01, 0x02, 0x04, 0x00, + 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, + 0x00, 0x03, 0x07, 0x08, 0x00, 0x00, + 0x20, 0x54, 0x54, 0x78, 0x40, 0x00, + 0x7F, 0x28, 0x44, 0x44, 0x38, 0x00, + 0x38, 0x44, 0x44, 0x44, 0x28, 0x00, + 0x38, 0x44, 0x44, 0x28, 0x7F, 0x00, + 0x38, 0x54, 0x54, 0x54, 0x18, 0x00, + 0x00, 0x08, 0x7E, 0x09, 0x02, 0x00, + 0x18, 0x24, 0x24, 0x1C, 0x78, 0x00, + 0x7F, 0x08, 0x04, 0x04, 0x78, 0x00, + 0x00, 0x44, 0x7D, 0x40, 0x00, 0x00, + 0x20, 0x40, 0x40, 0x3D, 0x00, 0x00, + 0x7F, 0x10, 0x28, 0x44, 0x00, 0x00, + 0x00, 0x41, 0x7F, 0x40, 0x00, 0x00, + 0x7C, 0x04, 0x78, 0x04, 0x78, 0x00, + 0x7C, 0x08, 0x04, 0x04, 0x78, 0x00, + 0x38, 0x44, 0x44, 0x44, 0x38, 0x00, + 0x7C, 0x18, 0x24, 0x24, 0x18, 0x00, + 0x18, 0x24, 0x24, 0x18, 0x7C, 0x00, + 0x7C, 0x08, 0x04, 0x04, 0x08, 0x00, + 0x48, 0x54, 0x54, 0x54, 0x24, 0x00, + 0x04, 0x04, 0x3F, 0x44, 0x24, 0x00, + 0x3C, 0x40, 0x40, 0x20, 0x7C, 0x00, + 0x1C, 0x20, 0x40, 0x20, 0x1C, 0x00, + 0x3C, 0x40, 0x30, 0x40, 0x3C, 0x00, + 0x44, 0x28, 0x10, 0x28, 0x44, 0x00, + 0x4C, 0x90, 0x90, 0x90, 0x7C, 0x00, + 0x44, 0x64, 0x54, 0x4C, 0x44, 0x00, + 0x00, 0x08, 0x36, 0x41, 0x00, 0x00, + 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, + 0x00, 0x41, 0x36, 0x08, 0x00, 0x00, + 0x02, 0x01, 0x02, 0x04, 0x02, 0x00, + 0x3C, 0x26, 0x23, 0x26, 0x3C, 0x00 +}; diff --git a/navi_logo.c b/navi_logo.c new file mode 100644 index 0000000..6041aa5 --- /dev/null +++ b/navi_logo.c @@ -0,0 +1,117 @@ +// Copyright 2021 Nicolas Druoton (druotoni) +// SPDX-License-Identifier: GPL-2.0-or-later + +#include QMK_KEYBOARD_H + +#include "gui_state.h" +#include "navi_logo.h" +#include "fast_random.h" +#include "draw_helper.h" + +#define LOGO_SIZE 128 + +// glitch stuff +#define GLITCH_FRAME_NUMBER 11 + +uint8_t current_glitch_index = 0; +int current_glitch_time = 150; +uint32_t glitch_timer = 0; + +static void render_logo_clean(void) { + // your logo here + static const char PROGMEM raw_logo[] = { + 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, + }; + oled_write_raw_P(raw_logo, sizeof(raw_logo)); +} + +void render_glitch_bar(uint8_t x, uint8_t y, uint8_t width, uint8_t height, uint8_t iProb) { + // random horizontal scanlines + for (uint8_t i = 0; i < height; i++) { + bool bGenerateGlitch = (fastrand() % 100) < iProb; + + if (bGenerateGlitch) { + drawline_hr(x, y + i, width, true); + } + } +} + +void render_misc_glitch(uint8_t algo) { + char c = 0; + switch (algo) { + case 7: + // invert + for (uint8_t i = 0; i < LOGO_SIZE; i++) { + c = get_oled_char(i); + oled_write_raw_byte(~(c), i); + } + break; + + case 8: + // wobble + for (uint8_t i = 0; i < LOGO_SIZE; i++) { + if (i < LOGO_SIZE - 1) { + copy_pixel(i + 1, -1, 85); + + copy_pixel(LOGO_SIZE - 1 - 1 - i, 1, 170); + } + } + break; + } +} + +static void render_logo_glitch(void) { +#ifdef WITH_GLITCH + // get a random glitch index + uint8_t glitch_prob = get_glitch_probability(); + get_glitch_index(&glitch_timer, ¤t_glitch_time, ¤t_glitch_index, 0, 150, glitch_prob, GLITCH_FRAME_NUMBER); + + // no glitch + if (current_glitch_index <= 3) { + render_logo_clean(); + return; + } + + // glitch time ! + switch (current_glitch_index) { + case 4: + move_block(1, 11, 24, 3, 5); + move_block(2, 19, 14, 3, 4); + move_block(9, 22, 7, 4, 4); + return; + + case 5: + move_block(6, 25, 20, 7, 4); + move_block(0, 8, 32, 8, 7); + return; + case 6: + move_block(3, 7, 27, 4, -3); + move_block(13, 23, 19, 4, -4); + return; + + case 7: + case 8: + render_misc_glitch(current_glitch_index); + return; + + case 9: + render_glitch_bar(0, 0, 32, 32, 25); + return; + + case 10: + draw_static(0, 0, 32, 32, true, 0); + return; + } +#endif +} + +void render_logo(gui_state_t t) { + if (t == _IDLE) { + // on idle : glitch time ! + render_logo_glitch(); + return; + } + + // standart logo + render_logo_clean(); +} diff --git a/navi_logo.h b/navi_logo.h new file mode 100644 index 0000000..3504568 --- /dev/null +++ b/navi_logo.h @@ -0,0 +1,7 @@ +// Copyright 2021 Nicolas Druoton (druotoni) +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +void render_logo(gui_state_t t); + diff --git a/nm.json b/nm.json deleted file mode 100644 index 76c2e64..0000000 --- a/nm.json +++ /dev/null @@ -1,191 +0,0 @@ -{ - "version": 1, - "notes": "", - "documentation": "\"This file is a QMK Configurator export. You can import this at . It can also be used directly with QMK's source code.\n\nTo setup your QMK environment check out the tutorial: \n\nYou can convert this file to a keymap.c using this command: `qmk json2c {keymap}`\n\nYou can compile this keymap using this command: `qmk compile {keymap}`\"\n", - "keyboard": "lily58/rev1", - "keymap": "minhtrannhat", - "layout": "LAYOUT", - "layers": [ - [ - "KC_GESC", - "KC_1", - "KC_2", - "KC_3", - "KC_4", - "KC_5", - "KC_6", - "KC_7", - "KC_8", - "KC_9", - "KC_0", - "KC_BSPC", - "KC_TAB", - "KC_Q", - "KC_W", - "KC_E", - "KC_R", - "KC_T", - "KC_Y", - "KC_U", - "KC_I", - "KC_O", - "KC_P", - "KC_QUOT", - "KC_LSFT", - "KC_A", - "KC_S", - "KC_D", - "KC_F", - "KC_G", - "KC_H", - "KC_J", - "KC_K", - "KC_L", - "KC_SCLN", - "KC_ENT", - "KC_LCTL", - "KC_Z", - "KC_X", - "KC_C", - "KC_V", - "KC_B", - "KC_LBRC", - "KC_RBRC", - "KC_N", - "KC_M", - "KC_COMM", - "KC_DOT", - "KC_SLSH", - "KC_BSLS", - "KC_LGUI", - "KC_LAPO", - "MO(1)", - "KC_SPC", - "KC_SPC", - "MO(2)", - "KC_RAPC", - "KC_RCTL" - ], - [ - "KC_TRNS", - "KC_TRNS", - "KC_TRNS", - "KC_TRNS", - "KC_TRNS", - "KC_TRNS", - "KC_TRNS", - "KC_TRNS", - "KC_TRNS", - "KC_TRNS", - "KC_TRNS", - "KC_TRNS", - "KC_TRNS", - "KC_GRV", - "KC_NO", - "KC_NO", - "KC_NO", - "KC_NO", - "KC_NO", - "KC_NO", - "KC_NO", - "KC_NO", - "KC_NO", - "KC_NO", - "KC_TRNS", - "KC_BRID", - "KC_BRIU", - "KC_MPRV", - "KC_MNXT", - "KC_NO", - "KC_LEFT", - "KC_DOWN", - "KC_UP", - "KC_RGHT", - "KC_NO", - "KC_NO", - "KC_TRNS", - "KC_VOLD", - "KC_VOLU", - "KC_MUTE", - "KC_MSTP", - "KC_LPRN", - "KC_NO", - "KC_NO", - "KC_RPRN", - "KC_EQL", - "KC_MINS", - "KC_NO", - "KC_DEL", - "KC_BSLS", - "KC_TRNS", - "KC_TRNS", - "KC_TRNS", - "KC_TRNS", - "KC_TRNS", - "KC_NO", - "KC_TRNS", - "KC_TRNS" - ], - [ - "KC_TRNS", - "KC_F1", - "KC_F2", - "KC_F3", - "KC_F4", - "KC_F5", - "KC_F6", - "KC_F7", - "KC_F8", - "KC_F9", - "KC_F10", - "KC_TRNS", - "KC_TRNS", - "KC_NO", - "KC_NO", - "KC_NO", - "KC_NO", - "KC_NO", - "KC_NO", - "KC_NO", - "KC_NO", - "KC_NO", - "KC_F11", - "KC_F12", - "KC_TRNS", - "KC_NO", - "KC_NO", - "KC_NO", - "KC_NO", - "KC_NO", - "KC_LEFT", - "KC_DOWN", - "KC_UP", - "KC_RGHT", - "KC_NO", - "KC_TRNS", - "KC_TRNS", - "KC_NO", - "KC_NO", - "KC_NO", - "KC_NO", - "KC_NO", - "KC_NO", - "KC_NO", - "KC_NO", - "KC_NO", - "KC_NO", - "KC_NO", - "KC_NO", - "KC_NO", - "KC_TRNS", - "KC_TRNS", - "KC_TRNS", - "KC_TRNS", - "KC_TRNS", - "KC_TRNS", - "KC_TRNS", - "KC_TRNS" - ] - ], - "author": "" -} \ No newline at end of file diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..c6d47da --- /dev/null +++ b/readme.md @@ -0,0 +1,133 @@ +# HELL0 NAVI. Interface + +HELL0 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. + + +Ready to dive into the Wired ? + + +HELL0 NAVI provides interactive animations for both sides : +- a scope on left side for burst, WPM and active layer +- a ring on right side for the last key stroke + + + + + + + +## Typing animation + +The scope displays your burst time on a chart. The WPM is represented by an horizontal line. + +The 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. + + + +## Startup animation + +Your Navi boots when it leaves the sleep mode. The animation can be canceled by typing. + + + + + + + +## Waking up animation + +After 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. + + + + + +## Idle animation + +The Copland OS is still in beta test. After a while, some visual glitches will occur. + + + + + + +## Shutdown animation +The 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. + +# How to build & flash + +You need to flash each side with a specific version based on config.h configuration. + + ## Left side (master) + +IS_RIGHT needs to be commented in config.h +``` +#define IS_LEFT 1 +//#define IS_RIGHT 1 +``` +Connect the left side and flash + + ## Right side (slave) + +Comment IS_LEFT and uncomment IS_RIGHT in config.h +``` +//#define IS_LEFT 1 +#define IS_RIGHT 1 +``` +Connect the right side and flash + +# Customization + +## Logo +Logo can be change in navi_logo.c. +The new logo must be 32x32 pixels. +``` +static void render_logo_clean(void) { + // your logo here + static const char PROGMEM logo_raw[] = { + 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, + }; + oled_write_raw_P(logo_raw, sizeof(logo_raw)); +} +``` +## Layer names + +The current version handle 3 differents layers. Names can be changed in layer_frame.h. +``` +// layer name : must be 3 chars +#define LAYER_NAME_0 "ABC" +#define LAYER_NAME_1 "NAV" +#define LAYER_NAME_2 "SPE" +``` + +## Timing + +You can tweak states timing in gui_state.h. +``` +// states timing +#define BOOTING_TIME_TRESHOLD 7000 +#define WAKING_UP_TIME_TRESHOLD 300 +#define IDLE_TIME_TRESHOLD 4000 +#define HALTING_TIME_TRESHOLD IDLE_TIME_TRESHOLD + 6000 +#define SLEEP_TIME_TRESHOLD HALTING_TIME_TRESHOLD + 8000 +``` + +## Need space ? +Boot and gliches can be commented in config.h +``` +// states timing +// logo glitch +//#define WITH_GLITCH +// boot sequence +//#define WITH_BOOT +``` + +![My Navi](https://imgur.com/eYkgoZJ.png) +> Keyboard : https://github.com/kata0510/Lily58 +> +> Case : https://github.com/BoardSodie/Lily58-Acrylic-Case + diff --git a/ring.c b/ring.c new file mode 100644 index 0000000..e3b7472 --- /dev/null +++ b/ring.c @@ -0,0 +1,494 @@ +// Copyright 2021 Nicolas Druoton (druotoni) +// SPDX-License-Identifier: GPL-2.0-or-later + +#include QMK_KEYBOARD_H +#include "gui_state.h" +#include "ring.h" + +#include "fast_random.h" +#include "draw_helper.h" + +char tListeTotal[SIZE_ARRAY_1] = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P'}; +char tListeTotal2[SIZE_ARRAY_1] = {'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', ',', '.', '/', '1', '2', '3'}; + +static char tRefArc[SIZE_ARRAY_1] = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P'}; +static char tRefArc2[SIZE_ARRAY_1] = {'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', ',', '.', '/', '1', '2', '3'}; + +// ring target and previous char +char c_target = 'A'; +char c_target2 = 'Q'; +char c_last = ' '; +char c_previous = ' '; + +static 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', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ';', '\'', ' ', ',', '.', '/', ' ', ' ', ' '}; + +// main circle +#define CIRCLE_ANIM_FRAME_DURATION 40 +uint16_t circle_timer = 0; + +// special animation for special keys +#define ANIM_CENTER_FRAME_NUMBER 5 +#define ANIM_CENTER_FRAME_DURATION 40 +uint16_t anim_center_timer = 0; +uint8_t anim_center_current_frame = 0; + +// sleep animation +#define ANIM_SLEEP_RING_FRAME_NUMBER 9 +#define ANIM_SLEEP_RING_FRAME_DURATION 20 +uint16_t anim_sleep_ring_timer = 0; +uint8_t current_sleep_ring_frame = 0; +uint8_t sleep_ring_frame_destination = ANIM_SLEEP_RING_FRAME_NUMBER - 1; + +// glitch animation +uint16_t anim_ring_idle_timer = 0; +int current_glitch_ring_time = 150; +uint32_t glitch_ring_timer = 0; +uint8_t current_glitch_ring_index = 0; + +// central frame keylog animation +#define ANIM_KEYLOG_FRAME_NUMBER 8 +#define ANIM_KEYLOG_FRAME_DURATION 20 +uint8_t anim_keylog_current_frame = 0; +uint16_t anim_keylog_timer = 0; + +static const char PROGMEM raw_ring_sleep[4][64] = {{ + 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, + }, + + { + 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, + }, + + { + 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, + }, + + { + 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, + }}; + +static const char PROGMEM raw_circle[4][128] = {{ + 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, + }, + { + 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, + }, + { + 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, + }, + { + 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, + }}; + +static const char PROGMEM raw_bottom[] = { + 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, +}; + +static const char PROGMEM raw_middle[] = { + 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, +}; + +static void rotate_right(char str[]) { + uint8_t iSize = SIZE_ARRAY_1; + char cFist = str[0]; + + // rotate array to the right + for (uint8_t i = 0; i < iSize - 1; i++) { + str[i] = str[i + 1]; + } + str[iSize - 1] = cFist; +} + +static void rotate_left(char str[]) { + uint8_t iSize = SIZE_ARRAY_1; + char cLast = str[iSize - 1]; + + // rotate array to the left + for (uint8_t i = iSize - 1; i > 0; i--) { + str[i] = str[i - 1]; + } + str[0] = cLast; +} + +static signed char GetPosition(char c, char tListe[]) { + uint8_t iSize = SIZE_ARRAY_1; + + // find position of c in the array + for (uint8_t i = 0; i < iSize; i++) { + if (tListe[i] == c) return i; + } + + // not found + return -1; +} + +static signed char GetDistance(char cNew, char tListe[]) { + signed char iPositionNew = GetPosition(cNew, tListe); + if (iPositionNew == -1) { + // not found + return 0; + } + + return iPositionNew - CURSOR_1; +} + +static bool TesterEstDansListe(char c, char tListe[]) { + // char in the list ? + return GetPosition(c, tListe) != -1; +} + +static void SmartRotation(char c, char tListe[]) { + signed char i = GetDistance(c, tListe); + if (i == 0) return; + + // rotate in the shorter way + if (i < 0) { + rotate_left(tListe); + return; + } + + if (i > 0) { + rotate_right(tListe); + return; + } +} + +static void update_list(char cNouveau, char tListe[]) { + signed char iDistance = GetDistance(cNouveau, tListe); + if (iDistance != 0) { + // the new char is in the list : rotation + SmartRotation(cNouveau, tListe); + } +} + +static void draw_arc_sector_16(uint8_t x, uint8_t y, uint8_t radius, int position, bool color) { + unsigned int s = 1; + s = s << (position / 2); + + if (position % 4 == 0 || position % 4 == 3) { + draw_arc_sector(x, y, radius, s, 1, color); + } else { + draw_arc_sector(x, y, radius, s, 2, color); + } +} + +static void render_set(uint8_t x, uint8_t y, uint8_t r, int p, bool color) { + // 2 pixels arc sector + draw_arc_sector_16(x, y, r, p, color); + draw_arc_sector_16(x, y, r - 1, p, color); +} + +static void draw_letter_circle(char t[], char tRef[], char ct, uint8_t x, uint8_t y, uint8_t r, bool invert) { + char c = t[CURSOR_1]; + + signed char p = GetPosition(c, tRef); + signed char pt = GetPosition(ct, tRef); + + if (!invert) { + draw_fill_circle(x, y, r, false); + draw_circle(x, y, r, false); + draw_circle(x, y, r - 1, false); + draw_circle(x, y, r - 2, false); + draw_circle(x, y, r - 4, true); + draw_circle(x, y, r - 5, true); + } + + int pafter = (pt + 1) % SIZE_ARRAY_1; + int pbefore = (pt + SIZE_ARRAY_1 - 1) % SIZE_ARRAY_1; + render_set(x, y, r, pt, true); + render_set(x, y, r, pafter, true); + render_set(x, y, r, pbefore, true); + + pafter = (pt + 2) % SIZE_ARRAY_1; + pbefore = (pt + SIZE_ARRAY_1 - 2) % SIZE_ARRAY_1; + render_set(x, y, r, pafter, true); + render_set(x, y, r, pbefore, true); + + r -= 4; + + pafter = (p + 1) % SIZE_ARRAY_1; + pbefore = (p + SIZE_ARRAY_1 - 1) % SIZE_ARRAY_1; + + render_set(x, y, r, p, false); + render_set(x, y, r, pafter, false); + render_set(x, y, r, pbefore, false); + + draw_circle(x, y, r - 6, true); +} + +static void draw_center_circle_frame(uint8_t x, uint8_t y, uint8_t r, uint8_t f) { + draw_fill_circle(x, y, r, 0); + draw_circle(x, y, r, 0); + + if (f == 0) { + draw_circle(x, y, r, 1); + } else { + // animation + oled_write_raw_P_cursor(0, 11, raw_circle[f - 1], sizeof(raw_circle[f - 1])); + } +} + +static void render_anim_center_circle(uint8_t x, uint8_t y, uint8_t r) { + if (anim_center_current_frame == ANIM_CENTER_FRAME_NUMBER) { + // last frame : no animation + return; + } + + if (timer_elapsed(anim_center_timer) > ANIM_CENTER_FRAME_DURATION) { + anim_center_timer = timer_read(); + + draw_center_circle_frame(x, y, r, anim_center_current_frame); + + anim_center_current_frame++; + } +} + +static void write_char(char c) { + // write keylog char in the frame then offset to center + oled_set_cursor(2, 6); + oled_write_char(c, false); + move_block(12, 48, 6, 8, 2); +} + +static void render_keylog(gui_state_t t) { + if (anim_keylog_current_frame != ANIM_KEYLOG_FRAME_NUMBER) { + if (timer_elapsed(anim_keylog_timer) > ANIM_KEYLOG_FRAME_DURATION) { + // update frame number + anim_keylog_timer = timer_read(); + anim_keylog_current_frame++; + } + + // clean frame + draw_rectangle_fill(7, 46, 21, 11, false); + + // comb motion to merge current and previous + if (anim_keylog_current_frame < ANIM_KEYLOG_FRAME_NUMBER / 2) { + // expand the previous char + write_char(c_previous); + draw_glitch_comb(9, 6 * 8, 18, 8, anim_keylog_current_frame + 1, true); + } else { + // shrink the current char + write_char(c_last); + draw_glitch_comb(9, 6 * 8, 18, 8, ANIM_KEYLOG_FRAME_NUMBER - anim_keylog_current_frame, false); + } + + return; + } + + write_char(c_last); +} + +void reset_ring(void) { + // need to open + anim_sleep_ring_timer = timer_read(); + current_sleep_ring_frame = ANIM_SLEEP_RING_FRAME_NUMBER - 1; + sleep_ring_frame_destination = 0; +} + +static void render_tv_circle(uint8_t x, uint8_t y, uint8_t r, uint8_t f) { + // raw image + if (f == 2 || f == 3) { + oled_write_raw_P_cursor(0, 12, raw_ring_sleep[f - 2], sizeof(raw_ring_sleep[f - 2])); + return; + } + + // raw image + if (f == 5 || f == 6) { + oled_write_raw_P_cursor(0, 12, raw_ring_sleep[f - 3], sizeof(raw_ring_sleep[f - 3])); + return; + } + + // other frames : lighter to draw than using raw image + switch (f) { + case 1: + draw_circle(x, y, r, 1); + break; + + case 4: + drawline_hr(1, y, 12, 1); + drawline_hr(19, y, 12, 1); + drawline_vb(0, y - 1, 3, true); + drawline_vb(31, y - 1, 3, true); + break; + + case 7: + + oled_write_pixel(1, y, true); + oled_write_pixel(3, y, true); + oled_write_pixel(28, y, true); + oled_write_pixel(30, y, true); + + drawline_vb(0, y - 12, 26, true); + drawline_vb(31, y - 12, 26, true); + break; + + case 8: + drawline_vb(0, 88, 32, true); + drawline_vb(31, 88, 32, true); + break; + } +} + +static void render_circle_white(void) { + // top + oled_write_raw_P_cursor(0, 5, raw_middle, sizeof(raw_middle)); + drawline_hr(5, 39, 25, 1); + + // clean center + draw_rectangle_fill(0, 80, 32, 40, false); + + // bottom + drawline_vb(0, 80, 8, 1); + drawline_vb(31, 80, 8, 1); + oled_write_pixel(1, 80, true); + oled_write_pixel(30, 80, true); + + oled_write_raw_P_cursor(0, 15, raw_bottom, sizeof(raw_bottom)); +} + +static void render_ring_clean_close(void) { + render_circle_white(); + drawline_vb(0, 88, 32, true); + drawline_vb(31, 88, 32, true); +} + +static void render_glitch_square(void) { + if (timer_elapsed(anim_ring_idle_timer) > 60) { + anim_ring_idle_timer = timer_read(); + + render_ring_clean_close(); + + uint8_t size = 0; + for (uint8_t i = 0; i < 4; i++) { + size = 4 + (fastrand() % 6); + draw_rectangle_fill(3 + (fastrand() % 19), 85 + (fastrand() % 20), size, size, true); + + size = (fastrand() % 6); + draw_rectangle_fill(3 + (fastrand() % 19), 100 + (fastrand() % 20), size, size, true); + } + } +} + +static void render_ring_idle(void) { + uint8_t glitch_prob = get_glitch_probability(); + get_glitch_index(&glitch_ring_timer, ¤t_glitch_ring_time, ¤t_glitch_ring_index, 150, 350, glitch_prob, 2); + + switch (current_glitch_ring_index) { + case 0: + // no glitch + render_ring_clean_close(); + return; + case 1: + // square gliches + render_glitch_square(); + return; + } +} + +static void render_ring_sleep(void) { + if (current_sleep_ring_frame == sleep_ring_frame_destination) { + // no more animation needes : render the idle animation + render_ring_idle(); + return; + } + + // display wacking up / sleep animation + if (timer_elapsed(anim_sleep_ring_timer) > ANIM_SLEEP_RING_FRAME_DURATION) { + anim_sleep_ring_timer = timer_read(); + + // clean + new frame + render_circle_white(); + render_tv_circle(15, 103, 11, current_sleep_ring_frame); + + // update frame number + if (sleep_ring_frame_destination > current_sleep_ring_frame) { + current_sleep_ring_frame++; + } else { + current_sleep_ring_frame--; + } + } +} + +static void render_circle_middle(void) { + // clean + render_circle_white(); + + // center special animation + if (anim_center_current_frame < ANIM_CENTER_FRAME_NUMBER) { + render_anim_center_circle(15, 103, 15 - 4); + return; + } + + // ring render + if (anim_center_current_frame == ANIM_CENTER_FRAME_NUMBER) { + draw_letter_circle(tListeTotal, tRefArc, c_target, 15, 103, 15, false); + draw_letter_circle(tListeTotal2, tRefArc2, c_target2, 15, 103, 15, true); + } +} + +void render_circle(gui_state_t t) { + if (timer_elapsed(circle_timer) > CIRCLE_ANIM_FRAME_DURATION) { + // new frame + circle_timer = timer_read(); + + // shift rings + update_list(c_target, tListeTotal); + update_list(c_target2, tListeTotal2); + + // waking up animation + if (t == _WAKINGUP) { + render_ring_sleep(); + return; + } + + // idle animation + if (t == _IDLE) { + sleep_ring_frame_destination = ANIM_SLEEP_RING_FRAME_NUMBER - 1; + render_ring_sleep(); + return; + } + + // render on display + render_circle_middle(); + render_keylog(t); + } +} + +void update_circle(uint16_t keycode) { + // special animation for special keys + if (keycode == KC_ESC || keycode == KC_SPACE || keycode == KC_ENTER) { + anim_center_timer = timer_read(); + anim_center_current_frame = 0; + return; + } + + // cancel special animation on a new key + anim_center_current_frame = ANIM_CENTER_FRAME_NUMBER; + + // out of scope key + if (keycode >= 60) { + return; + } + + // keycode to char + char c = pgm_read_byte(&code_to_name[keycode]); + + // stock previous char + c_previous = c_last; + c_last = c; + + // start keylog animation + anim_keylog_current_frame = 0; + + // update target in ring #1 position + if (TesterEstDansListe(c, tListeTotal)) { + c_target = c; + return; + } + + // update target in #2 position + if (TesterEstDansListe(c, tListeTotal2)) { + c_target2 = c; + return; + } +} diff --git a/ring.h b/ring.h new file mode 100644 index 0000000..9ce4520 --- /dev/null +++ b/ring.h @@ -0,0 +1,11 @@ +// Copyright 2021 Nicolas Druoton (druotoni) +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#define SIZE_ARRAY_1 16 +#define CURSOR_1 9 + +void update_circle(uint16_t); +void render_circle(gui_state_t t); +void reset_ring(void); diff --git a/rules.mk b/rules.mk index ffef64c..a3d6bcb 100644 --- a/rules.mk +++ b/rules.mk @@ -2,29 +2,26 @@ # change to "no" to disable the options, or define them in the Makefile in # the appropriate keymap folder that will get included automatically # -BOOTMAGIC_ENABLE = no # Virtual DIP switch configuration -MOUSEKEY_ENABLE = no # Mouse keys -CONSOLE_ENABLE = no # Console for debug -COMMAND_ENABLE = no # Commands for debug and configuration -NKRO_ENABLE = no # Nkey Rollover - if this doesn't work, see here: https://github.com/tmk/tmk_keyboard/wiki/FAQ#nkro-doesnt-work -BACKLIGHT_ENABLE = no # Enable keyboard backlight functionality -MIDI_ENABLE = no # MIDI controls -AUDIO_ENABLE = no # Audio output on port C6 -UNICODE_ENABLE = no # Unicode -BLUETOOTH_ENABLE = no # Enable Bluetooth with the Adafruit EZ-Key HID RGBLIGHT_ENABLE = no # Enable WS2812 RGB underlight. -SWAP_HANDS_ENABLE = no # Enable one-hand typing -SLEEP_LED_ENABLE = no # Breathing sleep LED during USB suspend -WPM_ENABLE = yes -SPLIT_KEYBOARD = yes -OLED_ENABLE= yes # OLED display -EXTRAKEY_ENABLE = yes - -EXTRAFLAGS += -flto +# Bootloader selection BOOTLOADER = atmel-dfu -CONFIG_USB_ACM = yes -DEBOUNCE_TYPE = sym_eager_pk + +# Do not enable SLEEP_LED_ENABLE. it uses the same timer as BACKLIGHT_ENABLE +SLEEP_LED_ENABLE = no # Breathing sleep LED during USB suspend +LTO_ENABLE = yes +SPACE_CADET_ENABLE = no +GRAVE_ESC_ENABLE = no +MAGIC_ENABLE = no # If you want to change the display of OLED, you need to change here -SRC += ./lib/layer_state_reader.c +SRC += ./lib/rgb_state_reader.c \ + ./burst.c \ + ./navi_logo.c \ + ./gui_state.c \ + ./fast_random.c \ + ./layer_frame.c \ + ./ring.c \ + ./boot.c \ + ./draw_helper.c \ +