diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4e20e5f --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +cmake-build-debug/ +.idea/ +CMakeLists.txt +*.o +*.elf +*.out diff --git a/main.c b/main.c new file mode 100644 index 0000000..c7233e1 --- /dev/null +++ b/main.c @@ -0,0 +1,122 @@ +#include +#include +#include +#include +#include + +#include "ow_search.h" + +// ----------- DEMO ----------------- + +void main(void) +{ + struct ow_search_state search_state; + ow_search_init(&search_state, 0xFF); // the real onewire search command will go here when used with real hw + + ow_romcode_t addresses[4]; + + int x=0; + while (search_state.status == OW_SEARCH_MORE) { + uint16_t count = ow_search_run(&search_state, addresses, 4); + printf("Found %d addresses, status %d\n", count, search_state.status); + for(int i=0; i 10) break; + } +} + +// ------------ SIMULATOR --------------- + +struct owunit { + ow_romcode_t romcode; + bool selected; + uint8_t rompos; + int state; +}; + +#define UNITS_COUNT 12 +struct owunit units[UNITS_COUNT] = { + {.romcode = {0b00000000}},//00 + {.romcode = {0b00000001}},//01 + {.romcode = {0b00010001}},//11 + {.romcode = {0b00110001}},//31 + {.romcode = {0b00110101}},//35 + {.romcode = {0b01010001}},//51 + {.romcode = {0b10000000}},//80 + {.romcode = {0b10101010}},//aa + {.romcode = {0b11110101}},//f5 + {.romcode = {0b11110111}},//f7 + {.romcode = {0xFF,0x00,0xFF,0x00,0x55,0x00,0xAA,0x00}}, + {.romcode = {0x12,0x34,0x56,0x78,0x9a,0xbc,0xde,0xf0}}, +}; + +bool rom_device_reset(struct owunit *device) +{ + device->rompos = 0; + device->state = 0; + device->selected = true; +} + +bool rom_device_read(struct owunit *device) +{ + if (!device->selected) return true; + if (device->state == 0) { + device->state++; + bool res = ow_code_getbit(device->romcode, device->rompos); + return res; + } + if (device->state == 1) { + device->state++; + bool res = !ow_code_getbit(device->romcode, device->rompos); + return res; + } +} + +void rom_device_write(struct owunit *device, bool selectedbit) +{ + if (!device->selected) return; + + if (ow_code_getbit(device->romcode, device->rompos) != selectedbit) { + device->selected = false; + } + else { + device->rompos++; + device->state = 0; + } +} + +bool ow_reset(void) +{ + for (int i = 0; i < UNITS_COUNT; ++i) { + rom_device_reset(&units[i]); + } + return (UNITS_COUNT > 0); +} + +bool ow_read_bit(void) +{ + bool bus = 1; + for (int i = 0; i < UNITS_COUNT; ++i) { + bus &= rom_device_read(&units[i]); + } + return bus; +} + +void ow_write_bit(bool value) +{ + for (int i = 0; i < UNITS_COUNT; ++i) { + rom_device_write(&units[i], value); + } +} + +void ow_write_u8(uint8_t value) +{ + // Dummy, do nothing +} diff --git a/ow_search.c b/ow_search.c new file mode 100644 index 0000000..8b090a3 --- /dev/null +++ b/ow_search.c @@ -0,0 +1,92 @@ +// +// Created by MightyPork on 2018/02/01. +// + +#include +#include +#include +#include + +#include "ow_search.h" + +void ow_search_init(struct ow_search_state *state, uint8_t command) +{ + state->prev_last_fork = 64; + memset(&state->prev_code[0], 0, 8); + state->status = OW_SEARCH_MORE; + state->command = command; + state->first = true; +} + +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); + + 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) ow_code_setbit(code, index); + ow_write_bit(p); + index++; + } + + // Record a found address + for (int i = 0; i < 8; i++) { + state->prev_code[i] = codes[found_devices][i] = code[i]; + } + 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; +} diff --git a/ow_search.h b/ow_search.h new file mode 100644 index 0000000..8ce52ac --- /dev/null +++ b/ow_search.h @@ -0,0 +1,92 @@ +// +// Created by MightyPork on 2018/02/01. +// + +#ifndef OW_SEARCH_H +#define OW_SEARCH_H + +// -------------------------------------------------------------------------------------- + +// External API functions for interfacing the bus +// Customize as needed (and also update calls in the search function) + +/** + * Reset the 1-wire bus + * + * @return presence pulse received + */ +extern bool ow_reset(void); + +/** + * Write a byte to the bus + * + * @param[in] value byte value + */ +extern void ow_write_u8(uint8_t value); +/** + * Write a bit to the 1-wire bus + * + * @param[in] value bit value + */ +extern void ow_write_bit(bool value); + +/** + * Read a bit from the 1-wire bus + * + * @return bit value + */ +extern bool ow_read_bit(void); + +// -------------------------------------------------------------------------------------- + +/** Data type holding one romcode */ +typedef uint8_t ow_romcode_t[8]; + +/** Get a bit from a romcode */ +#define ow_code_getbit(code, index) (bool)((code)[(index) / 8] & (1 << ((index) % 8))) +/** Set a bit to 1 in a romcode */ +#define ow_code_setbit(code, index) ((code)[(index) / 8] |= (1 << ((index) % 8))) + +/** + * States of the search algorithm + */ +enum ow_search_result { + OW_SEARCH_DONE = 0, + OW_SEARCH_MORE = 1, + OW_SEARCH_FAILED = 2, +}; + +/** + * Internal state of the search algorithm. + * Check status to see if more remain to be read or an error occurred. + */ +struct ow_search_state { + int8_t prev_last_fork; + ow_romcode_t prev_code; + uint8_t command; + enum ow_search_result status; + bool first; +}; + +/** + * Init the state search struct + * + * @param[out] state - inited struct + * @param[in] command - command to send for requesting the search (e.g. SEARCH_ROM) + */ +void ow_search_init(struct ow_search_state *state, uint8_t command); + +/** + * Perform a search of the 1-wire bus, with a state struct pre-inited + * using ow_search_init(). + * + * Romcodes are stored in the byte arrays in a numerically ascending order. + * + * @param[in,out] state - search state, used for multiple calls with limited buffer size + * @param[out] codes - buffer for found romcodes + * @param[in] capacity - buffer capacity + * @return number of romcodes found. Search status is stored in state->status + */ +uint16_t ow_search_run(struct ow_search_state *state, ow_romcode_t *codes, uint16_t capacity); + +#endif //OW_SEARCH_H