Branch data Line data Source code
1 : : #include "onewire.h"
2 : : #include "ow_port.h"
3 : :
4 : : #ifdef OW_PORT_LOW_POWER
5 : : /** @brief Set by the driver while a long stage (>1ms) is running, read by the
6 : : * low-power application. Shared across translation units. */
7 : : uint8_t ow_long_pending = 0;
8 : : #endif
9 : :
10 : : /**
11 : : * @defgroup ONEWIRE_Private_Constants ONEWIRE Private Constants
12 : : * @{
13 : : */
14 : :
15 : : /** @brief Minimum reset pulse duration in microseconds */
16 : : #define RESET_PULSE_MIN 480U
17 : : /** @brief Maximum reset pulse duration in microseconds */
18 : : #define RESET_PULSE_MAX 540U
19 : : /** @brief Minimum presence pulse positive width in microseconds */
20 : : #define POSITIVE_WIDTH_MIN 15U
21 : : /** @brief Maximum presence pulse positive width in microseconds */
22 : : #define POSITIVE_WIDTH_MAX 60U
23 : : /** @brief Minimum presence pulse negative width in microseconds */
24 : : #define NEGATIVE_WIDTH_MIN 60U
25 : : /** @brief Maximum presence pulse negative width in microseconds */
26 : : #define NEGATIVE_WIDTH_MAX 240U
27 : : /** @brief Calculated minimum presence pulse timing */
28 : : #define PRESENCE_PULSE_MIN (RESET_PULSE_MIN + POSITIVE_WIDTH_MIN + NEGATIVE_WIDTH_MIN)
29 : : /** @brief Calculated maximum presence pulse timing */
30 : : #define PRESENCE_PULSE_MAX (RESET_PULSE_MAX + POSITIVE_WIDTH_MAX + NEGATIVE_WIDTH_MAX)
31 : : /** @brief CRC8 polynomial of the Dallas/Maxim 1-Wire algorithm */
32 : : #define ONEWIRE_CRC8_POLY 0x8C
33 : :
34 : : /** @} */
35 : :
36 : : static const onewire_timing_t timing_profiles[ONEWIRE_TIMING_COUNT] = {
37 : : [ONEWIRE_TIMING_FAST] = {5, 60, 3, 50, 10},
38 : : [ONEWIRE_TIMING_STANDARD] = {5, 60, 5, 100, 10},
39 : : [ONEWIRE_TIMING_SLOW] = {8, 90, 20, 200, 15},
40 : : [ONEWIRE_TIMING_ROBUST] = {10, 110, 30, 250, 18},
41 : : [ONEWIRE_TIMING_CUSTOM] = {1, 60, 1, 1, 15},
42 : : };
43 : :
44 : : static onewire_timing_profile_t ow_profile = ONEWIRE_TIMING_PROFILE_DEFAULT;
45 : : static uint8_t ow_parasite_flag = 0;
46 : : uint8_t ow_one_pulse_us = ONEWIRE_ONE_PULSE;
47 : : uint8_t ow_zero_pulse_us = ONEWIRE_ZERO_PULSE;
48 : : uint8_t ow_guard_band_us = ONEWIRE_GUARD_BAND;
49 : : uint8_t ow_short_pulse_max_us = ONEWIRE_SHORT_PULSE_MAX;
50 : : static uint8_t search_read_pulse[3];
51 : :
52 : 619 : void ow_set_parasite_guard(uint8_t parasite) {
53 [ + + ]: 619 : ow_parasite_flag = parasite ? 1u : 0u;
54 [ + + ]: 619 : ow_guard_band_us = ow_parasite_flag ? timing_profiles[ow_profile].parasite_guard_band
55 : 469 : : timing_profiles[ow_profile].guard_band;
56 : 619 : }
57 : :
58 : 469 : void onewire_set_timing_profile(onewire_timing_profile_t profile) {
59 [ + + ]: 469 : if (profile >= ONEWIRE_TIMING_COUNT) {
60 : 12 : return;
61 : : }
62 : 457 : ow_profile = profile;
63 : 457 : ow_one_pulse_us = timing_profiles[profile].one_pulse;
64 : 457 : ow_zero_pulse_us = timing_profiles[profile].zero_pulse;
65 : 457 : ow_short_pulse_max_us = timing_profiles[profile].short_pulse_max;
66 : 457 : search_read_pulse[0] = ow_one_pulse_us;
67 : 457 : search_read_pulse[1] = ow_one_pulse_us;
68 : 457 : search_read_pulse[2] = 0;
69 : 457 : ow_set_parasite_guard(ow_parasite_flag);
70 : : }
71 : :
72 : 42 : onewire_timing_profile_t onewire_get_timing_profile(void) {
73 : 42 : return ow_profile;
74 : : }
75 : :
76 : : /**
77 : : * @defgroup ONEWIRE_Private_Variables ONEWIRE Private Variables
78 : : * @{
79 : : */
80 : :
81 : : /** @brief Capture buffer for the merged search write+read operation
82 : : * @note Holds [write-slot capture, id pulse, cmp pulse]. The CH4 input capture
83 : : * runs for the whole timer pass, so the write-slot capture lands in entry
84 : : * 0 as well; id/cmp are decoded from the pulse durations in entries 1
85 : : * and 2. */
86 : : static volatile uint16_t search_pulse3[3];
87 : :
88 : : /** @brief Read pulse durations reloaded by DMA for the merged search operation
89 : : * (the CCR3 feed DMA reads from this). Entry 0 is loaded at the CH2
90 : : * end-of-slot compare at the end of slot 1 and sets the read slot 2
91 : : * length, entry 1 sets slot 3, and the trailing 0 is written during
92 : : * slot 3 so the one-pulse timer stops with the line released to idle
93 : : * HIGH (hardware bus release). */
94 : :
95 : : /** @brief Pulse capture buffer used by the search engine for bus resets and
96 : : * plain id/cmp pair reads (the merged write+read uses search_pulse3). */
97 : : static volatile uint16_t search_pair_pulse[OW_PORT_CAPTURE_BUF_SIZE];
98 : :
99 : : /** @brief Search state machine phases */
100 : : typedef enum {
101 : : ONEWIRE_SEARCH_RESET, /**< reset scheduled; check presence, send the search command */
102 : : ONEWIRE_SEARCH_CMD, /**< search command sent; prepare first bit iteration */
103 : : ONEWIRE_SEARCH_READ_PAIR, /**< first id/cmp pair read; compute and write direction */
104 : : ONEWIRE_SEARCH_WRITE_READ, /**< merged direction write + next pair read completed */
105 : : ONEWIRE_SEARCH_WRITE_DIR, /**< final direction written; advance bit counters */
106 : : ONEWIRE_SEARCH_DONE, /**< search finished; restore the owner state */
107 : : #ifdef DS18B20_TEST_HARNESS
108 : : ONEWIRE_SEARCH_GAP /**< [TEST] timed idle-HIGH gap before the next slot */
109 : : #endif
110 : : } onewire_search_phase_t;
111 : :
112 : : /**
113 : : * @brief Non-blocking search context
114 : : * @note Holds the loop counters of the search algorithm; the persistent pulse
115 : : * buffer (pulses) must stay valid across poll calls because the DMA
116 : : * feeds CCR3 from it asynchronously while the search command is sent.
117 : : */
118 : : typedef struct {
119 : : onewire_search_phase_t phase; /**< Current phase of the search state machine */
120 : : uint8_t command; /**< Search command byte (0xF0 Search ROM / 0xEC Alarm Search) */
121 : : uint8_t family; /**< 1-Wire family code to accept, or 0 to accept every family */
122 : : uint8_t rom[ONEWIRE_ROM_BYTES]; /**< ROM being assembled (bit by bit) */
123 : : uint8_t pulses[ONEWIRE_BITS_PER_BYTE + 1]; /**< Pulse buffer for the search command (+ trailing 0 for hardware bus release) */
124 : : uint8_t id_bit_number; /**< Current bit position (1..64) */
125 : : uint16_t last_discrepancy; /**< Last discrepancy point (Maxim algorithm) */
126 : : uint16_t last_zero; /**< Last position where the '0' branch was taken */
127 : : uint8_t found; /**< Number of accepted devices found */
128 : : uint8_t max; /**< Maximum number of devices to report */
129 : : uint8_t finished; /**< 1 once the search has completed */
130 : : onewire_search_sink_t sink; /**< Per-device callback */
131 : : } onewire_search_ctx_t;
132 : :
133 : : /** @brief Global search context instance */
134 : : static onewire_search_ctx_t search_ctx;
135 : :
136 : : #ifdef DS18B20_TEST_HARNESS
137 : : /** @brief [TEST] Idle-HIGH gap (µs) inserted after every completed search
138 : : * operation before scheduling the next one (0 = no gap). */
139 : : static uint16_t test_gap_us;
140 : : /** @brief [TEST] Search phase to resume after the gap wait completes */
141 : : static uint8_t test_gap_pending_phase;
142 : : #endif
143 : :
144 : : /** @} */
145 : :
146 : : /**
147 : : * @defgroup ONEWIRE_Bus_Impl ONEWIRE Non-Blocking Bus Primitives
148 : : * @{
149 : : */
150 : :
151 : 415 : void onewire_init(void) {
152 : : // No search running after init: lets the slave driver own the timer until
153 : : // the application starts a search.
154 : 415 : search_ctx.finished = 1;
155 : : // Enable clocks, configure the timer prescaler, bus pin AF open-drain.
156 : : ow_port_init();
157 : 415 : onewire_set_timing_profile(ONEWIRE_TIMING_PROFILE_DEFAULT);
158 : : #ifdef OW_PORT_LOW_POWER
159 : : // WFE Sleep Triggering: a pending interrupt wakes the core from WFE as an
160 : : // event even though no ISR is enabled. Done once here; the corresponding
161 : : // pending bit is cleared in ow_port_bus_done(). NVIC_EnableIRQ is never
162 : : // called — the project has no ISR vector for TIM1 at all.
163 : 209 : SCB->SCR |= SCB_SCR_SEVONPEND_Msk;
164 : : #endif
165 : 415 : }
166 : :
167 [ + + ]: 17226 : uint8_t onewire_bus_done(void) {
168 : 17226 : return ow_port_bus_done();
169 : : }
170 : :
171 [ - + ]: 1019 : void onewire_reset(volatile uint16_t* reset_pulses) {
172 : : ow_port_reset(reset_pulses);
173 : 1019 : }
174 : :
175 : 930 : uint8_t onewire_present(const volatile uint16_t* pulses) {
176 : 930 : uint16_t reset = pulses[0];
177 : 930 : uint16_t presence = pulses[1];
178 : : // Validate that reset pulse duration is within specification
179 : : // and presence pulse timing indicates a responding device
180 [ + + + + ]: 822 : return (reset >= RESET_PULSE_MIN) && (reset <= RESET_PULSE_MAX) &&
181 [ + + + + ]: 1752 : (presence >= PRESENCE_PULSE_MIN) && (presence <= PRESENCE_PULSE_MAX);
182 : : }
183 : :
184 : 840 : void onewire_start_timer(uint16_t arr, uint8_t rcr) {
185 [ + + ]: 840 : ow_port_start_timer(arr, rcr);
186 : 840 : }
187 : :
188 : 660 : void onewire_strong_pullup(uint8_t on) {
189 [ + + ]: 660 : ow_port_strong_pullup(on);
190 : 660 : }
191 : :
192 : 1082 : void onewire_write_slots(const uint8_t* pulses, uint16_t slots) {
193 [ + + ]: 1082 : ow_port_write_slots(pulses, slots);
194 : 1082 : }
195 : :
196 : 249 : void onewire_write_bit(uint8_t bit) {
197 [ + + ]: 249 : uint8_t pulse = bit ? ow_one_pulse_us : ow_zero_pulse_us;
198 : 249 : onewire_write_slots(&pulse, 1);
199 : 249 : }
200 : :
201 : 273 : void onewire_read_pair(volatile uint16_t* pair_pulses) {
202 : : ow_port_read_pair(pair_pulses);
203 : 273 : }
204 : :
205 : 246 : void onewire_pair_bits(const volatile uint16_t* pair_pulses, uint8_t* id_bit, uint8_t* cmp_bit) {
206 : 246 : *id_bit = onewire_bit_from_pulse(pair_pulses[0]);
207 : 246 : *cmp_bit = onewire_bit_from_pulse(pair_pulses[1]);
208 : 246 : }
209 : :
210 : 14769 : void onewire_write_then_read(uint8_t bit) {
211 [ + + ]: 14769 : ow_port_write_then_read(bit, search_pulse3, search_read_pulse);
212 : 14769 : }
213 : :
214 : 234 : void onewire_read_data(volatile uint8_t* dst, uint8_t bytes) {
215 [ + + ]: 234 : ow_port_read_data(dst, bytes);
216 : 234 : }
217 : :
218 : 336 : void onewire_decode_pulses(uint8_t* dst, const volatile uint8_t* pulse, uint8_t nbytes) {
219 [ + + ]: 2958 : for (uint8_t byte = 0; byte < nbytes; byte++) {
220 : 2622 : uint8_t value = 0;
221 [ + + ]: 23598 : for (uint8_t bit = 0; bit < ONEWIRE_BITS_PER_BYTE; bit++) {
222 : 20976 : value |= (uint8_t)(onewire_bit_from_pulse(pulse[byte * ONEWIRE_BITS_PER_BYTE + bit]) << bit);
223 : : }
224 : 2622 : dst[byte] = value;
225 : : }
226 : 336 : }
227 : :
228 : 5876 : void onewire_encode_byte(uint8_t* out, uint8_t byte) {
229 [ + + ]: 52884 : for (uint8_t i = 0; i < ONEWIRE_BITS_PER_BYTE; i++) {
230 [ + + ]: 47008 : out[i] = (byte & (1u << i)) ? ow_one_pulse_us : ow_zero_pulse_us;
231 : : }
232 : 5876 : }
233 : :
234 : 1272 : uint8_t onewire_crc8(const uint8_t* data, uint8_t len) {
235 : 1272 : uint8_t crc = 0;
236 : : // Process each byte in the buffer
237 [ + + ]: 10842 : for (uint8_t i = 0; i < len; i++) {
238 : 9570 : uint8_t inByte = data[i];
239 : : // Process each bit in the byte using Dallas/Maxim CRC8 algorithm
240 [ + + ]: 86130 : for (uint8_t b = 0; b < ONEWIRE_BITS_PER_BYTE; b++) {
241 : 76560 : uint8_t mix = (crc ^ inByte) & 0x01;
242 : 76560 : crc >>= 1;
243 [ + + ]: 76560 : if (mix) crc ^= ONEWIRE_CRC8_POLY;
244 : 76560 : inByte >>= 1;
245 : : }
246 : : }
247 : 1272 : return crc;
248 : : }
249 : :
250 : : /** @} */
251 : :
252 : : /**
253 : : * @defgroup ONEWIRE_Search_Impl ONEWIRE Generic Search ROM Engine
254 : : * @{
255 : : */
256 : :
257 : : /**
258 : : * @brief Process one decoded id/cmp pair: pick a direction, update the ROM,
259 : : * and schedule the next hardware operation
260 : : * @param[in] id_bit Id bit of the current position
261 : : * @param[in] cmp_bit Complement bit of the current position
262 : : * @note For all but the last bit the direction write is merged with the read
263 : : * of the next pair (ONEWIRE_SEARCH_WRITE_READ); the 64th bit is written
264 : : * alone so the device can be finalized.
265 : : */
266 : 14988 : static void onewire_search_advance_bit(uint8_t id_bit, uint8_t cmp_bit) {
267 : 14988 : const uint8_t byte_idx = (search_ctx.id_bit_number - 1) / ONEWIRE_BITS_PER_BYTE;
268 : 14988 : const uint8_t mask = (uint8_t)(1u << ((search_ctx.id_bit_number - 1) % ONEWIRE_BITS_PER_BYTE));
269 : : uint8_t direction;
270 : :
271 [ + + + + ]: 14988 : if (id_bit && cmp_bit) {
272 : : // No device follows this path - search tree exhausted
273 : 12 : search_ctx.phase = ONEWIRE_SEARCH_DONE;
274 : 12 : return;
275 : : }
276 [ + + ]: 14976 : if (id_bit != cmp_bit) {
277 : : // Single device on this path - its bit fixes the direction
278 : 14688 : direction = id_bit;
279 [ + + ]: 288 : } else if (search_ctx.id_bit_number < search_ctx.last_discrepancy) {
280 : : // Follow the previously taken path
281 [ + + ]: 114 : direction = (search_ctx.rom[byte_idx] & mask) ? 1u : 0u;
282 [ + + ]: 114 : if (direction == 0) {
283 : : // Remember the last 0-branch taken at a discrepancy
284 : 78 : search_ctx.last_zero = search_ctx.id_bit_number;
285 : : }
286 : : } else {
287 : : // At the discrepancy point take the '1' branch first
288 [ + + ]: 174 : direction = (search_ctx.id_bit_number == search_ctx.last_discrepancy) ? 1u : 0u;
289 [ + + ]: 174 : if (direction == 0) {
290 : : // Remember the last 0-branch taken at a discrepancy
291 : 96 : search_ctx.last_zero = search_ctx.id_bit_number;
292 : : }
293 : : }
294 [ + + ]: 14976 : if (direction) {
295 : 3576 : search_ctx.rom[byte_idx] |= mask;
296 : : } else {
297 : 11400 : search_ctx.rom[byte_idx] &= (uint8_t)~mask;
298 : : }
299 [ + + ]: 14976 : if (search_ctx.id_bit_number < ONEWIRE_ROM_BITS) {
300 : : // Merge the direction write with the read of the next id/cmp pair.
301 : 14742 : onewire_write_then_read(direction);
302 : 14742 : search_ctx.phase = ONEWIRE_SEARCH_WRITE_READ;
303 : : } else {
304 : 234 : onewire_write_bit(direction);
305 : 234 : search_ctx.phase = ONEWIRE_SEARCH_WRITE_DIR;
306 : : }
307 : : }
308 : :
309 : 228 : void onewire_search_start(onewire_search_sink_t sink, uint8_t max_devices,
310 : : uint8_t command, uint8_t family) {
311 [ + + ]: 228 : if (!search_ctx.finished) {
312 : 6 : return; // a search is already running
313 : : }
314 [ + + ]: 1998 : for (uint8_t i = 0; i < ONEWIRE_ROM_BYTES; i++) {
315 : 1776 : search_ctx.rom[i] = 0;
316 : : }
317 : : // Trailing zero consumed by the CCR3-feed DMA's final transfer: this is the
318 : : // hardware bus release after the search command.
319 : 222 : search_ctx.pulses[ONEWIRE_BITS_PER_BYTE] = 0;
320 : 222 : search_ctx.sink = sink;
321 : 222 : search_ctx.max = max_devices;
322 : 222 : search_ctx.found = 0;
323 : 222 : search_ctx.finished = 0;
324 : 222 : search_ctx.last_discrepancy = 0;
325 : 222 : search_ctx.command = command;
326 : 222 : search_ctx.family = family;
327 [ + + ]: 222 : if (max_devices == 0) {
328 : 12 : search_ctx.phase = ONEWIRE_SEARCH_DONE;
329 : 12 : return;
330 : : }
331 : 210 : search_ctx.phase = ONEWIRE_SEARCH_RESET;
332 : 210 : onewire_reset(search_pair_pulse); // Schedule the first hardware operation
333 : : }
334 : :
335 : 16554 : uint8_t onewire_search_poll(void) {
336 [ + + ]: 16554 : if (search_ctx.finished) {
337 : 54 : return 1;
338 : : }
339 : :
340 [ + + ]: 16500 : if (search_ctx.phase == ONEWIRE_SEARCH_DONE) {
341 : : // No hardware operation is pending at the end of the search: hand the
342 : : // timer back to the owner exactly once.
343 : : ow_port_kick();
344 : 192 : search_ctx.finished = 1;
345 : 192 : return 1;
346 : : }
347 : :
348 : : // Wait for the currently scheduled hardware operation to complete.
349 : : // This is a non-blocking poll, not a busy-wait.
350 [ + + ]: 16308 : if (!onewire_bus_done()) {
351 : 180 : return 0;
352 : : }
353 : :
354 : : #ifdef DS18B20_TEST_HARNESS
355 : : // [TEST] Inject a hardware-timed idle-HIGH gap between search slots to
356 : : // measure a 1-Wire slave's tolerance to a delayed next slot (RTOS scenario).
357 [ + + + + ]: 16128 : if (test_gap_us != 0u && search_ctx.phase != ONEWIRE_SEARCH_GAP) {
358 : 402 : test_gap_pending_phase = (uint8_t)search_ctx.phase;
359 : 402 : search_ctx.phase = ONEWIRE_SEARCH_GAP;
360 : 402 : onewire_start_timer(test_gap_us, 0);
361 : 402 : return 0;
362 : : }
363 [ + + ]: 15726 : if (search_ctx.phase == ONEWIRE_SEARCH_GAP) {
364 : 402 : search_ctx.phase = (onewire_search_phase_t)test_gap_pending_phase;
365 : : }
366 : : #endif
367 : :
368 [ + + + + : 15726 : switch (search_ctx.phase) {
+ - - ]
369 : 258 : case ONEWIRE_SEARCH_RESET:
370 : : // Reset completed: a presence pulse means at least one device is on
371 : : // the bus, so start a new search pass with the search command
372 : : // (0xF0 Search ROM / 0xEC Alarm Search).
373 [ + + ]: 258 : if (!onewire_present(search_pair_pulse)) {
374 : 12 : search_ctx.phase = ONEWIRE_SEARCH_DONE;
375 : 12 : break;
376 : : }
377 : 246 : onewire_encode_byte(search_ctx.pulses, search_ctx.command);
378 : 246 : onewire_write_slots(search_ctx.pulses, ONEWIRE_BITS_PER_BYTE);
379 : 246 : search_ctx.phase = ONEWIRE_SEARCH_CMD;
380 : 246 : break;
381 : :
382 : 246 : case ONEWIRE_SEARCH_CMD:
383 : : // Search command sent: prepare the first bit iteration and read the
384 : : // id/cmp pair.
385 : 246 : search_ctx.id_bit_number = 1;
386 : 246 : search_ctx.last_zero = 0;
387 : 246 : onewire_read_pair(search_pair_pulse);
388 : 246 : search_ctx.phase = ONEWIRE_SEARCH_READ_PAIR;
389 : 246 : break;
390 : :
391 : 246 : case ONEWIRE_SEARCH_READ_PAIR:
392 : : // First id/cmp pair decoded from the plain two-slot read.
393 : : {
394 : : uint8_t id_bit;
395 : : uint8_t cmp_bit;
396 : 246 : onewire_pair_bits(search_pair_pulse, &id_bit, &cmp_bit);
397 : 246 : onewire_search_advance_bit(id_bit, cmp_bit);
398 : : }
399 : 246 : break;
400 : :
401 : 14742 : case ONEWIRE_SEARCH_WRITE_READ:
402 : : // The merged operation wrote the direction for the previous bit and
403 : : // captured the id/cmp pair of the current bit into search_pulse3.
404 : 14742 : search_ctx.id_bit_number++;
405 : 14742 : onewire_search_advance_bit(
406 : 14742 : onewire_bit_from_pulse(search_pulse3[1]),
407 : 14742 : onewire_bit_from_pulse(search_pulse3[2]));
408 : 14742 : break;
409 : :
410 : 234 : case ONEWIRE_SEARCH_WRITE_DIR:
411 : : // The final (64th) direction bit was written: the ROM is assembled.
412 : 234 : search_ctx.id_bit_number++;
413 : 234 : search_ctx.last_discrepancy = search_ctx.last_zero;
414 [ + + ]: 234 : if (onewire_crc8(search_ctx.rom, ONEWIRE_ROM_BYTES) != 0) {
415 : 12 : search_ctx.phase = ONEWIRE_SEARCH_DONE;
416 : 12 : break;
417 : : }
418 : : // The family filter decides which devices are accepted: only accepted
419 : : // devices increment the found counter and reach the sink. The sink may
420 : : // stop the search early with a non-zero return value.
421 [ + + + + ]: 222 : if (search_ctx.family == 0u || search_ctx.rom[0] == search_ctx.family) {
422 : 210 : search_ctx.found++;
423 [ + - + + ]: 210 : if (search_ctx.sink && search_ctx.sink(search_ctx.rom)) {
424 : 12 : search_ctx.phase = ONEWIRE_SEARCH_DONE;
425 : 12 : break;
426 : : }
427 [ + + ]: 198 : if (search_ctx.found >= search_ctx.max) {
428 : 120 : search_ctx.phase = ONEWIRE_SEARCH_DONE;
429 : 120 : break;
430 : : }
431 : : }
432 [ + + ]: 90 : if (search_ctx.last_discrepancy == 0) {
433 : 12 : search_ctx.phase = ONEWIRE_SEARCH_DONE;
434 : 12 : break;
435 : : }
436 : : // Another device may exist - run another search pass.
437 : 78 : onewire_reset(search_pair_pulse);
438 : 78 : search_ctx.phase = ONEWIRE_SEARCH_RESET;
439 : 78 : break;
440 : :
441 : 0 : case ONEWIRE_SEARCH_DONE:
442 : : #ifdef DS18B20_TEST_HARNESS
443 : : case ONEWIRE_SEARCH_GAP:
444 : : #endif
445 : : // DONE and GAP are handled before the switch (see above); keep as a
446 : : // no-op so -Wswitch-enum stays satisfied.
447 : 0 : break;
448 : :
449 : 0 : default:
450 : 0 : break;
451 : : }
452 : :
453 : 15726 : return 0;
454 : : }
455 : :
456 : 216 : uint8_t onewire_search_count(void) { return search_ctx.found; }
457 : :
458 : 1986 : uint8_t onewire_search_active(void) { return (uint8_t)!search_ctx.finished; }
459 : :
460 : : /** @} */
461 : :
462 : : #ifdef DS18B20_TEST_HARNESS
463 : 1768 : void onewire_test_set_gap_us(uint16_t us) { test_gap_us = us; }
464 : : #endif
|