1-Wire bus search algorithm, new C implementation

ow_search.c 3.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. //
  2. // Created by MightyPork on 2018/02/01.
  3. // MIT license
  4. //
  5. #include <stdlib.h>
  6. #include <stdint.h>
  7. #include <stdbool.h>
  8. #include <string.h>
  9. #include "ow_search.h"
  10. // -------- CHECKSUM --------
  11. static inline uint8_t crc8_bits(uint8_t data)
  12. {
  13. uint8_t crc = 0;
  14. if(data & 1) crc ^= 0x5e;
  15. if(data & 2) crc ^= 0xbc;
  16. if(data & 4) crc ^= 0x61;
  17. if(data & 8) crc ^= 0xc2;
  18. if(data & 0x10) crc ^= 0x9d;
  19. if(data & 0x20) crc ^= 0x23;
  20. if(data & 0x40) crc ^= 0x46;
  21. if(data & 0x80) crc ^= 0x8c;
  22. return crc;
  23. }
  24. static uint8_t crc8_add(uint8_t cksum, uint8_t byte)
  25. {
  26. return crc8_bits(byte ^ cksum);
  27. }
  28. uint8_t ow_checksum(const uint8_t *buff, uint16_t len)
  29. {
  30. uint8_t cksum = 0;
  31. for(uint16_t i = 0; i < len; i++) {
  32. cksum = crc8_add(cksum, buff[i]);
  33. }
  34. return cksum;
  35. }
  36. // -----------------------------
  37. void ow_search_init(struct ow_search_state *state, uint8_t command, bool test_checksums)
  38. {
  39. state->prev_last_fork = 64;
  40. memset(state->prev_code, 0, 8);
  41. state->status = OW_SEARCH_MORE;
  42. state->command = command;
  43. state->first = true;
  44. state->test_checksums = test_checksums;
  45. }
  46. uint16_t ow_search_run(struct ow_search_state *state, ow_romcode_t *codes, uint16_t capacity)
  47. {
  48. if (state->status != OW_SEARCH_MORE) return 0;
  49. uint16_t found_devices = 0;
  50. while (found_devices < capacity) {
  51. uint8_t index = 0;
  52. ow_romcode_t code = {};
  53. int8_t last_fork = -1;
  54. // Start a new transaction. Devices respond to reset
  55. if (!ow_reset()) {
  56. state->status = OW_SEARCH_FAILED;
  57. goto done;
  58. }
  59. // Send the search command (SEARCH_ROM, SEARCH_ALARM)
  60. ow_write_u8(state->command);
  61. uint8_t *code_byte = &code[0];
  62. bool p, n;
  63. while (index != 64) {
  64. // Read a bit and its complement
  65. p = ow_read_bit();
  66. n = ow_read_bit();
  67. if (!p && !n) {
  68. // A fork: there are devices on the bus with different bit value
  69. // (the bus is open-drain, in both cases one device pulls it low)
  70. if ((found_devices > 0 || !state->first) && index < state->prev_last_fork) {
  71. // earlier than the last fork, take the same turn as before
  72. p = ow_code_getbit(state->prev_code, index);
  73. if (!p) last_fork = index; // remember for future runs, 1 not explored yet
  74. }
  75. else if (index == state->prev_last_fork) {
  76. p = 1; // both forks are now exhausted
  77. }
  78. else { // a new fork
  79. last_fork = index;
  80. }
  81. }
  82. else if (p && n) {
  83. // No devices left connected - this doesn't normally happen
  84. state->status = OW_SEARCH_FAILED;
  85. goto done;
  86. }
  87. // All devices have a matching bit here, or it was resolved in a fork
  88. if (p) *code_byte |= (1 << (index & 7));
  89. ow_write_bit(p);
  90. index++;
  91. if((index & 7) == 0) {
  92. code_byte++;
  93. }
  94. }
  95. memcpy(state->prev_code, code, 8);
  96. if (!state->test_checksums || 0 == ow_checksum(code, 8)) {
  97. // Record a found address
  98. memcpy(codes[found_devices], code, 8);
  99. found_devices++;
  100. }
  101. // Stop condition
  102. if (last_fork == -1) {
  103. state->status = OW_SEARCH_DONE;
  104. goto done;
  105. }
  106. state->prev_last_fork = last_fork;
  107. }
  108. done:
  109. state->first = false;
  110. return found_devices;
  111. }