avr_isp_worker.c 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. #include "avr_isp_worker.h"
  2. #include "../lib/driver/avr_isp_prog.h"
  3. #include "../lib/driver/avr_isp_prog_cmd.h"
  4. #include "../lib/driver/avr_isp_chip_arr.h"
  5. #include <furi.h>
  6. #include <furi_hal_pwm.h>
  7. #include <cli/cli_vcp.h>
  8. #define TAG "AvrIspWorker"
  9. typedef enum {
  10. AvrIspWorkerEvtStop = (1 << 0),
  11. AvrIspWorkerEvtRx = (1 << 1),
  12. AvrIspWorkerEvtTxCoplete = (1 << 2),
  13. AvrIspWorkerEvtTx = (1 << 3),
  14. AvrIspWorkerEvtState = (1 << 4),
  15. //AvrIspWorkerEvtCfg = (1 << 5),
  16. } AvrIspWorkerEvt;
  17. struct AvrIspWorker {
  18. FuriThread* thread;
  19. volatile bool worker_running;
  20. uint8_t connect_usb;
  21. AvrIspWorkerCallback callback;
  22. void* context;
  23. CliVcp* cli_vcp;
  24. };
  25. #define AVR_ISP_WORKER_PROG_ALL_EVENTS (AvrIspWorkerEvtStop)
  26. #define AVR_ISP_WORKER_ALL_EVENTS \
  27. (AvrIspWorkerEvtTx | AvrIspWorkerEvtTxCoplete | AvrIspWorkerEvtRx | AvrIspWorkerEvtStop | \
  28. AvrIspWorkerEvtState)
  29. //########################/* VCP CDC */#############################################
  30. #include "usb_cdc.h"
  31. #include <furi_hal_usb_cdc.h>
  32. #define AVR_ISP_VCP_CDC_CH 1
  33. #define AVR_ISP_VCP_CDC_PKT_LEN CDC_DATA_SZ
  34. #define AVR_ISP_VCP_UART_RX_BUF_SIZE (AVR_ISP_VCP_CDC_PKT_LEN * 5)
  35. static void vcp_on_cdc_tx_complete(void* context);
  36. static void vcp_on_cdc_rx(void* context);
  37. static void vcp_state_callback(void* context, uint8_t state);
  38. static void vcp_on_cdc_control_line(void* context, uint8_t state);
  39. static void vcp_on_line_config(void* context, struct usb_cdc_line_coding* config);
  40. static const CdcCallbacks cdc_cb = {
  41. vcp_on_cdc_tx_complete,
  42. vcp_on_cdc_rx,
  43. vcp_state_callback,
  44. vcp_on_cdc_control_line,
  45. vcp_on_line_config,
  46. };
  47. /* VCP callbacks */
  48. static void vcp_on_cdc_tx_complete(void* context) {
  49. furi_assert(context);
  50. AvrIspWorker* instance = context;
  51. furi_thread_flags_set(furi_thread_get_id(instance->thread), AvrIspWorkerEvtTxCoplete);
  52. }
  53. static void vcp_on_cdc_rx(void* context) {
  54. furi_assert(context);
  55. AvrIspWorker* instance = context;
  56. furi_thread_flags_set(furi_thread_get_id(instance->thread), AvrIspWorkerEvtRx);
  57. }
  58. static void vcp_state_callback(void* context, uint8_t state) {
  59. UNUSED(context);
  60. AvrIspWorker* instance = context;
  61. instance->connect_usb = state;
  62. furi_thread_flags_set(furi_thread_get_id(instance->thread), AvrIspWorkerEvtState);
  63. }
  64. static void vcp_on_cdc_control_line(void* context, uint8_t state) {
  65. UNUSED(context);
  66. UNUSED(state);
  67. }
  68. static void vcp_on_line_config(void* context, struct usb_cdc_line_coding* config) {
  69. UNUSED(context);
  70. UNUSED(config);
  71. }
  72. static void avr_isp_worker_vcp_cdc_init(AvrIspWorker* worker) {
  73. worker->cli_vcp = furi_record_open(RECORD_CLI_VCP);
  74. cli_vcp_disable(worker->cli_vcp);
  75. furi_check(furi_hal_usb_set_config(&usb_cdc_dual, NULL) == true);
  76. furi_hal_usb_lock();
  77. cli_vcp_enable(worker->cli_vcp);
  78. furi_hal_cdc_set_callbacks(AVR_ISP_VCP_CDC_CH, (CdcCallbacks*)&cdc_cb, worker);
  79. }
  80. static void avr_isp_worker_vcp_cdc_deinit(AvrIspWorker* worker) {
  81. furi_hal_cdc_set_callbacks(AVR_ISP_VCP_CDC_CH, NULL, NULL);
  82. cli_vcp_disable(worker->cli_vcp);
  83. furi_hal_usb_unlock();
  84. furi_check(furi_hal_usb_set_config(&usb_cdc_single, NULL) == true);
  85. cli_vcp_enable(worker->cli_vcp);
  86. furi_record_close(RECORD_CLI_VCP);
  87. }
  88. //#################################################################################
  89. static int32_t avr_isp_worker_prog_thread(void* context) {
  90. AvrIspProg* prog = context;
  91. FURI_LOG_D(TAG, "AvrIspProgWorker Start");
  92. while(1) {
  93. if(furi_thread_flags_get() & AvrIspWorkerEvtStop) break;
  94. avr_isp_prog_avrisp(prog);
  95. }
  96. FURI_LOG_D(TAG, "AvrIspProgWorker Stop");
  97. return 0;
  98. }
  99. static void avr_isp_worker_prog_tx_data(void* context) {
  100. furi_assert(context);
  101. AvrIspWorker* instance = context;
  102. furi_thread_flags_set(furi_thread_get_id(instance->thread), AvrIspWorkerEvtTx);
  103. }
  104. /** Worker thread
  105. *
  106. * @param context
  107. * @return exit code
  108. */
  109. static int32_t avr_isp_worker_thread(void* context) {
  110. AvrIspWorker* instance = context;
  111. avr_isp_worker_vcp_cdc_init(instance);
  112. /* start PWM on &gpio_ext_pa4 */
  113. furi_hal_pwm_start(FuriHalPwmOutputIdLptim2PA4, 4000000, 50);
  114. AvrIspProg* prog = avr_isp_prog_init();
  115. avr_isp_prog_set_tx_callback(prog, avr_isp_worker_prog_tx_data, instance);
  116. uint8_t buf[AVR_ISP_VCP_UART_RX_BUF_SIZE];
  117. size_t len = 0;
  118. FuriThread* prog_thread =
  119. furi_thread_alloc_ex("AvrIspProgWorker", 1024, avr_isp_worker_prog_thread, prog);
  120. furi_thread_start(prog_thread);
  121. FURI_LOG_D(TAG, "Start");
  122. while(instance->worker_running) {
  123. uint32_t events =
  124. furi_thread_flags_wait(AVR_ISP_WORKER_ALL_EVENTS, FuriFlagWaitAny, FuriWaitForever);
  125. if(events & AvrIspWorkerEvtRx) {
  126. if(avr_isp_prog_spaces_rx(prog) >= AVR_ISP_VCP_CDC_PKT_LEN) {
  127. len = furi_hal_cdc_receive(AVR_ISP_VCP_CDC_CH, buf, AVR_ISP_VCP_CDC_PKT_LEN);
  128. // for(uint8_t i = 0; i < len; i++) {
  129. // FURI_LOG_I(TAG, "--> %X", buf[i]);
  130. // }
  131. avr_isp_prog_rx(prog, buf, len);
  132. } else {
  133. furi_thread_flags_set(furi_thread_get_id(instance->thread), AvrIspWorkerEvtRx);
  134. }
  135. }
  136. if((events & AvrIspWorkerEvtTxCoplete) || (events & AvrIspWorkerEvtTx)) {
  137. len = avr_isp_prog_tx(prog, buf, AVR_ISP_VCP_CDC_PKT_LEN);
  138. // for(uint8_t i = 0; i < len; i++) {
  139. // FURI_LOG_I(TAG, "<-- %X", buf[i]);
  140. // }
  141. if(len > 0) furi_hal_cdc_send(AVR_ISP_VCP_CDC_CH, buf, len);
  142. }
  143. if(events & AvrIspWorkerEvtStop) {
  144. break;
  145. }
  146. if(events & AvrIspWorkerEvtState) {
  147. if(instance->callback)
  148. instance->callback(instance->context, (bool)instance->connect_usb);
  149. }
  150. }
  151. FURI_LOG_D(TAG, "Stop");
  152. furi_thread_flags_set(furi_thread_get_id(prog_thread), AvrIspWorkerEvtStop);
  153. avr_isp_prog_exit(prog);
  154. furi_delay_ms(10);
  155. furi_thread_join(prog_thread);
  156. furi_thread_free(prog_thread);
  157. avr_isp_prog_free(prog);
  158. furi_hal_pwm_stop(FuriHalPwmOutputIdLptim2PA4);
  159. avr_isp_worker_vcp_cdc_deinit(instance);
  160. return 0;
  161. }
  162. AvrIspWorker* avr_isp_worker_alloc(void* context) {
  163. furi_assert(context);
  164. UNUSED(context);
  165. AvrIspWorker* instance = malloc(sizeof(AvrIspWorker));
  166. instance->thread = furi_thread_alloc_ex("AvrIspWorker", 2048, avr_isp_worker_thread, instance);
  167. return instance;
  168. }
  169. void avr_isp_worker_free(AvrIspWorker* instance) {
  170. furi_assert(instance);
  171. furi_check(!instance->worker_running);
  172. furi_thread_free(instance->thread);
  173. free(instance);
  174. }
  175. void avr_isp_worker_set_callback(
  176. AvrIspWorker* instance,
  177. AvrIspWorkerCallback callback,
  178. void* context) {
  179. furi_assert(instance);
  180. instance->callback = callback;
  181. instance->context = context;
  182. }
  183. void avr_isp_worker_start(AvrIspWorker* instance) {
  184. furi_assert(instance);
  185. furi_assert(!instance->worker_running);
  186. instance->worker_running = true;
  187. furi_thread_start(instance->thread);
  188. }
  189. void avr_isp_worker_stop(AvrIspWorker* instance) {
  190. furi_assert(instance);
  191. furi_assert(instance->worker_running);
  192. instance->worker_running = false;
  193. furi_thread_flags_set(furi_thread_get_id(instance->thread), AvrIspWorkerEvtStop);
  194. furi_thread_join(instance->thread);
  195. }
  196. bool avr_isp_worker_is_running(AvrIspWorker* instance) {
  197. furi_assert(instance);
  198. return instance->worker_running;
  199. }