dallas_common.c 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261
  1. #include "dallas_common.h"
  2. #include <core/common_defines.h>
  3. #include <one_wire/maxim_crc.h>
  4. #define BITS_IN_BYTE 8U
  5. #define DALLAS_COMMON_ROM_DATA_KEY_V1 "Data"
  6. #define DALLAS_COMMON_ROM_DATA_KEY_V2 "Rom Data"
  7. #define DALLAS_COMMON_COPY_SCRATCH_MIN_TIMEOUT_US 5U
  8. #define DALLAS_COMMON_COPY_SCRATCH_POLL_COUNT 20U
  9. #define DALLAS_COMMON_END_ADDRESS_MASK 0x01F
  10. #define DALLAS_COMMON_STATUS_FLAG_PF (1U << 5)
  11. #define DALLAS_COMMON_STATUS_FLAG_OF (1U << 6)
  12. #define DALLAS_COMMON_STATUS_FLAG_AA (1U << 7)
  13. #define DALLAS_COMMON_BRIEF_HEAD_COUNT 4U
  14. #define DALLAS_COMMON_BRIEF_TAIL_COUNT 3U
  15. #define BITS_IN_BYTE 8U
  16. #define BITS_IN_KBIT 1024U
  17. #define BITS_IN_MBIT (BITS_IN_KBIT * 1024U)
  18. bool dallas_common_skip_rom(OneWireHost* host) {
  19. onewire_host_write(host, DALLAS_COMMON_CMD_SKIP_ROM);
  20. return true;
  21. }
  22. bool dallas_common_read_rom(OneWireHost* host, DallasCommonRomData* rom_data) {
  23. onewire_host_write(host, DALLAS_COMMON_CMD_READ_ROM);
  24. onewire_host_read_bytes(host, rom_data->bytes, sizeof(DallasCommonRomData));
  25. return dallas_common_is_valid_crc(rom_data);
  26. }
  27. bool dallas_common_write_scratchpad(
  28. OneWireHost* host,
  29. uint16_t address,
  30. const uint8_t* data,
  31. size_t data_size) {
  32. onewire_host_write(host, DALLAS_COMMON_CMD_WRITE_SCRATCH);
  33. onewire_host_write(host, (uint8_t)address);
  34. onewire_host_write(host, (uint8_t)(address >> BITS_IN_BYTE));
  35. onewire_host_write_bytes(host, data, data_size);
  36. return true;
  37. }
  38. bool dallas_common_read_scratchpad(
  39. OneWireHost* host,
  40. DallasCommonAddressRegs* regs,
  41. uint8_t* data,
  42. size_t data_size) {
  43. onewire_host_write(host, DALLAS_COMMON_CMD_READ_SCRATCH);
  44. onewire_host_read_bytes(host, regs->bytes, sizeof(DallasCommonAddressRegs));
  45. onewire_host_read_bytes(host, data, data_size);
  46. return true;
  47. }
  48. bool dallas_common_copy_scratchpad(
  49. OneWireHost* host,
  50. const DallasCommonAddressRegs* regs,
  51. uint32_t timeout_us) {
  52. onewire_host_write(host, DALLAS_COMMON_CMD_COPY_SCRATCH);
  53. onewire_host_write_bytes(host, regs->bytes, sizeof(DallasCommonAddressRegs));
  54. const uint32_t poll_delay =
  55. MAX(timeout_us / DALLAS_COMMON_COPY_SCRATCH_POLL_COUNT,
  56. DALLAS_COMMON_COPY_SCRATCH_MIN_TIMEOUT_US);
  57. uint32_t time_elapsed;
  58. for(time_elapsed = 0; time_elapsed < timeout_us; time_elapsed += poll_delay) {
  59. if(!onewire_host_read_bit(host)) break;
  60. furi_delay_us(poll_delay);
  61. }
  62. return time_elapsed < timeout_us;
  63. }
  64. bool dallas_common_read_mem(OneWireHost* host, uint16_t address, uint8_t* data, size_t data_size) {
  65. onewire_host_write(host, DALLAS_COMMON_CMD_READ_MEM);
  66. onewire_host_write(host, (uint8_t)address);
  67. onewire_host_write(host, (uint8_t)(address >> BITS_IN_BYTE));
  68. onewire_host_read_bytes(host, data, (uint16_t)data_size);
  69. return true;
  70. }
  71. bool dallas_common_write_mem(
  72. OneWireHost* host,
  73. uint32_t timeout_us,
  74. size_t page_size,
  75. const uint8_t* data,
  76. size_t data_size) {
  77. // Data size must be a multiple of page size
  78. furi_check(data_size % page_size == 0);
  79. DallasCommonAddressRegs regs;
  80. uint8_t* scratch = malloc(page_size);
  81. size_t i;
  82. for(i = 0; i < data_size; i += page_size) {
  83. const uint8_t* data_ptr = data + i;
  84. // Write scratchpad with the next page value
  85. if(!onewire_host_reset(host)) break;
  86. if(!dallas_common_skip_rom(host)) break;
  87. if(!dallas_common_write_scratchpad(host, i, data_ptr, page_size)) break;
  88. // Read back the scratchpad contents and address registers
  89. if(!onewire_host_reset(host)) break;
  90. if(!dallas_common_skip_rom(host)) break;
  91. if(!dallas_common_read_scratchpad(host, &regs, scratch, page_size)) break;
  92. // Verify scratchpad contents
  93. if(memcmp(data_ptr, scratch, page_size) != 0) break;
  94. // Write scratchpad to internal memory
  95. if(!onewire_host_reset(host)) break;
  96. if(!dallas_common_skip_rom(host)) break;
  97. if(!dallas_common_copy_scratchpad(host, &regs, timeout_us)) break;
  98. // Read back the address registers again
  99. if(!onewire_host_reset(host)) break;
  100. if(!dallas_common_skip_rom(host)) break;
  101. if(!dallas_common_read_scratchpad(host, &regs, scratch, 0)) break;
  102. // Check if AA flag is set
  103. if(!(regs.fields.status & DALLAS_COMMON_STATUS_FLAG_AA)) break;
  104. }
  105. free(scratch);
  106. return i == data_size;
  107. }
  108. bool dallas_common_emulate_search_rom(OneWireSlave* bus, const DallasCommonRomData* rom_data) {
  109. for(size_t i = 0; i < sizeof(DallasCommonRomData); i++) {
  110. for(size_t j = 0; j < BITS_IN_BYTE; j++) {
  111. bool bit = (rom_data->bytes[i] >> j) & 0x01;
  112. if(!onewire_slave_send_bit(bus, bit)) return false;
  113. if(!onewire_slave_send_bit(bus, !bit)) return false;
  114. onewire_slave_receive_bit(bus);
  115. // TODO: check for errors and return if any
  116. }
  117. }
  118. return true;
  119. }
  120. bool dallas_common_emulate_read_rom(OneWireSlave* bus, const DallasCommonRomData* rom_data) {
  121. return onewire_slave_send(bus, rom_data->bytes, sizeof(DallasCommonRomData));
  122. }
  123. bool dallas_common_emulate_read_mem(OneWireSlave* bus, const uint8_t* data, size_t data_size) {
  124. bool success = false;
  125. union {
  126. uint8_t bytes[sizeof(uint16_t)];
  127. uint16_t word;
  128. } address;
  129. do {
  130. if(!onewire_slave_receive(bus, address.bytes, sizeof(address))) break;
  131. if(address.word >= data_size) break;
  132. if(!onewire_slave_send(bus, data + address.word, data_size - address.word)) break;
  133. success = true;
  134. } while(false);
  135. return success;
  136. }
  137. bool dallas_common_save_rom_data(FlipperFormat* ff, const DallasCommonRomData* rom_data) {
  138. return flipper_format_write_hex(
  139. ff, DALLAS_COMMON_ROM_DATA_KEY_V2, rom_data->bytes, sizeof(DallasCommonRomData));
  140. }
  141. bool dallas_common_load_rom_data(
  142. FlipperFormat* ff,
  143. uint32_t format_version,
  144. DallasCommonRomData* rom_data) {
  145. switch(format_version) {
  146. case 1:
  147. return flipper_format_read_hex(
  148. ff, DALLAS_COMMON_ROM_DATA_KEY_V1, rom_data->bytes, sizeof(DallasCommonRomData));
  149. case 2:
  150. return flipper_format_read_hex(
  151. ff, DALLAS_COMMON_ROM_DATA_KEY_V2, rom_data->bytes, sizeof(DallasCommonRomData));
  152. default:
  153. return false;
  154. }
  155. }
  156. bool dallas_common_is_valid_crc(const DallasCommonRomData* rom_data) {
  157. const uint8_t crc_calculated =
  158. maxim_crc8(rom_data->bytes, sizeof(DallasCommonRomData) - 1, MAXIM_CRC8_INIT);
  159. const uint8_t crc_received = rom_data->fields.checksum;
  160. return crc_calculated == crc_received;
  161. }
  162. void dallas_common_render_brief_data(
  163. FuriString* result,
  164. const DallasCommonRomData* rom_data,
  165. const uint8_t* mem_data,
  166. size_t mem_size,
  167. const char* mem_name) {
  168. for(size_t i = 0; i < sizeof(rom_data->bytes); ++i) {
  169. furi_string_cat_printf(result, "%02X ", rom_data->bytes[i]);
  170. }
  171. const char* size_prefix = "";
  172. size_t mem_size_bits = mem_size * BITS_IN_BYTE;
  173. if(mem_size_bits >= BITS_IN_MBIT) {
  174. size_prefix = "M";
  175. mem_size_bits /= BITS_IN_MBIT;
  176. } else if(mem_size_bits >= BITS_IN_KBIT) {
  177. size_prefix = "K";
  178. mem_size_bits /= BITS_IN_KBIT;
  179. }
  180. furi_string_cat_printf(
  181. result, "\nInternal %s: %zu %sbit\n", mem_name, mem_size_bits, size_prefix);
  182. for(size_t i = 0; i < DALLAS_COMMON_BRIEF_HEAD_COUNT; ++i) {
  183. furi_string_cat_printf(result, "%02X ", mem_data[i]);
  184. }
  185. furi_string_cat_printf(result, "[ . . . ]");
  186. for(size_t i = mem_size - DALLAS_COMMON_BRIEF_TAIL_COUNT; i < mem_size; ++i) {
  187. furi_string_cat_printf(result, " %02X", mem_data[i]);
  188. }
  189. }
  190. void dallas_common_render_crc_error(FuriString* result, const DallasCommonRomData* rom_data) {
  191. furi_string_set(result, "CRC Error\n");
  192. const size_t data_size = sizeof(DallasCommonRomData);
  193. for(size_t i = 0; i < data_size; ++i) {
  194. furi_string_cat_printf(result, (i < data_size - 1) ? "%02X " : "%02X", rom_data->bytes[i]);
  195. }
  196. }
  197. void dallas_common_apply_edits(DallasCommonRomData* rom_data, uint8_t family_code) {
  198. rom_data->fields.family_code = family_code;
  199. const uint8_t crc =
  200. maxim_crc8(rom_data->bytes, sizeof(DallasCommonRomData) - 1, MAXIM_CRC8_INIT);
  201. rom_data->fields.checksum = crc;
  202. }