Branch data Line data Source code
1 : : /**
2 : : * @file ow_stats.c
3 : : * @brief 1-Wire signal statistics implementation.
4 : : * @see ow_stats.h for the public API.
5 : : */
6 : :
7 : : #include "ow_stats.h"
8 : : #include "ds18b20.h"
9 : :
10 : : #ifdef OW_STATS_ENABLE
11 : :
12 : : #include "app.h"
13 : : #include <string.h>
14 : :
15 : : #if defined(OW_PORT_FAMILY_G0)
16 : : #include "stm32g0xx.h"
17 : : #elif defined(OW_PORT_FAMILY_F0)
18 : : #include "stm32f0xx.h"
19 : : #else
20 : : #include "stm32f1xx.h"
21 : : #endif
22 : :
23 : : /* ---- private state ---- */
24 : :
25 : : static ow_stats_t st;
26 : :
27 : : /** Non-blocking dump state. */
28 : : static uint32_t dump_phase; /**< 0 = idle, 1+ = active */
29 : : static uint32_t dump_sensor; /**< current sensor index */
30 : :
31 : : /* ---- histogram helpers ---- */
32 : :
33 : 3373992 : static uint8_t hist_bucket(uint8_t pulse) {
34 [ + + ]: 3373992 : if (pulse <= 2) return 0;
35 [ + + ]: 3373884 : if (pulse <= 4) return 1;
36 [ + + ]: 3373860 : if (pulse <= 6) return 2;
37 [ + + ]: 3367938 : if (pulse <= 9) return 3;
38 [ + + ]: 3367902 : if (pulse <= 12) return 4;
39 [ + + ]: 7200 : if (pulse <= 14) return 5;
40 [ + + ]: 7188 : if (pulse <= 19) return 6;
41 [ + + ]: 7098 : if (pulse <= 24) return 7;
42 [ + + ]: 7038 : if (pulse <= 29) return 8;
43 [ + + ]: 7026 : if (pulse <= 39) return 9;
44 [ + + ]: 7014 : if (pulse <= 49) return 10;
45 [ + + ]: 7002 : if (pulse <= 59) return 11;
46 : 6978 : return 12;
47 : : }
48 : :
49 : : /* ---- sensor lookup ---- */
50 : :
51 : 420420 : static uint8_t sensor_find_or_alloc(const uint8_t* rom) {
52 [ + + ]: 420420 : if (!rom) return OW_STATS_MAX_SENSORS;
53 [ + + ]: 420534 : for (uint8_t i = 0; i < st.sensor_count; i++) {
54 [ + + ]: 420306 : if (memcmp(st.sensors[i].rom, rom, 8) == 0) return i;
55 : : }
56 [ + + ]: 228 : if (st.sensor_count < OW_STATS_MAX_SENSORS) {
57 : 222 : uint8_t idx = st.sensor_count++;
58 : 222 : memcpy(st.sensors[idx].rom, rom, 8);
59 : 222 : st.sensors[idx].min_pulse = 0xFF;
60 : 222 : st.sensors[idx].max_pulse = 0;
61 : 222 : return idx;
62 : : }
63 : 6 : return OW_STATS_MAX_SENSORS;
64 : : }
65 : :
66 : : /* ---- public API ---- */
67 : :
68 : 1858 : void ow_stats_init(void) {
69 : 1858 : memset(&st, 0, sizeof(st));
70 : 1858 : dump_phase = 0;
71 : 1858 : }
72 : :
73 : 420312 : void ow_stats_capture_pulse(const volatile uint8_t* pulse, uint8_t n,
74 : : const uint8_t* rom) {
75 : 420312 : uint8_t si = sensor_find_or_alloc(rom);
76 [ + + ]: 3794304 : for (uint8_t i = 0; i < n; i++) {
77 : 3373992 : uint8_t p = pulse[i];
78 : 3373992 : st.histogram[hist_bucket(p)]++;
79 [ + + ]: 3373992 : if (si < OW_STATS_MAX_SENSORS) {
80 [ + + ]: 3365952 : if (p < st.sensors[si].min_pulse) st.sensors[si].min_pulse = p;
81 [ + + ]: 3365952 : if (p > st.sensors[si].max_pulse) st.sensors[si].max_pulse = p;
82 : : }
83 : : }
84 [ + + ]: 420312 : if (si < OW_STATS_MAX_SENSORS) {
85 : 420168 : st.sensors[si].count++;
86 : : }
87 : 420312 : }
88 : :
89 : 108 : void ow_stats_count_error(int16_t error, const uint8_t* rom) {
90 : 108 : uint8_t si = sensor_find_or_alloc(rom);
91 [ + + ]: 108 : if (si < OW_STATS_MAX_SENSORS) {
92 [ + + + ]: 102 : switch (error) {
93 : 78 : case DS18B20_TEMP_ERROR_CRC_FAIL:
94 : 78 : st.sensors[si].crc_err++;
95 : 78 : break;
96 : 18 : case DS18B20_TEMP_ERROR_NO_SENSOR:
97 : 18 : st.sensors[si].no_presence++;
98 : 18 : break;
99 : 6 : default:
100 : 6 : st.sensors[si].generic_err++;
101 : 6 : break;
102 : : }
103 : : }
104 : 108 : st.total_errors++;
105 : 108 : }
106 : :
107 : 12 : void ow_stats_dump_start(void) {
108 : 12 : dump_phase = 1;
109 : 12 : dump_sensor = 0;
110 : 12 : }
111 : :
112 : 30 : uint8_t ow_stats_dump_poll(void) {
113 [ - + ]: 30 : if (dump_phase == 0) return 1;
114 : :
115 : : /* Each poll call enqueues one line into the non-blocking UART TX ring
116 : : * buffer. The main loop drains the buffer via uart_poll_tx(), so nothing
117 : : * here blocks on the USART. UART_TX_BUF_SIZE is chosen per app (default
118 : : * 128 B, demos 256 B, demo5 1024 B) so the longest single line fits
119 : : * without overflowing; the dump itself streams across poll calls. */
120 [ + + + + : 30 : switch (dump_phase) {
- ]
121 : 6 : case 1:
122 : 6 : uart_write_str("--- stats [");
123 : 6 : uart_write_int(st.total_cycles);
124 : 6 : uart_write_str(" c] ---\r\n");
125 : 6 : dump_phase = 2;
126 : 6 : dump_sensor = 0;
127 : 6 : break;
128 : :
129 : 12 : case 2:
130 [ + + ]: 12 : if (dump_sensor < st.sensor_count) {
131 : 6 : const ow_stats_sensor_t* s = &st.sensors[dump_sensor];
132 [ + + ]: 54 : for (uint32_t j = 0; j < 8; j++) {
133 : 48 : uart_write_hex(s->rom[j]);
134 [ + + ]: 48 : if (j != 7) uart_tx_enqueue_byte(' ');
135 : : }
136 : 6 : uart_tx_enqueue_byte(':');
137 : 6 : uart_write_int(s->min_pulse);
138 : 6 : uart_tx_enqueue_byte('-');
139 : 6 : uart_write_int(s->max_pulse);
140 : 6 : uart_tx_enqueue_byte(' ');
141 : 6 : uart_tx_enqueue_byte('n');
142 : 6 : uart_write_int(s->count);
143 : 6 : uart_tx_enqueue_byte(' ');
144 : 6 : uart_tx_enqueue_byte('e');
145 : 6 : uart_write_int(s->crc_err + s->no_presence + s->generic_err);
146 : 6 : uart_write_str("\r\n");
147 : 6 : dump_sensor++;
148 : : } else {
149 : 6 : dump_phase = 3;
150 : : }
151 : 12 : break;
152 : :
153 : 6 : case 3:
154 : 6 : uart_write_str("h:");
155 [ + + ]: 102 : for (uint32_t i = 0; i < OW_STATS_HIST_BUCKETS; i++) {
156 [ + + ]: 96 : if (st.histogram[i]) {
157 : 6 : uart_write_int(i);
158 : 6 : uart_tx_enqueue_byte('=');
159 : 6 : uart_write_int(st.histogram[i]);
160 : 6 : uart_tx_enqueue_byte(' ');
161 : : }
162 : : }
163 : 6 : uart_write_str("\r\n");
164 : 6 : dump_phase = 4;
165 : 6 : break;
166 : :
167 : 6 : case 4:
168 : 6 : uart_write_str("t=");
169 : 6 : uart_write_int(st.total_cycles);
170 : 6 : uart_write_str("c ");
171 : 6 : uart_write_int(st.total_errors);
172 : 6 : uart_write_str("e\r\n");
173 : 6 : dump_phase = 0;
174 : 6 : break;
175 : : }
176 : :
177 : 30 : return (dump_phase == 0) ? 1 : 0;
178 : : }
179 : :
180 : 6 : void ow_stats_reset(void) {
181 : 6 : uint32_t n = st.sensor_count;
182 : : uint8_t roms[OW_STATS_MAX_SENSORS][8];
183 [ + + ]: 12 : for (uint32_t i = 0; i < n; i++) {
184 : 6 : memcpy(roms[i], st.sensors[i].rom, 8);
185 : : }
186 : 6 : memset(&st, 0, sizeof(st));
187 [ + + ]: 12 : for (uint32_t i = 0; i < n; i++) {
188 : 6 : memcpy(st.sensors[i].rom, roms[i], 8);
189 : 6 : st.sensors[i].min_pulse = 0xFF;
190 : : }
191 : 6 : st.sensor_count = n;
192 : 6 : }
193 : :
194 : 420036 : uint32_t ow_stats_tick(void) {
195 : 420036 : return ++st.total_cycles;
196 : : }
197 : :
198 : : #endif /* OW_STATS_ENABLE */
|