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