main_view.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538
  1. #include "main_view.h"
  2. #include <math.h>
  3. #include <furi.h>
  4. #include <furi_hal.h>
  5. #include <gui/elements.h>
  6. #include "../../lightmeter.h"
  7. #include "../../lightmeter_helper.h"
  8. #define WORKER_TAG "Main View"
  9. const int iso_numbers[] = {
  10. [ISO_6] = 6,
  11. [ISO_12] = 12,
  12. [ISO_25] = 25,
  13. [ISO_50] = 50,
  14. [ISO_100] = 100,
  15. [ISO_200] = 200,
  16. [ISO_400] = 400,
  17. [ISO_800] = 800,
  18. [ISO_1600] = 1600,
  19. [ISO_3200] = 3200,
  20. [ISO_6400] = 6400,
  21. [ISO_12800] = 12800,
  22. [ISO_25600] = 25600,
  23. [ISO_51200] = 51200,
  24. [ISO_102400] = 102400,
  25. };
  26. static const int nd_numbers[] = {
  27. [ND_0] = 0,
  28. [ND_2] = 2,
  29. [ND_4] = 4,
  30. [ND_8] = 8,
  31. [ND_16] = 16,
  32. [ND_32] = 32,
  33. [ND_64] = 64,
  34. [ND_128] = 128,
  35. [ND_256] = 256,
  36. [ND_512] = 512,
  37. [ND_1024] = 1024,
  38. [ND_2048] = 2048,
  39. [ND_4096] = 4096,
  40. };
  41. const float aperture_numbers[] = {
  42. [AP_1] = 1.0,
  43. [AP_1_4] = 1.4,
  44. [AP_2] = 2.0,
  45. [AP_2_8] = 2.8,
  46. [AP_4] = 4.0,
  47. [AP_5_6] = 5.6,
  48. [AP_8] = 8,
  49. [AP_11] = 11,
  50. [AP_16] = 16,
  51. [AP_22] = 22,
  52. [AP_32] = 32,
  53. [AP_45] = 45,
  54. [AP_64] = 64,
  55. [AP_90] = 90,
  56. [AP_128] = 128,
  57. };
  58. const float speed_numbers[] = {
  59. [SPEED_8000] = 1.0 / 8000, [SPEED_4000] = 1.0 / 4000, [SPEED_2000] = 1.0 / 2000,
  60. [SPEED_1000] = 1.0 / 1000, [SPEED_500] = 1.0 / 500, [SPEED_250] = 1.0 / 250,
  61. [SPEED_125] = 1.0 / 125, [SPEED_60] = 1.0 / 60, [SPEED_48] = 1.0 / 48,
  62. [SPEED_30] = 1.0 / 30, [SPEED_15] = 1.0 / 15, [SPEED_8] = 1.0 / 8,
  63. [SPEED_4] = 1.0 / 4, [SPEED_2] = 1.0 / 2, [SPEED_1S] = 1.0,
  64. [SPEED_2S] = 2.0, [SPEED_4S] = 4.0, [SPEED_8S] = 8.0,
  65. [SPEED_15S] = 15.0, [SPEED_30S] = 30.0,
  66. };
  67. struct MainView {
  68. View* view;
  69. LightMeterMainViewButtonCallback cb_left;
  70. LightMeterMainViewButtonCallback cb_right;
  71. void* cb_context;
  72. };
  73. void lightmeter_main_view_set_left_callback(
  74. MainView* lightmeter_main_view,
  75. LightMeterMainViewButtonCallback callback,
  76. void* context) {
  77. with_view_model(
  78. lightmeter_main_view->view,
  79. MainViewModel * model,
  80. {
  81. UNUSED(model);
  82. lightmeter_main_view->cb_left = callback;
  83. lightmeter_main_view->cb_context = context;
  84. },
  85. true);
  86. }
  87. void lightmeter_main_view_set_right_callback(
  88. MainView* lightmeter_main_view,
  89. LightMeterMainViewButtonCallback callback,
  90. void* context) {
  91. with_view_model(
  92. lightmeter_main_view->view,
  93. MainViewModel * model,
  94. {
  95. UNUSED(model);
  96. lightmeter_main_view->cb_right = callback;
  97. lightmeter_main_view->cb_context = context;
  98. },
  99. true);
  100. }
  101. static void main_view_draw_callback(Canvas* canvas, void* context) {
  102. furi_assert(context);
  103. MainViewModel* model = context;
  104. canvas_clear(canvas);
  105. // draw button
  106. canvas_set_font(canvas, FontSecondary);
  107. elements_button_left(canvas, "Config");
  108. if(!model->lux_only) {
  109. // top row
  110. draw_top_row(canvas, model);
  111. // add f, T values
  112. canvas_set_font(canvas, FontBigNumbers);
  113. // draw f icon and number
  114. canvas_draw_icon(canvas, 15, 17, &I_f_10x14);
  115. draw_aperture(canvas, model);
  116. // draw T icon and number
  117. canvas_draw_icon(canvas, 15, 34, &I_T_10x14);
  118. draw_speed(canvas, model);
  119. // draw ND number
  120. draw_nd_number(canvas, model);
  121. // draw EV number
  122. canvas_set_font(canvas, FontSecondary);
  123. draw_EV_number(canvas, model);
  124. // draw mode indicator
  125. draw_mode_indicator(canvas, model);
  126. } else {
  127. elements_button_right(canvas, "Reset");
  128. draw_lux_only_mode(canvas, model);
  129. }
  130. }
  131. static void main_view_process(MainView* main_view, InputEvent* event) {
  132. with_view_model(
  133. main_view->view,
  134. MainViewModel * model,
  135. {
  136. if(event->type == InputTypePress) {
  137. if(event->key == InputKeyUp) {
  138. switch(model->current_mode) {
  139. case FIXED_APERTURE:
  140. if(model->aperture < AP_NUM - 1) model->aperture++;
  141. break;
  142. case FIXED_SPEED:
  143. if(model->speed < SPEED_NUM - 1) model->speed++;
  144. break;
  145. default:
  146. break;
  147. }
  148. } else if(event->key == InputKeyDown) {
  149. switch(model->current_mode) {
  150. case FIXED_APERTURE:
  151. if(model->aperture > 0) model->aperture--;
  152. break;
  153. case FIXED_SPEED:
  154. if(model->speed > 0) model->speed--;
  155. break;
  156. default:
  157. break;
  158. }
  159. } else if(event->key == InputKeyOk) {
  160. switch(model->current_mode) {
  161. case FIXED_SPEED:
  162. model->current_mode = FIXED_APERTURE;
  163. break;
  164. case FIXED_APERTURE:
  165. model->current_mode = FIXED_SPEED;
  166. break;
  167. default:
  168. break;
  169. }
  170. }
  171. }
  172. },
  173. true);
  174. }
  175. static bool main_view_input_callback(InputEvent* event, void* context) {
  176. furi_assert(context);
  177. MainView* main_view = context;
  178. bool consumed = false;
  179. if(event->type == InputTypeShort && event->key == InputKeyLeft) {
  180. if(main_view->cb_left) {
  181. main_view->cb_left(main_view->cb_context);
  182. }
  183. consumed = true;
  184. } else if(event->type == InputTypeShort && event->key == InputKeyRight) {
  185. if(main_view->cb_right) {
  186. main_view->cb_right(main_view->cb_context);
  187. }
  188. consumed = true;
  189. } else if(event->type == InputTypeShort && event->key == InputKeyBack) {
  190. } else {
  191. main_view_process(main_view, event);
  192. consumed = true;
  193. }
  194. return consumed;
  195. }
  196. MainView* main_view_alloc() {
  197. MainView* main_view = malloc(sizeof(MainView));
  198. main_view->view = view_alloc();
  199. view_set_context(main_view->view, main_view);
  200. view_allocate_model(main_view->view, ViewModelTypeLocking, sizeof(MainViewModel));
  201. view_set_draw_callback(main_view->view, main_view_draw_callback);
  202. view_set_input_callback(main_view->view, main_view_input_callback);
  203. return main_view;
  204. }
  205. void main_view_free(MainView* main_view) {
  206. furi_assert(main_view);
  207. view_free(main_view->view);
  208. free(main_view);
  209. }
  210. View* main_view_get_view(MainView* main_view) {
  211. furi_assert(main_view);
  212. return main_view->view;
  213. }
  214. void main_view_set_lux(MainView* main_view, float val) {
  215. furi_assert(main_view);
  216. with_view_model(
  217. main_view->view,
  218. MainViewModel * model,
  219. {
  220. model->lux = val;
  221. model->peakLux = fmax(model->peakLux, val);
  222. model->luxHistogram[model->luxHistogramIndex++] = val;
  223. model->luxHistogramIndex %= LUX_HISTORGRAM_LENGTH;
  224. },
  225. true);
  226. }
  227. void main_view_reset_lux(MainView* main_view) {
  228. furi_assert(main_view);
  229. with_view_model(main_view->view, MainViewModel * model, { model->peakLux = 0; }, true);
  230. }
  231. void main_view_set_EV(MainView* main_view, float val) {
  232. furi_assert(main_view);
  233. with_view_model(main_view->view, MainViewModel * model, { model->EV = val; }, true);
  234. }
  235. void main_view_set_response(MainView* main_view, bool val) {
  236. furi_assert(main_view);
  237. with_view_model(main_view->view, MainViewModel * model, { model->response = val; }, true);
  238. }
  239. void main_view_set_iso(MainView* main_view, int iso) {
  240. furi_assert(main_view);
  241. with_view_model(main_view->view, MainViewModel * model, { model->iso = iso; }, true);
  242. }
  243. void main_view_set_nd(MainView* main_view, int nd) {
  244. furi_assert(main_view);
  245. with_view_model(main_view->view, MainViewModel * model, { model->nd = nd; }, true);
  246. }
  247. void main_view_set_aperture(MainView* main_view, int aperture) {
  248. furi_assert(main_view);
  249. with_view_model(main_view->view, MainViewModel * model, { model->aperture = aperture; }, true);
  250. }
  251. void main_view_set_speed(MainView* main_view, int speed) {
  252. furi_assert(main_view);
  253. with_view_model(main_view->view, MainViewModel * model, { model->speed = speed; }, true);
  254. }
  255. void main_view_set_dome(MainView* main_view, bool dome) {
  256. furi_assert(main_view);
  257. with_view_model(main_view->view, MainViewModel * model, { model->dome = dome; }, true);
  258. }
  259. void main_view_set_lux_only(MainView* main_view, bool lux_only) {
  260. furi_assert(main_view);
  261. with_view_model(main_view->view, MainViewModel * model, { model->lux_only = lux_only; }, true);
  262. }
  263. void main_view_set_measurement_resolution(MainView* main_view, int measurement_resolution) {
  264. furi_assert(main_view);
  265. with_view_model(
  266. main_view->view,
  267. MainViewModel * model,
  268. { model->measurement_resolution = measurement_resolution; },
  269. true);
  270. }
  271. void main_view_set_device_addr(MainView* main_view, int device_addr) {
  272. furi_assert(main_view);
  273. with_view_model(
  274. main_view->view, MainViewModel * model, { model->device_addr = device_addr; }, true);
  275. }
  276. void main_view_set_sensor_type(MainView* main_view, int sensor_type) {
  277. furi_assert(main_view);
  278. with_view_model(
  279. main_view->view, MainViewModel * model, { model->sensor_type = sensor_type; }, true);
  280. }
  281. bool main_view_get_dome(MainView* main_view) {
  282. furi_assert(main_view);
  283. bool val = false;
  284. with_view_model(main_view->view, MainViewModel * model, { val = model->dome; }, true);
  285. return val;
  286. }
  287. void draw_top_row(Canvas* canvas, MainViewModel* context) {
  288. MainViewModel* model = context;
  289. char str[12];
  290. if(!model->response) {
  291. canvas_draw_box(canvas, 0, 0, 128, 12);
  292. canvas_set_color(canvas, ColorWhite);
  293. canvas_set_font(canvas, FontPrimary);
  294. canvas_draw_str(canvas, 24, 10, "No sensor found");
  295. canvas_set_color(canvas, ColorBlack);
  296. } else {
  297. model->iso_val = iso_numbers[model->iso];
  298. if(model->nd > 0) model->iso_val /= nd_numbers[model->nd];
  299. if(model->lux > 0) {
  300. if(model->current_mode == FIXED_APERTURE) {
  301. model->speed_val = 100 * pow(aperture_numbers[model->aperture], 2) /
  302. (double)model->iso_val / pow(2, model->EV);
  303. } else {
  304. model->aperture_val = sqrt(
  305. pow(2, model->EV) * (double)model->iso_val *
  306. (double)speed_numbers[model->speed] / 100);
  307. }
  308. }
  309. // TODO when T:30, f/0 instead of f/128
  310. canvas_draw_line(canvas, 0, 10, 128, 10);
  311. canvas_set_font(canvas, FontPrimary);
  312. // metering mode A ÔÇô ambient, F ÔÇô flash
  313. // canvas_draw_str_aligned(canvas, 1, 1, AlignLeft, AlignTop, "A");
  314. snprintf(str, sizeof(str), "ISO: %d", iso_numbers[model->iso]);
  315. canvas_draw_str_aligned(canvas, 19, 1, AlignLeft, AlignTop, str);
  316. canvas_set_font(canvas, FontSecondary);
  317. snprintf(str, sizeof(str), "lx: %.0f", (double)model->lux);
  318. canvas_draw_str_aligned(canvas, 87, 2, AlignLeft, AlignTop, str);
  319. }
  320. }
  321. void draw_aperture(Canvas* canvas, MainViewModel* context) {
  322. MainViewModel* model = context;
  323. char str[12];
  324. switch(model->current_mode) {
  325. case FIXED_APERTURE:
  326. if(model->response) {
  327. if(model->aperture < AP_8) {
  328. snprintf(str, sizeof(str), "/%.1f", (double)aperture_numbers[model->aperture]);
  329. } else {
  330. snprintf(str, sizeof(str), "/%.0f", (double)aperture_numbers[model->aperture]);
  331. }
  332. } else {
  333. snprintf(str, sizeof(str), " ---");
  334. }
  335. canvas_draw_str_aligned(canvas, 27, 15, AlignLeft, AlignTop, str);
  336. break;
  337. case FIXED_SPEED:
  338. if(model->aperture_val < aperture_numbers[0] || !model->response) {
  339. snprintf(str, sizeof(str), " ---");
  340. } else if(model->aperture_val < aperture_numbers[AP_8]) {
  341. snprintf(str, sizeof(str), "/%.1f", (double)normalizeAperture(model->aperture_val));
  342. } else {
  343. snprintf(str, sizeof(str), "/%.0f", (double)normalizeAperture(model->aperture_val));
  344. }
  345. canvas_draw_str_aligned(canvas, 27, 15, AlignLeft, AlignTop, str);
  346. break;
  347. default:
  348. break;
  349. }
  350. }
  351. void draw_speed(Canvas* canvas, MainViewModel* context) {
  352. MainViewModel* model = context;
  353. char str[12];
  354. switch(model->current_mode) {
  355. case FIXED_APERTURE:
  356. if(model->lux > 0 && model->response) {
  357. if(model->speed_val < 1 && model->speed_val > 0) {
  358. snprintf(str, sizeof(str), ":1/%.0f", 1 / (double)normalizeTime(model->speed_val));
  359. } else {
  360. snprintf(str, sizeof(str), ":%.0f", (double)normalizeTime(model->speed_val));
  361. }
  362. } else {
  363. snprintf(str, sizeof(str), " ---");
  364. }
  365. canvas_draw_str_aligned(canvas, 27, 34, AlignLeft, AlignTop, str);
  366. break;
  367. case FIXED_SPEED:
  368. if(model->response) {
  369. if(model->speed < SPEED_1S) {
  370. snprintf(str, sizeof(str), ":1/%.0f", 1 / (double)speed_numbers[model->speed]);
  371. } else {
  372. snprintf(str, sizeof(str), ":%.0f", (double)speed_numbers[model->speed]);
  373. }
  374. } else {
  375. snprintf(str, sizeof(str), " ---");
  376. }
  377. canvas_draw_str_aligned(canvas, 27, 34, AlignLeft, AlignTop, str);
  378. break;
  379. default:
  380. break;
  381. }
  382. }
  383. void draw_mode_indicator(Canvas* canvas, MainViewModel* context) {
  384. MainViewModel* model = context;
  385. switch(model->current_mode) {
  386. case FIXED_SPEED:
  387. canvas_set_font(canvas, FontBigNumbers);
  388. canvas_draw_str_aligned(canvas, 3, 36, AlignLeft, AlignTop, "*");
  389. break;
  390. case FIXED_APERTURE:
  391. canvas_set_font(canvas, FontBigNumbers);
  392. canvas_draw_str_aligned(canvas, 3, 17, AlignLeft, AlignTop, "*");
  393. break;
  394. default:
  395. break;
  396. }
  397. }
  398. void draw_nd_number(Canvas* canvas, MainViewModel* context) {
  399. MainViewModel* model = context;
  400. char str[9];
  401. canvas_set_font(canvas, FontSecondary);
  402. if(model->response) {
  403. snprintf(str, sizeof(str), "ND: %d", nd_numbers[model->nd]);
  404. } else {
  405. snprintf(str, sizeof(str), "ND: ---");
  406. }
  407. canvas_draw_str_aligned(canvas, 87, 20, AlignLeft, AlignBottom, str);
  408. }
  409. void draw_EV_number(Canvas* canvas, MainViewModel* context) {
  410. MainViewModel* model = context;
  411. char str[7];
  412. if(model->lux > 0 && model->response) {
  413. snprintf(str, sizeof(str), "EV: %1.0f", (double)model->EV);
  414. canvas_draw_str_aligned(canvas, 87, 29, AlignLeft, AlignBottom, str);
  415. } else {
  416. canvas_draw_str_aligned(canvas, 87, 29, AlignLeft, AlignBottom, "EV: --");
  417. }
  418. }
  419. void draw_lux_only_mode(Canvas* canvas, MainViewModel* context) {
  420. MainViewModel* model = context;
  421. if(!model->response) {
  422. canvas_draw_box(canvas, 0, 0, 128, 12);
  423. canvas_set_color(canvas, ColorWhite);
  424. canvas_set_font(canvas, FontPrimary);
  425. canvas_draw_str(canvas, 24, 10, "No sensor found");
  426. canvas_set_color(canvas, ColorBlack);
  427. } else {
  428. char str[12];
  429. canvas_set_font(canvas, FontPrimary);
  430. canvas_draw_line(canvas, 0, 10, 128, 10);
  431. canvas_draw_str_aligned(canvas, 64, 1, AlignCenter, AlignTop, "Lux meter mode");
  432. canvas_set_font(canvas, FontBigNumbers);
  433. snprintf(str, sizeof(str), "%.0f", (double)model->lux);
  434. canvas_draw_str_aligned(canvas, 80, 22, AlignRight, AlignCenter, str);
  435. canvas_set_font(canvas, FontSecondary);
  436. canvas_draw_str_aligned(canvas, 85, 29, AlignLeft, AlignBottom, "Lux now");
  437. canvas_set_font(canvas, FontPrimary);
  438. snprintf(str, sizeof(str), "%.0f", (double)model->peakLux);
  439. canvas_draw_str_aligned(canvas, 80, 39, AlignRight, AlignCenter, str);
  440. canvas_set_font(canvas, FontSecondary);
  441. canvas_draw_str_aligned(canvas, 85, 43, AlignLeft, AlignBottom, "Lux peak");
  442. for(int i = 0; i < LUX_HISTORGRAM_LENGTH; i++) {
  443. float lux =
  444. model->luxHistogram[(i + model->luxHistogramIndex) % LUX_HISTORGRAM_LENGTH];
  445. int barHeight = log10(lux) / log10(LUX_HISTORGRAM_LOGBASE);
  446. canvas_draw_line(
  447. canvas,
  448. LUX_HISTORGRAM_LEFT + i,
  449. LUX_HISTORGRAM_BOTTOM,
  450. LUX_HISTORGRAM_LEFT + i,
  451. LUX_HISTORGRAM_BOTTOM - barHeight);
  452. }
  453. }
  454. }