camera_suite_view_wifi_camera.cpp 9.0 KB

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