notification_app.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485
  1. #include <furi.h>
  2. #include <furi_hal.h>
  3. #include <storage/storage.h>
  4. #include "notification.h"
  5. #include "notification_messages.h"
  6. #include "notification_app.h"
  7. #define TAG "NotificationSrv"
  8. static const uint8_t minimal_delay = 100;
  9. static const uint8_t led_off_values[NOTIFICATION_LED_COUNT] = {0x00, 0x00, 0x00};
  10. static const uint8_t reset_red_mask = 1 << 0;
  11. static const uint8_t reset_green_mask = 1 << 1;
  12. static const uint8_t reset_blue_mask = 1 << 2;
  13. static const uint8_t reset_vibro_mask = 1 << 3;
  14. static const uint8_t reset_sound_mask = 1 << 4;
  15. static const uint8_t reset_display_mask = 1 << 5;
  16. void notification_vibro_on();
  17. void notification_vibro_off();
  18. void notification_sound_on(float pwm, float freq);
  19. void notification_sound_off();
  20. uint8_t notification_settings_get_display_brightness(NotificationApp* app, uint8_t value);
  21. uint8_t notification_settings_get_rgb_led_brightness(NotificationApp* app, uint8_t value);
  22. uint32_t notification_settings_display_off_delay_ticks(NotificationApp* app);
  23. void notification_message_save_settings(NotificationApp* app) {
  24. NotificationAppMessage m = {.type = SaveSettingsMessage, .back_event = osEventFlagsNew(NULL)};
  25. furi_check(osMessageQueuePut(app->queue, &m, 0, osWaitForever) == osOK);
  26. osEventFlagsWait(m.back_event, NOTIFICATION_EVENT_COMPLETE, osFlagsWaitAny, osWaitForever);
  27. osEventFlagsDelete(m.back_event);
  28. };
  29. // internal layer
  30. void notification_apply_internal_led_layer(NotificationLedLayer* layer, uint8_t layer_value) {
  31. furi_assert(layer);
  32. furi_assert(layer->index < LayerMAX);
  33. // set value
  34. layer->value[LayerInternal] = layer_value;
  35. // apply if current layer is internal
  36. if(layer->index == LayerInternal) {
  37. furi_hal_light_set(layer->light, layer->value[LayerInternal]);
  38. }
  39. }
  40. bool notification_is_any_led_layer_internal_and_not_empty(NotificationApp* app) {
  41. bool result = false;
  42. if((app->led[0].index == LayerInternal) || (app->led[1].index == LayerInternal) ||
  43. (app->led[2].index == LayerInternal)) {
  44. if((app->led[0].value[LayerInternal] != 0x00) ||
  45. (app->led[1].value[LayerInternal] != 0x00) ||
  46. (app->led[2].value[LayerInternal] != 0x00)) {
  47. result = true;
  48. }
  49. }
  50. return result;
  51. }
  52. // notification layer
  53. void notification_apply_notification_led_layer(
  54. NotificationLedLayer* layer,
  55. const uint8_t layer_value) {
  56. furi_assert(layer);
  57. furi_assert(layer->index < LayerMAX);
  58. // set value
  59. layer->index = LayerNotification;
  60. // set layer
  61. layer->value[LayerNotification] = layer_value;
  62. // apply
  63. furi_hal_light_set(layer->light, layer->value[LayerNotification]);
  64. }
  65. void notification_reset_notification_led_layer(NotificationLedLayer* layer) {
  66. furi_assert(layer);
  67. furi_assert(layer->index < LayerMAX);
  68. // set value
  69. layer->value[LayerNotification] = 0;
  70. // set layer
  71. layer->index = LayerInternal;
  72. // apply
  73. furi_hal_light_set(layer->light, layer->value[LayerInternal]);
  74. }
  75. void notification_reset_notification_layer(NotificationApp* app, uint8_t reset_mask) {
  76. if(reset_mask & reset_red_mask) {
  77. notification_reset_notification_led_layer(&app->led[0]);
  78. }
  79. if(reset_mask & reset_green_mask) {
  80. notification_reset_notification_led_layer(&app->led[1]);
  81. }
  82. if(reset_mask & reset_blue_mask) {
  83. notification_reset_notification_led_layer(&app->led[2]);
  84. }
  85. if(reset_mask & reset_vibro_mask) {
  86. notification_vibro_off();
  87. }
  88. if(reset_mask & reset_sound_mask) {
  89. notification_sound_off();
  90. }
  91. if(reset_mask & reset_display_mask) {
  92. osTimerStart(app->display_timer, notification_settings_display_off_delay_ticks(app));
  93. }
  94. }
  95. static void notification_apply_notification_leds(NotificationApp* app, const uint8_t* values) {
  96. for(uint8_t i = 0; i < NOTIFICATION_LED_COUNT; i++) {
  97. notification_apply_notification_led_layer(
  98. &app->led[i], notification_settings_get_rgb_led_brightness(app, values[i]));
  99. }
  100. }
  101. // settings
  102. uint8_t notification_settings_get_display_brightness(NotificationApp* app, uint8_t value) {
  103. return (value * app->settings.display_brightness);
  104. }
  105. uint8_t notification_settings_get_rgb_led_brightness(NotificationApp* app, uint8_t value) {
  106. return (value * app->settings.led_brightness);
  107. }
  108. uint32_t notification_settings_display_off_delay_ticks(NotificationApp* app) {
  109. return ((float)(app->settings.display_off_delay_ms) / (1000.0f / osKernelGetTickFreq()));
  110. }
  111. // generics
  112. void notification_vibro_on() {
  113. furi_hal_vibro_on(true);
  114. }
  115. void notification_vibro_off() {
  116. furi_hal_vibro_on(false);
  117. }
  118. void notification_sound_on(float pwm, float freq) {
  119. hal_pwm_set(pwm, freq, &SPEAKER_TIM, SPEAKER_CH);
  120. }
  121. void notification_sound_off() {
  122. hal_pwm_stop(&SPEAKER_TIM, SPEAKER_CH);
  123. }
  124. // display timer
  125. static void notification_display_timer(void* ctx) {
  126. furi_assert(ctx);
  127. NotificationApp* app = ctx;
  128. notification_message(app, &sequence_display_off);
  129. }
  130. // message processing
  131. void notification_process_notification_message(
  132. NotificationApp* app,
  133. NotificationAppMessage* message) {
  134. uint32_t notification_message_index = 0;
  135. const NotificationMessage* notification_message;
  136. notification_message = (*message->sequence)[notification_message_index];
  137. bool led_active = false;
  138. uint8_t led_values[NOTIFICATION_LED_COUNT] = {0x00, 0x00, 0x00};
  139. bool reset_notifications = true;
  140. float speaker_volume_setting = app->settings.speaker_volume;
  141. bool vibro_setting = app->settings.vibro_on;
  142. float display_brightness_setting = app->settings.display_brightness;
  143. uint8_t reset_mask = 0;
  144. while(notification_message != NULL) {
  145. switch(notification_message->type) {
  146. case NotificationMessageTypeLedDisplay:
  147. // if on - switch on and start timer
  148. // if off - switch off and stop timer
  149. // on timer - switch off
  150. if(notification_message->data.led.value > 0x00) {
  151. notification_apply_notification_led_layer(
  152. &app->display,
  153. notification_message->data.led.value * display_brightness_setting);
  154. } else {
  155. notification_reset_notification_led_layer(&app->display);
  156. if(osTimerIsRunning(app->display_timer)) {
  157. osTimerStop(app->display_timer);
  158. }
  159. }
  160. reset_mask |= reset_display_mask;
  161. break;
  162. case NotificationMessageTypeLedRed:
  163. // store and send on delay or after seq
  164. led_active = true;
  165. led_values[0] = notification_message->data.led.value;
  166. reset_mask |= reset_red_mask;
  167. break;
  168. case NotificationMessageTypeLedGreen:
  169. // store and send on delay or after seq
  170. led_active = true;
  171. led_values[1] = notification_message->data.led.value;
  172. reset_mask |= reset_green_mask;
  173. break;
  174. case NotificationMessageTypeLedBlue:
  175. // store and send on delay or after seq
  176. led_active = true;
  177. led_values[2] = notification_message->data.led.value;
  178. reset_mask |= reset_blue_mask;
  179. break;
  180. case NotificationMessageTypeVibro:
  181. if(notification_message->data.vibro.on) {
  182. if(vibro_setting) notification_vibro_on();
  183. } else {
  184. notification_vibro_off();
  185. }
  186. reset_mask |= reset_vibro_mask;
  187. break;
  188. case NotificationMessageTypeSoundOn:
  189. notification_sound_on(
  190. notification_message->data.sound.pwm * speaker_volume_setting,
  191. notification_message->data.sound.frequency);
  192. reset_mask |= reset_sound_mask;
  193. break;
  194. case NotificationMessageTypeSoundOff:
  195. notification_sound_off();
  196. reset_mask |= reset_sound_mask;
  197. break;
  198. case NotificationMessageTypeDelay:
  199. if(led_active) {
  200. if(notification_is_any_led_layer_internal_and_not_empty(app)) {
  201. notification_apply_notification_leds(app, led_off_values);
  202. delay(minimal_delay);
  203. }
  204. led_active = false;
  205. notification_apply_notification_leds(app, led_values);
  206. reset_mask |= reset_red_mask;
  207. reset_mask |= reset_green_mask;
  208. reset_mask |= reset_blue_mask;
  209. }
  210. delay(notification_message->data.delay.length);
  211. break;
  212. case NotificationMessageTypeDoNotReset:
  213. reset_notifications = false;
  214. break;
  215. case NotificationMessageTypeForceSpeakerVolumeSetting:
  216. speaker_volume_setting = notification_message->data.forced_settings.speaker_volume;
  217. break;
  218. case NotificationMessageTypeForceVibroSetting:
  219. vibro_setting = notification_message->data.forced_settings.vibro;
  220. break;
  221. case NotificationMessageTypeForceDisplayBrightnessSetting:
  222. display_brightness_setting =
  223. notification_message->data.forced_settings.display_brightness;
  224. }
  225. notification_message_index++;
  226. notification_message = (*message->sequence)[notification_message_index];
  227. };
  228. // send and do minimal delay
  229. if(led_active) {
  230. bool need_minimal_delay = false;
  231. if(notification_is_any_led_layer_internal_and_not_empty(app)) {
  232. need_minimal_delay = true;
  233. }
  234. led_active = false;
  235. notification_apply_notification_leds(app, led_values);
  236. reset_mask |= reset_red_mask;
  237. reset_mask |= reset_green_mask;
  238. reset_mask |= reset_blue_mask;
  239. if(need_minimal_delay) {
  240. notification_apply_notification_leds(app, led_off_values);
  241. delay(minimal_delay);
  242. }
  243. }
  244. if(reset_notifications) {
  245. notification_reset_notification_layer(app, reset_mask);
  246. }
  247. }
  248. void notification_process_internal_message(NotificationApp* app, NotificationAppMessage* message) {
  249. uint32_t notification_message_index = 0;
  250. const NotificationMessage* notification_message;
  251. notification_message = (*message->sequence)[notification_message_index];
  252. while(notification_message != NULL) {
  253. switch(notification_message->type) {
  254. case NotificationMessageTypeLedDisplay:
  255. notification_apply_internal_led_layer(
  256. &app->display,
  257. notification_settings_get_display_brightness(
  258. app, notification_message->data.led.value));
  259. break;
  260. case NotificationMessageTypeLedRed:
  261. notification_apply_internal_led_layer(
  262. &app->led[0],
  263. notification_settings_get_rgb_led_brightness(
  264. app, notification_message->data.led.value));
  265. break;
  266. case NotificationMessageTypeLedGreen:
  267. notification_apply_internal_led_layer(
  268. &app->led[1],
  269. notification_settings_get_rgb_led_brightness(
  270. app, notification_message->data.led.value));
  271. break;
  272. case NotificationMessageTypeLedBlue:
  273. notification_apply_internal_led_layer(
  274. &app->led[2],
  275. notification_settings_get_rgb_led_brightness(
  276. app, notification_message->data.led.value));
  277. break;
  278. default:
  279. break;
  280. }
  281. notification_message_index++;
  282. notification_message = (*message->sequence)[notification_message_index];
  283. }
  284. }
  285. static bool notification_load_settings(NotificationApp* app) {
  286. NotificationSettings settings;
  287. File* file = storage_file_alloc(furi_record_open("storage"));
  288. const size_t settings_size = sizeof(NotificationSettings);
  289. FURI_LOG_I(TAG, "loading settings from \"%s\"", NOTIFICATION_SETTINGS_PATH);
  290. bool fs_result =
  291. storage_file_open(file, NOTIFICATION_SETTINGS_PATH, FSAM_READ, FSOM_OPEN_EXISTING);
  292. if(fs_result) {
  293. uint16_t bytes_count = storage_file_read(file, &settings, settings_size);
  294. if(bytes_count != settings_size) {
  295. fs_result = false;
  296. }
  297. }
  298. if(fs_result) {
  299. FURI_LOG_I(TAG, "load success");
  300. if(settings.version != NOTIFICATION_SETTINGS_VERSION) {
  301. FURI_LOG_E(
  302. TAG, "version(%d != %d) mismatch", settings.version, NOTIFICATION_SETTINGS_VERSION);
  303. } else {
  304. osKernelLock();
  305. memcpy(&app->settings, &settings, settings_size);
  306. osKernelUnlock();
  307. }
  308. } else {
  309. FURI_LOG_E(TAG, "load failed, %s", storage_file_get_error_desc(file));
  310. }
  311. storage_file_close(file);
  312. storage_file_free(file);
  313. furi_record_close("storage");
  314. return fs_result;
  315. };
  316. static bool notification_save_settings(NotificationApp* app) {
  317. NotificationSettings settings;
  318. File* file = storage_file_alloc(furi_record_open("storage"));
  319. const size_t settings_size = sizeof(NotificationSettings);
  320. FURI_LOG_I(TAG, "saving settings to \"%s\"", NOTIFICATION_SETTINGS_PATH);
  321. osKernelLock();
  322. memcpy(&settings, &app->settings, settings_size);
  323. osKernelUnlock();
  324. bool fs_result =
  325. storage_file_open(file, NOTIFICATION_SETTINGS_PATH, FSAM_WRITE, FSOM_CREATE_ALWAYS);
  326. if(fs_result) {
  327. uint16_t bytes_count = storage_file_write(file, &settings, settings_size);
  328. if(bytes_count != settings_size) {
  329. fs_result = false;
  330. }
  331. }
  332. if(fs_result) {
  333. FURI_LOG_I(TAG, "save success");
  334. } else {
  335. FURI_LOG_E(TAG, "save failed, %s", storage_file_get_error_desc(file));
  336. }
  337. storage_file_close(file);
  338. storage_file_free(file);
  339. furi_record_close("storage");
  340. return fs_result;
  341. };
  342. static void input_event_callback(const void* value, void* context) {
  343. NotificationApp* app = context;
  344. notification_message(app, &sequence_display_on);
  345. }
  346. // App alloc
  347. static NotificationApp* notification_app_alloc() {
  348. NotificationApp* app = furi_alloc(sizeof(NotificationApp));
  349. app->queue = osMessageQueueNew(8, sizeof(NotificationAppMessage), NULL);
  350. app->display_timer = osTimerNew(notification_display_timer, osTimerOnce, app, NULL);
  351. app->settings.speaker_volume = 1.0f;
  352. app->settings.display_brightness = 1.0f;
  353. app->settings.led_brightness = 1.0f;
  354. app->settings.display_off_delay_ms = 30000;
  355. app->settings.vibro_on = true;
  356. app->display.value[LayerInternal] = 0x00;
  357. app->display.value[LayerNotification] = 0x00;
  358. app->display.index = LayerInternal;
  359. app->display.light = LightBacklight;
  360. app->led[0].value[LayerInternal] = 0x00;
  361. app->led[0].value[LayerNotification] = 0x00;
  362. app->led[0].index = LayerInternal;
  363. app->led[0].light = LightRed;
  364. app->led[1].value[LayerInternal] = 0x00;
  365. app->led[1].value[LayerNotification] = 0x00;
  366. app->led[1].index = LayerInternal;
  367. app->led[1].light = LightGreen;
  368. app->led[2].value[LayerInternal] = 0x00;
  369. app->led[2].value[LayerNotification] = 0x00;
  370. app->led[2].index = LayerInternal;
  371. app->led[2].light = LightBlue;
  372. app->settings.version = NOTIFICATION_SETTINGS_VERSION;
  373. // display backlight control
  374. app->event_record = furi_record_open("input_events");
  375. furi_pubsub_subscribe(app->event_record, input_event_callback, app);
  376. notification_message(app, &sequence_display_on);
  377. return app;
  378. };
  379. // App
  380. int32_t notification_srv(void* p) {
  381. NotificationApp* app = notification_app_alloc();
  382. if(!notification_load_settings(app)) {
  383. notification_save_settings(app);
  384. }
  385. notification_vibro_off();
  386. notification_sound_off();
  387. notification_apply_internal_led_layer(&app->display, 0x00);
  388. notification_apply_internal_led_layer(&app->led[0], 0x00);
  389. notification_apply_internal_led_layer(&app->led[1], 0x00);
  390. notification_apply_internal_led_layer(&app->led[2], 0x00);
  391. furi_record_create("notification", app);
  392. NotificationAppMessage message;
  393. while(1) {
  394. furi_check(osMessageQueueGet(app->queue, &message, NULL, osWaitForever) == osOK);
  395. switch(message.type) {
  396. case NotificationLayerMessage:
  397. notification_process_notification_message(app, &message);
  398. break;
  399. case InternalLayerMessage:
  400. notification_process_internal_message(app, &message);
  401. break;
  402. case SaveSettingsMessage:
  403. notification_save_settings(app);
  404. break;
  405. }
  406. if(message.back_event != NULL) {
  407. osEventFlagsSet(message.back_event, NOTIFICATION_EVENT_COMPLETE);
  408. }
  409. }
  410. return 0;
  411. };