You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							134 lines
						
					
					
						
							3.6 KiB
						
					
					
				
			
		
		
	
	
							134 lines
						
					
					
						
							3.6 KiB
						
					
					
				//
 | 
						|
// Created by MightyPork on 2018/02/01.
 | 
						|
// MIT license
 | 
						|
//
 | 
						|
 | 
						|
#include <stdlib.h>
 | 
						|
#include <stdint.h>
 | 
						|
#include <stdbool.h>
 | 
						|
#include <string.h>
 | 
						|
 | 
						|
#include "ow_search.h"
 | 
						|
 | 
						|
// -------- CHECKSUM --------
 | 
						|
 | 
						|
static inline uint8_t crc8_bits(uint8_t data)
 | 
						|
{
 | 
						|
    uint8_t crc = 0;
 | 
						|
    if(data & 1)     crc ^= 0x5e;
 | 
						|
    if(data & 2)     crc ^= 0xbc;
 | 
						|
    if(data & 4)     crc ^= 0x61;
 | 
						|
    if(data & 8)     crc ^= 0xc2;
 | 
						|
    if(data & 0x10)  crc ^= 0x9d;
 | 
						|
    if(data & 0x20)  crc ^= 0x23;
 | 
						|
    if(data & 0x40)  crc ^= 0x46;
 | 
						|
    if(data & 0x80)  crc ^= 0x8c;
 | 
						|
    return crc;
 | 
						|
}
 | 
						|
 | 
						|
static uint8_t crc8_add(uint8_t cksum, uint8_t byte)
 | 
						|
{
 | 
						|
    return crc8_bits(byte ^ cksum);
 | 
						|
}
 | 
						|
 | 
						|
uint8_t ow_checksum(const uint8_t *buff, uint16_t len)
 | 
						|
{
 | 
						|
    uint8_t cksum = 0;
 | 
						|
    for(uint16_t i = 0; i < len; i++) {
 | 
						|
        cksum = crc8_add(cksum, buff[i]);
 | 
						|
    }
 | 
						|
    return cksum;
 | 
						|
}
 | 
						|
 | 
						|
// -----------------------------
 | 
						|
 | 
						|
 | 
						|
void ow_search_init(struct ow_search_state *state, uint8_t command, bool test_checksums)
 | 
						|
{
 | 
						|
    state->prev_last_fork = 64;
 | 
						|
    memset(state->prev_code, 0, 8);
 | 
						|
    state->status = OW_SEARCH_MORE;
 | 
						|
    state->command = command;
 | 
						|
    state->first = true;
 | 
						|
    state->test_checksums = test_checksums;
 | 
						|
}
 | 
						|
 | 
						|
uint16_t ow_search_run(struct ow_search_state *state, ow_romcode_t *codes, uint16_t capacity)
 | 
						|
{
 | 
						|
    if (state->status != OW_SEARCH_MORE) return 0;
 | 
						|
 | 
						|
    uint16_t found_devices = 0;
 | 
						|
 | 
						|
    while (found_devices < capacity) {
 | 
						|
        uint8_t index = 0;
 | 
						|
        ow_romcode_t code = {};
 | 
						|
        int8_t last_fork = -1;
 | 
						|
 | 
						|
        // Start a new transaction. Devices respond to reset
 | 
						|
        if (!ow_reset()) {
 | 
						|
            state->status = OW_SEARCH_FAILED;
 | 
						|
            goto done;
 | 
						|
        }
 | 
						|
        // Send the search command (SEARCH_ROM, SEARCH_ALARM)
 | 
						|
        ow_write_u8(state->command);
 | 
						|
 | 
						|
        uint8_t *code_byte = &code[0];
 | 
						|
 | 
						|
        bool p, n;
 | 
						|
        while (index != 64) {
 | 
						|
            // Read a bit and its complement
 | 
						|
            p = ow_read_bit();
 | 
						|
            n = ow_read_bit();
 | 
						|
 | 
						|
            if (!p && !n) {
 | 
						|
                // A fork: there are devices on the bus with different bit value
 | 
						|
                // (the bus is open-drain, in both cases one device pulls it low)
 | 
						|
                if ((found_devices > 0 || !state->first) && index < state->prev_last_fork) {
 | 
						|
                    // earlier than the last fork, take the same turn as before
 | 
						|
                    p = ow_code_getbit(state->prev_code, index);
 | 
						|
                    if (!p) last_fork = index; // remember for future runs, 1 not explored yet
 | 
						|
                }
 | 
						|
                else if (index == state->prev_last_fork) {
 | 
						|
                    p = 1; // both forks are now exhausted
 | 
						|
                }
 | 
						|
                else { // a new fork
 | 
						|
                    last_fork = index;
 | 
						|
                }
 | 
						|
            }
 | 
						|
            else if (p && n) {
 | 
						|
                // No devices left connected - this doesn't normally happen
 | 
						|
                state->status = OW_SEARCH_FAILED;
 | 
						|
                goto done;
 | 
						|
            }
 | 
						|
 | 
						|
            // All devices have a matching bit here, or it was resolved in a fork
 | 
						|
            if (p) *code_byte |= (1 << (index & 7));
 | 
						|
            ow_write_bit(p);
 | 
						|
 | 
						|
            index++;
 | 
						|
            if((index & 7) == 0) {
 | 
						|
                code_byte++;
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        memcpy(state->prev_code, code, 8);
 | 
						|
 | 
						|
        if (!state->test_checksums || 0 == ow_checksum(code, 8)) {
 | 
						|
            // Record a found address
 | 
						|
            memcpy(codes[found_devices], code, 8);
 | 
						|
            found_devices++;
 | 
						|
        }
 | 
						|
 | 
						|
        // Stop condition
 | 
						|
        if (last_fork == -1) {
 | 
						|
            state->status = OW_SEARCH_DONE;
 | 
						|
            goto done;
 | 
						|
        }
 | 
						|
 | 
						|
        state->prev_last_fork = last_fork;
 | 
						|
    }
 | 
						|
 | 
						|
done:
 | 
						|
    state->first = false;
 | 
						|
    return found_devices;
 | 
						|
}
 | 
						|
 |