gblink.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593
  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/include/gblink.h>
  9. #include "exti_workaround_i.h"
  10. #include "clock_timer_i.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. const GpioPin *serin;
  29. const GpioPin *serout;
  30. const GpioPin *clk;
  31. const GpioPin *sd;
  32. gblink_mode mode;
  33. void (*callback)(void* cb_context, uint8_t in);
  34. void *cb_context;
  35. /* These two semaphores serve similar but distinct purposes. */
  36. /* The transfer semaphore is taken as soon as a transfer() request
  37. * has been started. This is used in the function to wait until the
  38. * transfer has been completed.
  39. */
  40. FuriSemaphore *transfer_sem;
  41. /* The out byte semaphore is used to indicate that a byte transfer
  42. * is in progress. This is used in the transfer function to not allow
  43. * a transfer request if we're in the middle of sending a byte.
  44. * The transfer semaphore is not used for that purpose since if the
  45. * Flipper is in EXT clk mode, once a transfer() is started, there
  46. * would be no way to both prevent transfer() from being called again
  47. * as well as cancelling/changing what we're wanting to send. Using
  48. * out byte semaphore means a transfer() can be called at any time,
  49. * waited on synchronously for a timeout, and then re-called at a
  50. * later time; while blocking that update if a byte is actually
  51. * in the middle of being transmitted.
  52. */
  53. FuriSemaphore *out_byte_sem;
  54. /* Used to lock out changing things after a certain point. Pinout,
  55. * mode, etc.
  56. * XXX: Might make more sense to use the mutex to protect a flag?
  57. * Maybe a semaphore? Though I think that is the wrong use.
  58. */
  59. FuriMutex *start_mutex;
  60. /*
  61. * The following should probably have the world stopped around them
  62. * if not modified in an interrupt context.
  63. */
  64. uint8_t in;
  65. uint8_t out;
  66. uint8_t shift;
  67. uint8_t nobyte;
  68. /* Should only be changed when not in middle of tx, will affect a lot */
  69. gblink_clk_source source;
  70. /* Can be changed at any time, will only take effect on the next
  71. * transfer.
  72. */
  73. gblink_speed speed;
  74. /*
  75. * The following is based on observing Pokemon trade data
  76. *
  77. * Clocks idle between bytes is nominally 430 us long for burst data,
  78. * 15 ms for idle polling (e.g. waiting for menu selection), some oddball
  79. * 2 ms gaps that appears between one 0xFE byte from the Game Boy every trade;
  80. * clock period is nominally 122 us.
  81. *
  82. * Therefore, if we haven't seen a clock in 500 us, reset our bit counter.
  83. * Note that, this should never actually be a concern, but it is an additional
  84. * safeguard against desyncing.
  85. */
  86. uint32_t time;
  87. uint32_t bitclk_timeout_us;
  88. void *exti_workaround_handle;
  89. };
  90. static inline bool gblink_transfer_in_progress(struct gblink *gblink)
  91. {
  92. return !(furi_semaphore_get_count(gblink->out_byte_sem));
  93. }
  94. static void gblink_shift_in_isr(struct gblink *gblink)
  95. {
  96. const uint32_t time_ticks = furi_hal_cortex_instructions_per_microsecond() * gblink->bitclk_timeout_us;
  97. if (gblink->source == GBLINK_CLK_INT)
  98. furi_hal_gpio_write(gblink->clk, 1);
  99. /* If we exceeded the bit clock timeout, reset all counters */
  100. if ((DWT->CYCCNT - gblink->time) > time_ticks) {
  101. gblink->in = 0;
  102. gblink->shift = 0;
  103. }
  104. gblink->time = DWT->CYCCNT;
  105. gblink->in <<= 1;
  106. gblink->in |= furi_hal_gpio_read(gblink->serin);
  107. gblink->shift++;
  108. /* If 8 bits transfered, reset shift counter, call registered
  109. * callback, re-set nobyte in output buffer.
  110. */
  111. if (gblink->shift == 8) {
  112. if (gblink->source == GBLINK_CLK_INT)
  113. clock_timer_stop();
  114. gblink->shift = 0;
  115. /*
  116. * Set up next out byte before calling the callback.
  117. * This is in case the callback itself sets a new out
  118. * byte which it will in most cases.
  119. *
  120. * The nobyte value is set in place as the next output byte,
  121. * in case the flipper does not set a real byte before the next
  122. * transfer starts.
  123. */
  124. gblink->out = gblink->nobyte;
  125. furi_semaphore_release(gblink->out_byte_sem);
  126. /*
  127. * Call the callback, if set, and then release the semaphore
  128. * in case a thread is waiting on TX to complete.
  129. */
  130. if (gblink->callback)
  131. gblink->callback(gblink->cb_context, gblink->in);
  132. furi_semaphore_release(gblink->transfer_sem);
  133. }
  134. }
  135. static void gblink_shift_out_isr(struct gblink *gblink)
  136. {
  137. furi_semaphore_acquire(gblink->out_byte_sem, 0);
  138. furi_hal_gpio_write(gblink->serout, !!(gblink->out & 0x80));
  139. gblink->out <<= 1;
  140. /* XXX: TODO: Check that this is the correct thing with open drain.
  141. * does 0 value actually drive the line low, or high?
  142. */
  143. if (gblink->source == GBLINK_CLK_INT)
  144. furi_hal_gpio_write(gblink->clk, 0);
  145. }
  146. static void gblink_clk_isr(void *context)
  147. {
  148. furi_assert(context);
  149. struct gblink *gblink = context;
  150. bool out = false;
  151. /*
  152. * Whether we're shifting in or out is dependent on the clock source.
  153. * If external, and the clock line is high, that means a posedge just
  154. * occurred and we need to shift data in.
  155. *
  156. * If internal, and the clock line is high, that means we're about
  157. * to drive a negedge and need to shift data out.
  158. *
  159. * The actual in/out functions drive the clock state at the right times
  160. * if the clock is internal source.
  161. */
  162. out = (furi_hal_gpio_read(gblink->clk) ==
  163. (gblink->source == GBLINK_CLK_INT));
  164. if (out)
  165. gblink_shift_out_isr(gblink);
  166. else
  167. gblink_shift_in_isr(gblink);
  168. }
  169. /*
  170. * Call to set up the clk pin modes to do the right thing based on if INT or
  171. * EXT clock source is configured.
  172. */
  173. static void gblink_clk_configure(struct gblink *gblink)
  174. {
  175. if (gblink->source == GBLINK_CLK_EXT) {
  176. furi_hal_gpio_init(gblink->clk, GpioModeInterruptRiseFall, GpioPullUp, GpioSpeedVeryHigh);
  177. /* furi_hal_gpio_init, while it sets interrupt settings on the GPIO,
  178. * does not actually enable the EXTI interrupt.
  179. */
  180. gblink_int_enable(gblink);
  181. } else {
  182. /* This will disable the EXTI interrupt for us */
  183. furi_hal_gpio_init(gblink->clk, GpioModeOutputOpenDrain, GpioPullUp, GpioSpeedVeryHigh);
  184. };
  185. }
  186. void gblink_clk_source_set(void *handle, gblink_clk_source source)
  187. {
  188. furi_assert(handle);
  189. struct gblink *gblink = handle;
  190. if (source == gblink->source)
  191. return;
  192. /*
  193. * NOTE:
  194. * I'm not sure the best way to handle this at the moment. In theory,
  195. * it should be safe to check that we're just not in the middle of a
  196. * transfer and not worry about getting stuck.
  197. * However, I'm not really sure how true that is, so for now this will
  198. * always change the source and reset the current byte transfer.
  199. * It is up to the callee to ensure that they are between bytes.
  200. *
  201. * One idea would be to get the semaphore, but wait the set timeout.
  202. * if that is exceeded or the semaphore is acquired, then its probably
  203. * safe to change the source and reset shift register.
  204. */
  205. gblink->source = source;
  206. gblink->shift = 0;
  207. gblink_clk_configure(gblink);
  208. }
  209. void gblink_speed_set(void *handle, gblink_speed speed)
  210. {
  211. furi_assert(handle);
  212. struct gblink *gblink = handle;
  213. /*
  214. * This does not need any protection, it will take effect at the start
  215. * of the next byte.
  216. */
  217. gblink->speed = speed;
  218. }
  219. /* default is set to 500 us */
  220. void gblink_timeout_set(void *handle, uint32_t us)
  221. {
  222. furi_assert(handle);
  223. struct gblink *gblink = handle;
  224. gblink->bitclk_timeout_us = us;
  225. }
  226. int gblink_pin_set(void *handle, gblink_bus_pins pin, const GpioPin *gpio)
  227. {
  228. furi_assert(handle);
  229. struct gblink *gblink = handle;
  230. if (furi_mutex_acquire(gblink->start_mutex, 0) != FuriStatusOk)
  231. return 1;
  232. switch (pin) {
  233. case PIN_SERIN:
  234. gblink->serin = gpio;
  235. break;
  236. case PIN_SEROUT:
  237. gblink->serout = gpio;
  238. break;
  239. case PIN_CLK:
  240. gblink->clk = gpio;
  241. break;
  242. case PIN_SD:
  243. gblink->sd = gpio;
  244. break;
  245. default:
  246. furi_crash();
  247. break;
  248. }
  249. furi_mutex_release(gblink->start_mutex);
  250. return 0;
  251. }
  252. int gblink_pin_set_default(void *handle, gblink_pinouts pinout)
  253. {
  254. furi_assert(handle);
  255. struct gblink *gblink = handle;
  256. if (furi_mutex_acquire(gblink->start_mutex, 0) != FuriStatusOk)
  257. return 1;
  258. gblink->serin = common_pinouts[pinout].serin;
  259. gblink->serout = common_pinouts[pinout].serout;
  260. gblink->clk = common_pinouts[pinout].clk;
  261. gblink->sd = common_pinouts[pinout].sd;
  262. furi_mutex_release(gblink->start_mutex);
  263. return 0;
  264. }
  265. const GpioPin *gblink_pin_get(void *handle, gblink_bus_pins pin)
  266. {
  267. furi_assert(handle);
  268. struct gblink *gblink = handle;
  269. switch (pin) {
  270. case PIN_SERIN:
  271. return gblink->serin;
  272. case PIN_SEROUT:
  273. return gblink->serout;
  274. case PIN_CLK:
  275. return gblink->clk;
  276. case PIN_SD:
  277. return gblink->sd;
  278. default:
  279. furi_crash();
  280. break;
  281. }
  282. return NULL;
  283. }
  284. int gblink_callback_set(void *handle, void (*callback)(void* cb_context, uint8_t in), void *cb_context)
  285. {
  286. furi_assert(handle);
  287. struct gblink *gblink = handle;
  288. if (furi_mutex_acquire(gblink->start_mutex, 0) != FuriStatusOk)
  289. return 1;
  290. gblink->callback = callback;
  291. gblink->cb_context = cb_context;
  292. furi_mutex_release(gblink->start_mutex);
  293. return 0;
  294. }
  295. int gblink_mode_set(void *handle, gblink_mode mode)
  296. {
  297. furi_assert(handle);
  298. struct gblink *gblink = handle;
  299. if (furi_mutex_acquire(gblink->start_mutex, 0) != FuriStatusOk)
  300. return 1;
  301. gblink->mode = mode;
  302. furi_mutex_release(gblink->start_mutex);
  303. return 0;
  304. }
  305. bool gblink_transfer(void *handle, uint8_t val)
  306. {
  307. furi_assert(handle);
  308. struct gblink *gblink = handle;
  309. bool ret = false;
  310. /* Stop the world, this is to ensure we can safely set the next out byte */
  311. /*
  312. * The reason for and therefore issue of setting the next byte has a few
  313. * points to keep in mind.
  314. *
  315. * First, with EXT clock source, the first hint of the external device
  316. * clocking in data is a negative edge where it would set data. This
  317. * means that the next out byte needs to be set before that.
  318. *
  319. * Second, since the interrupt on the neg clock edge loads the next
  320. * byte in to serout after grabbing the semaphore; we can stop the
  321. * world right now, and set the byte if there is no transfer in
  322. * progress. As soon as the world is resumed, the IRQ will fire, and
  323. * the correct, new, data byte will start to be shifted out.
  324. */
  325. FURI_CRITICAL_ENTER();
  326. /* If we're in the middle of a tranfer, don't let the byte be set. */
  327. if (!gblink_transfer_in_progress(gblink)) {
  328. gblink->out = val;
  329. ret = true;
  330. /*
  331. * Now that we're this far, this means the byte we set will be
  332. * transferred one way or another. Because of that, take the
  333. * transfer semaphore. This gets released once a full byte has
  334. * been transferred. This is for the TX wait function. We cannot
  335. * use the out_byte_sem as if the wait is called immediately
  336. * after the transfer, and no data has yet been shifted out,
  337. * the TX wait function would incorrectly return immediately.
  338. */
  339. furi_semaphore_acquire(gblink->transfer_sem, 0);
  340. }
  341. FURI_CRITICAL_EXIT();
  342. /*
  343. * If the out byte was successfully set, and we're driving the clock,
  344. * turn on our timer for byte transfer.
  345. */
  346. if (ret && gblink->source == GBLINK_CLK_INT)
  347. clock_timer_start(gblink_clk_isr, gblink, gblink->speed);
  348. return ret;
  349. }
  350. uint8_t gblink_transfer_tx_wait_complete(void *handle)
  351. {
  352. struct gblink *gblink = handle;
  353. /* XXX: TODO: Think about how to implement this in a way that we can
  354. * use the semaphore to see if there is a transfer waiting to happen,
  355. * but not in a way that would incorrectly show a transfer waiting. e.g.
  356. * if this takes the semaphore, then the semaphore is in the same state
  357. * as if a transfer was in progress. Should this put back the semaphore
  358. * after acquiring it? Is there a better way of handling it?
  359. */
  360. furi_semaphore_acquire(gblink->transfer_sem, FuriWaitForever);
  361. return gblink->in;
  362. }
  363. void gblink_nobyte_set(void *handle, uint8_t val)
  364. {
  365. struct gblink *gblink = handle;
  366. /*
  367. * This is safe to run at any time. It is only copied in after a byte
  368. * transfer is completed.
  369. */
  370. gblink->nobyte = val;
  371. }
  372. void gblink_int_enable(void *handle)
  373. {
  374. furi_assert(handle);
  375. struct gblink *gblink = handle;
  376. /*
  377. * NOTE: This is currently safe to run even with the exti workaround
  378. * in effect. It just enables the root EXTI interrupt source of the
  379. * given pin.
  380. */
  381. furi_hal_gpio_enable_int_callback(gblink->clk);
  382. }
  383. void gblink_int_disable(void *handle)
  384. {
  385. furi_assert(handle);
  386. struct gblink *gblink = handle;
  387. /*
  388. * NOTE: This is currently safe to run even with the exti workaround
  389. * in effect. It just disables the root EXTI interrupt source of the
  390. * given pin.
  391. */
  392. furi_hal_gpio_disable_int_callback(gblink->clk);
  393. }
  394. void *gblink_alloc(void)
  395. {
  396. struct gblink *gblink;
  397. /* Allocate and zero struct */
  398. gblink = malloc(sizeof(struct gblink));
  399. //gblink->spec = malloc(sizeof(struct gblink_spec));
  400. gblink->transfer_sem = furi_semaphore_alloc(1, 1);
  401. gblink->out_byte_sem = furi_semaphore_alloc(1, 1);
  402. gblink->start_mutex = furi_mutex_alloc(FuriMutexTypeNormal);
  403. /* Set defaults */
  404. gblink_pin_set_default(gblink, PINOUT_ORIGINAL);
  405. gblink_mode_set(gblink, GBLINK_MODE_GBC);
  406. gblink_clk_source_set(gblink, GBLINK_CLK_EXT);
  407. gblink_speed_set(gblink, GBLINK_SPD_8192HZ);
  408. gblink_timeout_set(gblink, 500);
  409. /* Set current time to start timeout calculations */
  410. gblink->time = DWT->CYCCNT;
  411. return gblink;
  412. }
  413. void gblink_start(void *handle)
  414. {
  415. furi_assert(handle);
  416. struct gblink *gblink = handle;
  417. /* XXX: Check callback is valid */
  418. furi_mutex_acquire(gblink->start_mutex, FuriWaitForever);
  419. /* Set up pins */
  420. /* TODO: Set up a list of pins that are not safe to use with interrupts.
  421. * I do believe the main FURI GPIO struct has this data baked in so that
  422. * could be used. For now though, we're only checking for the MALVEKE
  423. * pinout which uses a clk pin that has its IRQ shared with the Okay
  424. * button.
  425. * See the work done in pokemon trade tool custom pinout selection for
  426. * an idea of how to check all that.
  427. */
  428. furi_hal_gpio_write(gblink->serout, false);
  429. furi_hal_gpio_init(gblink->serout, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh);
  430. furi_hal_gpio_write(gblink->serin, false);
  431. furi_hal_gpio_init(gblink->serin, GpioModeInput, GpioPullUp, GpioSpeedVeryHigh);
  432. /* Set up interrupt on clock pin */
  433. if (gblink->clk == &gpio_ext_pb3) {
  434. /* The clock pin is on a pin that is not safe to set an interrupt
  435. * on, so we do a gross workaround to get an interrupt enabled
  436. * on that pin in a way that can be undone safely later with
  437. * no impact to the shared IRQ.
  438. */
  439. gblink->exti_workaround_handle = exti_workaround(gblink->clk, gblink_clk_isr, gblink);
  440. } else {
  441. /* This may not be needed after NFC refactor */
  442. furi_hal_gpio_remove_int_callback(gblink->clk);
  443. furi_hal_gpio_add_int_callback(gblink->clk, gblink_clk_isr, gblink);
  444. }
  445. /* The above immediately enables the interrupt, we don't want
  446. * that just yet and we want configure to handle it.
  447. */
  448. gblink_int_disable(gblink);
  449. gblink_clk_configure(gblink);
  450. }
  451. void gblink_stop(void *handle)
  452. {
  453. furi_assert(handle);
  454. struct gblink *gblink = handle;
  455. /* If we can acquire the mutex, that means start was never actually
  456. * called. Crash.
  457. * XXX: Probably a bit harsh to just crash, can it gracefully recover
  458. * without too much effort?
  459. */
  460. if (furi_mutex_acquire(gblink->start_mutex, 0) == FuriStatusOk) {
  461. furi_crash();
  462. return;
  463. }
  464. if (gblink->clk == &gpio_ext_pb3) {
  465. /* This handles switching the IVT back and putting the EXTI
  466. * regs and pin regs in a valid state for normal use.
  467. */
  468. exti_workaround_undo(gblink->exti_workaround_handle);
  469. } else {
  470. /* Remove interrupt, set IO to sane state */
  471. furi_hal_gpio_remove_int_callback(gblink->clk);
  472. }
  473. furi_hal_gpio_init_simple(gblink->serin, GpioModeAnalog);
  474. furi_hal_gpio_init_simple(gblink->serout, GpioModeAnalog);
  475. furi_hal_gpio_init_simple(gblink->clk, GpioModeAnalog);
  476. furi_mutex_release(gblink->start_mutex);
  477. }
  478. void gblink_free(void *handle)
  479. {
  480. furi_assert(handle);
  481. struct gblink *gblink = handle;
  482. /* If we cannot acquire the mutex, that means the link was never properly
  483. * stopped. Crash.
  484. * XXX: Can this be gracefully handled?
  485. */
  486. if (furi_mutex_acquire(gblink->start_mutex, 0) != FuriStatusOk) {
  487. furi_crash();
  488. return;
  489. }
  490. furi_mutex_release(gblink->start_mutex);
  491. furi_mutex_free(gblink->start_mutex);
  492. furi_semaphore_free(gblink->transfer_sem);
  493. furi_semaphore_free(gblink->out_byte_sem);
  494. free(gblink);
  495. }