logo

qmk_firmware

custom branch of QMK firmware git clone https://anongit.hacktivis.me/git/qmk_firmware.git

transport.c (6284B)


  1. /* Copyright 2020 Dimitris Papavasiliou <dpapavas@protonmail.ch>
  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 3 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 <https://www.gnu.org/licenses/>.
  15. */
  16. #include "spi_master.h"
  17. #include "split_util.h"
  18. #include "transport.h"
  19. #include "timer.h"
  20. #include "lagrange.h"
  21. struct led_context {
  22. led_t led_state;
  23. layer_state_t layer_state;
  24. };
  25. uint8_t transceive(uint8_t b) {
  26. for (SPDR = b ; !(SPSR & _BV(SPIF)) ; );
  27. return SPDR;
  28. }
  29. /* The SPI bus, doesn't have any form of protocol built in, so when
  30. * the other side isn't present, any old noise on the line will appear
  31. * as matrix data. To avoid interpreting data as keystrokes, we do a
  32. * simple n-way (8-way here) handshake before each scan, where each
  33. * side sends a prearranged sequence of bytes. */
  34. bool shake_hands(bool master) {
  35. const uint8_t m = master ? 0xf8 : 0;
  36. const uint8_t a = 0xa8 ^ m, b = 0x50 ^ m;
  37. bool synchronized = true;
  38. uint8_t i;
  39. i = SPSR;
  40. i = SPDR;
  41. do {
  42. /* Cycling the SS pin on each attempt is necessary, as it
  43. * resets the AVR's SPI core and guarantees proper
  44. * alignment. */
  45. if (master) {
  46. gpio_write_pin_low(SPI_SS_PIN);
  47. }
  48. for (i = 0 ; i < 8 ; i += 1) {
  49. if (transceive(a + i) != b + i) {
  50. synchronized = false;
  51. break;
  52. }
  53. }
  54. if (master) {
  55. gpio_write_pin_high(SPI_SS_PIN);
  56. }
  57. } while (i < 8);
  58. return synchronized;
  59. }
  60. bool transport_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
  61. const struct led_context context = {
  62. host_keyboard_led_state(),
  63. layer_state
  64. };
  65. uint8_t i;
  66. /* We shake hands both before and after transmitting the matrix.
  67. * Doing it before transmitting is necessary to ensure
  68. * synchronization: Due to the master-slave nature of the SPI bus,
  69. * the master calls the shots. If we just go ahead and start
  70. * clocking bits, the slave side might be otherwise engaged at
  71. * that moment, so we'll initially read zeros, or garbage. Then
  72. * when the slave gets around to transmitting its matrix, we'll
  73. * misinterpret the keys it sends, leading to spurious
  74. * keypresses. */
  75. /* The handshake forces the master to wait for the slave to be
  76. * ready to start transmitting. */
  77. do {
  78. shake_hands(true);
  79. /* Receive the matrix from the other side, while transmitting
  80. * LED and layer states. */
  81. spi_start(SPI_SS_PIN, 0, 0, 4);
  82. for (i = 0 ; i < sizeof(matrix_row_t[MATRIX_ROWS / 2]) ; i += 1) {
  83. spi_status_t x;
  84. x = spi_write(i < sizeof(struct led_context) ?
  85. ((uint8_t *)&context)[i] : 0);
  86. if (x == SPI_STATUS_TIMEOUT) {
  87. return false;
  88. }
  89. ((uint8_t *)slave_matrix)[i] = (uint8_t)x;
  90. }
  91. spi_stop();
  92. /* In case of errors during the transmission, e.g. if the
  93. * cable was disconnected and since there is no inherent
  94. * error-checking protocol, we would simply interpret noise as
  95. * data. */
  96. /* To avoid this, both sides shake hands after transmitting.
  97. * If synchronization was lost during transmission, the (first)
  98. * handshake will fail. In that case we go around and
  99. * re-transmit. */
  100. } while (!shake_hands(true));
  101. return true;
  102. }
  103. void transport_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
  104. static struct led_context context;
  105. struct led_context new_context;
  106. uint8_t i;
  107. /* Do the reverse of master above. Note that timing is critical,
  108. * so interrupts must be turned off. */
  109. cli();
  110. shake_hands(false);
  111. do {
  112. for (i = 0 ; i < sizeof(matrix_row_t[MATRIX_ROWS / 2]) ; i += 1) {
  113. uint8_t b;
  114. b = transceive(((uint8_t *)slave_matrix)[i]);
  115. if (i < sizeof(struct led_context)) {
  116. ((uint8_t *)&new_context)[i] = b;
  117. }
  118. }
  119. } while (!shake_hands(false));
  120. sei();
  121. /* Update the layer and LED state if necessary. */
  122. if (!isLeftHand) {
  123. if (context.led_state.raw != new_context.led_state.raw) {
  124. context.led_state.raw = new_context.led_state.raw;
  125. led_update_kb(context.led_state);
  126. }
  127. if (context.layer_state != new_context.layer_state) {
  128. context.layer_state = new_context.layer_state;
  129. layer_state_set_kb(context.layer_state);
  130. }
  131. }
  132. }
  133. void transport_master_init(void) {
  134. /* We need to set the SS pin as output as the handshake logic
  135. * above depends on it and the SPI master driver won't do it
  136. * before we call spi_start(). */
  137. gpio_write_pin_high(SPI_SS_PIN);
  138. gpio_set_pin_output(SPI_SS_PIN);
  139. spi_init();
  140. shake_hands(true);
  141. }
  142. void transport_slave_init(void) {
  143. /* The datasheet isn't very clear on whether the internal pull-up
  144. * is selectable when the SS pin is used by the SPI slave, but
  145. * experimentations shows that it is, at least on the ATMega32u4.
  146. * We enable the pull-up to guard against the case where both
  147. * halves end up as slaves. In that case the SS pin would
  148. * otherwise be floating and free to fluctuate due to picked up
  149. * noise, etc. When reading low it would make both halves think
  150. * they're asserted making the MISO pin an output on both ends and
  151. * leading to potential shorts. */
  152. gpio_set_pin_input_high(SPI_SS_PIN);
  153. gpio_set_pin_input(SPI_SCK_PIN);
  154. gpio_set_pin_input(SPI_MOSI_PIN);
  155. gpio_set_pin_output(SPI_MISO_PIN);
  156. SPCR = _BV(SPE);
  157. shake_hands(false);
  158. }