transport.c
4982 bytes
1/* Copyright 2021 QMK
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#include <string.h>
18#include <debug.h>
19
20#include "transactions.h"
21#include "transport.h"
22#include "transaction_id_define.h"
23#include "atomic_util.h"
24
25#ifdef USE_I2C
26
27# ifndef SLAVE_I2C_TIMEOUT
28# define SLAVE_I2C_TIMEOUT 100
29# endif // SLAVE_I2C_TIMEOUT
30
31# ifndef SLAVE_I2C_ADDRESS
32# define SLAVE_I2C_ADDRESS 0x32
33# endif
34
35# include "i2c_master.h"
36# include "i2c_slave.h"
37
38// Ensure the I2C buffer has enough space
39_Static_assert(sizeof(split_shared_memory_t) <= I2C_SLAVE_REG_COUNT, "split_shared_memory_t too large for I2C_SLAVE_REG_COUNT");
40
41split_shared_memory_t *const split_shmem = (split_shared_memory_t *)i2c_slave_reg;
42
43void transport_master_init(void) {
44 i2c_init();
45}
46void transport_slave_init(void) {
47 i2c_slave_init(SLAVE_I2C_ADDRESS);
48}
49
50i2c_status_t transport_trigger_callback(int8_t id) {
51 // If there's no callback, indicate that we were successful
52 if (!split_transaction_table[id].slave_callback) {
53 return I2C_STATUS_SUCCESS;
54 }
55
56 // Kick off the "callback executor", now that data has been written to the slave
57 split_shmem->transaction_id = id;
58 split_transaction_desc_t *trans = &split_transaction_table[I2C_EXECUTE_CALLBACK];
59 return i2c_write_register(SLAVE_I2C_ADDRESS, trans->initiator2target_offset, split_trans_initiator2target_buffer(trans), trans->initiator2target_buffer_size, SLAVE_I2C_TIMEOUT);
60}
61
62bool transport_execute_transaction(int8_t id, const void *initiator2target_buf, uint16_t initiator2target_length, void *target2initiator_buf, uint16_t target2initiator_length) {
63 i2c_status_t status;
64 split_transaction_desc_t *trans = &split_transaction_table[id];
65 if (initiator2target_length > 0) {
66 size_t len = trans->initiator2target_buffer_size < initiator2target_length ? trans->initiator2target_buffer_size : initiator2target_length;
67 memcpy(split_trans_initiator2target_buffer(trans), initiator2target_buf, len);
68 if ((status = i2c_write_register(SLAVE_I2C_ADDRESS, trans->initiator2target_offset, split_trans_initiator2target_buffer(trans), len, SLAVE_I2C_TIMEOUT)) < 0) {
69 return false;
70 }
71 }
72
73 // If we need to execute a callback on the slave, do so
74 if ((status = transport_trigger_callback(id)) < 0) {
75 return false;
76 }
77
78 if (target2initiator_length > 0) {
79 size_t len = trans->target2initiator_buffer_size < target2initiator_length ? trans->target2initiator_buffer_size : target2initiator_length;
80 if ((status = i2c_read_register(SLAVE_I2C_ADDRESS, trans->target2initiator_offset, split_trans_target2initiator_buffer(trans), len, SLAVE_I2C_TIMEOUT)) < 0) {
81 return false;
82 }
83 memcpy(target2initiator_buf, split_trans_target2initiator_buffer(trans), len);
84 }
85
86 return true;
87}
88
89#else // USE_I2C
90
91# include "serial.h"
92
93static split_shared_memory_t shared_memory;
94split_shared_memory_t *const split_shmem = &shared_memory;
95
96void transport_master_init(void) {
97 soft_serial_initiator_init();
98}
99void transport_slave_init(void) {
100 soft_serial_target_init();
101}
102
103bool transport_execute_transaction(int8_t id, const void *initiator2target_buf, uint16_t initiator2target_length, void *target2initiator_buf, uint16_t target2initiator_length) {
104 split_transaction_desc_t *trans = &split_transaction_table[id];
105 if (initiator2target_length > 0) {
106 size_t len = trans->initiator2target_buffer_size < initiator2target_length ? trans->initiator2target_buffer_size : initiator2target_length;
107 memcpy(split_trans_initiator2target_buffer(trans), initiator2target_buf, len);
108 }
109
110 if (!soft_serial_transaction(id)) {
111 return false;
112 }
113
114 if (target2initiator_length > 0) {
115 size_t len = trans->target2initiator_buffer_size < target2initiator_length ? trans->target2initiator_buffer_size : target2initiator_length;
116 memcpy(target2initiator_buf, split_trans_target2initiator_buffer(trans), len);
117 }
118
119 return true;
120}
121
122#endif // USE_I2C
123
124bool transport_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
125 return transactions_master(master_matrix, slave_matrix);
126}
127
128void transport_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
129 transactions_slave(master_matrix, slave_matrix);
130}