]> git.donarmstrong.com Git - qmk_firmware.git/blob - quantum/split_common/transport.c
b32d48eb88c7946a5289ddbca66a5228f74adfbb
[qmk_firmware.git] / quantum / split_common / transport.c
1 #include <string.h>
2 #include <stddef.h>
3
4 #include "config.h"
5 #include "matrix.h"
6 #include "quantum.h"
7
8 #define ROWS_PER_HAND (MATRIX_ROWS / 2)
9
10 #ifdef RGBLIGHT_ENABLE
11 #  include "rgblight.h"
12 #endif
13
14 #ifdef BACKLIGHT_ENABLE
15 #  include "backlight.h"
16 #endif
17
18 #ifdef ENCODER_ENABLE
19 #  include "encoder.h"
20 #endif
21
22 #if defined(USE_I2C) || defined(EH)
23
24 #  include "i2c_master.h"
25 #  include "i2c_slave.h"
26
27 typedef struct _I2C_slave_buffer_t {
28     matrix_row_t smatrix[ROWS_PER_HAND];
29     uint8_t      backlight_level;
30 #if defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT)
31     rgblight_syncinfo_t rgblight_sync;
32 #endif
33 #ifdef ENCODER_ENABLE
34     uint8_t encoder_state[NUMBER_OF_ENCODERS];
35 #endif
36 } I2C_slave_buffer_t;
37
38 static I2C_slave_buffer_t * const i2c_buffer = (I2C_slave_buffer_t *)i2c_slave_reg;
39
40 #  define I2C_BACKLIGHT_START offsetof(I2C_slave_buffer_t, backlight_level)
41 #  define I2C_RGB_START offsetof(I2C_slave_buffer_t, rgblight_sync)
42 #  define I2C_KEYMAP_START offsetof(I2C_slave_buffer_t, smatrix)
43 #  define I2C_ENCODER_START offsetof(I2C_slave_buffer_t, encoder_state)
44
45 #  define TIMEOUT 100
46
47 #  ifndef SLAVE_I2C_ADDRESS
48 #    define SLAVE_I2C_ADDRESS 0x32
49 #  endif
50
51 // Get rows from other half over i2c
52 bool transport_master(matrix_row_t matrix[]) {
53   i2c_readReg(SLAVE_I2C_ADDRESS, I2C_KEYMAP_START, (void *)matrix, sizeof(i2c_buffer->smatrix), TIMEOUT);
54
55   // write backlight info
56 #  ifdef BACKLIGHT_ENABLE
57   uint8_t level = is_backlight_enabled() ? get_backlight_level() : 0;
58   if (level != i2c_buffer->backlight_level) {
59     if (i2c_writeReg(SLAVE_I2C_ADDRESS, I2C_BACKLIGHT_START, (void *)&level, sizeof(level), TIMEOUT) >= 0) {
60       i2c_buffer->backlight_level = level;
61     }
62   }
63 #  endif
64
65 #  if defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT)
66   if (rgblight_get_change_flags()) {
67     rgblight_syncinfo_t rgblight_sync;
68     rgblight_get_syncinfo(&rgblight_sync);
69     if (i2c_writeReg(SLAVE_I2C_ADDRESS, I2C_RGB_START,
70                      (void *)&rgblight_sync, sizeof(rgblight_sync), TIMEOUT) >= 0) {
71       rgblight_clear_change_flags();
72     }
73   }
74 #  endif
75
76 #  ifdef ENCODER_ENABLE
77   i2c_readReg(SLAVE_I2C_ADDRESS, I2C_ENCODER_START, (void *)i2c_buffer->encoder_state, sizeof(i2c_buffer->encoder_state), TIMEOUT);
78   encoder_update_raw(i2c_buffer->encoder_state);
79 #  endif
80
81   return true;
82 }
83
84 void transport_slave(matrix_row_t matrix[]) {
85   // Copy matrix to I2C buffer
86   memcpy((void*)i2c_buffer->smatrix, (void *)matrix, sizeof(i2c_buffer->smatrix));
87
88 // Read Backlight Info
89 #  ifdef BACKLIGHT_ENABLE
90   backlight_set(i2c_buffer->backlight_level);
91 #  endif
92
93 #  if defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT)
94   // Update the RGB with the new data
95   if (i2c_buffer->rgblight_sync.status.change_flags != 0) {
96       rgblight_update_sync(&i2c_buffer->rgblight_sync, false);
97       i2c_buffer->rgblight_sync.status.change_flags = 0;
98   }
99 #  endif
100
101 #  ifdef ENCODER_ENABLE
102   encoder_state_raw(i2c_buffer->encoder_state);
103 #  endif
104 }
105
106 void transport_master_init(void) { i2c_init(); }
107
108 void transport_slave_init(void) { i2c_slave_init(SLAVE_I2C_ADDRESS); }
109
110 #else  // USE_SERIAL
111
112 #  include "serial.h"
113
114 typedef struct _Serial_s2m_buffer_t {
115   // TODO: if MATRIX_COLS > 8 change to uint8_t packed_matrix[] for pack/unpack
116   matrix_row_t smatrix[ROWS_PER_HAND];
117
118 #  ifdef ENCODER_ENABLE
119   uint8_t encoder_state[NUMBER_OF_ENCODERS];
120 #  endif
121
122 } Serial_s2m_buffer_t;
123
124 typedef struct _Serial_m2s_buffer_t {
125 #  ifdef BACKLIGHT_ENABLE
126   uint8_t           backlight_level;
127 #  endif
128 } Serial_m2s_buffer_t;
129
130 #if defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT)
131 // When MCUs on both sides drive their respective RGB LED chains,
132 // it is necessary to synchronize, so it is necessary to communicate RGB
133 // information. In that case, define RGBLIGHT_SPLIT with info on the number
134 // of LEDs on each half.
135 //
136 // Otherwise, if the master side MCU drives both sides RGB LED chains,
137 // there is no need to communicate.
138
139 typedef struct _Serial_rgblight_t {
140     rgblight_syncinfo_t rgblight_sync;
141 } Serial_rgblight_t;
142
143 volatile Serial_rgblight_t serial_rgblight = {};
144 uint8_t volatile status_rgblight           = 0;
145 #endif
146
147 volatile Serial_s2m_buffer_t serial_s2m_buffer = {};
148 volatile Serial_m2s_buffer_t serial_m2s_buffer = {};
149 uint8_t volatile status0                       = 0;
150
151 enum serial_transaction_id {
152     GET_SLAVE_MATRIX = 0,
153 #if defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT)
154     PUT_RGBLIGHT,
155 #endif
156 };
157
158 SSTD_t transactions[] = {
159     [GET_SLAVE_MATRIX] = {
160         (uint8_t *)&status0,
161         sizeof(serial_m2s_buffer),
162         (uint8_t *)&serial_m2s_buffer,
163         sizeof(serial_s2m_buffer),
164         (uint8_t *)&serial_s2m_buffer,
165     },
166 #if defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT)
167     [PUT_RGBLIGHT] = {
168         (uint8_t *)&status_rgblight,
169         sizeof(serial_rgblight),
170         (uint8_t *)&serial_rgblight,
171         0, NULL // no slave to master transfer
172     },
173 #endif
174 };
175
176 void transport_master_init(void) { soft_serial_initiator_init(transactions, TID_LIMIT(transactions)); }
177
178 void transport_slave_init(void) { soft_serial_target_init(transactions, TID_LIMIT(transactions)); }
179
180 #if defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT)
181
182 // rgblight synchronization information communication.
183
184 void transport_rgblight_master(void) {
185   if (rgblight_get_change_flags()) {
186     rgblight_get_syncinfo((rgblight_syncinfo_t *)&serial_rgblight.rgblight_sync);
187     if (soft_serial_transaction(PUT_RGBLIGHT) == TRANSACTION_END) {
188         rgblight_clear_change_flags();
189     }
190   }
191 }
192
193 void transport_rgblight_slave(void) {
194   if (status_rgblight == TRANSACTION_ACCEPTED) {
195     rgblight_update_sync((rgblight_syncinfo_t *)&serial_rgblight.rgblight_sync,
196                          false);
197     status_rgblight = TRANSACTION_END;
198   }
199 }
200
201 #else
202 #define transport_rgblight_master()
203 #define transport_rgblight_slave()
204 #endif
205
206 bool transport_master(matrix_row_t matrix[]) {
207 #ifndef SERIAL_USE_MULTI_TRANSACTION
208   if (soft_serial_transaction() != TRANSACTION_END) {
209     return false;
210   }
211 #else
212   transport_rgblight_master();
213   if (soft_serial_transaction(GET_SLAVE_MATRIX) != TRANSACTION_END) {
214     return false;
215   }
216 #endif
217
218   // TODO:  if MATRIX_COLS > 8 change to unpack()
219   for (int i = 0; i < ROWS_PER_HAND; ++i) {
220     matrix[i] = serial_s2m_buffer.smatrix[i];
221   }
222
223 #  ifdef BACKLIGHT_ENABLE
224   // Write backlight level for slave to read
225   serial_m2s_buffer.backlight_level = is_backlight_enabled() ? get_backlight_level() : 0;
226 #  endif
227
228 #  ifdef ENCODER_ENABLE
229   encoder_update_raw((uint8_t *)serial_s2m_buffer.encoder_state);
230 #  endif
231
232   return true;
233 }
234
235 void transport_slave(matrix_row_t matrix[]) {
236   transport_rgblight_slave();
237   // TODO: if MATRIX_COLS > 8 change to pack()
238   for (int i = 0; i < ROWS_PER_HAND; ++i) {
239     serial_s2m_buffer.smatrix[i] = matrix[i];
240   }
241 #  ifdef BACKLIGHT_ENABLE
242   backlight_set(serial_m2s_buffer.backlight_level);
243 #  endif
244
245 #  ifdef ENCODER_ENABLE
246   encoder_state_raw((uint8_t *)serial_s2m_buffer.encoder_state);
247 #  endif
248
249 }
250
251 #endif