avr_isp_worker_rw.c 41 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157
  1. #include "avr_isp_worker_rw.h"
  2. #include <furi_hal_pwm.h>
  3. #include "avr_isp_types.h"
  4. #include "avr_isp.h"
  5. #include "../lib/driver/avr_isp_prog_cmd.h"
  6. #include "../lib/driver/avr_isp_chip_arr.h"
  7. #include "flipper_i32hex_file.h"
  8. #include <flipper_format/flipper_format.h>
  9. #include <furi.h>
  10. #define TAG "AvrIspWorkerRW"
  11. #define NAME_PATERN_FLASH_FILE "flash.hex"
  12. #define NAME_PATERN_EEPROM_FILE "eeprom.hex"
  13. struct AvrIspWorkerRW {
  14. AvrIsp* avr_isp;
  15. FuriThread* thread;
  16. volatile bool worker_running;
  17. uint32_t chip_arr_ind;
  18. bool chip_detect;
  19. uint8_t lfuse;
  20. uint8_t hfuse;
  21. uint8_t efuse;
  22. uint8_t lock;
  23. float progress_flash;
  24. float progress_eeprom;
  25. const char* file_path;
  26. const char* file_name;
  27. AvrIspSignature signature;
  28. AvrIspWorkerRWCallback callback;
  29. void* context;
  30. AvrIspWorkerRWStatusCallback callback_status;
  31. void* context_status;
  32. };
  33. typedef enum {
  34. AvrIspWorkerRWEvtStop = (1 << 0),
  35. AvrIspWorkerRWEvtReading = (1 << 1),
  36. AvrIspWorkerRWEvtVerification = (1 << 2),
  37. AvrIspWorkerRWEvtWriting = (1 << 3),
  38. AvrIspWorkerRWEvtWritingFuse = (1 << 4),
  39. } AvrIspWorkerRWEvt;
  40. #define AVR_ISP_WORKER_ALL_EVENTS \
  41. (AvrIspWorkerRWEvtWritingFuse | AvrIspWorkerRWEvtWriting | AvrIspWorkerRWEvtVerification | \
  42. AvrIspWorkerRWEvtReading | AvrIspWorkerRWEvtStop)
  43. /** Worker thread
  44. *
  45. * @param context
  46. * @return exit code
  47. */
  48. static int32_t avr_isp_worker_rw_thread(void* context) {
  49. AvrIspWorkerRW* instance = context;
  50. /* start PWM on &gpio_ext_pa4 */
  51. if(!furi_hal_pwm_is_running(FuriHalPwmOutputIdLptim2PA4)) {
  52. furi_hal_pwm_start(FuriHalPwmOutputIdLptim2PA4, 4000000, 50);
  53. }
  54. FURI_LOG_D(TAG, "Start");
  55. while(1) {
  56. uint32_t events =
  57. furi_thread_flags_wait(AVR_ISP_WORKER_ALL_EVENTS, FuriFlagWaitAny, FuriWaitForever);
  58. if(events & AvrIspWorkerRWEvtStop) {
  59. break;
  60. }
  61. if(events & AvrIspWorkerRWEvtWritingFuse) {
  62. if(avr_isp_worker_rw_write_fuse(instance, instance->file_path, instance->file_name)) {
  63. if(instance->callback_status)
  64. instance->callback_status(
  65. instance->context_status, AvrIspWorkerRWStatusEndWritingFuse);
  66. } else {
  67. if(instance->callback_status)
  68. instance->callback_status(
  69. instance->context_status, AvrIspWorkerRWStatusErrorWritingFuse);
  70. }
  71. }
  72. if(events & AvrIspWorkerRWEvtWriting) {
  73. if(avr_isp_worker_rw_write_dump(instance, instance->file_path, instance->file_name)) {
  74. if(instance->callback_status)
  75. instance->callback_status(
  76. instance->context_status, AvrIspWorkerRWStatusEndWriting);
  77. } else {
  78. if(instance->callback_status)
  79. instance->callback_status(
  80. instance->context_status, AvrIspWorkerRWStatusErrorWriting);
  81. }
  82. }
  83. if(events & AvrIspWorkerRWEvtVerification) {
  84. if(avr_isp_worker_rw_verification(instance, instance->file_path, instance->file_name)) {
  85. if(instance->callback_status)
  86. instance->callback_status(
  87. instance->context_status, AvrIspWorkerRWStatusEndVerification);
  88. } else {
  89. if(instance->callback_status)
  90. instance->callback_status(
  91. instance->context_status, AvrIspWorkerRWStatusErrorVerification);
  92. }
  93. }
  94. if(events & AvrIspWorkerRWEvtReading) {
  95. if(avr_isp_worker_rw_read_dump(instance, instance->file_path, instance->file_name)) {
  96. if(instance->callback_status)
  97. instance->callback_status(
  98. instance->context_status, AvrIspWorkerRWStatusEndReading);
  99. } else {
  100. if(instance->callback_status)
  101. instance->callback_status(
  102. instance->context_status, AvrIspWorkerRWStatusErrorReading);
  103. }
  104. }
  105. }
  106. FURI_LOG_D(TAG, "Stop");
  107. if(furi_hal_pwm_is_running(FuriHalPwmOutputIdLptim2PA4)) {
  108. furi_hal_pwm_stop(FuriHalPwmOutputIdLptim2PA4);
  109. }
  110. return 0;
  111. }
  112. bool avr_isp_worker_rw_detect_chip(AvrIspWorkerRW* instance) {
  113. furi_assert(instance);
  114. FURI_LOG_D(TAG, "Detecting AVR chip");
  115. instance->chip_detect = false;
  116. instance->chip_arr_ind = avr_isp_chip_arr_size + 1;
  117. /* start PWM on &gpio_ext_pa4 */
  118. bool was_pwm_enabled = false;
  119. if(!furi_hal_pwm_is_running(FuriHalPwmOutputIdLptim2PA4)) {
  120. furi_hal_pwm_start(FuriHalPwmOutputIdLptim2PA4, 4000000, 50);
  121. } else {
  122. was_pwm_enabled = true;
  123. }
  124. do {
  125. if(!avr_isp_auto_set_spi_speed_start_pmode(instance->avr_isp)) {
  126. FURI_LOG_E(TAG, "Well, I managed to enter the mod program");
  127. break;
  128. }
  129. instance->signature = avr_isp_read_signature(instance->avr_isp);
  130. if(instance->signature.vendor != 0x1E) {
  131. //No detect chip
  132. } else {
  133. for(uint32_t ind = 0; ind < avr_isp_chip_arr_size; ind++) {
  134. if(avr_isp_chip_arr[ind].avrarch != F_AVR8) continue;
  135. if(avr_isp_chip_arr[ind].sigs[1] == instance->signature.part_family) {
  136. if(avr_isp_chip_arr[ind].sigs[2] == instance->signature.part_number) {
  137. FURI_LOG_D(TAG, "Detect AVR chip = \"%s\"", avr_isp_chip_arr[ind].name);
  138. FURI_LOG_D(
  139. TAG,
  140. "Signature = 0x%02X 0x%02X 0x%02X",
  141. instance->signature.vendor,
  142. instance->signature.part_family,
  143. instance->signature.part_number);
  144. switch(avr_isp_chip_arr[ind].nfuses) {
  145. case 1:
  146. instance->lfuse = avr_isp_read_fuse_low(instance->avr_isp);
  147. FURI_LOG_D(TAG, "Lfuse = %02X", instance->lfuse);
  148. break;
  149. case 2:
  150. instance->lfuse = avr_isp_read_fuse_low(instance->avr_isp);
  151. instance->hfuse = avr_isp_read_fuse_high(instance->avr_isp);
  152. FURI_LOG_D(
  153. TAG, "Lfuse = %02X Hfuse = %02X", instance->lfuse, instance->hfuse);
  154. break;
  155. case 3:
  156. instance->lfuse = avr_isp_read_fuse_low(instance->avr_isp);
  157. instance->hfuse = avr_isp_read_fuse_high(instance->avr_isp);
  158. instance->efuse = avr_isp_read_fuse_extended(instance->avr_isp);
  159. FURI_LOG_D(
  160. TAG,
  161. "Lfuse = %02X Hfuse = %02X Efuse = %02X",
  162. instance->lfuse,
  163. instance->hfuse,
  164. instance->efuse);
  165. break;
  166. default:
  167. break;
  168. }
  169. if(avr_isp_chip_arr[ind].nlocks == 1) {
  170. instance->lock = avr_isp_read_lock_byte(instance->avr_isp);
  171. FURI_LOG_D(TAG, "Lock = %02X", instance->lock);
  172. }
  173. instance->chip_detect = true;
  174. instance->chip_arr_ind = ind;
  175. break;
  176. }
  177. }
  178. }
  179. }
  180. avr_isp_end_pmode(instance->avr_isp);
  181. } while(0);
  182. if(furi_hal_pwm_is_running(FuriHalPwmOutputIdLptim2PA4) && !was_pwm_enabled) {
  183. furi_hal_pwm_stop(FuriHalPwmOutputIdLptim2PA4);
  184. }
  185. if(instance->callback) {
  186. if(instance->chip_arr_ind > avr_isp_chip_arr_size) {
  187. instance->callback(instance->context, "No detect", instance->chip_detect, 0);
  188. } else if(instance->chip_arr_ind < avr_isp_chip_arr_size) {
  189. instance->callback(
  190. instance->context,
  191. avr_isp_chip_arr[instance->chip_arr_ind].name,
  192. instance->chip_detect,
  193. avr_isp_chip_arr[instance->chip_arr_ind].flashsize);
  194. } else {
  195. instance->callback(instance->context, "Unknown", instance->chip_detect, 0);
  196. }
  197. }
  198. return instance->chip_detect;
  199. }
  200. AvrIspWorkerRW* avr_isp_worker_rw_alloc(void* context) {
  201. furi_assert(context);
  202. UNUSED(context);
  203. AvrIspWorkerRW* instance = malloc(sizeof(AvrIspWorkerRW));
  204. instance->avr_isp = avr_isp_alloc();
  205. instance->thread =
  206. furi_thread_alloc_ex("AvrIspWorkerRW", 4096, avr_isp_worker_rw_thread, instance);
  207. instance->chip_detect = false;
  208. instance->lfuse = 0;
  209. instance->hfuse = 0;
  210. instance->efuse = 0;
  211. instance->lock = 0;
  212. instance->progress_flash = 0.0f;
  213. instance->progress_eeprom = 0.0f;
  214. return instance;
  215. }
  216. void avr_isp_worker_rw_free(AvrIspWorkerRW* instance) {
  217. furi_assert(instance);
  218. avr_isp_free(instance->avr_isp);
  219. furi_check(!instance->worker_running);
  220. furi_thread_free(instance->thread);
  221. free(instance);
  222. }
  223. void avr_isp_worker_rw_start(AvrIspWorkerRW* instance) {
  224. furi_assert(instance);
  225. furi_assert(!instance->worker_running);
  226. instance->worker_running = true;
  227. furi_thread_start(instance->thread);
  228. }
  229. void avr_isp_worker_rw_stop(AvrIspWorkerRW* instance) {
  230. furi_assert(instance);
  231. furi_assert(instance->worker_running);
  232. instance->worker_running = false;
  233. furi_thread_flags_set(furi_thread_get_id(instance->thread), AvrIspWorkerRWEvtStop);
  234. furi_thread_join(instance->thread);
  235. }
  236. bool avr_isp_worker_rw_is_running(AvrIspWorkerRW* instance) {
  237. furi_assert(instance);
  238. return instance->worker_running;
  239. }
  240. void avr_isp_worker_rw_set_callback(
  241. AvrIspWorkerRW* instance,
  242. AvrIspWorkerRWCallback callback,
  243. void* context) {
  244. furi_assert(instance);
  245. instance->callback = callback;
  246. instance->context = context;
  247. }
  248. void avr_isp_worker_rw_set_callback_status(
  249. AvrIspWorkerRW* instance,
  250. AvrIspWorkerRWStatusCallback callback_status,
  251. void* context_status) {
  252. furi_assert(instance);
  253. instance->callback_status = callback_status;
  254. instance->context_status = context_status;
  255. }
  256. float avr_isp_worker_rw_get_progress_flash(AvrIspWorkerRW* instance) {
  257. furi_assert(instance);
  258. return instance->progress_flash;
  259. }
  260. float avr_isp_worker_rw_get_progress_eeprom(AvrIspWorkerRW* instance) {
  261. furi_assert(instance);
  262. return instance->progress_eeprom;
  263. }
  264. static void avr_isp_worker_rw_get_dump_flash(AvrIspWorkerRW* instance, const char* file_path) {
  265. furi_assert(instance);
  266. furi_check(instance->avr_isp);
  267. FURI_LOG_D(TAG, "Dump FLASH %s", file_path);
  268. FlipperI32HexFile* flipper_hex_flash = flipper_i32hex_file_open_write(
  269. file_path, avr_isp_chip_arr[instance->chip_arr_ind].flashoffset);
  270. uint8_t data[272] = {0};
  271. bool send_extended_addr = ((avr_isp_chip_arr[instance->chip_arr_ind].flashsize / 2) > 0x10000);
  272. uint8_t extended_addr = 0;
  273. for(int32_t i = avr_isp_chip_arr[instance->chip_arr_ind].flashoffset;
  274. i < avr_isp_chip_arr[instance->chip_arr_ind].flashsize / 2;
  275. i += avr_isp_chip_arr[instance->chip_arr_ind].pagesize / 2) {
  276. if(send_extended_addr) {
  277. if(extended_addr <= ((i >> 16) & 0xFF)) {
  278. avr_isp_write_extended_addr(instance->avr_isp, extended_addr);
  279. extended_addr = ((i >> 16) & 0xFF) + 1;
  280. }
  281. }
  282. avr_isp_read_page(
  283. instance->avr_isp,
  284. STK_SET_FLASH_TYPE,
  285. (uint16_t)i,
  286. avr_isp_chip_arr[instance->chip_arr_ind].pagesize,
  287. data,
  288. sizeof(data));
  289. flipper_i32hex_file_bin_to_i32hex_set_data(
  290. flipper_hex_flash, data, avr_isp_chip_arr[instance->chip_arr_ind].pagesize);
  291. FURI_LOG_D(TAG, "%s", flipper_i32hex_file_get_string(flipper_hex_flash));
  292. instance->progress_flash =
  293. (float)(i) / ((float)avr_isp_chip_arr[instance->chip_arr_ind].flashsize / 2.0f);
  294. }
  295. flipper_i32hex_file_bin_to_i32hex_set_end_line(flipper_hex_flash);
  296. FURI_LOG_D(TAG, "%s", flipper_i32hex_file_get_string(flipper_hex_flash));
  297. flipper_i32hex_file_close(flipper_hex_flash);
  298. instance->progress_flash = 1.0f;
  299. }
  300. static void avr_isp_worker_rw_get_dump_eeprom(AvrIspWorkerRW* instance, const char* file_path) {
  301. furi_assert(instance);
  302. furi_check(instance->avr_isp);
  303. FURI_LOG_D(TAG, "Dump EEPROM %s", file_path);
  304. FlipperI32HexFile* flipper_hex_eeprom = flipper_i32hex_file_open_write(
  305. file_path, avr_isp_chip_arr[instance->chip_arr_ind].eepromoffset);
  306. int32_t size_data = 32;
  307. uint8_t data[256] = {0};
  308. if(size_data > avr_isp_chip_arr[instance->chip_arr_ind].eepromsize)
  309. size_data = avr_isp_chip_arr[instance->chip_arr_ind].eepromsize;
  310. for(int32_t i = avr_isp_chip_arr[instance->chip_arr_ind].eepromoffset;
  311. i < avr_isp_chip_arr[instance->chip_arr_ind].eepromsize;
  312. i += size_data) {
  313. avr_isp_read_page(
  314. instance->avr_isp, STK_SET_EEPROM_TYPE, (uint16_t)i, size_data, data, sizeof(data));
  315. flipper_i32hex_file_bin_to_i32hex_set_data(flipper_hex_eeprom, data, size_data);
  316. FURI_LOG_D(TAG, "%s", flipper_i32hex_file_get_string(flipper_hex_eeprom));
  317. instance->progress_eeprom =
  318. (float)(i) / ((float)avr_isp_chip_arr[instance->chip_arr_ind].eepromsize);
  319. }
  320. flipper_i32hex_file_bin_to_i32hex_set_end_line(flipper_hex_eeprom);
  321. FURI_LOG_D(TAG, "%s", flipper_i32hex_file_get_string(flipper_hex_eeprom));
  322. flipper_i32hex_file_close(flipper_hex_eeprom);
  323. instance->progress_eeprom = 1.0f;
  324. }
  325. bool avr_isp_worker_rw_read_dump(
  326. AvrIspWorkerRW* instance,
  327. const char* file_path,
  328. const char* file_name) {
  329. furi_assert(instance);
  330. furi_assert(file_path);
  331. furi_assert(file_name);
  332. FURI_LOG_D(TAG, "Read dump chip");
  333. instance->progress_flash = 0.0f;
  334. instance->progress_eeprom = 0.0f;
  335. bool ret = false;
  336. Storage* storage = furi_record_open(RECORD_STORAGE);
  337. FlipperFormat* flipper_format = flipper_format_file_alloc(storage);
  338. FuriString* file_path_name = furi_string_alloc();
  339. if(!avr_isp_worker_rw_detect_chip(instance)) {
  340. FURI_LOG_E(TAG, "No detect AVR chip");
  341. } else {
  342. do {
  343. furi_string_printf(
  344. file_path_name, "%s/%s%s", file_path, file_name, AVR_ISP_APP_EXTENSION);
  345. if(!flipper_format_file_open_always(
  346. flipper_format, furi_string_get_cstr(file_path_name))) {
  347. FURI_LOG_E(TAG, "flipper_format_file_open_always");
  348. break;
  349. }
  350. if(!flipper_format_write_header_cstr(
  351. flipper_format, AVR_ISP_APP_FILE_TYPE, AVR_ISP_APP_FILE_VERSION)) {
  352. FURI_LOG_E(TAG, "flipper_format_write_header_cstr");
  353. break;
  354. }
  355. if(!flipper_format_write_string_cstr(
  356. flipper_format, "Chip name", avr_isp_chip_arr[instance->chip_arr_ind].name)) {
  357. FURI_LOG_E(TAG, "Chip name");
  358. break;
  359. }
  360. if(!flipper_format_write_hex(
  361. flipper_format,
  362. "Signature",
  363. (uint8_t*)&instance->signature,
  364. sizeof(AvrIspSignature))) {
  365. FURI_LOG_E(TAG, "Unable to add Signature");
  366. break;
  367. }
  368. if(avr_isp_chip_arr[instance->chip_arr_ind].nfuses > 0) {
  369. if(!flipper_format_write_hex(flipper_format, "Lfuse", &instance->lfuse, 1)) {
  370. FURI_LOG_E(TAG, "Unable to add Lfuse");
  371. break;
  372. }
  373. }
  374. if(avr_isp_chip_arr[instance->chip_arr_ind].nfuses > 1) {
  375. if(!flipper_format_write_hex(flipper_format, "Hfuse", &instance->hfuse, 1)) {
  376. FURI_LOG_E(TAG, "Unable to add Hfuse");
  377. break;
  378. }
  379. }
  380. if(avr_isp_chip_arr[instance->chip_arr_ind].nfuses > 2) {
  381. if(!flipper_format_write_hex(flipper_format, "Efuse", &instance->efuse, 1)) {
  382. FURI_LOG_E(TAG, "Unable to add Efuse");
  383. break;
  384. }
  385. }
  386. if(avr_isp_chip_arr[instance->chip_arr_ind].nlocks == 1) {
  387. if(!flipper_format_write_hex(flipper_format, "Lock", &instance->lock, 1)) {
  388. FURI_LOG_E(TAG, "Unable to add Lock");
  389. break;
  390. }
  391. }
  392. furi_string_printf(file_path_name, "%s_%s", file_name, NAME_PATERN_FLASH_FILE);
  393. if(!flipper_format_write_string_cstr(
  394. flipper_format, "Dump_flash", furi_string_get_cstr(file_path_name))) {
  395. FURI_LOG_E(TAG, "Unable to add Dump_flash");
  396. break;
  397. }
  398. if(avr_isp_chip_arr[instance->chip_arr_ind].eepromsize > 0) {
  399. furi_string_printf(file_path_name, "%s_%s", file_name, NAME_PATERN_EEPROM_FILE);
  400. if(avr_isp_chip_arr[instance->chip_arr_ind].eepromsize > 0) {
  401. if(!flipper_format_write_string_cstr(
  402. flipper_format, "Dump_eeprom", furi_string_get_cstr(file_path_name))) {
  403. FURI_LOG_E(TAG, "Unable to add Dump_eeprom");
  404. break;
  405. }
  406. }
  407. }
  408. ret = true;
  409. } while(false);
  410. }
  411. flipper_format_free(flipper_format);
  412. furi_record_close(RECORD_STORAGE);
  413. if(ret) {
  414. if(avr_isp_auto_set_spi_speed_start_pmode(instance->avr_isp)) {
  415. //Dump flash
  416. furi_string_printf(
  417. file_path_name, "%s/%s_%s", file_path, file_name, NAME_PATERN_FLASH_FILE);
  418. avr_isp_worker_rw_get_dump_flash(instance, furi_string_get_cstr(file_path_name));
  419. //Dump eeprom
  420. if(avr_isp_chip_arr[instance->chip_arr_ind].eepromsize > 0) {
  421. furi_string_printf(
  422. file_path_name, "%s/%s_%s", file_path, file_name, NAME_PATERN_EEPROM_FILE);
  423. avr_isp_worker_rw_get_dump_eeprom(instance, furi_string_get_cstr(file_path_name));
  424. }
  425. avr_isp_end_pmode(instance->avr_isp);
  426. }
  427. }
  428. furi_string_free(file_path_name);
  429. return true;
  430. }
  431. void avr_isp_worker_rw_read_dump_start(
  432. AvrIspWorkerRW* instance,
  433. const char* file_path,
  434. const char* file_name) {
  435. furi_assert(instance);
  436. instance->file_path = file_path;
  437. instance->file_name = file_name;
  438. furi_thread_flags_set(furi_thread_get_id(instance->thread), AvrIspWorkerRWEvtReading);
  439. }
  440. static bool avr_isp_worker_rw_verification_flash(AvrIspWorkerRW* instance, const char* file_path) {
  441. furi_assert(instance);
  442. furi_assert(file_path);
  443. FURI_LOG_D(TAG, "Verification flash %s", file_path);
  444. instance->progress_flash = 0.0;
  445. bool ret = true;
  446. FlipperI32HexFile* flipper_hex_flash = flipper_i32hex_file_open_read(file_path);
  447. uint8_t data_read_flash[272] = {0};
  448. uint8_t data_read_hex[272] = {0};
  449. uint32_t addr = avr_isp_chip_arr[instance->chip_arr_ind].flashoffset;
  450. bool send_extended_addr = ((avr_isp_chip_arr[instance->chip_arr_ind].flashsize / 2) > 0x10000);
  451. uint8_t extended_addr = 0;
  452. FlipperI32HexFileRet flipper_hex_ret = flipper_i32hex_file_i32hex_to_bin_get_data(
  453. flipper_hex_flash, data_read_hex, sizeof(data_read_hex));
  454. while(((flipper_hex_ret.status == FlipperI32HexFileStatusData) ||
  455. (flipper_hex_ret.status == FlipperI32HexFileStatusUdateAddr)) &&
  456. ret) {
  457. switch(flipper_hex_ret.status) {
  458. case FlipperI32HexFileStatusData:
  459. if(send_extended_addr) {
  460. if(extended_addr <= ((addr >> 16) & 0xFF)) {
  461. avr_isp_write_extended_addr(instance->avr_isp, extended_addr);
  462. extended_addr = ((addr >> 16) & 0xFF) + 1;
  463. }
  464. }
  465. avr_isp_read_page(
  466. instance->avr_isp,
  467. STK_SET_FLASH_TYPE,
  468. (uint16_t)addr,
  469. flipper_hex_ret.data_size,
  470. data_read_flash,
  471. sizeof(data_read_flash));
  472. if(memcmp(data_read_hex, data_read_flash, flipper_hex_ret.data_size) != 0) {
  473. ret = false;
  474. FURI_LOG_E(TAG, "Verification flash error");
  475. FURI_LOG_E(TAG, "Addr: 0x%04lX", addr);
  476. for(uint32_t i = 0; i < flipper_hex_ret.data_size; i++) {
  477. FURI_LOG_RAW_E("%02X ", data_read_hex[i]);
  478. }
  479. FURI_LOG_RAW_E("\r\n");
  480. for(uint32_t i = 0; i < flipper_hex_ret.data_size; i++) {
  481. FURI_LOG_RAW_E("%02X ", data_read_flash[i]);
  482. }
  483. FURI_LOG_RAW_E("\r\n");
  484. }
  485. addr += flipper_hex_ret.data_size / 2;
  486. instance->progress_flash =
  487. (float)(addr) / ((float)avr_isp_chip_arr[instance->chip_arr_ind].flashsize / 2.0f);
  488. break;
  489. case FlipperI32HexFileStatusUdateAddr:
  490. addr = (data_read_hex[0] << 24 | data_read_hex[1] << 16) / 2;
  491. break;
  492. default:
  493. furi_crash(TAG " Incorrect status.");
  494. break;
  495. }
  496. flipper_hex_ret = flipper_i32hex_file_i32hex_to_bin_get_data(
  497. flipper_hex_flash, data_read_hex, sizeof(data_read_hex));
  498. }
  499. flipper_i32hex_file_close(flipper_hex_flash);
  500. instance->progress_flash = 1.0f;
  501. return ret;
  502. }
  503. static bool
  504. avr_isp_worker_rw_verification_eeprom(AvrIspWorkerRW* instance, const char* file_path) {
  505. furi_assert(instance);
  506. furi_assert(file_path);
  507. FURI_LOG_D(TAG, "Verification eeprom %s", file_path);
  508. instance->progress_eeprom = 0.0;
  509. bool ret = true;
  510. FlipperI32HexFile* flipper_hex_eeprom = flipper_i32hex_file_open_read(file_path);
  511. uint8_t data_read_eeprom[272] = {0};
  512. uint8_t data_read_hex[272] = {0};
  513. uint32_t addr = avr_isp_chip_arr[instance->chip_arr_ind].eepromoffset;
  514. FlipperI32HexFileRet flipper_hex_ret = flipper_i32hex_file_i32hex_to_bin_get_data(
  515. flipper_hex_eeprom, data_read_hex, sizeof(data_read_hex));
  516. while(((flipper_hex_ret.status == FlipperI32HexFileStatusData) ||
  517. (flipper_hex_ret.status == FlipperI32HexFileStatusUdateAddr)) &&
  518. ret) {
  519. switch(flipper_hex_ret.status) {
  520. case FlipperI32HexFileStatusData:
  521. avr_isp_read_page(
  522. instance->avr_isp,
  523. STK_SET_EEPROM_TYPE,
  524. (uint16_t)addr,
  525. flipper_hex_ret.data_size,
  526. data_read_eeprom,
  527. sizeof(data_read_eeprom));
  528. if(memcmp(data_read_hex, data_read_eeprom, flipper_hex_ret.data_size) != 0) {
  529. ret = false;
  530. FURI_LOG_E(TAG, "Verification eeprom error");
  531. FURI_LOG_E(TAG, "Addr: 0x%04lX", addr);
  532. for(uint32_t i = 0; i < flipper_hex_ret.data_size; i++) {
  533. FURI_LOG_RAW_E("%02X ", data_read_hex[i]);
  534. }
  535. FURI_LOG_RAW_E("\r\n");
  536. for(uint32_t i = 0; i < flipper_hex_ret.data_size; i++) {
  537. FURI_LOG_RAW_E("%02X ", data_read_eeprom[i]);
  538. }
  539. FURI_LOG_RAW_E("\r\n");
  540. }
  541. addr += flipper_hex_ret.data_size;
  542. instance->progress_eeprom =
  543. (float)(addr) / ((float)avr_isp_chip_arr[instance->chip_arr_ind].eepromsize);
  544. break;
  545. case FlipperI32HexFileStatusUdateAddr:
  546. addr = (data_read_hex[0] << 24 | data_read_hex[1] << 16);
  547. break;
  548. default:
  549. furi_crash(TAG " Incorrect status.");
  550. break;
  551. }
  552. flipper_hex_ret = flipper_i32hex_file_i32hex_to_bin_get_data(
  553. flipper_hex_eeprom, data_read_hex, sizeof(data_read_hex));
  554. }
  555. flipper_i32hex_file_close(flipper_hex_eeprom);
  556. instance->progress_eeprom = 1.0f;
  557. return ret;
  558. }
  559. bool avr_isp_worker_rw_verification(
  560. AvrIspWorkerRW* instance,
  561. const char* file_path,
  562. const char* file_name) {
  563. furi_assert(instance);
  564. furi_assert(file_path);
  565. furi_assert(file_name);
  566. FURI_LOG_D(TAG, "Verification chip");
  567. instance->progress_flash = 0.0f;
  568. instance->progress_eeprom = 0.0f;
  569. FuriString* file_path_name = furi_string_alloc();
  570. bool ret = false;
  571. if(avr_isp_auto_set_spi_speed_start_pmode(instance->avr_isp)) {
  572. do {
  573. furi_string_printf(
  574. file_path_name, "%s/%s_%s", file_path, file_name, NAME_PATERN_FLASH_FILE);
  575. if(!avr_isp_worker_rw_verification_flash(
  576. instance, furi_string_get_cstr(file_path_name)))
  577. break;
  578. if(avr_isp_chip_arr[instance->chip_arr_ind].eepromsize > 0) {
  579. furi_string_printf(
  580. file_path_name, "%s/%s_%s", file_path, file_name, NAME_PATERN_EEPROM_FILE);
  581. if(!avr_isp_worker_rw_verification_eeprom(
  582. instance, furi_string_get_cstr(file_path_name)))
  583. break;
  584. }
  585. ret = true;
  586. } while(false);
  587. avr_isp_end_pmode(instance->avr_isp);
  588. furi_string_free(file_path_name);
  589. }
  590. return ret;
  591. }
  592. void avr_isp_worker_rw_verification_start(
  593. AvrIspWorkerRW* instance,
  594. const char* file_path,
  595. const char* file_name) {
  596. furi_assert(instance);
  597. instance->file_path = file_path;
  598. instance->file_name = file_name;
  599. furi_thread_flags_set(furi_thread_get_id(instance->thread), AvrIspWorkerRWEvtVerification);
  600. }
  601. static void avr_isp_worker_rw_write_flash(AvrIspWorkerRW* instance, const char* file_path) {
  602. furi_assert(instance);
  603. furi_check(instance->avr_isp);
  604. instance->progress_flash = 0.0;
  605. FURI_LOG_D(TAG, "Write Flash %s", file_path);
  606. uint8_t data[288] = {0};
  607. FlipperI32HexFile* flipper_hex_flash = flipper_i32hex_file_open_read(file_path);
  608. uint32_t addr = avr_isp_chip_arr[instance->chip_arr_ind].flashoffset;
  609. bool send_extended_addr = ((avr_isp_chip_arr[instance->chip_arr_ind].flashsize / 2) > 0x10000);
  610. uint8_t extended_addr = 0;
  611. FlipperI32HexFileRet flipper_hex_ret =
  612. flipper_i32hex_file_i32hex_to_bin_get_data(flipper_hex_flash, data, sizeof(data));
  613. while((flipper_hex_ret.status == FlipperI32HexFileStatusData) ||
  614. (flipper_hex_ret.status == FlipperI32HexFileStatusUdateAddr)) {
  615. switch(flipper_hex_ret.status) {
  616. case FlipperI32HexFileStatusData:
  617. if(send_extended_addr) {
  618. if(extended_addr <= ((addr >> 16) & 0xFF)) {
  619. avr_isp_write_extended_addr(instance->avr_isp, extended_addr);
  620. extended_addr = ((addr >> 16) & 0xFF) + 1;
  621. }
  622. }
  623. if(!avr_isp_write_page(
  624. instance->avr_isp,
  625. STK_SET_FLASH_TYPE,
  626. avr_isp_chip_arr[instance->chip_arr_ind].flashsize,
  627. (uint16_t)addr,
  628. avr_isp_chip_arr[instance->chip_arr_ind].pagesize,
  629. data,
  630. flipper_hex_ret.data_size)) {
  631. break;
  632. }
  633. addr += flipper_hex_ret.data_size / 2;
  634. instance->progress_flash =
  635. (float)(addr) / ((float)avr_isp_chip_arr[instance->chip_arr_ind].flashsize / 2.0f);
  636. break;
  637. case FlipperI32HexFileStatusUdateAddr:
  638. addr = (data[0] << 24 | data[1] << 16) / 2;
  639. break;
  640. default:
  641. furi_crash(TAG " Incorrect status.");
  642. break;
  643. }
  644. flipper_hex_ret =
  645. flipper_i32hex_file_i32hex_to_bin_get_data(flipper_hex_flash, data, sizeof(data));
  646. }
  647. flipper_i32hex_file_close(flipper_hex_flash);
  648. instance->progress_flash = 1.0f;
  649. }
  650. static void avr_isp_worker_rw_write_eeprom(AvrIspWorkerRW* instance, const char* file_path) {
  651. furi_assert(instance);
  652. furi_check(instance->avr_isp);
  653. instance->progress_eeprom = 0.0;
  654. uint8_t data[288] = {0};
  655. FURI_LOG_D(TAG, "Write EEPROM %s", file_path);
  656. FlipperI32HexFile* flipper_hex_eeprom_read = flipper_i32hex_file_open_read(file_path);
  657. uint32_t addr = avr_isp_chip_arr[instance->chip_arr_ind].eepromoffset;
  658. FlipperI32HexFileRet flipper_hex_ret =
  659. flipper_i32hex_file_i32hex_to_bin_get_data(flipper_hex_eeprom_read, data, sizeof(data));
  660. while((flipper_hex_ret.status == FlipperI32HexFileStatusData) ||
  661. (flipper_hex_ret.status == FlipperI32HexFileStatusUdateAddr)) {
  662. switch(flipper_hex_ret.status) {
  663. case FlipperI32HexFileStatusData:
  664. if(!avr_isp_write_page(
  665. instance->avr_isp,
  666. STK_SET_EEPROM_TYPE,
  667. avr_isp_chip_arr[instance->chip_arr_ind].eepromsize,
  668. (uint16_t)addr,
  669. avr_isp_chip_arr[instance->chip_arr_ind].eeprompagesize,
  670. data,
  671. flipper_hex_ret.data_size)) {
  672. break;
  673. }
  674. addr += flipper_hex_ret.data_size;
  675. instance->progress_eeprom =
  676. (float)(addr) / ((float)avr_isp_chip_arr[instance->chip_arr_ind].eepromsize);
  677. break;
  678. case FlipperI32HexFileStatusUdateAddr:
  679. addr = data[0] << 24 | data[1] << 16;
  680. break;
  681. default:
  682. furi_crash(TAG " Incorrect status.");
  683. break;
  684. }
  685. flipper_hex_ret = flipper_i32hex_file_i32hex_to_bin_get_data(
  686. flipper_hex_eeprom_read, data, sizeof(data));
  687. }
  688. flipper_i32hex_file_close(flipper_hex_eeprom_read);
  689. instance->progress_eeprom = 1.0f;
  690. }
  691. bool avr_isp_worker_rw_write_dump(
  692. AvrIspWorkerRW* instance,
  693. const char* file_path,
  694. const char* file_name) {
  695. furi_assert(instance);
  696. furi_assert(file_path);
  697. furi_assert(file_name);
  698. FURI_LOG_D(TAG, "Write dump chip");
  699. instance->progress_flash = 0.0f;
  700. instance->progress_eeprom = 0.0f;
  701. bool ret = false;
  702. Storage* storage = furi_record_open(RECORD_STORAGE);
  703. FlipperFormat* flipper_format = flipper_format_file_alloc(storage);
  704. FuriString* file_path_name = furi_string_alloc();
  705. FuriString* temp_str_1 = furi_string_alloc();
  706. FuriString* temp_str_2 = furi_string_alloc();
  707. uint32_t temp_data32;
  708. if(!avr_isp_worker_rw_detect_chip(instance)) {
  709. FURI_LOG_E(TAG, "No detect AVR chip");
  710. } else {
  711. //upload file with description
  712. do {
  713. furi_string_printf(
  714. file_path_name, "%s/%s%s", file_path, file_name, AVR_ISP_APP_EXTENSION);
  715. if(!flipper_format_file_open_existing(
  716. flipper_format, furi_string_get_cstr(file_path_name))) {
  717. FURI_LOG_E(TAG, "Error open file %s", furi_string_get_cstr(file_path_name));
  718. break;
  719. }
  720. if(!flipper_format_read_header(flipper_format, temp_str_1, &temp_data32)) {
  721. FURI_LOG_E(TAG, "Missing or incorrect header");
  722. break;
  723. }
  724. if((!strcmp(furi_string_get_cstr(temp_str_1), AVR_ISP_APP_FILE_TYPE)) &&
  725. temp_data32 == AVR_ISP_APP_FILE_VERSION) {
  726. } else {
  727. FURI_LOG_E(TAG, "Type or version mismatch");
  728. break;
  729. }
  730. AvrIspSignature sig_read = {0};
  731. if(!flipper_format_read_hex(
  732. flipper_format, "Signature", (uint8_t*)&sig_read, sizeof(AvrIspSignature))) {
  733. FURI_LOG_E(TAG, "Missing Signature");
  734. break;
  735. }
  736. if(memcmp(
  737. (uint8_t*)&instance->signature, (uint8_t*)&sig_read, sizeof(AvrIspSignature)) !=
  738. 0) {
  739. FURI_LOG_E(
  740. TAG,
  741. "Wrong chip. Connected (%02X %02X %02X), read from file (%02X %02X %02X)",
  742. instance->signature.vendor,
  743. instance->signature.part_family,
  744. instance->signature.part_number,
  745. sig_read.vendor,
  746. sig_read.part_family,
  747. sig_read.part_number);
  748. break;
  749. }
  750. if(!flipper_format_read_string(flipper_format, "Dump_flash", temp_str_1)) {
  751. FURI_LOG_E(TAG, "Missing Dump_flash");
  752. break;
  753. }
  754. //may not be
  755. flipper_format_read_string(flipper_format, "Dump_eeprom", temp_str_2);
  756. ret = true;
  757. } while(false);
  758. }
  759. flipper_format_free(flipper_format);
  760. furi_record_close(RECORD_STORAGE);
  761. if(ret) {
  762. do {
  763. //checking .hex files for errors
  764. furi_string_printf(
  765. file_path_name, "%s/%s", file_path, furi_string_get_cstr(temp_str_1));
  766. FURI_LOG_D(TAG, "Check flash file");
  767. FlipperI32HexFile* flipper_hex_flash_read =
  768. flipper_i32hex_file_open_read(furi_string_get_cstr(file_path_name));
  769. if(flipper_i32hex_file_check(flipper_hex_flash_read)) {
  770. FURI_LOG_D(TAG, "Check flash file: OK");
  771. } else {
  772. FURI_LOG_E(TAG, "Check flash file: Error");
  773. ret = false;
  774. }
  775. flipper_i32hex_file_close(flipper_hex_flash_read);
  776. if(furi_string_size(temp_str_2) > 4) {
  777. furi_string_printf(
  778. file_path_name, "%s/%s", file_path, furi_string_get_cstr(temp_str_2));
  779. FURI_LOG_D(TAG, "Check eeprom file");
  780. FlipperI32HexFile* flipper_hex_eeprom_read =
  781. flipper_i32hex_file_open_read(furi_string_get_cstr(file_path_name));
  782. if(flipper_i32hex_file_check(flipper_hex_eeprom_read)) {
  783. FURI_LOG_D(TAG, "Check eeprom file: OK");
  784. } else {
  785. FURI_LOG_E(TAG, "Check eeprom file: Error");
  786. ret = false;
  787. }
  788. flipper_i32hex_file_close(flipper_hex_eeprom_read);
  789. }
  790. if(!ret) break;
  791. ret = false;
  792. //erase chip
  793. FURI_LOG_D(TAG, "Erase chip");
  794. if(!avr_isp_erase_chip(instance->avr_isp)) {
  795. FURI_LOG_E(TAG, "Erase chip: Error");
  796. break;
  797. }
  798. if(!avr_isp_auto_set_spi_speed_start_pmode(instance->avr_isp)) {
  799. FURI_LOG_E(TAG, "Well, I managed to enter the mod program");
  800. break;
  801. }
  802. //write flash
  803. furi_string_printf(
  804. file_path_name, "%s/%s", file_path, furi_string_get_cstr(temp_str_1));
  805. avr_isp_worker_rw_write_flash(instance, furi_string_get_cstr(file_path_name));
  806. //write eeprom
  807. if(furi_string_size(temp_str_2) > 4) {
  808. furi_string_printf(
  809. file_path_name, "%s/%s", file_path, furi_string_get_cstr(temp_str_2));
  810. avr_isp_worker_rw_write_eeprom(instance, furi_string_get_cstr(file_path_name));
  811. }
  812. ret = true;
  813. avr_isp_end_pmode(instance->avr_isp);
  814. } while(false);
  815. }
  816. furi_string_free(file_path_name);
  817. furi_string_free(temp_str_1);
  818. furi_string_free(temp_str_2);
  819. return ret;
  820. }
  821. void avr_isp_worker_rw_write_dump_start(
  822. AvrIspWorkerRW* instance,
  823. const char* file_path,
  824. const char* file_name) {
  825. furi_assert(instance);
  826. instance->file_path = file_path;
  827. instance->file_name = file_name;
  828. furi_thread_flags_set(furi_thread_get_id(instance->thread), AvrIspWorkerRWEvtWriting);
  829. }
  830. bool avr_isp_worker_rw_write_fuse(
  831. AvrIspWorkerRW* instance,
  832. const char* file_path,
  833. const char* file_name) {
  834. furi_assert(instance);
  835. furi_assert(file_path);
  836. furi_assert(file_name);
  837. FURI_LOG_D(TAG, "Write fuse chip");
  838. bool ret = false;
  839. uint8_t lfuse;
  840. uint8_t hfuse;
  841. uint8_t efuse;
  842. uint8_t lock;
  843. Storage* storage = furi_record_open(RECORD_STORAGE);
  844. FlipperFormat* flipper_format = flipper_format_file_alloc(storage);
  845. FuriString* temp_str = furi_string_alloc();
  846. uint32_t temp_data32;
  847. if(!avr_isp_worker_rw_detect_chip(instance)) {
  848. FURI_LOG_E(TAG, "No detect AVR chip");
  849. } else {
  850. //upload file with description
  851. do {
  852. furi_string_printf(temp_str, "%s/%s%s", file_path, file_name, AVR_ISP_APP_EXTENSION);
  853. if(!flipper_format_file_open_existing(flipper_format, furi_string_get_cstr(temp_str))) {
  854. FURI_LOG_E(TAG, "Error open file %s", furi_string_get_cstr(temp_str));
  855. break;
  856. }
  857. if(!flipper_format_read_header(flipper_format, temp_str, &temp_data32)) {
  858. FURI_LOG_E(TAG, "Missing or incorrect header");
  859. break;
  860. }
  861. if((!strcmp(furi_string_get_cstr(temp_str), AVR_ISP_APP_FILE_TYPE)) &&
  862. temp_data32 == AVR_ISP_APP_FILE_VERSION) {
  863. } else {
  864. FURI_LOG_E(TAG, "Type or version mismatch");
  865. break;
  866. }
  867. AvrIspSignature sig_read = {0};
  868. if(!flipper_format_read_hex(
  869. flipper_format, "Signature", (uint8_t*)&sig_read, sizeof(AvrIspSignature))) {
  870. FURI_LOG_E(TAG, "Missing Signature");
  871. break;
  872. }
  873. if(memcmp(
  874. (uint8_t*)&instance->signature, (uint8_t*)&sig_read, sizeof(AvrIspSignature)) !=
  875. 0) {
  876. FURI_LOG_E(
  877. TAG,
  878. "Wrong chip. Connected (%02X %02X %02X), read from file (%02X %02X %02X)",
  879. instance->signature.vendor,
  880. instance->signature.part_family,
  881. instance->signature.part_number,
  882. sig_read.vendor,
  883. sig_read.part_family,
  884. sig_read.part_number);
  885. break;
  886. }
  887. if(avr_isp_chip_arr[instance->chip_arr_ind].nfuses > 0) {
  888. if(!flipper_format_read_hex(flipper_format, "Lfuse", &lfuse, 1)) {
  889. FURI_LOG_E(TAG, "Missing Lfuse");
  890. break;
  891. }
  892. }
  893. if(avr_isp_chip_arr[instance->chip_arr_ind].nfuses > 1) {
  894. if(!flipper_format_read_hex(flipper_format, "Hfuse", &hfuse, 1)) {
  895. FURI_LOG_E(TAG, "Missing Hfuse");
  896. break;
  897. }
  898. }
  899. if(avr_isp_chip_arr[instance->chip_arr_ind].nfuses > 2) {
  900. if(!flipper_format_read_hex(flipper_format, "Efuse", &efuse, 1)) {
  901. FURI_LOG_E(TAG, "Missing Efuse");
  902. break;
  903. }
  904. }
  905. if(avr_isp_chip_arr[instance->chip_arr_ind].nlocks == 1) {
  906. if(!flipper_format_read_hex(flipper_format, "Lock", &lock, 1)) {
  907. FURI_LOG_E(TAG, "Missing Lock");
  908. break;
  909. }
  910. }
  911. if(!avr_isp_auto_set_spi_speed_start_pmode(instance->avr_isp)) {
  912. FURI_LOG_E(TAG, "Well, I managed to enter the mod program");
  913. break;
  914. }
  915. ret = true;
  916. if(avr_isp_chip_arr[instance->chip_arr_ind].nfuses > 0) {
  917. if(instance->lfuse != lfuse) {
  918. if(!avr_isp_write_fuse_low(instance->avr_isp, lfuse)) {
  919. FURI_LOG_E(TAG, "Write Lfuse: error");
  920. ret = false;
  921. }
  922. }
  923. }
  924. if(avr_isp_chip_arr[instance->chip_arr_ind].nfuses > 1) {
  925. if(instance->hfuse != hfuse) {
  926. if(!avr_isp_write_fuse_high(instance->avr_isp, hfuse)) {
  927. FURI_LOG_E(TAG, "Write Hfuse: error");
  928. ret = false;
  929. }
  930. }
  931. }
  932. if(avr_isp_chip_arr[instance->chip_arr_ind].nfuses > 2) {
  933. if(instance->efuse != efuse) {
  934. if(!avr_isp_write_fuse_extended(instance->avr_isp, efuse)) {
  935. FURI_LOG_E(TAG, "Write Efuse: error");
  936. ret = false;
  937. }
  938. }
  939. }
  940. if(avr_isp_chip_arr[instance->chip_arr_ind].nlocks == 1) {
  941. FURI_LOG_D(TAG, "Write lock byte");
  942. if(instance->lock != lock) {
  943. if(!avr_isp_write_lock_byte(instance->avr_isp, lock)) {
  944. FURI_LOG_E(TAG, "Write Lock byte: error");
  945. ret = false;
  946. }
  947. }
  948. }
  949. avr_isp_end_pmode(instance->avr_isp);
  950. } while(false);
  951. }
  952. flipper_format_free(flipper_format);
  953. furi_record_close(RECORD_STORAGE);
  954. furi_string_free(temp_str);
  955. return ret;
  956. }
  957. void avr_isp_worker_rw_write_fuse_start(
  958. AvrIspWorkerRW* instance,
  959. const char* file_path,
  960. const char* file_name) {
  961. furi_assert(instance);
  962. instance->file_path = file_path;
  963. instance->file_name = file_name;
  964. furi_thread_flags_set(furi_thread_get_id(instance->thread), AvrIspWorkerRWEvtWritingFuse);
  965. }