swd_probe_app.c 70 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191
  1. #include <furi.h>
  2. #include <gui/gui.h>
  3. #include <gui/elements.h>
  4. #include <dialogs/dialogs.h>
  5. #include <input/input.h>
  6. #include <storage/storage.h>
  7. #include <stdlib.h>
  8. #include <dolphin/dolphin.h>
  9. #include <notification/notification.h>
  10. #include <notification/notification_messages.h>
  11. #include "swd_probe_app.h"
  12. #include "swd_probe_icons.h"
  13. #include "jep106.h"
  14. #define COUNT(x) (sizeof(x) / sizeof((x)[0]))
  15. static void render_callback(Canvas* const canvas, void* cb_ctx);
  16. static bool swd_message_process(AppFSM* ctx);
  17. static uint8_t swd_transfer(AppFSM* const ctx, bool ap, bool write, uint8_t a23, uint32_t* data);
  18. static const GpioPin* gpios[] = {
  19. &gpio_ext_pc0,
  20. &gpio_ext_pc1,
  21. &gpio_ext_pc3,
  22. &gpio_ext_pb2,
  23. &gpio_ext_pb3,
  24. &gpio_ext_pa4,
  25. &gpio_ext_pa6,
  26. &gpio_ext_pa7};
  27. static const char* gpio_names[] = {"PC0", "PC1", "PC3", "PB2", "PB3", "PA4", "PA6", "PA7"};
  28. /* bit set: clock, else data */
  29. static const uint8_t gpio_direction_mask[6] =
  30. {0b10101010, 0b01010101, 0b11001100, 0b00110011, 0b11110000, 0b00001111};
  31. static const uint8_t gpio_direction_ind[6] = "-\\||/-";
  32. static bool has_multiple_bits(uint8_t x) {
  33. return (x & (x - 1)) != 0;
  34. }
  35. static int get_bit_num(uint8_t x) {
  36. return __builtin_ctz(x);
  37. }
  38. static const char* gpio_name(uint8_t mask) {
  39. if(has_multiple_bits(mask)) {
  40. return "Pxx";
  41. }
  42. int io = get_bit_num(mask);
  43. if(io >= COUNT(gpio_names)) {
  44. return "Pxx";
  45. }
  46. return gpio_names[io];
  47. }
  48. static void swd_configure_pins(AppFSM* const ctx, bool output) {
  49. if(ctx->mode_page != ModePageScan && ctx->io_num_swc < 8 && ctx->io_num_swd < 8) {
  50. furi_hal_gpio_init(
  51. gpios[ctx->io_num_swc], GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh);
  52. if(!output) {
  53. furi_hal_gpio_init(
  54. gpios[ctx->io_num_swd], GpioModeInput, GpioPullUp, GpioSpeedVeryHigh);
  55. } else {
  56. furi_hal_gpio_init(
  57. gpios[ctx->io_num_swd], GpioModeOutputOpenDrain, GpioPullUp, GpioSpeedVeryHigh);
  58. }
  59. return;
  60. }
  61. for(int io = 0; io < 8; io++) {
  62. uint8_t bitmask = 1 << io;
  63. /* if neither candidate for SWC nor SWD then skip */
  64. if(!(ctx->io_swc & bitmask) && !(ctx->io_swd & bitmask)) {
  65. furi_hal_gpio_init(gpios[io], GpioModeInput, GpioPullUp, GpioSpeedVeryHigh);
  66. continue;
  67. }
  68. if(ctx->current_mask & bitmask) {
  69. /* set for clock */
  70. furi_hal_gpio_init(gpios[io], GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh);
  71. } else {
  72. /* set for data */
  73. if(!output) {
  74. furi_hal_gpio_init(gpios[io], GpioModeInput, GpioPullUp, GpioSpeedVeryHigh);
  75. } else {
  76. furi_hal_gpio_init(
  77. gpios[io], GpioModeOutputOpenDrain, GpioPullUp, GpioSpeedVeryHigh);
  78. }
  79. }
  80. }
  81. }
  82. static void swd_set_clock(AppFSM* const ctx, const uint8_t level) {
  83. if(ctx->mode_page != ModePageScan && ctx->io_num_swc < 8) {
  84. furi_hal_gpio_write(gpios[ctx->io_num_swc], level);
  85. return;
  86. }
  87. for(int io = 0; io < 8; io++) {
  88. uint8_t bitmask = 1 << io;
  89. /* if no candidate for SWC then skip */
  90. if(!(ctx->io_swc & bitmask)) {
  91. continue;
  92. }
  93. if(ctx->current_mask & bitmask) {
  94. furi_hal_gpio_write(gpios[io], level);
  95. }
  96. }
  97. }
  98. static void swd_set_data(AppFSM* const ctx, const uint8_t level) {
  99. if(ctx->mode_page != ModePageScan && ctx->io_num_swd < 8) {
  100. furi_hal_gpio_write(gpios[ctx->io_num_swd], level);
  101. return;
  102. }
  103. for(int io = 0; io < 8; io++) {
  104. uint8_t bitmask = 1 << io;
  105. /* if no candidate for SWD then skip */
  106. if(!(ctx->io_swd & bitmask)) {
  107. continue;
  108. }
  109. if(!(ctx->current_mask & bitmask)) {
  110. furi_hal_gpio_write(gpios[io], level);
  111. }
  112. }
  113. }
  114. static uint8_t swd_get_data(AppFSM* const ctx) {
  115. if(ctx->mode_page != ModePageScan && ctx->io_num_swd < 8) {
  116. return furi_hal_gpio_read(gpios[ctx->io_num_swd]);
  117. }
  118. uint8_t bits = 0;
  119. for(int io = 0; io < 8; io++) {
  120. uint8_t bitmask = 1 << io;
  121. /* if no candidate for SWD then skip */
  122. if(!(ctx->io_swd & bitmask)) {
  123. continue;
  124. }
  125. bits |= furi_hal_gpio_read(gpios[io]) ? bitmask : 0;
  126. }
  127. return bits;
  128. }
  129. static void swd_clock_delay(AppFSM* const ctx) {
  130. if(ctx->swd_clock_delay) {
  131. furi_delay_us(ctx->swd_clock_delay);
  132. }
  133. }
  134. static void swd_write_bit(AppFSM* const ctx, bool level) {
  135. swd_set_clock(ctx, 0);
  136. swd_set_data(ctx, level);
  137. swd_clock_delay(ctx);
  138. swd_set_clock(ctx, 1);
  139. swd_clock_delay(ctx);
  140. swd_set_clock(ctx, 0);
  141. }
  142. static uint8_t swd_read_bit(AppFSM* const ctx) {
  143. swd_set_clock(ctx, 1);
  144. swd_clock_delay(ctx);
  145. swd_set_clock(ctx, 0);
  146. uint8_t bits = swd_get_data(ctx);
  147. swd_clock_delay(ctx);
  148. swd_set_clock(ctx, 1);
  149. return bits;
  150. }
  151. /* send a byte or less LSB-first */
  152. static void swd_write_byte(AppFSM* const ctx, const uint8_t data, size_t bits) {
  153. for(size_t pos = 0; pos < bits; pos++) {
  154. swd_write_bit(ctx, data & (1 << pos));
  155. }
  156. }
  157. /* send a sequence of bytes LSB-first */
  158. static void swd_write(AppFSM* const ctx, const uint8_t* data, size_t bits) {
  159. size_t byte_pos = 0;
  160. while(bits > 0) {
  161. size_t remain = (bits > 8) ? 8 : bits;
  162. swd_write_byte(ctx, data[byte_pos++], remain);
  163. bits -= remain;
  164. }
  165. }
  166. static uint8_t swd_transfer(AppFSM* const ctx, bool ap, bool write, uint8_t a23, uint32_t* data) {
  167. swd_set_data(ctx, false);
  168. swd_configure_pins(ctx, true);
  169. uint32_t idle = 0;
  170. swd_write(ctx, (uint8_t*)&idle, ctx->swd_idle_bits);
  171. uint8_t request[] = {0};
  172. request[0] |= 0x01; /* start bit*/
  173. request[0] |= ap ? 0x02 : 0; /* APnDP */
  174. request[0] |= write ? 0 : 0x04; /* operation */
  175. request[0] |= (a23 & 0x01) ? 0x08 : 0; /* A[2:3] */
  176. request[0] |= (a23 & 0x02) ? 0x10 : 0; /* A[2:3] */
  177. request[0] |= 0x80; /* park bit */
  178. request[0] |= __builtin_parity(request[0]) ? 0x20 : 0; /* parity */
  179. swd_write(ctx, request, sizeof(request) * 8);
  180. /* turnaround cycle */
  181. swd_configure_pins(ctx, false);
  182. uint8_t ack = 0;
  183. /* receive 3 ACK bits */
  184. for(int pos = 0; pos < 3; pos++) {
  185. ack >>= 1;
  186. ack |= swd_read_bit(ctx) ? 0x04 : 0;
  187. }
  188. /* force ABORT/CTRL to always work */
  189. if(!ap && a23 == 0) {
  190. ack = 1;
  191. }
  192. if(ack != 0x01) {
  193. return ack;
  194. }
  195. if(write) {
  196. swd_write_bit(ctx, 0);
  197. swd_configure_pins(ctx, true);
  198. /* send 32 WDATA bits */
  199. for(int pos = 0; pos < 32; pos++) {
  200. swd_write_bit(ctx, *data & (1 << pos));
  201. }
  202. /* send parity bit */
  203. swd_write_bit(ctx, __builtin_parity(*data));
  204. } else {
  205. *data = 0;
  206. /* receive 32 RDATA bits */
  207. for(int pos = 0; pos < 32; pos++) {
  208. *data >>= 1;
  209. *data |= swd_read_bit(ctx) ? 0x80000000 : 0;
  210. }
  211. /* receive parity bit */
  212. bool parity = swd_read_bit(ctx);
  213. if(parity != __builtin_parity(*data)) {
  214. return 8;
  215. }
  216. }
  217. swd_set_data(ctx, false);
  218. swd_configure_pins(ctx, true);
  219. return ack;
  220. }
  221. /* A line reset is achieved by holding the data signal HIGH for at least 50 clock cycles, followed by at least two idle cycles. */
  222. static void swd_line_reset(AppFSM* const ctx) {
  223. for(int bitcount = 0; bitcount < 50; bitcount += 8) {
  224. swd_write_byte(ctx, 0xFF, 8);
  225. }
  226. swd_write_byte(ctx, 0, 8);
  227. ctx->dp_regs.select_ok = false;
  228. }
  229. static void swd_abort(AppFSM* const ctx) {
  230. uint32_t dpidr;
  231. /* first reset the line */
  232. swd_line_reset(ctx);
  233. swd_transfer(ctx, false, false, 0, &dpidr);
  234. uint32_t abort = 0x0E;
  235. swd_transfer(ctx, false, true, 0, &abort);
  236. }
  237. /*
  238. static uint8_t swd_transferxx(AppFSM* const ctx, bool ap, bool write, uint8_t a23, uint32_t* data) {
  239. uint8_t ret = 0;
  240. for(int tries = 0; tries < 3; tries++) {
  241. ret = swd_transfer(ctx, ap, write, a23, data);
  242. if(ret == 1) {
  243. return ret;
  244. }
  245. furi_log_print_format(FuriLogLevelDefault, TAG, "swd_transfer: failed: %d/3", tries);
  246. swd_abort(ctx);
  247. }
  248. return 9;
  249. }*/
  250. static void swd_abort_simple(AppFSM* const ctx) {
  251. uint32_t abort = 0x0E;
  252. swd_transfer(ctx, false, true, 0, &abort);
  253. uint32_t dpidr;
  254. if(swd_transfer(ctx, false, false, 0, &dpidr) != 1) {
  255. swd_abort(ctx);
  256. }
  257. }
  258. static uint8_t swd_select(AppFSM* const ctx, uint8_t ap_sel, uint8_t ap_bank, uint8_t dp_bank) {
  259. uint32_t bank_reg = (ap_sel << 24) | ((ap_bank & 0x0F) << 4) | (dp_bank & 0x0F);
  260. if(ctx->dp_regs.select_ok && bank_reg == ctx->dp_regs.select) {
  261. return 1;
  262. }
  263. uint8_t ret = swd_transfer(ctx, false, true, 2, &bank_reg);
  264. if(ret != 1) {
  265. //ctx->dp_regs.select_ok = false;
  266. furi_log_print_format(FuriLogLevelDefault, TAG, "swd_select: failed: %d", ret);
  267. }
  268. ctx->dp_regs.select = bank_reg;
  269. ctx->dp_regs.select_ok = true;
  270. return ret;
  271. }
  272. static uint8_t
  273. swd_read_dpbank(AppFSM* const ctx, uint8_t dp_off, uint8_t dp_bank, uint32_t* data) {
  274. /* select target bank */
  275. uint8_t ret = swd_select(ctx, 0, 0, dp_bank);
  276. if(ret != 1) {
  277. furi_log_print_format(FuriLogLevelDefault, TAG, "swd_read_dpbank: swd_select failed");
  278. return ret;
  279. }
  280. /* read data from it */
  281. *data = 0;
  282. ret = swd_transfer(ctx, false, false, dp_off, data);
  283. if(ret != 1) {
  284. furi_log_print_format(FuriLogLevelDefault, TAG, "swd_read_dpbank: failed: %d", ret);
  285. return ret;
  286. }
  287. return ret;
  288. }
  289. static uint8_t swd_read_ap(AppFSM* const ctx, uint8_t ap, uint8_t ap_off, uint32_t* data) {
  290. uint8_t ret = swd_select(ctx, ap, (ap_off >> 4) & 0x0F, 0);
  291. if(ret != 1) {
  292. furi_log_print_format(FuriLogLevelDefault, TAG, "swd_read_ap: swd_select failed");
  293. return ret;
  294. }
  295. ret = swd_transfer(ctx, true, false, (ap_off >> 2) & 3, data);
  296. *data = 0;
  297. ret = swd_transfer(ctx, true, false, (ap_off >> 2) & 3, data);
  298. if(ret != 1) {
  299. furi_log_print_format(FuriLogLevelDefault, TAG, "swd_read_ap: failed: %d", ret);
  300. return ret;
  301. }
  302. return ret;
  303. }
  304. static uint8_t swd_read_ap_single(AppFSM* const ctx, uint8_t ap, uint8_t ap_off, uint32_t* data) {
  305. uint8_t ret = swd_select(ctx, ap, (ap_off >> 4) & 0x0F, 0);
  306. if(ret != 1) {
  307. furi_log_print_format(FuriLogLevelDefault, TAG, "swd_read_ap_single: swd_select failed");
  308. return ret;
  309. }
  310. *data = 0;
  311. ret = swd_transfer(ctx, true, false, (ap_off >> 2) & 3, data);
  312. if(ret != 1) {
  313. furi_log_print_format(FuriLogLevelDefault, TAG, "swd_read_ap_single: failed: %d", ret);
  314. return ret;
  315. }
  316. return ret;
  317. }
  318. static uint8_t swd_write_ap(AppFSM* const ctx, uint8_t ap, uint8_t ap_off, uint32_t data) {
  319. uint8_t ret = swd_select(ctx, ap, (ap_off >> 4) & 0x0F, 0);
  320. if(ret != 1) {
  321. furi_log_print_format(FuriLogLevelDefault, TAG, "swd_write_ap: swd_select failed");
  322. return ret;
  323. }
  324. ret = swd_transfer(ctx, true, true, (ap_off >> 2) & 3, &data);
  325. if(ret != 1) {
  326. furi_log_print_format(FuriLogLevelDefault, TAG, "swd_write_ap: failed: %d", ret);
  327. return ret;
  328. }
  329. return ret;
  330. }
  331. static uint8_t swd_write_memory(AppFSM* const ctx, uint8_t ap, uint32_t address, uint32_t data) {
  332. uint8_t ret = 0;
  333. uint32_t csw = 0x23000002;
  334. ret |= swd_write_ap(ctx, ap, MEMAP_CSW, csw);
  335. ret |= swd_write_ap(ctx, ap, MEMAP_TAR, address);
  336. ret |= swd_write_ap(ctx, ap, MEMAP_DRW, data);
  337. furi_log_print_format(
  338. FuriLogLevelDefault, TAG, "swd_write_memory: write 0x%08lX to 0x%08lX", data, address);
  339. if(ret != 1) {
  340. swd_abort(ctx);
  341. }
  342. return ret;
  343. }
  344. static uint8_t swd_read_memory(AppFSM* const ctx, uint8_t ap, uint32_t address, uint32_t* data) {
  345. uint8_t ret = 0;
  346. uint32_t csw = 0x23000002;
  347. ret |= swd_write_ap(ctx, ap, MEMAP_CSW, csw);
  348. ret |= swd_write_ap(ctx, ap, MEMAP_TAR, address);
  349. ret |= swd_read_ap(ctx, ap, MEMAP_DRW, data);
  350. if(ret != 1) {
  351. swd_abort(ctx);
  352. }
  353. return ret;
  354. }
  355. static uint8_t swd_read_memory_block(
  356. AppFSM* const ctx,
  357. uint8_t ap,
  358. uint32_t address,
  359. uint8_t* buf,
  360. uint32_t len) {
  361. uint8_t ret = 0;
  362. uint32_t data = 0;
  363. bool first = true;
  364. uint32_t csw = 0x23000002;
  365. ret |= swd_write_ap(ctx, ap, MEMAP_CSW, csw);
  366. ret |= swd_write_ap(ctx, ap, MEMAP_TAR, address);
  367. ret |= swd_read_ap_single(ctx, ap, MEMAP_DRW, &data);
  368. for(size_t pos = 0; pos < len; pos += 4) {
  369. data = 0xDEADBEEF;
  370. ret |= swd_read_ap_single(ctx, ap, MEMAP_DRW, &data);
  371. furi_log_print_format(FuriLogLevelDefault, TAG, "##read %lX", data);
  372. memcpy(&buf[pos], &data, 4);
  373. if(ret != 1) {
  374. swd_abort(ctx);
  375. return ret;
  376. }
  377. }
  378. return ret;
  379. }
  380. static uint32_t swd_detect(AppFSM* const ctx) {
  381. swd_set_data(ctx, false);
  382. swd_configure_pins(ctx, true);
  383. uint8_t data[] = {0xA5};
  384. swd_write(ctx, data, sizeof(data) * 8);
  385. /* turnaround cycle */
  386. swd_configure_pins(ctx, false);
  387. uint8_t ack_bits[3];
  388. uint8_t rdata[32];
  389. /* receive 3 ACK bits */
  390. for(int pos = 0; pos < 3; pos++) {
  391. ack_bits[pos] = swd_read_bit(ctx);
  392. }
  393. /* receive 32 RDATA bits */
  394. for(int pos = 0; pos < 32; pos++) {
  395. rdata[pos] = swd_read_bit(ctx);
  396. }
  397. /* receive parity bit */
  398. uint8_t parity = swd_read_bit(ctx);
  399. for(int io = 0; io < 8; io++) {
  400. uint8_t bitmask = 1 << io;
  401. /* skip if it's a clock */
  402. if(ctx->current_mask & bitmask) {
  403. continue;
  404. }
  405. uint8_t ack = 0;
  406. for(int pos = 0; pos < 3; pos++) {
  407. ack >>= 1;
  408. ack |= (ack_bits[pos] & bitmask) ? 4 : 0;
  409. }
  410. uint32_t dpidr = 0;
  411. for(int pos = 0; pos < 32; pos++) {
  412. dpidr >>= 1;
  413. dpidr |= (rdata[pos] & bitmask) ? 0x80000000 : 0;
  414. }
  415. if(ack == 1 && dpidr != 0 && dpidr != 0xFFFFFFFF) {
  416. bool received_parity = (parity & bitmask);
  417. if(__builtin_parity(dpidr) == received_parity) {
  418. ctx->dp_regs.dpidr = dpidr;
  419. ctx->dp_regs.dpidr_ok = true;
  420. ctx->detected = true;
  421. ctx->io_swd = bitmask;
  422. ctx->io_swc &= ctx->current_mask;
  423. furi_log_print_format(
  424. FuriLogLevelDefault,
  425. TAG,
  426. "swd_detect: data: %08lX, io_swd %02X, io_swc %02X",
  427. dpidr,
  428. ctx->io_swd,
  429. ctx->io_swc);
  430. if(!has_multiple_bits(ctx->io_swc)) {
  431. ctx->io_num_swd = get_bit_num(ctx->io_swd);
  432. ctx->io_num_swc = get_bit_num(ctx->io_swc);
  433. }
  434. }
  435. }
  436. }
  437. swd_set_data(ctx, false);
  438. swd_configure_pins(ctx, true);
  439. return 0;
  440. }
  441. static void swd_scan(AppFSM* const ctx) {
  442. /* To switch SWJ-DP from JTAG to SWD operation:
  443. 1. Send at least 50 SWCLKTCK cycles with SWDIOTMS HIGH. This ensures that the current interface is in its reset state. The JTAG interface only detects the 16-bit JTAG-to-SWD sequence starting from the Test-Logic-Reset state.
  444. 2. Send the 16-bit JTAG-to-SWD select sequence 0x79e7 on SWDIOTMS.
  445. 3. Send at least 50 SWCLKTCK cycles with SWDIOTMS HIGH. This ensures that if SWJ-DP was already in SWD operation before sending the select sequence, the SWD interface enters line reset state.
  446. */
  447. swd_configure_pins(ctx, true);
  448. /* reset JTAG interface */
  449. for(int bitcount = 0; bitcount < 50; bitcount += 8) {
  450. swd_write_byte(ctx, 0xFF, 8);
  451. }
  452. /* Send the 16-bit JTAG-to-SWD select sequence */
  453. swd_write_byte(ctx, 0x9E, 8);
  454. swd_write_byte(ctx, 0xE7, 8);
  455. /* resynchronize SWD */
  456. swd_line_reset(ctx);
  457. swd_detect(ctx);
  458. }
  459. static bool swd_ensure_powerup(AppFSM* const ctx) {
  460. if(!(ctx->dp_regs.ctrlstat & (CSYSPWRUPREQ | CDBGPWRUPREQ))) {
  461. /* fetch current CTRL/STAT */
  462. swd_transfer(ctx, false, false, 1, &ctx->dp_regs.ctrlstat);
  463. /* enable requests */
  464. ctx->dp_regs.ctrlstat |= CDBGPWRUPREQ;
  465. ctx->dp_regs.ctrlstat |= CSYSPWRUPREQ;
  466. furi_log_print_format(FuriLogLevelDefault, TAG, "no (CSYSPWRUPREQ | CDBGPWRUPREQ)");
  467. swd_transfer(ctx, false, true, 1, &ctx->dp_regs.ctrlstat);
  468. return false;
  469. }
  470. if(!(ctx->dp_regs.ctrlstat & CDBGPWRUPACK)) {
  471. /* fetch current CTRL/STAT */
  472. swd_transfer(ctx, false, false, 1, &ctx->dp_regs.ctrlstat);
  473. furi_log_print_format(FuriLogLevelDefault, TAG, "no CDBGPWRUPACK");
  474. return false;
  475. }
  476. return true;
  477. }
  478. static void swd_apscan_reset(AppFSM* const ctx) {
  479. for(int reset_ap = 0; reset_ap < COUNT(ctx->apidr_info); reset_ap++) {
  480. ctx->apidr_info[reset_ap].tested = false;
  481. }
  482. }
  483. static bool swd_apscan_test(AppFSM* const ctx, uint32_t ap) {
  484. furi_assert(ctx);
  485. furi_assert(ap < sizeof(ctx->apidr_info));
  486. ctx->apidr_info[ap].tested = true;
  487. uint32_t data = 0;
  488. uint32_t base = 0;
  489. if(swd_read_ap(ctx, ap, AP_IDR, &data) != 1) {
  490. swd_abort(ctx);
  491. return false;
  492. }
  493. if(data == 0) {
  494. return false;
  495. }
  496. furi_log_print_format(FuriLogLevelDefault, TAG, "AP%lu detected", ap);
  497. ctx->apidr_info[ap].ok = true;
  498. ctx->apidr_info[ap].revision = (data >> 24) & 0x0F;
  499. ctx->apidr_info[ap].designer = (data >> 17) & 0x3FF;
  500. ctx->apidr_info[ap].class = (data >> 13) & 0x0F;
  501. ctx->apidr_info[ap].variant = (data >> 4) & 0x0F;
  502. ctx->apidr_info[ap].type = (data >> 0) & 0x0F;
  503. if(swd_read_ap(ctx, ap, AP_BASE, &ctx->apidr_info[ap].base) != 1) {
  504. swd_abort(ctx);
  505. return false;
  506. }
  507. return true;
  508. }
  509. /************************** script helpers **************************/
  510. static bool swd_script_seek_newline(ScriptContext* ctx) {
  511. while(true) {
  512. uint8_t ch = 0;
  513. uint16_t ret = storage_file_read(ctx->script_file, &ch, 1);
  514. if(ret != 1) {
  515. return false;
  516. }
  517. if(ch == '\n') {
  518. return true;
  519. }
  520. }
  521. }
  522. static bool swd_script_skip_whitespace(ScriptContext* ctx) {
  523. while(true) {
  524. uint8_t ch = 0;
  525. uint64_t start_pos = storage_file_tell(ctx->script_file);
  526. uint16_t ret = storage_file_read(ctx->script_file, &ch, 1);
  527. if(ret != 1) {
  528. return false;
  529. }
  530. if(ch == '\n') {
  531. return false;
  532. }
  533. if(ch != ' ') {
  534. storage_file_seek(ctx->script_file, start_pos, true);
  535. return true;
  536. }
  537. }
  538. }
  539. static bool swd_script_get_string(ScriptContext* ctx, char* str, size_t max_length) {
  540. bool quot = false;
  541. size_t pos = 0;
  542. str[pos] = '\000';
  543. while(true) {
  544. char ch = 0;
  545. uint64_t start_pos = storage_file_tell(ctx->script_file);
  546. uint16_t ret = storage_file_read(ctx->script_file, &ch, 1);
  547. if(ret != 1) {
  548. furi_log_print_format(FuriLogLevelDefault, TAG, "swd_script_get_string: end reached?");
  549. return false;
  550. }
  551. if(ch == '"') {
  552. quot = !quot;
  553. continue;
  554. }
  555. if(!quot) {
  556. if(ch == ' ') {
  557. break;
  558. }
  559. if(ch == '\r' || ch == '\n') {
  560. storage_file_seek(ctx->script_file, start_pos, true);
  561. break;
  562. }
  563. }
  564. if(pos + 2 > max_length) {
  565. furi_log_print_format(FuriLogLevelDefault, TAG, "swd_script_get_string: too long");
  566. return false;
  567. }
  568. str[pos++] = ch;
  569. str[pos] = '\000';
  570. }
  571. furi_log_print_format(FuriLogLevelDebug, TAG, "swd_script_get_string: got '%s'", str);
  572. return true;
  573. }
  574. static bool swd_script_get_number(ScriptContext* ctx, uint32_t* number) {
  575. char str[16];
  576. if(!swd_script_get_string(ctx, str, sizeof(str))) {
  577. furi_log_print_format(
  578. FuriLogLevelDefault, TAG, "swd_script_get_number: could not get string");
  579. return false;
  580. }
  581. furi_log_print_format(FuriLogLevelDebug, TAG, "swd_script_get_number: got '%s'", str);
  582. size_t pos = 0;
  583. *number = 0;
  584. /* hex number? */
  585. if(!strncmp(str, "0x", 2)) {
  586. pos += 2;
  587. while(str[pos]) {
  588. uint8_t ch = str[pos++];
  589. uint8_t ch_num = ch - '0';
  590. uint8_t ch_hex = (ch & ~0x20) - 'A';
  591. *number <<= 4;
  592. if(ch_num <= 10) {
  593. *number += ch_num;
  594. } else if(ch_hex <= 5) {
  595. *number += 10 + ch_hex;
  596. } else {
  597. return false;
  598. }
  599. }
  600. } else {
  601. while(str[pos]) {
  602. uint8_t ch = str[pos++];
  603. uint8_t ch_num = ch - '0';
  604. *number *= 10;
  605. if(ch_num < 10) {
  606. *number += ch_num;
  607. } else {
  608. return false;
  609. }
  610. }
  611. }
  612. return true;
  613. }
  614. static void swd_script_gui_refresh(ScriptContext* ctx) {
  615. if(furi_message_queue_get_count(ctx->app->event_queue) > 0) {
  616. swd_message_process(ctx->app);
  617. }
  618. if(!ctx->status_ignore) {
  619. furi_log_print_format(FuriLogLevelDebug, TAG, "Status: %s", ctx->app->state_string);
  620. view_port_update(ctx->app->view_port);
  621. }
  622. }
  623. /************************** script functions **************************/
  624. static bool swd_scriptfunc_comment(ScriptContext* ctx) {
  625. furi_log_print_format(FuriLogLevelDebug, TAG, "comment");
  626. swd_script_seek_newline(ctx);
  627. return true;
  628. }
  629. static bool swd_scriptfunc_label(ScriptContext* ctx) {
  630. uint32_t sound = 0;
  631. char label[256];
  632. furi_log_print_format(FuriLogLevelDebug, TAG, "label");
  633. swd_script_skip_whitespace(ctx);
  634. if(!swd_script_get_string(ctx, label, sizeof(label))) {
  635. furi_log_print_format(FuriLogLevelDefault, TAG, "label: failed to parse");
  636. return false;
  637. }
  638. if(!strcmp(label, ctx->goto_label)) {
  639. ctx->goto_active = false;
  640. furi_log_print_format(FuriLogLevelDebug, TAG, "label: matches '%s'", ctx->goto_label);
  641. }
  642. swd_script_seek_newline(ctx);
  643. return true;
  644. }
  645. static bool swd_scriptfunc_goto(ScriptContext* ctx) {
  646. uint32_t sound = 0;
  647. furi_log_print_format(FuriLogLevelDebug, TAG, "goto");
  648. swd_script_skip_whitespace(ctx);
  649. if(!swd_script_get_string(ctx, ctx->goto_label, sizeof(ctx->goto_label))) {
  650. furi_log_print_format(FuriLogLevelDefault, TAG, "goto: failed to parse");
  651. return false;
  652. }
  653. /* start from beginning and rerun starting from label */
  654. ctx->goto_active = true;
  655. ctx->restart = true;
  656. swd_script_seek_newline(ctx);
  657. return true;
  658. }
  659. static bool swd_scriptfunc_status(ScriptContext* ctx) {
  660. uint32_t status = 1;
  661. furi_log_print_format(FuriLogLevelDebug, TAG, "status");
  662. swd_script_skip_whitespace(ctx);
  663. swd_script_get_number(ctx, &status);
  664. ctx->status_ignore = status == 0;
  665. swd_script_seek_newline(ctx);
  666. return true;
  667. }
  668. static bool swd_scriptfunc_errors(ScriptContext* ctx) {
  669. char type[32];
  670. furi_log_print_format(FuriLogLevelDebug, TAG, "errors");
  671. swd_script_skip_whitespace(ctx);
  672. if(!swd_script_get_string(ctx, type, sizeof(type))) {
  673. furi_log_print_format(FuriLogLevelDebug, TAG, "goto: failed to parse");
  674. return false;
  675. }
  676. if(!strcmp(type, "ignore")) {
  677. ctx->errors_ignore = true;
  678. }
  679. if(!strcmp(type, "fail")) {
  680. ctx->errors_ignore = false;
  681. }
  682. swd_script_seek_newline(ctx);
  683. return true;
  684. }
  685. static bool swd_scriptfunc_beep(ScriptContext* ctx) {
  686. uint32_t sound = 0;
  687. furi_log_print_format(FuriLogLevelDebug, TAG, "beep");
  688. swd_script_skip_whitespace(ctx);
  689. swd_script_get_number(ctx, &sound);
  690. notification_message_block(ctx->app->notification, seq_sounds[sound]);
  691. swd_script_seek_newline(ctx);
  692. return true;
  693. }
  694. static bool swd_scriptfunc_message(ScriptContext* ctx) {
  695. uint32_t wait_time = 0;
  696. char message[256];
  697. char type[256];
  698. bool success = true;
  699. bool show_dialog = false;
  700. if(!swd_script_skip_whitespace(ctx)) {
  701. furi_log_print_format(FuriLogLevelDefault, TAG, "message: missing whitespace");
  702. return false;
  703. }
  704. if(!swd_script_get_number(ctx, &wait_time)) {
  705. furi_log_print_format(FuriLogLevelDefault, TAG, "message: failed to parse wait_time");
  706. return false;
  707. }
  708. if(!swd_script_get_string(ctx, message, sizeof(message))) {
  709. furi_log_print_format(FuriLogLevelDefault, TAG, "message: failed to parse message");
  710. return false;
  711. }
  712. if(swd_script_get_string(ctx, type, sizeof(type))) {
  713. if(!strcmp(type, "dialog")) {
  714. show_dialog = true;
  715. }
  716. }
  717. if(wait_time <= 60 * 1000) {
  718. strcpy(ctx->app->state_string, message);
  719. swd_script_gui_refresh(ctx);
  720. furi_delay_ms(wait_time);
  721. if(show_dialog) {
  722. DialogMessage* message = dialog_message_alloc();
  723. dialog_message_set_header(message, "SWD Probe", 16, 2, AlignLeft, AlignTop);
  724. dialog_message_set_icon(message, &I_app, 3, 2);
  725. dialog_message_set_text(message, ctx->app->state_string, 3, 16, AlignLeft, AlignTop);
  726. dialog_message_set_buttons(message, "Abort", "Ok", NULL);
  727. success = dialog_message_show(ctx->app->dialogs, message) == DialogMessageButtonCenter;
  728. dialog_message_free(message);
  729. }
  730. }
  731. swd_script_seek_newline(ctx);
  732. return success;
  733. }
  734. static bool swd_scriptfunc_swd_idle_bits(ScriptContext* ctx) {
  735. uint32_t swd_idle_bits = 0;
  736. if(!swd_script_skip_whitespace(ctx)) {
  737. furi_log_print_format(FuriLogLevelDefault, TAG, "swd_idle_bits: missing whitespace");
  738. return false;
  739. }
  740. if(!swd_script_get_number(ctx, &swd_idle_bits)) {
  741. furi_log_print_format(FuriLogLevelDefault, TAG, "swd_idle_bits: failed to parse");
  742. return false;
  743. }
  744. if(swd_idle_bits <= 32) {
  745. ctx->app->swd_idle_bits = swd_idle_bits;
  746. } else {
  747. furi_log_print_format(
  748. FuriLogLevelDefault, TAG, "swd_idle_bits: value must be between 1 and 32");
  749. }
  750. swd_script_seek_newline(ctx);
  751. return true;
  752. }
  753. static bool swd_scriptfunc_swd_clock_delay(ScriptContext* ctx) {
  754. uint32_t swd_clock_delay = 0;
  755. if(!swd_script_skip_whitespace(ctx)) {
  756. furi_log_print_format(FuriLogLevelDefault, TAG, "swd_clock_delay: missing whitespace");
  757. return false;
  758. }
  759. if(!swd_script_get_number(ctx, &swd_clock_delay)) {
  760. furi_log_print_format(FuriLogLevelDefault, TAG, "swd_clock_delay: failed to parse");
  761. return false;
  762. }
  763. if(swd_clock_delay <= 1000000) {
  764. ctx->app->swd_clock_delay = swd_clock_delay;
  765. } else {
  766. furi_log_print_format(
  767. FuriLogLevelDefault, TAG, "swd_clock_delay: value must be between 1 and 1000000");
  768. }
  769. swd_script_seek_newline(ctx);
  770. return true;
  771. }
  772. static bool swd_scriptfunc_maxtries(ScriptContext* ctx) {
  773. uint32_t max_tries = 0;
  774. if(!swd_script_skip_whitespace(ctx)) {
  775. furi_log_print_format(FuriLogLevelDefault, TAG, "max_tries: missing whitespace");
  776. return false;
  777. }
  778. if(!swd_script_get_number(ctx, &max_tries)) {
  779. furi_log_print_format(FuriLogLevelDefault, TAG, "max_tries: failed to parse");
  780. return false;
  781. }
  782. if(max_tries >= 1 && max_tries <= 1024) {
  783. ctx->max_tries = max_tries;
  784. } else {
  785. furi_log_print_format(
  786. FuriLogLevelDefault, TAG, "max_tries: value must be between 1 and 1024");
  787. }
  788. swd_script_seek_newline(ctx);
  789. return true;
  790. }
  791. static bool swd_scriptfunc_blocksize(ScriptContext* ctx) {
  792. uint32_t block_size = 0;
  793. if(!swd_script_skip_whitespace(ctx)) {
  794. furi_log_print_format(FuriLogLevelDefault, TAG, "block_size: missing whitespace");
  795. return false;
  796. }
  797. if(!swd_script_get_number(ctx, &block_size)) {
  798. furi_log_print_format(FuriLogLevelDefault, TAG, "block_size: failed to parse");
  799. return false;
  800. }
  801. if(block_size >= 4 && block_size <= 0x1000) {
  802. ctx->block_size = block_size;
  803. } else {
  804. furi_log_print_format(
  805. FuriLogLevelDefault, TAG, "block_size: value must be between 4 and 4096");
  806. }
  807. swd_script_seek_newline(ctx);
  808. return true;
  809. }
  810. static bool swd_scriptfunc_apselect(ScriptContext* ctx) {
  811. uint32_t ap = 0;
  812. if(!swd_script_skip_whitespace(ctx)) {
  813. furi_log_print_format(FuriLogLevelDefault, TAG, "apselect: missing whitespace");
  814. return false;
  815. }
  816. if(!swd_script_get_number(ctx, &ap)) {
  817. furi_log_print_format(FuriLogLevelDefault, TAG, "apselect: failed to parse");
  818. return false;
  819. }
  820. if(!swd_apscan_test(ctx->app, ap)) {
  821. furi_log_print_format(FuriLogLevelDefault, TAG, "apselect: no selected AP");
  822. return false;
  823. }
  824. ctx->selected_ap = ap;
  825. swd_script_seek_newline(ctx);
  826. return true;
  827. }
  828. static bool swd_scriptfunc_apscan(ScriptContext* ctx) {
  829. furi_log_print_format(FuriLogLevelDefault, TAG, "apscan: Scanning APs");
  830. for(uint32_t ap = 0; ap < 255; ap++) {
  831. snprintf(ctx->app->state_string, sizeof(ctx->app->state_string), "Scan AP %lu", ap);
  832. swd_script_gui_refresh(ctx);
  833. if(swd_apscan_test(ctx->app, ap)) {
  834. furi_log_print_format(FuriLogLevelDefault, TAG, "apscan: AP%lu detected", ap);
  835. }
  836. }
  837. swd_script_seek_newline(ctx);
  838. return true;
  839. }
  840. static bool swd_scriptfunc_abort(ScriptContext* ctx) {
  841. furi_log_print_format(FuriLogLevelDefault, TAG, "abort: Aborting");
  842. swd_abort(ctx->app);
  843. swd_script_seek_newline(ctx);
  844. return true;
  845. }
  846. static bool swd_scriptfunc_mem_dump(ScriptContext* ctx) {
  847. char filename[MAX_FILE_LENGTH];
  848. uint32_t address = 0;
  849. uint32_t length = 0;
  850. uint32_t flags = 0;
  851. bool success = true;
  852. /* get file */
  853. if(!swd_script_skip_whitespace(ctx)) {
  854. furi_log_print_format(FuriLogLevelDefault, TAG, "mem_dump: missing whitespace");
  855. return false;
  856. }
  857. if(!swd_script_get_string(ctx, filename, sizeof(filename))) {
  858. furi_log_print_format(FuriLogLevelDefault, TAG, "mem_dump: failed to parse filename");
  859. return false;
  860. }
  861. /* get address */
  862. if(!swd_script_get_number(ctx, &address)) {
  863. furi_log_print_format(FuriLogLevelDefault, TAG, "mem_dump: failed to parse address");
  864. return false;
  865. }
  866. /* get length */
  867. if(!swd_script_get_number(ctx, &length)) {
  868. furi_log_print_format(FuriLogLevelDefault, TAG, "mem_dump: failed to parse length");
  869. return false;
  870. }
  871. /* get flags */
  872. if(swd_script_get_number(ctx, &flags)) {
  873. furi_log_print_format(FuriLogLevelDefault, TAG, "mem_dump: found extra flags");
  874. }
  875. furi_log_print_format(
  876. FuriLogLevelDefault,
  877. TAG,
  878. "mem_dump: would dump %08lX, len %08lX into %s",
  879. address,
  880. length,
  881. filename);
  882. File* dump = storage_file_alloc(ctx->app->storage);
  883. if(!storage_file_open(dump, filename, FSAM_WRITE, FSOM_CREATE_ALWAYS)) {
  884. storage_file_free(dump);
  885. snprintf(ctx->app->state_string, sizeof(ctx->app->state_string), "Failed to create file");
  886. swd_script_gui_refresh(ctx);
  887. notification_message_block(ctx->app->notification, &seq_error);
  888. return false;
  889. }
  890. if(ctx->block_size == 0) {
  891. ctx->block_size = 0x100;
  892. }
  893. if(ctx->block_size > 0x1000) {
  894. ctx->block_size = 0x1000;
  895. }
  896. uint8_t* buffer = malloc(ctx->block_size);
  897. for(uint32_t pos = 0; pos < length; pos += ctx->block_size) {
  898. if((pos & 0xFF) == 0) {
  899. int pct = pos * 100 / length;
  900. snprintf(
  901. ctx->app->state_string,
  902. sizeof(ctx->app->state_string),
  903. "Dump %08lX (%d%%)",
  904. pos,
  905. pct);
  906. swd_script_gui_refresh(ctx);
  907. }
  908. bool read_ok = false;
  909. uint32_t data = 0;
  910. for(uint32_t tries = 0; tries < ctx->max_tries; tries++) {
  911. if(ctx->abort) {
  912. furi_log_print_format(FuriLogLevelDefault, TAG, "mem_dump: aborting read");
  913. break;
  914. }
  915. uint32_t ret = 0;
  916. if(ctx->block_size > 4) {
  917. ret = swd_read_memory_block(
  918. ctx->app, ctx->selected_ap, address + pos, buffer, ctx->block_size);
  919. } else {
  920. ret = swd_read_memory(
  921. ctx->app, ctx->selected_ap, address + pos, (uint8_t*)(void*)buffer);
  922. }
  923. read_ok = (ret == 1);
  924. if(!read_ok) {
  925. snprintf(
  926. ctx->app->state_string,
  927. sizeof(ctx->app->state_string),
  928. "Failed at 0x%08lX",
  929. address + pos);
  930. swd_script_gui_refresh(ctx);
  931. furi_delay_ms(100);
  932. } else {
  933. break;
  934. }
  935. }
  936. if(ctx->abort) {
  937. furi_log_print_format(FuriLogLevelDefault, TAG, "mem_dump: aborting");
  938. break;
  939. }
  940. if(!read_ok) {
  941. /* flags == 1: "continue reading even if it fails" */
  942. /* flags == 2: "its okay if cannot dump fully" */
  943. if(flags & 1) {
  944. /* set all content to a known value as indication */
  945. for(size_t fill_pos = 0; fill_pos < ctx->block_size; fill_pos += 4) {
  946. *((uint32_t*)&buffer[fill_pos]) = 0xDEADFACE;
  947. }
  948. } else if(flags & 2) {
  949. success = (pos > 0);
  950. break;
  951. } else {
  952. notification_message_block(ctx->app->notification, &seq_error);
  953. success = false;
  954. break;
  955. }
  956. }
  957. storage_file_write(dump, buffer, ctx->block_size);
  958. }
  959. storage_file_close(dump);
  960. swd_script_seek_newline(ctx);
  961. free(buffer);
  962. return success;
  963. }
  964. static bool swd_scriptfunc_mem_write(ScriptContext* ctx) {
  965. uint32_t address = 0;
  966. uint32_t data = 0;
  967. bool success = true;
  968. /* get file */
  969. if(!swd_script_skip_whitespace(ctx)) {
  970. furi_log_print_format(FuriLogLevelDefault, TAG, "mem_write: missing whitespace");
  971. return false;
  972. }
  973. /* get address */
  974. if(!swd_script_get_number(ctx, &address)) {
  975. furi_log_print_format(FuriLogLevelDefault, TAG, "mem_write: failed to parse 1");
  976. return false;
  977. }
  978. /* get data */
  979. if(!swd_script_get_number(ctx, &data)) {
  980. furi_log_print_format(FuriLogLevelDefault, TAG, "mem_write: failed to parse 2");
  981. return false;
  982. }
  983. furi_log_print_format(
  984. FuriLogLevelDefault, TAG, "mem_write: write %08lX to %08lX", data, address);
  985. bool access_ok = false;
  986. for(uint32_t tries = 0; tries < ctx->max_tries; tries++) {
  987. if(ctx->abort) {
  988. furi_log_print_format(FuriLogLevelDefault, TAG, "mem_write: aborting");
  989. break;
  990. }
  991. access_ok = swd_write_memory(ctx->app, ctx->selected_ap, address, data) == 1;
  992. access_ok |= ctx->errors_ignore;
  993. swd_read_memory(ctx->app, ctx->selected_ap, address, &data);
  994. furi_log_print_format(
  995. FuriLogLevelDefault, TAG, "mem_write: read %08lX from %08lX", data, address);
  996. if(!access_ok) {
  997. snprintf(
  998. ctx->app->state_string,
  999. sizeof(ctx->app->state_string),
  1000. "Failed write 0x%08lX",
  1001. address);
  1002. swd_script_gui_refresh(ctx);
  1003. }
  1004. }
  1005. if(!access_ok) {
  1006. notification_message_block(ctx->app->notification, &seq_error);
  1007. success = false;
  1008. }
  1009. swd_script_seek_newline(ctx);
  1010. return success;
  1011. }
  1012. static bool swd_scriptfunc_mem_ldmst(ScriptContext* ctx) {
  1013. uint32_t address = 0;
  1014. uint32_t data = 0;
  1015. uint32_t mask = 0;
  1016. bool success = true;
  1017. /* get file */
  1018. if(!swd_script_skip_whitespace(ctx)) {
  1019. furi_log_print_format(FuriLogLevelDefault, TAG, "mem_ldmst: missing whitespace");
  1020. return false;
  1021. }
  1022. /* get address */
  1023. if(!swd_script_get_number(ctx, &address)) {
  1024. furi_log_print_format(FuriLogLevelDefault, TAG, "mem_ldmst: failed to parse 1");
  1025. return false;
  1026. }
  1027. /* get data */
  1028. if(!swd_script_get_number(ctx, &data)) {
  1029. furi_log_print_format(FuriLogLevelDefault, TAG, "mem_ldmst: failed to parse 2");
  1030. return false;
  1031. }
  1032. /* get mask */
  1033. if(!swd_script_get_number(ctx, &mask)) {
  1034. furi_log_print_format(FuriLogLevelDefault, TAG, "mem_ldmst: failed to parse 2");
  1035. return false;
  1036. }
  1037. furi_log_print_format(
  1038. FuriLogLevelDefault,
  1039. TAG,
  1040. "mem_ldmst: write %08lX to %08lX, mask %08lX",
  1041. data,
  1042. address,
  1043. mask);
  1044. bool access_ok = false;
  1045. uint32_t modified = 0;
  1046. for(uint32_t tries = 0; tries < ctx->max_tries; tries++) {
  1047. if(ctx->abort) {
  1048. furi_log_print_format(FuriLogLevelDefault, TAG, "mem_ldmst: aborting");
  1049. break;
  1050. }
  1051. access_ok = swd_read_memory(ctx->app, ctx->selected_ap, address, &modified) == 1;
  1052. modified = (modified & mask) | data;
  1053. access_ok &= swd_write_memory(ctx->app, ctx->selected_ap, address, modified) == 1;
  1054. access_ok |= ctx->errors_ignore;
  1055. if(!access_ok) {
  1056. snprintf(
  1057. ctx->app->state_string,
  1058. sizeof(ctx->app->state_string),
  1059. "Failed access 0x%08lX",
  1060. address);
  1061. swd_script_gui_refresh(ctx);
  1062. }
  1063. }
  1064. if(!access_ok) {
  1065. notification_message_block(ctx->app->notification, &seq_error);
  1066. success = false;
  1067. }
  1068. swd_script_seek_newline(ctx);
  1069. return success;
  1070. }
  1071. static const ScriptFunctionInfo script_funcs[] = {
  1072. {"#", &swd_scriptfunc_comment},
  1073. {".label", &swd_scriptfunc_label},
  1074. {"goto", &swd_scriptfunc_goto},
  1075. {"status", &swd_scriptfunc_status},
  1076. {"errors", &swd_scriptfunc_errors},
  1077. {"message", &swd_scriptfunc_message},
  1078. {"beep", &swd_scriptfunc_beep},
  1079. {"apscan", &swd_scriptfunc_apscan},
  1080. {"apselect", &swd_scriptfunc_apselect},
  1081. {"max_tries", &swd_scriptfunc_maxtries},
  1082. {"swd_clock_delay", &swd_scriptfunc_swd_clock_delay},
  1083. {"swd_idle_bits", &swd_scriptfunc_swd_idle_bits},
  1084. {"block_size", &swd_scriptfunc_blocksize},
  1085. {"abort", &swd_scriptfunc_abort},
  1086. {"mem_dump", &swd_scriptfunc_mem_dump},
  1087. {"mem_ldmst", &swd_scriptfunc_mem_ldmst},
  1088. {"mem_write", &swd_scriptfunc_mem_write}};
  1089. /************************** script main code **************************/
  1090. static bool swd_execute_script_line(ScriptContext* const ctx, File* file) {
  1091. char buffer[64];
  1092. uint64_t start_pos = storage_file_tell(ctx->script_file);
  1093. uint16_t ret = storage_file_read(ctx->script_file, buffer, 2);
  1094. storage_file_seek(ctx->script_file, start_pos, true);
  1095. if(ret < 2) {
  1096. return true;
  1097. }
  1098. if(buffer[0] == '\n' || (buffer[0] == '\r' && buffer[1] == '\n')) {
  1099. return true;
  1100. }
  1101. for(size_t entry = 0; entry < COUNT(script_funcs); entry++) {
  1102. if(ctx->abort) {
  1103. furi_log_print_format(FuriLogLevelDefault, TAG, "swd_execute_script_line: aborting");
  1104. break;
  1105. }
  1106. char buffer[64];
  1107. storage_file_seek(ctx->script_file, start_pos, true);
  1108. size_t expected = strlen(script_funcs[entry].prefix);
  1109. uint16_t ret = storage_file_read(ctx->script_file, buffer, expected);
  1110. if(ret != expected) {
  1111. continue;
  1112. }
  1113. buffer[expected] = '\000';
  1114. if(strncmp(buffer, script_funcs[entry].prefix, expected)) {
  1115. continue;
  1116. }
  1117. bool success = true;
  1118. if(ctx->goto_active) {
  1119. furi_log_print_format(
  1120. FuriLogLevelDebug, TAG, "ignore: '%s'", script_funcs[entry].prefix);
  1121. /* only execute label handlers */
  1122. if(buffer[0] == '.') {
  1123. success = script_funcs[entry].func(ctx);
  1124. } else {
  1125. swd_script_seek_newline(ctx);
  1126. }
  1127. } else {
  1128. furi_log_print_format(
  1129. FuriLogLevelDebug, TAG, "command: '%s'", script_funcs[entry].prefix);
  1130. if(!ctx->status_ignore) {
  1131. snprintf(
  1132. ctx->app->state_string,
  1133. sizeof(ctx->app->state_string),
  1134. "CMD: %s",
  1135. script_funcs[entry].prefix);
  1136. }
  1137. swd_script_gui_refresh(ctx);
  1138. /* function, execute */
  1139. success = script_funcs[entry].func(ctx);
  1140. if(!success && !ctx->errors_ignore) {
  1141. furi_log_print_format(
  1142. FuriLogLevelDefault, TAG, "Command failed: %s", script_funcs[entry].prefix);
  1143. snprintf(
  1144. ctx->app->state_string,
  1145. sizeof(ctx->app->state_string),
  1146. "Command failed: %s",
  1147. script_funcs[entry].prefix);
  1148. return false;
  1149. }
  1150. }
  1151. return true;
  1152. }
  1153. furi_log_print_format(FuriLogLevelDefault, TAG, "unknown command '%s'", buffer);
  1154. return false;
  1155. }
  1156. static bool swd_execute_script(AppFSM* const ctx, const char* filename) {
  1157. bool success = true;
  1158. ctx->script = malloc(sizeof(ScriptContext));
  1159. ctx->script->app = ctx;
  1160. ctx->script->max_tries = 1;
  1161. if(!storage_file_exists(ctx->storage, filename)) {
  1162. furi_log_print_format(FuriLogLevelDefault, TAG, "Does not exist '%s'", filename);
  1163. free(ctx->script);
  1164. ctx->script = NULL;
  1165. return false;
  1166. }
  1167. /* first allocate a file object */
  1168. ctx->script->script_file = storage_file_alloc(ctx->storage);
  1169. /* then get our script opened */
  1170. if(!storage_file_open(ctx->script->script_file, filename, FSAM_READ, FSOM_OPEN_EXISTING)) {
  1171. FURI_LOG_E(TAG, "open, %s", storage_file_get_error_desc(ctx->script->script_file));
  1172. furi_log_print_format(FuriLogLevelDefault, TAG, "Failed to open '%s'", filename);
  1173. storage_file_free(ctx->script->script_file);
  1174. free(ctx->script);
  1175. ctx->script = NULL;
  1176. return false;
  1177. }
  1178. do {
  1179. success = true;
  1180. ctx->script->restart = false;
  1181. storage_file_seek(ctx->script->script_file, 0, true);
  1182. uint32_t line = 1;
  1183. while(line < SCRIPT_MAX_LINES) {
  1184. if(ctx->script->abort) {
  1185. furi_log_print_format(FuriLogLevelDefault, TAG, "Abort requested");
  1186. break;
  1187. }
  1188. if(storage_file_eof(ctx->script->script_file)) {
  1189. break;
  1190. }
  1191. furi_log_print_format(FuriLogLevelDebug, TAG, "line %lu", line);
  1192. if(!swd_execute_script_line(ctx->script, ctx->script->script_file)) {
  1193. success = false;
  1194. break;
  1195. }
  1196. if(ctx->script->restart) {
  1197. break;
  1198. }
  1199. line++;
  1200. }
  1201. if(ctx->script->restart) {
  1202. furi_log_print_format(FuriLogLevelDebug, TAG, "Restarting");
  1203. } else {
  1204. furi_log_print_format(FuriLogLevelDebug, TAG, "Finished");
  1205. }
  1206. if(!success) {
  1207. char text_buf[128];
  1208. snprintf(text_buf, sizeof(text_buf), "Line %lu failed:\n%s", line, ctx->state_string);
  1209. DialogMessage* message = dialog_message_alloc();
  1210. dialog_message_set_header(message, "SWD Probe", 16, 2, AlignLeft, AlignTop);
  1211. dialog_message_set_icon(message, &I_app, 3, 2);
  1212. dialog_message_set_text(message, text_buf, 3, 16, AlignLeft, AlignTop);
  1213. dialog_message_set_buttons(message, "Back", "Retry", NULL);
  1214. if(dialog_message_show(ctx->dialogs, message) == DialogMessageButtonCenter) {
  1215. ctx->script->restart = true;
  1216. }
  1217. dialog_message_free(message);
  1218. }
  1219. } while(ctx->script->restart);
  1220. storage_file_close(ctx->script->script_file);
  1221. storage_file_free(ctx->script->script_file);
  1222. free(ctx->script);
  1223. ctx->script = NULL;
  1224. return success;
  1225. }
  1226. /************************** UI functions **************************/
  1227. static void render_callback(Canvas* const canvas, void* cb_ctx) {
  1228. AppFSM* ctx = acquire_mutex((ValueMutex*)cb_ctx, 25);
  1229. if(ctx == NULL) {
  1230. return;
  1231. }
  1232. char buffer[64];
  1233. int y = 10;
  1234. canvas_draw_frame(canvas, 0, 0, 128, 64);
  1235. canvas_set_font(canvas, FontPrimary);
  1236. if(ctx->detected_device) {
  1237. /* if seen less than a quarter second ago */
  1238. switch(ctx->mode_page) {
  1239. case ModePageScan: {
  1240. if((ctx->detected_timeout + TIMER_HZ / 4) >= TIMER_HZ * TIMEOUT) {
  1241. snprintf(buffer, sizeof(buffer), "FOUND!");
  1242. } else {
  1243. /* if it was seen more than a quarter second ago, show countdown */
  1244. snprintf(
  1245. buffer,
  1246. sizeof(buffer),
  1247. "FOUND! (%lus)",
  1248. (ctx->detected_timeout / TIMER_HZ) + 1);
  1249. }
  1250. canvas_draw_str_aligned(canvas, 64, y, AlignCenter, AlignBottom, buffer);
  1251. y += 10;
  1252. canvas_set_font(canvas, FontKeyboard);
  1253. snprintf(
  1254. buffer,
  1255. sizeof(buffer),
  1256. "SWC/SWD: %s/%s",
  1257. gpio_name(ctx->io_swc),
  1258. gpio_name(ctx->io_swd));
  1259. canvas_draw_str_aligned(canvas, 5, y, AlignLeft, AlignBottom, buffer);
  1260. y += 10;
  1261. snprintf(buffer, sizeof(buffer), "DPIDR 0x%08lX", ctx->dp_regs.dpidr);
  1262. canvas_draw_str_aligned(canvas, 5, y, AlignLeft, AlignBottom, buffer);
  1263. y += 10;
  1264. snprintf(
  1265. buffer,
  1266. sizeof(buffer),
  1267. "Part %02X Rev %X DAPv%d",
  1268. ctx->dpidr_info.partno,
  1269. ctx->dpidr_info.revision,
  1270. ctx->dpidr_info.version);
  1271. canvas_draw_str_aligned(canvas, 5, y, AlignLeft, AlignBottom, buffer);
  1272. y += 10;
  1273. canvas_set_font(canvas, FontSecondary);
  1274. snprintf(buffer, sizeof(buffer), "%s", jep106_manufacturer(ctx->dpidr_info.designer));
  1275. canvas_draw_str_aligned(canvas, 5, y, AlignLeft, AlignBottom, buffer);
  1276. y += 10;
  1277. canvas_set_font(canvas, FontSecondary);
  1278. elements_button_left(canvas, "Script");
  1279. elements_button_right(canvas, "DP Regs");
  1280. break;
  1281. }
  1282. case ModePageDPRegs: {
  1283. canvas_draw_str_aligned(canvas, 64, y, AlignCenter, AlignBottom, "DP Registers");
  1284. y += 10;
  1285. canvas_set_font(canvas, FontKeyboard);
  1286. if(ctx->dp_regs.dpidr_ok) {
  1287. snprintf(buffer, sizeof(buffer), "DPIDR %08lX", ctx->dp_regs.dpidr);
  1288. canvas_draw_str_aligned(canvas, 5, y, AlignLeft, AlignBottom, buffer);
  1289. }
  1290. y += 10;
  1291. if(ctx->dp_regs.ctrlstat_ok) {
  1292. snprintf(buffer, sizeof(buffer), "CTRL %08lX", ctx->dp_regs.ctrlstat);
  1293. canvas_draw_str_aligned(canvas, 5, y, AlignLeft, AlignBottom, buffer);
  1294. }
  1295. y += 10;
  1296. if(ctx->dp_regs.targetid_ok) {
  1297. snprintf(buffer, sizeof(buffer), "TGTID %08lX", ctx->dp_regs.targetid);
  1298. canvas_draw_str_aligned(canvas, 5, y, AlignLeft, AlignBottom, buffer);
  1299. }
  1300. y += 10;
  1301. if(ctx->dp_regs.eventstat_ok) {
  1302. snprintf(buffer, sizeof(buffer), "EVTST %08lX", ctx->dp_regs.eventstat);
  1303. canvas_draw_str_aligned(canvas, 5, y, AlignLeft, AlignBottom, buffer);
  1304. }
  1305. y += 10;
  1306. canvas_set_font(canvas, FontSecondary);
  1307. elements_button_left(canvas, "Scan");
  1308. elements_button_right(canvas, "DPID");
  1309. break;
  1310. }
  1311. case ModePageDPID: {
  1312. canvas_draw_str_aligned(canvas, 64, y, AlignCenter, AlignBottom, "DP ID Register");
  1313. y += 10;
  1314. canvas_set_font(canvas, FontKeyboard);
  1315. if(ctx->dpidr_info.version != 2) {
  1316. snprintf(buffer, sizeof(buffer), "TARGETID not supported");
  1317. canvas_draw_str_aligned(canvas, 5, y, AlignLeft, AlignBottom, buffer);
  1318. y += 10;
  1319. } else {
  1320. if(ctx->dp_regs.targetid_ok) {
  1321. snprintf(buffer, sizeof(buffer), "TGTID %08lX", ctx->dp_regs.targetid);
  1322. canvas_draw_str_aligned(canvas, 5, y, AlignLeft, AlignBottom, buffer);
  1323. y += 10;
  1324. snprintf(buffer, sizeof(buffer), "Part No. %04X", ctx->targetid_info.partno);
  1325. canvas_draw_str_aligned(canvas, 5, y, AlignLeft, AlignBottom, buffer);
  1326. y += 10;
  1327. snprintf(
  1328. buffer,
  1329. sizeof(buffer),
  1330. "%s",
  1331. jep106_manufacturer(ctx->targetid_info.designer));
  1332. canvas_draw_str_aligned(canvas, 5, y, AlignLeft, AlignBottom, buffer);
  1333. y += 10;
  1334. }
  1335. }
  1336. canvas_set_font(canvas, FontSecondary);
  1337. elements_button_left(canvas, "DP Regs");
  1338. elements_button_right(canvas, "APs");
  1339. break;
  1340. }
  1341. case ModePageAPID: {
  1342. canvas_draw_str_aligned(canvas, 64, y, AlignCenter, AlignBottom, "AP Menu");
  1343. y += 10;
  1344. canvas_set_font(canvas, FontKeyboard);
  1345. char state = ' ';
  1346. if(ctx->ap_pos >= ctx->ap_scanned && ctx->ap_pos <= ctx->ap_scanned + 10) {
  1347. state = '*';
  1348. }
  1349. if(!ctx->apidr_info[ctx->ap_pos].ok) {
  1350. snprintf(buffer, sizeof(buffer), "[%d]%c<none>", ctx->ap_pos, state);
  1351. canvas_draw_str_aligned(canvas, 5, y, AlignLeft, AlignBottom, buffer);
  1352. y += 10;
  1353. if(ctx->ap_pos == 0) {
  1354. for(int pos = 0; pos < COUNT(ctx->apidr_info); pos++) {
  1355. if(ctx->apidr_info[pos].ok) {
  1356. ctx->ap_pos = pos;
  1357. }
  1358. }
  1359. }
  1360. } else {
  1361. const char* class = "";
  1362. switch(ctx->apidr_info[ctx->ap_pos].class) {
  1363. case 0:
  1364. class = "und";
  1365. break;
  1366. case 1:
  1367. class = "COM";
  1368. break;
  1369. case 8:
  1370. class = "MEM";
  1371. break;
  1372. default:
  1373. class = "unk";
  1374. break;
  1375. }
  1376. const char* types[] = {
  1377. "COM-AP",
  1378. "AHB3",
  1379. "APB2 or APB3",
  1380. "Type unknown",
  1381. "AXI3 or AXI4",
  1382. "AHB5",
  1383. "APB4 and APB5",
  1384. "AXI5",
  1385. "AHB5 enh.",
  1386. };
  1387. const char* type = "Type unk";
  1388. if(ctx->apidr_info[ctx->ap_pos].type < COUNT(types)) {
  1389. type = types[ctx->apidr_info[ctx->ap_pos].type];
  1390. }
  1391. snprintf(buffer, sizeof(buffer), "[%d]%c%s, %s", ctx->ap_pos, state, class, type);
  1392. canvas_draw_str_aligned(canvas, 5, y, AlignLeft, AlignBottom, buffer);
  1393. y += 10;
  1394. snprintf(
  1395. buffer, sizeof(buffer), "Base 0x%08lX", ctx->apidr_info[ctx->ap_pos].base);
  1396. canvas_draw_str_aligned(canvas, 5, y, AlignLeft, AlignBottom, buffer);
  1397. y += 10;
  1398. snprintf(
  1399. buffer,
  1400. sizeof(buffer),
  1401. "Rev %d Var %d",
  1402. ctx->apidr_info[ctx->ap_pos].revision,
  1403. ctx->apidr_info[ctx->ap_pos].variant);
  1404. canvas_draw_str_aligned(canvas, 5, y, AlignLeft, AlignBottom, buffer);
  1405. y += 10;
  1406. snprintf(
  1407. buffer,
  1408. sizeof(buffer),
  1409. "%s",
  1410. jep106_manufacturer(ctx->apidr_info[ctx->ap_pos].designer));
  1411. canvas_draw_str_aligned(canvas, 5, y, AlignLeft, AlignBottom, buffer);
  1412. y += 10;
  1413. elements_button_center(canvas, "Show");
  1414. }
  1415. canvas_set_font(canvas, FontSecondary);
  1416. elements_button_left(canvas, "DPID");
  1417. elements_scrollbar_pos(
  1418. canvas, 4, 10, 40, ctx->ap_pos / 32, COUNT(ctx->apidr_info) / 32);
  1419. } break;
  1420. /* hex dump view */
  1421. case ModePageHexDump: {
  1422. canvas_draw_str_aligned(canvas, 64, y, AlignCenter, AlignBottom, "Hex dump");
  1423. y += 10;
  1424. canvas_set_font(canvas, FontKeyboard);
  1425. canvas_draw_str_aligned(canvas, 5, y, AlignLeft, AlignBottom, "Addr:");
  1426. snprintf(buffer, sizeof(buffer), "%08lX", ctx->hex_addr);
  1427. canvas_draw_str_aligned(canvas, 38, y, AlignLeft, AlignBottom, buffer);
  1428. uint32_t font_width = canvas_glyph_width(canvas, '0');
  1429. uint32_t x = 37 + (7 - ctx->hex_select) * font_width;
  1430. /* draw selection */
  1431. canvas_draw_line(canvas, x, y + 1, x + font_width, y + 1);
  1432. y += 10;
  1433. uint32_t byte_num = 0;
  1434. for(int line = 0; line < 4; line++) {
  1435. uint32_t x_pos = 5;
  1436. for(int byte_pos = 0; byte_pos < 8; byte_pos++) {
  1437. if(ctx->hex_buffer_valid[byte_num / 4]) {
  1438. snprintf(buffer, sizeof(buffer), "%02X", ctx->hex_buffer[byte_num]);
  1439. } else {
  1440. snprintf(buffer, sizeof(buffer), "--");
  1441. }
  1442. byte_num++;
  1443. canvas_draw_str_aligned(canvas, x_pos, y, AlignLeft, AlignBottom, buffer);
  1444. x_pos += font_width * 2 + font_width / 2;
  1445. }
  1446. y += 10;
  1447. }
  1448. break;
  1449. }
  1450. /* hex dump view */
  1451. case ModePageScript: {
  1452. canvas_draw_str_aligned(canvas, 64, y, AlignCenter, AlignBottom, "Script");
  1453. y += 10;
  1454. y += 10;
  1455. canvas_draw_str_aligned(canvas, 10, y, AlignLeft, AlignBottom, "Status:");
  1456. y += 10;
  1457. canvas_set_font(canvas, FontKeyboard);
  1458. canvas_draw_str_aligned(canvas, 64, y, AlignCenter, AlignBottom, ctx->state_string);
  1459. y += 10;
  1460. } break;
  1461. }
  1462. } else {
  1463. snprintf(
  1464. buffer, sizeof(buffer), "Searching... %c", gpio_direction_ind[ctx->current_mask_id]);
  1465. canvas_draw_str_aligned(canvas, 64, y, AlignCenter, AlignBottom, buffer);
  1466. y += 10;
  1467. y += 10;
  1468. canvas_draw_str_aligned(canvas, 10, y, AlignLeft, AlignBottom, "Script:");
  1469. y += 10;
  1470. if(strlen(ctx->script_detected) > 0) {
  1471. canvas_set_font(canvas, FontKeyboard);
  1472. const char* filename = strrchr(ctx->script_detected, '/');
  1473. canvas_draw_str_aligned(canvas, 64, y, AlignCenter, AlignBottom, &filename[1]);
  1474. y += 10;
  1475. canvas_set_font(canvas, FontSecondary);
  1476. canvas_draw_str_aligned(canvas, 64, y, AlignCenter, AlignBottom, "Up to clear");
  1477. y += 10;
  1478. } else {
  1479. canvas_set_font(canvas, FontKeyboard);
  1480. canvas_draw_str_aligned(canvas, 64, y, AlignCenter, AlignBottom, "<none>");
  1481. y += 10;
  1482. canvas_set_font(canvas, FontSecondary);
  1483. canvas_draw_str_aligned(canvas, 64, y, AlignCenter, AlignBottom, "Down to select");
  1484. y += 10;
  1485. }
  1486. elements_button_left(canvas, "Script");
  1487. }
  1488. release_mutex((ValueMutex*)cb_ctx, ctx);
  1489. }
  1490. static void input_callback(InputEvent* input_event, FuriMessageQueue* event_queue) {
  1491. furi_assert(event_queue);
  1492. /* better skip than sorry */
  1493. if(furi_message_queue_get_count(event_queue) < QUEUE_SIZE) {
  1494. AppEvent event = {.type = EventKeyPress, .input = *input_event};
  1495. furi_message_queue_put(event_queue, &event, 100);
  1496. }
  1497. }
  1498. static void timer_tick_callback(FuriMessageQueue* event_queue) {
  1499. furi_assert(event_queue);
  1500. /* filling buffer makes no sense, as we lost timing anyway */
  1501. if(furi_message_queue_get_count(event_queue) < 1) {
  1502. AppEvent event = {.type = EventTimerTick};
  1503. furi_message_queue_put(event_queue, &event, 100);
  1504. }
  1505. }
  1506. static void app_init(AppFSM* const app) {
  1507. app->current_mask_id = 0;
  1508. app->current_mask = gpio_direction_mask[app->current_mask_id];
  1509. app->io_swd = 0xFF;
  1510. app->io_swc = 0xFF;
  1511. app->hex_addr = 0x40002800;
  1512. app->hex_addr = 0xE000EDF0;
  1513. app->swd_clock_delay = CLOCK_DELAY;
  1514. app->swd_idle_bits = IDLE_BITS;
  1515. strcpy(app->state_string, "none");
  1516. strcpy(app->script_detected, "");
  1517. }
  1518. static void app_deinit(AppFSM* const ctx) {
  1519. furi_timer_free(ctx->timer);
  1520. }
  1521. static void on_timer_tick(AppFSM* ctx) {
  1522. switch(ctx->mode_page) {
  1523. case ModePageScan: {
  1524. /* reset after timeout */
  1525. if(ctx->detected_timeout == 0) {
  1526. ctx->detected_device = false;
  1527. ctx->io_swd = 0xFF;
  1528. ctx->io_swc = 0xFF;
  1529. ctx->io_num_swd = 0xFF;
  1530. ctx->io_num_swc = 0xFF;
  1531. ctx->ap_scanned = 0;
  1532. memset(&ctx->dp_regs, 0x00, sizeof(ctx->dp_regs));
  1533. memset(&ctx->targetid_info, 0x00, sizeof(ctx->targetid_info));
  1534. memset(&ctx->apidr_info, 0x00, sizeof(ctx->apidr_info));
  1535. ctx->script_detected_executed = false;
  1536. } else {
  1537. ctx->detected_timeout--;
  1538. }
  1539. ctx->detected = false;
  1540. ctx->current_mask = gpio_direction_mask[ctx->current_mask_id];
  1541. /* when SWD was already detected, set it to data pin regardless of the mask */
  1542. if(ctx->detected_device) {
  1543. ctx->current_mask &= ~ctx->io_swd;
  1544. }
  1545. /* do the scan */
  1546. swd_scan(ctx);
  1547. /* now when detected a device, set the timeout */
  1548. if(ctx->detected) {
  1549. ctx->detected_device = true;
  1550. ctx->detected_timeout = TIMER_HZ * TIMEOUT;
  1551. /* update DPIDR fields */
  1552. ctx->dpidr_info.revision = (ctx->dp_regs.dpidr >> 28) & 0x0F;
  1553. ctx->dpidr_info.partno = (ctx->dp_regs.dpidr >> 20) & 0xFF;
  1554. ctx->dpidr_info.version = (ctx->dp_regs.dpidr >> 12) & 0x0F;
  1555. ctx->dpidr_info.designer = (ctx->dp_regs.dpidr >> 1) & 0x3FF;
  1556. if(!has_multiple_bits(ctx->io_swc)) {
  1557. furi_log_print_format(FuriLogLevelDebug, TAG, " - Detected pins");
  1558. furi_log_print_format(FuriLogLevelDebug, TAG, " - Resetting error");
  1559. /* reset error */
  1560. uint8_t ack = swd_transfer(ctx, false, false, 1, &ctx->dp_regs.ctrlstat);
  1561. furi_log_print_format(
  1562. FuriLogLevelDebug, TAG, "stat %02lX %d", ctx->dp_regs.ctrlstat, ack);
  1563. if(ack != 1 || (ctx->dp_regs.ctrlstat & STAT_ERROR_FLAGS)) {
  1564. furi_log_print_format(FuriLogLevelDebug, TAG, "send ABORT");
  1565. swd_abort(ctx);
  1566. }
  1567. furi_log_print_format(FuriLogLevelDebug, TAG, " - Fetch CTRL/STAT");
  1568. ctx->dp_regs.ctrlstat_ok = swd_read_dpbank(ctx, 1, 0, &ctx->dp_regs.ctrlstat) == 1;
  1569. if(ctx->dpidr_info.version >= 1) {
  1570. furi_log_print_format(FuriLogLevelDebug, TAG, " - DAPv1, read DLCR");
  1571. ctx->dp_regs.dlcr_ok = swd_read_dpbank(ctx, 1, 1, &ctx->dp_regs.dlcr) == 1;
  1572. }
  1573. if(ctx->dpidr_info.version >= 2) {
  1574. furi_log_print_format(FuriLogLevelDebug, TAG, " - DAPv2, read TARGETID");
  1575. ctx->dp_regs.targetid_ok =
  1576. swd_read_dpbank(ctx, 1, 2, &ctx->dp_regs.targetid) == 1;
  1577. furi_log_print_format(FuriLogLevelDebug, TAG, " - DAPv2, read EVENTSTAT");
  1578. ctx->dp_regs.eventstat_ok =
  1579. swd_read_dpbank(ctx, 1, 4, &ctx->dp_regs.eventstat) == 1;
  1580. furi_log_print_format(FuriLogLevelDebug, TAG, " - DAPv2, read DLPIDR");
  1581. ctx->dp_regs.dlpidr_ok = swd_read_dpbank(ctx, 1, 3, &ctx->dp_regs.dlpidr) == 1;
  1582. }
  1583. if(ctx->dp_regs.targetid_ok) {
  1584. ctx->targetid_info.revision = (ctx->dp_regs.targetid >> 28) & 0x0F;
  1585. ctx->targetid_info.partno = (ctx->dp_regs.targetid >> 12) & 0xFFFF;
  1586. ctx->targetid_info.designer = (ctx->dp_regs.targetid >> 1) & 0x3FF;
  1587. }
  1588. if(!ctx->script_detected_executed && strlen(ctx->script_detected) > 0) {
  1589. furi_log_print_format(
  1590. FuriLogLevelDefault, TAG, " - Run script '%s'", ctx->script_detected);
  1591. ctx->script_detected_executed = true;
  1592. ctx->mode_page = ModePageScript;
  1593. swd_execute_script(ctx, ctx->script_detected);
  1594. ctx->mode_page = ModePageScan;
  1595. }
  1596. }
  1597. } else {
  1598. if(!has_multiple_bits(ctx->io_swc)) {
  1599. furi_log_print_format(FuriLogLevelDebug, TAG, " - Lost device");
  1600. }
  1601. }
  1602. ctx->current_mask_id = (ctx->current_mask_id + 1) % COUNT(gpio_direction_mask);
  1603. break;
  1604. }
  1605. case ModePageDPRegs:
  1606. case ModePageDPID:
  1607. case ModePageAPID: {
  1608. /* set debug enable request */
  1609. if(!swd_ensure_powerup(ctx)) {
  1610. break;
  1611. }
  1612. /* only scan a few APs at once to stay responsive */
  1613. for(int pos = 0; pos < 5; pos++) {
  1614. if(ctx->ap_scanned == 0) {
  1615. swd_apscan_reset(ctx);
  1616. }
  1617. uint8_t ap = ctx->ap_scanned++;
  1618. if(ctx->apidr_info[ap].tested) {
  1619. continue;
  1620. }
  1621. if(swd_apscan_test(ctx, ap)) {
  1622. break;
  1623. }
  1624. }
  1625. break;
  1626. }
  1627. case ModePageHexDump: {
  1628. if(ctx->hex_read_delay++ < 10) {
  1629. break;
  1630. }
  1631. ctx->hex_read_delay = 0;
  1632. memset(ctx->hex_buffer, 0xEE, sizeof(ctx->hex_buffer));
  1633. uint32_t addr = ctx->hex_addr;
  1634. uint32_t data = 0;
  1635. for(int pos = 0; pos < sizeof(ctx->hex_buffer) / 4; pos++) {
  1636. ctx->hex_buffer_valid[pos] = swd_read_memory(ctx, ctx->ap_pos, addr, &data) == 1;
  1637. if(ctx->hex_buffer_valid[pos]) {
  1638. memcpy(&ctx->hex_buffer[pos * 4], &data, 4);
  1639. } else {
  1640. swd_abort_simple(ctx);
  1641. }
  1642. addr += 4;
  1643. }
  1644. }
  1645. }
  1646. }
  1647. static bool swd_message_process(AppFSM* ctx) {
  1648. bool processing = true;
  1649. AppEvent event;
  1650. FuriStatus event_status = furi_message_queue_get(ctx->event_queue, &event, 100);
  1651. if(event_status == FuriStatusOk) {
  1652. if(event.type == EventKeyPress) {
  1653. if(event.input.type == InputTypePress) {
  1654. switch(event.input.key) {
  1655. case InputKeyUp:
  1656. switch(ctx->mode_page) {
  1657. default:
  1658. break;
  1659. case ModePageScan: {
  1660. strcpy(ctx->script_detected, "");
  1661. break;
  1662. }
  1663. case ModePageAPID:
  1664. if(ctx->ap_pos > 0) {
  1665. ctx->ap_pos--;
  1666. }
  1667. break;
  1668. case ModePageHexDump: {
  1669. ctx->hex_addr +=
  1670. ((ctx->hex_select) ? 1 : 8) * (1 << (4 * ctx->hex_select));
  1671. break;
  1672. }
  1673. }
  1674. break;
  1675. case InputKeyDown:
  1676. switch(ctx->mode_page) {
  1677. default:
  1678. break;
  1679. case ModePageScan: {
  1680. FuriString* result_path = furi_string_alloc_printf(ANY_PATH("swd"));
  1681. FuriString* preselected = furi_string_alloc_printf(
  1682. (strlen(ctx->script_detected) > 0) ? ctx->script_detected :
  1683. ANY_PATH("swd"));
  1684. DialogsFileBrowserOptions options;
  1685. dialog_file_browser_set_basic_options(&options, "swd", &I_swd);
  1686. if(dialog_file_browser_show(
  1687. ctx->dialogs, result_path, preselected, &options)) {
  1688. const char* path = furi_string_get_cstr(result_path);
  1689. strcpy(ctx->script_detected, path);
  1690. }
  1691. furi_string_free(result_path);
  1692. furi_string_free(preselected);
  1693. break;
  1694. }
  1695. case ModePageAPID:
  1696. if(ctx->ap_pos + 1 < COUNT(ctx->apidr_info)) {
  1697. ctx->ap_pos++;
  1698. }
  1699. break;
  1700. case ModePageHexDump: {
  1701. ctx->hex_addr -=
  1702. ((ctx->hex_select) ? 1 : 8) * (1 << (4 * ctx->hex_select));
  1703. break;
  1704. }
  1705. }
  1706. break;
  1707. case InputKeyRight:
  1708. if(ctx->mode_page == ModePageHexDump) {
  1709. if(ctx->hex_select > 0) {
  1710. ctx->hex_select--;
  1711. }
  1712. } else {
  1713. if(ctx->mode_page + 1 < ModePageCount) {
  1714. ctx->mode_page++;
  1715. }
  1716. }
  1717. break;
  1718. case InputKeyLeft:
  1719. if(ctx->mode_page == ModePageHexDump) {
  1720. if(ctx->hex_select < 7) {
  1721. ctx->hex_select++;
  1722. }
  1723. } else if(ctx->mode_page == ModePageScan) {
  1724. FuriString* result_path = furi_string_alloc_printf(ANY_PATH("swd"));
  1725. FuriString* preselected = furi_string_alloc_printf(
  1726. (strlen(ctx->script_detected) > 0) ? ctx->script_detected :
  1727. ANY_PATH("swd"));
  1728. DialogsFileBrowserOptions options;
  1729. dialog_file_browser_set_basic_options(&options, "swd", &I_swd);
  1730. if(dialog_file_browser_show(
  1731. ctx->dialogs, result_path, preselected, &options)) {
  1732. const char* path = furi_string_get_cstr(result_path);
  1733. ctx->mode_page = ModePageScript;
  1734. swd_execute_script(ctx, path);
  1735. ctx->mode_page = ModePageScan;
  1736. }
  1737. furi_string_free(result_path);
  1738. furi_string_free(preselected);
  1739. break;
  1740. } else {
  1741. if(ctx->mode_page > 0) {
  1742. ctx->mode_page--;
  1743. }
  1744. }
  1745. break;
  1746. case InputKeyOk:
  1747. if(ctx->mode_page == ModePageAPID && ctx->apidr_info[ctx->ap_pos].ok) {
  1748. ctx->mode_page = ModePageHexDump;
  1749. }
  1750. break;
  1751. case InputKeyBack:
  1752. if(ctx->mode_page == ModePageHexDump) {
  1753. ctx->mode_page = ModePageAPID;
  1754. } else if(ctx->mode_page == ModePageScript) {
  1755. ctx->script->abort = true;
  1756. } else if(ctx->mode_page != ModePageScan) {
  1757. ctx->mode_page = ModePageScan;
  1758. } else {
  1759. processing = false;
  1760. }
  1761. break;
  1762. default:
  1763. break;
  1764. }
  1765. }
  1766. } else if(event.type == EventTimerTick) {
  1767. on_timer_tick(ctx);
  1768. }
  1769. } else {
  1770. /* timeout */
  1771. }
  1772. return processing;
  1773. }
  1774. int32_t swd_probe_app_main(void* p) {
  1775. UNUSED(p);
  1776. AppFSM* app = malloc(sizeof(AppFSM));
  1777. app_init(app);
  1778. if(!init_mutex(&app->state_mutex, app, sizeof(AppFSM))) {
  1779. FURI_LOG_E(TAG, "cannot create mutex\r\n");
  1780. free(app);
  1781. return 255;
  1782. }
  1783. app->notification = furi_record_open(RECORD_NOTIFICATION);
  1784. app->gui = furi_record_open(RECORD_GUI);
  1785. app->dialogs = furi_record_open(RECORD_DIALOGS);
  1786. app->storage = furi_record_open(RECORD_STORAGE);
  1787. app->view_port = view_port_alloc();
  1788. app->event_queue = furi_message_queue_alloc(QUEUE_SIZE, sizeof(AppEvent));
  1789. app->timer = furi_timer_alloc(timer_tick_callback, FuriTimerTypePeriodic, app->event_queue);
  1790. view_port_draw_callback_set(app->view_port, render_callback, &app->state_mutex);
  1791. view_port_input_callback_set(app->view_port, input_callback, app->event_queue);
  1792. gui_add_view_port(app->gui, app->view_port, GuiLayerFullscreen);
  1793. notification_message_block(app->notification, &sequence_display_backlight_enforce_on);
  1794. swd_execute_script(app, ANY_PATH("swd/startup.swd"));
  1795. DOLPHIN_DEED(DolphinDeedPluginGameStart);
  1796. furi_timer_start(app->timer, furi_kernel_get_tick_frequency() / TIMER_HZ);
  1797. for(bool processing = true; processing;) {
  1798. //AppFSM* ctx = (AppFSM*)acquire_mutex_block(&app->state_mutex);
  1799. processing = swd_message_process(app);
  1800. view_port_update(app->view_port);
  1801. //release_mutex(&ctx->state_mutex, ctx);
  1802. bool beep = false;
  1803. if(app->detected_device && !app->detected_notified) {
  1804. app->detected_notified = true;
  1805. beep = true;
  1806. }
  1807. if(!app->detected_device && app->detected_notified) {
  1808. app->detected_notified = false;
  1809. }
  1810. if(beep) {
  1811. notification_message_block(app->notification, &seq_c_minor);
  1812. }
  1813. }
  1814. app_deinit(app);
  1815. // Wait for all notifications to be played and return backlight to normal state
  1816. notification_message_block(app->notification, &sequence_display_backlight_enforce_auto);
  1817. view_port_enabled_set(app->view_port, false);
  1818. gui_remove_view_port(app->gui, app->view_port);
  1819. furi_record_close(RECORD_GUI);
  1820. furi_record_close(RECORD_NOTIFICATION);
  1821. view_port_free(app->view_port);
  1822. furi_message_queue_free(app->event_queue);
  1823. delete_mutex(&app->state_mutex);
  1824. free(app);
  1825. return 0;
  1826. }