You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

208 lines
6.1 KiB

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