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