printer_proto.c 4.7 KB

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