gblink.c 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  1. // SPDX-License-Identifier: BSD-2-Clause
  2. // Copyright (c) 2023 KBEmbedded
  3. #include <furi.h>
  4. #include <furi_hal.h>
  5. #include <stm32wbxx_ll_exti.h>
  6. #include <stm32wbxx_ll_system.h>
  7. #include <stdint.h>
  8. #include "gblink.h"
  9. #include "exti_workaround.h"
  10. const struct gblink_pins common_pinouts[PINOUT_COUNT] = {
  11. /* Original */
  12. {
  13. &gpio_ext_pc3,
  14. &gpio_ext_pb3,
  15. &gpio_ext_pb2,
  16. &gpio_ext_pa4,
  17. },
  18. /* MALVEKE EXT1 */
  19. {
  20. &gpio_ext_pa6,
  21. &gpio_ext_pa7,
  22. &gpio_ext_pb3,
  23. &gpio_ext_pa4,
  24. },
  25. };
  26. struct gblink {
  27. const GpioPin *serin;
  28. const GpioPin *serout;
  29. const GpioPin *clk;
  30. const GpioPin *sd;
  31. uint8_t in;
  32. uint8_t out;
  33. uint8_t out_buf;
  34. bool out_buf_valid;
  35. uint8_t shift;
  36. uint8_t nobyte;
  37. gblink_clk_source source;
  38. gblink_mode mode;
  39. gblink_speed speed;
  40. uint32_t time;
  41. uint32_t bitclk_timeout_us;
  42. /* Clocks idle between bytes is nominally 430 us long for burst data,
  43. * 15 ms for idle polling (e.g. waiting for menu selection), some oddball
  44. * 2 ms gaps that appears between one 0xFE byte from the Game Boy every trade;
  45. * clock period is nominally 122 us.
  46. * Therefore, if we haven't seen a clock in 500 us, reset our bit counter.
  47. * Note that, this should never actually be a concern, but it is an additional
  48. * safeguard against desyncing.
  49. */
  50. void (*callback)(void* cb_context, uint8_t in);
  51. void *cb_context;
  52. void *exti_workaround_handle;
  53. };
  54. static void gblink_shift_in(struct gblink *gblink)
  55. {
  56. const uint32_t time_ticks = furi_hal_cortex_instructions_per_microsecond() * gblink->bitclk_timeout_us;
  57. /* If we exceeded the bit clock timeout, reset all counters */
  58. if ((DWT->CYCCNT - gblink->time) > time_ticks) {
  59. gblink->in = 0;
  60. gblink->shift = 0;
  61. }
  62. gblink->time = DWT->CYCCNT;
  63. gblink->in <<= 1;
  64. gblink->in |= furi_hal_gpio_read(gblink->serin);
  65. gblink->shift++;
  66. /* If 8 bits transfered, reset shift counter, call registered
  67. * callback, re-set nobyte in output buffer.
  68. */
  69. if (gblink->shift == 8) {
  70. gblink->shift = 0;
  71. /* Set up next out byte before calling the callback.
  72. * This is in case the callback itself sets a new out
  73. * byte which it will in most cases. It is up to the
  74. * main application at this time to ensure that
  75. * gblink_transfer() isn't called multiple times before
  76. * a byte has a chance to be sent out.
  77. */
  78. if (gblink->out_buf_valid) {
  79. gblink->out = gblink->out_buf;
  80. gblink->out_buf_valid = false;
  81. } else {
  82. gblink->out = gblink->nobyte;
  83. }
  84. gblink->callback(gblink->cb_context, gblink->in);
  85. }
  86. }
  87. static void gblink_shift_out(struct gblink *gblink)
  88. {
  89. furi_hal_gpio_write(gblink->serout, !!(gblink->out & 0x80));
  90. gblink->out <<= 1;
  91. }
  92. static void gblink_clk_isr(void *context)
  93. {
  94. furi_assert(context);
  95. struct gblink *gblink = context;
  96. if (furi_hal_gpio_read(gblink->clk)) {
  97. /* Posedge Shift in data */
  98. gblink_shift_in(gblink);
  99. } else {
  100. /* Negedge shift out data */
  101. gblink_shift_out(gblink);
  102. }
  103. }
  104. void gblink_clk_source_set(void *handle, gblink_clk_source source)
  105. {
  106. furi_assert(handle);
  107. struct gblink *gblink = handle;
  108. gblink->source = source;
  109. gblink->shift = 0;
  110. }
  111. void gblink_speed_set(void *handle, gblink_speed speed)
  112. {
  113. furi_assert(handle);
  114. struct gblink *gblink = handle;
  115. gblink->speed = speed;
  116. }
  117. /* default is set to 500 us */
  118. void gblink_timeout_set(void *handle, uint32_t us)
  119. {
  120. furi_assert(handle);
  121. struct gblink *gblink = handle;
  122. gblink->bitclk_timeout_us = us;
  123. }
  124. void gblink_transfer(void *handle, uint8_t val)
  125. {
  126. furi_assert(handle);
  127. struct gblink *gblink = handle;
  128. /* This checks the value of gblink->shift which can change in the ISR.
  129. * Because of that, disable interrupts when checking gblink->shift and
  130. * setting gblink->out_buf_valid
  131. * If shift is 0, we're between bytes and can safely set the out byte.
  132. * If shift is nonzero, a byte is currently being transmitted. Set the
  133. * out_buf and set out_buf_valid. When the ISR is finished writing the
  134. * next byte it will check out_buf_valid and copy in out_buf.
  135. *
  136. * The correct/smart way of doing this would be a mutex rather than
  137. * stopping the world.
  138. *
  139. * Realistically, this should only ever be called from the transfer
  140. * complete callback. There are few situations outside of that which
  141. * would make sense.
  142. *
  143. * Note that, this currently has no checks for if there is data already
  144. * pending to be transmitted. Calling this back to back can cause data
  145. * loss!
  146. */
  147. FURI_CRITICAL_ENTER();
  148. if (gblink->shift == 0) {
  149. gblink->out = val;
  150. gblink->out_buf_valid = false;
  151. } else {
  152. gblink->out_buf = val;
  153. gblink->out_buf_valid = true;
  154. }
  155. FURI_CRITICAL_EXIT();
  156. }
  157. void gblink_nobyte_set(void *handle, uint8_t val)
  158. {
  159. struct gblink *gblink = handle;
  160. gblink->nobyte = val;
  161. }
  162. void gblink_int_enable(void *handle)
  163. {
  164. furi_assert(handle);
  165. struct gblink *gblink = handle;
  166. furi_hal_gpio_enable_int_callback(gblink->clk);
  167. }
  168. void gblink_int_disable(void *handle)
  169. {
  170. furi_assert(handle);
  171. struct gblink *gblink = handle;
  172. furi_hal_gpio_disable_int_callback(gblink->clk);
  173. }
  174. void *gblink_alloc(struct gblink_def *gblink_def)
  175. {
  176. struct gblink *gblink;
  177. /* Allocate and zero struct */
  178. gblink = malloc(sizeof(struct gblink));
  179. /* Set struct values from function args */
  180. gblink->serin = gblink_def->pins->serin;
  181. gblink->serout = gblink_def->pins->serout;
  182. gblink->clk = gblink_def->pins->clk;
  183. gblink->sd = gblink_def->pins->sd;
  184. gblink->source = gblink_def->source;
  185. gblink->speed = GBLINK_SPD_8192HZ;
  186. /* Set up timeout variables */
  187. gblink->bitclk_timeout_us = 500;
  188. gblink->time = DWT->CYCCNT;
  189. /* Set up secondary callback */
  190. gblink->callback = gblink_def->callback;
  191. gblink->cb_context = gblink_def->cb_context;
  192. /* Set up pins */
  193. /* TODO: Set up a list of pins that are not safe to use with interrupts.
  194. * I do believe the main FURI GPIO struct has this data baked in so that
  195. * could be used. For now though, we're only checking for the MALVEKE
  196. * pinout which uses a clk pin that has its IRQ shared with the Okay
  197. * button.
  198. * See the work done in pokemon trade tool custom pinout selection for
  199. * an idea of how to check all that.
  200. */
  201. /* TODO: Currently assumes external clock source only */
  202. /* XXX: This might actually be open-drain on real GB hardware */
  203. furi_hal_gpio_write(gblink->serout, false);
  204. furi_hal_gpio_init(gblink->serout, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh);
  205. furi_hal_gpio_write(gblink->serin, false);
  206. furi_hal_gpio_init(gblink->serin, GpioModeInput, GpioPullUp, GpioSpeedVeryHigh);
  207. /* Set up interrupt on clock */
  208. if (gblink->clk == &gpio_ext_pb3) {
  209. /* The clock pin is on a pin that is not safe to set an interrupt
  210. * on, so we do a gross workaround to get an interrupt enabled
  211. * on that pin in a way that can be undone safely later with
  212. * no impact to the shared IRQ.
  213. */
  214. gblink->exti_workaround_handle = exti_workaround(gblink->clk, gblink_clk_isr, gblink);
  215. } else {
  216. furi_hal_gpio_init(gblink->clk, GpioModeInterruptRiseFall, GpioPullUp, GpioSpeedVeryHigh);
  217. /* This may not be needed after NFC refactor */
  218. furi_hal_gpio_remove_int_callback(gblink->clk);
  219. furi_hal_gpio_add_int_callback(gblink->clk, gblink_clk_isr, gblink);
  220. }
  221. return gblink;
  222. }
  223. void gblink_free(void *handle)
  224. {
  225. furi_assert(handle);
  226. struct gblink *gblink = handle;
  227. if (gblink->clk == &gpio_ext_pb3) {
  228. /* This handles switching the IVT back and putting the EXTI
  229. * regs and pin regs in a valid state for normal use.
  230. */
  231. exti_workaround_undo(gblink->exti_workaround_handle);
  232. } else {
  233. /* Remove interrupt, set IO to sane state */
  234. furi_hal_gpio_remove_int_callback(gblink->clk);
  235. }
  236. furi_hal_gpio_init_simple(gblink->serin, GpioModeAnalog);
  237. furi_hal_gpio_init_simple(gblink->serout, GpioModeAnalog);
  238. furi_hal_gpio_init_simple(gblink->clk, GpioModeAnalog);
  239. free(gblink);
  240. }