notification-app.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373
  1. #include <furi.h>
  2. #include <api-hal.h>
  3. #include "notification.h"
  4. #include "notification-messages.h"
  5. #include "notification-app.h"
  6. static const uint8_t minimal_delay = 100;
  7. static const uint8_t led_off_values[NOTIFICATION_LED_COUNT] = {0x00, 0x00, 0x00};
  8. static const uint8_t reset_red_mask = 1 << 0;
  9. static const uint8_t reset_green_mask = 1 << 1;
  10. static const uint8_t reset_blue_mask = 1 << 2;
  11. static const uint8_t reset_vibro_mask = 1 << 3;
  12. static const uint8_t reset_sound_mask = 1 << 4;
  13. static const uint8_t reset_display_mask = 1 << 5;
  14. void notification_vibro_on();
  15. void notification_vibro_off();
  16. void notification_sound_on(float pwm, float freq);
  17. void notification_sound_off();
  18. uint8_t notification_settings_get_display_brightness(NotificationApp* app, uint8_t value);
  19. uint8_t notification_settings_get_rgb_led_brightness(NotificationApp* app, uint8_t value);
  20. uint32_t notification_settings_display_off_delay_ticks(NotificationApp* app);
  21. // internal layer
  22. void notification_apply_internal_led_layer(NotificationLedLayer* layer, uint8_t layer_value) {
  23. furi_assert(layer);
  24. furi_assert(layer->index < LayerMAX);
  25. // set value
  26. layer->value[LayerInternal] = layer_value;
  27. // apply if current layer is internal
  28. if(layer->index == LayerInternal) {
  29. api_hal_light_set(layer->light, layer->value[LayerInternal]);
  30. }
  31. }
  32. bool notification_is_any_led_layer_internal_and_not_empty(NotificationApp* app) {
  33. bool result = false;
  34. if((app->led[0].index == LayerInternal) || (app->led[1].index == LayerInternal) ||
  35. (app->led[2].index == LayerInternal)) {
  36. if((app->led[0].value[LayerInternal] != 0x00) ||
  37. (app->led[1].value[LayerInternal] != 0x00) ||
  38. (app->led[2].value[LayerInternal] != 0x00)) {
  39. result = true;
  40. }
  41. }
  42. return result;
  43. }
  44. // notification layer
  45. void notification_apply_notification_led_layer(
  46. NotificationLedLayer* layer,
  47. const uint8_t layer_value) {
  48. furi_assert(layer);
  49. furi_assert(layer->index < LayerMAX);
  50. // set value
  51. layer->index = LayerNotification;
  52. // set layer
  53. layer->value[LayerNotification] = layer_value;
  54. // apply
  55. api_hal_light_set(layer->light, layer->value[LayerNotification]);
  56. }
  57. void notification_reset_notification_led_layer(NotificationLedLayer* layer) {
  58. furi_assert(layer);
  59. furi_assert(layer->index < LayerMAX);
  60. // set value
  61. layer->value[LayerNotification] = 0;
  62. // set layer
  63. layer->index = LayerInternal;
  64. // apply
  65. api_hal_light_set(layer->light, layer->value[LayerInternal]);
  66. }
  67. void notification_reset_notification_layer(NotificationApp* app, uint8_t reset_mask) {
  68. if(reset_mask & reset_red_mask) {
  69. notification_reset_notification_led_layer(&app->led[0]);
  70. }
  71. if(reset_mask & reset_green_mask) {
  72. notification_reset_notification_led_layer(&app->led[1]);
  73. }
  74. if(reset_mask & reset_blue_mask) {
  75. notification_reset_notification_led_layer(&app->led[2]);
  76. }
  77. if(reset_mask & reset_vibro_mask) {
  78. notification_vibro_off();
  79. }
  80. if(reset_mask & reset_sound_mask) {
  81. notification_sound_off();
  82. }
  83. if(reset_mask & reset_display_mask) {
  84. osTimerStart(app->display_timer, notification_settings_display_off_delay_ticks(app));
  85. }
  86. }
  87. static void notification_apply_notification_leds(NotificationApp* app, const uint8_t* values) {
  88. for(uint8_t i = 0; i < NOTIFICATION_LED_COUNT; i++) {
  89. notification_apply_notification_led_layer(
  90. &app->led[i], notification_settings_get_display_brightness(app, values[i]));
  91. }
  92. }
  93. // settings
  94. uint8_t notification_settings_get_display_brightness(NotificationApp* app, uint8_t value) {
  95. return (value * app->settings.display_brightness);
  96. }
  97. uint8_t notification_settings_get_rgb_led_brightness(NotificationApp* app, uint8_t value) {
  98. return (value * app->settings.led_brightness);
  99. }
  100. uint32_t notification_settings_display_off_delay_ticks(NotificationApp* app) {
  101. return ((float)(app->settings.display_off_delay_ms) / (1000.0f / osKernelGetTickFreq()));
  102. }
  103. // generics
  104. void notification_vibro_on() {
  105. api_hal_vibro_on(true);
  106. }
  107. void notification_vibro_off() {
  108. api_hal_vibro_on(false);
  109. }
  110. void notification_sound_on(float pwm, float freq) {
  111. hal_pwm_set(pwm, freq, &SPEAKER_TIM, SPEAKER_CH);
  112. }
  113. void notification_sound_off() {
  114. hal_pwm_stop(&SPEAKER_TIM, SPEAKER_CH);
  115. }
  116. // display timer
  117. static void notification_display_timer(void* ctx) {
  118. furi_assert(ctx);
  119. NotificationApp* app = ctx;
  120. notification_message(app, &sequence_display_off);
  121. }
  122. // message processing
  123. void notification_process_notification_message(
  124. NotificationApp* app,
  125. NotificationAppMessage* message) {
  126. uint32_t notification_message_index = 0;
  127. const NotificationMessage* notification_message;
  128. notification_message = (*message->sequence)[notification_message_index];
  129. bool led_active = false;
  130. uint8_t led_values[NOTIFICATION_LED_COUNT] = {0x00, 0x00, 0x00};
  131. bool reset_notifications = true;
  132. uint8_t reset_mask = 0;
  133. while(notification_message != NULL) {
  134. switch(notification_message->type) {
  135. case NotificationMessageTypeLedDisplay:
  136. // if on - switch on and start timer
  137. // if off - switch off and stop timer
  138. // on timer - switch off
  139. if(notification_message->data.led.value > 0x00) {
  140. notification_apply_notification_led_layer(
  141. &app->display,
  142. notification_settings_get_display_brightness(
  143. app, notification_message->data.led.value));
  144. } else {
  145. notification_reset_notification_led_layer(&app->display);
  146. if(osTimerIsRunning(app->display_timer)) {
  147. osTimerStop(app->display_timer);
  148. }
  149. }
  150. reset_mask |= reset_display_mask;
  151. break;
  152. case NotificationMessageTypeLedRed:
  153. // store and send on delay or after seq
  154. led_active = true;
  155. led_values[0] = notification_message->data.led.value;
  156. reset_mask |= reset_red_mask;
  157. break;
  158. case NotificationMessageTypeLedGreen:
  159. // store and send on delay or after seq
  160. led_active = true;
  161. led_values[1] = notification_message->data.led.value;
  162. reset_mask |= reset_green_mask;
  163. break;
  164. case NotificationMessageTypeLedBlue:
  165. // store and send on delay or after seq
  166. led_active = true;
  167. led_values[2] = notification_message->data.led.value;
  168. reset_mask |= reset_blue_mask;
  169. break;
  170. case NotificationMessageTypeVibro:
  171. if(notification_message->data.vibro.on) {
  172. notification_vibro_on();
  173. } else {
  174. notification_vibro_off();
  175. }
  176. reset_mask |= reset_vibro_mask;
  177. break;
  178. case NotificationMessageTypeSoundOn:
  179. notification_sound_on(
  180. notification_message->data.sound.pwm * app->settings.speaker_volume,
  181. notification_message->data.sound.frequency);
  182. reset_mask |= reset_sound_mask;
  183. break;
  184. case NotificationMessageTypeSoundOff:
  185. notification_sound_off();
  186. reset_mask |= reset_sound_mask;
  187. break;
  188. case NotificationMessageTypeDelay:
  189. if(led_active) {
  190. if(notification_is_any_led_layer_internal_and_not_empty(app)) {
  191. notification_apply_notification_leds(app, led_off_values);
  192. delay(minimal_delay);
  193. }
  194. led_active = false;
  195. notification_apply_notification_leds(app, led_values);
  196. reset_mask |= reset_red_mask;
  197. reset_mask |= reset_green_mask;
  198. reset_mask |= reset_blue_mask;
  199. }
  200. delay(notification_message->data.delay.length);
  201. break;
  202. case NotificationMessageTypeDoNotReset:
  203. reset_notifications = false;
  204. break;
  205. }
  206. notification_message_index++;
  207. notification_message = (*message->sequence)[notification_message_index];
  208. };
  209. // send and do minimal delay
  210. if(led_active) {
  211. bool need_minimal_delay = false;
  212. if(notification_is_any_led_layer_internal_and_not_empty(app)) {
  213. need_minimal_delay = true;
  214. }
  215. led_active = false;
  216. notification_apply_notification_leds(app, led_values);
  217. reset_mask |= reset_red_mask;
  218. reset_mask |= reset_green_mask;
  219. reset_mask |= reset_blue_mask;
  220. if(need_minimal_delay) {
  221. notification_apply_notification_leds(app, led_off_values);
  222. delay(minimal_delay);
  223. }
  224. }
  225. if(reset_notifications) {
  226. notification_reset_notification_layer(app, reset_mask);
  227. }
  228. if(message->back_event != NULL) {
  229. osEventFlagsSet(message->back_event, NOTIFICATION_EVENT_COMPLETE);
  230. }
  231. }
  232. void notification_process_internal_message(NotificationApp* app, NotificationAppMessage* message) {
  233. uint32_t notification_message_index = 0;
  234. const NotificationMessage* notification_message;
  235. notification_message = (*message->sequence)[notification_message_index];
  236. while(notification_message != NULL) {
  237. switch(notification_message->type) {
  238. case NotificationMessageTypeLedDisplay:
  239. notification_apply_internal_led_layer(
  240. &app->display,
  241. notification_settings_get_display_brightness(
  242. app, notification_message->data.led.value));
  243. break;
  244. case NotificationMessageTypeLedRed:
  245. notification_apply_internal_led_layer(
  246. &app->led[0],
  247. notification_settings_get_rgb_led_brightness(
  248. app, notification_message->data.led.value));
  249. break;
  250. case NotificationMessageTypeLedGreen:
  251. notification_apply_internal_led_layer(
  252. &app->led[1],
  253. notification_settings_get_rgb_led_brightness(
  254. app, notification_message->data.led.value));
  255. break;
  256. case NotificationMessageTypeLedBlue:
  257. notification_apply_internal_led_layer(
  258. &app->led[2],
  259. notification_settings_get_rgb_led_brightness(
  260. app, notification_message->data.led.value));
  261. break;
  262. default:
  263. break;
  264. }
  265. notification_message_index++;
  266. notification_message = (*message->sequence)[notification_message_index];
  267. }
  268. if(message->back_event != NULL) {
  269. osEventFlagsSet(message->back_event, NOTIFICATION_EVENT_COMPLETE);
  270. }
  271. }
  272. // App alloc
  273. static NotificationApp* notification_app_alloc() {
  274. NotificationApp* app = furi_alloc(sizeof(NotificationApp));
  275. app->queue = osMessageQueueNew(8, sizeof(NotificationAppMessage), NULL);
  276. app->display_timer = osTimerNew(notification_display_timer, osTimerOnce, app, NULL);
  277. app->settings.speaker_volume = 1.0f;
  278. app->settings.display_brightness = 1.0f;
  279. app->settings.led_brightness = 1.0f;
  280. app->settings.display_off_delay_ms = 30000;
  281. app->display.value[LayerInternal] = 0x00;
  282. app->display.value[LayerNotification] = 0x00;
  283. app->display.index = LayerInternal;
  284. app->display.light = LightBacklight;
  285. app->led[0].value[LayerInternal] = 0x00;
  286. app->led[0].value[LayerNotification] = 0x00;
  287. app->led[0].index = LayerInternal;
  288. app->led[0].light = LightRed;
  289. app->led[1].value[LayerInternal] = 0x00;
  290. app->led[1].value[LayerNotification] = 0x00;
  291. app->led[1].index = LayerInternal;
  292. app->led[1].light = LightGreen;
  293. app->led[2].value[LayerInternal] = 0x00;
  294. app->led[2].value[LayerNotification] = 0x00;
  295. app->led[2].index = LayerInternal;
  296. app->led[2].light = LightBlue;
  297. return app;
  298. };
  299. // App
  300. int32_t notification_app(void* p) {
  301. NotificationApp* app = notification_app_alloc();
  302. notification_vibro_off();
  303. notification_sound_off();
  304. notification_apply_internal_led_layer(&app->display, 0x00);
  305. notification_apply_internal_led_layer(&app->led[0], 0x00);
  306. notification_apply_internal_led_layer(&app->led[1], 0x00);
  307. notification_apply_internal_led_layer(&app->led[2], 0x00);
  308. furi_record_create("notification", app);
  309. NotificationAppMessage message;
  310. while(1) {
  311. furi_check(osMessageQueueGet(app->queue, &message, NULL, osWaitForever) == osOK);
  312. switch(message.type) {
  313. case NotificationLayerMessage:
  314. notification_process_notification_message(app, &message);
  315. break;
  316. case InternalLayerMessage:
  317. notification_process_internal_message(app, &message);
  318. }
  319. }
  320. return 0;
  321. };