LCOV - code coverage report
Current view: top level - src - onewire.c (source / functions) Coverage Total Hit
Test: stm32-async-1wire core coverage Lines: 97.9 % 187 183
Test Date: 2026-09-10 04:33:53 Functions: 100.0 % 24 24
Branches: 96.2 % 105 101

             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
        

Generated by: LCOV version 2.0-1