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;
|
|
}
|
|
|