spi_mem_worker_modes.c 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. #include "spi_mem_worker_i.h"
  2. #include "spi_mem_chip.h"
  3. #include "spi_mem_tools.h"
  4. #include "../../spi_mem_files.h"
  5. static void spi_mem_worker_chip_detect_process(SPIMemWorker* worker);
  6. static void spi_mem_worker_read_process(SPIMemWorker* worker);
  7. static void spi_mem_worker_verify_process(SPIMemWorker* worker);
  8. static void spi_mem_worker_erase_process(SPIMemWorker* worker);
  9. static void spi_mem_worker_write_process(SPIMemWorker* worker);
  10. const SPIMemWorkerModeType spi_mem_worker_modes[] = {
  11. [SPIMemWorkerModeIdle] = {.process = NULL},
  12. [SPIMemWorkerModeChipDetect] = {.process = spi_mem_worker_chip_detect_process},
  13. [SPIMemWorkerModeRead] = {.process = spi_mem_worker_read_process},
  14. [SPIMemWorkerModeVerify] = {.process = spi_mem_worker_verify_process},
  15. [SPIMemWorkerModeErase] = {.process = spi_mem_worker_erase_process},
  16. [SPIMemWorkerModeWrite] = {.process = spi_mem_worker_write_process}};
  17. static void spi_mem_worker_run_callback(SPIMemWorker* worker, SPIMemCustomEventWorker event) {
  18. if(worker->callback) {
  19. worker->callback(worker->cb_ctx, event);
  20. }
  21. }
  22. static bool spi_mem_worker_await_chip_busy(SPIMemWorker* worker) {
  23. while(true) {
  24. furi_delay_tick(10); // to give some time to OS
  25. if(spi_mem_worker_check_for_stop(worker)) return true;
  26. SPIMemChipStatus chip_status = spi_mem_tools_get_chip_status(worker->chip_info);
  27. if(chip_status == SPIMemChipStatusError) return false;
  28. if(chip_status == SPIMemChipStatusBusy) continue;
  29. return true;
  30. }
  31. }
  32. static size_t spi_mem_worker_modes_get_total_size(SPIMemWorker* worker) {
  33. size_t chip_size = spi_mem_chip_get_size(worker->chip_info);
  34. size_t file_size = spi_mem_file_get_size(worker->cb_ctx);
  35. size_t total_size = chip_size;
  36. if(chip_size > file_size) total_size = file_size;
  37. return total_size;
  38. }
  39. // ChipDetect
  40. static void spi_mem_worker_chip_detect_process(SPIMemWorker* worker) {
  41. SPIMemCustomEventWorker event;
  42. while(!spi_mem_tools_read_chip_info(worker->chip_info)) {
  43. furi_delay_tick(10); // to give some time to OS
  44. if(spi_mem_worker_check_for_stop(worker)) return;
  45. }
  46. if(spi_mem_chip_find_all(worker->chip_info, *worker->found_chips)) {
  47. event = SPIMemCustomEventWorkerChipIdentified;
  48. } else {
  49. event = SPIMemCustomEventWorkerChipUnknown;
  50. }
  51. spi_mem_worker_run_callback(worker, event);
  52. }
  53. // Read
  54. static bool spi_mem_worker_read(SPIMemWorker* worker, SPIMemCustomEventWorker* event) {
  55. uint8_t data_buffer[SPI_MEM_FILE_BUFFER_SIZE];
  56. size_t chip_size = spi_mem_chip_get_size(worker->chip_info);
  57. size_t offset = 0;
  58. bool success = true;
  59. while(true) {
  60. furi_delay_tick(10); // to give some time to OS
  61. size_t block_size = SPI_MEM_FILE_BUFFER_SIZE;
  62. if(spi_mem_worker_check_for_stop(worker)) break;
  63. if(offset >= chip_size) break;
  64. if((offset + block_size) > chip_size) block_size = chip_size - offset;
  65. if(!spi_mem_tools_read_block(worker->chip_info, offset, data_buffer, block_size)) {
  66. *event = SPIMemCustomEventWorkerChipFail;
  67. success = false;
  68. break;
  69. }
  70. if(!spi_mem_file_write_block(worker->cb_ctx, data_buffer, block_size)) {
  71. success = false;
  72. break;
  73. }
  74. offset += block_size;
  75. spi_mem_worker_run_callback(worker, SPIMemCustomEventWorkerBlockReaded);
  76. }
  77. if(success) *event = SPIMemCustomEventWorkerDone;
  78. return success;
  79. }
  80. static void spi_mem_worker_read_process(SPIMemWorker* worker) {
  81. SPIMemCustomEventWorker event = SPIMemCustomEventWorkerFileFail;
  82. do {
  83. if(!spi_mem_worker_await_chip_busy(worker)) break;
  84. if(!spi_mem_file_create_open(worker->cb_ctx)) break;
  85. if(!spi_mem_worker_read(worker, &event)) break;
  86. } while(0);
  87. spi_mem_file_close(worker->cb_ctx);
  88. spi_mem_worker_run_callback(worker, event);
  89. }
  90. // Verify
  91. static bool
  92. spi_mem_worker_verify(SPIMemWorker* worker, size_t total_size, SPIMemCustomEventWorker* event) {
  93. uint8_t data_buffer_chip[SPI_MEM_FILE_BUFFER_SIZE];
  94. uint8_t data_buffer_file[SPI_MEM_FILE_BUFFER_SIZE];
  95. size_t offset = 0;
  96. bool success = true;
  97. while(true) {
  98. furi_delay_tick(10); // to give some time to OS
  99. size_t block_size = SPI_MEM_FILE_BUFFER_SIZE;
  100. if(spi_mem_worker_check_for_stop(worker)) break;
  101. if(offset >= total_size) break;
  102. if((offset + block_size) > total_size) block_size = total_size - offset;
  103. if(!spi_mem_tools_read_block(worker->chip_info, offset, data_buffer_chip, block_size)) {
  104. *event = SPIMemCustomEventWorkerChipFail;
  105. success = false;
  106. break;
  107. }
  108. if(!spi_mem_file_read_block(worker->cb_ctx, data_buffer_file, block_size)) {
  109. success = false;
  110. break;
  111. }
  112. if(memcmp(data_buffer_chip, data_buffer_file, block_size) != 0) {
  113. *event = SPIMemCustomEventWorkerVerifyFail;
  114. success = false;
  115. break;
  116. }
  117. offset += block_size;
  118. spi_mem_worker_run_callback(worker, SPIMemCustomEventWorkerBlockReaded);
  119. }
  120. if(success) *event = SPIMemCustomEventWorkerDone;
  121. return success;
  122. }
  123. static void spi_mem_worker_verify_process(SPIMemWorker* worker) {
  124. SPIMemCustomEventWorker event = SPIMemCustomEventWorkerFileFail;
  125. size_t total_size = spi_mem_worker_modes_get_total_size(worker);
  126. do {
  127. if(!spi_mem_worker_await_chip_busy(worker)) break;
  128. if(!spi_mem_file_open(worker->cb_ctx)) break;
  129. if(!spi_mem_worker_verify(worker, total_size, &event)) break;
  130. } while(0);
  131. spi_mem_file_close(worker->cb_ctx);
  132. spi_mem_worker_run_callback(worker, event);
  133. }
  134. // Erase
  135. static void spi_mem_worker_erase_process(SPIMemWorker* worker) {
  136. SPIMemCustomEventWorker event = SPIMemCustomEventWorkerChipFail;
  137. do {
  138. if(!spi_mem_worker_await_chip_busy(worker)) break;
  139. if(!spi_mem_tools_erase_chip(worker->chip_info)) break;
  140. if(!spi_mem_worker_await_chip_busy(worker)) break;
  141. event = SPIMemCustomEventWorkerDone;
  142. } while(0);
  143. spi_mem_worker_run_callback(worker, event);
  144. }
  145. // Write
  146. static bool spi_mem_worker_write_block_by_page(
  147. SPIMemWorker* worker,
  148. size_t offset,
  149. uint8_t* data,
  150. size_t block_size,
  151. size_t page_size) {
  152. for(size_t i = 0; i < block_size; i += page_size) {
  153. if(!spi_mem_worker_await_chip_busy(worker)) return false;
  154. if(!spi_mem_tools_write_bytes(worker->chip_info, offset, data, page_size)) return false;
  155. offset += page_size;
  156. data += page_size;
  157. }
  158. return true;
  159. }
  160. static bool
  161. spi_mem_worker_write(SPIMemWorker* worker, size_t total_size, SPIMemCustomEventWorker* event) {
  162. bool success = true;
  163. uint8_t data_buffer[SPI_MEM_FILE_BUFFER_SIZE];
  164. size_t page_size = spi_mem_chip_get_page_size(worker->chip_info);
  165. size_t offset = 0;
  166. while(true) {
  167. furi_delay_tick(10); // to give some time to OS
  168. size_t block_size = SPI_MEM_FILE_BUFFER_SIZE;
  169. if(spi_mem_worker_check_for_stop(worker)) break;
  170. if(offset >= total_size) break;
  171. if((offset + block_size) > total_size) block_size = total_size - offset;
  172. if(!spi_mem_file_read_block(worker->cb_ctx, data_buffer, block_size)) {
  173. *event = SPIMemCustomEventWorkerFileFail;
  174. success = false;
  175. break;
  176. }
  177. if(!spi_mem_worker_write_block_by_page(
  178. worker, offset, data_buffer, block_size, page_size)) {
  179. success = false;
  180. break;
  181. }
  182. offset += block_size;
  183. spi_mem_worker_run_callback(worker, SPIMemCustomEventWorkerBlockReaded);
  184. }
  185. return success;
  186. }
  187. static void spi_mem_worker_write_process(SPIMemWorker* worker) {
  188. SPIMemCustomEventWorker event = SPIMemCustomEventWorkerChipFail;
  189. size_t total_size =
  190. spi_mem_worker_modes_get_total_size(worker); // need to be executed before opening file
  191. do {
  192. if(!spi_mem_file_open(worker->cb_ctx)) break;
  193. if(!spi_mem_worker_await_chip_busy(worker)) break;
  194. if(!spi_mem_worker_write(worker, total_size, &event)) break;
  195. if(!spi_mem_worker_await_chip_busy(worker)) break;
  196. event = SPIMemCustomEventWorkerDone;
  197. } while(0);
  198. spi_mem_file_close(worker->cb_ctx);
  199. spi_mem_worker_run_callback(worker, event);
  200. }