1 /* Copyright 2020 The Chromium OS Authors. All rights reserved.
2  * Use of this source code is governed by a BSD-style license that can be
3  * found in the LICENSE file.
4  */
5 
6 #ifndef PACKET_STATUS_LOGGER_
7 #define PACKET_STATUS_LOGGER_
8 
9 #include <stdint.h>
10 #include <stdbool.h>
11 
12 #define PACKET_STATUS_LEN_BYTES 64
13 #define WBS_FRAME_NS 7500000
14 
15 /* Avoid 32, 40, 64 consecutive hex characters so CrOS feedback redact
16  * tool doesn't trim our dump. */
17 #define PACKET_STATUS_LOG_LINE_WRAP 50
18 
19 /*
20  * Object to log consecutive packets' status.
21  * Members:
22  *    data - Bytes to store packets' status.
23  *    size - Total number of bits in |data|.
24  *    wp - Position of the next bit to log packet status.
25  *    num_wraps - Number of times the ring buffer has wrapped.
26  *    ts - The timestamp of the last time when the first bit of |data| updated.
27  */
28 struct packet_status_logger {
29 	uint8_t data[PACKET_STATUS_LEN_BYTES];
30 	int size;
31 	int wp;
32 	int num_wraps;
33 	struct timespec ts;
34 };
35 
36 /* Initializes the packet status logger. */
37 void packet_status_logger_init(struct packet_status_logger *logger);
38 
39 /* Updates the next packet status to logger. */
40 void packet_status_logger_update(struct packet_status_logger *logger, bool val);
41 
42 /* Rewinds logger's time stamp to calculate the beginning.
43  * If logger's ring buffer hasn't wrapped, simply return logger_ts.
44  * Otherwise beginning_ts = logger_ts - WBS_FRAME_NS * (size - wp)
45  */
46 static inline void
packet_status_logger_begin_ts(const struct packet_status_logger * logger,struct timespec * ts)47 packet_status_logger_begin_ts(const struct packet_status_logger *logger,
48 			      struct timespec *ts)
49 {
50 	long nsec = WBS_FRAME_NS * (logger->size - logger->wp);
51 
52 	*ts = logger->ts;
53 	if (logger->num_wraps == 0)
54 		return;
55 	while (nsec > 1000000000L) {
56 		ts->tv_sec--;
57 		nsec -= 1000000000L;
58 	}
59 	ts->tv_nsec -= nsec;
60 	if (ts->tv_nsec < 0) {
61 		ts->tv_sec--;
62 		ts->tv_nsec += 1000000000L;
63 	}
64 }
65 
66 /* Fast-forwards the logger's time stamp to calculate the end.
67  * In other words, end_ts = logger_ts + WBS_FRAME_NS * wp
68  */
69 static inline void
packet_status_logger_end_ts(const struct packet_status_logger * logger,struct timespec * ts)70 packet_status_logger_end_ts(const struct packet_status_logger *logger,
71 			    struct timespec *ts)
72 {
73 	*ts = logger->ts;
74 	ts->tv_nsec += WBS_FRAME_NS * logger->wp;
75 	while (ts->tv_nsec > 1000000000L) {
76 		ts->tv_sec++;
77 		ts->tv_nsec -= 1000000000L;
78 	}
79 }
80 
81 /* Prints the logger data in hex format */
82 static inline void
packet_status_logger_dump_hex(const struct packet_status_logger * logger)83 packet_status_logger_dump_hex(const struct packet_status_logger *logger)
84 {
85 	int i = logger->wp / 8;
86 
87 	/* Print the bits after wp only if buffer has wrapped. */
88 	if (logger->num_wraps) {
89 		if (logger->wp % 8)
90 			printf("%.2x",
91 			       logger->data[i] & (0xff << (logger->wp % 8)));
92 		for (; i < PACKET_STATUS_LEN_BYTES; i++)
93 			printf("%.2x", logger->data[i]);
94 	}
95 	for (i = 0; i < logger->wp / 8; i++)
96 		printf("%.2x", logger->data[i]);
97 	if (logger->wp % 8)
98 		printf("%.2x", logger->data[i] & (~(0xff << (logger->wp % 8))));
99 	printf("\n");
100 }
101 
102 /* Prints the logger data in binary format */
103 static inline void
packet_status_logger_dump_binary(const struct packet_status_logger * logger)104 packet_status_logger_dump_binary(const struct packet_status_logger *logger)
105 {
106 	/* Don't print the bits after wp if buffer hasn't wrapped. */
107 	int head = logger->num_wraps ? logger->wp : 0;
108 	int len = logger->num_wraps ? logger->size : logger->wp;
109 	int i, j;
110 
111 	for (i = 0; i < len; ++i) {
112 		j = (head + i) % logger->size;
113 		printf("%d", (logger->data[j / 8] >> (j % 8)) & 1U);
114 		if ((i + 1) % PACKET_STATUS_LOG_LINE_WRAP == 0)
115 			printf("\n");
116 	}
117 	/* Fill indicator digit 'D' until the last line wraps. */
118 	if (len % PACKET_STATUS_LOG_LINE_WRAP) {
119 		while (len % PACKET_STATUS_LOG_LINE_WRAP) {
120 			printf("D");
121 			++len;
122 		}
123 		printf("\n");
124 	}
125 }
126 
127 #endif /* PACKET_STATUS_LOGGER_ */
128