| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120 |
- commit d1ad9242165143215ec9267914d23e58f837374c
- Author: Skorpionm <85568270+Skorpionm@users.noreply.github.com>
- Date: Thu Apr 6 08:13:30 2023 +0400
- [AVR_ISP]: add AVR ISP Programmer FAP (#2475)
-
- * [AVR_ISP]: add AVR ISP Programmer FAP
- * [AVR_ISP]: add auto detect AVR chip
- * [AVR_ISP]: fix auto detect chip
- * [AVR_ISP]: fix fast write flash
- * AVR_ISP: auto set SPI speed
- * AVR_ISP: add clock 4Mhz on &gpio_ext_pa4
- * AVR_ISP: fix "[CRASH][ISR 4] NULL pointer dereference" with no AVR chip connected
- * AVR_ISP: add AVR ISP Reader
- * AVR_ISP: add read and check I32HEX file
- * AVR_ISP: add write eerom, flash, fuse, lock byte
- * AVR_ISP: add gui Reader, Writer
- * Github: unshallow on decontamination
- * AVR_ISP: move to external
- * API: fix api_symbols
- * AVR_ISP: add wiring scene
- * GUI: model mutex FuriMutexTypeNormal -> FuriMutexTypeRecursive
- * AVR_ISP: add chip_detect view
- * AVR_ISP: refactoring gui ISP Programmer
- * AVR_ISP: add gui "Dump AVR"
- * AVR_ISP: add gui "Flash AVR"
- * AVR_ISP: fix navigation gui
- * GUI: model mutex FuriMutexTypeRecursive -> FuriMutexTypeNormal
- * AVR_ISP: fix conflicts
- * AVR_ISP: fix build
- * AVR_ISP: delete images
- * AVR_ISP: add images
- * AVR_ISP: fix gui
- * AVR_ISP: fix stuck in navigation
- * AVR_ISP: changing the Fuse bit recording logic
- * AVR_ISP: fix read/write chips with memory greater than 64Kb
- * AVR_ISP: fix auto set speed SPI
- * AVR_ISP: fix gui
- * ISP: switching on +5 volts to an external GPIO
-
- Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com>
- diff --git a/applications/external/avr_isp_programmer/application.fam b/applications/external/avr_isp_programmer/application.fam
- new file mode 100644
- index 000000000..19556d03d
- --- /dev/null
- +++ b/applications/external/avr_isp_programmer/application.fam
- @@ -0,0 +1,17 @@
- +App(
- + appid="avr_isp",
- + name="AVR Flasher",
- + apptype=FlipperAppType.EXTERNAL,
- + entry_point="avr_isp_app",
- + requires=["gui"],
- + stack_size=4 * 1024,
- + order=20,
- + fap_icon="avr_app_icon_10x10.png",
- + fap_category="GPIO",
- + fap_icon_assets="images",
- + fap_private_libs=[
- + Lib(
- + name="driver",
- + ),
- + ],
- +)
- diff --git a/applications/external/avr_isp_programmer/avr_app_icon_10x10.png b/applications/external/avr_isp_programmer/avr_app_icon_10x10.png
- new file mode 100644
- index 000000000..533787fe3
- Binary files /dev/null and b/applications/external/avr_isp_programmer/avr_app_icon_10x10.png differ
- diff --git a/applications/external/avr_isp_programmer/avr_isp_app.c b/applications/external/avr_isp_programmer/avr_isp_app.c
- new file mode 100644
- index 000000000..740dc3610
- --- /dev/null
- +++ b/applications/external/avr_isp_programmer/avr_isp_app.c
- @@ -0,0 +1,179 @@
- +#include "avr_isp_app_i.h"
- +
- +static bool avr_isp_app_custom_event_callback(void* context, uint32_t event) {
- + furi_assert(context);
- + AvrIspApp* app = context;
- + return scene_manager_handle_custom_event(app->scene_manager, event);
- +}
- +
- +static bool avr_isp_app_back_event_callback(void* context) {
- + furi_assert(context);
- + AvrIspApp* app = context;
- + return scene_manager_handle_back_event(app->scene_manager);
- +}
- +
- +static void avr_isp_app_tick_event_callback(void* context) {
- + furi_assert(context);
- + AvrIspApp* app = context;
- + scene_manager_handle_tick_event(app->scene_manager);
- +}
- +
- +AvrIspApp* avr_isp_app_alloc() {
- + AvrIspApp* app = malloc(sizeof(AvrIspApp));
- +
- + app->file_path = furi_string_alloc();
- + furi_string_set(app->file_path, STORAGE_APP_DATA_PATH_PREFIX);
- + app->error = AvrIspErrorNoError;
- +
- + // GUI
- + app->gui = furi_record_open(RECORD_GUI);
- +
- + // View Dispatcher
- + app->view_dispatcher = view_dispatcher_alloc();
- + app->scene_manager = scene_manager_alloc(&avr_isp_scene_handlers, app);
- + view_dispatcher_enable_queue(app->view_dispatcher);
- +
- + view_dispatcher_set_event_callback_context(app->view_dispatcher, app);
- + view_dispatcher_set_custom_event_callback(
- + app->view_dispatcher, avr_isp_app_custom_event_callback);
- + view_dispatcher_set_navigation_event_callback(
- + app->view_dispatcher, avr_isp_app_back_event_callback);
- + view_dispatcher_set_tick_event_callback(
- + app->view_dispatcher, avr_isp_app_tick_event_callback, 100);
- +
- + view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen);
- +
- + // Open Notification record
- + app->notifications = furi_record_open(RECORD_NOTIFICATION);
- +
- + // SubMenu
- + app->submenu = submenu_alloc();
- + view_dispatcher_add_view(
- + app->view_dispatcher, AvrIspViewSubmenu, submenu_get_view(app->submenu));
- +
- + // Widget
- + app->widget = widget_alloc();
- + view_dispatcher_add_view(app->view_dispatcher, AvrIspViewWidget, widget_get_view(app->widget));
- +
- + // Text Input
- + app->text_input = text_input_alloc();
- + view_dispatcher_add_view(
- + app->view_dispatcher, AvrIspViewTextInput, text_input_get_view(app->text_input));
- +
- + // Popup
- + app->popup = popup_alloc();
- + view_dispatcher_add_view(app->view_dispatcher, AvrIspViewPopup, popup_get_view(app->popup));
- +
- + //Dialog
- + app->dialogs = furi_record_open(RECORD_DIALOGS);
- +
- + // Programmer view
- + app->avr_isp_programmer_view = avr_isp_programmer_view_alloc();
- + view_dispatcher_add_view(
- + app->view_dispatcher,
- + AvrIspViewProgrammer,
- + avr_isp_programmer_view_get_view(app->avr_isp_programmer_view));
- +
- + // Reader view
- + app->avr_isp_reader_view = avr_isp_reader_view_alloc();
- + view_dispatcher_add_view(
- + app->view_dispatcher,
- + AvrIspViewReader,
- + avr_isp_reader_view_get_view(app->avr_isp_reader_view));
- +
- + // Writer view
- + app->avr_isp_writer_view = avr_isp_writer_view_alloc();
- + view_dispatcher_add_view(
- + app->view_dispatcher,
- + AvrIspViewWriter,
- + avr_isp_writer_view_get_view(app->avr_isp_writer_view));
- +
- + // Chip detect view
- + app->avr_isp_chip_detect_view = avr_isp_chip_detect_view_alloc();
- + view_dispatcher_add_view(
- + app->view_dispatcher,
- + AvrIspViewChipDetect,
- + avr_isp_chip_detect_view_get_view(app->avr_isp_chip_detect_view));
- +
- + // Enable 5v power, multiple attempts to avoid issues with power chip protection false triggering
- + uint8_t attempts = 0;
- + while(!furi_hal_power_is_otg_enabled() && attempts++ < 5) {
- + furi_hal_power_enable_otg();
- + furi_delay_ms(10);
- + }
- +
- + scene_manager_next_scene(app->scene_manager, AvrIspSceneStart);
- +
- + return app;
- +} //-V773
- +
- +void avr_isp_app_free(AvrIspApp* app) {
- + furi_assert(app);
- +
- + // Disable 5v power
- + if(furi_hal_power_is_otg_enabled()) {
- + furi_hal_power_disable_otg();
- + }
- +
- + // Submenu
- + view_dispatcher_remove_view(app->view_dispatcher, AvrIspViewSubmenu);
- + submenu_free(app->submenu);
- +
- + // Widget
- + view_dispatcher_remove_view(app->view_dispatcher, AvrIspViewWidget);
- + widget_free(app->widget);
- +
- + // TextInput
- + view_dispatcher_remove_view(app->view_dispatcher, AvrIspViewTextInput);
- + text_input_free(app->text_input);
- +
- + // Popup
- + view_dispatcher_remove_view(app->view_dispatcher, AvrIspViewPopup);
- + popup_free(app->popup);
- +
- + //Dialog
- + furi_record_close(RECORD_DIALOGS);
- +
- + // Programmer view
- + view_dispatcher_remove_view(app->view_dispatcher, AvrIspViewProgrammer);
- + avr_isp_programmer_view_free(app->avr_isp_programmer_view);
- +
- + // Reader view
- + view_dispatcher_remove_view(app->view_dispatcher, AvrIspViewReader);
- + avr_isp_reader_view_free(app->avr_isp_reader_view);
- +
- + // Writer view
- + view_dispatcher_remove_view(app->view_dispatcher, AvrIspViewWriter);
- + avr_isp_writer_view_free(app->avr_isp_writer_view);
- +
- + // Chip detect view
- + view_dispatcher_remove_view(app->view_dispatcher, AvrIspViewChipDetect);
- + avr_isp_chip_detect_view_free(app->avr_isp_chip_detect_view);
- +
- + // View dispatcher
- + view_dispatcher_free(app->view_dispatcher);
- + scene_manager_free(app->scene_manager);
- +
- + // Notifications
- + furi_record_close(RECORD_NOTIFICATION);
- + app->notifications = NULL;
- +
- + // Close records
- + furi_record_close(RECORD_GUI);
- +
- + // Path strings
- + furi_string_free(app->file_path);
- +
- + free(app);
- +}
- +
- +int32_t avr_isp_app(void* p) {
- + UNUSED(p);
- + AvrIspApp* avr_isp_app = avr_isp_app_alloc();
- +
- + view_dispatcher_run(avr_isp_app->view_dispatcher);
- +
- + avr_isp_app_free(avr_isp_app);
- +
- + return 0;
- +}
- diff --git a/applications/external/avr_isp_programmer/avr_isp_app_i.c b/applications/external/avr_isp_programmer/avr_isp_app_i.c
- new file mode 100644
- index 000000000..7a7fa6d7f
- --- /dev/null
- +++ b/applications/external/avr_isp_programmer/avr_isp_app_i.c
- @@ -0,0 +1,31 @@
- +#include "avr_isp_app_i.h"
- +#include <lib/toolbox/path.h>
- +#include <flipper_format/flipper_format_i.h>
- +
- +#define TAG "AvrIsp"
- +
- +bool avr_isp_load_from_file(AvrIspApp* app) {
- + furi_assert(app);
- +
- + FuriString* file_path = furi_string_alloc();
- + FuriString* file_name = furi_string_alloc();
- +
- + DialogsFileBrowserOptions browser_options;
- + dialog_file_browser_set_basic_options(
- + &browser_options, AVR_ISP_APP_EXTENSION, &I_avr_app_icon_10x10);
- + browser_options.base_path = STORAGE_APP_DATA_PATH_PREFIX;
- +
- + // Input events and views are managed by file_select
- + bool res = dialog_file_browser_show(app->dialogs, file_path, app->file_path, &browser_options);
- +
- + if(res) {
- + path_extract_dirname(furi_string_get_cstr(file_path), app->file_path);
- + path_extract_filename(file_path, file_name, true);
- + strncpy(app->file_name_tmp, furi_string_get_cstr(file_name), AVR_ISP_MAX_LEN_NAME);
- + }
- +
- + furi_string_free(file_name);
- + furi_string_free(file_path);
- +
- + return res;
- +}
- diff --git a/applications/external/avr_isp_programmer/avr_isp_app_i.h b/applications/external/avr_isp_programmer/avr_isp_app_i.h
- new file mode 100644
- index 000000000..17c69f8f2
- --- /dev/null
- +++ b/applications/external/avr_isp_programmer/avr_isp_app_i.h
- @@ -0,0 +1,44 @@
- +#pragma once
- +
- +#include "helpers/avr_isp_types.h"
- +#include <avr_isp_icons.h>
- +
- +#include "scenes/avr_isp_scene.h"
- +#include <gui/gui.h>
- +#include <gui/view_dispatcher.h>
- +#include <gui/scene_manager.h>
- +#include <gui/modules/submenu.h>
- +#include <gui/modules/widget.h>
- +#include <notification/notification_messages.h>
- +#include <gui/modules/text_input.h>
- +#include <dialogs/dialogs.h>
- +#include <storage/storage.h>
- +#include <gui/modules/popup.h>
- +
- +#include "views/avr_isp_view_programmer.h"
- +#include "views/avr_isp_view_reader.h"
- +#include "views/avr_isp_view_writer.h"
- +#include "views/avr_isp_view_chip_detect.h"
- +
- +#define AVR_ISP_MAX_LEN_NAME 64
- +
- +typedef struct {
- + Gui* gui;
- + ViewDispatcher* view_dispatcher;
- + SceneManager* scene_manager;
- + NotificationApp* notifications;
- + DialogsApp* dialogs;
- + Popup* popup;
- + Submenu* submenu;
- + Widget* widget;
- + TextInput* text_input;
- + FuriString* file_path;
- + char file_name_tmp[AVR_ISP_MAX_LEN_NAME];
- + AvrIspProgrammerView* avr_isp_programmer_view;
- + AvrIspReaderView* avr_isp_reader_view;
- + AvrIspWriterView* avr_isp_writer_view;
- + AvrIspChipDetectView* avr_isp_chip_detect_view;
- + AvrIspError error;
- +} AvrIspApp;
- +
- +bool avr_isp_load_from_file(AvrIspApp* app);
- \ No newline at end of file
- diff --git a/applications/external/avr_isp_programmer/helpers/avr_isp.c b/applications/external/avr_isp_programmer/helpers/avr_isp.c
- new file mode 100644
- index 000000000..76e0a80b0
- --- /dev/null
- +++ b/applications/external/avr_isp_programmer/helpers/avr_isp.c
- @@ -0,0 +1,490 @@
- +#include "avr_isp.h"
- +#include "../lib/driver/avr_isp_prog_cmd.h"
- +#include "../lib/driver/avr_isp_spi_sw.h"
- +
- +#include <furi.h>
- +
- +#define AVR_ISP_PROG_TX_RX_BUF_SIZE 320
- +#define TAG "AvrIsp"
- +
- +struct AvrIsp {
- + AvrIspSpiSw* spi;
- + bool pmode;
- + AvrIspCallback callback;
- + void* context;
- +};
- +
- +AvrIsp* avr_isp_alloc(void) {
- + AvrIsp* instance = malloc(sizeof(AvrIsp));
- + return instance;
- +}
- +
- +void avr_isp_free(AvrIsp* instance) {
- + furi_assert(instance);
- +
- + if(instance->spi) avr_isp_end_pmode(instance);
- + free(instance);
- +}
- +
- +void avr_isp_set_tx_callback(AvrIsp* instance, AvrIspCallback callback, void* context) {
- + furi_assert(instance);
- + furi_assert(context);
- +
- + instance->callback = callback;
- + instance->context = context;
- +}
- +
- +uint8_t avr_isp_spi_transaction(
- + AvrIsp* instance,
- + uint8_t cmd,
- + uint8_t addr_hi,
- + uint8_t addr_lo,
- + uint8_t data) {
- + furi_assert(instance);
- +
- + avr_isp_spi_sw_txrx(instance->spi, cmd);
- + avr_isp_spi_sw_txrx(instance->spi, addr_hi);
- + avr_isp_spi_sw_txrx(instance->spi, addr_lo);
- + return avr_isp_spi_sw_txrx(instance->spi, data);
- +}
- +
- +static bool avr_isp_set_pmode(AvrIsp* instance, uint8_t a, uint8_t b, uint8_t c, uint8_t d) {
- + furi_assert(instance);
- +
- + uint8_t res = 0;
- + avr_isp_spi_sw_txrx(instance->spi, a);
- + avr_isp_spi_sw_txrx(instance->spi, b);
- + res = avr_isp_spi_sw_txrx(instance->spi, c);
- + avr_isp_spi_sw_txrx(instance->spi, d);
- + return res == 0x53;
- +}
- +
- +void avr_isp_end_pmode(AvrIsp* instance) {
- + furi_assert(instance);
- +
- + if(instance->pmode) {
- + avr_isp_spi_sw_res_set(instance->spi, true);
- + // We're about to take the target out of reset
- + // so configure SPI pins as input
- + if(instance->spi) avr_isp_spi_sw_free(instance->spi);
- + instance->spi = NULL;
- + }
- +
- + instance->pmode = false;
- +}
- +
- +static bool avr_isp_start_pmode(AvrIsp* instance, AvrIspSpiSwSpeed spi_speed) {
- + furi_assert(instance);
- +
- + // Reset target before driving PIN_SCK or PIN_MOSI
- +
- + // SPI.begin() will configure SS as output,
- + // so SPI master mode is selected.
- + // We have defined RESET as pin 10,
- + // which for many arduino's is not the SS pin.
- + // So we have to configure RESET as output here,
- + // (reset_target() first sets the correct level)
- + if(instance->spi) avr_isp_spi_sw_free(instance->spi);
- + instance->spi = avr_isp_spi_sw_init(spi_speed);
- +
- + avr_isp_spi_sw_res_set(instance->spi, false);
- + // See avr datasheets, chapter "SERIAL_PRG Programming Algorithm":
- +
- + // Pulse RESET after PIN_SCK is low:
- + avr_isp_spi_sw_sck_set(instance->spi, false);
- +
- + // discharge PIN_SCK, value arbitrally chosen
- + furi_delay_ms(20);
- + avr_isp_spi_sw_res_set(instance->spi, true);
- +
- + // Pulse must be minimum 2 target CPU speed cycles
- + // so 100 usec is ok for CPU speeds above 20KHz
- + furi_delay_ms(1);
- +
- + avr_isp_spi_sw_res_set(instance->spi, false);
- +
- + // Send the enable programming command:
- + // datasheet: must be > 20 msec
- + furi_delay_ms(50);
- + if(avr_isp_set_pmode(instance, AVR_ISP_SET_PMODE)) {
- + instance->pmode = true;
- + return true;
- + }
- + return false;
- +}
- +
- +bool avr_isp_auto_set_spi_speed_start_pmode(AvrIsp* instance) {
- + furi_assert(instance);
- +
- + AvrIspSpiSwSpeed spi_speed[] = {
- + AvrIspSpiSwSpeed1Mhz,
- + AvrIspSpiSwSpeed400Khz,
- + AvrIspSpiSwSpeed250Khz,
- + AvrIspSpiSwSpeed125Khz,
- + AvrIspSpiSwSpeed60Khz,
- + AvrIspSpiSwSpeed40Khz,
- + AvrIspSpiSwSpeed20Khz,
- + AvrIspSpiSwSpeed10Khz,
- + AvrIspSpiSwSpeed5Khz,
- + AvrIspSpiSwSpeed1Khz,
- + };
- + for(uint8_t i = 0; i < COUNT_OF(spi_speed); i++) {
- + if(avr_isp_start_pmode(instance, spi_speed[i])) {
- + AvrIspSignature sig = avr_isp_read_signature(instance);
- + AvrIspSignature sig_examination = avr_isp_read_signature(instance); //-V656
- + uint8_t y = 0;
- + while(y < 8) {
- + if(memcmp((uint8_t*)&sig, (uint8_t*)&sig_examination, sizeof(AvrIspSignature)) !=
- + 0)
- + break;
- + sig_examination = avr_isp_read_signature(instance);
- + y++;
- + }
- + if(y == 8) {
- + if(spi_speed[i] > AvrIspSpiSwSpeed1Mhz) {
- + if(i < (COUNT_OF(spi_speed) - 1)) {
- + avr_isp_end_pmode(instance);
- + i++;
- + return avr_isp_start_pmode(instance, spi_speed[i]);
- + }
- + }
- + return true;
- + }
- + }
- + }
- + return false;
- +}
- +
- +static void avr_isp_commit(AvrIsp* instance, uint16_t addr, uint8_t data) {
- + furi_assert(instance);
- +
- + avr_isp_spi_transaction(instance, AVR_ISP_COMMIT(addr));
- + /* polling flash */
- + if(data == 0xFF) {
- + furi_delay_ms(5);
- + } else {
- + /* polling flash */
- + uint32_t starttime = furi_get_tick();
- + while((furi_get_tick() - starttime) < 30) {
- + if(avr_isp_spi_transaction(instance, AVR_ISP_READ_FLASH_HI(addr)) != 0xFF) {
- + break;
- + };
- + }
- + }
- +}
- +
- +static uint16_t avr_isp_current_page(AvrIsp* instance, uint32_t addr, uint16_t page_size) {
- + furi_assert(instance);
- +
- + uint16_t page = 0;
- + switch(page_size) {
- + case 32:
- + page = addr & 0xFFFFFFF0;
- + break;
- + case 64:
- + page = addr & 0xFFFFFFE0;
- + break;
- + case 128:
- + page = addr & 0xFFFFFFC0;
- + break;
- + case 256:
- + page = addr & 0xFFFFFF80;
- + break;
- +
- + default:
- + page = addr;
- + break;
- + }
- +
- + return page;
- +}
- +
- +static bool avr_isp_flash_write_pages(
- + AvrIsp* instance,
- + uint16_t addr,
- + uint16_t page_size,
- + uint8_t* data,
- + uint32_t data_size) {
- + furi_assert(instance);
- +
- + size_t x = 0;
- + uint16_t page = avr_isp_current_page(instance, addr, page_size);
- +
- + while(x < data_size) {
- + if(page != avr_isp_current_page(instance, addr, page_size)) {
- + avr_isp_commit(instance, page, data[x - 1]);
- + page = avr_isp_current_page(instance, addr, page_size);
- + }
- + avr_isp_spi_transaction(instance, AVR_ISP_WRITE_FLASH_LO(addr, data[x++]));
- + avr_isp_spi_transaction(instance, AVR_ISP_WRITE_FLASH_HI(addr, data[x++]));
- + addr++;
- + }
- + avr_isp_commit(instance, page, data[x - 1]);
- + return true;
- +}
- +
- +bool avr_isp_erase_chip(AvrIsp* instance) {
- + furi_assert(instance);
- +
- + bool ret = false;
- + if(!instance->pmode) avr_isp_auto_set_spi_speed_start_pmode(instance);
- + if(instance->pmode) {
- + avr_isp_spi_transaction(instance, AVR_ISP_ERASE_CHIP);
- + furi_delay_ms(100);
- + avr_isp_end_pmode(instance);
- + ret = true;
- + }
- + return ret;
- +}
- +
- +static bool
- + avr_isp_eeprom_write(AvrIsp* instance, uint16_t addr, uint8_t* data, uint32_t data_size) {
- + furi_assert(instance);
- +
- + for(uint16_t i = 0; i < data_size; i++) {
- + avr_isp_spi_transaction(instance, AVR_ISP_WRITE_EEPROM(addr, data[i]));
- + furi_delay_ms(10);
- + addr++;
- + }
- + return true;
- +}
- +
- +bool avr_isp_write_page(
- + AvrIsp* instance,
- + uint32_t mem_type,
- + uint32_t mem_size,
- + uint16_t addr,
- + uint16_t page_size,
- + uint8_t* data,
- + uint32_t data_size) {
- + furi_assert(instance);
- +
- + bool ret = false;
- + switch(mem_type) {
- + case STK_SET_FLASH_TYPE:
- + if((addr + data_size / 2) <= mem_size) {
- + ret = avr_isp_flash_write_pages(instance, addr, page_size, data, data_size);
- + }
- + break;
- +
- + case STK_SET_EEPROM_TYPE:
- + if((addr + data_size) <= mem_size) {
- + ret = avr_isp_eeprom_write(instance, addr, data, data_size);
- + }
- + break;
- +
- + default:
- + furi_crash(TAG " Incorrect mem type.");
- + break;
- + }
- +
- + return ret;
- +}
- +
- +static bool avr_isp_flash_read_page(
- + AvrIsp* instance,
- + uint16_t addr,
- + uint16_t page_size,
- + uint8_t* data,
- + uint32_t data_size) {
- + furi_assert(instance);
- +
- + if(page_size > data_size) return false;
- + for(uint16_t i = 0; i < page_size; i += 2) {
- + data[i] = avr_isp_spi_transaction(instance, AVR_ISP_READ_FLASH_LO(addr));
- + data[i + 1] = avr_isp_spi_transaction(instance, AVR_ISP_READ_FLASH_HI(addr));
- + addr++;
- + }
- + return true;
- +}
- +
- +static bool avr_isp_eeprom_read_page(
- + AvrIsp* instance,
- + uint16_t addr,
- + uint16_t page_size,
- + uint8_t* data,
- + uint32_t data_size) {
- + furi_assert(instance);
- +
- + if(page_size > data_size) return false;
- + for(uint16_t i = 0; i < page_size; i++) {
- + data[i] = avr_isp_spi_transaction(instance, AVR_ISP_READ_EEPROM(addr));
- + addr++;
- + }
- + return true;
- +}
- +
- +bool avr_isp_read_page(
- + AvrIsp* instance,
- + uint32_t mem_type,
- + uint16_t addr,
- + uint16_t page_size,
- + uint8_t* data,
- + uint32_t data_size) {
- + furi_assert(instance);
- +
- + bool res = false;
- + if(mem_type == STK_SET_FLASH_TYPE)
- + res = avr_isp_flash_read_page(instance, addr, page_size, data, data_size);
- + if(mem_type == STK_SET_EEPROM_TYPE)
- + res = avr_isp_eeprom_read_page(instance, addr, page_size, data, data_size);
- +
- + return res;
- +}
- +
- +AvrIspSignature avr_isp_read_signature(AvrIsp* instance) {
- + furi_assert(instance);
- +
- + AvrIspSignature signature;
- + signature.vendor = avr_isp_spi_transaction(instance, AVR_ISP_READ_VENDOR);
- + signature.part_family = avr_isp_spi_transaction(instance, AVR_ISP_READ_PART_FAMILY);
- + signature.part_number = avr_isp_spi_transaction(instance, AVR_ISP_READ_PART_NUMBER);
- + return signature;
- +}
- +
- +uint8_t avr_isp_read_lock_byte(AvrIsp* instance) {
- + furi_assert(instance);
- +
- + uint8_t data = 0;
- + uint32_t starttime = furi_get_tick();
- + while((furi_get_tick() - starttime) < 300) {
- + data = avr_isp_spi_transaction(instance, AVR_ISP_READ_LOCK_BYTE);
- + if(avr_isp_spi_transaction(instance, AVR_ISP_READ_LOCK_BYTE) == data) {
- + break;
- + };
- + data = 0x00;
- + }
- + return data;
- +}
- +
- +bool avr_isp_write_lock_byte(AvrIsp* instance, uint8_t lock) {
- + furi_assert(instance);
- +
- + bool ret = false;
- + if(avr_isp_read_lock_byte(instance) == lock) {
- + ret = true;
- + } else {
- + avr_isp_spi_transaction(instance, AVR_ISP_WRITE_LOCK_BYTE(lock));
- + /* polling lock byte */
- + uint32_t starttime = furi_get_tick();
- + while((furi_get_tick() - starttime) < 30) {
- + if(avr_isp_spi_transaction(instance, AVR_ISP_READ_LOCK_BYTE) == lock) {
- + ret = true;
- + break;
- + };
- + }
- + }
- + return ret;
- +}
- +
- +uint8_t avr_isp_read_fuse_low(AvrIsp* instance) {
- + furi_assert(instance);
- +
- + uint8_t data = 0;
- + uint32_t starttime = furi_get_tick();
- + while((furi_get_tick() - starttime) < 300) {
- + data = avr_isp_spi_transaction(instance, AVR_ISP_READ_FUSE_LOW);
- + if(avr_isp_spi_transaction(instance, AVR_ISP_READ_FUSE_LOW) == data) {
- + break;
- + };
- + data = 0x00;
- + }
- + return data;
- +}
- +
- +bool avr_isp_write_fuse_low(AvrIsp* instance, uint8_t lfuse) {
- + furi_assert(instance);
- +
- + bool ret = false;
- + if(avr_isp_read_fuse_low(instance) == lfuse) {
- + ret = true;
- + } else {
- + avr_isp_spi_transaction(instance, AVR_ISP_WRITE_FUSE_LOW(lfuse));
- + /* polling fuse */
- + uint32_t starttime = furi_get_tick();
- + while((furi_get_tick() - starttime) < 30) {
- + if(avr_isp_spi_transaction(instance, AVR_ISP_READ_FUSE_LOW) == lfuse) {
- + ret = true;
- + break;
- + };
- + }
- + }
- + return ret;
- +}
- +
- +uint8_t avr_isp_read_fuse_high(AvrIsp* instance) {
- + furi_assert(instance);
- +
- + uint8_t data = 0;
- + uint32_t starttime = furi_get_tick();
- + while((furi_get_tick() - starttime) < 300) {
- + data = avr_isp_spi_transaction(instance, AVR_ISP_READ_FUSE_HIGH);
- + if(avr_isp_spi_transaction(instance, AVR_ISP_READ_FUSE_HIGH) == data) {
- + break;
- + };
- + data = 0x00;
- + }
- + return data;
- +}
- +
- +bool avr_isp_write_fuse_high(AvrIsp* instance, uint8_t hfuse) {
- + furi_assert(instance);
- +
- + bool ret = false;
- + if(avr_isp_read_fuse_high(instance) == hfuse) {
- + ret = true;
- + } else {
- + avr_isp_spi_transaction(instance, AVR_ISP_WRITE_FUSE_HIGH(hfuse));
- + /* polling fuse */
- + uint32_t starttime = furi_get_tick();
- + while((furi_get_tick() - starttime) < 30) {
- + if(avr_isp_spi_transaction(instance, AVR_ISP_READ_FUSE_HIGH) == hfuse) {
- + ret = true;
- + break;
- + };
- + }
- + }
- + return ret;
- +}
- +
- +uint8_t avr_isp_read_fuse_extended(AvrIsp* instance) {
- + furi_assert(instance);
- +
- + uint8_t data = 0;
- + uint32_t starttime = furi_get_tick();
- + while((furi_get_tick() - starttime) < 300) {
- + data = avr_isp_spi_transaction(instance, AVR_ISP_READ_FUSE_EXTENDED);
- + if(avr_isp_spi_transaction(instance, AVR_ISP_READ_FUSE_EXTENDED) == data) {
- + break;
- + };
- + data = 0x00;
- + }
- + return data;
- +}
- +
- +bool avr_isp_write_fuse_extended(AvrIsp* instance, uint8_t efuse) {
- + furi_assert(instance);
- +
- + bool ret = false;
- + if(avr_isp_read_fuse_extended(instance) == efuse) {
- + ret = true;
- + } else {
- + avr_isp_spi_transaction(instance, AVR_ISP_WRITE_FUSE_EXTENDED(efuse));
- + /* polling fuse */
- + uint32_t starttime = furi_get_tick();
- + while((furi_get_tick() - starttime) < 30) {
- + if(avr_isp_spi_transaction(instance, AVR_ISP_READ_FUSE_EXTENDED) == efuse) {
- + ret = true;
- + break;
- + };
- + }
- + }
- + return ret;
- +}
- +
- +void avr_isp_write_extended_addr(AvrIsp* instance, uint8_t extended_addr) {
- + furi_assert(instance);
- +
- + avr_isp_spi_transaction(instance, AVR_ISP_EXTENDED_ADDR(extended_addr));
- + furi_delay_ms(10);
- +}
- \ No newline at end of file
- diff --git a/applications/external/avr_isp_programmer/helpers/avr_isp.h b/applications/external/avr_isp_programmer/helpers/avr_isp.h
- new file mode 100644
- index 000000000..476fc3d64
- --- /dev/null
- +++ b/applications/external/avr_isp_programmer/helpers/avr_isp.h
- @@ -0,0 +1,70 @@
- +#pragma once
- +
- +#include <furi_hal.h>
- +
- +typedef struct AvrIsp AvrIsp;
- +typedef void (*AvrIspCallback)(void* context);
- +
- +struct AvrIspSignature {
- + uint8_t vendor;
- + uint8_t part_family;
- + uint8_t part_number;
- +};
- +
- +typedef struct AvrIspSignature AvrIspSignature;
- +
- +AvrIsp* avr_isp_alloc(void);
- +
- +void avr_isp_free(AvrIsp* instance);
- +
- +void avr_isp_set_tx_callback(AvrIsp* instance, AvrIspCallback callback, void* context);
- +
- +bool avr_isp_auto_set_spi_speed_start_pmode(AvrIsp* instance);
- +
- +AvrIspSignature avr_isp_read_signature(AvrIsp* instance);
- +
- +void avr_isp_end_pmode(AvrIsp* instance);
- +
- +bool avr_isp_erase_chip(AvrIsp* instance);
- +
- +uint8_t avr_isp_spi_transaction(
- + AvrIsp* instance,
- + uint8_t cmd,
- + uint8_t addr_hi,
- + uint8_t addr_lo,
- + uint8_t data);
- +
- +bool avr_isp_read_page(
- + AvrIsp* instance,
- + uint32_t memtype,
- + uint16_t addr,
- + uint16_t page_size,
- + uint8_t* data,
- + uint32_t data_size);
- +
- +bool avr_isp_write_page(
- + AvrIsp* instance,
- + uint32_t mem_type,
- + uint32_t mem_size,
- + uint16_t addr,
- + uint16_t page_size,
- + uint8_t* data,
- + uint32_t data_size);
- +
- +uint8_t avr_isp_read_lock_byte(AvrIsp* instance);
- +
- +bool avr_isp_write_lock_byte(AvrIsp* instance, uint8_t lock);
- +
- +uint8_t avr_isp_read_fuse_low(AvrIsp* instance);
- +
- +bool avr_isp_write_fuse_low(AvrIsp* instance, uint8_t lfuse);
- +
- +uint8_t avr_isp_read_fuse_high(AvrIsp* instance);
- +
- +bool avr_isp_write_fuse_high(AvrIsp* instance, uint8_t hfuse);
- +
- +uint8_t avr_isp_read_fuse_extended(AvrIsp* instance);
- +
- +bool avr_isp_write_fuse_extended(AvrIsp* instance, uint8_t efuse);
- +
- +void avr_isp_write_extended_addr(AvrIsp* instance, uint8_t extended_addr);
- \ No newline at end of file
- diff --git a/applications/external/avr_isp_programmer/helpers/avr_isp_event.h b/applications/external/avr_isp_programmer/helpers/avr_isp_event.h
- new file mode 100644
- index 000000000..c704b5b35
- --- /dev/null
- +++ b/applications/external/avr_isp_programmer/helpers/avr_isp_event.h
- @@ -0,0 +1,23 @@
- +#pragma once
- +
- +typedef enum {
- + //SubmenuIndex
- + SubmenuIndexAvrIspProgrammer = 10,
- + SubmenuIndexAvrIspReader,
- + SubmenuIndexAvrIspWriter,
- + SubmenuIndexAvrIsWiring,
- + SubmenuIndexAvrIspAbout,
- +
- + //AvrIspCustomEvent
- + AvrIspCustomEventSceneChipDetectOk = 100,
- + AvrIspCustomEventSceneReadingOk,
- + AvrIspCustomEventSceneWritingOk,
- + AvrIspCustomEventSceneErrorVerification,
- + AvrIspCustomEventSceneErrorReading,
- + AvrIspCustomEventSceneErrorWriting,
- + AvrIspCustomEventSceneErrorWritingFuse,
- + AvrIspCustomEventSceneInputName,
- + AvrIspCustomEventSceneSuccess,
- + AvrIspCustomEventSceneExit,
- + AvrIspCustomEventSceneExitStartMenu,
- +} AvrIspCustomEvent;
- diff --git a/applications/external/avr_isp_programmer/helpers/avr_isp_types.h b/applications/external/avr_isp_programmer/helpers/avr_isp_types.h
- new file mode 100644
- index 000000000..5e174ec3b
- --- /dev/null
- +++ b/applications/external/avr_isp_programmer/helpers/avr_isp_types.h
- @@ -0,0 +1,32 @@
- +#pragma once
- +
- +#include <furi.h>
- +#include <furi_hal.h>
- +
- +#define AVR_ISP_VERSION_APP "0.1"
- +#define AVR_ISP_DEVELOPED "SkorP"
- +#define AVR_ISP_GITHUB "https://github.com/flipperdevices/flipperzero-firmware"
- +
- +#define AVR_ISP_APP_FILE_VERSION 1
- +#define AVR_ISP_APP_FILE_TYPE "Flipper Dump AVR"
- +#define AVR_ISP_APP_EXTENSION ".avr"
- +
- +typedef enum {
- + //AvrIspViewVariableItemList,
- + AvrIspViewSubmenu,
- + AvrIspViewProgrammer,
- + AvrIspViewReader,
- + AvrIspViewWriter,
- + AvrIspViewWidget,
- + AvrIspViewPopup,
- + AvrIspViewTextInput,
- + AvrIspViewChipDetect,
- +} AvrIspView;
- +
- +typedef enum {
- + AvrIspErrorNoError,
- + AvrIspErrorReading,
- + AvrIspErrorWriting,
- + AvrIspErrorVerification,
- + AvrIspErrorWritingFuse,
- +} AvrIspError;
- \ No newline at end of file
- diff --git a/applications/external/avr_isp_programmer/helpers/avr_isp_worker.c b/applications/external/avr_isp_programmer/helpers/avr_isp_worker.c
- new file mode 100644
- index 000000000..dfe1f43c2
- --- /dev/null
- +++ b/applications/external/avr_isp_programmer/helpers/avr_isp_worker.c
- @@ -0,0 +1,266 @@
- +#include "avr_isp_worker.h"
- +#include <furi_hal_pwm.h>
- +#include "../lib/driver/avr_isp_prog.h"
- +#include "../lib/driver/avr_isp_prog_cmd.h"
- +#include "../lib/driver/avr_isp_chip_arr.h"
- +
- +#include <furi.h>
- +
- +#define TAG "AvrIspWorker"
- +
- +typedef enum {
- + AvrIspWorkerEvtStop = (1 << 0),
- +
- + AvrIspWorkerEvtRx = (1 << 1),
- + AvrIspWorkerEvtTxCoplete = (1 << 2),
- + AvrIspWorkerEvtTx = (1 << 3),
- + AvrIspWorkerEvtState = (1 << 4),
- +
- + //AvrIspWorkerEvtCfg = (1 << 5),
- +
- +} AvrIspWorkerEvt;
- +
- +struct AvrIspWorker {
- + FuriThread* thread;
- + volatile bool worker_running;
- + uint8_t connect_usb;
- + AvrIspWorkerCallback callback;
- + void* context;
- +};
- +
- +#define AVR_ISP_WORKER_PROG_ALL_EVENTS (AvrIspWorkerEvtStop)
- +#define AVR_ISP_WORKER_ALL_EVENTS \
- + (AvrIspWorkerEvtTx | AvrIspWorkerEvtTxCoplete | AvrIspWorkerEvtRx | AvrIspWorkerEvtStop | \
- + AvrIspWorkerEvtState)
- +
- +//########################/* VCP CDC */#############################################
- +#include "usb_cdc.h"
- +#include <cli/cli_vcp.h>
- +#include <cli/cli.h>
- +#include <furi_hal_usb_cdc.h>
- +
- +#define AVR_ISP_VCP_CDC_CH 1
- +#define AVR_ISP_VCP_CDC_PKT_LEN CDC_DATA_SZ
- +#define AVR_ISP_VCP_UART_RX_BUF_SIZE (AVR_ISP_VCP_CDC_PKT_LEN * 5)
- +
- +static void vcp_on_cdc_tx_complete(void* context);
- +static void vcp_on_cdc_rx(void* context);
- +static void vcp_state_callback(void* context, uint8_t state);
- +static void vcp_on_cdc_control_line(void* context, uint8_t state);
- +static void vcp_on_line_config(void* context, struct usb_cdc_line_coding* config);
- +
- +static const CdcCallbacks cdc_cb = {
- + vcp_on_cdc_tx_complete,
- + vcp_on_cdc_rx,
- + vcp_state_callback,
- + vcp_on_cdc_control_line,
- + vcp_on_line_config,
- +};
- +
- +/* VCP callbacks */
- +
- +static void vcp_on_cdc_tx_complete(void* context) {
- + furi_assert(context);
- + AvrIspWorker* instance = context;
- + furi_thread_flags_set(furi_thread_get_id(instance->thread), AvrIspWorkerEvtTxCoplete);
- +}
- +
- +static void vcp_on_cdc_rx(void* context) {
- + furi_assert(context);
- + AvrIspWorker* instance = context;
- + furi_thread_flags_set(furi_thread_get_id(instance->thread), AvrIspWorkerEvtRx);
- +}
- +
- +static void vcp_state_callback(void* context, uint8_t state) {
- + UNUSED(context);
- +
- + AvrIspWorker* instance = context;
- + instance->connect_usb = state;
- + furi_thread_flags_set(furi_thread_get_id(instance->thread), AvrIspWorkerEvtState);
- +}
- +
- +static void vcp_on_cdc_control_line(void* context, uint8_t state) {
- + UNUSED(context);
- + UNUSED(state);
- +}
- +
- +static void vcp_on_line_config(void* context, struct usb_cdc_line_coding* config) {
- + UNUSED(context);
- + UNUSED(config);
- +}
- +
- +static void avr_isp_worker_vcp_cdc_init(void* context) {
- + furi_hal_usb_unlock();
- + Cli* cli = furi_record_open(RECORD_CLI);
- + //close cli
- + cli_session_close(cli);
- + //disable callbacks VCP_CDC=0
- + furi_hal_cdc_set_callbacks(0, NULL, NULL);
- + //set 2 cdc
- + furi_check(furi_hal_usb_set_config(&usb_cdc_dual, NULL) == true);
- + //open cli VCP_CDC=0
- + cli_session_open(cli, &cli_vcp);
- + furi_record_close(RECORD_CLI);
- +
- + furi_hal_cdc_set_callbacks(AVR_ISP_VCP_CDC_CH, (CdcCallbacks*)&cdc_cb, context);
- +}
- +
- +static void avr_isp_worker_vcp_cdc_deinit(void) {
- + //disable callbacks AVR_ISP_VCP_CDC_CH
- + furi_hal_cdc_set_callbacks(AVR_ISP_VCP_CDC_CH, NULL, NULL);
- +
- + Cli* cli = furi_record_open(RECORD_CLI);
- + //close cli
- + cli_session_close(cli);
- + furi_hal_usb_unlock();
- + //set 1 cdc
- + furi_check(furi_hal_usb_set_config(&usb_cdc_single, NULL) == true);
- + //open cli VCP_CDC=0
- + cli_session_open(cli, &cli_vcp);
- + furi_record_close(RECORD_CLI);
- +}
- +
- +//#################################################################################
- +
- +static int32_t avr_isp_worker_prog_thread(void* context) {
- + AvrIspProg* prog = context;
- + FURI_LOG_D(TAG, "AvrIspProgWorker Start");
- + while(1) {
- + if(furi_thread_flags_get() & AvrIspWorkerEvtStop) break;
- + avr_isp_prog_avrisp(prog);
- + }
- + FURI_LOG_D(TAG, "AvrIspProgWorker Stop");
- + return 0;
- +}
- +
- +static void avr_isp_worker_prog_tx_data(void* context) {
- + furi_assert(context);
- + AvrIspWorker* instance = context;
- + furi_thread_flags_set(furi_thread_get_id(instance->thread), AvrIspWorkerEvtTx);
- +}
- +
- +/** Worker thread
- + *
- + * @param context
- + * @return exit code
- + */
- +static int32_t avr_isp_worker_thread(void* context) {
- + AvrIspWorker* instance = context;
- + avr_isp_worker_vcp_cdc_init(instance);
- +
- + /* start PWM on &gpio_ext_pa4 */
- + furi_hal_pwm_start(FuriHalPwmOutputIdLptim2PA4, 4000000, 50);
- +
- + AvrIspProg* prog = avr_isp_prog_init();
- + avr_isp_prog_set_tx_callback(prog, avr_isp_worker_prog_tx_data, instance);
- +
- + uint8_t buf[AVR_ISP_VCP_UART_RX_BUF_SIZE];
- + size_t len = 0;
- +
- + FuriThread* prog_thread =
- + furi_thread_alloc_ex("AvrIspProgWorker", 1024, avr_isp_worker_prog_thread, prog);
- + furi_thread_start(prog_thread);
- +
- + FURI_LOG_D(TAG, "Start");
- +
- + while(instance->worker_running) {
- + uint32_t events =
- + furi_thread_flags_wait(AVR_ISP_WORKER_ALL_EVENTS, FuriFlagWaitAny, FuriWaitForever);
- +
- + if(events & AvrIspWorkerEvtRx) {
- + if(avr_isp_prog_spaces_rx(prog) >= AVR_ISP_VCP_CDC_PKT_LEN) {
- + len = furi_hal_cdc_receive(AVR_ISP_VCP_CDC_CH, buf, AVR_ISP_VCP_CDC_PKT_LEN);
- + // for(uint8_t i = 0; i < len; i++) {
- + // FURI_LOG_I(TAG, "--> %X", buf[i]);
- + // }
- + avr_isp_prog_rx(prog, buf, len);
- + } else {
- + furi_thread_flags_set(furi_thread_get_id(instance->thread), AvrIspWorkerEvtRx);
- + }
- + }
- +
- + if((events & AvrIspWorkerEvtTxCoplete) || (events & AvrIspWorkerEvtTx)) {
- + len = avr_isp_prog_tx(prog, buf, AVR_ISP_VCP_CDC_PKT_LEN);
- +
- + // for(uint8_t i = 0; i < len; i++) {
- + // FURI_LOG_I(TAG, "<-- %X", buf[i]);
- + // }
- +
- + if(len > 0) furi_hal_cdc_send(AVR_ISP_VCP_CDC_CH, buf, len);
- + }
- +
- + if(events & AvrIspWorkerEvtStop) {
- + break;
- + }
- +
- + if(events & AvrIspWorkerEvtState) {
- + if(instance->callback)
- + instance->callback(instance->context, (bool)instance->connect_usb);
- + }
- + }
- +
- + FURI_LOG_D(TAG, "Stop");
- +
- + furi_thread_flags_set(furi_thread_get_id(prog_thread), AvrIspWorkerEvtStop);
- + avr_isp_prog_exit(prog);
- + furi_delay_ms(10);
- + furi_thread_join(prog_thread);
- + furi_thread_free(prog_thread);
- +
- + avr_isp_prog_free(prog);
- + furi_hal_pwm_stop(FuriHalPwmOutputIdLptim2PA4);
- + avr_isp_worker_vcp_cdc_deinit();
- + return 0;
- +}
- +
- +AvrIspWorker* avr_isp_worker_alloc(void* context) {
- + furi_assert(context);
- + UNUSED(context);
- + AvrIspWorker* instance = malloc(sizeof(AvrIspWorker));
- +
- + instance->thread = furi_thread_alloc_ex("AvrIspWorker", 2048, avr_isp_worker_thread, instance);
- + return instance;
- +}
- +
- +void avr_isp_worker_free(AvrIspWorker* instance) {
- + furi_assert(instance);
- +
- + furi_check(!instance->worker_running);
- + furi_thread_free(instance->thread);
- + free(instance);
- +}
- +
- +void avr_isp_worker_set_callback(
- + AvrIspWorker* instance,
- + AvrIspWorkerCallback callback,
- + void* context) {
- + furi_assert(instance);
- +
- + instance->callback = callback;
- + instance->context = context;
- +}
- +
- +void avr_isp_worker_start(AvrIspWorker* instance) {
- + furi_assert(instance);
- + furi_assert(!instance->worker_running);
- +
- + instance->worker_running = true;
- +
- + furi_thread_start(instance->thread);
- +}
- +
- +void avr_isp_worker_stop(AvrIspWorker* instance) {
- + furi_assert(instance);
- + furi_assert(instance->worker_running);
- +
- + instance->worker_running = false;
- + furi_thread_flags_set(furi_thread_get_id(instance->thread), AvrIspWorkerEvtStop);
- +
- + furi_thread_join(instance->thread);
- +}
- +
- +bool avr_isp_worker_is_running(AvrIspWorker* instance) {
- + furi_assert(instance);
- +
- + return instance->worker_running;
- +}
- diff --git a/applications/external/avr_isp_programmer/helpers/avr_isp_worker.h b/applications/external/avr_isp_programmer/helpers/avr_isp_worker.h
- new file mode 100644
- index 000000000..cd9897dff
- --- /dev/null
- +++ b/applications/external/avr_isp_programmer/helpers/avr_isp_worker.h
- @@ -0,0 +1,49 @@
- +#pragma once
- +
- +#include <furi_hal.h>
- +
- +typedef struct AvrIspWorker AvrIspWorker;
- +
- +typedef void (*AvrIspWorkerCallback)(void* context, bool connect_usb);
- +
- +/** Allocate AvrIspWorker
- + *
- + * @param context AvrIsp* context
- + * @return AvrIspWorker*
- + */
- +AvrIspWorker* avr_isp_worker_alloc(void* context);
- +
- +/** Free AvrIspWorker
- + *
- + * @param instance AvrIspWorker instance
- + */
- +void avr_isp_worker_free(AvrIspWorker* instance);
- +
- +/** Callback AvrIspWorker
- + *
- + * @param instance AvrIspWorker instance
- + * @param callback AvrIspWorkerOverrunCallback callback
- + * @param context
- + */
- +void avr_isp_worker_set_callback(
- + AvrIspWorker* instance,
- + AvrIspWorkerCallback callback,
- + void* context);
- +
- +/** Start AvrIspWorker
- + *
- + * @param instance AvrIspWorker instance
- + */
- +void avr_isp_worker_start(AvrIspWorker* instance);
- +
- +/** Stop AvrIspWorker
- + *
- + * @param instance AvrIspWorker instance
- + */
- +void avr_isp_worker_stop(AvrIspWorker* instance);
- +
- +/** Check if worker is running
- + * @param instance AvrIspWorker instance
- + * @return bool - true if running
- + */
- +bool avr_isp_worker_is_running(AvrIspWorker* instance);
- 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
- new file mode 100644
- index 000000000..fc8d3b09f
- --- /dev/null
- +++ b/applications/external/avr_isp_programmer/helpers/avr_isp_worker_rw.c
- @@ -0,0 +1,1145 @@
- +#include "avr_isp_worker_rw.h"
- +#include <furi_hal_pwm.h>
- +#include "avr_isp_types.h"
- +#include "avr_isp.h"
- +#include "../lib/driver/avr_isp_prog_cmd.h"
- +#include "../lib/driver/avr_isp_chip_arr.h"
- +
- +#include "flipper_i32hex_file.h"
- +#include <flipper_format/flipper_format.h>
- +
- +#include <furi.h>
- +
- +#define TAG "AvrIspWorkerRW"
- +
- +#define NAME_PATERN_FLASH_FILE "flash.hex"
- +#define NAME_PATERN_EEPROM_FILE "eeprom.hex"
- +
- +struct AvrIspWorkerRW {
- + AvrIsp* avr_isp;
- + FuriThread* thread;
- + volatile bool worker_running;
- +
- + uint32_t chip_arr_ind;
- + bool chip_detect;
- + uint8_t lfuse;
- + uint8_t hfuse;
- + uint8_t efuse;
- + uint8_t lock;
- + float progress_flash;
- + float progress_eeprom;
- + const char* file_path;
- + const char* file_name;
- + AvrIspSignature signature;
- + AvrIspWorkerRWCallback callback;
- + void* context;
- +
- + AvrIspWorkerRWStatusCallback callback_status;
- + void* context_status;
- +};
- +
- +typedef enum {
- + AvrIspWorkerRWEvtStop = (1 << 0),
- +
- + AvrIspWorkerRWEvtReading = (1 << 1),
- + AvrIspWorkerRWEvtVerification = (1 << 2),
- + AvrIspWorkerRWEvtWriting = (1 << 3),
- + AvrIspWorkerRWEvtWritingFuse = (1 << 4),
- +
- +} AvrIspWorkerRWEvt;
- +#define AVR_ISP_WORKER_ALL_EVENTS \
- + (AvrIspWorkerRWEvtWritingFuse | AvrIspWorkerRWEvtWriting | AvrIspWorkerRWEvtVerification | \
- + AvrIspWorkerRWEvtReading | AvrIspWorkerRWEvtStop)
- +
- +/** Worker thread
- + *
- + * @param context
- + * @return exit code
- + */
- +static int32_t avr_isp_worker_rw_thread(void* context) {
- + AvrIspWorkerRW* instance = context;
- +
- + /* start PWM on &gpio_ext_pa4 */
- + furi_hal_pwm_start(FuriHalPwmOutputIdLptim2PA4, 4000000, 50);
- +
- + FURI_LOG_D(TAG, "Start");
- +
- + while(1) {
- + uint32_t events =
- + furi_thread_flags_wait(AVR_ISP_WORKER_ALL_EVENTS, FuriFlagWaitAny, FuriWaitForever);
- +
- + if(events & AvrIspWorkerRWEvtStop) {
- + break;
- + }
- +
- + if(events & AvrIspWorkerRWEvtWritingFuse) {
- + if(avr_isp_worker_rw_write_fuse(instance, instance->file_path, instance->file_name)) {
- + if(instance->callback_status)
- + instance->callback_status(
- + instance->context_status, AvrIspWorkerRWStatusEndWritingFuse);
- + } else {
- + if(instance->callback_status)
- + instance->callback_status(
- + instance->context_status, AvrIspWorkerRWStatusErrorWritingFuse);
- + }
- + }
- +
- + if(events & AvrIspWorkerRWEvtWriting) {
- + if(avr_isp_worker_rw_write_dump(instance, instance->file_path, instance->file_name)) {
- + if(instance->callback_status)
- + instance->callback_status(
- + instance->context_status, AvrIspWorkerRWStatusEndWriting);
- + } else {
- + if(instance->callback_status)
- + instance->callback_status(
- + instance->context_status, AvrIspWorkerRWStatusErrorWriting);
- + }
- + }
- +
- + if(events & AvrIspWorkerRWEvtVerification) {
- + if(avr_isp_worker_rw_verification(instance, instance->file_path, instance->file_name)) {
- + if(instance->callback_status)
- + instance->callback_status(
- + instance->context_status, AvrIspWorkerRWStatusEndVerification);
- + } else {
- + if(instance->callback_status)
- + instance->callback_status(
- + instance->context_status, AvrIspWorkerRWStatusErrorVerification);
- + }
- + }
- +
- + if(events & AvrIspWorkerRWEvtReading) {
- + if(avr_isp_worker_rw_read_dump(instance, instance->file_path, instance->file_name)) {
- + if(instance->callback_status)
- + instance->callback_status(
- + instance->context_status, AvrIspWorkerRWStatusEndReading);
- + } else {
- + if(instance->callback_status)
- + instance->callback_status(
- + instance->context_status, AvrIspWorkerRWStatusErrorReading);
- + }
- + }
- + }
- + FURI_LOG_D(TAG, "Stop");
- +
- + furi_hal_pwm_stop(FuriHalPwmOutputIdLptim2PA4);
- +
- + return 0;
- +}
- +
- +bool avr_isp_worker_rw_detect_chip(AvrIspWorkerRW* instance) {
- + furi_assert(instance);
- +
- + FURI_LOG_D(TAG, "Detecting AVR chip");
- +
- + instance->chip_detect = false;
- + instance->chip_arr_ind = avr_isp_chip_arr_size + 1;
- +
- + /* start PWM on &gpio_ext_pa4 */
- + furi_hal_pwm_start(FuriHalPwmOutputIdLptim2PA4, 4000000, 50);
- +
- + do {
- + if(!avr_isp_auto_set_spi_speed_start_pmode(instance->avr_isp)) {
- + FURI_LOG_E(TAG, "Well, I managed to enter the mod program");
- + break;
- + }
- + instance->signature = avr_isp_read_signature(instance->avr_isp);
- +
- + if(instance->signature.vendor != 0x1E) {
- + //No detect chip
- + } else {
- + for(uint32_t ind = 0; ind < avr_isp_chip_arr_size; ind++) {
- + if(avr_isp_chip_arr[ind].avrarch != F_AVR8) continue;
- + if(avr_isp_chip_arr[ind].sigs[1] == instance->signature.part_family) {
- + if(avr_isp_chip_arr[ind].sigs[2] == instance->signature.part_number) {
- + FURI_LOG_D(TAG, "Detect AVR chip = \"%s\"", avr_isp_chip_arr[ind].name);
- + FURI_LOG_D(
- + TAG,
- + "Signature = 0x%02X 0x%02X 0x%02X",
- + instance->signature.vendor,
- + instance->signature.part_family,
- + instance->signature.part_number);
- +
- + switch(avr_isp_chip_arr[ind].nfuses) {
- + case 1:
- + instance->lfuse = avr_isp_read_fuse_low(instance->avr_isp);
- + FURI_LOG_D(TAG, "Lfuse = %02X", instance->lfuse);
- + break;
- + case 2:
- + instance->lfuse = avr_isp_read_fuse_low(instance->avr_isp);
- + instance->hfuse = avr_isp_read_fuse_high(instance->avr_isp);
- + FURI_LOG_D(
- + TAG, "Lfuse = %02X Hfuse = %02X", instance->lfuse, instance->hfuse);
- + break;
- + case 3:
- + instance->lfuse = avr_isp_read_fuse_low(instance->avr_isp);
- + instance->hfuse = avr_isp_read_fuse_high(instance->avr_isp);
- + instance->efuse = avr_isp_read_fuse_extended(instance->avr_isp);
- + FURI_LOG_D(
- + TAG,
- + "Lfuse = %02X Hfuse = %02X Efuse = %02X",
- + instance->lfuse,
- + instance->hfuse,
- + instance->efuse);
- + break;
- + default:
- + break;
- + }
- + if(avr_isp_chip_arr[ind].nlocks == 1) {
- + instance->lock = avr_isp_read_lock_byte(instance->avr_isp);
- + FURI_LOG_D(TAG, "Lock = %02X", instance->lock);
- + }
- + instance->chip_detect = true;
- + instance->chip_arr_ind = ind;
- + break;
- + }
- + }
- + }
- + }
- + avr_isp_end_pmode(instance->avr_isp);
- +
- + furi_hal_pwm_stop(FuriHalPwmOutputIdLptim2PA4);
- +
- + } while(0);
- + if(instance->callback) {
- + if(instance->chip_arr_ind > avr_isp_chip_arr_size) {
- + instance->callback(instance->context, "No detect", instance->chip_detect, 0);
- + } else if(instance->chip_arr_ind < avr_isp_chip_arr_size) {
- + instance->callback(
- + instance->context,
- + avr_isp_chip_arr[instance->chip_arr_ind].name,
- + instance->chip_detect,
- + avr_isp_chip_arr[instance->chip_arr_ind].flashsize);
- + } else {
- + instance->callback(instance->context, "Unknown", instance->chip_detect, 0);
- + }
- + }
- +
- + return instance->chip_detect;
- +}
- +
- +AvrIspWorkerRW* avr_isp_worker_rw_alloc(void* context) {
- + furi_assert(context);
- + UNUSED(context);
- +
- + AvrIspWorkerRW* instance = malloc(sizeof(AvrIspWorkerRW));
- + instance->avr_isp = avr_isp_alloc();
- +
- + instance->thread =
- + furi_thread_alloc_ex("AvrIspWorkerRW", 4096, avr_isp_worker_rw_thread, instance);
- +
- + instance->chip_detect = false;
- + instance->lfuse = 0;
- + instance->hfuse = 0;
- + instance->efuse = 0;
- + instance->lock = 0;
- + instance->progress_flash = 0.0f;
- + instance->progress_eeprom = 0.0f;
- +
- + return instance;
- +}
- +
- +void avr_isp_worker_rw_free(AvrIspWorkerRW* instance) {
- + furi_assert(instance);
- +
- + avr_isp_free(instance->avr_isp);
- +
- + furi_check(!instance->worker_running);
- + furi_thread_free(instance->thread);
- +
- + free(instance);
- +}
- +
- +void avr_isp_worker_rw_start(AvrIspWorkerRW* instance) {
- + furi_assert(instance);
- + furi_assert(!instance->worker_running);
- +
- + instance->worker_running = true;
- +
- + furi_thread_start(instance->thread);
- +}
- +
- +void avr_isp_worker_rw_stop(AvrIspWorkerRW* instance) {
- + furi_assert(instance);
- + furi_assert(instance->worker_running);
- +
- + instance->worker_running = false;
- + furi_thread_flags_set(furi_thread_get_id(instance->thread), AvrIspWorkerRWEvtStop);
- +
- + furi_thread_join(instance->thread);
- +}
- +
- +bool avr_isp_worker_rw_is_running(AvrIspWorkerRW* instance) {
- + furi_assert(instance);
- +
- + return instance->worker_running;
- +}
- +
- +void avr_isp_worker_rw_set_callback(
- + AvrIspWorkerRW* instance,
- + AvrIspWorkerRWCallback callback,
- + void* context) {
- + furi_assert(instance);
- +
- + instance->callback = callback;
- + instance->context = context;
- +}
- +
- +void avr_isp_worker_rw_set_callback_status(
- + AvrIspWorkerRW* instance,
- + AvrIspWorkerRWStatusCallback callback_status,
- + void* context_status) {
- + furi_assert(instance);
- +
- + instance->callback_status = callback_status;
- + instance->context_status = context_status;
- +}
- +
- +float avr_isp_worker_rw_get_progress_flash(AvrIspWorkerRW* instance) {
- + furi_assert(instance);
- +
- + return instance->progress_flash;
- +}
- +
- +float avr_isp_worker_rw_get_progress_eeprom(AvrIspWorkerRW* instance) {
- + furi_assert(instance);
- +
- + return instance->progress_eeprom;
- +}
- +
- +static void avr_isp_worker_rw_get_dump_flash(AvrIspWorkerRW* instance, const char* file_path) {
- + furi_assert(instance);
- + furi_check(instance->avr_isp);
- +
- + FURI_LOG_D(TAG, "Dump FLASH %s", file_path);
- +
- + FlipperI32HexFile* flipper_hex_flash = flipper_i32hex_file_open_write(
- + file_path, avr_isp_chip_arr[instance->chip_arr_ind].flashoffset);
- +
- + uint8_t data[272] = {0};
- + bool send_extended_addr = ((avr_isp_chip_arr[instance->chip_arr_ind].flashsize / 2) > 0x10000);
- + uint8_t extended_addr = 0;
- +
- + for(int32_t i = avr_isp_chip_arr[instance->chip_arr_ind].flashoffset;
- + i < avr_isp_chip_arr[instance->chip_arr_ind].flashsize / 2;
- + i += avr_isp_chip_arr[instance->chip_arr_ind].pagesize / 2) {
- + if(send_extended_addr) {
- + if(extended_addr <= ((i >> 16) & 0xFF)) {
- + avr_isp_write_extended_addr(instance->avr_isp, extended_addr);
- + extended_addr = ((i >> 16) & 0xFF) + 1;
- + }
- + }
- + avr_isp_read_page(
- + instance->avr_isp,
- + STK_SET_FLASH_TYPE,
- + (uint16_t)i,
- + avr_isp_chip_arr[instance->chip_arr_ind].pagesize,
- + data,
- + sizeof(data));
- + flipper_i32hex_file_bin_to_i32hex_set_data(
- + flipper_hex_flash, data, avr_isp_chip_arr[instance->chip_arr_ind].pagesize);
- + FURI_LOG_D(TAG, "%s", flipper_i32hex_file_get_string(flipper_hex_flash));
- + instance->progress_flash =
- + (float)(i) / ((float)avr_isp_chip_arr[instance->chip_arr_ind].flashsize / 2.0f);
- + }
- + flipper_i32hex_file_bin_to_i32hex_set_end_line(flipper_hex_flash);
- + FURI_LOG_D(TAG, "%s", flipper_i32hex_file_get_string(flipper_hex_flash));
- + flipper_i32hex_file_close(flipper_hex_flash);
- + instance->progress_flash = 1.0f;
- +}
- +
- +static void avr_isp_worker_rw_get_dump_eeprom(AvrIspWorkerRW* instance, const char* file_path) {
- + furi_assert(instance);
- + furi_check(instance->avr_isp);
- +
- + FURI_LOG_D(TAG, "Dump EEPROM %s", file_path);
- +
- + FlipperI32HexFile* flipper_hex_eeprom = flipper_i32hex_file_open_write(
- + file_path, avr_isp_chip_arr[instance->chip_arr_ind].eepromoffset);
- +
- + int32_t size_data = 32;
- + uint8_t data[256] = {0};
- +
- + if(size_data > avr_isp_chip_arr[instance->chip_arr_ind].eepromsize)
- + size_data = avr_isp_chip_arr[instance->chip_arr_ind].eepromsize;
- +
- + for(int32_t i = avr_isp_chip_arr[instance->chip_arr_ind].eepromoffset;
- + i < avr_isp_chip_arr[instance->chip_arr_ind].eepromsize;
- + i += size_data) {
- + avr_isp_read_page(
- + instance->avr_isp, STK_SET_EEPROM_TYPE, (uint16_t)i, size_data, data, sizeof(data));
- + flipper_i32hex_file_bin_to_i32hex_set_data(flipper_hex_eeprom, data, size_data);
- + FURI_LOG_D(TAG, "%s", flipper_i32hex_file_get_string(flipper_hex_eeprom));
- + instance->progress_eeprom =
- + (float)(i) / ((float)avr_isp_chip_arr[instance->chip_arr_ind].eepromsize);
- + }
- + flipper_i32hex_file_bin_to_i32hex_set_end_line(flipper_hex_eeprom);
- + FURI_LOG_D(TAG, "%s", flipper_i32hex_file_get_string(flipper_hex_eeprom));
- + flipper_i32hex_file_close(flipper_hex_eeprom);
- + instance->progress_eeprom = 1.0f;
- +}
- +
- +bool avr_isp_worker_rw_read_dump(
- + AvrIspWorkerRW* instance,
- + const char* file_path,
- + const char* file_name) {
- + furi_assert(instance);
- + furi_assert(file_path);
- + furi_assert(file_name);
- +
- + FURI_LOG_D(TAG, "Read dump chip");
- +
- + instance->progress_flash = 0.0f;
- + instance->progress_eeprom = 0.0f;
- + bool ret = false;
- + Storage* storage = furi_record_open(RECORD_STORAGE);
- + FlipperFormat* flipper_format = flipper_format_file_alloc(storage);
- + FuriString* file_path_name = furi_string_alloc();
- +
- + if(!avr_isp_worker_rw_detect_chip(instance)) {
- + FURI_LOG_E(TAG, "No detect AVR chip");
- + } else {
- + do {
- + furi_string_printf(
- + file_path_name, "%s/%s%s", file_path, file_name, AVR_ISP_APP_EXTENSION);
- + if(!flipper_format_file_open_always(
- + flipper_format, furi_string_get_cstr(file_path_name))) {
- + FURI_LOG_E(TAG, "flipper_format_file_open_always");
- + break;
- + }
- + if(!flipper_format_write_header_cstr(
- + flipper_format, AVR_ISP_APP_FILE_TYPE, AVR_ISP_APP_FILE_VERSION)) {
- + FURI_LOG_E(TAG, "flipper_format_write_header_cstr");
- + break;
- + }
- + if(!flipper_format_write_string_cstr(
- + flipper_format, "Chip name", avr_isp_chip_arr[instance->chip_arr_ind].name)) {
- + FURI_LOG_E(TAG, "Chip name");
- + break;
- + }
- + if(!flipper_format_write_hex(
- + flipper_format,
- + "Signature",
- + (uint8_t*)&instance->signature,
- + sizeof(AvrIspSignature))) {
- + FURI_LOG_E(TAG, "Unable to add Signature");
- + break;
- + }
- + if(avr_isp_chip_arr[instance->chip_arr_ind].nfuses > 0) {
- + if(!flipper_format_write_hex(flipper_format, "Lfuse", &instance->lfuse, 1)) {
- + FURI_LOG_E(TAG, "Unable to add Lfuse");
- + break;
- + }
- + }
- + if(avr_isp_chip_arr[instance->chip_arr_ind].nfuses > 1) {
- + if(!flipper_format_write_hex(flipper_format, "Hfuse", &instance->hfuse, 1)) {
- + FURI_LOG_E(TAG, "Unable to add Hfuse");
- + break;
- + }
- + }
- + if(avr_isp_chip_arr[instance->chip_arr_ind].nfuses > 2) {
- + if(!flipper_format_write_hex(flipper_format, "Efuse", &instance->efuse, 1)) {
- + FURI_LOG_E(TAG, "Unable to add Efuse");
- + break;
- + }
- + }
- + if(avr_isp_chip_arr[instance->chip_arr_ind].nlocks == 1) {
- + if(!flipper_format_write_hex(flipper_format, "Lock", &instance->lock, 1)) {
- + FURI_LOG_E(TAG, "Unable to add Lock");
- + break;
- + }
- + }
- + furi_string_printf(file_path_name, "%s_%s", file_name, NAME_PATERN_FLASH_FILE);
- + if(!flipper_format_write_string_cstr(
- + flipper_format, "Dump_flash", furi_string_get_cstr(file_path_name))) {
- + FURI_LOG_E(TAG, "Unable to add Dump_flash");
- + break;
- + }
- +
- + if(avr_isp_chip_arr[instance->chip_arr_ind].eepromsize > 0) {
- + furi_string_printf(file_path_name, "%s_%s", file_name, NAME_PATERN_EEPROM_FILE);
- + if(avr_isp_chip_arr[instance->chip_arr_ind].eepromsize > 0) {
- + if(!flipper_format_write_string_cstr(
- + flipper_format, "Dump_eeprom", furi_string_get_cstr(file_path_name))) {
- + FURI_LOG_E(TAG, "Unable to add Dump_eeprom");
- + break;
- + }
- + }
- + }
- + ret = true;
- + } while(false);
- + }
- +
- + flipper_format_free(flipper_format);
- + furi_record_close(RECORD_STORAGE);
- +
- + if(ret) {
- + if(avr_isp_auto_set_spi_speed_start_pmode(instance->avr_isp)) {
- + //Dump flash
- + furi_string_printf(
- + file_path_name, "%s/%s_%s", file_path, file_name, NAME_PATERN_FLASH_FILE);
- + avr_isp_worker_rw_get_dump_flash(instance, furi_string_get_cstr(file_path_name));
- + //Dump eeprom
- + if(avr_isp_chip_arr[instance->chip_arr_ind].eepromsize > 0) {
- + furi_string_printf(
- + file_path_name, "%s/%s_%s", file_path, file_name, NAME_PATERN_EEPROM_FILE);
- + avr_isp_worker_rw_get_dump_eeprom(instance, furi_string_get_cstr(file_path_name));
- + }
- +
- + avr_isp_end_pmode(instance->avr_isp);
- + }
- + }
- +
- + furi_string_free(file_path_name);
- +
- + return true;
- +}
- +
- +void avr_isp_worker_rw_read_dump_start(
- + AvrIspWorkerRW* instance,
- + const char* file_path,
- + const char* file_name) {
- + furi_assert(instance);
- +
- + instance->file_path = file_path;
- + instance->file_name = file_name;
- + furi_thread_flags_set(furi_thread_get_id(instance->thread), AvrIspWorkerRWEvtReading);
- +}
- +
- +static bool avr_isp_worker_rw_verification_flash(AvrIspWorkerRW* instance, const char* file_path) {
- + furi_assert(instance);
- + furi_assert(file_path);
- +
- + FURI_LOG_D(TAG, "Verification flash %s", file_path);
- +
- + instance->progress_flash = 0.0;
- + bool ret = true;
- +
- + FlipperI32HexFile* flipper_hex_flash = flipper_i32hex_file_open_read(file_path);
- +
- + uint8_t data_read_flash[272] = {0};
- + uint8_t data_read_hex[272] = {0};
- +
- + uint32_t addr = avr_isp_chip_arr[instance->chip_arr_ind].flashoffset;
- + bool send_extended_addr = ((avr_isp_chip_arr[instance->chip_arr_ind].flashsize / 2) > 0x10000);
- + uint8_t extended_addr = 0;
- +
- + FlipperI32HexFileRet flipper_hex_ret = flipper_i32hex_file_i32hex_to_bin_get_data(
- + flipper_hex_flash, data_read_hex, sizeof(data_read_hex));
- +
- + while(((flipper_hex_ret.status == FlipperI32HexFileStatusData) ||
- + (flipper_hex_ret.status == FlipperI32HexFileStatusUdateAddr)) &&
- + ret) {
- + switch(flipper_hex_ret.status) {
- + case FlipperI32HexFileStatusData:
- +
- + if(send_extended_addr) {
- + if(extended_addr <= ((addr >> 16) & 0xFF)) {
- + avr_isp_write_extended_addr(instance->avr_isp, extended_addr);
- + extended_addr = ((addr >> 16) & 0xFF) + 1;
- + }
- + }
- +
- + avr_isp_read_page(
- + instance->avr_isp,
- + STK_SET_FLASH_TYPE,
- + (uint16_t)addr,
- + flipper_hex_ret.data_size,
- + data_read_flash,
- + sizeof(data_read_flash));
- +
- + if(memcmp(data_read_hex, data_read_flash, flipper_hex_ret.data_size) != 0) {
- + ret = false;
- +
- + FURI_LOG_E(TAG, "Verification flash error");
- + FURI_LOG_E(TAG, "Addr: 0x%04lX", addr);
- + for(uint32_t i = 0; i < flipper_hex_ret.data_size; i++) {
- + FURI_LOG_RAW_E("%02X ", data_read_hex[i]);
- + }
- + FURI_LOG_RAW_E("\r\n");
- + for(uint32_t i = 0; i < flipper_hex_ret.data_size; i++) {
- + FURI_LOG_RAW_E("%02X ", data_read_flash[i]);
- + }
- + FURI_LOG_RAW_E("\r\n");
- + }
- +
- + addr += flipper_hex_ret.data_size / 2;
- + instance->progress_flash =
- + (float)(addr) / ((float)avr_isp_chip_arr[instance->chip_arr_ind].flashsize / 2.0f);
- + break;
- +
- + case FlipperI32HexFileStatusUdateAddr:
- + addr = (data_read_hex[0] << 24 | data_read_hex[1] << 16) / 2;
- + break;
- +
- + default:
- + furi_crash(TAG " Incorrect status.");
- + break;
- + }
- +
- + flipper_hex_ret = flipper_i32hex_file_i32hex_to_bin_get_data(
- + flipper_hex_flash, data_read_hex, sizeof(data_read_hex));
- + }
- +
- + flipper_i32hex_file_close(flipper_hex_flash);
- + instance->progress_flash = 1.0f;
- +
- + return ret;
- +}
- +
- +static bool
- + avr_isp_worker_rw_verification_eeprom(AvrIspWorkerRW* instance, const char* file_path) {
- + furi_assert(instance);
- + furi_assert(file_path);
- +
- + FURI_LOG_D(TAG, "Verification eeprom %s", file_path);
- +
- + instance->progress_eeprom = 0.0;
- + bool ret = true;
- +
- + FlipperI32HexFile* flipper_hex_eeprom = flipper_i32hex_file_open_read(file_path);
- +
- + uint8_t data_read_eeprom[272] = {0};
- + uint8_t data_read_hex[272] = {0};
- +
- + uint32_t addr = avr_isp_chip_arr[instance->chip_arr_ind].eepromoffset;
- +
- + FlipperI32HexFileRet flipper_hex_ret = flipper_i32hex_file_i32hex_to_bin_get_data(
- + flipper_hex_eeprom, data_read_hex, sizeof(data_read_hex));
- +
- + while(((flipper_hex_ret.status == FlipperI32HexFileStatusData) ||
- + (flipper_hex_ret.status == FlipperI32HexFileStatusUdateAddr)) &&
- + ret) {
- + switch(flipper_hex_ret.status) {
- + case FlipperI32HexFileStatusData:
- + avr_isp_read_page(
- + instance->avr_isp,
- + STK_SET_EEPROM_TYPE,
- + (uint16_t)addr,
- + flipper_hex_ret.data_size,
- + data_read_eeprom,
- + sizeof(data_read_eeprom));
- +
- + if(memcmp(data_read_hex, data_read_eeprom, flipper_hex_ret.data_size) != 0) {
- + ret = false;
- + FURI_LOG_E(TAG, "Verification eeprom error");
- + FURI_LOG_E(TAG, "Addr: 0x%04lX", addr);
- + for(uint32_t i = 0; i < flipper_hex_ret.data_size; i++) {
- + FURI_LOG_RAW_E("%02X ", data_read_hex[i]);
- + }
- + FURI_LOG_RAW_E("\r\n");
- + for(uint32_t i = 0; i < flipper_hex_ret.data_size; i++) {
- + FURI_LOG_RAW_E("%02X ", data_read_eeprom[i]);
- + }
- + FURI_LOG_RAW_E("\r\n");
- + }
- +
- + addr += flipper_hex_ret.data_size;
- + instance->progress_eeprom =
- + (float)(addr) / ((float)avr_isp_chip_arr[instance->chip_arr_ind].eepromsize);
- + break;
- +
- + case FlipperI32HexFileStatusUdateAddr:
- + addr = (data_read_hex[0] << 24 | data_read_hex[1] << 16);
- + break;
- +
- + default:
- + furi_crash(TAG " Incorrect status.");
- + break;
- + }
- +
- + flipper_hex_ret = flipper_i32hex_file_i32hex_to_bin_get_data(
- + flipper_hex_eeprom, data_read_hex, sizeof(data_read_hex));
- + }
- +
- + flipper_i32hex_file_close(flipper_hex_eeprom);
- + instance->progress_eeprom = 1.0f;
- +
- + return ret;
- +}
- +
- +bool avr_isp_worker_rw_verification(
- + AvrIspWorkerRW* instance,
- + const char* file_path,
- + const char* file_name) {
- + furi_assert(instance);
- + furi_assert(file_path);
- + furi_assert(file_name);
- +
- + FURI_LOG_D(TAG, "Verification chip");
- +
- + instance->progress_flash = 0.0f;
- + instance->progress_eeprom = 0.0f;
- + FuriString* file_path_name = furi_string_alloc();
- +
- + bool ret = false;
- +
- + if(avr_isp_auto_set_spi_speed_start_pmode(instance->avr_isp)) {
- + do {
- + furi_string_printf(
- + file_path_name, "%s/%s_%s", file_path, file_name, NAME_PATERN_FLASH_FILE);
- + if(!avr_isp_worker_rw_verification_flash(
- + instance, furi_string_get_cstr(file_path_name)))
- + break;
- +
- + if(avr_isp_chip_arr[instance->chip_arr_ind].eepromsize > 0) {
- + furi_string_printf(
- + file_path_name, "%s/%s_%s", file_path, file_name, NAME_PATERN_EEPROM_FILE);
- +
- + if(!avr_isp_worker_rw_verification_eeprom(
- + instance, furi_string_get_cstr(file_path_name)))
- + break;
- + }
- + ret = true;
- + } while(false);
- + avr_isp_end_pmode(instance->avr_isp);
- + furi_string_free(file_path_name);
- + }
- + return ret;
- +}
- +
- +void avr_isp_worker_rw_verification_start(
- + AvrIspWorkerRW* instance,
- + const char* file_path,
- + const char* file_name) {
- + furi_assert(instance);
- +
- + instance->file_path = file_path;
- + instance->file_name = file_name;
- + furi_thread_flags_set(furi_thread_get_id(instance->thread), AvrIspWorkerRWEvtVerification);
- +}
- +
- +static void avr_isp_worker_rw_write_flash(AvrIspWorkerRW* instance, const char* file_path) {
- + furi_assert(instance);
- + furi_check(instance->avr_isp);
- +
- + instance->progress_flash = 0.0;
- +
- + FURI_LOG_D(TAG, "Write Flash %s", file_path);
- +
- + uint8_t data[288] = {0};
- +
- + FlipperI32HexFile* flipper_hex_flash = flipper_i32hex_file_open_read(file_path);
- +
- + uint32_t addr = avr_isp_chip_arr[instance->chip_arr_ind].flashoffset;
- + bool send_extended_addr = ((avr_isp_chip_arr[instance->chip_arr_ind].flashsize / 2) > 0x10000);
- + uint8_t extended_addr = 0;
- +
- + FlipperI32HexFileRet flipper_hex_ret =
- + flipper_i32hex_file_i32hex_to_bin_get_data(flipper_hex_flash, data, sizeof(data));
- +
- + while((flipper_hex_ret.status == FlipperI32HexFileStatusData) ||
- + (flipper_hex_ret.status == FlipperI32HexFileStatusUdateAddr)) {
- + switch(flipper_hex_ret.status) {
- + case FlipperI32HexFileStatusData:
- +
- + if(send_extended_addr) {
- + if(extended_addr <= ((addr >> 16) & 0xFF)) {
- + avr_isp_write_extended_addr(instance->avr_isp, extended_addr);
- + extended_addr = ((addr >> 16) & 0xFF) + 1;
- + }
- + }
- +
- + if(!avr_isp_write_page(
- + instance->avr_isp,
- + STK_SET_FLASH_TYPE,
- + avr_isp_chip_arr[instance->chip_arr_ind].flashsize,
- + (uint16_t)addr,
- + avr_isp_chip_arr[instance->chip_arr_ind].pagesize,
- + data,
- + flipper_hex_ret.data_size)) {
- + break;
- + }
- + addr += flipper_hex_ret.data_size / 2;
- + instance->progress_flash =
- + (float)(addr) / ((float)avr_isp_chip_arr[instance->chip_arr_ind].flashsize / 2.0f);
- + break;
- +
- + case FlipperI32HexFileStatusUdateAddr:
- + addr = (data[0] << 24 | data[1] << 16) / 2;
- + break;
- +
- + default:
- + furi_crash(TAG " Incorrect status.");
- + break;
- + }
- +
- + flipper_hex_ret =
- + flipper_i32hex_file_i32hex_to_bin_get_data(flipper_hex_flash, data, sizeof(data));
- + }
- +
- + flipper_i32hex_file_close(flipper_hex_flash);
- + instance->progress_flash = 1.0f;
- +}
- +
- +static void avr_isp_worker_rw_write_eeprom(AvrIspWorkerRW* instance, const char* file_path) {
- + furi_assert(instance);
- + furi_check(instance->avr_isp);
- +
- + instance->progress_eeprom = 0.0;
- + uint8_t data[288] = {0};
- +
- + FURI_LOG_D(TAG, "Write EEPROM %s", file_path);
- +
- + FlipperI32HexFile* flipper_hex_eeprom_read = flipper_i32hex_file_open_read(file_path);
- +
- + uint32_t addr = avr_isp_chip_arr[instance->chip_arr_ind].eepromoffset;
- + FlipperI32HexFileRet flipper_hex_ret =
- + flipper_i32hex_file_i32hex_to_bin_get_data(flipper_hex_eeprom_read, data, sizeof(data));
- +
- + while((flipper_hex_ret.status == FlipperI32HexFileStatusData) ||
- + (flipper_hex_ret.status == FlipperI32HexFileStatusUdateAddr)) {
- + switch(flipper_hex_ret.status) {
- + case FlipperI32HexFileStatusData:
- + if(!avr_isp_write_page(
- + instance->avr_isp,
- + STK_SET_EEPROM_TYPE,
- + avr_isp_chip_arr[instance->chip_arr_ind].eepromsize,
- + (uint16_t)addr,
- + avr_isp_chip_arr[instance->chip_arr_ind].eeprompagesize,
- + data,
- + flipper_hex_ret.data_size)) {
- + break;
- + }
- + addr += flipper_hex_ret.data_size;
- + instance->progress_eeprom =
- + (float)(addr) / ((float)avr_isp_chip_arr[instance->chip_arr_ind].eepromsize);
- + break;
- +
- + case FlipperI32HexFileStatusUdateAddr:
- + addr = data[0] << 24 | data[1] << 16;
- + break;
- +
- + default:
- + furi_crash(TAG " Incorrect status.");
- + break;
- + }
- +
- + flipper_hex_ret = flipper_i32hex_file_i32hex_to_bin_get_data(
- + flipper_hex_eeprom_read, data, sizeof(data));
- + }
- +
- + flipper_i32hex_file_close(flipper_hex_eeprom_read);
- + instance->progress_eeprom = 1.0f;
- +}
- +
- +bool avr_isp_worker_rw_write_dump(
- + AvrIspWorkerRW* instance,
- + const char* file_path,
- + const char* file_name) {
- + furi_assert(instance);
- + furi_assert(file_path);
- + furi_assert(file_name);
- +
- + FURI_LOG_D(TAG, "Write dump chip");
- +
- + instance->progress_flash = 0.0f;
- + instance->progress_eeprom = 0.0f;
- + bool ret = false;
- +
- + Storage* storage = furi_record_open(RECORD_STORAGE);
- + FlipperFormat* flipper_format = flipper_format_file_alloc(storage);
- + FuriString* file_path_name = furi_string_alloc();
- +
- + FuriString* temp_str_1 = furi_string_alloc();
- + FuriString* temp_str_2 = furi_string_alloc();
- + uint32_t temp_data32;
- +
- + if(!avr_isp_worker_rw_detect_chip(instance)) {
- + FURI_LOG_E(TAG, "No detect AVR chip");
- + } else {
- + //upload file with description
- + do {
- + furi_string_printf(
- + file_path_name, "%s/%s%s", file_path, file_name, AVR_ISP_APP_EXTENSION);
- + if(!flipper_format_file_open_existing(
- + flipper_format, furi_string_get_cstr(file_path_name))) {
- + FURI_LOG_E(TAG, "Error open file %s", furi_string_get_cstr(file_path_name));
- + break;
- + }
- +
- + if(!flipper_format_read_header(flipper_format, temp_str_1, &temp_data32)) {
- + FURI_LOG_E(TAG, "Missing or incorrect header");
- + break;
- + }
- +
- + if((!strcmp(furi_string_get_cstr(temp_str_1), AVR_ISP_APP_FILE_TYPE)) &&
- + temp_data32 == AVR_ISP_APP_FILE_VERSION) {
- + } else {
- + FURI_LOG_E(TAG, "Type or version mismatch");
- + break;
- + }
- +
- + AvrIspSignature sig_read = {0};
- +
- + if(!flipper_format_read_hex(
- + flipper_format, "Signature", (uint8_t*)&sig_read, sizeof(AvrIspSignature))) {
- + FURI_LOG_E(TAG, "Missing Signature");
- + break;
- + }
- +
- + if(memcmp(
- + (uint8_t*)&instance->signature, (uint8_t*)&sig_read, sizeof(AvrIspSignature)) !=
- + 0) {
- + FURI_LOG_E(
- + TAG,
- + "Wrong chip. Connected (%02X %02X %02X), read from file (%02X %02X %02X)",
- + instance->signature.vendor,
- + instance->signature.part_family,
- + instance->signature.part_number,
- + sig_read.vendor,
- + sig_read.part_family,
- + sig_read.part_number);
- + break;
- + }
- +
- + if(!flipper_format_read_string(flipper_format, "Dump_flash", temp_str_1)) {
- + FURI_LOG_E(TAG, "Missing Dump_flash");
- + break;
- + }
- +
- + //may not be
- + flipper_format_read_string(flipper_format, "Dump_eeprom", temp_str_2);
- + ret = true;
- + } while(false);
- + }
- + flipper_format_free(flipper_format);
- + furi_record_close(RECORD_STORAGE);
- +
- + if(ret) {
- + do {
- + //checking .hex files for errors
- +
- + furi_string_printf(
- + file_path_name, "%s/%s", file_path, furi_string_get_cstr(temp_str_1));
- +
- + FURI_LOG_D(TAG, "Check flash file");
- + FlipperI32HexFile* flipper_hex_flash_read =
- + flipper_i32hex_file_open_read(furi_string_get_cstr(file_path_name));
- + if(flipper_i32hex_file_check(flipper_hex_flash_read)) {
- + FURI_LOG_D(TAG, "Check flash file: OK");
- + } else {
- + FURI_LOG_E(TAG, "Check flash file: Error");
- + ret = false;
- + }
- + flipper_i32hex_file_close(flipper_hex_flash_read);
- +
- + if(furi_string_size(temp_str_2) > 4) {
- + furi_string_printf(
- + file_path_name, "%s/%s", file_path, furi_string_get_cstr(temp_str_2));
- +
- + FURI_LOG_D(TAG, "Check eeprom file");
- + FlipperI32HexFile* flipper_hex_eeprom_read =
- + flipper_i32hex_file_open_read(furi_string_get_cstr(file_path_name));
- + if(flipper_i32hex_file_check(flipper_hex_eeprom_read)) {
- + FURI_LOG_D(TAG, "Check eeprom file: OK");
- + } else {
- + FURI_LOG_E(TAG, "Check eeprom file: Error");
- + ret = false;
- + }
- + flipper_i32hex_file_close(flipper_hex_eeprom_read);
- + }
- +
- + if(!ret) break;
- + ret = false;
- +
- + //erase chip
- + FURI_LOG_D(TAG, "Erase chip");
- + if(!avr_isp_erase_chip(instance->avr_isp)) {
- + FURI_LOG_E(TAG, "Erase chip: Error");
- + break;
- + }
- +
- + if(!avr_isp_auto_set_spi_speed_start_pmode(instance->avr_isp)) {
- + FURI_LOG_E(TAG, "Well, I managed to enter the mod program");
- + break;
- + }
- +
- + //write flash
- + furi_string_printf(
- + file_path_name, "%s/%s", file_path, furi_string_get_cstr(temp_str_1));
- + avr_isp_worker_rw_write_flash(instance, furi_string_get_cstr(file_path_name));
- +
- + //write eeprom
- + if(furi_string_size(temp_str_2) > 4) {
- + furi_string_printf(
- + file_path_name, "%s/%s", file_path, furi_string_get_cstr(temp_str_2));
- + avr_isp_worker_rw_write_eeprom(instance, furi_string_get_cstr(file_path_name));
- + }
- + ret = true;
- + avr_isp_end_pmode(instance->avr_isp);
- + } while(false);
- + }
- +
- + furi_string_free(file_path_name);
- + furi_string_free(temp_str_1);
- + furi_string_free(temp_str_2);
- +
- + return ret;
- +}
- +
- +void avr_isp_worker_rw_write_dump_start(
- + AvrIspWorkerRW* instance,
- + const char* file_path,
- + const char* file_name) {
- + furi_assert(instance);
- +
- + instance->file_path = file_path;
- + instance->file_name = file_name;
- + furi_thread_flags_set(furi_thread_get_id(instance->thread), AvrIspWorkerRWEvtWriting);
- +}
- +
- +bool avr_isp_worker_rw_write_fuse(
- + AvrIspWorkerRW* instance,
- + const char* file_path,
- + const char* file_name) {
- + furi_assert(instance);
- + furi_assert(file_path);
- + furi_assert(file_name);
- +
- + FURI_LOG_D(TAG, "Write fuse chip");
- +
- + bool ret = false;
- + uint8_t lfuse;
- + uint8_t hfuse;
- + uint8_t efuse;
- + uint8_t lock;
- +
- + Storage* storage = furi_record_open(RECORD_STORAGE);
- + FlipperFormat* flipper_format = flipper_format_file_alloc(storage);
- + FuriString* temp_str = furi_string_alloc();
- +
- + uint32_t temp_data32;
- +
- + if(!avr_isp_worker_rw_detect_chip(instance)) {
- + FURI_LOG_E(TAG, "No detect AVR chip");
- + } else {
- + //upload file with description
- + do {
- + furi_string_printf(temp_str, "%s/%s%s", file_path, file_name, AVR_ISP_APP_EXTENSION);
- + if(!flipper_format_file_open_existing(flipper_format, furi_string_get_cstr(temp_str))) {
- + FURI_LOG_E(TAG, "Error open file %s", furi_string_get_cstr(temp_str));
- + break;
- + }
- +
- + if(!flipper_format_read_header(flipper_format, temp_str, &temp_data32)) {
- + FURI_LOG_E(TAG, "Missing or incorrect header");
- + break;
- + }
- +
- + if((!strcmp(furi_string_get_cstr(temp_str), AVR_ISP_APP_FILE_TYPE)) &&
- + temp_data32 == AVR_ISP_APP_FILE_VERSION) {
- + } else {
- + FURI_LOG_E(TAG, "Type or version mismatch");
- + break;
- + }
- +
- + AvrIspSignature sig_read = {0};
- +
- + if(!flipper_format_read_hex(
- + flipper_format, "Signature", (uint8_t*)&sig_read, sizeof(AvrIspSignature))) {
- + FURI_LOG_E(TAG, "Missing Signature");
- + break;
- + }
- +
- + if(memcmp(
- + (uint8_t*)&instance->signature, (uint8_t*)&sig_read, sizeof(AvrIspSignature)) !=
- + 0) {
- + FURI_LOG_E(
- + TAG,
- + "Wrong chip. Connected (%02X %02X %02X), read from file (%02X %02X %02X)",
- + instance->signature.vendor,
- + instance->signature.part_family,
- + instance->signature.part_number,
- + sig_read.vendor,
- + sig_read.part_family,
- + sig_read.part_number);
- + break;
- + }
- +
- + if(avr_isp_chip_arr[instance->chip_arr_ind].nfuses > 0) {
- + if(!flipper_format_read_hex(flipper_format, "Lfuse", &lfuse, 1)) {
- + FURI_LOG_E(TAG, "Missing Lfuse");
- + break;
- + }
- + }
- + if(avr_isp_chip_arr[instance->chip_arr_ind].nfuses > 1) {
- + if(!flipper_format_read_hex(flipper_format, "Hfuse", &hfuse, 1)) {
- + FURI_LOG_E(TAG, "Missing Hfuse");
- + break;
- + }
- + }
- + if(avr_isp_chip_arr[instance->chip_arr_ind].nfuses > 2) {
- + if(!flipper_format_read_hex(flipper_format, "Efuse", &efuse, 1)) {
- + FURI_LOG_E(TAG, "Missing Efuse");
- + break;
- + }
- + }
- + if(avr_isp_chip_arr[instance->chip_arr_ind].nlocks == 1) {
- + if(!flipper_format_read_hex(flipper_format, "Lock", &lock, 1)) {
- + FURI_LOG_E(TAG, "Missing Lock");
- + break;
- + }
- + }
- +
- + if(!avr_isp_auto_set_spi_speed_start_pmode(instance->avr_isp)) {
- + FURI_LOG_E(TAG, "Well, I managed to enter the mod program");
- + break;
- + }
- +
- + ret = true;
- +
- + if(avr_isp_chip_arr[instance->chip_arr_ind].nfuses > 0) {
- + if(instance->lfuse != lfuse) {
- + if(!avr_isp_write_fuse_low(instance->avr_isp, lfuse)) {
- + FURI_LOG_E(TAG, "Write Lfuse: error");
- + ret = false;
- + }
- + }
- + }
- + if(avr_isp_chip_arr[instance->chip_arr_ind].nfuses > 1) {
- + if(instance->hfuse != hfuse) {
- + if(!avr_isp_write_fuse_high(instance->avr_isp, hfuse)) {
- + FURI_LOG_E(TAG, "Write Hfuse: error");
- + ret = false;
- + }
- + }
- + }
- + if(avr_isp_chip_arr[instance->chip_arr_ind].nfuses > 2) {
- + if(instance->efuse != efuse) {
- + if(!avr_isp_write_fuse_extended(instance->avr_isp, efuse)) {
- + FURI_LOG_E(TAG, "Write Efuse: error");
- + ret = false;
- + }
- + }
- + }
- +
- + if(avr_isp_chip_arr[instance->chip_arr_ind].nlocks == 1) {
- + FURI_LOG_D(TAG, "Write lock byte");
- + if(instance->lock != lock) {
- + if(!avr_isp_write_lock_byte(instance->avr_isp, lock)) {
- + FURI_LOG_E(TAG, "Write Lock byte: error");
- + ret = false;
- + }
- + }
- + }
- + avr_isp_end_pmode(instance->avr_isp);
- + } while(false);
- + }
- +
- + flipper_format_free(flipper_format);
- + furi_record_close(RECORD_STORAGE);
- + furi_string_free(temp_str);
- + return ret;
- +}
- +
- +void avr_isp_worker_rw_write_fuse_start(
- + AvrIspWorkerRW* instance,
- + const char* file_path,
- + const char* file_name) {
- + furi_assert(instance);
- +
- + instance->file_path = file_path;
- + instance->file_name = file_name;
- + furi_thread_flags_set(furi_thread_get_id(instance->thread), AvrIspWorkerRWEvtWritingFuse);
- +}
- \ No newline at end of file
- 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
- new file mode 100644
- index 000000000..2c52a8700
- --- /dev/null
- +++ b/applications/external/avr_isp_programmer/helpers/avr_isp_worker_rw.h
- @@ -0,0 +1,99 @@
- +#pragma once
- +
- +#include <furi_hal.h>
- +
- +typedef struct AvrIspWorkerRW AvrIspWorkerRW;
- +
- +typedef void (*AvrIspWorkerRWCallback)(
- + void* context,
- + const char* name,
- + bool detect_chip,
- + uint32_t flash_size);
- +
- +typedef enum {
- + AvrIspWorkerRWStatusILDE = 0,
- + AvrIspWorkerRWStatusEndReading = 1,
- + AvrIspWorkerRWStatusEndVerification = 2,
- + AvrIspWorkerRWStatusEndWriting = 3,
- + AvrIspWorkerRWStatusEndWritingFuse = 4,
- +
- + AvrIspWorkerRWStatusErrorReading = (-1),
- + AvrIspWorkerRWStatusErrorVerification = (-2),
- + AvrIspWorkerRWStatusErrorWriting = (-3),
- + AvrIspWorkerRWStatusErrorWritingFuse = (-4),
- +
- + AvrIspWorkerRWStatusReserved = 0x7FFFFFFF, ///< Prevents enum down-size compiler optimization.
- +} AvrIspWorkerRWStatus;
- +
- +typedef void (*AvrIspWorkerRWStatusCallback)(void* context, AvrIspWorkerRWStatus status);
- +
- +AvrIspWorkerRW* avr_isp_worker_rw_alloc(void* context);
- +
- +void avr_isp_worker_rw_free(AvrIspWorkerRW* instance);
- +
- +void avr_isp_worker_rw_start(AvrIspWorkerRW* instance);
- +
- +void avr_isp_worker_rw_stop(AvrIspWorkerRW* instance);
- +
- +bool avr_isp_worker_rw_is_running(AvrIspWorkerRW* instance);
- +
- +void avr_isp_worker_rw_set_callback(
- + AvrIspWorkerRW* instance,
- + AvrIspWorkerRWCallback callback,
- + void* context);
- +
- +void avr_isp_worker_rw_set_callback_status(
- + AvrIspWorkerRW* instance,
- + AvrIspWorkerRWStatusCallback callback_status,
- + void* context_status);
- +
- +bool avr_isp_worker_rw_detect_chip(AvrIspWorkerRW* instance);
- +
- +float avr_isp_worker_rw_get_progress_flash(AvrIspWorkerRW* instance);
- +
- +float avr_isp_worker_rw_get_progress_eeprom(AvrIspWorkerRW* instance);
- +
- +bool avr_isp_worker_rw_read_dump(
- + AvrIspWorkerRW* instance,
- + const char* file_path,
- + const char* file_name);
- +
- +void avr_isp_worker_rw_read_dump_start(
- + AvrIspWorkerRW* instance,
- + const char* file_path,
- + const char* file_name);
- +
- +bool avr_isp_worker_rw_verification(
- + AvrIspWorkerRW* instance,
- + const char* file_path,
- + const char* file_name);
- +
- +void avr_isp_worker_rw_verification_start(
- + AvrIspWorkerRW* instance,
- + const char* file_path,
- + const char* file_name);
- +
- +bool avr_isp_worker_rw_check_hex(
- + AvrIspWorkerRW* instance,
- + const char* file_path,
- + const char* file_name);
- +
- +bool avr_isp_worker_rw_write_dump(
- + AvrIspWorkerRW* instance,
- + const char* file_path,
- + const char* file_name);
- +
- +void avr_isp_worker_rw_write_dump_start(
- + AvrIspWorkerRW* instance,
- + const char* file_path,
- + const char* file_name);
- +
- +bool avr_isp_worker_rw_write_fuse(
- + AvrIspWorkerRW* instance,
- + const char* file_path,
- + const char* file_name);
- +
- +void avr_isp_worker_rw_write_fuse_start(
- + AvrIspWorkerRW* instance,
- + const char* file_path,
- + const char* file_name);
- \ No newline at end of file
- diff --git a/applications/external/avr_isp_programmer/helpers/flipper_i32hex_file.c b/applications/external/avr_isp_programmer/helpers/flipper_i32hex_file.c
- new file mode 100644
- index 000000000..a8c20a0bd
- --- /dev/null
- +++ b/applications/external/avr_isp_programmer/helpers/flipper_i32hex_file.c
- @@ -0,0 +1,321 @@
- +#include "flipper_i32hex_file.h"
- +#include <string.h>
- +#include <storage/storage.h>
- +#include <toolbox/stream/stream.h>
- +#include <toolbox/stream/file_stream.h>
- +#include <toolbox/hex.h>
- +
- +//https://en.wikipedia.org/wiki/Intel_HEX
- +
- +#define TAG "FlipperI32HexFile"
- +
- +#define COUNT_BYTE_PAYLOAD 32 //how much payload will be used
- +
- +#define I32HEX_TYPE_DATA 0x00
- +#define I32HEX_TYPE_END_OF_FILE 0x01
- +#define I32HEX_TYPE_EXT_LINEAR_ADDR 0x04
- +#define I32HEX_TYPE_START_LINEAR_ADDR 0x05
- +
- +struct FlipperI32HexFile {
- + uint32_t addr;
- + uint32_t addr_last;
- + Storage* storage;
- + Stream* stream;
- + FuriString* str_data;
- + FlipperI32HexFileStatus file_open;
- +};
- +
- +FlipperI32HexFile* flipper_i32hex_file_open_write(const char* name, uint32_t start_addr) {
- + furi_assert(name);
- +
- + FlipperI32HexFile* instance = malloc(sizeof(FlipperI32HexFile));
- + instance->addr = start_addr;
- + instance->addr_last = 0;
- + instance->storage = furi_record_open(RECORD_STORAGE);
- + instance->stream = file_stream_alloc(instance->storage);
- +
- + if(file_stream_open(instance->stream, name, FSAM_WRITE, FSOM_CREATE_ALWAYS)) {
- + instance->file_open = FlipperI32HexFileStatusOpenFileWrite;
- + FURI_LOG_D(TAG, "Open write file %s", name);
- + } else {
- + FURI_LOG_E(TAG, "Failed to open file %s", name);
- + instance->file_open = FlipperI32HexFileStatusErrorNoOpenFile;
- + }
- + instance->str_data = furi_string_alloc(instance->storage);
- +
- + return instance;
- +}
- +
- +FlipperI32HexFile* flipper_i32hex_file_open_read(const char* name) {
- + furi_assert(name);
- +
- + FlipperI32HexFile* instance = malloc(sizeof(FlipperI32HexFile));
- + instance->addr = 0;
- + instance->addr_last = 0;
- + instance->storage = furi_record_open(RECORD_STORAGE);
- + instance->stream = file_stream_alloc(instance->storage);
- +
- + if(file_stream_open(instance->stream, name, FSAM_READ, FSOM_OPEN_EXISTING)) {
- + instance->file_open = FlipperI32HexFileStatusOpenFileRead;
- + FURI_LOG_D(TAG, "Open read file %s", name);
- + } else {
- + FURI_LOG_E(TAG, "Failed to open file %s", name);
- + instance->file_open = FlipperI32HexFileStatusErrorNoOpenFile;
- + }
- + instance->str_data = furi_string_alloc(instance->storage);
- +
- + return instance;
- +}
- +
- +void flipper_i32hex_file_close(FlipperI32HexFile* instance) {
- + furi_assert(instance);
- +
- + furi_string_free(instance->str_data);
- + file_stream_close(instance->stream);
- + stream_free(instance->stream);
- + furi_record_close(RECORD_STORAGE);
- +}
- +
- +FlipperI32HexFileRet flipper_i32hex_file_bin_to_i32hex_set_data(
- + FlipperI32HexFile* instance,
- + uint8_t* data,
- + uint32_t data_size) {
- + furi_assert(instance);
- + furi_assert(data);
- +
- + FlipperI32HexFileRet ret = {.status = FlipperI32HexFileStatusOK, .data_size = 0};
- + if(instance->file_open != FlipperI32HexFileStatusOpenFileWrite) {
- + ret.status = FlipperI32HexFileStatusErrorFileWrite;
- + }
- + uint8_t count_byte = 0;
- + uint32_t ind = 0;
- + uint8_t crc = 0;
- +
- + furi_string_reset(instance->str_data);
- +
- + if((instance->addr_last & 0xFF0000) < (instance->addr & 0xFF0000)) {
- + crc = 0x02 + 0x04 + ((instance->addr >> 24) & 0xFF) + ((instance->addr >> 16) & 0xFF);
- + crc = 0x01 + ~crc;
- + //I32HEX_TYPE_EXT_LINEAR_ADDR
- + furi_string_cat_printf(
- + instance->str_data, ":02000004%04lX%02X\r\n", (instance->addr >> 16), crc);
- + instance->addr_last = instance->addr;
- + }
- +
- + while(ind < data_size) {
- + if((ind + COUNT_BYTE_PAYLOAD) > data_size) {
- + count_byte = data_size - ind;
- + } else {
- + count_byte = COUNT_BYTE_PAYLOAD;
- + }
- + //I32HEX_TYPE_DATA
- + furi_string_cat_printf(
- + instance->str_data, ":%02X%04lX00", count_byte, (instance->addr & 0xFFFF));
- + crc = count_byte + ((instance->addr >> 8) & 0xFF) + (instance->addr & 0xFF);
- +
- + for(uint32_t i = 0; i < count_byte; i++) {
- + furi_string_cat_printf(instance->str_data, "%02X", *data);
- + crc += *data++;
- + }
- + crc = 0x01 + ~crc;
- + furi_string_cat_printf(instance->str_data, "%02X\r\n", crc);
- +
- + ind += count_byte;
- + instance->addr += count_byte;
- + }
- + if(instance->file_open) stream_write_string(instance->stream, instance->str_data);
- + return ret;
- +}
- +
- +FlipperI32HexFileRet flipper_i32hex_file_bin_to_i32hex_set_end_line(FlipperI32HexFile* instance) {
- + furi_assert(instance);
- +
- + FlipperI32HexFileRet ret = {.status = FlipperI32HexFileStatusOK, .data_size = 0};
- + if(instance->file_open != FlipperI32HexFileStatusOpenFileWrite) {
- + ret.status = FlipperI32HexFileStatusErrorFileWrite;
- + }
- + furi_string_reset(instance->str_data);
- + //I32HEX_TYPE_END_OF_FILE
- + furi_string_cat_printf(instance->str_data, ":00000001FF\r\n");
- + if(instance->file_open) stream_write_string(instance->stream, instance->str_data);
- + return ret;
- +}
- +
- +void flipper_i32hex_file_bin_to_i32hex_set_addr(FlipperI32HexFile* instance, uint32_t addr) {
- + furi_assert(instance);
- +
- + instance->addr = addr;
- +}
- +
- +const char* flipper_i32hex_file_get_string(FlipperI32HexFile* instance) {
- + furi_assert(instance);
- +
- + return furi_string_get_cstr(instance->str_data);
- +}
- +
- +static FlipperI32HexFileRet flipper_i32hex_file_parse_line(
- + FlipperI32HexFile* instance,
- + const char* str,
- + uint8_t* data,
- + uint32_t data_size) {
- + furi_assert(instance);
- + furi_assert(data);
- +
- + char* str1;
- + uint32_t data_wrire_ind = 0;
- + uint32_t data_len = 0;
- + FlipperI32HexFileRet ret = {.status = FlipperI32HexFileStatusErrorData, .data_size = 0};
- +
- + //Search for start of data I32HEX
- + str1 = strstr(str, ":");
- + do {
- + if(str1 == NULL) {
- + ret.status = FlipperI32HexFileStatusErrorData;
- + break;
- + }
- + str1++;
- + if(!hex_char_to_uint8(*str1, str1[1], data + data_wrire_ind)) {
- + ret.status = FlipperI32HexFileStatusErrorData;
- + break;
- + }
- + str1++;
- + if(++data_wrire_ind > data_size) {
- + ret.status = FlipperI32HexFileStatusErrorOverflow;
- + break;
- + }
- + data_len = 5 + data[0]; // +5 bytes per header and crc
- + while(data_len > data_wrire_ind) {
- + str1++;
- + if(!hex_char_to_uint8(*str1, str1[1], data + data_wrire_ind)) {
- + ret.status = FlipperI32HexFileStatusErrorData;
- + break;
- + }
- + str1++;
- + if(++data_wrire_ind > data_size) {
- + ret.status = FlipperI32HexFileStatusErrorOverflow;
- + break;
- + }
- + }
- + ret.status = FlipperI32HexFileStatusOK;
- + ret.data_size = data_wrire_ind;
- +
- + } while(0);
- + return ret;
- +}
- +
- +static bool flipper_i32hex_file_check_data(uint8_t* data, uint32_t data_size) {
- + furi_assert(data);
- +
- + uint8_t crc = 0;
- + uint32_t data_read_ind = 0;
- + if(data[0] > data_size) return false;
- + while(data_read_ind < data_size - 1) {
- + crc += data[data_read_ind++];
- + }
- + return data[data_size - 1] == ((1 + ~crc) & 0xFF);
- +}
- +
- +static FlipperI32HexFileRet flipper_i32hex_file_parse(
- + FlipperI32HexFile* instance,
- + const char* str,
- + uint8_t* data,
- + uint32_t data_size) {
- + furi_assert(instance);
- + furi_assert(data);
- +
- + FlipperI32HexFileRet ret = flipper_i32hex_file_parse_line(instance, str, data, data_size);
- +
- + if((ret.status == FlipperI32HexFileStatusOK) && (ret.data_size > 4)) {
- + switch(data[3]) {
- + case I32HEX_TYPE_DATA:
- + if(flipper_i32hex_file_check_data(data, ret.data_size)) {
- + ret.data_size -= 5;
- + memcpy(data, data + 4, ret.data_size);
- + ret.status = FlipperI32HexFileStatusData;
- + } else {
- + ret.status = FlipperI32HexFileStatusErrorCrc;
- + ret.data_size = 0;
- + }
- + break;
- + case I32HEX_TYPE_END_OF_FILE:
- + if(flipper_i32hex_file_check_data(data, ret.data_size)) {
- + ret.status = FlipperI32HexFileStatusEofFile;
- + ret.data_size = 0;
- + } else {
- + ret.status = FlipperI32HexFileStatusErrorCrc;
- + ret.data_size = 0;
- + }
- + break;
- + case I32HEX_TYPE_EXT_LINEAR_ADDR:
- + if(flipper_i32hex_file_check_data(data, ret.data_size)) {
- + data[0] = data[4];
- + data[1] = data[5];
- + data[3] = 0;
- + data[4] = 0;
- + ret.status = FlipperI32HexFileStatusUdateAddr;
- + ret.data_size = 4;
- + } else {
- + ret.status = FlipperI32HexFileStatusErrorCrc;
- + ret.data_size = 0;
- + }
- + break;
- + case I32HEX_TYPE_START_LINEAR_ADDR:
- + ret.status = FlipperI32HexFileStatusErrorUnsupportedCommand;
- + ret.data_size = 0;
- + break;
- + default:
- + ret.status = FlipperI32HexFileStatusErrorUnsupportedCommand;
- + ret.data_size = 0;
- + break;
- + }
- + } else {
- + ret.status = FlipperI32HexFileStatusErrorData;
- + ret.data_size = 0;
- + }
- + return ret;
- +}
- +
- +bool flipper_i32hex_file_check(FlipperI32HexFile* instance) {
- + furi_assert(instance);
- +
- + uint32_t data_size = 280;
- + uint8_t data[280] = {0};
- + bool ret = true;
- +
- + if(instance->file_open != FlipperI32HexFileStatusOpenFileRead) {
- + FURI_LOG_E(TAG, "File is not open");
- + ret = false;
- + } else {
- + stream_rewind(instance->stream);
- +
- + while(stream_read_line(instance->stream, instance->str_data)) {
- + FlipperI32HexFileRet parse_ret = flipper_i32hex_file_parse(
- + instance, furi_string_get_cstr(instance->str_data), data, data_size);
- +
- + if(parse_ret.status < 0) {
- + ret = false;
- + }
- + }
- + stream_rewind(instance->stream);
- + }
- + return ret;
- +}
- +
- +FlipperI32HexFileRet flipper_i32hex_file_i32hex_to_bin_get_data(
- + FlipperI32HexFile* instance,
- + uint8_t* data,
- + uint32_t data_size) {
- + furi_assert(instance);
- + furi_assert(data);
- +
- + FlipperI32HexFileRet ret = {.status = FlipperI32HexFileStatusOK, .data_size = 0};
- + if(instance->file_open != FlipperI32HexFileStatusOpenFileRead) {
- + ret.status = FlipperI32HexFileStatusErrorFileRead;
- + } else {
- + stream_read_line(instance->stream, instance->str_data);
- + ret = flipper_i32hex_file_parse(
- + instance, furi_string_get_cstr(instance->str_data), data, data_size);
- + }
- +
- + return ret;
- +}
- \ No newline at end of file
- diff --git a/applications/external/avr_isp_programmer/helpers/flipper_i32hex_file.h b/applications/external/avr_isp_programmer/helpers/flipper_i32hex_file.h
- new file mode 100644
- index 000000000..765b94beb
- --- /dev/null
- +++ b/applications/external/avr_isp_programmer/helpers/flipper_i32hex_file.h
- @@ -0,0 +1,55 @@
- +#pragma once
- +
- +#include <furi_hal.h>
- +
- +typedef struct FlipperI32HexFile FlipperI32HexFile;
- +
- +typedef enum {
- + FlipperI32HexFileStatusOK = 0,
- + FlipperI32HexFileStatusData = 2,
- + FlipperI32HexFileStatusUdateAddr = 3,
- + FlipperI32HexFileStatusEofFile = 4,
- + FlipperI32HexFileStatusOpenFileWrite = 5,
- + FlipperI32HexFileStatusOpenFileRead = 6,
- +
- + // Errors
- + FlipperI32HexFileStatusErrorCrc = (-1),
- + FlipperI32HexFileStatusErrorOverflow = (-2),
- + FlipperI32HexFileStatusErrorData = (-3),
- + FlipperI32HexFileStatusErrorUnsupportedCommand = (-4),
- + FlipperI32HexFileStatusErrorNoOpenFile = (-5),
- + FlipperI32HexFileStatusErrorFileWrite = (-6),
- + FlipperI32HexFileStatusErrorFileRead = (-7),
- +
- + FlipperI32HexFileStatusReserved =
- + 0x7FFFFFFF, ///< Prevents enum down-size compiler optimization.
- +} FlipperI32HexFileStatus;
- +
- +typedef struct {
- + FlipperI32HexFileStatus status;
- + uint32_t data_size;
- +} FlipperI32HexFileRet;
- +
- +FlipperI32HexFile* flipper_i32hex_file_open_write(const char* name, uint32_t start_addr);
- +
- +FlipperI32HexFile* flipper_i32hex_file_open_read(const char* name);
- +
- +void flipper_i32hex_file_close(FlipperI32HexFile* instance);
- +
- +FlipperI32HexFileRet flipper_i32hex_file_bin_to_i32hex_set_data(
- + FlipperI32HexFile* instance,
- + uint8_t* data,
- + uint32_t data_size);
- +
- +FlipperI32HexFileRet flipper_i32hex_file_bin_to_i32hex_set_end_line(FlipperI32HexFile* instance);
- +
- +const char* flipper_i32hex_file_get_string(FlipperI32HexFile* instance);
- +
- +void flipper_i32hex_file_bin_to_i32hex_set_addr(FlipperI32HexFile* instance, uint32_t addr);
- +
- +bool flipper_i32hex_file_check(FlipperI32HexFile* instance);
- +
- +FlipperI32HexFileRet flipper_i32hex_file_i32hex_to_bin_get_data(
- + FlipperI32HexFile* instance,
- + uint8_t* data,
- + uint32_t data_size);
- \ No newline at end of file
- 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
- new file mode 100644
- index 000000000..533787fe3
- Binary files /dev/null and b/applications/external/avr_isp_programmer/images/avr_app_icon_10x10.png differ
- diff --git a/applications/external/avr_isp_programmer/images/avr_wiring.png b/applications/external/avr_isp_programmer/images/avr_wiring.png
- new file mode 100644
- index 000000000..957012405
- Binary files /dev/null and b/applications/external/avr_isp_programmer/images/avr_wiring.png differ
- 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
- new file mode 100644
- index 000000000..b03bf3567
- Binary files /dev/null and b/applications/external/avr_isp_programmer/images/chif_not_found_83x37.png differ
- diff --git a/applications/external/avr_isp_programmer/images/chip_error_70x22.png b/applications/external/avr_isp_programmer/images/chip_error_70x22.png
- new file mode 100644
- index 000000000..16f81178c
- Binary files /dev/null and b/applications/external/avr_isp_programmer/images/chip_error_70x22.png differ
- diff --git a/applications/external/avr_isp_programmer/images/chip_long_70x22.png b/applications/external/avr_isp_programmer/images/chip_long_70x22.png
- new file mode 100644
- index 000000000..3edfff82d
- Binary files /dev/null and b/applications/external/avr_isp_programmer/images/chip_long_70x22.png differ
- 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
- new file mode 100644
- index 000000000..6d56dcfa0
- Binary files /dev/null and b/applications/external/avr_isp_programmer/images/chip_not_found_83x37.png differ
- diff --git a/applications/external/avr_isp_programmer/images/dolphin_nice_96x59.png b/applications/external/avr_isp_programmer/images/dolphin_nice_96x59.png
- new file mode 100644
- index 000000000..a299d3630
- Binary files /dev/null and b/applications/external/avr_isp_programmer/images/dolphin_nice_96x59.png differ
- diff --git a/applications/external/avr_isp_programmer/images/isp_active_128x53.png b/applications/external/avr_isp_programmer/images/isp_active_128x53.png
- new file mode 100644
- index 000000000..843792123
- Binary files /dev/null and b/applications/external/avr_isp_programmer/images/isp_active_128x53.png differ
- diff --git a/applications/external/avr_isp_programmer/images/link_waiting_77x56.png b/applications/external/avr_isp_programmer/images/link_waiting_77x56.png
- new file mode 100644
- index 000000000..d7d32aed5
- Binary files /dev/null and b/applications/external/avr_isp_programmer/images/link_waiting_77x56.png differ
- 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
- new file mode 100644
- index 000000000..2be54de6a
- --- /dev/null
- +++ b/applications/external/avr_isp_programmer/lib/driver/avr_isp_chip_arr.c
- @@ -0,0 +1,386 @@
- +#include "avr_isp_chip_arr.h"
- +
- +#include <furi.h>
- +
- +//https://github.com/avrdudes/avrdude/blob/master/src/avrintel.c
- +
- +const AvrIspChipArr avr_isp_chip_arr[] = { // Value of -1 typically means unknown
- + //{mcu_name, mcuid, family, {sig, na, ture}, flstart, flsize, pgsiz, nb, bootsz, eestart, eesize, ep, rambeg, ramsiz, nf, nl, ni}, // Source
- + {"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)
- + {"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)
- + {"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)
- + {"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)
- + {"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)
- + {"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)
- + {"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)
- + {"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)
- +
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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)
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"ATtiny828R", 36, F_AVR8, {0x1E, 0x93, 0x14}, 0, 0x02000, 0x040, 4, 0x0100, 0, 0x0100, 4, 0x0100, 0x0200, 3, 1, 26}, // avrdude, from ATtiny828
- + {"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
- + {"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
- + {"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
- + {"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
- + {"ATtiny1634R", 41, F_AVR8, {0x1E, 0x94, 0x12}, 0, 0x04000, 0x020, 0, 0, 0, 0x0100, 4, 0x0100, 0x0400, 3, 1, 28}, // avrdude, from ATtiny1634
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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)
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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)
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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)
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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)
- + {"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
- + {"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)
- + {"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
- + {"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
- + {"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
- + {"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)
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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)
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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)
- + {"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
- + {"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
- + {"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
- + {"ATmega324PB", 113, F_AVR8, {0x1E, 0x95, 0x17}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 51}, // atdf, avrdude
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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)
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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)
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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)
- + {"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
- + {"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
- + {"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)
- + {"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)
- + {"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)
- + {"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)
- + {"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)
- + {"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)
- + {"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)
- + {"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)
- + {"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
- + {"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)
- + {"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
- + {"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
- + {"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
- + {"ATA5700M322", 199, F_AVR8, {0x1E, 0x95, 0x67}, 0x08000, 0x08000, 0x040, 0, 0, 0, 0x0880, 16, 0x0200, 0x0400, 1, 1, 51}, // atdf
- + {"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
- + {"ATA5781", 201, F_AVR8, {0x1E, 0x95, 0x64}, -1, -1, -1, 0, 0, 0, 0x0400, 16, 0x0200, 0x0400, 1, 1, 42}, // atdf
- + {"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
- + {"ATA5783", 203, F_AVR8, {0x1E, 0x95, 0x66}, -1, -1, -1, 0, 0, 0, 0x0400, 16, 0x0200, 0x0400, 1, 1, 42}, // atdf
- + {"ATA5787", 204, F_AVR8, {0x1E, 0x94, 0x6C}, 0x08000, 0x05200, 0x040, 0, 0, 0, 0x0400, 16, 0x0200, 0x0800, 1, 1, 44}, // atdf
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"ATA5832", 210, F_AVR8, {0x1E, 0x95, 0x62}, -1, -1, -1, 0, 0, 0, 0x0400, 16, 0x0200, 0x0400, 1, 1, 42}, // atdf
- + {"ATA5833", 211, F_AVR8, {0x1E, 0x95, 0x63}, -1, -1, -1, 0, 0, 0, 0x0400, 16, 0x0200, 0x0400, 1, 1, 42}, // atdf
- + {"ATA5835", 212, F_AVR8, {0x1E, 0x94, 0x6B}, 0x08000, 0x05200, 0x040, 0, 0, 0, 0x0400, 16, 0x0200, 0x0800, 1, 1, 44}, // atdf
- + {"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
- + {"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
- + {"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)
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"ATA8215", 222, F_AVR8, {0x1E, 0x95, 0x64}, -1, -1, -1, 0, 0, 0, 0x0400, 16, 0x0200, 0x0400, 1, 1, 42}, // atdf
- + {"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
- + {"ATA8515", 224, F_AVR8, {0x1E, 0x95, 0x63}, -1, -1, -1, 0, 0, 0, 0x0400, 16, 0x0200, 0x0400, 1, 1, 42}, // atdf
- + {"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
- + {"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
- + {"LGT8F88P", 227, F_AVR8, {0x1E, 0x93, 0x0F}, 0, 0x02000, 0x040, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 26}, // avrdude, from ATmega88
- + {"LGT8F168P", 228, F_AVR8, {0x1E, 0x94, 0x0B}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 26}, // avrdude, from ATmega168P
- + {"LGT8F328P", 229, F_AVR8, {0x1E, 0x95, 0x0F}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 26}, // avrdude, from ATmega328P
- +
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"ATxmega64A4", 251, F_XMEGA, {0x1E, 0x96, 0x46}, 0, 0x11000, 0x100, -1, -1, 0, 0x0800, 32, -1, -1, -1, -1, 0}, // avrdude
- + {"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
- + {"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
- + {"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
- + {"ATxmega128A1revD", 255, F_XMEGA, {0x1E, 0x97, 0x41}, 0, 0x22000, 0x200, -1, -1, 0, 0x0800, 32, -1, -1, -1, -1, 0}, // avrdude
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"ATxmega128A4", 263, F_XMEGA, {0x1E, 0x97, 0x46}, 0, 0x22000, 0x200, -1, -1, 0, 0x0800, 32, -1, -1, -1, -1, 0}, // avrdude
- + {"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
- + {"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
- + {"ATxmega192A1", 266, F_XMEGA, {0x1E, 0x97, 0x4E}, 0, 0x32000, 0x200, -1, -1, 0, 0x0800, 32, -1, -1, -1, -1, 0}, // avrdude
- + {"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
- + {"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
- + {"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
- + {"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
- + {"ATxmega256A1", 271, F_XMEGA, {0x1E, 0x98, 0x46}, 0, 0x42000, 0x200, -1, -1, 0, 0x1000, 32, -1, -1, -1, -1, 0}, // avrdude
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- +
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"ATtiny416auto", 290, F_AVR8X, {0x1E, 0x92, 0x28}, 0, 0x01000, 0x040, 1, 0, 0x01400, 0x0080, 32, 0x3f00, 0x0100, 10, 1, 26}, // atdf
- + {"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
- + {"ATtiny424", 292, F_AVR8X, {0x1E, 0x92, 0x2C}, 0, 0x01000, 0x040, 1, 0, 0x01400, 0x0080, 32, 0x3e00, 0x0200, 10, 1, 30}, // atdf, avrdude
- + {"ATtiny426", 293, F_AVR8X, {0x1E, 0x92, 0x2B}, 0, 0x01000, 0x040, 1, 0, 0x01400, 0x0080, 32, 0x3e00, 0x0200, 10, 1, 30}, // atdf, avrdude
- + {"ATtiny427", 294, F_AVR8X, {0x1E, 0x92, 0x2A}, 0, 0x01000, 0x040, 1, 0, 0x01400, 0x0080, 32, 0x3e00, 0x0200, 10, 1, 30}, // atdf, avrdude
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"ATtiny824", 301, F_AVR8X, {0x1E, 0x93, 0x29}, 0, 0x02000, 0x040, 1, 0, 0x01400, 0x0080, 32, 0x3c00, 0x0400, 10, 1, 30}, // atdf, avrdude
- + {"ATtiny826", 302, F_AVR8X, {0x1E, 0x93, 0x28}, 0, 0x02000, 0x040, 1, 0, 0x01400, 0x0080, 32, 0x3c00, 0x0400, 10, 1, 30}, // atdf, avrdude
- + {"ATtiny827", 303, F_AVR8X, {0x1E, 0x93, 0x27}, 0, 0x02000, 0x040, 1, 0, 0x01400, 0x0080, 32, 0x3c00, 0x0400, 10, 1, 30}, // atdf, avrdude
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"ATtiny1624", 310, F_AVR8X, {0x1E, 0x94, 0x2A}, 0, 0x04000, 0x040, 1, 0, 0x01400, 0x0100, 32, 0x3800, 0x0800, 10, 1, 30}, // atdf, avrdude
- + {"ATtiny1626", 311, F_AVR8X, {0x1E, 0x94, 0x29}, 0, 0x04000, 0x040, 1, 0, 0x01400, 0x0100, 32, 0x3800, 0x0800, 10, 1, 30}, // atdf, avrdude
- + {"ATtiny1627", 312, F_AVR8X, {0x1E, 0x94, 0x28}, 0, 0x04000, 0x040, 1, 0, 0x01400, 0x0100, 32, 0x3800, 0x0800, 10, 1, 30}, // atdf, avrdude
- + {"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
- + {"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
- + {"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
- + {"ATtiny3224", 316, F_AVR8X, {0x1E, 0x95, 0x28}, 0, 0x08000, 0x080, 1, 0, 0x01400, 0x0100, 64, 0x3400, 0x0c00, 10, 1, 30}, // atdf, avrdude
- + {"ATtiny3226", 317, F_AVR8X, {0x1E, 0x95, 0x27}, 0, 0x08000, 0x080, 1, 0, 0x01400, 0x0100, 64, 0x3400, 0x0c00, 10, 1, 30}, // atdf, avrdude
- + {"ATtiny3227", 318, F_AVR8X, {0x1E, 0x95, 0x26}, 0, 0x08000, 0x080, 1, 0, 0x01400, 0x0100, 64, 0x3400, 0x0c00, 10, 1, 30}, // atdf, avrdude
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"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
- + {"AVR8EA28", 327, F_AVR8X, {0x1E, 0x93, 0x2C}, 0, 0x02000, 0x040, 1, 0, 0x01400, 0x0200, 8, -1, -1, -1, -1, 0}, // avrdude
- + {"AVR8EA32", 328, F_AVR8X, {0x1E, 0x93, 0x2B}, 0, 0x02000, 0x040, 1, 0, 0x01400, 0x0200, 8, -1, -1, -1, -1, 0}, // avrdude
- + {"AVR16DD14", 329, F_AVR8X, {0x1E, 0x94, 0x34}, 0, 0x04000, 0x200, 1, 0, 0x01400, 0x0100, 1, 0x7800, 0x0800, 16, 4, 36}, // atdf, avrdude
- + {"AVR16DD20", 330, F_AVR8X, {0x1E, 0x94, 0x33}, 0, 0x04000, 0x200, 1, 0, 0x01400, 0x0100, 1, 0x7800, 0x0800, 16, 4, 36}, // atdf, avrdude
- + {"AVR16DD28", 331, F_AVR8X, {0x1E, 0x94, 0x32}, 0, 0x04000, 0x200, 1, 0, 0x01400, 0x0100, 1, 0x7800, 0x0800, 16, 4, 36}, // atdf, avrdude
- + {"AVR16EA28", 332, F_AVR8X, {0x1E, 0x94, 0x37}, 0, 0x04000, 0x040, 1, 0, 0x01400, 0x0200, 8, -1, -1, -1, -1, 0}, // avrdude
- + {"AVR16DD32", 333, F_AVR8X, {0x1E, 0x94, 0x31}, 0, 0x04000, 0x200, 1, 0, 0x01400, 0x0100, 1, 0x7800, 0x0800, 16, 4, 36}, // atdf, avrdude
- + {"AVR16EA32", 334, F_AVR8X, {0x1E, 0x94, 0x36}, 0, 0x04000, 0x040, 1, 0, 0x01400, 0x0200, 8, -1, -1, -1, -1, 0}, // avrdude
- + {"AVR16EA48", 335, F_AVR8X, {0x1E, 0x94, 0x35}, 0, 0x04000, 0x040, 1, 0, 0x01400, 0x0200, 8, -1, -1, -1, -1, 0}, // avrdude
- + {"AVR32DD14", 336, F_AVR8X, {0x1E, 0x95, 0x3B}, 0, 0x08000, 0x200, 1, 0, 0x01400, 0x0100, 1, 0x7000, 0x1000, 16, 4, 36}, // atdf, avrdude
- + {"AVR32DD20", 337, F_AVR8X, {0x1E, 0x95, 0x3A}, 0, 0x08000, 0x200, 1, 0, 0x01400, 0x0100, 1, 0x7000, 0x1000, 16, 4, 36}, // atdf, avrdude
- + {"AVR32DA28", 338, F_AVR8X, {0x1E, 0x95, 0x34}, 0, 0x08000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x7000, 0x1000, 16, 4, 41}, // atdf, avrdude
- + {"AVR32DB28", 339, F_AVR8X, {0x1E, 0x95, 0x37}, 0, 0x08000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x7000, 0x1000, 16, 4, 42}, // atdf, avrdude
- + {"AVR32DD28", 340, F_AVR8X, {0x1E, 0x95, 0x39}, 0, 0x08000, 0x200, 1, 0, 0x01400, 0x0100, 1, 0x7000, 0x1000, 16, 4, 36}, // atdf, avrdude
- + {"AVR32EA28", 341, F_AVR8X, {0x1E, 0x95, 0x3E}, 0, 0x08000, 0x040, 1, 0, 0x01400, 0x0200, 8, -1, -1, -1, -1, 0}, // avrdude
- + {"AVR32DA32", 342, F_AVR8X, {0x1E, 0x95, 0x33}, 0, 0x08000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x7000, 0x1000, 16, 4, 44}, // atdf, avrdude
- + {"AVR32DB32", 343, F_AVR8X, {0x1E, 0x95, 0x36}, 0, 0x08000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x7000, 0x1000, 16, 4, 44}, // atdf, avrdude
- + {"AVR32DD32", 344, F_AVR8X, {0x1E, 0x95, 0x38}, 0, 0x08000, 0x200, 1, 0, 0x01400, 0x0100, 1, 0x7000, 0x1000, 16, 4, 36}, // atdf, avrdude
- + {"AVR32EA32", 345, F_AVR8X, {0x1E, 0x95, 0x3D}, 0, 0x08000, 0x040, 1, 0, 0x01400, 0x0200, 8, -1, -1, -1, -1, 0}, // avrdude
- + {"AVR32DA48", 346, F_AVR8X, {0x1E, 0x95, 0x32}, 0, 0x08000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x7000, 0x1000, 16, 4, 58}, // atdf, avrdude
- + {"AVR32DB48", 347, F_AVR8X, {0x1E, 0x95, 0x35}, 0, 0x08000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x7000, 0x1000, 16, 4, 61}, // atdf, avrdude
- + {"AVR32EA48", 348, F_AVR8X, {0x1E, 0x95, 0x3C}, 0, 0x08000, 0x040, 1, 0, 0x01400, 0x0200, 8, -1, -1, -1, -1, 0}, // avrdude
- + {"AVR64DD14", 349, F_AVR8X, {0x1E, 0x96, 0x1D}, 0, 0x10000, 0x200, 1, 0, 0x01400, 0x0100, 1, 0x6000, 0x2000, 16, 4, 36}, // atdf, avrdude
- + {"AVR64DD20", 350, F_AVR8X, {0x1E, 0x96, 0x1C}, 0, 0x10000, 0x200, 1, 0, 0x01400, 0x0100, 1, 0x6000, 0x2000, 16, 4, 36}, // atdf, avrdude
- + {"AVR64DA28", 351, F_AVR8X, {0x1E, 0x96, 0x15}, 0, 0x10000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x6000, 0x2000, 16, 4, 41}, // atdf, avrdude
- + {"AVR64DB28", 352, F_AVR8X, {0x1E, 0x96, 0x19}, 0, 0x10000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x6000, 0x2000, 16, 4, 42}, // atdf, avrdude
- + {"AVR64DD28", 353, F_AVR8X, {0x1E, 0x96, 0x1B}, 0, 0x10000, 0x200, 1, 0, 0x01400, 0x0100, 1, 0x6000, 0x2000, 16, 4, 36}, // atdf, avrdude
- + {"AVR64EA28", 354, F_AVR8X, {0x1E, 0x96, 0x20}, 0, 0x10000, 0x080, 1, 0, 0x01400, 0x0200, 8, 0x6800, 0x1800, 16, 4, 37}, // atdf, avrdude
- + {"AVR64DA32", 355, F_AVR8X, {0x1E, 0x96, 0x14}, 0, 0x10000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x6000, 0x2000, 16, 4, 44}, // atdf, avrdude
- + {"AVR64DB32", 356, F_AVR8X, {0x1E, 0x96, 0x18}, 0, 0x10000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x6000, 0x2000, 16, 4, 44}, // atdf, avrdude
- + {"AVR64DD32", 357, F_AVR8X, {0x1E, 0x96, 0x1A}, 0, 0x10000, 0x200, 1, 0, 0x01400, 0x0100, 1, 0x6000, 0x2000, 16, 4, 36}, // atdf, avrdude
- + {"AVR64EA32", 358, F_AVR8X, {0x1E, 0x96, 0x1F}, 0, 0x10000, 0x080, 1, 0, 0x01400, 0x0200, 8, 0x6800, 0x1800, 16, 4, 37}, // atdf, avrdude
- + {"AVR64DA48", 359, F_AVR8X, {0x1E, 0x96, 0x13}, 0, 0x10000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x6000, 0x2000, 16, 4, 58}, // atdf, avrdude
- + {"AVR64DB48", 360, F_AVR8X, {0x1E, 0x96, 0x17}, 0, 0x10000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x6000, 0x2000, 16, 4, 61}, // atdf, avrdude
- + {"AVR64EA48", 361, F_AVR8X, {0x1E, 0x96, 0x1E}, 0, 0x10000, 0x080, 1, 0, 0x01400, 0x0200, 8, 0x6800, 0x1800, 16, 4, 45}, // atdf, avrdude
- + {"AVR64DA64", 362, F_AVR8X, {0x1E, 0x96, 0x12}, 0, 0x10000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x6000, 0x2000, 16, 4, 64}, // atdf, avrdude
- + {"AVR64DB64", 363, F_AVR8X, {0x1E, 0x96, 0x16}, 0, 0x10000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x6000, 0x2000, 16, 4, 65}, // atdf, avrdude
- + {"AVR128DA28", 364, F_AVR8X, {0x1E, 0x97, 0x0A}, 0, 0x20000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x4000, 0x4000, 16, 4, 41}, // atdf, avrdude
- + {"AVR128DB28", 365, F_AVR8X, {0x1E, 0x97, 0x0E}, 0, 0x20000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x4000, 0x4000, 16, 4, 42}, // atdf, avrdude
- + {"AVR128DA32", 366, F_AVR8X, {0x1E, 0x97, 0x09}, 0, 0x20000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x4000, 0x4000, 16, 4, 44}, // atdf, avrdude
- + {"AVR128DB32", 367, F_AVR8X, {0x1E, 0x97, 0x0D}, 0, 0x20000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x4000, 0x4000, 16, 4, 44}, // atdf, avrdude
- + {"AVR128DA48", 368, F_AVR8X, {0x1E, 0x97, 0x08}, 0, 0x20000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x4000, 0x4000, 16, 4, 58}, // atdf, avrdude
- + {"AVR128DB48", 369, F_AVR8X, {0x1E, 0x97, 0x0C}, 0, 0x20000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x4000, 0x4000, 16, 4, 61}, // atdf, avrdude
- + {"AVR128DA64", 370, F_AVR8X, {0x1E, 0x97, 0x07}, 0, 0x20000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x4000, 0x4000, 16, 4, 64}, // atdf, avrdude
- + {"AVR128DB64", 371, F_AVR8X, {0x1E, 0x97, 0x0B}, 0, 0x20000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x4000, 0x4000, 16, 4, 65}, // atdf, avrdude
- +};
- +
- +const size_t avr_isp_chip_arr_size = COUNT_OF(avr_isp_chip_arr);
- \ No newline at end of file
- 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
- new file mode 100644
- index 000000000..66f16a7b9
- --- /dev/null
- +++ b/applications/external/avr_isp_programmer/lib/driver/avr_isp_chip_arr.h
- @@ -0,0 +1,33 @@
- +#pragma once
- +
- +#include <furi_hal.h>
- +
- +#define F_AVR8L 1 // TPI programming, ATtiny(4|5|9|10|20|40|102|104)
- +#define F_AVR8 2 // ISP programming with SPI, "classic" AVRs
- +#define F_XMEGA 4 // PDI programming, ATxmega family
- +#define F_AVR8X 8 // UPDI programming, newer 8-bit MCUs
- +
- +struct AvrIspChipArr { // Value of -1 typically means unknown
- + const char* name; // Name of part
- + uint16_t mcuid; // ID of MCU in 0..2039
- + uint8_t avrarch; // F_AVR8L, F_AVR8, F_XMEGA or F_AVR8X
- + uint8_t sigs[3]; // Signature bytes
- + int32_t flashoffset; // Flash offset
- + int32_t flashsize; // Flash size
- + int16_t pagesize; // Flash page size
- + int8_t nboots; // Number of supported boot sectors
- + int16_t bootsize; // Size of (smallest) boot sector
- + int32_t eepromoffset; // EEPROM offset
- + int32_t eepromsize; // EEPROM size
- + int32_t eeprompagesize; // EEPROM page size
- + int32_t sramstart; // SRAM offset
- + int32_t sramsize; // SRAM size
- + int8_t nfuses; // Number of fuse bytes
- + int8_t nlocks; // Number of lock bytes
- + uint8_t ninterrupts; // Number of vectors in interrupt vector table
- +};
- +
- +typedef struct AvrIspChipArr AvrIspChipArr;
- +
- +extern const AvrIspChipArr avr_isp_chip_arr[];
- +extern const size_t avr_isp_chip_arr_size;
- \ No newline at end of file
- 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
- new file mode 100644
- index 000000000..b457e4c27
- --- /dev/null
- +++ b/applications/external/avr_isp_programmer/lib/driver/avr_isp_prog.c
- @@ -0,0 +1,633 @@
- +#include "avr_isp_prog.h"
- +#include "avr_isp_prog_cmd.h"
- +
- +#include <furi.h>
- +
- +#define AVR_ISP_PROG_TX_RX_BUF_SIZE 320
- +#define TAG "AvrIspProg"
- +
- +struct AvrIspProgSignature {
- + uint8_t vendor;
- + uint8_t part_family;
- + uint8_t part_number;
- +};
- +
- +typedef struct AvrIspProgSignature AvrIspProgSignature;
- +
- +struct AvrIspProgCfgDevice {
- + uint8_t devicecode;
- + uint8_t revision;
- + uint8_t progtype;
- + uint8_t parmode;
- + uint8_t polling;
- + uint8_t selftimed;
- + uint8_t lockbytes;
- + uint8_t fusebytes;
- + uint8_t flashpoll;
- + uint16_t eeprompoll;
- + uint16_t pagesize;
- + uint16_t eepromsize;
- + uint32_t flashsize;
- +};
- +
- +typedef struct AvrIspProgCfgDevice AvrIspProgCfgDevice;
- +
- +struct AvrIspProg {
- + AvrIspSpiSw* spi;
- + AvrIspProgCfgDevice* cfg;
- + FuriStreamBuffer* stream_rx;
- + FuriStreamBuffer* stream_tx;
- +
- + uint16_t error;
- + uint16_t addr;
- + bool pmode;
- + bool exit;
- + bool rst_active_high;
- + uint8_t buff[AVR_ISP_PROG_TX_RX_BUF_SIZE];
- +
- + AvrIspProgCallback callback;
- + void* context;
- +};
- +
- +static void avr_isp_prog_end_pmode(AvrIspProg* instance);
- +
- +AvrIspProg* avr_isp_prog_init(void) {
- + AvrIspProg* instance = malloc(sizeof(AvrIspProg));
- + instance->cfg = malloc(sizeof(AvrIspProgCfgDevice));
- + instance->stream_rx =
- + furi_stream_buffer_alloc(sizeof(int8_t) * AVR_ISP_PROG_TX_RX_BUF_SIZE, sizeof(int8_t));
- + instance->stream_tx =
- + furi_stream_buffer_alloc(sizeof(int8_t) * AVR_ISP_PROG_TX_RX_BUF_SIZE, sizeof(int8_t));
- + instance->rst_active_high = false;
- + instance->exit = false;
- + return instance;
- +}
- +
- +void avr_isp_prog_free(AvrIspProg* instance) {
- + furi_assert(instance);
- + if(instance->spi) avr_isp_prog_end_pmode(instance);
- + furi_stream_buffer_free(instance->stream_tx);
- + furi_stream_buffer_free(instance->stream_rx);
- + free(instance->cfg);
- + free(instance);
- +}
- +
- +size_t avr_isp_prog_spaces_rx(AvrIspProg* instance) {
- + return furi_stream_buffer_spaces_available(instance->stream_rx);
- +}
- +
- +bool avr_isp_prog_rx(AvrIspProg* instance, uint8_t* data, size_t len) {
- + furi_assert(instance);
- + furi_assert(data);
- + furi_assert(len != 0);
- + size_t ret = furi_stream_buffer_send(instance->stream_rx, data, sizeof(uint8_t) * len, 0);
- + return ret == sizeof(uint8_t) * len;
- +}
- +
- +size_t avr_isp_prog_tx(AvrIspProg* instance, uint8_t* data, size_t max_len) {
- + furi_assert(instance);
- + return furi_stream_buffer_receive(instance->stream_tx, data, sizeof(int8_t) * max_len, 0);
- +}
- +
- +void avr_isp_prog_exit(AvrIspProg* instance) {
- + furi_assert(instance);
- + instance->exit = true;
- +}
- +
- +void avr_isp_prog_set_tx_callback(AvrIspProg* instance, AvrIspProgCallback callback, void* context) {
- + furi_assert(instance);
- + furi_assert(context);
- + instance->callback = callback;
- + instance->context = context;
- +}
- +
- +static void avr_isp_prog_tx_ch(AvrIspProg* instance, uint8_t data) {
- + furi_assert(instance);
- + furi_stream_buffer_send(instance->stream_tx, &data, sizeof(uint8_t), FuriWaitForever);
- +}
- +
- +static uint8_t avr_isp_prog_getch(AvrIspProg* instance) {
- + furi_assert(instance);
- + uint8_t data[1] = {0};
- + while(furi_stream_buffer_receive(instance->stream_rx, &data, sizeof(int8_t), 30) == 0) {
- + if(instance->exit) break;
- + };
- + return data[0];
- +}
- +
- +static void avr_isp_prog_fill(AvrIspProg* instance, size_t len) {
- + furi_assert(instance);
- + for(size_t x = 0; x < len; x++) {
- + instance->buff[x] = avr_isp_prog_getch(instance);
- + }
- +}
- +
- +static void avr_isp_prog_reset_target(AvrIspProg* instance, bool reset) {
- + furi_assert(instance);
- + avr_isp_spi_sw_res_set(instance->spi, (reset == instance->rst_active_high) ? true : false);
- +}
- +
- +static uint8_t avr_isp_prog_spi_transaction(
- + AvrIspProg* instance,
- + uint8_t cmd,
- + uint8_t addr_hi,
- + uint8_t addr_lo,
- + uint8_t data) {
- + furi_assert(instance);
- +
- + avr_isp_spi_sw_txrx(instance->spi, cmd);
- + avr_isp_spi_sw_txrx(instance->spi, addr_hi);
- + avr_isp_spi_sw_txrx(instance->spi, addr_lo);
- + return avr_isp_spi_sw_txrx(instance->spi, data);
- +}
- +
- +static void avr_isp_prog_empty_reply(AvrIspProg* instance) {
- + furi_assert(instance);
- + if(avr_isp_prog_getch(instance) == CRC_EOP) {
- + avr_isp_prog_tx_ch(instance, STK_INSYNC);
- + avr_isp_prog_tx_ch(instance, STK_OK);
- + } else {
- + instance->error++;
- + avr_isp_prog_tx_ch(instance, STK_NOSYNC);
- + }
- +}
- +
- +static void avr_isp_prog_breply(AvrIspProg* instance, uint8_t data) {
- + furi_assert(instance);
- + if(avr_isp_prog_getch(instance) == CRC_EOP) {
- + avr_isp_prog_tx_ch(instance, STK_INSYNC);
- + avr_isp_prog_tx_ch(instance, data);
- + avr_isp_prog_tx_ch(instance, STK_OK);
- + } else {
- + instance->error++;
- + avr_isp_prog_tx_ch(instance, STK_NOSYNC);
- + }
- +}
- +
- +static void avr_isp_prog_get_version(AvrIspProg* instance, uint8_t data) {
- + furi_assert(instance);
- + switch(data) {
- + case STK_HW_VER:
- + avr_isp_prog_breply(instance, AVR_ISP_HWVER);
- + break;
- + case STK_SW_MAJOR:
- + avr_isp_prog_breply(instance, AVR_ISP_SWMAJ);
- + break;
- + case STK_SW_MINOR:
- + avr_isp_prog_breply(instance, AVR_ISP_SWMIN);
- + break;
- + case AVP_ISP_CONNECT_TYPE:
- + avr_isp_prog_breply(instance, AVP_ISP_SERIAL_CONNECT_TYPE);
- + break;
- + default:
- + avr_isp_prog_breply(instance, AVR_ISP_RESP_0);
- + }
- +}
- +
- +static void avr_isp_prog_set_cfg(AvrIspProg* instance) {
- + furi_assert(instance);
- + // call this after reading cfg packet into buff[]
- + instance->cfg->devicecode = instance->buff[0];
- + instance->cfg->revision = instance->buff[1];
- + instance->cfg->progtype = instance->buff[2];
- + instance->cfg->parmode = instance->buff[3];
- + instance->cfg->polling = instance->buff[4];
- + instance->cfg->selftimed = instance->buff[5];
- + instance->cfg->lockbytes = instance->buff[6];
- + instance->cfg->fusebytes = instance->buff[7];
- + instance->cfg->flashpoll = instance->buff[8];
- + // ignore (instance->buff[9] == instance->buff[8]) //FLASH polling value. Same as “flashpoll”
- + instance->cfg->eeprompoll = instance->buff[10] << 8 | instance->buff[11];
- + instance->cfg->pagesize = instance->buff[12] << 8 | instance->buff[13];
- + instance->cfg->eepromsize = instance->buff[14] << 8 | instance->buff[15];
- + instance->cfg->flashsize = instance->buff[16] << 24 | instance->buff[17] << 16 |
- + instance->buff[18] << 8 | instance->buff[19];
- +
- + // avr devices have active low reset, at89sx are active high
- + instance->rst_active_high = (instance->cfg->devicecode >= 0xe0);
- +}
- +static bool
- + avr_isp_prog_set_pmode(AvrIspProg* instance, uint8_t a, uint8_t b, uint8_t c, uint8_t d) {
- + furi_assert(instance);
- + uint8_t res = 0;
- + avr_isp_spi_sw_txrx(instance->spi, a);
- + avr_isp_spi_sw_txrx(instance->spi, b);
- + res = avr_isp_spi_sw_txrx(instance->spi, c);
- + avr_isp_spi_sw_txrx(instance->spi, d);
- + return res == 0x53;
- +}
- +
- +static void avr_isp_prog_end_pmode(AvrIspProg* instance) {
- + furi_assert(instance);
- + if(instance->pmode) {
- + avr_isp_prog_reset_target(instance, false);
- + // We're about to take the target out of reset
- + // so configure SPI pins as input
- +
- + if(instance->spi) avr_isp_spi_sw_free(instance->spi);
- + instance->spi = NULL;
- + }
- +
- + instance->pmode = false;
- +}
- +
- +static bool avr_isp_prog_start_pmode(AvrIspProg* instance, AvrIspSpiSwSpeed spi_speed) {
- + furi_assert(instance);
- + // Reset target before driving PIN_SCK or PIN_MOSI
- +
- + // SPI.begin() will configure SS as output,
- + // so SPI master mode is selected.
- + // We have defined RESET as pin 10,
- + // which for many arduino's is not the SS pin.
- + // So we have to configure RESET as output here,
- + // (reset_target() first sets the correct level)
- + if(instance->spi) avr_isp_spi_sw_free(instance->spi);
- + instance->spi = avr_isp_spi_sw_init(spi_speed);
- +
- + avr_isp_prog_reset_target(instance, true);
- + // See avr datasheets, chapter "SERIAL_PRG Programming Algorithm":
- +
- + // Pulse RESET after PIN_SCK is low:
- + avr_isp_spi_sw_sck_set(instance->spi, false);
- +
- + // discharge PIN_SCK, value arbitrally chosen
- + furi_delay_ms(20);
- + avr_isp_prog_reset_target(instance, false);
- +
- + // Pulse must be minimum 2 target CPU speed cycles
- + // so 100 usec is ok for CPU speeds above 20KHz
- + furi_delay_ms(1);
- +
- + avr_isp_prog_reset_target(instance, true);
- +
- + // Send the enable programming command:
- + // datasheet: must be > 20 msec
- + furi_delay_ms(50);
- + if(avr_isp_prog_set_pmode(instance, AVR_ISP_SET_PMODE)) {
- + instance->pmode = true;
- + return true;
- + }
- + return false;
- +}
- +
- +static AvrIspProgSignature avr_isp_prog_check_signature(AvrIspProg* instance) {
- + furi_assert(instance);
- + AvrIspProgSignature signature;
- + signature.vendor = avr_isp_prog_spi_transaction(instance, AVR_ISP_READ_VENDOR);
- + signature.part_family = avr_isp_prog_spi_transaction(instance, AVR_ISP_READ_PART_FAMILY);
- + signature.part_number = avr_isp_prog_spi_transaction(instance, AVR_ISP_READ_PART_NUMBER);
- + return signature;
- +}
- +
- +static bool avr_isp_prog_auto_set_spi_speed_start_pmode(AvrIspProg* instance) {
- + AvrIspSpiSwSpeed spi_speed[] = {
- + AvrIspSpiSwSpeed1Mhz,
- + AvrIspSpiSwSpeed400Khz,
- + AvrIspSpiSwSpeed250Khz,
- + AvrIspSpiSwSpeed125Khz,
- + AvrIspSpiSwSpeed60Khz,
- + AvrIspSpiSwSpeed40Khz,
- + AvrIspSpiSwSpeed20Khz,
- + AvrIspSpiSwSpeed10Khz,
- + AvrIspSpiSwSpeed5Khz,
- + AvrIspSpiSwSpeed1Khz,
- + };
- + for(uint8_t i = 0; i < COUNT_OF(spi_speed); i++) {
- + if(avr_isp_prog_start_pmode(instance, spi_speed[i])) {
- + AvrIspProgSignature sig = avr_isp_prog_check_signature(instance);
- + AvrIspProgSignature sig_examination = avr_isp_prog_check_signature(instance); //-V656
- + uint8_t y = 0;
- + while(y < 8) {
- + if(memcmp(
- + (uint8_t*)&sig, (uint8_t*)&sig_examination, sizeof(AvrIspProgSignature)) !=
- + 0)
- + break;
- + sig_examination = avr_isp_prog_check_signature(instance);
- + y++;
- + }
- + if(y == 8) {
- + if(spi_speed[i] > AvrIspSpiSwSpeed1Mhz) {
- + if(i < (COUNT_OF(spi_speed) - 1)) {
- + avr_isp_prog_end_pmode(instance);
- + i++;
- + return avr_isp_prog_start_pmode(instance, spi_speed[i]);
- + }
- + }
- + return true;
- + }
- + }
- + }
- + return false;
- +}
- +
- +static void avr_isp_prog_universal(AvrIspProg* instance) {
- + furi_assert(instance);
- + uint8_t data;
- +
- + avr_isp_prog_fill(instance, 4);
- + data = avr_isp_prog_spi_transaction(
- + instance, instance->buff[0], instance->buff[1], instance->buff[2], instance->buff[3]);
- + avr_isp_prog_breply(instance, data);
- +}
- +
- +static void avr_isp_prog_commit(AvrIspProg* instance, uint16_t addr, uint8_t data) {
- + furi_assert(instance);
- + avr_isp_prog_spi_transaction(instance, AVR_ISP_COMMIT(addr));
- + /* polling flash */
- + if(data == 0xFF) {
- + furi_delay_ms(5);
- + } else {
- + /* polling flash */
- + uint32_t starttime = furi_get_tick();
- + while((furi_get_tick() - starttime) < 30) {
- + if(avr_isp_prog_spi_transaction(instance, AVR_ISP_READ_FLASH_HI(addr)) != 0xFF) {
- + break;
- + };
- + }
- + }
- +}
- +
- +static uint16_t avr_isp_prog_current_page(AvrIspProg* instance) {
- + furi_assert(instance);
- + uint16_t page = 0;
- + switch(instance->cfg->pagesize) {
- + case 32:
- + page = instance->addr & 0xFFFFFFF0;
- + break;
- + case 64:
- + page = instance->addr & 0xFFFFFFE0;
- + break;
- + case 128:
- + page = instance->addr & 0xFFFFFFC0;
- + break;
- + case 256:
- + page = instance->addr & 0xFFFFFF80;
- + break;
- +
- + default:
- + page = instance->addr;
- + break;
- + }
- +
- + return page;
- +}
- +
- +static uint8_t avr_isp_prog_write_flash_pages(AvrIspProg* instance, size_t length) {
- + furi_assert(instance);
- + size_t x = 0;
- + uint16_t page = avr_isp_prog_current_page(instance);
- + while(x < length) {
- + if(page != avr_isp_prog_current_page(instance)) {
- + --x;
- + avr_isp_prog_commit(instance, page, instance->buff[x++]);
- + page = avr_isp_prog_current_page(instance);
- + }
- + avr_isp_prog_spi_transaction(
- + instance, AVR_ISP_WRITE_FLASH_LO(instance->addr, instance->buff[x++]));
- +
- + avr_isp_prog_spi_transaction(
- + instance, AVR_ISP_WRITE_FLASH_HI(instance->addr, instance->buff[x++]));
- + instance->addr++;
- + }
- +
- + avr_isp_prog_commit(instance, page, instance->buff[--x]);
- + return STK_OK;
- +}
- +
- +static void avr_isp_prog_write_flash(AvrIspProg* instance, size_t length) {
- + furi_assert(instance);
- + avr_isp_prog_fill(instance, length);
- + if(avr_isp_prog_getch(instance) == CRC_EOP) {
- + avr_isp_prog_tx_ch(instance, STK_INSYNC);
- + avr_isp_prog_tx_ch(instance, avr_isp_prog_write_flash_pages(instance, length));
- + } else {
- + instance->error++;
- + avr_isp_prog_tx_ch(instance, STK_NOSYNC);
- + }
- +}
- +
- +// write (length) bytes, (start) is a byte address
- +static uint8_t
- + avr_isp_prog_write_eeprom_chunk(AvrIspProg* instance, uint16_t start, uint16_t length) {
- + furi_assert(instance);
- + // this writes byte-by-byte,
- + // page writing may be faster (4 bytes at a time)
- + avr_isp_prog_fill(instance, length);
- + for(uint16_t x = 0; x < length; x++) {
- + uint16_t addr = start + x;
- + avr_isp_prog_spi_transaction(instance, AVR_ISP_WRITE_EEPROM(addr, instance->buff[x]));
- + furi_delay_ms(10);
- + }
- + return STK_OK;
- +}
- +
- +static uint8_t avr_isp_prog_write_eeprom(AvrIspProg* instance, size_t length) {
- + furi_assert(instance);
- + // here is a word address, get the byte address
- + uint16_t start = instance->addr * 2;
- + uint16_t remaining = length;
- + if(length > instance->cfg->eepromsize) {
- + instance->error++;
- + return STK_FAILED;
- + }
- + while(remaining > AVR_ISP_EECHUNK) {
- + avr_isp_prog_write_eeprom_chunk(instance, start, AVR_ISP_EECHUNK);
- + start += AVR_ISP_EECHUNK;
- + remaining -= AVR_ISP_EECHUNK;
- + }
- + avr_isp_prog_write_eeprom_chunk(instance, start, remaining);
- + return STK_OK;
- +}
- +
- +static void avr_isp_prog_program_page(AvrIspProg* instance) {
- + furi_assert(instance);
- + uint8_t result = STK_FAILED;
- + uint16_t length = avr_isp_prog_getch(instance) << 8 | avr_isp_prog_getch(instance);
- + uint8_t memtype = avr_isp_prog_getch(instance);
- + // flash memory @addr, (length) bytes
- + if(memtype == STK_SET_FLASH_TYPE) {
- + avr_isp_prog_write_flash(instance, length);
- + return;
- + }
- + if(memtype == STK_SET_EEPROM_TYPE) {
- + result = avr_isp_prog_write_eeprom(instance, length);
- + if(avr_isp_prog_getch(instance) == CRC_EOP) {
- + avr_isp_prog_tx_ch(instance, STK_INSYNC);
- + avr_isp_prog_tx_ch(instance, result);
- +
- + } else {
- + instance->error++;
- + avr_isp_prog_tx_ch(instance, STK_NOSYNC);
- + }
- + return;
- + }
- + avr_isp_prog_tx_ch(instance, STK_FAILED);
- + return;
- +}
- +
- +static uint8_t avr_isp_prog_flash_read_page(AvrIspProg* instance, uint16_t length) {
- + furi_assert(instance);
- + for(uint16_t x = 0; x < length; x += 2) {
- + avr_isp_prog_tx_ch(
- + instance,
- + avr_isp_prog_spi_transaction(instance, AVR_ISP_READ_FLASH_LO(instance->addr)));
- + avr_isp_prog_tx_ch(
- + instance,
- + avr_isp_prog_spi_transaction(instance, AVR_ISP_READ_FLASH_HI(instance->addr)));
- + instance->addr++;
- + }
- + return STK_OK;
- +}
- +
- +static uint8_t avr_isp_prog_eeprom_read_page(AvrIspProg* instance, uint16_t length) {
- + furi_assert(instance);
- + // here again we have a word address
- + uint16_t start = instance->addr * 2;
- + for(uint16_t x = 0; x < length; x++) {
- + uint16_t addr = start + x;
- + avr_isp_prog_tx_ch(
- + instance, avr_isp_prog_spi_transaction(instance, AVR_ISP_READ_EEPROM(addr)));
- + }
- + return STK_OK;
- +}
- +
- +static void avr_isp_prog_read_page(AvrIspProg* instance) {
- + furi_assert(instance);
- + uint8_t result = STK_FAILED;
- + uint16_t length = avr_isp_prog_getch(instance) << 8 | avr_isp_prog_getch(instance);
- + uint8_t memtype = avr_isp_prog_getch(instance);
- + if(avr_isp_prog_getch(instance) != CRC_EOP) {
- + instance->error++;
- + avr_isp_prog_tx_ch(instance, STK_NOSYNC);
- + return;
- + }
- + avr_isp_prog_tx_ch(instance, STK_INSYNC);
- + if(memtype == STK_SET_FLASH_TYPE) result = avr_isp_prog_flash_read_page(instance, length);
- + if(memtype == STK_SET_EEPROM_TYPE) result = avr_isp_prog_eeprom_read_page(instance, length);
- + avr_isp_prog_tx_ch(instance, result);
- +}
- +
- +static void avr_isp_prog_read_signature(AvrIspProg* instance) {
- + furi_assert(instance);
- + if(avr_isp_prog_getch(instance) != CRC_EOP) {
- + instance->error++;
- + avr_isp_prog_tx_ch(instance, STK_NOSYNC);
- + return;
- + }
- + avr_isp_prog_tx_ch(instance, STK_INSYNC);
- +
- + avr_isp_prog_tx_ch(instance, avr_isp_prog_spi_transaction(instance, AVR_ISP_READ_VENDOR));
- + avr_isp_prog_tx_ch(instance, avr_isp_prog_spi_transaction(instance, AVR_ISP_READ_PART_FAMILY));
- + avr_isp_prog_tx_ch(instance, avr_isp_prog_spi_transaction(instance, AVR_ISP_READ_PART_NUMBER));
- +
- + avr_isp_prog_tx_ch(instance, STK_OK);
- +}
- +
- +void avr_isp_prog_avrisp(AvrIspProg* instance) {
- + furi_assert(instance);
- + uint8_t ch = avr_isp_prog_getch(instance);
- +
- + switch(ch) {
- + case STK_GET_SYNC:
- + FURI_LOG_D(TAG, "cmd STK_GET_SYNC");
- + instance->error = 0;
- + avr_isp_prog_empty_reply(instance);
- + break;
- + case STK_GET_SIGN_ON:
- + FURI_LOG_D(TAG, "cmd STK_GET_SIGN_ON");
- + if(avr_isp_prog_getch(instance) == CRC_EOP) {
- + avr_isp_prog_tx_ch(instance, STK_INSYNC);
- +
- + avr_isp_prog_tx_ch(instance, 'A');
- + avr_isp_prog_tx_ch(instance, 'V');
- + avr_isp_prog_tx_ch(instance, 'R');
- + avr_isp_prog_tx_ch(instance, ' ');
- + avr_isp_prog_tx_ch(instance, 'I');
- + avr_isp_prog_tx_ch(instance, 'S');
- + avr_isp_prog_tx_ch(instance, 'P');
- +
- + avr_isp_prog_tx_ch(instance, STK_OK);
- + } else {
- + instance->error++;
- + avr_isp_prog_tx_ch(instance, STK_NOSYNC);
- + }
- + break;
- + case STK_GET_PARAMETER:
- + FURI_LOG_D(TAG, "cmd STK_GET_PARAMETER");
- + avr_isp_prog_get_version(instance, avr_isp_prog_getch(instance));
- + break;
- + case STK_SET_DEVICE:
- + FURI_LOG_D(TAG, "cmd STK_SET_DEVICE");
- + avr_isp_prog_fill(instance, 20);
- + avr_isp_prog_set_cfg(instance);
- + avr_isp_prog_empty_reply(instance);
- + break;
- + case STK_SET_DEVICE_EXT: // ignore for now
- + FURI_LOG_D(TAG, "cmd STK_SET_DEVICE_EXT");
- + avr_isp_prog_fill(instance, 5);
- + avr_isp_prog_empty_reply(instance);
- + break;
- + case STK_ENTER_PROGMODE:
- + FURI_LOG_D(TAG, "cmd STK_ENTER_PROGMODE");
- + if(!instance->pmode) avr_isp_prog_auto_set_spi_speed_start_pmode(instance);
- + avr_isp_prog_empty_reply(instance);
- + break;
- + case STK_LOAD_ADDRESS:
- + FURI_LOG_D(TAG, "cmd STK_LOAD_ADDRESS");
- + instance->addr = avr_isp_prog_getch(instance) | avr_isp_prog_getch(instance) << 8;
- + avr_isp_prog_empty_reply(instance);
- + break;
- + case STK_PROG_FLASH: // ignore for now
- + FURI_LOG_D(TAG, "cmd STK_PROG_FLASH");
- + avr_isp_prog_getch(instance);
- + avr_isp_prog_getch(instance);
- + avr_isp_prog_empty_reply(instance);
- + break;
- + case STK_PROG_DATA: // ignore for now
- + FURI_LOG_D(TAG, "cmd STK_PROG_DATA");
- + avr_isp_prog_getch(instance);
- + avr_isp_prog_empty_reply(instance);
- + break;
- + case STK_PROG_PAGE:
- + FURI_LOG_D(TAG, "cmd STK_PROG_PAGE");
- + avr_isp_prog_program_page(instance);
- + break;
- + case STK_READ_PAGE:
- + FURI_LOG_D(TAG, "cmd STK_READ_PAGE");
- + avr_isp_prog_read_page(instance);
- + break;
- + case STK_UNIVERSAL:
- + FURI_LOG_D(TAG, "cmd STK_UNIVERSAL");
- + avr_isp_prog_universal(instance);
- + break;
- + case STK_LEAVE_PROGMODE:
- + FURI_LOG_D(TAG, "cmd STK_LEAVE_PROGMODE");
- + instance->error = 0;
- + if(instance->pmode) avr_isp_prog_end_pmode(instance);
- + avr_isp_prog_empty_reply(instance);
- + break;
- + case STK_READ_SIGN:
- + FURI_LOG_D(TAG, "cmd STK_READ_SIGN");
- + avr_isp_prog_read_signature(instance);
- + break;
- + // expecting a command, not CRC_EOP
- + // this is how we can get back in sync
- + case CRC_EOP:
- + FURI_LOG_D(TAG, "cmd CRC_EOP");
- + instance->error++;
- + avr_isp_prog_tx_ch(instance, STK_NOSYNC);
- + break;
- + // anything else we will return STK_UNKNOWN
- + default:
- + FURI_LOG_D(TAG, "cmd STK_ERROR_CMD");
- + instance->error++;
- + if(avr_isp_prog_getch(instance) == CRC_EOP)
- + avr_isp_prog_tx_ch(instance, STK_UNKNOWN);
- + else
- + avr_isp_prog_tx_ch(instance, STK_NOSYNC);
- + }
- +
- + if(instance->callback) {
- + instance->callback(instance->context);
- + }
- +}
- 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
- new file mode 100644
- index 000000000..2c15ab066
- --- /dev/null
- +++ b/applications/external/avr_isp_programmer/lib/driver/avr_isp_prog.h
- @@ -0,0 +1,16 @@
- +#pragma once
- +
- +#include "avr_isp_spi_sw.h"
- +#include <furi_hal.h>
- +
- +typedef struct AvrIspProg AvrIspProg;
- +typedef void (*AvrIspProgCallback)(void* context);
- +
- +AvrIspProg* avr_isp_prog_init(void);
- +void avr_isp_prog_free(AvrIspProg* instance);
- +size_t avr_isp_prog_spaces_rx(AvrIspProg* instance) ;
- +bool avr_isp_prog_rx(AvrIspProg* instance, uint8_t* data, size_t len);
- +size_t avr_isp_prog_tx(AvrIspProg* instance, uint8_t* data, size_t max_len);
- +void avr_isp_prog_avrisp(AvrIspProg* instance);
- +void avr_isp_prog_exit(AvrIspProg* instance);
- +void avr_isp_prog_set_tx_callback(AvrIspProg* instance, AvrIspProgCallback callback, void* context);
- 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
- new file mode 100644
- index 000000000..f8b07203e
- --- /dev/null
- +++ b/applications/external/avr_isp_programmer/lib/driver/avr_isp_prog_cmd.h
- @@ -0,0 +1,97 @@
- +#pragma once
- +
- +// http://ww1.microchip.com/downloads/en/appnotes/atmel-0943-in-system-programming_applicationnote_avr910.pdf
- +// AVR ISP Definitions
- +#define AVR_ISP_HWVER 0X02
- +#define AVR_ISP_SWMAJ 0X01
- +#define AVR_ISP_SWMIN 0X12
- +#define AVP_ISP_SERIAL_CONNECT_TYPE 0X53
- +#define AVP_ISP_CONNECT_TYPE 0x93
- +#define AVR_ISP_RESP_0 0X00
- +
- +#define AVR_ISP_SET_PMODE 0xAC, 0x53, 0x00, 0x00
- +#define AVR_ISP_READ_VENDOR 0x30, 0x00, 0x00, 0x00
- +#define AVR_ISP_READ_PART_FAMILY 0x30, 0x00, 0x01, 0x00
- +#define AVR_ISP_READ_PART_NUMBER 0x30, 0x00, 0x02, 0x00
- +#define AVR_ISP_ERASE_CHIP \
- + 0xAC, 0x80, 0x00, 0x00 //Erase Chip, Wait N ms, Release RESET to end the erase.
- +//The only way to end a Chip Erase cycle is by temporarily releasing the Reset line
- +
- +#define AVR_ISP_EXTENDED_ADDR(data) 0x4D, 0x00, data, 0x00
- +#define AVR_ISP_WRITE_FLASH_LO(add, data) 0x40, (add >> 8) & 0xFF, add & 0xFF, data
- +#define AVR_ISP_WRITE_FLASH_HI(add, data) 0x48, (add >> 8) & 0xFF, add & 0xFF, data
- +#define AVR_ISP_READ_FLASH_LO(add) 0x20, (add >> 8) & 0xFF, add & 0xFF, 0x00
- +#define AVR_ISP_READ_FLASH_HI(add) 0x28, (add >> 8) & 0xFF, add & 0xFF, 0x00
- +
- +#define AVR_ISP_WRITE_EEPROM(add, data) \
- + 0xC0, (add >> 8) & 0xFF, add & 0xFF, data //Send cmd, Wait N ms
- +#define AVR_ISP_READ_EEPROM(add) 0xA0, (add >> 8) & 0xFF, add & 0xFF, 0xFF
- +
- +#define AVR_ISP_COMMIT(add) \
- + 0x4C, (add >> 8) & 0xFF, add & 0xFF, 0x00 //Send cmd, polling read last addr page
- +
- +#define AVR_ISP_OSCCAL(add) 0x38, 0x00, add, 0x00
- +
- +#define AVR_ISP_WRITE_LOCK_BYTE(data) 0xAC, 0xE0, 0x00, data //Send cmd, Wait N ms
- +#define AVR_ISP_READ_LOCK_BYTE 0x58, 0x00, 0x00, 0x00
- +#define AVR_ISP_WRITE_FUSE_LOW(data) 0xAC, 0xA0, 0x00, data //Send cmd, Wait N ms
- +#define AVR_ISP_READ_FUSE_LOW 0x50, 0x00, 0x00, 0x00
- +#define AVR_ISP_WRITE_FUSE_HIGH(data) 0xAC, 0xA8, 0x00, data //Send cmd, Wait N ms
- +#define AVR_ISP_READ_FUSE_HIGH 0x58, 0x08, 0x00, 0x00
- +#define AVR_ISP_WRITE_FUSE_EXTENDED(data) 0xAC, 0xA4, 0x00, data //Send cmd, Wait N ms (~write)
- +#define AVR_ISP_READ_FUSE_EXTENDED 0x50, 0x08, 0x00, 0x00
- +
- +#define AVR_ISP_EECHUNK 0x20
- +
- +// https://www.microchip.com/content/dam/mchp/documents/OTH/ApplicationNotes/ApplicationNotes/doc2525.pdf
- +// STK Definitions
- +#define STK_OK 0x10
- +#define STK_FAILED 0x11
- +#define STK_UNKNOWN 0x12
- +#define STK_INSYNC 0x14
- +#define STK_NOSYNC 0x15
- +#define CRC_EOP 0x20
- +
- +#define STK_GET_SYNC 0x30
- +#define STK_GET_SIGN_ON 0x31
- +#define STK_SET_PARAMETER 0x40
- +#define STK_GET_PARAMETER 0x41
- +#define STK_SET_DEVICE 0x42
- +#define STK_SET_DEVICE_EXT 0x45
- +#define STK_ENTER_PROGMODE 0x50
- +#define STK_LEAVE_PROGMODE 0x51
- +#define STK_CHIP_ERASE 0x52
- +#define STK_CHECK_AUTOINC 0x53
- +#define STK_LOAD_ADDRESS 0x55
- +#define STK_UNIVERSAL 0x56
- +#define STK_UNIVERSAL_MULTI 0x57
- +#define STK_PROG_FLASH 0x60
- +#define STK_PROG_DATA 0x61
- +#define STK_PROG_FUSE 0x62
- +#define STK_PROG_FUSE_EXT 0x65
- +#define STK_PROG_LOCK 0x63
- +#define STK_PROG_PAGE 0x64
- +#define STK_READ_FLASH 0x70
- +#define STK_READ_DATA 0x71
- +#define STK_READ_FUSE 0x72
- +#define STK_READ_LOCK 0x73
- +#define STK_READ_PAGE 0x74
- +#define STK_READ_SIGN 0x75
- +#define STK_READ_OSCCAL 0x76
- +#define STK_READ_FUSE_EXT 0x77
- +#define STK_READ_OSCCAL_EXT 0x78
- +#define STK_HW_VER 0x80
- +#define STK_SW_MAJOR 0x81
- +#define STK_SW_MINOR 0x82
- +#define STK_LEDS 0x83
- +#define STK_VTARGET 0x84
- +#define STK_VADJUST 0x85
- +#define STK_OSC_PSCALE 0x86
- +#define STK_OSC_CMATCH 0x87
- +#define STK_SCK_DURATION 0x89
- +#define STK_BUFSIZEL 0x90
- +#define STK_BUFSIZEH 0x91
- +#define STK_STK500_TOPCARD_DETECT 0x98
- +
- +#define STK_SET_EEPROM_TYPE 0X45
- +#define STK_SET_FLASH_TYPE 0X46
- 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
- new file mode 100644
- index 000000000..f60850c84
- --- /dev/null
- +++ b/applications/external/avr_isp_programmer/lib/driver/avr_isp_spi_sw.c
- @@ -0,0 +1,73 @@
- +#include "avr_isp_spi_sw.h"
- +
- +#include <furi.h>
- +
- +#define AVR_ISP_SPI_SW_MISO &gpio_ext_pa6
- +#define AVR_ISP_SPI_SW_MOSI &gpio_ext_pa7
- +#define AVR_ISP_SPI_SW_SCK &gpio_ext_pb3
- +#define AVR_ISP_RESET &gpio_ext_pb2
- +
- +struct AvrIspSpiSw {
- + AvrIspSpiSwSpeed speed_wait_time;
- + const GpioPin* miso;
- + const GpioPin* mosi;
- + const GpioPin* sck;
- + const GpioPin* res;
- +};
- +
- +AvrIspSpiSw* avr_isp_spi_sw_init(AvrIspSpiSwSpeed speed) {
- + AvrIspSpiSw* instance = malloc(sizeof(AvrIspSpiSw));
- + instance->speed_wait_time = speed;
- +
- + instance->miso = AVR_ISP_SPI_SW_MISO;
- + instance->mosi = AVR_ISP_SPI_SW_MOSI;
- + instance->sck = AVR_ISP_SPI_SW_SCK;
- + instance->res = AVR_ISP_RESET;
- +
- + furi_hal_gpio_init(instance->miso, GpioModeInput, GpioPullNo, GpioSpeedVeryHigh);
- + furi_hal_gpio_write(instance->mosi, false);
- + furi_hal_gpio_init(instance->mosi, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh);
- + furi_hal_gpio_write(instance->sck, false);
- + furi_hal_gpio_init(instance->sck, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh);
- + furi_hal_gpio_init(instance->res, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh);
- +
- + return instance;
- +}
- +
- +void avr_isp_spi_sw_free(AvrIspSpiSw* instance) {
- + furi_assert(instance);
- + furi_hal_gpio_init(instance->res, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
- + furi_hal_gpio_init(instance->miso, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
- + furi_hal_gpio_init(instance->mosi, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
- + furi_hal_gpio_init(instance->sck, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
- +
- + free(instance);
- +}
- +
- +uint8_t avr_isp_spi_sw_txrx(AvrIspSpiSw* instance, uint8_t data) {
- + furi_assert(instance);
- + for(uint8_t i = 0; i < 8; ++i) {
- + furi_hal_gpio_write(instance->mosi, (data & 0x80) ? true : false);
- +
- + furi_hal_gpio_write(instance->sck, true);
- + if(instance->speed_wait_time != AvrIspSpiSwSpeed1Mhz)
- + furi_delay_us(instance->speed_wait_time - 1);
- +
- + data = (data << 1) | furi_hal_gpio_read(instance->miso); //-V792
- +
- + furi_hal_gpio_write(instance->sck, false);
- + if(instance->speed_wait_time != AvrIspSpiSwSpeed1Mhz)
- + furi_delay_us(instance->speed_wait_time - 1);
- + }
- + return data;
- +}
- +
- +void avr_isp_spi_sw_res_set(AvrIspSpiSw* instance, bool state) {
- + furi_assert(instance);
- + furi_hal_gpio_write(instance->res, state);
- +}
- +
- +void avr_isp_spi_sw_sck_set(AvrIspSpiSw* instance, bool state) {
- + furi_assert(instance);
- + furi_hal_gpio_write(instance->sck, state);
- +}
- \ No newline at end of file
- 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
- new file mode 100644
- index 000000000..44de5ff79
- --- /dev/null
- +++ b/applications/external/avr_isp_programmer/lib/driver/avr_isp_spi_sw.h
- @@ -0,0 +1,24 @@
- +#pragma once
- +
- +#include <furi_hal.h>
- +
- +typedef enum {
- + AvrIspSpiSwSpeed1Mhz = 0,
- + AvrIspSpiSwSpeed400Khz = 1,
- + AvrIspSpiSwSpeed250Khz = 2,
- + AvrIspSpiSwSpeed125Khz = 4,
- + AvrIspSpiSwSpeed60Khz = 8,
- + AvrIspSpiSwSpeed40Khz = 12,
- + AvrIspSpiSwSpeed20Khz = 24,
- + AvrIspSpiSwSpeed10Khz = 48,
- + AvrIspSpiSwSpeed5Khz = 96,
- + AvrIspSpiSwSpeed1Khz = 480,
- +} AvrIspSpiSwSpeed;
- +
- +typedef struct AvrIspSpiSw AvrIspSpiSw;
- +
- +AvrIspSpiSw* avr_isp_spi_sw_init(AvrIspSpiSwSpeed speed);
- +void avr_isp_spi_sw_free(AvrIspSpiSw* instance);
- +uint8_t avr_isp_spi_sw_txrx(AvrIspSpiSw* instance, uint8_t data);
- +void avr_isp_spi_sw_res_set(AvrIspSpiSw* instance, bool state);
- +void avr_isp_spi_sw_sck_set(AvrIspSpiSw* instance, bool state);
- \ No newline at end of file
- diff --git a/applications/external/avr_isp_programmer/lib/driver/clock.png b/applications/external/avr_isp_programmer/lib/driver/clock.png
- new file mode 100644
- index 000000000..93a59fe68
- Binary files /dev/null and b/applications/external/avr_isp_programmer/lib/driver/clock.png differ
- diff --git a/applications/external/avr_isp_programmer/scenes/avr_isp_scene.c b/applications/external/avr_isp_programmer/scenes/avr_isp_scene.c
- new file mode 100644
- index 000000000..4af125aee
- --- /dev/null
- +++ b/applications/external/avr_isp_programmer/scenes/avr_isp_scene.c
- @@ -0,0 +1,30 @@
- +#include "../avr_isp_app_i.h"
- +
- +// Generate scene on_enter handlers array
- +#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_enter,
- +void (*const avr_isp_scene_on_enter_handlers[])(void*) = {
- +#include "avr_isp_scene_config.h"
- +};
- +#undef ADD_SCENE
- +
- +// Generate scene on_event handlers array
- +#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_event,
- +bool (*const avr_isp_scene_on_event_handlers[])(void* context, SceneManagerEvent event) = {
- +#include "avr_isp_scene_config.h"
- +};
- +#undef ADD_SCENE
- +
- +// Generate scene on_exit handlers array
- +#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_exit,
- +void (*const avr_isp_scene_on_exit_handlers[])(void* context) = {
- +#include "avr_isp_scene_config.h"
- +};
- +#undef ADD_SCENE
- +
- +// Initialize scene handlers configuration structure
- +const SceneManagerHandlers avr_isp_scene_handlers = {
- + .on_enter_handlers = avr_isp_scene_on_enter_handlers,
- + .on_event_handlers = avr_isp_scene_on_event_handlers,
- + .on_exit_handlers = avr_isp_scene_on_exit_handlers,
- + .scene_num = AvrIspSceneNum,
- +};
- diff --git a/applications/external/avr_isp_programmer/scenes/avr_isp_scene.h b/applications/external/avr_isp_programmer/scenes/avr_isp_scene.h
- new file mode 100644
- index 000000000..658ee7432
- --- /dev/null
- +++ b/applications/external/avr_isp_programmer/scenes/avr_isp_scene.h
- @@ -0,0 +1,29 @@
- +#pragma once
- +
- +#include <gui/scene_manager.h>
- +
- +// Generate scene id and total number
- +#define ADD_SCENE(prefix, name, id) AvrIspScene##id,
- +typedef enum {
- +#include "avr_isp_scene_config.h"
- + AvrIspSceneNum,
- +} AvrIspScene;
- +#undef ADD_SCENE
- +
- +extern const SceneManagerHandlers avr_isp_scene_handlers;
- +
- +// Generate scene on_enter handlers declaration
- +#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_enter(void*);
- +#include "avr_isp_scene_config.h"
- +#undef ADD_SCENE
- +
- +// Generate scene on_event handlers declaration
- +#define ADD_SCENE(prefix, name, id) \
- + bool prefix##_scene_##name##_on_event(void* context, SceneManagerEvent event);
- +#include "avr_isp_scene_config.h"
- +#undef ADD_SCENE
- +
- +// Generate scene on_exit handlers declaration
- +#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_exit(void* context);
- +#include "avr_isp_scene_config.h"
- +#undef ADD_SCENE
- 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
- new file mode 100644
- index 000000000..e5f530fec
- --- /dev/null
- +++ b/applications/external/avr_isp_programmer/scenes/avr_isp_scene_about.c
- @@ -0,0 +1,99 @@
- +#include "../avr_isp_app_i.h"
- +#include "../helpers/avr_isp_types.h"
- +
- +void avr_isp_scene_about_widget_callback(GuiButtonType result, InputType type, void* context) {
- + furi_assert(context);
- +
- + AvrIspApp* app = context;
- + if(type == InputTypeShort) {
- + view_dispatcher_send_custom_event(app->view_dispatcher, result);
- + }
- +}
- +
- +void avr_isp_scene_about_on_enter(void* context) {
- + furi_assert(context);
- +
- + AvrIspApp* app = context;
- + FuriString* temp_str = furi_string_alloc();
- + furi_string_printf(temp_str, "\e#%s\n", "Information");
- +
- + furi_string_cat_printf(temp_str, "Version: %s\n", AVR_ISP_VERSION_APP);
- + furi_string_cat_printf(temp_str, "Developed by: %s\n", AVR_ISP_DEVELOPED);
- + furi_string_cat_printf(temp_str, "Github: %s\n\n", AVR_ISP_GITHUB);
- +
- + furi_string_cat_printf(temp_str, "\e#%s\n", "Description");
- + furi_string_cat_printf(
- + temp_str,
- + "This application is an AVR in-system programmer based on stk500mk1. It is compatible with AVR-based"
- + " microcontrollers including Arduino. You can also use it to repair the chip if you accidentally"
- + " corrupt the bootloader.\n\n");
- +
- + furi_string_cat_printf(temp_str, "\e#%s\n", "What it can do:");
- + furi_string_cat_printf(temp_str, "- Create a dump of your chip on an SD card\n");
- + furi_string_cat_printf(temp_str, "- Flash your chip firmware from the SD card\n");
- + furi_string_cat_printf(temp_str, "- Act as a wired USB ISP using avrdude software\n\n");
- +
- + furi_string_cat_printf(temp_str, "\e#%s\n", "Supported chip series:");
- + furi_string_cat_printf(
- + temp_str,
- + "Example command for avrdude flashing: avrdude.exe -p m328p -c stk500v1 -P COMxx -U flash:r:"
- + "X:\\sketch_sample.hex"
- + ":i\n");
- + furi_string_cat_printf(
- + temp_str,
- + "Where: "
- + "-p m328p"
- + " brand of your chip, "
- + "-P COMxx"
- + " com port number in the system when "
- + "ISP Programmer"
- + " is enabled\n\n");
- +
- + furi_string_cat_printf(temp_str, "\e#%s\n", "Info");
- + furi_string_cat_printf(
- + temp_str,
- + "ATtinyXXXX\nATmegaXXXX\nAT43Uxxx\nAT76C711\nAT86RF401\nAT90xxxxx\nAT94K\n"
- + "ATAxxxxx\nATA664251\nM3000\nLGT8F88P\nLGT8F168P\nLGT8F328P\n");
- +
- + furi_string_cat_printf(
- + temp_str, "For a more detailed list of supported chips, see AVRDude help\n");
- +
- + widget_add_text_box_element(
- + app->widget,
- + 0,
- + 0,
- + 128,
- + 14,
- + AlignCenter,
- + AlignBottom,
- + "\e#\e! \e!\n",
- + false);
- + widget_add_text_box_element(
- + app->widget,
- + 0,
- + 2,
- + 128,
- + 14,
- + AlignCenter,
- + AlignBottom,
- + "\e#\e! ISP Programmer \e!\n",
- + false);
- + widget_add_text_scroll_element(app->widget, 0, 16, 128, 50, furi_string_get_cstr(temp_str));
- + furi_string_free(temp_str);
- +
- + view_dispatcher_switch_to_view(app->view_dispatcher, AvrIspViewWidget);
- +}
- +
- +bool avr_isp_scene_about_on_event(void* context, SceneManagerEvent event) {
- + UNUSED(context);
- + UNUSED(event);
- + return false;
- +}
- +
- +void avr_isp_scene_about_on_exit(void* context) {
- + furi_assert(context);
- +
- + AvrIspApp* app = context;
- + // Clear views
- + widget_reset(app->widget);
- +}
- 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
- new file mode 100644
- index 000000000..79c239390
- --- /dev/null
- +++ b/applications/external/avr_isp_programmer/scenes/avr_isp_scene_chip_detect.c
- @@ -0,0 +1,72 @@
- +#include "../avr_isp_app_i.h"
- +
- +void avr_isp_scene_chip_detect_callback(AvrIspCustomEvent event, void* context) {
- + furi_assert(context);
- +
- + AvrIspApp* app = context;
- + view_dispatcher_send_custom_event(app->view_dispatcher, event);
- +}
- +
- +void avr_isp_scene_chip_detect_on_enter(void* context) {
- + furi_assert(context);
- +
- + AvrIspApp* app = context;
- + switch(app->error) {
- + case AvrIspErrorReading:
- + case AvrIspErrorWriting:
- + case AvrIspErrorWritingFuse:
- + avr_isp_chip_detect_set_state(
- + app->avr_isp_chip_detect_view, AvrIspChipDetectViewStateErrorOccured);
- + break;
- + case AvrIspErrorVerification:
- + avr_isp_chip_detect_set_state(
- + app->avr_isp_chip_detect_view, AvrIspChipDetectViewStateErrorVerification);
- + break;
- +
- + default:
- + avr_isp_chip_detect_set_state(
- + app->avr_isp_chip_detect_view, AvrIspChipDetectViewStateNoDetect);
- + break;
- + }
- + app->error = AvrIspErrorNoError;
- + avr_isp_chip_detect_view_set_callback(
- + app->avr_isp_chip_detect_view, avr_isp_scene_chip_detect_callback, app);
- +
- + view_dispatcher_switch_to_view(app->view_dispatcher, AvrIspViewChipDetect);
- +}
- +
- +bool avr_isp_scene_chip_detect_on_event(void* context, SceneManagerEvent event) {
- + furi_assert(context);
- +
- + AvrIspApp* app = context;
- + bool consumed = false;
- + if(event.type == SceneManagerEventTypeCustom) {
- + switch(event.event) {
- + case AvrIspCustomEventSceneChipDetectOk:
- +
- + if(scene_manager_get_scene_state(app->scene_manager, AvrIspSceneChipDetect) ==
- + AvrIspViewProgrammer) {
- + scene_manager_next_scene(app->scene_manager, AvrIspSceneProgrammer);
- + } else if(
- + scene_manager_get_scene_state(app->scene_manager, AvrIspSceneChipDetect) ==
- + AvrIspViewReader) {
- + scene_manager_next_scene(app->scene_manager, AvrIspSceneInputName);
- + } else if(
- + scene_manager_get_scene_state(app->scene_manager, AvrIspSceneChipDetect) ==
- + AvrIspViewWriter) {
- + scene_manager_next_scene(app->scene_manager, AvrIspSceneLoad);
- + }
- +
- + consumed = true;
- + break;
- + default:
- + break;
- + }
- + } else if(event.type == SceneManagerEventTypeTick) {
- + }
- + return consumed;
- +}
- +
- +void avr_isp_scene_chip_detect_on_exit(void* context) {
- + UNUSED(context);
- +}
- 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
- new file mode 100644
- index 000000000..6f22511db
- --- /dev/null
- +++ b/applications/external/avr_isp_programmer/scenes/avr_isp_scene_config.h
- @@ -0,0 +1,10 @@
- +ADD_SCENE(avr_isp, start, Start)
- +ADD_SCENE(avr_isp, about, About)
- +ADD_SCENE(avr_isp, programmer, Programmer)
- +ADD_SCENE(avr_isp, reader, Reader)
- +ADD_SCENE(avr_isp, input_name, InputName)
- +ADD_SCENE(avr_isp, load, Load)
- +ADD_SCENE(avr_isp, writer, Writer)
- +ADD_SCENE(avr_isp, wiring, Wiring)
- +ADD_SCENE(avr_isp, chip_detect, ChipDetect)
- +ADD_SCENE(avr_isp, success, Success)
- 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
- new file mode 100644
- index 000000000..3394f4362
- --- /dev/null
- +++ b/applications/external/avr_isp_programmer/scenes/avr_isp_scene_input_name.c
- @@ -0,0 +1,89 @@
- +#include "../avr_isp_app_i.h"
- +#include <gui/modules/validators.h>
- +
- +#define MAX_TEXT_INPUT_LEN 22
- +
- +void avr_isp_scene_input_name_text_callback(void* context) {
- + furi_assert(context);
- +
- + AvrIspApp* app = context;
- + view_dispatcher_send_custom_event(app->view_dispatcher, AvrIspCustomEventSceneInputName);
- +}
- +
- +void avr_isp_scene_input_name_get_timefilename(FuriString* name) {
- + FuriHalRtcDateTime datetime = {0};
- + furi_hal_rtc_get_datetime(&datetime);
- + furi_string_printf(
- + name,
- + "AVR_dump-%.4d%.2d%.2d-%.2d%.2d%.2d",
- + datetime.year,
- + datetime.month,
- + datetime.day,
- + datetime.hour,
- + datetime.minute,
- + datetime.second);
- +}
- +
- +void avr_isp_scene_input_name_on_enter(void* context) {
- + furi_assert(context);
- +
- + AvrIspApp* app = context;
- + // Setup view
- + TextInput* text_input = app->text_input;
- + bool dev_name_empty = false;
- +
- + FuriString* file_name = furi_string_alloc();
- +
- + avr_isp_scene_input_name_get_timefilename(file_name);
- + furi_string_set(app->file_path, STORAGE_APP_DATA_PATH_PREFIX);
- + //highlighting the entire filename by default
- + dev_name_empty = true;
- +
- + strncpy(app->file_name_tmp, furi_string_get_cstr(file_name), AVR_ISP_MAX_LEN_NAME);
- + text_input_set_header_text(text_input, "Name dump");
- + text_input_set_result_callback(
- + text_input,
- + avr_isp_scene_input_name_text_callback,
- + app,
- + app->file_name_tmp,
- + MAX_TEXT_INPUT_LEN, // buffer size
- + dev_name_empty);
- +
- + ValidatorIsFile* validator_is_file =
- + validator_is_file_alloc_init(STORAGE_APP_DATA_PATH_PREFIX, AVR_ISP_APP_EXTENSION, "");
- + text_input_set_validator(text_input, validator_is_file_callback, validator_is_file);
- +
- + furi_string_free(file_name);
- +
- + view_dispatcher_switch_to_view(app->view_dispatcher, AvrIspViewTextInput);
- +}
- +
- +bool avr_isp_scene_input_name_on_event(void* context, SceneManagerEvent event) {
- + furi_assert(context);
- +
- + AvrIspApp* app = context;
- + if(event.type == SceneManagerEventTypeBack) {
- + scene_manager_previous_scene(app->scene_manager);
- + return true;
- + } else if(event.type == SceneManagerEventTypeCustom) {
- + if(event.event == AvrIspCustomEventSceneInputName) {
- + if(strcmp(app->file_name_tmp, "") != 0) {
- + scene_manager_next_scene(app->scene_manager, AvrIspSceneReader);
- + } else {
- + }
- + }
- + }
- + return false;
- +}
- +
- +void avr_isp_scene_input_name_on_exit(void* context) {
- + furi_assert(context);
- +
- + AvrIspApp* app = context;
- + // Clear validator
- + void* validator_context = text_input_get_validator_callback_context(app->text_input);
- + text_input_set_validator(app->text_input, NULL, NULL);
- + validator_is_file_free(validator_context);
- + // Clear view
- + text_input_reset(app->text_input);
- +}
- 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
- new file mode 100644
- index 000000000..e8890e373
- --- /dev/null
- +++ b/applications/external/avr_isp_programmer/scenes/avr_isp_scene_load.c
- @@ -0,0 +1,22 @@
- +#include "../avr_isp_app_i.h"
- +
- +void avr_isp_scene_load_on_enter(void* context) {
- + furi_assert(context);
- +
- + AvrIspApp* app = context;
- + if(avr_isp_load_from_file(app)) {
- + scene_manager_next_scene(app->scene_manager, AvrIspSceneWriter);
- + } else {
- + scene_manager_previous_scene(app->scene_manager);
- + }
- +}
- +
- +bool avr_isp_scene_load_on_event(void* context, SceneManagerEvent event) {
- + UNUSED(context);
- + UNUSED(event);
- + return false;
- +}
- +
- +void avr_isp_scene_load_on_exit(void* context) {
- + UNUSED(context);
- +}
- 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
- new file mode 100644
- index 000000000..0915e1e8a
- --- /dev/null
- +++ b/applications/external/avr_isp_programmer/scenes/avr_isp_scene_programmer.c
- @@ -0,0 +1,28 @@
- +#include "../avr_isp_app_i.h"
- +
- +void avr_isp_scene_programmer_callback(AvrIspCustomEvent event, void* context) {
- + furi_assert(context);
- +
- + AvrIspApp* app = context;
- + view_dispatcher_send_custom_event(app->view_dispatcher, event);
- +}
- +
- +void avr_isp_scene_programmer_on_enter(void* context) {
- + furi_assert(context);
- +
- + AvrIspApp* app = context;
- + avr_isp_programmer_view_set_callback(
- + app->avr_isp_programmer_view, avr_isp_scene_programmer_callback, app);
- +
- + view_dispatcher_switch_to_view(app->view_dispatcher, AvrIspViewProgrammer);
- +}
- +
- +bool avr_isp_scene_programmer_on_event(void* context, SceneManagerEvent event) {
- + UNUSED(context);
- + UNUSED(event);
- + return false;
- +}
- +
- +void avr_isp_scene_programmer_on_exit(void* context) {
- + UNUSED(context);
- +}
- 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
- new file mode 100644
- index 000000000..8dcb47597
- --- /dev/null
- +++ b/applications/external/avr_isp_programmer/scenes/avr_isp_scene_reader.c
- @@ -0,0 +1,64 @@
- +#include "../avr_isp_app_i.h"
- +
- +void avr_isp_scene_reader_callback(AvrIspCustomEvent event, void* context) {
- + furi_assert(context);
- +
- + AvrIspApp* app = context;
- + view_dispatcher_send_custom_event(app->view_dispatcher, event);
- +}
- +
- +void avr_isp_scene_reader_on_enter(void* context) {
- + furi_assert(context);
- +
- + AvrIspApp* app = context;
- + avr_isp_reader_set_file_path(
- + app->avr_isp_reader_view, furi_string_get_cstr(app->file_path), app->file_name_tmp);
- + avr_isp_reader_view_set_callback(app->avr_isp_reader_view, avr_isp_scene_reader_callback, app);
- +
- + view_dispatcher_switch_to_view(app->view_dispatcher, AvrIspViewReader);
- +}
- +
- +bool avr_isp_scene_reader_on_event(void* context, SceneManagerEvent event) {
- + furi_assert(context);
- +
- + AvrIspApp* app = context;
- + UNUSED(app);
- + bool consumed = false;
- + if(event.type == SceneManagerEventTypeBack) {
- + //do not handle exit on "Back"
- + consumed = true;
- + } else if(event.type == SceneManagerEventTypeCustom) {
- + switch(event.event) {
- + case AvrIspCustomEventSceneReadingOk:
- + scene_manager_next_scene(app->scene_manager, AvrIspSceneSuccess);
- + consumed = true;
- + break;
- + case AvrIspCustomEventSceneExit:
- + scene_manager_search_and_switch_to_previous_scene(
- + app->scene_manager, AvrIspSceneChipDetect);
- + consumed = true;
- + break;
- + case AvrIspCustomEventSceneErrorVerification:
- + app->error = AvrIspErrorVerification;
- + scene_manager_search_and_switch_to_previous_scene(
- + app->scene_manager, AvrIspSceneChipDetect);
- + consumed = true;
- + break;
- + case AvrIspCustomEventSceneErrorReading:
- + app->error = AvrIspErrorReading;
- + scene_manager_search_and_switch_to_previous_scene(
- + app->scene_manager, AvrIspSceneChipDetect);
- + consumed = true;
- + break;
- + default:
- + break;
- + }
- + } else if(event.type == SceneManagerEventTypeTick) {
- + avr_isp_reader_update_progress(app->avr_isp_reader_view);
- + }
- + return consumed;
- +}
- +
- +void avr_isp_scene_reader_on_exit(void* context) {
- + UNUSED(context);
- +}
- 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
- new file mode 100644
- index 000000000..b00bfefce
- --- /dev/null
- +++ b/applications/external/avr_isp_programmer/scenes/avr_isp_scene_start.c
- @@ -0,0 +1,75 @@
- +#include "../avr_isp_app_i.h"
- +
- +void avr_isp_scene_start_submenu_callback(void* context, uint32_t index) {
- + furi_assert(context);
- + AvrIspApp* app = context;
- +
- + view_dispatcher_send_custom_event(app->view_dispatcher, index);
- +}
- +
- +void avr_isp_scene_start_on_enter(void* context) {
- + furi_assert(context);
- +
- + AvrIspApp* app = context;
- + Submenu* submenu = app->submenu;
- + submenu_add_item(
- + submenu, "Dump AVR", SubmenuIndexAvrIspReader, avr_isp_scene_start_submenu_callback, app);
- + submenu_add_item(
- + submenu, "Flash AVR", SubmenuIndexAvrIspWriter, avr_isp_scene_start_submenu_callback, app);
- + submenu_add_item(
- + submenu,
- + "ISP Programmer",
- + SubmenuIndexAvrIspProgrammer,
- + avr_isp_scene_start_submenu_callback,
- + app);
- + submenu_add_item(
- + submenu, "Wiring", SubmenuIndexAvrIsWiring, avr_isp_scene_start_submenu_callback, app);
- + submenu_add_item(
- + submenu, "About", SubmenuIndexAvrIspAbout, avr_isp_scene_start_submenu_callback, app);
- +
- + submenu_set_selected_item(
- + submenu, scene_manager_get_scene_state(app->scene_manager, AvrIspSceneStart));
- +
- + view_dispatcher_switch_to_view(app->view_dispatcher, AvrIspViewSubmenu);
- +}
- +
- +bool avr_isp_scene_start_on_event(void* context, SceneManagerEvent event) {
- + furi_assert(context);
- +
- + AvrIspApp* app = context;
- + bool consumed = false;
- + if(event.type == SceneManagerEventTypeCustom) {
- + if(event.event == SubmenuIndexAvrIspAbout) {
- + scene_manager_next_scene(app->scene_manager, AvrIspSceneAbout);
- + consumed = true;
- + } else if(event.event == SubmenuIndexAvrIspProgrammer) {
- + scene_manager_set_scene_state(
- + app->scene_manager, AvrIspSceneChipDetect, AvrIspViewProgrammer);
- + scene_manager_next_scene(app->scene_manager, AvrIspSceneChipDetect);
- + consumed = true;
- + } else if(event.event == SubmenuIndexAvrIspReader) {
- + scene_manager_set_scene_state(
- + app->scene_manager, AvrIspSceneChipDetect, AvrIspViewReader);
- + scene_manager_next_scene(app->scene_manager, AvrIspSceneChipDetect);
- + consumed = true;
- + } else if(event.event == SubmenuIndexAvrIspWriter) {
- + scene_manager_set_scene_state(
- + app->scene_manager, AvrIspSceneChipDetect, AvrIspViewWriter);
- + scene_manager_next_scene(app->scene_manager, AvrIspSceneChipDetect);
- + consumed = true;
- + } else if(event.event == SubmenuIndexAvrIsWiring) {
- + scene_manager_next_scene(app->scene_manager, AvrIspSceneWiring);
- + consumed = true;
- + }
- + scene_manager_set_scene_state(app->scene_manager, AvrIspSceneStart, event.event);
- + }
- +
- + return consumed;
- +}
- +
- +void avr_isp_scene_start_on_exit(void* context) {
- + furi_assert(context);
- +
- + AvrIspApp* app = context;
- + submenu_reset(app->submenu);
- +}
- 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
- new file mode 100644
- index 000000000..a88ed28aa
- --- /dev/null
- +++ b/applications/external/avr_isp_programmer/scenes/avr_isp_scene_success.c
- @@ -0,0 +1,44 @@
- +#include "../avr_isp_app_i.h"
- +
- +void avr_isp_scene_success_popup_callback(void* context) {
- + furi_assert(context);
- +
- + AvrIspApp* app = context;
- + view_dispatcher_send_custom_event(app->view_dispatcher, AvrIspCustomEventSceneSuccess);
- +}
- +
- +void avr_isp_scene_success_on_enter(void* context) {
- + furi_assert(context);
- +
- + AvrIspApp* app = context;
- + Popup* popup = app->popup;
- + popup_set_icon(popup, 32, 5, &I_dolphin_nice_96x59);
- + popup_set_header(popup, "Success!", 8, 22, AlignLeft, AlignBottom);
- + popup_set_timeout(popup, 1500);
- + popup_set_context(popup, app);
- + popup_set_callback(popup, avr_isp_scene_success_popup_callback);
- + popup_enable_timeout(popup);
- + view_dispatcher_switch_to_view(app->view_dispatcher, AvrIspViewPopup);
- +}
- +
- +bool avr_isp_scene_success_on_event(void* context, SceneManagerEvent event) {
- + furi_assert(context);
- +
- + AvrIspApp* app = context;
- + if(event.type == SceneManagerEventTypeCustom) {
- + if(event.event == AvrIspCustomEventSceneSuccess) {
- + scene_manager_search_and_switch_to_previous_scene(
- + app->scene_manager, AvrIspSceneStart);
- + return true;
- + }
- + }
- + return false;
- +}
- +
- +void avr_isp_scene_success_on_exit(void* context) {
- + furi_assert(context);
- +
- + AvrIspApp* app = context;
- + Popup* popup = app->popup;
- + popup_reset(popup);
- +}
- 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
- new file mode 100644
- index 000000000..787ed5673
- --- /dev/null
- +++ b/applications/external/avr_isp_programmer/scenes/avr_isp_scene_wiring.c
- @@ -0,0 +1,21 @@
- +#include "../avr_isp_app_i.h"
- +
- +void avr_isp_scene_wiring_on_enter(void* context) {
- + furi_assert(context);
- +
- + AvrIspApp* app = context;
- + widget_add_icon_element(app->widget, 0, 0, &I_avr_wiring);
- + view_dispatcher_switch_to_view(app->view_dispatcher, AvrIspViewWidget);
- +}
- +
- +bool avr_isp_scene_wiring_on_event(void* context, SceneManagerEvent event) {
- + UNUSED(context);
- + UNUSED(event);
- + return false;
- +}
- +void avr_isp_scene_wiring_on_exit(void* context) {
- + furi_assert(context);
- +
- + AvrIspApp* app = context;
- + widget_reset(app->widget);
- +}
- 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
- new file mode 100644
- index 000000000..39c944fd5
- --- /dev/null
- +++ b/applications/external/avr_isp_programmer/scenes/avr_isp_scene_writer.c
- @@ -0,0 +1,69 @@
- +#include "../avr_isp_app_i.h"
- +
- +void avr_isp_scene_writer_callback(AvrIspCustomEvent event, void* context) {
- + furi_assert(context);
- +
- + AvrIspApp* app = context;
- + view_dispatcher_send_custom_event(app->view_dispatcher, event);
- +}
- +
- +void avr_isp_scene_writer_on_enter(void* context) {
- + furi_assert(context);
- +
- + AvrIspApp* app = context;
- + avr_isp_writer_set_file_path(
- + app->avr_isp_writer_view, furi_string_get_cstr(app->file_path), app->file_name_tmp);
- + avr_isp_writer_view_set_callback(app->avr_isp_writer_view, avr_isp_scene_writer_callback, app);
- + view_dispatcher_switch_to_view(app->view_dispatcher, AvrIspViewWriter);
- +}
- +
- +bool avr_isp_scene_writer_on_event(void* context, SceneManagerEvent event) {
- + furi_assert(context);
- +
- + AvrIspApp* app = context;
- + bool consumed = false;
- + if(event.type == SceneManagerEventTypeBack) {
- + //do not handle exit on "Back"
- + consumed = true;
- + } else if(event.type == SceneManagerEventTypeCustom) {
- + switch(event.event) {
- + case AvrIspCustomEventSceneExitStartMenu:
- + scene_manager_search_and_switch_to_previous_scene(
- + app->scene_manager, AvrIspSceneStart);
- + consumed = true;
- + break;
- + case AvrIspCustomEventSceneExit:
- + scene_manager_search_and_switch_to_previous_scene(
- + app->scene_manager, AvrIspSceneChipDetect);
- + consumed = true;
- + break;
- + case AvrIspCustomEventSceneErrorVerification:
- + app->error = AvrIspErrorVerification;
- + scene_manager_search_and_switch_to_previous_scene(
- + app->scene_manager, AvrIspSceneChipDetect);
- + consumed = true;
- + break;
- + case AvrIspCustomEventSceneErrorWriting:
- + app->error = AvrIspErrorWriting;
- + scene_manager_search_and_switch_to_previous_scene(
- + app->scene_manager, AvrIspSceneChipDetect);
- + consumed = true;
- + break;
- + case AvrIspCustomEventSceneErrorWritingFuse:
- + app->error = AvrIspErrorWritingFuse;
- + scene_manager_search_and_switch_to_previous_scene(
- + app->scene_manager, AvrIspSceneChipDetect);
- + consumed = true;
- + break;
- + default:
- + break;
- + }
- + } else if(event.type == SceneManagerEventTypeTick) {
- + avr_isp_writer_update_progress(app->avr_isp_writer_view);
- + }
- + return consumed;
- +}
- +
- +void avr_isp_scene_writer_on_exit(void* context) {
- + UNUSED(context);
- +}
- 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
- new file mode 100644
- index 000000000..fdcf71c36
- --- /dev/null
- +++ b/applications/external/avr_isp_programmer/views/avr_isp_view_chip_detect.c
- @@ -0,0 +1,213 @@
- +#include "avr_isp_view_chip_detect.h"
- +#include <avr_isp_icons.h>
- +#include <gui/elements.h>
- +
- +#include "../helpers/avr_isp_worker_rw.h"
- +
- +struct AvrIspChipDetectView {
- + View* view;
- + AvrIspWorkerRW* avr_isp_worker_rw;
- + AvrIspChipDetectViewCallback callback;
- + void* context;
- +};
- +
- +typedef struct {
- + uint16_t idx;
- + const char* name_chip;
- + uint32_t flash_size;
- + AvrIspChipDetectViewState state;
- +} AvrIspChipDetectViewModel;
- +
- +void avr_isp_chip_detect_view_set_callback(
- + AvrIspChipDetectView* instance,
- + AvrIspChipDetectViewCallback callback,
- + void* context) {
- + furi_assert(instance);
- + furi_assert(callback);
- +
- + instance->callback = callback;
- + instance->context = context;
- +}
- +
- +void avr_isp_chip_detect_set_state(AvrIspChipDetectView* instance, AvrIspChipDetectViewState state) {
- + furi_assert(instance);
- +
- + with_view_model(
- + instance->view, AvrIspChipDetectViewModel * model, { model->state = state; }, true);
- +}
- +
- +void avr_isp_chip_detect_view_draw(Canvas* canvas, AvrIspChipDetectViewModel* model) {
- + canvas_clear(canvas);
- +
- + char str_buf[64] = {0};
- + canvas_set_font(canvas, FontPrimary);
- +
- + switch(model->state) {
- + case AvrIspChipDetectViewStateDetected:
- + canvas_draw_str_aligned(canvas, 64, 5, AlignCenter, AlignCenter, "AVR chip detected!");
- + canvas_draw_icon(canvas, 29, 14, &I_chip_long_70x22);
- + canvas_set_font(canvas, FontSecondary);
- + snprintf(str_buf, sizeof(str_buf), "%ld Kb", model->flash_size / 1024);
- + canvas_draw_str_aligned(canvas, 64, 25, AlignCenter, AlignCenter, str_buf);
- + canvas_draw_str_aligned(canvas, 64, 45, AlignCenter, AlignCenter, model->name_chip);
- + elements_button_right(canvas, "Next");
- + break;
- + case AvrIspChipDetectViewStateErrorOccured:
- + canvas_draw_str_aligned(
- + canvas, 64, 5, AlignCenter, AlignCenter, "Error occured, try again!");
- + canvas_draw_icon(canvas, 29, 14, &I_chip_error_70x22);
- + canvas_set_font(canvas, FontSecondary);
- + canvas_draw_str_aligned(
- + canvas, 64, 45, AlignCenter, AlignCenter, "Check the wiring and retry");
- + break;
- + case AvrIspChipDetectViewStateErrorVerification:
- + canvas_draw_str_aligned(
- + canvas, 64, 5, AlignCenter, AlignCenter, "Data verification failed");
- + canvas_draw_icon(canvas, 29, 14, &I_chip_error_70x22);
- + canvas_set_font(canvas, FontSecondary);
- + canvas_draw_str_aligned(
- + canvas, 64, 45, AlignCenter, AlignCenter, "Try to restart the process");
- + break;
- +
- + default:
- + //AvrIspChipDetectViewStateNoDetect
- + canvas_draw_str_aligned(canvas, 64, 5, AlignCenter, AlignCenter, "AVR chip not found!");
- + canvas_draw_icon(canvas, 29, 12, &I_chif_not_found_83x37);
- +
- + break;
- + }
- + canvas_set_font(canvas, FontSecondary);
- + elements_button_left(canvas, "Retry");
- +}
- +
- +bool avr_isp_chip_detect_view_input(InputEvent* event, void* context) {
- + furi_assert(context);
- +
- + AvrIspChipDetectView* instance = context;
- +
- + if(event->type == InputTypeShort) {
- + if(event->key == InputKeyBack) {
- + return false;
- + } else if(event->key == InputKeyRight) {
- + with_view_model(
- + instance->view,
- + AvrIspChipDetectViewModel * model,
- + {
- + if(model->state == AvrIspChipDetectViewStateDetected) {
- + if(instance->callback)
- + instance->callback(
- + AvrIspCustomEventSceneChipDetectOk, instance->context);
- + }
- + },
- + false);
- +
- + } else if(event->key == InputKeyLeft) {
- + bool detect_chip = false;
- + with_view_model(
- + instance->view,
- + AvrIspChipDetectViewModel * model,
- + {
- + if(model->state != AvrIspChipDetectViewStateDetecting) {
- + model->state = AvrIspChipDetectViewStateDetecting;
- + detect_chip = true;
- + }
- + },
- + false);
- + if(detect_chip) avr_isp_worker_rw_detect_chip(instance->avr_isp_worker_rw);
- + }
- + } else {
- + return false;
- + }
- +
- + return true;
- +}
- +
- +static void avr_isp_chip_detect_detect_chip_callback(
- + void* context,
- + const char* name,
- + bool detect_chip,
- + uint32_t flash_size) {
- + furi_assert(context);
- +
- + AvrIspChipDetectView* instance = context;
- + with_view_model(
- + instance->view,
- + AvrIspChipDetectViewModel * model,
- + {
- + model->name_chip = name;
- + model->flash_size = flash_size;
- + if(detect_chip) {
- + model->state = AvrIspChipDetectViewStateDetected;
- + } else {
- + model->state = AvrIspChipDetectViewStateNoDetect;
- + }
- + },
- + true);
- +}
- +void avr_isp_chip_detect_view_enter(void* context) {
- + furi_assert(context);
- +
- + AvrIspChipDetectView* instance = context;
- + bool detect_chip = false;
- + with_view_model(
- + instance->view,
- + AvrIspChipDetectViewModel * model,
- + {
- + if(model->state == AvrIspChipDetectViewStateNoDetect ||
- + model->state == AvrIspChipDetectViewStateDetected) {
- + detect_chip = true;
- + }
- + },
- + false);
- +
- + //Start avr_isp_worker_rw
- + instance->avr_isp_worker_rw = avr_isp_worker_rw_alloc(instance->context);
- +
- + avr_isp_worker_rw_set_callback(
- + instance->avr_isp_worker_rw, avr_isp_chip_detect_detect_chip_callback, instance);
- +
- + if(detect_chip) avr_isp_worker_rw_detect_chip(instance->avr_isp_worker_rw);
- +}
- +
- +void avr_isp_chip_detect_view_exit(void* context) {
- + furi_assert(context);
- +
- + AvrIspChipDetectView* instance = context;
- +
- + avr_isp_worker_rw_set_callback(instance->avr_isp_worker_rw, NULL, NULL);
- + avr_isp_worker_rw_free(instance->avr_isp_worker_rw);
- +}
- +
- +AvrIspChipDetectView* avr_isp_chip_detect_view_alloc() {
- + AvrIspChipDetectView* instance = malloc(sizeof(AvrIspChipDetectView));
- +
- + // View allocation and configuration
- + instance->view = view_alloc();
- +
- + view_allocate_model(instance->view, ViewModelTypeLocking, sizeof(AvrIspChipDetectViewModel));
- + view_set_context(instance->view, instance);
- + view_set_draw_callback(instance->view, (ViewDrawCallback)avr_isp_chip_detect_view_draw);
- + view_set_input_callback(instance->view, avr_isp_chip_detect_view_input);
- + view_set_enter_callback(instance->view, avr_isp_chip_detect_view_enter);
- + view_set_exit_callback(instance->view, avr_isp_chip_detect_view_exit);
- +
- + with_view_model(
- + instance->view,
- + AvrIspChipDetectViewModel * model,
- + { model->state = AvrIspChipDetectViewStateNoDetect; },
- + false);
- + return instance;
- +}
- +
- +void avr_isp_chip_detect_view_free(AvrIspChipDetectView* instance) {
- + furi_assert(instance);
- +
- + view_free(instance->view);
- + free(instance);
- +}
- +
- +View* avr_isp_chip_detect_view_get_view(AvrIspChipDetectView* instance) {
- + furi_assert(instance);
- +
- + return instance->view;
- +}
- 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
- new file mode 100644
- index 000000000..37f2ae233
- --- /dev/null
- +++ b/applications/external/avr_isp_programmer/views/avr_isp_view_chip_detect.h
- @@ -0,0 +1,32 @@
- +#pragma once
- +
- +#include <gui/view.h>
- +#include "../helpers/avr_isp_types.h"
- +#include "../helpers/avr_isp_event.h"
- +
- +typedef struct AvrIspChipDetectView AvrIspChipDetectView;
- +
- +typedef void (*AvrIspChipDetectViewCallback)(AvrIspCustomEvent event, void* context);
- +
- +typedef enum {
- + AvrIspChipDetectViewStateNoDetect,
- + AvrIspChipDetectViewStateDetecting,
- + AvrIspChipDetectViewStateDetected,
- + AvrIspChipDetectViewStateErrorOccured,
- + AvrIspChipDetectViewStateErrorVerification,
- +} AvrIspChipDetectViewState;
- +
- +void avr_isp_chip_detect_view_set_callback(
- + AvrIspChipDetectView* instance,
- + AvrIspChipDetectViewCallback callback,
- + void* context);
- +
- +void avr_isp_chip_detect_set_state(AvrIspChipDetectView* instance, AvrIspChipDetectViewState state);
- +
- +AvrIspChipDetectView* avr_isp_chip_detect_view_alloc();
- +
- +void avr_isp_chip_detect_view_free(AvrIspChipDetectView* instance);
- +
- +View* avr_isp_chip_detect_view_get_view(AvrIspChipDetectView* instance);
- +
- +void avr_isp_chip_detect_view_exit(void* context);
- 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
- new file mode 100644
- index 000000000..34e18770b
- --- /dev/null
- +++ b/applications/external/avr_isp_programmer/views/avr_isp_view_programmer.c
- @@ -0,0 +1,134 @@
- +#include "avr_isp_view_programmer.h"
- +#include <avr_isp_icons.h>
- +
- +#include "../helpers/avr_isp_worker.h"
- +#include <gui/elements.h>
- +
- +struct AvrIspProgrammerView {
- + View* view;
- + AvrIspWorker* worker;
- + AvrIspProgrammerViewCallback callback;
- + void* context;
- +};
- +
- +typedef struct {
- + AvrIspProgrammerViewStatus status;
- +} AvrIspProgrammerViewModel;
- +
- +void avr_isp_programmer_view_set_callback(
- + AvrIspProgrammerView* instance,
- + AvrIspProgrammerViewCallback callback,
- + void* context) {
- + furi_assert(instance);
- + furi_assert(callback);
- +
- + instance->callback = callback;
- + instance->context = context;
- +}
- +
- +void avr_isp_programmer_view_draw(Canvas* canvas, AvrIspProgrammerViewModel* model) {
- + canvas_clear(canvas);
- +
- + if(model->status == AvrIspProgrammerViewStatusUSBConnect) {
- + canvas_set_font(canvas, FontPrimary);
- + canvas_draw_icon(canvas, 0, 0, &I_isp_active_128x53);
- + elements_multiline_text(canvas, 45, 10, "ISP mode active");
- + } else {
- + canvas_set_font(canvas, FontSecondary);
- + canvas_draw_icon(canvas, 51, 6, &I_link_waiting_77x56);
- + elements_multiline_text(canvas, 0, 25, "Waiting for\nsoftware\nconnection");
- + }
- +}
- +
- +bool avr_isp_programmer_view_input(InputEvent* event, void* context) {
- + furi_assert(context);
- + UNUSED(context);
- +
- + if(event->key == InputKeyBack || event->type != InputTypeShort) {
- + return false;
- + }
- +
- + return true;
- +}
- +
- +static void avr_isp_programmer_usb_connect_callback(void* context, bool status_connect) {
- + furi_assert(context);
- + AvrIspProgrammerView* instance = context;
- +
- + with_view_model(
- + instance->view,
- + AvrIspProgrammerViewModel * model,
- + {
- + if(status_connect) {
- + model->status = AvrIspProgrammerViewStatusUSBConnect;
- + } else {
- + model->status = AvrIspProgrammerViewStatusNoUSBConnect;
- + }
- + },
- + true);
- +}
- +
- +void avr_isp_programmer_view_enter(void* context) {
- + furi_assert(context);
- +
- + AvrIspProgrammerView* instance = context;
- + with_view_model(
- + instance->view,
- + AvrIspProgrammerViewModel * model,
- + { model->status = AvrIspProgrammerViewStatusNoUSBConnect; },
- + true);
- +
- + //Start worker
- + instance->worker = avr_isp_worker_alloc(instance->context);
- +
- + avr_isp_worker_set_callback(
- + instance->worker, avr_isp_programmer_usb_connect_callback, instance);
- +
- + avr_isp_worker_start(instance->worker);
- +}
- +
- +void avr_isp_programmer_view_exit(void* context) {
- + furi_assert(context);
- +
- + AvrIspProgrammerView* instance = context;
- + //Stop worker
- + if(avr_isp_worker_is_running(instance->worker)) {
- + avr_isp_worker_stop(instance->worker);
- + }
- + avr_isp_worker_set_callback(instance->worker, NULL, NULL);
- + avr_isp_worker_free(instance->worker);
- +}
- +
- +AvrIspProgrammerView* avr_isp_programmer_view_alloc() {
- + AvrIspProgrammerView* instance = malloc(sizeof(AvrIspProgrammerView));
- +
- + // View allocation and configuration
- + instance->view = view_alloc();
- +
- + view_allocate_model(instance->view, ViewModelTypeLocking, sizeof(AvrIspProgrammerViewModel));
- + view_set_context(instance->view, instance);
- + view_set_draw_callback(instance->view, (ViewDrawCallback)avr_isp_programmer_view_draw);
- + view_set_input_callback(instance->view, avr_isp_programmer_view_input);
- + view_set_enter_callback(instance->view, avr_isp_programmer_view_enter);
- + view_set_exit_callback(instance->view, avr_isp_programmer_view_exit);
- +
- + with_view_model(
- + instance->view,
- + AvrIspProgrammerViewModel * model,
- + { model->status = AvrIspProgrammerViewStatusNoUSBConnect; },
- + false);
- + return instance;
- +}
- +
- +void avr_isp_programmer_view_free(AvrIspProgrammerView* instance) {
- + furi_assert(instance);
- +
- + view_free(instance->view);
- + free(instance);
- +}
- +
- +View* avr_isp_programmer_view_get_view(AvrIspProgrammerView* instance) {
- + furi_assert(instance);
- +
- + return instance->view;
- +}
- 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
- new file mode 100644
- index 000000000..9f005b026
- --- /dev/null
- +++ b/applications/external/avr_isp_programmer/views/avr_isp_view_programmer.h
- @@ -0,0 +1,27 @@
- +#pragma once
- +
- +#include <gui/view.h>
- +#include "../helpers/avr_isp_types.h"
- +#include "../helpers/avr_isp_event.h"
- +
- +typedef struct AvrIspProgrammerView AvrIspProgrammerView;
- +
- +typedef void (*AvrIspProgrammerViewCallback)(AvrIspCustomEvent event, void* context);
- +
- +typedef enum {
- + AvrIspProgrammerViewStatusNoUSBConnect,
- + AvrIspProgrammerViewStatusUSBConnect,
- +} AvrIspProgrammerViewStatus;
- +
- +void avr_isp_programmer_view_set_callback(
- + AvrIspProgrammerView* instance,
- + AvrIspProgrammerViewCallback callback,
- + void* context);
- +
- +AvrIspProgrammerView* avr_isp_programmer_view_alloc();
- +
- +void avr_isp_programmer_view_free(AvrIspProgrammerView* instance);
- +
- +View* avr_isp_programmer_view_get_view(AvrIspProgrammerView* instance);
- +
- +void avr_isp_programmer_view_exit(void* context);
- 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
- new file mode 100644
- index 000000000..92d15bd7f
- --- /dev/null
- +++ b/applications/external/avr_isp_programmer/views/avr_isp_view_reader.c
- @@ -0,0 +1,215 @@
- +#include "avr_isp_view_reader.h"
- +#include <gui/elements.h>
- +
- +#include "../helpers/avr_isp_worker_rw.h"
- +
- +struct AvrIspReaderView {
- + View* view;
- + AvrIspWorkerRW* avr_isp_worker_rw;
- + const char* file_path;
- + const char* file_name;
- + AvrIspReaderViewCallback callback;
- + void* context;
- +};
- +
- +typedef struct {
- + AvrIspReaderViewStatus status;
- + float progress_flash;
- + float progress_eeprom;
- +} AvrIspReaderViewModel;
- +
- +void avr_isp_reader_update_progress(AvrIspReaderView* instance) {
- + with_view_model(
- + instance->view,
- + AvrIspReaderViewModel * model,
- + {
- + model->progress_flash =
- + avr_isp_worker_rw_get_progress_flash(instance->avr_isp_worker_rw);
- + model->progress_eeprom =
- + avr_isp_worker_rw_get_progress_eeprom(instance->avr_isp_worker_rw);
- + },
- + true);
- +}
- +
- +void avr_isp_reader_view_set_callback(
- + AvrIspReaderView* instance,
- + AvrIspReaderViewCallback callback,
- + void* context) {
- + furi_assert(instance);
- + furi_assert(callback);
- +
- + instance->callback = callback;
- + instance->context = context;
- +}
- +
- +void avr_isp_reader_set_file_path(
- + AvrIspReaderView* instance,
- + const char* file_path,
- + const char* file_name) {
- + furi_assert(instance);
- +
- + instance->file_path = file_path;
- + instance->file_name = file_name;
- +}
- +
- +void avr_isp_reader_view_draw(Canvas* canvas, AvrIspReaderViewModel* model) {
- + canvas_clear(canvas);
- + char str_buf[64] = {0};
- +
- + canvas_set_font(canvas, FontPrimary);
- + switch(model->status) {
- + case AvrIspReaderViewStatusIDLE:
- + canvas_draw_str_aligned(canvas, 64, 5, AlignCenter, AlignCenter, "Press start to dump");
- + canvas_set_font(canvas, FontSecondary);
- + elements_button_center(canvas, "Start");
- + break;
- + case AvrIspReaderViewStatusReading:
- + canvas_draw_str_aligned(canvas, 64, 5, AlignCenter, AlignCenter, "Reading dump");
- + break;
- + case AvrIspReaderViewStatusVerification:
- + canvas_draw_str_aligned(canvas, 64, 5, AlignCenter, AlignCenter, "Verifyng dump");
- + break;
- +
- + default:
- + break;
- + }
- +
- + canvas_set_font(canvas, FontSecondary);
- + canvas_draw_str(canvas, 0, 27, "Flash");
- + snprintf(str_buf, sizeof(str_buf), "%d%%", (uint8_t)(model->progress_flash * 100));
- + elements_progress_bar_with_text(canvas, 44, 17, 84, model->progress_flash, str_buf);
- + canvas_draw_str(canvas, 0, 43, "EEPROM");
- + snprintf(str_buf, sizeof(str_buf), "%d%%", (uint8_t)(model->progress_eeprom * 100));
- + elements_progress_bar_with_text(canvas, 44, 34, 84, model->progress_eeprom, str_buf);
- +}
- +
- +bool avr_isp_reader_view_input(InputEvent* event, void* context) {
- + furi_assert(context);
- + AvrIspReaderView* instance = context;
- +
- + bool ret = true;
- + if(event->key == InputKeyBack && event->type == InputTypeShort) {
- + with_view_model(
- + instance->view,
- + AvrIspReaderViewModel * model,
- + {
- + if(model->status == AvrIspReaderViewStatusIDLE) {
- + if(instance->callback)
- + instance->callback(AvrIspCustomEventSceneExit, instance->context);
- + ret = false;
- + }
- + },
- + false);
- + } else if(event->key == InputKeyOk && event->type == InputTypeShort) {
- + with_view_model(
- + instance->view,
- + AvrIspReaderViewModel * model,
- + {
- + if(model->status == AvrIspReaderViewStatusIDLE) {
- + model->status = AvrIspReaderViewStatusReading;
- + avr_isp_worker_rw_read_dump_start(
- + instance->avr_isp_worker_rw, instance->file_path, instance->file_name);
- + }
- + },
- + false);
- + }
- + return ret;
- +}
- +
- +static void avr_isp_reader_callback_status(void* context, AvrIspWorkerRWStatus status) {
- + furi_assert(context);
- + AvrIspReaderView* instance = context;
- +
- + with_view_model(
- + instance->view,
- + AvrIspReaderViewModel * model,
- + {
- + switch(status) {
- + case AvrIspWorkerRWStatusEndReading:
- + model->status = AvrIspReaderViewStatusVerification;
- + avr_isp_worker_rw_verification_start(
- + instance->avr_isp_worker_rw, instance->file_path, instance->file_name);
- + model->status = AvrIspReaderViewStatusVerification;
- + break;
- + case AvrIspWorkerRWStatusEndVerification:
- + if(instance->callback)
- + instance->callback(AvrIspCustomEventSceneReadingOk, instance->context);
- + break;
- + case AvrIspWorkerRWStatusErrorVerification:
- + if(instance->callback)
- + instance->callback(AvrIspCustomEventSceneErrorVerification, instance->context);
- + break;
- +
- + default:
- + //AvrIspWorkerRWStatusErrorReading;
- + if(instance->callback)
- + instance->callback(AvrIspCustomEventSceneErrorReading, instance->context);
- + break;
- + }
- + },
- + true);
- +}
- +
- +void avr_isp_reader_view_enter(void* context) {
- + furi_assert(context);
- + AvrIspReaderView* instance = context;
- +
- + with_view_model(
- + instance->view,
- + AvrIspReaderViewModel * model,
- + {
- + model->status = AvrIspReaderViewStatusIDLE;
- + model->progress_flash = 0.0f;
- + model->progress_eeprom = 0.0f;
- + },
- + true);
- +
- + //Start avr_isp_worker_rw
- + instance->avr_isp_worker_rw = avr_isp_worker_rw_alloc(instance->context);
- +
- + avr_isp_worker_rw_set_callback_status(
- + instance->avr_isp_worker_rw, avr_isp_reader_callback_status, instance);
- +
- + avr_isp_worker_rw_start(instance->avr_isp_worker_rw);
- +}
- +
- +void avr_isp_reader_view_exit(void* context) {
- + furi_assert(context);
- +
- + AvrIspReaderView* instance = context;
- + //Stop avr_isp_worker_rw
- + if(avr_isp_worker_rw_is_running(instance->avr_isp_worker_rw)) {
- + avr_isp_worker_rw_stop(instance->avr_isp_worker_rw);
- + }
- +
- + avr_isp_worker_rw_free(instance->avr_isp_worker_rw);
- +}
- +
- +AvrIspReaderView* avr_isp_reader_view_alloc() {
- + AvrIspReaderView* instance = malloc(sizeof(AvrIspReaderView));
- +
- + // View allocation and configuration
- + instance->view = view_alloc();
- +
- + view_allocate_model(instance->view, ViewModelTypeLocking, sizeof(AvrIspReaderViewModel));
- + view_set_context(instance->view, instance);
- + view_set_draw_callback(instance->view, (ViewDrawCallback)avr_isp_reader_view_draw);
- + view_set_input_callback(instance->view, avr_isp_reader_view_input);
- + view_set_enter_callback(instance->view, avr_isp_reader_view_enter);
- + view_set_exit_callback(instance->view, avr_isp_reader_view_exit);
- +
- + return instance;
- +}
- +
- +void avr_isp_reader_view_free(AvrIspReaderView* instance) {
- + furi_assert(instance);
- +
- + view_free(instance->view);
- + free(instance);
- +}
- +
- +View* avr_isp_reader_view_get_view(AvrIspReaderView* instance) {
- + furi_assert(instance);
- +
- + return instance->view;
- +}
- 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
- new file mode 100644
- index 000000000..44a439948
- --- /dev/null
- +++ b/applications/external/avr_isp_programmer/views/avr_isp_view_reader.h
- @@ -0,0 +1,35 @@
- +#pragma once
- +
- +#include <gui/view.h>
- +#include "../helpers/avr_isp_types.h"
- +#include "../helpers/avr_isp_event.h"
- +
- +typedef struct AvrIspReaderView AvrIspReaderView;
- +
- +typedef void (*AvrIspReaderViewCallback)(AvrIspCustomEvent event, void* context);
- +
- +typedef enum {
- + AvrIspReaderViewStatusIDLE,
- + AvrIspReaderViewStatusReading,
- + AvrIspReaderViewStatusVerification,
- +} AvrIspReaderViewStatus;
- +
- +void avr_isp_reader_update_progress(AvrIspReaderView* instance);
- +
- +void avr_isp_reader_set_file_path(
- + AvrIspReaderView* instance,
- + const char* file_path,
- + const char* file_name);
- +
- +void avr_isp_reader_view_set_callback(
- + AvrIspReaderView* instance,
- + AvrIspReaderViewCallback callback,
- + void* context);
- +
- +AvrIspReaderView* avr_isp_reader_view_alloc();
- +
- +void avr_isp_reader_view_free(AvrIspReaderView* instance);
- +
- +View* avr_isp_reader_view_get_view(AvrIspReaderView* instance);
- +
- +void avr_isp_reader_view_exit(void* context);
- 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
- new file mode 100644
- index 000000000..a06b78535
- --- /dev/null
- +++ b/applications/external/avr_isp_programmer/views/avr_isp_view_writer.c
- @@ -0,0 +1,268 @@
- +#include "avr_isp_view_writer.h"
- +#include <gui/elements.h>
- +
- +#include "../helpers/avr_isp_worker_rw.h"
- +#include <float_tools.h>
- +
- +struct AvrIspWriterView {
- + View* view;
- + AvrIspWorkerRW* avr_isp_worker_rw;
- + const char* file_path;
- + const char* file_name;
- + AvrIspWriterViewCallback callback;
- + void* context;
- +};
- +
- +typedef struct {
- + AvrIspWriterViewStatus status;
- + float progress_flash;
- + float progress_eeprom;
- +} AvrIspWriterViewModel;
- +
- +void avr_isp_writer_update_progress(AvrIspWriterView* instance) {
- + with_view_model(
- + instance->view,
- + AvrIspWriterViewModel * model,
- + {
- + model->progress_flash =
- + avr_isp_worker_rw_get_progress_flash(instance->avr_isp_worker_rw);
- + model->progress_eeprom =
- + avr_isp_worker_rw_get_progress_eeprom(instance->avr_isp_worker_rw);
- + },
- + true);
- +}
- +
- +void avr_isp_writer_view_set_callback(
- + AvrIspWriterView* instance,
- + AvrIspWriterViewCallback callback,
- + void* context) {
- + furi_assert(instance);
- + furi_assert(callback);
- +
- + instance->callback = callback;
- + instance->context = context;
- +}
- +
- +void avr_isp_writer_set_file_path(
- + AvrIspWriterView* instance,
- + const char* file_path,
- + const char* file_name) {
- + furi_assert(instance);
- +
- + instance->file_path = file_path;
- + instance->file_name = file_name;
- +}
- +
- +void avr_isp_writer_view_draw(Canvas* canvas, AvrIspWriterViewModel* model) {
- + canvas_clear(canvas);
- + char str_flash[32] = {0};
- + char str_eeprom[32] = {0};
- +
- + canvas_set_font(canvas, FontPrimary);
- +
- + switch(model->status) {
- + case AvrIspWriterViewStatusIDLE:
- + canvas_draw_str_aligned(canvas, 64, 5, AlignCenter, AlignCenter, "Press start to write");
- + canvas_set_font(canvas, FontSecondary);
- + elements_button_center(canvas, "Start");
- + snprintf(str_flash, sizeof(str_flash), "%d%%", (uint8_t)(model->progress_flash * 100));
- + snprintf(str_eeprom, sizeof(str_eeprom), "%d%%", (uint8_t)(model->progress_eeprom * 100));
- + break;
- + case AvrIspWriterViewStatusWriting:
- + if(float_is_equal(model->progress_flash, 0.f)) {
- + canvas_draw_str_aligned(canvas, 64, 5, AlignCenter, AlignCenter, "Verifying firmware");
- + snprintf(str_flash, sizeof(str_flash), "***");
- + snprintf(str_eeprom, sizeof(str_eeprom), "***");
- + } else {
- + canvas_draw_str_aligned(canvas, 64, 5, AlignCenter, AlignCenter, "Writing dump");
- + snprintf(str_flash, sizeof(str_flash), "%d%%", (uint8_t)(model->progress_flash * 100));
- + snprintf(
- + str_eeprom, sizeof(str_eeprom), "%d%%", (uint8_t)(model->progress_eeprom * 100));
- + }
- + break;
- + case AvrIspWriterViewStatusVerification:
- + canvas_draw_str_aligned(canvas, 64, 5, AlignCenter, AlignCenter, "Verifying dump");
- + snprintf(str_flash, sizeof(str_flash), "%d%%", (uint8_t)(model->progress_flash * 100));
- + snprintf(str_eeprom, sizeof(str_eeprom), "%d%%", (uint8_t)(model->progress_eeprom * 100));
- + break;
- + case AvrIspWriterViewStatusWritingFuse:
- + canvas_draw_str_aligned(canvas, 64, 5, AlignCenter, AlignCenter, "Writing fuse");
- + snprintf(str_flash, sizeof(str_flash), "%d%%", (uint8_t)(model->progress_flash * 100));
- + snprintf(str_eeprom, sizeof(str_eeprom), "%d%%", (uint8_t)(model->progress_eeprom * 100));
- + break;
- + case AvrIspWriterViewStatusWritingFuseOk:
- + canvas_draw_str_aligned(canvas, 64, 5, AlignCenter, AlignCenter, "Done!");
- + snprintf(str_flash, sizeof(str_flash), "%d%%", (uint8_t)(model->progress_flash * 100));
- + snprintf(str_eeprom, sizeof(str_eeprom), "%d%%", (uint8_t)(model->progress_eeprom * 100));
- + canvas_set_font(canvas, FontSecondary);
- + elements_button_center(canvas, "Reflash");
- + elements_button_right(canvas, "Exit");
- + break;
- +
- + default:
- + break;
- + }
- +
- + canvas_set_font(canvas, FontSecondary);
- + canvas_draw_str(canvas, 0, 27, "Flash");
- + // snprintf(str_buf, sizeof(str_buf), "%d%%", (uint8_t)(model->progress_flash * 100));
- + elements_progress_bar_with_text(canvas, 44, 17, 84, model->progress_flash, str_flash);
- + canvas_draw_str(canvas, 0, 43, "EEPROM");
- + // snprintf(str_buf, sizeof(str_buf), "%d%%", (uint8_t)(model->progress_eeprom * 100));
- + elements_progress_bar_with_text(canvas, 44, 34, 84, model->progress_eeprom, str_eeprom);
- +}
- +
- +bool avr_isp_writer_view_input(InputEvent* event, void* context) {
- + furi_assert(context);
- + AvrIspWriterView* instance = context;
- +
- + bool ret = true;
- + if(event->key == InputKeyBack && event->type == InputTypeShort) {
- + with_view_model(
- + instance->view,
- + AvrIspWriterViewModel * model,
- + {
- + if((model->status == AvrIspWriterViewStatusIDLE) ||
- + (model->status == AvrIspWriterViewStatusWritingFuseOk)) {
- + if(instance->callback)
- + instance->callback(AvrIspCustomEventSceneExit, instance->context);
- + ret = false;
- + }
- + },
- + false);
- + } else if(event->key == InputKeyOk && event->type == InputTypeShort) {
- + with_view_model(
- + instance->view,
- + AvrIspWriterViewModel * model,
- + {
- + if((model->status == AvrIspWriterViewStatusIDLE) ||
- + (model->status == AvrIspWriterViewStatusWritingFuseOk)) {
- + model->status = AvrIspWriterViewStatusWriting;
- +
- + avr_isp_worker_rw_write_dump_start(
- + instance->avr_isp_worker_rw, instance->file_path, instance->file_name);
- + }
- + },
- + false);
- + } else if(event->key == InputKeyRight && event->type == InputTypeShort) {
- + with_view_model(
- + instance->view,
- + AvrIspWriterViewModel * model,
- + {
- + if((model->status == AvrIspWriterViewStatusIDLE) ||
- + (model->status == AvrIspWriterViewStatusWritingFuseOk)) {
- + if(instance->callback)
- + instance->callback(AvrIspCustomEventSceneExitStartMenu, instance->context);
- + ret = false;
- + }
- + },
- + false);
- + }
- + return ret;
- +}
- +
- +static void avr_isp_writer_callback_status(void* context, AvrIspWorkerRWStatus status) {
- + furi_assert(context);
- +
- + AvrIspWriterView* instance = context;
- + with_view_model(
- + instance->view,
- + AvrIspWriterViewModel * model,
- + {
- + switch(status) {
- + case AvrIspWorkerRWStatusEndWriting:
- + model->status = AvrIspWriterViewStatusVerification;
- + avr_isp_worker_rw_verification_start(
- + instance->avr_isp_worker_rw, instance->file_path, instance->file_name);
- + model->status = AvrIspWriterViewStatusVerification;
- + break;
- + case AvrIspWorkerRWStatusErrorVerification:
- + if(instance->callback)
- + instance->callback(AvrIspCustomEventSceneErrorVerification, instance->context);
- + break;
- + case AvrIspWorkerRWStatusEndVerification:
- + avr_isp_worker_rw_write_fuse_start(
- + instance->avr_isp_worker_rw, instance->file_path, instance->file_name);
- + model->status = AvrIspWriterViewStatusWritingFuse;
- + break;
- + case AvrIspWorkerRWStatusErrorWritingFuse:
- + if(instance->callback)
- + instance->callback(AvrIspCustomEventSceneErrorWritingFuse, instance->context);
- + break;
- + case AvrIspWorkerRWStatusEndWritingFuse:
- + model->status = AvrIspWriterViewStatusWritingFuseOk;
- + break;
- +
- + default:
- + //AvrIspWorkerRWStatusErrorWriting;
- + if(instance->callback)
- + instance->callback(AvrIspCustomEventSceneErrorWriting, instance->context);
- + break;
- + }
- + },
- + true);
- +}
- +
- +void avr_isp_writer_view_enter(void* context) {
- + furi_assert(context);
- +
- + AvrIspWriterView* instance = context;
- + with_view_model(
- + instance->view,
- + AvrIspWriterViewModel * model,
- + {
- + model->status = AvrIspWriterViewStatusIDLE;
- + model->progress_flash = 0.0f;
- + model->progress_eeprom = 0.0f;
- + },
- + true);
- +
- + //Start avr_isp_worker_rw
- + instance->avr_isp_worker_rw = avr_isp_worker_rw_alloc(instance->context);
- +
- + avr_isp_worker_rw_set_callback_status(
- + instance->avr_isp_worker_rw, avr_isp_writer_callback_status, instance);
- +
- + avr_isp_worker_rw_start(instance->avr_isp_worker_rw);
- +}
- +
- +void avr_isp_writer_view_exit(void* context) {
- + furi_assert(context);
- + AvrIspWriterView* instance = context;
- +
- + //Stop avr_isp_worker_rw
- + if(avr_isp_worker_rw_is_running(instance->avr_isp_worker_rw)) {
- + avr_isp_worker_rw_stop(instance->avr_isp_worker_rw);
- + }
- +
- + avr_isp_worker_rw_free(instance->avr_isp_worker_rw);
- +}
- +
- +AvrIspWriterView* avr_isp_writer_view_alloc() {
- + AvrIspWriterView* instance = malloc(sizeof(AvrIspWriterView));
- +
- + // View allocation and configuration
- + instance->view = view_alloc();
- +
- + view_allocate_model(instance->view, ViewModelTypeLocking, sizeof(AvrIspWriterViewModel));
- + view_set_context(instance->view, instance);
- + view_set_draw_callback(instance->view, (ViewDrawCallback)avr_isp_writer_view_draw);
- + view_set_input_callback(instance->view, avr_isp_writer_view_input);
- + view_set_enter_callback(instance->view, avr_isp_writer_view_enter);
- + view_set_exit_callback(instance->view, avr_isp_writer_view_exit);
- +
- + return instance;
- +}
- +
- +void avr_isp_writer_view_free(AvrIspWriterView* instance) {
- + furi_assert(instance);
- +
- + view_free(instance->view);
- + free(instance);
- +}
- +
- +View* avr_isp_writer_view_get_view(AvrIspWriterView* instance) {
- + furi_assert(instance);
- +
- + return instance->view;
- +}
- 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
- new file mode 100644
- index 000000000..1ff728387
- --- /dev/null
- +++ b/applications/external/avr_isp_programmer/views/avr_isp_view_writer.h
- @@ -0,0 +1,37 @@
- +#pragma once
- +
- +#include <gui/view.h>
- +#include "../helpers/avr_isp_types.h"
- +#include "../helpers/avr_isp_event.h"
- +
- +typedef struct AvrIspWriterView AvrIspWriterView;
- +
- +typedef void (*AvrIspWriterViewCallback)(AvrIspCustomEvent event, void* context);
- +
- +typedef enum {
- + AvrIspWriterViewStatusIDLE,
- + AvrIspWriterViewStatusWriting,
- + AvrIspWriterViewStatusVerification,
- + AvrIspWriterViewStatusWritingFuse,
- + AvrIspWriterViewStatusWritingFuseOk,
- +} AvrIspWriterViewStatus;
- +
- +void avr_isp_writer_update_progress(AvrIspWriterView* instance);
- +
- +void avr_isp_writer_set_file_path(
- + AvrIspWriterView* instance,
- + const char* file_path,
- + const char* file_name);
- +
- +void avr_isp_writer_view_set_callback(
- + AvrIspWriterView* instance,
- + AvrIspWriterViewCallback callback,
- + void* context);
- +
- +AvrIspWriterView* avr_isp_writer_view_alloc();
- +
- +void avr_isp_writer_view_free(AvrIspWriterView* instance);
- +
- +View* avr_isp_writer_view_get_view(AvrIspWriterView* instance);
- +
- +void avr_isp_writer_view_exit(void* context);
- diff --git a/firmware/targets/f18/api_symbols.csv b/firmware/targets/f18/api_symbols.csv
- index 7713beb93..3806ac47b 100644
- --- a/firmware/targets/f18/api_symbols.csv
- +++ b/firmware/targets/f18/api_symbols.csv
- @@ -158,6 +158,7 @@ Header,+,lib/toolbox/args.h,,
- Header,+,lib/toolbox/crc32_calc.h,,
- Header,+,lib/toolbox/dir_walk.h,,
- Header,+,lib/toolbox/float_tools.h,,
- +Header,+,lib/toolbox/hex.h,,
- Header,+,lib/toolbox/manchester_decoder.h,,
- Header,+,lib/toolbox/manchester_encoder.h,,
- Header,+,lib/toolbox/md5.h,,
- @@ -1309,6 +1310,10 @@ Function,+,gui_view_port_send_to_front,void,"Gui*, ViewPort*"
- Function,+,hal_sd_detect,_Bool,
- Function,+,hal_sd_detect_init,void,
- Function,+,hal_sd_detect_set_low,void,
- +Function,+,hex_char_to_hex_nibble,_Bool,"char, uint8_t*"
- +Function,+,hex_char_to_uint8,_Bool,"char, char, uint8_t*"
- +Function,+,hex_chars_to_uint64,_Bool,"const char*, uint64_t*"
- +Function,+,hex_chars_to_uint8,_Bool,"const char*, uint8_t*"
- Function,+,icon_animation_alloc,IconAnimation*,const Icon*
- Function,+,icon_animation_free,void,IconAnimation*
- Function,+,icon_animation_get_height,uint8_t,const IconAnimation*
- @@ -1870,6 +1875,7 @@ Function,+,uECC_sign,int,"const uint8_t*, const uint8_t*, unsigned, uint8_t*, uE
- Function,-,uECC_sign_deterministic,int,"const uint8_t*, const uint8_t*, unsigned, const uECC_HashContext*, uint8_t*, uECC_Curve"
- Function,-,uECC_valid_public_key,int,"const uint8_t*, uECC_Curve"
- Function,-,uECC_verify,int,"const uint8_t*, const uint8_t*, unsigned, const uint8_t*, uECC_Curve"
- +Function,+,uint8_to_hex_chars,void,"const uint8_t*, uint8_t*, int"
- Function,-,ulTaskGenericNotifyTake,uint32_t,"UBaseType_t, BaseType_t, TickType_t"
- Function,-,ulTaskGenericNotifyValueClear,uint32_t,"TaskHandle_t, UBaseType_t, uint32_t"
- Function,-,ulTaskGetIdleRunTimeCounter,uint32_t,
- diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv
- index fea792680..efc20b4a7 100644
- --- a/firmware/targets/f7/api_symbols.csv
- +++ b/firmware/targets/f7/api_symbols.csv
- @@ -190,6 +190,7 @@ Header,+,lib/toolbox/args.h,,
- Header,+,lib/toolbox/crc32_calc.h,,
- Header,+,lib/toolbox/dir_walk.h,,
- Header,+,lib/toolbox/float_tools.h,,
- +Header,+,lib/toolbox/hex.h,,
- Header,+,lib/toolbox/manchester_decoder.h,,
- Header,+,lib/toolbox/manchester_encoder.h,,
- Header,+,lib/toolbox/md5.h,,
- @@ -1597,6 +1598,10 @@ Function,+,gui_view_port_send_to_front,void,"Gui*, ViewPort*"
- Function,+,hal_sd_detect,_Bool,
- Function,+,hal_sd_detect_init,void,
- Function,+,hal_sd_detect_set_low,void,
- +Function,+,hex_char_to_hex_nibble,_Bool,"char, uint8_t*"
- +Function,+,hex_char_to_uint8,_Bool,"char, char, uint8_t*"
- +Function,+,hex_chars_to_uint64,_Bool,"const char*, uint64_t*"
- +Function,+,hex_chars_to_uint8,_Bool,"const char*, uint8_t*"
- Function,-,hypot,double,"double, double"
- Function,-,hypotf,float,"float, float"
- Function,-,hypotl,long double,"long double, long double"
- @@ -2801,6 +2806,7 @@ Function,+,uECC_sign,int,"const uint8_t*, const uint8_t*, unsigned, uint8_t*, uE
- Function,-,uECC_sign_deterministic,int,"const uint8_t*, const uint8_t*, unsigned, const uECC_HashContext*, uint8_t*, uECC_Curve"
- Function,-,uECC_valid_public_key,int,"const uint8_t*, uECC_Curve"
- Function,-,uECC_verify,int,"const uint8_t*, const uint8_t*, unsigned, const uint8_t*, uECC_Curve"
- +Function,+,uint8_to_hex_chars,void,"const uint8_t*, uint8_t*, int"
- Function,-,ulTaskGenericNotifyTake,uint32_t,"UBaseType_t, BaseType_t, TickType_t"
- Function,-,ulTaskGenericNotifyValueClear,uint32_t,"TaskHandle_t, UBaseType_t, uint32_t"
- Function,-,ulTaskGetIdleRunTimeCounter,uint32_t,
- diff --git a/lib/toolbox/SConscript b/lib/toolbox/SConscript
- index fad4c5584..bb06c2db4 100644
- --- a/lib/toolbox/SConscript
- +++ b/lib/toolbox/SConscript
- @@ -28,6 +28,7 @@ env.Append(
- File("stream/buffered_file_stream.h"),
- File("protocols/protocol_dict.h"),
- File("pretty_format.h"),
- + File("hex.h"),
- ],
- )
-
|