printer_receive.c 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. // SPDX-License-Identifier: BSD-2-Clause
  2. // Copyright (c) 2024 KBEmbedded
  3. #include <stdint.h>
  4. #include <furi.h>
  5. #include <gblink/include/gblink.h>
  6. #include "printer_i.h"
  7. #define TAG "printer_receive"
  8. static void printer_reset(struct printer_proto *printer)
  9. {
  10. /* Clear out the current packet data */
  11. memset(printer->packet, '\0', sizeof(struct packet));
  12. printer->image->data_sz = 0;
  13. /* This is technically redundant, done for completeness */
  14. printer->packet->state = START_L;
  15. /* Packet timeout start */
  16. printer->packet->time = DWT->CYCCNT;
  17. }
  18. static void byte_callback(void *context, uint8_t val)
  19. {
  20. struct printer_proto *printer = context;
  21. struct packet *packet = printer->packet;
  22. const uint32_t time_ticks = furi_hal_cortex_instructions_per_microsecond() * HARD_TIMEOUT_US;
  23. uint8_t data_out = 0x00;
  24. if ((DWT->CYCCNT - packet->time) > time_ticks)
  25. printer_reset(printer);
  26. if ((DWT->CYCCNT - packet->time) > furi_hal_cortex_instructions_per_microsecond() * SOFT_TIMEOUT_US)
  27. packet->state = START_L;
  28. /* Packet timeout restart */
  29. packet->time = DWT->CYCCNT;
  30. /* TODO: flash led? */
  31. switch (packet->state) {
  32. case START_L:
  33. if (val == START_L_BYTE) {
  34. packet->state = START_H;
  35. packet->zero_counter = 0;
  36. }
  37. if (val == 0x00) {
  38. packet->zero_counter++;
  39. if (packet->zero_counter == 16)
  40. printer_reset(printer);
  41. }
  42. break;
  43. case START_H:
  44. if (val == START_H_BYTE)
  45. packet->state = COMMAND;
  46. else
  47. packet->state = START_L;
  48. break;
  49. case COMMAND:
  50. packet->cmd = val;
  51. packet->state = COMPRESS;
  52. packet->cksum_calc += val;
  53. break;
  54. case COMPRESS:
  55. packet->cksum_calc += val;
  56. packet->state = LEN_L;
  57. if (val) {
  58. FURI_LOG_E(TAG, "Compression not supported!");
  59. packet->status |= STATUS_PKT_ERR;
  60. }
  61. break;
  62. case LEN_L:
  63. packet->cksum_calc += val;
  64. packet->state = LEN_H;
  65. packet->len = (val & 0xff);
  66. break;
  67. case LEN_H:
  68. packet->cksum_calc += val;
  69. packet->len |= ((val & 0xff) << 8);
  70. /* Override length for a TRANSFER */
  71. if (packet->cmd == CMD_TRANSFER)
  72. packet->len = TRANSFER_SZ;
  73. if (packet->len) {
  74. packet->state = DATA;
  75. } else {
  76. packet->state = CKSUM_L;
  77. }
  78. break;
  79. case DATA:
  80. packet->cksum_calc += val;
  81. packet->line_buf[packet->line_buf_sz] = val;
  82. packet->line_buf_sz++;
  83. if (packet->line_buf_sz == packet->len)
  84. packet->state = CKSUM_L;
  85. break;
  86. case CKSUM_L:
  87. packet->state = CKSUM_H;
  88. if ((packet->cksum_calc & 0xff) != val)
  89. packet->status |= STATUS_CKSUM_ERR;
  90. break;
  91. case CKSUM_H:
  92. packet->state = ALIVE;
  93. if (((packet->cksum_calc >> 8) & 0xff) != val)
  94. packet->status |= STATUS_CKSUM_ERR;
  95. // TRANSFER does not set checksum bytes
  96. if (packet->cmd == CMD_TRANSFER)
  97. packet->status &= ~STATUS_CKSUM_ERR;
  98. data_out = ALIVE_BYTE;
  99. break;
  100. case ALIVE:
  101. packet->state = STATUS;
  102. data_out = packet->status;
  103. break;
  104. case STATUS:
  105. packet->state = START_L;
  106. switch (packet->cmd) {
  107. case CMD_INIT:
  108. printer_reset(printer);
  109. break;
  110. case CMD_DATA:
  111. if (printer->image->data_sz < PRINT_FULL_SZ) {
  112. if ((printer->image->data_sz + packet->len) <= PRINT_FULL_SZ) {
  113. memcpy((printer->image->data)+printer->image->data_sz, packet->line_buf, packet->len);
  114. printer->image->data_sz += packet->len;
  115. } else {
  116. memcpy((printer->image->data)+printer->image->data_sz, packet->line_buf, ((printer->image->data_sz + packet->len)) - PRINT_FULL_SZ);
  117. printer->image->data_sz += (PRINT_FULL_SZ - (printer->image->data_sz + packet->len));
  118. furi_assert(printer->image->data_sz <= PRINT_FULL_SZ);
  119. }
  120. }
  121. /* Any time data is written to the buffer, READY is set */
  122. packet->status |= STATUS_READY;
  123. furi_thread_flags_set(printer->thread, THREAD_FLAGS_DATA);
  124. break;
  125. case CMD_TRANSFER:
  126. /* XXX: TODO: Check to see if we're still printing when getting
  127. * a transfer command. If so, then we have failed to beat the clock.
  128. */
  129. case CMD_PRINT:
  130. /* TODO: Be able to memcpy these */
  131. printer->image->num_sheets = packet->line_buf[0];
  132. printer->image->margins = packet->line_buf[1];
  133. printer->image->palette = packet->line_buf[2];
  134. printer->image->exposure = packet->line_buf[3];
  135. packet->status &= ~STATUS_READY;
  136. packet->status |= (STATUS_PRINTING | STATUS_FULL);
  137. furi_thread_flags_set(printer->thread, THREAD_FLAGS_PRINT);
  138. break;
  139. case CMD_STATUS:
  140. /* READY cleared on status request */
  141. packet->status &= ~STATUS_READY;
  142. if ((packet->status & STATUS_PRINTING) && packet->print_complete) {
  143. packet->status &= ~(STATUS_PRINTING);
  144. packet->print_complete = false;
  145. furi_thread_flags_set(printer->thread, THREAD_FLAGS_COMPLETE);
  146. }
  147. }
  148. packet->line_buf_sz = 0;
  149. packet->cksum_calc = 0;
  150. /* XXX: TODO: if the command had something we need to do, do it here. */
  151. /* done! flush our buffers, deal with any status changes like
  152. * not printing -> printing -> not printing, etc.
  153. */
  154. /* Do a callback here?
  155. * if so, I guess we should wait for callback completion before accepting more line_buf?
  156. * but that means the callback is in an interrupt context, which, is probably okay?
  157. */
  158. /* XXX: TODO: NOTE: FIXME:
  159. * all of the notes..
  160. * This module needs to maintain the whole buffer, but it can be safely assumed that the buffer
  161. * will never exceed 20x18 tiles (no clue how many bytes) as that is the max the printer can
  162. * take on in a single print. Printing mulitples needs a print, and then a second print with
  163. * no margin. So the margins are important and need to be passed to the final application,
  164. * SOMEHOW.
  165. *
  166. * More imporatntly, is the completed callback NEEDS to have a return value. This allows
  167. * the end application to take that whole panel, however its laid out, and do whatever
  168. * it wants to do with it. Write it to a file, convert, etc., etc., so that this module
  169. * will forever return that it is printing until the callback returns true.
  170. *
  171. * Once we call the callback and it shows a true, then we can be sure the higher module
  172. * is done with the buffer, and we can tell the host that yes, its done, you can continue
  173. * if you want.
  174. */
  175. /* XXX: On TRANSFER, there is no checking of status, it is only two packets in total.
  176. * I can assume that if we delay a bit in moving the buffer around that should be okay
  177. * but we probably don't want to wait too long.
  178. * Upon testing, transfer seems to doesn't
  179. */
  180. break;
  181. default:
  182. FURI_LOG_E(TAG, "unknown status!");
  183. break;
  184. }
  185. /* transfer next byte */
  186. gblink_transfer(printer->gblink_handle, data_out);
  187. }
  188. void printer_receive_start(void *printer_handle)
  189. {
  190. struct printer_proto *printer = printer_handle;
  191. /* Set up defaults the receive path needs */
  192. gblink_callback_set(printer->gblink_handle, byte_callback, printer);
  193. gblink_clk_source_set(printer->gblink_handle, GBLINK_CLK_EXT);
  194. printer_reset(printer);
  195. gblink_start(printer->gblink_handle);
  196. }
  197. void printer_receive_print_complete(void *printer_handle)
  198. {
  199. struct printer_proto *printer = printer_handle;
  200. printer->packet->print_complete = true;
  201. }