printer_proto.c 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. // SPDX-License-Identifier: BSD-2-Clause
  2. // Copyright (c) 2024 KBEmbedded
  3. #include <furi.h>
  4. #include <gblink/include/gblink.h>
  5. #include <protocols/printer/include/printer_proto.h>
  6. #include "printer_i.h"
  7. /* XXX: Does this make sense to be a message dispatcher rather than calling callbacks?
  8. * In order to keep the stack small for the thread, need to be weary of all calls made from here. */
  9. /* XXX TODO Test using a timer pending callback instead of this */
  10. /* XXX: TODO: Create a more streamlined callback that can simply pass a struct that has
  11. * pointers to data, sz, reason, margins (aka is there more data coming), etc., could even place
  12. * the callback context in there which would allow using the timer pending callback function
  13. */
  14. static int32_t printer_callback_thread(void *context)
  15. {
  16. struct printer_proto *printer = context;
  17. uint32_t flags;
  18. while (1) {
  19. /* XXX: TODO: align flags and enum cb_reason to share them */
  20. flags = furi_thread_flags_wait(THREAD_FLAGS_ALL, FuriFlagWaitAny, FuriWaitForever);
  21. furi_check(!(flags & FuriFlagError));
  22. if (flags & THREAD_FLAGS_EXIT)
  23. break;
  24. if (flags & THREAD_FLAGS_DATA)
  25. printer->callback(printer->cb_context, printer->image, reason_line_xfer);
  26. if (flags & THREAD_FLAGS_PRINT)
  27. printer->callback(printer->cb_context, printer->image, reason_print);
  28. }
  29. return 0;
  30. }
  31. void *printer_alloc(void)
  32. {
  33. struct printer_proto *printer = NULL;
  34. printer = malloc(sizeof(struct printer_proto));
  35. /* Allocate and start callback handling thread */
  36. /* XXX: TODO: The stack can decrease if FURI_LOG calls are removed in callbacks! */
  37. printer->thread = furi_thread_alloc_ex("GBLinkPrinterProtoCB",
  38. 1024,
  39. printer_callback_thread,
  40. printer);
  41. /* Highest priority to ensure it runs ASAP */
  42. furi_thread_set_priority(printer->thread, FuriThreadPriorityHighest);
  43. furi_thread_start(printer->thread);
  44. printer->packet = malloc(sizeof(struct packet));
  45. printer->image = malloc(sizeof(struct gb_image));
  46. printer->gblink_handle = gblink_alloc();
  47. /* Set up some settings for the print protocol. The final send/receive() calls
  48. * may clobber some of these, but that is intentional and they don't need to
  49. * care about some of the other details that are specified here.
  50. */
  51. /* Reported 1.49 ms timeout between bytes, need confirmation */
  52. gblink_timeout_set(printer->gblink_handle, 1490);
  53. gblink_nobyte_set(printer->gblink_handle, 0x00);
  54. return printer;
  55. }
  56. /* TODO: Allow free() without stop, add a way to check if printer_stop has not
  57. * yet been called.
  58. */
  59. void printer_free(void *printer_handle)
  60. {
  61. struct printer_proto *printer = printer_handle;
  62. furi_thread_flags_set(printer->thread, THREAD_FLAGS_EXIT);
  63. furi_thread_join(printer->thread);
  64. furi_thread_free(printer->thread);
  65. gblink_free(printer->gblink_handle);
  66. free(printer->packet);
  67. free(printer->image);
  68. free(printer);
  69. }
  70. void printer_callback_context_set(void *printer_handle, void *context)
  71. {
  72. struct printer_proto *printer = printer_handle;
  73. printer->cb_context = context;
  74. }
  75. void printer_callback_set(void *printer_handle, void (*callback)(void *context, struct gb_image *image, enum cb_reason reason))
  76. {
  77. struct printer_proto *printer = printer_handle;
  78. printer->callback = callback;
  79. }
  80. int printer_pin_set_default(void *printer_handle, gblink_pinouts pinout)
  81. {
  82. struct printer_proto *printer = printer_handle;
  83. return gblink_pin_set_default(printer->gblink_handle, pinout);
  84. }
  85. int printer_pin_set(void *printer_handle, gblink_bus_pins pin, const GpioPin *gpio)
  86. {
  87. struct printer_proto *printer = printer_handle;
  88. return gblink_pin_set(printer->gblink_handle, pin, gpio);
  89. }
  90. const GpioPin *printer_pin_get(void *printer_handle, gblink_bus_pins pin)
  91. {
  92. struct printer_proto *printer = printer_handle;
  93. return gblink_pin_get(printer->gblink_handle, pin);
  94. }
  95. void printer_stop(void *printer_handle)
  96. {
  97. struct printer_proto *printer = printer_handle;
  98. gblink_stop(printer->gblink_handle);
  99. /* TODO: Call the callback one last time with a flag to indicate that the transfer has completely
  100. * ended.
  101. * Receive/send should also have a separate timeout, doesn't need to call stop, but, will
  102. * also retrigger the complete callback. This allows for both the actual process to signal
  103. * there was a gap (I think the gameboy print normally has a "I'm done" marker as well),
  104. * and then the actual application that started the send/receive, can catch a back or other
  105. * nav event, call stop itself, which will then call the callback again with a "we're done here"
  106. * message as well.
  107. */
  108. /* TODO: Figure out what mode we're in, and run stop. Though, it might
  109. * not be necessary to actually to know the mode. We should be able to
  110. * just stop?
  111. */
  112. }