gblink.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443
  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. #include "clock_timer.h"
  11. const struct gblink_pins common_pinouts[PINOUT_COUNT] = {
  12. /* Original */
  13. {
  14. &gpio_ext_pc3,
  15. &gpio_ext_pb3,
  16. &gpio_ext_pb2,
  17. &gpio_ext_pa4,
  18. },
  19. /* MALVEKE EXT1 */
  20. {
  21. &gpio_ext_pa6,
  22. &gpio_ext_pa7,
  23. &gpio_ext_pb3,
  24. &gpio_ext_pa4,
  25. },
  26. };
  27. struct gblink {
  28. /* The spec contains:
  29. * spec->pins->serin
  30. * spec->pins->serout
  31. * spec->pins->clk
  32. * spec->pins->sd
  33. * spec->mode
  34. * spec->callback
  35. * spec->cb_context
  36. *
  37. * These are currently set up never to change during the lifetime of
  38. * a handle. If any of these need to change then the handle should be
  39. * destroyed and reopened. It is to save on complexity and is also an
  40. * opertion that would very rarely be needed without strong reason.
  41. */
  42. struct gblink_spec *spec;
  43. /* Used to control the wait until TX complete function. */
  44. FuriSemaphore *transfer_sem;
  45. FuriSemaphore *out_byte_sem;
  46. /*
  47. * The following should probably have the world stopped around them
  48. * if not modified in an interrupt context.
  49. */
  50. uint8_t in;
  51. uint8_t out;
  52. uint8_t shift;
  53. uint8_t nobyte;
  54. /* Should only be changed when not in middle of tx, will affect a lot */
  55. gblink_clk_source source;
  56. /* Can be changed at any time, will only take effect on the next
  57. * transfer.
  58. */
  59. gblink_speed speed;
  60. /*
  61. * The following is based on observing Pokemon trade data
  62. *
  63. * Clocks idle between bytes is nominally 430 us long for burst data,
  64. * 15 ms for idle polling (e.g. waiting for menu selection), some oddball
  65. * 2 ms gaps that appears between one 0xFE byte from the Game Boy every trade;
  66. * clock period is nominally 122 us.
  67. *
  68. * Therefore, if we haven't seen a clock in 500 us, reset our bit counter.
  69. * Note that, this should never actually be a concern, but it is an additional
  70. * safeguard against desyncing.
  71. */
  72. uint32_t time;
  73. uint32_t bitclk_timeout_us;
  74. void *exti_workaround_handle;
  75. };
  76. static inline bool gblink_transfer_in_progress(struct gblink *gblink)
  77. {
  78. return !(furi_semaphore_get_count(gblink->out_byte_sem));
  79. }
  80. static void gblink_shift_in_isr(struct gblink *gblink)
  81. {
  82. const uint32_t time_ticks = furi_hal_cortex_instructions_per_microsecond() * gblink->bitclk_timeout_us;
  83. if (gblink->source == GBLINK_CLK_INT)
  84. furi_hal_gpio_write(gblink->spec->pins->clk, 1);
  85. /* If we exceeded the bit clock timeout, reset all counters */
  86. if ((DWT->CYCCNT - gblink->time) > time_ticks) {
  87. gblink->in = 0;
  88. gblink->shift = 0;
  89. }
  90. gblink->time = DWT->CYCCNT;
  91. gblink->in <<= 1;
  92. gblink->in |= furi_hal_gpio_read(gblink->spec->pins->serin);
  93. gblink->shift++;
  94. /* If 8 bits transfered, reset shift counter, call registered
  95. * callback, re-set nobyte in output buffer.
  96. */
  97. if (gblink->shift == 8) {
  98. if (gblink->source == GBLINK_CLK_INT)
  99. clock_timer_stop();
  100. gblink->shift = 0;
  101. /*
  102. * Set up next out byte before calling the callback.
  103. * This is in case the callback itself sets a new out
  104. * byte which it will in most cases.
  105. *
  106. * The nobyte value is set in place as the next output byte,
  107. * in case the flipper does not set a real byte before the next
  108. * transfer starts.
  109. */
  110. gblink->out = gblink->nobyte;
  111. furi_semaphore_release(gblink->out_byte_sem);
  112. /*
  113. * Call the callback, if set, and then release the semaphore
  114. * in case a thread is waiting on TX to complete.
  115. */
  116. if (gblink->spec->callback)
  117. gblink->spec->callback(gblink->spec->cb_context, gblink->in);
  118. furi_semaphore_release(gblink->transfer_sem);
  119. }
  120. }
  121. static void gblink_shift_out_isr(struct gblink *gblink)
  122. {
  123. furi_semaphore_acquire(gblink->out_byte_sem, 0);
  124. furi_hal_gpio_write(gblink->spec->pins->serout, !!(gblink->out & 0x80));
  125. gblink->out <<= 1;
  126. /* XXX: TODO: Check that this is the correct thing with open drain.
  127. * does 0 value actually drive the line low, or high?
  128. */
  129. if (gblink->source == GBLINK_CLK_INT)
  130. furi_hal_gpio_write(gblink->spec->pins->clk, 0);
  131. }
  132. static void gblink_clk_isr(void *context)
  133. {
  134. furi_assert(context);
  135. struct gblink *gblink = context;
  136. bool out = false;
  137. /*
  138. * Whether we're shifting in or out is dependent on the clock source.
  139. * If external, and the clock line is high, that means a posedge just
  140. * occurred and we need to shift data in.
  141. *
  142. * If internal, and the clock line is high, that means we're about
  143. * to drive a negedge and need to shift data out.
  144. *
  145. * The actual in/out functions drive the clock state at the right times
  146. * if the clock is internal source.
  147. */
  148. out = (furi_hal_gpio_read(gblink->spec->pins->clk) ==
  149. (gblink->source == GBLINK_CLK_INT));
  150. if (out)
  151. gblink_shift_out_isr(gblink);
  152. else
  153. gblink_shift_in_isr(gblink);
  154. }
  155. /*
  156. * Call to set up the clk pin modes to do the right thing based on if INT or
  157. * EXT clock source is configured.
  158. */
  159. static void gblink_clk_configure(struct gblink *gblink)
  160. {
  161. struct gblink_pins *pins = gblink->spec->pins;
  162. if (gblink->source == GBLINK_CLK_EXT) {
  163. furi_hal_gpio_init(pins->clk, GpioModeInterruptRiseFall, GpioPullUp, GpioSpeedVeryHigh);
  164. /* furi_hal_gpio_init, while it sets interrupt settings on the GPIO,
  165. * does not actually enable the EXTI interrupt.
  166. */
  167. gblink_int_enable(gblink);
  168. } else {
  169. /* This will disable the EXTI interrupt for us */
  170. furi_hal_gpio_init(pins->clk, GpioModeOutputOpenDrain, GpioPullUp, GpioSpeedVeryHigh);
  171. };
  172. }
  173. void gblink_clk_source_set(void *handle, gblink_clk_source source)
  174. {
  175. furi_assert(handle);
  176. struct gblink *gblink = handle;
  177. if (source == gblink->source)
  178. return;
  179. /*
  180. * NOTE:
  181. * I'm not sure the best way to handle this at the moment. In theory,
  182. * it should be safe to check that we're just not in the middle of a
  183. * transfer and not worry about getting stuck.
  184. * However, I'm not really sure how true that is, so for now this will
  185. * always change the source and reset the current byte transfer.
  186. * It is up to the callee to ensure that they are between bytes.
  187. *
  188. * One idea would be to get the semaphore, but wait the set timeout.
  189. * if that is exceeded or the semaphore is acquired, then its probably
  190. * safe to change the source and reset shift register.
  191. */
  192. gblink->source = source;
  193. gblink->shift = 0;
  194. gblink_clk_configure(gblink);
  195. }
  196. void gblink_speed_set(void *handle, gblink_speed speed)
  197. {
  198. furi_assert(handle);
  199. struct gblink *gblink = handle;
  200. /*
  201. * This does not need any protection, it will take effect at the start
  202. * of the next byte.
  203. */
  204. gblink->speed = speed;
  205. }
  206. /* default is set to 500 us */
  207. void gblink_timeout_set(void *handle, uint32_t us)
  208. {
  209. furi_assert(handle);
  210. struct gblink *gblink = handle;
  211. gblink->bitclk_timeout_us = us;
  212. }
  213. bool gblink_transfer(void *handle, uint8_t val)
  214. {
  215. furi_assert(handle);
  216. struct gblink *gblink = handle;
  217. bool ret = false;
  218. /* Stop the world, this is to ensure we can safely set the next out byte */
  219. /*
  220. * The reason for and therefore issue of setting the next byte has a few
  221. * points to keep in mind.
  222. *
  223. * First, with EXT clock source, the first hint of the external device
  224. * clocking in data is a negative edge where it would set data. This
  225. * means that the next out byte needs to be set before that.
  226. *
  227. * Second, since the interrupt on the neg clock edge loads the next
  228. * byte in to serout after grabbing the semaphore; we can stop the
  229. * world right now, and set the byte if there is no transfer in
  230. * progress. As soon as the world is resumed, the IRQ will fire, and
  231. * the correct, new, data byte will start to be shifted out.
  232. */
  233. FURI_CRITICAL_ENTER();
  234. /* If we're in the middle of a tranfer, don't let the byte be set. */
  235. if (!gblink_transfer_in_progress(gblink)) {
  236. gblink->out = val;
  237. ret = true;
  238. /*
  239. * Now that we're this far, this means the byte we set will be
  240. * transferred one way or another. Because of that, take the
  241. * transfer semaphore. This gets released once a full byte has
  242. * been transferred. This is for the TX wait function. We cannot
  243. * use the out_byte_sem as if the wait is called immediately
  244. * after the transfer, and no data has yet been shifted out,
  245. * the TX wait function would incorrectly return immediately.
  246. */
  247. furi_semaphore_acquire(gblink->transfer_sem, 0);
  248. }
  249. FURI_CRITICAL_EXIT();
  250. /*
  251. * If the out byte was successfully set, and we're driving the clock,
  252. * turn on our timer for byte transfer.
  253. */
  254. if (ret && gblink->source == GBLINK_CLK_INT)
  255. clock_timer_start(gblink_clk_isr, gblink, gblink->speed);
  256. return ret;
  257. }
  258. uint8_t gblink_transfer_tx_wait_complete(void *handle)
  259. {
  260. struct gblink *gblink = handle;
  261. /* XXX: TODO: Think about how to implement this in a way that we can
  262. * use the semaphore to see if there is a transfer waiting to happen,
  263. * but not in a way that would incorrectly show a transfer waiting. e.g.
  264. * if this takes the semaphore, then the semaphore is in the same state
  265. * as if a transfer was in progress. Should this put back the semaphore
  266. * after acquiring it? Is there a better way of handling it?
  267. */
  268. furi_semaphore_acquire(gblink->transfer_sem, FuriWaitForever);
  269. return gblink->in;
  270. }
  271. void gblink_nobyte_set(void *handle, uint8_t val)
  272. {
  273. struct gblink *gblink = handle;
  274. /*
  275. * This is safe to run at any time. It is only copied in after a byte
  276. * transfer is completed.
  277. */
  278. gblink->nobyte = val;
  279. }
  280. void gblink_int_enable(void *handle)
  281. {
  282. furi_assert(handle);
  283. struct gblink *gblink = handle;
  284. /*
  285. * NOTE: This is currently safe to run even with the exti workaround
  286. * in effect. It just enables the root EXTI interrupt source of the
  287. * given pin.
  288. */
  289. furi_hal_gpio_enable_int_callback(gblink->spec->pins->clk);
  290. }
  291. void gblink_int_disable(void *handle)
  292. {
  293. furi_assert(handle);
  294. struct gblink *gblink = handle;
  295. /*
  296. * NOTE: This is currently safe to run even with the exti workaround
  297. * in effect. It just disables the root EXTI interrupt source of the
  298. * given pin.
  299. */
  300. furi_hal_gpio_disable_int_callback(gblink->spec->pins->clk);
  301. }
  302. void *gblink_alloc(struct gblink_spec *spec)
  303. {
  304. struct gblink *gblink;
  305. struct gblink_pins pins;
  306. /* Allocate and zero struct */
  307. gblink = malloc(sizeof(struct gblink));
  308. gblink->spec = malloc(sizeof(struct gblink_spec));
  309. gblink->transfer_sem = furi_semaphore_alloc(1, 1);
  310. gblink->out_byte_sem = furi_semaphore_alloc(1, 1);
  311. /* Copy data from the spec to our local struct. This is so the application
  312. * using this library doesn't need to maintain the data for the life of the
  313. * application.
  314. */
  315. memcpy(gblink->spec, spec, sizeof(struct gblink_spec));
  316. /* Copy pins from spec to local var just to make fewer dereferences */
  317. memcpy(&pins, gblink->spec->pins, sizeof(struct gblink_pins));
  318. /* Set default values for other variables */
  319. gblink->source = GBLINK_CLK_EXT;
  320. gblink->speed = GBLINK_SPD_8192HZ;
  321. gblink->bitclk_timeout_us = 500;
  322. gblink->time = DWT->CYCCNT;
  323. /* Set up pins */
  324. /* TODO: Set up a list of pins that are not safe to use with interrupts.
  325. * I do believe the main FURI GPIO struct has this data baked in so that
  326. * could be used. For now though, we're only checking for the MALVEKE
  327. * pinout which uses a clk pin that has its IRQ shared with the Okay
  328. * button.
  329. * See the work done in pokemon trade tool custom pinout selection for
  330. * an idea of how to check all that.
  331. */
  332. furi_hal_gpio_write(pins.serout, false);
  333. furi_hal_gpio_init(pins.serout, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh);
  334. furi_hal_gpio_write(pins.serin, false);
  335. furi_hal_gpio_init(pins.serin, GpioModeInput, GpioPullUp, GpioSpeedVeryHigh);
  336. /* Set up interrupt on clock pin */
  337. if (pins.clk == &gpio_ext_pb3) {
  338. /* The clock pin is on a pin that is not safe to set an interrupt
  339. * on, so we do a gross workaround to get an interrupt enabled
  340. * on that pin in a way that can be undone safely later with
  341. * no impact to the shared IRQ.
  342. */
  343. gblink->exti_workaround_handle = exti_workaround(pins.clk, gblink_clk_isr, gblink);
  344. } else {
  345. /* This may not be needed after NFC refactor */
  346. furi_hal_gpio_remove_int_callback(pins.clk);
  347. furi_hal_gpio_add_int_callback(pins.clk, gblink_clk_isr, gblink);
  348. }
  349. /* The above immediately enables the interrupt, we don't want
  350. * that just yet and we want configure to handle it.
  351. */
  352. gblink_int_disable(gblink);
  353. gblink_clk_configure(gblink);
  354. return gblink;
  355. }
  356. void gblink_free(void *handle)
  357. {
  358. furi_assert(handle);
  359. struct gblink *gblink = handle;
  360. struct gblink_pins *pins = gblink->spec->pins;
  361. if (pins->clk == &gpio_ext_pb3) {
  362. /* This handles switching the IVT back and putting the EXTI
  363. * regs and pin regs in a valid state for normal use.
  364. */
  365. exti_workaround_undo(gblink->exti_workaround_handle);
  366. } else {
  367. /* Remove interrupt, set IO to sane state */
  368. furi_hal_gpio_remove_int_callback(pins->clk);
  369. }
  370. furi_hal_gpio_init_simple(pins->serin, GpioModeAnalog);
  371. furi_hal_gpio_init_simple(pins->serout, GpioModeAnalog);
  372. furi_hal_gpio_init_simple(pins->clk, GpioModeAnalog);
  373. free(gblink);
  374. }