camera_suite_view_wifi_camera.c 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. #include "../camera_suite.h"
  2. #include "camera_suite_view_wifi_camera.h"
  3. static void camera_suite_view_wifi_camera_draw(Canvas* canvas, void* wifi_model) {
  4. furi_assert(canvas);
  5. furi_assert(wifi_model);
  6. CameraSuiteViewWiFiCameraModel* model = wifi_model;
  7. canvas_clear(canvas);
  8. canvas_set_color(canvas, ColorBlack);
  9. canvas_set_font(canvas, FontSecondary);
  10. canvas_draw_frame(canvas, 0, 0, FRAME_WIDTH, FRAME_HEIGHT);
  11. canvas_draw_str_aligned(canvas, 3, 3, AlignLeft, AlignTop, "Starting WiFi Stream at:");
  12. // Draw log from camera.
  13. canvas_draw_str_aligned(canvas, 3, 13, AlignLeft, AlignTop, furi_string_get_cstr(model->log));
  14. }
  15. static int32_t camera_suite_wifi_camera_worker(void* wifi_view_instance) {
  16. furi_assert(wifi_view_instance);
  17. CameraSuiteViewWiFiCamera* instance = wifi_view_instance;
  18. while(1) {
  19. uint32_t events =
  20. furi_thread_flags_wait(WORKER_EVENTS_MASK, FuriFlagWaitAny, FuriWaitForever);
  21. // Check if an error occurred.
  22. furi_check((events & FuriFlagError) == 0);
  23. // Check if the thread should stop.
  24. if(events & WorkerEventStop) {
  25. break;
  26. } else if(events & WorkerEventRx) {
  27. size_t length = 0;
  28. do {
  29. size_t buffer_size = 320;
  30. uint8_t data[buffer_size];
  31. length =
  32. furi_stream_buffer_receive(instance->wifi_rx_stream, data, buffer_size, 0);
  33. if(length > 0) {
  34. data[length] = '\0';
  35. with_view_model(
  36. instance->view,
  37. CameraSuiteViewWiFiCameraModel * model,
  38. {
  39. furi_string_cat_printf(model->log, "%s", data);
  40. // Truncate if too long.
  41. model->log_strlen += length;
  42. if(model->log_strlen >= 4096 - 1) {
  43. furi_string_right(model->log, model->log_strlen / 2);
  44. model->log_strlen = furi_string_size(model->log) + length;
  45. }
  46. },
  47. true);
  48. }
  49. } while(length > 0);
  50. with_view_model(
  51. instance->view, CameraSuiteViewWiFiCameraModel * model, { UNUSED(model); }, true);
  52. }
  53. }
  54. return 0;
  55. }
  56. static bool
  57. camera_suite_view_wifi_camera_input(InputEvent* input_event, void* wifi_view_instance) {
  58. furi_assert(wifi_view_instance);
  59. furi_assert(input_event);
  60. CameraSuiteViewWiFiCamera* instance = wifi_view_instance;
  61. uint8_t data[1];
  62. if(input_event->type == InputTypeRelease) {
  63. switch(input_event->key) {
  64. default:
  65. with_view_model(
  66. instance->view,
  67. CameraSuiteViewWiFiCameraModel * model,
  68. {
  69. UNUSED(model);
  70. // Stop all sounds, reset the LED.
  71. camera_suite_play_bad_bump(instance->context);
  72. camera_suite_stop_all_sound(instance->context);
  73. camera_suite_led_set_rgb(instance->context, 0, 0, 0);
  74. },
  75. true);
  76. break;
  77. }
  78. } else if(input_event->type == InputTypePress) {
  79. switch(input_event->key) {
  80. case InputKeyBack: {
  81. with_view_model(
  82. instance->view,
  83. CameraSuiteViewWiFiCameraModel * model,
  84. {
  85. UNUSED(model);
  86. // Stop camera WiFi stream.
  87. data[0] = 'w';
  88. furi_hal_serial_tx(instance->wifi_serial_handle, data, 1);
  89. furi_delay_ms(50);
  90. // Go back to the main menu.
  91. instance->callback(CameraSuiteCustomEventSceneCameraBack, instance->context);
  92. },
  93. true);
  94. break;
  95. }
  96. case InputKeyLeft:
  97. case InputKeyRight:
  98. case InputKeyUp:
  99. case InputKeyDown:
  100. case InputKeyOk:
  101. case InputKeyMAX:
  102. default: {
  103. break;
  104. }
  105. }
  106. }
  107. return false;
  108. }
  109. static void camera_suite_view_wifi_camera_exit(void* wifi_view_instance) {
  110. UNUSED(wifi_view_instance);
  111. }
  112. static void camera_suite_view_wifi_camera_model_init(CameraSuiteViewWiFiCameraModel* const model) {
  113. model->log = furi_string_alloc();
  114. furi_string_reserve(model->log, 4096);
  115. }
  116. static void camera_suite_view_wifi_camera_enter(void* wifi_view_instance) {
  117. furi_assert(wifi_view_instance);
  118. CameraSuiteViewWiFiCamera* instance = wifi_view_instance;
  119. // Start wifi camera stream.
  120. uint8_t data[1] = {'W'};
  121. furi_hal_serial_tx(instance->wifi_serial_handle, data, 1);
  122. furi_delay_ms(50);
  123. with_view_model(
  124. instance->view,
  125. CameraSuiteViewWiFiCameraModel * model,
  126. { camera_suite_view_wifi_camera_model_init(model); },
  127. true);
  128. }
  129. static void wifi_camera_on_irq_cb(
  130. FuriHalSerialHandle* handle,
  131. FuriHalSerialRxEvent event,
  132. void* wifi_view_instance) {
  133. furi_assert(handle);
  134. furi_assert(wifi_view_instance);
  135. CameraSuiteViewWiFiCamera* instance = wifi_view_instance;
  136. if(event == FuriHalSerialRxEventData) {
  137. uint8_t data = furi_hal_serial_async_rx(handle);
  138. furi_stream_buffer_send(instance->wifi_rx_stream, &data, 1, 0);
  139. furi_thread_flags_set(furi_thread_get_id(instance->wifi_worker_thread), WorkerEventRx);
  140. }
  141. }
  142. CameraSuiteViewWiFiCamera* camera_suite_view_wifi_camera_alloc() {
  143. // Allocate memory for the instance
  144. CameraSuiteViewWiFiCamera* instance = malloc(sizeof(CameraSuiteViewWiFiCamera));
  145. // Allocate the view object
  146. instance->view = view_alloc();
  147. // Allocate model
  148. view_allocate_model(
  149. instance->view, ViewModelTypeLocking, sizeof(CameraSuiteViewWiFiCameraModel));
  150. // Set context for the view (furi_assert crashes in events without this)
  151. view_set_context(instance->view, instance);
  152. // Allocate a stream buffer
  153. instance->wifi_rx_stream = furi_stream_buffer_alloc(1024, 1);
  154. // Allocate a thread for this camera to run on.
  155. // @NOTICE: THIS SEEMINGLY BREAKS THE CAMERA VIEW THREAD...
  156. FuriThread* thread = furi_thread_alloc_ex(
  157. "Camera_Suite_WiFi_Rx_Thread", 1024, camera_suite_wifi_camera_worker, instance);
  158. instance->wifi_worker_thread = thread;
  159. furi_thread_start(instance->wifi_worker_thread);
  160. // Set up UART thread.
  161. instance->wifi_serial_handle = furi_hal_serial_control_acquire(UART_CH);
  162. furi_check(instance->wifi_serial_handle);
  163. furi_hal_serial_init(instance->wifi_serial_handle, 230400);
  164. // Enable UART1 and set the IRQ callback.
  165. furi_hal_serial_async_rx_start(
  166. instance->wifi_serial_handle, wifi_camera_on_irq_cb, instance, false);
  167. // Set draw callback
  168. view_set_draw_callback(instance->view, (ViewDrawCallback)camera_suite_view_wifi_camera_draw);
  169. // Set input callback
  170. view_set_input_callback(instance->view, camera_suite_view_wifi_camera_input);
  171. // Set enter callback
  172. view_set_enter_callback(instance->view, camera_suite_view_wifi_camera_enter);
  173. // Set exit callback
  174. view_set_exit_callback(instance->view, camera_suite_view_wifi_camera_exit);
  175. with_view_model(
  176. instance->view,
  177. CameraSuiteViewWiFiCameraModel * model,
  178. { camera_suite_view_wifi_camera_model_init(model); },
  179. true);
  180. return instance;
  181. }
  182. void camera_suite_view_wifi_camera_free(CameraSuiteViewWiFiCamera* instance) {
  183. furi_assert(instance);
  184. // Free the worker thread.
  185. furi_thread_flags_set(furi_thread_get_id(instance->wifi_worker_thread), WorkerEventStop);
  186. furi_thread_join(instance->wifi_worker_thread);
  187. furi_thread_free(instance->wifi_worker_thread);
  188. // Free the allocated stream buffer.
  189. furi_stream_buffer_free(instance->wifi_rx_stream);
  190. // Deinitialize the UART.
  191. furi_hal_serial_deinit(instance->wifi_serial_handle);
  192. furi_hal_serial_control_release(instance->wifi_serial_handle);
  193. with_view_model(
  194. instance->view,
  195. CameraSuiteViewWiFiCameraModel * model,
  196. { furi_string_free(model->log); },
  197. true);
  198. view_free(instance->view);
  199. free(instance);
  200. }
  201. View* camera_suite_view_wifi_camera_get_view(CameraSuiteViewWiFiCamera* instance) {
  202. furi_assert(instance);
  203. return instance->view;
  204. }
  205. void camera_suite_view_wifi_camera_set_callback(
  206. CameraSuiteViewWiFiCamera* instance,
  207. CameraSuiteViewWiFiCameraCallback callback,
  208. void* context) {
  209. furi_assert(instance);
  210. furi_assert(callback);
  211. instance->callback = callback;
  212. instance->context = context;
  213. }