GEX core repository.
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.
gex-core/units/1wire/_ow_search.c

131 lines
3.7 KiB

//
// Created by MightyPork on 2018/02/01.
//
#include "platform.h"
#include "unit_1wire.h"
#define OW_INTERNAL
#include "_ow_search.h"
#include "_ow_internal.h"
#include "_ow_low_level.h"
#include "_ow_checksum.h"
#include "_ow_commands.h"
void ow_search_init(Unit *unit, uint8_t command, bool test_checksums)
{
if (unit->driver != &UNIT_1WIRE)
trap("Wrong unit type - %s", unit->driver->name);
assert_param(command == OW_ROM_SEARCH || command == OW_ROM_ALM_SEARCH);
struct priv *priv = unit->data;
struct ow_search_state *state = &priv->searchState;
state->prev_last_fork = 64;
memset(state->prev_code, 0, 8);
state->status = OW_SEARCH_MORE;
state->error = E_SUCCESS;
state->command = command;
state->first = true;
state->test_checksums = test_checksums;
}
uint32_t ow_search_run(Unit *unit, ow_romcode_t *codes, uint32_t capacity)
{
if (unit->driver != &UNIT_1WIRE)
trap("Wrong unit type - %s", unit->driver->name);
assert_param(codes);
struct priv *priv = unit->data;
struct ow_search_state *state = &priv->searchState;
if (state->status != OW_SEARCH_MORE) return 0;
uint32_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(unit)) {
state->status = OW_SEARCH_FAILED;
state->error = E_HW_TIMEOUT;
goto done;
}
// Send the search command (SEARCH_ROM, SEARCH_ALARM)
ow_write_u8(unit, state->command);
uint8_t *code_byte = &code[0];
bool p, n;
while (index != 64) {
// Read a bit and its complement
p = ow_read_bit(unit);
n = ow_read_bit(unit);
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;
state->error = E_BUS_FAULT;
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(unit, p);
index++;
if((index & 7) == 0) {
code_byte++;
}
}
memcpy(state->prev_code, code, 8);
if (state->test_checksums) {
if (0 != ow_checksum(code, 8)) {
state->status = OW_SEARCH_FAILED;
state->error = E_CHECKSUM_MISMATCH;
goto done;
}
}
// 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;
}