blob: bf9452987b8ded7141aa4216cccf6b155952a095 [file] [log] [blame]
David Sodmanbbcb0522014-09-19 10:34:07 -07001/*
2 * Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
3 * Use of this source code is governed by a BSD-style license that can be
4 * found in the LICENSE file.
5 */
6
Dominik Behrda6df412016-08-02 12:56:42 -07007#include <errno.h>
David Sodman8ef20062015-01-06 09:23:40 -08008#include <fcntl.h>
David Sodmanbbcb0522014-09-19 10:34:07 -07009#include <stdbool.h>
10#include <stddef.h>
11#include <stdio.h>
12#include <stdlib.h>
13#include <string.h>
14#include <sys/mman.h>
15#include <unistd.h>
David Sodmanbbcb0522014-09-19 10:34:07 -070016
Dominik Behr797a3832016-01-11 15:53:11 -080017#include "dbus.h"
David Sodmanbbcb0522014-09-19 10:34:07 -070018#include "dbus_interface.h"
David Sodman8ef20062015-01-06 09:23:40 -080019#include "image.h"
David Sodmanf0a925a2015-05-04 11:19:19 -070020#include "input.h"
Dominik Behr44e07e62016-01-13 19:43:57 -080021#include "main.h"
David Sodman8ef20062015-01-06 09:23:40 -080022#include "splash.h"
David Sodmanf0a925a2015-05-04 11:19:19 -070023#include "term.h"
David Sodman8ef20062015-01-06 09:23:40 -080024#include "util.h"
David Sodmanbbcb0522014-09-19 10:34:07 -070025
Jingkui Wangda4fdd32017-01-06 01:05:41 +000026#define MAX_SPLASH_IMAGES (30)
David Sodmandd5b23e2015-02-18 21:36:38 -080027#define MAX_SPLASH_WAITTIME (8)
David Sodmanbbcb0522014-09-19 10:34:07 -070028
29typedef struct {
Stéphane Marchesin00ff1872015-12-14 13:40:09 -080030 image_t* image;
31 uint32_t duration;
David Sodman8ef20062015-01-06 09:23:40 -080032} splash_frame_t;
David Sodmanbbcb0522014-09-19 10:34:07 -070033
34struct _splash_t {
Stéphane Marchesin00ff1872015-12-14 13:40:09 -080035 int num_images;
36 uint32_t clear;
37 splash_frame_t image_frames[MAX_SPLASH_IMAGES];
38 bool terminated;
Stéphane Marchesin00ff1872015-12-14 13:40:09 -080039 int32_t loop_start;
Dominik Behrfd9fdda2016-03-28 17:16:45 -070040 int32_t loop_count;
Stéphane Marchesin00ff1872015-12-14 13:40:09 -080041 uint32_t loop_duration;
42 uint32_t default_duration;
43 int32_t offset_x;
44 int32_t offset_y;
45 int32_t loop_offset_x;
46 int32_t loop_offset_y;
Dominik Behr92d9e312016-05-04 20:10:48 -070047 uint32_t scale;
David Sodmanbbcb0522014-09-19 10:34:07 -070048};
49
David Sodmanbf3f2842014-11-12 08:26:58 -080050
Dominik Behrda6df412016-08-02 12:56:42 -070051splash_t* splash_init(int pts_fd)
David Sodmanbbcb0522014-09-19 10:34:07 -070052{
53 splash_t* splash;
54
55 splash = (splash_t*)calloc(1, sizeof(splash_t));
Stéphane Marchesinc236e0b2015-12-14 15:29:15 -080056 if (!splash)
David Sodmanbbcb0522014-09-19 10:34:07 -070057 return NULL;
58
Dominik Behrda6df412016-08-02 12:56:42 -070059 term_create_splash_term(pts_fd);
David Sodman8ef20062015-01-06 09:23:40 -080060 splash->loop_start = -1;
Dominik Behrfd9fdda2016-03-28 17:16:45 -070061 splash->loop_count = -1;
David Sodman8ef20062015-01-06 09:23:40 -080062 splash->default_duration = 25;
63 splash->loop_duration = 25;
Dominik Behr92d9e312016-05-04 20:10:48 -070064 splash->scale = 1;
David Sodmanbbcb0522014-09-19 10:34:07 -070065
66 return splash;
67}
68
Dominik Behrda6df412016-08-02 12:56:42 -070069int splash_destroy(splash_t* splash)
David Sodmanbbcb0522014-09-19 10:34:07 -070070{
David Sodman8ef20062015-01-06 09:23:40 -080071 free(splash);
Dominik Behrda6df412016-08-02 12:56:42 -070072 term_destroy_splash_term();
David Sodmanbbcb0522014-09-19 10:34:07 -070073 return 0;
74}
75
Stéphane Marchesin00ff1872015-12-14 13:40:09 -080076int splash_set_clear(splash_t* splash, uint32_t clear_color)
David Sodmanbbcb0522014-09-19 10:34:07 -070077{
78 splash->clear = clear_color;
79 return 0;
80}
81
David Sodman8ef20062015-01-06 09:23:40 -080082int splash_add_image(splash_t* splash, char* filespec)
David Sodmanbbcb0522014-09-19 10:34:07 -070083{
David Sodman8ef20062015-01-06 09:23:40 -080084 image_t* image;
85 int32_t offset_x, offset_y;
Stéphane Marchesin00ff1872015-12-14 13:40:09 -080086 char* filename;
David Sodman8ef20062015-01-06 09:23:40 -080087 uint32_t duration;
David Sodmanbbcb0522014-09-19 10:34:07 -070088 if (splash->num_images >= MAX_SPLASH_IMAGES)
89 return 1;
90
David Sodman8ef20062015-01-06 09:23:40 -080091 filename = (char*)malloc(strlen(filespec) + 1);
92 parse_filespec(filespec,
93 filename,
94 &offset_x, &offset_y, &duration,
95 splash->default_duration,
96 splash->offset_x,
97 splash->offset_y);
98
99 image = image_create();
100 image_set_filename(image, filename);
101 image_set_offset(image, offset_x, offset_y);
Dominik Behr92d9e312016-05-04 20:10:48 -0700102 if (splash->scale == 0)
103 image_set_scale(image, splash_is_hires(splash) ? 2 : 1);
104 else
105 image_set_scale(image, splash->scale);
David Sodman8ef20062015-01-06 09:23:40 -0800106 splash->image_frames[splash->num_images].image = image;
107 splash->image_frames[splash->num_images].duration = duration;
David Sodmanbbcb0522014-09-19 10:34:07 -0700108 splash->num_images++;
David Sodman8ef20062015-01-06 09:23:40 -0800109
110 free(filename);
David Sodmanbbcb0522014-09-19 10:34:07 -0700111 return 0;
112}
113
Dominik Behr797a3832016-01-11 15:53:11 -0800114int splash_run(splash_t* splash)
David Sodmanbbcb0522014-09-19 10:34:07 -0700115{
116 int i;
Dominik Behrfd9fdda2016-03-28 17:16:45 -0700117 int status = 0;
Dominik Behr607e4dc2016-06-14 21:21:28 -0700118 /*
119 * Counters for throttling error messages. Only at most MAX_SPLASH_IMAGES
120 * of each type of error are logged so every frame of animation could log
121 * error message but it wouldn't spam the log.
122 */
123 int ec_li = 0, ec_ts = 0, ec_ip = 0;
David Sodmanbbcb0522014-09-19 10:34:07 -0700124 int64_t last_show_ms;
125 int64_t now_ms;
126 int64_t sleep_ms;
127 struct timespec sleep_spec;
David Sodman8ef20062015-01-06 09:23:40 -0800128 image_t* image;
129 uint32_t duration;
Dominik Behrfd9fdda2016-03-28 17:16:45 -0700130 int32_t c, loop_start, loop_count;
Dominik Behr5f9fc7d2017-08-25 15:30:24 -0700131 bool active = false;
David Sodmanbbcb0522014-09-19 10:34:07 -0700132
Dominik Behrda6df412016-08-02 12:56:42 -0700133 terminal_t *terminal = term_get_terminal(TERM_SPLASH_TERMINAL);
134 if (!terminal)
135 return -ENOENT;
136
David Sodmanbbcb0522014-09-19 10:34:07 -0700137 /*
138 * First draw the actual splash screen
139 */
Dominik Behrda6df412016-08-02 12:56:42 -0700140 term_set_background(terminal, splash->clear);
141 term_clear(terminal);
142 term_set_current_to(terminal);
Dominik Behrda6df412016-08-02 12:56:42 -0700143
David Sodmanf0a925a2015-05-04 11:19:19 -0700144 last_show_ms = -1;
Dominik Behrfd9fdda2016-03-28 17:16:45 -0700145 loop_count = (splash->loop_start >= 0 && splash->loop_start < splash->num_images) ? splash->loop_count : 1;
146 loop_start = (splash->loop_start >= 0 && splash->loop_start < splash->num_images) ? splash->loop_start : 0;
147
148 for (c = 0; ((loop_count < 0) ? true : (c < loop_count)); c++)
149 for (i = (c > 0) ? loop_start : 0; i < splash->num_images; i++) {
David Sodmanf0a925a2015-05-04 11:19:19 -0700150 image = splash->image_frames[i].image;
151 status = image_load_image_from_file(image);
Dominik Behr607e4dc2016-06-14 21:21:28 -0700152 if (status != 0 && ec_li < MAX_SPLASH_IMAGES) {
Dominik Behr46755a42016-04-21 18:08:33 -0700153 LOG(WARNING, "image_load_image_from_file %s failed: %d:%s.",
154 image_get_filename(image), status, strerror(status));
Dominik Behr607e4dc2016-06-14 21:21:28 -0700155 ec_li++;
David Sodman8ef20062015-01-06 09:23:40 -0800156 }
Dominik Behr607e4dc2016-06-14 21:21:28 -0700157 /*
158 * Check status again after timing code so we preserve animation
159 * frame timings and dont's monopolize CPU time.
160 */
David Sodmanf0a925a2015-05-04 11:19:19 -0700161 now_ms = get_monotonic_time_ms();
162 if (last_show_ms > 0) {
163 if (splash->loop_start >= 0 && i >= splash->loop_start)
164 duration = splash->loop_duration;
165 else
166 duration = splash->image_frames[i].duration;
167 sleep_ms = duration - (now_ms - last_show_ms);
168 if (sleep_ms > 0) {
169 sleep_spec.tv_sec = sleep_ms / MS_PER_SEC;
170 sleep_spec.tv_nsec = (sleep_ms % MS_PER_SEC) * NS_PER_MS;
171 nanosleep(&sleep_spec, NULL);
172 }
173 }
174
175 now_ms = get_monotonic_time_ms();
Dominik Behr607e4dc2016-06-14 21:21:28 -0700176 if (status != 0) {
177 goto img_error;
178 }
David Sodmanf0a925a2015-05-04 11:19:19 -0700179
180 if (i >= splash->loop_start) {
181 image_set_offset(image,
182 splash->loop_offset_x,
183 splash->loop_offset_y);
184 }
185
Dominik Behrda6df412016-08-02 12:56:42 -0700186 status = term_show_image(terminal, image);
Dominik Behr607e4dc2016-06-14 21:21:28 -0700187 if (status != 0 && ec_ts < MAX_SPLASH_IMAGES) {
Dominik Behr46755a42016-04-21 18:08:33 -0700188 LOG(WARNING, "term_show_image failed: %d:%s.", status, strerror(status));
Dominik Behr607e4dc2016-06-14 21:21:28 -0700189 ec_ts++;
190 goto img_error;
David Sodmanf0a925a2015-05-04 11:19:19 -0700191 }
Dominik Behr5f9fc7d2017-08-25 15:30:24 -0700192
193 if (!active) {
194 /*
195 * Set video mode on first frame so user does not see
196 * us drawing first frame.
197 */
198 term_activate(terminal);
199 active = true;
200 }
201
Dominik Behr44e07e62016-01-13 19:43:57 -0800202 status = main_process_events(1);
Dominik Behr607e4dc2016-06-14 21:21:28 -0700203 if (status != 0 && ec_ip < MAX_SPLASH_IMAGES) {
Dominik Behr46755a42016-04-21 18:08:33 -0700204 LOG(WARNING, "input_process failed: %d:%s.", status, strerror(status));
Dominik Behr607e4dc2016-06-14 21:21:28 -0700205 ec_ip++;
David Sodmanf0a925a2015-05-04 11:19:19 -0700206 }
Dominik Behr607e4dc2016-06-14 21:21:28 -0700207img_error:
David Sodmanf0a925a2015-05-04 11:19:19 -0700208 last_show_ms = now_ms;
209
David Sodmanf0a925a2015-05-04 11:19:19 -0700210 image_release(image);
Dominik Behr46c567f2016-03-08 15:11:48 -0800211 /* see if we can initialize DBUS */
212 if (!dbus_is_initialized())
213 dbus_init();
Dominik Behr607e4dc2016-06-14 21:21:28 -0700214 if (status != 0) {
215 break;
216 }
David Sodmanf0a925a2015-05-04 11:19:19 -0700217 }
218
219 for (i = 0; i < splash->num_images; i++) {
220 image_destroy(splash->image_frames[i].image);
221 }
222
David Sodmanbbcb0522014-09-19 10:34:07 -0700223 return status;
224}
225
David Sodman8ef20062015-01-06 09:23:40 -0800226void splash_set_offset(splash_t* splash, int32_t x, int32_t y)
227{
228 if (splash) {
229 splash->offset_x = x;
230 splash->offset_y = y;
231 }
232}
233
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800234int splash_num_images(splash_t* splash)
David Sodman8ef20062015-01-06 09:23:40 -0800235{
236 if (splash)
237 return splash->num_images;
238
239 return 0;
240}
241
Dominik Behrfd9fdda2016-03-28 17:16:45 -0700242void splash_set_loop_count(splash_t* splash, int32_t count)
243{
244 if (splash)
245 splash->loop_count = count;
246}
247
David Sodman8ef20062015-01-06 09:23:40 -0800248void splash_set_default_duration(splash_t* splash, uint32_t duration)
249{
250 if (splash)
251 splash->default_duration = duration;
252}
253
254void splash_set_loop_start(splash_t* splash, int32_t loop_start)
255{
256 if (splash)
257 splash->loop_start = loop_start;
258}
259
260void splash_set_loop_duration(splash_t* splash, uint32_t duration)
261{
262 if (splash)
263 splash->loop_duration = duration;
264}
265
266void splash_set_loop_offset(splash_t* splash, int32_t x, int32_t y)
267{
268 if (splash) {
269 splash->loop_offset_x = x;
270 splash->loop_offset_y = y;
271 }
David Sodmanbbcb0522014-09-19 10:34:07 -0700272}
David Sodmanf0a925a2015-05-04 11:19:19 -0700273
Dominik Behr92d9e312016-05-04 20:10:48 -0700274void splash_set_scale(splash_t* splash, uint32_t scale)
275{
276 if (scale > MAX_SCALE_FACTOR)
277 scale = MAX_SCALE_FACTOR;
278 if (splash)
279 splash->scale = scale;
280}
281
Dominik Behr32a7c892015-10-09 15:47:53 -0700282int splash_is_hires(splash_t* splash)
283{
Dominik Behrda6df412016-08-02 12:56:42 -0700284 terminal_t *terminal = term_get_terminal(TERM_SPLASH_TERMINAL);
285 if (!terminal)
286 return 0;
287
288 if (term_getfb(terminal))
Brian Norrisb86eb582017-12-04 12:31:06 -0800289 return image_is_hires(term_getfb(terminal));
Dominik Behr32a7c892015-10-09 15:47:53 -0700290 return 0;
291}
Dominik Behrb1abcba2016-04-14 14:57:21 -0700292
293void splash_redrm(splash_t* splash)
294{
Dominik Behrda6df412016-08-02 12:56:42 -0700295 terminal_t *terminal = term_get_terminal(TERM_SPLASH_TERMINAL);
296 if (!terminal)
297 return;
298 term_redrm(terminal);
Dominik Behrb1abcba2016-04-14 14:57:21 -0700299}