summaryrefslogtreecommitdiff
path: root/keyboards/ibm/model_m/mschwingen/mschwingen.c
blob: 8e3810cd234fce8f10ea97142d36284b8ff56870 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
/*
 * Copyright 2020 Michael Schwingen

 * 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 <http://www.gnu.org/licenses/>.
 */
#include <util/delay.h>
#include "mschwingen.h"
#include "uart.h"
#include "print.h"
#include "sendchar.h"
#include "ws2812.h"
#include "sleep_led.h"

#ifdef UART_DEBUG
#    undef sendchar
static int8_t capture_sendchar(uint8_t c) {
    //  sendchar(c);
    uart_write(c);
    return 0;
}
#endif

static uint16_t blink_cycle_timer;
static bool     blink_state = false;
static uint8_t  isRecording = 0;

#ifdef KEYBOARD_ibm_model_m_mschwingen_led_ws2812
#    if RGBLED_NUM < 3
#        error we need at least 3 RGB LEDs!
#    endif
static rgb_led_t led[RGBLED_NUM] = {{255, 255, 255}, {255, 255, 255}, {255, 255, 255}};

#    define BRIGHT 32
#    define DIM 6

static const rgb_led_t black = {.r = 0, .g = 0, .b = 0};

static const __attribute__((unused)) rgb_led_t green  = {.r = 0, .g = BRIGHT, .b = 0};
static const __attribute__((unused)) rgb_led_t lgreen = {.r = 0, .g = DIM, .b = 0};

static const __attribute__((unused)) rgb_led_t red  = {.r = BRIGHT, .g = 0, .b = 0};
static const __attribute__((unused)) rgb_led_t lred = {.r = DIM, .g = 0, .b = 0};

static const __attribute__((unused)) rgb_led_t blue  = {.r = 0, .g = 0, .b = BRIGHT};
static const __attribute__((unused)) rgb_led_t lblue = {.r = 0, .g = 0, .b = DIM};

static const __attribute__((unused)) rgb_led_t turq  = {.r = 0, .g = BRIGHT, .b = BRIGHT};
static const __attribute__((unused)) rgb_led_t lturq = {.r = 0, .g = DIM, .b = DIM};

static const __attribute__((unused)) rgb_led_t white = {.r = BRIGHT, .g = BRIGHT, .b = BRIGHT};

static led_t   led_state;
static uint8_t layer;
static uint8_t default_layer;
#endif

// we need our own sleep_led_* implementation to get callbacks on USB
// suspend/resume in order to completely turn off WS2812 LEDs
static bool suspend_active = false;
void sleep_led_init(void) {}

void sleep_led_toggle(void) {}

void sleep_led_disable(void) {
    suspend_active = false;
    writePinHigh(MODELM_STATUS_LED);
}

void sleep_led_enable(void) {
    suspend_active = true;
    writePinLow(MODELM_STATUS_LED);
#ifdef KEYBOARD_ibm_model_m_mschwingen_led_ws2812
    led[0] = black;
    led[1] = black;
    led[2] = black;
    ws2812_setleds(led, RGBLED_NUM);
#endif
}

void keyboard_pre_init_kb(void) {
#ifdef KEYBOARD_ibm_model_m_mschwingen_led_ws2812
    ws2812_setleds(led, RGBLED_NUM);
#else
    /* Set status LEDs pins to output and Low (on) */
    setPinOutput(MODELM_LED_CAPSLOCK);
    setPinOutput(MODELM_LED_SCROLLOCK);
    setPinOutput(MODELM_LED_NUMLOCK);
    writePinLow(MODELM_LED_CAPSLOCK);
    writePinLow(MODELM_LED_SCROLLOCK);
    writePinLow(MODELM_LED_NUMLOCK);
#endif
    setPinOutput(MODELM_STATUS_LED);
    writePinHigh(MODELM_STATUS_LED);
    _delay_ms(50);
#ifdef UART_DEBUG
    uart_init(115200);
    print_set_sendchar(capture_sendchar);
    uprintf("\r\nHello world!\r\n");
#endif

    setPinOutput(SR_LOAD_PIN);
    setPinOutput(SR_CLK_PIN);
    setPinOutput(SR_DOUT_PIN);  // MOSI - unused
    writePinLow(SR_CLK_PIN);
}

#ifdef KEYBOARD_ibm_model_m_mschwingen_led_ws2812
static void led_update_rgb(void) {
    if (isRecording && blink_state) {
        led[0] = white;
    } else {
        switch (default_layer) {
            case 0:
                led[0] = led_state.num_lock ? blue : lblue;
                break;
            case 1:
                led[0] = led_state.num_lock ? green : black;
                break;
        }
    }

    led[1] = led_state.caps_lock ? green : black;

    switch (layer) {
        case 0:
        case 1:
        default:
            led[2] = led_state.scroll_lock ? green : black;
            break;
        case 2:
            led[2] = led_state.scroll_lock ? red : lred;
            break;
        case 3:
            led[2] = led_state.scroll_lock ? turq : lturq;
            break;
    }
    if (!suspend_active) {
	ws2812_setleds(led, RGBLED_NUM);
    }
}

bool led_update_kb(led_t state) {
    dprintf("LED Update: %d %d %d", led_state.num_lock, led_state.caps_lock, led_state.scroll_lock);
    led_state = state;
    led_update_rgb();

    return true;
}

void update_layer_leds(void) {
    static uint8_t old_layer         = 255;
    static uint8_t old_default_layer = 255;

    layer         = get_highest_layer(layer_state);
    default_layer = get_highest_layer(default_layer_state);

    if (isRecording && timer_elapsed(blink_cycle_timer) > 150) {
        blink_state       = !blink_state;
        blink_cycle_timer = timer_read();
        old_layer         = 255;  // fallthrough next check
    }

    if (layer == old_layer && default_layer == old_default_layer) {
	return;
    }
    old_layer         = layer;
    old_default_layer = default_layer;
    dprintf("Layer change: %d %d", default_layer, layer);
    led_update_rgb();
}

/*****************************************************************************/
#else  // classic LEDs on GPIO
bool led_update_kb(led_t led_state) {
    dprintf("LED Update: %d %d %d", led_state.num_lock, led_state.caps_lock, led_state.scroll_lock);

    if (led_update_user(led_state)) {
        if (!isRecording) writePin(MODELM_LED_NUMLOCK, !led_state.num_lock);
        writePin(MODELM_LED_CAPSLOCK, !led_state.caps_lock);
        writePin(MODELM_LED_SCROLLOCK, !led_state.scroll_lock);
    }
    return true;
}

void update_layer_leds(void) {
    if (isRecording && timer_elapsed(blink_cycle_timer) > 150) {
        blink_state = !blink_state;
        blink_cycle_timer = timer_read();
        writePin(MODELM_LED_NUMLOCK, blink_state);
    }
}

#endif

void dynamic_macro_record_start_user(int8_t direction) {
    isRecording++;
    blink_cycle_timer = timer_read();
}

void dynamic_macro_record_end_user(int8_t direction) {
    if (isRecording) isRecording--;
}