flipperzero-firmware_official_dev 2.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120
  1. commit d1ad9242165143215ec9267914d23e58f837374c
  2. Author: Skorpionm <85568270+Skorpionm@users.noreply.github.com>
  3. Date: Thu Apr 6 08:13:30 2023 +0400
  4. [AVR_ISP]: add AVR ISP Programmer FAP (#2475)
  5. * [AVR_ISP]: add AVR ISP Programmer FAP
  6. * [AVR_ISP]: add auto detect AVR chip
  7. * [AVR_ISP]: fix auto detect chip
  8. * [AVR_ISP]: fix fast write flash
  9. * AVR_ISP: auto set SPI speed
  10. * AVR_ISP: add clock 4Mhz on &gpio_ext_pa4
  11. * AVR_ISP: fix "[CRASH][ISR 4] NULL pointer dereference" with no AVR chip connected
  12. * AVR_ISP: add AVR ISP Reader
  13. * AVR_ISP: add read and check I32HEX file
  14. * AVR_ISP: add write eerom, flash, fuse, lock byte
  15. * AVR_ISP: add gui Reader, Writer
  16. * Github: unshallow on decontamination
  17. * AVR_ISP: move to external
  18. * API: fix api_symbols
  19. * AVR_ISP: add wiring scene
  20. * GUI: model mutex FuriMutexTypeNormal -> FuriMutexTypeRecursive
  21. * AVR_ISP: add chip_detect view
  22. * AVR_ISP: refactoring gui ISP Programmer
  23. * AVR_ISP: add gui "Dump AVR"
  24. * AVR_ISP: add gui "Flash AVR"
  25. * AVR_ISP: fix navigation gui
  26. * GUI: model mutex FuriMutexTypeRecursive -> FuriMutexTypeNormal
  27. * AVR_ISP: fix conflicts
  28. * AVR_ISP: fix build
  29. * AVR_ISP: delete images
  30. * AVR_ISP: add images
  31. * AVR_ISP: fix gui
  32. * AVR_ISP: fix stuck in navigation
  33. * AVR_ISP: changing the Fuse bit recording logic
  34. * AVR_ISP: fix read/write chips with memory greater than 64Kb
  35. * AVR_ISP: fix auto set speed SPI
  36. * AVR_ISP: fix gui
  37. * ISP: switching on +5 volts to an external GPIO
  38. Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com>
  39. diff --git a/applications/external/avr_isp_programmer/application.fam b/applications/external/avr_isp_programmer/application.fam
  40. new file mode 100644
  41. index 000000000..19556d03d
  42. --- /dev/null
  43. +++ b/applications/external/avr_isp_programmer/application.fam
  44. @@ -0,0 +1,17 @@
  45. +App(
  46. + appid="avr_isp",
  47. + name="AVR Flasher",
  48. + apptype=FlipperAppType.EXTERNAL,
  49. + entry_point="avr_isp_app",
  50. + requires=["gui"],
  51. + stack_size=4 * 1024,
  52. + order=20,
  53. + fap_icon="avr_app_icon_10x10.png",
  54. + fap_category="GPIO",
  55. + fap_icon_assets="images",
  56. + fap_private_libs=[
  57. + Lib(
  58. + name="driver",
  59. + ),
  60. + ],
  61. +)
  62. diff --git a/applications/external/avr_isp_programmer/avr_app_icon_10x10.png b/applications/external/avr_isp_programmer/avr_app_icon_10x10.png
  63. new file mode 100644
  64. index 000000000..533787fe3
  65. Binary files /dev/null and b/applications/external/avr_isp_programmer/avr_app_icon_10x10.png differ
  66. diff --git a/applications/external/avr_isp_programmer/avr_isp_app.c b/applications/external/avr_isp_programmer/avr_isp_app.c
  67. new file mode 100644
  68. index 000000000..740dc3610
  69. --- /dev/null
  70. +++ b/applications/external/avr_isp_programmer/avr_isp_app.c
  71. @@ -0,0 +1,179 @@
  72. +#include "avr_isp_app_i.h"
  73. +
  74. +static bool avr_isp_app_custom_event_callback(void* context, uint32_t event) {
  75. + furi_assert(context);
  76. + AvrIspApp* app = context;
  77. + return scene_manager_handle_custom_event(app->scene_manager, event);
  78. +}
  79. +
  80. +static bool avr_isp_app_back_event_callback(void* context) {
  81. + furi_assert(context);
  82. + AvrIspApp* app = context;
  83. + return scene_manager_handle_back_event(app->scene_manager);
  84. +}
  85. +
  86. +static void avr_isp_app_tick_event_callback(void* context) {
  87. + furi_assert(context);
  88. + AvrIspApp* app = context;
  89. + scene_manager_handle_tick_event(app->scene_manager);
  90. +}
  91. +
  92. +AvrIspApp* avr_isp_app_alloc() {
  93. + AvrIspApp* app = malloc(sizeof(AvrIspApp));
  94. +
  95. + app->file_path = furi_string_alloc();
  96. + furi_string_set(app->file_path, STORAGE_APP_DATA_PATH_PREFIX);
  97. + app->error = AvrIspErrorNoError;
  98. +
  99. + // GUI
  100. + app->gui = furi_record_open(RECORD_GUI);
  101. +
  102. + // View Dispatcher
  103. + app->view_dispatcher = view_dispatcher_alloc();
  104. + app->scene_manager = scene_manager_alloc(&avr_isp_scene_handlers, app);
  105. + view_dispatcher_enable_queue(app->view_dispatcher);
  106. +
  107. + view_dispatcher_set_event_callback_context(app->view_dispatcher, app);
  108. + view_dispatcher_set_custom_event_callback(
  109. + app->view_dispatcher, avr_isp_app_custom_event_callback);
  110. + view_dispatcher_set_navigation_event_callback(
  111. + app->view_dispatcher, avr_isp_app_back_event_callback);
  112. + view_dispatcher_set_tick_event_callback(
  113. + app->view_dispatcher, avr_isp_app_tick_event_callback, 100);
  114. +
  115. + view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen);
  116. +
  117. + // Open Notification record
  118. + app->notifications = furi_record_open(RECORD_NOTIFICATION);
  119. +
  120. + // SubMenu
  121. + app->submenu = submenu_alloc();
  122. + view_dispatcher_add_view(
  123. + app->view_dispatcher, AvrIspViewSubmenu, submenu_get_view(app->submenu));
  124. +
  125. + // Widget
  126. + app->widget = widget_alloc();
  127. + view_dispatcher_add_view(app->view_dispatcher, AvrIspViewWidget, widget_get_view(app->widget));
  128. +
  129. + // Text Input
  130. + app->text_input = text_input_alloc();
  131. + view_dispatcher_add_view(
  132. + app->view_dispatcher, AvrIspViewTextInput, text_input_get_view(app->text_input));
  133. +
  134. + // Popup
  135. + app->popup = popup_alloc();
  136. + view_dispatcher_add_view(app->view_dispatcher, AvrIspViewPopup, popup_get_view(app->popup));
  137. +
  138. + //Dialog
  139. + app->dialogs = furi_record_open(RECORD_DIALOGS);
  140. +
  141. + // Programmer view
  142. + app->avr_isp_programmer_view = avr_isp_programmer_view_alloc();
  143. + view_dispatcher_add_view(
  144. + app->view_dispatcher,
  145. + AvrIspViewProgrammer,
  146. + avr_isp_programmer_view_get_view(app->avr_isp_programmer_view));
  147. +
  148. + // Reader view
  149. + app->avr_isp_reader_view = avr_isp_reader_view_alloc();
  150. + view_dispatcher_add_view(
  151. + app->view_dispatcher,
  152. + AvrIspViewReader,
  153. + avr_isp_reader_view_get_view(app->avr_isp_reader_view));
  154. +
  155. + // Writer view
  156. + app->avr_isp_writer_view = avr_isp_writer_view_alloc();
  157. + view_dispatcher_add_view(
  158. + app->view_dispatcher,
  159. + AvrIspViewWriter,
  160. + avr_isp_writer_view_get_view(app->avr_isp_writer_view));
  161. +
  162. + // Chip detect view
  163. + app->avr_isp_chip_detect_view = avr_isp_chip_detect_view_alloc();
  164. + view_dispatcher_add_view(
  165. + app->view_dispatcher,
  166. + AvrIspViewChipDetect,
  167. + avr_isp_chip_detect_view_get_view(app->avr_isp_chip_detect_view));
  168. +
  169. + // Enable 5v power, multiple attempts to avoid issues with power chip protection false triggering
  170. + uint8_t attempts = 0;
  171. + while(!furi_hal_power_is_otg_enabled() && attempts++ < 5) {
  172. + furi_hal_power_enable_otg();
  173. + furi_delay_ms(10);
  174. + }
  175. +
  176. + scene_manager_next_scene(app->scene_manager, AvrIspSceneStart);
  177. +
  178. + return app;
  179. +} //-V773
  180. +
  181. +void avr_isp_app_free(AvrIspApp* app) {
  182. + furi_assert(app);
  183. +
  184. + // Disable 5v power
  185. + if(furi_hal_power_is_otg_enabled()) {
  186. + furi_hal_power_disable_otg();
  187. + }
  188. +
  189. + // Submenu
  190. + view_dispatcher_remove_view(app->view_dispatcher, AvrIspViewSubmenu);
  191. + submenu_free(app->submenu);
  192. +
  193. + // Widget
  194. + view_dispatcher_remove_view(app->view_dispatcher, AvrIspViewWidget);
  195. + widget_free(app->widget);
  196. +
  197. + // TextInput
  198. + view_dispatcher_remove_view(app->view_dispatcher, AvrIspViewTextInput);
  199. + text_input_free(app->text_input);
  200. +
  201. + // Popup
  202. + view_dispatcher_remove_view(app->view_dispatcher, AvrIspViewPopup);
  203. + popup_free(app->popup);
  204. +
  205. + //Dialog
  206. + furi_record_close(RECORD_DIALOGS);
  207. +
  208. + // Programmer view
  209. + view_dispatcher_remove_view(app->view_dispatcher, AvrIspViewProgrammer);
  210. + avr_isp_programmer_view_free(app->avr_isp_programmer_view);
  211. +
  212. + // Reader view
  213. + view_dispatcher_remove_view(app->view_dispatcher, AvrIspViewReader);
  214. + avr_isp_reader_view_free(app->avr_isp_reader_view);
  215. +
  216. + // Writer view
  217. + view_dispatcher_remove_view(app->view_dispatcher, AvrIspViewWriter);
  218. + avr_isp_writer_view_free(app->avr_isp_writer_view);
  219. +
  220. + // Chip detect view
  221. + view_dispatcher_remove_view(app->view_dispatcher, AvrIspViewChipDetect);
  222. + avr_isp_chip_detect_view_free(app->avr_isp_chip_detect_view);
  223. +
  224. + // View dispatcher
  225. + view_dispatcher_free(app->view_dispatcher);
  226. + scene_manager_free(app->scene_manager);
  227. +
  228. + // Notifications
  229. + furi_record_close(RECORD_NOTIFICATION);
  230. + app->notifications = NULL;
  231. +
  232. + // Close records
  233. + furi_record_close(RECORD_GUI);
  234. +
  235. + // Path strings
  236. + furi_string_free(app->file_path);
  237. +
  238. + free(app);
  239. +}
  240. +
  241. +int32_t avr_isp_app(void* p) {
  242. + UNUSED(p);
  243. + AvrIspApp* avr_isp_app = avr_isp_app_alloc();
  244. +
  245. + view_dispatcher_run(avr_isp_app->view_dispatcher);
  246. +
  247. + avr_isp_app_free(avr_isp_app);
  248. +
  249. + return 0;
  250. +}
  251. diff --git a/applications/external/avr_isp_programmer/avr_isp_app_i.c b/applications/external/avr_isp_programmer/avr_isp_app_i.c
  252. new file mode 100644
  253. index 000000000..7a7fa6d7f
  254. --- /dev/null
  255. +++ b/applications/external/avr_isp_programmer/avr_isp_app_i.c
  256. @@ -0,0 +1,31 @@
  257. +#include "avr_isp_app_i.h"
  258. +#include <lib/toolbox/path.h>
  259. +#include <flipper_format/flipper_format_i.h>
  260. +
  261. +#define TAG "AvrIsp"
  262. +
  263. +bool avr_isp_load_from_file(AvrIspApp* app) {
  264. + furi_assert(app);
  265. +
  266. + FuriString* file_path = furi_string_alloc();
  267. + FuriString* file_name = furi_string_alloc();
  268. +
  269. + DialogsFileBrowserOptions browser_options;
  270. + dialog_file_browser_set_basic_options(
  271. + &browser_options, AVR_ISP_APP_EXTENSION, &I_avr_app_icon_10x10);
  272. + browser_options.base_path = STORAGE_APP_DATA_PATH_PREFIX;
  273. +
  274. + // Input events and views are managed by file_select
  275. + bool res = dialog_file_browser_show(app->dialogs, file_path, app->file_path, &browser_options);
  276. +
  277. + if(res) {
  278. + path_extract_dirname(furi_string_get_cstr(file_path), app->file_path);
  279. + path_extract_filename(file_path, file_name, true);
  280. + strncpy(app->file_name_tmp, furi_string_get_cstr(file_name), AVR_ISP_MAX_LEN_NAME);
  281. + }
  282. +
  283. + furi_string_free(file_name);
  284. + furi_string_free(file_path);
  285. +
  286. + return res;
  287. +}
  288. diff --git a/applications/external/avr_isp_programmer/avr_isp_app_i.h b/applications/external/avr_isp_programmer/avr_isp_app_i.h
  289. new file mode 100644
  290. index 000000000..17c69f8f2
  291. --- /dev/null
  292. +++ b/applications/external/avr_isp_programmer/avr_isp_app_i.h
  293. @@ -0,0 +1,44 @@
  294. +#pragma once
  295. +
  296. +#include "helpers/avr_isp_types.h"
  297. +#include <avr_isp_icons.h>
  298. +
  299. +#include "scenes/avr_isp_scene.h"
  300. +#include <gui/gui.h>
  301. +#include <gui/view_dispatcher.h>
  302. +#include <gui/scene_manager.h>
  303. +#include <gui/modules/submenu.h>
  304. +#include <gui/modules/widget.h>
  305. +#include <notification/notification_messages.h>
  306. +#include <gui/modules/text_input.h>
  307. +#include <dialogs/dialogs.h>
  308. +#include <storage/storage.h>
  309. +#include <gui/modules/popup.h>
  310. +
  311. +#include "views/avr_isp_view_programmer.h"
  312. +#include "views/avr_isp_view_reader.h"
  313. +#include "views/avr_isp_view_writer.h"
  314. +#include "views/avr_isp_view_chip_detect.h"
  315. +
  316. +#define AVR_ISP_MAX_LEN_NAME 64
  317. +
  318. +typedef struct {
  319. + Gui* gui;
  320. + ViewDispatcher* view_dispatcher;
  321. + SceneManager* scene_manager;
  322. + NotificationApp* notifications;
  323. + DialogsApp* dialogs;
  324. + Popup* popup;
  325. + Submenu* submenu;
  326. + Widget* widget;
  327. + TextInput* text_input;
  328. + FuriString* file_path;
  329. + char file_name_tmp[AVR_ISP_MAX_LEN_NAME];
  330. + AvrIspProgrammerView* avr_isp_programmer_view;
  331. + AvrIspReaderView* avr_isp_reader_view;
  332. + AvrIspWriterView* avr_isp_writer_view;
  333. + AvrIspChipDetectView* avr_isp_chip_detect_view;
  334. + AvrIspError error;
  335. +} AvrIspApp;
  336. +
  337. +bool avr_isp_load_from_file(AvrIspApp* app);
  338. \ No newline at end of file
  339. diff --git a/applications/external/avr_isp_programmer/helpers/avr_isp.c b/applications/external/avr_isp_programmer/helpers/avr_isp.c
  340. new file mode 100644
  341. index 000000000..76e0a80b0
  342. --- /dev/null
  343. +++ b/applications/external/avr_isp_programmer/helpers/avr_isp.c
  344. @@ -0,0 +1,490 @@
  345. +#include "avr_isp.h"
  346. +#include "../lib/driver/avr_isp_prog_cmd.h"
  347. +#include "../lib/driver/avr_isp_spi_sw.h"
  348. +
  349. +#include <furi.h>
  350. +
  351. +#define AVR_ISP_PROG_TX_RX_BUF_SIZE 320
  352. +#define TAG "AvrIsp"
  353. +
  354. +struct AvrIsp {
  355. + AvrIspSpiSw* spi;
  356. + bool pmode;
  357. + AvrIspCallback callback;
  358. + void* context;
  359. +};
  360. +
  361. +AvrIsp* avr_isp_alloc(void) {
  362. + AvrIsp* instance = malloc(sizeof(AvrIsp));
  363. + return instance;
  364. +}
  365. +
  366. +void avr_isp_free(AvrIsp* instance) {
  367. + furi_assert(instance);
  368. +
  369. + if(instance->spi) avr_isp_end_pmode(instance);
  370. + free(instance);
  371. +}
  372. +
  373. +void avr_isp_set_tx_callback(AvrIsp* instance, AvrIspCallback callback, void* context) {
  374. + furi_assert(instance);
  375. + furi_assert(context);
  376. +
  377. + instance->callback = callback;
  378. + instance->context = context;
  379. +}
  380. +
  381. +uint8_t avr_isp_spi_transaction(
  382. + AvrIsp* instance,
  383. + uint8_t cmd,
  384. + uint8_t addr_hi,
  385. + uint8_t addr_lo,
  386. + uint8_t data) {
  387. + furi_assert(instance);
  388. +
  389. + avr_isp_spi_sw_txrx(instance->spi, cmd);
  390. + avr_isp_spi_sw_txrx(instance->spi, addr_hi);
  391. + avr_isp_spi_sw_txrx(instance->spi, addr_lo);
  392. + return avr_isp_spi_sw_txrx(instance->spi, data);
  393. +}
  394. +
  395. +static bool avr_isp_set_pmode(AvrIsp* instance, uint8_t a, uint8_t b, uint8_t c, uint8_t d) {
  396. + furi_assert(instance);
  397. +
  398. + uint8_t res = 0;
  399. + avr_isp_spi_sw_txrx(instance->spi, a);
  400. + avr_isp_spi_sw_txrx(instance->spi, b);
  401. + res = avr_isp_spi_sw_txrx(instance->spi, c);
  402. + avr_isp_spi_sw_txrx(instance->spi, d);
  403. + return res == 0x53;
  404. +}
  405. +
  406. +void avr_isp_end_pmode(AvrIsp* instance) {
  407. + furi_assert(instance);
  408. +
  409. + if(instance->pmode) {
  410. + avr_isp_spi_sw_res_set(instance->spi, true);
  411. + // We're about to take the target out of reset
  412. + // so configure SPI pins as input
  413. + if(instance->spi) avr_isp_spi_sw_free(instance->spi);
  414. + instance->spi = NULL;
  415. + }
  416. +
  417. + instance->pmode = false;
  418. +}
  419. +
  420. +static bool avr_isp_start_pmode(AvrIsp* instance, AvrIspSpiSwSpeed spi_speed) {
  421. + furi_assert(instance);
  422. +
  423. + // Reset target before driving PIN_SCK or PIN_MOSI
  424. +
  425. + // SPI.begin() will configure SS as output,
  426. + // so SPI master mode is selected.
  427. + // We have defined RESET as pin 10,
  428. + // which for many arduino's is not the SS pin.
  429. + // So we have to configure RESET as output here,
  430. + // (reset_target() first sets the correct level)
  431. + if(instance->spi) avr_isp_spi_sw_free(instance->spi);
  432. + instance->spi = avr_isp_spi_sw_init(spi_speed);
  433. +
  434. + avr_isp_spi_sw_res_set(instance->spi, false);
  435. + // See avr datasheets, chapter "SERIAL_PRG Programming Algorithm":
  436. +
  437. + // Pulse RESET after PIN_SCK is low:
  438. + avr_isp_spi_sw_sck_set(instance->spi, false);
  439. +
  440. + // discharge PIN_SCK, value arbitrally chosen
  441. + furi_delay_ms(20);
  442. + avr_isp_spi_sw_res_set(instance->spi, true);
  443. +
  444. + // Pulse must be minimum 2 target CPU speed cycles
  445. + // so 100 usec is ok for CPU speeds above 20KHz
  446. + furi_delay_ms(1);
  447. +
  448. + avr_isp_spi_sw_res_set(instance->spi, false);
  449. +
  450. + // Send the enable programming command:
  451. + // datasheet: must be > 20 msec
  452. + furi_delay_ms(50);
  453. + if(avr_isp_set_pmode(instance, AVR_ISP_SET_PMODE)) {
  454. + instance->pmode = true;
  455. + return true;
  456. + }
  457. + return false;
  458. +}
  459. +
  460. +bool avr_isp_auto_set_spi_speed_start_pmode(AvrIsp* instance) {
  461. + furi_assert(instance);
  462. +
  463. + AvrIspSpiSwSpeed spi_speed[] = {
  464. + AvrIspSpiSwSpeed1Mhz,
  465. + AvrIspSpiSwSpeed400Khz,
  466. + AvrIspSpiSwSpeed250Khz,
  467. + AvrIspSpiSwSpeed125Khz,
  468. + AvrIspSpiSwSpeed60Khz,
  469. + AvrIspSpiSwSpeed40Khz,
  470. + AvrIspSpiSwSpeed20Khz,
  471. + AvrIspSpiSwSpeed10Khz,
  472. + AvrIspSpiSwSpeed5Khz,
  473. + AvrIspSpiSwSpeed1Khz,
  474. + };
  475. + for(uint8_t i = 0; i < COUNT_OF(spi_speed); i++) {
  476. + if(avr_isp_start_pmode(instance, spi_speed[i])) {
  477. + AvrIspSignature sig = avr_isp_read_signature(instance);
  478. + AvrIspSignature sig_examination = avr_isp_read_signature(instance); //-V656
  479. + uint8_t y = 0;
  480. + while(y < 8) {
  481. + if(memcmp((uint8_t*)&sig, (uint8_t*)&sig_examination, sizeof(AvrIspSignature)) !=
  482. + 0)
  483. + break;
  484. + sig_examination = avr_isp_read_signature(instance);
  485. + y++;
  486. + }
  487. + if(y == 8) {
  488. + if(spi_speed[i] > AvrIspSpiSwSpeed1Mhz) {
  489. + if(i < (COUNT_OF(spi_speed) - 1)) {
  490. + avr_isp_end_pmode(instance);
  491. + i++;
  492. + return avr_isp_start_pmode(instance, spi_speed[i]);
  493. + }
  494. + }
  495. + return true;
  496. + }
  497. + }
  498. + }
  499. + return false;
  500. +}
  501. +
  502. +static void avr_isp_commit(AvrIsp* instance, uint16_t addr, uint8_t data) {
  503. + furi_assert(instance);
  504. +
  505. + avr_isp_spi_transaction(instance, AVR_ISP_COMMIT(addr));
  506. + /* polling flash */
  507. + if(data == 0xFF) {
  508. + furi_delay_ms(5);
  509. + } else {
  510. + /* polling flash */
  511. + uint32_t starttime = furi_get_tick();
  512. + while((furi_get_tick() - starttime) < 30) {
  513. + if(avr_isp_spi_transaction(instance, AVR_ISP_READ_FLASH_HI(addr)) != 0xFF) {
  514. + break;
  515. + };
  516. + }
  517. + }
  518. +}
  519. +
  520. +static uint16_t avr_isp_current_page(AvrIsp* instance, uint32_t addr, uint16_t page_size) {
  521. + furi_assert(instance);
  522. +
  523. + uint16_t page = 0;
  524. + switch(page_size) {
  525. + case 32:
  526. + page = addr & 0xFFFFFFF0;
  527. + break;
  528. + case 64:
  529. + page = addr & 0xFFFFFFE0;
  530. + break;
  531. + case 128:
  532. + page = addr & 0xFFFFFFC0;
  533. + break;
  534. + case 256:
  535. + page = addr & 0xFFFFFF80;
  536. + break;
  537. +
  538. + default:
  539. + page = addr;
  540. + break;
  541. + }
  542. +
  543. + return page;
  544. +}
  545. +
  546. +static bool avr_isp_flash_write_pages(
  547. + AvrIsp* instance,
  548. + uint16_t addr,
  549. + uint16_t page_size,
  550. + uint8_t* data,
  551. + uint32_t data_size) {
  552. + furi_assert(instance);
  553. +
  554. + size_t x = 0;
  555. + uint16_t page = avr_isp_current_page(instance, addr, page_size);
  556. +
  557. + while(x < data_size) {
  558. + if(page != avr_isp_current_page(instance, addr, page_size)) {
  559. + avr_isp_commit(instance, page, data[x - 1]);
  560. + page = avr_isp_current_page(instance, addr, page_size);
  561. + }
  562. + avr_isp_spi_transaction(instance, AVR_ISP_WRITE_FLASH_LO(addr, data[x++]));
  563. + avr_isp_spi_transaction(instance, AVR_ISP_WRITE_FLASH_HI(addr, data[x++]));
  564. + addr++;
  565. + }
  566. + avr_isp_commit(instance, page, data[x - 1]);
  567. + return true;
  568. +}
  569. +
  570. +bool avr_isp_erase_chip(AvrIsp* instance) {
  571. + furi_assert(instance);
  572. +
  573. + bool ret = false;
  574. + if(!instance->pmode) avr_isp_auto_set_spi_speed_start_pmode(instance);
  575. + if(instance->pmode) {
  576. + avr_isp_spi_transaction(instance, AVR_ISP_ERASE_CHIP);
  577. + furi_delay_ms(100);
  578. + avr_isp_end_pmode(instance);
  579. + ret = true;
  580. + }
  581. + return ret;
  582. +}
  583. +
  584. +static bool
  585. + avr_isp_eeprom_write(AvrIsp* instance, uint16_t addr, uint8_t* data, uint32_t data_size) {
  586. + furi_assert(instance);
  587. +
  588. + for(uint16_t i = 0; i < data_size; i++) {
  589. + avr_isp_spi_transaction(instance, AVR_ISP_WRITE_EEPROM(addr, data[i]));
  590. + furi_delay_ms(10);
  591. + addr++;
  592. + }
  593. + return true;
  594. +}
  595. +
  596. +bool avr_isp_write_page(
  597. + AvrIsp* instance,
  598. + uint32_t mem_type,
  599. + uint32_t mem_size,
  600. + uint16_t addr,
  601. + uint16_t page_size,
  602. + uint8_t* data,
  603. + uint32_t data_size) {
  604. + furi_assert(instance);
  605. +
  606. + bool ret = false;
  607. + switch(mem_type) {
  608. + case STK_SET_FLASH_TYPE:
  609. + if((addr + data_size / 2) <= mem_size) {
  610. + ret = avr_isp_flash_write_pages(instance, addr, page_size, data, data_size);
  611. + }
  612. + break;
  613. +
  614. + case STK_SET_EEPROM_TYPE:
  615. + if((addr + data_size) <= mem_size) {
  616. + ret = avr_isp_eeprom_write(instance, addr, data, data_size);
  617. + }
  618. + break;
  619. +
  620. + default:
  621. + furi_crash(TAG " Incorrect mem type.");
  622. + break;
  623. + }
  624. +
  625. + return ret;
  626. +}
  627. +
  628. +static bool avr_isp_flash_read_page(
  629. + AvrIsp* instance,
  630. + uint16_t addr,
  631. + uint16_t page_size,
  632. + uint8_t* data,
  633. + uint32_t data_size) {
  634. + furi_assert(instance);
  635. +
  636. + if(page_size > data_size) return false;
  637. + for(uint16_t i = 0; i < page_size; i += 2) {
  638. + data[i] = avr_isp_spi_transaction(instance, AVR_ISP_READ_FLASH_LO(addr));
  639. + data[i + 1] = avr_isp_spi_transaction(instance, AVR_ISP_READ_FLASH_HI(addr));
  640. + addr++;
  641. + }
  642. + return true;
  643. +}
  644. +
  645. +static bool avr_isp_eeprom_read_page(
  646. + AvrIsp* instance,
  647. + uint16_t addr,
  648. + uint16_t page_size,
  649. + uint8_t* data,
  650. + uint32_t data_size) {
  651. + furi_assert(instance);
  652. +
  653. + if(page_size > data_size) return false;
  654. + for(uint16_t i = 0; i < page_size; i++) {
  655. + data[i] = avr_isp_spi_transaction(instance, AVR_ISP_READ_EEPROM(addr));
  656. + addr++;
  657. + }
  658. + return true;
  659. +}
  660. +
  661. +bool avr_isp_read_page(
  662. + AvrIsp* instance,
  663. + uint32_t mem_type,
  664. + uint16_t addr,
  665. + uint16_t page_size,
  666. + uint8_t* data,
  667. + uint32_t data_size) {
  668. + furi_assert(instance);
  669. +
  670. + bool res = false;
  671. + if(mem_type == STK_SET_FLASH_TYPE)
  672. + res = avr_isp_flash_read_page(instance, addr, page_size, data, data_size);
  673. + if(mem_type == STK_SET_EEPROM_TYPE)
  674. + res = avr_isp_eeprom_read_page(instance, addr, page_size, data, data_size);
  675. +
  676. + return res;
  677. +}
  678. +
  679. +AvrIspSignature avr_isp_read_signature(AvrIsp* instance) {
  680. + furi_assert(instance);
  681. +
  682. + AvrIspSignature signature;
  683. + signature.vendor = avr_isp_spi_transaction(instance, AVR_ISP_READ_VENDOR);
  684. + signature.part_family = avr_isp_spi_transaction(instance, AVR_ISP_READ_PART_FAMILY);
  685. + signature.part_number = avr_isp_spi_transaction(instance, AVR_ISP_READ_PART_NUMBER);
  686. + return signature;
  687. +}
  688. +
  689. +uint8_t avr_isp_read_lock_byte(AvrIsp* instance) {
  690. + furi_assert(instance);
  691. +
  692. + uint8_t data = 0;
  693. + uint32_t starttime = furi_get_tick();
  694. + while((furi_get_tick() - starttime) < 300) {
  695. + data = avr_isp_spi_transaction(instance, AVR_ISP_READ_LOCK_BYTE);
  696. + if(avr_isp_spi_transaction(instance, AVR_ISP_READ_LOCK_BYTE) == data) {
  697. + break;
  698. + };
  699. + data = 0x00;
  700. + }
  701. + return data;
  702. +}
  703. +
  704. +bool avr_isp_write_lock_byte(AvrIsp* instance, uint8_t lock) {
  705. + furi_assert(instance);
  706. +
  707. + bool ret = false;
  708. + if(avr_isp_read_lock_byte(instance) == lock) {
  709. + ret = true;
  710. + } else {
  711. + avr_isp_spi_transaction(instance, AVR_ISP_WRITE_LOCK_BYTE(lock));
  712. + /* polling lock byte */
  713. + uint32_t starttime = furi_get_tick();
  714. + while((furi_get_tick() - starttime) < 30) {
  715. + if(avr_isp_spi_transaction(instance, AVR_ISP_READ_LOCK_BYTE) == lock) {
  716. + ret = true;
  717. + break;
  718. + };
  719. + }
  720. + }
  721. + return ret;
  722. +}
  723. +
  724. +uint8_t avr_isp_read_fuse_low(AvrIsp* instance) {
  725. + furi_assert(instance);
  726. +
  727. + uint8_t data = 0;
  728. + uint32_t starttime = furi_get_tick();
  729. + while((furi_get_tick() - starttime) < 300) {
  730. + data = avr_isp_spi_transaction(instance, AVR_ISP_READ_FUSE_LOW);
  731. + if(avr_isp_spi_transaction(instance, AVR_ISP_READ_FUSE_LOW) == data) {
  732. + break;
  733. + };
  734. + data = 0x00;
  735. + }
  736. + return data;
  737. +}
  738. +
  739. +bool avr_isp_write_fuse_low(AvrIsp* instance, uint8_t lfuse) {
  740. + furi_assert(instance);
  741. +
  742. + bool ret = false;
  743. + if(avr_isp_read_fuse_low(instance) == lfuse) {
  744. + ret = true;
  745. + } else {
  746. + avr_isp_spi_transaction(instance, AVR_ISP_WRITE_FUSE_LOW(lfuse));
  747. + /* polling fuse */
  748. + uint32_t starttime = furi_get_tick();
  749. + while((furi_get_tick() - starttime) < 30) {
  750. + if(avr_isp_spi_transaction(instance, AVR_ISP_READ_FUSE_LOW) == lfuse) {
  751. + ret = true;
  752. + break;
  753. + };
  754. + }
  755. + }
  756. + return ret;
  757. +}
  758. +
  759. +uint8_t avr_isp_read_fuse_high(AvrIsp* instance) {
  760. + furi_assert(instance);
  761. +
  762. + uint8_t data = 0;
  763. + uint32_t starttime = furi_get_tick();
  764. + while((furi_get_tick() - starttime) < 300) {
  765. + data = avr_isp_spi_transaction(instance, AVR_ISP_READ_FUSE_HIGH);
  766. + if(avr_isp_spi_transaction(instance, AVR_ISP_READ_FUSE_HIGH) == data) {
  767. + break;
  768. + };
  769. + data = 0x00;
  770. + }
  771. + return data;
  772. +}
  773. +
  774. +bool avr_isp_write_fuse_high(AvrIsp* instance, uint8_t hfuse) {
  775. + furi_assert(instance);
  776. +
  777. + bool ret = false;
  778. + if(avr_isp_read_fuse_high(instance) == hfuse) {
  779. + ret = true;
  780. + } else {
  781. + avr_isp_spi_transaction(instance, AVR_ISP_WRITE_FUSE_HIGH(hfuse));
  782. + /* polling fuse */
  783. + uint32_t starttime = furi_get_tick();
  784. + while((furi_get_tick() - starttime) < 30) {
  785. + if(avr_isp_spi_transaction(instance, AVR_ISP_READ_FUSE_HIGH) == hfuse) {
  786. + ret = true;
  787. + break;
  788. + };
  789. + }
  790. + }
  791. + return ret;
  792. +}
  793. +
  794. +uint8_t avr_isp_read_fuse_extended(AvrIsp* instance) {
  795. + furi_assert(instance);
  796. +
  797. + uint8_t data = 0;
  798. + uint32_t starttime = furi_get_tick();
  799. + while((furi_get_tick() - starttime) < 300) {
  800. + data = avr_isp_spi_transaction(instance, AVR_ISP_READ_FUSE_EXTENDED);
  801. + if(avr_isp_spi_transaction(instance, AVR_ISP_READ_FUSE_EXTENDED) == data) {
  802. + break;
  803. + };
  804. + data = 0x00;
  805. + }
  806. + return data;
  807. +}
  808. +
  809. +bool avr_isp_write_fuse_extended(AvrIsp* instance, uint8_t efuse) {
  810. + furi_assert(instance);
  811. +
  812. + bool ret = false;
  813. + if(avr_isp_read_fuse_extended(instance) == efuse) {
  814. + ret = true;
  815. + } else {
  816. + avr_isp_spi_transaction(instance, AVR_ISP_WRITE_FUSE_EXTENDED(efuse));
  817. + /* polling fuse */
  818. + uint32_t starttime = furi_get_tick();
  819. + while((furi_get_tick() - starttime) < 30) {
  820. + if(avr_isp_spi_transaction(instance, AVR_ISP_READ_FUSE_EXTENDED) == efuse) {
  821. + ret = true;
  822. + break;
  823. + };
  824. + }
  825. + }
  826. + return ret;
  827. +}
  828. +
  829. +void avr_isp_write_extended_addr(AvrIsp* instance, uint8_t extended_addr) {
  830. + furi_assert(instance);
  831. +
  832. + avr_isp_spi_transaction(instance, AVR_ISP_EXTENDED_ADDR(extended_addr));
  833. + furi_delay_ms(10);
  834. +}
  835. \ No newline at end of file
  836. diff --git a/applications/external/avr_isp_programmer/helpers/avr_isp.h b/applications/external/avr_isp_programmer/helpers/avr_isp.h
  837. new file mode 100644
  838. index 000000000..476fc3d64
  839. --- /dev/null
  840. +++ b/applications/external/avr_isp_programmer/helpers/avr_isp.h
  841. @@ -0,0 +1,70 @@
  842. +#pragma once
  843. +
  844. +#include <furi_hal.h>
  845. +
  846. +typedef struct AvrIsp AvrIsp;
  847. +typedef void (*AvrIspCallback)(void* context);
  848. +
  849. +struct AvrIspSignature {
  850. + uint8_t vendor;
  851. + uint8_t part_family;
  852. + uint8_t part_number;
  853. +};
  854. +
  855. +typedef struct AvrIspSignature AvrIspSignature;
  856. +
  857. +AvrIsp* avr_isp_alloc(void);
  858. +
  859. +void avr_isp_free(AvrIsp* instance);
  860. +
  861. +void avr_isp_set_tx_callback(AvrIsp* instance, AvrIspCallback callback, void* context);
  862. +
  863. +bool avr_isp_auto_set_spi_speed_start_pmode(AvrIsp* instance);
  864. +
  865. +AvrIspSignature avr_isp_read_signature(AvrIsp* instance);
  866. +
  867. +void avr_isp_end_pmode(AvrIsp* instance);
  868. +
  869. +bool avr_isp_erase_chip(AvrIsp* instance);
  870. +
  871. +uint8_t avr_isp_spi_transaction(
  872. + AvrIsp* instance,
  873. + uint8_t cmd,
  874. + uint8_t addr_hi,
  875. + uint8_t addr_lo,
  876. + uint8_t data);
  877. +
  878. +bool avr_isp_read_page(
  879. + AvrIsp* instance,
  880. + uint32_t memtype,
  881. + uint16_t addr,
  882. + uint16_t page_size,
  883. + uint8_t* data,
  884. + uint32_t data_size);
  885. +
  886. +bool avr_isp_write_page(
  887. + AvrIsp* instance,
  888. + uint32_t mem_type,
  889. + uint32_t mem_size,
  890. + uint16_t addr,
  891. + uint16_t page_size,
  892. + uint8_t* data,
  893. + uint32_t data_size);
  894. +
  895. +uint8_t avr_isp_read_lock_byte(AvrIsp* instance);
  896. +
  897. +bool avr_isp_write_lock_byte(AvrIsp* instance, uint8_t lock);
  898. +
  899. +uint8_t avr_isp_read_fuse_low(AvrIsp* instance);
  900. +
  901. +bool avr_isp_write_fuse_low(AvrIsp* instance, uint8_t lfuse);
  902. +
  903. +uint8_t avr_isp_read_fuse_high(AvrIsp* instance);
  904. +
  905. +bool avr_isp_write_fuse_high(AvrIsp* instance, uint8_t hfuse);
  906. +
  907. +uint8_t avr_isp_read_fuse_extended(AvrIsp* instance);
  908. +
  909. +bool avr_isp_write_fuse_extended(AvrIsp* instance, uint8_t efuse);
  910. +
  911. +void avr_isp_write_extended_addr(AvrIsp* instance, uint8_t extended_addr);
  912. \ No newline at end of file
  913. diff --git a/applications/external/avr_isp_programmer/helpers/avr_isp_event.h b/applications/external/avr_isp_programmer/helpers/avr_isp_event.h
  914. new file mode 100644
  915. index 000000000..c704b5b35
  916. --- /dev/null
  917. +++ b/applications/external/avr_isp_programmer/helpers/avr_isp_event.h
  918. @@ -0,0 +1,23 @@
  919. +#pragma once
  920. +
  921. +typedef enum {
  922. + //SubmenuIndex
  923. + SubmenuIndexAvrIspProgrammer = 10,
  924. + SubmenuIndexAvrIspReader,
  925. + SubmenuIndexAvrIspWriter,
  926. + SubmenuIndexAvrIsWiring,
  927. + SubmenuIndexAvrIspAbout,
  928. +
  929. + //AvrIspCustomEvent
  930. + AvrIspCustomEventSceneChipDetectOk = 100,
  931. + AvrIspCustomEventSceneReadingOk,
  932. + AvrIspCustomEventSceneWritingOk,
  933. + AvrIspCustomEventSceneErrorVerification,
  934. + AvrIspCustomEventSceneErrorReading,
  935. + AvrIspCustomEventSceneErrorWriting,
  936. + AvrIspCustomEventSceneErrorWritingFuse,
  937. + AvrIspCustomEventSceneInputName,
  938. + AvrIspCustomEventSceneSuccess,
  939. + AvrIspCustomEventSceneExit,
  940. + AvrIspCustomEventSceneExitStartMenu,
  941. +} AvrIspCustomEvent;
  942. diff --git a/applications/external/avr_isp_programmer/helpers/avr_isp_types.h b/applications/external/avr_isp_programmer/helpers/avr_isp_types.h
  943. new file mode 100644
  944. index 000000000..5e174ec3b
  945. --- /dev/null
  946. +++ b/applications/external/avr_isp_programmer/helpers/avr_isp_types.h
  947. @@ -0,0 +1,32 @@
  948. +#pragma once
  949. +
  950. +#include <furi.h>
  951. +#include <furi_hal.h>
  952. +
  953. +#define AVR_ISP_VERSION_APP "0.1"
  954. +#define AVR_ISP_DEVELOPED "SkorP"
  955. +#define AVR_ISP_GITHUB "https://github.com/flipperdevices/flipperzero-firmware"
  956. +
  957. +#define AVR_ISP_APP_FILE_VERSION 1
  958. +#define AVR_ISP_APP_FILE_TYPE "Flipper Dump AVR"
  959. +#define AVR_ISP_APP_EXTENSION ".avr"
  960. +
  961. +typedef enum {
  962. + //AvrIspViewVariableItemList,
  963. + AvrIspViewSubmenu,
  964. + AvrIspViewProgrammer,
  965. + AvrIspViewReader,
  966. + AvrIspViewWriter,
  967. + AvrIspViewWidget,
  968. + AvrIspViewPopup,
  969. + AvrIspViewTextInput,
  970. + AvrIspViewChipDetect,
  971. +} AvrIspView;
  972. +
  973. +typedef enum {
  974. + AvrIspErrorNoError,
  975. + AvrIspErrorReading,
  976. + AvrIspErrorWriting,
  977. + AvrIspErrorVerification,
  978. + AvrIspErrorWritingFuse,
  979. +} AvrIspError;
  980. \ No newline at end of file
  981. diff --git a/applications/external/avr_isp_programmer/helpers/avr_isp_worker.c b/applications/external/avr_isp_programmer/helpers/avr_isp_worker.c
  982. new file mode 100644
  983. index 000000000..dfe1f43c2
  984. --- /dev/null
  985. +++ b/applications/external/avr_isp_programmer/helpers/avr_isp_worker.c
  986. @@ -0,0 +1,266 @@
  987. +#include "avr_isp_worker.h"
  988. +#include <furi_hal_pwm.h>
  989. +#include "../lib/driver/avr_isp_prog.h"
  990. +#include "../lib/driver/avr_isp_prog_cmd.h"
  991. +#include "../lib/driver/avr_isp_chip_arr.h"
  992. +
  993. +#include <furi.h>
  994. +
  995. +#define TAG "AvrIspWorker"
  996. +
  997. +typedef enum {
  998. + AvrIspWorkerEvtStop = (1 << 0),
  999. +
  1000. + AvrIspWorkerEvtRx = (1 << 1),
  1001. + AvrIspWorkerEvtTxCoplete = (1 << 2),
  1002. + AvrIspWorkerEvtTx = (1 << 3),
  1003. + AvrIspWorkerEvtState = (1 << 4),
  1004. +
  1005. + //AvrIspWorkerEvtCfg = (1 << 5),
  1006. +
  1007. +} AvrIspWorkerEvt;
  1008. +
  1009. +struct AvrIspWorker {
  1010. + FuriThread* thread;
  1011. + volatile bool worker_running;
  1012. + uint8_t connect_usb;
  1013. + AvrIspWorkerCallback callback;
  1014. + void* context;
  1015. +};
  1016. +
  1017. +#define AVR_ISP_WORKER_PROG_ALL_EVENTS (AvrIspWorkerEvtStop)
  1018. +#define AVR_ISP_WORKER_ALL_EVENTS \
  1019. + (AvrIspWorkerEvtTx | AvrIspWorkerEvtTxCoplete | AvrIspWorkerEvtRx | AvrIspWorkerEvtStop | \
  1020. + AvrIspWorkerEvtState)
  1021. +
  1022. +//########################/* VCP CDC */#############################################
  1023. +#include "usb_cdc.h"
  1024. +#include <cli/cli_vcp.h>
  1025. +#include <cli/cli.h>
  1026. +#include <furi_hal_usb_cdc.h>
  1027. +
  1028. +#define AVR_ISP_VCP_CDC_CH 1
  1029. +#define AVR_ISP_VCP_CDC_PKT_LEN CDC_DATA_SZ
  1030. +#define AVR_ISP_VCP_UART_RX_BUF_SIZE (AVR_ISP_VCP_CDC_PKT_LEN * 5)
  1031. +
  1032. +static void vcp_on_cdc_tx_complete(void* context);
  1033. +static void vcp_on_cdc_rx(void* context);
  1034. +static void vcp_state_callback(void* context, uint8_t state);
  1035. +static void vcp_on_cdc_control_line(void* context, uint8_t state);
  1036. +static void vcp_on_line_config(void* context, struct usb_cdc_line_coding* config);
  1037. +
  1038. +static const CdcCallbacks cdc_cb = {
  1039. + vcp_on_cdc_tx_complete,
  1040. + vcp_on_cdc_rx,
  1041. + vcp_state_callback,
  1042. + vcp_on_cdc_control_line,
  1043. + vcp_on_line_config,
  1044. +};
  1045. +
  1046. +/* VCP callbacks */
  1047. +
  1048. +static void vcp_on_cdc_tx_complete(void* context) {
  1049. + furi_assert(context);
  1050. + AvrIspWorker* instance = context;
  1051. + furi_thread_flags_set(furi_thread_get_id(instance->thread), AvrIspWorkerEvtTxCoplete);
  1052. +}
  1053. +
  1054. +static void vcp_on_cdc_rx(void* context) {
  1055. + furi_assert(context);
  1056. + AvrIspWorker* instance = context;
  1057. + furi_thread_flags_set(furi_thread_get_id(instance->thread), AvrIspWorkerEvtRx);
  1058. +}
  1059. +
  1060. +static void vcp_state_callback(void* context, uint8_t state) {
  1061. + UNUSED(context);
  1062. +
  1063. + AvrIspWorker* instance = context;
  1064. + instance->connect_usb = state;
  1065. + furi_thread_flags_set(furi_thread_get_id(instance->thread), AvrIspWorkerEvtState);
  1066. +}
  1067. +
  1068. +static void vcp_on_cdc_control_line(void* context, uint8_t state) {
  1069. + UNUSED(context);
  1070. + UNUSED(state);
  1071. +}
  1072. +
  1073. +static void vcp_on_line_config(void* context, struct usb_cdc_line_coding* config) {
  1074. + UNUSED(context);
  1075. + UNUSED(config);
  1076. +}
  1077. +
  1078. +static void avr_isp_worker_vcp_cdc_init(void* context) {
  1079. + furi_hal_usb_unlock();
  1080. + Cli* cli = furi_record_open(RECORD_CLI);
  1081. + //close cli
  1082. + cli_session_close(cli);
  1083. + //disable callbacks VCP_CDC=0
  1084. + furi_hal_cdc_set_callbacks(0, NULL, NULL);
  1085. + //set 2 cdc
  1086. + furi_check(furi_hal_usb_set_config(&usb_cdc_dual, NULL) == true);
  1087. + //open cli VCP_CDC=0
  1088. + cli_session_open(cli, &cli_vcp);
  1089. + furi_record_close(RECORD_CLI);
  1090. +
  1091. + furi_hal_cdc_set_callbacks(AVR_ISP_VCP_CDC_CH, (CdcCallbacks*)&cdc_cb, context);
  1092. +}
  1093. +
  1094. +static void avr_isp_worker_vcp_cdc_deinit(void) {
  1095. + //disable callbacks AVR_ISP_VCP_CDC_CH
  1096. + furi_hal_cdc_set_callbacks(AVR_ISP_VCP_CDC_CH, NULL, NULL);
  1097. +
  1098. + Cli* cli = furi_record_open(RECORD_CLI);
  1099. + //close cli
  1100. + cli_session_close(cli);
  1101. + furi_hal_usb_unlock();
  1102. + //set 1 cdc
  1103. + furi_check(furi_hal_usb_set_config(&usb_cdc_single, NULL) == true);
  1104. + //open cli VCP_CDC=0
  1105. + cli_session_open(cli, &cli_vcp);
  1106. + furi_record_close(RECORD_CLI);
  1107. +}
  1108. +
  1109. +//#################################################################################
  1110. +
  1111. +static int32_t avr_isp_worker_prog_thread(void* context) {
  1112. + AvrIspProg* prog = context;
  1113. + FURI_LOG_D(TAG, "AvrIspProgWorker Start");
  1114. + while(1) {
  1115. + if(furi_thread_flags_get() & AvrIspWorkerEvtStop) break;
  1116. + avr_isp_prog_avrisp(prog);
  1117. + }
  1118. + FURI_LOG_D(TAG, "AvrIspProgWorker Stop");
  1119. + return 0;
  1120. +}
  1121. +
  1122. +static void avr_isp_worker_prog_tx_data(void* context) {
  1123. + furi_assert(context);
  1124. + AvrIspWorker* instance = context;
  1125. + furi_thread_flags_set(furi_thread_get_id(instance->thread), AvrIspWorkerEvtTx);
  1126. +}
  1127. +
  1128. +/** Worker thread
  1129. + *
  1130. + * @param context
  1131. + * @return exit code
  1132. + */
  1133. +static int32_t avr_isp_worker_thread(void* context) {
  1134. + AvrIspWorker* instance = context;
  1135. + avr_isp_worker_vcp_cdc_init(instance);
  1136. +
  1137. + /* start PWM on &gpio_ext_pa4 */
  1138. + furi_hal_pwm_start(FuriHalPwmOutputIdLptim2PA4, 4000000, 50);
  1139. +
  1140. + AvrIspProg* prog = avr_isp_prog_init();
  1141. + avr_isp_prog_set_tx_callback(prog, avr_isp_worker_prog_tx_data, instance);
  1142. +
  1143. + uint8_t buf[AVR_ISP_VCP_UART_RX_BUF_SIZE];
  1144. + size_t len = 0;
  1145. +
  1146. + FuriThread* prog_thread =
  1147. + furi_thread_alloc_ex("AvrIspProgWorker", 1024, avr_isp_worker_prog_thread, prog);
  1148. + furi_thread_start(prog_thread);
  1149. +
  1150. + FURI_LOG_D(TAG, "Start");
  1151. +
  1152. + while(instance->worker_running) {
  1153. + uint32_t events =
  1154. + furi_thread_flags_wait(AVR_ISP_WORKER_ALL_EVENTS, FuriFlagWaitAny, FuriWaitForever);
  1155. +
  1156. + if(events & AvrIspWorkerEvtRx) {
  1157. + if(avr_isp_prog_spaces_rx(prog) >= AVR_ISP_VCP_CDC_PKT_LEN) {
  1158. + len = furi_hal_cdc_receive(AVR_ISP_VCP_CDC_CH, buf, AVR_ISP_VCP_CDC_PKT_LEN);
  1159. + // for(uint8_t i = 0; i < len; i++) {
  1160. + // FURI_LOG_I(TAG, "--> %X", buf[i]);
  1161. + // }
  1162. + avr_isp_prog_rx(prog, buf, len);
  1163. + } else {
  1164. + furi_thread_flags_set(furi_thread_get_id(instance->thread), AvrIspWorkerEvtRx);
  1165. + }
  1166. + }
  1167. +
  1168. + if((events & AvrIspWorkerEvtTxCoplete) || (events & AvrIspWorkerEvtTx)) {
  1169. + len = avr_isp_prog_tx(prog, buf, AVR_ISP_VCP_CDC_PKT_LEN);
  1170. +
  1171. + // for(uint8_t i = 0; i < len; i++) {
  1172. + // FURI_LOG_I(TAG, "<-- %X", buf[i]);
  1173. + // }
  1174. +
  1175. + if(len > 0) furi_hal_cdc_send(AVR_ISP_VCP_CDC_CH, buf, len);
  1176. + }
  1177. +
  1178. + if(events & AvrIspWorkerEvtStop) {
  1179. + break;
  1180. + }
  1181. +
  1182. + if(events & AvrIspWorkerEvtState) {
  1183. + if(instance->callback)
  1184. + instance->callback(instance->context, (bool)instance->connect_usb);
  1185. + }
  1186. + }
  1187. +
  1188. + FURI_LOG_D(TAG, "Stop");
  1189. +
  1190. + furi_thread_flags_set(furi_thread_get_id(prog_thread), AvrIspWorkerEvtStop);
  1191. + avr_isp_prog_exit(prog);
  1192. + furi_delay_ms(10);
  1193. + furi_thread_join(prog_thread);
  1194. + furi_thread_free(prog_thread);
  1195. +
  1196. + avr_isp_prog_free(prog);
  1197. + furi_hal_pwm_stop(FuriHalPwmOutputIdLptim2PA4);
  1198. + avr_isp_worker_vcp_cdc_deinit();
  1199. + return 0;
  1200. +}
  1201. +
  1202. +AvrIspWorker* avr_isp_worker_alloc(void* context) {
  1203. + furi_assert(context);
  1204. + UNUSED(context);
  1205. + AvrIspWorker* instance = malloc(sizeof(AvrIspWorker));
  1206. +
  1207. + instance->thread = furi_thread_alloc_ex("AvrIspWorker", 2048, avr_isp_worker_thread, instance);
  1208. + return instance;
  1209. +}
  1210. +
  1211. +void avr_isp_worker_free(AvrIspWorker* instance) {
  1212. + furi_assert(instance);
  1213. +
  1214. + furi_check(!instance->worker_running);
  1215. + furi_thread_free(instance->thread);
  1216. + free(instance);
  1217. +}
  1218. +
  1219. +void avr_isp_worker_set_callback(
  1220. + AvrIspWorker* instance,
  1221. + AvrIspWorkerCallback callback,
  1222. + void* context) {
  1223. + furi_assert(instance);
  1224. +
  1225. + instance->callback = callback;
  1226. + instance->context = context;
  1227. +}
  1228. +
  1229. +void avr_isp_worker_start(AvrIspWorker* instance) {
  1230. + furi_assert(instance);
  1231. + furi_assert(!instance->worker_running);
  1232. +
  1233. + instance->worker_running = true;
  1234. +
  1235. + furi_thread_start(instance->thread);
  1236. +}
  1237. +
  1238. +void avr_isp_worker_stop(AvrIspWorker* instance) {
  1239. + furi_assert(instance);
  1240. + furi_assert(instance->worker_running);
  1241. +
  1242. + instance->worker_running = false;
  1243. + furi_thread_flags_set(furi_thread_get_id(instance->thread), AvrIspWorkerEvtStop);
  1244. +
  1245. + furi_thread_join(instance->thread);
  1246. +}
  1247. +
  1248. +bool avr_isp_worker_is_running(AvrIspWorker* instance) {
  1249. + furi_assert(instance);
  1250. +
  1251. + return instance->worker_running;
  1252. +}
  1253. diff --git a/applications/external/avr_isp_programmer/helpers/avr_isp_worker.h b/applications/external/avr_isp_programmer/helpers/avr_isp_worker.h
  1254. new file mode 100644
  1255. index 000000000..cd9897dff
  1256. --- /dev/null
  1257. +++ b/applications/external/avr_isp_programmer/helpers/avr_isp_worker.h
  1258. @@ -0,0 +1,49 @@
  1259. +#pragma once
  1260. +
  1261. +#include <furi_hal.h>
  1262. +
  1263. +typedef struct AvrIspWorker AvrIspWorker;
  1264. +
  1265. +typedef void (*AvrIspWorkerCallback)(void* context, bool connect_usb);
  1266. +
  1267. +/** Allocate AvrIspWorker
  1268. + *
  1269. + * @param context AvrIsp* context
  1270. + * @return AvrIspWorker*
  1271. + */
  1272. +AvrIspWorker* avr_isp_worker_alloc(void* context);
  1273. +
  1274. +/** Free AvrIspWorker
  1275. + *
  1276. + * @param instance AvrIspWorker instance
  1277. + */
  1278. +void avr_isp_worker_free(AvrIspWorker* instance);
  1279. +
  1280. +/** Callback AvrIspWorker
  1281. + *
  1282. + * @param instance AvrIspWorker instance
  1283. + * @param callback AvrIspWorkerOverrunCallback callback
  1284. + * @param context
  1285. + */
  1286. +void avr_isp_worker_set_callback(
  1287. + AvrIspWorker* instance,
  1288. + AvrIspWorkerCallback callback,
  1289. + void* context);
  1290. +
  1291. +/** Start AvrIspWorker
  1292. + *
  1293. + * @param instance AvrIspWorker instance
  1294. + */
  1295. +void avr_isp_worker_start(AvrIspWorker* instance);
  1296. +
  1297. +/** Stop AvrIspWorker
  1298. + *
  1299. + * @param instance AvrIspWorker instance
  1300. + */
  1301. +void avr_isp_worker_stop(AvrIspWorker* instance);
  1302. +
  1303. +/** Check if worker is running
  1304. + * @param instance AvrIspWorker instance
  1305. + * @return bool - true if running
  1306. + */
  1307. +bool avr_isp_worker_is_running(AvrIspWorker* instance);
  1308. diff --git a/applications/external/avr_isp_programmer/helpers/avr_isp_worker_rw.c b/applications/external/avr_isp_programmer/helpers/avr_isp_worker_rw.c
  1309. new file mode 100644
  1310. index 000000000..fc8d3b09f
  1311. --- /dev/null
  1312. +++ b/applications/external/avr_isp_programmer/helpers/avr_isp_worker_rw.c
  1313. @@ -0,0 +1,1145 @@
  1314. +#include "avr_isp_worker_rw.h"
  1315. +#include <furi_hal_pwm.h>
  1316. +#include "avr_isp_types.h"
  1317. +#include "avr_isp.h"
  1318. +#include "../lib/driver/avr_isp_prog_cmd.h"
  1319. +#include "../lib/driver/avr_isp_chip_arr.h"
  1320. +
  1321. +#include "flipper_i32hex_file.h"
  1322. +#include <flipper_format/flipper_format.h>
  1323. +
  1324. +#include <furi.h>
  1325. +
  1326. +#define TAG "AvrIspWorkerRW"
  1327. +
  1328. +#define NAME_PATERN_FLASH_FILE "flash.hex"
  1329. +#define NAME_PATERN_EEPROM_FILE "eeprom.hex"
  1330. +
  1331. +struct AvrIspWorkerRW {
  1332. + AvrIsp* avr_isp;
  1333. + FuriThread* thread;
  1334. + volatile bool worker_running;
  1335. +
  1336. + uint32_t chip_arr_ind;
  1337. + bool chip_detect;
  1338. + uint8_t lfuse;
  1339. + uint8_t hfuse;
  1340. + uint8_t efuse;
  1341. + uint8_t lock;
  1342. + float progress_flash;
  1343. + float progress_eeprom;
  1344. + const char* file_path;
  1345. + const char* file_name;
  1346. + AvrIspSignature signature;
  1347. + AvrIspWorkerRWCallback callback;
  1348. + void* context;
  1349. +
  1350. + AvrIspWorkerRWStatusCallback callback_status;
  1351. + void* context_status;
  1352. +};
  1353. +
  1354. +typedef enum {
  1355. + AvrIspWorkerRWEvtStop = (1 << 0),
  1356. +
  1357. + AvrIspWorkerRWEvtReading = (1 << 1),
  1358. + AvrIspWorkerRWEvtVerification = (1 << 2),
  1359. + AvrIspWorkerRWEvtWriting = (1 << 3),
  1360. + AvrIspWorkerRWEvtWritingFuse = (1 << 4),
  1361. +
  1362. +} AvrIspWorkerRWEvt;
  1363. +#define AVR_ISP_WORKER_ALL_EVENTS \
  1364. + (AvrIspWorkerRWEvtWritingFuse | AvrIspWorkerRWEvtWriting | AvrIspWorkerRWEvtVerification | \
  1365. + AvrIspWorkerRWEvtReading | AvrIspWorkerRWEvtStop)
  1366. +
  1367. +/** Worker thread
  1368. + *
  1369. + * @param context
  1370. + * @return exit code
  1371. + */
  1372. +static int32_t avr_isp_worker_rw_thread(void* context) {
  1373. + AvrIspWorkerRW* instance = context;
  1374. +
  1375. + /* start PWM on &gpio_ext_pa4 */
  1376. + furi_hal_pwm_start(FuriHalPwmOutputIdLptim2PA4, 4000000, 50);
  1377. +
  1378. + FURI_LOG_D(TAG, "Start");
  1379. +
  1380. + while(1) {
  1381. + uint32_t events =
  1382. + furi_thread_flags_wait(AVR_ISP_WORKER_ALL_EVENTS, FuriFlagWaitAny, FuriWaitForever);
  1383. +
  1384. + if(events & AvrIspWorkerRWEvtStop) {
  1385. + break;
  1386. + }
  1387. +
  1388. + if(events & AvrIspWorkerRWEvtWritingFuse) {
  1389. + if(avr_isp_worker_rw_write_fuse(instance, instance->file_path, instance->file_name)) {
  1390. + if(instance->callback_status)
  1391. + instance->callback_status(
  1392. + instance->context_status, AvrIspWorkerRWStatusEndWritingFuse);
  1393. + } else {
  1394. + if(instance->callback_status)
  1395. + instance->callback_status(
  1396. + instance->context_status, AvrIspWorkerRWStatusErrorWritingFuse);
  1397. + }
  1398. + }
  1399. +
  1400. + if(events & AvrIspWorkerRWEvtWriting) {
  1401. + if(avr_isp_worker_rw_write_dump(instance, instance->file_path, instance->file_name)) {
  1402. + if(instance->callback_status)
  1403. + instance->callback_status(
  1404. + instance->context_status, AvrIspWorkerRWStatusEndWriting);
  1405. + } else {
  1406. + if(instance->callback_status)
  1407. + instance->callback_status(
  1408. + instance->context_status, AvrIspWorkerRWStatusErrorWriting);
  1409. + }
  1410. + }
  1411. +
  1412. + if(events & AvrIspWorkerRWEvtVerification) {
  1413. + if(avr_isp_worker_rw_verification(instance, instance->file_path, instance->file_name)) {
  1414. + if(instance->callback_status)
  1415. + instance->callback_status(
  1416. + instance->context_status, AvrIspWorkerRWStatusEndVerification);
  1417. + } else {
  1418. + if(instance->callback_status)
  1419. + instance->callback_status(
  1420. + instance->context_status, AvrIspWorkerRWStatusErrorVerification);
  1421. + }
  1422. + }
  1423. +
  1424. + if(events & AvrIspWorkerRWEvtReading) {
  1425. + if(avr_isp_worker_rw_read_dump(instance, instance->file_path, instance->file_name)) {
  1426. + if(instance->callback_status)
  1427. + instance->callback_status(
  1428. + instance->context_status, AvrIspWorkerRWStatusEndReading);
  1429. + } else {
  1430. + if(instance->callback_status)
  1431. + instance->callback_status(
  1432. + instance->context_status, AvrIspWorkerRWStatusErrorReading);
  1433. + }
  1434. + }
  1435. + }
  1436. + FURI_LOG_D(TAG, "Stop");
  1437. +
  1438. + furi_hal_pwm_stop(FuriHalPwmOutputIdLptim2PA4);
  1439. +
  1440. + return 0;
  1441. +}
  1442. +
  1443. +bool avr_isp_worker_rw_detect_chip(AvrIspWorkerRW* instance) {
  1444. + furi_assert(instance);
  1445. +
  1446. + FURI_LOG_D(TAG, "Detecting AVR chip");
  1447. +
  1448. + instance->chip_detect = false;
  1449. + instance->chip_arr_ind = avr_isp_chip_arr_size + 1;
  1450. +
  1451. + /* start PWM on &gpio_ext_pa4 */
  1452. + furi_hal_pwm_start(FuriHalPwmOutputIdLptim2PA4, 4000000, 50);
  1453. +
  1454. + do {
  1455. + if(!avr_isp_auto_set_spi_speed_start_pmode(instance->avr_isp)) {
  1456. + FURI_LOG_E(TAG, "Well, I managed to enter the mod program");
  1457. + break;
  1458. + }
  1459. + instance->signature = avr_isp_read_signature(instance->avr_isp);
  1460. +
  1461. + if(instance->signature.vendor != 0x1E) {
  1462. + //No detect chip
  1463. + } else {
  1464. + for(uint32_t ind = 0; ind < avr_isp_chip_arr_size; ind++) {
  1465. + if(avr_isp_chip_arr[ind].avrarch != F_AVR8) continue;
  1466. + if(avr_isp_chip_arr[ind].sigs[1] == instance->signature.part_family) {
  1467. + if(avr_isp_chip_arr[ind].sigs[2] == instance->signature.part_number) {
  1468. + FURI_LOG_D(TAG, "Detect AVR chip = \"%s\"", avr_isp_chip_arr[ind].name);
  1469. + FURI_LOG_D(
  1470. + TAG,
  1471. + "Signature = 0x%02X 0x%02X 0x%02X",
  1472. + instance->signature.vendor,
  1473. + instance->signature.part_family,
  1474. + instance->signature.part_number);
  1475. +
  1476. + switch(avr_isp_chip_arr[ind].nfuses) {
  1477. + case 1:
  1478. + instance->lfuse = avr_isp_read_fuse_low(instance->avr_isp);
  1479. + FURI_LOG_D(TAG, "Lfuse = %02X", instance->lfuse);
  1480. + break;
  1481. + case 2:
  1482. + instance->lfuse = avr_isp_read_fuse_low(instance->avr_isp);
  1483. + instance->hfuse = avr_isp_read_fuse_high(instance->avr_isp);
  1484. + FURI_LOG_D(
  1485. + TAG, "Lfuse = %02X Hfuse = %02X", instance->lfuse, instance->hfuse);
  1486. + break;
  1487. + case 3:
  1488. + instance->lfuse = avr_isp_read_fuse_low(instance->avr_isp);
  1489. + instance->hfuse = avr_isp_read_fuse_high(instance->avr_isp);
  1490. + instance->efuse = avr_isp_read_fuse_extended(instance->avr_isp);
  1491. + FURI_LOG_D(
  1492. + TAG,
  1493. + "Lfuse = %02X Hfuse = %02X Efuse = %02X",
  1494. + instance->lfuse,
  1495. + instance->hfuse,
  1496. + instance->efuse);
  1497. + break;
  1498. + default:
  1499. + break;
  1500. + }
  1501. + if(avr_isp_chip_arr[ind].nlocks == 1) {
  1502. + instance->lock = avr_isp_read_lock_byte(instance->avr_isp);
  1503. + FURI_LOG_D(TAG, "Lock = %02X", instance->lock);
  1504. + }
  1505. + instance->chip_detect = true;
  1506. + instance->chip_arr_ind = ind;
  1507. + break;
  1508. + }
  1509. + }
  1510. + }
  1511. + }
  1512. + avr_isp_end_pmode(instance->avr_isp);
  1513. +
  1514. + furi_hal_pwm_stop(FuriHalPwmOutputIdLptim2PA4);
  1515. +
  1516. + } while(0);
  1517. + if(instance->callback) {
  1518. + if(instance->chip_arr_ind > avr_isp_chip_arr_size) {
  1519. + instance->callback(instance->context, "No detect", instance->chip_detect, 0);
  1520. + } else if(instance->chip_arr_ind < avr_isp_chip_arr_size) {
  1521. + instance->callback(
  1522. + instance->context,
  1523. + avr_isp_chip_arr[instance->chip_arr_ind].name,
  1524. + instance->chip_detect,
  1525. + avr_isp_chip_arr[instance->chip_arr_ind].flashsize);
  1526. + } else {
  1527. + instance->callback(instance->context, "Unknown", instance->chip_detect, 0);
  1528. + }
  1529. + }
  1530. +
  1531. + return instance->chip_detect;
  1532. +}
  1533. +
  1534. +AvrIspWorkerRW* avr_isp_worker_rw_alloc(void* context) {
  1535. + furi_assert(context);
  1536. + UNUSED(context);
  1537. +
  1538. + AvrIspWorkerRW* instance = malloc(sizeof(AvrIspWorkerRW));
  1539. + instance->avr_isp = avr_isp_alloc();
  1540. +
  1541. + instance->thread =
  1542. + furi_thread_alloc_ex("AvrIspWorkerRW", 4096, avr_isp_worker_rw_thread, instance);
  1543. +
  1544. + instance->chip_detect = false;
  1545. + instance->lfuse = 0;
  1546. + instance->hfuse = 0;
  1547. + instance->efuse = 0;
  1548. + instance->lock = 0;
  1549. + instance->progress_flash = 0.0f;
  1550. + instance->progress_eeprom = 0.0f;
  1551. +
  1552. + return instance;
  1553. +}
  1554. +
  1555. +void avr_isp_worker_rw_free(AvrIspWorkerRW* instance) {
  1556. + furi_assert(instance);
  1557. +
  1558. + avr_isp_free(instance->avr_isp);
  1559. +
  1560. + furi_check(!instance->worker_running);
  1561. + furi_thread_free(instance->thread);
  1562. +
  1563. + free(instance);
  1564. +}
  1565. +
  1566. +void avr_isp_worker_rw_start(AvrIspWorkerRW* instance) {
  1567. + furi_assert(instance);
  1568. + furi_assert(!instance->worker_running);
  1569. +
  1570. + instance->worker_running = true;
  1571. +
  1572. + furi_thread_start(instance->thread);
  1573. +}
  1574. +
  1575. +void avr_isp_worker_rw_stop(AvrIspWorkerRW* instance) {
  1576. + furi_assert(instance);
  1577. + furi_assert(instance->worker_running);
  1578. +
  1579. + instance->worker_running = false;
  1580. + furi_thread_flags_set(furi_thread_get_id(instance->thread), AvrIspWorkerRWEvtStop);
  1581. +
  1582. + furi_thread_join(instance->thread);
  1583. +}
  1584. +
  1585. +bool avr_isp_worker_rw_is_running(AvrIspWorkerRW* instance) {
  1586. + furi_assert(instance);
  1587. +
  1588. + return instance->worker_running;
  1589. +}
  1590. +
  1591. +void avr_isp_worker_rw_set_callback(
  1592. + AvrIspWorkerRW* instance,
  1593. + AvrIspWorkerRWCallback callback,
  1594. + void* context) {
  1595. + furi_assert(instance);
  1596. +
  1597. + instance->callback = callback;
  1598. + instance->context = context;
  1599. +}
  1600. +
  1601. +void avr_isp_worker_rw_set_callback_status(
  1602. + AvrIspWorkerRW* instance,
  1603. + AvrIspWorkerRWStatusCallback callback_status,
  1604. + void* context_status) {
  1605. + furi_assert(instance);
  1606. +
  1607. + instance->callback_status = callback_status;
  1608. + instance->context_status = context_status;
  1609. +}
  1610. +
  1611. +float avr_isp_worker_rw_get_progress_flash(AvrIspWorkerRW* instance) {
  1612. + furi_assert(instance);
  1613. +
  1614. + return instance->progress_flash;
  1615. +}
  1616. +
  1617. +float avr_isp_worker_rw_get_progress_eeprom(AvrIspWorkerRW* instance) {
  1618. + furi_assert(instance);
  1619. +
  1620. + return instance->progress_eeprom;
  1621. +}
  1622. +
  1623. +static void avr_isp_worker_rw_get_dump_flash(AvrIspWorkerRW* instance, const char* file_path) {
  1624. + furi_assert(instance);
  1625. + furi_check(instance->avr_isp);
  1626. +
  1627. + FURI_LOG_D(TAG, "Dump FLASH %s", file_path);
  1628. +
  1629. + FlipperI32HexFile* flipper_hex_flash = flipper_i32hex_file_open_write(
  1630. + file_path, avr_isp_chip_arr[instance->chip_arr_ind].flashoffset);
  1631. +
  1632. + uint8_t data[272] = {0};
  1633. + bool send_extended_addr = ((avr_isp_chip_arr[instance->chip_arr_ind].flashsize / 2) > 0x10000);
  1634. + uint8_t extended_addr = 0;
  1635. +
  1636. + for(int32_t i = avr_isp_chip_arr[instance->chip_arr_ind].flashoffset;
  1637. + i < avr_isp_chip_arr[instance->chip_arr_ind].flashsize / 2;
  1638. + i += avr_isp_chip_arr[instance->chip_arr_ind].pagesize / 2) {
  1639. + if(send_extended_addr) {
  1640. + if(extended_addr <= ((i >> 16) & 0xFF)) {
  1641. + avr_isp_write_extended_addr(instance->avr_isp, extended_addr);
  1642. + extended_addr = ((i >> 16) & 0xFF) + 1;
  1643. + }
  1644. + }
  1645. + avr_isp_read_page(
  1646. + instance->avr_isp,
  1647. + STK_SET_FLASH_TYPE,
  1648. + (uint16_t)i,
  1649. + avr_isp_chip_arr[instance->chip_arr_ind].pagesize,
  1650. + data,
  1651. + sizeof(data));
  1652. + flipper_i32hex_file_bin_to_i32hex_set_data(
  1653. + flipper_hex_flash, data, avr_isp_chip_arr[instance->chip_arr_ind].pagesize);
  1654. + FURI_LOG_D(TAG, "%s", flipper_i32hex_file_get_string(flipper_hex_flash));
  1655. + instance->progress_flash =
  1656. + (float)(i) / ((float)avr_isp_chip_arr[instance->chip_arr_ind].flashsize / 2.0f);
  1657. + }
  1658. + flipper_i32hex_file_bin_to_i32hex_set_end_line(flipper_hex_flash);
  1659. + FURI_LOG_D(TAG, "%s", flipper_i32hex_file_get_string(flipper_hex_flash));
  1660. + flipper_i32hex_file_close(flipper_hex_flash);
  1661. + instance->progress_flash = 1.0f;
  1662. +}
  1663. +
  1664. +static void avr_isp_worker_rw_get_dump_eeprom(AvrIspWorkerRW* instance, const char* file_path) {
  1665. + furi_assert(instance);
  1666. + furi_check(instance->avr_isp);
  1667. +
  1668. + FURI_LOG_D(TAG, "Dump EEPROM %s", file_path);
  1669. +
  1670. + FlipperI32HexFile* flipper_hex_eeprom = flipper_i32hex_file_open_write(
  1671. + file_path, avr_isp_chip_arr[instance->chip_arr_ind].eepromoffset);
  1672. +
  1673. + int32_t size_data = 32;
  1674. + uint8_t data[256] = {0};
  1675. +
  1676. + if(size_data > avr_isp_chip_arr[instance->chip_arr_ind].eepromsize)
  1677. + size_data = avr_isp_chip_arr[instance->chip_arr_ind].eepromsize;
  1678. +
  1679. + for(int32_t i = avr_isp_chip_arr[instance->chip_arr_ind].eepromoffset;
  1680. + i < avr_isp_chip_arr[instance->chip_arr_ind].eepromsize;
  1681. + i += size_data) {
  1682. + avr_isp_read_page(
  1683. + instance->avr_isp, STK_SET_EEPROM_TYPE, (uint16_t)i, size_data, data, sizeof(data));
  1684. + flipper_i32hex_file_bin_to_i32hex_set_data(flipper_hex_eeprom, data, size_data);
  1685. + FURI_LOG_D(TAG, "%s", flipper_i32hex_file_get_string(flipper_hex_eeprom));
  1686. + instance->progress_eeprom =
  1687. + (float)(i) / ((float)avr_isp_chip_arr[instance->chip_arr_ind].eepromsize);
  1688. + }
  1689. + flipper_i32hex_file_bin_to_i32hex_set_end_line(flipper_hex_eeprom);
  1690. + FURI_LOG_D(TAG, "%s", flipper_i32hex_file_get_string(flipper_hex_eeprom));
  1691. + flipper_i32hex_file_close(flipper_hex_eeprom);
  1692. + instance->progress_eeprom = 1.0f;
  1693. +}
  1694. +
  1695. +bool avr_isp_worker_rw_read_dump(
  1696. + AvrIspWorkerRW* instance,
  1697. + const char* file_path,
  1698. + const char* file_name) {
  1699. + furi_assert(instance);
  1700. + furi_assert(file_path);
  1701. + furi_assert(file_name);
  1702. +
  1703. + FURI_LOG_D(TAG, "Read dump chip");
  1704. +
  1705. + instance->progress_flash = 0.0f;
  1706. + instance->progress_eeprom = 0.0f;
  1707. + bool ret = false;
  1708. + Storage* storage = furi_record_open(RECORD_STORAGE);
  1709. + FlipperFormat* flipper_format = flipper_format_file_alloc(storage);
  1710. + FuriString* file_path_name = furi_string_alloc();
  1711. +
  1712. + if(!avr_isp_worker_rw_detect_chip(instance)) {
  1713. + FURI_LOG_E(TAG, "No detect AVR chip");
  1714. + } else {
  1715. + do {
  1716. + furi_string_printf(
  1717. + file_path_name, "%s/%s%s", file_path, file_name, AVR_ISP_APP_EXTENSION);
  1718. + if(!flipper_format_file_open_always(
  1719. + flipper_format, furi_string_get_cstr(file_path_name))) {
  1720. + FURI_LOG_E(TAG, "flipper_format_file_open_always");
  1721. + break;
  1722. + }
  1723. + if(!flipper_format_write_header_cstr(
  1724. + flipper_format, AVR_ISP_APP_FILE_TYPE, AVR_ISP_APP_FILE_VERSION)) {
  1725. + FURI_LOG_E(TAG, "flipper_format_write_header_cstr");
  1726. + break;
  1727. + }
  1728. + if(!flipper_format_write_string_cstr(
  1729. + flipper_format, "Chip name", avr_isp_chip_arr[instance->chip_arr_ind].name)) {
  1730. + FURI_LOG_E(TAG, "Chip name");
  1731. + break;
  1732. + }
  1733. + if(!flipper_format_write_hex(
  1734. + flipper_format,
  1735. + "Signature",
  1736. + (uint8_t*)&instance->signature,
  1737. + sizeof(AvrIspSignature))) {
  1738. + FURI_LOG_E(TAG, "Unable to add Signature");
  1739. + break;
  1740. + }
  1741. + if(avr_isp_chip_arr[instance->chip_arr_ind].nfuses > 0) {
  1742. + if(!flipper_format_write_hex(flipper_format, "Lfuse", &instance->lfuse, 1)) {
  1743. + FURI_LOG_E(TAG, "Unable to add Lfuse");
  1744. + break;
  1745. + }
  1746. + }
  1747. + if(avr_isp_chip_arr[instance->chip_arr_ind].nfuses > 1) {
  1748. + if(!flipper_format_write_hex(flipper_format, "Hfuse", &instance->hfuse, 1)) {
  1749. + FURI_LOG_E(TAG, "Unable to add Hfuse");
  1750. + break;
  1751. + }
  1752. + }
  1753. + if(avr_isp_chip_arr[instance->chip_arr_ind].nfuses > 2) {
  1754. + if(!flipper_format_write_hex(flipper_format, "Efuse", &instance->efuse, 1)) {
  1755. + FURI_LOG_E(TAG, "Unable to add Efuse");
  1756. + break;
  1757. + }
  1758. + }
  1759. + if(avr_isp_chip_arr[instance->chip_arr_ind].nlocks == 1) {
  1760. + if(!flipper_format_write_hex(flipper_format, "Lock", &instance->lock, 1)) {
  1761. + FURI_LOG_E(TAG, "Unable to add Lock");
  1762. + break;
  1763. + }
  1764. + }
  1765. + furi_string_printf(file_path_name, "%s_%s", file_name, NAME_PATERN_FLASH_FILE);
  1766. + if(!flipper_format_write_string_cstr(
  1767. + flipper_format, "Dump_flash", furi_string_get_cstr(file_path_name))) {
  1768. + FURI_LOG_E(TAG, "Unable to add Dump_flash");
  1769. + break;
  1770. + }
  1771. +
  1772. + if(avr_isp_chip_arr[instance->chip_arr_ind].eepromsize > 0) {
  1773. + furi_string_printf(file_path_name, "%s_%s", file_name, NAME_PATERN_EEPROM_FILE);
  1774. + if(avr_isp_chip_arr[instance->chip_arr_ind].eepromsize > 0) {
  1775. + if(!flipper_format_write_string_cstr(
  1776. + flipper_format, "Dump_eeprom", furi_string_get_cstr(file_path_name))) {
  1777. + FURI_LOG_E(TAG, "Unable to add Dump_eeprom");
  1778. + break;
  1779. + }
  1780. + }
  1781. + }
  1782. + ret = true;
  1783. + } while(false);
  1784. + }
  1785. +
  1786. + flipper_format_free(flipper_format);
  1787. + furi_record_close(RECORD_STORAGE);
  1788. +
  1789. + if(ret) {
  1790. + if(avr_isp_auto_set_spi_speed_start_pmode(instance->avr_isp)) {
  1791. + //Dump flash
  1792. + furi_string_printf(
  1793. + file_path_name, "%s/%s_%s", file_path, file_name, NAME_PATERN_FLASH_FILE);
  1794. + avr_isp_worker_rw_get_dump_flash(instance, furi_string_get_cstr(file_path_name));
  1795. + //Dump eeprom
  1796. + if(avr_isp_chip_arr[instance->chip_arr_ind].eepromsize > 0) {
  1797. + furi_string_printf(
  1798. + file_path_name, "%s/%s_%s", file_path, file_name, NAME_PATERN_EEPROM_FILE);
  1799. + avr_isp_worker_rw_get_dump_eeprom(instance, furi_string_get_cstr(file_path_name));
  1800. + }
  1801. +
  1802. + avr_isp_end_pmode(instance->avr_isp);
  1803. + }
  1804. + }
  1805. +
  1806. + furi_string_free(file_path_name);
  1807. +
  1808. + return true;
  1809. +}
  1810. +
  1811. +void avr_isp_worker_rw_read_dump_start(
  1812. + AvrIspWorkerRW* instance,
  1813. + const char* file_path,
  1814. + const char* file_name) {
  1815. + furi_assert(instance);
  1816. +
  1817. + instance->file_path = file_path;
  1818. + instance->file_name = file_name;
  1819. + furi_thread_flags_set(furi_thread_get_id(instance->thread), AvrIspWorkerRWEvtReading);
  1820. +}
  1821. +
  1822. +static bool avr_isp_worker_rw_verification_flash(AvrIspWorkerRW* instance, const char* file_path) {
  1823. + furi_assert(instance);
  1824. + furi_assert(file_path);
  1825. +
  1826. + FURI_LOG_D(TAG, "Verification flash %s", file_path);
  1827. +
  1828. + instance->progress_flash = 0.0;
  1829. + bool ret = true;
  1830. +
  1831. + FlipperI32HexFile* flipper_hex_flash = flipper_i32hex_file_open_read(file_path);
  1832. +
  1833. + uint8_t data_read_flash[272] = {0};
  1834. + uint8_t data_read_hex[272] = {0};
  1835. +
  1836. + uint32_t addr = avr_isp_chip_arr[instance->chip_arr_ind].flashoffset;
  1837. + bool send_extended_addr = ((avr_isp_chip_arr[instance->chip_arr_ind].flashsize / 2) > 0x10000);
  1838. + uint8_t extended_addr = 0;
  1839. +
  1840. + FlipperI32HexFileRet flipper_hex_ret = flipper_i32hex_file_i32hex_to_bin_get_data(
  1841. + flipper_hex_flash, data_read_hex, sizeof(data_read_hex));
  1842. +
  1843. + while(((flipper_hex_ret.status == FlipperI32HexFileStatusData) ||
  1844. + (flipper_hex_ret.status == FlipperI32HexFileStatusUdateAddr)) &&
  1845. + ret) {
  1846. + switch(flipper_hex_ret.status) {
  1847. + case FlipperI32HexFileStatusData:
  1848. +
  1849. + if(send_extended_addr) {
  1850. + if(extended_addr <= ((addr >> 16) & 0xFF)) {
  1851. + avr_isp_write_extended_addr(instance->avr_isp, extended_addr);
  1852. + extended_addr = ((addr >> 16) & 0xFF) + 1;
  1853. + }
  1854. + }
  1855. +
  1856. + avr_isp_read_page(
  1857. + instance->avr_isp,
  1858. + STK_SET_FLASH_TYPE,
  1859. + (uint16_t)addr,
  1860. + flipper_hex_ret.data_size,
  1861. + data_read_flash,
  1862. + sizeof(data_read_flash));
  1863. +
  1864. + if(memcmp(data_read_hex, data_read_flash, flipper_hex_ret.data_size) != 0) {
  1865. + ret = false;
  1866. +
  1867. + FURI_LOG_E(TAG, "Verification flash error");
  1868. + FURI_LOG_E(TAG, "Addr: 0x%04lX", addr);
  1869. + for(uint32_t i = 0; i < flipper_hex_ret.data_size; i++) {
  1870. + FURI_LOG_RAW_E("%02X ", data_read_hex[i]);
  1871. + }
  1872. + FURI_LOG_RAW_E("\r\n");
  1873. + for(uint32_t i = 0; i < flipper_hex_ret.data_size; i++) {
  1874. + FURI_LOG_RAW_E("%02X ", data_read_flash[i]);
  1875. + }
  1876. + FURI_LOG_RAW_E("\r\n");
  1877. + }
  1878. +
  1879. + addr += flipper_hex_ret.data_size / 2;
  1880. + instance->progress_flash =
  1881. + (float)(addr) / ((float)avr_isp_chip_arr[instance->chip_arr_ind].flashsize / 2.0f);
  1882. + break;
  1883. +
  1884. + case FlipperI32HexFileStatusUdateAddr:
  1885. + addr = (data_read_hex[0] << 24 | data_read_hex[1] << 16) / 2;
  1886. + break;
  1887. +
  1888. + default:
  1889. + furi_crash(TAG " Incorrect status.");
  1890. + break;
  1891. + }
  1892. +
  1893. + flipper_hex_ret = flipper_i32hex_file_i32hex_to_bin_get_data(
  1894. + flipper_hex_flash, data_read_hex, sizeof(data_read_hex));
  1895. + }
  1896. +
  1897. + flipper_i32hex_file_close(flipper_hex_flash);
  1898. + instance->progress_flash = 1.0f;
  1899. +
  1900. + return ret;
  1901. +}
  1902. +
  1903. +static bool
  1904. + avr_isp_worker_rw_verification_eeprom(AvrIspWorkerRW* instance, const char* file_path) {
  1905. + furi_assert(instance);
  1906. + furi_assert(file_path);
  1907. +
  1908. + FURI_LOG_D(TAG, "Verification eeprom %s", file_path);
  1909. +
  1910. + instance->progress_eeprom = 0.0;
  1911. + bool ret = true;
  1912. +
  1913. + FlipperI32HexFile* flipper_hex_eeprom = flipper_i32hex_file_open_read(file_path);
  1914. +
  1915. + uint8_t data_read_eeprom[272] = {0};
  1916. + uint8_t data_read_hex[272] = {0};
  1917. +
  1918. + uint32_t addr = avr_isp_chip_arr[instance->chip_arr_ind].eepromoffset;
  1919. +
  1920. + FlipperI32HexFileRet flipper_hex_ret = flipper_i32hex_file_i32hex_to_bin_get_data(
  1921. + flipper_hex_eeprom, data_read_hex, sizeof(data_read_hex));
  1922. +
  1923. + while(((flipper_hex_ret.status == FlipperI32HexFileStatusData) ||
  1924. + (flipper_hex_ret.status == FlipperI32HexFileStatusUdateAddr)) &&
  1925. + ret) {
  1926. + switch(flipper_hex_ret.status) {
  1927. + case FlipperI32HexFileStatusData:
  1928. + avr_isp_read_page(
  1929. + instance->avr_isp,
  1930. + STK_SET_EEPROM_TYPE,
  1931. + (uint16_t)addr,
  1932. + flipper_hex_ret.data_size,
  1933. + data_read_eeprom,
  1934. + sizeof(data_read_eeprom));
  1935. +
  1936. + if(memcmp(data_read_hex, data_read_eeprom, flipper_hex_ret.data_size) != 0) {
  1937. + ret = false;
  1938. + FURI_LOG_E(TAG, "Verification eeprom error");
  1939. + FURI_LOG_E(TAG, "Addr: 0x%04lX", addr);
  1940. + for(uint32_t i = 0; i < flipper_hex_ret.data_size; i++) {
  1941. + FURI_LOG_RAW_E("%02X ", data_read_hex[i]);
  1942. + }
  1943. + FURI_LOG_RAW_E("\r\n");
  1944. + for(uint32_t i = 0; i < flipper_hex_ret.data_size; i++) {
  1945. + FURI_LOG_RAW_E("%02X ", data_read_eeprom[i]);
  1946. + }
  1947. + FURI_LOG_RAW_E("\r\n");
  1948. + }
  1949. +
  1950. + addr += flipper_hex_ret.data_size;
  1951. + instance->progress_eeprom =
  1952. + (float)(addr) / ((float)avr_isp_chip_arr[instance->chip_arr_ind].eepromsize);
  1953. + break;
  1954. +
  1955. + case FlipperI32HexFileStatusUdateAddr:
  1956. + addr = (data_read_hex[0] << 24 | data_read_hex[1] << 16);
  1957. + break;
  1958. +
  1959. + default:
  1960. + furi_crash(TAG " Incorrect status.");
  1961. + break;
  1962. + }
  1963. +
  1964. + flipper_hex_ret = flipper_i32hex_file_i32hex_to_bin_get_data(
  1965. + flipper_hex_eeprom, data_read_hex, sizeof(data_read_hex));
  1966. + }
  1967. +
  1968. + flipper_i32hex_file_close(flipper_hex_eeprom);
  1969. + instance->progress_eeprom = 1.0f;
  1970. +
  1971. + return ret;
  1972. +}
  1973. +
  1974. +bool avr_isp_worker_rw_verification(
  1975. + AvrIspWorkerRW* instance,
  1976. + const char* file_path,
  1977. + const char* file_name) {
  1978. + furi_assert(instance);
  1979. + furi_assert(file_path);
  1980. + furi_assert(file_name);
  1981. +
  1982. + FURI_LOG_D(TAG, "Verification chip");
  1983. +
  1984. + instance->progress_flash = 0.0f;
  1985. + instance->progress_eeprom = 0.0f;
  1986. + FuriString* file_path_name = furi_string_alloc();
  1987. +
  1988. + bool ret = false;
  1989. +
  1990. + if(avr_isp_auto_set_spi_speed_start_pmode(instance->avr_isp)) {
  1991. + do {
  1992. + furi_string_printf(
  1993. + file_path_name, "%s/%s_%s", file_path, file_name, NAME_PATERN_FLASH_FILE);
  1994. + if(!avr_isp_worker_rw_verification_flash(
  1995. + instance, furi_string_get_cstr(file_path_name)))
  1996. + break;
  1997. +
  1998. + if(avr_isp_chip_arr[instance->chip_arr_ind].eepromsize > 0) {
  1999. + furi_string_printf(
  2000. + file_path_name, "%s/%s_%s", file_path, file_name, NAME_PATERN_EEPROM_FILE);
  2001. +
  2002. + if(!avr_isp_worker_rw_verification_eeprom(
  2003. + instance, furi_string_get_cstr(file_path_name)))
  2004. + break;
  2005. + }
  2006. + ret = true;
  2007. + } while(false);
  2008. + avr_isp_end_pmode(instance->avr_isp);
  2009. + furi_string_free(file_path_name);
  2010. + }
  2011. + return ret;
  2012. +}
  2013. +
  2014. +void avr_isp_worker_rw_verification_start(
  2015. + AvrIspWorkerRW* instance,
  2016. + const char* file_path,
  2017. + const char* file_name) {
  2018. + furi_assert(instance);
  2019. +
  2020. + instance->file_path = file_path;
  2021. + instance->file_name = file_name;
  2022. + furi_thread_flags_set(furi_thread_get_id(instance->thread), AvrIspWorkerRWEvtVerification);
  2023. +}
  2024. +
  2025. +static void avr_isp_worker_rw_write_flash(AvrIspWorkerRW* instance, const char* file_path) {
  2026. + furi_assert(instance);
  2027. + furi_check(instance->avr_isp);
  2028. +
  2029. + instance->progress_flash = 0.0;
  2030. +
  2031. + FURI_LOG_D(TAG, "Write Flash %s", file_path);
  2032. +
  2033. + uint8_t data[288] = {0};
  2034. +
  2035. + FlipperI32HexFile* flipper_hex_flash = flipper_i32hex_file_open_read(file_path);
  2036. +
  2037. + uint32_t addr = avr_isp_chip_arr[instance->chip_arr_ind].flashoffset;
  2038. + bool send_extended_addr = ((avr_isp_chip_arr[instance->chip_arr_ind].flashsize / 2) > 0x10000);
  2039. + uint8_t extended_addr = 0;
  2040. +
  2041. + FlipperI32HexFileRet flipper_hex_ret =
  2042. + flipper_i32hex_file_i32hex_to_bin_get_data(flipper_hex_flash, data, sizeof(data));
  2043. +
  2044. + while((flipper_hex_ret.status == FlipperI32HexFileStatusData) ||
  2045. + (flipper_hex_ret.status == FlipperI32HexFileStatusUdateAddr)) {
  2046. + switch(flipper_hex_ret.status) {
  2047. + case FlipperI32HexFileStatusData:
  2048. +
  2049. + if(send_extended_addr) {
  2050. + if(extended_addr <= ((addr >> 16) & 0xFF)) {
  2051. + avr_isp_write_extended_addr(instance->avr_isp, extended_addr);
  2052. + extended_addr = ((addr >> 16) & 0xFF) + 1;
  2053. + }
  2054. + }
  2055. +
  2056. + if(!avr_isp_write_page(
  2057. + instance->avr_isp,
  2058. + STK_SET_FLASH_TYPE,
  2059. + avr_isp_chip_arr[instance->chip_arr_ind].flashsize,
  2060. + (uint16_t)addr,
  2061. + avr_isp_chip_arr[instance->chip_arr_ind].pagesize,
  2062. + data,
  2063. + flipper_hex_ret.data_size)) {
  2064. + break;
  2065. + }
  2066. + addr += flipper_hex_ret.data_size / 2;
  2067. + instance->progress_flash =
  2068. + (float)(addr) / ((float)avr_isp_chip_arr[instance->chip_arr_ind].flashsize / 2.0f);
  2069. + break;
  2070. +
  2071. + case FlipperI32HexFileStatusUdateAddr:
  2072. + addr = (data[0] << 24 | data[1] << 16) / 2;
  2073. + break;
  2074. +
  2075. + default:
  2076. + furi_crash(TAG " Incorrect status.");
  2077. + break;
  2078. + }
  2079. +
  2080. + flipper_hex_ret =
  2081. + flipper_i32hex_file_i32hex_to_bin_get_data(flipper_hex_flash, data, sizeof(data));
  2082. + }
  2083. +
  2084. + flipper_i32hex_file_close(flipper_hex_flash);
  2085. + instance->progress_flash = 1.0f;
  2086. +}
  2087. +
  2088. +static void avr_isp_worker_rw_write_eeprom(AvrIspWorkerRW* instance, const char* file_path) {
  2089. + furi_assert(instance);
  2090. + furi_check(instance->avr_isp);
  2091. +
  2092. + instance->progress_eeprom = 0.0;
  2093. + uint8_t data[288] = {0};
  2094. +
  2095. + FURI_LOG_D(TAG, "Write EEPROM %s", file_path);
  2096. +
  2097. + FlipperI32HexFile* flipper_hex_eeprom_read = flipper_i32hex_file_open_read(file_path);
  2098. +
  2099. + uint32_t addr = avr_isp_chip_arr[instance->chip_arr_ind].eepromoffset;
  2100. + FlipperI32HexFileRet flipper_hex_ret =
  2101. + flipper_i32hex_file_i32hex_to_bin_get_data(flipper_hex_eeprom_read, data, sizeof(data));
  2102. +
  2103. + while((flipper_hex_ret.status == FlipperI32HexFileStatusData) ||
  2104. + (flipper_hex_ret.status == FlipperI32HexFileStatusUdateAddr)) {
  2105. + switch(flipper_hex_ret.status) {
  2106. + case FlipperI32HexFileStatusData:
  2107. + if(!avr_isp_write_page(
  2108. + instance->avr_isp,
  2109. + STK_SET_EEPROM_TYPE,
  2110. + avr_isp_chip_arr[instance->chip_arr_ind].eepromsize,
  2111. + (uint16_t)addr,
  2112. + avr_isp_chip_arr[instance->chip_arr_ind].eeprompagesize,
  2113. + data,
  2114. + flipper_hex_ret.data_size)) {
  2115. + break;
  2116. + }
  2117. + addr += flipper_hex_ret.data_size;
  2118. + instance->progress_eeprom =
  2119. + (float)(addr) / ((float)avr_isp_chip_arr[instance->chip_arr_ind].eepromsize);
  2120. + break;
  2121. +
  2122. + case FlipperI32HexFileStatusUdateAddr:
  2123. + addr = data[0] << 24 | data[1] << 16;
  2124. + break;
  2125. +
  2126. + default:
  2127. + furi_crash(TAG " Incorrect status.");
  2128. + break;
  2129. + }
  2130. +
  2131. + flipper_hex_ret = flipper_i32hex_file_i32hex_to_bin_get_data(
  2132. + flipper_hex_eeprom_read, data, sizeof(data));
  2133. + }
  2134. +
  2135. + flipper_i32hex_file_close(flipper_hex_eeprom_read);
  2136. + instance->progress_eeprom = 1.0f;
  2137. +}
  2138. +
  2139. +bool avr_isp_worker_rw_write_dump(
  2140. + AvrIspWorkerRW* instance,
  2141. + const char* file_path,
  2142. + const char* file_name) {
  2143. + furi_assert(instance);
  2144. + furi_assert(file_path);
  2145. + furi_assert(file_name);
  2146. +
  2147. + FURI_LOG_D(TAG, "Write dump chip");
  2148. +
  2149. + instance->progress_flash = 0.0f;
  2150. + instance->progress_eeprom = 0.0f;
  2151. + bool ret = false;
  2152. +
  2153. + Storage* storage = furi_record_open(RECORD_STORAGE);
  2154. + FlipperFormat* flipper_format = flipper_format_file_alloc(storage);
  2155. + FuriString* file_path_name = furi_string_alloc();
  2156. +
  2157. + FuriString* temp_str_1 = furi_string_alloc();
  2158. + FuriString* temp_str_2 = furi_string_alloc();
  2159. + uint32_t temp_data32;
  2160. +
  2161. + if(!avr_isp_worker_rw_detect_chip(instance)) {
  2162. + FURI_LOG_E(TAG, "No detect AVR chip");
  2163. + } else {
  2164. + //upload file with description
  2165. + do {
  2166. + furi_string_printf(
  2167. + file_path_name, "%s/%s%s", file_path, file_name, AVR_ISP_APP_EXTENSION);
  2168. + if(!flipper_format_file_open_existing(
  2169. + flipper_format, furi_string_get_cstr(file_path_name))) {
  2170. + FURI_LOG_E(TAG, "Error open file %s", furi_string_get_cstr(file_path_name));
  2171. + break;
  2172. + }
  2173. +
  2174. + if(!flipper_format_read_header(flipper_format, temp_str_1, &temp_data32)) {
  2175. + FURI_LOG_E(TAG, "Missing or incorrect header");
  2176. + break;
  2177. + }
  2178. +
  2179. + if((!strcmp(furi_string_get_cstr(temp_str_1), AVR_ISP_APP_FILE_TYPE)) &&
  2180. + temp_data32 == AVR_ISP_APP_FILE_VERSION) {
  2181. + } else {
  2182. + FURI_LOG_E(TAG, "Type or version mismatch");
  2183. + break;
  2184. + }
  2185. +
  2186. + AvrIspSignature sig_read = {0};
  2187. +
  2188. + if(!flipper_format_read_hex(
  2189. + flipper_format, "Signature", (uint8_t*)&sig_read, sizeof(AvrIspSignature))) {
  2190. + FURI_LOG_E(TAG, "Missing Signature");
  2191. + break;
  2192. + }
  2193. +
  2194. + if(memcmp(
  2195. + (uint8_t*)&instance->signature, (uint8_t*)&sig_read, sizeof(AvrIspSignature)) !=
  2196. + 0) {
  2197. + FURI_LOG_E(
  2198. + TAG,
  2199. + "Wrong chip. Connected (%02X %02X %02X), read from file (%02X %02X %02X)",
  2200. + instance->signature.vendor,
  2201. + instance->signature.part_family,
  2202. + instance->signature.part_number,
  2203. + sig_read.vendor,
  2204. + sig_read.part_family,
  2205. + sig_read.part_number);
  2206. + break;
  2207. + }
  2208. +
  2209. + if(!flipper_format_read_string(flipper_format, "Dump_flash", temp_str_1)) {
  2210. + FURI_LOG_E(TAG, "Missing Dump_flash");
  2211. + break;
  2212. + }
  2213. +
  2214. + //may not be
  2215. + flipper_format_read_string(flipper_format, "Dump_eeprom", temp_str_2);
  2216. + ret = true;
  2217. + } while(false);
  2218. + }
  2219. + flipper_format_free(flipper_format);
  2220. + furi_record_close(RECORD_STORAGE);
  2221. +
  2222. + if(ret) {
  2223. + do {
  2224. + //checking .hex files for errors
  2225. +
  2226. + furi_string_printf(
  2227. + file_path_name, "%s/%s", file_path, furi_string_get_cstr(temp_str_1));
  2228. +
  2229. + FURI_LOG_D(TAG, "Check flash file");
  2230. + FlipperI32HexFile* flipper_hex_flash_read =
  2231. + flipper_i32hex_file_open_read(furi_string_get_cstr(file_path_name));
  2232. + if(flipper_i32hex_file_check(flipper_hex_flash_read)) {
  2233. + FURI_LOG_D(TAG, "Check flash file: OK");
  2234. + } else {
  2235. + FURI_LOG_E(TAG, "Check flash file: Error");
  2236. + ret = false;
  2237. + }
  2238. + flipper_i32hex_file_close(flipper_hex_flash_read);
  2239. +
  2240. + if(furi_string_size(temp_str_2) > 4) {
  2241. + furi_string_printf(
  2242. + file_path_name, "%s/%s", file_path, furi_string_get_cstr(temp_str_2));
  2243. +
  2244. + FURI_LOG_D(TAG, "Check eeprom file");
  2245. + FlipperI32HexFile* flipper_hex_eeprom_read =
  2246. + flipper_i32hex_file_open_read(furi_string_get_cstr(file_path_name));
  2247. + if(flipper_i32hex_file_check(flipper_hex_eeprom_read)) {
  2248. + FURI_LOG_D(TAG, "Check eeprom file: OK");
  2249. + } else {
  2250. + FURI_LOG_E(TAG, "Check eeprom file: Error");
  2251. + ret = false;
  2252. + }
  2253. + flipper_i32hex_file_close(flipper_hex_eeprom_read);
  2254. + }
  2255. +
  2256. + if(!ret) break;
  2257. + ret = false;
  2258. +
  2259. + //erase chip
  2260. + FURI_LOG_D(TAG, "Erase chip");
  2261. + if(!avr_isp_erase_chip(instance->avr_isp)) {
  2262. + FURI_LOG_E(TAG, "Erase chip: Error");
  2263. + break;
  2264. + }
  2265. +
  2266. + if(!avr_isp_auto_set_spi_speed_start_pmode(instance->avr_isp)) {
  2267. + FURI_LOG_E(TAG, "Well, I managed to enter the mod program");
  2268. + break;
  2269. + }
  2270. +
  2271. + //write flash
  2272. + furi_string_printf(
  2273. + file_path_name, "%s/%s", file_path, furi_string_get_cstr(temp_str_1));
  2274. + avr_isp_worker_rw_write_flash(instance, furi_string_get_cstr(file_path_name));
  2275. +
  2276. + //write eeprom
  2277. + if(furi_string_size(temp_str_2) > 4) {
  2278. + furi_string_printf(
  2279. + file_path_name, "%s/%s", file_path, furi_string_get_cstr(temp_str_2));
  2280. + avr_isp_worker_rw_write_eeprom(instance, furi_string_get_cstr(file_path_name));
  2281. + }
  2282. + ret = true;
  2283. + avr_isp_end_pmode(instance->avr_isp);
  2284. + } while(false);
  2285. + }
  2286. +
  2287. + furi_string_free(file_path_name);
  2288. + furi_string_free(temp_str_1);
  2289. + furi_string_free(temp_str_2);
  2290. +
  2291. + return ret;
  2292. +}
  2293. +
  2294. +void avr_isp_worker_rw_write_dump_start(
  2295. + AvrIspWorkerRW* instance,
  2296. + const char* file_path,
  2297. + const char* file_name) {
  2298. + furi_assert(instance);
  2299. +
  2300. + instance->file_path = file_path;
  2301. + instance->file_name = file_name;
  2302. + furi_thread_flags_set(furi_thread_get_id(instance->thread), AvrIspWorkerRWEvtWriting);
  2303. +}
  2304. +
  2305. +bool avr_isp_worker_rw_write_fuse(
  2306. + AvrIspWorkerRW* instance,
  2307. + const char* file_path,
  2308. + const char* file_name) {
  2309. + furi_assert(instance);
  2310. + furi_assert(file_path);
  2311. + furi_assert(file_name);
  2312. +
  2313. + FURI_LOG_D(TAG, "Write fuse chip");
  2314. +
  2315. + bool ret = false;
  2316. + uint8_t lfuse;
  2317. + uint8_t hfuse;
  2318. + uint8_t efuse;
  2319. + uint8_t lock;
  2320. +
  2321. + Storage* storage = furi_record_open(RECORD_STORAGE);
  2322. + FlipperFormat* flipper_format = flipper_format_file_alloc(storage);
  2323. + FuriString* temp_str = furi_string_alloc();
  2324. +
  2325. + uint32_t temp_data32;
  2326. +
  2327. + if(!avr_isp_worker_rw_detect_chip(instance)) {
  2328. + FURI_LOG_E(TAG, "No detect AVR chip");
  2329. + } else {
  2330. + //upload file with description
  2331. + do {
  2332. + furi_string_printf(temp_str, "%s/%s%s", file_path, file_name, AVR_ISP_APP_EXTENSION);
  2333. + if(!flipper_format_file_open_existing(flipper_format, furi_string_get_cstr(temp_str))) {
  2334. + FURI_LOG_E(TAG, "Error open file %s", furi_string_get_cstr(temp_str));
  2335. + break;
  2336. + }
  2337. +
  2338. + if(!flipper_format_read_header(flipper_format, temp_str, &temp_data32)) {
  2339. + FURI_LOG_E(TAG, "Missing or incorrect header");
  2340. + break;
  2341. + }
  2342. +
  2343. + if((!strcmp(furi_string_get_cstr(temp_str), AVR_ISP_APP_FILE_TYPE)) &&
  2344. + temp_data32 == AVR_ISP_APP_FILE_VERSION) {
  2345. + } else {
  2346. + FURI_LOG_E(TAG, "Type or version mismatch");
  2347. + break;
  2348. + }
  2349. +
  2350. + AvrIspSignature sig_read = {0};
  2351. +
  2352. + if(!flipper_format_read_hex(
  2353. + flipper_format, "Signature", (uint8_t*)&sig_read, sizeof(AvrIspSignature))) {
  2354. + FURI_LOG_E(TAG, "Missing Signature");
  2355. + break;
  2356. + }
  2357. +
  2358. + if(memcmp(
  2359. + (uint8_t*)&instance->signature, (uint8_t*)&sig_read, sizeof(AvrIspSignature)) !=
  2360. + 0) {
  2361. + FURI_LOG_E(
  2362. + TAG,
  2363. + "Wrong chip. Connected (%02X %02X %02X), read from file (%02X %02X %02X)",
  2364. + instance->signature.vendor,
  2365. + instance->signature.part_family,
  2366. + instance->signature.part_number,
  2367. + sig_read.vendor,
  2368. + sig_read.part_family,
  2369. + sig_read.part_number);
  2370. + break;
  2371. + }
  2372. +
  2373. + if(avr_isp_chip_arr[instance->chip_arr_ind].nfuses > 0) {
  2374. + if(!flipper_format_read_hex(flipper_format, "Lfuse", &lfuse, 1)) {
  2375. + FURI_LOG_E(TAG, "Missing Lfuse");
  2376. + break;
  2377. + }
  2378. + }
  2379. + if(avr_isp_chip_arr[instance->chip_arr_ind].nfuses > 1) {
  2380. + if(!flipper_format_read_hex(flipper_format, "Hfuse", &hfuse, 1)) {
  2381. + FURI_LOG_E(TAG, "Missing Hfuse");
  2382. + break;
  2383. + }
  2384. + }
  2385. + if(avr_isp_chip_arr[instance->chip_arr_ind].nfuses > 2) {
  2386. + if(!flipper_format_read_hex(flipper_format, "Efuse", &efuse, 1)) {
  2387. + FURI_LOG_E(TAG, "Missing Efuse");
  2388. + break;
  2389. + }
  2390. + }
  2391. + if(avr_isp_chip_arr[instance->chip_arr_ind].nlocks == 1) {
  2392. + if(!flipper_format_read_hex(flipper_format, "Lock", &lock, 1)) {
  2393. + FURI_LOG_E(TAG, "Missing Lock");
  2394. + break;
  2395. + }
  2396. + }
  2397. +
  2398. + if(!avr_isp_auto_set_spi_speed_start_pmode(instance->avr_isp)) {
  2399. + FURI_LOG_E(TAG, "Well, I managed to enter the mod program");
  2400. + break;
  2401. + }
  2402. +
  2403. + ret = true;
  2404. +
  2405. + if(avr_isp_chip_arr[instance->chip_arr_ind].nfuses > 0) {
  2406. + if(instance->lfuse != lfuse) {
  2407. + if(!avr_isp_write_fuse_low(instance->avr_isp, lfuse)) {
  2408. + FURI_LOG_E(TAG, "Write Lfuse: error");
  2409. + ret = false;
  2410. + }
  2411. + }
  2412. + }
  2413. + if(avr_isp_chip_arr[instance->chip_arr_ind].nfuses > 1) {
  2414. + if(instance->hfuse != hfuse) {
  2415. + if(!avr_isp_write_fuse_high(instance->avr_isp, hfuse)) {
  2416. + FURI_LOG_E(TAG, "Write Hfuse: error");
  2417. + ret = false;
  2418. + }
  2419. + }
  2420. + }
  2421. + if(avr_isp_chip_arr[instance->chip_arr_ind].nfuses > 2) {
  2422. + if(instance->efuse != efuse) {
  2423. + if(!avr_isp_write_fuse_extended(instance->avr_isp, efuse)) {
  2424. + FURI_LOG_E(TAG, "Write Efuse: error");
  2425. + ret = false;
  2426. + }
  2427. + }
  2428. + }
  2429. +
  2430. + if(avr_isp_chip_arr[instance->chip_arr_ind].nlocks == 1) {
  2431. + FURI_LOG_D(TAG, "Write lock byte");
  2432. + if(instance->lock != lock) {
  2433. + if(!avr_isp_write_lock_byte(instance->avr_isp, lock)) {
  2434. + FURI_LOG_E(TAG, "Write Lock byte: error");
  2435. + ret = false;
  2436. + }
  2437. + }
  2438. + }
  2439. + avr_isp_end_pmode(instance->avr_isp);
  2440. + } while(false);
  2441. + }
  2442. +
  2443. + flipper_format_free(flipper_format);
  2444. + furi_record_close(RECORD_STORAGE);
  2445. + furi_string_free(temp_str);
  2446. + return ret;
  2447. +}
  2448. +
  2449. +void avr_isp_worker_rw_write_fuse_start(
  2450. + AvrIspWorkerRW* instance,
  2451. + const char* file_path,
  2452. + const char* file_name) {
  2453. + furi_assert(instance);
  2454. +
  2455. + instance->file_path = file_path;
  2456. + instance->file_name = file_name;
  2457. + furi_thread_flags_set(furi_thread_get_id(instance->thread), AvrIspWorkerRWEvtWritingFuse);
  2458. +}
  2459. \ No newline at end of file
  2460. diff --git a/applications/external/avr_isp_programmer/helpers/avr_isp_worker_rw.h b/applications/external/avr_isp_programmer/helpers/avr_isp_worker_rw.h
  2461. new file mode 100644
  2462. index 000000000..2c52a8700
  2463. --- /dev/null
  2464. +++ b/applications/external/avr_isp_programmer/helpers/avr_isp_worker_rw.h
  2465. @@ -0,0 +1,99 @@
  2466. +#pragma once
  2467. +
  2468. +#include <furi_hal.h>
  2469. +
  2470. +typedef struct AvrIspWorkerRW AvrIspWorkerRW;
  2471. +
  2472. +typedef void (*AvrIspWorkerRWCallback)(
  2473. + void* context,
  2474. + const char* name,
  2475. + bool detect_chip,
  2476. + uint32_t flash_size);
  2477. +
  2478. +typedef enum {
  2479. + AvrIspWorkerRWStatusILDE = 0,
  2480. + AvrIspWorkerRWStatusEndReading = 1,
  2481. + AvrIspWorkerRWStatusEndVerification = 2,
  2482. + AvrIspWorkerRWStatusEndWriting = 3,
  2483. + AvrIspWorkerRWStatusEndWritingFuse = 4,
  2484. +
  2485. + AvrIspWorkerRWStatusErrorReading = (-1),
  2486. + AvrIspWorkerRWStatusErrorVerification = (-2),
  2487. + AvrIspWorkerRWStatusErrorWriting = (-3),
  2488. + AvrIspWorkerRWStatusErrorWritingFuse = (-4),
  2489. +
  2490. + AvrIspWorkerRWStatusReserved = 0x7FFFFFFF, ///< Prevents enum down-size compiler optimization.
  2491. +} AvrIspWorkerRWStatus;
  2492. +
  2493. +typedef void (*AvrIspWorkerRWStatusCallback)(void* context, AvrIspWorkerRWStatus status);
  2494. +
  2495. +AvrIspWorkerRW* avr_isp_worker_rw_alloc(void* context);
  2496. +
  2497. +void avr_isp_worker_rw_free(AvrIspWorkerRW* instance);
  2498. +
  2499. +void avr_isp_worker_rw_start(AvrIspWorkerRW* instance);
  2500. +
  2501. +void avr_isp_worker_rw_stop(AvrIspWorkerRW* instance);
  2502. +
  2503. +bool avr_isp_worker_rw_is_running(AvrIspWorkerRW* instance);
  2504. +
  2505. +void avr_isp_worker_rw_set_callback(
  2506. + AvrIspWorkerRW* instance,
  2507. + AvrIspWorkerRWCallback callback,
  2508. + void* context);
  2509. +
  2510. +void avr_isp_worker_rw_set_callback_status(
  2511. + AvrIspWorkerRW* instance,
  2512. + AvrIspWorkerRWStatusCallback callback_status,
  2513. + void* context_status);
  2514. +
  2515. +bool avr_isp_worker_rw_detect_chip(AvrIspWorkerRW* instance);
  2516. +
  2517. +float avr_isp_worker_rw_get_progress_flash(AvrIspWorkerRW* instance);
  2518. +
  2519. +float avr_isp_worker_rw_get_progress_eeprom(AvrIspWorkerRW* instance);
  2520. +
  2521. +bool avr_isp_worker_rw_read_dump(
  2522. + AvrIspWorkerRW* instance,
  2523. + const char* file_path,
  2524. + const char* file_name);
  2525. +
  2526. +void avr_isp_worker_rw_read_dump_start(
  2527. + AvrIspWorkerRW* instance,
  2528. + const char* file_path,
  2529. + const char* file_name);
  2530. +
  2531. +bool avr_isp_worker_rw_verification(
  2532. + AvrIspWorkerRW* instance,
  2533. + const char* file_path,
  2534. + const char* file_name);
  2535. +
  2536. +void avr_isp_worker_rw_verification_start(
  2537. + AvrIspWorkerRW* instance,
  2538. + const char* file_path,
  2539. + const char* file_name);
  2540. +
  2541. +bool avr_isp_worker_rw_check_hex(
  2542. + AvrIspWorkerRW* instance,
  2543. + const char* file_path,
  2544. + const char* file_name);
  2545. +
  2546. +bool avr_isp_worker_rw_write_dump(
  2547. + AvrIspWorkerRW* instance,
  2548. + const char* file_path,
  2549. + const char* file_name);
  2550. +
  2551. +void avr_isp_worker_rw_write_dump_start(
  2552. + AvrIspWorkerRW* instance,
  2553. + const char* file_path,
  2554. + const char* file_name);
  2555. +
  2556. +bool avr_isp_worker_rw_write_fuse(
  2557. + AvrIspWorkerRW* instance,
  2558. + const char* file_path,
  2559. + const char* file_name);
  2560. +
  2561. +void avr_isp_worker_rw_write_fuse_start(
  2562. + AvrIspWorkerRW* instance,
  2563. + const char* file_path,
  2564. + const char* file_name);
  2565. \ No newline at end of file
  2566. diff --git a/applications/external/avr_isp_programmer/helpers/flipper_i32hex_file.c b/applications/external/avr_isp_programmer/helpers/flipper_i32hex_file.c
  2567. new file mode 100644
  2568. index 000000000..a8c20a0bd
  2569. --- /dev/null
  2570. +++ b/applications/external/avr_isp_programmer/helpers/flipper_i32hex_file.c
  2571. @@ -0,0 +1,321 @@
  2572. +#include "flipper_i32hex_file.h"
  2573. +#include <string.h>
  2574. +#include <storage/storage.h>
  2575. +#include <toolbox/stream/stream.h>
  2576. +#include <toolbox/stream/file_stream.h>
  2577. +#include <toolbox/hex.h>
  2578. +
  2579. +//https://en.wikipedia.org/wiki/Intel_HEX
  2580. +
  2581. +#define TAG "FlipperI32HexFile"
  2582. +
  2583. +#define COUNT_BYTE_PAYLOAD 32 //how much payload will be used
  2584. +
  2585. +#define I32HEX_TYPE_DATA 0x00
  2586. +#define I32HEX_TYPE_END_OF_FILE 0x01
  2587. +#define I32HEX_TYPE_EXT_LINEAR_ADDR 0x04
  2588. +#define I32HEX_TYPE_START_LINEAR_ADDR 0x05
  2589. +
  2590. +struct FlipperI32HexFile {
  2591. + uint32_t addr;
  2592. + uint32_t addr_last;
  2593. + Storage* storage;
  2594. + Stream* stream;
  2595. + FuriString* str_data;
  2596. + FlipperI32HexFileStatus file_open;
  2597. +};
  2598. +
  2599. +FlipperI32HexFile* flipper_i32hex_file_open_write(const char* name, uint32_t start_addr) {
  2600. + furi_assert(name);
  2601. +
  2602. + FlipperI32HexFile* instance = malloc(sizeof(FlipperI32HexFile));
  2603. + instance->addr = start_addr;
  2604. + instance->addr_last = 0;
  2605. + instance->storage = furi_record_open(RECORD_STORAGE);
  2606. + instance->stream = file_stream_alloc(instance->storage);
  2607. +
  2608. + if(file_stream_open(instance->stream, name, FSAM_WRITE, FSOM_CREATE_ALWAYS)) {
  2609. + instance->file_open = FlipperI32HexFileStatusOpenFileWrite;
  2610. + FURI_LOG_D(TAG, "Open write file %s", name);
  2611. + } else {
  2612. + FURI_LOG_E(TAG, "Failed to open file %s", name);
  2613. + instance->file_open = FlipperI32HexFileStatusErrorNoOpenFile;
  2614. + }
  2615. + instance->str_data = furi_string_alloc(instance->storage);
  2616. +
  2617. + return instance;
  2618. +}
  2619. +
  2620. +FlipperI32HexFile* flipper_i32hex_file_open_read(const char* name) {
  2621. + furi_assert(name);
  2622. +
  2623. + FlipperI32HexFile* instance = malloc(sizeof(FlipperI32HexFile));
  2624. + instance->addr = 0;
  2625. + instance->addr_last = 0;
  2626. + instance->storage = furi_record_open(RECORD_STORAGE);
  2627. + instance->stream = file_stream_alloc(instance->storage);
  2628. +
  2629. + if(file_stream_open(instance->stream, name, FSAM_READ, FSOM_OPEN_EXISTING)) {
  2630. + instance->file_open = FlipperI32HexFileStatusOpenFileRead;
  2631. + FURI_LOG_D(TAG, "Open read file %s", name);
  2632. + } else {
  2633. + FURI_LOG_E(TAG, "Failed to open file %s", name);
  2634. + instance->file_open = FlipperI32HexFileStatusErrorNoOpenFile;
  2635. + }
  2636. + instance->str_data = furi_string_alloc(instance->storage);
  2637. +
  2638. + return instance;
  2639. +}
  2640. +
  2641. +void flipper_i32hex_file_close(FlipperI32HexFile* instance) {
  2642. + furi_assert(instance);
  2643. +
  2644. + furi_string_free(instance->str_data);
  2645. + file_stream_close(instance->stream);
  2646. + stream_free(instance->stream);
  2647. + furi_record_close(RECORD_STORAGE);
  2648. +}
  2649. +
  2650. +FlipperI32HexFileRet flipper_i32hex_file_bin_to_i32hex_set_data(
  2651. + FlipperI32HexFile* instance,
  2652. + uint8_t* data,
  2653. + uint32_t data_size) {
  2654. + furi_assert(instance);
  2655. + furi_assert(data);
  2656. +
  2657. + FlipperI32HexFileRet ret = {.status = FlipperI32HexFileStatusOK, .data_size = 0};
  2658. + if(instance->file_open != FlipperI32HexFileStatusOpenFileWrite) {
  2659. + ret.status = FlipperI32HexFileStatusErrorFileWrite;
  2660. + }
  2661. + uint8_t count_byte = 0;
  2662. + uint32_t ind = 0;
  2663. + uint8_t crc = 0;
  2664. +
  2665. + furi_string_reset(instance->str_data);
  2666. +
  2667. + if((instance->addr_last & 0xFF0000) < (instance->addr & 0xFF0000)) {
  2668. + crc = 0x02 + 0x04 + ((instance->addr >> 24) & 0xFF) + ((instance->addr >> 16) & 0xFF);
  2669. + crc = 0x01 + ~crc;
  2670. + //I32HEX_TYPE_EXT_LINEAR_ADDR
  2671. + furi_string_cat_printf(
  2672. + instance->str_data, ":02000004%04lX%02X\r\n", (instance->addr >> 16), crc);
  2673. + instance->addr_last = instance->addr;
  2674. + }
  2675. +
  2676. + while(ind < data_size) {
  2677. + if((ind + COUNT_BYTE_PAYLOAD) > data_size) {
  2678. + count_byte = data_size - ind;
  2679. + } else {
  2680. + count_byte = COUNT_BYTE_PAYLOAD;
  2681. + }
  2682. + //I32HEX_TYPE_DATA
  2683. + furi_string_cat_printf(
  2684. + instance->str_data, ":%02X%04lX00", count_byte, (instance->addr & 0xFFFF));
  2685. + crc = count_byte + ((instance->addr >> 8) & 0xFF) + (instance->addr & 0xFF);
  2686. +
  2687. + for(uint32_t i = 0; i < count_byte; i++) {
  2688. + furi_string_cat_printf(instance->str_data, "%02X", *data);
  2689. + crc += *data++;
  2690. + }
  2691. + crc = 0x01 + ~crc;
  2692. + furi_string_cat_printf(instance->str_data, "%02X\r\n", crc);
  2693. +
  2694. + ind += count_byte;
  2695. + instance->addr += count_byte;
  2696. + }
  2697. + if(instance->file_open) stream_write_string(instance->stream, instance->str_data);
  2698. + return ret;
  2699. +}
  2700. +
  2701. +FlipperI32HexFileRet flipper_i32hex_file_bin_to_i32hex_set_end_line(FlipperI32HexFile* instance) {
  2702. + furi_assert(instance);
  2703. +
  2704. + FlipperI32HexFileRet ret = {.status = FlipperI32HexFileStatusOK, .data_size = 0};
  2705. + if(instance->file_open != FlipperI32HexFileStatusOpenFileWrite) {
  2706. + ret.status = FlipperI32HexFileStatusErrorFileWrite;
  2707. + }
  2708. + furi_string_reset(instance->str_data);
  2709. + //I32HEX_TYPE_END_OF_FILE
  2710. + furi_string_cat_printf(instance->str_data, ":00000001FF\r\n");
  2711. + if(instance->file_open) stream_write_string(instance->stream, instance->str_data);
  2712. + return ret;
  2713. +}
  2714. +
  2715. +void flipper_i32hex_file_bin_to_i32hex_set_addr(FlipperI32HexFile* instance, uint32_t addr) {
  2716. + furi_assert(instance);
  2717. +
  2718. + instance->addr = addr;
  2719. +}
  2720. +
  2721. +const char* flipper_i32hex_file_get_string(FlipperI32HexFile* instance) {
  2722. + furi_assert(instance);
  2723. +
  2724. + return furi_string_get_cstr(instance->str_data);
  2725. +}
  2726. +
  2727. +static FlipperI32HexFileRet flipper_i32hex_file_parse_line(
  2728. + FlipperI32HexFile* instance,
  2729. + const char* str,
  2730. + uint8_t* data,
  2731. + uint32_t data_size) {
  2732. + furi_assert(instance);
  2733. + furi_assert(data);
  2734. +
  2735. + char* str1;
  2736. + uint32_t data_wrire_ind = 0;
  2737. + uint32_t data_len = 0;
  2738. + FlipperI32HexFileRet ret = {.status = FlipperI32HexFileStatusErrorData, .data_size = 0};
  2739. +
  2740. + //Search for start of data I32HEX
  2741. + str1 = strstr(str, ":");
  2742. + do {
  2743. + if(str1 == NULL) {
  2744. + ret.status = FlipperI32HexFileStatusErrorData;
  2745. + break;
  2746. + }
  2747. + str1++;
  2748. + if(!hex_char_to_uint8(*str1, str1[1], data + data_wrire_ind)) {
  2749. + ret.status = FlipperI32HexFileStatusErrorData;
  2750. + break;
  2751. + }
  2752. + str1++;
  2753. + if(++data_wrire_ind > data_size) {
  2754. + ret.status = FlipperI32HexFileStatusErrorOverflow;
  2755. + break;
  2756. + }
  2757. + data_len = 5 + data[0]; // +5 bytes per header and crc
  2758. + while(data_len > data_wrire_ind) {
  2759. + str1++;
  2760. + if(!hex_char_to_uint8(*str1, str1[1], data + data_wrire_ind)) {
  2761. + ret.status = FlipperI32HexFileStatusErrorData;
  2762. + break;
  2763. + }
  2764. + str1++;
  2765. + if(++data_wrire_ind > data_size) {
  2766. + ret.status = FlipperI32HexFileStatusErrorOverflow;
  2767. + break;
  2768. + }
  2769. + }
  2770. + ret.status = FlipperI32HexFileStatusOK;
  2771. + ret.data_size = data_wrire_ind;
  2772. +
  2773. + } while(0);
  2774. + return ret;
  2775. +}
  2776. +
  2777. +static bool flipper_i32hex_file_check_data(uint8_t* data, uint32_t data_size) {
  2778. + furi_assert(data);
  2779. +
  2780. + uint8_t crc = 0;
  2781. + uint32_t data_read_ind = 0;
  2782. + if(data[0] > data_size) return false;
  2783. + while(data_read_ind < data_size - 1) {
  2784. + crc += data[data_read_ind++];
  2785. + }
  2786. + return data[data_size - 1] == ((1 + ~crc) & 0xFF);
  2787. +}
  2788. +
  2789. +static FlipperI32HexFileRet flipper_i32hex_file_parse(
  2790. + FlipperI32HexFile* instance,
  2791. + const char* str,
  2792. + uint8_t* data,
  2793. + uint32_t data_size) {
  2794. + furi_assert(instance);
  2795. + furi_assert(data);
  2796. +
  2797. + FlipperI32HexFileRet ret = flipper_i32hex_file_parse_line(instance, str, data, data_size);
  2798. +
  2799. + if((ret.status == FlipperI32HexFileStatusOK) && (ret.data_size > 4)) {
  2800. + switch(data[3]) {
  2801. + case I32HEX_TYPE_DATA:
  2802. + if(flipper_i32hex_file_check_data(data, ret.data_size)) {
  2803. + ret.data_size -= 5;
  2804. + memcpy(data, data + 4, ret.data_size);
  2805. + ret.status = FlipperI32HexFileStatusData;
  2806. + } else {
  2807. + ret.status = FlipperI32HexFileStatusErrorCrc;
  2808. + ret.data_size = 0;
  2809. + }
  2810. + break;
  2811. + case I32HEX_TYPE_END_OF_FILE:
  2812. + if(flipper_i32hex_file_check_data(data, ret.data_size)) {
  2813. + ret.status = FlipperI32HexFileStatusEofFile;
  2814. + ret.data_size = 0;
  2815. + } else {
  2816. + ret.status = FlipperI32HexFileStatusErrorCrc;
  2817. + ret.data_size = 0;
  2818. + }
  2819. + break;
  2820. + case I32HEX_TYPE_EXT_LINEAR_ADDR:
  2821. + if(flipper_i32hex_file_check_data(data, ret.data_size)) {
  2822. + data[0] = data[4];
  2823. + data[1] = data[5];
  2824. + data[3] = 0;
  2825. + data[4] = 0;
  2826. + ret.status = FlipperI32HexFileStatusUdateAddr;
  2827. + ret.data_size = 4;
  2828. + } else {
  2829. + ret.status = FlipperI32HexFileStatusErrorCrc;
  2830. + ret.data_size = 0;
  2831. + }
  2832. + break;
  2833. + case I32HEX_TYPE_START_LINEAR_ADDR:
  2834. + ret.status = FlipperI32HexFileStatusErrorUnsupportedCommand;
  2835. + ret.data_size = 0;
  2836. + break;
  2837. + default:
  2838. + ret.status = FlipperI32HexFileStatusErrorUnsupportedCommand;
  2839. + ret.data_size = 0;
  2840. + break;
  2841. + }
  2842. + } else {
  2843. + ret.status = FlipperI32HexFileStatusErrorData;
  2844. + ret.data_size = 0;
  2845. + }
  2846. + return ret;
  2847. +}
  2848. +
  2849. +bool flipper_i32hex_file_check(FlipperI32HexFile* instance) {
  2850. + furi_assert(instance);
  2851. +
  2852. + uint32_t data_size = 280;
  2853. + uint8_t data[280] = {0};
  2854. + bool ret = true;
  2855. +
  2856. + if(instance->file_open != FlipperI32HexFileStatusOpenFileRead) {
  2857. + FURI_LOG_E(TAG, "File is not open");
  2858. + ret = false;
  2859. + } else {
  2860. + stream_rewind(instance->stream);
  2861. +
  2862. + while(stream_read_line(instance->stream, instance->str_data)) {
  2863. + FlipperI32HexFileRet parse_ret = flipper_i32hex_file_parse(
  2864. + instance, furi_string_get_cstr(instance->str_data), data, data_size);
  2865. +
  2866. + if(parse_ret.status < 0) {
  2867. + ret = false;
  2868. + }
  2869. + }
  2870. + stream_rewind(instance->stream);
  2871. + }
  2872. + return ret;
  2873. +}
  2874. +
  2875. +FlipperI32HexFileRet flipper_i32hex_file_i32hex_to_bin_get_data(
  2876. + FlipperI32HexFile* instance,
  2877. + uint8_t* data,
  2878. + uint32_t data_size) {
  2879. + furi_assert(instance);
  2880. + furi_assert(data);
  2881. +
  2882. + FlipperI32HexFileRet ret = {.status = FlipperI32HexFileStatusOK, .data_size = 0};
  2883. + if(instance->file_open != FlipperI32HexFileStatusOpenFileRead) {
  2884. + ret.status = FlipperI32HexFileStatusErrorFileRead;
  2885. + } else {
  2886. + stream_read_line(instance->stream, instance->str_data);
  2887. + ret = flipper_i32hex_file_parse(
  2888. + instance, furi_string_get_cstr(instance->str_data), data, data_size);
  2889. + }
  2890. +
  2891. + return ret;
  2892. +}
  2893. \ No newline at end of file
  2894. diff --git a/applications/external/avr_isp_programmer/helpers/flipper_i32hex_file.h b/applications/external/avr_isp_programmer/helpers/flipper_i32hex_file.h
  2895. new file mode 100644
  2896. index 000000000..765b94beb
  2897. --- /dev/null
  2898. +++ b/applications/external/avr_isp_programmer/helpers/flipper_i32hex_file.h
  2899. @@ -0,0 +1,55 @@
  2900. +#pragma once
  2901. +
  2902. +#include <furi_hal.h>
  2903. +
  2904. +typedef struct FlipperI32HexFile FlipperI32HexFile;
  2905. +
  2906. +typedef enum {
  2907. + FlipperI32HexFileStatusOK = 0,
  2908. + FlipperI32HexFileStatusData = 2,
  2909. + FlipperI32HexFileStatusUdateAddr = 3,
  2910. + FlipperI32HexFileStatusEofFile = 4,
  2911. + FlipperI32HexFileStatusOpenFileWrite = 5,
  2912. + FlipperI32HexFileStatusOpenFileRead = 6,
  2913. +
  2914. + // Errors
  2915. + FlipperI32HexFileStatusErrorCrc = (-1),
  2916. + FlipperI32HexFileStatusErrorOverflow = (-2),
  2917. + FlipperI32HexFileStatusErrorData = (-3),
  2918. + FlipperI32HexFileStatusErrorUnsupportedCommand = (-4),
  2919. + FlipperI32HexFileStatusErrorNoOpenFile = (-5),
  2920. + FlipperI32HexFileStatusErrorFileWrite = (-6),
  2921. + FlipperI32HexFileStatusErrorFileRead = (-7),
  2922. +
  2923. + FlipperI32HexFileStatusReserved =
  2924. + 0x7FFFFFFF, ///< Prevents enum down-size compiler optimization.
  2925. +} FlipperI32HexFileStatus;
  2926. +
  2927. +typedef struct {
  2928. + FlipperI32HexFileStatus status;
  2929. + uint32_t data_size;
  2930. +} FlipperI32HexFileRet;
  2931. +
  2932. +FlipperI32HexFile* flipper_i32hex_file_open_write(const char* name, uint32_t start_addr);
  2933. +
  2934. +FlipperI32HexFile* flipper_i32hex_file_open_read(const char* name);
  2935. +
  2936. +void flipper_i32hex_file_close(FlipperI32HexFile* instance);
  2937. +
  2938. +FlipperI32HexFileRet flipper_i32hex_file_bin_to_i32hex_set_data(
  2939. + FlipperI32HexFile* instance,
  2940. + uint8_t* data,
  2941. + uint32_t data_size);
  2942. +
  2943. +FlipperI32HexFileRet flipper_i32hex_file_bin_to_i32hex_set_end_line(FlipperI32HexFile* instance);
  2944. +
  2945. +const char* flipper_i32hex_file_get_string(FlipperI32HexFile* instance);
  2946. +
  2947. +void flipper_i32hex_file_bin_to_i32hex_set_addr(FlipperI32HexFile* instance, uint32_t addr);
  2948. +
  2949. +bool flipper_i32hex_file_check(FlipperI32HexFile* instance);
  2950. +
  2951. +FlipperI32HexFileRet flipper_i32hex_file_i32hex_to_bin_get_data(
  2952. + FlipperI32HexFile* instance,
  2953. + uint8_t* data,
  2954. + uint32_t data_size);
  2955. \ No newline at end of file
  2956. diff --git a/applications/external/avr_isp_programmer/images/avr_app_icon_10x10.png b/applications/external/avr_isp_programmer/images/avr_app_icon_10x10.png
  2957. new file mode 100644
  2958. index 000000000..533787fe3
  2959. Binary files /dev/null and b/applications/external/avr_isp_programmer/images/avr_app_icon_10x10.png differ
  2960. diff --git a/applications/external/avr_isp_programmer/images/avr_wiring.png b/applications/external/avr_isp_programmer/images/avr_wiring.png
  2961. new file mode 100644
  2962. index 000000000..957012405
  2963. Binary files /dev/null and b/applications/external/avr_isp_programmer/images/avr_wiring.png differ
  2964. diff --git a/applications/external/avr_isp_programmer/images/chif_not_found_83x37.png b/applications/external/avr_isp_programmer/images/chif_not_found_83x37.png
  2965. new file mode 100644
  2966. index 000000000..b03bf3567
  2967. Binary files /dev/null and b/applications/external/avr_isp_programmer/images/chif_not_found_83x37.png differ
  2968. diff --git a/applications/external/avr_isp_programmer/images/chip_error_70x22.png b/applications/external/avr_isp_programmer/images/chip_error_70x22.png
  2969. new file mode 100644
  2970. index 000000000..16f81178c
  2971. Binary files /dev/null and b/applications/external/avr_isp_programmer/images/chip_error_70x22.png differ
  2972. diff --git a/applications/external/avr_isp_programmer/images/chip_long_70x22.png b/applications/external/avr_isp_programmer/images/chip_long_70x22.png
  2973. new file mode 100644
  2974. index 000000000..3edfff82d
  2975. Binary files /dev/null and b/applications/external/avr_isp_programmer/images/chip_long_70x22.png differ
  2976. diff --git a/applications/external/avr_isp_programmer/images/chip_not_found_83x37.png b/applications/external/avr_isp_programmer/images/chip_not_found_83x37.png
  2977. new file mode 100644
  2978. index 000000000..6d56dcfa0
  2979. Binary files /dev/null and b/applications/external/avr_isp_programmer/images/chip_not_found_83x37.png differ
  2980. diff --git a/applications/external/avr_isp_programmer/images/dolphin_nice_96x59.png b/applications/external/avr_isp_programmer/images/dolphin_nice_96x59.png
  2981. new file mode 100644
  2982. index 000000000..a299d3630
  2983. Binary files /dev/null and b/applications/external/avr_isp_programmer/images/dolphin_nice_96x59.png differ
  2984. diff --git a/applications/external/avr_isp_programmer/images/isp_active_128x53.png b/applications/external/avr_isp_programmer/images/isp_active_128x53.png
  2985. new file mode 100644
  2986. index 000000000..843792123
  2987. Binary files /dev/null and b/applications/external/avr_isp_programmer/images/isp_active_128x53.png differ
  2988. diff --git a/applications/external/avr_isp_programmer/images/link_waiting_77x56.png b/applications/external/avr_isp_programmer/images/link_waiting_77x56.png
  2989. new file mode 100644
  2990. index 000000000..d7d32aed5
  2991. Binary files /dev/null and b/applications/external/avr_isp_programmer/images/link_waiting_77x56.png differ
  2992. diff --git a/applications/external/avr_isp_programmer/lib/driver/avr_isp_chip_arr.c b/applications/external/avr_isp_programmer/lib/driver/avr_isp_chip_arr.c
  2993. new file mode 100644
  2994. index 000000000..2be54de6a
  2995. --- /dev/null
  2996. +++ b/applications/external/avr_isp_programmer/lib/driver/avr_isp_chip_arr.c
  2997. @@ -0,0 +1,386 @@
  2998. +#include "avr_isp_chip_arr.h"
  2999. +
  3000. +#include <furi.h>
  3001. +
  3002. +//https://github.com/avrdudes/avrdude/blob/master/src/avrintel.c
  3003. +
  3004. +const AvrIspChipArr avr_isp_chip_arr[] = { // Value of -1 typically means unknown
  3005. + //{mcu_name, mcuid, family, {sig, na, ture}, flstart, flsize, pgsiz, nb, bootsz, eestart, eesize, ep, rambeg, ramsiz, nf, nl, ni}, // Source
  3006. + {"ATtiny4", 0, F_AVR8L, {0x1E, 0x8F, 0x0A}, 0, 0x00200, 0x010, 0, 0, 0, 0, 0, 0x0040, 0x0020, 1, 1, 10}, // atdf, avr-gcc 12.2.0, avrdude, boot size (manual)
  3007. + {"ATtiny5", 1, F_AVR8L, {0x1E, 0x8F, 0x09}, 0, 0x00200, 0x010, 0, 0, 0, 0, 0, 0x0040, 0x0020, 1, 1, 11}, // atdf, avr-gcc 12.2.0, avrdude, boot size (manual)
  3008. + {"ATtiny9", 2, F_AVR8L, {0x1E, 0x90, 0x08}, 0, 0x00400, 0x010, 0, 0, 0, 0, 0, 0x0040, 0x0020, 1, 1, 10}, // atdf, avr-gcc 12.2.0, avrdude, boot size (manual)
  3009. + {"ATtiny10", 3, F_AVR8L, {0x1E, 0x90, 0x03}, 0, 0x00400, 0x010, 0, 0, 0, 0, 0, 0x0040, 0x0020, 1, 1, 11}, // atdf, avr-gcc 12.2.0, avrdude, boot size (manual)
  3010. + {"ATtiny20", 4, F_AVR8L, {0x1E, 0x91, 0x0F}, 0, 0x00800, 0x020, 0, 0, 0, 0, 0, 0x0040, 0x0080, 1, 1, 17}, // atdf, avr-gcc 12.2.0, avrdude, boot size (manual)
  3011. + {"ATtiny40", 5, F_AVR8L, {0x1E, 0x92, 0x0E}, 0, 0x01000, 0x040, 0, 0, 0, 0, 0, 0x0040, 0x0100, 1, 1, 18}, // atdf, avr-gcc 12.2.0, avrdude, boot size (manual)
  3012. + {"ATtiny102", 6, F_AVR8L, {0x1E, 0x90, 0x0C}, 0, 0x00400, 0x010, 0, 0, 0, 0, 0, 0x0040, 0x0020, 1, 1, 16}, // atdf, avrdude, boot size (manual)
  3013. + {"ATtiny104", 7, F_AVR8L, {0x1E, 0x90, 0x0B}, 0, 0x00400, 0x010, 0, 0, 0, 0, 0, 0x0040, 0x0020, 1, 1, 16}, // atdf, avrdude, boot size (manual)
  3014. +
  3015. + {"ATtiny11", 8, F_AVR8, {0x1E, 0x90, 0x04}, 0, 0x00400, 0x001, 0, 0, 0, 0x0040, 1, 0x0060, 0x0020, 1, 1, 5}, // atdf, avr-gcc 12.2.0, avrdude
  3016. + {"ATtiny12", 9, F_AVR8, {0x1E, 0x90, 0x05}, 0, 0x00400, 0x001, 0, 0, 0, 0x0040, 2, 0x0060, 0x0020, 1, 1, 6}, // atdf, avr-gcc 12.2.0, avrdude
  3017. + {"ATtiny13", 10, F_AVR8, {0x1E, 0x90, 0x07}, 0, 0x00400, 0x020, 0, 0, 0, 0x0040, 4, 0x0060, 0x0040, 2, 1, 10}, // atdf, avr-gcc 12.2.0, avrdude
  3018. + {"ATtiny13A", 11, F_AVR8, {0x1E, 0x90, 0x07}, 0, 0x00400, 0x020, 0, 0, 0, 0x0040, 4, 0x0060, 0x0040, 2, 1, 10}, // atdf, avr-gcc 12.2.0, avrdude
  3019. + {"ATtiny15", 12, F_AVR8, {0x1E, 0x90, 0x06}, 0, 0x00400, 0x001, 0, 0, 0, 0x0040, 2, 0x0060, 0x0020, 1, 1, 9}, // atdf, avr-gcc 12.2.0, avrdude
  3020. + {"ATtiny22", 13, F_AVR8, {0x1E, 0x91, 0x06}, 0, 0x00800, -1, 0, 0, -1, -1, -1, 0x0060, 0x0080, 1, 1, 3}, // avr-gcc 12.2.0, boot size (manual)
  3021. + {"ATtiny24", 14, F_AVR8, {0x1E, 0x91, 0x0B}, 0, 0x00800, 0x020, 0, 0, 0, 0x0080, 4, 0x0060, 0x0080, 3, 1, 17}, // atdf, avr-gcc 12.2.0, avrdude
  3022. + {"ATtiny24A", 15, F_AVR8, {0x1E, 0x91, 0x0B}, 0, 0x00800, 0x020, 0, 0, 0, 0x0080, 4, 0x0060, 0x0080, 3, 1, 17}, // atdf, avr-gcc 12.2.0, avrdude
  3023. + {"ATtiny25", 16, F_AVR8, {0x1E, 0x91, 0x08}, 0, 0x00800, 0x020, 0, 0, 0, 0x0080, 4, 0x0060, 0x0080, 3, 1, 15}, // atdf, avr-gcc 12.2.0, avrdude
  3024. + {"ATtiny26", 17, F_AVR8, {0x1E, 0x91, 0x09}, 0, 0x00800, 0x020, 0, 0, 0, 0x0080, 4, 0x0060, 0x0080, 2, 1, 12}, // atdf, avr-gcc 12.2.0, avrdude
  3025. + {"ATtiny28", 18, F_AVR8, {0x1E, 0x91, 0x07}, 0, 0x00800, 0x002, 0, 0, 0, 0, 0, 0x0060, 0x0020, 1, 1, 6}, // atdf, avr-gcc 12.2.0, avrdude
  3026. + {"ATtiny43U", 19, F_AVR8, {0x1E, 0x92, 0x0C}, 0, 0x01000, 0x040, 0, 0, 0, 0x0040, 4, 0x0060, 0x0100, 3, 1, 16}, // atdf, avr-gcc 12.2.0, avrdude
  3027. + {"ATtiny44", 20, F_AVR8, {0x1E, 0x92, 0x07}, 0, 0x01000, 0x040, 0, 0, 0, 0x0100, 4, 0x0060, 0x0100, 3, 1, 17}, // atdf, avr-gcc 12.2.0, avrdude
  3028. + {"ATtiny44A", 21, F_AVR8, {0x1E, 0x92, 0x07}, 0, 0x01000, 0x040, 0, 0, 0, 0x0100, 4, 0x0060, 0x0100, 3, 1, 17}, // atdf, avr-gcc 12.2.0, avrdude
  3029. + {"ATtiny45", 22, F_AVR8, {0x1E, 0x92, 0x06}, 0, 0x01000, 0x040, 0, 0, 0, 0x0100, 4, 0x0060, 0x0100, 3, 1, 15}, // atdf, avr-gcc 12.2.0, avrdude
  3030. + {"ATtiny48", 23, F_AVR8, {0x1E, 0x92, 0x09}, 0, 0x01000, 0x040, 0, 0, 0, 0x0040, 4, 0x0100, 0x0100, 3, 1, 20}, // atdf, avr-gcc 12.2.0, avrdude
  3031. + {"ATtiny84", 24, F_AVR8, {0x1E, 0x93, 0x0C}, 0, 0x02000, 0x040, 0, 0, 0, 0x0200, 4, 0x0060, 0x0200, 3, 1, 17}, // atdf, avr-gcc 12.2.0, avrdude
  3032. + {"ATtiny84A", 25, F_AVR8, {0x1E, 0x93, 0x0C}, 0, 0x02000, 0x040, 0, 0, 0, 0x0200, 4, 0x0060, 0x0200, 3, 1, 17}, // atdf, avr-gcc 12.2.0, avrdude
  3033. + {"ATtiny85", 26, F_AVR8, {0x1E, 0x93, 0x0B}, 0, 0x02000, 0x040, 0, 0, 0, 0x0200, 4, 0x0060, 0x0200, 3, 1, 15}, // atdf, avr-gcc 12.2.0, avrdude
  3034. + {"ATtiny87", 27, F_AVR8, {0x1E, 0x93, 0x87}, 0, 0x02000, 0x080, 0, 0, 0, 0x0200, 4, 0x0100, 0x0200, 3, 1, 20}, // atdf, avr-gcc 12.2.0, avrdude
  3035. + {"ATtiny88", 28, F_AVR8, {0x1E, 0x93, 0x11}, 0, 0x02000, 0x040, 0, 0, 0, 0x0040, 4, 0x0100, 0x0200, 3, 1, 20}, // atdf, avr-gcc 12.2.0, avrdude
  3036. + {"ATtiny167", 29, F_AVR8, {0x1E, 0x94, 0x87}, 0, 0x04000, 0x080, 0, 0, 0, 0x0200, 4, 0x0100, 0x0200, 3, 1, 20}, // atdf, avr-gcc 12.2.0, avrdude
  3037. + {"ATtiny261", 30, F_AVR8, {0x1E, 0x91, 0x0C}, 0, 0x00800, 0x020, 0, 0, 0, 0x0080, 4, 0x0060, 0x0080, 3, 1, 19}, // atdf, avr-gcc 12.2.0, avrdude
  3038. + {"ATtiny261A", 31, F_AVR8, {0x1E, 0x91, 0x0C}, 0, 0x00800, 0x020, 0, 0, 0, 0x0080, 4, 0x0060, 0x0080, 3, 1, 19}, // atdf, avr-gcc 12.2.0, avrdude
  3039. + {"ATtiny441", 32, F_AVR8, {0x1E, 0x92, 0x15}, 0, 0x01000, 0x010, 0, 0, 0, 0x0100, 4, 0x0100, 0x0100, 3, 1, 30}, // atdf, avr-gcc 12.2.0, avrdude
  3040. + {"ATtiny461", 33, F_AVR8, {0x1E, 0x92, 0x08}, 0, 0x01000, 0x040, 0, 0, 0, 0x0100, 4, 0x0060, 0x0100, 3, 1, 19}, // atdf, avr-gcc 12.2.0, avrdude
  3041. + {"ATtiny461A", 34, F_AVR8, {0x1E, 0x92, 0x08}, 0, 0x01000, 0x040, 0, 0, 0, 0x0100, 4, 0x0060, 0x0100, 3, 1, 19}, // atdf, avr-gcc 12.2.0, avrdude
  3042. + {"ATtiny828", 35, F_AVR8, {0x1E, 0x93, 0x14}, 0, 0x02000, 0x040, 4, 0x0100, 0, 0x0100, 4, 0x0100, 0x0200, 3, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
  3043. + {"ATtiny828R", 36, F_AVR8, {0x1E, 0x93, 0x14}, 0, 0x02000, 0x040, 4, 0x0100, 0, 0x0100, 4, 0x0100, 0x0200, 3, 1, 26}, // avrdude, from ATtiny828
  3044. + {"ATtiny841", 37, F_AVR8, {0x1E, 0x93, 0x15}, 0, 0x02000, 0x010, 0, 0, 0, 0x0200, 4, 0x0100, 0x0200, 3, 1, 30}, // atdf, avr-gcc 12.2.0, avrdude
  3045. + {"ATtiny861", 38, F_AVR8, {0x1E, 0x93, 0x0D}, 0, 0x02000, 0x040, 0, 0, 0, 0x0200, 4, 0x0060, 0x0200, 3, 1, 19}, // atdf, avr-gcc 12.2.0, avrdude
  3046. + {"ATtiny861A", 39, F_AVR8, {0x1E, 0x93, 0x0D}, 0, 0x02000, 0x040, 0, 0, 0, 0x0200, 4, 0x0060, 0x0200, 3, 1, 19}, // atdf, avr-gcc 12.2.0, avrdude
  3047. + {"ATtiny1634", 40, F_AVR8, {0x1E, 0x94, 0x12}, 0, 0x04000, 0x020, 0, 0, 0, 0x0100, 4, 0x0100, 0x0400, 3, 1, 28}, // atdf, avr-gcc 12.2.0, avrdude
  3048. + {"ATtiny1634R", 41, F_AVR8, {0x1E, 0x94, 0x12}, 0, 0x04000, 0x020, 0, 0, 0, 0x0100, 4, 0x0100, 0x0400, 3, 1, 28}, // avrdude, from ATtiny1634
  3049. + {"ATtiny2313", 42, F_AVR8, {0x1E, 0x91, 0x0A}, 0, 0x00800, 0x020, 0, 0, 0, 0x0080, 4, 0x0060, 0x0080, 3, 1, 19}, // atdf, avr-gcc 12.2.0, avrdude
  3050. + {"ATtiny2313A", 43, F_AVR8, {0x1E, 0x91, 0x0A}, 0, 0x00800, 0x020, 0, 0, 0, 0x0080, 4, 0x0060, 0x0080, 3, 1, 21}, // atdf, avr-gcc 12.2.0, avrdude
  3051. + {"ATtiny4313", 44, F_AVR8, {0x1E, 0x92, 0x0D}, 0, 0x01000, 0x040, 0, 0, 0, 0x0100, 4, 0x0060, 0x0100, 3, 1, 21}, // atdf, avr-gcc 12.2.0, avrdude
  3052. + {"ATmega8", 45, F_AVR8, {0x1E, 0x93, 0x07}, 0, 0x02000, 0x040, 4, 0x0100, 0, 0x0200, 4, 0x0060, 0x0400, 2, 1, 19}, // atdf, avr-gcc 12.2.0, avrdude
  3053. + {"ATmega8A", 46, F_AVR8, {0x1E, 0x93, 0x07}, 0, 0x02000, 0x040, 4, 0x0100, 0, 0x0200, 4, 0x0060, 0x0400, 2, 1, 19}, // atdf, avr-gcc 12.2.0, avrdude
  3054. + {"ATmega8HVA", 47, F_AVR8, {0x1E, 0x93, 0x10}, 0, 0x02000, 0x080, 0, 0, 0, 0x0100, 4, 0x0100, 0x0200, 1, 1, 21}, // atdf, avr-gcc 12.2.0
  3055. + {"ATmega8U2", 48, F_AVR8, {0x1E, 0x93, 0x89}, 0, 0x02000, 0x080, 4, 0x0200, 0, 0x0200, 4, 0x0100, 0x0200, 3, 1, 29}, // atdf, avr-gcc 12.2.0, avrdude
  3056. + {"ATmega16", 49, F_AVR8, {0x1E, 0x94, 0x03}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 4, 0x0060, 0x0400, 2, 1, 21}, // atdf, avr-gcc 12.2.0, avrdude
  3057. + {"ATmega16A", 50, F_AVR8, {0x1E, 0x94, 0x03}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 4, 0x0060, 0x0400, 2, 1, 21}, // atdf, avr-gcc 12.2.0, avrdude
  3058. + {"ATmega16HVA", 51, F_AVR8, {0x1E, 0x94, 0x0C}, 0, 0x04000, 0x080, 0, 0, 0, 0x0100, 4, 0x0100, 0x0200, 1, 1, 21}, // atdf, avr-gcc 12.2.0
  3059. + {"ATmega16HVB", 52, F_AVR8, {0x1E, 0x94, 0x0D}, 0, 0x04000, 0x080, 4, 0x0200, 0, 0x0200, 4, 0x0100, 0x0400, 2, 1, 29}, // atdf, avr-gcc 12.2.0
  3060. + {"ATmega16HVBrevB", 53, F_AVR8, {0x1E, 0x94, 0x0D}, 0, 0x04000, 0x080, 4, 0x0200, 0, 0x0200, 4, 0x0100, 0x0400, 2, 1, 29}, // atdf, avr-gcc 12.2.0
  3061. + {"ATmega16M1", 54, F_AVR8, {0x1E, 0x94, 0x84}, 0, 0x04000, 0x080, 4, 0x0200, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 31}, // atdf, avr-gcc 12.2.0
  3062. + {"ATmega16HVA2", 55, F_AVR8, {0x1E, 0x94, 0x0E}, 0, 0x04000, 0x080, -1, -1, -1, -1, -1, 0x0100, 0x0400, 2, 1, 22}, // avr-gcc 12.2.0
  3063. + {"ATmega16U2", 56, F_AVR8, {0x1E, 0x94, 0x89}, 0, 0x04000, 0x080, 4, 0x0200, 0, 0x0200, 4, 0x0100, 0x0200, 3, 1, 29}, // atdf, avr-gcc 12.2.0, avrdude
  3064. + {"ATmega16U4", 57, F_AVR8, {0x1E, 0x94, 0x88}, 0, 0x04000, 0x080, 4, 0x0200, 0, 0x0200, 4, 0x0100, 0x0500, 3, 1, 43}, // atdf, avr-gcc 12.2.0, avrdude
  3065. + {"ATmega32", 58, F_AVR8, {0x1E, 0x95, 0x02}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0060, 0x0800, 2, 1, 21}, // atdf, avr-gcc 12.2.0, avrdude
  3066. + {"ATmega32A", 59, F_AVR8, {0x1E, 0x95, 0x02}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0060, 0x0800, 2, 1, 21}, // atdf, avr-gcc 12.2.0, avrdude
  3067. + {"ATmega32HVB", 60, F_AVR8, {0x1E, 0x95, 0x10}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 2, 1, 29}, // atdf, avr-gcc 12.2.0
  3068. + {"ATmega32HVBrevB", 61, F_AVR8, {0x1E, 0x95, 0x10}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 2, 1, 29}, // atdf, avr-gcc 12.2.0
  3069. + {"ATmega32C1", 62, F_AVR8, {0x1E, 0x95, 0x86}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 31}, // atdf, avr-gcc 12.2.0
  3070. + {"ATmega32M1", 63, F_AVR8, {0x1E, 0x95, 0x84}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 31}, // atdf, avr-gcc 12.2.0, avrdude
  3071. + {"ATmega32U2", 64, F_AVR8, {0x1E, 0x95, 0x8A}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0400, 3, 1, 29}, // atdf, avr-gcc 12.2.0, avrdude
  3072. + {"ATmega32U4", 65, F_AVR8, {0x1E, 0x95, 0x87}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0a00, 3, 1, 43}, // atdf, avr-gcc 12.2.0, avrdude
  3073. + {"ATmega32U6", 66, F_AVR8, {0x1E, 0x95, 0x88}, 0, 0x08000, 0x080, 4, 0x0200, -1, -1, -1, 0x0100, 0x0a00, 3, 1, 38}, // avr-gcc 12.2.0, boot size (manual)
  3074. + {"ATmega48", 67, F_AVR8, {0x1E, 0x92, 0x05}, 0, 0x01000, 0x040, 0, 0, 0, 0x0100, 4, 0x0100, 0x0200, 3, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
  3075. + {"ATmega48A", 68, F_AVR8, {0x1E, 0x92, 0x05}, 0, 0x01000, 0x040, 0, 0, 0, 0x0100, 4, 0x0100, 0x0200, 3, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
  3076. + {"ATmega48P", 69, F_AVR8, {0x1E, 0x92, 0x0A}, 0, 0x01000, 0x040, 0, 0, 0, 0x0100, 4, 0x0100, 0x0200, 3, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
  3077. + {"ATmega48PA", 70, F_AVR8, {0x1E, 0x92, 0x0A}, 0, 0x01000, 0x040, 0, 0, 0, 0x0100, 4, 0x0100, 0x0200, 3, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
  3078. + {"ATmega48PB", 71, F_AVR8, {0x1E, 0x92, 0x10}, 0, 0x01000, 0x040, 0, 0, 0, 0x0100, 4, 0x0100, 0x0200, 3, 1, 27}, // atdf, avr-gcc 12.2.0, avrdude
  3079. + {"ATmega64", 72, F_AVR8, {0x1E, 0x96, 0x02}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0100, 0x1000, 3, 1, 35}, // atdf, avr-gcc 12.2.0, avrdude
  3080. + {"ATmega64A", 73, F_AVR8, {0x1E, 0x96, 0x02}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0100, 0x1000, 3, 1, 35}, // atdf, avr-gcc 12.2.0, avrdude
  3081. + {"ATmega64HVE", 74, F_AVR8, {0x1E, 0x96, 0x10}, 0, 0x10000, 0x080, 4, 0x0400, -1, -1, -1, 0x0100, 0x1000, 2, 1, 25}, // avr-gcc 12.2.0, boot size (manual)
  3082. + {"ATmega64C1", 75, F_AVR8, {0x1E, 0x96, 0x86}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0100, 0x1000, 3, 1, 31}, // atdf, avr-gcc 12.2.0
  3083. + {"ATmega64M1", 76, F_AVR8, {0x1E, 0x96, 0x84}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0100, 0x1000, 3, 1, 31}, // atdf, avr-gcc 12.2.0, avrdude
  3084. + {"ATmega64HVE2", 77, F_AVR8, {0x1E, 0x96, 0x10}, 0, 0x10000, 0x080, 4, 0x0400, 0, 0x0400, 4, 0x0100, 0x1000, 2, 1, 25}, // atdf, avr-gcc 12.2.0
  3085. + {"ATmega64RFR2", 78, F_AVR8, {0x1E, 0xA6, 0x02}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0200, 0x2000, 3, 1, 77}, // atdf, avr-gcc 12.2.0, avrdude
  3086. + {"ATmega88", 79, F_AVR8, {0x1E, 0x93, 0x0A}, 0, 0x02000, 0x040, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
  3087. + {"ATmega88A", 80, F_AVR8, {0x1E, 0x93, 0x0A}, 0, 0x02000, 0x040, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
  3088. + {"ATmega88P", 81, F_AVR8, {0x1E, 0x93, 0x0F}, 0, 0x02000, 0x040, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
  3089. + {"ATmega88PA", 82, F_AVR8, {0x1E, 0x93, 0x0F}, 0, 0x02000, 0x040, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
  3090. + {"ATmega88PB", 83, F_AVR8, {0x1E, 0x93, 0x16}, 0, 0x02000, 0x040, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 27}, // atdf, avr-gcc 12.2.0, avrdude
  3091. + {"ATmega103", 84, F_AVR8, {0x1E, 0x97, 0x01}, 0, 0x20000, 0x100, 0, 0, 0, 0x1000, 1, 0x0060, 0x0fa0, 1, 1, 24}, // avr-gcc 12.2.0, avrdude, boot size (manual)
  3092. + {"ATmega128", 85, F_AVR8, {0x1E, 0x97, 0x02}, 0, 0x20000, 0x100, 4, 0x0400, 0, 0x1000, 8, 0x0100, 0x1000, 3, 1, 35}, // atdf, avr-gcc 12.2.0, avrdude
  3093. + {"ATmega128A", 86, F_AVR8, {0x1E, 0x97, 0x02}, 0, 0x20000, 0x100, 4, 0x0400, 0, 0x1000, 8, 0x0100, 0x1000, 3, 1, 35}, // atdf, avr-gcc 12.2.0, avrdude
  3094. + {"ATmega128RFA1", 87, F_AVR8, {0x1E, 0xA7, 0x01}, 0, 0x20000, 0x100, 4, 0x0400, 0, 0x1000, 8, 0x0200, 0x4000, 3, 1, 72}, // atdf, avr-gcc 12.2.0, avrdude
  3095. + {"ATmega128RFR2", 88, F_AVR8, {0x1E, 0xA7, 0x02}, 0, 0x20000, 0x100, 4, 0x0400, 0, 0x1000, 8, 0x0200, 0x4000, 3, 1, 77}, // atdf, avr-gcc 12.2.0, avrdude
  3096. + {"ATmega161", 89, F_AVR8, {0x1E, 0x94, 0x01}, 0, 0x04000, 0x080, 1, 0x0400, 0, 0x0200, 1, 0x0060, 0x0400, 1, 1, 21}, // avr-gcc 12.2.0, avrdude, boot size (manual)
  3097. + {"ATmega162", 90, F_AVR8, {0x1E, 0x94, 0x04}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 28}, // atdf, avr-gcc 12.2.0, avrdude
  3098. + {"ATmega163", 91, F_AVR8, {0x1E, 0x94, 0x02}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 1, 0x0060, 0x0400, 2, 1, 18}, // avr-gcc 12.2.0, avrdude, boot size (manual)
  3099. + {"ATmega164A", 92, F_AVR8, {0x1E, 0x94, 0x0F}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 31}, // atdf, avr-gcc 12.2.0, avrdude
  3100. + {"ATmega164P", 93, F_AVR8, {0x1E, 0x94, 0x0A}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 31}, // atdf, avr-gcc 12.2.0, avrdude
  3101. + {"ATmega164PA", 94, F_AVR8, {0x1E, 0x94, 0x0A}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 31}, // atdf, avr-gcc 12.2.0, avrdude
  3102. + {"ATmega165", 95, F_AVR8, {0x1E, 0x94, 0x10}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 22}, // avr-gcc 12.2.0, avrdude, boot size (manual)
  3103. + {"ATmega165A", 96, F_AVR8, {0x1E, 0x94, 0x10}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 22}, // atdf, avr-gcc 12.2.0, avrdude
  3104. + {"ATmega165P", 97, F_AVR8, {0x1E, 0x94, 0x07}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 22}, // atdf, avr-gcc 12.2.0, avrdude
  3105. + {"ATmega165PA", 98, F_AVR8, {0x1E, 0x94, 0x07}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 22}, // atdf, avr-gcc 12.2.0, avrdude
  3106. + {"ATmega168", 99, F_AVR8, {0x1E, 0x94, 0x06}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
  3107. + {"ATmega168A", 100, F_AVR8, {0x1E, 0x94, 0x06}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
  3108. + {"ATmega168P", 101, F_AVR8, {0x1E, 0x94, 0x0B}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
  3109. + {"ATmega168PA", 102, F_AVR8, {0x1E, 0x94, 0x0B}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
  3110. + {"ATmega168PB", 103, F_AVR8, {0x1E, 0x94, 0x15}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 27}, // atdf, avr-gcc 7.3.0, avrdude
  3111. + {"ATmega169", 104, F_AVR8, {0x1E, 0x94, 0x05}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 23}, // avr-gcc 12.2.0, avrdude, boot size (manual)
  3112. + {"ATmega169A", 105, F_AVR8, {0x1E, 0x94, 0x11}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 23}, // atdf, avr-gcc 12.2.0, avrdude
  3113. + {"ATmega169P", 106, F_AVR8, {0x1E, 0x94, 0x05}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 23}, // atdf, avr-gcc 12.2.0, avrdude
  3114. + {"ATmega169PA", 107, F_AVR8, {0x1E, 0x94, 0x05}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 23}, // atdf, avr-gcc 12.2.0, avrdude
  3115. + {"ATmega256RFR2", 108, F_AVR8, {0x1E, 0xA8, 0x02}, 0, 0x40000, 0x100, 4, 0x0400, 0, 0x2000, 8, 0x0200, 0x8000, 3, 1, 77}, // atdf, avr-gcc 12.2.0, avrdude
  3116. + {"ATmega323", 109, F_AVR8, {0x1E, 0x95, 0x01}, 0, 0x08000, 0x080, 4, 0x0200, -1, -1, -1, 0x0060, 0x0800, 2, 1, 21}, // avr-gcc 12.2.0, boot size (manual)
  3117. + {"ATmega324A", 110, F_AVR8, {0x1E, 0x95, 0x15}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 31}, // atdf, avr-gcc 12.2.0, avrdude
  3118. + {"ATmega324P", 111, F_AVR8, {0x1E, 0x95, 0x08}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 31}, // atdf, avr-gcc 12.2.0, avrdude
  3119. + {"ATmega324PA", 112, F_AVR8, {0x1E, 0x95, 0x11}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 31}, // atdf, avr-gcc 12.2.0, avrdude
  3120. + {"ATmega324PB", 113, F_AVR8, {0x1E, 0x95, 0x17}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 51}, // atdf, avrdude
  3121. + {"ATmega325", 114, F_AVR8, {0x1E, 0x95, 0x05}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 22}, // atdf, avr-gcc 12.2.0, avrdude
  3122. + {"ATmega325A", 115, F_AVR8, {0x1E, 0x95, 0x05}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 22}, // atdf, avr-gcc 12.2.0, avrdude
  3123. + {"ATmega325P", 116, F_AVR8, {0x1E, 0x95, 0x0D}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 22}, // atdf, avr-gcc 12.2.0, avrdude
  3124. + {"ATmega325PA", 117, F_AVR8, {0x1E, 0x95, 0x0D}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 22}, // atdf, avr-gcc 12.2.0, avrdude
  3125. + {"ATmega328", 118, F_AVR8, {0x1E, 0x95, 0x14}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
  3126. + {"ATmega328P", 119, F_AVR8, {0x1E, 0x95, 0x0F}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
  3127. + {"ATmega328PB", 120, F_AVR8, {0x1E, 0x95, 0x16}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 45}, // atdf, avr-gcc 7.3.0, avrdude
  3128. + {"ATmega329", 121, F_AVR8, {0x1E, 0x95, 0x03}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 23}, // atdf, avr-gcc 12.2.0, avrdude
  3129. + {"ATmega329A", 122, F_AVR8, {0x1E, 0x95, 0x03}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 23}, // atdf, avr-gcc 12.2.0, avrdude
  3130. + {"ATmega329P", 123, F_AVR8, {0x1E, 0x95, 0x0B}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 23}, // atdf, avr-gcc 12.2.0, avrdude
  3131. + {"ATmega329PA", 124, F_AVR8, {0x1E, 0x95, 0x0B}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 23}, // atdf, avr-gcc 12.2.0, avrdude
  3132. + {"ATmega406", 125, F_AVR8, {0x1E, 0x95, 0x07}, 0, 0x0a000, 0x080, 4, 0x0200, 0, 0x0200, 4, 0x0100, 0x0800, 2, 1, 23}, // atdf, avr-gcc 12.2.0, avrdude
  3133. + {"ATmega640", 126, F_AVR8, {0x1E, 0x96, 0x08}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x1000, 8, 0x0200, 0x2000, 3, 1, 57}, // atdf, avr-gcc 12.2.0, avrdude
  3134. + {"ATmega644", 127, F_AVR8, {0x1E, 0x96, 0x09}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0100, 0x1000, 3, 1, 28}, // atdf, avr-gcc 12.2.0, avrdude
  3135. + {"ATmega644A", 128, F_AVR8, {0x1E, 0x96, 0x09}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0100, 0x1000, 3, 1, 31}, // atdf, avr-gcc 12.2.0, avrdude
  3136. + {"ATmega644P", 129, F_AVR8, {0x1E, 0x96, 0x0A}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0100, 0x1000, 3, 1, 31}, // atdf, avr-gcc 12.2.0, avrdude
  3137. + {"ATmega644PA", 130, F_AVR8, {0x1E, 0x96, 0x0A}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0100, 0x1000, 3, 1, 31}, // atdf, avr-gcc 12.2.0, avrdude
  3138. + {"ATmega644RFR2", 131, F_AVR8, {0x1E, 0xA6, 0x03}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0200, 0x2000, 3, 1, 77}, // atdf, avr-gcc 12.2.0, avrdude
  3139. + {"ATmega645", 132, F_AVR8, {0x1E, 0x96, 0x05}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0100, 0x1000, 3, 1, 22}, // atdf, avr-gcc 12.2.0, avrdude
  3140. + {"ATmega645A", 133, F_AVR8, {0x1E, 0x96, 0x05}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0100, 0x1000, 3, 1, 22}, // atdf, avr-gcc 12.2.0, avrdude
  3141. + {"ATmega645P", 134, F_AVR8, {0x1E, 0x96, 0x0D}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0100, 0x1000, 3, 1, 22}, // atdf, avr-gcc 12.2.0, avrdude
  3142. + {"ATmega649", 135, F_AVR8, {0x1E, 0x96, 0x03}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0100, 0x1000, 3, 1, 23}, // atdf, avr-gcc 12.2.0, avrdude
  3143. + {"ATmega649A", 136, F_AVR8, {0x1E, 0x96, 0x03}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0100, 0x1000, 3, 1, 23}, // atdf, avr-gcc 12.2.0, avrdude
  3144. + {"ATmega649P", 137, F_AVR8, {0x1E, 0x96, 0x0B}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0100, 0x1000, 3, 1, 23}, // atdf, avr-gcc 12.2.0, avrdude
  3145. + {"ATmega1280", 138, F_AVR8, {0x1E, 0x97, 0x03}, 0, 0x20000, 0x100, 4, 0x0400, 0, 0x1000, 8, 0x0200, 0x2000, 3, 1, 57}, // atdf, avr-gcc 12.2.0, avrdude
  3146. + {"ATmega1281", 139, F_AVR8, {0x1E, 0x97, 0x04}, 0, 0x20000, 0x100, 4, 0x0400, 0, 0x1000, 8, 0x0200, 0x2000, 3, 1, 57}, // atdf, avr-gcc 12.2.0, avrdude
  3147. + {"ATmega1284", 140, F_AVR8, {0x1E, 0x97, 0x06}, 0, 0x20000, 0x100, 4, 0x0400, 0, 0x1000, 8, 0x0100, 0x4000, 3, 1, 35}, // atdf, avr-gcc 12.2.0, avrdude
  3148. + {"ATmega1284P", 141, F_AVR8, {0x1E, 0x97, 0x05}, 0, 0x20000, 0x100, 4, 0x0400, 0, 0x1000, 8, 0x0100, 0x4000, 3, 1, 35}, // atdf, avr-gcc 12.2.0, avrdude
  3149. + {"ATmega1284RFR2", 142, F_AVR8, {0x1E, 0xA7, 0x03}, 0, 0x20000, 0x100, 4, 0x0400, 0, 0x1000, 8, 0x0200, 0x4000, 3, 1, 77}, // atdf, avr-gcc 12.2.0, avrdude
  3150. + {"ATmega2560", 143, F_AVR8, {0x1E, 0x98, 0x01}, 0, 0x40000, 0x100, 4, 0x0400, 0, 0x1000, 8, 0x0200, 0x2000, 3, 1, 57}, // atdf, avr-gcc 12.2.0, avrdude
  3151. + {"ATmega2561", 144, F_AVR8, {0x1E, 0x98, 0x02}, 0, 0x40000, 0x100, 4, 0x0400, 0, 0x1000, 8, 0x0200, 0x2000, 3, 1, 57}, // atdf, avr-gcc 12.2.0, avrdude
  3152. + {"ATmega2564RFR2", 145, F_AVR8, {0x1E, 0xA8, 0x03}, 0, 0x40000, 0x100, 4, 0x0400, 0, 0x2000, 8, 0x0200, 0x8000, 3, 1, 77}, // atdf, avr-gcc 12.2.0, avrdude
  3153. + {"ATmega3250", 146, F_AVR8, {0x1E, 0x95, 0x06}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 25}, // atdf, avr-gcc 12.2.0, avrdude
  3154. + {"ATmega3250A", 147, F_AVR8, {0x1E, 0x95, 0x06}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 25}, // atdf, avr-gcc 12.2.0, avrdude
  3155. + {"ATmega3250P", 148, F_AVR8, {0x1E, 0x95, 0x0E}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 25}, // atdf, avr-gcc 12.2.0, avrdude
  3156. + {"ATmega3250PA", 149, F_AVR8, {0x1E, 0x95, 0x0E}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 25}, // atdf, avr-gcc 12.2.0, avrdude
  3157. + {"ATmega3290", 150, F_AVR8, {0x1E, 0x95, 0x04}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 25}, // atdf, avr-gcc 12.2.0, avrdude
  3158. + {"ATmega3290A", 151, F_AVR8, {0x1E, 0x95, 0x04}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 25}, // atdf, avr-gcc 12.2.0, avrdude
  3159. + {"ATmega3290P", 152, F_AVR8, {0x1E, 0x95, 0x0C}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 25}, // atdf, avr-gcc 12.2.0, avrdude
  3160. + {"ATmega3290PA", 153, F_AVR8, {0x1E, 0x95, 0x0C}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 25}, // atdf, avr-gcc 12.2.0, avrdude
  3161. + {"ATmega6450", 154, F_AVR8, {0x1E, 0x96, 0x06}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0100, 0x1000, 3, 1, 25}, // atdf, avr-gcc 12.2.0, avrdude
  3162. + {"ATmega6450A", 155, F_AVR8, {0x1E, 0x96, 0x06}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0100, 0x1000, 3, 1, 25}, // atdf, avr-gcc 12.2.0, avrdude
  3163. + {"ATmega6450P", 156, F_AVR8, {0x1E, 0x96, 0x0E}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0100, 0x1000, 3, 1, 25}, // atdf, avr-gcc 12.2.0, avrdude
  3164. + {"ATmega6490", 157, F_AVR8, {0x1E, 0x96, 0x04}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0100, 0x1000, 3, 1, 25}, // atdf, avr-gcc 12.2.0, avrdude
  3165. + {"ATmega6490A", 158, F_AVR8, {0x1E, 0x96, 0x04}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0100, 0x1000, 3, 1, 25}, // atdf, avr-gcc 12.2.0, avrdude
  3166. + {"ATmega6490P", 159, F_AVR8, {0x1E, 0x96, 0x0C}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0100, 0x1000, 3, 1, 25}, // atdf, avr-gcc 12.2.0, avrdude
  3167. + {"ATmega8515", 160, F_AVR8, {0x1E, 0x93, 0x06}, 0, 0x02000, 0x040, 4, 0x0100, 0, 0x0200, 4, 0x0060, 0x0200, 2, 1, 17}, // atdf, avr-gcc 12.2.0, avrdude
  3168. + {"ATmega8535", 161, F_AVR8, {0x1E, 0x93, 0x08}, 0, 0x02000, 0x040, 4, 0x0100, 0, 0x0200, 4, 0x0060, 0x0200, 2, 1, 21}, // atdf, avr-gcc 12.2.0, avrdude
  3169. + {"AT43USB320", 162, F_AVR8, {0xff, -1, -1}, 0, 0x10000, -1, -1, -1, -1, -1, -1, 0x0060, 0x0200, -1, -1, 0}, // avr-gcc 12.2.0
  3170. + {"AT43USB355", 163, F_AVR8, {0xff, -1, -1}, 0, 0x06000, -1, -1, -1, -1, -1, -1, 0x0060, 0x0400, -1, -1, 0}, // avr-gcc 12.2.0
  3171. + {"AT76C711", 164, F_AVR8, {0xff, -1, -1}, 0, 0x04000, -1, -1, -1, -1, -1, -1, 0x0060, 0x07a0, -1, -1, 0}, // avr-gcc 12.2.0
  3172. + {"AT86RF401", 165, F_AVR8, {0x1E, 0x91, 0x81}, 0, 0x00800, -1, -1, -1, -1, -1, -1, 0x0060, 0x0080, 0, 1, 3}, // avr-gcc 12.2.0
  3173. + {"AT90PWM1", 166, F_AVR8, {0x1E, 0x93, 0x83}, 0, 0x02000, 0x040, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0200, 3, 1, 32}, // atdf, avr-gcc 12.2.0
  3174. + {"AT90PWM2", 167, F_AVR8, {0x1E, 0x93, 0x81}, 0, 0x02000, 0x040, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0200, 3, 1, 32}, // avr-gcc 12.2.0, avrdude, boot size (manual)
  3175. + {"AT90PWM2B", 168, F_AVR8, {0x1E, 0x93, 0x83}, 0, 0x02000, 0x040, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0200, 3, 1, 32}, // atdf, avr-gcc 12.2.0, avrdude
  3176. + {"AT90PWM3", 169, F_AVR8, {0x1E, 0x93, 0x81}, 0, 0x02000, 0x040, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0200, 3, 1, 32}, // atdf, avr-gcc 12.2.0, avrdude
  3177. + {"AT90PWM3B", 170, F_AVR8, {0x1E, 0x93, 0x83}, 0, 0x02000, 0x040, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0200, 3, 1, 32}, // atdf, avr-gcc 12.2.0, avrdude
  3178. + {"AT90CAN32", 171, F_AVR8, {0x1E, 0x95, 0x81}, 0, 0x08000, 0x100, 4, 0x0400, 0, 0x0400, 8, 0x0100, 0x0800, 3, 1, 37}, // atdf, avr-gcc 12.2.0, avrdude
  3179. + {"AT90CAN64", 172, F_AVR8, {0x1E, 0x96, 0x81}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0100, 0x1000, 3, 1, 37}, // atdf, avr-gcc 12.2.0, avrdude
  3180. + {"AT90PWM81", 173, F_AVR8, {0x1E, 0x93, 0x88}, 0, 0x02000, 0x040, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0100, 3, 1, 20}, // atdf, avr-gcc 12.2.0
  3181. + {"AT90USB82", 174, F_AVR8, {0x1E, 0x93, 0x82}, 0, 0x02000, 0x080, 4, 0x0200, 0, 0x0200, 4, 0x0100, 0x0200, 3, 1, 29}, // atdf, avr-gcc 12.2.0, avrdude
  3182. + {"AT90SCR100", 175, F_AVR8, {0x1E, 0x96, 0xC1}, 0, 0x10000, 0x100, 4, 0x0200, -1, -1, -1, 0x0100, 0x1000, 3, 1, 38}, // avr-gcc 12.2.0, boot size (manual)
  3183. + {"AT90CAN128", 176, F_AVR8, {0x1E, 0x97, 0x81}, 0, 0x20000, 0x100, 4, 0x0400, 0, 0x1000, 8, 0x0100, 0x1000, 3, 1, 37}, // atdf, avr-gcc 12.2.0, avrdude
  3184. + {"AT90PWM161", 177, F_AVR8, {0x1E, 0x94, 0x8B}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 20}, // atdf, avr-gcc 12.2.0
  3185. + {"AT90USB162", 178, F_AVR8, {0x1E, 0x94, 0x82}, 0, 0x04000, 0x080, 4, 0x0200, 0, 0x0200, 4, 0x0100, 0x0200, 3, 1, 29}, // atdf, avr-gcc 12.2.0, avrdude
  3186. + {"AT90PWM216", 179, F_AVR8, {0x1E, 0x94, 0x83}, 0, 0x04000, 0x080, 4, 0x0200, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 32}, // atdf, avr-gcc 12.2.0, avrdude
  3187. + {"AT90PWM316", 180, F_AVR8, {0x1E, 0x94, 0x83}, 0, 0x04000, 0x080, 4, 0x0200, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 32}, // atdf, avr-gcc 12.2.0, avrdude
  3188. + {"AT90USB646", 181, F_AVR8, {0x1E, 0x96, 0x82}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0100, 0x1000, 3, 1, 38}, // atdf, avr-gcc 12.2.0, avrdude
  3189. + {"AT90USB647", 182, F_AVR8, {0x1E, 0x96, 0x82}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0100, 0x1000, 3, 1, 38}, // atdf, avr-gcc 12.2.0, avrdude
  3190. + {"AT90S1200", 183, F_AVR8, {0x1E, 0x90, 0x01}, 0, 0x00400, 0x001, 0, 0, 0, 0x0040, 1, 0x0060, 0x0020, 1, 1, 4}, // avr-gcc 12.2.0, avrdude, boot size (manual)
  3191. + {"AT90USB1286", 184, F_AVR8, {0x1E, 0x97, 0x82}, 0, 0x20000, 0x100, 4, 0x0400, 0, 0x1000, 8, 0x0100, 0x2000, 3, 1, 38}, // atdf, avr-gcc 12.2.0, avrdude
  3192. + {"AT90USB1287", 185, F_AVR8, {0x1E, 0x97, 0x82}, 0, 0x20000, 0x100, 4, 0x0400, 0, 0x1000, 8, 0x0100, 0x2000, 3, 1, 38}, // atdf, avr-gcc 12.2.0, avrdude
  3193. + {"AT90S2313", 186, F_AVR8, {0x1E, 0x91, 0x01}, 0, 0x00800, 0x001, 0, 0, 0, 0x0080, 1, 0x0060, 0x0080, 1, 1, 11}, // avr-gcc 12.2.0, avrdude, boot size (manual)
  3194. + {"AT90S2323", 187, F_AVR8, {0x1E, 0x91, 0x02}, 0, 0x00800, -1, 0, 0, -1, -1, -1, 0x0060, 0x0080, 1, 1, 3}, // avr-gcc 12.2.0, boot size (manual)
  3195. + {"AT90S2333", 188, F_AVR8, {0x1E, 0x91, 0x05}, 0, 0x00800, 0x001, 0, 0, 0, 0x0080, 1, 0x0060, 0x0080, -1, -1, 14}, // avr-gcc 12.2.0, avrdude, boot size (manual)
  3196. + {"AT90S2343", 189, F_AVR8, {0x1E, 0x91, 0x03}, 0, 0x00800, 0x001, 0, 0, 0, 0x0080, 1, 0x0060, 0x0080, 1, 1, 3}, // avr-gcc 12.2.0, avrdude, boot size (manual)
  3197. + {"AT90S4414", 190, F_AVR8, {0x1E, 0x92, 0x01}, 0, 0x01000, 0x001, 0, 0, 0, 0x0100, 1, 0x0060, 0x0100, 1, 1, 13}, // avr-gcc 12.2.0, avrdude, boot size (manual)
  3198. + {"AT90S4433", 191, F_AVR8, {0x1E, 0x92, 0x03}, 0, 0x01000, 0x001, 0, 0, 0, 0x0100, 1, 0x0060, 0x0080, 1, 1, 14}, // avr-gcc 12.2.0, avrdude, boot size (manual)
  3199. + {"AT90S4434", 192, F_AVR8, {0x1E, 0x92, 0x02}, 0, 0x01000, 0x001, 0, 0, 0, 0x0100, 1, 0x0060, 0x0100, 1, 1, 17}, // avr-gcc 12.2.0, avrdude, boot size (manual)
  3200. + {"AT90S8515", 193, F_AVR8, {0x1E, 0x93, 0x01}, 0, 0x02000, 0x001, 0, 0, 0, 0x0200, 1, 0x0060, 0x0200, 1, 1, 13}, // avr-gcc 12.2.0, avrdude, boot size (manual)
  3201. + {"AT90C8534", 194, F_AVR8, {0xff, -1, -1}, 0, 0x02000, -1, -1, -1, -1, -1, -1, 0x0060, 0x0100, -1, -1, 0}, // avr-gcc 12.2.0
  3202. + {"AT90S8535", 195, F_AVR8, {0x1E, 0x93, 0x03}, 0, 0x02000, 0x001, 0, 0, 0, 0x0200, 1, 0x0060, 0x0200, 1, 1, 17}, // avr-gcc 12.2.0, avrdude, boot size (manual)
  3203. + {"AT94K", 196, F_AVR8, {0xff, -1, -1}, 0, 0x08000, -1, -1, -1, -1, -1, -1, 0x0060, 0x0fa0, -1, -1, 0}, // avr-gcc 12.2.0
  3204. + {"ATA5272", 197, F_AVR8, {0x1E, 0x93, 0x87}, 0, 0x02000, 0x080, 0, 0, 0, 0x0200, 4, 0x0100, 0x0200, 3, 1, 37}, // atdf, avr-gcc 12.2.0
  3205. + {"ATA5505", 198, F_AVR8, {0x1E, 0x94, 0x87}, 0, 0x04000, 0x080, 0, 0, 0, 0x0200, 4, 0x0100, 0x0200, 3, 1, 20}, // atdf, avr-gcc 12.2.0
  3206. + {"ATA5700M322", 199, F_AVR8, {0x1E, 0x95, 0x67}, 0x08000, 0x08000, 0x040, 0, 0, 0, 0x0880, 16, 0x0200, 0x0400, 1, 1, 51}, // atdf
  3207. + {"ATA5702M322", 200, F_AVR8, {0x1E, 0x95, 0x69}, 0x08000, 0x08000, 0x040, 0, 0, 0, 0x0880, 16, 0x0200, 0x0400, 1, 1, 51}, // atdf, avr-gcc 12.2.0
  3208. + {"ATA5781", 201, F_AVR8, {0x1E, 0x95, 0x64}, -1, -1, -1, 0, 0, 0, 0x0400, 16, 0x0200, 0x0400, 1, 1, 42}, // atdf
  3209. + {"ATA5782", 202, F_AVR8, {0x1E, 0x95, 0x65}, 0x08000, 0x05000, 0x040, 1, 0x5000, 0, 0x0400, 16, 0x0200, 0x0400, 1, 1, 42}, // atdf, avr-gcc 12.2.0
  3210. + {"ATA5783", 203, F_AVR8, {0x1E, 0x95, 0x66}, -1, -1, -1, 0, 0, 0, 0x0400, 16, 0x0200, 0x0400, 1, 1, 42}, // atdf
  3211. + {"ATA5787", 204, F_AVR8, {0x1E, 0x94, 0x6C}, 0x08000, 0x05200, 0x040, 0, 0, 0, 0x0400, 16, 0x0200, 0x0800, 1, 1, 44}, // atdf
  3212. + {"ATA5790", 205, F_AVR8, {0x1E, 0x94, 0x61}, 0, 0x04000, 0x080, 1, 0x0800, 0, 0x0800, 16, 0x0100, 0x0200, 1, 1, 30}, // atdf, avr-gcc 12.2.0
  3213. + {"ATA5790N", 206, F_AVR8, {0x1E, 0x94, 0x62}, 0, 0x04000, 0x080, 1, 0x0800, 0, 0x0800, 16, 0x0100, 0x0200, 1, 1, 31}, // atdf, avr-gcc 12.2.0
  3214. + {"ATA5791", 207, F_AVR8, {0x1E, 0x94, 0x62}, 0, 0x04000, 0x080, 1, 0x0800, 0, 0x0800, 16, 0x0100, 0x0200, 1, 1, 31}, // atdf, avr-gcc 7.3.0
  3215. + {"ATA5795", 208, F_AVR8, {0x1E, 0x93, 0x61}, 0, 0x02000, 0x040, 1, 0x0800, 0, 0x0800, 16, 0x0100, 0x0200, 1, 1, 23}, // atdf, avr-gcc 12.2.0
  3216. + {"ATA5831", 209, F_AVR8, {0x1E, 0x95, 0x61}, 0x08000, 0x05000, 0x040, 1, 0x5000, 0, 0x0400, 16, 0x0200, 0x0400, 1, 1, 42}, // atdf, avr-gcc 12.2.0
  3217. + {"ATA5832", 210, F_AVR8, {0x1E, 0x95, 0x62}, -1, -1, -1, 0, 0, 0, 0x0400, 16, 0x0200, 0x0400, 1, 1, 42}, // atdf
  3218. + {"ATA5833", 211, F_AVR8, {0x1E, 0x95, 0x63}, -1, -1, -1, 0, 0, 0, 0x0400, 16, 0x0200, 0x0400, 1, 1, 42}, // atdf
  3219. + {"ATA5835", 212, F_AVR8, {0x1E, 0x94, 0x6B}, 0x08000, 0x05200, 0x040, 0, 0, 0, 0x0400, 16, 0x0200, 0x0800, 1, 1, 44}, // atdf
  3220. + {"ATA6285", 213, F_AVR8, {0x1E, 0x93, 0x82}, 0, 0x02000, 0x040, 4, 0x0100, 0, 0x0140, 4, 0x0100, 0x0200, 2, 1, 27}, // atdf, avr-gcc 12.2.0
  3221. + {"ATA6286", 214, F_AVR8, {0x1E, 0x93, 0x82}, 0, 0x02000, 0x040, 4, 0x0100, 0, 0x0140, 4, 0x0100, 0x0200, 2, 1, 27}, // atdf, avr-gcc 12.2.0
  3222. + {"ATA6289", 215, F_AVR8, {0x1E, 0x93, 0x82}, 0, 0x02000, 0x040, 4, 0x0100, -1, -1, -1, 0x0100, 0x0200, 2, 1, 27}, // avr-gcc 12.2.0, boot size (manual)
  3223. + {"ATA6612C", 216, F_AVR8, {0x1E, 0x93, 0x0A}, 0, 0x02000, 0x040, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 26}, // atdf, avr-gcc 12.2.0
  3224. + {"ATA6613C", 217, F_AVR8, {0x1E, 0x94, 0x06}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 26}, // atdf, avr-gcc 12.2.0
  3225. + {"ATA6614Q", 218, F_AVR8, {0x1E, 0x95, 0x0F}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 26}, // atdf, avr-gcc 12.2.0
  3226. + {"ATA6616C", 219, F_AVR8, {0x1E, 0x93, 0x87}, 0, 0x02000, 0x080, 0, 0, 0, 0x0200, 4, 0x0100, 0x0200, 3, 1, 20}, // atdf, avr-gcc 12.2.0
  3227. + {"ATA6617C", 220, F_AVR8, {0x1E, 0x94, 0x87}, 0, 0x04000, 0x080, 0, 0, 0, 0x0200, 4, 0x0100, 0x0200, 3, 1, 20}, // atdf, avr-gcc 12.2.0
  3228. + {"ATA8210", 221, F_AVR8, {0x1E, 0x95, 0x65}, 0x08000, 0x05000, 0x040, 1, 0x5000, 0, 0x0400, 16, 0x0200, 0x0400, 1, 1, 42}, // atdf, avr-gcc 7.3.0
  3229. + {"ATA8215", 222, F_AVR8, {0x1E, 0x95, 0x64}, -1, -1, -1, 0, 0, 0, 0x0400, 16, 0x0200, 0x0400, 1, 1, 42}, // atdf
  3230. + {"ATA8510", 223, F_AVR8, {0x1E, 0x95, 0x61}, 0x08000, 0x05000, 0x040, 1, 0x5000, 0, 0x0400, 16, 0x0200, 0x0400, 1, 1, 42}, // atdf, avr-gcc 7.3.0
  3231. + {"ATA8515", 224, F_AVR8, {0x1E, 0x95, 0x63}, -1, -1, -1, 0, 0, 0, 0x0400, 16, 0x0200, 0x0400, 1, 1, 42}, // atdf
  3232. + {"ATA664251", 225, F_AVR8, {0x1E, 0x94, 0x87}, 0, 0x04000, 0x080, 0, 0, 0, 0x0200, 4, 0x0100, 0x0200, 3, 1, 20}, // atdf, avr-gcc 12.2.0
  3233. + {"M3000", 226, F_AVR8, {0xff, -1, -1}, 0, 0x10000, -1, -1, -1, -1, -1, -1, 0x1000, 0x1000, -1, -1, 0}, // avr-gcc 12.2.0
  3234. + {"LGT8F88P", 227, F_AVR8, {0x1E, 0x93, 0x0F}, 0, 0x02000, 0x040, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 26}, // avrdude, from ATmega88
  3235. + {"LGT8F168P", 228, F_AVR8, {0x1E, 0x94, 0x0B}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 26}, // avrdude, from ATmega168P
  3236. + {"LGT8F328P", 229, F_AVR8, {0x1E, 0x95, 0x0F}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 26}, // avrdude, from ATmega328P
  3237. +
  3238. + {"ATxmega8E5", 230, F_XMEGA, {0x1E, 0x93, 0x41}, 0, 0x02800, 0x080, 1, 0x0800, 0, 0x0200, 32, 0x2000, 0x0400, 7, 1, 43}, // atdf, avr-gcc 12.2.0, avrdude
  3239. + {"ATxmega16A4", 231, F_XMEGA, {0x1E, 0x94, 0x41}, 0, 0x05000, 0x100, 1, 0x1000, 0, 0x0400, 32, 0x2000, 0x0800, 6, 1, 94}, // atdf, avr-gcc 12.2.0, avrdude
  3240. + {"ATxmega16A4U", 232, F_XMEGA, {0x1E, 0x94, 0x41}, 0, 0x05000, 0x100, 1, 0x1000, 0, 0x0400, 32, 0x2000, 0x0800, 6, 1, 127}, // atdf, avr-gcc 12.2.0, avrdude
  3241. + {"ATxmega16C4", 233, F_XMEGA, {0x1E, 0x94, 0x43}, 0, 0x05000, 0x100, 1, 0x1000, 0, 0x0400, 32, 0x2000, 0x0800, 6, 1, 127}, // atdf, avr-gcc 12.2.0, avrdude
  3242. + {"ATxmega16D4", 234, F_XMEGA, {0x1E, 0x94, 0x42}, 0, 0x05000, 0x100, 1, 0x1000, 0, 0x0400, 32, 0x2000, 0x0800, 6, 1, 91}, // atdf, avr-gcc 12.2.0, avrdude
  3243. + {"ATxmega16E5", 235, F_XMEGA, {0x1E, 0x94, 0x45}, 0, 0x05000, 0x080, 1, 0x1000, 0, 0x0200, 32, 0x2000, 0x0800, 7, 1, 43}, // atdf, avr-gcc 7.3.0, avrdude
  3244. + {"ATxmega32C3", 236, F_XMEGA, {0x1E, 0x95, 0x49}, 0, 0x09000, 0x100, 1, 0x1000, 0, 0x0400, 32, 0x2000, 0x1000, 6, 1, 127}, // atdf, avr-gcc 12.2.0
  3245. + {"ATxmega32D3", 237, F_XMEGA, {0x1E, 0x95, 0x4A}, 0, 0x09000, 0x100, 1, 0x1000, 0, 0x0400, 32, 0x2000, 0x1000, 6, 1, 114}, // atdf, avr-gcc 12.2.0
  3246. + {"ATxmega32A4", 238, F_XMEGA, {0x1E, 0x95, 0x41}, 0, 0x09000, 0x100, 1, 0x1000, 0, 0x0400, 32, 0x2000, 0x1000, 6, 1, 94}, // atdf, avr-gcc 12.2.0, avrdude
  3247. + {"ATxmega32A4U", 239, F_XMEGA, {0x1E, 0x95, 0x41}, 0, 0x09000, 0x100, 1, 0x1000, 0, 0x0400, 32, 0x2000, 0x1000, 6, 1, 127}, // atdf, avr-gcc 12.2.0, avrdude
  3248. + {"ATxmega32C4", 240, F_XMEGA, {0x1E, 0x95, 0x44}, 0, 0x09000, 0x100, 1, 0x1000, 0, 0x0400, 32, 0x2000, 0x1000, 6, 1, 127}, // atdf, avr-gcc 12.2.0, avrdude
  3249. + {"ATxmega32D4", 241, F_XMEGA, {0x1E, 0x95, 0x42}, 0, 0x09000, 0x100, 1, 0x1000, 0, 0x0400, 32, 0x2000, 0x1000, 6, 1, 91}, // atdf, avr-gcc 12.2.0, avrdude
  3250. + {"ATxmega32E5", 242, F_XMEGA, {0x1E, 0x95, 0x4C}, 0, 0x09000, 0x080, 1, 0x1000, 0, 0x0400, 32, 0x2000, 0x1000, 7, 1, 43}, // atdf, avr-gcc 12.2.0, avrdude
  3251. + {"ATxmega64A1", 243, F_XMEGA, {0x1E, 0x96, 0x4E}, 0, 0x11000, 0x100, 1, 0x1000, 0, 0x0800, 32, 0x2000, 0x1000, 6, 1, 125}, // atdf, avr-gcc 12.2.0, avrdude
  3252. + {"ATxmega64A1U", 244, F_XMEGA, {0x1E, 0x96, 0x4E}, 0, 0x11000, 0x100, 1, 0x1000, 0, 0x0800, 32, 0x2000, 0x1000, 6, 1, 127}, // atdf, avr-gcc 12.2.0, avrdude
  3253. + {"ATxmega64B1", 245, F_XMEGA, {0x1E, 0x96, 0x52}, 0, 0x11000, 0x100, 1, 0x1000, 0, 0x0800, 32, 0x2000, 0x1000, 6, 1, 81}, // atdf, avr-gcc 12.2.0, avrdude
  3254. + {"ATxmega64A3", 246, F_XMEGA, {0x1E, 0x96, 0x42}, 0, 0x11000, 0x100, 1, 0x1000, 0, 0x0800, 32, 0x2000, 0x1000, 6, 1, 122}, // atdf, avr-gcc 12.2.0, avrdude
  3255. + {"ATxmega64A3U", 247, F_XMEGA, {0x1E, 0x96, 0x42}, 0, 0x11000, 0x100, 1, 0x1000, 0, 0x0800, 32, 0x2000, 0x1000, 6, 1, 127}, // atdf, avr-gcc 12.2.0, avrdude
  3256. + {"ATxmega64B3", 248, F_XMEGA, {0x1E, 0x96, 0x51}, 0, 0x11000, 0x100, 1, 0x1000, 0, 0x0800, 32, 0x2000, 0x1000, 6, 1, 54}, // atdf, avr-gcc 12.2.0, avrdude
  3257. + {"ATxmega64C3", 249, F_XMEGA, {0x1E, 0x96, 0x49}, 0, 0x11000, 0x100, 1, 0x1000, 0, 0x0800, 32, 0x2000, 0x1000, 6, 1, 127}, // atdf, avr-gcc 12.2.0, avrdude
  3258. + {"ATxmega64D3", 250, F_XMEGA, {0x1E, 0x96, 0x4A}, 0, 0x11000, 0x100, 1, 0x1000, 0, 0x0800, 32, 0x2000, 0x1000, 6, 1, 114}, // atdf, avr-gcc 12.2.0, avrdude
  3259. + {"ATxmega64A4", 251, F_XMEGA, {0x1E, 0x96, 0x46}, 0, 0x11000, 0x100, -1, -1, 0, 0x0800, 32, -1, -1, -1, -1, 0}, // avrdude
  3260. + {"ATxmega64A4U", 252, F_XMEGA, {0x1E, 0x96, 0x46}, 0, 0x11000, 0x100, 1, 0x1000, 0, 0x0800, 32, 0x2000, 0x1000, 6, 1, 127}, // atdf, avr-gcc 12.2.0, avrdude
  3261. + {"ATxmega64D4", 253, F_XMEGA, {0x1E, 0x96, 0x47}, 0, 0x11000, 0x100, 1, 0x1000, 0, 0x0800, 32, 0x2000, 0x1000, 6, 1, 91}, // atdf, avr-gcc 12.2.0, avrdude
  3262. + {"ATxmega128A1", 254, F_XMEGA, {0x1E, 0x97, 0x4C}, 0, 0x22000, 0x200, 1, 0x2000, 0, 0x0800, 32, 0x2000, 0x2000, 6, 1, 125}, // atdf, avr-gcc 12.2.0, avrdude
  3263. + {"ATxmega128A1revD", 255, F_XMEGA, {0x1E, 0x97, 0x41}, 0, 0x22000, 0x200, -1, -1, 0, 0x0800, 32, -1, -1, -1, -1, 0}, // avrdude
  3264. + {"ATxmega128A1U", 256, F_XMEGA, {0x1E, 0x97, 0x4C}, 0, 0x22000, 0x200, 1, 0x2000, 0, 0x0800, 32, 0x2000, 0x2000, 6, 1, 127}, // atdf, avr-gcc 12.2.0, avrdude
  3265. + {"ATxmega128B1", 257, F_XMEGA, {0x1E, 0x97, 0x4D}, 0, 0x22000, 0x100, 1, 0x2000, 0, 0x0800, 32, 0x2000, 0x2000, 6, 1, 81}, // atdf, avr-gcc 12.2.0, avrdude
  3266. + {"ATxmega128A3", 258, F_XMEGA, {0x1E, 0x97, 0x42}, 0, 0x22000, 0x200, 1, 0x2000, 0, 0x0800, 32, 0x2000, 0x2000, 6, 1, 122}, // atdf, avr-gcc 12.2.0, avrdude
  3267. + {"ATxmega128A3U", 259, F_XMEGA, {0x1E, 0x97, 0x42}, 0, 0x22000, 0x200, 1, 0x2000, 0, 0x0800, 32, 0x2000, 0x2000, 6, 1, 127}, // atdf, avr-gcc 12.2.0, avrdude
  3268. + {"ATxmega128B3", 260, F_XMEGA, {0x1E, 0x97, 0x4B}, 0, 0x22000, 0x100, 1, 0x2000, 0, 0x0800, 32, 0x2000, 0x2000, 6, 1, 54}, // atdf, avr-gcc 12.2.0, avrdude
  3269. + {"ATxmega128C3", 261, F_XMEGA, {0x1E, 0x97, 0x52}, 0, 0x22000, 0x200, 1, 0x2000, 0, 0x0800, 32, 0x2000, 0x2000, 6, 1, 127}, // atdf, avr-gcc 12.2.0, avrdude
  3270. + {"ATxmega128D3", 262, F_XMEGA, {0x1E, 0x97, 0x48}, 0, 0x22000, 0x200, 1, 0x2000, 0, 0x0800, 32, 0x2000, 0x2000, 6, 1, 114}, // atdf, avr-gcc 12.2.0, avrdude
  3271. + {"ATxmega128A4", 263, F_XMEGA, {0x1E, 0x97, 0x46}, 0, 0x22000, 0x200, -1, -1, 0, 0x0800, 32, -1, -1, -1, -1, 0}, // avrdude
  3272. + {"ATxmega128A4U", 264, F_XMEGA, {0x1E, 0x97, 0x46}, 0, 0x22000, 0x100, 1, 0x2000, 0, 0x0800, 32, 0x2000, 0x2000, 6, 1, 127}, // atdf, avr-gcc 12.2.0, avrdude
  3273. + {"ATxmega128D4", 265, F_XMEGA, {0x1E, 0x97, 0x47}, 0, 0x22000, 0x100, 1, 0x2000, 0, 0x0800, 32, 0x2000, 0x2000, 6, 1, 91}, // atdf, avr-gcc 12.2.0, avrdude
  3274. + {"ATxmega192A1", 266, F_XMEGA, {0x1E, 0x97, 0x4E}, 0, 0x32000, 0x200, -1, -1, 0, 0x0800, 32, -1, -1, -1, -1, 0}, // avrdude
  3275. + {"ATxmega192A3", 267, F_XMEGA, {0x1E, 0x97, 0x44}, 0, 0x32000, 0x200, 1, 0x2000, 0, 0x0800, 32, 0x2000, 0x4000, 6, 1, 122}, // atdf, avr-gcc 12.2.0, avrdude
  3276. + {"ATxmega192A3U", 268, F_XMEGA, {0x1E, 0x97, 0x44}, 0, 0x32000, 0x200, 1, 0x2000, 0, 0x0800, 32, 0x2000, 0x4000, 6, 1, 127}, // atdf, avr-gcc 12.2.0, avrdude
  3277. + {"ATxmega192C3", 269, F_XMEGA, {0x1E, 0x97, 0x51}, 0, 0x32000, 0x200, 1, 0x2000, 0, 0x0800, 32, 0x2000, 0x4000, 6, 1, 127}, // atdf, avr-gcc 12.2.0, avrdude
  3278. + {"ATxmega192D3", 270, F_XMEGA, {0x1E, 0x97, 0x49}, 0, 0x32000, 0x200, 1, 0x2000, 0, 0x0800, 32, 0x2000, 0x4000, 6, 1, 114}, // atdf, avr-gcc 12.2.0, avrdude
  3279. + {"ATxmega256A1", 271, F_XMEGA, {0x1E, 0x98, 0x46}, 0, 0x42000, 0x200, -1, -1, 0, 0x1000, 32, -1, -1, -1, -1, 0}, // avrdude
  3280. + {"ATxmega256A3", 272, F_XMEGA, {0x1E, 0x98, 0x42}, 0, 0x42000, 0x200, 1, 0x2000, 0, 0x1000, 32, 0x2000, 0x4000, 6, 1, 122}, // atdf, avr-gcc 12.2.0, avrdude
  3281. + {"ATxmega256A3B", 273, F_XMEGA, {0x1E, 0x98, 0x43}, 0, 0x42000, 0x200, 1, 0x2000, 0, 0x1000, 32, 0x2000, 0x4000, 6, 1, 122}, // atdf, avr-gcc 12.2.0, avrdude
  3282. + {"ATxmega256A3BU", 274, F_XMEGA, {0x1E, 0x98, 0x43}, 0, 0x42000, 0x200, 1, 0x2000, 0, 0x1000, 32, 0x2000, 0x4000, 6, 1, 127}, // atdf, avr-gcc 12.2.0, avrdude
  3283. + {"ATxmega256A3U", 275, F_XMEGA, {0x1E, 0x98, 0x42}, 0, 0x42000, 0x200, 1, 0x2000, 0, 0x1000, 32, 0x2000, 0x4000, 6, 1, 127}, // atdf, avr-gcc 12.2.0, avrdude
  3284. + {"ATxmega256C3", 276, F_XMEGA, {0x1E, 0x98, 0x46}, 0, 0x42000, 0x200, 1, 0x2000, 0, 0x1000, 32, 0x2000, 0x4000, 6, 1, 127}, // atdf, avr-gcc 12.2.0, avrdude
  3285. + {"ATxmega256D3", 277, F_XMEGA, {0x1E, 0x98, 0x44}, 0, 0x42000, 0x200, 1, 0x2000, 0, 0x1000, 32, 0x2000, 0x4000, 6, 1, 114}, // atdf, avr-gcc 12.2.0, avrdude
  3286. + {"ATxmega384C3", 278, F_XMEGA, {0x1E, 0x98, 0x45}, 0, 0x62000, 0x200, 1, 0x2000, 0, 0x1000, 32, 0x2000, 0x8000, 6, 1, 127}, // atdf, avr-gcc 12.2.0, avrdude
  3287. + {"ATxmega384D3", 279, F_XMEGA, {0x1E, 0x98, 0x47}, 0, 0x62000, 0x200, 1, 0x2000, 0, 0x1000, 32, 0x2000, 0x8000, 6, 1, 114}, // atdf, avr-gcc 12.2.0, avrdude
  3288. +
  3289. + {"ATtiny202", 280, F_AVR8X, {0x1E, 0x91, 0x23}, 0, 0x00800, 0x040, 1, 0, 0x01400, 0x0040, 32, 0x3f80, 0x0080, 10, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
  3290. + {"ATtiny204", 281, F_AVR8X, {0x1E, 0x91, 0x22}, 0, 0x00800, 0x040, 1, 0, 0x01400, 0x0040, 32, 0x3f80, 0x0080, 10, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
  3291. + {"ATtiny212", 282, F_AVR8X, {0x1E, 0x91, 0x21}, 0, 0x00800, 0x040, 1, 0, 0x01400, 0x0040, 32, 0x3f80, 0x0080, 10, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
  3292. + {"ATtiny214", 283, F_AVR8X, {0x1E, 0x91, 0x20}, 0, 0x00800, 0x040, 1, 0, 0x01400, 0x0040, 32, 0x3f80, 0x0080, 10, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
  3293. + {"ATtiny402", 284, F_AVR8X, {0x1E, 0x92, 0x27}, 0, 0x01000, 0x040, 1, 0, 0x01400, 0x0080, 32, 0x3f00, 0x0100, 10, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
  3294. + {"ATtiny404", 285, F_AVR8X, {0x1E, 0x92, 0x26}, 0, 0x01000, 0x040, 1, 0, 0x01400, 0x0080, 32, 0x3f00, 0x0100, 10, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
  3295. + {"ATtiny406", 286, F_AVR8X, {0x1E, 0x92, 0x25}, 0, 0x01000, 0x040, 1, 0, 0x01400, 0x0080, 32, 0x3f00, 0x0100, 10, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
  3296. + {"ATtiny412", 287, F_AVR8X, {0x1E, 0x92, 0x23}, 0, 0x01000, 0x040, 1, 0, 0x01400, 0x0080, 32, 0x3f00, 0x0100, 10, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
  3297. + {"ATtiny414", 288, F_AVR8X, {0x1E, 0x92, 0x22}, 0, 0x01000, 0x040, 1, 0, 0x01400, 0x0080, 32, 0x3f00, 0x0100, 10, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
  3298. + {"ATtiny416", 289, F_AVR8X, {0x1E, 0x92, 0x21}, 0, 0x01000, 0x040, 1, 0, 0x01400, 0x0080, 32, 0x3f00, 0x0100, 10, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
  3299. + {"ATtiny416auto", 290, F_AVR8X, {0x1E, 0x92, 0x28}, 0, 0x01000, 0x040, 1, 0, 0x01400, 0x0080, 32, 0x3f00, 0x0100, 10, 1, 26}, // atdf
  3300. + {"ATtiny417", 291, F_AVR8X, {0x1E, 0x92, 0x20}, 0, 0x01000, 0x040, 1, 0, 0x01400, 0x0080, 32, 0x3f00, 0x0100, 10, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
  3301. + {"ATtiny424", 292, F_AVR8X, {0x1E, 0x92, 0x2C}, 0, 0x01000, 0x040, 1, 0, 0x01400, 0x0080, 32, 0x3e00, 0x0200, 10, 1, 30}, // atdf, avrdude
  3302. + {"ATtiny426", 293, F_AVR8X, {0x1E, 0x92, 0x2B}, 0, 0x01000, 0x040, 1, 0, 0x01400, 0x0080, 32, 0x3e00, 0x0200, 10, 1, 30}, // atdf, avrdude
  3303. + {"ATtiny427", 294, F_AVR8X, {0x1E, 0x92, 0x2A}, 0, 0x01000, 0x040, 1, 0, 0x01400, 0x0080, 32, 0x3e00, 0x0200, 10, 1, 30}, // atdf, avrdude
  3304. + {"ATtiny804", 295, F_AVR8X, {0x1E, 0x93, 0x25}, 0, 0x02000, 0x040, 1, 0, 0x01400, 0x0080, 32, 0x3e00, 0x0200, 10, 1, 31}, // atdf, avr-gcc 12.2.0, avrdude
  3305. + {"ATtiny806", 296, F_AVR8X, {0x1E, 0x93, 0x24}, 0, 0x02000, 0x040, 1, 0, 0x01400, 0x0080, 32, 0x3e00, 0x0200, 10, 1, 31}, // atdf, avr-gcc 12.2.0, avrdude
  3306. + {"ATtiny807", 297, F_AVR8X, {0x1E, 0x93, 0x23}, 0, 0x02000, 0x040, 1, 0, 0x01400, 0x0080, 32, 0x3e00, 0x0200, 10, 1, 31}, // atdf, avr-gcc 12.2.0, avrdude
  3307. + {"ATtiny814", 298, F_AVR8X, {0x1E, 0x93, 0x22}, 0, 0x02000, 0x040, 1, 0, 0x01400, 0x0080, 32, 0x3e00, 0x0200, 10, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
  3308. + {"ATtiny816", 299, F_AVR8X, {0x1E, 0x93, 0x21}, 0, 0x02000, 0x040, 1, 0, 0x01400, 0x0080, 32, 0x3e00, 0x0200, 10, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
  3309. + {"ATtiny817", 300, F_AVR8X, {0x1E, 0x93, 0x20}, 0, 0x02000, 0x040, 1, 0, 0x01400, 0x0080, 32, 0x3e00, 0x0200, 10, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
  3310. + {"ATtiny824", 301, F_AVR8X, {0x1E, 0x93, 0x29}, 0, 0x02000, 0x040, 1, 0, 0x01400, 0x0080, 32, 0x3c00, 0x0400, 10, 1, 30}, // atdf, avrdude
  3311. + {"ATtiny826", 302, F_AVR8X, {0x1E, 0x93, 0x28}, 0, 0x02000, 0x040, 1, 0, 0x01400, 0x0080, 32, 0x3c00, 0x0400, 10, 1, 30}, // atdf, avrdude
  3312. + {"ATtiny827", 303, F_AVR8X, {0x1E, 0x93, 0x27}, 0, 0x02000, 0x040, 1, 0, 0x01400, 0x0080, 32, 0x3c00, 0x0400, 10, 1, 30}, // atdf, avrdude
  3313. + {"ATtiny1604", 304, F_AVR8X, {0x1E, 0x94, 0x25}, 0, 0x04000, 0x040, 1, 0, 0x01400, 0x0100, 32, 0x3c00, 0x0400, 10, 1, 31}, // atdf, avr-gcc 12.2.0, avrdude
  3314. + {"ATtiny1606", 305, F_AVR8X, {0x1E, 0x94, 0x24}, 0, 0x04000, 0x040, 1, 0, 0x01400, 0x0100, 32, 0x3c00, 0x0400, 10, 1, 31}, // atdf, avr-gcc 12.2.0, avrdude
  3315. + {"ATtiny1607", 306, F_AVR8X, {0x1E, 0x94, 0x23}, 0, 0x04000, 0x040, 1, 0, 0x01400, 0x0100, 32, 0x3c00, 0x0400, 10, 1, 31}, // atdf, avr-gcc 12.2.0, avrdude
  3316. + {"ATtiny1614", 307, F_AVR8X, {0x1E, 0x94, 0x22}, 0, 0x04000, 0x040, 1, 0, 0x01400, 0x0100, 32, 0x3800, 0x0800, 10, 1, 31}, // atdf, avr-gcc 12.2.0, avrdude
  3317. + {"ATtiny1616", 308, F_AVR8X, {0x1E, 0x94, 0x21}, 0, 0x04000, 0x040, 1, 0, 0x01400, 0x0100, 32, 0x3800, 0x0800, 10, 1, 31}, // atdf, avr-gcc 12.2.0, avrdude
  3318. + {"ATtiny1617", 309, F_AVR8X, {0x1E, 0x94, 0x20}, 0, 0x04000, 0x040, 1, 0, 0x01400, 0x0100, 32, 0x3800, 0x0800, 10, 1, 31}, // atdf, avr-gcc 12.2.0, avrdude
  3319. + {"ATtiny1624", 310, F_AVR8X, {0x1E, 0x94, 0x2A}, 0, 0x04000, 0x040, 1, 0, 0x01400, 0x0100, 32, 0x3800, 0x0800, 10, 1, 30}, // atdf, avrdude
  3320. + {"ATtiny1626", 311, F_AVR8X, {0x1E, 0x94, 0x29}, 0, 0x04000, 0x040, 1, 0, 0x01400, 0x0100, 32, 0x3800, 0x0800, 10, 1, 30}, // atdf, avrdude
  3321. + {"ATtiny1627", 312, F_AVR8X, {0x1E, 0x94, 0x28}, 0, 0x04000, 0x040, 1, 0, 0x01400, 0x0100, 32, 0x3800, 0x0800, 10, 1, 30}, // atdf, avrdude
  3322. + {"ATtiny3214", 313, F_AVR8X, {0x1E, 0x95, 0x20}, 0, 0x08000, 0x080, 1, 0, 0x01400, 0x0100, 64, 0x3800, 0x0800, 10, 1, 31}, // avr-gcc 12.2.0
  3323. + {"ATtiny3216", 314, F_AVR8X, {0x1E, 0x95, 0x21}, 0, 0x08000, 0x080, 1, 0, 0x01400, 0x0100, 64, 0x3800, 0x0800, 10, 1, 31}, // atdf, avr-gcc 12.2.0, avrdude
  3324. + {"ATtiny3217", 315, F_AVR8X, {0x1E, 0x95, 0x22}, 0, 0x08000, 0x080, 1, 0, 0x01400, 0x0100, 64, 0x3800, 0x0800, 10, 1, 31}, // atdf, avr-gcc 12.2.0, avrdude
  3325. + {"ATtiny3224", 316, F_AVR8X, {0x1E, 0x95, 0x28}, 0, 0x08000, 0x080, 1, 0, 0x01400, 0x0100, 64, 0x3400, 0x0c00, 10, 1, 30}, // atdf, avrdude
  3326. + {"ATtiny3226", 317, F_AVR8X, {0x1E, 0x95, 0x27}, 0, 0x08000, 0x080, 1, 0, 0x01400, 0x0100, 64, 0x3400, 0x0c00, 10, 1, 30}, // atdf, avrdude
  3327. + {"ATtiny3227", 318, F_AVR8X, {0x1E, 0x95, 0x26}, 0, 0x08000, 0x080, 1, 0, 0x01400, 0x0100, 64, 0x3400, 0x0c00, 10, 1, 30}, // atdf, avrdude
  3328. + {"ATmega808", 319, F_AVR8X, {0x1E, 0x93, 0x26}, 0, 0x02000, 0x040, 1, 0, 0x01400, 0x0100, 32, 0x3c00, 0x0400, 10, 1, 36}, // atdf, avr-gcc 12.2.0, avrdude
  3329. + {"ATmega809", 320, F_AVR8X, {0x1E, 0x93, 0x2A}, 0, 0x02000, 0x040, 1, 0, 0x01400, 0x0100, 32, 0x3c00, 0x0400, 10, 1, 40}, // atdf, avr-gcc 12.2.0, avrdude
  3330. + {"ATmega1608", 321, F_AVR8X, {0x1E, 0x94, 0x27}, 0, 0x04000, 0x040, 1, 0, 0x01400, 0x0100, 32, 0x3800, 0x0800, 10, 1, 36}, // atdf, avr-gcc 12.2.0, avrdude
  3331. + {"ATmega1609", 322, F_AVR8X, {0x1E, 0x94, 0x26}, 0, 0x04000, 0x040, 1, 0, 0x01400, 0x0100, 32, 0x3800, 0x0800, 10, 1, 40}, // atdf, avr-gcc 12.2.0, avrdude
  3332. + {"ATmega3208", 323, F_AVR8X, {0x1E, 0x95, 0x30}, 0, 0x08000, 0x080, 1, 0, 0x01400, 0x0100, 64, 0x3000, 0x1000, 10, 1, 36}, // atdf, avr-gcc 12.2.0, avrdude
  3333. + {"ATmega3209", 324, F_AVR8X, {0x1E, 0x95, 0x31}, 0, 0x08000, 0x080, 1, 0, 0x01400, 0x0100, 64, 0x3000, 0x1000, 10, 1, 40}, // atdf, avr-gcc 12.2.0, avrdude
  3334. + {"ATmega4808", 325, F_AVR8X, {0x1E, 0x96, 0x50}, 0, 0x0c000, 0x080, 1, 0, 0x01400, 0x0100, 64, 0x2800, 0x1800, 10, 1, 36}, // atdf, avr-gcc 12.2.0, avrdude
  3335. + {"ATmega4809", 326, F_AVR8X, {0x1E, 0x96, 0x51}, 0, 0x0c000, 0x080, 1, 0, 0x01400, 0x0100, 64, 0x2800, 0x1800, 10, 1, 40}, // atdf, avr-gcc 12.2.0, avrdude
  3336. + {"AVR8EA28", 327, F_AVR8X, {0x1E, 0x93, 0x2C}, 0, 0x02000, 0x040, 1, 0, 0x01400, 0x0200, 8, -1, -1, -1, -1, 0}, // avrdude
  3337. + {"AVR8EA32", 328, F_AVR8X, {0x1E, 0x93, 0x2B}, 0, 0x02000, 0x040, 1, 0, 0x01400, 0x0200, 8, -1, -1, -1, -1, 0}, // avrdude
  3338. + {"AVR16DD14", 329, F_AVR8X, {0x1E, 0x94, 0x34}, 0, 0x04000, 0x200, 1, 0, 0x01400, 0x0100, 1, 0x7800, 0x0800, 16, 4, 36}, // atdf, avrdude
  3339. + {"AVR16DD20", 330, F_AVR8X, {0x1E, 0x94, 0x33}, 0, 0x04000, 0x200, 1, 0, 0x01400, 0x0100, 1, 0x7800, 0x0800, 16, 4, 36}, // atdf, avrdude
  3340. + {"AVR16DD28", 331, F_AVR8X, {0x1E, 0x94, 0x32}, 0, 0x04000, 0x200, 1, 0, 0x01400, 0x0100, 1, 0x7800, 0x0800, 16, 4, 36}, // atdf, avrdude
  3341. + {"AVR16EA28", 332, F_AVR8X, {0x1E, 0x94, 0x37}, 0, 0x04000, 0x040, 1, 0, 0x01400, 0x0200, 8, -1, -1, -1, -1, 0}, // avrdude
  3342. + {"AVR16DD32", 333, F_AVR8X, {0x1E, 0x94, 0x31}, 0, 0x04000, 0x200, 1, 0, 0x01400, 0x0100, 1, 0x7800, 0x0800, 16, 4, 36}, // atdf, avrdude
  3343. + {"AVR16EA32", 334, F_AVR8X, {0x1E, 0x94, 0x36}, 0, 0x04000, 0x040, 1, 0, 0x01400, 0x0200, 8, -1, -1, -1, -1, 0}, // avrdude
  3344. + {"AVR16EA48", 335, F_AVR8X, {0x1E, 0x94, 0x35}, 0, 0x04000, 0x040, 1, 0, 0x01400, 0x0200, 8, -1, -1, -1, -1, 0}, // avrdude
  3345. + {"AVR32DD14", 336, F_AVR8X, {0x1E, 0x95, 0x3B}, 0, 0x08000, 0x200, 1, 0, 0x01400, 0x0100, 1, 0x7000, 0x1000, 16, 4, 36}, // atdf, avrdude
  3346. + {"AVR32DD20", 337, F_AVR8X, {0x1E, 0x95, 0x3A}, 0, 0x08000, 0x200, 1, 0, 0x01400, 0x0100, 1, 0x7000, 0x1000, 16, 4, 36}, // atdf, avrdude
  3347. + {"AVR32DA28", 338, F_AVR8X, {0x1E, 0x95, 0x34}, 0, 0x08000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x7000, 0x1000, 16, 4, 41}, // atdf, avrdude
  3348. + {"AVR32DB28", 339, F_AVR8X, {0x1E, 0x95, 0x37}, 0, 0x08000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x7000, 0x1000, 16, 4, 42}, // atdf, avrdude
  3349. + {"AVR32DD28", 340, F_AVR8X, {0x1E, 0x95, 0x39}, 0, 0x08000, 0x200, 1, 0, 0x01400, 0x0100, 1, 0x7000, 0x1000, 16, 4, 36}, // atdf, avrdude
  3350. + {"AVR32EA28", 341, F_AVR8X, {0x1E, 0x95, 0x3E}, 0, 0x08000, 0x040, 1, 0, 0x01400, 0x0200, 8, -1, -1, -1, -1, 0}, // avrdude
  3351. + {"AVR32DA32", 342, F_AVR8X, {0x1E, 0x95, 0x33}, 0, 0x08000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x7000, 0x1000, 16, 4, 44}, // atdf, avrdude
  3352. + {"AVR32DB32", 343, F_AVR8X, {0x1E, 0x95, 0x36}, 0, 0x08000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x7000, 0x1000, 16, 4, 44}, // atdf, avrdude
  3353. + {"AVR32DD32", 344, F_AVR8X, {0x1E, 0x95, 0x38}, 0, 0x08000, 0x200, 1, 0, 0x01400, 0x0100, 1, 0x7000, 0x1000, 16, 4, 36}, // atdf, avrdude
  3354. + {"AVR32EA32", 345, F_AVR8X, {0x1E, 0x95, 0x3D}, 0, 0x08000, 0x040, 1, 0, 0x01400, 0x0200, 8, -1, -1, -1, -1, 0}, // avrdude
  3355. + {"AVR32DA48", 346, F_AVR8X, {0x1E, 0x95, 0x32}, 0, 0x08000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x7000, 0x1000, 16, 4, 58}, // atdf, avrdude
  3356. + {"AVR32DB48", 347, F_AVR8X, {0x1E, 0x95, 0x35}, 0, 0x08000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x7000, 0x1000, 16, 4, 61}, // atdf, avrdude
  3357. + {"AVR32EA48", 348, F_AVR8X, {0x1E, 0x95, 0x3C}, 0, 0x08000, 0x040, 1, 0, 0x01400, 0x0200, 8, -1, -1, -1, -1, 0}, // avrdude
  3358. + {"AVR64DD14", 349, F_AVR8X, {0x1E, 0x96, 0x1D}, 0, 0x10000, 0x200, 1, 0, 0x01400, 0x0100, 1, 0x6000, 0x2000, 16, 4, 36}, // atdf, avrdude
  3359. + {"AVR64DD20", 350, F_AVR8X, {0x1E, 0x96, 0x1C}, 0, 0x10000, 0x200, 1, 0, 0x01400, 0x0100, 1, 0x6000, 0x2000, 16, 4, 36}, // atdf, avrdude
  3360. + {"AVR64DA28", 351, F_AVR8X, {0x1E, 0x96, 0x15}, 0, 0x10000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x6000, 0x2000, 16, 4, 41}, // atdf, avrdude
  3361. + {"AVR64DB28", 352, F_AVR8X, {0x1E, 0x96, 0x19}, 0, 0x10000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x6000, 0x2000, 16, 4, 42}, // atdf, avrdude
  3362. + {"AVR64DD28", 353, F_AVR8X, {0x1E, 0x96, 0x1B}, 0, 0x10000, 0x200, 1, 0, 0x01400, 0x0100, 1, 0x6000, 0x2000, 16, 4, 36}, // atdf, avrdude
  3363. + {"AVR64EA28", 354, F_AVR8X, {0x1E, 0x96, 0x20}, 0, 0x10000, 0x080, 1, 0, 0x01400, 0x0200, 8, 0x6800, 0x1800, 16, 4, 37}, // atdf, avrdude
  3364. + {"AVR64DA32", 355, F_AVR8X, {0x1E, 0x96, 0x14}, 0, 0x10000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x6000, 0x2000, 16, 4, 44}, // atdf, avrdude
  3365. + {"AVR64DB32", 356, F_AVR8X, {0x1E, 0x96, 0x18}, 0, 0x10000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x6000, 0x2000, 16, 4, 44}, // atdf, avrdude
  3366. + {"AVR64DD32", 357, F_AVR8X, {0x1E, 0x96, 0x1A}, 0, 0x10000, 0x200, 1, 0, 0x01400, 0x0100, 1, 0x6000, 0x2000, 16, 4, 36}, // atdf, avrdude
  3367. + {"AVR64EA32", 358, F_AVR8X, {0x1E, 0x96, 0x1F}, 0, 0x10000, 0x080, 1, 0, 0x01400, 0x0200, 8, 0x6800, 0x1800, 16, 4, 37}, // atdf, avrdude
  3368. + {"AVR64DA48", 359, F_AVR8X, {0x1E, 0x96, 0x13}, 0, 0x10000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x6000, 0x2000, 16, 4, 58}, // atdf, avrdude
  3369. + {"AVR64DB48", 360, F_AVR8X, {0x1E, 0x96, 0x17}, 0, 0x10000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x6000, 0x2000, 16, 4, 61}, // atdf, avrdude
  3370. + {"AVR64EA48", 361, F_AVR8X, {0x1E, 0x96, 0x1E}, 0, 0x10000, 0x080, 1, 0, 0x01400, 0x0200, 8, 0x6800, 0x1800, 16, 4, 45}, // atdf, avrdude
  3371. + {"AVR64DA64", 362, F_AVR8X, {0x1E, 0x96, 0x12}, 0, 0x10000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x6000, 0x2000, 16, 4, 64}, // atdf, avrdude
  3372. + {"AVR64DB64", 363, F_AVR8X, {0x1E, 0x96, 0x16}, 0, 0x10000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x6000, 0x2000, 16, 4, 65}, // atdf, avrdude
  3373. + {"AVR128DA28", 364, F_AVR8X, {0x1E, 0x97, 0x0A}, 0, 0x20000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x4000, 0x4000, 16, 4, 41}, // atdf, avrdude
  3374. + {"AVR128DB28", 365, F_AVR8X, {0x1E, 0x97, 0x0E}, 0, 0x20000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x4000, 0x4000, 16, 4, 42}, // atdf, avrdude
  3375. + {"AVR128DA32", 366, F_AVR8X, {0x1E, 0x97, 0x09}, 0, 0x20000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x4000, 0x4000, 16, 4, 44}, // atdf, avrdude
  3376. + {"AVR128DB32", 367, F_AVR8X, {0x1E, 0x97, 0x0D}, 0, 0x20000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x4000, 0x4000, 16, 4, 44}, // atdf, avrdude
  3377. + {"AVR128DA48", 368, F_AVR8X, {0x1E, 0x97, 0x08}, 0, 0x20000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x4000, 0x4000, 16, 4, 58}, // atdf, avrdude
  3378. + {"AVR128DB48", 369, F_AVR8X, {0x1E, 0x97, 0x0C}, 0, 0x20000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x4000, 0x4000, 16, 4, 61}, // atdf, avrdude
  3379. + {"AVR128DA64", 370, F_AVR8X, {0x1E, 0x97, 0x07}, 0, 0x20000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x4000, 0x4000, 16, 4, 64}, // atdf, avrdude
  3380. + {"AVR128DB64", 371, F_AVR8X, {0x1E, 0x97, 0x0B}, 0, 0x20000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x4000, 0x4000, 16, 4, 65}, // atdf, avrdude
  3381. +};
  3382. +
  3383. +const size_t avr_isp_chip_arr_size = COUNT_OF(avr_isp_chip_arr);
  3384. \ No newline at end of file
  3385. diff --git a/applications/external/avr_isp_programmer/lib/driver/avr_isp_chip_arr.h b/applications/external/avr_isp_programmer/lib/driver/avr_isp_chip_arr.h
  3386. new file mode 100644
  3387. index 000000000..66f16a7b9
  3388. --- /dev/null
  3389. +++ b/applications/external/avr_isp_programmer/lib/driver/avr_isp_chip_arr.h
  3390. @@ -0,0 +1,33 @@
  3391. +#pragma once
  3392. +
  3393. +#include <furi_hal.h>
  3394. +
  3395. +#define F_AVR8L 1 // TPI programming, ATtiny(4|5|9|10|20|40|102|104)
  3396. +#define F_AVR8 2 // ISP programming with SPI, "classic" AVRs
  3397. +#define F_XMEGA 4 // PDI programming, ATxmega family
  3398. +#define F_AVR8X 8 // UPDI programming, newer 8-bit MCUs
  3399. +
  3400. +struct AvrIspChipArr { // Value of -1 typically means unknown
  3401. + const char* name; // Name of part
  3402. + uint16_t mcuid; // ID of MCU in 0..2039
  3403. + uint8_t avrarch; // F_AVR8L, F_AVR8, F_XMEGA or F_AVR8X
  3404. + uint8_t sigs[3]; // Signature bytes
  3405. + int32_t flashoffset; // Flash offset
  3406. + int32_t flashsize; // Flash size
  3407. + int16_t pagesize; // Flash page size
  3408. + int8_t nboots; // Number of supported boot sectors
  3409. + int16_t bootsize; // Size of (smallest) boot sector
  3410. + int32_t eepromoffset; // EEPROM offset
  3411. + int32_t eepromsize; // EEPROM size
  3412. + int32_t eeprompagesize; // EEPROM page size
  3413. + int32_t sramstart; // SRAM offset
  3414. + int32_t sramsize; // SRAM size
  3415. + int8_t nfuses; // Number of fuse bytes
  3416. + int8_t nlocks; // Number of lock bytes
  3417. + uint8_t ninterrupts; // Number of vectors in interrupt vector table
  3418. +};
  3419. +
  3420. +typedef struct AvrIspChipArr AvrIspChipArr;
  3421. +
  3422. +extern const AvrIspChipArr avr_isp_chip_arr[];
  3423. +extern const size_t avr_isp_chip_arr_size;
  3424. \ No newline at end of file
  3425. diff --git a/applications/external/avr_isp_programmer/lib/driver/avr_isp_prog.c b/applications/external/avr_isp_programmer/lib/driver/avr_isp_prog.c
  3426. new file mode 100644
  3427. index 000000000..b457e4c27
  3428. --- /dev/null
  3429. +++ b/applications/external/avr_isp_programmer/lib/driver/avr_isp_prog.c
  3430. @@ -0,0 +1,633 @@
  3431. +#include "avr_isp_prog.h"
  3432. +#include "avr_isp_prog_cmd.h"
  3433. +
  3434. +#include <furi.h>
  3435. +
  3436. +#define AVR_ISP_PROG_TX_RX_BUF_SIZE 320
  3437. +#define TAG "AvrIspProg"
  3438. +
  3439. +struct AvrIspProgSignature {
  3440. + uint8_t vendor;
  3441. + uint8_t part_family;
  3442. + uint8_t part_number;
  3443. +};
  3444. +
  3445. +typedef struct AvrIspProgSignature AvrIspProgSignature;
  3446. +
  3447. +struct AvrIspProgCfgDevice {
  3448. + uint8_t devicecode;
  3449. + uint8_t revision;
  3450. + uint8_t progtype;
  3451. + uint8_t parmode;
  3452. + uint8_t polling;
  3453. + uint8_t selftimed;
  3454. + uint8_t lockbytes;
  3455. + uint8_t fusebytes;
  3456. + uint8_t flashpoll;
  3457. + uint16_t eeprompoll;
  3458. + uint16_t pagesize;
  3459. + uint16_t eepromsize;
  3460. + uint32_t flashsize;
  3461. +};
  3462. +
  3463. +typedef struct AvrIspProgCfgDevice AvrIspProgCfgDevice;
  3464. +
  3465. +struct AvrIspProg {
  3466. + AvrIspSpiSw* spi;
  3467. + AvrIspProgCfgDevice* cfg;
  3468. + FuriStreamBuffer* stream_rx;
  3469. + FuriStreamBuffer* stream_tx;
  3470. +
  3471. + uint16_t error;
  3472. + uint16_t addr;
  3473. + bool pmode;
  3474. + bool exit;
  3475. + bool rst_active_high;
  3476. + uint8_t buff[AVR_ISP_PROG_TX_RX_BUF_SIZE];
  3477. +
  3478. + AvrIspProgCallback callback;
  3479. + void* context;
  3480. +};
  3481. +
  3482. +static void avr_isp_prog_end_pmode(AvrIspProg* instance);
  3483. +
  3484. +AvrIspProg* avr_isp_prog_init(void) {
  3485. + AvrIspProg* instance = malloc(sizeof(AvrIspProg));
  3486. + instance->cfg = malloc(sizeof(AvrIspProgCfgDevice));
  3487. + instance->stream_rx =
  3488. + furi_stream_buffer_alloc(sizeof(int8_t) * AVR_ISP_PROG_TX_RX_BUF_SIZE, sizeof(int8_t));
  3489. + instance->stream_tx =
  3490. + furi_stream_buffer_alloc(sizeof(int8_t) * AVR_ISP_PROG_TX_RX_BUF_SIZE, sizeof(int8_t));
  3491. + instance->rst_active_high = false;
  3492. + instance->exit = false;
  3493. + return instance;
  3494. +}
  3495. +
  3496. +void avr_isp_prog_free(AvrIspProg* instance) {
  3497. + furi_assert(instance);
  3498. + if(instance->spi) avr_isp_prog_end_pmode(instance);
  3499. + furi_stream_buffer_free(instance->stream_tx);
  3500. + furi_stream_buffer_free(instance->stream_rx);
  3501. + free(instance->cfg);
  3502. + free(instance);
  3503. +}
  3504. +
  3505. +size_t avr_isp_prog_spaces_rx(AvrIspProg* instance) {
  3506. + return furi_stream_buffer_spaces_available(instance->stream_rx);
  3507. +}
  3508. +
  3509. +bool avr_isp_prog_rx(AvrIspProg* instance, uint8_t* data, size_t len) {
  3510. + furi_assert(instance);
  3511. + furi_assert(data);
  3512. + furi_assert(len != 0);
  3513. + size_t ret = furi_stream_buffer_send(instance->stream_rx, data, sizeof(uint8_t) * len, 0);
  3514. + return ret == sizeof(uint8_t) * len;
  3515. +}
  3516. +
  3517. +size_t avr_isp_prog_tx(AvrIspProg* instance, uint8_t* data, size_t max_len) {
  3518. + furi_assert(instance);
  3519. + return furi_stream_buffer_receive(instance->stream_tx, data, sizeof(int8_t) * max_len, 0);
  3520. +}
  3521. +
  3522. +void avr_isp_prog_exit(AvrIspProg* instance) {
  3523. + furi_assert(instance);
  3524. + instance->exit = true;
  3525. +}
  3526. +
  3527. +void avr_isp_prog_set_tx_callback(AvrIspProg* instance, AvrIspProgCallback callback, void* context) {
  3528. + furi_assert(instance);
  3529. + furi_assert(context);
  3530. + instance->callback = callback;
  3531. + instance->context = context;
  3532. +}
  3533. +
  3534. +static void avr_isp_prog_tx_ch(AvrIspProg* instance, uint8_t data) {
  3535. + furi_assert(instance);
  3536. + furi_stream_buffer_send(instance->stream_tx, &data, sizeof(uint8_t), FuriWaitForever);
  3537. +}
  3538. +
  3539. +static uint8_t avr_isp_prog_getch(AvrIspProg* instance) {
  3540. + furi_assert(instance);
  3541. + uint8_t data[1] = {0};
  3542. + while(furi_stream_buffer_receive(instance->stream_rx, &data, sizeof(int8_t), 30) == 0) {
  3543. + if(instance->exit) break;
  3544. + };
  3545. + return data[0];
  3546. +}
  3547. +
  3548. +static void avr_isp_prog_fill(AvrIspProg* instance, size_t len) {
  3549. + furi_assert(instance);
  3550. + for(size_t x = 0; x < len; x++) {
  3551. + instance->buff[x] = avr_isp_prog_getch(instance);
  3552. + }
  3553. +}
  3554. +
  3555. +static void avr_isp_prog_reset_target(AvrIspProg* instance, bool reset) {
  3556. + furi_assert(instance);
  3557. + avr_isp_spi_sw_res_set(instance->spi, (reset == instance->rst_active_high) ? true : false);
  3558. +}
  3559. +
  3560. +static uint8_t avr_isp_prog_spi_transaction(
  3561. + AvrIspProg* instance,
  3562. + uint8_t cmd,
  3563. + uint8_t addr_hi,
  3564. + uint8_t addr_lo,
  3565. + uint8_t data) {
  3566. + furi_assert(instance);
  3567. +
  3568. + avr_isp_spi_sw_txrx(instance->spi, cmd);
  3569. + avr_isp_spi_sw_txrx(instance->spi, addr_hi);
  3570. + avr_isp_spi_sw_txrx(instance->spi, addr_lo);
  3571. + return avr_isp_spi_sw_txrx(instance->spi, data);
  3572. +}
  3573. +
  3574. +static void avr_isp_prog_empty_reply(AvrIspProg* instance) {
  3575. + furi_assert(instance);
  3576. + if(avr_isp_prog_getch(instance) == CRC_EOP) {
  3577. + avr_isp_prog_tx_ch(instance, STK_INSYNC);
  3578. + avr_isp_prog_tx_ch(instance, STK_OK);
  3579. + } else {
  3580. + instance->error++;
  3581. + avr_isp_prog_tx_ch(instance, STK_NOSYNC);
  3582. + }
  3583. +}
  3584. +
  3585. +static void avr_isp_prog_breply(AvrIspProg* instance, uint8_t data) {
  3586. + furi_assert(instance);
  3587. + if(avr_isp_prog_getch(instance) == CRC_EOP) {
  3588. + avr_isp_prog_tx_ch(instance, STK_INSYNC);
  3589. + avr_isp_prog_tx_ch(instance, data);
  3590. + avr_isp_prog_tx_ch(instance, STK_OK);
  3591. + } else {
  3592. + instance->error++;
  3593. + avr_isp_prog_tx_ch(instance, STK_NOSYNC);
  3594. + }
  3595. +}
  3596. +
  3597. +static void avr_isp_prog_get_version(AvrIspProg* instance, uint8_t data) {
  3598. + furi_assert(instance);
  3599. + switch(data) {
  3600. + case STK_HW_VER:
  3601. + avr_isp_prog_breply(instance, AVR_ISP_HWVER);
  3602. + break;
  3603. + case STK_SW_MAJOR:
  3604. + avr_isp_prog_breply(instance, AVR_ISP_SWMAJ);
  3605. + break;
  3606. + case STK_SW_MINOR:
  3607. + avr_isp_prog_breply(instance, AVR_ISP_SWMIN);
  3608. + break;
  3609. + case AVP_ISP_CONNECT_TYPE:
  3610. + avr_isp_prog_breply(instance, AVP_ISP_SERIAL_CONNECT_TYPE);
  3611. + break;
  3612. + default:
  3613. + avr_isp_prog_breply(instance, AVR_ISP_RESP_0);
  3614. + }
  3615. +}
  3616. +
  3617. +static void avr_isp_prog_set_cfg(AvrIspProg* instance) {
  3618. + furi_assert(instance);
  3619. + // call this after reading cfg packet into buff[]
  3620. + instance->cfg->devicecode = instance->buff[0];
  3621. + instance->cfg->revision = instance->buff[1];
  3622. + instance->cfg->progtype = instance->buff[2];
  3623. + instance->cfg->parmode = instance->buff[3];
  3624. + instance->cfg->polling = instance->buff[4];
  3625. + instance->cfg->selftimed = instance->buff[5];
  3626. + instance->cfg->lockbytes = instance->buff[6];
  3627. + instance->cfg->fusebytes = instance->buff[7];
  3628. + instance->cfg->flashpoll = instance->buff[8];
  3629. + // ignore (instance->buff[9] == instance->buff[8]) //FLASH polling value. Same as “flashpoll”
  3630. + instance->cfg->eeprompoll = instance->buff[10] << 8 | instance->buff[11];
  3631. + instance->cfg->pagesize = instance->buff[12] << 8 | instance->buff[13];
  3632. + instance->cfg->eepromsize = instance->buff[14] << 8 | instance->buff[15];
  3633. + instance->cfg->flashsize = instance->buff[16] << 24 | instance->buff[17] << 16 |
  3634. + instance->buff[18] << 8 | instance->buff[19];
  3635. +
  3636. + // avr devices have active low reset, at89sx are active high
  3637. + instance->rst_active_high = (instance->cfg->devicecode >= 0xe0);
  3638. +}
  3639. +static bool
  3640. + avr_isp_prog_set_pmode(AvrIspProg* instance, uint8_t a, uint8_t b, uint8_t c, uint8_t d) {
  3641. + furi_assert(instance);
  3642. + uint8_t res = 0;
  3643. + avr_isp_spi_sw_txrx(instance->spi, a);
  3644. + avr_isp_spi_sw_txrx(instance->spi, b);
  3645. + res = avr_isp_spi_sw_txrx(instance->spi, c);
  3646. + avr_isp_spi_sw_txrx(instance->spi, d);
  3647. + return res == 0x53;
  3648. +}
  3649. +
  3650. +static void avr_isp_prog_end_pmode(AvrIspProg* instance) {
  3651. + furi_assert(instance);
  3652. + if(instance->pmode) {
  3653. + avr_isp_prog_reset_target(instance, false);
  3654. + // We're about to take the target out of reset
  3655. + // so configure SPI pins as input
  3656. +
  3657. + if(instance->spi) avr_isp_spi_sw_free(instance->spi);
  3658. + instance->spi = NULL;
  3659. + }
  3660. +
  3661. + instance->pmode = false;
  3662. +}
  3663. +
  3664. +static bool avr_isp_prog_start_pmode(AvrIspProg* instance, AvrIspSpiSwSpeed spi_speed) {
  3665. + furi_assert(instance);
  3666. + // Reset target before driving PIN_SCK or PIN_MOSI
  3667. +
  3668. + // SPI.begin() will configure SS as output,
  3669. + // so SPI master mode is selected.
  3670. + // We have defined RESET as pin 10,
  3671. + // which for many arduino's is not the SS pin.
  3672. + // So we have to configure RESET as output here,
  3673. + // (reset_target() first sets the correct level)
  3674. + if(instance->spi) avr_isp_spi_sw_free(instance->spi);
  3675. + instance->spi = avr_isp_spi_sw_init(spi_speed);
  3676. +
  3677. + avr_isp_prog_reset_target(instance, true);
  3678. + // See avr datasheets, chapter "SERIAL_PRG Programming Algorithm":
  3679. +
  3680. + // Pulse RESET after PIN_SCK is low:
  3681. + avr_isp_spi_sw_sck_set(instance->spi, false);
  3682. +
  3683. + // discharge PIN_SCK, value arbitrally chosen
  3684. + furi_delay_ms(20);
  3685. + avr_isp_prog_reset_target(instance, false);
  3686. +
  3687. + // Pulse must be minimum 2 target CPU speed cycles
  3688. + // so 100 usec is ok for CPU speeds above 20KHz
  3689. + furi_delay_ms(1);
  3690. +
  3691. + avr_isp_prog_reset_target(instance, true);
  3692. +
  3693. + // Send the enable programming command:
  3694. + // datasheet: must be > 20 msec
  3695. + furi_delay_ms(50);
  3696. + if(avr_isp_prog_set_pmode(instance, AVR_ISP_SET_PMODE)) {
  3697. + instance->pmode = true;
  3698. + return true;
  3699. + }
  3700. + return false;
  3701. +}
  3702. +
  3703. +static AvrIspProgSignature avr_isp_prog_check_signature(AvrIspProg* instance) {
  3704. + furi_assert(instance);
  3705. + AvrIspProgSignature signature;
  3706. + signature.vendor = avr_isp_prog_spi_transaction(instance, AVR_ISP_READ_VENDOR);
  3707. + signature.part_family = avr_isp_prog_spi_transaction(instance, AVR_ISP_READ_PART_FAMILY);
  3708. + signature.part_number = avr_isp_prog_spi_transaction(instance, AVR_ISP_READ_PART_NUMBER);
  3709. + return signature;
  3710. +}
  3711. +
  3712. +static bool avr_isp_prog_auto_set_spi_speed_start_pmode(AvrIspProg* instance) {
  3713. + AvrIspSpiSwSpeed spi_speed[] = {
  3714. + AvrIspSpiSwSpeed1Mhz,
  3715. + AvrIspSpiSwSpeed400Khz,
  3716. + AvrIspSpiSwSpeed250Khz,
  3717. + AvrIspSpiSwSpeed125Khz,
  3718. + AvrIspSpiSwSpeed60Khz,
  3719. + AvrIspSpiSwSpeed40Khz,
  3720. + AvrIspSpiSwSpeed20Khz,
  3721. + AvrIspSpiSwSpeed10Khz,
  3722. + AvrIspSpiSwSpeed5Khz,
  3723. + AvrIspSpiSwSpeed1Khz,
  3724. + };
  3725. + for(uint8_t i = 0; i < COUNT_OF(spi_speed); i++) {
  3726. + if(avr_isp_prog_start_pmode(instance, spi_speed[i])) {
  3727. + AvrIspProgSignature sig = avr_isp_prog_check_signature(instance);
  3728. + AvrIspProgSignature sig_examination = avr_isp_prog_check_signature(instance); //-V656
  3729. + uint8_t y = 0;
  3730. + while(y < 8) {
  3731. + if(memcmp(
  3732. + (uint8_t*)&sig, (uint8_t*)&sig_examination, sizeof(AvrIspProgSignature)) !=
  3733. + 0)
  3734. + break;
  3735. + sig_examination = avr_isp_prog_check_signature(instance);
  3736. + y++;
  3737. + }
  3738. + if(y == 8) {
  3739. + if(spi_speed[i] > AvrIspSpiSwSpeed1Mhz) {
  3740. + if(i < (COUNT_OF(spi_speed) - 1)) {
  3741. + avr_isp_prog_end_pmode(instance);
  3742. + i++;
  3743. + return avr_isp_prog_start_pmode(instance, spi_speed[i]);
  3744. + }
  3745. + }
  3746. + return true;
  3747. + }
  3748. + }
  3749. + }
  3750. + return false;
  3751. +}
  3752. +
  3753. +static void avr_isp_prog_universal(AvrIspProg* instance) {
  3754. + furi_assert(instance);
  3755. + uint8_t data;
  3756. +
  3757. + avr_isp_prog_fill(instance, 4);
  3758. + data = avr_isp_prog_spi_transaction(
  3759. + instance, instance->buff[0], instance->buff[1], instance->buff[2], instance->buff[3]);
  3760. + avr_isp_prog_breply(instance, data);
  3761. +}
  3762. +
  3763. +static void avr_isp_prog_commit(AvrIspProg* instance, uint16_t addr, uint8_t data) {
  3764. + furi_assert(instance);
  3765. + avr_isp_prog_spi_transaction(instance, AVR_ISP_COMMIT(addr));
  3766. + /* polling flash */
  3767. + if(data == 0xFF) {
  3768. + furi_delay_ms(5);
  3769. + } else {
  3770. + /* polling flash */
  3771. + uint32_t starttime = furi_get_tick();
  3772. + while((furi_get_tick() - starttime) < 30) {
  3773. + if(avr_isp_prog_spi_transaction(instance, AVR_ISP_READ_FLASH_HI(addr)) != 0xFF) {
  3774. + break;
  3775. + };
  3776. + }
  3777. + }
  3778. +}
  3779. +
  3780. +static uint16_t avr_isp_prog_current_page(AvrIspProg* instance) {
  3781. + furi_assert(instance);
  3782. + uint16_t page = 0;
  3783. + switch(instance->cfg->pagesize) {
  3784. + case 32:
  3785. + page = instance->addr & 0xFFFFFFF0;
  3786. + break;
  3787. + case 64:
  3788. + page = instance->addr & 0xFFFFFFE0;
  3789. + break;
  3790. + case 128:
  3791. + page = instance->addr & 0xFFFFFFC0;
  3792. + break;
  3793. + case 256:
  3794. + page = instance->addr & 0xFFFFFF80;
  3795. + break;
  3796. +
  3797. + default:
  3798. + page = instance->addr;
  3799. + break;
  3800. + }
  3801. +
  3802. + return page;
  3803. +}
  3804. +
  3805. +static uint8_t avr_isp_prog_write_flash_pages(AvrIspProg* instance, size_t length) {
  3806. + furi_assert(instance);
  3807. + size_t x = 0;
  3808. + uint16_t page = avr_isp_prog_current_page(instance);
  3809. + while(x < length) {
  3810. + if(page != avr_isp_prog_current_page(instance)) {
  3811. + --x;
  3812. + avr_isp_prog_commit(instance, page, instance->buff[x++]);
  3813. + page = avr_isp_prog_current_page(instance);
  3814. + }
  3815. + avr_isp_prog_spi_transaction(
  3816. + instance, AVR_ISP_WRITE_FLASH_LO(instance->addr, instance->buff[x++]));
  3817. +
  3818. + avr_isp_prog_spi_transaction(
  3819. + instance, AVR_ISP_WRITE_FLASH_HI(instance->addr, instance->buff[x++]));
  3820. + instance->addr++;
  3821. + }
  3822. +
  3823. + avr_isp_prog_commit(instance, page, instance->buff[--x]);
  3824. + return STK_OK;
  3825. +}
  3826. +
  3827. +static void avr_isp_prog_write_flash(AvrIspProg* instance, size_t length) {
  3828. + furi_assert(instance);
  3829. + avr_isp_prog_fill(instance, length);
  3830. + if(avr_isp_prog_getch(instance) == CRC_EOP) {
  3831. + avr_isp_prog_tx_ch(instance, STK_INSYNC);
  3832. + avr_isp_prog_tx_ch(instance, avr_isp_prog_write_flash_pages(instance, length));
  3833. + } else {
  3834. + instance->error++;
  3835. + avr_isp_prog_tx_ch(instance, STK_NOSYNC);
  3836. + }
  3837. +}
  3838. +
  3839. +// write (length) bytes, (start) is a byte address
  3840. +static uint8_t
  3841. + avr_isp_prog_write_eeprom_chunk(AvrIspProg* instance, uint16_t start, uint16_t length) {
  3842. + furi_assert(instance);
  3843. + // this writes byte-by-byte,
  3844. + // page writing may be faster (4 bytes at a time)
  3845. + avr_isp_prog_fill(instance, length);
  3846. + for(uint16_t x = 0; x < length; x++) {
  3847. + uint16_t addr = start + x;
  3848. + avr_isp_prog_spi_transaction(instance, AVR_ISP_WRITE_EEPROM(addr, instance->buff[x]));
  3849. + furi_delay_ms(10);
  3850. + }
  3851. + return STK_OK;
  3852. +}
  3853. +
  3854. +static uint8_t avr_isp_prog_write_eeprom(AvrIspProg* instance, size_t length) {
  3855. + furi_assert(instance);
  3856. + // here is a word address, get the byte address
  3857. + uint16_t start = instance->addr * 2;
  3858. + uint16_t remaining = length;
  3859. + if(length > instance->cfg->eepromsize) {
  3860. + instance->error++;
  3861. + return STK_FAILED;
  3862. + }
  3863. + while(remaining > AVR_ISP_EECHUNK) {
  3864. + avr_isp_prog_write_eeprom_chunk(instance, start, AVR_ISP_EECHUNK);
  3865. + start += AVR_ISP_EECHUNK;
  3866. + remaining -= AVR_ISP_EECHUNK;
  3867. + }
  3868. + avr_isp_prog_write_eeprom_chunk(instance, start, remaining);
  3869. + return STK_OK;
  3870. +}
  3871. +
  3872. +static void avr_isp_prog_program_page(AvrIspProg* instance) {
  3873. + furi_assert(instance);
  3874. + uint8_t result = STK_FAILED;
  3875. + uint16_t length = avr_isp_prog_getch(instance) << 8 | avr_isp_prog_getch(instance);
  3876. + uint8_t memtype = avr_isp_prog_getch(instance);
  3877. + // flash memory @addr, (length) bytes
  3878. + if(memtype == STK_SET_FLASH_TYPE) {
  3879. + avr_isp_prog_write_flash(instance, length);
  3880. + return;
  3881. + }
  3882. + if(memtype == STK_SET_EEPROM_TYPE) {
  3883. + result = avr_isp_prog_write_eeprom(instance, length);
  3884. + if(avr_isp_prog_getch(instance) == CRC_EOP) {
  3885. + avr_isp_prog_tx_ch(instance, STK_INSYNC);
  3886. + avr_isp_prog_tx_ch(instance, result);
  3887. +
  3888. + } else {
  3889. + instance->error++;
  3890. + avr_isp_prog_tx_ch(instance, STK_NOSYNC);
  3891. + }
  3892. + return;
  3893. + }
  3894. + avr_isp_prog_tx_ch(instance, STK_FAILED);
  3895. + return;
  3896. +}
  3897. +
  3898. +static uint8_t avr_isp_prog_flash_read_page(AvrIspProg* instance, uint16_t length) {
  3899. + furi_assert(instance);
  3900. + for(uint16_t x = 0; x < length; x += 2) {
  3901. + avr_isp_prog_tx_ch(
  3902. + instance,
  3903. + avr_isp_prog_spi_transaction(instance, AVR_ISP_READ_FLASH_LO(instance->addr)));
  3904. + avr_isp_prog_tx_ch(
  3905. + instance,
  3906. + avr_isp_prog_spi_transaction(instance, AVR_ISP_READ_FLASH_HI(instance->addr)));
  3907. + instance->addr++;
  3908. + }
  3909. + return STK_OK;
  3910. +}
  3911. +
  3912. +static uint8_t avr_isp_prog_eeprom_read_page(AvrIspProg* instance, uint16_t length) {
  3913. + furi_assert(instance);
  3914. + // here again we have a word address
  3915. + uint16_t start = instance->addr * 2;
  3916. + for(uint16_t x = 0; x < length; x++) {
  3917. + uint16_t addr = start + x;
  3918. + avr_isp_prog_tx_ch(
  3919. + instance, avr_isp_prog_spi_transaction(instance, AVR_ISP_READ_EEPROM(addr)));
  3920. + }
  3921. + return STK_OK;
  3922. +}
  3923. +
  3924. +static void avr_isp_prog_read_page(AvrIspProg* instance) {
  3925. + furi_assert(instance);
  3926. + uint8_t result = STK_FAILED;
  3927. + uint16_t length = avr_isp_prog_getch(instance) << 8 | avr_isp_prog_getch(instance);
  3928. + uint8_t memtype = avr_isp_prog_getch(instance);
  3929. + if(avr_isp_prog_getch(instance) != CRC_EOP) {
  3930. + instance->error++;
  3931. + avr_isp_prog_tx_ch(instance, STK_NOSYNC);
  3932. + return;
  3933. + }
  3934. + avr_isp_prog_tx_ch(instance, STK_INSYNC);
  3935. + if(memtype == STK_SET_FLASH_TYPE) result = avr_isp_prog_flash_read_page(instance, length);
  3936. + if(memtype == STK_SET_EEPROM_TYPE) result = avr_isp_prog_eeprom_read_page(instance, length);
  3937. + avr_isp_prog_tx_ch(instance, result);
  3938. +}
  3939. +
  3940. +static void avr_isp_prog_read_signature(AvrIspProg* instance) {
  3941. + furi_assert(instance);
  3942. + if(avr_isp_prog_getch(instance) != CRC_EOP) {
  3943. + instance->error++;
  3944. + avr_isp_prog_tx_ch(instance, STK_NOSYNC);
  3945. + return;
  3946. + }
  3947. + avr_isp_prog_tx_ch(instance, STK_INSYNC);
  3948. +
  3949. + avr_isp_prog_tx_ch(instance, avr_isp_prog_spi_transaction(instance, AVR_ISP_READ_VENDOR));
  3950. + avr_isp_prog_tx_ch(instance, avr_isp_prog_spi_transaction(instance, AVR_ISP_READ_PART_FAMILY));
  3951. + avr_isp_prog_tx_ch(instance, avr_isp_prog_spi_transaction(instance, AVR_ISP_READ_PART_NUMBER));
  3952. +
  3953. + avr_isp_prog_tx_ch(instance, STK_OK);
  3954. +}
  3955. +
  3956. +void avr_isp_prog_avrisp(AvrIspProg* instance) {
  3957. + furi_assert(instance);
  3958. + uint8_t ch = avr_isp_prog_getch(instance);
  3959. +
  3960. + switch(ch) {
  3961. + case STK_GET_SYNC:
  3962. + FURI_LOG_D(TAG, "cmd STK_GET_SYNC");
  3963. + instance->error = 0;
  3964. + avr_isp_prog_empty_reply(instance);
  3965. + break;
  3966. + case STK_GET_SIGN_ON:
  3967. + FURI_LOG_D(TAG, "cmd STK_GET_SIGN_ON");
  3968. + if(avr_isp_prog_getch(instance) == CRC_EOP) {
  3969. + avr_isp_prog_tx_ch(instance, STK_INSYNC);
  3970. +
  3971. + avr_isp_prog_tx_ch(instance, 'A');
  3972. + avr_isp_prog_tx_ch(instance, 'V');
  3973. + avr_isp_prog_tx_ch(instance, 'R');
  3974. + avr_isp_prog_tx_ch(instance, ' ');
  3975. + avr_isp_prog_tx_ch(instance, 'I');
  3976. + avr_isp_prog_tx_ch(instance, 'S');
  3977. + avr_isp_prog_tx_ch(instance, 'P');
  3978. +
  3979. + avr_isp_prog_tx_ch(instance, STK_OK);
  3980. + } else {
  3981. + instance->error++;
  3982. + avr_isp_prog_tx_ch(instance, STK_NOSYNC);
  3983. + }
  3984. + break;
  3985. + case STK_GET_PARAMETER:
  3986. + FURI_LOG_D(TAG, "cmd STK_GET_PARAMETER");
  3987. + avr_isp_prog_get_version(instance, avr_isp_prog_getch(instance));
  3988. + break;
  3989. + case STK_SET_DEVICE:
  3990. + FURI_LOG_D(TAG, "cmd STK_SET_DEVICE");
  3991. + avr_isp_prog_fill(instance, 20);
  3992. + avr_isp_prog_set_cfg(instance);
  3993. + avr_isp_prog_empty_reply(instance);
  3994. + break;
  3995. + case STK_SET_DEVICE_EXT: // ignore for now
  3996. + FURI_LOG_D(TAG, "cmd STK_SET_DEVICE_EXT");
  3997. + avr_isp_prog_fill(instance, 5);
  3998. + avr_isp_prog_empty_reply(instance);
  3999. + break;
  4000. + case STK_ENTER_PROGMODE:
  4001. + FURI_LOG_D(TAG, "cmd STK_ENTER_PROGMODE");
  4002. + if(!instance->pmode) avr_isp_prog_auto_set_spi_speed_start_pmode(instance);
  4003. + avr_isp_prog_empty_reply(instance);
  4004. + break;
  4005. + case STK_LOAD_ADDRESS:
  4006. + FURI_LOG_D(TAG, "cmd STK_LOAD_ADDRESS");
  4007. + instance->addr = avr_isp_prog_getch(instance) | avr_isp_prog_getch(instance) << 8;
  4008. + avr_isp_prog_empty_reply(instance);
  4009. + break;
  4010. + case STK_PROG_FLASH: // ignore for now
  4011. + FURI_LOG_D(TAG, "cmd STK_PROG_FLASH");
  4012. + avr_isp_prog_getch(instance);
  4013. + avr_isp_prog_getch(instance);
  4014. + avr_isp_prog_empty_reply(instance);
  4015. + break;
  4016. + case STK_PROG_DATA: // ignore for now
  4017. + FURI_LOG_D(TAG, "cmd STK_PROG_DATA");
  4018. + avr_isp_prog_getch(instance);
  4019. + avr_isp_prog_empty_reply(instance);
  4020. + break;
  4021. + case STK_PROG_PAGE:
  4022. + FURI_LOG_D(TAG, "cmd STK_PROG_PAGE");
  4023. + avr_isp_prog_program_page(instance);
  4024. + break;
  4025. + case STK_READ_PAGE:
  4026. + FURI_LOG_D(TAG, "cmd STK_READ_PAGE");
  4027. + avr_isp_prog_read_page(instance);
  4028. + break;
  4029. + case STK_UNIVERSAL:
  4030. + FURI_LOG_D(TAG, "cmd STK_UNIVERSAL");
  4031. + avr_isp_prog_universal(instance);
  4032. + break;
  4033. + case STK_LEAVE_PROGMODE:
  4034. + FURI_LOG_D(TAG, "cmd STK_LEAVE_PROGMODE");
  4035. + instance->error = 0;
  4036. + if(instance->pmode) avr_isp_prog_end_pmode(instance);
  4037. + avr_isp_prog_empty_reply(instance);
  4038. + break;
  4039. + case STK_READ_SIGN:
  4040. + FURI_LOG_D(TAG, "cmd STK_READ_SIGN");
  4041. + avr_isp_prog_read_signature(instance);
  4042. + break;
  4043. + // expecting a command, not CRC_EOP
  4044. + // this is how we can get back in sync
  4045. + case CRC_EOP:
  4046. + FURI_LOG_D(TAG, "cmd CRC_EOP");
  4047. + instance->error++;
  4048. + avr_isp_prog_tx_ch(instance, STK_NOSYNC);
  4049. + break;
  4050. + // anything else we will return STK_UNKNOWN
  4051. + default:
  4052. + FURI_LOG_D(TAG, "cmd STK_ERROR_CMD");
  4053. + instance->error++;
  4054. + if(avr_isp_prog_getch(instance) == CRC_EOP)
  4055. + avr_isp_prog_tx_ch(instance, STK_UNKNOWN);
  4056. + else
  4057. + avr_isp_prog_tx_ch(instance, STK_NOSYNC);
  4058. + }
  4059. +
  4060. + if(instance->callback) {
  4061. + instance->callback(instance->context);
  4062. + }
  4063. +}
  4064. diff --git a/applications/external/avr_isp_programmer/lib/driver/avr_isp_prog.h b/applications/external/avr_isp_programmer/lib/driver/avr_isp_prog.h
  4065. new file mode 100644
  4066. index 000000000..2c15ab066
  4067. --- /dev/null
  4068. +++ b/applications/external/avr_isp_programmer/lib/driver/avr_isp_prog.h
  4069. @@ -0,0 +1,16 @@
  4070. +#pragma once
  4071. +
  4072. +#include "avr_isp_spi_sw.h"
  4073. +#include <furi_hal.h>
  4074. +
  4075. +typedef struct AvrIspProg AvrIspProg;
  4076. +typedef void (*AvrIspProgCallback)(void* context);
  4077. +
  4078. +AvrIspProg* avr_isp_prog_init(void);
  4079. +void avr_isp_prog_free(AvrIspProg* instance);
  4080. +size_t avr_isp_prog_spaces_rx(AvrIspProg* instance) ;
  4081. +bool avr_isp_prog_rx(AvrIspProg* instance, uint8_t* data, size_t len);
  4082. +size_t avr_isp_prog_tx(AvrIspProg* instance, uint8_t* data, size_t max_len);
  4083. +void avr_isp_prog_avrisp(AvrIspProg* instance);
  4084. +void avr_isp_prog_exit(AvrIspProg* instance);
  4085. +void avr_isp_prog_set_tx_callback(AvrIspProg* instance, AvrIspProgCallback callback, void* context);
  4086. diff --git a/applications/external/avr_isp_programmer/lib/driver/avr_isp_prog_cmd.h b/applications/external/avr_isp_programmer/lib/driver/avr_isp_prog_cmd.h
  4087. new file mode 100644
  4088. index 000000000..f8b07203e
  4089. --- /dev/null
  4090. +++ b/applications/external/avr_isp_programmer/lib/driver/avr_isp_prog_cmd.h
  4091. @@ -0,0 +1,97 @@
  4092. +#pragma once
  4093. +
  4094. +// http://ww1.microchip.com/downloads/en/appnotes/atmel-0943-in-system-programming_applicationnote_avr910.pdf
  4095. +// AVR ISP Definitions
  4096. +#define AVR_ISP_HWVER 0X02
  4097. +#define AVR_ISP_SWMAJ 0X01
  4098. +#define AVR_ISP_SWMIN 0X12
  4099. +#define AVP_ISP_SERIAL_CONNECT_TYPE 0X53
  4100. +#define AVP_ISP_CONNECT_TYPE 0x93
  4101. +#define AVR_ISP_RESP_0 0X00
  4102. +
  4103. +#define AVR_ISP_SET_PMODE 0xAC, 0x53, 0x00, 0x00
  4104. +#define AVR_ISP_READ_VENDOR 0x30, 0x00, 0x00, 0x00
  4105. +#define AVR_ISP_READ_PART_FAMILY 0x30, 0x00, 0x01, 0x00
  4106. +#define AVR_ISP_READ_PART_NUMBER 0x30, 0x00, 0x02, 0x00
  4107. +#define AVR_ISP_ERASE_CHIP \
  4108. + 0xAC, 0x80, 0x00, 0x00 //Erase Chip, Wait N ms, Release RESET to end the erase.
  4109. +//The only way to end a Chip Erase cycle is by temporarily releasing the Reset line
  4110. +
  4111. +#define AVR_ISP_EXTENDED_ADDR(data) 0x4D, 0x00, data, 0x00
  4112. +#define AVR_ISP_WRITE_FLASH_LO(add, data) 0x40, (add >> 8) & 0xFF, add & 0xFF, data
  4113. +#define AVR_ISP_WRITE_FLASH_HI(add, data) 0x48, (add >> 8) & 0xFF, add & 0xFF, data
  4114. +#define AVR_ISP_READ_FLASH_LO(add) 0x20, (add >> 8) & 0xFF, add & 0xFF, 0x00
  4115. +#define AVR_ISP_READ_FLASH_HI(add) 0x28, (add >> 8) & 0xFF, add & 0xFF, 0x00
  4116. +
  4117. +#define AVR_ISP_WRITE_EEPROM(add, data) \
  4118. + 0xC0, (add >> 8) & 0xFF, add & 0xFF, data //Send cmd, Wait N ms
  4119. +#define AVR_ISP_READ_EEPROM(add) 0xA0, (add >> 8) & 0xFF, add & 0xFF, 0xFF
  4120. +
  4121. +#define AVR_ISP_COMMIT(add) \
  4122. + 0x4C, (add >> 8) & 0xFF, add & 0xFF, 0x00 //Send cmd, polling read last addr page
  4123. +
  4124. +#define AVR_ISP_OSCCAL(add) 0x38, 0x00, add, 0x00
  4125. +
  4126. +#define AVR_ISP_WRITE_LOCK_BYTE(data) 0xAC, 0xE0, 0x00, data //Send cmd, Wait N ms
  4127. +#define AVR_ISP_READ_LOCK_BYTE 0x58, 0x00, 0x00, 0x00
  4128. +#define AVR_ISP_WRITE_FUSE_LOW(data) 0xAC, 0xA0, 0x00, data //Send cmd, Wait N ms
  4129. +#define AVR_ISP_READ_FUSE_LOW 0x50, 0x00, 0x00, 0x00
  4130. +#define AVR_ISP_WRITE_FUSE_HIGH(data) 0xAC, 0xA8, 0x00, data //Send cmd, Wait N ms
  4131. +#define AVR_ISP_READ_FUSE_HIGH 0x58, 0x08, 0x00, 0x00
  4132. +#define AVR_ISP_WRITE_FUSE_EXTENDED(data) 0xAC, 0xA4, 0x00, data //Send cmd, Wait N ms (~write)
  4133. +#define AVR_ISP_READ_FUSE_EXTENDED 0x50, 0x08, 0x00, 0x00
  4134. +
  4135. +#define AVR_ISP_EECHUNK 0x20
  4136. +
  4137. +// https://www.microchip.com/content/dam/mchp/documents/OTH/ApplicationNotes/ApplicationNotes/doc2525.pdf
  4138. +// STK Definitions
  4139. +#define STK_OK 0x10
  4140. +#define STK_FAILED 0x11
  4141. +#define STK_UNKNOWN 0x12
  4142. +#define STK_INSYNC 0x14
  4143. +#define STK_NOSYNC 0x15
  4144. +#define CRC_EOP 0x20
  4145. +
  4146. +#define STK_GET_SYNC 0x30
  4147. +#define STK_GET_SIGN_ON 0x31
  4148. +#define STK_SET_PARAMETER 0x40
  4149. +#define STK_GET_PARAMETER 0x41
  4150. +#define STK_SET_DEVICE 0x42
  4151. +#define STK_SET_DEVICE_EXT 0x45
  4152. +#define STK_ENTER_PROGMODE 0x50
  4153. +#define STK_LEAVE_PROGMODE 0x51
  4154. +#define STK_CHIP_ERASE 0x52
  4155. +#define STK_CHECK_AUTOINC 0x53
  4156. +#define STK_LOAD_ADDRESS 0x55
  4157. +#define STK_UNIVERSAL 0x56
  4158. +#define STK_UNIVERSAL_MULTI 0x57
  4159. +#define STK_PROG_FLASH 0x60
  4160. +#define STK_PROG_DATA 0x61
  4161. +#define STK_PROG_FUSE 0x62
  4162. +#define STK_PROG_FUSE_EXT 0x65
  4163. +#define STK_PROG_LOCK 0x63
  4164. +#define STK_PROG_PAGE 0x64
  4165. +#define STK_READ_FLASH 0x70
  4166. +#define STK_READ_DATA 0x71
  4167. +#define STK_READ_FUSE 0x72
  4168. +#define STK_READ_LOCK 0x73
  4169. +#define STK_READ_PAGE 0x74
  4170. +#define STK_READ_SIGN 0x75
  4171. +#define STK_READ_OSCCAL 0x76
  4172. +#define STK_READ_FUSE_EXT 0x77
  4173. +#define STK_READ_OSCCAL_EXT 0x78
  4174. +#define STK_HW_VER 0x80
  4175. +#define STK_SW_MAJOR 0x81
  4176. +#define STK_SW_MINOR 0x82
  4177. +#define STK_LEDS 0x83
  4178. +#define STK_VTARGET 0x84
  4179. +#define STK_VADJUST 0x85
  4180. +#define STK_OSC_PSCALE 0x86
  4181. +#define STK_OSC_CMATCH 0x87
  4182. +#define STK_SCK_DURATION 0x89
  4183. +#define STK_BUFSIZEL 0x90
  4184. +#define STK_BUFSIZEH 0x91
  4185. +#define STK_STK500_TOPCARD_DETECT 0x98
  4186. +
  4187. +#define STK_SET_EEPROM_TYPE 0X45
  4188. +#define STK_SET_FLASH_TYPE 0X46
  4189. diff --git a/applications/external/avr_isp_programmer/lib/driver/avr_isp_spi_sw.c b/applications/external/avr_isp_programmer/lib/driver/avr_isp_spi_sw.c
  4190. new file mode 100644
  4191. index 000000000..f60850c84
  4192. --- /dev/null
  4193. +++ b/applications/external/avr_isp_programmer/lib/driver/avr_isp_spi_sw.c
  4194. @@ -0,0 +1,73 @@
  4195. +#include "avr_isp_spi_sw.h"
  4196. +
  4197. +#include <furi.h>
  4198. +
  4199. +#define AVR_ISP_SPI_SW_MISO &gpio_ext_pa6
  4200. +#define AVR_ISP_SPI_SW_MOSI &gpio_ext_pa7
  4201. +#define AVR_ISP_SPI_SW_SCK &gpio_ext_pb3
  4202. +#define AVR_ISP_RESET &gpio_ext_pb2
  4203. +
  4204. +struct AvrIspSpiSw {
  4205. + AvrIspSpiSwSpeed speed_wait_time;
  4206. + const GpioPin* miso;
  4207. + const GpioPin* mosi;
  4208. + const GpioPin* sck;
  4209. + const GpioPin* res;
  4210. +};
  4211. +
  4212. +AvrIspSpiSw* avr_isp_spi_sw_init(AvrIspSpiSwSpeed speed) {
  4213. + AvrIspSpiSw* instance = malloc(sizeof(AvrIspSpiSw));
  4214. + instance->speed_wait_time = speed;
  4215. +
  4216. + instance->miso = AVR_ISP_SPI_SW_MISO;
  4217. + instance->mosi = AVR_ISP_SPI_SW_MOSI;
  4218. + instance->sck = AVR_ISP_SPI_SW_SCK;
  4219. + instance->res = AVR_ISP_RESET;
  4220. +
  4221. + furi_hal_gpio_init(instance->miso, GpioModeInput, GpioPullNo, GpioSpeedVeryHigh);
  4222. + furi_hal_gpio_write(instance->mosi, false);
  4223. + furi_hal_gpio_init(instance->mosi, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh);
  4224. + furi_hal_gpio_write(instance->sck, false);
  4225. + furi_hal_gpio_init(instance->sck, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh);
  4226. + furi_hal_gpio_init(instance->res, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh);
  4227. +
  4228. + return instance;
  4229. +}
  4230. +
  4231. +void avr_isp_spi_sw_free(AvrIspSpiSw* instance) {
  4232. + furi_assert(instance);
  4233. + furi_hal_gpio_init(instance->res, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
  4234. + furi_hal_gpio_init(instance->miso, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
  4235. + furi_hal_gpio_init(instance->mosi, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
  4236. + furi_hal_gpio_init(instance->sck, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
  4237. +
  4238. + free(instance);
  4239. +}
  4240. +
  4241. +uint8_t avr_isp_spi_sw_txrx(AvrIspSpiSw* instance, uint8_t data) {
  4242. + furi_assert(instance);
  4243. + for(uint8_t i = 0; i < 8; ++i) {
  4244. + furi_hal_gpio_write(instance->mosi, (data & 0x80) ? true : false);
  4245. +
  4246. + furi_hal_gpio_write(instance->sck, true);
  4247. + if(instance->speed_wait_time != AvrIspSpiSwSpeed1Mhz)
  4248. + furi_delay_us(instance->speed_wait_time - 1);
  4249. +
  4250. + data = (data << 1) | furi_hal_gpio_read(instance->miso); //-V792
  4251. +
  4252. + furi_hal_gpio_write(instance->sck, false);
  4253. + if(instance->speed_wait_time != AvrIspSpiSwSpeed1Mhz)
  4254. + furi_delay_us(instance->speed_wait_time - 1);
  4255. + }
  4256. + return data;
  4257. +}
  4258. +
  4259. +void avr_isp_spi_sw_res_set(AvrIspSpiSw* instance, bool state) {
  4260. + furi_assert(instance);
  4261. + furi_hal_gpio_write(instance->res, state);
  4262. +}
  4263. +
  4264. +void avr_isp_spi_sw_sck_set(AvrIspSpiSw* instance, bool state) {
  4265. + furi_assert(instance);
  4266. + furi_hal_gpio_write(instance->sck, state);
  4267. +}
  4268. \ No newline at end of file
  4269. diff --git a/applications/external/avr_isp_programmer/lib/driver/avr_isp_spi_sw.h b/applications/external/avr_isp_programmer/lib/driver/avr_isp_spi_sw.h
  4270. new file mode 100644
  4271. index 000000000..44de5ff79
  4272. --- /dev/null
  4273. +++ b/applications/external/avr_isp_programmer/lib/driver/avr_isp_spi_sw.h
  4274. @@ -0,0 +1,24 @@
  4275. +#pragma once
  4276. +
  4277. +#include <furi_hal.h>
  4278. +
  4279. +typedef enum {
  4280. + AvrIspSpiSwSpeed1Mhz = 0,
  4281. + AvrIspSpiSwSpeed400Khz = 1,
  4282. + AvrIspSpiSwSpeed250Khz = 2,
  4283. + AvrIspSpiSwSpeed125Khz = 4,
  4284. + AvrIspSpiSwSpeed60Khz = 8,
  4285. + AvrIspSpiSwSpeed40Khz = 12,
  4286. + AvrIspSpiSwSpeed20Khz = 24,
  4287. + AvrIspSpiSwSpeed10Khz = 48,
  4288. + AvrIspSpiSwSpeed5Khz = 96,
  4289. + AvrIspSpiSwSpeed1Khz = 480,
  4290. +} AvrIspSpiSwSpeed;
  4291. +
  4292. +typedef struct AvrIspSpiSw AvrIspSpiSw;
  4293. +
  4294. +AvrIspSpiSw* avr_isp_spi_sw_init(AvrIspSpiSwSpeed speed);
  4295. +void avr_isp_spi_sw_free(AvrIspSpiSw* instance);
  4296. +uint8_t avr_isp_spi_sw_txrx(AvrIspSpiSw* instance, uint8_t data);
  4297. +void avr_isp_spi_sw_res_set(AvrIspSpiSw* instance, bool state);
  4298. +void avr_isp_spi_sw_sck_set(AvrIspSpiSw* instance, bool state);
  4299. \ No newline at end of file
  4300. diff --git a/applications/external/avr_isp_programmer/lib/driver/clock.png b/applications/external/avr_isp_programmer/lib/driver/clock.png
  4301. new file mode 100644
  4302. index 000000000..93a59fe68
  4303. Binary files /dev/null and b/applications/external/avr_isp_programmer/lib/driver/clock.png differ
  4304. diff --git a/applications/external/avr_isp_programmer/scenes/avr_isp_scene.c b/applications/external/avr_isp_programmer/scenes/avr_isp_scene.c
  4305. new file mode 100644
  4306. index 000000000..4af125aee
  4307. --- /dev/null
  4308. +++ b/applications/external/avr_isp_programmer/scenes/avr_isp_scene.c
  4309. @@ -0,0 +1,30 @@
  4310. +#include "../avr_isp_app_i.h"
  4311. +
  4312. +// Generate scene on_enter handlers array
  4313. +#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_enter,
  4314. +void (*const avr_isp_scene_on_enter_handlers[])(void*) = {
  4315. +#include "avr_isp_scene_config.h"
  4316. +};
  4317. +#undef ADD_SCENE
  4318. +
  4319. +// Generate scene on_event handlers array
  4320. +#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_event,
  4321. +bool (*const avr_isp_scene_on_event_handlers[])(void* context, SceneManagerEvent event) = {
  4322. +#include "avr_isp_scene_config.h"
  4323. +};
  4324. +#undef ADD_SCENE
  4325. +
  4326. +// Generate scene on_exit handlers array
  4327. +#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_exit,
  4328. +void (*const avr_isp_scene_on_exit_handlers[])(void* context) = {
  4329. +#include "avr_isp_scene_config.h"
  4330. +};
  4331. +#undef ADD_SCENE
  4332. +
  4333. +// Initialize scene handlers configuration structure
  4334. +const SceneManagerHandlers avr_isp_scene_handlers = {
  4335. + .on_enter_handlers = avr_isp_scene_on_enter_handlers,
  4336. + .on_event_handlers = avr_isp_scene_on_event_handlers,
  4337. + .on_exit_handlers = avr_isp_scene_on_exit_handlers,
  4338. + .scene_num = AvrIspSceneNum,
  4339. +};
  4340. diff --git a/applications/external/avr_isp_programmer/scenes/avr_isp_scene.h b/applications/external/avr_isp_programmer/scenes/avr_isp_scene.h
  4341. new file mode 100644
  4342. index 000000000..658ee7432
  4343. --- /dev/null
  4344. +++ b/applications/external/avr_isp_programmer/scenes/avr_isp_scene.h
  4345. @@ -0,0 +1,29 @@
  4346. +#pragma once
  4347. +
  4348. +#include <gui/scene_manager.h>
  4349. +
  4350. +// Generate scene id and total number
  4351. +#define ADD_SCENE(prefix, name, id) AvrIspScene##id,
  4352. +typedef enum {
  4353. +#include "avr_isp_scene_config.h"
  4354. + AvrIspSceneNum,
  4355. +} AvrIspScene;
  4356. +#undef ADD_SCENE
  4357. +
  4358. +extern const SceneManagerHandlers avr_isp_scene_handlers;
  4359. +
  4360. +// Generate scene on_enter handlers declaration
  4361. +#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_enter(void*);
  4362. +#include "avr_isp_scene_config.h"
  4363. +#undef ADD_SCENE
  4364. +
  4365. +// Generate scene on_event handlers declaration
  4366. +#define ADD_SCENE(prefix, name, id) \
  4367. + bool prefix##_scene_##name##_on_event(void* context, SceneManagerEvent event);
  4368. +#include "avr_isp_scene_config.h"
  4369. +#undef ADD_SCENE
  4370. +
  4371. +// Generate scene on_exit handlers declaration
  4372. +#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_exit(void* context);
  4373. +#include "avr_isp_scene_config.h"
  4374. +#undef ADD_SCENE
  4375. diff --git a/applications/external/avr_isp_programmer/scenes/avr_isp_scene_about.c b/applications/external/avr_isp_programmer/scenes/avr_isp_scene_about.c
  4376. new file mode 100644
  4377. index 000000000..e5f530fec
  4378. --- /dev/null
  4379. +++ b/applications/external/avr_isp_programmer/scenes/avr_isp_scene_about.c
  4380. @@ -0,0 +1,99 @@
  4381. +#include "../avr_isp_app_i.h"
  4382. +#include "../helpers/avr_isp_types.h"
  4383. +
  4384. +void avr_isp_scene_about_widget_callback(GuiButtonType result, InputType type, void* context) {
  4385. + furi_assert(context);
  4386. +
  4387. + AvrIspApp* app = context;
  4388. + if(type == InputTypeShort) {
  4389. + view_dispatcher_send_custom_event(app->view_dispatcher, result);
  4390. + }
  4391. +}
  4392. +
  4393. +void avr_isp_scene_about_on_enter(void* context) {
  4394. + furi_assert(context);
  4395. +
  4396. + AvrIspApp* app = context;
  4397. + FuriString* temp_str = furi_string_alloc();
  4398. + furi_string_printf(temp_str, "\e#%s\n", "Information");
  4399. +
  4400. + furi_string_cat_printf(temp_str, "Version: %s\n", AVR_ISP_VERSION_APP);
  4401. + furi_string_cat_printf(temp_str, "Developed by: %s\n", AVR_ISP_DEVELOPED);
  4402. + furi_string_cat_printf(temp_str, "Github: %s\n\n", AVR_ISP_GITHUB);
  4403. +
  4404. + furi_string_cat_printf(temp_str, "\e#%s\n", "Description");
  4405. + furi_string_cat_printf(
  4406. + temp_str,
  4407. + "This application is an AVR in-system programmer based on stk500mk1. It is compatible with AVR-based"
  4408. + " microcontrollers including Arduino. You can also use it to repair the chip if you accidentally"
  4409. + " corrupt the bootloader.\n\n");
  4410. +
  4411. + furi_string_cat_printf(temp_str, "\e#%s\n", "What it can do:");
  4412. + furi_string_cat_printf(temp_str, "- Create a dump of your chip on an SD card\n");
  4413. + furi_string_cat_printf(temp_str, "- Flash your chip firmware from the SD card\n");
  4414. + furi_string_cat_printf(temp_str, "- Act as a wired USB ISP using avrdude software\n\n");
  4415. +
  4416. + furi_string_cat_printf(temp_str, "\e#%s\n", "Supported chip series:");
  4417. + furi_string_cat_printf(
  4418. + temp_str,
  4419. + "Example command for avrdude flashing: avrdude.exe -p m328p -c stk500v1 -P COMxx -U flash:r:"
  4420. + "X:\\sketch_sample.hex"
  4421. + ":i\n");
  4422. + furi_string_cat_printf(
  4423. + temp_str,
  4424. + "Where: "
  4425. + "-p m328p"
  4426. + " brand of your chip, "
  4427. + "-P COMxx"
  4428. + " com port number in the system when "
  4429. + "ISP Programmer"
  4430. + " is enabled\n\n");
  4431. +
  4432. + furi_string_cat_printf(temp_str, "\e#%s\n", "Info");
  4433. + furi_string_cat_printf(
  4434. + temp_str,
  4435. + "ATtinyXXXX\nATmegaXXXX\nAT43Uxxx\nAT76C711\nAT86RF401\nAT90xxxxx\nAT94K\n"
  4436. + "ATAxxxxx\nATA664251\nM3000\nLGT8F88P\nLGT8F168P\nLGT8F328P\n");
  4437. +
  4438. + furi_string_cat_printf(
  4439. + temp_str, "For a more detailed list of supported chips, see AVRDude help\n");
  4440. +
  4441. + widget_add_text_box_element(
  4442. + app->widget,
  4443. + 0,
  4444. + 0,
  4445. + 128,
  4446. + 14,
  4447. + AlignCenter,
  4448. + AlignBottom,
  4449. + "\e#\e! \e!\n",
  4450. + false);
  4451. + widget_add_text_box_element(
  4452. + app->widget,
  4453. + 0,
  4454. + 2,
  4455. + 128,
  4456. + 14,
  4457. + AlignCenter,
  4458. + AlignBottom,
  4459. + "\e#\e! ISP Programmer \e!\n",
  4460. + false);
  4461. + widget_add_text_scroll_element(app->widget, 0, 16, 128, 50, furi_string_get_cstr(temp_str));
  4462. + furi_string_free(temp_str);
  4463. +
  4464. + view_dispatcher_switch_to_view(app->view_dispatcher, AvrIspViewWidget);
  4465. +}
  4466. +
  4467. +bool avr_isp_scene_about_on_event(void* context, SceneManagerEvent event) {
  4468. + UNUSED(context);
  4469. + UNUSED(event);
  4470. + return false;
  4471. +}
  4472. +
  4473. +void avr_isp_scene_about_on_exit(void* context) {
  4474. + furi_assert(context);
  4475. +
  4476. + AvrIspApp* app = context;
  4477. + // Clear views
  4478. + widget_reset(app->widget);
  4479. +}
  4480. diff --git a/applications/external/avr_isp_programmer/scenes/avr_isp_scene_chip_detect.c b/applications/external/avr_isp_programmer/scenes/avr_isp_scene_chip_detect.c
  4481. new file mode 100644
  4482. index 000000000..79c239390
  4483. --- /dev/null
  4484. +++ b/applications/external/avr_isp_programmer/scenes/avr_isp_scene_chip_detect.c
  4485. @@ -0,0 +1,72 @@
  4486. +#include "../avr_isp_app_i.h"
  4487. +
  4488. +void avr_isp_scene_chip_detect_callback(AvrIspCustomEvent event, void* context) {
  4489. + furi_assert(context);
  4490. +
  4491. + AvrIspApp* app = context;
  4492. + view_dispatcher_send_custom_event(app->view_dispatcher, event);
  4493. +}
  4494. +
  4495. +void avr_isp_scene_chip_detect_on_enter(void* context) {
  4496. + furi_assert(context);
  4497. +
  4498. + AvrIspApp* app = context;
  4499. + switch(app->error) {
  4500. + case AvrIspErrorReading:
  4501. + case AvrIspErrorWriting:
  4502. + case AvrIspErrorWritingFuse:
  4503. + avr_isp_chip_detect_set_state(
  4504. + app->avr_isp_chip_detect_view, AvrIspChipDetectViewStateErrorOccured);
  4505. + break;
  4506. + case AvrIspErrorVerification:
  4507. + avr_isp_chip_detect_set_state(
  4508. + app->avr_isp_chip_detect_view, AvrIspChipDetectViewStateErrorVerification);
  4509. + break;
  4510. +
  4511. + default:
  4512. + avr_isp_chip_detect_set_state(
  4513. + app->avr_isp_chip_detect_view, AvrIspChipDetectViewStateNoDetect);
  4514. + break;
  4515. + }
  4516. + app->error = AvrIspErrorNoError;
  4517. + avr_isp_chip_detect_view_set_callback(
  4518. + app->avr_isp_chip_detect_view, avr_isp_scene_chip_detect_callback, app);
  4519. +
  4520. + view_dispatcher_switch_to_view(app->view_dispatcher, AvrIspViewChipDetect);
  4521. +}
  4522. +
  4523. +bool avr_isp_scene_chip_detect_on_event(void* context, SceneManagerEvent event) {
  4524. + furi_assert(context);
  4525. +
  4526. + AvrIspApp* app = context;
  4527. + bool consumed = false;
  4528. + if(event.type == SceneManagerEventTypeCustom) {
  4529. + switch(event.event) {
  4530. + case AvrIspCustomEventSceneChipDetectOk:
  4531. +
  4532. + if(scene_manager_get_scene_state(app->scene_manager, AvrIspSceneChipDetect) ==
  4533. + AvrIspViewProgrammer) {
  4534. + scene_manager_next_scene(app->scene_manager, AvrIspSceneProgrammer);
  4535. + } else if(
  4536. + scene_manager_get_scene_state(app->scene_manager, AvrIspSceneChipDetect) ==
  4537. + AvrIspViewReader) {
  4538. + scene_manager_next_scene(app->scene_manager, AvrIspSceneInputName);
  4539. + } else if(
  4540. + scene_manager_get_scene_state(app->scene_manager, AvrIspSceneChipDetect) ==
  4541. + AvrIspViewWriter) {
  4542. + scene_manager_next_scene(app->scene_manager, AvrIspSceneLoad);
  4543. + }
  4544. +
  4545. + consumed = true;
  4546. + break;
  4547. + default:
  4548. + break;
  4549. + }
  4550. + } else if(event.type == SceneManagerEventTypeTick) {
  4551. + }
  4552. + return consumed;
  4553. +}
  4554. +
  4555. +void avr_isp_scene_chip_detect_on_exit(void* context) {
  4556. + UNUSED(context);
  4557. +}
  4558. diff --git a/applications/external/avr_isp_programmer/scenes/avr_isp_scene_config.h b/applications/external/avr_isp_programmer/scenes/avr_isp_scene_config.h
  4559. new file mode 100644
  4560. index 000000000..6f22511db
  4561. --- /dev/null
  4562. +++ b/applications/external/avr_isp_programmer/scenes/avr_isp_scene_config.h
  4563. @@ -0,0 +1,10 @@
  4564. +ADD_SCENE(avr_isp, start, Start)
  4565. +ADD_SCENE(avr_isp, about, About)
  4566. +ADD_SCENE(avr_isp, programmer, Programmer)
  4567. +ADD_SCENE(avr_isp, reader, Reader)
  4568. +ADD_SCENE(avr_isp, input_name, InputName)
  4569. +ADD_SCENE(avr_isp, load, Load)
  4570. +ADD_SCENE(avr_isp, writer, Writer)
  4571. +ADD_SCENE(avr_isp, wiring, Wiring)
  4572. +ADD_SCENE(avr_isp, chip_detect, ChipDetect)
  4573. +ADD_SCENE(avr_isp, success, Success)
  4574. diff --git a/applications/external/avr_isp_programmer/scenes/avr_isp_scene_input_name.c b/applications/external/avr_isp_programmer/scenes/avr_isp_scene_input_name.c
  4575. new file mode 100644
  4576. index 000000000..3394f4362
  4577. --- /dev/null
  4578. +++ b/applications/external/avr_isp_programmer/scenes/avr_isp_scene_input_name.c
  4579. @@ -0,0 +1,89 @@
  4580. +#include "../avr_isp_app_i.h"
  4581. +#include <gui/modules/validators.h>
  4582. +
  4583. +#define MAX_TEXT_INPUT_LEN 22
  4584. +
  4585. +void avr_isp_scene_input_name_text_callback(void* context) {
  4586. + furi_assert(context);
  4587. +
  4588. + AvrIspApp* app = context;
  4589. + view_dispatcher_send_custom_event(app->view_dispatcher, AvrIspCustomEventSceneInputName);
  4590. +}
  4591. +
  4592. +void avr_isp_scene_input_name_get_timefilename(FuriString* name) {
  4593. + FuriHalRtcDateTime datetime = {0};
  4594. + furi_hal_rtc_get_datetime(&datetime);
  4595. + furi_string_printf(
  4596. + name,
  4597. + "AVR_dump-%.4d%.2d%.2d-%.2d%.2d%.2d",
  4598. + datetime.year,
  4599. + datetime.month,
  4600. + datetime.day,
  4601. + datetime.hour,
  4602. + datetime.minute,
  4603. + datetime.second);
  4604. +}
  4605. +
  4606. +void avr_isp_scene_input_name_on_enter(void* context) {
  4607. + furi_assert(context);
  4608. +
  4609. + AvrIspApp* app = context;
  4610. + // Setup view
  4611. + TextInput* text_input = app->text_input;
  4612. + bool dev_name_empty = false;
  4613. +
  4614. + FuriString* file_name = furi_string_alloc();
  4615. +
  4616. + avr_isp_scene_input_name_get_timefilename(file_name);
  4617. + furi_string_set(app->file_path, STORAGE_APP_DATA_PATH_PREFIX);
  4618. + //highlighting the entire filename by default
  4619. + dev_name_empty = true;
  4620. +
  4621. + strncpy(app->file_name_tmp, furi_string_get_cstr(file_name), AVR_ISP_MAX_LEN_NAME);
  4622. + text_input_set_header_text(text_input, "Name dump");
  4623. + text_input_set_result_callback(
  4624. + text_input,
  4625. + avr_isp_scene_input_name_text_callback,
  4626. + app,
  4627. + app->file_name_tmp,
  4628. + MAX_TEXT_INPUT_LEN, // buffer size
  4629. + dev_name_empty);
  4630. +
  4631. + ValidatorIsFile* validator_is_file =
  4632. + validator_is_file_alloc_init(STORAGE_APP_DATA_PATH_PREFIX, AVR_ISP_APP_EXTENSION, "");
  4633. + text_input_set_validator(text_input, validator_is_file_callback, validator_is_file);
  4634. +
  4635. + furi_string_free(file_name);
  4636. +
  4637. + view_dispatcher_switch_to_view(app->view_dispatcher, AvrIspViewTextInput);
  4638. +}
  4639. +
  4640. +bool avr_isp_scene_input_name_on_event(void* context, SceneManagerEvent event) {
  4641. + furi_assert(context);
  4642. +
  4643. + AvrIspApp* app = context;
  4644. + if(event.type == SceneManagerEventTypeBack) {
  4645. + scene_manager_previous_scene(app->scene_manager);
  4646. + return true;
  4647. + } else if(event.type == SceneManagerEventTypeCustom) {
  4648. + if(event.event == AvrIspCustomEventSceneInputName) {
  4649. + if(strcmp(app->file_name_tmp, "") != 0) {
  4650. + scene_manager_next_scene(app->scene_manager, AvrIspSceneReader);
  4651. + } else {
  4652. + }
  4653. + }
  4654. + }
  4655. + return false;
  4656. +}
  4657. +
  4658. +void avr_isp_scene_input_name_on_exit(void* context) {
  4659. + furi_assert(context);
  4660. +
  4661. + AvrIspApp* app = context;
  4662. + // Clear validator
  4663. + void* validator_context = text_input_get_validator_callback_context(app->text_input);
  4664. + text_input_set_validator(app->text_input, NULL, NULL);
  4665. + validator_is_file_free(validator_context);
  4666. + // Clear view
  4667. + text_input_reset(app->text_input);
  4668. +}
  4669. diff --git a/applications/external/avr_isp_programmer/scenes/avr_isp_scene_load.c b/applications/external/avr_isp_programmer/scenes/avr_isp_scene_load.c
  4670. new file mode 100644
  4671. index 000000000..e8890e373
  4672. --- /dev/null
  4673. +++ b/applications/external/avr_isp_programmer/scenes/avr_isp_scene_load.c
  4674. @@ -0,0 +1,22 @@
  4675. +#include "../avr_isp_app_i.h"
  4676. +
  4677. +void avr_isp_scene_load_on_enter(void* context) {
  4678. + furi_assert(context);
  4679. +
  4680. + AvrIspApp* app = context;
  4681. + if(avr_isp_load_from_file(app)) {
  4682. + scene_manager_next_scene(app->scene_manager, AvrIspSceneWriter);
  4683. + } else {
  4684. + scene_manager_previous_scene(app->scene_manager);
  4685. + }
  4686. +}
  4687. +
  4688. +bool avr_isp_scene_load_on_event(void* context, SceneManagerEvent event) {
  4689. + UNUSED(context);
  4690. + UNUSED(event);
  4691. + return false;
  4692. +}
  4693. +
  4694. +void avr_isp_scene_load_on_exit(void* context) {
  4695. + UNUSED(context);
  4696. +}
  4697. diff --git a/applications/external/avr_isp_programmer/scenes/avr_isp_scene_programmer.c b/applications/external/avr_isp_programmer/scenes/avr_isp_scene_programmer.c
  4698. new file mode 100644
  4699. index 000000000..0915e1e8a
  4700. --- /dev/null
  4701. +++ b/applications/external/avr_isp_programmer/scenes/avr_isp_scene_programmer.c
  4702. @@ -0,0 +1,28 @@
  4703. +#include "../avr_isp_app_i.h"
  4704. +
  4705. +void avr_isp_scene_programmer_callback(AvrIspCustomEvent event, void* context) {
  4706. + furi_assert(context);
  4707. +
  4708. + AvrIspApp* app = context;
  4709. + view_dispatcher_send_custom_event(app->view_dispatcher, event);
  4710. +}
  4711. +
  4712. +void avr_isp_scene_programmer_on_enter(void* context) {
  4713. + furi_assert(context);
  4714. +
  4715. + AvrIspApp* app = context;
  4716. + avr_isp_programmer_view_set_callback(
  4717. + app->avr_isp_programmer_view, avr_isp_scene_programmer_callback, app);
  4718. +
  4719. + view_dispatcher_switch_to_view(app->view_dispatcher, AvrIspViewProgrammer);
  4720. +}
  4721. +
  4722. +bool avr_isp_scene_programmer_on_event(void* context, SceneManagerEvent event) {
  4723. + UNUSED(context);
  4724. + UNUSED(event);
  4725. + return false;
  4726. +}
  4727. +
  4728. +void avr_isp_scene_programmer_on_exit(void* context) {
  4729. + UNUSED(context);
  4730. +}
  4731. diff --git a/applications/external/avr_isp_programmer/scenes/avr_isp_scene_reader.c b/applications/external/avr_isp_programmer/scenes/avr_isp_scene_reader.c
  4732. new file mode 100644
  4733. index 000000000..8dcb47597
  4734. --- /dev/null
  4735. +++ b/applications/external/avr_isp_programmer/scenes/avr_isp_scene_reader.c
  4736. @@ -0,0 +1,64 @@
  4737. +#include "../avr_isp_app_i.h"
  4738. +
  4739. +void avr_isp_scene_reader_callback(AvrIspCustomEvent event, void* context) {
  4740. + furi_assert(context);
  4741. +
  4742. + AvrIspApp* app = context;
  4743. + view_dispatcher_send_custom_event(app->view_dispatcher, event);
  4744. +}
  4745. +
  4746. +void avr_isp_scene_reader_on_enter(void* context) {
  4747. + furi_assert(context);
  4748. +
  4749. + AvrIspApp* app = context;
  4750. + avr_isp_reader_set_file_path(
  4751. + app->avr_isp_reader_view, furi_string_get_cstr(app->file_path), app->file_name_tmp);
  4752. + avr_isp_reader_view_set_callback(app->avr_isp_reader_view, avr_isp_scene_reader_callback, app);
  4753. +
  4754. + view_dispatcher_switch_to_view(app->view_dispatcher, AvrIspViewReader);
  4755. +}
  4756. +
  4757. +bool avr_isp_scene_reader_on_event(void* context, SceneManagerEvent event) {
  4758. + furi_assert(context);
  4759. +
  4760. + AvrIspApp* app = context;
  4761. + UNUSED(app);
  4762. + bool consumed = false;
  4763. + if(event.type == SceneManagerEventTypeBack) {
  4764. + //do not handle exit on "Back"
  4765. + consumed = true;
  4766. + } else if(event.type == SceneManagerEventTypeCustom) {
  4767. + switch(event.event) {
  4768. + case AvrIspCustomEventSceneReadingOk:
  4769. + scene_manager_next_scene(app->scene_manager, AvrIspSceneSuccess);
  4770. + consumed = true;
  4771. + break;
  4772. + case AvrIspCustomEventSceneExit:
  4773. + scene_manager_search_and_switch_to_previous_scene(
  4774. + app->scene_manager, AvrIspSceneChipDetect);
  4775. + consumed = true;
  4776. + break;
  4777. + case AvrIspCustomEventSceneErrorVerification:
  4778. + app->error = AvrIspErrorVerification;
  4779. + scene_manager_search_and_switch_to_previous_scene(
  4780. + app->scene_manager, AvrIspSceneChipDetect);
  4781. + consumed = true;
  4782. + break;
  4783. + case AvrIspCustomEventSceneErrorReading:
  4784. + app->error = AvrIspErrorReading;
  4785. + scene_manager_search_and_switch_to_previous_scene(
  4786. + app->scene_manager, AvrIspSceneChipDetect);
  4787. + consumed = true;
  4788. + break;
  4789. + default:
  4790. + break;
  4791. + }
  4792. + } else if(event.type == SceneManagerEventTypeTick) {
  4793. + avr_isp_reader_update_progress(app->avr_isp_reader_view);
  4794. + }
  4795. + return consumed;
  4796. +}
  4797. +
  4798. +void avr_isp_scene_reader_on_exit(void* context) {
  4799. + UNUSED(context);
  4800. +}
  4801. diff --git a/applications/external/avr_isp_programmer/scenes/avr_isp_scene_start.c b/applications/external/avr_isp_programmer/scenes/avr_isp_scene_start.c
  4802. new file mode 100644
  4803. index 000000000..b00bfefce
  4804. --- /dev/null
  4805. +++ b/applications/external/avr_isp_programmer/scenes/avr_isp_scene_start.c
  4806. @@ -0,0 +1,75 @@
  4807. +#include "../avr_isp_app_i.h"
  4808. +
  4809. +void avr_isp_scene_start_submenu_callback(void* context, uint32_t index) {
  4810. + furi_assert(context);
  4811. + AvrIspApp* app = context;
  4812. +
  4813. + view_dispatcher_send_custom_event(app->view_dispatcher, index);
  4814. +}
  4815. +
  4816. +void avr_isp_scene_start_on_enter(void* context) {
  4817. + furi_assert(context);
  4818. +
  4819. + AvrIspApp* app = context;
  4820. + Submenu* submenu = app->submenu;
  4821. + submenu_add_item(
  4822. + submenu, "Dump AVR", SubmenuIndexAvrIspReader, avr_isp_scene_start_submenu_callback, app);
  4823. + submenu_add_item(
  4824. + submenu, "Flash AVR", SubmenuIndexAvrIspWriter, avr_isp_scene_start_submenu_callback, app);
  4825. + submenu_add_item(
  4826. + submenu,
  4827. + "ISP Programmer",
  4828. + SubmenuIndexAvrIspProgrammer,
  4829. + avr_isp_scene_start_submenu_callback,
  4830. + app);
  4831. + submenu_add_item(
  4832. + submenu, "Wiring", SubmenuIndexAvrIsWiring, avr_isp_scene_start_submenu_callback, app);
  4833. + submenu_add_item(
  4834. + submenu, "About", SubmenuIndexAvrIspAbout, avr_isp_scene_start_submenu_callback, app);
  4835. +
  4836. + submenu_set_selected_item(
  4837. + submenu, scene_manager_get_scene_state(app->scene_manager, AvrIspSceneStart));
  4838. +
  4839. + view_dispatcher_switch_to_view(app->view_dispatcher, AvrIspViewSubmenu);
  4840. +}
  4841. +
  4842. +bool avr_isp_scene_start_on_event(void* context, SceneManagerEvent event) {
  4843. + furi_assert(context);
  4844. +
  4845. + AvrIspApp* app = context;
  4846. + bool consumed = false;
  4847. + if(event.type == SceneManagerEventTypeCustom) {
  4848. + if(event.event == SubmenuIndexAvrIspAbout) {
  4849. + scene_manager_next_scene(app->scene_manager, AvrIspSceneAbout);
  4850. + consumed = true;
  4851. + } else if(event.event == SubmenuIndexAvrIspProgrammer) {
  4852. + scene_manager_set_scene_state(
  4853. + app->scene_manager, AvrIspSceneChipDetect, AvrIspViewProgrammer);
  4854. + scene_manager_next_scene(app->scene_manager, AvrIspSceneChipDetect);
  4855. + consumed = true;
  4856. + } else if(event.event == SubmenuIndexAvrIspReader) {
  4857. + scene_manager_set_scene_state(
  4858. + app->scene_manager, AvrIspSceneChipDetect, AvrIspViewReader);
  4859. + scene_manager_next_scene(app->scene_manager, AvrIspSceneChipDetect);
  4860. + consumed = true;
  4861. + } else if(event.event == SubmenuIndexAvrIspWriter) {
  4862. + scene_manager_set_scene_state(
  4863. + app->scene_manager, AvrIspSceneChipDetect, AvrIspViewWriter);
  4864. + scene_manager_next_scene(app->scene_manager, AvrIspSceneChipDetect);
  4865. + consumed = true;
  4866. + } else if(event.event == SubmenuIndexAvrIsWiring) {
  4867. + scene_manager_next_scene(app->scene_manager, AvrIspSceneWiring);
  4868. + consumed = true;
  4869. + }
  4870. + scene_manager_set_scene_state(app->scene_manager, AvrIspSceneStart, event.event);
  4871. + }
  4872. +
  4873. + return consumed;
  4874. +}
  4875. +
  4876. +void avr_isp_scene_start_on_exit(void* context) {
  4877. + furi_assert(context);
  4878. +
  4879. + AvrIspApp* app = context;
  4880. + submenu_reset(app->submenu);
  4881. +}
  4882. diff --git a/applications/external/avr_isp_programmer/scenes/avr_isp_scene_success.c b/applications/external/avr_isp_programmer/scenes/avr_isp_scene_success.c
  4883. new file mode 100644
  4884. index 000000000..a88ed28aa
  4885. --- /dev/null
  4886. +++ b/applications/external/avr_isp_programmer/scenes/avr_isp_scene_success.c
  4887. @@ -0,0 +1,44 @@
  4888. +#include "../avr_isp_app_i.h"
  4889. +
  4890. +void avr_isp_scene_success_popup_callback(void* context) {
  4891. + furi_assert(context);
  4892. +
  4893. + AvrIspApp* app = context;
  4894. + view_dispatcher_send_custom_event(app->view_dispatcher, AvrIspCustomEventSceneSuccess);
  4895. +}
  4896. +
  4897. +void avr_isp_scene_success_on_enter(void* context) {
  4898. + furi_assert(context);
  4899. +
  4900. + AvrIspApp* app = context;
  4901. + Popup* popup = app->popup;
  4902. + popup_set_icon(popup, 32, 5, &I_dolphin_nice_96x59);
  4903. + popup_set_header(popup, "Success!", 8, 22, AlignLeft, AlignBottom);
  4904. + popup_set_timeout(popup, 1500);
  4905. + popup_set_context(popup, app);
  4906. + popup_set_callback(popup, avr_isp_scene_success_popup_callback);
  4907. + popup_enable_timeout(popup);
  4908. + view_dispatcher_switch_to_view(app->view_dispatcher, AvrIspViewPopup);
  4909. +}
  4910. +
  4911. +bool avr_isp_scene_success_on_event(void* context, SceneManagerEvent event) {
  4912. + furi_assert(context);
  4913. +
  4914. + AvrIspApp* app = context;
  4915. + if(event.type == SceneManagerEventTypeCustom) {
  4916. + if(event.event == AvrIspCustomEventSceneSuccess) {
  4917. + scene_manager_search_and_switch_to_previous_scene(
  4918. + app->scene_manager, AvrIspSceneStart);
  4919. + return true;
  4920. + }
  4921. + }
  4922. + return false;
  4923. +}
  4924. +
  4925. +void avr_isp_scene_success_on_exit(void* context) {
  4926. + furi_assert(context);
  4927. +
  4928. + AvrIspApp* app = context;
  4929. + Popup* popup = app->popup;
  4930. + popup_reset(popup);
  4931. +}
  4932. diff --git a/applications/external/avr_isp_programmer/scenes/avr_isp_scene_wiring.c b/applications/external/avr_isp_programmer/scenes/avr_isp_scene_wiring.c
  4933. new file mode 100644
  4934. index 000000000..787ed5673
  4935. --- /dev/null
  4936. +++ b/applications/external/avr_isp_programmer/scenes/avr_isp_scene_wiring.c
  4937. @@ -0,0 +1,21 @@
  4938. +#include "../avr_isp_app_i.h"
  4939. +
  4940. +void avr_isp_scene_wiring_on_enter(void* context) {
  4941. + furi_assert(context);
  4942. +
  4943. + AvrIspApp* app = context;
  4944. + widget_add_icon_element(app->widget, 0, 0, &I_avr_wiring);
  4945. + view_dispatcher_switch_to_view(app->view_dispatcher, AvrIspViewWidget);
  4946. +}
  4947. +
  4948. +bool avr_isp_scene_wiring_on_event(void* context, SceneManagerEvent event) {
  4949. + UNUSED(context);
  4950. + UNUSED(event);
  4951. + return false;
  4952. +}
  4953. +void avr_isp_scene_wiring_on_exit(void* context) {
  4954. + furi_assert(context);
  4955. +
  4956. + AvrIspApp* app = context;
  4957. + widget_reset(app->widget);
  4958. +}
  4959. diff --git a/applications/external/avr_isp_programmer/scenes/avr_isp_scene_writer.c b/applications/external/avr_isp_programmer/scenes/avr_isp_scene_writer.c
  4960. new file mode 100644
  4961. index 000000000..39c944fd5
  4962. --- /dev/null
  4963. +++ b/applications/external/avr_isp_programmer/scenes/avr_isp_scene_writer.c
  4964. @@ -0,0 +1,69 @@
  4965. +#include "../avr_isp_app_i.h"
  4966. +
  4967. +void avr_isp_scene_writer_callback(AvrIspCustomEvent event, void* context) {
  4968. + furi_assert(context);
  4969. +
  4970. + AvrIspApp* app = context;
  4971. + view_dispatcher_send_custom_event(app->view_dispatcher, event);
  4972. +}
  4973. +
  4974. +void avr_isp_scene_writer_on_enter(void* context) {
  4975. + furi_assert(context);
  4976. +
  4977. + AvrIspApp* app = context;
  4978. + avr_isp_writer_set_file_path(
  4979. + app->avr_isp_writer_view, furi_string_get_cstr(app->file_path), app->file_name_tmp);
  4980. + avr_isp_writer_view_set_callback(app->avr_isp_writer_view, avr_isp_scene_writer_callback, app);
  4981. + view_dispatcher_switch_to_view(app->view_dispatcher, AvrIspViewWriter);
  4982. +}
  4983. +
  4984. +bool avr_isp_scene_writer_on_event(void* context, SceneManagerEvent event) {
  4985. + furi_assert(context);
  4986. +
  4987. + AvrIspApp* app = context;
  4988. + bool consumed = false;
  4989. + if(event.type == SceneManagerEventTypeBack) {
  4990. + //do not handle exit on "Back"
  4991. + consumed = true;
  4992. + } else if(event.type == SceneManagerEventTypeCustom) {
  4993. + switch(event.event) {
  4994. + case AvrIspCustomEventSceneExitStartMenu:
  4995. + scene_manager_search_and_switch_to_previous_scene(
  4996. + app->scene_manager, AvrIspSceneStart);
  4997. + consumed = true;
  4998. + break;
  4999. + case AvrIspCustomEventSceneExit:
  5000. + scene_manager_search_and_switch_to_previous_scene(
  5001. + app->scene_manager, AvrIspSceneChipDetect);
  5002. + consumed = true;
  5003. + break;
  5004. + case AvrIspCustomEventSceneErrorVerification:
  5005. + app->error = AvrIspErrorVerification;
  5006. + scene_manager_search_and_switch_to_previous_scene(
  5007. + app->scene_manager, AvrIspSceneChipDetect);
  5008. + consumed = true;
  5009. + break;
  5010. + case AvrIspCustomEventSceneErrorWriting:
  5011. + app->error = AvrIspErrorWriting;
  5012. + scene_manager_search_and_switch_to_previous_scene(
  5013. + app->scene_manager, AvrIspSceneChipDetect);
  5014. + consumed = true;
  5015. + break;
  5016. + case AvrIspCustomEventSceneErrorWritingFuse:
  5017. + app->error = AvrIspErrorWritingFuse;
  5018. + scene_manager_search_and_switch_to_previous_scene(
  5019. + app->scene_manager, AvrIspSceneChipDetect);
  5020. + consumed = true;
  5021. + break;
  5022. + default:
  5023. + break;
  5024. + }
  5025. + } else if(event.type == SceneManagerEventTypeTick) {
  5026. + avr_isp_writer_update_progress(app->avr_isp_writer_view);
  5027. + }
  5028. + return consumed;
  5029. +}
  5030. +
  5031. +void avr_isp_scene_writer_on_exit(void* context) {
  5032. + UNUSED(context);
  5033. +}
  5034. diff --git a/applications/external/avr_isp_programmer/views/avr_isp_view_chip_detect.c b/applications/external/avr_isp_programmer/views/avr_isp_view_chip_detect.c
  5035. new file mode 100644
  5036. index 000000000..fdcf71c36
  5037. --- /dev/null
  5038. +++ b/applications/external/avr_isp_programmer/views/avr_isp_view_chip_detect.c
  5039. @@ -0,0 +1,213 @@
  5040. +#include "avr_isp_view_chip_detect.h"
  5041. +#include <avr_isp_icons.h>
  5042. +#include <gui/elements.h>
  5043. +
  5044. +#include "../helpers/avr_isp_worker_rw.h"
  5045. +
  5046. +struct AvrIspChipDetectView {
  5047. + View* view;
  5048. + AvrIspWorkerRW* avr_isp_worker_rw;
  5049. + AvrIspChipDetectViewCallback callback;
  5050. + void* context;
  5051. +};
  5052. +
  5053. +typedef struct {
  5054. + uint16_t idx;
  5055. + const char* name_chip;
  5056. + uint32_t flash_size;
  5057. + AvrIspChipDetectViewState state;
  5058. +} AvrIspChipDetectViewModel;
  5059. +
  5060. +void avr_isp_chip_detect_view_set_callback(
  5061. + AvrIspChipDetectView* instance,
  5062. + AvrIspChipDetectViewCallback callback,
  5063. + void* context) {
  5064. + furi_assert(instance);
  5065. + furi_assert(callback);
  5066. +
  5067. + instance->callback = callback;
  5068. + instance->context = context;
  5069. +}
  5070. +
  5071. +void avr_isp_chip_detect_set_state(AvrIspChipDetectView* instance, AvrIspChipDetectViewState state) {
  5072. + furi_assert(instance);
  5073. +
  5074. + with_view_model(
  5075. + instance->view, AvrIspChipDetectViewModel * model, { model->state = state; }, true);
  5076. +}
  5077. +
  5078. +void avr_isp_chip_detect_view_draw(Canvas* canvas, AvrIspChipDetectViewModel* model) {
  5079. + canvas_clear(canvas);
  5080. +
  5081. + char str_buf[64] = {0};
  5082. + canvas_set_font(canvas, FontPrimary);
  5083. +
  5084. + switch(model->state) {
  5085. + case AvrIspChipDetectViewStateDetected:
  5086. + canvas_draw_str_aligned(canvas, 64, 5, AlignCenter, AlignCenter, "AVR chip detected!");
  5087. + canvas_draw_icon(canvas, 29, 14, &I_chip_long_70x22);
  5088. + canvas_set_font(canvas, FontSecondary);
  5089. + snprintf(str_buf, sizeof(str_buf), "%ld Kb", model->flash_size / 1024);
  5090. + canvas_draw_str_aligned(canvas, 64, 25, AlignCenter, AlignCenter, str_buf);
  5091. + canvas_draw_str_aligned(canvas, 64, 45, AlignCenter, AlignCenter, model->name_chip);
  5092. + elements_button_right(canvas, "Next");
  5093. + break;
  5094. + case AvrIspChipDetectViewStateErrorOccured:
  5095. + canvas_draw_str_aligned(
  5096. + canvas, 64, 5, AlignCenter, AlignCenter, "Error occured, try again!");
  5097. + canvas_draw_icon(canvas, 29, 14, &I_chip_error_70x22);
  5098. + canvas_set_font(canvas, FontSecondary);
  5099. + canvas_draw_str_aligned(
  5100. + canvas, 64, 45, AlignCenter, AlignCenter, "Check the wiring and retry");
  5101. + break;
  5102. + case AvrIspChipDetectViewStateErrorVerification:
  5103. + canvas_draw_str_aligned(
  5104. + canvas, 64, 5, AlignCenter, AlignCenter, "Data verification failed");
  5105. + canvas_draw_icon(canvas, 29, 14, &I_chip_error_70x22);
  5106. + canvas_set_font(canvas, FontSecondary);
  5107. + canvas_draw_str_aligned(
  5108. + canvas, 64, 45, AlignCenter, AlignCenter, "Try to restart the process");
  5109. + break;
  5110. +
  5111. + default:
  5112. + //AvrIspChipDetectViewStateNoDetect
  5113. + canvas_draw_str_aligned(canvas, 64, 5, AlignCenter, AlignCenter, "AVR chip not found!");
  5114. + canvas_draw_icon(canvas, 29, 12, &I_chif_not_found_83x37);
  5115. +
  5116. + break;
  5117. + }
  5118. + canvas_set_font(canvas, FontSecondary);
  5119. + elements_button_left(canvas, "Retry");
  5120. +}
  5121. +
  5122. +bool avr_isp_chip_detect_view_input(InputEvent* event, void* context) {
  5123. + furi_assert(context);
  5124. +
  5125. + AvrIspChipDetectView* instance = context;
  5126. +
  5127. + if(event->type == InputTypeShort) {
  5128. + if(event->key == InputKeyBack) {
  5129. + return false;
  5130. + } else if(event->key == InputKeyRight) {
  5131. + with_view_model(
  5132. + instance->view,
  5133. + AvrIspChipDetectViewModel * model,
  5134. + {
  5135. + if(model->state == AvrIspChipDetectViewStateDetected) {
  5136. + if(instance->callback)
  5137. + instance->callback(
  5138. + AvrIspCustomEventSceneChipDetectOk, instance->context);
  5139. + }
  5140. + },
  5141. + false);
  5142. +
  5143. + } else if(event->key == InputKeyLeft) {
  5144. + bool detect_chip = false;
  5145. + with_view_model(
  5146. + instance->view,
  5147. + AvrIspChipDetectViewModel * model,
  5148. + {
  5149. + if(model->state != AvrIspChipDetectViewStateDetecting) {
  5150. + model->state = AvrIspChipDetectViewStateDetecting;
  5151. + detect_chip = true;
  5152. + }
  5153. + },
  5154. + false);
  5155. + if(detect_chip) avr_isp_worker_rw_detect_chip(instance->avr_isp_worker_rw);
  5156. + }
  5157. + } else {
  5158. + return false;
  5159. + }
  5160. +
  5161. + return true;
  5162. +}
  5163. +
  5164. +static void avr_isp_chip_detect_detect_chip_callback(
  5165. + void* context,
  5166. + const char* name,
  5167. + bool detect_chip,
  5168. + uint32_t flash_size) {
  5169. + furi_assert(context);
  5170. +
  5171. + AvrIspChipDetectView* instance = context;
  5172. + with_view_model(
  5173. + instance->view,
  5174. + AvrIspChipDetectViewModel * model,
  5175. + {
  5176. + model->name_chip = name;
  5177. + model->flash_size = flash_size;
  5178. + if(detect_chip) {
  5179. + model->state = AvrIspChipDetectViewStateDetected;
  5180. + } else {
  5181. + model->state = AvrIspChipDetectViewStateNoDetect;
  5182. + }
  5183. + },
  5184. + true);
  5185. +}
  5186. +void avr_isp_chip_detect_view_enter(void* context) {
  5187. + furi_assert(context);
  5188. +
  5189. + AvrIspChipDetectView* instance = context;
  5190. + bool detect_chip = false;
  5191. + with_view_model(
  5192. + instance->view,
  5193. + AvrIspChipDetectViewModel * model,
  5194. + {
  5195. + if(model->state == AvrIspChipDetectViewStateNoDetect ||
  5196. + model->state == AvrIspChipDetectViewStateDetected) {
  5197. + detect_chip = true;
  5198. + }
  5199. + },
  5200. + false);
  5201. +
  5202. + //Start avr_isp_worker_rw
  5203. + instance->avr_isp_worker_rw = avr_isp_worker_rw_alloc(instance->context);
  5204. +
  5205. + avr_isp_worker_rw_set_callback(
  5206. + instance->avr_isp_worker_rw, avr_isp_chip_detect_detect_chip_callback, instance);
  5207. +
  5208. + if(detect_chip) avr_isp_worker_rw_detect_chip(instance->avr_isp_worker_rw);
  5209. +}
  5210. +
  5211. +void avr_isp_chip_detect_view_exit(void* context) {
  5212. + furi_assert(context);
  5213. +
  5214. + AvrIspChipDetectView* instance = context;
  5215. +
  5216. + avr_isp_worker_rw_set_callback(instance->avr_isp_worker_rw, NULL, NULL);
  5217. + avr_isp_worker_rw_free(instance->avr_isp_worker_rw);
  5218. +}
  5219. +
  5220. +AvrIspChipDetectView* avr_isp_chip_detect_view_alloc() {
  5221. + AvrIspChipDetectView* instance = malloc(sizeof(AvrIspChipDetectView));
  5222. +
  5223. + // View allocation and configuration
  5224. + instance->view = view_alloc();
  5225. +
  5226. + view_allocate_model(instance->view, ViewModelTypeLocking, sizeof(AvrIspChipDetectViewModel));
  5227. + view_set_context(instance->view, instance);
  5228. + view_set_draw_callback(instance->view, (ViewDrawCallback)avr_isp_chip_detect_view_draw);
  5229. + view_set_input_callback(instance->view, avr_isp_chip_detect_view_input);
  5230. + view_set_enter_callback(instance->view, avr_isp_chip_detect_view_enter);
  5231. + view_set_exit_callback(instance->view, avr_isp_chip_detect_view_exit);
  5232. +
  5233. + with_view_model(
  5234. + instance->view,
  5235. + AvrIspChipDetectViewModel * model,
  5236. + { model->state = AvrIspChipDetectViewStateNoDetect; },
  5237. + false);
  5238. + return instance;
  5239. +}
  5240. +
  5241. +void avr_isp_chip_detect_view_free(AvrIspChipDetectView* instance) {
  5242. + furi_assert(instance);
  5243. +
  5244. + view_free(instance->view);
  5245. + free(instance);
  5246. +}
  5247. +
  5248. +View* avr_isp_chip_detect_view_get_view(AvrIspChipDetectView* instance) {
  5249. + furi_assert(instance);
  5250. +
  5251. + return instance->view;
  5252. +}
  5253. diff --git a/applications/external/avr_isp_programmer/views/avr_isp_view_chip_detect.h b/applications/external/avr_isp_programmer/views/avr_isp_view_chip_detect.h
  5254. new file mode 100644
  5255. index 000000000..37f2ae233
  5256. --- /dev/null
  5257. +++ b/applications/external/avr_isp_programmer/views/avr_isp_view_chip_detect.h
  5258. @@ -0,0 +1,32 @@
  5259. +#pragma once
  5260. +
  5261. +#include <gui/view.h>
  5262. +#include "../helpers/avr_isp_types.h"
  5263. +#include "../helpers/avr_isp_event.h"
  5264. +
  5265. +typedef struct AvrIspChipDetectView AvrIspChipDetectView;
  5266. +
  5267. +typedef void (*AvrIspChipDetectViewCallback)(AvrIspCustomEvent event, void* context);
  5268. +
  5269. +typedef enum {
  5270. + AvrIspChipDetectViewStateNoDetect,
  5271. + AvrIspChipDetectViewStateDetecting,
  5272. + AvrIspChipDetectViewStateDetected,
  5273. + AvrIspChipDetectViewStateErrorOccured,
  5274. + AvrIspChipDetectViewStateErrorVerification,
  5275. +} AvrIspChipDetectViewState;
  5276. +
  5277. +void avr_isp_chip_detect_view_set_callback(
  5278. + AvrIspChipDetectView* instance,
  5279. + AvrIspChipDetectViewCallback callback,
  5280. + void* context);
  5281. +
  5282. +void avr_isp_chip_detect_set_state(AvrIspChipDetectView* instance, AvrIspChipDetectViewState state);
  5283. +
  5284. +AvrIspChipDetectView* avr_isp_chip_detect_view_alloc();
  5285. +
  5286. +void avr_isp_chip_detect_view_free(AvrIspChipDetectView* instance);
  5287. +
  5288. +View* avr_isp_chip_detect_view_get_view(AvrIspChipDetectView* instance);
  5289. +
  5290. +void avr_isp_chip_detect_view_exit(void* context);
  5291. diff --git a/applications/external/avr_isp_programmer/views/avr_isp_view_programmer.c b/applications/external/avr_isp_programmer/views/avr_isp_view_programmer.c
  5292. new file mode 100644
  5293. index 000000000..34e18770b
  5294. --- /dev/null
  5295. +++ b/applications/external/avr_isp_programmer/views/avr_isp_view_programmer.c
  5296. @@ -0,0 +1,134 @@
  5297. +#include "avr_isp_view_programmer.h"
  5298. +#include <avr_isp_icons.h>
  5299. +
  5300. +#include "../helpers/avr_isp_worker.h"
  5301. +#include <gui/elements.h>
  5302. +
  5303. +struct AvrIspProgrammerView {
  5304. + View* view;
  5305. + AvrIspWorker* worker;
  5306. + AvrIspProgrammerViewCallback callback;
  5307. + void* context;
  5308. +};
  5309. +
  5310. +typedef struct {
  5311. + AvrIspProgrammerViewStatus status;
  5312. +} AvrIspProgrammerViewModel;
  5313. +
  5314. +void avr_isp_programmer_view_set_callback(
  5315. + AvrIspProgrammerView* instance,
  5316. + AvrIspProgrammerViewCallback callback,
  5317. + void* context) {
  5318. + furi_assert(instance);
  5319. + furi_assert(callback);
  5320. +
  5321. + instance->callback = callback;
  5322. + instance->context = context;
  5323. +}
  5324. +
  5325. +void avr_isp_programmer_view_draw(Canvas* canvas, AvrIspProgrammerViewModel* model) {
  5326. + canvas_clear(canvas);
  5327. +
  5328. + if(model->status == AvrIspProgrammerViewStatusUSBConnect) {
  5329. + canvas_set_font(canvas, FontPrimary);
  5330. + canvas_draw_icon(canvas, 0, 0, &I_isp_active_128x53);
  5331. + elements_multiline_text(canvas, 45, 10, "ISP mode active");
  5332. + } else {
  5333. + canvas_set_font(canvas, FontSecondary);
  5334. + canvas_draw_icon(canvas, 51, 6, &I_link_waiting_77x56);
  5335. + elements_multiline_text(canvas, 0, 25, "Waiting for\nsoftware\nconnection");
  5336. + }
  5337. +}
  5338. +
  5339. +bool avr_isp_programmer_view_input(InputEvent* event, void* context) {
  5340. + furi_assert(context);
  5341. + UNUSED(context);
  5342. +
  5343. + if(event->key == InputKeyBack || event->type != InputTypeShort) {
  5344. + return false;
  5345. + }
  5346. +
  5347. + return true;
  5348. +}
  5349. +
  5350. +static void avr_isp_programmer_usb_connect_callback(void* context, bool status_connect) {
  5351. + furi_assert(context);
  5352. + AvrIspProgrammerView* instance = context;
  5353. +
  5354. + with_view_model(
  5355. + instance->view,
  5356. + AvrIspProgrammerViewModel * model,
  5357. + {
  5358. + if(status_connect) {
  5359. + model->status = AvrIspProgrammerViewStatusUSBConnect;
  5360. + } else {
  5361. + model->status = AvrIspProgrammerViewStatusNoUSBConnect;
  5362. + }
  5363. + },
  5364. + true);
  5365. +}
  5366. +
  5367. +void avr_isp_programmer_view_enter(void* context) {
  5368. + furi_assert(context);
  5369. +
  5370. + AvrIspProgrammerView* instance = context;
  5371. + with_view_model(
  5372. + instance->view,
  5373. + AvrIspProgrammerViewModel * model,
  5374. + { model->status = AvrIspProgrammerViewStatusNoUSBConnect; },
  5375. + true);
  5376. +
  5377. + //Start worker
  5378. + instance->worker = avr_isp_worker_alloc(instance->context);
  5379. +
  5380. + avr_isp_worker_set_callback(
  5381. + instance->worker, avr_isp_programmer_usb_connect_callback, instance);
  5382. +
  5383. + avr_isp_worker_start(instance->worker);
  5384. +}
  5385. +
  5386. +void avr_isp_programmer_view_exit(void* context) {
  5387. + furi_assert(context);
  5388. +
  5389. + AvrIspProgrammerView* instance = context;
  5390. + //Stop worker
  5391. + if(avr_isp_worker_is_running(instance->worker)) {
  5392. + avr_isp_worker_stop(instance->worker);
  5393. + }
  5394. + avr_isp_worker_set_callback(instance->worker, NULL, NULL);
  5395. + avr_isp_worker_free(instance->worker);
  5396. +}
  5397. +
  5398. +AvrIspProgrammerView* avr_isp_programmer_view_alloc() {
  5399. + AvrIspProgrammerView* instance = malloc(sizeof(AvrIspProgrammerView));
  5400. +
  5401. + // View allocation and configuration
  5402. + instance->view = view_alloc();
  5403. +
  5404. + view_allocate_model(instance->view, ViewModelTypeLocking, sizeof(AvrIspProgrammerViewModel));
  5405. + view_set_context(instance->view, instance);
  5406. + view_set_draw_callback(instance->view, (ViewDrawCallback)avr_isp_programmer_view_draw);
  5407. + view_set_input_callback(instance->view, avr_isp_programmer_view_input);
  5408. + view_set_enter_callback(instance->view, avr_isp_programmer_view_enter);
  5409. + view_set_exit_callback(instance->view, avr_isp_programmer_view_exit);
  5410. +
  5411. + with_view_model(
  5412. + instance->view,
  5413. + AvrIspProgrammerViewModel * model,
  5414. + { model->status = AvrIspProgrammerViewStatusNoUSBConnect; },
  5415. + false);
  5416. + return instance;
  5417. +}
  5418. +
  5419. +void avr_isp_programmer_view_free(AvrIspProgrammerView* instance) {
  5420. + furi_assert(instance);
  5421. +
  5422. + view_free(instance->view);
  5423. + free(instance);
  5424. +}
  5425. +
  5426. +View* avr_isp_programmer_view_get_view(AvrIspProgrammerView* instance) {
  5427. + furi_assert(instance);
  5428. +
  5429. + return instance->view;
  5430. +}
  5431. diff --git a/applications/external/avr_isp_programmer/views/avr_isp_view_programmer.h b/applications/external/avr_isp_programmer/views/avr_isp_view_programmer.h
  5432. new file mode 100644
  5433. index 000000000..9f005b026
  5434. --- /dev/null
  5435. +++ b/applications/external/avr_isp_programmer/views/avr_isp_view_programmer.h
  5436. @@ -0,0 +1,27 @@
  5437. +#pragma once
  5438. +
  5439. +#include <gui/view.h>
  5440. +#include "../helpers/avr_isp_types.h"
  5441. +#include "../helpers/avr_isp_event.h"
  5442. +
  5443. +typedef struct AvrIspProgrammerView AvrIspProgrammerView;
  5444. +
  5445. +typedef void (*AvrIspProgrammerViewCallback)(AvrIspCustomEvent event, void* context);
  5446. +
  5447. +typedef enum {
  5448. + AvrIspProgrammerViewStatusNoUSBConnect,
  5449. + AvrIspProgrammerViewStatusUSBConnect,
  5450. +} AvrIspProgrammerViewStatus;
  5451. +
  5452. +void avr_isp_programmer_view_set_callback(
  5453. + AvrIspProgrammerView* instance,
  5454. + AvrIspProgrammerViewCallback callback,
  5455. + void* context);
  5456. +
  5457. +AvrIspProgrammerView* avr_isp_programmer_view_alloc();
  5458. +
  5459. +void avr_isp_programmer_view_free(AvrIspProgrammerView* instance);
  5460. +
  5461. +View* avr_isp_programmer_view_get_view(AvrIspProgrammerView* instance);
  5462. +
  5463. +void avr_isp_programmer_view_exit(void* context);
  5464. diff --git a/applications/external/avr_isp_programmer/views/avr_isp_view_reader.c b/applications/external/avr_isp_programmer/views/avr_isp_view_reader.c
  5465. new file mode 100644
  5466. index 000000000..92d15bd7f
  5467. --- /dev/null
  5468. +++ b/applications/external/avr_isp_programmer/views/avr_isp_view_reader.c
  5469. @@ -0,0 +1,215 @@
  5470. +#include "avr_isp_view_reader.h"
  5471. +#include <gui/elements.h>
  5472. +
  5473. +#include "../helpers/avr_isp_worker_rw.h"
  5474. +
  5475. +struct AvrIspReaderView {
  5476. + View* view;
  5477. + AvrIspWorkerRW* avr_isp_worker_rw;
  5478. + const char* file_path;
  5479. + const char* file_name;
  5480. + AvrIspReaderViewCallback callback;
  5481. + void* context;
  5482. +};
  5483. +
  5484. +typedef struct {
  5485. + AvrIspReaderViewStatus status;
  5486. + float progress_flash;
  5487. + float progress_eeprom;
  5488. +} AvrIspReaderViewModel;
  5489. +
  5490. +void avr_isp_reader_update_progress(AvrIspReaderView* instance) {
  5491. + with_view_model(
  5492. + instance->view,
  5493. + AvrIspReaderViewModel * model,
  5494. + {
  5495. + model->progress_flash =
  5496. + avr_isp_worker_rw_get_progress_flash(instance->avr_isp_worker_rw);
  5497. + model->progress_eeprom =
  5498. + avr_isp_worker_rw_get_progress_eeprom(instance->avr_isp_worker_rw);
  5499. + },
  5500. + true);
  5501. +}
  5502. +
  5503. +void avr_isp_reader_view_set_callback(
  5504. + AvrIspReaderView* instance,
  5505. + AvrIspReaderViewCallback callback,
  5506. + void* context) {
  5507. + furi_assert(instance);
  5508. + furi_assert(callback);
  5509. +
  5510. + instance->callback = callback;
  5511. + instance->context = context;
  5512. +}
  5513. +
  5514. +void avr_isp_reader_set_file_path(
  5515. + AvrIspReaderView* instance,
  5516. + const char* file_path,
  5517. + const char* file_name) {
  5518. + furi_assert(instance);
  5519. +
  5520. + instance->file_path = file_path;
  5521. + instance->file_name = file_name;
  5522. +}
  5523. +
  5524. +void avr_isp_reader_view_draw(Canvas* canvas, AvrIspReaderViewModel* model) {
  5525. + canvas_clear(canvas);
  5526. + char str_buf[64] = {0};
  5527. +
  5528. + canvas_set_font(canvas, FontPrimary);
  5529. + switch(model->status) {
  5530. + case AvrIspReaderViewStatusIDLE:
  5531. + canvas_draw_str_aligned(canvas, 64, 5, AlignCenter, AlignCenter, "Press start to dump");
  5532. + canvas_set_font(canvas, FontSecondary);
  5533. + elements_button_center(canvas, "Start");
  5534. + break;
  5535. + case AvrIspReaderViewStatusReading:
  5536. + canvas_draw_str_aligned(canvas, 64, 5, AlignCenter, AlignCenter, "Reading dump");
  5537. + break;
  5538. + case AvrIspReaderViewStatusVerification:
  5539. + canvas_draw_str_aligned(canvas, 64, 5, AlignCenter, AlignCenter, "Verifyng dump");
  5540. + break;
  5541. +
  5542. + default:
  5543. + break;
  5544. + }
  5545. +
  5546. + canvas_set_font(canvas, FontSecondary);
  5547. + canvas_draw_str(canvas, 0, 27, "Flash");
  5548. + snprintf(str_buf, sizeof(str_buf), "%d%%", (uint8_t)(model->progress_flash * 100));
  5549. + elements_progress_bar_with_text(canvas, 44, 17, 84, model->progress_flash, str_buf);
  5550. + canvas_draw_str(canvas, 0, 43, "EEPROM");
  5551. + snprintf(str_buf, sizeof(str_buf), "%d%%", (uint8_t)(model->progress_eeprom * 100));
  5552. + elements_progress_bar_with_text(canvas, 44, 34, 84, model->progress_eeprom, str_buf);
  5553. +}
  5554. +
  5555. +bool avr_isp_reader_view_input(InputEvent* event, void* context) {
  5556. + furi_assert(context);
  5557. + AvrIspReaderView* instance = context;
  5558. +
  5559. + bool ret = true;
  5560. + if(event->key == InputKeyBack && event->type == InputTypeShort) {
  5561. + with_view_model(
  5562. + instance->view,
  5563. + AvrIspReaderViewModel * model,
  5564. + {
  5565. + if(model->status == AvrIspReaderViewStatusIDLE) {
  5566. + if(instance->callback)
  5567. + instance->callback(AvrIspCustomEventSceneExit, instance->context);
  5568. + ret = false;
  5569. + }
  5570. + },
  5571. + false);
  5572. + } else if(event->key == InputKeyOk && event->type == InputTypeShort) {
  5573. + with_view_model(
  5574. + instance->view,
  5575. + AvrIspReaderViewModel * model,
  5576. + {
  5577. + if(model->status == AvrIspReaderViewStatusIDLE) {
  5578. + model->status = AvrIspReaderViewStatusReading;
  5579. + avr_isp_worker_rw_read_dump_start(
  5580. + instance->avr_isp_worker_rw, instance->file_path, instance->file_name);
  5581. + }
  5582. + },
  5583. + false);
  5584. + }
  5585. + return ret;
  5586. +}
  5587. +
  5588. +static void avr_isp_reader_callback_status(void* context, AvrIspWorkerRWStatus status) {
  5589. + furi_assert(context);
  5590. + AvrIspReaderView* instance = context;
  5591. +
  5592. + with_view_model(
  5593. + instance->view,
  5594. + AvrIspReaderViewModel * model,
  5595. + {
  5596. + switch(status) {
  5597. + case AvrIspWorkerRWStatusEndReading:
  5598. + model->status = AvrIspReaderViewStatusVerification;
  5599. + avr_isp_worker_rw_verification_start(
  5600. + instance->avr_isp_worker_rw, instance->file_path, instance->file_name);
  5601. + model->status = AvrIspReaderViewStatusVerification;
  5602. + break;
  5603. + case AvrIspWorkerRWStatusEndVerification:
  5604. + if(instance->callback)
  5605. + instance->callback(AvrIspCustomEventSceneReadingOk, instance->context);
  5606. + break;
  5607. + case AvrIspWorkerRWStatusErrorVerification:
  5608. + if(instance->callback)
  5609. + instance->callback(AvrIspCustomEventSceneErrorVerification, instance->context);
  5610. + break;
  5611. +
  5612. + default:
  5613. + //AvrIspWorkerRWStatusErrorReading;
  5614. + if(instance->callback)
  5615. + instance->callback(AvrIspCustomEventSceneErrorReading, instance->context);
  5616. + break;
  5617. + }
  5618. + },
  5619. + true);
  5620. +}
  5621. +
  5622. +void avr_isp_reader_view_enter(void* context) {
  5623. + furi_assert(context);
  5624. + AvrIspReaderView* instance = context;
  5625. +
  5626. + with_view_model(
  5627. + instance->view,
  5628. + AvrIspReaderViewModel * model,
  5629. + {
  5630. + model->status = AvrIspReaderViewStatusIDLE;
  5631. + model->progress_flash = 0.0f;
  5632. + model->progress_eeprom = 0.0f;
  5633. + },
  5634. + true);
  5635. +
  5636. + //Start avr_isp_worker_rw
  5637. + instance->avr_isp_worker_rw = avr_isp_worker_rw_alloc(instance->context);
  5638. +
  5639. + avr_isp_worker_rw_set_callback_status(
  5640. + instance->avr_isp_worker_rw, avr_isp_reader_callback_status, instance);
  5641. +
  5642. + avr_isp_worker_rw_start(instance->avr_isp_worker_rw);
  5643. +}
  5644. +
  5645. +void avr_isp_reader_view_exit(void* context) {
  5646. + furi_assert(context);
  5647. +
  5648. + AvrIspReaderView* instance = context;
  5649. + //Stop avr_isp_worker_rw
  5650. + if(avr_isp_worker_rw_is_running(instance->avr_isp_worker_rw)) {
  5651. + avr_isp_worker_rw_stop(instance->avr_isp_worker_rw);
  5652. + }
  5653. +
  5654. + avr_isp_worker_rw_free(instance->avr_isp_worker_rw);
  5655. +}
  5656. +
  5657. +AvrIspReaderView* avr_isp_reader_view_alloc() {
  5658. + AvrIspReaderView* instance = malloc(sizeof(AvrIspReaderView));
  5659. +
  5660. + // View allocation and configuration
  5661. + instance->view = view_alloc();
  5662. +
  5663. + view_allocate_model(instance->view, ViewModelTypeLocking, sizeof(AvrIspReaderViewModel));
  5664. + view_set_context(instance->view, instance);
  5665. + view_set_draw_callback(instance->view, (ViewDrawCallback)avr_isp_reader_view_draw);
  5666. + view_set_input_callback(instance->view, avr_isp_reader_view_input);
  5667. + view_set_enter_callback(instance->view, avr_isp_reader_view_enter);
  5668. + view_set_exit_callback(instance->view, avr_isp_reader_view_exit);
  5669. +
  5670. + return instance;
  5671. +}
  5672. +
  5673. +void avr_isp_reader_view_free(AvrIspReaderView* instance) {
  5674. + furi_assert(instance);
  5675. +
  5676. + view_free(instance->view);
  5677. + free(instance);
  5678. +}
  5679. +
  5680. +View* avr_isp_reader_view_get_view(AvrIspReaderView* instance) {
  5681. + furi_assert(instance);
  5682. +
  5683. + return instance->view;
  5684. +}
  5685. diff --git a/applications/external/avr_isp_programmer/views/avr_isp_view_reader.h b/applications/external/avr_isp_programmer/views/avr_isp_view_reader.h
  5686. new file mode 100644
  5687. index 000000000..44a439948
  5688. --- /dev/null
  5689. +++ b/applications/external/avr_isp_programmer/views/avr_isp_view_reader.h
  5690. @@ -0,0 +1,35 @@
  5691. +#pragma once
  5692. +
  5693. +#include <gui/view.h>
  5694. +#include "../helpers/avr_isp_types.h"
  5695. +#include "../helpers/avr_isp_event.h"
  5696. +
  5697. +typedef struct AvrIspReaderView AvrIspReaderView;
  5698. +
  5699. +typedef void (*AvrIspReaderViewCallback)(AvrIspCustomEvent event, void* context);
  5700. +
  5701. +typedef enum {
  5702. + AvrIspReaderViewStatusIDLE,
  5703. + AvrIspReaderViewStatusReading,
  5704. + AvrIspReaderViewStatusVerification,
  5705. +} AvrIspReaderViewStatus;
  5706. +
  5707. +void avr_isp_reader_update_progress(AvrIspReaderView* instance);
  5708. +
  5709. +void avr_isp_reader_set_file_path(
  5710. + AvrIspReaderView* instance,
  5711. + const char* file_path,
  5712. + const char* file_name);
  5713. +
  5714. +void avr_isp_reader_view_set_callback(
  5715. + AvrIspReaderView* instance,
  5716. + AvrIspReaderViewCallback callback,
  5717. + void* context);
  5718. +
  5719. +AvrIspReaderView* avr_isp_reader_view_alloc();
  5720. +
  5721. +void avr_isp_reader_view_free(AvrIspReaderView* instance);
  5722. +
  5723. +View* avr_isp_reader_view_get_view(AvrIspReaderView* instance);
  5724. +
  5725. +void avr_isp_reader_view_exit(void* context);
  5726. diff --git a/applications/external/avr_isp_programmer/views/avr_isp_view_writer.c b/applications/external/avr_isp_programmer/views/avr_isp_view_writer.c
  5727. new file mode 100644
  5728. index 000000000..a06b78535
  5729. --- /dev/null
  5730. +++ b/applications/external/avr_isp_programmer/views/avr_isp_view_writer.c
  5731. @@ -0,0 +1,268 @@
  5732. +#include "avr_isp_view_writer.h"
  5733. +#include <gui/elements.h>
  5734. +
  5735. +#include "../helpers/avr_isp_worker_rw.h"
  5736. +#include <float_tools.h>
  5737. +
  5738. +struct AvrIspWriterView {
  5739. + View* view;
  5740. + AvrIspWorkerRW* avr_isp_worker_rw;
  5741. + const char* file_path;
  5742. + const char* file_name;
  5743. + AvrIspWriterViewCallback callback;
  5744. + void* context;
  5745. +};
  5746. +
  5747. +typedef struct {
  5748. + AvrIspWriterViewStatus status;
  5749. + float progress_flash;
  5750. + float progress_eeprom;
  5751. +} AvrIspWriterViewModel;
  5752. +
  5753. +void avr_isp_writer_update_progress(AvrIspWriterView* instance) {
  5754. + with_view_model(
  5755. + instance->view,
  5756. + AvrIspWriterViewModel * model,
  5757. + {
  5758. + model->progress_flash =
  5759. + avr_isp_worker_rw_get_progress_flash(instance->avr_isp_worker_rw);
  5760. + model->progress_eeprom =
  5761. + avr_isp_worker_rw_get_progress_eeprom(instance->avr_isp_worker_rw);
  5762. + },
  5763. + true);
  5764. +}
  5765. +
  5766. +void avr_isp_writer_view_set_callback(
  5767. + AvrIspWriterView* instance,
  5768. + AvrIspWriterViewCallback callback,
  5769. + void* context) {
  5770. + furi_assert(instance);
  5771. + furi_assert(callback);
  5772. +
  5773. + instance->callback = callback;
  5774. + instance->context = context;
  5775. +}
  5776. +
  5777. +void avr_isp_writer_set_file_path(
  5778. + AvrIspWriterView* instance,
  5779. + const char* file_path,
  5780. + const char* file_name) {
  5781. + furi_assert(instance);
  5782. +
  5783. + instance->file_path = file_path;
  5784. + instance->file_name = file_name;
  5785. +}
  5786. +
  5787. +void avr_isp_writer_view_draw(Canvas* canvas, AvrIspWriterViewModel* model) {
  5788. + canvas_clear(canvas);
  5789. + char str_flash[32] = {0};
  5790. + char str_eeprom[32] = {0};
  5791. +
  5792. + canvas_set_font(canvas, FontPrimary);
  5793. +
  5794. + switch(model->status) {
  5795. + case AvrIspWriterViewStatusIDLE:
  5796. + canvas_draw_str_aligned(canvas, 64, 5, AlignCenter, AlignCenter, "Press start to write");
  5797. + canvas_set_font(canvas, FontSecondary);
  5798. + elements_button_center(canvas, "Start");
  5799. + snprintf(str_flash, sizeof(str_flash), "%d%%", (uint8_t)(model->progress_flash * 100));
  5800. + snprintf(str_eeprom, sizeof(str_eeprom), "%d%%", (uint8_t)(model->progress_eeprom * 100));
  5801. + break;
  5802. + case AvrIspWriterViewStatusWriting:
  5803. + if(float_is_equal(model->progress_flash, 0.f)) {
  5804. + canvas_draw_str_aligned(canvas, 64, 5, AlignCenter, AlignCenter, "Verifying firmware");
  5805. + snprintf(str_flash, sizeof(str_flash), "***");
  5806. + snprintf(str_eeprom, sizeof(str_eeprom), "***");
  5807. + } else {
  5808. + canvas_draw_str_aligned(canvas, 64, 5, AlignCenter, AlignCenter, "Writing dump");
  5809. + snprintf(str_flash, sizeof(str_flash), "%d%%", (uint8_t)(model->progress_flash * 100));
  5810. + snprintf(
  5811. + str_eeprom, sizeof(str_eeprom), "%d%%", (uint8_t)(model->progress_eeprom * 100));
  5812. + }
  5813. + break;
  5814. + case AvrIspWriterViewStatusVerification:
  5815. + canvas_draw_str_aligned(canvas, 64, 5, AlignCenter, AlignCenter, "Verifying dump");
  5816. + snprintf(str_flash, sizeof(str_flash), "%d%%", (uint8_t)(model->progress_flash * 100));
  5817. + snprintf(str_eeprom, sizeof(str_eeprom), "%d%%", (uint8_t)(model->progress_eeprom * 100));
  5818. + break;
  5819. + case AvrIspWriterViewStatusWritingFuse:
  5820. + canvas_draw_str_aligned(canvas, 64, 5, AlignCenter, AlignCenter, "Writing fuse");
  5821. + snprintf(str_flash, sizeof(str_flash), "%d%%", (uint8_t)(model->progress_flash * 100));
  5822. + snprintf(str_eeprom, sizeof(str_eeprom), "%d%%", (uint8_t)(model->progress_eeprom * 100));
  5823. + break;
  5824. + case AvrIspWriterViewStatusWritingFuseOk:
  5825. + canvas_draw_str_aligned(canvas, 64, 5, AlignCenter, AlignCenter, "Done!");
  5826. + snprintf(str_flash, sizeof(str_flash), "%d%%", (uint8_t)(model->progress_flash * 100));
  5827. + snprintf(str_eeprom, sizeof(str_eeprom), "%d%%", (uint8_t)(model->progress_eeprom * 100));
  5828. + canvas_set_font(canvas, FontSecondary);
  5829. + elements_button_center(canvas, "Reflash");
  5830. + elements_button_right(canvas, "Exit");
  5831. + break;
  5832. +
  5833. + default:
  5834. + break;
  5835. + }
  5836. +
  5837. + canvas_set_font(canvas, FontSecondary);
  5838. + canvas_draw_str(canvas, 0, 27, "Flash");
  5839. + // snprintf(str_buf, sizeof(str_buf), "%d%%", (uint8_t)(model->progress_flash * 100));
  5840. + elements_progress_bar_with_text(canvas, 44, 17, 84, model->progress_flash, str_flash);
  5841. + canvas_draw_str(canvas, 0, 43, "EEPROM");
  5842. + // snprintf(str_buf, sizeof(str_buf), "%d%%", (uint8_t)(model->progress_eeprom * 100));
  5843. + elements_progress_bar_with_text(canvas, 44, 34, 84, model->progress_eeprom, str_eeprom);
  5844. +}
  5845. +
  5846. +bool avr_isp_writer_view_input(InputEvent* event, void* context) {
  5847. + furi_assert(context);
  5848. + AvrIspWriterView* instance = context;
  5849. +
  5850. + bool ret = true;
  5851. + if(event->key == InputKeyBack && event->type == InputTypeShort) {
  5852. + with_view_model(
  5853. + instance->view,
  5854. + AvrIspWriterViewModel * model,
  5855. + {
  5856. + if((model->status == AvrIspWriterViewStatusIDLE) ||
  5857. + (model->status == AvrIspWriterViewStatusWritingFuseOk)) {
  5858. + if(instance->callback)
  5859. + instance->callback(AvrIspCustomEventSceneExit, instance->context);
  5860. + ret = false;
  5861. + }
  5862. + },
  5863. + false);
  5864. + } else if(event->key == InputKeyOk && event->type == InputTypeShort) {
  5865. + with_view_model(
  5866. + instance->view,
  5867. + AvrIspWriterViewModel * model,
  5868. + {
  5869. + if((model->status == AvrIspWriterViewStatusIDLE) ||
  5870. + (model->status == AvrIspWriterViewStatusWritingFuseOk)) {
  5871. + model->status = AvrIspWriterViewStatusWriting;
  5872. +
  5873. + avr_isp_worker_rw_write_dump_start(
  5874. + instance->avr_isp_worker_rw, instance->file_path, instance->file_name);
  5875. + }
  5876. + },
  5877. + false);
  5878. + } else if(event->key == InputKeyRight && event->type == InputTypeShort) {
  5879. + with_view_model(
  5880. + instance->view,
  5881. + AvrIspWriterViewModel * model,
  5882. + {
  5883. + if((model->status == AvrIspWriterViewStatusIDLE) ||
  5884. + (model->status == AvrIspWriterViewStatusWritingFuseOk)) {
  5885. + if(instance->callback)
  5886. + instance->callback(AvrIspCustomEventSceneExitStartMenu, instance->context);
  5887. + ret = false;
  5888. + }
  5889. + },
  5890. + false);
  5891. + }
  5892. + return ret;
  5893. +}
  5894. +
  5895. +static void avr_isp_writer_callback_status(void* context, AvrIspWorkerRWStatus status) {
  5896. + furi_assert(context);
  5897. +
  5898. + AvrIspWriterView* instance = context;
  5899. + with_view_model(
  5900. + instance->view,
  5901. + AvrIspWriterViewModel * model,
  5902. + {
  5903. + switch(status) {
  5904. + case AvrIspWorkerRWStatusEndWriting:
  5905. + model->status = AvrIspWriterViewStatusVerification;
  5906. + avr_isp_worker_rw_verification_start(
  5907. + instance->avr_isp_worker_rw, instance->file_path, instance->file_name);
  5908. + model->status = AvrIspWriterViewStatusVerification;
  5909. + break;
  5910. + case AvrIspWorkerRWStatusErrorVerification:
  5911. + if(instance->callback)
  5912. + instance->callback(AvrIspCustomEventSceneErrorVerification, instance->context);
  5913. + break;
  5914. + case AvrIspWorkerRWStatusEndVerification:
  5915. + avr_isp_worker_rw_write_fuse_start(
  5916. + instance->avr_isp_worker_rw, instance->file_path, instance->file_name);
  5917. + model->status = AvrIspWriterViewStatusWritingFuse;
  5918. + break;
  5919. + case AvrIspWorkerRWStatusErrorWritingFuse:
  5920. + if(instance->callback)
  5921. + instance->callback(AvrIspCustomEventSceneErrorWritingFuse, instance->context);
  5922. + break;
  5923. + case AvrIspWorkerRWStatusEndWritingFuse:
  5924. + model->status = AvrIspWriterViewStatusWritingFuseOk;
  5925. + break;
  5926. +
  5927. + default:
  5928. + //AvrIspWorkerRWStatusErrorWriting;
  5929. + if(instance->callback)
  5930. + instance->callback(AvrIspCustomEventSceneErrorWriting, instance->context);
  5931. + break;
  5932. + }
  5933. + },
  5934. + true);
  5935. +}
  5936. +
  5937. +void avr_isp_writer_view_enter(void* context) {
  5938. + furi_assert(context);
  5939. +
  5940. + AvrIspWriterView* instance = context;
  5941. + with_view_model(
  5942. + instance->view,
  5943. + AvrIspWriterViewModel * model,
  5944. + {
  5945. + model->status = AvrIspWriterViewStatusIDLE;
  5946. + model->progress_flash = 0.0f;
  5947. + model->progress_eeprom = 0.0f;
  5948. + },
  5949. + true);
  5950. +
  5951. + //Start avr_isp_worker_rw
  5952. + instance->avr_isp_worker_rw = avr_isp_worker_rw_alloc(instance->context);
  5953. +
  5954. + avr_isp_worker_rw_set_callback_status(
  5955. + instance->avr_isp_worker_rw, avr_isp_writer_callback_status, instance);
  5956. +
  5957. + avr_isp_worker_rw_start(instance->avr_isp_worker_rw);
  5958. +}
  5959. +
  5960. +void avr_isp_writer_view_exit(void* context) {
  5961. + furi_assert(context);
  5962. + AvrIspWriterView* instance = context;
  5963. +
  5964. + //Stop avr_isp_worker_rw
  5965. + if(avr_isp_worker_rw_is_running(instance->avr_isp_worker_rw)) {
  5966. + avr_isp_worker_rw_stop(instance->avr_isp_worker_rw);
  5967. + }
  5968. +
  5969. + avr_isp_worker_rw_free(instance->avr_isp_worker_rw);
  5970. +}
  5971. +
  5972. +AvrIspWriterView* avr_isp_writer_view_alloc() {
  5973. + AvrIspWriterView* instance = malloc(sizeof(AvrIspWriterView));
  5974. +
  5975. + // View allocation and configuration
  5976. + instance->view = view_alloc();
  5977. +
  5978. + view_allocate_model(instance->view, ViewModelTypeLocking, sizeof(AvrIspWriterViewModel));
  5979. + view_set_context(instance->view, instance);
  5980. + view_set_draw_callback(instance->view, (ViewDrawCallback)avr_isp_writer_view_draw);
  5981. + view_set_input_callback(instance->view, avr_isp_writer_view_input);
  5982. + view_set_enter_callback(instance->view, avr_isp_writer_view_enter);
  5983. + view_set_exit_callback(instance->view, avr_isp_writer_view_exit);
  5984. +
  5985. + return instance;
  5986. +}
  5987. +
  5988. +void avr_isp_writer_view_free(AvrIspWriterView* instance) {
  5989. + furi_assert(instance);
  5990. +
  5991. + view_free(instance->view);
  5992. + free(instance);
  5993. +}
  5994. +
  5995. +View* avr_isp_writer_view_get_view(AvrIspWriterView* instance) {
  5996. + furi_assert(instance);
  5997. +
  5998. + return instance->view;
  5999. +}
  6000. diff --git a/applications/external/avr_isp_programmer/views/avr_isp_view_writer.h b/applications/external/avr_isp_programmer/views/avr_isp_view_writer.h
  6001. new file mode 100644
  6002. index 000000000..1ff728387
  6003. --- /dev/null
  6004. +++ b/applications/external/avr_isp_programmer/views/avr_isp_view_writer.h
  6005. @@ -0,0 +1,37 @@
  6006. +#pragma once
  6007. +
  6008. +#include <gui/view.h>
  6009. +#include "../helpers/avr_isp_types.h"
  6010. +#include "../helpers/avr_isp_event.h"
  6011. +
  6012. +typedef struct AvrIspWriterView AvrIspWriterView;
  6013. +
  6014. +typedef void (*AvrIspWriterViewCallback)(AvrIspCustomEvent event, void* context);
  6015. +
  6016. +typedef enum {
  6017. + AvrIspWriterViewStatusIDLE,
  6018. + AvrIspWriterViewStatusWriting,
  6019. + AvrIspWriterViewStatusVerification,
  6020. + AvrIspWriterViewStatusWritingFuse,
  6021. + AvrIspWriterViewStatusWritingFuseOk,
  6022. +} AvrIspWriterViewStatus;
  6023. +
  6024. +void avr_isp_writer_update_progress(AvrIspWriterView* instance);
  6025. +
  6026. +void avr_isp_writer_set_file_path(
  6027. + AvrIspWriterView* instance,
  6028. + const char* file_path,
  6029. + const char* file_name);
  6030. +
  6031. +void avr_isp_writer_view_set_callback(
  6032. + AvrIspWriterView* instance,
  6033. + AvrIspWriterViewCallback callback,
  6034. + void* context);
  6035. +
  6036. +AvrIspWriterView* avr_isp_writer_view_alloc();
  6037. +
  6038. +void avr_isp_writer_view_free(AvrIspWriterView* instance);
  6039. +
  6040. +View* avr_isp_writer_view_get_view(AvrIspWriterView* instance);
  6041. +
  6042. +void avr_isp_writer_view_exit(void* context);
  6043. diff --git a/firmware/targets/f18/api_symbols.csv b/firmware/targets/f18/api_symbols.csv
  6044. index 7713beb93..3806ac47b 100644
  6045. --- a/firmware/targets/f18/api_symbols.csv
  6046. +++ b/firmware/targets/f18/api_symbols.csv
  6047. @@ -158,6 +158,7 @@ Header,+,lib/toolbox/args.h,,
  6048. Header,+,lib/toolbox/crc32_calc.h,,
  6049. Header,+,lib/toolbox/dir_walk.h,,
  6050. Header,+,lib/toolbox/float_tools.h,,
  6051. +Header,+,lib/toolbox/hex.h,,
  6052. Header,+,lib/toolbox/manchester_decoder.h,,
  6053. Header,+,lib/toolbox/manchester_encoder.h,,
  6054. Header,+,lib/toolbox/md5.h,,
  6055. @@ -1309,6 +1310,10 @@ Function,+,gui_view_port_send_to_front,void,"Gui*, ViewPort*"
  6056. Function,+,hal_sd_detect,_Bool,
  6057. Function,+,hal_sd_detect_init,void,
  6058. Function,+,hal_sd_detect_set_low,void,
  6059. +Function,+,hex_char_to_hex_nibble,_Bool,"char, uint8_t*"
  6060. +Function,+,hex_char_to_uint8,_Bool,"char, char, uint8_t*"
  6061. +Function,+,hex_chars_to_uint64,_Bool,"const char*, uint64_t*"
  6062. +Function,+,hex_chars_to_uint8,_Bool,"const char*, uint8_t*"
  6063. Function,+,icon_animation_alloc,IconAnimation*,const Icon*
  6064. Function,+,icon_animation_free,void,IconAnimation*
  6065. Function,+,icon_animation_get_height,uint8_t,const IconAnimation*
  6066. @@ -1870,6 +1875,7 @@ Function,+,uECC_sign,int,"const uint8_t*, const uint8_t*, unsigned, uint8_t*, uE
  6067. Function,-,uECC_sign_deterministic,int,"const uint8_t*, const uint8_t*, unsigned, const uECC_HashContext*, uint8_t*, uECC_Curve"
  6068. Function,-,uECC_valid_public_key,int,"const uint8_t*, uECC_Curve"
  6069. Function,-,uECC_verify,int,"const uint8_t*, const uint8_t*, unsigned, const uint8_t*, uECC_Curve"
  6070. +Function,+,uint8_to_hex_chars,void,"const uint8_t*, uint8_t*, int"
  6071. Function,-,ulTaskGenericNotifyTake,uint32_t,"UBaseType_t, BaseType_t, TickType_t"
  6072. Function,-,ulTaskGenericNotifyValueClear,uint32_t,"TaskHandle_t, UBaseType_t, uint32_t"
  6073. Function,-,ulTaskGetIdleRunTimeCounter,uint32_t,
  6074. diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv
  6075. index fea792680..efc20b4a7 100644
  6076. --- a/firmware/targets/f7/api_symbols.csv
  6077. +++ b/firmware/targets/f7/api_symbols.csv
  6078. @@ -190,6 +190,7 @@ Header,+,lib/toolbox/args.h,,
  6079. Header,+,lib/toolbox/crc32_calc.h,,
  6080. Header,+,lib/toolbox/dir_walk.h,,
  6081. Header,+,lib/toolbox/float_tools.h,,
  6082. +Header,+,lib/toolbox/hex.h,,
  6083. Header,+,lib/toolbox/manchester_decoder.h,,
  6084. Header,+,lib/toolbox/manchester_encoder.h,,
  6085. Header,+,lib/toolbox/md5.h,,
  6086. @@ -1597,6 +1598,10 @@ Function,+,gui_view_port_send_to_front,void,"Gui*, ViewPort*"
  6087. Function,+,hal_sd_detect,_Bool,
  6088. Function,+,hal_sd_detect_init,void,
  6089. Function,+,hal_sd_detect_set_low,void,
  6090. +Function,+,hex_char_to_hex_nibble,_Bool,"char, uint8_t*"
  6091. +Function,+,hex_char_to_uint8,_Bool,"char, char, uint8_t*"
  6092. +Function,+,hex_chars_to_uint64,_Bool,"const char*, uint64_t*"
  6093. +Function,+,hex_chars_to_uint8,_Bool,"const char*, uint8_t*"
  6094. Function,-,hypot,double,"double, double"
  6095. Function,-,hypotf,float,"float, float"
  6096. Function,-,hypotl,long double,"long double, long double"
  6097. @@ -2801,6 +2806,7 @@ Function,+,uECC_sign,int,"const uint8_t*, const uint8_t*, unsigned, uint8_t*, uE
  6098. Function,-,uECC_sign_deterministic,int,"const uint8_t*, const uint8_t*, unsigned, const uECC_HashContext*, uint8_t*, uECC_Curve"
  6099. Function,-,uECC_valid_public_key,int,"const uint8_t*, uECC_Curve"
  6100. Function,-,uECC_verify,int,"const uint8_t*, const uint8_t*, unsigned, const uint8_t*, uECC_Curve"
  6101. +Function,+,uint8_to_hex_chars,void,"const uint8_t*, uint8_t*, int"
  6102. Function,-,ulTaskGenericNotifyTake,uint32_t,"UBaseType_t, BaseType_t, TickType_t"
  6103. Function,-,ulTaskGenericNotifyValueClear,uint32_t,"TaskHandle_t, UBaseType_t, uint32_t"
  6104. Function,-,ulTaskGetIdleRunTimeCounter,uint32_t,
  6105. diff --git a/lib/toolbox/SConscript b/lib/toolbox/SConscript
  6106. index fad4c5584..bb06c2db4 100644
  6107. --- a/lib/toolbox/SConscript
  6108. +++ b/lib/toolbox/SConscript
  6109. @@ -28,6 +28,7 @@ env.Append(
  6110. File("stream/buffered_file_stream.h"),
  6111. File("protocols/protocol_dict.h"),
  6112. File("pretty_format.h"),
  6113. + File("hex.h"),
  6114. ],
  6115. )