dallas_common.c 7.9 KB

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