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