summaryrefslogtreecommitdiff
path: root/include/object/ptalog.h
blob: 9d070ab49d77d566877bbf003f5443bacb58563a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
/*
 * Copyright 2020 Daniel Friesel
 *
 * SPDX-License-Identifier: BSD-2-Clause
 */
#ifndef PTALOG_H
#define PTALOG_H

#include <stdlib.h>
#include "driver/stdout.h"

#ifdef PTALOG_GPIO
#include "driver/gpio.h"
#if defined(PTALOG_GPIO_BEFORE) || defined(PTALOG_GPIO_BAR)
#include "arch.h"
#endif
#endif

#ifdef PTALOG_TIMING
#include "driver/counter.h"
#endif

class PTALog {

	private:
		PTALog(const PTALog& copy);
#ifdef PTALOG_GPIO
		uint8_t sync_pin;
#endif

	public:
		typedef struct {
			uint8_t transition_id;
#ifdef PTALOG_TIMING
			counter_value_t timer;
			counter_overflow_t overflow;
			counter_value_t prev_state_timer;
			counter_overflow_t prev_state_overflow;
#endif
#ifdef PTALOG_WITH_RETURNVALUES
			uint16_t return_value;
#endif
		} log_entry;

		int const max_entry = 15;

		log_entry log[16];
		uint8_t log_index;

#ifdef PTALOG_GPIO
		PTALog(uint8_t pin_number) : sync_pin(pin_number), log_index(0) {}
#else
		PTALog() : log_index(0) {}
#endif

		void passTransition(uint8_t transition_id)
		{
			log[log_index].transition_id = transition_id;
			if (log_index < max_entry) {
				log_index++;
			}
		}

#ifdef PTALOG_TIMING
		/*
		 * This function is meant to estimate the overhead of counter.start()
		 * and counter.stop(). It immediately restarts the counter to ensure that
		 * state durations are captured accurately.
		 * This means that the overflow value is unusable. We assume that there
		 * are no overflows in this short time span.
		 */
		inline void passNop()
		{
			counter.start();
			counter.stop();
			counter.start(); // .value is kept until .stop
			kout << "[PTA] nop=" << counter.value << "/" << 0 << endl;
		}
#endif

		void reset()
		{
			log_index = 0;
		}

		void startBenchmark(uint8_t id)
		{
			kout << "[PTA] benchmark start, id=" << dec << id << endl;
#ifdef PTALOG_GPIO
			gpio.output(sync_pin);
#endif
		}

		void stopBenchmark()
		{
#ifdef PTALOG_TIMING
			counter.stop();
			kout << "[PTA] benchmark stop, cycles=" << counter.value << "/" << counter.overflow << endl;
#else
			kout << "[PTA] benchmark stop" << endl;
#endif
		}

		void dump(uint16_t trace_id)
		{
			kout << "[PTA] trace=" << dec << trace_id << " count=" << log_index << endl;
			for (uint8_t i = 0; i < log_index; i++) {
				kout << "[PTA] transition=" << log[i].transition_id;
#ifdef PTALOG_TIMING
				kout << " prevcycles=" << log[i].prev_state_timer << "/" << log[i].prev_state_overflow;
				kout << " cycles=" << log[i].timer << "/" << log[i].overflow;
#endif
#ifdef PTALOG_WITH_RETURNVALUES
				kout << " return=" << log[i].return_value;
#endif
				kout << endl;
			}
		}

#ifdef PTALOG_GPIO_BAR
		void startTransition(char const *code, uint8_t code_length)
		{
			counter.stop();
			log[log_index - 1].prev_state_timer = counter.value;
			log[log_index - 1].prev_state_overflow = counter.overflow;
			// Quiet zone (must last at least 10x longer than a module)
			arch.sleep_ms(60);
			for (uint8_t byte = 0; byte < code_length; byte++) {
				for (uint16_t mask = 0x01; mask <= 0x80; mask <<= 1) {
					// a single module, which is part of a bar
					gpio.write(sync_pin, code[byte] & mask ? 1 : 0);
					arch.sleep_ms(5);
				}
			}
			gpio.write(sync_pin, 0);
			// Quiet zone
			arch.sleep_ms(60);
			counter.start();
		}
#else
		inline void startTransition()
		{
#ifdef PTALOG_GPIO_BEFORE
			gpio.write(sync_pin, 1);
			arch.sleep_ms(10);
			gpio.write(sync_pin, 0);
			arch.sleep_ms(10);
#endif
#ifdef PTALOG_TIMING
			counter.stop();
			log[log_index - 1].prev_state_timer = counter.value;
			log[log_index - 1].prev_state_overflow = counter.overflow;
			counter.start();
#endif
#ifndef PTALOG_GPIO_BEFORE
			gpio.write(sync_pin, 1);
#endif
		}
#endif

#ifdef PTALOG_WITH_RETURNVALUES
		inline void logReturn(uint16_t ret)
		{
			log[log_index - 1].return_value = ret;
		}
#endif

		inline void stopTransition()
		{
#ifdef PTALOG_GPIO
#if !defined(PTALOG_GPIO_BEFORE) && !defined(PTALOG_GPIO_BAR)
			gpio.write(sync_pin, 0);
#endif
#endif
#ifdef PTALOG_TIMING
			counter.stop();
			log[log_index - 1].timer = counter.value;
			log[log_index - 1].overflow = counter.overflow;
			counter.start();
#endif
		}
};

#endif