avr_isp_worker.c 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  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. };
  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(void* context) {
  73. furi_hal_usb_unlock();
  74. Cli* cli = furi_record_open(RECORD_CLI);
  75. //close cli
  76. cli_session_close(cli);
  77. //disable callbacks VCP_CDC=0
  78. furi_hal_cdc_set_callbacks(0, NULL, NULL);
  79. //set 2 cdc
  80. furi_check(furi_hal_usb_set_config(&usb_cdc_dual, NULL) == true);
  81. //open cli VCP_CDC=0
  82. cli_session_open(cli, &cli_vcp);
  83. furi_record_close(RECORD_CLI);
  84. furi_hal_cdc_set_callbacks(AVR_ISP_VCP_CDC_CH, (CdcCallbacks*)&cdc_cb, context);
  85. }
  86. static void avr_isp_worker_vcp_cdc_deinit(void) {
  87. //disable callbacks AVR_ISP_VCP_CDC_CH
  88. furi_hal_cdc_set_callbacks(AVR_ISP_VCP_CDC_CH, NULL, NULL);
  89. Cli* cli = furi_record_open(RECORD_CLI);
  90. //close cli
  91. cli_session_close(cli);
  92. furi_hal_usb_unlock();
  93. //set 1 cdc
  94. furi_check(furi_hal_usb_set_config(&usb_cdc_single, NULL) == true);
  95. //open cli VCP_CDC=0
  96. cli_session_open(cli, &cli_vcp);
  97. furi_record_close(RECORD_CLI);
  98. }
  99. //#################################################################################
  100. static int32_t avr_isp_worker_prog_thread(void* context) {
  101. AvrIspProg* prog = context;
  102. FURI_LOG_D(TAG, "AvrIspProgWorker Start");
  103. while(1) {
  104. if(furi_thread_flags_get() & AvrIspWorkerEvtStop) break;
  105. avr_isp_prog_avrisp(prog);
  106. }
  107. FURI_LOG_D(TAG, "AvrIspProgWorker Stop");
  108. return 0;
  109. }
  110. static void avr_isp_worker_prog_tx_data(void* context) {
  111. furi_assert(context);
  112. AvrIspWorker* instance = context;
  113. furi_thread_flags_set(furi_thread_get_id(instance->thread), AvrIspWorkerEvtTx);
  114. }
  115. /** Worker thread
  116. *
  117. * @param context
  118. * @return exit code
  119. */
  120. static int32_t avr_isp_worker_thread(void* context) {
  121. AvrIspWorker* instance = context;
  122. avr_isp_worker_vcp_cdc_init(instance);
  123. /* start PWM on &gpio_ext_pa4 */
  124. furi_hal_pwm_start(FuriHalPwmOutputIdLptim2PA4, 4000000, 50);
  125. AvrIspProg* prog = avr_isp_prog_init();
  126. avr_isp_prog_set_tx_callback(prog, avr_isp_worker_prog_tx_data, instance);
  127. uint8_t buf[AVR_ISP_VCP_UART_RX_BUF_SIZE];
  128. size_t len = 0;
  129. FuriThread* prog_thread =
  130. furi_thread_alloc_ex("AvrIspProgWorker", 1024, avr_isp_worker_prog_thread, prog);
  131. furi_thread_start(prog_thread);
  132. FURI_LOG_D(TAG, "Start");
  133. while(instance->worker_running) {
  134. uint32_t events =
  135. furi_thread_flags_wait(AVR_ISP_WORKER_ALL_EVENTS, FuriFlagWaitAny, FuriWaitForever);
  136. if(events & AvrIspWorkerEvtRx) {
  137. if(avr_isp_prog_spaces_rx(prog) >= AVR_ISP_VCP_CDC_PKT_LEN) {
  138. len = furi_hal_cdc_receive(AVR_ISP_VCP_CDC_CH, buf, AVR_ISP_VCP_CDC_PKT_LEN);
  139. // for(uint8_t i = 0; i < len; i++) {
  140. // FURI_LOG_I(TAG, "--> %X", buf[i]);
  141. // }
  142. avr_isp_prog_rx(prog, buf, len);
  143. } else {
  144. furi_thread_flags_set(furi_thread_get_id(instance->thread), AvrIspWorkerEvtRx);
  145. }
  146. }
  147. if((events & AvrIspWorkerEvtTxCoplete) || (events & AvrIspWorkerEvtTx)) {
  148. len = avr_isp_prog_tx(prog, buf, AVR_ISP_VCP_CDC_PKT_LEN);
  149. // for(uint8_t i = 0; i < len; i++) {
  150. // FURI_LOG_I(TAG, "<-- %X", buf[i]);
  151. // }
  152. if(len > 0) furi_hal_cdc_send(AVR_ISP_VCP_CDC_CH, buf, len);
  153. }
  154. if(events & AvrIspWorkerEvtStop) {
  155. break;
  156. }
  157. if(events & AvrIspWorkerEvtState) {
  158. if(instance->callback)
  159. instance->callback(instance->context, (bool)instance->connect_usb);
  160. }
  161. }
  162. FURI_LOG_D(TAG, "Stop");
  163. furi_thread_flags_set(furi_thread_get_id(prog_thread), AvrIspWorkerEvtStop);
  164. avr_isp_prog_exit(prog);
  165. furi_delay_ms(10);
  166. furi_thread_join(prog_thread);
  167. furi_thread_free(prog_thread);
  168. avr_isp_prog_free(prog);
  169. furi_hal_pwm_stop(FuriHalPwmOutputIdLptim2PA4);
  170. avr_isp_worker_vcp_cdc_deinit();
  171. return 0;
  172. }
  173. AvrIspWorker* avr_isp_worker_alloc(void* context) {
  174. furi_assert(context);
  175. UNUSED(context);
  176. AvrIspWorker* instance = malloc(sizeof(AvrIspWorker));
  177. instance->thread = furi_thread_alloc_ex("AvrIspWorker", 2048, avr_isp_worker_thread, instance);
  178. return instance;
  179. }
  180. void avr_isp_worker_free(AvrIspWorker* instance) {
  181. furi_assert(instance);
  182. furi_check(!instance->worker_running);
  183. furi_thread_free(instance->thread);
  184. free(instance);
  185. }
  186. void avr_isp_worker_set_callback(
  187. AvrIspWorker* instance,
  188. AvrIspWorkerCallback callback,
  189. void* context) {
  190. furi_assert(instance);
  191. instance->callback = callback;
  192. instance->context = context;
  193. }
  194. void avr_isp_worker_start(AvrIspWorker* instance) {
  195. furi_assert(instance);
  196. furi_assert(!instance->worker_running);
  197. instance->worker_running = true;
  198. furi_thread_start(instance->thread);
  199. }
  200. void avr_isp_worker_stop(AvrIspWorker* instance) {
  201. furi_assert(instance);
  202. furi_assert(instance->worker_running);
  203. instance->worker_running = false;
  204. furi_thread_flags_set(furi_thread_get_id(instance->thread), AvrIspWorkerEvtStop);
  205. furi_thread_join(instance->thread);
  206. }
  207. bool avr_isp_worker_is_running(AvrIspWorker* instance) {
  208. furi_assert(instance);
  209. return instance->worker_running;
  210. }