avr_isp_worker.c 7.7 KB

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