summaryrefslogtreecommitdiff
path: root/keyboards/whale/sk/v3/v3.c
blob: 4cfb87e401fcbccdccfd845cae5ed138d0e396a8 (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
#include "quantum.h"

#if defined(__AVR__)
#    include <avr/io.h>
#    include <avr/interrupt.h>
#endif

#define ROWS_PER_HAND (MATRIX_ROWS / 2)
#define SLAVE_MATRIX_SYNC_ADDR (0x01)

typedef struct {
    char*  buffer;
    size_t count;
    bool*  flag;
} transmit_status;

transmit_status irx = {}, itx = {};

// Buffer for master/slave matrix scan transmit.
// Master: receive buffer.
// Slave: transmit buffer.
matrix_row_t sync_matrix[ROWS_PER_HAND];
bool         matrix_synced = false;

void USART_init(uint16_t baud) {
    cli();

    // UBRR1H = (unsigned char)(baud >>8);
    // UBRR1L = (unsigned char)(baud);
    UBRR1 = baud;
    // Enable U2X1 for double speed.
    UCSR1A = (1 << U2X1);
    // Enable RX/TX, 9N1 mode
    UCSR1B = (1 << RXEN1) | (1 << TXEN1) | (1 << RXCIE1) | (1 << TXCIE1) | (1 << UCSZ12);
    UCSR1C = (1 << UCSZ10) | (1 << UCSZ11);
    sei();
}

ISR(USART1_RX_vect) {
    // read data from reg.
    uint8_t status   = UCSR1A;
    uint8_t high_bit = UCSR1B;
    uint8_t low_data = UDR1;
    if (status & ((1 << FE1) | (1 << DOR1) | (1 << UPE1))) {
        // Something error happen, ignore this package.
        irx.count = 0;
        return;
    }

    // Is it a addr? (9th bit is one/zero?)
    if (high_bit & (1 << RXB81)) {
        // data is addr. prepend for receive.
        switch (low_data) {
            case SLAVE_MATRIX_SYNC_ADDR:
                irx.buffer = (char *)sync_matrix;
                irx.count = sizeof(sync_matrix) * sizeof(matrix_row_t);
                irx.flag = &matrix_synced;
                break;

            default:
                // ignore this package.
                irx.count = 0;
                break;
        }

    } else if (irx.count > 0) {
        *irx.buffer = low_data;
        ++irx.buffer;
        if (--irx.count == 0 && irx.flag != NULL) {
            *irx.flag = true;
        }
    }
}

// TX complete
ISR(USART1_TX_vect) {
    // Is in transmit?
    if (itx.count > 0) {
        // Send data.
        UCSR1B &= ~(1 << TXB81);
        UDR1 = *itx.buffer;

        // Move to next char.
        ++itx.buffer;
        if (--itx.count == 0) {
            *itx.flag = true;
        }
    }
    // TODO: read queue/register for next message.
}

// return: queue depth.
int send_packet(uint8_t addr, char* buffer, size_t length, bool* flag) {
    // See if we can start transmit right now.
    if ((itx.count == 0) && (UCSR1A & (1 << UDRE1))) {
        // Ready to write.
        // Prepend registers.
        itx.buffer = buffer;
        itx.count  = length;
        itx.flag   = flag;

        // Write addr to kick start transmit.
        UCSR1B |= (1 << TXB81);
        UDR1 = addr;
        // TODO: put request in queue;
        // }else{
    }

    return 0;
}

void transport_master_init(void) { USART_init(0); }

void transport_slave_init(void) { USART_init(0); }

// returns false if valid data not received from slave
bool transport_master(matrix_row_t matrix[]) {
    if (matrix_synced) {
        for (uint8_t i = 0; i < ROWS_PER_HAND; ++i) {
            matrix[i] = sync_matrix[i];
        }
        matrix_synced = false;
        return true;
    }
    return false;
}

void transport_slave(matrix_row_t matrix[]) {
    for (uint8_t i = 0; i < ROWS_PER_HAND; ++i) {
        sync_matrix[i] = matrix[i];
    }
    matrix_synced = false;
    send_packet(SLAVE_MATRIX_SYNC_ADDR, (char*)sync_matrix, sizeof(sync_matrix) * sizeof(matrix_row_t), &matrix_synced);
}