mirror of
				https://github.com/davidgiven/fluxengine.git
				synced 2025-10-31 11:17:01 -07:00 
			
		
		
		
	Compare commits
	
		
			38 Commits
		
	
	
		
			FluxEngine
			...
			FluxEngine
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | b570e44ee4 | ||
|  | b115d0b55b | ||
|  | 529488cab0 | ||
|  | b2429a7ca3 | ||
|  | 0bce12d3b4 | ||
|  | 75f557cb18 | ||
|  | 035dd1fad1 | ||
|  | d2df79a665 | ||
|  | 103e0a13bb | ||
|  | d1b5eec84a | ||
|  | 6b1e6b31ed | ||
|  | f6f6db913e | ||
|  | ec0a6416fd | ||
|  | 1787402be9 | ||
|  | 5f6d99f138 | ||
|  | d1e2b0d1f8 | ||
|  | c2c51bbe33 | ||
|  | bb806e3853 | ||
|  | a11d0e75c8 | ||
|  | 5406ff0ea3 | ||
|  | c88317b44a | ||
|  | 6898062d66 | ||
|  | 6e1f264e6a | ||
|  | 082be14232 | ||
|  | 231aa44d03 | ||
|  | cdb12f35d4 | ||
|  | e831ee8b44 | ||
|  | 40e9a6082f | ||
|  | 53cec292d0 | ||
|  | 3f85309ee5 | ||
|  | 70944f8521 | ||
|  | 2ab00c42ff | ||
|  | a572742caa | ||
|  | 400e5f8580 | ||
|  | 74f0fd89b6 | ||
|  | 09f9bea7a2 | ||
|  | d3a5bb08d3 | ||
|  | f1506d0dbd | 
| @@ -1,246 +1,246 @@ | ||||
| :400000000080002011000000CD0F0000CD0F0000064A08B5136843F020031360044B1A6803F53F5302331A6000F0EEFFE8460040FA46004010B5054C237833B9044B13B181 | ||||
| :400040000448AFF300800123237010BD6881FF1F0000000058380000084B10B51BB108490848AFF300800848036803B910BD074B002BFBD0BDE81040184700BF00000000B1 | ||||
| :400080006C81FF1F58380000C880FF1F000000000A4A0B4B116801310B40002BBEBF03F1FF3363F03F030133136011685368994202BF024B01221A72704700BF8881FF1F2C | ||||
| :4000C0003F0000800A4A0B4B516801310B40002BBEBF03F1FF3363F03F030133536051681368994202BF024B01221A72704700BF8881FF1F3F000080024B012200205A7293 | ||||
| :4001000002F028B98881FF1F10B5C4B2204601F03DF90128FAD110BD08B572B60F4B0F49DA680132DA601A690132C82A08BF00221A615A6918690132A72A08BF00224A610E | ||||
| :400140005B69002B0CBF02230023002814BF184643F0010002F066FE62B608BD8881FF1F38B50446C5B2284602F096F8062002F0B3FA44F00200C0B202F08EF8062002F0FD | ||||
| :40018000ABFA284602F088F8BDE83840062002F08DBA10B5642402F079F828B9FFF7E0FF013CF8D1204610BD012010BD70B5C4B2054620460E4601F0E9F8012805D02046DB | ||||
| :4001C00001F002FA2846FFF79FFF204601F0E6F8314605460246204601F0A2F9204601F0D5F80028FAD1284670BD000038B5044D0024285D013402F01FFA402CF9D138BDDB | ||||
| :40020000A081FF1F08B502F039FC002002F042FC02F054FC02F05EFC80B208BD10B50446012002F051F8642002F040FAFFF7EAFF2080002002F048F8642002F037FAFFF73D | ||||
| :40024000E1FF608010BD08B502F044FD002002F04DFD02F05FFD02F069FD80B208BD10B50446FFF796FF322002F020FAFFF7EBFF20800120FFF774FF322002F017FAFFF7BB | ||||
| :40028000E2FF608010BD0FB400B593B014AB53F8042B402102A8019302F0C6FE02A802F060F802F06AF813B05DF804EB04B0704710B5044601780648FFF7E5FF0420FFF7E3 | ||||
| :4002C00023FF62782146BDE81040042001F0B6B86C38000007B50023ADF804308DF80600032301A88DF80530FFF7E2FF03B05DF804FB000010B5074C94F8583043B1002095 | ||||
| :4003000001F0BEFF002002F051FD002384F8583010BD00BF8881FF1F38B5104D837895F85B2004469A4204D0FFF7E4FF002385F85E302368C5F859302279094B1A71A37821 | ||||
| :40034000002B14BF0220012002F030FDE07802F027FD2079BDE8384002F05EBD8881FF1FE181FF1F38B50D4C94F8585065B904F15900FFF7D1FF012001F082FF4FF47A70D9 | ||||
| :4003800002F094F984F85E50E3682366012384F85830BDE8384002F0C7B900BF8881FF1FF8B5214C0546FFF7DDFF94F85E3003B15DB91E48FFF767FFFFF7EBFE0120002323 | ||||
| :4003C00084F85E00636602F087F92A46616E1848FFF759FF144E0027636E9D4216D001F055FF00B17766636E9D4205DD0120FFF7B7FE736E013305E005DA0020FFF7B0FE0E | ||||
| :40040000736E013B736602F08FF9E5E7322002F04DF92A2DCCBF0020012002F009FDBDE8F8400448FFF72FBF8881FF1F79380000803800009D3800002DE9F04F99B062B6B3 | ||||
| :4004400002F0DCF99949042002F000FA984801F029FF984802F0CCFC974801F05DFF02F0ADFB02F07FFA002002F0A0FC01F078FF0221002000F040FF904C012001F0B8F8D9 | ||||
| :40048000002384F85B30FFF76DFFFFF782FE84F86800FFF72FFF012384F85B30FFF762FFFFF777FE84F86900FFF724FF844B94F86800844994F869202546002A14BF0A46EA | ||||
| :4004C0001A46002808BF19467F48FFF7DCFE0321084602F009F9264602F026F994F8583043B12A6EEB689B1A41F28832934201D9FFF700FF00F038FF18B97448FFF7C3FE30 | ||||
| :4005000004E000F037FF0028F7D10BE000F02CFF10B902F009F9F9E76D48FFF7B4FE032001F052F8032000F031FF0128D4D16948FFF7F2FE68490320FFF738FE94F86A10B5 | ||||
| :400540006648FFF7A0FE94F86A30023B142B00F2BA83DFE813F01500B8031E00B8032400B8034600B8036C00B803CF00B803B101B803F102B8031003B8031703B803310372 | ||||
| :4005800003238DF820308DF821300E238DF822300EE394F86C00FFF703FF514B05E3FFF7E1FE00236372E068627A02F0FF0132B9EB681B1AB3F57A7FF6DD0B4608E03BB10E | ||||
| :4005C00000227272F168627A12B9EB685B1AFAE707228DF8202004228DF82120ADF82230E6E20220FFF790FD4FF000080DF1200A02F09AF84FF480790027C9EB0803DA1906 | ||||
| :4006000007F80A200137402FF9D10220FFF77CFD3A465146022000F011FFB9F10109EBD108F10108B8F1400FE2D12E4B38E04FF0010A4FF000080DF1200B02F075F84FF050 | ||||
| :40064000000959460120FFF7B1FD08EB090300270493049B1BF807203B44DBB2934209D08DE80C0041463B464A461F48FFF70BFE4FF0000A0137402FEBD109F10109B9F5E0 | ||||
| :40068000807FDED108F10108B8F1400FD5D151461648FFF7F8FDBAF1000F00F01581144B1B8807A8ADF81C3083E200BF19010000F900000091000000C50000008881FF1F76 | ||||
| :4006C000AF380000AB380000B2380000CA380000DD380000E181FF1FF281FF1FE73800005C3800005E380000F63800001239000060380000606EFFF753FE94F86C0001F0C6 | ||||
| :40070000E3FD94F86C0001F0C7FD02F0F9FBB64BDFF8F0821A78002702F0FB021A701A7842F001021A701A7802F0FE021A701A7802F0FE021A7002F0E7FB0220FFF7E4FC91 | ||||
| :40074000012141F6FF734FF48042084602F034FB84F8AA0001F056FF08F807000137402FF8D1DFF8A4A200270AF199091FFA89F80137402F14BF3A4600221AF8010F224438 | ||||
| :400780000623127E402101F071FF424646F24E419AF8000001F07CFF08F14008402F1FFA88F8E5D196F86D3033B100237372637A002BFCD00023737200234FF0FF32236069 | ||||
| :4007C00062602372236894F8AA002344197E01F0D1FE94F8AA0001F08FFE012194F8AA0001F062FE2368002BFCD0002398467360D6F80CA0012701F097FFE368B4F86E20C2 | ||||
| :40080000CAEB030393420DD367B1042195F8AA0001F0BCFE94F8AA0001F0C8FE0028F9D107463072237AFBB96A682B689A4202D1002FE0D118E00220FFF766FC6968402271 | ||||
| :4008400009EB8111022000F0F9FD6A68674B01321340002BBEBF03F1FF3363F03F03013308F101086360C6E70220277AFFF74CFC00221146022000F0E1FD0220FFF744FC15 | ||||
| :40088000FFB2FFF7B3FC002001F006FD37B15848FFF7F9FC0220FFF71DFD06E0554B08A81B88ADF82030FFF703FD627A4146237A5148FFF7E8FC09E25048FFF7E4FCD4F8CD | ||||
| :4008C0006E7017F03F0701D00320FDE1686EFFF767FD95F86C0001F0F7FC95F86C0001F0DBFC012001F0F6FC02F00AFB444BDFF814811A7842F004021A701A7842F001021C | ||||
| :400900001A701A7802F0FE021A701A7802F0FE021A7002F0F9FA01214FF4804341F6FF72084601F0DDFC85F8AA0001F06BFE08F807000137402FF8D1DFF8CC90002709F1F8 | ||||
| :4009400099031FFA83F804930137402F14BF3A46002219F8010F22440523127E402101F085FE414646F24B5299F8000001F090FE08F14008402F1FFA88F8E5D100274FF0AF | ||||
| :40098000FF33376098467360BB463B46D6F86E9037725FEA99190CBF4FF0010A4FF0000A2168124A01310A40002ABCBF02F1FF3262F03F026068B8BF013282426CD02BB162 | ||||
| :4009C000227A002A77D16A7A002A74D12068049A059302EB8010BAF1000F17D040223F2102F0EEFA1DE000BF9E6400403F0000801C39000062380000363900004939000081 | ||||
| :400A00009B650040A081FF1F9F81FF1F014601370120FFF7CBFBC7EB0903D3F1000A4AEB030A2168AD4A01310A40002ABEBF02F1FF3262F03F02013222606268059B013223 | ||||
| :400A40002AD12A683F2A27D14FF00008C5F8048001F074FC85F808806B6895F8AA002B44197E01F087FD95F8AA0001F045FD012195F8AA0001F018FD85F80980637A002B3E | ||||
| :400A8000FCD04FF00008012086F8098001F062FC404601F01FFC00E023B1237A5BB96B7A4BB90123626842453FF47AAF0BF1010BD5F8048074E701F047FC012001F00AFCFB | ||||
| :400AC000002001F047FC042194F8AA0001F05EFD94F8AA0001F06AFD0028F9D196F8AA0001F0F8FC737A327A0293012303920193CDF800A05B463A4649467948FFF7C3FB59 | ||||
| :400B0000BAF1000F0BD0FFF771FB002001F0C4FB237A63B17348FFF7B6FB0220D4E0B945F1D071490120FFF741FB0137F7E76F48FFF7A9FB6E4B38E094F86C0001F0C4FB59 | ||||
| :400B4000606EFFF72DFC6B48FFF79DFB00236372637A002BFCD0012001F0FCFB00237372637A002BFCD0002001F0F4FB6248FFF78AFB624B19E0002084F85E00FFF710FCCF | ||||
| :400B80005F4B12E094F8683023B195F869200AB985F86C2094F869201AB113B9012385F86C305848FFF7B8FB574B1B88ADF8203008A8FFF77DFB89E0FFF79CFB02F07CF8D9 | ||||
| :400BC000002002F01FF82A2701F04AFF002001F0EDFE3A46002108A802F0F2F917238DF820308DF8217001F09FFD002001F048FB002002F0DBF8C82001F058FD0DF12200DE | ||||
| :400C0000FFF70CFB0DF13600FFF729FB01F08CFD012002F0CBF8322001F048FD0DF12600FFF7FCFA0DF13A00FFF719FB012001F027FB4FF4967001F039FD01F075FD0DF13A | ||||
| :400C40002E00FFF7EBFA0DF14200FFF708FB002001F016FB4FF4967001F028FD01F064FD022002F0A3F8322001F020FD0DEB0700FFF7D4FA0DF13E00FFF7F1FA012001F05E | ||||
| :400C8000FFFA4FF4967001F011FD01F04DFD0DF13200FFF7C3FA0DF14600FFF7E0FA002001F0EEFA4FF4967001F000FD01F03CFD002002F07BF8002384F85E3001F07EFF47 | ||||
| :400CC00001F050FE74E70120FFF704FB032000F07BFC0E48FFF7D7FAFFF7FEBB3F00008053390000833900003892FF1F8D3900006438000095390000A33900006638000055 | ||||
| :400D000068380000F281FF1F6A380000B03900002DE9F04172B6884B61221A70A3F5F06301221A801924854A9C7092E803008033062283F8002283E80300522203F5807326 | ||||
| :400D40001A707F4B7F4A1B787F4EDBB2137040F618027E4B00251A8041F2512223F8022C33784FF4F07003F0010343EA450502F0BFF8013C05F003052ED0032DF0D1744BD2 | ||||
| :400D80004FF480721A8007221A70724A002548211570917002221D705D7103F8032C0422DA716D4A6D4C13786D4E43F00103137012F8013C062743F0030302F8013C2378D8 | ||||
| :400DC000012243F0800323705B4B1A70654A137843F02003137000E0FEE707FB056300219A881868013502F0EBF8072DF5D15E485E4E002550F8041F05F1105303F14802D4 | ||||
| :400E000021F0FF074933C9B20B4452005B0002329A4206D012F802EC12F801CC0EF807C0F5E7B0420D44E5D1514A002313609360136193614F4B504F1A68504BDFF888818F | ||||
| :400E40001A604F4B1A684F4B1A604F4A137843F002031370137C43F0020313742378A2F5863243F040032370413A137843F010031370464A464B07CA03C31A80454A28339D | ||||
| :400E8000106843F8250C127903F8212C424A07CA03C31A80414AE83B07CA03C31A80404A083307CA03C31A803E4A3F4BA2F5616203CBC2F8100EC2F8141E1378042043F009 | ||||
| :400EC00008031370394B02F5AA521B783D78DBB298F80060EDB203F007010C321B091170F6B2537045F003033B7046F0030388F800302F4B48221A702E4A402313702E492B | ||||
| :400F0000937013729372082382F81F3220220A7048710A72294A0A20137001F0DDFB284B88F8006044223D70264D1A7094E80F0007C52B80BDE8F081004800405C090048A4 | ||||
| :400F40000F010049A146004025420040224200400440004006400040A2430040A0430040B5390000E8460040FCFFFF478C0000480076004064090048F84600402076004024 | ||||
| :400F80006809004828760040035001401C090048C051004028090048300900483C090048480900483251004054090048CF0100491D51004001590040235B0040585B0040AE | ||||
| :400FC00076580040B0430040F946004008B501F0CBFF03680C2B00D1FEE7FEE7084908B50B68084A1844821A802A01DC086005E001F0BAFF0C2303604FF0FF33184608BD0D | ||||
| :40100000CC80FF1F8893FF1F80B51148114B0025C0B1A3F1100192C922460439161BB74204D051F8046F42F8046BF7E7114653F8046C8C1AA64202D041F8045BF9E7013884 | ||||
| :401040001033E5E701F096FFFFF7F6F9FEE700BF01000000843B0000124A134B10B51A60124A134C1368134843F4007313600023032B98BF54F823204FEA830188BF0E4A58 | ||||
| :401080000133302B4250F3D10C4B1A780C4B1A700C4B084A1A60FFF73BFEBDE8104001F0EDB900BF0004FA050CED00E014ED00E0000000000080FF1FCD0F0000BC7600403B | ||||
| :4010C000C080FF1F08ED00E0F8B501F019FF4B4A01271378022643F001031370137C484C43F001031374474B02F5E3521F700B3203F8946C1378054603F07F031370002089 | ||||
| :4011000001F0EAFA2378404A03F0F90323701378384603F0DF03137023783B43237001F0DBFA282001F0D8FA384B30461A7802F07F021A701A7802F0BF021A7023783343ED | ||||
| :40114000237001F0C9FA2378314A43F0040323700023137053702F4AFF2199540133092BFBD1284601F0D0FE0721172001F0FCFA2949172001F0EAFA0721182001F0F4FAF2 | ||||
| :401180002649182001F0E2FA0721152001F0ECFA2349152001F0DAFA0721052001F0E4FA2049052001F0D2FA0721062001F0DCFA1D49062001F0CAFA0721084601F0D4FA2F | ||||
| :4011C0001A49072001F0C2FA0721082001F0CCFA1749082001F0BAFA0021162001F0C4FA1449162001F0B2FA07210C2001F0BCFABDE8F84010490C2001F0A8BAA543004076 | ||||
| :40120000944300409D60004012600040F851004084600040AD92FF1F971A0000D1180000951A0000C9190000F5190000251A00005D1A00009D1A0000111B0000214B224AF4 | ||||
| :4012400010B5187000231370204A40201370204A0F2413701F4A13701F4A13701F4A13701F4A13701F4B4FF400021A604FF080721A604FF400121A6020221A6018608020E7 | ||||
| :4012800018604FF480701860174804704FF480001860164B1A70933B19B91A7802F0FE0202E01A7842F001021A70114B03221A70802203F8202C012001F01AFE0D4B04221F | ||||
| :4012C0001A7010BDC892FF1FCE92FF1FCC92FF1FCD92FF1FC992FF1FB892FF1FCB92FF1F4093FF1F00E100E09E6000409C600040286000401260004070B5074C0546237848 | ||||
| :401300000E461BB9FFF7E0FE0123237031462846BDE87040FFF792BF7892FF1F0A4A002313700A4A13700A4A13700A4A13700A4A13700A4A13700A4A13700A4B03221A7049 | ||||
| :40134000802203F8202C7047CE92FF1FCC92FF1FCD92FF1FC992FF1FB892FF1FCB92FF1F4093FF1F28600040014B1878704700BFCD92FF1F044B1A7802F0FF001AB1187845 | ||||
| :401380000022C0B21A707047CC92FF1F024A0C2303FB002040787047D492FF1F431E072B0CD8074A064B00010344805C5B7800F00F0043EA0020023880B2704700207047FA | ||||
| :4013C000FC5F00401A4A38B50C2303FB00231B79090C13F0800F00F1FF35044619BF8AB24FF480438BB24FF48042032D18D8DFE805F002070C110021084601F01BF80DE049 | ||||
| :401400000021084600F0FAFF08E00021084600F0D9FF03E00021084600F0B8FF054B1855EDB2072D03D801F0EDF8034B185538BDD492FF1FA492FF1FAD92FF1F431E072B83 | ||||
| :401440002DE9F0470446894615465CD82F4F0C2202FB0072D388DFF8B8A09BB2C3F500739D424FF00C0303FB007388BFD588DB7884BFC5F50075ADB2254A43EA1523060119 | ||||
| :40148000B354B244EBB28AF80130224B1A5C9846FF2A01D1FFF796FF0C2303FB047200215170B9F1000F28D03DB31B4F385D01F011F811232946FE2218F8040001F0D6F8E3 | ||||
| :4014C00006F5C04278321FFA89F118F8040001F0DFF8124D18F80410385D01F04BF80121385D00F0E1FF735D43F002037355735D03F0FD037355BDE8F08703FB047463793A | ||||
| :40150000DBB28AF80230BDE8F08700BFD492FF1FFC5F0040AD92FF1FA492FF1F706000402DE9F047044615468846002940D0431E072B3FD8FFF732FFA84203D22046FFF7CA | ||||
| :401540002DFF05461D4E335DFF2B03D141462046FFF738FFDFF868A027011AF8040000F0B9FF1223FE222946305D01F07FF807F5C0411FFA88F27831305D01F089F8DFF854 | ||||
| :401580004490315D1AF8040000F0F4FF01211AF8040000F089FF17F8093043F0020307F8093017F8093003F0FD0307F8093002E00D4600E000252846BDE8F087AD92FF1FD4 | ||||
| :4015C000A492FF1F70600040431E072B0AD8064A0C2303FB002300225A705A79034BD2B200011A54704700BFD492FF1FFE5F0040431E072B9FBF024B000108221A5470474D | ||||
| :40160000FE5F004030B51A4A1A491B4D0878138803449BB21380194A00231488D8B2A4B27CB1082B0CD050680078C0B2E85450680133013050601088013880B21080ECE768 | ||||
| :4016400018460B780E4C082B0E4A00D040B10E4D2B7883F080032B700F232370022301E0022323701370094B1870087030BD00BF4493FF1F4093FF1F00600040BC92FF1F5C | ||||
| :40168000B992FF1FCE92FF1FCA92FF1F4193FF1F074B02221A70074B80221A70064B0F221A70064A00231370054A012013707047CE92FF1FCA92FF1FB992FF1F4093FF1F5B | ||||
| :4016C0004193FF1F30B5164B16491B780A8803F00F03023BDBB21A4492B20A80124C134A0020118889B279B173B15568215C013BC9B229705168DBB20131516011880130B9 | ||||
| :40170000013989B21180ECE7094A1370094A137883F080031370084B0B221A7030BD00BF296000404493FF1F00600040BC92FF1F4193FF1FCA92FF1FB992FF1F064A0623D5 | ||||
| :401740001370064A01201370054B80221A70054B00221A70704700BFCE92FF1FB992FF1FCA92FF1F4193FF1F054B9A683AB19A68044910709A680988518000229A6070476E | ||||
| :40178000BC92FF1F4493FF1F08B5124B1A78D2B21A701B78DBB21A0602D50F4A137008BD0220FFF7E1FF0D4B1B7803F06003202B05D0402B06D043B900F012FC04E001F0ED | ||||
| :4017C000A7FB01E000F046FD10B9034B03221A7008BD00BF28600040B992FF1F0060004008B5084A084B0120197813880B449BB21380064B00221A70FFF7B6FF044B03221E | ||||
| :401800001A7008BD4493FF1F4093FF1FCE92FF1FB992FF1F08B50C4B1B78DBB2042B07D0062B09D0022B0DD1BDE80840FFF7D8BFBDE80840FFF746BF0320FFF795FF034BE0 | ||||
| :4018400003221A7008BD00BFCE92FF1FB992FF1F08B5054B002201201A70FFF785FF034B03221A7008BD00BFCE92FF1FB992FF1F08B50A4B1A7832B11A78094942F0800273 | ||||
| :401880000A7000221A70074B002201201A70FFF76BFF054B03221A7008BD00BFB892FF1F08600040CE92FF1FB992FF1F074B1B78DBB2042B05D0062B05D0022B05D1FFF794 | ||||
| :4018C000A1BEFFF7C5BFFFF7D3BF7047CE92FF1F38B51D4C2378DBB2DD0634D518060AD503F00F03012B2ED1FFF74EFF174B1B78190609D538BD5A0602D5FFF7D7FF03E0AB | ||||
| :401900009D0620D5FFF786FF23781B061BD4104B1A78104B1B7813430F4A13701278934211D10A4A0849154613782078DBB2000605D41378DBB20B700B7803F00F03287851 | ||||
| :401940008342F1D138BD38BD28600040B992FF1FCA92FF1F4193FF1F29600040054A00231380054A916819B191680B7092685380704700BF4493FF1FBC92FF1F0E4808B54E | ||||
| :4019800003889BB213B9FFF783FE13E00B4B02221A700B4B00221A70FFF7E0FF094AD1799379028843EA012392B2934238BF0380FFF728FE012008BDBC92FF1FCE92FF1F3B | ||||
| :4019C000CA92FF1F00600040084B01221A700F3B9B7C074B1A7B02F00302012A1EBFDA7B82F08002DA7301225A7370470B600040D492FF1F094B02221A700F3B93F82230F1 | ||||
| :401A0000074B1A7E02F00302012A1EBFDA7E82F08002DA7601225A76704700BF0B600040D492FF1F0B4B04221A700F3B93F83230094B93F8242002F00302012A1EBF93F89F | ||||
| :401A4000272082F0800283F82720012283F82520704700BF0B600040D492FF1F0B4B08221A700F3B93F84230094B93F8302002F00302012A1EBF93F8332082F0800283F815 | ||||
| :401A80003320012283F83120704700BF0B600040D492FF1F7047FFF741BC0000F0B5184B184E19780C27C9B201234FF0000C31B3CA0720D5144A4FEA031E7244947850788D | ||||
| :401AC0002040C5070DD507FB03652C79240608D5147804F0FE0414706D790C4CEDB204F80E50840706D507FB036425792D0658BF84F801C090700133DBB24908D7E7F0BD14 | ||||
| :401B00009F600040D492FF1F70600040FE5F004000F0ACBC70B50446184B88B003AA03F11006154618685968083303C5B3422A46F7D11B782B70FCB12223237001AD0323C9 | ||||
| :401B40002846637000F08AFE002220461146AB5C08AC04EB131414F8144C03F00F03847008AC234413F8143C0132082AC1700371417100F10400EAD108B070BDDF390000B8 | ||||
| :401B80002DE9F0431C4D01222E460C201F274FF0800E4FF0080C194B00FB02581401234418705F70164998F805902144B9F1000F07D098F8044024064CBF887081F802C009 | ||||
| :401BC00001E081F802E000FB0261CC880132E4B29C71CC88092AC4F30724DC71CC88E4B21C71C988C1F307215971D4D1054BFF221A70BDE8F08300BFD492FF1F70600040F2 | ||||
| :401C0000FC5F00400A600040064B074A1B7802EBC30253681A7C824286BF03EBC003586900207047C892FF1F403A00002DE9F84F424B1A78002A7ED01878414D0138C0B226 | ||||
| :401C4000FFF7E2FFA8463F4AC3681478007ADFF800C1E4B203EBC0000C2600274FF0010E834268D01A78A24263D11CF80420597891425ED19A7893F8039002F07F0206FB0C | ||||
| :401C800002FA05EB0A01CF7093F802B009F0030981F804B093F803B005F80AB0B3F804A0A1F808A093F902A0BAF1000F0BDAB9F1010F0CBF4FF007094FF00D0981F80590F6 | ||||
| :401CC00081F801E009E0B9F1010F0CBF4FF005094FF0090981F805904F704FEA02191A4906FB0282494481F802E0B2F808A0CAF3072A81F800A0B2F808A05FFA8AFA81F88C | ||||
| :401D000001A0B2F806A011495FFA8AFA494481F806A0B2F80690C9F3072981F80790B2F806905FFA89F981F80490D288C2F307224A71083394E7BDE8F88F00BFCD92FF1F5A | ||||
| :401D4000D492FF1FC992FF1FFC5F004070600040BA92FF1F08B5064B18780138C0B2FFF753FF20B143681B7900EBC300406908BDCD92FF1F00212DE9F84F0B464E4E0C2779 | ||||
| :401D800007FB01F401313219092933554FF000059370494CD3701381937253705371EFD118B1464B1D70464B1D70464B1A78002A7FD0187801250138C0B2FFF725FFA846EC | ||||
| :401DC0004368DFF8F8E0DB790C2713F0400F3E4B4FF0000C1A7814BF42F0010202F0FE021A70027AD20007FB0541C36803EB02094B4531D093F802A00AF07F06AE4229D1E5 | ||||
| :401E00000E89B3F804B0B6B25E4538BFA1F808B01E7893F801B01EF80660B3451AD181F804A0DE780E7093F902A0DE78BAF1000F06F0030607DA012E0CBF07260D264E7100 | ||||
| :401E400081F8018006E0012E0CBF052609264E7181F801C00833CBE70135092DC3D1C1680A328B1C0A440C200833934209D013F8081C13F80A5C01F07F0100FB01418D728C | ||||
| :401E8000F2E7FFF767FF114B0121186000230C2000FB0142D3801289013113449BB203F00102134409299BB2F2D1BDE8F84FFFF767BEBDE8F88F00BFD492FF1FBA92FF1F37 | ||||
| :401EC0004293FF1FCD92FF1FCB92FF1FD092FF1F114B1B7903F07F035A1E072A19D80F490C2202FB031291781B0141F0010191700021D170517841F002015170127912F0DA | ||||
| :401F0000800F074A1A4414BF8D2389239370FFF715BC0020704700BF00600040D492FF1FFC5F004030B4194B1A7902F07F02531E072B27D8164B0C2404FB02339978154DED | ||||
| :401F400001F0FE0199700021D97029461201505D114400F07F0050555A7802F0FD025A701A795B78120605D5012B01D18C7006E00D2303E0012B0CBF082309238B7030BC59 | ||||
| :401F8000FFF7DCBB002030BC704700BF00600040D492FF1FFC5F004010B50D4B0D4C21791878C9B20138C0B2FFF72EFE43681B798B4201D2012909D8074A0848535CDBB2A4 | ||||
| :401FC0004354A3780120DBB2535410BD002010BDCD92FF1F00600040BA92FF1F4293FF1F38B58A4A8A4C13780021DBB221801806517840F18D800A2900F20581DFE811F09D | ||||
| :402000005D00030103010301030103010B0003017E0003018200D3787C49012B09D17D4B1A787D4B03EBC2035B685B686360122310E0CB78022B12D18878FFF7E5FD002870 | ||||
| :4020400000F0E180436863606368DA7863689B7843EA02232380BDE83840FFF78FBCCB78032B26D16D4B00228878D5B2854209D3664A91786A4AEE2908BF1346634A91788D | ||||
| :4020800081B106E0187801320028F1D018780344EAE764499278097C914203D16248FFF739FD614B1A78002A00F0AD801A78228018E0BDE8384000F02BBF13F0030313D067 | ||||
| :4020C000022B40F0A0802380504B0C211B7903F07F02564B01FB02339A78554BD2B21A7000225A706360B6E702222280514A11784F4AC9B2117053706260ACE701232380B4 | ||||
| :402100004D4BEFE70123238013794C4A1344E9E701390A2977D8DFE801F037764F76067676760A7620009378454ADBB25AE0937803F0FF0153B9404B1A7891425FD0197020 | ||||
| :40214000404B01201870FFF715FE58E0481EC0B2FFF75AFD0028EED155E0FFF71DFF002851D02A4A384913791279DBB2D2B20A70364A3249D25CCB5C9A4240D0314B0122DC | ||||
| :402180001A70FFF753FD3AE003F00303012B2BD009D3022B37D11D4B9B78002B33D1BDE83840FFF7BFBE194B9B78012B2BD1214A137803F0FD0315E003F00303012B13D045 | ||||
| :4021C00008D3022B1FD1114B9B78E3B9BDE83840FFF77EBE0D4B9B78012B14D1154A137843F0020313700AE0084B1A795AB998781B791749DBB2CA5C22EA0002CA54BDE801 | ||||
| :402200003840FFF79BBA002038BD00BF00600040BC92FF1FC892FF1F403A0000A43A00002C3A0000173B00006093FF1FD492FF1F7992FF1FCB92FF1FCD92FF1FBA92FF1F53 | ||||
| :40224000B892FF1FCC92FF1FC992FF1F4293FF1FCF92FF1F074B1A78120609D55B78012B06D1054B054A5A6012781A80FFF786BB0020704700600040BC92FF1F043A00000A | ||||
| :40228000014B1870704700BF7A640040014B1878704700BF6B650040014B1870704700BF79640040064A0123136002F688321268E0211064034A1170A2F540721360704724 | ||||
| :4022C00080E100E000E400E0014B1870704700BF7A650040014B1870704700BF7865004073B515461E460B4C05230022019200920A4601461846237000F064F932462946A0 | ||||
| :40230000207800F01FF90221207800F009F9207802B070BDD080FF1F064A0423136002F688321268E0219064034A1170A2F202321360704780E100E002E400E0014B042227 | ||||
| :402340001A60704700E100E0014B04221A60704780E100E0014B1870704700BF7E640040704738B505460078012428B100F068FD285D0134E4B2F8E738BD08B50D2000F063 | ||||
| :402380005FFDBDE808400A2000F05ABDF7B516461F460B4C00230325019300930A4601462846257000F00EF93A463146207800F0C9F80221207800F0B3F8207803B0F0BD4E | ||||
| :4023C000E080FF1FF7B516461F460B4C00230225019300930A4601462846257000F0F2F83A463146207800F0ADF82946207800F097F8207803B0F0BDE180FF1FF7B516468D | ||||
| :402400001F460B4C00230125019300930A4601462846257000F0D6F83A463146207800F091F80221207800F07BF8207803B0F0BDE280FF1F73B515461E460B4C0023019385 | ||||
| :4024400000930A4601461846237000F0BBF832462946207800F076F80221207800F060F8207802B070BD00BFE380FF1F024B1878C0F38010704700BF8F450040074A7F236A | ||||
| :40248000802113705170064A013BDBB202F80839002BF9D1034A1370704700BFE480FF1FF87B00400078004017280FD8084B0001C25C11B142F0200201E002F0DF02C25443 | ||||
| :4024C000C25C42F00102C25400207047012070471070004017280BD8064B0001C25C02F0FE02C254C25C02F0DF02C25400207047012070471070004017280DD8074900017F | ||||
| :402500000B4603441A7942F004021A71435C43F00103435400207047012070471070004017280BD8064A0001835C490003F0F10301F00E011943815400207047012070476F | ||||
| :402540001070004041F6FF73994208BF4FF400519A4208BF4FF4005217289FBFC00000F1804000F5EC4081809ABFC280002001207047000017289FBF034B00011954002048 | ||||
| :4025800088BF0120704700BF1970004017289FBF054B00011A5C01F007019DBF1143195400200120704700BF1470004017289FBF034B0001185C00F0070088BFFF2070470B | ||||
| :4025C00014700040172810B51AD8C00001F07F0100F1804441EAC21204F5EC44D2B222709DF8082003F00F0343EA0213DBB263709DF80C30002003F00F03A370E07010BD73 | ||||
| :40260000012010BD10B500F07BFC0A4A5378182B0AD91478013B5370E30003F1804303F5F0431B78137000E0FF2400F06DFC204610BD00BFE480FF1F030610B5044611D408 | ||||
| :4026400000F05EFC084AE300117803F1804303F5F04319705378147001335370BDE8104000F052BC10BD00BFE480FF1F30B504060CD411F4704509D1C40004F1804404F5C7 | ||||
| :40268000F0442180A270E370284630BD012030BD03065FBFC00000F1804000F5F04081805ABFC280002001207047000038B50446084DB4F5004F05D9286800F019FCA4F5D6 | ||||
| :4026C0000044F6E7034B58686043BDE8384000F00FBC00BFEC80FF1F024B1B7A584300F007BC00BFEC80FF1F0E4B00F003001A78490102F0FC02104318701A7801F0600197 | ||||
| :4027000042F080021A701A7802F07F021A701A7802F09F020A431A701A7842F010021A70704700BF83430040014B01221A70704784430040044B00F00F021B6853F82200FD | ||||
| :4027400043F82210704700BF08ED00E0054A00F01F00126800F1100352F8230042F82310704700BF08ED00E000F01F0000F16040490100F56440C9B2017070470F4B10B55B | ||||
| :402780000F4900240F205C609C60DC601C615C61FFF7D0FF0B4A136843F0040313600A4B4FF47A72DB68B3FBF2F3084A1360084B4FF400421C60C3F8E82010BD7C92FF1FCF | ||||
| :4027C0002928000010E000E0EC80FF1F14E000E018E000E0024A136843F002031360704710E000E008B5FFF7F5FF034A136843F00103136008BD00BF10E000E010B5054C06 | ||||
| :40280000A3691BB9FFF7BAFF0123A361BDE81040FFF7E8BF7C92FF1F024B1868C0F30040704700BF10E000E038B5FFF7F5FF012808D1054D002455F8243003B19847013465 | ||||
| :40284000052CF8D138BD00BF8092FF1F024B03EB80035868596070477C92FF1F134B144A1B78DBB20360127843EA0223114A0360127843EA0243104A0360127843EA0263B2 | ||||
| :4028800003600E4B0E4A1B78DBB24360127843EA02230C4A4360127843EA02430A4A4360127843EA02634360704700BF0301004904010049EC4600400201004901010049A0 | ||||
| :4028C00000010049050100490601004910B500F017FB204A044613780A2043F002031370137C43F00203137412F80A3C43F0010302F80A3C937943F00103937102F5AB52B4 | ||||
| :40290000137843F003031370134B18221A7013F8012C42F0400203F8012C13F8012C02F0FC0203F8012CCE2203F8062CA3F597530222183B1A70094A137843F008031370CB | ||||
| :40294000FFF7CAFE064B10222046BDE810401A6000F0DABAAB4300400E5900402F5B004080E200E008B500F0CBFA0F4A137803F0FE031370A2F5AA521D3A137803F0FD03A7 | ||||
| :402980001370137C03F0FD03137412F80A3C03F0FE0302F80A3C937903F0FE039371BDE8084000F0B1BA00BF08590040044A137803F03F0343EA8010C0B21070704700BF28 | ||||
| :4029C00008590040082804D00A280CBF8223C22300E0422308380E4AC0B20428137098BF0C4B4FF0000298BF33F910100A4B88BF11461A8042F210734B4341F2883103F664 | ||||
| :402A0000C41393FBF1F305490B60054B1A8070470A590040F03900004A93FF1F4C93FF1F5093FF1F08B5102000F0A6F907210420FFF79AFE07490420FFF788FE064A0C206C | ||||
| :402A4000137843F006031370FFF7BCFF034B00221A8008BD1D2B0000095900404893FF1F10B5054C23781BB9FFF7DCFF01232370BDE81040FFF72ABF9892FF1F044B1A789F | ||||
| :402A800002F0FB021A701A7842F001021A7070470859004010B5084B1C7814F0010403D10028F9D0002404E02046FFF715FE024B1B78204610BD00BF09590040034A044BF3 | ||||
| :402AC0001B881088181A00B2704700BF5093FF1FA25B00400E4A13881BB223B111880A2309B2594301E00B4B19680B4B1B88C01A42F2107300B203FB00F2022391FBF3F3D7 | ||||
| :402B00000028D8BF5B42134493FBF1F000B270474A93FF1F4C93FF1F4893FF1F7047000010B500F0EDF9214A044613780A2043F001031370137C43F00103137412F80A3C06 | ||||
| :402B400043F0020302F80A3C937943F00203937102F5AA521832137843F003031370144B18221A7013F8012C42F0400203F8012C13F8012C02F0FC0203F8012CCE2203F8DF | ||||
| :402B8000062CA3F597530222123B1A70094A137843F008031370FFF79FFD074B08222046BDE810401A6000F0AFB900BFAB43004006590040275B004080E200E008B500F04F | ||||
| :402BC0009FF90F4A137803F0FE031370A2F5AA52153A137803F0FE031370137C03F0FE03137412F80A3C03F0FD0302F80A3C937903F0FD039371BDE8084000F085B900BF94 | ||||
| :402C000000590040044A137803F03F0343EA8010C0B21070704700BF00590040082804D00A280CBF8223C22300E0422308380E4AC0B20428137098BF0C4B4FF0000298BF60 | ||||
| :402C400033F910100A4B88BF11461A8042F210734B4341F2883103F6C41393FBF1F305490B60054B1A80704702590040FA3900005693FF1F5C93FF1F5493FF1F08B51020DA | ||||
| :402C800000F084F807210320FFF76EFD07490320FFF75CFD064A0C20137843F006031370FFF7BCFF034B00221A8008BD752D0000015900405893FF1F10B5054C23781BB92A | ||||
| :402CC000FFF7DCFF01232370BDE81040FFF728BF9992FF1F044B1A7802F0FB021A701A7842F001021A7070470059004010B5084B1C7814F0010403D10028F9D0002404E0B4 | ||||
| :402D00002046FFF7E9FC024B1B78204610BD00BF01590040034A044B1B881088181A00B2704700BF5493FF1FA05B00400E4A13881BB223B111880A2309B2594301E00B4B8D | ||||
| :402D400019680B4B1B88C01A42F2107300B203FB00F2022391FBF3F30028D8BF5B42134493FBF1F000B270475693FF1F5C93FF1F5893FF1F70470000034A00F0F8001378F0 | ||||
| :402D800003431370704700BF02410040034A00F0F800137803431370704700BF06410040014B1870704700BF78640040014B1870704700BF7965004073B515461E460B4CBF | ||||
| :402DC00004230022019200920A46014618462370FFF7F8FB324629462078FFF7B3FB02212078FFF79DFB207802B070BDFC80FF1F074A0223136002F688321268E0215064AD | ||||
| :402E0000044A11706FF440710A441360704700BF80E100E001E400E0014B1870704700BF7C640040014B1870704700BF7B640040014B1870704700BF7F6400400000000032 | ||||
| :402E4000FEB5494652465B460EB40746244909688A46244A12682448022100F071F8030020480068C018204900F06AF8143883460121C9430C460125002600F041F8814613 | ||||
| :402E800051460B7823400B705846013000F030F83800F04028400B78234003430B70584600F026F80136072EF2D9002001300138013001200B78234003430B705846043084 | ||||
| :402EC00000F016F8484600F01FF800BF00BF00BF0EBC894692469B46FEBD00BFAFF30080D480FF1FF880FF1F00C20100000000000230800803D000BF01380046FCD17047FA | ||||
| :402F0000EFF3108072B6704780F31088704700BF094A137803F00303012B0AD0022B09D113790C2103F07F02044B01FB02339B7A00E013790020704700600040D492FF1FB2 | ||||
| :402F4000002902D0B0FBF1F0704708B14FF0FF3000F008B80029F8D00246B0FBF1F000FB11217047704700BF014B1868704700BF6081FF1F0E4B70B51E460E4C0025E41A7D | ||||
| :402F8000A410A54204D056F8253098470135F8E700F0DEFD084B094C1E46E41AA4100025A54204D056F8253098470135F8E770BD5C3B00005C3B00005C3B0000643B00007A | ||||
| :402FC00003460244934202D003F8011BFAE7704730B5141E05469BB0184604DA8B232B604FF0FF301DE04FF40273ADF80C300CBF234604F1FF33029305934FF6FF730091F6 | ||||
| :403000000491ADF80E3002461E9B6946284600F073F8431CBCBF8B232B6014B1009B00221A701BB030BD000007B5009313460A46014603480068FFF7CBFF03B05DF804FB0F | ||||
| :403040006081FF1F2DE9F0478E6882469E420C46914698463ED88A8912F4906F3AD02568096902236F1A656905EB450595FBF3F57B1C43449D4238BF1D4653050FD52946F8 | ||||
| :4030800000F04AFB064698B13A46216900F0D2FAA38923F4906343F08003A38113E02A4600F098FB064670B92169504600F0E8FA0C23CAF80030A3894FF0FF3043F04003F2 | ||||
| :4030C000A381BDE8F08726613E44266046466561ED1BA560464528BF464649463246206800F0B3FAA36800209B1BA36023681E442660BDE8F08700002DE9F04F9DB00393CD | ||||
| :403100008B8980461C060D4616460DD50B695BB9402100F001FB2860286118B90C23C8F80030CDE040236B610023099320238DF82930DFF89CB130238DF82A3037463C461B | ||||
| :4031400014F8013B1BB9B7EB060910D003E0252BF9D02746F3E74B46324629464046FFF771FF013000F0A780099B4B4409933B78002B00F0A08000234FF0FF320493079332 | ||||
| :40318000059206938DF853301A930126052221784E4800F041FA671C049B38B14B4A3C46801A06FA00F018430490EFE7D90644BF20228DF853201A0744BF2B228DF853208C | ||||
| :4031C00022782A2A03D0079A00210A200BE0039A111D12680391002A10DA524243F00200079204900BE027463B780134303B092B03D800FB02320121F5E701B107923B786F | ||||
| :403200002E2B1ED17B782A2B0AD1039B02371A1D1B680392002BB8BF4FF0FF33059310E0002319460593781C0A2407463A780130303A092A03D804FB01210123F5E703B109 | ||||
| :40324000059103223978224800F0E6F940B14023CBEB000003FA00F0049B013718430490397806221B487E1C8DF8281000F0D4F988B1194B33B9039B073323F007030833E3 | ||||
| :40328000039314E003AB00932A46144B04A94046AFF3008007E003AB00932A460F4B04A9404600F093F8B0F1FF3F824603D0099B5344099342E7AB895B0601D4099801E019 | ||||
| :4032C0004FF0FF301DB0BDE8F08F00BF2B3B0000313B0000353B000000000000453000002DE9F04791461F460A698B6806469342B8BF1346C9F8003091F843200C46DDF815 | ||||
| :40330000208012B10133C9F800302368990642BFD9F800300233C9F80030256815F0060510D104F1190A07E00123524639463046C04701301AD00135E368D9F800209B1A3C | ||||
| :403340009D42F1DB94F843302268003318BF012392060FD5E118302081F843005A1C94F845102244023382F8431003E04FF0FF30BDE8F08704F1430239463046C0470130D7 | ||||
| :40338000F4D02268D9F80050E36802F00602042A08BF5D1B2269A3680CBF25EAE57500259342C4BF9B1AED184FF000091A344D4509D00123224639463046C0470130D5D08C | ||||
| :4033C00009F10109F3E70020BDE8F0872DE9F04317460A7E85B06E2A984606460C460C9B01F1430E00F0AE8011D8632A22D009D8002A00F0BB80582A40F0CA8081F84520BC | ||||
| :40340000834955E0642A1ED0692A1CD0C0E0732A00F0B08009D86F2A2ED0702A40F0B8800A6842F020020A603EE0752A24D0782A3AD0ADE01A6801F14205111D19601368C2 | ||||
| :4034400084F84230A8E021681A6811F0800F02D0111D196008E011F0400F02F10401196002D0B2F9003000E01368002B3CDA2D225B4284F8432037E021681A6811F0800F53 | ||||
| :4034800002D0111D196007E011F0400F02F10401196001D0138800E01368227E5C496F2A14BF0A2208221BE078225A4984F845202268186812F0800F00F104051D6003D11E | ||||
| :4034C000550601D5038800E00368D00744BF42F0200222601BB9226822F0200222601022002084F8430001E049490A226568002DA56008DB206820F0040020602BB9002D42 | ||||
| :403500007DD175460CE0002B79D07546B3FBF2F002FB1033CB5C05F8013D03460028F5D1082A0BD12368DA0708D5236962689A42DEBF302305F8013C05F1FF35C5EB0E0360 | ||||
| :4035400023612EE008681A6810F0800F496903D0101D1860136808E010F0400F02F104001860136801D0198000E0196000232361754616E01A68111D1960156800216268C6 | ||||
| :40358000284600F049F808B1401B6060636804E004F1420584F8422001232361002384F84330CDF800803B4603AA21463046FFF797FE013002D14FF0FF3026E023692A46C6 | ||||
| :4035C00039463046C0470130F5D023689B0710D5002504F1190907E001234A4639463046C0470130E7D00135E368039A9B1A9D42F2DBE068039B9842B8BF184605E00B7890 | ||||
| :4036000004F1420584F842308AE705B0BDE8F083DF3900003C3B000010B5C9B202449042034605D01C7801308C42F8D1184610BD002010BD10B5431E0A44914204D011F885 | ||||
| :40364000014B03F8014FF8E710BD884210B501EB020301D8421E0BE09842FBD28118D21AD34204D013F8014D01F8014DF8E710BD994204D011F8014B02F8014FF8E710BD08 | ||||
| :4036800038B50546002944D051F8043C0C1F002BB8BFE41800F0D4F81E4A1368114613B96360146030E0A3420DD92268A018834201BF18685B681218226063600C6023E087 | ||||
| :4036C000A24203D813465A68002AF9D118681918A1420BD12168014458188242196013D110685268014419605A600DE002D90C232B6009E021686018824201BF1068526861 | ||||
| :403700000918216062605C602846BDE8384000F098B838BDA092FF1F70B5CD1C25F0030508350C2D38BF0C25002D064601DBA94202D90C23336046E000F082F8234B1C6831 | ||||
| :403740001A462146A1B10B685B1B0ED40B2B03D90B60CC18CD501EE08C420BBF63684B681360636018BF0C4615E00C464968E9E7174C23681BB9304600F052F8206029464B | ||||
| :40378000304600F04DF8431C18D0C41C24F00304A0420DD12560304600F053F804F10B00231D20F00700C31A0ED05A42E25070BD211A304600F034F80130EBD10C2333609D | ||||
| :4037C000304600F03EF8002070BD00BFA092FF1F9C92FF1FF8B5074615460E4621B91146BDE8F840FFF798BF1AB9FFF749FF2846F8BD00F027F885420ED929463846FFF7AD | ||||
| :403800008BFF044650B131462A46FFF713FF31463846FFF735FF01E03046F8BD2046F8BD38B5064C0023054608462360FDF7D6FB431C02D1236803B12B6038BD8493FF1F15 | ||||
| :403840007047704751F8040C0028BEBF091851F8043CC0180438704700000000050209020B020D020F021102130215027265706C792030782530327800686F6D696E670074 | ||||
| :40388000626567696E6E696E67207365656B2066726F6D20256420746F2025640066696E6973686564207365656B00796573006E6F00647269766520303A202573206472D4 | ||||
| :4038C00069766520313A2025730057616974696E6720666F72205553422E2E2E0055534220726561647900636F6D6D616E6420307825303278006661696C2025642B2564B5 | ||||
| :403900002B2564203D3D2025642C206E6F74202564007061737365643D256400756E64657272756E206166746572202564207061636B65747300636F756E743D2564206933 | ||||
| :403940003D256420643D256400636D645F777269746500703D25642063723D25642063773D256420663D256420773D256420696E6465783D256420756E64657272756E3D51 | ||||
| :40398000256400756E64657272756E2100737563636573730073746172742065726173696E670073746F702065726173696E670069646C65000051004010004051004030AB | ||||
| :4039C0000000000140001000140140000800400140000A004C0140000200500140200030313233343536373839414243444546000001000000040000001000010000000492 | ||||
| :403A00000000001028000000000104000100000000000000000157494E5553420000303030303100000000000000000012034D00530046005400310030003000010000009D | ||||
| :403A400001000000483A000001000000173B0000000000000000000001000000603A000001000000E93A000004000000823A0000000000000000000000000000803A000037 | ||||
| :403A8000FF00000001024000FF00000082024000FF00000003034000FF00000084034000FF00020304030904160346006C007500780045006E00670069006E0065002A03A3 | ||||
| :403AC00043006F0077006C00610072006B00200054006500630068006E006F006C006F0067006900650073000009022E0001010080320904000004FF0000010705010240A2 | ||||
| :403B00000000070582024000000705030340000A0705840340000A12010002FF0001080912006E0100020180014300232D302B2000686C4C00656667454647003031323359 | ||||
| :403B400034353637383961626364656600000000F8B500BFF8BC08BC9E4670475900000059100000F8B500BFF8BC08BC9E46704735000000883B0000C880FF1FA0000000EB | ||||
| :403B80002012000000000000000000008893FF1FFF000000675000400C00000007000000FFFFFFFF7F8000003F0000000000007D00FA0000400000000090D003FF0000003E | ||||
| :403BC0000000000000000000000000000000000000000000000000000000000000000000293B00000000000000000000000000000000000000000000000000000000000061 | ||||
| :403C000000000000000000000000000000000000000000000000000000000000000000000081FF1F00000000000000000000000000000000000000000000000000000000E5 | ||||
| :403C40000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000044 | ||||
| :403C80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004 | ||||
| :4000000000800020110000003110000031100000064A08B5136843F020031360044B1A6803F53F5302331A6001F020F8E8460040FA46004010B5054C237833B9044B13B18B | ||||
| :400040000448AFF300800123237010BD6881FF1F00000000B8380000084B10B51BB108490848AFF300800848036803B910BD074B002BFBD0BDE81040184700BF0000000051 | ||||
| :400080006C81FF1FB8380000C880FF1F000000000A4A0B4B116801310B40002BBEBF03F1FF3363F03F030133136011685368994202BF024B01221A72704700BF8881FF1FCC | ||||
| :4000C0003F0000800A4A0B4B516801310B40002BBEBF03F1FF3363F03F030133536051681368994202BF024B01221A72704700BF8881FF1F3F0000800E4BDA681AB901215F | ||||
| :4001000019745A7410E05A7C1A741A7C0AB1002207E059699A69D8688A1A82428CBF002201225A745A699A611B7C13B1002002F043B970478881FF1F10B5C4B2204601F054 | ||||
| :4001400057F90128FAD110BD08B572B60F4B0F495A6901325A61DA690132C82A08BF0022DA611A6AD8690132A72A08BF00220A621B6A002B0CBF02230023002814BF184660 | ||||
| :4001800043F0010002F080FE62B608BD8881FF1F38B50446C5B2284602F0B0F8062002F0CDFA44F00200C0B202F0A8F8062002F0C5FA284602F0A2F8BDE83840062002F0C2 | ||||
| :4001C000A7BA10B5642402F093F828B9FFF7E0FF013CF8D1204610BD012010BD70B5C4B2054620460E4601F003F9012805D0204601F01CFA2846FFF79FFF204601F000F9AD | ||||
| :40020000314605460246204601F0BCF9204601F0EFF80028FAD1284670BD000038B5044D0024285D013402F039FA402CF9D138BDAC81FF1F08B502F053FC002002F05CFCBD | ||||
| :4002400002F06EFC02F078FC80B208BD10B50446012002F06BF8642002F05AFAFFF7EAFF2080002002F062F8642002F051FAFFF7E1FF608010BD08B502F05EFD002002F02B | ||||
| :4002800067FD02F079FD02F083FD80B208BD10B50446FFF796FF322002F03AFAFFF7EBFF20800120FFF774FF322002F031FAFFF7E2FF608010BD0FB400B593B014AB53F835 | ||||
| :4002C000042B402102A8019302F0DEFE02A802F07AF802F084F813B05DF804EB04B0704710B5044601780648FFF7E5FF0420FFF723FF62782146BDE81040042001F0D0B8B5 | ||||
| :40030000CC38000007B50023ADF804308DF80600032301A88DF80530FFF7E2FF03B05DF804FB000010B5074C94F8643043B1002001F0D8FF002002F06BFD002384F864304E | ||||
| :4003400010BD00BF8881FF1F38B5104D837895F8672004469A4204D0FFF7E4FF002385F86A302368C5F865302279094B1A71A378002B14BF0220012002F04AFDE07802F02E | ||||
| :4003800041FD2079BDE8384002F078BD8881FF1FED81FF1F38B50D4C94F8645065B904F16500FFF7D1FF012001F09CFF4FF47A7002F0AEF984F86A506369E366012384F84D | ||||
| :4003C0006430BDE8384002F0E1B900BF8881FF1FF8B5214C0546FFF7DDFF94F86A3003B15DB91E48FFF767FFFFF7EBFE0120002384F86A00236702F0A1F92A46216F184872 | ||||
| :40040000FFF759FF144E0027236F9D4216D001F06FFF00B13767236F9D4205DD0120FFF7B7FE336F013305E005DA0020FFF7B0FE336F013B336702F0A9F9E5E7322002F047 | ||||
| :4004400067F92A2DCCBF0020012002F023FDBDE8F8400448FFF72FBF8881FF1FD9380000E0380000FD3800002DE9F04F99B062B602F0F6F99D49042002F01AFA9C4801F0D9 | ||||
| :4004800043FF9C4802F0E6FC9B4801F077FF02F0C7FB02F099FA002002F0BAFC01F092FF0221002000F05AFF944C012001F0D2F8002384F86730FFF76DFFFFF782FE84F8A3 | ||||
| :4004C0007400FFF72FFF012384F86730FFF762FFFFF777FE84F87500FFF724FF884B94F87400884994F875202546002A14BF0A461A46002808BF19468348FFF7DCFE032177 | ||||
| :40050000084602F023F9264602F040F994F8643043B1EA6E6B699B1A41F28832934201D9FFF700FF00F052FF18B97848FFF7C3FE04E000F051FF0028F7D10BE000F046FF85 | ||||
| :4005400010B902F023F9F9E77148FFF7B4FE032001F06CF8032000F04BFF0128D4D16D48FFF7F2FE6C490320FFF738FE94F876106A48FFF7A0FE94F87630023B142B00F229 | ||||
| :40058000D483DFE813F01500D2031E00D2032400D2034F00D2037500D203D700D203BF01D2030603D2032A03D2033103D2034B0303238DF820308DF821300F238DF8223084 | ||||
| :4005C00028E394F87800FFF703FF554B1FE3FFF7E1FE002323746069227C02F0FF0132B96B691B1AB3F57A7FF6DD0B4611E083B10022174696F878107069277494F810E007 | ||||
| :40060000BEF1000F02D16B691B1AF7E701329142F3DA07228DF8202004228DF82120ADF82230F7E20220FFF787FD4FF000080DF1200A02F0ABF84FF480790027C9EB080303 | ||||
| :40064000DA1907F80A200137402FF9D10220FFF773FD3A465146022000F022FFB9F10109EBD108F10108B8F1400FE2D12D4B38E04FF0010A4FF000080DF1200B02F086F844 | ||||
| :400680004FF0000959460120FFF7A8FD08EB090300270493049B1BF807203B44DBB29A4209D08DE80C0041463B464A461E48FFF702FE4FF0000A0137402FEBD109F101091B | ||||
| :4006C000B9F5807FDED108F10108B8F1400FD5D151461648FFF7EFFDBAF1000F00F01A81134B1B8807A8ADF81C3094E249010000F900000091000000C50000008881FF1F0B | ||||
| :400700000F3900000B390000123900002A3900003D390000ED81FF1FFE81FF1F47390000BC380000BE3800005639000072390000C0380000206FFFF74BFE94F8780001F081 | ||||
| :40074000F5FD94F8780001F0D9FD02F009FCB94BDFF8FC821A78002702F0FB021A701A7842F001021A701A7802F0FE021A701A7802F0FE021A7002F0F7FB0220FFF7DCFCF9 | ||||
| :40078000012141F6FF734FF48042084602F046FB84F8B60001F068FF08F807000137402FF8D1DFF8B0A200270AF195091FFA89F80137402F14BF3A4600221AF8010F2244C0 | ||||
| :4007C000062392F82420402101F082FF424646F24E419AF8000001F08DFF08F14008402F1FFA88F8E4D196F8793053B196F87C30F36000233374237C002BFCD000233374E1 | ||||
| :40080000F36000234FF0FF32236062602372236894F8B600234493F8241001F0DDFE94F8B60001F09BFE012194F8B60001F06EFE2368002BFCD0002398467360D6F814A0D4 | ||||
| :40084000012701F0A3FF6369B4F87A20CAEB030393420DD367B1042195F8B60001F0C8FE94F8B60001F0D4FE0028F9D107463072237AFBB96A682B689A4202D1002FE0D1D9 | ||||
| :4008800018E00220FFF758FC6968402209EB8111022000F005FE6A68674B01321340002BBEBF03F1FF3363F03F03013308F101086360C6E70220277AFFF73EFC0022114687 | ||||
| :4008C000022000F0EDFD0220FFF736FCFFB2FFF7A5FC002001F012FD37B15848FFF7EBFC0220FFF70FFD06E0554B08A81B88ADF82030FFF7F5FC227C4146237A5148FFF7BB | ||||
| :40090000DAFC15E25048FFF7D6FCD4F87A7017F03F0701D0032009E2286FFFF759FD95F8780001F003FD95F8780001F0E7FC012001F002FD02F014FB444BDFF814811A7857 | ||||
| :4009400042F004021A701A7842F001021A701A7802F0FE021A701A7802F0FE021A7002F003FB01214FF4804341F6FF72084601F0E9FC85F8B60001F077FE08F8070001378C | ||||
| :40098000402FF8D1DFF8CC90002709F195031FFA83F804930137402F14BF3A46002219F8010F2244052392F82420402101F090FE414646F24B5299F8000001F09BFE08F1FF | ||||
| :4009C0004008402F1FFA88F8E4D100274FF0FF33376098467360BB463B46D6F87A9037725FEA99190CBF4FF0010A4FF0000A2168114A01310A40002ABCBF02F1FF3262F03B | ||||
| :400A00003F026068B8BF013282426FD02BB1227A002A7AD12A7C002A77D12068049A059302EB8010BAF1000F16D040223F2102F0F7FA1CE09E6400403F0000807C390000C9 | ||||
| :400A4000C238000096390000A93900009B650040AC81FF1FAB81FF1F014601370120FFF7BDFBC7EB0903D3F1000A4AEB030A2168B34A01310A40002ABEBF02F1FF3262F0BB | ||||
| :400A80003F02013222606268059B01322ED12A683F2A2BD14FF00008C5F8048001F080FC85F808806B6895F8B6002B4493F8241001F092FD95F8B60001F050FD012195F8BF | ||||
| :400AC000B60001F023FD95F87E30EB6085F81080237C002BFCD04FF00008012086F8108001F06AFC404601F027FC00E023B1237A5BB92B7C4BB90123626842453FF477AFC1 | ||||
| :400B00000BF1010BD5F8048071E701F04FFC012001F012FC002001F04FFC042194F8B60001F066FD94F8B60001F072FD80460028F8D196F8B60001F0FFFC337C327A029318 | ||||
| :400B4000012303920193CDF800A05B463A4649467C48FFF7B0FBC6F80C80BAF1000F0BD0FFF75CFB002001F0C9FB237A63B17648FFF7A1FB0220D9E0B945F1D07349012035 | ||||
| :400B8000FFF72CFB0137F7E77148FFF794FB714B3DE094F8780001F0C9FB206FFFF718FC6D48FFF788FB94F87930E36000232374237C002BFCD0012001F0FEFB00233374CE | ||||
| :400BC000237C002BFCD0002001F0F6FB00236348F360FFF770FB624B19E0002084F86A00FFF7F6FB5F4B12E094F8743023B195F875200AB985F8782094F875201AB113B9F6 | ||||
| :400C0000012385F878305848FFF79EFB574B1B88ADF8203008A8FFF763FB89E0FFF782FB02F07CF8002002F01FF82A2701F04AFF002001F0EDFE3A46002108A802F0F0F9E0 | ||||
| :400C400017238DF820308DF8217001F09FFD002001F048FB002002F0DBF8C82001F058FD0DF12200FFF7F2FA0DF13600FFF70FFB01F08CFD012002F0CBF8322001F048FD4D | ||||
| :400C80000DF12600FFF7E2FA0DF13A00FFF7FFFA012001F027FB4FF4967001F039FD01F075FD0DF12E00FFF7D1FA0DF14200FFF7EEFA002001F016FB4FF4967001F028FD84 | ||||
| :400CC00001F064FD022002F0A3F8322001F020FD0DEB0700FFF7BAFA0DF13E00FFF7D7FA012001F0FFFA4FF4967001F011FD01F04DFD0DF13200FFF7A9FA0DF14600FFF756 | ||||
| :400D0000C6FA002001F0EEFA4FF4967001F000FD01F03CFD002002F07BF8002384F86A3001F07EFF01F050FE74E70120FFF7EAFA032000F07BFC0E48FFF7BDFAFFF7E4BBB6 | ||||
| :400D40003F000080B3390000E33900004092FF1FED390000C4380000F5390000033A0000C6380000C8380000FE81FF1FCA380000103A00002DE9F04172B6884B61221A70F9 | ||||
| :400D8000A3F5F06301221A801924854A9C7092E803008033062283F8002283E80300522203F580731A707F4B7F4A1B787F4EDBB2137040F618027E4B00251A8041F25122A6 | ||||
| :400DC00023F8022C33784FF4F07003F0010343EA450502F0BDF8013C05F003052ED0032DF0D1744B4FF480721A8007221A70724A002548211570917002221D705D7103F893 | ||||
| :400E0000032C0422DA716D4A6D4C13786D4E43F00103137012F8013C062743F0030302F8013C2378012243F0800323705B4B1A70654A137843F02003137000E0FEE707FBAD | ||||
| :400E4000056300219A881868013502F0E9F8072DF5D15E485E4E002550F8041F05F1105303F1480221F0FF074933C9B20B4452005B0002329A4206D012F802EC12F801CC0C | ||||
| :400E80000EF807C0F5E7B0420D44E5D1514A002313609360136193614F4B504F1A68504BDFF888811A604F4B1A684F4B1A604F4A137843F002031370137C43F002031374F7 | ||||
| :400EC0002378A2F5863243F040032370413A137843F010031370464A464B07CA03C31A80454A2833106843F8250C127903F8212C424A07CA03C31A80414AE83B07CA03C33B | ||||
| :400F00001A80404A083307CA03C31A803E4A3F4BA2F5616203CBC2F8100EC2F8141E1378042043F008031370394B02F5AA521B783D78DBB298F80060EDB203F007010C329F | ||||
| :400F40001B091170F6B2537045F003033B7046F0030388F800302F4B48221A702E4A402313702E49937013729372082382F81F3220220A7048710A72294A0A20137001F0C7 | ||||
| :400F8000DDFB284B88F8006044223D70264D1A7094E80F0007C52B80BDE8F081004800405C0900480F010049A146004025420040224200400440004006400040A2430040AF | ||||
| :400FC000A0430040153A0000E8460040FCFFFF478C0000480076004064090048F8460040207600406809004828760040035001401C090048C051004028090048300900485A | ||||
| :401000003C090048480900483251004054090048CF0100491D51004001590040235B0040585B004076580040B0430040F946004008B501F0C9FF03680C2B00D1FEE7FEE79D | ||||
| :40104000084908B50B68084A1844821A802A01DC086005E001F0B8FF0C2303604FF0FF33184608BDCC80FF1F9093FF1F80B51148114B0025C0B1A3F1100192C92246043933 | ||||
| :40108000161BB74204D051F8046F42F8046BF7E7114653F8046C8C1AA64202D041F8045BF9E701381033E5E701F094FFFFF7DCF9FEE700BF01000000E43B0000124A134BF0 | ||||
| :4010C00010B51A60124A134C1368134843F4007313600023032B98BF54F823204FEA830188BF0E4A0133302B4250F3D10C4B1A780C4B1A700C4B084A1A60FFF73BFEBDE8CA | ||||
| :40110000104001F0EDB900BF0004FA050CED00E014ED00E0000000000080FF1F31100000BC760040C080FF1F08ED00E0F8B501F017FF4B4A01271378022643F001031370EA | ||||
| :40114000137C484C43F001031374474B02F5E3521F700B3203F8946C1378054603F07F031370002001F0EAFA2378404A03F0F90323701378384603F0DF03137023783B4325 | ||||
| :40118000237001F0DBFA282001F0D8FA384B30461A7802F07F021A701A7802F0BF021A7023783343237001F0C9FA2378314A43F0040323700023137053702F4AFF2199544A | ||||
| :4011C0000133092BFBD1284601F0CEFE0721172001F0FCFA2949172001F0EAFA0721182001F0F4FA2649182001F0E2FA0721152001F0ECFA2349152001F0DAFA0721052032 | ||||
| :4012000001F0E4FA2049052001F0D2FA0721062001F0DCFA1D49062001F0CAFA0721084601F0D4FA1A49072001F0C2FA0721082001F0CCFA1749082001F0BAFA0021162047 | ||||
| :4012400001F0C4FA1449162001F0B2FA07210C2001F0BCFABDE8F84010490C2001F0A8BAA5430040944300409D60004012600040F851004084600040B592FF1FFB1A00008A | ||||
| :4012800035190000F91A00002D1A0000591A0000891A0000C11A0000011B0000751B0000214B224A10B5187000231370204A40201370204A0F2413701F4A13701F4A1370D9 | ||||
| :4012C0001F4A13701F4A13701F4B4FF400021A604FF080721A604FF400121A6020221A601860802018604FF480701860174804704FF480001860164B1A70933B19B91A7851 | ||||
| :4013000002F0FE0202E01A7842F001021A70114B03221A70802203F8202C012001F018FE0D4B04221A7010BDD092FF1FD692FF1FD492FF1FD592FF1FD192FF1FC092FF1F97 | ||||
| :40134000D392FF1F4893FF1F00E100E09E6000409C600040286000401260004070B5074C054623780E461BB9FFF7E0FE0123237031462846BDE87040FFF792BF8092FF1F7A | ||||
| :401380000A4A002313700A4A13700A4A13700A4A13700A4A13700A4A13700A4A13700A4B03221A70802203F8202C7047D692FF1FD492FF1FD592FF1FD192FF1FC092FF1F05 | ||||
| :4013C000D392FF1F4893FF1F28600040014B1878704700BFD592FF1F044B1A7802F0FF001AB118780022C0B21A707047D492FF1F024A0C2303FB002040787047DC92FF1FB8 | ||||
| :40140000431E072B0CD8074A064B00010344805C5B7800F00F0043EA0020023880B2704700207047FC5F00401A4A38B50C2303FB00231B79090C13F0800F00F1FF35044670 | ||||
| :4014400019BF8AB24FF480438BB24FF48042032D18D8DFE805F002070C110021084601F01BF80DE00021084600F0FAFF08E00021084600F0D9FF03E00021084600F0B8FF3E | ||||
| :40148000054B1855EDB2072D03D801F0EDF8034B185538BDDC92FF1FAC92FF1FB592FF1F431E072B2DE9F0470446894615465CD82F4F0C2202FB0072D388DFF8B8A09BB274 | ||||
| :4014C000C3F500739D424FF00C0303FB007388BFD588DB7884BFC5F50075ADB2254A43EA15230601B354B244EBB28AF80130224B1A5C9846FF2A01D1FFF796FF0C2303FBBF | ||||
| :40150000047200215170B9F1000F28D03DB31B4F385D01F011F811232946FE2218F8040001F0D6F806F5C04278321FFA89F118F8040001F0DFF8124D18F80410385D01F004 | ||||
| :401540004BF80121385D00F0E1FF735D43F002037355735D03F0FD037355BDE8F08703FB04746379DBB28AF80230BDE8F08700BFDC92FF1FFC5F0040B592FF1FAC92FF1FD4 | ||||
| :40158000706000402DE9F047044615468846002940D0431E072B3FD8FFF732FFA84203D22046FFF72DFF05461D4E335DFF2B03D141462046FFF738FFDFF868A027011AF893 | ||||
| :4015C000040000F0B9FF1223FE222946305D01F07FF807F5C0411FFA88F27831305D01F089F8DFF84490315D1AF8040000F0F4FF01211AF8040000F089FF17F8093043F0F1 | ||||
| :40160000020307F8093017F8093003F0FD0307F8093002E00D4600E000252846BDE8F087B592FF1FAC92FF1F70600040431E072B0AD8064A0C2303FB002300225A705A7991 | ||||
| :40164000034BD2B200011A54704700BFDC92FF1FFE5F0040431E072B9FBF024B000108221A547047FE5F004030B51A4A1A491B4D0878138803449BB21380194A00231488E7 | ||||
| :40168000D8B2A4B27CB1082B0CD050680078C0B2E85450680133013050601088013880B21080ECE718460B780E4C082B0E4A00D040B10E4D2B7883F080032B700F23237022 | ||||
| :4016C000022301E0022323701370094B1870087030BD00BF4C93FF1F4893FF1F00600040C492FF1FC192FF1FD692FF1FD292FF1F4993FF1F074B02221A70074B80221A70AE | ||||
| :40170000064B0F221A70064A00231370054A012013707047D692FF1FD292FF1FC192FF1F4893FF1F4993FF1F30B5164B16491B780A8803F00F03023BDBB21A4492B20A80CC | ||||
| :40174000124C134A0020118889B279B173B15568215C013BC9B229705168DBB20131516011880130013989B21180ECE7094A1370094A137883F080031370084B0B221A70DF | ||||
| :4017800030BD00BF296000404C93FF1F00600040C492FF1F4993FF1FD292FF1FC192FF1F064A06231370064A01201370054B80221A70054B00221A70704700BFD692FF1F52 | ||||
| :4017C000C192FF1FD292FF1F4993FF1F054B9A683AB19A68044910709A680988518000229A607047C492FF1F4C93FF1F08B5124B1A78D2B21A701B78DBB21A0602D50F4A1E | ||||
| :40180000137008BD0220FFF7E1FF0D4B1B7803F06003202B05D0402B06D043B900F012FC04E001F0A5FB01E000F046FD10B9034B03221A7008BD00BF28600040C192FF1FC0 | ||||
| :401840000060004008B5084A084B0120197813880B449BB21380064B00221A70FFF7B6FF044B03221A7008BD4C93FF1F4893FF1FD692FF1FC192FF1F08B50C4B1B78DBB25E | ||||
| :40188000042B07D0062B09D0022B0DD1BDE80840FFF7D8BFBDE80840FFF746BF0320FFF795FF034B03221A7008BD00BFD692FF1FC192FF1F08B5054B002201201A70FFF7B6 | ||||
| :4018C00085FF034B03221A7008BD00BFD692FF1FC192FF1F08B50A4B1A7832B11A78094942F080020A7000221A70074B002201201A70FFF76BFF054B03221A7008BD00BFA5 | ||||
| :40190000C092FF1F08600040D692FF1FC192FF1F074B1B78DBB2042B05D0062B05D0022B05D1FFF7A1BEFFF7C5BFFFF7D3BF7047D692FF1F38B51D4C2378DBB2DD0634D51B | ||||
| :4019400018060AD503F00F03012B2ED1FFF74EFF174B1B78190609D538BD5A0602D5FFF7D7FF03E09D0620D5FFF786FF23781B061BD4104B1A78104B1B7813430F4A13705F | ||||
| :401980001278934211D10A4A0849154613782078DBB2000605D41378DBB20B700B7803F00F0328788342F1D138BD38BD28600040C192FF1FD292FF1F4993FF1F29600040AD | ||||
| :4019C000054A00231380054A916819B191680B7092685380704700BF4C93FF1FC492FF1F0E4808B503889BB213B9FFF783FE13E00B4B02221A700B4B00221A70FFF7E0FFAC | ||||
| :401A0000094AD1799379028843EA012392B2934238BF0380FFF728FE012008BDC492FF1FD692FF1FD292FF1F00600040084B01221A700F3B9B7C074B1A7B02F00302012A07 | ||||
| :401A40001EBFDA7B82F08002DA7301225A7370470B600040DC92FF1F094B02221A700F3B93F82230074B1A7E02F00302012A1EBFDA7E82F08002DA7601225A76704700BFFE | ||||
| :401A80000B600040DC92FF1F0B4B04221A700F3B93F83230094B93F8242002F00302012A1EBF93F8272082F0800283F82720012283F82520704700BF0B600040DC92FF1F78 | ||||
| :401AC0000B4B08221A700F3B93F84230094B93F8302002F00302012A1EBF93F8332082F0800283F83320012283F83120704700BF0B600040DC92FF1F7047FFF741BC000081 | ||||
| :401B0000F0B5184B184E19780C27C9B201234FF0000C31B3CA0720D5144A4FEA031E7244947850782040C5070DD507FB03652C79240608D5147804F0FE0414706D790C4C35 | ||||
| :401B4000EDB204F80E50840706D507FB036425792D0658BF84F801C090700133DBB24908D7E7F0BD9F600040DC92FF1F70600040FE5F004000F0ACBC70B50446184B88B021 | ||||
| :401B800003AA03F11006154618685968083303C5B3422A46F7D11B782B70FCB12223237001AD03232846637000F08AFE002220461146AB5C08AC04EB131414F8144C03F053 | ||||
| :401BC0000F03847008AC234413F8143C0132082AC1700371417100F10400EAD108B070BD3F3A00002DE9F0431C4D01222E460C201F274FF0800E4FF0080C194B00FB02580B | ||||
| :401C00001401234418705F70164998F805902144B9F1000F07D098F8044024064CBF887081F802C001E081F802E000FB0261CC880132E4B29C71CC88092AC4F30724DC71A2 | ||||
| :401C4000CC88E4B21C71C988C1F307215971D4D1054BFF221A70BDE8F08300BFDC92FF1F70600040FC5F00400A600040064B074A1B7802EBC30253681A7C824286BF03EB6F | ||||
| :401C8000C003586900207047D092FF1FA03A00002DE9F84F424B1A78002A7ED01878414D0138C0B2FFF7E2FFA8463F4AC3681478007ADFF800C1E4B203EBC0000C260027FE | ||||
| :401CC0004FF0010E834268D01A78A24263D11CF80420597891425ED19A7893F8039002F07F0206FB02FA05EB0A01CF7093F802B009F0030981F804B093F803B005F80AB0A6 | ||||
| :401D0000B3F804A0A1F808A093F902A0BAF1000F0BDAB9F1010F0CBF4FF007094FF00D0981F8059081F801E009E0B9F1010F0CBF4FF005094FF0090981F805904F704FEAA3 | ||||
| :401D400002191A4906FB0282494481F802E0B2F808A0CAF3072A81F800A0B2F808A05FFA8AFA81F801A0B2F806A011495FFA8AFA494481F806A0B2F80690C9F3072981F8FE | ||||
| :401D80000790B2F806905FFA89F981F80490D288C2F307224A71083394E7BDE8F88F00BFD592FF1FDC92FF1FD192FF1FFC5F004070600040C292FF1F08B5064B187801384A | ||||
| :401DC000C0B2FFF753FF20B143681B7900EBC300406908BDD592FF1F00212DE9F84F0B464E4E0C2707FB01F401313219092933554FF000059370494CD37013819372537031 | ||||
| :401E00005371EFD118B1464B1D70464B1D70464B1A78002A7FD0187801250138C0B2FFF725FFA8464368DFF8F8E0DB790C2713F0400F3E4B4FF0000C1A7814BF42F0010273 | ||||
| :401E400002F0FE021A70027AD20007FB0541C36803EB02094B4531D093F802A00AF07F06AE4229D10E89B3F804B0B6B25E4538BFA1F808B01E7893F801B01EF80660B34576 | ||||
| :401E80001AD181F804A0DE780E7093F902A0DE78BAF1000F06F0030607DA012E0CBF07260D264E7181F8018006E0012E0CBF052609264E7181F801C00833CBE70135092D89 | ||||
| :401EC000C3D1C1680A328B1C0A440C200833934209D013F8081C13F80A5C01F07F0100FB01418D72F2E7FFF767FF114B0121186000230C2000FB0142D38012890131134463 | ||||
| :401F00009BB203F00102134409299BB2F2D1BDE8F84FFFF767BEBDE8F88F00BFDC92FF1FC292FF1F4A93FF1FD592FF1FD392FF1FD892FF1F114B1B7903F07F035A1E072A3C | ||||
| :401F400019D80F490C2202FB031291781B0141F0010191700021D170517841F002015170127912F0800F074A1A4414BF8D2389239370FFF715BC0020704700BF0060004065 | ||||
| :401F8000DC92FF1FFC5F004030B4194B1A7902F07F02531E072B27D8164B0C2404FB02339978154D01F0FE0199700021D97029461201505D114400F07F0050555A7802F013 | ||||
| :401FC000FD025A701A795B78120605D5012B01D18C7006E00D2303E0012B0CBF082309238B7030BCFFF7DCBB002030BC704700BF00600040DC92FF1FFC5F004010B50D4BA5 | ||||
| :402000000D4C21791878C9B20138C0B2FFF72EFE43681B798B4201D2012909D8074A0848535CDBB24354A3780120DBB2535410BD002010BDD592FF1F00600040C292FF1FB6 | ||||
| :402040004A93FF1F38B58A4A8A4C13780021DBB221801806517840F18D800A2900F20581DFE811F05D00030103010301030103010B0003017E0003018200D3787C49012B9C | ||||
| :4020800009D17D4B1A787D4B03EBC2035B685B686360122310E0CB78022B12D18878FFF7E5FD002800F0E180436863606368DA7863689B7843EA02232380BDE83840FFF7EE | ||||
| :4020C0008FBCCB78032B26D16D4B00228878D5B2854209D3664A91786A4AEE2908BF1346634A917881B106E0187801320028F1D018780344EAE764499278097C914203D180 | ||||
| :402100006248FFF739FD614B1A78002A00F0AD801A78228018E0BDE8384000F029BF13F0030313D0022B40F0A0802380504B0C211B7903F07F02564B01FB02339A78554BC3 | ||||
| :40214000D2B21A7000225A706360B6E702222280514A11784F4AC9B2117053706260ACE7012323804D4BEFE70123238013794C4A1344E9E701390A2977D8DFE801F0377608 | ||||
| :402180004F76067676760A7620009378454ADBB25AE0937803F0FF0153B9404B1A7891425FD01970404B01201870FFF715FE58E0481EC0B2FFF75AFD0028EED155E0FFF793 | ||||
| :4021C0001DFF002851D02A4A384913791279DBB2D2B20A70364A3249D25CCB5C9A4240D0314B01221A70FFF753FD3AE003F00303012B2BD009D3022B37D11D4B9B78002B47 | ||||
| :4022000033D1BDE83840FFF7BFBE194B9B78012B2BD1214A137803F0FD0315E003F00303012B13D008D3022B1FD1114B9B78E3B9BDE83840FFF77EBE0D4B9B78012B14D1B7 | ||||
| :40224000154A137843F0020313700AE0084B1A795AB998781B791749DBB2CA5C22EA0002CA54BDE83840FFF79BBA002038BD00BF00600040C492FF1FD092FF1FA03A000049 | ||||
| :40228000043B00008C3A0000773B00006893FF1FDC92FF1F8192FF1FD392FF1FD592FF1FC292FF1FC092FF1FD492FF1FD192FF1F4A93FF1FD792FF1F074B1A78120609D546 | ||||
| :4022C0005B78012B06D1054B054A5A6012781A80FFF786BB0020704700600040C492FF1F643A0000014B1870704700BF7A640040014B1878704700BF6B650040014B18702D | ||||
| :40230000704700BF79640040064A0123136002F688321268E0211064034A1170A2F540721360704780E100E000E400E0014B1870704700BF7A650040014B1870704700BF89 | ||||
| :402340007865004073B515461E460B4C05230022019200920A4601461846237000F064F932462946207800F01FF90221207800F009F9207802B070BDD080FF1F064A04232E | ||||
| :40238000136002F688321268E0219064034A1170A2F202321360704780E100E002E400E0014B04221A60704700E100E0014B04221A60704780E100E0014B1870704700BF30 | ||||
| :4023C0007E640040704738B505460078012428B100F066FD285D0134E4B2F8E738BD08B50D2000F05DFDBDE808400A2000F058BDF7B516461F460B4C002303250193009359 | ||||
| :402400000A4601462846257000F00EF93A463146207800F0C9F80221207800F0B3F8207803B0F0BDE080FF1FF7B516461F460B4C00230225019300930A4601462846257030 | ||||
| :4024400000F0F2F83A463146207800F0ADF82946207800F097F8207803B0F0BDE180FF1FF7B516461F460B4C00230125019300930A4601462846257000F0D6F83A463146DE | ||||
| :40248000207800F091F80221207800F07BF8207803B0F0BDE280FF1F73B515461E460B4C0023019300930A4601461846237000F0BBF832462946207800F076F8022120782A | ||||
| :4024C00000F060F8207802B070BD00BFE380FF1F024B1878C0F38010704700BF8F450040074A7F23802113705170064A013BDBB202F80839002BF9D1034A1370704700BFCC | ||||
| :40250000E480FF1FF87B00400078004017280FD8084B0001C25C11B142F0200201E002F0DF02C254C25C42F00102C25400207047012070471070004017280BD8064B0001EA | ||||
| :40254000C25C02F0FE02C254C25C02F0DF02C25400207047012070471070004017280DD8074900010B4603441A7942F004021A71435C43F001034354002070470120704740 | ||||
| :402580001070004017280BD8064A0001835C490003F0F10301F00E011943815400207047012070471070004041F6FF73994208BF4FF400519A4208BF4FF4005217289FBF85 | ||||
| :4025C000C00000F1804000F5EC4081809ABFC280002001207047000017289FBF034B00011954002088BF0120704700BF1970004017289FBF054B00011A5C01F007019DBFDC | ||||
| :402600001143195400200120704700BF1470004017289FBF034B0001185C00F0070088BFFF20704714700040172810B51AD8C00001F07F0100F1804441EAC21204F5EC4422 | ||||
| :40264000D2B222709DF8082003F00F0343EA0213DBB263709DF80C30002003F00F03A370E07010BD012010BD10B500F079FC0A4A5378182B0AD91478013B5370E30003F1FB | ||||
| :40268000804303F5F0431B78137000E0FF2400F06BFC204610BD00BFE480FF1F030610B5044611D400F05CFC084AE300117803F1804303F5F0431970537814700133537094 | ||||
| :4026C000BDE8104000F050BC10BD00BFE480FF1F30B504060CD411F4704509D1C40004F1804404F5F0442180A270E370284630BD012030BD03065FBFC00000F1804000F5D2 | ||||
| :40270000F04081805ABFC280002001207047000038B50446084DB4F5004F05D9286800F017FCA4F50044F6E7034B58686043BDE8384000F00DBC00BFEC80FF1F024B1B7AB4 | ||||
| :40274000584300F005BC00BFEC80FF1F0E4B00F003001A78490102F0FC02104318701A7801F0600142F080021A701A7802F07F021A701A7802F09F020A431A701A7842F060 | ||||
| :4027800010021A70704700BF83430040014B01221A70704784430040044B00F00F021B6853F8220043F82210704700BF08ED00E0054A00F01F00126800F1100352F8230009 | ||||
| :4027C00042F82310704700BF08ED00E000F01F0000F16040490100F56440C9B2017070470F4B10B50F4900240F205C609C60DC601C615C61FFF7D0FF0B4A136843F0040334 | ||||
| :4028000013600A4B4FF47A72DB68B3FBF2F3084A1360084B4FF400421C60C3F8E82010BD8492FF1F8D28000010E000E0EC80FF1F14E000E018E000E0024A136843F0020334 | ||||
| :402840001360704710E000E008B5FFF7F5FF034A136843F00103136008BD00BF10E000E010B5054CA3691BB9FFF7BAFF0123A361BDE81040FFF7E8BF8492FF1F024B186891 | ||||
| :40288000C0F30040704700BF10E000E038B5FFF7F5FF012808D1054D002455F8243003B198470134052CF8D138BD00BF8892FF1F024B03EB80035868596070478492FF1F1F | ||||
| :4028C000134B144A1B78DBB20360127843EA0223114A0360127843EA0243104A0360127843EA026303600E4B0E4A1B78DBB24360127843EA02230C4A4360127843EA024382 | ||||
| :402900000A4A4360127843EA02634360704700BF0301004904010049EC460040020100490101004900010049050100490601004910B500F015FB204A044613780A2043F07D | ||||
| :4029400002031370137C43F00203137412F80A3C43F0010302F80A3C937943F00103937102F5AB52137843F003031370134B18221A7013F8012C42F0400203F8012C13F837 | ||||
| :40298000012C02F0FC0203F8012CCE2203F8062CA3F597530222183B1A70094A137843F008031370FFF7CAFE064B10222046BDE810401A6000F0D8BAAB4300400E59004026 | ||||
| :4029C0002F5B004080E200E008B500F0C9FA0F4A137803F0FE031370A2F5AA521D3A137803F0FD031370137C03F0FD03137412F80A3C03F0FE0302F80A3C937903F0FE0388 | ||||
| :402A00009371BDE8084000F0AFBA00BF08590040044A137803F03F0343EA8010C0B21070704700BF08590040082804D00A280CBF8223C22300E0422308380E4AC0B2042812 | ||||
| :402A4000137098BF0C4B4FF0000298BF33F910100A4B88BF11461A8042F210734B4341F2883103F6C41393FBF1F305490B60054B1A8070470A590040503A00005293FF1FB7 | ||||
| :402A80005493FF1F5893FF1F08B5102000F0A6F907210420FFF79AFE07490420FFF788FE064A0C20137843F006031370FFF7BCFF034B00221A8008BD812B0000095900402E | ||||
| :402AC0005093FF1F10B5054C23781BB9FFF7DCFF01232370BDE81040FFF72ABFA092FF1F044B1A7802F0FB021A701A7842F001021A7070470859004010B5084B1C7814F0F1 | ||||
| :402B0000010403D10028F9D0002404E02046FFF715FE024B1B78204610BD00BF09590040034A044B1B881088181A00B2704700BF5893FF1FA25B00400E4A13881BB223B1D5 | ||||
| :402B400011880A2309B2594301E00B4B19680B4B1B88C01A42F2107300B203FB00F2022391FBF3F30028D8BF5B42134493FBF1F000B270475293FF1F5493FF1F5093FF1F29 | ||||
| :402B80007047000010B500F0EBF9214A044613780A2043F001031370137C43F00103137412F80A3C43F0020302F80A3C937943F00203937102F5AA521832137843F0030343 | ||||
| :402BC0001370144B18221A7013F8012C42F0400203F8012C13F8012C02F0FC0203F8012CCE2203F8062CA3F597530222123B1A70094A137843F008031370FFF79FFD074BEE | ||||
| :402C000008222046BDE810401A6000F0ADB900BFAB43004006590040275B004080E200E008B500F09DF90F4A137803F0FE031370A2F5AA52153A137803F0FE031370137C9E | ||||
| :402C400003F0FE03137412F80A3C03F0FD0302F80A3C937903F0FD039371BDE8084000F083B900BF00590040044A137803F03F0343EA8010C0B21070704700BF0059004016 | ||||
| :402C8000082804D00A280CBF8223C22300E0422308380E4AC0B20428137098BF0C4B4FF0000298BF33F910100A4B88BF11461A8042F210734B4341F2883103F6C41393FBDD | ||||
| :402CC000F1F305490B60054B1A807047025900405A3A00005E93FF1F6493FF1F5C93FF1F08B5102000F084F807210320FFF76EFD07490320FFF75CFD064A0C20137843F035 | ||||
| :402D000006031370FFF7BCFF034B00221A8008BDD92D0000015900406093FF1F10B5054C23781BB9FFF7DCFF01232370BDE81040FFF728BFA192FF1F044B1A7802F0FB02D6 | ||||
| :402D40001A701A7842F001021A7070470059004010B5084B1C7814F0010403D10028F9D0002404E02046FFF7E9FC024B1B78204610BD00BF01590040034A044B1B88108822 | ||||
| :402D8000181A00B2704700BF5C93FF1FA05B00400E4A13881BB223B111880A2309B2594301E00B4B19680B4B1B88C01A42F2107300B203FB00F2022391FBF3F30028D8BF86 | ||||
| :402DC0005B42134493FBF1F000B270475E93FF1F6493FF1F6093FF1F70470000034A00F0F800137803431370704700BF02410040034A00F0F800137803431370704700BF9A | ||||
| :402E000006410040014B1870704700BF78640040014B1870704700BF7965004073B515461E460B4C04230022019200920A46014618462370FFF7F8FB324629462078FFF7AB | ||||
| :402E4000B3FB02212078FFF79DFB207802B070BDFC80FF1F074A0223136002F688321268E0215064044A11706FF440710A441360704700BF80E100E001E400E0014B18708C | ||||
| :402E8000704700BF7C640040014B1870704700BF7B640040014B1870704700BF7F640040FEB5494652465B460EB40746244909688A46244A12682448022100F071F803009B | ||||
| :402EC00020480068C018204900F06AF8143883460121C9430C460125002600F041F8814651460B7823400B705846013000F030F83800F04028400B78234003430B705846AA | ||||
| :402F000000F026F80136072EF2D9002001300138013001200B78234003430B705846043000F016F8484600F01FF800BF00BF00BF0EBC894692469B46FEBD00BFAFF3008039 | ||||
| :402F4000D480FF1FF880FF1F00C20100000000000230800803D000BF01380046FCD17047EFF3108072B6704780F31088704700BF094A137803F00303012B0AD0022B09D181 | ||||
| :402F800013790C2103F07F02044B01FB02339B7A00E013790020704700600040DC92FF1F002902D0B0FBF1F0704708B14FF0FF3000F008B80029F8D00246B0FBF1F000FB0B | ||||
| :402FC00011217047704700BF014B1868704700BF6081FF1F0E4B70B51E460E4C0025E41AA410A54204D056F8253098470135F8E700F0DEFD084B094C1E46E41AA41000251E | ||||
| :40300000A54204D056F8253098470135F8E770BDBC3B0000BC3B0000BC3B0000C43B000003460244934202D003F8011BFAE7704730B5141E05469BB0184604DA8B232B6026 | ||||
| :403040004FF0FF301DE04FF40273ADF80C300CBF234604F1FF33029305934FF6FF7300910491ADF80E3002461E9B6946284600F073F8431CBCBF8B232B6014B1009B0022F6 | ||||
| :403080001A701BB030BD000007B5009313460A46014603480068FFF7CBFF03B05DF804FB6081FF1F2DE9F0478E6882469E420C46914698463ED88A8912F4906F3AD025685F | ||||
| :4030C000096902236F1A656905EB450595FBF3F57B1C43449D4238BF1D4653050FD5294600F04AFB064698B13A46216900F0D2FAA38923F4906343F08003A38113E02A462B | ||||
| :4031000000F098FB064670B92169504600F0E8FA0C23CAF80030A3894FF0FF3043F04003A381BDE8F08726613E44266046466561ED1BA560464528BF4646494632462068B9 | ||||
| :4031400000F0B3FAA36800209B1BA36023681E442660BDE8F08700002DE9F04F9DB003938B8980461C060D4616460DD50B695BB9402100F001FB2860286118B90C23C8F8D4 | ||||
| :403180000030CDE040236B610023099320238DF82930DFF89CB130238DF82A3037463C4614F8013B1BB9B7EB060910D003E0252BF9D02746F3E74B46324629464046FFF7EA | ||||
| :4031C00071FF013000F0A780099B4B4409933B78002B00F0A08000234FF0FF3204930793059206938DF853301A930126052221784E4800F041FA671C049B38B14B4A3C46E7 | ||||
| :40320000801A06FA00F018430490EFE7D90644BF20228DF853201A0744BF2B228DF8532022782A2A03D0079A00210A200BE0039A111D12680391002A10DA524243F002006C | ||||
| :40324000079204900BE027463B780134303B092B03D800FB02320121F5E701B107923B782E2B1ED17B782A2B0AD1039B02371A1D1B680392002BB8BF4FF0FF33059310E010 | ||||
| :40328000002319460593781C0A2407463A780130303A092A03D804FB01210123F5E703B1059103223978224800F0E6F940B14023CBEB000003FA00F0049B01371843049053 | ||||
| :4032C000397806221B487E1C8DF8281000F0D4F988B1194B33B9039B073323F007030833039314E003AB00932A46144B04A94046AFF3008007E003AB00932A460F4B04A937 | ||||
| :40330000404600F093F8B0F1FF3F824603D0099B5344099342E7AB895B0601D4099801E04FF0FF301DB0BDE8F08F00BF8B3B0000913B0000953B000000000000A5300000D1 | ||||
| :403340002DE9F04791461F460A698B6806469342B8BF1346C9F8003091F843200C46DDF8208012B10133C9F800302368990642BFD9F800300233C9F80030256815F00605F2 | ||||
| :4033800010D104F1190A07E00123524639463046C04701301AD00135E368D9F800209B1A9D42F1DB94F843302268003318BF012392060FD5E118302081F843005A1C94F84E | ||||
| :4033C00045102244023382F8431003E04FF0FF30BDE8F08704F1430239463046C0470130F4D02268D9F80050E36802F00602042A08BF5D1B2269A3680CBF25EAE57500252C | ||||
| :403400009342C4BF9B1AED184FF000091A344D4509D00123224639463046C0470130D5D009F10109F3E70020BDE8F0872DE9F04317460A7E85B06E2A984606460C460C9BE3 | ||||
| :4034400001F1430E00F0AE8011D8632A22D009D8002A00F0BB80582A40F0CA8081F84520834955E0642A1ED0692A1CD0C0E0732A00F0B08009D86F2A2ED0702A40F0B880A0 | ||||
| :403480000A6842F020020A603EE0752A24D0782A3AD0ADE01A6801F14205111D1960136884F84230A8E021681A6811F0800F02D0111D196008E011F0400F02F104011960E2 | ||||
| :4034C00002D0B2F9003000E01368002B3CDA2D225B4284F8432037E021681A6811F0800F02D0111D196007E011F0400F02F10401196001D0138800E01368227E5C496F2A40 | ||||
| :4035000014BF0A2208221BE078225A4984F845202268186812F0800F00F104051D6003D1550601D5038800E00368D00744BF42F0200222601BB9226822F020022260102266 | ||||
| :40354000002084F8430001E049490A226568002DA56008DB206820F0040020602BB9002D7DD175460CE0002B79D07546B3FBF2F002FB1033CB5C05F8013D03460028F5D131 | ||||
| :40358000082A0BD12368DA0708D5236962689A42DEBF302305F8013C05F1FF35C5EB0E0323612EE008681A6810F0800F496903D0101D1860136808E010F0400F02F1040087 | ||||
| :4035C0001860136801D0198000E0196000232361754616E01A68111D1960156800216268284600F049F808B1401B6060636804E004F1420584F8422001232361002384F8A9 | ||||
| :403600004330CDF800803B4603AA21463046FFF797FE013002D14FF0FF3026E023692A4639463046C0470130F5D023689B0710D5002504F1190907E001234A4639463046F8 | ||||
| :40364000C0470130E7D00135E368039A9B1A9D42F2DBE068039B9842B8BF184605E00B7804F1420584F842308AE705B0BDE8F0833F3A00009C3B000010B5C9B202449042CF | ||||
| :40368000034605D01C7801308C42F8D1184610BD002010BD10B5431E0A44914204D011F8014B03F8014FF8E710BD884210B501EB020301D8421E0BE09842FBD28118D21A41 | ||||
| :4036C000D34204D013F8014D01F8014DF8E710BD994204D011F8014B02F8014FF8E710BD38B50546002944D051F8043C0C1F002BB8BFE41800F0D4F81E4A1368114613B912 | ||||
| :403700006360146030E0A3420DD92268A018834201BF18685B681218226063600C6023E0A24203D813465A68002AF9D118681918A1420BD12168014458188242196013D1F2 | ||||
| :4037400010685268014419605A600DE002D90C232B6009E021686018824201BF106852680918216062605C602846BDE8384000F098B838BDA892FF1F70B5CD1C25F003051A | ||||
| :4037800008350C2D38BF0C25002D064601DBA94202D90C23336046E000F082F8234B1C681A462146A1B10B685B1B0ED40B2B03D90B60CC18CD501EE08C420BBF63684B6896 | ||||
| :4037C0001360636018BF0C4615E00C464968E9E7174C23681BB9304600F052F820602946304600F04DF8431C18D0C41C24F00304A0420DD12560304600F053F804F10B005E | ||||
| :40380000231D20F00700C31A0ED05A42E25070BD211A304600F034F80130EBD10C233360304600F03EF8002070BD00BFA892FF1FA492FF1FF8B5074615460E4621B91146D1 | ||||
| :40384000BDE8F840FFF798BF1AB9FFF749FF2846F8BD00F027F885420ED929463846FFF78BFF044650B131462A46FFF713FF31463846FFF735FF01E03046F8BD2046F8BD40 | ||||
| :4038800038B5064C0023054608462360FDF7D8FB431C02D1236803B12B6038BD8C93FF1F7047704751F8040C0028BEBF091851F8043CC018043870470000000005020902A2 | ||||
| :4038C0000B020D020F021102130215027265706C792030782530327800686F6D696E6700626567696E6E696E67207365656B2066726F6D20256420746F2025640066696E08 | ||||
| :403900006973686564207365656B00796573006E6F00647269766520303A20257320647269766520313A2025730057616974696E6720666F72205553422E2E2E00555342F3 | ||||
| :4039400020726561647900636F6D6D616E6420307825303278006661696C2025642B25642B2564203D3D2025642C206E6F74202564007061737365643D256400756E646544 | ||||
| :403980007272756E206166746572202564207061636B65747300636F756E743D256420693D256420643D256400636D645F777269746500703D25642063723D256420637729 | ||||
| :4039C0003D256420663D256420773D256420696E6465783D256420756E64657272756E3D256400756E64657272756E21007375636365737300737461727420657261736912 | ||||
| :403A00006E670073746F702065726173696E670069646C650000510040100040510040300000000140001000140140000800400140000A004C0140000200500140200030F9 | ||||
| :403A400031323334353637383941424344454600000100000004000000100001000000040000001028000000000104000100000000000000000157494E5553420000303043 | ||||
| :403A800030303100000000000000000012034D005300460054003100300030000100000001000000A83A000001000000773B0000000000000000000001000000C03A000003 | ||||
| :403AC00001000000493B000004000000E23A0000000000000000000000000000E03A0000FF00000001024000FF00000082024000FF00000003034000FF00000084034000F7 | ||||
| :403B0000FF00020304030904160346006C007500780045006E00670069006E0065002A0343006F0077006C00610072006B00200054006500630068006E006F006C006F0003 | ||||
| :403B400067006900650073000009022E0001010080320904000004FF00000107050102400000070582024000000705030340000A0705840340000A12010002FF0001080921 | ||||
| :403B800012006E0100020180014300232D302B2000686C4C00656667454647003031323334353637383961626364656600000000F8B500BFF8BC08BC9E4670475900000094 | ||||
| :403BC000BD100000F8B500BFF8BC08BC9E46704735000000E83B0000C880FF1FA00000002812000000000000000000009093FF1FFF000000675000400C0000000700000097 | ||||
| :403C0000FFFFFFFF7F8000003F0000000000007D00FA0000400000000090D003FF000000000000000000000000000000000000000000000000000000000000000000000031 | ||||
| :403C4000893B000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080 | ||||
| :403C80000081FF1F00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000065 | ||||
| :403CC00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000C4 | ||||
| :403D00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000083 | ||||
| :403D40000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000043 | ||||
| @@ -4615,12 +4615,12 @@ | ||||
| :0200000490105A | ||||
| :04000000BC90ACAF55 | ||||
| :0200000490303A | ||||
| :0200000096F078 | ||||
| :02000000CEC56B | ||||
| :0200000490402A | ||||
| :4000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000C0 | ||||
| :400040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080 | ||||
| :400080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040 | ||||
| :4000C0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 | ||||
| :0200000490501A | ||||
| :0C00000000012E16106900002E2FA759D9 | ||||
| :0C00000000012E16106900002E2FDF2ECC | ||||
| :00000001FF | ||||
| @@ -21,6 +21,10 @@ static bool drive1_present; | ||||
|  | ||||
| static volatile uint32_t clock = 0; /* ms */ | ||||
| static volatile bool index_irq = false; | ||||
| /* Duration in ms. 0 causes every pulse to be an index pulse. Durations since | ||||
|  * last pulse greater than this value imply sector pulse. Otherwise is an index | ||||
|  * pulse. */ | ||||
| static volatile uint32_t hardsec_index_threshold = 0; | ||||
|  | ||||
| static bool motor_on = false; | ||||
| static uint32_t motor_on_time = 0; | ||||
| @@ -69,12 +73,34 @@ static void system_timer_cb(void) | ||||
|  | ||||
| CY_ISR(index_irq_cb) | ||||
| { | ||||
|     index_irq = true; | ||||
|     /* Hard sectored media has sector pulses at the beginning of every sector | ||||
|      * and the index pulse is an extra pulse in the middle of the last sector. | ||||
|      * When the extra pulse is seen, the next sector pulse is also the start of | ||||
|      * the track. */ | ||||
|     static bool hardsec_index_irq_primed = false; | ||||
|     static uint32_t hardsec_last_pulse_time = 0; | ||||
|  | ||||
|     if (!hardsec_index_threshold) | ||||
|     { | ||||
|         index_irq = true; | ||||
|         hardsec_index_irq_primed = false; | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         index_irq = hardsec_index_irq_primed; | ||||
|         if (index_irq) | ||||
|             hardsec_index_irq_primed = false; | ||||
|         else | ||||
|             hardsec_index_irq_primed = | ||||
|                 clock - hardsec_last_pulse_time <= hardsec_index_threshold; | ||||
|         hardsec_last_pulse_time = clock; | ||||
|     } | ||||
|      | ||||
|     /* Stop writing the instant the index pulse comes along; it may take a few | ||||
|      * moments for the main code to notice the pulse, and we don't want to overwrite | ||||
|      * the beginning of the track. */ | ||||
|     ERASE_REG_Write(0); | ||||
|     if (index_irq) | ||||
|         ERASE_REG_Write(0); | ||||
| } | ||||
|  | ||||
| CY_ISR(capture_dma_finished_irq_cb) | ||||
| @@ -269,7 +295,7 @@ static void cmd_recalibrate(void) | ||||
|     send_reply(&r);     | ||||
| } | ||||
|      | ||||
| static void cmd_measure_speed(struct any_frame* f) | ||||
| static void cmd_measure_speed(struct measurespeed_frame* f) | ||||
| { | ||||
|     start_motor(); | ||||
|      | ||||
| @@ -288,10 +314,14 @@ static void cmd_measure_speed(struct any_frame* f) | ||||
|  | ||||
|     if (elapsed != 0) | ||||
|     { | ||||
|         index_irq = false; | ||||
|         int target_pulse_count = f->hard_sector_count + 1; | ||||
|         start_clock = clock; | ||||
|         while (!index_irq) | ||||
|             elapsed = clock - start_clock; | ||||
|         for (int x=0; x<target_pulse_count; x++) | ||||
|         { | ||||
|             index_irq = false; | ||||
|             while (!index_irq) | ||||
|                 elapsed = clock - start_clock; | ||||
|         } | ||||
|     } | ||||
|      | ||||
|     DECLARE_REPLY_FRAME(struct speed_frame, F_FRAME_MEASURE_SPEED_REPLY); | ||||
| @@ -404,10 +434,12 @@ static void cmd_read(struct read_frame* f) | ||||
|          | ||||
|     if (f->synced) | ||||
|     { | ||||
|         hardsec_index_threshold = f->hardsec_threshold_ms; | ||||
|         index_irq = false; | ||||
|         while (!index_irq) | ||||
|             ; | ||||
|         index_irq = false; | ||||
|         hardsec_index_threshold = 0; | ||||
|     } | ||||
|      | ||||
|     dma_writing_to_td = 0; | ||||
| @@ -596,6 +628,7 @@ static void cmd_write(struct write_frame* f) | ||||
|                 /* Wait for the index marker. While this happens, the DMA engine | ||||
|                  * will prime the FIFO. */ | ||||
|  | ||||
|                 hardsec_index_threshold = f->hardsec_threshold_ms; | ||||
|                 index_irq = false; | ||||
|                 while (!index_irq) | ||||
|                     ; | ||||
| @@ -630,6 +663,7 @@ abort: | ||||
|     } | ||||
|      | ||||
|     print("p=%d cr=%d cw=%d f=%d w=%d index=%d underrun=%d", packets, count_read, count_written, finished, writing, index_irq, dma_underrun); | ||||
|     hardsec_index_threshold = 0; | ||||
|     if (!finished) | ||||
|     { | ||||
|         /* There's still some data to read, so just read and blackhole it --- | ||||
| @@ -663,6 +697,7 @@ static void cmd_erase(struct erase_frame* f) | ||||
|     /* Disk is now spinning. */ | ||||
|      | ||||
|     print("start erasing"); | ||||
|     hardsec_index_threshold = f->hardsec_threshold_ms; | ||||
|     index_irq = false; | ||||
|     while (!index_irq) | ||||
|         ; | ||||
| @@ -671,6 +706,7 @@ static void cmd_erase(struct erase_frame* f) | ||||
|     while (!index_irq) | ||||
|         ; | ||||
|     ERASE_REG_Write(0); | ||||
|     hardsec_index_threshold = 0; | ||||
|     print("stop erasing"); | ||||
|  | ||||
|     DECLARE_REPLY_FRAME(struct any_frame, F_FRAME_ERASE_REPLY); | ||||
| @@ -796,7 +832,7 @@ static void handle_command(void) | ||||
|             break; | ||||
|          | ||||
|         case F_FRAME_MEASURE_SPEED_CMD: | ||||
|             cmd_measure_speed(f); | ||||
|             cmd_measure_speed((struct measurespeed_frame*) f); | ||||
|             break; | ||||
|              | ||||
|         case F_FRAME_BULK_WRITE_TEST_CMD: | ||||
|   | ||||
							
								
								
									
										19
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										19
									
								
								README.md
									
									
									
									
									
								
							| @@ -24,6 +24,14 @@ Don't believe me? Watch the demo reel! | ||||
| <iframe width="373" height="210" src="https://www.youtube.com/embed/m_s1iw8eW7o" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe> | ||||
| </div> | ||||
|  | ||||
| **New!** The FluxEngine client software now works with | ||||
| [GreaseWeazle](https://github.com/keirf/Greaseweazle/wiki) hardware. So, if you | ||||
| can't find a PSoC5 development kit, or don't want to use the Cypress Windows | ||||
| tools for programming it, you can use one of these instead. Very nearly all | ||||
| FluxEngine features are available with the GreaseWeazle and it works out-of-the | ||||
| box. See the [dedicated GreaseWeazle documentation page](doc/greaseweazle.md) | ||||
| for more information. | ||||
|  | ||||
| **Important note.** On 2020-04-02 I changed the bytecode format (and firmware). | ||||
| Flux files will need to be upgraded with `fluxengine upgradefluxfile`. The new | ||||
| format should be more reliable and use way, way less bandwidth. Sorry for the | ||||
| @@ -52,8 +60,15 @@ following friendly articles: | ||||
|   - [Using a FluxEngine](doc/using.md) ∾ what to do with your new hardware ∾ | ||||
|     flux files and image files ∾ knowing what you're doing | ||||
|  | ||||
|   - [Troubleshooting dubious disks](doc/problems.md) ∾ it's not an exact science ∾ | ||||
|     the sector map ∾ clock detection and the histogram | ||||
|   - [Using GreaseWeazle hardware with the FluxEngine client | ||||
| 	software](doc/greaseweazle.md) ∾ what works ∾ what doesn't work ∾ where to | ||||
| 	go for help | ||||
|  | ||||
|   - [Troubleshooting dubious disks](doc/problems.md) ∾ it's not an exact | ||||
| 	science ∾ the sector map ∾ clock detection and the histogram | ||||
|  | ||||
|   - [Checking your drive](doc/driveresponse.md) ∾ you can't do that with that ∾ | ||||
| 	measuring your drive's ability to work with exotic formats | ||||
|  | ||||
| Which? | ||||
| ------ | ||||
|   | ||||
| @@ -19,7 +19,7 @@ static DoubleFlag postIndexGapUs( | ||||
| static DoubleFlag clockCompensation( | ||||
| 	{ "--clock-compensation-factor" }, | ||||
| 	"Scale the output clock by this much.", | ||||
| 	.9724); | ||||
| 	1.0); | ||||
|  | ||||
| static bool lastBit; | ||||
|  | ||||
|   | ||||
| @@ -184,7 +184,7 @@ well, although on Windows it'll need MSYS2 and mingw32. You'll need to | ||||
| install some support packages. | ||||
|  | ||||
|   - For Linux (this is Ubuntu, but this should apply to Debian too): | ||||
| 	`ninja-build`, `libusb-1.0-0-dev`, `libsqlite3-dev`. | ||||
| 	`ninja-build`, `libusb-1.0-0-dev`, `libsqlite3-dev`, `zlib1g-dev`. | ||||
|   - For OSX with Homebrew: `ninja`, `libusb`, `pkg-config`, `sqlite`. | ||||
|   - For Windows with MSYS2: `make`, `ninja`, `mingw-w64-i686-libusb`, | ||||
| 	`mingw-w64-i686-sqlite3`, `mingw-w64-i686-zlib`, `mingw-w64-i686-gcc`. | ||||
|   | ||||
							
								
								
									
										81
									
								
								doc/driveresponse.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										81
									
								
								doc/driveresponse.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,81 @@ | ||||
| Analysing drive response | ||||
| ======================== | ||||
|  | ||||
| Not all PC drives are made equal. Some are less equal than others. | ||||
|  | ||||
| The way floppy disk storage works is that the floppy drive controller will | ||||
| generate a series of pulses, which the drive stores on the disk. Then, when the | ||||
| disk is read, the drive will reproduce the same series of pulses and return it | ||||
| to the floppy drive controller. The data is stored in the intervals between | ||||
| pulses. | ||||
|  | ||||
| The problem is that some PC drives assume that they're going to be used with | ||||
| IBM scheme disks, which use particular pulse intervals --- in the case of DD | ||||
| disks, intervals are always 4us, 6us or 8us. So, in a misguided attempt to | ||||
| improve reliability, they sometimes... tidy... the incoming pulse stream. This | ||||
| can have nasty effects if you're not a disk which _doesn't_ use those intervals. | ||||
|  | ||||
| In addition, they won't work properly if the intervals are too great, or too | ||||
| small. Partly this is a limitation of the underlying physics of the magnetic | ||||
| media, and partly it's due to the drive's automatic gain adjustment: if the | ||||
| drive doesn't see a pulse, it'll start ramping up the gain of its amplifier, | ||||
| until it starts interpreting random noise as a valid pulse. | ||||
|  | ||||
| FluxEngine has a tool to analyse a drive and report on this behaviour. It works | ||||
| by writing a sequence of timed pulses to the disk, then reading them back and | ||||
| seeing what the drive actually reports. To use it, do: | ||||
|  | ||||
| ``` | ||||
| fluxengine analyse driveresponse -d :d=1:t=0 --min-interval-us=0 --max-interval-us=30 --interval-step-us=.1 --write-csv=driveresponse.csv | ||||
| python3 scripts/driveresponse.csv | ||||
| ``` | ||||
|  | ||||
| This will scan all intervals from 0us to 30us, at 0.1us steps, and write the | ||||
| result as a CSV file. Then the Python script uses matplotlib to render the | ||||
| result as a heatmap. They look like this. | ||||
|  | ||||
| (Click to expand) | ||||
|  | ||||
| <div style="text-align: center"> | ||||
| <a href="sony-mpf920-dd.png"><img src="sony-mpf920-dd.png" style="width:40%" alt="Sony MPF-920, DD"></a> | ||||
| <a href="sony-mpf920-hd.png"><img src="sony-mpf920-hd.png" style="width:40%" alt="Sony MPF-920, HD"></a> | ||||
| </div> | ||||
|  | ||||
| This is the analysis from the [Sony | ||||
| MPF-920](https://docs.sony.com/release/MPF920Z.pdf) 3.5" drive I mostly use for | ||||
| testing. The left-hand image shows the result from a DD disk, while the right | ||||
| hand image shows the result from a HD disk. | ||||
|  | ||||
| The vertical axis is the width of pulse being written; the horizontal axis | ||||
| and heatmap shows the distribution of pulses being read back. You can see the | ||||
| diagonal line, which represents correct pulses. The triangular smear in the top | ||||
| left shows spurious pulses which are being read back because the interval is | ||||
| too great; these start at about 12us for DD disks and 7us for HD disks. This is | ||||
| an artifact of the different magnetic media for the two types of disk. | ||||
|  | ||||
| (This, by the way, is why you shouldn't use DD formats on HD disks. The | ||||
| intervals on a DD disk can go up to 8us, which is on the edge of the ability of | ||||
| an HD disk and drive to correctly report back the pulses.) | ||||
|  | ||||
| You also note the hard cut-off on the left: this represents the filter on the | ||||
| drive, which will simply refuse to report pulse intervals shorter than about | ||||
| 1.5us. FluxEngine itself can't write intervals shorter than 2us. | ||||
|  | ||||
| For comparison purposes, here's another set of graphs. | ||||
|  | ||||
| <div style="text-align: center"> | ||||
| <a href="fdd-90206-dd.png"><img src="fdd-90206-dd.png" style="width:40%" alt="FDD-90206, DD"></a> | ||||
| <a href="fdd-90206-hd.png"><img src="fdd-90206-hd.png" style="width:40%" alt="FDD-90206, HD"></a> | ||||
| </div> | ||||
|  | ||||
| This is from another drive I have; it's an unbranded combo | ||||
| card-reader-and-floppy drive unit; the 90206 is the only identification mark it | ||||
| has. I don't use this because it's problematic, and the graph shows why; you | ||||
| can just see some ghosting on the HD graph at at 3us, where some pulses are | ||||
| coming back reported at 6us. This won't affect IBM scheme disks because they | ||||
| don't use 3us as an interval, but it might effect other formats. And the DD | ||||
| graph shows that intervals below about 4us are reported as double what they | ||||
| should be: so, this drive won't work on [Macintosh 800kB | ||||
| formats](disk-macintosh.md) at all, because they use intervals starting at | ||||
| 2.6us, below this limit. But it should work on PC formats --- just. | ||||
|  | ||||
							
								
								
									
										
											BIN
										
									
								
								doc/fdd-90206-dd.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								doc/fdd-90206-dd.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 88 KiB | 
							
								
								
									
										
											BIN
										
									
								
								doc/fdd-90206-hd.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								doc/fdd-90206-hd.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 137 KiB | 
							
								
								
									
										71
									
								
								doc/greaseweazle.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								doc/greaseweazle.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,71 @@ | ||||
| Using the FluxEngine client software with GreaseWeazle hardware | ||||
| =============================================================== | ||||
|  | ||||
| The FluxEngine isn't the only project which does this; another one is the | ||||
| [GreaseWeazle](https://github.com/keirf/Greaseweazle/wiki), a Blue Pill based | ||||
| completely open source solution. This requires more work to set up (or you can | ||||
| buy a prebuilt GreaseWeazle board), but provides completely open source | ||||
| hardware which doesn't require the use of the Cypress Windows-based tools that | ||||
| the FluxEngine does. Luckily, the FluxEngine software supports it | ||||
| out-of-the-box --- just plug it in and nearly everything should work. | ||||
|  | ||||
| I am aware that having _software_ called FluxEngine and _hardware_ called | ||||
| FluxEngine makes things complicated when you're not using the FluxEngine client | ||||
| software with a FluxEngine board, but I'm afraid it's too late to change that | ||||
| now. Sorry. | ||||
|  | ||||
| If you're using Windows | ||||
| ----------------------- | ||||
|  | ||||
| In order to access the GreaseWeazle from Windows, you need to install a WinUSB | ||||
| driver for it. You can do this with the [Zadig](https://zadig.akeo.ie/) | ||||
| program. Download it, plug in the GreaseWeazle, and run it; select Options, | ||||
| List All Devices, and then open the big dropdown box and select the | ||||
| GreaseWeazle. You should see something like this. | ||||
|  | ||||
| <div style="text-align: center"> | ||||
| <img src="zadig.png" style="width:80%" alt="Zadig screenshot"> | ||||
| </div> | ||||
|  | ||||
| Ensure that the Driver boxes say `usbser` and `WinUSB`. Then press 'Replace | ||||
| Driver'. Once done, the GreaseWeazle will be visible to the FluxEngine client. | ||||
|  | ||||
| **Important note!** Unfortunately, now, the original GreaseWeazle client won't | ||||
| work --- you can't use both drivers at once. I'm working on this. To switch | ||||
| back to the original driver, for using the GreaseWeazle client software | ||||
| instead, open up Zadig again, go through the same process, but make sure the left Driver box says `WinUSB` and the right one says `USB Serial (CDC)`. Now, when you press 'Replace Driver' the original driver will be restored. | ||||
|  | ||||
| What works | ||||
| ---------- | ||||
|  | ||||
| Supported features with the GreaseWeazle include: | ||||
|  | ||||
|   - simple reading and writing of disks, seeking etc | ||||
|   - erasing disks | ||||
|   - determining disk rotation speed | ||||
|  | ||||
| What doesn't work | ||||
| ----------------- | ||||
|  | ||||
| (I'm still working on this. If you have an urgent need for anything, please | ||||
| [file an issue](https://github.com/davidgiven/fluxengine/issues/new) and I'll | ||||
| see what I can do.) | ||||
|  | ||||
|   - voltage measurement | ||||
|   - hard sectored disks (you can still read these, but you can't use | ||||
| 	`--hard-sector-count`). | ||||
|  | ||||
| Who to contact | ||||
| -------------- | ||||
|  | ||||
| I want to make it clear that the FluxEngine code is _not_ supported by the | ||||
| GreaseWeazle team. If you have any problems, please [contact | ||||
| me](https://github.com/davidgiven/fluxengine/issues/new) and not them. | ||||
|  | ||||
| In addition, the GreaseWeazle release cycle is not synchronised to the | ||||
| FluxEngine release cycle, so it's possible you'll have a version of the | ||||
| GreaseWeazle firmware which is not supported by FluxEngine. Hopefully, it'll | ||||
| detect this and complain. Again, [file an | ||||
| issue](https://github.com/davidgiven/fluxengine/issues/new) and I'll look into | ||||
| it. | ||||
|  | ||||
| @@ -10,6 +10,11 @@ been written to be largely fire-and-forget and is mostly self-adjusting. | ||||
| However, there are still some things that can be tuned to produce better | ||||
| reads. | ||||
|  | ||||
| Also, it's important to remember that some drives are problematic --- in | ||||
| particular, some 3.5" floppy drives are designed to work with just IBM scheme | ||||
| disks with a certain set of pulse intervals. There's a tool to let you diagnose | ||||
| this; see [the drive response](driveresponse.md) page. | ||||
|  | ||||
| The sector map | ||||
| -------------- | ||||
|  | ||||
|   | ||||
							
								
								
									
										
											BIN
										
									
								
								doc/sony-mpf920-dd.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								doc/sony-mpf920-dd.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 102 KiB | 
							
								
								
									
										
											BIN
										
									
								
								doc/sony-mpf920-hd.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								doc/sony-mpf920-hd.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 104 KiB | 
| @@ -82,16 +82,10 @@ FluxEngine hardware on a $2 Blue Pill. | ||||
| I am _not_ planning on replacing the PSoC5 with a Blue Pill, because someone | ||||
| already has: [the GreaseWeazle](https://github.com/keirf/Greaseweazle/wiki) is | ||||
| a completely open source firmware package which will read and write Supercard | ||||
| Pro files via a standard Blue Pill. The GreaseWeazle's USB protocol is | ||||
| different from the FluxEngine's so they're not directly interchangeable. You | ||||
| can, however, read a Supercard Pro file with a GreaseWeazle and then use the | ||||
| FluxEngine client to decode it. It should work the other way around, too, but | ||||
| FluxEngine's SCP export [is curently | ||||
| broken](https://github.com/davidgiven/fluxengine/issues/134). | ||||
|  | ||||
| I _am_ considering adding direct support for the GreaseWeazle to the FluxEngine | ||||
| client, which will let you just plug one in and make it go as a direct | ||||
| replacement to the FluxEngine hardware. | ||||
| Pro files via a standard Blue Pill or via a prebuilt board. It's supported by | ||||
| the FluxEngine client software, and you should, mostly, be able to use | ||||
| GreaseWeazle hardware interchangeably with FluxEngine hardware. See the | ||||
| [dedicated page](greaseweazle.md) for more information. | ||||
|  | ||||
|  | ||||
| ### Some useful links | ||||
|   | ||||
							
								
								
									
										
											BIN
										
									
								
								doc/zadig.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								doc/zadig.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 17 KiB | 
| @@ -24,6 +24,7 @@ public: | ||||
| }; | ||||
|  | ||||
| extern void setHardwareFluxSinkDensity(bool high_density); | ||||
| extern void setHardwareFluxSinkHardSectorCount(int sectorCount); | ||||
|  | ||||
| #endif | ||||
|  | ||||
|   | ||||
| @@ -3,6 +3,7 @@ | ||||
| #include "fluxmap.h" | ||||
| #include "usb/usb.h" | ||||
| #include "fluxsink/fluxsink.h" | ||||
| #include "fmt/format.h" | ||||
|  | ||||
| FlagGroup hardwareFluxSinkFlags = { | ||||
| 	&usbFlags, | ||||
| @@ -15,17 +16,37 @@ static IntFlag indexMode( | ||||
|     "index pulse source (0=drive, 1=300 RPM fake source, 2=360 RPM fake source", | ||||
|     0); | ||||
|  | ||||
| static IntFlag hardSectorCount( | ||||
|     { "--write-hard-sector-count" }, | ||||
|     "number of hard sectors on the disk (0=soft sectors)", | ||||
|     0); | ||||
|  | ||||
| void setHardwareFluxSinkDensity(bool high_density) | ||||
| { | ||||
| 	::high_density = high_density; | ||||
| } | ||||
|  | ||||
| void setHardwareFluxSinkHardSectorCount(int sectorCount) | ||||
| { | ||||
| 	::hardSectorCount.setDefaultValue(sectorCount); | ||||
| } | ||||
|  | ||||
| class HardwareFluxSink : public FluxSink | ||||
| { | ||||
| public: | ||||
|     HardwareFluxSink(unsigned drive): | ||||
|         _drive(drive) | ||||
|     { | ||||
| 		if (hardSectorCount != 0) | ||||
| 		{ | ||||
| 			usbSetDrive(_drive, high_density, indexMode); | ||||
| 			std::cerr << "Measuring rotational speed... " << std::flush; | ||||
| 			nanoseconds_t oneRevolution = usbGetRotationalPeriod(hardSectorCount); | ||||
| 			_hardSectorThreshold = oneRevolution * 3 / (4 * hardSectorCount); | ||||
| 			std::cerr << fmt::format("{}ms\n", oneRevolution / 1e6); | ||||
| 		} | ||||
| 		else | ||||
| 			_hardSectorThreshold = 0; | ||||
|     } | ||||
|  | ||||
|     ~HardwareFluxSink() | ||||
| @@ -38,11 +59,12 @@ public: | ||||
|         usbSetDrive(_drive, high_density, indexMode); | ||||
|         usbSeek(track); | ||||
|  | ||||
|         return usbWrite(side, fluxmap.rawBytes()); | ||||
|         return usbWrite(side, fluxmap.rawBytes(), _hardSectorThreshold); | ||||
|     } | ||||
|  | ||||
| private: | ||||
|     unsigned _drive; | ||||
|     nanoseconds_t _hardSectorThreshold; | ||||
| }; | ||||
|  | ||||
| std::unique_ptr<FluxSink> FluxSink::createHardwareFluxSink(unsigned drive) | ||||
|   | ||||
| @@ -30,6 +30,7 @@ public: | ||||
| extern void setHardwareFluxSourceRevolutions(double revolutions); | ||||
| extern void setHardwareFluxSourceDensity(bool high_density); | ||||
| extern void setHardwareFluxSourceSynced(bool synced); | ||||
| extern void setHardwareFluxSourceHardSectorCount(int sectorCount); | ||||
|  | ||||
| #endif | ||||
|  | ||||
|   | ||||
| @@ -24,6 +24,11 @@ static IntFlag indexMode( | ||||
|     "index pulse source (0=drive, 1=300 RPM fake source, 2=360 RPM fake source", | ||||
|     0); | ||||
|  | ||||
| static IntFlag hardSectorCount( | ||||
|     { "--hard-sector-count" }, | ||||
|     "number of hard sectors on the disk (0=soft sectors)", | ||||
|     0); | ||||
|  | ||||
| static bool high_density = false; | ||||
|  | ||||
| void setHardwareFluxSourceDensity(bool high_density) | ||||
| @@ -39,7 +44,11 @@ public: | ||||
|     { | ||||
|         usbSetDrive(_drive, high_density, indexMode); | ||||
|         std::cerr << "Measuring rotational speed... " << std::flush; | ||||
|         _oneRevolution = usbGetRotationalPeriod(); | ||||
|         _oneRevolution = usbGetRotationalPeriod(hardSectorCount); | ||||
| 	if (hardSectorCount != 0) | ||||
| 		_hardSectorThreshold = _oneRevolution * 3 / (4 * hardSectorCount); | ||||
| 	else | ||||
| 		_hardSectorThreshold = 0; | ||||
|         std::cerr << fmt::format("{}ms\n", _oneRevolution / 1e6); | ||||
|     } | ||||
|  | ||||
| @@ -52,7 +61,8 @@ public: | ||||
|     { | ||||
|         usbSetDrive(_drive, high_density, indexMode); | ||||
|         usbSeek(track); | ||||
|         Bytes data = usbRead(side, synced, revolutions * _oneRevolution); | ||||
|         Bytes data = usbRead( | ||||
| 			side, synced, revolutions * _oneRevolution, _hardSectorThreshold); | ||||
|         auto fluxmap = std::make_unique<Fluxmap>(); | ||||
|         fluxmap->appendBytes(data); | ||||
|         return fluxmap; | ||||
| @@ -72,6 +82,7 @@ private: | ||||
|     unsigned _drive; | ||||
|     unsigned _revolutions; | ||||
|     nanoseconds_t _oneRevolution; | ||||
|     nanoseconds_t _hardSectorThreshold; | ||||
| }; | ||||
|  | ||||
| void setHardwareFluxSourceRevolutions(double revolutions) | ||||
| @@ -84,6 +95,11 @@ void setHardwareFluxSourceSynced(bool synced) | ||||
|     ::synced.setDefaultValue(synced); | ||||
| } | ||||
|  | ||||
| void setHardwareFluxSourceHardSectorCount(int sectorCount) | ||||
| { | ||||
|     ::hardSectorCount.setDefaultValue(sectorCount); | ||||
| } | ||||
|  | ||||
| std::unique_ptr<FluxSource> FluxSource::createHardwareFluxSource(unsigned drive) | ||||
| { | ||||
|     return std::unique_ptr<FluxSource>(new HardwareFluxSource(drive)); | ||||
|   | ||||
| @@ -91,6 +91,11 @@ void setReaderRevolutions(int revolutions) | ||||
| 	setHardwareFluxSourceRevolutions(revolutions); | ||||
| } | ||||
|  | ||||
| void setReaderHardSectorCount(int sectorCount) | ||||
| { | ||||
|     setHardwareFluxSourceHardSectorCount(sectorCount); | ||||
| } | ||||
|  | ||||
| static void writeSectorsToFile(const SectorSet& sectors, const ImageSpec& spec) | ||||
| { | ||||
| 	std::unique_ptr<ImageWriter> writer(ImageWriter::create(sectors, spec)); | ||||
|   | ||||
| @@ -13,6 +13,7 @@ extern FlagGroup readerFlags; | ||||
| extern void setReaderDefaultSource(const std::string& source); | ||||
| extern void setReaderDefaultOutput(const std::string& output); | ||||
| extern void setReaderRevolutions(int revolutions); | ||||
| extern void setReaderHardSectorCount(int sectorCount); | ||||
|  | ||||
| extern std::vector<std::unique_ptr<Track>> readTracks(); | ||||
|  | ||||
|   | ||||
| @@ -144,9 +144,12 @@ public: | ||||
| 		await_reply<struct any_frame>(F_FRAME_RECALIBRATE_REPLY); | ||||
| 	} | ||||
|  | ||||
| 	nanoseconds_t getRotationalPeriod(void) | ||||
| 	nanoseconds_t getRotationalPeriod(int hardSectorCount) | ||||
| 	{ | ||||
| 		struct any_frame f = { .f = {.type = F_FRAME_MEASURE_SPEED_CMD, .size = sizeof(f)} }; | ||||
| 		struct measurespeed_frame f = { | ||||
| 			.f = {.type = F_FRAME_MEASURE_SPEED_CMD, .size = sizeof(f)}, | ||||
| 			.hard_sector_count = (uint8_t) hardSectorCount, | ||||
| 		}; | ||||
| 		usb_cmd_send(&f, f.f.size); | ||||
|  | ||||
| 		auto r = await_reply<struct speed_frame>(F_FRAME_MEASURE_SPEED_REPLY); | ||||
| @@ -227,13 +230,15 @@ public: | ||||
| 		await_reply<struct any_frame>(F_FRAME_BULK_READ_TEST_REPLY); | ||||
| 	} | ||||
|  | ||||
| 	Bytes read(int side, bool synced, nanoseconds_t readTime) | ||||
| 	Bytes read(int side, bool synced, nanoseconds_t readTime, | ||||
| 	           nanoseconds_t hardSectorThreshold) | ||||
| 	{ | ||||
| 		struct read_frame f = { | ||||
| 			.f = { .type = F_FRAME_READ_CMD, .size = sizeof(f) }, | ||||
| 			.side = (uint8_t) side, | ||||
| 			.synced = (uint8_t) synced | ||||
| 			.synced = (uint8_t) synced, | ||||
| 		}; | ||||
| 		f.hardsec_threshold_ms = (hardSectorThreshold + 5e5) / 1e6; /* round to nearest ms */ | ||||
| 		uint16_t milliseconds = readTime / 1e6; | ||||
| 		((uint8_t*)&f.milliseconds)[0] = milliseconds; | ||||
| 		((uint8_t*)&f.milliseconds)[1] = milliseconds >> 8; | ||||
| @@ -249,7 +254,7 @@ public: | ||||
| 		return buffer; | ||||
| 	} | ||||
|  | ||||
| 	void write(int side, const Bytes& bytes) | ||||
| 	void write(int side, const Bytes& bytes, nanoseconds_t hardSectorThreshold) | ||||
| 	{ | ||||
| 		unsigned safelen = bytes.size() & ~(FRAME_SIZE-1); | ||||
| 		Bytes safeBytes = bytes.slice(0, safelen); | ||||
| @@ -258,6 +263,7 @@ public: | ||||
| 			.f = { .type = F_FRAME_WRITE_CMD, .size = sizeof(f) }, | ||||
| 			.side = (uint8_t) side, | ||||
| 		}; | ||||
| 		f.hardsec_threshold_ms = (hardSectorThreshold + 5e5) / 1e6; /* round to nearest ms */ | ||||
| 		((uint8_t*)&f.bytes_to_write)[0] = safelen; | ||||
| 		((uint8_t*)&f.bytes_to_write)[1] = safelen >> 8; | ||||
| 		((uint8_t*)&f.bytes_to_write)[2] = safelen >> 16; | ||||
| @@ -269,12 +275,13 @@ public: | ||||
| 		await_reply<struct any_frame>(F_FRAME_WRITE_REPLY); | ||||
| 	} | ||||
|  | ||||
| 	void erase(int side) | ||||
| 	void erase(int side, nanoseconds_t hardSectorThreshold) | ||||
| 	{ | ||||
| 		struct erase_frame f = { | ||||
| 			.f = { .type = F_FRAME_ERASE_CMD, .size = sizeof(f) }, | ||||
| 			.side = (uint8_t) side, | ||||
| 		}; | ||||
| 		f.hardsec_threshold_ms = (hardSectorThreshold + 5e5) / 1e6; /* round to nearest ms */ | ||||
| 		usb_cmd_send(&f, f.f.size); | ||||
|  | ||||
| 		await_reply<struct any_frame>(F_FRAME_ERASE_REPLY); | ||||
|   | ||||
							
								
								
									
										156
									
								
								lib/usb/greaseweazle.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										156
									
								
								lib/usb/greaseweazle.cc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,156 @@ | ||||
| #include "globals.h" | ||||
| #include "usb.h" | ||||
| #include "protocol.h" | ||||
| #include "bytes.h" | ||||
| #include "fmt/format.h" | ||||
| #include "greaseweazle.h" | ||||
|  | ||||
| Bytes fluxEngineToGreaseWeazle(const Bytes& fldata, nanoseconds_t clock) | ||||
| { | ||||
| 	Bytes gwdata; | ||||
| 	ByteWriter bw(gwdata); | ||||
| 	ByteReader br(fldata); | ||||
| 	uint32_t ticks_fl = 0; | ||||
| 	uint32_t ticks_gw = 0; | ||||
|  | ||||
| 	auto write_28 = [&](uint32_t val) { | ||||
| 		bw.write_8(1 | (val<<1) & 0xff); | ||||
| 		bw.write_8(1 | (val>>6) & 0xff); | ||||
| 		bw.write_8(1 | (val>>13) & 0xff); | ||||
| 		bw.write_8(1 | (val>>20) & 0xff); | ||||
| 	}; | ||||
|  | ||||
| 	while (!br.eof()) | ||||
| 	{ | ||||
| 		uint8_t b = br.read_8(); | ||||
| 		ticks_fl += b & 0x3f; | ||||
| 		if (b & F_BIT_PULSE) | ||||
| 		{ | ||||
| 			uint32_t newticks_gw = ticks_fl * NS_PER_TICK / clock; | ||||
| 			uint32_t delta = newticks_gw - ticks_gw; | ||||
| 			if (delta < 250) | ||||
| 				bw.write_8(delta); | ||||
| 			else | ||||
| 			{ | ||||
| 				int high = (delta-250) / 255; | ||||
| 				if (high < 5) | ||||
| 				{ | ||||
| 					bw.write_8(250 + high); | ||||
| 					bw.write_8(1 + (delta-250) % 255); | ||||
| 				} | ||||
| 				else | ||||
| 				{ | ||||
| 					bw.write_8(255); | ||||
| 					bw.write_8(FLUXOP_SPACE); | ||||
| 					write_28(delta - 249); | ||||
| 					bw.write_8(249); | ||||
| 				} | ||||
| 			} | ||||
| 			ticks_gw = newticks_gw; | ||||
| 		} | ||||
| 	} | ||||
| 	bw.write_8(0); /* end of stream */ | ||||
| 	return gwdata; | ||||
| } | ||||
|  | ||||
| Bytes greaseWeazleToFluxEngine(const Bytes& gwdata, nanoseconds_t clock) | ||||
| { | ||||
| 	Bytes fldata; | ||||
| 	ByteReader br(gwdata); | ||||
| 	ByteWriter bw(fldata); | ||||
|  | ||||
|     auto read_28 = [&]() { | ||||
|         return ((br.read_8() & 0xfe) >> 1) | ||||
|             | ((br.read_8() & 0xfe) << 6) | ||||
|             | ((br.read_8() & 0xfe) << 13) | ||||
|             | ((br.read_8() & 0xfe) << 20); | ||||
|     }; | ||||
|  | ||||
| 	uint32_t ticks_gw = 0; | ||||
| 	uint32_t lastevent_fl = 0; | ||||
| 	uint32_t index_gw = ~0; | ||||
|  | ||||
| 	while (!br.eof()) | ||||
| 	{ | ||||
| 		uint8_t b = br.read_8(); | ||||
| 		if (!b) | ||||
| 			break; | ||||
|  | ||||
| 		uint8_t event = 0; | ||||
| 		if (b == 255) | ||||
| 		{ | ||||
| 			switch (br.read_8()) | ||||
| 			{ | ||||
| 				case FLUXOP_INDEX: | ||||
| 					index_gw = ticks_gw + read_28(); | ||||
| 					break; | ||||
|  | ||||
| 				case FLUXOP_SPACE: | ||||
| 					ticks_gw += read_28(); | ||||
| 					break; | ||||
|  | ||||
| 				default: | ||||
| 					Error() << "bad opcode in GreaseWeazle stream"; | ||||
| 			} | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			if (b < 250) | ||||
| 				ticks_gw += b; | ||||
| 			else | ||||
| 			{ | ||||
| 				int delta = 250 + (b-250)*255 + br.read_8() - 1; | ||||
| 				ticks_gw += delta; | ||||
| 			} | ||||
| 			event = F_BIT_PULSE; | ||||
| 		} | ||||
|  | ||||
| 		if (event) | ||||
| 		{ | ||||
| 			uint32_t index_fl = (index_gw * clock) / NS_PER_TICK; | ||||
| 			uint32_t ticks_fl = (ticks_gw * clock) / NS_PER_TICK; | ||||
| 			if (index_gw != ~0) | ||||
| 			{ | ||||
| 				if (index_fl < ticks_fl) | ||||
| 				{ | ||||
| 					uint32_t delta_fl = index_fl - lastevent_fl; | ||||
| 					while (delta_fl > 0x3f) | ||||
| 					{ | ||||
| 						bw.write_8(0x3f); | ||||
| 						delta_fl -= 0x3f; | ||||
| 					} | ||||
| 					bw.write_8(delta_fl | F_BIT_INDEX); | ||||
| 					lastevent_fl = index_fl; | ||||
| 					index_gw = ~0; | ||||
| 				} | ||||
| 				else if (index_fl == ticks_fl) | ||||
| 					event |= F_BIT_INDEX; | ||||
| 			} | ||||
|  | ||||
| 			uint32_t delta_fl = ticks_fl - lastevent_fl; | ||||
| 			while (delta_fl > 0x3f) | ||||
| 			{ | ||||
| 				bw.write_8(0x3f); | ||||
| 				delta_fl -= 0x3f; | ||||
| 			} | ||||
| 			bw.write_8(delta_fl | event); | ||||
| 			lastevent_fl = ticks_fl; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return fldata; | ||||
| } | ||||
|  | ||||
| /* Left-truncates at the first index mark, so the resulting data as aligned at | ||||
|  * the index. */ | ||||
| Bytes stripPartialRotation(const Bytes& fldata) | ||||
| { | ||||
| 	for (unsigned i=0; i<fldata.size(); i++) | ||||
| 	{ | ||||
| 		uint8_t b = fldata[i]; | ||||
| 		if (b & F_BIT_INDEX) | ||||
| 			return fldata.slice(i); | ||||
| 	} | ||||
| 	return fldata; | ||||
| } | ||||
|  | ||||
							
								
								
									
										203
									
								
								lib/usb/greaseweazle.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										203
									
								
								lib/usb/greaseweazle.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,203 @@ | ||||
| #ifndef GREASEWEAZLE_H | ||||
| #define GREASEWEAZLE_H | ||||
|  | ||||
| #define GREASEWEAZLE_VID 0x1209 | ||||
| #define GREASEWEAZLE_PID 0x4d69 | ||||
|  | ||||
| #define EP_OUT 0x02 | ||||
| #define EP_IN 0x83 | ||||
|  | ||||
| #define GREASEWEAZLE_VERSION 22 | ||||
|  | ||||
| extern Bytes fluxEngineToGreaseWeazle(const Bytes& fldata, nanoseconds_t clock); | ||||
| extern Bytes greaseWeazleToFluxEngine(const Bytes& gwdata, nanoseconds_t clock); | ||||
| extern Bytes stripPartialRotation(const Bytes& fldata); | ||||
|  | ||||
| /* Copied from https://github.com/keirf/Greaseweazle/blob/master/inc/cdc_acm_protocol.h. | ||||
|  * | ||||
|  * WANING: these headers were originally defined with 'packed', which is a gccism so it's | ||||
|  * been dummied out. Don't use them expecting wire protocol structures. */ | ||||
|  | ||||
| #define packed /* */ | ||||
|  | ||||
| /* | ||||
|  * GREASEWEAZLE COMMAND SET | ||||
|  */ | ||||
|  | ||||
| /* CMD_GET_INFO, length=3, idx. Returns 32 bytes after ACK. */ | ||||
| #define CMD_GET_INFO        0 | ||||
| /* [BOOTLOADER] CMD_UPDATE, length=6, <update_len>.  | ||||
|  * Host follows with <update_len> bytes. | ||||
|  * Bootloader finally returns a status byte, 0 on success. */ | ||||
| /* [MAIN FIRMWARE] CMD_UPDATE, length=10, <update_len>, 0xdeafbee3. | ||||
|  * Host follows with <update_len> bytes. | ||||
|  * Main firmware finally returns a status byte, 0 on success. */ | ||||
| #define CMD_UPDATE          1 | ||||
| /* CMD_SEEK, length=3, cyl#. Seek to cyl# on selected drive. */ | ||||
| #define CMD_SEEK            2 | ||||
| /* CMD_HEAD, length=3, head# (0=bottom) */ | ||||
| #define CMD_HEAD            3 | ||||
| /* CMD_SET_PARAMS, length=3+nr, idx, <nr bytes> */ | ||||
| #define CMD_SET_PARAMS      4 | ||||
| /* CMD_GET_PARAMS, length=4, idx, nr_bytes. Returns nr_bytes after ACK. */ | ||||
| #define CMD_GET_PARAMS      5 | ||||
| /* CMD_MOTOR, length=4, drive#, on/off. Turn on/off a drive motor. */ | ||||
| #define CMD_MOTOR           6 | ||||
| /* CMD_READ_FLUX, length=2-8. Argument is gw_read_flux. | ||||
|  * Returns flux readings until EOStream. */ | ||||
| #define CMD_READ_FLUX       7 | ||||
| /* CMD_WRITE_FLUX, length=2-4. Argument is gw_write_flux. | ||||
|  * Host follows with flux readings until EOStream. */ | ||||
| #define CMD_WRITE_FLUX      8 | ||||
| /* CMD_GET_FLUX_STATUS, length=2. Last read/write status returned in ACK. */ | ||||
| #define CMD_GET_FLUX_STATUS 9 | ||||
| /* CMD_SWITCH_FW_MODE, length=3, <mode> */ | ||||
| #define CMD_SWITCH_FW_MODE 11 | ||||
| /* CMD_SELECT, length=3, drive#. Select drive# as current unit. */ | ||||
| #define CMD_SELECT         12 | ||||
| /* CMD_DESELECT, length=2. Deselect current unit (if any). */ | ||||
| #define CMD_DESELECT       13 | ||||
| /* CMD_SET_BUS_TYPE, length=3, bus_type. Set the bus type. */ | ||||
| #define CMD_SET_BUS_TYPE   14 | ||||
| /* CMD_SET_PIN, length=4, pin#, level. */ | ||||
| #define CMD_SET_PIN        15 | ||||
| /* CMD_RESET, length=2. Reset all state to initial (power on) values. */ | ||||
| #define CMD_RESET          16 | ||||
| /* CMD_ERASE_FLUX, length=6. Argument is gw_erase_flux. */ | ||||
| #define CMD_ERASE_FLUX     17 | ||||
| /* CMD_SOURCE_BYTES, length=6. Argument is gw_sink_source_bytes. */ | ||||
| #define CMD_SOURCE_BYTES   18 | ||||
| /* CMD_SINK_BYTES, length=6. Argument is gw_sink_source_bytes. */ | ||||
| #define CMD_SINK_BYTES     19 | ||||
| #define CMD_MAX            19 | ||||
|  | ||||
|  | ||||
| /* | ||||
|  * CMD_SET_BUS CODES | ||||
|  */ | ||||
| #define BUS_NONE            0 | ||||
| #define BUS_IBMPC           1 | ||||
| #define BUS_SHUGART         2 | ||||
|  | ||||
|  | ||||
| /* | ||||
|  * ACK RETURN CODES | ||||
|  */ | ||||
| #define ACK_OKAY            0 | ||||
| #define ACK_BAD_COMMAND     1 | ||||
| #define ACK_NO_INDEX        2 | ||||
| #define ACK_NO_TRK0         3 | ||||
| #define ACK_FLUX_OVERFLOW   4 | ||||
| #define ACK_FLUX_UNDERFLOW  5 | ||||
| #define ACK_WRPROT          6 | ||||
| #define ACK_NO_UNIT         7 | ||||
| #define ACK_NO_BUS          8 | ||||
| #define ACK_BAD_UNIT        9 | ||||
| #define ACK_BAD_PIN        10 | ||||
| #define ACK_BAD_CYLINDER   11 | ||||
|  | ||||
|  | ||||
| /* | ||||
|  * CONTROL-CHANNEL COMMAND SET: | ||||
|  * We abuse SET_LINE_CODING requests over endpoint 0, stashing a command | ||||
|  * in the baud-rate field. | ||||
|  */ | ||||
| #define BAUD_NORMAL        9600 | ||||
| #define BAUD_CLEAR_COMMS  10000 | ||||
|  | ||||
| /* | ||||
|  * Flux stream opcodes. Preceded by 0xFF byte. | ||||
|  *  | ||||
|  * Argument types: | ||||
|  *  N28: 28-bit non-negative integer N, encoded as 4 bytes b0,b1,b2,b3: | ||||
|  *   b0 = (uint8_t)(1 | (N <<  1)) | ||||
|  *   b1 = (uint8_t)(1 | (N >>  6)) | ||||
|  *   b2 = (uint8_t)(1 | (N >> 13)) | ||||
|  *   b3 = (uint8_t)(1 | (N >> 20)) | ||||
|  */ | ||||
| /* FLUXOP_INDEX [CMD_READ_FLUX] | ||||
|  *  Args: | ||||
|  *   +4 [N28]: ticks to index, relative to sample cursor. | ||||
|  *  Signals an index pulse in the read stream. Sample cursor is unaffected. */ | ||||
| #define FLUXOP_INDEX      1 | ||||
| /* FLUXOP_SPACE [CMD_READ_FLUX, CMD_WRITE_FLUX] | ||||
|  *  Args: | ||||
|  *   +4 [N28]: ticks to increment the sample cursor. | ||||
|  *  Increments the sample cursor with no intervening flux transitions. */ | ||||
| #define FLUXOP_SPACE      2 | ||||
| /* FLUXOP_ASTABLE [CMD_WRITE_FLUX] | ||||
|  *  Args: | ||||
|  *   +4 [N28]: astable period. | ||||
|  *  Generate regular flux transitions at specified astable period.  | ||||
|  *  Duration is specified by immediately preceding FLUXOP_SPACE opcode(s). */ | ||||
| #define FLUXOP_ASTABLE    3 | ||||
|  | ||||
|  | ||||
| /* | ||||
|  * COMMAND PACKETS | ||||
|  */ | ||||
|  | ||||
| /* CMD_GET_INFO, index 0 */ | ||||
| #define GETINFO_FIRMWARE 0 | ||||
| struct packed gw_info { | ||||
|     uint8_t fw_major; | ||||
|     uint8_t fw_minor; | ||||
|     uint8_t is_main_firmware; /* == 0 -> update bootloader */ | ||||
|     uint8_t max_cmd; | ||||
|     uint32_t sample_freq; | ||||
|     uint8_t hw_model, hw_submodel; | ||||
|     uint8_t usb_speed; | ||||
| }; | ||||
| extern struct gw_info gw_info; | ||||
|  | ||||
| /* CMD_GET_INFO, index 1 */ | ||||
| #define GETINFO_BW_STATS 1 | ||||
| struct packed gw_bw_stats { | ||||
|     struct packed { | ||||
|         uint32_t bytes; | ||||
|         uint32_t usecs; | ||||
|     } min_bw, max_bw; | ||||
| }; | ||||
|  | ||||
| /* CMD_READ_FLUX */ | ||||
| struct packed gw_read_flux { | ||||
|     /* Maximum ticks to read for (or 0, for no limit). */ | ||||
|     uint32_t ticks; | ||||
|     /* Maximum index pulses to read (or 0, for no limit). */ | ||||
|     uint16_t max_index; | ||||
| }; | ||||
|  | ||||
| /* CMD_WRITE_FLUX */ | ||||
| struct packed gw_write_flux { | ||||
|     /* If non-zero, start the write at the index pulse. */ | ||||
|     uint8_t cue_at_index; | ||||
|     /* If non-zero, terminate the write at the next index pulse. */ | ||||
|     uint8_t terminate_at_index; | ||||
| }; | ||||
|  | ||||
| /* CMD_ERASE_FLUX */ | ||||
| struct packed gw_erase_flux { | ||||
|     uint32_t ticks; | ||||
| }; | ||||
|  | ||||
| /* CMD_SINK_SOURCE_BYTES */ | ||||
| struct packed gw_sink_source_bytes { | ||||
|     uint32_t nr_bytes; | ||||
| }; | ||||
|  | ||||
| /* CMD_{GET,SET}_PARAMS, index 0 */ | ||||
| #define PARAMS_DELAYS 0 | ||||
| struct packed gw_delay { | ||||
|     uint16_t select_delay; /* usec */ | ||||
|     uint16_t step_delay;   /* usec */ | ||||
|     uint16_t seek_settle;  /* msec */ | ||||
|     uint16_t motor_delay;  /* msec */ | ||||
|     uint16_t auto_off;     /* msec */ | ||||
| }; | ||||
|  | ||||
| /* CMD_SWITCH_FW_MODE */ | ||||
| #define FW_MODE_BOOTLOADER 0 | ||||
| #define FW_MODE_NORMAL     1 | ||||
|  | ||||
| #endif | ||||
|  | ||||
							
								
								
									
										390
									
								
								lib/usb/greaseweazleusb.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										390
									
								
								lib/usb/greaseweazleusb.cc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,390 @@ | ||||
| #include "globals.h" | ||||
| #include "usb.h" | ||||
| #include "protocol.h" | ||||
| #include "fluxmap.h" | ||||
| #include "bytes.h" | ||||
| #include <libusb.h> | ||||
| #include "fmt/format.h" | ||||
| #include "greaseweazle.h" | ||||
|  | ||||
| #define TIMEOUT 5000 | ||||
|  | ||||
| static const char* gw_error(int e) | ||||
| { | ||||
|     switch (e) | ||||
|     { | ||||
|         case ACK_OKAY:           return "OK"; | ||||
|         case ACK_BAD_COMMAND:    return "Bad command"; | ||||
|         case ACK_NO_INDEX:       return "No index"; | ||||
|         case ACK_NO_TRK0:        return "No track 0"; | ||||
|         case ACK_FLUX_OVERFLOW:  return "Overflow"; | ||||
|         case ACK_FLUX_UNDERFLOW: return "Underflow"; | ||||
|         case ACK_WRPROT:         return "Write protected"; | ||||
|         case ACK_NO_UNIT:        return "No unit"; | ||||
|         case ACK_NO_BUS:         return "No bus"; | ||||
|         case ACK_BAD_UNIT:       return "Invalid unit"; | ||||
|         case ACK_BAD_PIN:        return "Invalid pin"; | ||||
|         case ACK_BAD_CYLINDER:   return "Invalid cylinder"; | ||||
|         default:                 return "Unknown error"; | ||||
|     } | ||||
| } | ||||
|  | ||||
| class GreaseWeazleUsb : public USB | ||||
| { | ||||
| private: | ||||
|     uint8_t _readbuffer[4096]; | ||||
|     int _readbuffer_ptr = 0; | ||||
|     int _readbuffer_fill = 0; | ||||
|  | ||||
|     void read_bytes(uint8_t* buffer, int len) | ||||
|     { | ||||
|         while (len > 0) | ||||
|         { | ||||
|             if (_readbuffer_ptr < _readbuffer_fill) | ||||
|             { | ||||
|                 int buffered = std::min(len, _readbuffer_fill - _readbuffer_ptr); | ||||
|                 memcpy(buffer, _readbuffer + _readbuffer_ptr, buffered); | ||||
|                 _readbuffer_ptr += buffered; | ||||
|                 buffer += buffered; | ||||
|                 len -= buffered; | ||||
|             } | ||||
|  | ||||
|             if (len == 0) | ||||
|                 break; | ||||
|  | ||||
|             int actual; | ||||
|             int rc = libusb_bulk_transfer(_device, EP_IN, | ||||
|                 _readbuffer, sizeof(_readbuffer), | ||||
|                 &actual, TIMEOUT); | ||||
|             if (rc < 0) | ||||
|                 Error() << "failed to receive command reply: " << usberror(rc); | ||||
|  | ||||
|             _readbuffer_fill = actual; | ||||
|             _readbuffer_ptr = 0; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     void read_bytes(Bytes& bytes) | ||||
|     { | ||||
|         read_bytes(bytes.begin(), bytes.size()); | ||||
|     } | ||||
|  | ||||
|     Bytes read_bytes(unsigned len) | ||||
|     { | ||||
|         Bytes b(len); | ||||
|         read_bytes(b); | ||||
|         return b; | ||||
|     } | ||||
|  | ||||
|     uint8_t read_byte() | ||||
|     { | ||||
|         uint8_t b; | ||||
|         read_bytes(&b, 1); | ||||
|         return b; | ||||
|     } | ||||
|  | ||||
|     uint32_t read_28() | ||||
|     { | ||||
|         return ((read_byte() & 0xfe) >> 1) | ||||
|             | ((read_byte() & 0xfe) << 6) | ||||
|             | ((read_byte() & 0xfe) << 13) | ||||
|             | ((read_byte() & 0xfe) << 20); | ||||
|     } | ||||
|  | ||||
|     void write_bytes(const uint8_t* buffer, int len) | ||||
|     { | ||||
|         while (len > 0) | ||||
|         { | ||||
|             int actual; | ||||
|             int rc = libusb_bulk_transfer(_device, EP_OUT, (uint8_t*)buffer, len, &actual, 0); | ||||
|             if (rc < 0) | ||||
|                 Error() << "failed to send command: " << usberror(rc); | ||||
|  | ||||
|             buffer += actual; | ||||
|             len -= actual; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     void write_bytes(const Bytes& bytes) | ||||
|     { | ||||
|         write_bytes(bytes.cbegin(), bytes.size()); | ||||
|     } | ||||
|  | ||||
|     void do_command(const Bytes& command) | ||||
|     { | ||||
|         write_bytes(command); | ||||
|  | ||||
|         uint8_t buffer[2]; | ||||
|         read_bytes(buffer, sizeof(buffer)); | ||||
|  | ||||
|         if (buffer[0] != command[0]) | ||||
|             Error() << fmt::format("command returned garbage (0x{:x} != 0x{:x} with status 0x{:x})", | ||||
|                 buffer[0], command[0], buffer[1]); | ||||
|         if (buffer[1]) | ||||
|             Error() << fmt::format("GreaseWeazle error: {}", gw_error(buffer[1])); | ||||
|     } | ||||
|  | ||||
| public: | ||||
|     GreaseWeazleUsb(libusb_device_handle* device) | ||||
|     { | ||||
|         _device = device; | ||||
|  | ||||
|         /* Configure the device. */ | ||||
|  | ||||
|         int i; | ||||
|         int cfg = -1; | ||||
|         libusb_get_configuration(_device, &cfg); | ||||
|         if (cfg != 1) | ||||
|         { | ||||
|             i = libusb_set_configuration(_device, 1); | ||||
|             if (i < 0) | ||||
|                 Error() << "the GreaseWeazle would not accept configuration: " << usberror(i); | ||||
|         } | ||||
|  | ||||
|         /* Detach the existing kernel serial port driver, if there is one, and claim it ourselves. */ | ||||
|  | ||||
|         for (int i = 0; i < 2; i++) | ||||
|         { | ||||
|             if (libusb_kernel_driver_active(_device, i)) | ||||
|                 libusb_detach_kernel_driver(_device, i); | ||||
|             int rc = libusb_claim_interface(_device, i); | ||||
|             if (rc < 0) | ||||
|                 Error() << "unable to claim interface: " << libusb_error_name(rc); | ||||
|         } | ||||
|  | ||||
|         int version = getVersion(); | ||||
|         if (version != GREASEWEAZLE_VERSION) | ||||
|             Error() << "your GreaseWeazle firmware is at version " << version | ||||
|                     << " but the client is for version " << GREASEWEAZLE_VERSION | ||||
|                     << "; please upgrade"; | ||||
|  | ||||
|         /* Configure the hardware. */ | ||||
|  | ||||
|         do_command({ CMD_SET_BUS_TYPE, 3, BUS_IBMPC }); | ||||
|     } | ||||
|  | ||||
|     int getVersion() | ||||
|     { | ||||
|         do_command({ CMD_GET_INFO, 3, GETINFO_FIRMWARE }); | ||||
|  | ||||
|         Bytes response = read_bytes(32); | ||||
|         ByteReader br(response); | ||||
|  | ||||
|         br.seek(4); | ||||
|         nanoseconds_t freq = br.read_le32(); | ||||
|         _clock = 1000000000 / freq; | ||||
|  | ||||
|         br.seek(0); | ||||
|         return br.read_be16(); | ||||
|     } | ||||
|  | ||||
|     void recalibrate() | ||||
|     { | ||||
|         seek(0); | ||||
|     } | ||||
|      | ||||
|     void seek(int track) | ||||
|     { | ||||
|         do_command({ CMD_SEEK, 3, (uint8_t)track }); | ||||
|     } | ||||
|      | ||||
|     nanoseconds_t getRotationalPeriod(int hardSectorCount) | ||||
|     { | ||||
|         if (hardSectorCount != 0) | ||||
|             Error() << "hard sectors are currently unsupported on the GreaseWeazel"; | ||||
|  | ||||
|         /* The GreaseWeazle doesn't have a command to fetch the period directly, | ||||
|          * so we have to do a flux read. */ | ||||
|  | ||||
|         do_command({ CMD_READ_FLUX, 2 }); | ||||
|  | ||||
|         uint32_t ticks_gw = 0; | ||||
|         uint32_t firstindex = ~0; | ||||
|         uint32_t secondindex = ~0; | ||||
|         for (;;) | ||||
|         { | ||||
|             uint8_t b = read_byte(); | ||||
|             if (!b) | ||||
|                 break; | ||||
|  | ||||
|             if (b == 255) | ||||
|             { | ||||
|                 switch (read_byte()) | ||||
|                 { | ||||
|                     case FLUXOP_INDEX: | ||||
|                     { | ||||
|                         uint32_t index = read_28() + ticks_gw; | ||||
|                         if (firstindex == ~0) | ||||
|                             firstindex = index; | ||||
|                         else if (secondindex == ~0) | ||||
|                             secondindex = index; | ||||
|                         break; | ||||
|                     } | ||||
|  | ||||
|                     case FLUXOP_SPACE: | ||||
|                         read_bytes(4); | ||||
|                         break; | ||||
|  | ||||
|                     default: | ||||
|                         Error() << "bad opcode in GreaseWeazle stream"; | ||||
|                 } | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 if (b < 250) | ||||
|                     ticks_gw += b; | ||||
|                 else | ||||
|                 { | ||||
|                     int delta = 250 + (b-250)*255 + read_byte() - 1; | ||||
|                     ticks_gw += delta; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         if (secondindex == ~0) | ||||
|             Error() << "unable to determine disk rotational period (is a disk in the drive?)"; | ||||
|         do_command({ CMD_GET_FLUX_STATUS, 2 }); | ||||
|  | ||||
|         _revolutions = (nanoseconds_t)(secondindex - firstindex) * _clock; | ||||
|         return _revolutions; | ||||
|     } | ||||
|      | ||||
|     void testBulkWrite() | ||||
|     { | ||||
|         const int LEN = 10*1024*1024; | ||||
|         Bytes cmd(6); | ||||
|         ByteWriter bw(cmd); | ||||
|         bw.write_8(CMD_SINK_BYTES); | ||||
|         bw.write_8(cmd.size()); | ||||
|         bw.write_le32(LEN); | ||||
|         do_command(cmd); | ||||
|  | ||||
|         Bytes junk(LEN); | ||||
| 		double start_time = getCurrentTime(); | ||||
|         write_bytes(LEN); | ||||
|         read_bytes(1); | ||||
| 		double elapsed_time = getCurrentTime() - start_time; | ||||
|  | ||||
| 		std::cout << "Transferred " | ||||
| 				  << LEN | ||||
| 				  << " bytes from PC -> GreaseWeazle in " | ||||
| 				  << int(elapsed_time * 1000.0) | ||||
| 				  << " ms (" | ||||
| 				  << int((LEN / 1024.0) / elapsed_time) | ||||
| 				  << " kB/s)" | ||||
| 				  << std::endl; | ||||
|     } | ||||
|      | ||||
|     void testBulkRead() | ||||
|     { | ||||
|         const int LEN = 10*1024*1024; | ||||
|         Bytes cmd(6); | ||||
|         ByteWriter bw(cmd); | ||||
|         bw.write_8(CMD_SOURCE_BYTES); | ||||
|         bw.write_8(cmd.size()); | ||||
|         bw.write_le32(LEN); | ||||
|         do_command(cmd); | ||||
|  | ||||
| 		double start_time = getCurrentTime(); | ||||
|         read_bytes(LEN); | ||||
| 		double elapsed_time = getCurrentTime() - start_time; | ||||
|  | ||||
| 		std::cout << "Transferred " | ||||
| 				  << LEN | ||||
| 				  << " bytes from GreaseWeazle -> PC in " | ||||
| 				  << int(elapsed_time * 1000.0) | ||||
| 				  << " ms (" | ||||
| 				  << int((LEN / 1024.0) / elapsed_time) | ||||
| 				  << " kB/s)" | ||||
| 				  << std::endl; | ||||
|     } | ||||
|  | ||||
|     Bytes read(int side, bool synced, nanoseconds_t readTime, nanoseconds_t hardSectorThreshold) | ||||
|     { | ||||
|         if (hardSectorThreshold != 0) | ||||
|             Error() << "hard sectors are currently unsupported on the GreaseWeazel"; | ||||
|  | ||||
|         int revolutions = (readTime+_revolutions-1) / _revolutions; | ||||
|  | ||||
|         do_command({ CMD_HEAD, 3, (uint8_t)side }); | ||||
|  | ||||
|         { | ||||
|             Bytes cmd(4); | ||||
|             cmd.writer() | ||||
|                 .write_8(CMD_READ_FLUX) | ||||
|                 .write_8(cmd.size()) | ||||
|                 .write_le32(revolutions + (synced ? 1 : 0)); | ||||
|             do_command(cmd); | ||||
|         } | ||||
|  | ||||
| 		Bytes buffer; | ||||
|         ByteWriter bw(buffer); | ||||
|         for (;;) | ||||
|         { | ||||
|             uint8_t b = read_byte(); | ||||
|             if (!b) | ||||
|                 break; | ||||
|             bw.write_8(b); | ||||
|         } | ||||
|  | ||||
|         do_command({ CMD_GET_FLUX_STATUS, 2 }); | ||||
|  | ||||
|         Bytes fldata = greaseWeazleToFluxEngine(buffer, _clock); | ||||
|         if (synced) | ||||
|             fldata = stripPartialRotation(fldata); | ||||
|         return fldata; | ||||
|     } | ||||
|      | ||||
|     void write(int side, const Bytes& fldata, nanoseconds_t hardSectorThreshold) | ||||
|     { | ||||
|         if (hardSectorThreshold != 0) | ||||
|             Error() << "hard sectors are currently unsupported on the GreaseWeazel"; | ||||
|  | ||||
|         do_command({ CMD_HEAD, 3, (uint8_t)side }); | ||||
|         do_command({ CMD_WRITE_FLUX, 3, 1 }); | ||||
|         write_bytes(fluxEngineToGreaseWeazle(fldata, _clock)); | ||||
|         read_byte(); /* synchronise */ | ||||
|  | ||||
|         do_command({ CMD_GET_FLUX_STATUS, 2 }); | ||||
|     } | ||||
|      | ||||
|     void erase(int side, nanoseconds_t hardSectorThreshold) | ||||
|     { | ||||
|         if (hardSectorThreshold != 0) | ||||
|             Error() << "hard sectors are currently unsupported on the GreaseWeazel"; | ||||
|  | ||||
|         do_command({ CMD_HEAD, 3, (uint8_t)side }); | ||||
|  | ||||
|         Bytes cmd(6); | ||||
|         ByteWriter bw(cmd); | ||||
|         bw.write_8(CMD_ERASE_FLUX); | ||||
|         bw.write_8(cmd.size()); | ||||
|         bw.write_le32(200e6 / _clock); | ||||
|         do_command(cmd); | ||||
|         read_byte(); /* synchronise */ | ||||
|  | ||||
|         do_command({ CMD_GET_FLUX_STATUS, 2 }); | ||||
|     } | ||||
|      | ||||
|     void setDrive(int drive, bool high_density, int index_mode) | ||||
|     { | ||||
|         do_command({ CMD_SELECT, 3, (uint8_t)drive }); | ||||
|         do_command({ CMD_MOTOR, 4, (uint8_t)drive, 1 }); | ||||
|         do_command({ CMD_SET_PIN, 4, 2, (uint8_t)(high_density ? 0 : 1) }); | ||||
|     } | ||||
|  | ||||
|     void measureVoltages(struct voltages_frame* voltages) | ||||
|     { Error() << "unsupported operation on the GreaseWeazle"; } | ||||
|  | ||||
| private: | ||||
|     nanoseconds_t _clock; | ||||
|     nanoseconds_t _revolutions; | ||||
| }; | ||||
|  | ||||
| USB* createGreaseWeazleUsb(libusb_device_handle* device) | ||||
| { | ||||
|     return new GreaseWeazleUsb(device); | ||||
| } | ||||
|  | ||||
| // vim: sw=4 ts=4 et | ||||
|  | ||||
| @@ -6,6 +6,7 @@ | ||||
| #include "bytes.h" | ||||
| #include <libusb.h> | ||||
| #include "fmt/format.h" | ||||
| #include "greaseweazle.h" | ||||
|  | ||||
| FlagGroup usbFlags; | ||||
|  | ||||
| @@ -19,6 +20,7 @@ static USB* usb = NULL; | ||||
| enum | ||||
| { | ||||
| 	DEV_FLUXENGINE, | ||||
| 	DEV_GREASEWEAZLE, | ||||
| }; | ||||
|  | ||||
| struct CandidateDevice | ||||
| @@ -42,11 +44,28 @@ static const char* device_type(int i) | ||||
| 	switch (i) | ||||
| 	{ | ||||
| 		case DEV_FLUXENGINE: return "FluxEngine"; | ||||
| 		case DEV_GREASEWEAZLE: return "GreaseWeazle"; | ||||
| 		default: assert(false); | ||||
| 	} | ||||
| 	return NULL; | ||||
| } | ||||
|  | ||||
| static const std::string get_serial_number(libusb_device* device, libusb_device_descriptor* desc) | ||||
| { | ||||
| 	std::string serial; | ||||
|  | ||||
| 	libusb_device_handle* handle; | ||||
| 	if (libusb_open(device, &handle) == 0) | ||||
| 	{ | ||||
| 		unsigned char buffer[64]; | ||||
| 		libusb_get_string_descriptor_ascii(handle, desc->iSerialNumber, buffer, sizeof(buffer)); | ||||
| 		serial = (const char*) buffer; | ||||
| 		libusb_close(handle); | ||||
| 	} | ||||
|  | ||||
| 	return serial; | ||||
| } | ||||
|  | ||||
| static std::map<std::string, std::unique_ptr<CandidateDevice>> get_candidates(libusb_device** devices, int numdevices) | ||||
| { | ||||
| 	std::map<std::string, std::unique_ptr<CandidateDevice>> candidates; | ||||
| @@ -56,22 +75,24 @@ static std::map<std::string, std::unique_ptr<CandidateDevice>> get_candidates(li | ||||
| 		candidate->device = devices[i]; | ||||
| 		(void) libusb_get_device_descriptor(devices[i], &candidate->desc); | ||||
|  | ||||
| 		if ((candidate->desc.idVendor == FLUXENGINE_VID) && (candidate->desc.idProduct == FLUXENGINE_PID)) | ||||
| 		uint32_t id = (candidate->desc.idVendor << 16) | candidate->desc.idProduct; | ||||
| 		switch (id) | ||||
| 		{ | ||||
| 			candidate->type = DEV_FLUXENGINE; | ||||
| 			candidate->serial = ""; | ||||
|  | ||||
| 			libusb_device_handle* handle; | ||||
| 			if (libusb_open(candidate->device, &handle) == 0) | ||||
| 			case (FLUXENGINE_VID<<16) | FLUXENGINE_PID: | ||||
| 			{ | ||||
| 				unsigned char buffer[64]; | ||||
| 				libusb_get_string_descriptor_ascii(handle, | ||||
| 					candidate->desc.iSerialNumber, buffer, sizeof(buffer)); | ||||
| 				candidate->serial = (const char*) buffer; | ||||
| 				libusb_close(handle); | ||||
| 				candidate->type = DEV_FLUXENGINE; | ||||
| 				candidate->serial = get_serial_number(candidate->device, &candidate->desc); | ||||
| 				candidates[candidate->serial] = std::move(candidate); | ||||
| 				break; | ||||
| 			} | ||||
|  | ||||
| 			candidates[candidate->serial] = std::move(candidate); | ||||
| 			case (GREASEWEAZLE_VID<<16) | GREASEWEAZLE_PID: | ||||
| 			{ | ||||
| 				candidate->type = DEV_GREASEWEAZLE; | ||||
| 				candidate->serial = get_serial_number(candidate->device, &candidate->desc); | ||||
| 				candidates[candidate->serial] = std::move(candidate); | ||||
| 				break; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| @@ -86,7 +107,16 @@ static void open_device(CandidateDevice& candidate) | ||||
| 		Error() << "cannot open USB device: " << libusb_strerror((libusb_error) i); | ||||
| 	 | ||||
| 	std::cout << "Using " << device_type(candidate.type) << " with serial number " << candidate.serial << '\n'; | ||||
| 	usb = createFluxengineUsb(handle); | ||||
| 	switch (candidate.type) | ||||
| 	{ | ||||
| 		case DEV_FLUXENGINE: | ||||
| 			usb = createFluxengineUsb(handle); | ||||
| 			break; | ||||
|  | ||||
| 		case DEV_GREASEWEAZLE: | ||||
| 			usb = createGreaseWeazleUsb(handle); | ||||
| 			break; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| static CandidateDevice& select_candidate(const std::map<std::string, std::unique_ptr<CandidateDevice>>& devices) | ||||
|   | ||||
| @@ -15,12 +15,14 @@ public: | ||||
| 	virtual int getVersion() = 0; | ||||
| 	virtual void recalibrate() = 0; | ||||
| 	virtual void seek(int track) = 0; | ||||
| 	virtual nanoseconds_t getRotationalPeriod() = 0; | ||||
| 	virtual nanoseconds_t getRotationalPeriod(int hardSectorCount) = 0; | ||||
| 	virtual void testBulkWrite() = 0; | ||||
| 	virtual void testBulkRead() = 0; | ||||
| 	virtual Bytes read(int side, bool synced, nanoseconds_t readTime) = 0; | ||||
| 	virtual void write(int side, const Bytes& bytes) = 0; | ||||
| 	virtual void erase(int side) = 0; | ||||
| 	virtual Bytes read(int side, bool synced, nanoseconds_t readTime, | ||||
| 	                   nanoseconds_t hardSectorThreshold) = 0; | ||||
| 	virtual void write(int side, const Bytes& bytes, | ||||
| 	                   nanoseconds_t hardSectorThreshold) = 0; | ||||
| 	virtual void erase(int side, nanoseconds_t hardSectorThreshold) = 0; | ||||
| 	virtual void setDrive(int drive, bool high_density, int index_mode) = 0; | ||||
| 	virtual void measureVoltages(struct voltages_frame* voltages) = 0; | ||||
|  | ||||
| @@ -34,22 +36,27 @@ extern FlagGroup usbFlags; | ||||
| extern USB& getUsb(); | ||||
|  | ||||
| extern USB* createFluxengineUsb(libusb_device_handle* device); | ||||
| extern USB* createGreaseWeazleUsb(libusb_device_handle* device); | ||||
|  | ||||
| static inline int usbGetVersion()     { return getUsb().getVersion(); } | ||||
| static inline void usbRecalibrate()   { getUsb().recalibrate(); } | ||||
| static inline void usbSeek(int track) { getUsb().seek(track); } | ||||
| static inline void usbTestBulkWrite() { getUsb().testBulkWrite(); } | ||||
| static inline void usbTestBulkRead()  { getUsb().testBulkRead(); } | ||||
| static inline void usbErase(int side) { getUsb().erase(side); } | ||||
|  | ||||
| static inline nanoseconds_t usbGetRotationalPeriod() | ||||
| { return getUsb().getRotationalPeriod(); } | ||||
| static inline void usbErase(int side, nanoseconds_t hardSectorThreshold) | ||||
| { getUsb().erase(side, hardSectorThreshold); } | ||||
|  | ||||
| static inline Bytes usbRead(int side, bool synced, nanoseconds_t readTime) | ||||
| { return getUsb().read(side, synced, readTime); } | ||||
| static inline nanoseconds_t usbGetRotationalPeriod(int hardSectorCount) | ||||
| { return getUsb().getRotationalPeriod(hardSectorCount); } | ||||
|  | ||||
| static inline void usbWrite(int side, const Bytes& bytes) | ||||
| { getUsb().write(side, bytes); } | ||||
| static inline Bytes usbRead(int side, bool synced, nanoseconds_t readTime, | ||||
|                             nanoseconds_t hardSectorThreshold) | ||||
| { return getUsb().read(side, synced, readTime, hardSectorThreshold); } | ||||
|  | ||||
| static inline void usbWrite(int side, const Bytes& bytes, | ||||
|                             nanoseconds_t hardSectorThreshold) | ||||
| { getUsb().write(side, bytes, hardSectorThreshold); } | ||||
|  | ||||
| static inline void usbSetDrive(int drive, bool high_density, int index_mode) | ||||
| { getUsb().setDrive(drive, high_density, index_mode); } | ||||
|   | ||||
| @@ -43,6 +43,11 @@ void setWriterDefaultInput(const std::string& input) | ||||
|     ::input.set(input); | ||||
| } | ||||
|  | ||||
| void setWriterHardSectorCount(int sectorCount) | ||||
| { | ||||
| 	setHardwareFluxSinkHardSectorCount(sectorCount); | ||||
| } | ||||
|  | ||||
| static SectorSet readSectorsFromFile(const ImageSpec& spec) | ||||
| { | ||||
| 	return ImageReader::create(spec)->readImage(); | ||||
|   | ||||
| @@ -11,6 +11,7 @@ class Geometry; | ||||
|  | ||||
| extern void setWriterDefaultDest(const std::string& dest); | ||||
| extern void setWriterDefaultInput(const std::string& input); | ||||
| extern void setWriterHardSectorCount(int sectorCount); | ||||
|  | ||||
| extern void writeTracks(const std::function<std::unique_ptr<Fluxmap>(int track, int side)> producer); | ||||
|  | ||||
|   | ||||
| @@ -199,6 +199,8 @@ buildlibrary libbackend.a \ | ||||
|     lib/fluxsource/streamfluxsource.cc \ | ||||
|     lib/usb/usb.cc \ | ||||
|     lib/usb/fluxengineusb.cc \ | ||||
|     lib/usb/greaseweazle.cc \ | ||||
|     lib/usb/greaseweazleusb.cc \ | ||||
|     lib/globals.cc \ | ||||
|     lib/hexdump.cc \ | ||||
|     lib/ldbs.cc \ | ||||
| @@ -210,6 +212,7 @@ buildlibrary libbackend.a \ | ||||
|     lib/writer.cc \ | ||||
|  | ||||
| buildlibrary libfrontend.a \ | ||||
| 	src/fe-analysedriveresponse.cc \ | ||||
|     src/fe-cwftoflux.cc \ | ||||
|     src/fe-erase.cc \ | ||||
|     src/fe-fluxtoau.cc \ | ||||
| @@ -271,6 +274,7 @@ buildsimpleprogram brother240tool \ | ||||
|     libemu.a \ | ||||
|     libfmt.a \ | ||||
|  | ||||
| runtest amiga-test          tests/amiga.cc | ||||
| runtest bitaccumulator-test tests/bitaccumulator.cc | ||||
| runtest bytes-test          tests/bytes.cc | ||||
| runtest compression-test    tests/compression.cc | ||||
| @@ -278,6 +282,6 @@ runtest dataspec-test       tests/dataspec.cc | ||||
| runtest flags-test          tests/flags.cc | ||||
| runtest fluxpattern-test    tests/fluxpattern.cc | ||||
| runtest fmmfm-test          tests/fmmfm.cc | ||||
| runtest greaseweazle-test   tests/greaseweazle.cc | ||||
| runtest kryoflux-test       tests/kryoflux.cc | ||||
| runtest ldbs-test           tests/ldbs.cc | ||||
| runtest amiga-test          tests/amiga.cc | ||||
|   | ||||
							
								
								
									
										13
									
								
								protocol.h
									
									
									
									
									
								
							
							
						
						
									
										13
									
								
								protocol.h
									
									
									
									
									
								
							| @@ -3,7 +3,7 @@ | ||||
|  | ||||
| enum  | ||||
| { | ||||
|     FLUXENGINE_VERSION = 14, | ||||
|     FLUXENGINE_VERSION = 15, | ||||
|  | ||||
|     FLUXENGINE_VID = 0x1209, | ||||
|     FLUXENGINE_PID = 0x6e00, | ||||
| @@ -48,7 +48,7 @@ enum | ||||
|     F_FRAME_GET_VERSION_REPLY,    /* version_frame */ | ||||
|     F_FRAME_SEEK_CMD,             /* seek_frame */ | ||||
|     F_FRAME_SEEK_REPLY,           /* any_frame */ | ||||
|     F_FRAME_MEASURE_SPEED_CMD,    /* any_frame */ | ||||
|     F_FRAME_MEASURE_SPEED_CMD,    /* measurespeed_frame */ | ||||
|     F_FRAME_MEASURE_SPEED_REPLY,  /* speed_frame */ | ||||
|     F_FRAME_BULK_WRITE_TEST_CMD,   /* any_frame */ | ||||
|     F_FRAME_BULK_WRITE_TEST_REPLY, /* any_frame */ | ||||
| @@ -125,6 +125,12 @@ struct seek_frame | ||||
|     uint8_t track; | ||||
| }; | ||||
|  | ||||
| struct measurespeed_frame  | ||||
| { | ||||
|     struct frame_header f; | ||||
| 	uint8_t hard_sector_count; | ||||
| }; | ||||
|  | ||||
| struct speed_frame | ||||
| { | ||||
|     struct frame_header f; | ||||
| @@ -137,6 +143,7 @@ struct read_frame | ||||
|     uint8_t side; | ||||
|     uint8_t synced; | ||||
|     uint16_t milliseconds; | ||||
|     uint8_t hardsec_threshold_ms; | ||||
| }; | ||||
|  | ||||
| struct write_frame | ||||
| @@ -144,12 +151,14 @@ struct write_frame | ||||
|     struct frame_header f; | ||||
|     uint8_t side; | ||||
|     uint32_t bytes_to_write; | ||||
|     uint8_t hardsec_threshold_ms; | ||||
| }; | ||||
|  | ||||
| struct erase_frame | ||||
| { | ||||
|     struct frame_header f; | ||||
|     uint8_t side; | ||||
|     uint8_t hardsec_threshold_ms; | ||||
| }; | ||||
|  | ||||
| struct set_drive_frame | ||||
|   | ||||
							
								
								
									
										36
									
								
								scripts/analysedriveresponse.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								scripts/analysedriveresponse.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,36 @@ | ||||
| import numpy | ||||
| import matplotlib.pyplot as plt | ||||
| import matplotlib.animation as animation | ||||
|  | ||||
| TICK_FREQUENCY = 12e6 | ||||
| TICKS_PER_US = TICK_FREQUENCY / 1e6 | ||||
| print(TICKS_PER_US) | ||||
|  | ||||
| # Load data. | ||||
| data = numpy.loadtxt(open("driveresponse.csv", "rb"), delimiter=",", skiprows=1) | ||||
|  | ||||
| labels = data[:, 0] | ||||
| frequencies = data[:, 1:] | ||||
|  | ||||
| # Scale the frequencies. | ||||
| def scaled(row): | ||||
|     m = row.mean() | ||||
|     if m != 0: | ||||
|         return row / m | ||||
|     else: | ||||
|         return row | ||||
|  | ||||
| scaledfreq = numpy.array([scaled(row) for row in frequencies]) | ||||
|  | ||||
| # Create new Figure with black background | ||||
| fig = plt.figure(figsize=(8, 8), facecolor='#aaa') | ||||
|  | ||||
| plt.imshow(scaledfreq, extent=[0, 512/TICKS_PER_US, labels[0], labels[-1]], cmap='jet', | ||||
|            vmin=0, vmax=1, origin='lower', aspect='auto') | ||||
| plt.colorbar() | ||||
| plt.ylabel("Interval period (us)") | ||||
| plt.xlabel("Response (us)") | ||||
| plt.grid(True, dashes=(2, 2)) | ||||
| plt.show() | ||||
|  | ||||
| plt.show() | ||||
							
								
								
									
										135
									
								
								src/fe-analysedriveresponse.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										135
									
								
								src/fe-analysedriveresponse.cc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,135 @@ | ||||
| #include "globals.h" | ||||
| #include "flags.h" | ||||
| #include "usb/usb.h" | ||||
| #include "dataspec.h" | ||||
| #include "fluxmap.h" | ||||
| #include "decoders/fluxmapreader.h" | ||||
| #include "writer.h" | ||||
| #include "protocol.h" | ||||
| #include "fmt/format.h" | ||||
| #include <fstream> | ||||
|  | ||||
| static FlagGroup flags = { | ||||
| 	&usbFlags, | ||||
| }; | ||||
|  | ||||
| static DataSpecFlag dest( | ||||
|     { "--dest", "-d" }, | ||||
|     "destination to analyse", | ||||
|     ":d=0:t=0:s=0"); | ||||
|  | ||||
| static DoubleFlag minInterval( | ||||
| 	{ "--min-interval-us" }, | ||||
| 	"Minimum pulse interval", | ||||
| 	2.0); | ||||
|  | ||||
| static DoubleFlag maxInterval( | ||||
| 	{ "--max-interval-us" }, | ||||
| 	"Maximum pulse interval", | ||||
| 	10.0); | ||||
|  | ||||
| static DoubleFlag intervalStep( | ||||
| 	{ "--interval-step-us" }, | ||||
| 	"Interval step, approximately", | ||||
| 	0.2); | ||||
|  | ||||
| static StringFlag writeCsv( | ||||
| 	{ "--write-csv" }, | ||||
| 	"Write detailed CSV data", | ||||
| 	"driveresponse.csv"); | ||||
|  | ||||
| int mainAnalyseDriveResponse(int argc, const char* argv[]) | ||||
| { | ||||
|     flags.parseFlags(argc, argv); | ||||
|  | ||||
|     FluxSpec spec(dest); | ||||
| 	if (spec.locations.size() != 1) | ||||
| 		Error() << "the destination dataspec must contain exactly one track (two sides count as two tracks)"; | ||||
|  | ||||
|     usbSetDrive(spec.drive, false, F_INDEX_REAL); | ||||
| 	usbSeek(spec.locations[0].track); | ||||
|  | ||||
| 	std::cout << "Measuring rotational speed...\n"; | ||||
|     nanoseconds_t period = usbGetRotationalPeriod(0); | ||||
| 	if (period == 0) | ||||
| 		Error() << "Unable to measure rotational speed (try fluxengine rpm)."; | ||||
|  | ||||
| 	std::ofstream csv; | ||||
| 	if (writeCsv.get() != "") | ||||
| 		csv.open(writeCsv); | ||||
|  | ||||
| 	for (double interval = minInterval; interval<maxInterval; interval += intervalStep) | ||||
| 	{ | ||||
| 		unsigned ticks = (unsigned) (interval * TICKS_PER_US); | ||||
| 		std::cout << fmt::format("Interval {:.2f}: ", ticks * US_PER_TICK); | ||||
| 		std::cout << std::flush; | ||||
|  | ||||
| 		std::vector<int> frequencies(512); | ||||
|  | ||||
| 		if (interval >= 2.0) | ||||
| 		{ | ||||
| 			/* Write the test pattern. */ | ||||
|  | ||||
| 			Fluxmap outFluxmap; | ||||
| 			while (outFluxmap.duration() < period) | ||||
| 			{ | ||||
| 				outFluxmap.appendInterval(ticks); | ||||
| 				outFluxmap.appendPulse(); | ||||
| 			} | ||||
| 			usbWrite(spec.locations[0].side, outFluxmap.rawBytes(), 0); | ||||
|  | ||||
| 			/* Read the test pattern in again. */ | ||||
|  | ||||
| 			Fluxmap inFluxmap; | ||||
| 			inFluxmap.appendBytes(usbRead(spec.locations[0].side, true, period, 0)); | ||||
|  | ||||
| 			/* Compute histogram. */ | ||||
|  | ||||
| 			FluxmapReader fmr(inFluxmap); | ||||
| 			fmr.seek((double)period*0.1); /* skip first 10% and last 10% as contains junk */ | ||||
| 			fmr.findEvent(F_BIT_PULSE); | ||||
| 			while (fmr.tell().ns() < ((double)period*0.9)) | ||||
| 			{ | ||||
| 				unsigned ticks = fmr.findEvent(F_BIT_PULSE); | ||||
| 				if (ticks < frequencies.size()) | ||||
| 					frequencies[ticks]++; | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		/* Compute standard deviation. */ | ||||
|  | ||||
| 		int sum = 0; | ||||
| 		int prod = 0; | ||||
| 		for (int i=0; i<frequencies.size(); i++) | ||||
| 		{ | ||||
| 			sum += frequencies[i]; | ||||
| 			prod += i * frequencies[i]; | ||||
| 		} | ||||
| 		if (sum == 0) | ||||
| 			std::cout << "failed\n"; | ||||
| 		else | ||||
| 		{ | ||||
| 			double mean = prod / sum; | ||||
| 			double sqsum = 0; | ||||
| 			for (int i=0; i<frequencies.size(); i++) | ||||
| 			{ | ||||
| 				double dx = (double)i - mean; | ||||
| 				sqsum += (double)frequencies[i] * dx * dx; | ||||
| 			} | ||||
| 			double stdv = sqrt(sqsum / sum); | ||||
| 			std::cout << fmt::format("{:.4f} {:.4f}\n", stdv, mean/TICKS_PER_US); | ||||
|  | ||||
| 		} | ||||
|  | ||||
| 		if (writeCsv.get() != "") | ||||
| 		{ | ||||
| 			csv << interval; | ||||
| 			for (int i : frequencies) | ||||
| 				csv << "," << i; | ||||
| 			csv << '\n'; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| @@ -16,7 +16,7 @@ int mainReadMicropolis(int argc, const char* argv[]) | ||||
| { | ||||
| 	setReaderDefaultSource(":t=0-76"); | ||||
| 	setReaderDefaultOutput("micropolis.img"); | ||||
| 	setReaderRevolutions(21); /* 17 index holes * 1.25 */ | ||||
| 	setReaderHardSectorCount(16); | ||||
| 	flags.parseFlags(argc, argv); | ||||
|  | ||||
| 	MicropolisDecoder decoder; | ||||
|   | ||||
| @@ -13,13 +13,18 @@ static DataSpecFlag source( | ||||
|     "source for data", | ||||
|     ":d=0:t=0:s=0"); | ||||
|  | ||||
| static IntFlag hardSectorCount( | ||||
|     { "--hard-sector-count" }, | ||||
|     "number of hard sectors on the disk (0=soft sectors)", | ||||
|     0); | ||||
|  | ||||
| int mainRpm(int argc, const char* argv[]) | ||||
| { | ||||
|     flags.parseFlags(argc, argv); | ||||
|  | ||||
|     FluxSpec spec(source); | ||||
|     usbSetDrive(spec.drive, false, F_INDEX_REAL); | ||||
|     nanoseconds_t period = usbGetRotationalPeriod(); | ||||
|     nanoseconds_t period = usbGetRotationalPeriod(hardSectorCount); | ||||
|     if (period != 0) | ||||
|         std::cout << "Rotational period is " << period/1000000 << " ms (" << 60e9/period << " rpm)" << std::endl; | ||||
|     else | ||||
|   | ||||
| @@ -2,6 +2,7 @@ | ||||
|  | ||||
| typedef int command_cb(int agrc, const char* argv[]); | ||||
|  | ||||
| extern command_cb mainAnalyseDriveResponse; | ||||
| extern command_cb mainErase; | ||||
| extern command_cb mainConvertCwfToFlux; | ||||
| extern command_cb mainConvertFluxToAu; | ||||
| @@ -50,6 +51,7 @@ struct Command | ||||
| static command_cb mainRead; | ||||
| static command_cb mainWrite; | ||||
| static command_cb mainConvert; | ||||
| static command_cb mainAnalyse; | ||||
| static command_cb mainTest; | ||||
|  | ||||
| static std::vector<Command> commands = | ||||
| @@ -57,6 +59,7 @@ static std::vector<Command> commands = | ||||
|     { "erase",             mainErase,             "Permanently but rapidly erases some or all of a disk." }, | ||||
|     { "convert",           mainConvert,           "Converts various types of data file.", }, | ||||
|     { "inspect",           mainInspect,           "Low-level analysis and inspection of a disk." }, | ||||
| 	{ "analyse",           mainAnalyse,           "Disk and drive analysis tools." }, | ||||
|     { "read",              mainRead,              "Reads a disk, producing a sector image.", }, | ||||
|     { "rpm",               mainRpm,               "Measures the disk rotational speed.", }, | ||||
|     { "seek",              mainSeek,              "Moves the disk head.", }, | ||||
| @@ -107,6 +110,11 @@ static std::vector<Command> convertables = | ||||
| 	{ "image",         mainConvertImage,     "Converts one disk image to another.", }, | ||||
| }; | ||||
|  | ||||
| static std::vector<Command> analysables = | ||||
| { | ||||
| 	{ "driveresponse", mainAnalyseDriveResponse, "Measures the drive's ability to read and write pulses.", } | ||||
| }; | ||||
|  | ||||
| static std::vector<Command> testables = | ||||
| { | ||||
|     { "bandwidth",     mainTestBandwidth, "Measures your USB bandwidth.", }, | ||||
| @@ -153,6 +161,9 @@ static int mainWrite(int argc, const char* argv[]) | ||||
| static int mainConvert(int argc, const char* argv[]) | ||||
| { return mainExtended(convertables, "convert", argc, argv); } | ||||
|  | ||||
| static int mainAnalyse(int argc, const char* argv[]) | ||||
| { return mainExtended(analysables, "analyse", argc, argv); } | ||||
|  | ||||
| static int mainTest(int argc, const char* argv[]) | ||||
| { return mainExtended(testables, "test", argc, argv); } | ||||
|  | ||||
|   | ||||
							
								
								
									
										109
									
								
								tests/greaseweazle.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										109
									
								
								tests/greaseweazle.cc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,109 @@ | ||||
| #include <stdio.h> | ||||
| #include <unistd.h> | ||||
| #include <stdlib.h> | ||||
| #include "globals.h" | ||||
| #include "fluxmap.h" | ||||
| #include "lib/usb/greaseweazle.h" | ||||
|  | ||||
| static Bytes operator + (const Bytes& left, const Bytes& right) | ||||
| { | ||||
|     Bytes output; | ||||
|     ByteWriter bw(output); | ||||
|     bw += left; | ||||
|     bw += right; | ||||
|     return output; | ||||
| } | ||||
|  | ||||
| static Bytes operator * (const Bytes& left, size_t count) | ||||
| { | ||||
|     Bytes output; | ||||
|     ByteWriter bw(output); | ||||
|     while (count--) | ||||
|         bw += left; | ||||
|     return output; | ||||
| } | ||||
|  | ||||
| #define E28(val) \ | ||||
| 	(1 | (val<<1) & 0xff), \ | ||||
| 	(1 | (val>>6) & 0xff), \ | ||||
| 	(1 | (val>>13) & 0xff), \ | ||||
| 	(1 | (val>>20) & 0xff) | ||||
|  | ||||
|  | ||||
| static void test_convert(const Bytes& gwbytes, const Bytes& flbytes) | ||||
| { | ||||
| 	Bytes gwtoflbytes = greaseWeazleToFluxEngine(gwbytes, 2*NS_PER_TICK); | ||||
| 	Bytes fltogwbytes = fluxEngineToGreaseWeazle(flbytes, 2*NS_PER_TICK); | ||||
|  | ||||
|     if (gwtoflbytes != flbytes) | ||||
|     { | ||||
| 		std::cout << "GreaseWeazle to FluxEngine conversion failed.\n"; | ||||
|         std::cout << "GreaseWeazle bytes:" << std::endl; | ||||
|         hexdump(std::cout, gwbytes); | ||||
|         std::cout << std::endl << "Produced this:" << std::endl; | ||||
|         hexdump(std::cout, gwtoflbytes); | ||||
|         std::cout << std::endl << "Expected this:" << std::endl; | ||||
|         hexdump(std::cout, flbytes); | ||||
|         abort(); | ||||
|     } | ||||
|  | ||||
|     if (fltogwbytes != gwbytes) | ||||
|     { | ||||
| 		std::cout << "FluxEngine to GreaseWeazle conversion failed.\n"; | ||||
|         std::cout << "FluxEngine bytes:" << std::endl; | ||||
|         hexdump(std::cout, flbytes); | ||||
|         std::cout << std::endl << "Produced this:" << std::endl; | ||||
|         hexdump(std::cout, fltogwbytes); | ||||
|         std::cout << std::endl << "Expected this:" << std::endl; | ||||
|         hexdump(std::cout, gwbytes); | ||||
|         abort(); | ||||
|     } | ||||
| } | ||||
|  | ||||
| static void test_conversions() | ||||
| { | ||||
| 	/* Simple one-byte intervals. */ | ||||
|  | ||||
| 	test_convert( | ||||
| 		Bytes{ 1, 1, 1, 1, 0 }, | ||||
| 		Bytes{ 0x82, 0x82, 0x82, 0x82 } | ||||
| 	); | ||||
|  | ||||
| 	/* Larger one-byte intervals. */ | ||||
|  | ||||
| 	test_convert( | ||||
| 		Bytes{ 32, 0 }, | ||||
| 		Bytes{ 0x3f, 0x81 } | ||||
| 	); | ||||
|  | ||||
| 	test_convert( | ||||
| 		Bytes{ 64, 0 }, | ||||
| 		Bytes{ 0x3f, 0x3f, 0x82 } | ||||
| 	); | ||||
|  | ||||
| 	test_convert( | ||||
| 		Bytes{ 128, 0 }, | ||||
| 		Bytes{ 0x3f, 0x3f, 0x3f, 0x3f, 0x84 } | ||||
| 	); | ||||
|  | ||||
| 	/* Two-byte intervals. */ | ||||
|  | ||||
| 	test_convert( | ||||
| 		Bytes{ 250, 1, 0 }, | ||||
| 		Bytes{ 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0xbb } | ||||
| 	); | ||||
|  | ||||
| 	/* Very long intervals. */ | ||||
|  | ||||
| 	test_convert( | ||||
| 		Bytes{ 255, FLUXOP_SPACE, E28(2048 - 249), 249, 0 }, | ||||
| 		Bytes{ 0x3f }*0x41 + Bytes{ 0x81 } | ||||
| 	); | ||||
| } | ||||
|  | ||||
| int main(int argc, const char* argv[]) | ||||
| { | ||||
| 	test_conversions(); | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
		Reference in New Issue
	
	Block a user