• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
2 /*
3  * Copyright 2016 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
4  */
5 
6 #include <cerrno>
7 #include <ctime>
8 #include <string>
9 
10 #include <sys/ioctl.h>
11 #include <sys/time.h>
12 
13 #include "cec-follower.h"
14 #include "compiler.h"
15 
16 #define VOLUME_MAX 0x64
17 #define VOLUME_MIN 0
18 
19 /* States for the RC handling */
20 #define NOPRESS 0
21 #define PRESS 1
22 #define PRESS_HOLD 2
23 
24 /* The follower safety timeout as defined in the spec */
25 #define FOLLOWER_SAFETY_TIMEOUT 450
26 #define MIN_INITIATOR_REP_TIME 200
27 #define MAX_INITIATOR_REP_TIME 500
28 
29 /* Time between each polling message sent to a device */
30 #define POLL_PERIOD 15000
31 
32 /* The maximum interval in nanoseconds between audio rate messages as defined in the spec */
33 #define MAX_AUD_RATE_MSG_INTERVAL_NS (2 * 1000000000ULL)
34 
35 /* The maximum interval in nanoseconds to allow a deck to skip forward/reverse */
36 #define MAX_DECK_SKIP_NS (2 * 1000000000ULL)
37 
38 struct cec_enum_values {
39 	const char *type_name;
40 	__u8 value;
41 };
42 
43 struct la_info la_info[15];
44 
45 static struct timespec start_monotonic;
46 static struct timeval start_timeofday;
47 static constexpr time_t time_to_transient = 1;
48 static constexpr time_t time_to_stable = 8;
49 
get_ui_cmd_string(__u8 ui_cmd)50 static const char *get_ui_cmd_string(__u8 ui_cmd)
51 {
52 	return cec_log_ui_cmd_string(ui_cmd) ? : "Unknown";
53 }
54 
ts2s(__u64 ts,bool wallclock)55 static std::string ts2s(__u64 ts, bool wallclock)
56 {
57 	std::string s;
58 	struct timeval sub;
59 	struct timeval res;
60 	__u64 diff;
61 	char buf[64];
62 	time_t t;
63 
64 	if (!wallclock) {
65 		sprintf(buf, "%llu.%03llus", ts / 1000000000, (ts % 1000000000) / 1000000);
66 		return buf;
67 	}
68 	diff = ts - start_monotonic.tv_sec * 1000000000ULL - start_monotonic.tv_nsec;
69 	sub.tv_sec = diff / 1000000000ULL;
70 	sub.tv_usec = (diff % 1000000000ULL) / 1000;
71 	timeradd(&start_timeofday, &sub, &res);
72 	t = res.tv_sec;
73 	s = ctime(&t);
74 	s = s.substr(0, s.length() - 6);
75 	sprintf(buf, "%03llu", (__u64)res.tv_usec / 1000);
76 	return s + "." + buf;
77 }
78 
log_event(struct cec_event & ev,bool wallclock)79 static void log_event(struct cec_event &ev, bool wallclock)
80 {
81 	__u16 pa;
82 
83 	if (ev.flags & CEC_EVENT_FL_DROPPED_EVENTS)
84 		printf("(Note: events were lost)\n");
85 	if (ev.flags & CEC_EVENT_FL_INITIAL_STATE)
86 		printf("Initial ");
87 	switch (ev.event) {
88 	case CEC_EVENT_STATE_CHANGE:
89 		pa = ev.state_change.phys_addr;
90 		printf("Event: State Change: PA: %x.%x.%x.%x, LA mask: 0x%04x\n",
91 		       cec_phys_addr_exp(pa),
92 		       ev.state_change.log_addr_mask);
93 		break;
94 	case CEC_EVENT_LOST_MSGS:
95 		printf("Event: Lost Messages\n");
96 		break;
97 	case CEC_EVENT_PIN_HPD_LOW:
98 	case CEC_EVENT_PIN_HPD_HIGH:
99 		printf("Event: HPD Pin %s\n",
100 		       ev.event == CEC_EVENT_PIN_HPD_HIGH ? "High" : "Low");
101 		warn("Unexpected HPD pin event!\n");
102 		break;
103 	case CEC_EVENT_PIN_CEC_LOW:
104 	case CEC_EVENT_PIN_CEC_HIGH:
105 		printf("Event: CEC Pin %s\n",
106 		       ev.event == CEC_EVENT_PIN_CEC_HIGH ? "High" : "Low");
107 		warn("Unexpected CEC pin event!\n");
108 		break;
109 	default:
110 		printf("Event: Unknown (0x%x)\n", ev.event);
111 		break;
112 	}
113 	if (show_info)
114 		printf("\tTimestamp: %s\n", ts2s(ev.ts, wallclock).c_str());
115 }
116 
reply_feature_abort(struct node * node,struct cec_msg * msg,__u8 reason)117 void reply_feature_abort(struct node *node, struct cec_msg *msg, __u8 reason)
118 {
119 	unsigned la = cec_msg_initiator(msg);
120 	__u8 opcode = cec_msg_opcode(msg);
121 	__u64 ts_now = get_ts();
122 
123 	if (cec_msg_is_broadcast(msg) || cec_msg_initiator(msg) == CEC_LOG_ADDR_UNREGISTERED)
124 		return;
125 	if (reason == CEC_OP_ABORT_UNRECOGNIZED_OP) {
126 		la_info[la].feature_aborted[opcode].count++;
127 		if (la_info[la].feature_aborted[opcode].count == 2) {
128 			/* If the Abort Reason was "Unrecognized opcode", the Initiator should not send
129 			   the same message to the same Follower again at that time to avoid saturating
130 			   the bus. */
131 			warn("Received message %s from LA %d (%s) shortly after\n",
132 			     opcode2s(msg).c_str(), la, cec_la2s(la));
133 			warn("replying Feature Abort [Unrecognized Opcode] to the same message.\n");
134 		}
135 	}
136 	else if (la_info[la].feature_aborted[opcode].count) {
137 		warn("Replying Feature Abort with abort reason different than [Unrecognized Opcode]\n");
138 		warn("to message that has previously been replied Feature Abort to with [Unrecognized Opcode].\n");
139 	}
140 	else
141 		la_info[la].feature_aborted[opcode].ts = ts_now;
142 
143 	cec_msg_reply_feature_abort(msg, reason);
144 	transmit(node, msg);
145 }
146 
exit_standby(struct node * node)147 static bool exit_standby(struct node *node)
148 {
149 	/* Cancel any standby request that was pending. */
150 	node->state.record_received_standby = false;
151 
152 	if (node->state.power_status == CEC_OP_POWER_STATUS_STANDBY ||
153 	    node->state.power_status == CEC_OP_POWER_STATUS_TO_STANDBY) {
154 		node->state.old_power_status = node->state.power_status;
155 		node->state.power_status = CEC_OP_POWER_STATUS_ON;
156 		node->state.power_status_changed_time = time(nullptr);
157 		dev_info("Changing state to on\n");
158 		return true;
159 	}
160 	return false;
161 }
162 
enter_standby(struct node * node)163 bool enter_standby(struct node *node)
164 {
165 	if (node->state.power_status == CEC_OP_POWER_STATUS_ON ||
166 	    node->state.power_status == CEC_OP_POWER_STATUS_TO_ON) {
167 		/*
168 		 * Standby should not interrupt a recording in progress, but
169 		 * remember to go to standby once the recording is finished.
170 		 */
171 		if (node->state.one_touch_record_on) {
172 			node->state.record_received_standby = true;
173 			return false;
174 		}
175 		node->state.old_power_status = node->state.power_status;
176 		node->state.power_status = CEC_OP_POWER_STATUS_STANDBY;
177 		node->state.power_status_changed_time = time(nullptr);
178 		node->state.deck_skip_start = 0;
179 		node->state.record_received_standby = false;
180 		dev_info("Changing state to standby\n");
181 		return true;
182 	}
183 	return false;
184 }
185 
get_duration_ms(__u64 ts_a,__u64 ts_b)186 static unsigned get_duration_ms(__u64 ts_a, __u64 ts_b)
187 {
188 	return (ts_a - ts_b) / 1000000;
189 }
190 
rc_press_hold_stop(const struct state * state)191 static void rc_press_hold_stop(const struct state *state)
192 {
193 	unsigned mean_duration = state->rc_duration_sum / state->rc_press_hold_count;
194 
195 	dev_info("Stop Press and Hold. Mean duration between User Control Pressed messages: %dms\n",
196 		 mean_duration);
197 	if (mean_duration < MIN_INITIATOR_REP_TIME) {
198 		warn("The mean duration between User Control Pressed messages is lower\n");
199 		warn("than the Minimum Initiator Repetition Time (200ms).\n");
200 	}
201 	if (mean_duration > MAX_INITIATOR_REP_TIME) {
202 		warn("The mean duration between User Control Pressed messages is higher\n");
203 		warn("than the Maximum Initiator Repetition Time (500ms).\n");
204 	}
205 }
206 
pa_common_mask(__u16 pa1,__u16 pa2)207 static __u16 pa_common_mask(__u16 pa1, __u16 pa2)
208 {
209 	__u16 mask = 0xf000;
210 
211 	for (int i = 0; i < 3; i++) {
212 		if ((pa1 & mask) != (pa2 & mask))
213 			break;
214 		mask = (mask >> 4) | 0xf000;
215 	}
216 	return mask << 4;
217 }
pa_are_adjacent(__u16 pa1,__u16 pa2)218 static bool pa_are_adjacent(__u16 pa1, __u16 pa2)
219 {
220 	const __u16 mask = pa_common_mask(pa1, pa2);
221 	const __u16 trail_mask = ((~mask) & 0xffff) >> 4;
222 
223 	if (pa1 == CEC_PHYS_ADDR_INVALID || pa2 == CEC_PHYS_ADDR_INVALID || pa1 == pa2)
224 		return false;
225 	if ((pa1 & trail_mask) || (pa2 & trail_mask))
226 		return false;
227 	return !((pa1 & ~mask) && (pa2 & ~mask));
228 }
229 
pa_is_upstream_from(__u16 pa1,__u16 pa2)230 static bool pa_is_upstream_from(__u16 pa1, __u16 pa2)
231 {
232 	const __u16 mask = pa_common_mask(pa1, pa2);
233 
234 	if (pa1 == CEC_PHYS_ADDR_INVALID || pa2 == CEC_PHYS_ADDR_INVALID)
235 		return false;
236 	return !(pa1 & ~mask) && (pa2 & ~mask);
237 }
238 
current_power_state(struct node * node)239 static __u8 current_power_state(struct node *node)
240 {
241 	time_t t = time(nullptr);
242 
243 	if (t - node->state.power_status_changed_time <= time_to_transient)
244 		return node->state.old_power_status;
245 	if (t - node->state.power_status_changed_time >= time_to_stable)
246 		return node->state.power_status;
247 	if (node->state.power_status == CEC_OP_POWER_STATUS_ON)
248 		return CEC_OP_POWER_STATUS_TO_ON;
249 	return CEC_OP_POWER_STATUS_TO_STANDBY;
250 }
251 
aud_rate_msg_interval_check(struct node * node,__u64 ts_new)252 static void aud_rate_msg_interval_check(struct node *node, __u64 ts_new)
253 {
254 	/*
255 	 * The interval since the last audio rate message is only relevant
256 	 * if the Source is currently in audio rate controlled mode
257 	 * (i.e. state.last_aud_rate_rx_ts != 0).
258 	 */
259 	__u64 ts_old = node->state.last_aud_rate_rx_ts;
260 
261 	if (ts_old) {
262 		__u64 interval = ts_new - ts_old;
263 
264 		if (interval > MAX_AUD_RATE_MSG_INTERVAL_NS) {
265 			warn("The interval since the last Audio Rate Control message was > 2s.\n");
266 			node->state.last_aud_rate_rx_ts = 0;
267 		}
268 	}
269 }
270 
update_deck_state(struct node * node,unsigned me,__u8 deck_state_new)271 static void update_deck_state(struct node *node, unsigned me, __u8 deck_state_new)
272 {
273 	if (node->state.deck_state != deck_state_new) {
274 		node->state.deck_state = deck_state_new;
275 
276 		if (node->state.deck_report_changes) {
277 			struct cec_msg msg;
278 
279 			cec_msg_init(&msg, me, node->state.deck_report_changes_to);
280 			cec_msg_deck_status(&msg, node->state.deck_state);
281 			transmit(node, &msg);
282 		}
283 	}
284 }
285 
processMsg(struct node * node,struct cec_msg & msg,unsigned me,__u8 type)286 static void processMsg(struct node *node, struct cec_msg &msg, unsigned me, __u8 type)
287 {
288 	__u8 to = cec_msg_destination(&msg);
289 	__u8 from = cec_msg_initiator(&msg);
290 	bool is_bcast = cec_msg_is_broadcast(&msg);
291 	__u16 remote_pa = (from < 15) ? node->remote_phys_addr[from] : CEC_PHYS_ADDR_INVALID;
292 
293 	switch (msg.msg[1]) {
294 
295 		/* OSD Display */
296 
297 	case CEC_MSG_SET_OSD_STRING: {
298 		__u8 disp_ctl;
299 		char osd[14];
300 
301 		if (to != 0 && to != 14)
302 			break;
303 		if (!node->has_osd_string)
304 			break;
305 
306 		cec_ops_set_osd_string(&msg, &disp_ctl, osd);
307 		switch (disp_ctl) {
308 		case CEC_OP_DISP_CTL_DEFAULT:
309 		case CEC_OP_DISP_CTL_UNTIL_CLEARED:
310 		case CEC_OP_DISP_CTL_CLEAR:
311 			return;
312 		}
313 		cec_msg_reply_feature_abort(&msg, CEC_OP_ABORT_INVALID_OP);
314 		transmit(node, &msg);
315 		return;
316 	}
317 
318 
319 		/* Give Device Power Status */
320 
321 	case CEC_MSG_GIVE_DEVICE_POWER_STATUS:
322 		cec_msg_set_reply_to(&msg, &msg);
323 		cec_msg_report_power_status(&msg, current_power_state(node));
324 		transmit(node, &msg);
325 		return;
326 
327 	case CEC_MSG_REPORT_POWER_STATUS:
328 		// Nothing to do here for now.
329 		return;
330 
331 
332 		/* Standby */
333 
334 	case CEC_MSG_STANDBY:
335 		if (!node->ignore_standby || (++node->standby_cnt % node->ignore_standby))
336 			enter_standby(node);
337 		return;
338 
339 
340 		/* One Touch Play and Routing Control */
341 
342 	case CEC_MSG_ACTIVE_SOURCE: {
343 		__u16 phys_addr;
344 
345 		cec_ops_active_source(&msg, &phys_addr);
346 		node->state.active_source_pa = phys_addr;
347 		dev_info("New active source: %x.%x.%x.%x\n", cec_phys_addr_exp(phys_addr));
348 		return;
349 	}
350 	case CEC_MSG_INACTIVE_SOURCE: {
351 		__u16 phys_addr;
352 
353 		if (node->phys_addr)
354 			break;
355 
356 		cec_ops_active_source(&msg, &phys_addr);
357 		if (node->state.active_source_pa != phys_addr)
358 			break;
359 		node->state.active_source_pa = 0;
360 		cec_msg_init(&msg, me, CEC_LOG_ADDR_BROADCAST);
361 		cec_msg_active_source(&msg, node->phys_addr);
362 		transmit(node, &msg);
363 		dev_info("New active source: 0.0.0.0\n");
364 		return;
365 	}
366 	case CEC_MSG_IMAGE_VIEW_ON:
367 	case CEC_MSG_TEXT_VIEW_ON:
368 		if (!cec_has_tv(1 << me))
369 			break;
370 		if (!node->ignore_view_on || (++node->view_on_cnt % node->ignore_view_on))
371 			exit_standby(node);
372 		return;
373 	case CEC_MSG_SET_STREAM_PATH: {
374 		__u16 phys_addr;
375 
376 		cec_ops_set_stream_path(&msg, &phys_addr);
377 		if (phys_addr != node->phys_addr)
378 			return;
379 
380 		if (!cec_has_tv(1 << me))
381 			exit_standby(node);
382 
383 		cec_msg_init(&msg, me, CEC_LOG_ADDR_BROADCAST);
384 		cec_msg_active_source(&msg, node->phys_addr);
385 		transmit(node, &msg);
386 		dev_info("Stream Path is directed to this device\n");
387 		return;
388 	}
389 	case CEC_MSG_ROUTING_INFORMATION: {
390 		__u8 la = cec_msg_initiator(&msg);
391 
392 		if (cec_has_tv(1 << la) && la_info[la].phys_addr == 0)
393 			warn("TV (0) at 0.0.0.0 sent Routing Information.");
394 		return;
395 	}
396 
397 		/* System Information */
398 
399 	case CEC_MSG_GET_MENU_LANGUAGE:
400 		if (!cec_has_tv(1 << me))
401 			break;
402 		cec_msg_set_reply_to(&msg, &msg);
403 		cec_msg_set_menu_language(&msg, node->state.menu_language);
404 		transmit(node, &msg);
405 		return;
406 	case CEC_MSG_CEC_VERSION:
407 		return;
408 	case CEC_MSG_REPORT_PHYSICAL_ADDR: {
409 		__u16 phys_addr;
410 		__u8 prim_dev_type;
411 
412 		cec_ops_report_physical_addr(&msg, &phys_addr, &prim_dev_type);
413 		if (from < 15) {
414 			node->remote_phys_addr[from] = phys_addr;
415 			node->remote_prim_devtype[from] = prim_dev_type;
416 		}
417 		return;
418 	}
419 
420 
421 		/* Remote Control Passthrough
422 		   (System Audio Control, Device Menu Control) */
423 
424 	case CEC_MSG_USER_CONTROL_PRESSED: {
425 		struct cec_op_ui_command rc_press;
426 		unsigned new_state;
427 		unsigned duration;
428 
429 		cec_ops_user_control_pressed(&msg, &rc_press);
430 		duration = get_duration_ms(msg.rx_ts, node->state.rc_press_rx_ts);
431 
432 		new_state = PRESS;
433 		if (node->state.rc_state == NOPRESS)
434 			dev_info("Button press: %s\n", get_ui_cmd_string(rc_press.ui_cmd));
435 		else if (rc_press.ui_cmd != node->state.rc_ui_cmd) {
436 			/* We have not yet received User Control Released, but have received
437 			   another User Control Pressed with a different UI Command. */
438 			if (node->state.rc_state == PRESS_HOLD)
439 				rc_press_hold_stop(&node->state);
440 			dev_info("Button press (no User Control Released between): %s\n",
441 				 get_ui_cmd_string(rc_press.ui_cmd));
442 
443 			/* The device shall send User Control Released if the time between
444 			   two messages is longer than the maximum Initiator Repetition Time. */
445 			if (duration > MAX_INITIATOR_REP_TIME)
446 				warn("Device waited more than the maximum Initiatior Repetition Time and should have sent a User Control Released message.");
447 		} else if (duration < FOLLOWER_SAFETY_TIMEOUT) {
448 			/* We have not yet received a User Control Released, but received
449 			   another User Control Pressed, with the same UI Command as the
450 			   previous, which means that the Press and Hold behavior should
451 			   be invoked. */
452 			new_state = PRESS_HOLD;
453 			if (node->state.rc_state != PRESS_HOLD) {
454 				dev_info("Start Press and Hold with button %s\n",
455 					 get_ui_cmd_string(rc_press.ui_cmd));
456 				node->state.rc_duration_sum = 0;
457 				node->state.rc_press_hold_count = 0;
458 			}
459 			node->state.rc_duration_sum += duration;
460 			node->state.rc_press_hold_count++;
461 		}
462 
463 		node->state.rc_state = new_state;
464 		node->state.rc_ui_cmd = rc_press.ui_cmd;
465 		node->state.rc_press_rx_ts = msg.rx_ts;
466 
467 		switch (rc_press.ui_cmd) {
468 		case CEC_OP_UI_CMD_VOLUME_UP:
469 			if (node->state.volume < VOLUME_MAX)
470 				node->state.volume++;
471 			break;
472 		case CEC_OP_UI_CMD_VOLUME_DOWN:
473 			if (node->state.volume > VOLUME_MIN)
474 				node->state.volume--;
475 			break;
476 		case CEC_OP_UI_CMD_MUTE:
477 			node->state.mute = !node->state.mute;
478 			break;
479 		case CEC_OP_UI_CMD_MUTE_FUNCTION:
480 			node->state.mute = true;
481 			break;
482 		case CEC_OP_UI_CMD_RESTORE_VOLUME_FUNCTION:
483 			node->state.mute = false;
484 			break;
485 		case CEC_OP_UI_CMD_POWER_TOGGLE_FUNCTION:
486 			if (!enter_standby(node))
487 				exit_standby(node);
488 			break;
489 		case CEC_OP_UI_CMD_POWER_OFF_FUNCTION:
490 			enter_standby(node);
491 			break;
492 		case CEC_OP_UI_CMD_POWER_ON_FUNCTION:
493 			exit_standby(node);
494 			break;
495 		}
496 		if (rc_press.ui_cmd >= CEC_OP_UI_CMD_VOLUME_UP && rc_press.ui_cmd <= CEC_OP_UI_CMD_MUTE) {
497 			dev_info("Volume: %d%s\n", node->state.volume, node->state.mute ? ", muted" : "");
498 			cec_msg_set_reply_to(&msg, &msg);
499 			cec_msg_report_audio_status(&msg, node->state.mute ? 1 : 0, node->state.volume);
500 			transmit(node, &msg);
501 		}
502 
503 		return;
504 	}
505 	case CEC_MSG_USER_CONTROL_RELEASED:
506 		if (node->state.rc_state == PRESS_HOLD)
507 			rc_press_hold_stop(&node->state);
508 
509 		if (node->state.rc_state == NOPRESS)
510 			dev_info("Button release (unexpected, %ums after last press)\n",
511 				 ts_to_ms(msg.rx_ts - node->state.rc_press_rx_ts));
512 		else if (get_duration_ms(msg.rx_ts, node->state.rc_press_rx_ts) > FOLLOWER_SAFETY_TIMEOUT)
513 			dev_info("Button release: %s (after timeout, %ums after last press)\n",
514 				 get_ui_cmd_string(node->state.rc_ui_cmd),
515 				 ts_to_ms(msg.rx_ts - node->state.rc_press_rx_ts));
516 		else
517 			dev_info("Button release: %s (%ums after last press)\n",
518 				 get_ui_cmd_string(node->state.rc_ui_cmd),
519 				 ts_to_ms(msg.rx_ts - node->state.rc_press_rx_ts));
520 		node->state.rc_state = NOPRESS;
521 		return;
522 
523 
524 		/* Device Menu Control */
525 
526 	case CEC_MSG_MENU_REQUEST: {
527 		if (node->cec_version < CEC_OP_CEC_VERSION_2_0 &&
528 		    !cec_has_tv(1 << me)) {
529 			cec_msg_set_reply_to(&msg, &msg);
530 			cec_msg_menu_status(&msg, CEC_OP_MENU_STATE_ACTIVATED);
531 			transmit(node, &msg);
532 			return;
533 		}
534 		break;
535 	}
536 	case CEC_MSG_MENU_STATUS:
537 		if (node->cec_version < CEC_OP_CEC_VERSION_2_0 &&
538 		    cec_has_tv(1 << me))
539 			return;
540 		break;
541 
542 
543 		/* Deck Control */
544 
545 	case CEC_MSG_GIVE_DECK_STATUS:
546 		if (!node->has_deck_ctl)
547 			break;
548 
549 		__u8 status_req;
550 		cec_ops_give_deck_status(&msg, &status_req);
551 
552 		switch (status_req) {
553 		case CEC_OP_STATUS_REQ_ON:
554 			node->state.deck_report_changes = true;
555 			node->state.deck_report_changes_to = cec_msg_initiator(&msg);
556 			fallthrough;
557 		case CEC_OP_STATUS_REQ_ONCE:
558 			cec_msg_set_reply_to(&msg, &msg);
559 			cec_msg_deck_status(&msg, node->state.deck_state);
560 			transmit(node, &msg);
561 			return;
562 		case CEC_OP_STATUS_REQ_OFF:
563 			node->state.deck_report_changes = false;
564 			return;
565 		default:
566 			reply_feature_abort(node, &msg, CEC_OP_ABORT_INVALID_OP);
567 			return;
568 		}
569 	case CEC_MSG_PLAY:
570 		if (!node->has_deck_ctl)
571 			break;
572 
573 		__u8 deck_state;
574 		__u8 play_mode;
575 
576 		cec_ops_play(&msg, &play_mode);
577 
578 		switch (play_mode) {
579 		case CEC_OP_PLAY_MODE_PLAY_FWD:
580 			exit_standby(node);
581 			deck_state = CEC_OP_DECK_INFO_PLAY;
582 			break;
583 		case CEC_OP_PLAY_MODE_PLAY_REV:
584 			deck_state = CEC_OP_DECK_INFO_PLAY_REV;
585 			break;
586 		case CEC_OP_PLAY_MODE_PLAY_STILL:
587 			deck_state = CEC_OP_DECK_INFO_STILL;
588 			break;
589 		case CEC_OP_PLAY_MODE_PLAY_FAST_FWD_MIN:
590 		case CEC_OP_PLAY_MODE_PLAY_FAST_FWD_MED:
591 		case CEC_OP_PLAY_MODE_PLAY_FAST_FWD_MAX:
592 			deck_state = CEC_OP_DECK_INFO_FAST_FWD;
593 			break;
594 		case CEC_OP_PLAY_MODE_PLAY_FAST_REV_MIN:
595 		case CEC_OP_PLAY_MODE_PLAY_FAST_REV_MED:
596 		case CEC_OP_PLAY_MODE_PLAY_FAST_REV_MAX:
597 			deck_state = CEC_OP_DECK_INFO_FAST_REV;
598 			break;
599 		case CEC_OP_PLAY_MODE_PLAY_SLOW_FWD_MIN:
600 		case CEC_OP_PLAY_MODE_PLAY_SLOW_FWD_MED:
601 		case CEC_OP_PLAY_MODE_PLAY_SLOW_FWD_MAX:
602 			deck_state = CEC_OP_DECK_INFO_SLOW;
603 			break;
604 		case CEC_OP_PLAY_MODE_PLAY_SLOW_REV_MIN:
605 		case CEC_OP_PLAY_MODE_PLAY_SLOW_REV_MED:
606 		case CEC_OP_PLAY_MODE_PLAY_SLOW_REV_MAX:
607 			deck_state = CEC_OP_DECK_INFO_SLOW_REV;
608 			break;
609 		default:
610 			cec_msg_reply_feature_abort(&msg, CEC_OP_ABORT_INVALID_OP);
611 			transmit(node, &msg);
612 			return;
613 		}
614 		/* Only Play Forward and Play Still will close tray if open. */
615 		if (play_mode != CEC_OP_PLAY_MODE_PLAY_FWD &&
616 		    play_mode != CEC_OP_PLAY_MODE_PLAY_STILL &&
617 		    node->state.deck_state == CEC_OP_DECK_INFO_NO_MEDIA) {
618 			reply_feature_abort(node, &msg, CEC_OP_ABORT_INCORRECT_MODE);
619 			return;
620 		}
621 		node->state.deck_skip_start = 0;
622 		update_deck_state(node, me, deck_state);
623 		return;
624 	case CEC_MSG_DECK_CONTROL:
625 		if (!node->has_deck_ctl)
626 			break;
627 
628 		__u8 deck_control_mode;
629 
630 		cec_ops_deck_control(&msg, &deck_control_mode);
631 
632 		switch (deck_control_mode) {
633 		case CEC_OP_DECK_CTL_MODE_STOP:
634 			deck_state = CEC_OP_DECK_INFO_STOP;
635 			node->state.deck_skip_start = 0;
636 			break;
637 		case CEC_OP_DECK_CTL_MODE_EJECT:
638 			exit_standby(node);
639 			deck_state = CEC_OP_DECK_INFO_NO_MEDIA;
640 			node->state.deck_skip_start = 0;
641 			break;
642 		case CEC_OP_DECK_CTL_MODE_SKIP_FWD:
643 			/* Skip Forward will not retract the deck tray. */
644 			if (node->state.deck_state == CEC_OP_DECK_INFO_NO_MEDIA) {
645 				reply_feature_abort(node, &msg, CEC_OP_ABORT_INCORRECT_MODE);
646 				return;
647 			}
648 			deck_state = CEC_OP_DECK_INFO_SKIP_FWD;
649 			node->state.deck_skip_start = msg.rx_ts;
650 			break;
651 		case CEC_OP_DECK_CTL_MODE_SKIP_REV:
652 			/* Skip Reverse will not retract the deck tray. */
653 			if (node->state.deck_state == CEC_OP_DECK_INFO_NO_MEDIA) {
654 				reply_feature_abort(node, &msg, CEC_OP_ABORT_INCORRECT_MODE);
655 				return;
656 			}
657 			deck_state = CEC_OP_DECK_INFO_SKIP_REV;
658 			node->state.deck_skip_start = msg.rx_ts;
659 			break;
660 		default:
661 			cec_msg_reply_feature_abort(&msg, CEC_OP_ABORT_INVALID_OP);
662 			transmit(node, &msg);
663 			return;
664 		}
665 		update_deck_state(node, me, deck_state);
666 		return;
667 	case CEC_MSG_DECK_STATUS:
668 		return;
669 
670 	/* Tuner/Record/Timer Messages */
671 
672 	case CEC_MSG_GIVE_TUNER_DEVICE_STATUS:
673 	case CEC_MSG_TUNER_DEVICE_STATUS:
674 	case CEC_MSG_SELECT_ANALOGUE_SERVICE:
675 	case CEC_MSG_SELECT_DIGITAL_SERVICE:
676 	case CEC_MSG_TUNER_STEP_DECREMENT:
677 	case CEC_MSG_TUNER_STEP_INCREMENT:
678 		process_tuner_msgs(node, msg, me, type);
679 		return;
680 	case CEC_MSG_RECORD_TV_SCREEN:
681 	case CEC_MSG_RECORD_ON:
682 	case CEC_MSG_RECORD_OFF:
683 	case CEC_MSG_RECORD_STATUS:
684 		process_record_msgs(node, msg, me, type);
685 		return;
686 	case CEC_MSG_SET_ANALOGUE_TIMER:
687 	case CEC_MSG_SET_DIGITAL_TIMER:
688 	case CEC_MSG_SET_EXT_TIMER:
689 	case CEC_MSG_CLEAR_ANALOGUE_TIMER:
690 	case CEC_MSG_CLEAR_DIGITAL_TIMER:
691 	case CEC_MSG_CLEAR_EXT_TIMER:
692 	case CEC_MSG_SET_TIMER_PROGRAM_TITLE:
693 	case CEC_MSG_TIMER_CLEARED_STATUS:
694 	case CEC_MSG_TIMER_STATUS:
695 		process_timer_msgs(node, msg, me, type);
696 		return;
697 
698 		/* Dynamic Auto Lipsync */
699 
700 	case CEC_MSG_REQUEST_CURRENT_LATENCY: {
701 		__u16 phys_addr;
702 
703 		cec_ops_request_current_latency(&msg, &phys_addr);
704 		if (phys_addr == node->phys_addr) {
705 			cec_msg_init(&msg, me, from);
706 			cec_msg_report_current_latency(&msg, phys_addr,
707 						       node->state.video_latency,
708 						       node->state.low_latency_mode,
709 						       node->state.audio_out_compensated,
710 						       node->state.audio_out_delay);
711 			transmit(node, &msg);
712 		}
713 		return;
714 	}
715 
716 
717 		/* Audio Return Channel Control */
718 
719 	case CEC_MSG_INITIATE_ARC:
720 		if (node->sink_has_arc_tx) {
721 			if (!pa_is_upstream_from(node->phys_addr, remote_pa) ||
722 			    !pa_are_adjacent(node->phys_addr, remote_pa)) {
723 				cec_msg_reply_feature_abort(&msg, CEC_OP_ABORT_REFUSED);
724 				transmit(node, &msg);
725 				return;
726 			}
727 			cec_msg_set_reply_to(&msg, &msg);
728 			cec_msg_report_arc_initiated(&msg);
729 			transmit(node, &msg);
730 			node->state.arc_active = true;
731 			dev_info("ARC is initiated");
732 			return;
733 		}
734 		break;
735 	case CEC_MSG_TERMINATE_ARC:
736 		if (node->sink_has_arc_tx) {
737 			if (!pa_is_upstream_from(node->phys_addr, remote_pa) ||
738 			    !pa_are_adjacent(node->phys_addr, remote_pa)) {
739 				cec_msg_reply_feature_abort(&msg, CEC_OP_ABORT_REFUSED);
740 				transmit(node, &msg);
741 				return;
742 			}
743 			cec_msg_set_reply_to(&msg, &msg);
744 			cec_msg_report_arc_terminated(&msg);
745 			transmit(node, &msg);
746 			node->state.arc_active = false;
747 			dev_info("ARC is terminated\n");
748 			return;
749 		}
750 		break;
751 	case CEC_MSG_REQUEST_ARC_INITIATION:
752 		if (node->source_has_arc_rx) {
753 			if (pa_is_upstream_from(node->phys_addr, remote_pa) ||
754 			    !pa_are_adjacent(node->phys_addr, remote_pa)) {
755 				cec_msg_reply_feature_abort(&msg, CEC_OP_ABORT_REFUSED);
756 				transmit(node, &msg);
757 				return;
758 			}
759 			cec_msg_set_reply_to(&msg, &msg);
760 			cec_msg_initiate_arc(&msg, false);
761 			transmit(node, &msg);
762 			dev_info("ARC initiation has been requested.");
763 			return;
764 		}
765 		break;
766 	case CEC_MSG_REQUEST_ARC_TERMINATION:
767 		if (node->source_has_arc_rx) {
768 			if (pa_is_upstream_from(node->phys_addr, remote_pa) ||
769 			    !pa_are_adjacent(node->phys_addr, remote_pa)) {
770 				cec_msg_reply_feature_abort(&msg, CEC_OP_ABORT_REFUSED);
771 				transmit(node, &msg);
772 				return;
773 			}
774 			cec_msg_set_reply_to(&msg, &msg);
775 			cec_msg_terminate_arc(&msg, false);
776 			transmit(node, &msg);
777 			dev_info("ARC initiation has been requested.");
778 			return;
779 		}
780 		break;
781 	case CEC_MSG_REPORT_ARC_INITIATED:
782 		node->state.arc_active = true;
783 		dev_info("ARC is initiated\n");
784 		return;
785 	case CEC_MSG_REPORT_ARC_TERMINATED:
786 		node->state.arc_active = false;
787 		dev_info("ARC is terminated\n");
788 		return;
789 
790 
791 		/* System Audio Control */
792 
793 	case CEC_MSG_SYSTEM_AUDIO_MODE_REQUEST: {
794 		if (!cec_has_audiosystem(1 << me))
795 			break;
796 
797 		__u16 phys_addr;
798 
799 		cec_ops_system_audio_mode_request(&msg, &phys_addr);
800 		cec_msg_init(&msg, me, CEC_LOG_ADDR_BROADCAST);
801 		if (phys_addr != CEC_PHYS_ADDR_INVALID) {
802 			cec_msg_set_system_audio_mode(&msg, CEC_OP_SYS_AUD_STATUS_ON);
803 			transmit(node, &msg);
804 			node->state.sac_active = true;
805 		}
806 		else {
807 			cec_msg_set_system_audio_mode(&msg, CEC_OP_SYS_AUD_STATUS_OFF);
808 			transmit(node, &msg);
809 			node->state.sac_active = false;
810 		}
811 		dev_info("System Audio Mode: %s\n", node->state.sac_active ? "on" : "off");
812 		return;
813 	}
814 	case CEC_MSG_SET_SYSTEM_AUDIO_MODE: {
815 		__u8 system_audio_status;
816 
817 		if (!cec_msg_is_broadcast(&msg)) {
818 			/* Directly addressed Set System Audio Mode is used to see
819 			   if the TV supports the feature. If we time out, we
820 			   signalize that we support SAC. */
821 			if (cec_has_tv(1 << me))
822 				return;
823 
824 			break;
825 		}
826 		cec_ops_set_system_audio_mode(&msg, &system_audio_status);
827 		if (system_audio_status == CEC_OP_SYS_AUD_STATUS_ON)
828 			node->state.sac_active = true;
829 		else if (system_audio_status == CEC_OP_SYS_AUD_STATUS_OFF)
830 			node->state.sac_active = false;
831 		dev_info("System Audio Mode: %s\n", node->state.sac_active ? "on" : "off");
832 		return;
833 	}
834 	case CEC_MSG_REPORT_AUDIO_STATUS:
835 		return;
836 	case CEC_MSG_GIVE_SYSTEM_AUDIO_MODE_STATUS:
837 		if (!cec_has_audiosystem(1 << me))
838 			break;
839 		cec_msg_set_reply_to(&msg, &msg);
840 		cec_msg_system_audio_mode_status(&msg, node->state.sac_active ? CEC_OP_SYS_AUD_STATUS_ON :
841 						 CEC_OP_SYS_AUD_STATUS_OFF);
842 		transmit(node, &msg);
843 		fallthrough;
844 	case CEC_MSG_GIVE_AUDIO_STATUS:
845 		if (!cec_has_audiosystem(1 << me))
846 			break;
847 		cec_msg_set_reply_to(&msg, &msg);
848 		cec_msg_report_audio_status(&msg, node->state.mute ? 1 : 0, node->state.volume);
849 		transmit(node, &msg);
850 		return;
851 	case CEC_MSG_SYSTEM_AUDIO_MODE_STATUS:
852 		return;
853 	case CEC_MSG_REQUEST_SHORT_AUDIO_DESCRIPTOR: {
854 		if (!cec_has_audiosystem(1 << me))
855 			break;
856 
857 		/* The list of formats that the follower 'supports' */
858 		const struct short_audio_desc supported_formats[] = {
859 			{ 2, SAD_FMT_CODE_AC3,
860 			  SAD_SAMPLE_FREQ_MASK_32 | SAD_SAMPLE_FREQ_MASK_44_1,
861 			  { 64 }, 0, 0 },
862 			{ 4, SAD_FMT_CODE_AC3,
863 			  SAD_SAMPLE_FREQ_MASK_32,
864 			  { 32 }, 0, 0 },
865 			{ 4, SAD_FMT_CODE_ONE_BIT_AUDIO,
866 			  SAD_SAMPLE_FREQ_MASK_48 | SAD_SAMPLE_FREQ_MASK_192,
867 			  { 123 }, 0, 0 },
868 			{ 8, SAD_FMT_CODE_EXTENDED,
869 			  SAD_SAMPLE_FREQ_MASK_96,
870 			  { 0 }, 0, SAD_EXT_TYPE_DRA },
871 			{ 2, SAD_FMT_CODE_EXTENDED,
872 			  SAD_SAMPLE_FREQ_MASK_176_4,
873 			  { SAD_FRAME_LENGTH_MASK_960 | SAD_FRAME_LENGTH_MASK_1024 }, 1, SAD_EXT_TYPE_MPEG4_HE_AAC_SURROUND },
874 			{ 2, SAD_FMT_CODE_EXTENDED,
875 			  SAD_SAMPLE_FREQ_MASK_44_1,
876 			  { SAD_BIT_DEPTH_MASK_16 | SAD_BIT_DEPTH_MASK_24 }, 0, SAD_EXT_TYPE_LPCM_3D_AUDIO },
877 		};
878 
879 		__u8 num_descriptors, audio_format_id[4], audio_format_code[4];
880 		__u32 descriptors[4];
881 		std::string format_list;
882 
883 		cec_ops_request_short_audio_descriptor(&msg, &num_descriptors, audio_format_id, audio_format_code);
884 		if (num_descriptors == 0) {
885 			warn("Got Request Short Audio Descriptor with no operands");
886 			reply_feature_abort(node, &msg, CEC_OP_ABORT_INVALID_OP);
887 			return;
888 		}
889 
890 		unsigned found_descs = 0;
891 
892 		for (int i = 0; i < num_descriptors; i++)
893 			format_list += audio_format_id_code2s(audio_format_id[i], audio_format_code[i]) + ",";
894 		format_list.erase(format_list.end() - 1);
895 		dev_info("Requested descriptors: %s\n", format_list.c_str());
896 		for (unsigned i = 0; i < num_descriptors; i++) {
897 			for (const auto &supported_format : supported_formats) {
898 				if (found_descs >= 4)
899 					break;
900 				if ((audio_format_id[i] == 0 &&
901 				     audio_format_code[i] == supported_format.format_code) ||
902 				    (audio_format_id[i] == 1 &&
903 				     audio_format_code[i] == supported_format.extension_type_code))
904 					sad_encode(&supported_format, &descriptors[found_descs++]);
905 			}
906 		}
907 
908 		if (found_descs > 0) {
909 			cec_msg_set_reply_to(&msg, &msg);
910 			cec_msg_report_short_audio_descriptor(&msg, found_descs, descriptors);
911 			transmit(node, &msg);
912 		}
913 		else
914 			reply_feature_abort(node, &msg, CEC_OP_ABORT_INVALID_OP);
915 		return;
916 	}
917 
918 
919 		/* Device OSD Transfer */
920 
921 	case CEC_MSG_SET_OSD_NAME:
922 		return;
923 
924 
925 		/* Audio Rate Control */
926 
927 	case CEC_MSG_SET_AUDIO_RATE:
928 		if (!node->has_aud_rate)
929 			break;
930 
931 		switch (msg.msg[2]) {
932 		case CEC_OP_AUD_RATE_OFF:
933 			aud_rate_msg_interval_check(node, msg.rx_ts);
934 			node->state.last_aud_rate_rx_ts = 0;
935 			return;
936 		case CEC_OP_AUD_RATE_WIDE_STD:
937 		case CEC_OP_AUD_RATE_WIDE_FAST:
938 		case CEC_OP_AUD_RATE_WIDE_SLOW:
939 		case CEC_OP_AUD_RATE_NARROW_STD:
940 		case CEC_OP_AUD_RATE_NARROW_FAST:
941 		case CEC_OP_AUD_RATE_NARROW_SLOW:
942 			aud_rate_msg_interval_check(node, msg.rx_ts);
943 			node->state.last_aud_rate_rx_ts = msg.rx_ts;
944 			return;
945 		default:
946 			cec_msg_reply_feature_abort(&msg, CEC_OP_ABORT_INVALID_OP);
947 			transmit(node, &msg);
948 			break;
949 		}
950 		break;
951 
952 
953 		/* CDC */
954 
955 	case CEC_MSG_CDC_MESSAGE: {
956 		switch (msg.msg[4]) {
957 		case CEC_MSG_CDC_HEC_DISCOVER:
958 			__u16 phys_addr;
959 
960 			cec_msg_init(&msg, me, CEC_LOG_ADDR_BROADCAST);
961 			cec_ops_cdc_hec_discover(&msg, &phys_addr);
962 			cec_msg_cdc_hec_report_state(&msg, phys_addr,
963 						     CEC_OP_HEC_FUNC_STATE_NOT_SUPPORTED,
964 						     CEC_OP_HOST_FUNC_STATE_NOT_SUPPORTED,
965 						     CEC_OP_ENC_FUNC_STATE_EXT_CON_NOT_SUPPORTED,
966 						     CEC_OP_CDC_ERROR_CODE_NONE,
967 						     1, 0); // We do not support HEC on any HDMI connections
968 			transmit(node, &msg);
969 			return;
970 		}
971 	}
972 
973 
974 		/* Core */
975 
976 	case CEC_MSG_FEATURE_ABORT:
977 		return;
978 	default:
979 		break;
980 	}
981 
982 	if (is_bcast)
983 		return;
984 
985 	reply_feature_abort(node, &msg);
986 }
987 
poll_remote_devs(struct node * node,unsigned me)988 static void poll_remote_devs(struct node *node, unsigned me)
989 {
990 	node->remote_la_mask = 0;
991 	for (unsigned short & i : node->remote_phys_addr)
992 		i = CEC_PHYS_ADDR_INVALID;
993 
994 	if (!(node->caps & CEC_CAP_TRANSMIT))
995 		return;
996 
997 	for (unsigned i = 0; i < 15; i++) {
998 		struct cec_msg msg;
999 
1000 		cec_msg_init(&msg, me, i);
1001 
1002 		doioctl(node, CEC_TRANSMIT, &msg);
1003 		if (msg.tx_status & CEC_TX_STATUS_OK) {
1004 			node->remote_la_mask |= 1 << i;
1005 			cec_msg_init(&msg, me, i);
1006 			cec_msg_give_physical_addr(&msg, true);
1007 			doioctl(node, CEC_TRANSMIT, &msg);
1008 			if (cec_msg_status_is_ok(&msg))
1009 				node->remote_phys_addr[i] = (msg.msg[2] << 8) | msg.msg[3];
1010 		}
1011 	}
1012 }
1013 
update_programmed_timers(struct node * node)1014 static void update_programmed_timers(struct node *node)
1015 {
1016 	auto it = programmed_timers.begin();
1017 	/* Use the current minute because timers do not have second precision. */
1018 	time_t current_minute = time(nullptr) / 60;
1019 	time_t timer_start_minute = it->start_time / 60;
1020 	time_t timer_end_minute = (it->start_time + it->duration) / 60;
1021 
1022 	/* Start the timed recording only if the deck is not already recording. */
1023 	if (timer_start_minute == current_minute && !node->state.one_touch_record_on) {
1024 		node->state.one_touch_record_on = true;
1025 		node->state.recording_controlled_by_timer = true;
1026 		print_timers(node);
1027 	}
1028 
1029 	/* Delete an overlapped timer. Recording will be at best incomplete. */
1030 	if (timer_start_minute < current_minute &&
1031 	    (!node->state.recording_controlled_by_timer || !node->state.one_touch_record_on)) {
1032 		programmed_timers.erase(*it);
1033 		if (show_info)
1034 			printf("Deleted overlapped timer.\n");
1035 		print_timers(node);
1036 	}
1037 
1038 	if (timer_end_minute != current_minute || !node->state.recording_controlled_by_timer)
1039 		return;
1040 
1041 	/* Delete finished timers. */
1042 	node->state.one_touch_record_on = false;
1043 	node->state.recording_controlled_by_timer = false;
1044 	node->state.media_space_available -= it->duration; /* 1 MB per second */
1045 	/*
1046 	 * TODO: We are only ever decreasing the amount of space available,
1047 	 * there is no heuristic that reclaims the space.
1048 	 */
1049 
1050 	if (it->recording_seq) {
1051 		struct tm *last_start_time = localtime(&(it->start_time));
1052 		int next_wday = (last_start_time->tm_wday + 1) % 7;
1053 		int days_to_move_ahead = 1;
1054 
1055 		while ((it->recording_seq & (1 << next_wday)) == 0) {
1056 			days_to_move_ahead++;
1057 			next_wday = (next_wday + 1) % 7;
1058 		}
1059 		struct Timer next_timer = {};
1060 		next_timer = *it;
1061 		last_start_time->tm_mday += days_to_move_ahead;
1062 		last_start_time->tm_isdst = -1;
1063 		next_timer.start_time = mktime(last_start_time);
1064 		programmed_timers.insert(next_timer);
1065 	}
1066 	programmed_timers.erase(*it);
1067 	if (show_info)
1068 		printf("Deleted finished timer.\n");
1069 	print_timers(node);
1070 	/*
1071 	 * If the finished timer was recording, and standby was received during recording,
1072 	 * enter standby when the recording stops unless recording device is the active source.
1073 	 */
1074 	if (node->state.record_received_standby) {
1075 		if (node->phys_addr != node->state.active_source_pa)
1076 			enter_standby(node);
1077 		node->state.record_received_standby = false;
1078 	}
1079 }
1080 
testProcessing(struct node * node,bool exclusive,bool wallclock)1081 void testProcessing(struct node *node, bool exclusive, bool wallclock)
1082 {
1083 	struct cec_log_addrs laddrs;
1084 	fd_set rd_fds;
1085 	fd_set ex_fds;
1086 	int fd = node->fd;
1087 	__u32 mode = CEC_MODE_INITIATOR |
1088 		(exclusive ? CEC_MODE_EXCL_FOLLOWER : CEC_MODE_FOLLOWER);
1089 	unsigned me;
1090 	unsigned last_poll_la = 15;
1091 	__u8 last_pwr_state = current_power_state(node);
1092 	time_t last_pwr_status_toggle = time(nullptr);
1093 
1094 	clock_gettime(CLOCK_MONOTONIC, &start_monotonic);
1095 	gettimeofday(&start_timeofday, nullptr);
1096 
1097 	doioctl(node, CEC_S_MODE, &mode);
1098 	doioctl(node, CEC_ADAP_G_LOG_ADDRS, &laddrs);
1099 	me = laddrs.log_addr[0];
1100 	__u8 type = laddrs.log_addr_type[0];
1101 
1102 	poll_remote_devs(node, me);
1103 
1104 	while (true) {
1105 		int res;
1106 		struct timeval timeval = {};
1107 
1108 		fflush(stdout);
1109 		timeval.tv_sec = 1;
1110 		FD_ZERO(&rd_fds);
1111 		FD_ZERO(&ex_fds);
1112 		FD_SET(fd, &rd_fds);
1113 		FD_SET(fd, &ex_fds);
1114 		res = select(fd + 1, &rd_fds, nullptr, &ex_fds, &timeval);
1115 		if (res < 0)
1116 			break;
1117 		if (FD_ISSET(fd, &ex_fds)) {
1118 			struct cec_event ev;
1119 
1120 			res = doioctl(node, CEC_DQEVENT, &ev);
1121 			if (res == ENODEV) {
1122 				printf("Device was disconnected.\n");
1123 				break;
1124 			}
1125 			if (res)
1126 				continue;
1127 			log_event(ev, wallclock);
1128 			if (ev.event == CEC_EVENT_STATE_CHANGE) {
1129 				dev_info("CEC adapter state change.\n");
1130 				node->phys_addr = ev.state_change.phys_addr;
1131 				node->adap_la_mask = ev.state_change.log_addr_mask;
1132 				if (node->adap_la_mask) {
1133 					doioctl(node, CEC_ADAP_G_LOG_ADDRS, &laddrs);
1134 					me = laddrs.log_addr[0];
1135 				} else {
1136 					node->state.active_source_pa = CEC_PHYS_ADDR_INVALID;
1137 					me = CEC_LOG_ADDR_INVALID;
1138 				}
1139 				memset(la_info, 0, sizeof(la_info));
1140 			}
1141 		}
1142 		if (FD_ISSET(fd, &rd_fds)) {
1143 			struct cec_msg msg = { };
1144 
1145 			res = doioctl(node, CEC_RECEIVE, &msg);
1146 			if (res == ENODEV) {
1147 				printf("Device was disconnected.\n");
1148 				break;
1149 			}
1150 			if (res)
1151 				continue;
1152 
1153 			__u8 from = cec_msg_initiator(&msg);
1154 			__u8 to = cec_msg_destination(&msg);
1155 			__u8 opcode = cec_msg_opcode(&msg);
1156 
1157 			if (node->ignore_la[from])
1158 				continue;
1159 			if (node->ignore_opcode[msg.msg[1]] & (1 << from))
1160 				continue;
1161 
1162 			if (from != CEC_LOG_ADDR_UNREGISTERED &&
1163 			    la_info[from].feature_aborted[opcode].ts &&
1164 			    ts_to_ms(get_ts() - la_info[from].feature_aborted[opcode].ts) < 200) {
1165 				warn("Received message %s from LA %d (%s) less than 200 ms after\n",
1166 				     opcode2s(&msg).c_str(), from, cec_la2s(from));
1167 				warn("replying Feature Abort (not [Unrecognized Opcode]) to the same message.\n");
1168 			}
1169 			if (from != CEC_LOG_ADDR_UNREGISTERED && !la_info[from].ts)
1170 				dev_info("Logical address %d (%s) discovered.\n", from, cec_la2s(from));
1171 			if (show_msgs) {
1172 				printf("    %s to %s (%d to %d): ",
1173 				       cec_la2s(from), to == 0xf ? "all" : cec_la2s(to), from, to);
1174 				cec_log_msg(&msg);
1175 				if (show_info)
1176 					printf("\tSequence: %u Rx Timestamp: %s\n",
1177 					       msg.sequence, ts2s(msg.rx_ts, wallclock).c_str());
1178 			}
1179 			if (node->adap_la_mask)
1180 				processMsg(node, msg, me, type);
1181 		}
1182 
1183 		__u8 pwr_state = current_power_state(node);
1184 		if (node->cec_version >= CEC_OP_CEC_VERSION_2_0 &&
1185 		    last_pwr_state != pwr_state &&
1186 		    (time_to_stable > 2 || pwr_state < CEC_OP_POWER_STATUS_TO_ON)) {
1187 			struct cec_msg msg;
1188 
1189 			cec_msg_init(&msg, me, CEC_LOG_ADDR_BROADCAST);
1190 			cec_msg_report_power_status(&msg, pwr_state);
1191 			transmit(node, &msg);
1192 			last_pwr_state = pwr_state;
1193 		}
1194 
1195 		if (node->state.toggle_power_status && cec_has_tv(1 << me) &&
1196 		    (time(nullptr) - last_pwr_status_toggle > node->state.toggle_power_status)) {
1197 			last_pwr_status_toggle = time(nullptr);
1198 			if (pwr_state & 1) // standby or to-standby
1199 				exit_standby(node);
1200 			else
1201 				enter_standby(node);
1202 		}
1203 
1204 		__u64 ts_now = get_ts();
1205 		unsigned poll_la = ts_to_s(ts_now) % 16;
1206 
1207 		if (poll_la != me &&
1208 		    poll_la != last_poll_la && poll_la < 15 && la_info[poll_la].ts &&
1209 		    ts_to_ms(ts_now - la_info[poll_la].ts) > POLL_PERIOD) {
1210 			struct cec_msg msg;
1211 
1212 			cec_msg_init(&msg, me, poll_la);
1213 			transmit(node, &msg);
1214 			if (msg.tx_status & CEC_TX_STATUS_NACK) {
1215 				dev_info("Logical address %d stopped responding to polling message.\n", poll_la);
1216 				memset(&la_info[poll_la], 0, sizeof(la_info[poll_la]));
1217 				node->remote_la_mask &= ~(1 << poll_la);
1218 				node->remote_phys_addr[poll_la] = CEC_PHYS_ADDR_INVALID;
1219 			}
1220 		}
1221 		last_poll_la = poll_la;
1222 
1223 		unsigned ms_since_press = ts_to_ms(ts_now - node->state.rc_press_rx_ts);
1224 
1225 		if (ms_since_press > FOLLOWER_SAFETY_TIMEOUT) {
1226 			if (node->state.rc_state == PRESS_HOLD)
1227 				rc_press_hold_stop(&node->state);
1228 			else if (node->state.rc_state == PRESS) {
1229 				dev_info("Button timeout: %s\n", get_ui_cmd_string(node->state.rc_ui_cmd));
1230 				node->state.rc_state = NOPRESS;
1231 			}
1232 		}
1233 
1234 		if (node->has_aud_rate)
1235 			aud_rate_msg_interval_check(node, ts_now);
1236 
1237 		if (node->state.deck_skip_start && ts_now - node->state.deck_skip_start > MAX_DECK_SKIP_NS) {
1238 			node->state.deck_skip_start = 0;
1239 			update_deck_state(node, me, CEC_OP_DECK_INFO_PLAY);
1240 		}
1241 
1242 		if (!programmed_timers.empty())
1243 			update_programmed_timers(node);
1244 	}
1245 	mode = CEC_MODE_INITIATOR;
1246 	doioctl(node, CEC_S_MODE, &mode);
1247 }
1248