mirror of
				https://github.com/davidgiven/fluxengine.git
				synced 2025-10-24 11:11:02 -07:00 
			
		
		
		
	Compare commits
	
		
			59 Commits
		
	
	
		
			FluxEngine
			...
			FluxEngine
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | 5706877b67 | ||
|  | d60900262b | ||
|  | 54ea34400b | ||
|  | db2ab8841a | ||
|  | adba93ae0a | ||
|  | 98587d04a7 | ||
|  | 0051b64648 | ||
|  | 603009ba15 | ||
|  | adb9809692 | ||
|  | 06eb10d2a0 | ||
|  | 2244299bd9 | ||
|  | 6ca06ecafb | ||
|  | 9a5958f80b | ||
|  | 2b53ac057c | ||
|  | 5deba8af41 | ||
|  | 3c54a663b8 | ||
|  | 1fd65452c4 | ||
|  | 30646ccb07 | ||
|  | 5be7249a30 | ||
|  | 067af18103 | ||
|  | 8dbd2a72a7 | ||
|  | c29e131a3b | ||
|  | a9e30c1e49 | ||
|  | 972c8c6b61 | ||
|  | 2007ff7546 | ||
|  | 64694580cd | ||
|  | deaab94494 | ||
|  | 1509e1f89d | ||
|  | 29e1ddc2ff | ||
|  | 1fe6434563 | ||
|  | 0367b7e77d | ||
|  | e6da85bf64 | ||
|  | cd19fcdadd | ||
|  | 1954f02cfb | ||
|  | 39b23200b0 | ||
|  | 0644d6d965 | ||
|  | a075694d8e | ||
|  | b1ea5a9a35 | ||
|  | 00087cbb6b | ||
|  | 1b48ea20c4 | ||
|  | 3d0f019fc4 | ||
|  | a08bfc183f | ||
|  | c5aef9b051 | ||
|  | fc2655ecd6 | ||
|  | a737c723d3 | ||
|  | 37aa8b62b0 | ||
|  | a401173f6d | ||
|  | ce76dc4279 | ||
|  | 1025bd857b | ||
|  | 025802b2d0 | ||
|  | adbcb2cd31 | ||
|  | c47a563790 | ||
|  | 04c09d1a5b | ||
|  | 323da8272a | ||
|  | 38700c79fc | ||
|  | d504d1890a | ||
|  | d53e757cfb | ||
|  | 4983239458 | ||
|  | 376985828a | 
							
								
								
									
										2
									
								
								.github/workflows/ccpp.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/ccpp.yml
									
									
									
									
										vendored
									
									
								
							| @@ -10,7 +10,7 @@ jobs: | ||||
|       with: | ||||
|         fetch-depth: 1 | ||||
|     - name: apt | ||||
|       run: sudo apt install libusb-1.0-0-dev libsqlite3-dev ninja-build | ||||
|       run: sudo apt update && sudo apt install libusb-1.0-0-dev libsqlite3-dev ninja-build | ||||
|     - name: make | ||||
|       run: make | ||||
|  | ||||
|   | ||||
| @@ -1,252 +1,252 @@ | ||||
| :400000000080002011000000D5110000D5110000064A08B5136843F020031360044B1A6803F53F5302331A6001F0F2F8E8460040FA46004010B5054C237833B9044B13B16F | ||||
| :400040000448AFF300800123237010BD6881FF1F00000000503A0000084B10B51BB108490848AFF300800848036803B910BD074B002BFBD0BDE81040184700BF00000000B7 | ||||
| :400080006C81FF1F503A0000C880FF1F000000000A4A0B4B116801310B40002BBEBF03F1FF3363F03F030133136011685368994202BF024B01221A72704700BF8881FF1F32 | ||||
| :400000000080002011000000A10F0000A10F0000064A08B5136843F020031360044B1A6803F53F5302331A6000F0D8FFE8460040FA46004010B5054C237833B9044B13B1EF | ||||
| :400040000448AFF300800123237010BD6881FF1F0000000020380000084B10B51BB108490848AFF300800848036803B910BD074B002BFBD0BDE81040184700BF00000000E9 | ||||
| :400080006C81FF1F20380000C880FF1F000000000A4A0B4B116801310B40002BBEBF03F1FF3363F03F030133136011685368994202BF024B01221A72704700BF8881FF1F64 | ||||
| :4000C0003F0000800A4A0B4B516801310B40002BBEBF03F1FF3363F03F030133536051681368994202BF024B01221A72704700BF8881FF1F3F000080024B012200205A7293 | ||||
| :4001000002F02CBA8881FF1F10B5C4B2204601F041FA0128FAD110BD08B572B60F4B0F49DA680132DA601A690132C82A08BF00221A615A6918690132A72A08BF00224A6104 | ||||
| :400140005B69002B0CBF02230023002814BF184643F0010002F06AFF62B608BD8881FF1F10B504460D4B8278997E91421CBF00225A7702689A610279094B1A718378002B93 | ||||
| :4001800014BF0220012002F015FFE07802F00CFF2079BDE8104002F043BF00BF8881FF1FA081FF1F70B5C4B220460E4601F0FAF9314605460246204601F0B6FA204601F086 | ||||
| :4001C000E9F90128FAD0284670BD000038B50B4CA57F5DB904F11800FFF7C2FF012002F053F94FF47A7002F065FB6577E36823620123A377BDE8384002F09ABB8881FF1FFA | ||||
| :4002000038B50446C5B2284602F04AF9062002F067FB44F00200C0B202F042F9062002F05FFB284602F03CF9BDE83840062002F041BB10B5642402F02DF920B10120BDE8EA | ||||
| :400240001040FFF7DDBF0120FFF7DAFF013CF2D1F4E7000038B5044D0024285D013402F0EFFA402CF9D138BDAC81FF1F08B502F009FD002002F012FD02F024FD02F02EFD5E | ||||
| :4002800080B208BD10B50446012002F021F9642002F010FBFFF7EAFF2080002002F018F9642002F007FBFFF7E1FF608010BD08B502F014FE002002F01DFE02F02FFE02F0EE | ||||
| :4002C00039FE80B208BD10B50446FFF7B2FF322002F0F0FAFFF7EBFF20800020FFF790FF322002F0E7FAFFF7E2FF608010BD0FB400B593B014AB53F8042B402102A801938B | ||||
| :4003000002F08EFF02A802F030F902F03AF913B05DF804EB04B0704710B5044601780648FFF7E5FF0420FFF7EFFE62782146BDE81040042001F086B9643A000007B5002324 | ||||
| :40034000ADF804308DF80600032301A88DF80530FFF7E2FF03B05DF804FB0000F8B51D4C0646FFF733FF637F03B156B91A48FFF7BEFFFFF75EFF012000236077636602F045 | ||||
| :40038000AFFA3246616E1548FFF7B1FF114D0027636E9E4216D002F07DF800B16F66636E9E4205DD0020FFF72BFF6B6E013305E005DA0120FFF724FF6B6E013B6B6602F08B | ||||
| :4003C000B7FAE5E7322002F075FABDE8F8400448FFF78DBF8881FF1F713A0000783A0000953A00002DE9F04F9BB062B602F00AFB8A49042002F02EFB894802F057F889486B | ||||
| :4004000002F0FAFD884802F08BF802F0DBFC02F0ADFB002002F0CEFD02F0A6F80221002001F06EF8814D0321084602F061FAAA462C4602F07DFAAB7F73B12A6AEB689B1AE2 | ||||
| :4004400041F28832934207D9002002F01DF8002002F0B0FD0023AB7701F08AF818B97448FFF745FF04E001F089F80028F7D109E001F07EF80028FBD06E48FFF738FF0320E6 | ||||
| :4004800001F0A6F9032001F085F80128D1D16A48FFF766FE69490320FFF784FE94F868106748FFF724FF94F86830023B142B00F26A84DFE813F0150068041E0068042400B2 | ||||
| :4004C0006804480068046B006804D1006804F9016804A9036804C9036804CF036804DA0303238DF828308DF829300C238DF82A30B7E394F86A00FFF731FF524BAEE3FFF72E | ||||
| :4005000065FE00236372E068627A02F0FF0132B9EB681B1AB3F57A7FF6DD0B460AE04BB100228AF80920DAF80C10627A12B9EB685B1AFAE707228DF8282004228DF8292037 | ||||
| :40054000ADF82A308DE30220FFF7DEFD00270DF1280902F0EDF94FF480780026C8EB07039A1906F809200136402EF9D10220FFF7CBFD32464946022001F064F8B8F101087C | ||||
| :40058000EBD10137402FE4D12F4B42E04FF00109002702F0CDF94FF00008012001F018F9012000F0F7FF0128FAD10DF1280B4022594601F0B9F8012000F0ECFF0028FAD137 | ||||
| :4005C000064608EB07030593059B1BF806203344DBB2934209D08DE80C003946334642461A48FFF784FE4FF000090136402EEBD108F10108B8F5807FCFD10137402FC8D17D | ||||
| :4006000049461348FFF773FEB9F1000F00F05381104B1B8809A8ADF8243023E319010000F900000091000000C50000008881FF1FA33A0000B63A0000A081FF1FF081FF1F13 | ||||
| :40064000C03A0000543A0000563A0000CF3A0000EB3A0000583A000094F86A0001F038FF606EFFF77BFE02F047FD944B944F1A78002602F0FB021A701A7842F001021A70CD | ||||
| :400680001A7802F0FE021A701A7802F0FE021A7002F036FD0220FFF737FD41F6FF734FF480420121022002F08BFC84F8A80002F0ADF8B8550136402EF9D1DFF82482002668 | ||||
| :4006C00008F18D0B1FFA8BF70136402E14BF3246002218F8010F2244062392F82420402102F0C8F83A4646F2434198F8000002F0D3F84037402EBFB2E6D19AF86B3043B175 | ||||
| :4007000000238AF80930637A002BFCD000238AF80930182200210AA802F04EFD694B4FF0FF320C9340230D930023236062602372236894F8A800234493F8241002F01EF82F | ||||
| :4007400094F8A80001F0DCFF012194F8A80001F0AFFF2368002BFCD000239946CAF80430DAF80C200127059202F0E2F8059AE3689B1AB4F86C2093420ED36FB1042195F822 | ||||
| :40078000A80002F007F894F8A80002F013F80028F9D107468AF80800237A03F0FF08002B48D16A682B689A4202D1002FDCD141E063680AA80BEB831343440A93C8F1400391 | ||||
| :4007C0000B9300F0F9FA0B9B09F10109C3F1400398440D9B5FFA88F8E3B93B4E0220FFF793FCA6F1400EBEE80F000FC6BEE80F000FC6BEE80F000FC69EE80F0086E80F0019 | ||||
| :40080000A6F130014022022000F01CFF703E40230C960D93B8F13F0FCAD962682B4B01321340002BBEBF03F1FF3363F03F030133636099E70AA8267A00F014FB0220FFF76B | ||||
| :4008400063FC0D9BF6B2402B07D0022040221E4900F0F8FE0220FFF757FC0D9B022033F040021DBFC3F1400292B21749114600F0E9FE0220FFF748FCFFF7ECFC36B11448FB | ||||
| :40088000FFF735FD0220FFF759FD06E0114B09A81B88ADF82430FFF73FFD627A4946237A0D48FFF724FD71E20C48FFF720FDE66E16F03F0616D0032066E200BF93640040CD | ||||
| :4008C000AC81FF1F3892FF1F7892FF1F3F000080F53A00005A3A00000F3B0000223B0000AB81FF1F012001F0F9FD95F86A0001F0EFFD02F001FCBA4BB94A1B78B94F43F089 | ||||
| :4009000004031370137843F001031370137803F0FE031370137803F0FE03137002F0F0FB686EFFF71BFD01214FF4804341F6FF72084601F0D9FD85F8A80001F067FFB855B5 | ||||
| :400940000136402EF9D1DFF8BC82002708F18D039EB207930137402F14BF3A46002218F8010F2244052392F82420402101F082FF314646F2475298F8000001F08DFF403623 | ||||
| :40098000402FB6B2E6D1DAF86C3000269B09182231464FF0FF3B0AA8CAF800600593CAF804B0B1468AF80860B04602F005FC0D973746012000F00CFF069601F0B9FFB8F170 | ||||
| :4009C000000F0AD14EB9012000F0E4FD012804D14022854900F0A8FE06462268834B01321340002BBCBF03F1FF3363F03F036168B8BF01338B4200F09180069B3BB1237A59 | ||||
| :400A0000002B40F09C806B7A002B40F098800B9BBBBBB8F1000F09D0754A7F2199540133402BFBD1724A0B930A922AE04EB3012000F0B0FD28BBDFF8B8E13F2E0EF1400CB9 | ||||
| :400A4000BCE80F00AEE80F00BCE80F00AEE80F00BCE80F00AEE80F009CE80F008EE80F00AEF130030A9307F101070B9607DD059BBB4204D0012000F0ABFE464601E04FF08B | ||||
| :400A800001080B9BDBB12368079A0AA802EB83120D9BC3F1400313440C9300F0F2F90D9B6BB92A68514B01321340002BBEBF03F1FF3363F03F030133236040230D936368C3 | ||||
| :400AC00001332BD12B683F2B28D14FF0000BC5F804B001F037FD85F808B06B6895F8A8002B4493F8241001F049FE95F8A80001F007FE012195F8A80001F0DAFD85F809B0CD | ||||
| :400B0000637A002BFCD04FF0000B01208AF809B001F024FD584601F0E1FC01E0069B2BB1237A63B96B7A53B90123069363685B453FF443AF09F10109D5F804B03DE76168F6 | ||||
| :400B40002C482268FFF7D3FB01F002FD012001F0C5FC002001F002FD042194F8A80001F019FE94F8A80001F025FE0028F9D19AF8A80001F0B3FD9AF809309AF80820029350 | ||||
| :400B8000012303920193CDF800804B463A4605991948FFF7ACFBB8F1000F16D1059BBB420AD0012000F0F6FC01280646F6D10E49FFF7F8FA3F2803DC012000F01DFE04E00C | ||||
| :400BC000304600F005FE0137E8E7FFF743FB0B48FFF78DFB237A0BB10220D5E0084B18E597650040AC81FF1F7892FF1F3F0000803892FF1F2C3B0000373B0000673B00002F | ||||
| :400C00005C3A0000AB81FF1F94F86A0001F060FC606EFFF7A3FB6148FFF769FB00236372637A002BFCD0012001F098FC00238AF80930637A002BFCD0002001F08FFC5848CC | ||||
| :400C4000FFF755FB574B09E000206077FFF786FB554B03E05548FFF783FA554B1B88ADF828300AA8FFF758FB90E0A37F3BB1002001F00AFC002002F09DF90023AB7702F0F3 | ||||
| :400C80001FF9002002F0C2F82A2601F0EDFF002001F090FF324600210AA802F08DFA17238DF828308DF8296001F042FE002001F0EBFB002002F07EF9C82001F0FBFD0DEB20 | ||||
| :400CC0000600FFF7DFFA0DF13E00FFF7FCFA01F02FFE012002F06EF9322001F0EBFD0DF12E00FFF7CFFA0DF14200FFF7ECFA012001F0CAFB4FF4967001F0DCFD01F018FE3C | ||||
| :400D00000DF13600FFF7BEFA0DF14A00FFF7DBFA002001F0B9FB4FF4967001F0CBFD01F007FE022002F046F9322001F0C3FD0DF13200FFF7A7FA0DF14600FFF7C4FA0120CB | ||||
| :400D400001F0A2FB4FF4967001F0B4FD01F0F0FD0DF13A00FFF796FA0DF14E00FFF7B3FA002001F091FB4FF4967001F0A3FD01F0DFFD002002F01EF90023637702F022F8F9 | ||||
| :400D800001F0F4FE6DE70120FFF7D8FA032000F01FFD0848FFF7ABFAFFF74BBB763B0000843B00005E3A0000603A0000F081FF1F623A0000913B000070B50024012542684B | ||||
| :400DC000002A4ED0C368002B4BD00368013A591C01601B784260802B01D145752FE013F0800F467D0269017D12D036B1D20042F004020331026101754475026903F001030A | ||||
| :400E0000D20042F004021A43037D0261033315E046B13F2B06D9D20042F004020331026101754475026943EA0223427D036112B143F0C0030361037D447508330375037DC4 | ||||
| :400E4000072BBCD90269083B22FA03F38268511C81601370C368013BC360037D083B0375ADE770BD07B5027D42B102AA002102F8011D026001224260FFF79EFF03B05DF8D5 | ||||
| :400E800004FBF0B5012100244368002B43D0C268002A40D0427D4AB183685A1C8260827D1A70C3684475013BC360EDE7027D072A0BD806680769751C05603578013B45EADF | ||||
| :400EC00007250832056143600275027D0369A2F10805EB40DBB203F0C006802E07D0C02E0ED103F03F0383754175802308E0C3F3401363F07F03033A03F08103027502E065 | ||||
| :400F00000575002BC0D08268551C85601370C368013BC360B8E7F0BD2DE9F04172B6884B61221A70A3F5F06301221A801924854A9C7092E803008033062283F8002283E874 | ||||
| :400F40000300522203F580731A707F4B7F4A1B787F4EDBB2137040F618027E4B00251A8041F2512223F8022C33784FF4F07003F0010343EA450502F0B7F8013C05F0030524 | ||||
| :400F80002ED0032DF0D1744B4FF480721A8007221A70724A002548211570917002221D705D7103F8032C0422DA716D4A6D4C13786D4E43F00103137012F8013C062743F000 | ||||
| :400FC000030302F8013C2378012243F0800323705B4B1A70654A137843F02003137000E0FEE707FB056300219A881868013502F0E3F8072DF5D15E485E4E002550F8041F99 | ||||
| :4010000005F1105303F1520221F0FF075333C9B20B4452005B0002329A4206D012F802EC12F801CC0EF807C0F5E7B0420D44E5D1514A002313609360136193614F4B504FDF | ||||
| :401040001A68504BDFF888811A604F4B1A684F4B1A604F4A137843F002031370137C43F0020313742378A2F5863243F040032370413A137843F010031370464A464B07CAE8 | ||||
| :4010800003C31A80454A2833106843F8250C127903F8212C424A07CA03C31A80414AE83B07CA03C31A80404A083307CA03C31A803E4A3F4BA2F5616203CBC2F8100EC2F8D1 | ||||
| :4010C000141E1378042043F008031370394B02F5AA521B783D78DBB298F80060EDB203F007010C321B091170F6B2537045F003033B7046F0030388F800302F4B48221A70EA | ||||
| :401100002E4A402313702E49937013729372082382F81F3220220A7048710A72294A0A20137001F0DDFB284B88F8006044223D70264D1A7094E80F0007C52B80BDE8F08102 | ||||
| :40114000004800404C0F00480F010049A146004025420040224200400440004006400040A2430040A0430040963B0000E8460040FCFFFF47A000004800760040540F00485E | ||||
| :40118000F846004020760040580F004828760040035001400C0F0048C0510040180F0048200F00482C0F0048380F004832510040440F0048CF0100491D510040015900404F | ||||
| :4011C000235B0040585B004076580040B0430040F946004008B501F0C3FF03680C2B00D1FEE7FEE7084908B50B68084A1844821A802A01DC086005E001F0B2FF0C230360FE | ||||
| :401200004FF0FF33184608BDCC80FF1FC893FF1F80B51148114B0025C0B1A3F1100192C922460439161BB74204D051F8046F42F8046BF7E7114653F8046C8C1AA64202D05F | ||||
| :4012400041F8045BF9E701381033E5E701F08EFFFFF7C8F8FEE700BF01000000683D0000124A134B10B51A60124A134C1368134843F4007313600023032B98BF54F8232052 | ||||
| :401280004FEA830188BF0E4A0133302B4250F3D10C4B1A780C4B1A700C4B084A1A60FFF73BFEBDE8104001F0EDB900BF0004FA050CED00E014ED00E0000000000080FF1F2B | ||||
| :4012C000D5110000BC760040C080FF1F08ED00E0F8B501F011FF4B4A01271378022643F001031370137C484C43F001031374474B02F5E3521F700B3203F8946C137805464F | ||||
| :4013000003F07F031370002001F0EAFA2378404A03F0F90323701378384603F0DF03137023783B43237001F0DBFA282001F0D8FA384B30461A7802F07F021A701A7802F02F | ||||
| :40134000BF021A7023783343237001F0C9FA2378314A43F0040323700023137053702F4AFF2199540133092BFBD1284601F0C8FE0721172001F0FCFA2949172001F0EAFADB | ||||
| :401380000721182001F0F4FA2649182001F0E2FA0721152001F0ECFA2349152001F0DAFA0721052001F0E4FA2049052001F0D2FA0721062001F0DCFA1D49062001F0CAFA23 | ||||
| :4013C0000721084601F0D4FA1A49072001F0C2FA0721082001F0CCFA1749082001F0BAFA0021162001F0C4FA1449162001F0B2FA07210C2001F0BCFABDE8F84010490C20BA | ||||
| :4014000001F0A8BAA5430040944300409D60004012600040F851004084600040ED92FF1F9F1C0000D91A00009D1C0000D11B0000FD1B00002D1C0000651C0000A51C0000EB | ||||
| :40144000191D0000214B224A10B5187000231370204A40201370204A0F2413701F4A13701F4A13701F4A13701F4A13701F4B4FF400021A604FF080721A604FF400121A60AB | ||||
| :4014800020221A601860802018604FF480701860174804704FF480001860164B1A70933B19B91A7802F0FE0202E01A7842F001021A70114B03221A70802203F8202C0120D0 | ||||
| :4014C00001F012FE0D4B04221A7010BD0893FF1F0E93FF1F0C93FF1F0D93FF1F0993FF1FF892FF1F0B93FF1F8093FF1F00E100E09E6000409C60004028600040126000401F | ||||
| :4015000070B5074C054623780E461BB9FFF7E0FE0123237031462846BDE87040FFF792BFB892FF1F0A4A002313700A4A13700A4A13700A4A13700A4A13700A4A13700A4A30 | ||||
| :4015400013700A4B03221A70802203F8202C70470E93FF1F0C93FF1F0D93FF1F0993FF1FF892FF1F0B93FF1F8093FF1F28600040014B1878704700BF0D93FF1F044B1A7802 | ||||
| :4015800002F0FF001AB118780022C0B21A7070470C93FF1F024A0C2303FB0020407870471493FF1F431E072B0CD8074A064B00010344805C5B7800F00F0043EA00200238EA | ||||
| :4015C00080B2704700207047FC5F00401A4A38B50C2303FB00231B79090C13F0800F00F1FF35044619BF8AB24FF480438BB24FF48042032D18D8DFE805F002070C110021C6 | ||||
| :40160000084601F01BF80DE00021084600F0FAFF08E00021084600F0D9FF03E00021084600F0B8FF054B1855EDB2072D03D801F0EDF8034B185538BD1493FF1FE492FF1FB1 | ||||
| :40164000ED92FF1F431E072B2DE9F0470446894615465CD82F4F0C2202FB0072D388DFF8B8A09BB2C3F500739D424FF00C0303FB007388BFD588DB7884BFC5F50075ADB2C2 | ||||
| :40168000254A43EA15230601B354B244EBB28AF80130224B1A5C9846FF2A01D1FFF796FF0C2303FB047200215170B9F1000F28D03DB31B4F385D01F011F811232946FE22D9 | ||||
| :4016C00018F8040001F0D6F806F5C04278321FFA89F118F8040001F0DFF8124D18F80410385D01F04BF80121385D00F0E1FF735D43F002037355735D03F0FD037355BDE82E | ||||
| :40170000F08703FB04746379DBB28AF80230BDE8F08700BF1493FF1FFC5F0040ED92FF1FE492FF1F706000402DE9F047044615468846002940D0431E072B3FD8FFF732FF59 | ||||
| :40174000A84203D22046FFF72DFF05461D4E335DFF2B03D141462046FFF738FFDFF868A027011AF8040000F0B9FF1223FE222946305D01F07FF807F5C0411FFA88F278310D | ||||
| :40178000305D01F089F8DFF84490315D1AF8040000F0F4FF01211AF8040000F089FF17F8093043F0020307F8093017F8093003F0FD0307F8093002E00D4600E00025284675 | ||||
| :4017C000BDE8F087ED92FF1FE492FF1F70600040431E072B0AD8064A0C2303FB002300225A705A79034BD2B200011A54704700BF1493FF1FFE5F0040431E072B9FBF024B61 | ||||
| :40180000000108221A547047FE5F004030B51A4A1A491B4D0878138803449BB21380194A00231488D8B2A4B27CB1082B0CD050680078C0B2E85450680133013050601088E4 | ||||
| :40184000013880B21080ECE718460B780E4C082B0E4A00D040B10E4D2B7883F080032B700F232370022301E0022323701370094B1870087030BD00BF8493FF1F8093FF1F18 | ||||
| :4018800000600040FC92FF1FF992FF1F0E93FF1F0A93FF1F8193FF1F074B02221A70074B80221A70064B0F221A70064A00231370054A0120137070470E93FF1F0A93FF1FE3 | ||||
| :4018C000F992FF1F8093FF1F8193FF1F30B5164B16491B780A8803F00F03023BDBB21A4492B20A80124C134A0020118889B279B173B15568215C013BC9B229705168DBB24A | ||||
| :401900000131516011880130013989B21180ECE7094A1370094A137883F080031370084B0B221A7030BD00BF296000408493FF1F00600040FC92FF1F8193FF1F0A93FF1F07 | ||||
| :40194000F992FF1F064A06231370064A01201370054B80221A70054B00221A70704700BF0E93FF1FF992FF1F0A93FF1F8193FF1F054B9A683AB19A68044910709A680988EC | ||||
| :40198000518000229A607047FC92FF1F8493FF1F08B5124B1A78D2B21A701B78DBB21A0602D50F4A137008BD0220FFF7E1FF0D4B1B7803F06003202B05D0402B06D043B99A | ||||
| :4019C00000F012FC04E001F09FFB01E000F046FD10B9034B03221A7008BD00BF28600040F992FF1F0060004008B5084A084B0120197813880B449BB21380064B00221A7030 | ||||
| :401A0000FFF7B6FF044B03221A7008BD8493FF1F8093FF1F0E93FF1FF992FF1F08B50C4B1B78DBB2042B07D0062B09D0022B0DD1BDE80840FFF7D8BFBDE80840FFF746BFB9 | ||||
| :401A40000320FFF795FF034B03221A7008BD00BF0E93FF1FF992FF1F08B5054B002201201A70FFF785FF034B03221A7008BD00BF0E93FF1FF992FF1F08B50A4B1A7832B10C | ||||
| :401A80001A78094942F080020A7000221A70074B002201201A70FFF76BFF054B03221A7008BD00BFF892FF1F086000400E93FF1FF992FF1F074B1B78DBB2042B05D0062B07 | ||||
| :401AC00005D0022B05D1FFF7A1BEFFF7C5BFFFF7D3BF70470E93FF1F38B51D4C2378DBB2DD0634D518060AD503F00F03012B2ED1FFF74EFF174B1B78190609D538BD5A0620 | ||||
| :401B000002D5FFF7D7FF03E09D0620D5FFF786FF23781B061BD4104B1A78104B1B7813430F4A13701278934211D10A4A0849154613782078DBB2000605D41378DBB20B70F1 | ||||
| :401B40000B7803F00F0328788342F1D138BD38BD28600040F992FF1F0A93FF1F8193FF1F29600040054A00231380054A916819B191680B7092685380704700BF8493FF1FA2 | ||||
| :401B8000FC92FF1F0E4808B503889BB213B9FFF783FE13E00B4B02221A700B4B00221A70FFF7E0FF094AD1799379028843EA012392B2934238BF0380FFF728FE012008BD64 | ||||
| :401BC000FC92FF1F0E93FF1F0A93FF1F00600040084B01221A700F3B9B7C074B1A7B02F00302012A1EBFDA7B82F08002DA7301225A7370470B6000401493FF1F094B0222B3 | ||||
| :401C00001A700F3B93F82230074B1A7E02F00302012A1EBFDA7E82F08002DA7601225A76704700BF0B6000401493FF1F0B4B04221A700F3B93F83230094B93F8242002F043 | ||||
| :401C40000302012A1EBF93F8272082F0800283F82720012283F82520704700BF0B6000401493FF1F0B4B08221A700F3B93F84230094B93F8302002F00302012A1EBF93F8FC | ||||
| :401C8000332082F0800283F83320012283F83120704700BF0B6000401493FF1F7047FFF741BC0000F0B5184B184E19780C27C9B201234FF0000C31B3CA0720D5144A4FEA33 | ||||
| :401CC000031E7244947850782040C5070DD507FB03652C79240608D5147804F0FE0414706D790C4CEDB204F80E50840706D507FB036425792D0658BF84F801C090700133B0 | ||||
| :401D0000DBB24908D7E7F0BD9F6000401493FF1F70600040FE5F004000F0ACBC70B50446184B88B003AA03F11006154618685968083303C5B3422A46F7D11B782B70FCB1E9 | ||||
| :401D40002223237001AD03232846637000F08AFE002220461146AB5C08AC04EB131414F8144C03F00F03847008AC234413F8143C0132082AC1700371417100F10400EAD107 | ||||
| :401D800008B070BDC03B00002DE9F0431C4D01222E460C201F274FF0800E4FF0080C194B00FB02581401234418705F70164998F805902144B9F1000F07D098F80440240665 | ||||
| :401DC0004CBF887081F802C001E081F802E000FB0261CC880132E4B29C71CC88092AC4F30724DC71CC88E4B21C71C988C1F307215971D4D1054BFF221A70BDE8F08300BF46 | ||||
| :401E00001493FF1F70600040FC5F00400A600040064B074A1B7802EBC30253681A7C824286BF03EBC0035869002070470893FF1F243C00002DE9F84F424B1A78002A7ED0F1 | ||||
| :401E40001878414D0138C0B2FFF7E2FFA8463F4AC3681478007ADFF800C1E4B203EBC0000C2600274FF0010E834268D01A78A24263D11CF80420597891425ED19A7893F848 | ||||
| :401E8000039002F07F0206FB02FA05EB0A01CF7093F802B009F0030981F804B093F803B005F80AB0B3F804A0A1F808A093F902A0BAF1000F0BDAB9F1010F0CBF4FF0070950 | ||||
| :401EC0004FF00D0981F8059081F801E009E0B9F1010F0CBF4FF005094FF0090981F805904F704FEA02191A4906FB0282494481F802E0B2F808A0CAF3072A81F800A0B2F825 | ||||
| :401F000008A05FFA8AFA81F801A0B2F806A011495FFA8AFA494481F806A0B2F80690C9F3072981F80790B2F806905FFA89F981F80490D288C2F307224A71083394E7BDE81D | ||||
| :401F4000F88F00BF0D93FF1F1493FF1F0993FF1FFC5F004070600040FA92FF1F08B5064B18780138C0B2FFF753FF20B143681B7900EBC300406908BD0D93FF1F00212DE9D7 | ||||
| :401F8000F84F0B464E4E0C2707FB01F401313219092933554FF000059370494CD3701381937253705371EFD118B1464B1D70464B1D70464B1A78002A7FD0187801250138FD | ||||
| :401FC000C0B2FFF725FFA8464368DFF8F8E0DB790C2713F0400F3E4B4FF0000C1A7814BF42F0010202F0FE021A70027AD20007FB0541C36803EB02094B4531D093F802A0D2 | ||||
| :402000000AF07F06AE4229D10E89B3F804B0B6B25E4538BFA1F808B01E7893F801B01EF80660B3451AD181F804A0DE780E7093F902A0DE78BAF1000F06F0030607DA012E7F | ||||
| :402040000CBF07260D264E7181F8018006E0012E0CBF052609264E7181F801C00833CBE70135092DC3D1C1680A328B1C0A440C200833934209D013F8081C13F80A5C01F05C | ||||
| :402080007F0100FB01418D72F2E7FFF767FF114B0121186000230C2000FB0142D3801289013113449BB203F00102134409299BB2F2D1BDE8F84FFFF767BEBDE8F88F00BF67 | ||||
| :4020C0001493FF1FFA92FF1F8293FF1F0D93FF1F0B93FF1F1093FF1F114B1B7903F07F035A1E072A19D80F490C2202FB031291781B0141F0010191700021D170517841F0B7 | ||||
| :4021000002015170127912F0800F074A1A4414BF8D2389239370FFF715BC0020704700BF006000401493FF1FFC5F004030B4194B1A7902F07F02531E072B27D8164B0C2400 | ||||
| :4021400004FB02339978154D01F0FE0199700021D97029461201505D114400F07F0050555A7802F0FD025A701A795B78120605D5012B01D18C7006E00D2303E0012B0CBFEE | ||||
| :40218000082309238B7030BCFFF7DCBB002030BC704700BF006000401493FF1FFC5F004010B50D4B0D4C21791878C9B20138C0B2FFF72EFE43681B798B4201D2012909D800 | ||||
| :4021C000074A0848535CDBB24354A3780120DBB2535410BD002010BD0D93FF1F00600040FA92FF1F8293FF1F38B58A4A8A4C13780021DBB221801806517840F18D800A293D | ||||
| :4022000000F20581DFE811F05D00030103010301030103010B0003017E0003018200D3787C49012B09D17D4B1A787D4B03EBC2035B685B686360122310E0CB78022B12D12E | ||||
| :402240008878FFF7E5FD002800F0E180436863606368DA7863689B7843EA02232380BDE83840FFF78FBCCB78032B26D16D4B00228878D5B2854209D3664A91786A4AEE2961 | ||||
| :4022800008BF1346634A917881B106E0187801320028F1D018780344EAE764499278097C914203D16248FFF739FD614B1A78002A00F0AD801A78228018E0BDE8384000F065 | ||||
| :4022C00023BF13F0030313D0022B40F0A0802380504B0C211B7903F07F02564B01FB02339A78554BD2B21A7000225A706360B6E702222280514A11784F4AC9B21170537000 | ||||
| :402300006260ACE7012323804D4BEFE70123238013794C4A1344E9E701390A2977D8DFE801F037764F76067676760A7620009378454ADBB25AE0937803F0FF0153B9404B1F | ||||
| :402340001A7891425FD01970404B01201870FFF715FE58E0481EC0B2FFF75AFD0028EED155E0FFF71DFF002851D02A4A384913791279DBB2D2B20A70364A3249D25CCB5C48 | ||||
| :402380009A4240D0314B01221A70FFF753FD3AE003F00303012B2BD009D3022B37D11D4B9B78002B33D1BDE83840FFF7BFBE194B9B78012B2BD1214A137803F0FD0315E0C0 | ||||
| :4023C00003F00303012B13D008D3022B1FD1114B9B78E3B9BDE83840FFF77EBE0D4B9B78012B14D1154A137843F0020313700AE0084B1A795AB998781B791749DBB2CA5CC8 | ||||
| :4024000022EA0002CA54BDE83840FFF79BBA002038BD00BF00600040FC92FF1F0893FF1F243C0000883C0000103C0000FB3C0000A093FF1F1493FF1FB992FF1F0B93FF1F4D | ||||
| :402440000D93FF1FFA92FF1FF892FF1F0C93FF1F0993FF1F8293FF1F0F93FF1F074B1A78120609D55B78012B06D1054B054A5A6012781A80FFF786BB002070470060004007 | ||||
| :40248000FC92FF1FE83B0000014B1870704700BF7F640040014B1878704700BF69640040014B1870704700BF78650040064A0123136002F688321268E0211064034A1170C4 | ||||
| :4024C000A2F540721360704780E100E000E400E0014B1870704700BF72640040014B1870704700BF7665004073B515461E460B4C05230022019200920A460146184623706A | ||||
| :4025000000F064F932462946207800F01FF90221207800F009F9207802B070BDD080FF1F064A0423136002F688321268E0219064034A1170A2F202321360704780E100E029 | ||||
| :4025400002E400E0014B04221A60704700E100E0014B04221A60704780E100E0014B1870704700BF78640040704738B505460078012428B100F060FD285D0134E4B2F8E706 | ||||
| :4025800038BD08B50D2000F057FDBDE808400A2000F052BDF7B516461F460B4C00230325019300930A4601462846257000F00EF93A463146207800F0C9F80221207800F030 | ||||
| :4025C000B3F8207803B0F0BDE080FF1FF7B516461F460B4C00230225019300930A4601462846257000F0F2F83A463146207800F0ADF82946207800F097F8207803B0F0BD6F | ||||
| :40260000E180FF1FF7B516461F460B4C00230125019300930A4601462846257000F0D6F83A463146207800F091F80221207800F07BF8207803B0F0BDE280FF1F73B515466E | ||||
| :402640001E460B4C0023019300930A4601461846237000F0BBF832462946207800F076F80221207800F060F8207802B070BD00BFE380FF1F024B1878C0F38010704700BFFD | ||||
| :402680008F450040074A7F23802113705170064A013BDBB202F80839002BF9D1034A1370704700BFE480FF1FF87B00400078004017280FD8084B0001C25C11B142F0200204 | ||||
| :4026C00001E002F0DF02C254C25C42F00102C25400207047012070471070004017280BD8064B0001C25C02F0FE02C254C25C02F0DF02C25400207047012070471070004028 | ||||
| :4027000017280DD8074900010B4603441A7942F004021A71435C43F00103435400207047012070471070004017280BD8064A0001835C490003F0F10301F00E0119438154A7 | ||||
| :4027400000207047012070471070004041F6FF73994208BF4FF400519A4208BF4FF4005217289FBFC00000F1804000F5EC4081809ABFC280002001207047000017289FBF73 | ||||
| :40278000034B00011954002088BF0120704700BF1970004017289FBF054B00011A5C01F007019DBF1143195400200120704700BF1470004017289FBF034B0001185C00F051 | ||||
| :4027C000070088BFFF20704714700040172810B51AD8C00001F07F0100F1804441EAC21204F5EC44D2B222709DF8082003F00F0343EA0213DBB263709DF80C30002003F08F | ||||
| :402800000F03A370E07010BD012010BD10B500F073FC0A4A5378182B0AD91478013B5370E30003F1804303F5F0431B78137000E0FF2400F065FC204610BD00BFE480FF1FD1 | ||||
| :40284000030610B5044611D400F056FC084AE300117803F1804303F5F04319705378147001335370BDE8104000F04ABC10BD00BFE480FF1F30B504060CD411F4704509D14E | ||||
| :40288000C40004F1804404F5F0442180A270E370284630BD012030BD03065FBFC00000F1804000F5F04081805ABFC280002001207047000038B50446084DB4F5004F05D98C | ||||
| :4028C000286800F011FCA4F50044F6E7034B58686043BDE8384000F007BC00BFEC80FF1F024B1B7A584300F0FFBB00BFEC80FF1F0E4B00F003001A78490102F0FC021043EC | ||||
| :4029000018701A7801F0600142F080021A701A7802F07F021A701A7802F09F020A431A701A7842F010021A70704700BF83430040014B01221A70704784430040044B00F090 | ||||
| :402940000F021B6853F8220043F82210704700BF08ED00E0054A00F01F00126800F1100352F8230042F82310704700BF08ED00E000F01F0000F16040490100F56440C9B29F | ||||
| :40298000017070470F4B10B50F4900240F205C609C60DC601C615C61FFF7D0FF0B4A136843F0040313600A4B4FF47A72DB68B3FBF2F3084A1360084B4FF400421C60C3F887 | ||||
| :4029C000E82010BDBC92FF1F312A000010E000E0EC80FF1F14E000E018E000E0024A136843F002031360704710E000E008B5FFF7F5FF034A136843F00103136008BD00BF9F | ||||
| :402A000010E000E010B5054CA3691BB9FFF7BAFF0123A361BDE81040FFF7E8BFBC92FF1F024B1868C0F30040704700BF10E000E038B5FFF7F5FF012808D1054D002455F859 | ||||
| :402A4000243003B198470134052CF8D138BD00BFC092FF1F024B03EB8003586859607047BC92FF1F134B144A1B78DBB20360127843EA0223114A0360127843EA0243104A93 | ||||
| :402A80000360127843EA026303600E4B0E4A1B78DBB24360127843EA02230C4A4360127843EA02430A4A4360127843EA02634360704700BF0301004904010049EC460040B6 | ||||
| :402AC000020100490101004900010049050100490601004910B500F00FFB204A044613780A2043F002031370137C43F00203137412F80A3C43F0010302F80A3C937943F01F | ||||
| :402B00000103937102F5AB52137843F003031370134B18221A7013F8012C42F0400203F8012C13F8012C02F0FC0203F8012CCE2203F8062CA3F597530222183B1A70094A19 | ||||
| :402B4000137843F008031370FFF7CAFE064B10222046BDE810401A6000F0D2BAAB4300400E5900402F5B004080E200E008B500F0C3FA0F4A137803F0FE031370A2F5AA523E | ||||
| :402B80001D3A137803F0FD031370137C03F0FD03137412F80A3C03F0FE0302F80A3C937903F0FE039371BDE8084000F0A9BA00BF08590040044A137803F03F0343EA8010C1 | ||||
| :402BC000C0B21070704700BF08590040082804D00A280CBF8223C22300E0422308380E4AC0B20428137098BF0C4B4FF0000298BF33F910100A4B88BF11461A8042F210736D | ||||
| :402C00004B4341F2883103F6C41393FBF1F305490B60054B1A8070470A590040D23B00008A93FF1F8C93FF1F9093FF1F08B5102000F0A6F907210420FFF79AFE074904204B | ||||
| :402C4000FFF788FE064A0C20137843F006031370FFF7BCFF034B00221A8008BD252D0000095900408893FF1F10B5054C23781BB9FFF7DCFF01232370BDE81040FFF72ABF84 | ||||
| :402C8000D892FF1F044B1A7802F0FB021A701A7842F001021A7070470859004010B5084B1C7814F0010403D10028F9D0002404E02046FFF715FE024B1B78204610BD00BFC6 | ||||
| :402CC00009590040034A044B1B881088181A00B2704700BF9093FF1FA25B00400E4A13881BB223B111880A2309B2594301E00B4B19680B4B1B88C01A42F2107300B203FBE0 | ||||
| :402D000000F2022391FBF3F30028D8BF5B42134493FBF1F000B270478A93FF1F8C93FF1F8893FF1F7047000010B500F0E5F9214A044613780A2043F001031370137C43F09E | ||||
| :402D40000103137412F80A3C43F0020302F80A3C937943F00203937102F5AA521832137843F003031370144B18221A7013F8012C42F0400203F8012C13F8012C02F0FC0215 | ||||
| :402D800003F8012CCE2203F8062CA3F597530222123B1A70094A137843F008031370FFF79FFD074B08222046BDE810401A6000F0A7B900BFAB43004006590040275B004031 | ||||
| :402DC00080E200E008B500F097F90F4A137803F0FE031370A2F5AA52153A137803F0FE031370137C03F0FE03137412F80A3C03F0FD0302F80A3C937903F0FD039371BDE8E0 | ||||
| :402E0000084000F07DB900BF00590040044A137803F03F0343EA8010C0B21070704700BF00590040082804D00A280CBF8223C22300E0422308380E4AC0B20428137098BF20 | ||||
| :402E40000C4B4FF0000298BF33F910100A4B88BF11461A8042F210734B4341F2883103F6C41393FBF1F305490B60054B1A80704702590040DC3B00009693FF1F9C93FF1F77 | ||||
| :402E80009493FF1F08B5102000F084F807210320FFF76EFD07490320FFF75CFD064A0C20137843F006031370FFF7BCFF034B00221A8008BD7D2F0000015900409893FF1F31 | ||||
| :402EC00010B5054C23781BB9FFF7DCFF01232370BDE81040FFF728BFD992FF1F044B1A7802F0FB021A701A7842F001021A7070470059004010B5084B1C7814F0010403D1E6 | ||||
| :402F00000028F9D0002404E02046FFF7E9FC024B1B78204610BD00BF01590040034A044B1B881088181A00B2704700BF9493FF1FA05B00400E4A13881BB223B111880A23E0 | ||||
| :402F400009B2594301E00B4B19680B4B1B88C01A42F2107300B203FB00F2022391FBF3F30028D8BF5B42134493FBF1F000B270479693FF1F9C93FF1F9893FF1F7047000060 | ||||
| :402F8000034A00F0F800137803431370704700BF02410040034A00F0F800137803431370704700BF06410040014B1870704700BF76640040014B1870704700BF7C6400403B | ||||
| :402FC00073B515461E460B4C04230022019200920A46014618462370FFF7F8FB324629462078FFF7B3FB02212078FFF79DFB207802B070BDFC80FF1F074A0223136002F656 | ||||
| :4030000088321268E0215064044A11706FF440710A441360704700BF80E100E001E400E0014B1870704700BF74650040014B1870704700BF77640040FEB5494652465B4644 | ||||
| :403040000EB40746244909688A46244A12682448022100F071F8030020480068C018204900F06AF8143883460121C9430C460125002600F041F8814651460B7823400B7094 | ||||
| :403080005846013000F030F83800F04028400B78234003430B70584600F026F80136072EF2D9002001300138013001200B78234003430B705846043000F016F8484600F0FE | ||||
| :4030C0001FF800BF00BF00BF0EBC894692469B46FEBD00BFAFF30080D480FF1FF880FF1F00C20100000000000230800803D000BF01380046FCD17047EFF3108072B6704723 | ||||
| :4031000080F31088704700BF094A137803F00303012B0AD0022B09D113790C2103F07F02044B01FB02339B7A00E0137900207047006000401493FF1F002902D0B0FBF1F039 | ||||
| :40314000704708B14FF0FF3000F008B80029F8D00246B0FBF1F000FB11217047704700BF014B1868704700BF6081FF1F0E4B70B51E460E4C0025E41AA410A54204D056F845 | ||||
| :40318000253098470135F8E700F0D4FD084B094C1E46E41AA4100025A54204D056F8253098470135F8E770BD403D0000403D0000403D0000483D000003460244934202D071 | ||||
| :4031C00003F8011BFAE7704730B5141E05469BB0184604DA8B232B604FF0FF301DE04FF40273ADF80C300CBF234604F1FF33029305934FF6FF7300910491ADF80E3002466A | ||||
| :403200001E9B6946284600F073F8431CBCBF8B232B6014B1009B00221A701BB030BD000007B5009313460A46014603480068FFF7CBFF03B05DF804FB6081FF1F2DE9F04781 | ||||
| :403240008E6882469E420C46914698463ED88A8912F4906F3AD02568096902236F1A656905EB450595FBF3F57B1C43449D4238BF1D4653050FD5294600F04AFB064698B178 | ||||
| :403280003A46216900F0D2FAA38923F4906343F08003A38113E02A4600F098FB064670B92169504600F0E8FA0C23CAF80030A3894FF0FF3043F04003A381BDE8F0872661F3 | ||||
| :4032C0003E44266046466561ED1BA560464528BF464649463246206800F0B3FAA36800209B1BA36023681E442660BDE8F08700002DE9F04F9DB003938B8980461C060D4643 | ||||
| :4033000016460DD50B695BB9402100F001FB2860286118B90C23C8F80030CDE040236B610023099320238DF82930DFF89CB130238DF82A3037463C4614F8013B1BB9B7EBAA | ||||
| :40334000060910D003E0252BF9D02746F3E74B46324629464046FFF771FF013000F0A780099B4B4409933B78002B00F0A08000234FF0FF3204930793059206938DF85330B6 | ||||
| :403380001A930126052221784E4800F041FA671C049B38B14B4A3C46801A06FA00F018430490EFE7D90644BF20228DF853201A0744BF2B228DF8532022782A2A03D0079A60 | ||||
| :4033C00000210A200BE0039A111D12680391002A10DA524243F00200079204900BE027463B780134303B092B03D800FB02320121F5E701B107923B782E2B1ED17B782A2B3F | ||||
| :403400000AD1039B02371A1D1B680392002BB8BF4FF0FF33059310E0002319460593781C0A2407463A780130303A092A03D804FB01210123F5E703B10591032239782248C1 | ||||
| :4034400000F0E6F940B14023CBEB000003FA00F0049B013718430490397806221B487E1C8DF8281000F0D4F988B1194B33B9039B073323F007030833039314E003AB0093EC | ||||
| :403480002A46144B04A94046AFF3008007E003AB00932A460F4B04A9404600F093F8B0F1FF3F824603D0099B5344099342E7AB895B0601D4099801E04FF0FF301DB0BDE802 | ||||
| :4034C000F08F00BF0F3D0000153D0000193D0000000000003D3200002DE9F04791461F460A698B6806469342B8BF1346C9F8003091F843200C46DDF8208012B10133C9F8EF | ||||
| :4035000000302368990642BFD9F800300233C9F80030256815F0060510D104F1190A07E00123524639463046C04701301AD00135E368D9F800209B1A9D42F1DB94F84330E8 | ||||
| :403540002268003318BF012392060FD5E118302081F843005A1C94F845102244023382F8431003E04FF0FF30BDE8F08704F1430239463046C0470130F4D02268D9F8005010 | ||||
| :40358000E36802F00602042A08BF5D1B2269A3680CBF25EAE57500259342C4BF9B1AED184FF000091A344D4509D00123224639463046C0470130D5D009F10109F3E70020FB | ||||
| :4035C000BDE8F0872DE9F04317460A7E85B06E2A984606460C460C9B01F1430E00F0AE8011D8632A22D009D8002A00F0BB80582A40F0CA8081F84520834955E0642A1ED03B | ||||
| :40360000692A1CD0C0E0732A00F0B08009D86F2A2ED0702A40F0B8800A6842F020020A603EE0752A24D0782A3AD0ADE01A6801F14205111D1960136884F84230A8E021683E | ||||
| :403640001A6811F0800F02D0111D196008E011F0400F02F10401196002D0B2F9003000E01368002B3CDA2D225B4284F8432037E021681A6811F0800F02D0111D196007E0F0 | ||||
| :4036800011F0400F02F10401196001D0138800E01368227E5C496F2A14BF0A2208221BE078225A4984F845202268186812F0800F00F104051D6003D1550601D5038800E0E0 | ||||
| :4036C0000368D00744BF42F0200222601BB9226822F0200222601022002084F8430001E049490A226568002DA56008DB206820F0040020602BB9002D7DD175460CE0002BBC | ||||
| :4037000079D07546B3FBF2F002FB1033CB5C05F8013D03460028F5D1082A0BD12368DA0708D5236962689A42DEBF302305F8013C05F1FF35C5EB0E0323612EE008681A68FA | ||||
| :4037400010F0800F496903D0101D1860136808E010F0400F02F104001860136801D0198000E0196000232361754616E01A68111D1960156800216268284600F049F808B1F0 | ||||
| :40378000401B6060636804E004F1420584F8422001232361002384F84330CDF800803B4603AA21463046FFF797FE013002D14FF0FF3026E023692A4639463046C0470130EF | ||||
| :4037C000F5D023689B0710D5002504F1190907E001234A4639463046C0470130E7D00135E368039A9B1A9D42F2DBE068039B9842B8BF184605E00B7804F1420584F8423091 | ||||
| :403800008AE705B0BDE8F083C03B0000203D000010B5C9B202449042034605D01C7801308C42F8D1184610BD002010BD10B5431E0A44914204D011F8014B03F8014FF8E76E | ||||
| :4038400010BD884210B501EB020301D8421E0BE09842FBD28118D21AD34204D013F8014D01F8014DF8E710BD994204D011F8014B02F8014FF8E710BD38B50546002944D007 | ||||
| :4038800051F8043C0C1F002BB8BFE41800F0D4F81E4A1368114613B96360146030E0A3420DD92268A018834201BF18685B681218226063600C6023E0A24203D813465A6820 | ||||
| :4038C000002AF9D118681918A1420BD12168014458188242196013D110685268014419605A600DE002D90C232B6009E021686018824201BF106852680918216062605C6019 | ||||
| :403900002846BDE8384000F098B838BDE092FF1F70B5CD1C25F0030508350C2D38BF0C25002D064601DBA94202D90C23336046E000F082F8234B1C681A462146A1B10B6883 | ||||
| :403940005B1B0ED40B2B03D90B60CC18CD501EE08C420BBF63684B681360636018BF0C4615E00C464968E9E7174C23681BB9304600F052F820602946304600F04DF8431CCB | ||||
| :4039800018D0C41C24F00304A0420DD12560304600F053F804F10B00231D20F00700C31A0ED05A42E25070BD211A304600F034F80130EBD10C233360304600F03EF80020E9 | ||||
| :4039C00070BD00BFE092FF1FDC92FF1FF8B5074615460E4621B91146BDE8F840FFF798BF1AB9FFF749FF2846F8BD00F027F885420ED929463846FFF78BFF044650B131469B | ||||
| :403A00002A46FFF713FF31463846FFF735FF01E03046F8BD2046F8BD38B5064C0023054608462360FDF7DEFB431C02D1236803B12B6038BDC493FF1F7047704751F8040C50 | ||||
| :403A40000028BEBF091851F8043CC0180438704700000000050209020B020D020F021102130215027265706C792030782530327800686F6D696E6700626567696E6E696EEF | ||||
| :403A800067207365656B2066726F6D20256420746F2025640066696E6973686564207365656B0057616974696E6720666F72205553422E2E2E0055534220726561647900AF | ||||
| :403AC000636F6D6D616E6420307825303278006661696C2025642B25642B2564203D3D2025642C206E6F74202564007061737365643D256400756E64657272756E2061664A | ||||
| :403B0000746572202564207061636B65747300636F756E743D256420693D256420643D256400636D645F777269746500646F6E6520256420256400703D25642063723D25BB | ||||
| :403B4000642063773D256420663D256420773D256420696E6465783D256420756E64657272756E3D25640077726974652066696E6973686564007374617274206572617393 | ||||
| :403B8000696E670073746F702065726173696E670069646C650000510040100040510040300000000140001000140140000800400140000A004C014000020050014020003F | ||||
| :403BC0003031323334353637383941424344454600000001000000040000001000010000000400000010000028000000000104000100000000000000000157494E555342F2 | ||||
| :403C00000000303030303100000000000000000012034D0053004600540031003000300001000000010000002C3C000001000000FB3C000000000000000000000100000010 | ||||
| :403C4000443C000001000000CD3C000004000000663C0000000000000000000000000000643C0000FF00000001024000FF00000082024000FF00000003034000FF0000002B | ||||
| :403C800084034000FF00020304030904160346006C007500780045006E00670069006E0065002A0343006F0077006C00610072006B00200054006500630068006E006F0096 | ||||
| :403CC0006C006F0067006900650073000009022E0001010080320904000004FF00000107050102400000070582024000000705030340000A0705840340000A12010002FFD7 | ||||
| :403D00000001080912006E0100020180014300232D302B2000686C4C00656667454647003031323334353637383961626364656600000000F8B500BFF8BC08BC9E46704759 | ||||
| :403D40005900000061120000F8B500BFF8BC08BC9E46704735000000683D0000C880FF1FA00000006012000000000000C893FF1FFF000000675000400C0000000700000024 | ||||
| :403D8000FFFFFFFF7F8000003F0000000000007D00FA0000400000000090D003FF0000000000000000000000000000000000000000000000000000000000000000000000B0 | ||||
| :403DC0000D3D000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000079 | ||||
| :403E00000081FF1F000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000E3 | ||||
| :4001000002F012B98881FF1F10B5C4B2204601F027F90128FAD110BD08B572B60F4B0F49DA680132DA601A690132C82A08BF00221A615A6918690132A72A08BF00224A613A | ||||
| :400140005B69002B0CBF02230023002814BF184643F0010002F050FE62B608BD8881FF1F38B50446C5B2284602F080F8062002F09DFA44F00200C0B202F078F8062002F055 | ||||
| :4001800095FA284602F072F8BDE83840062002F077BA10B5642402F063F830B90120FFF7DFFF013CF7D1204610BD012010BD70B5C4B2054620460E4601F0D2F8012805D089 | ||||
| :4001C000204601F0EBF92846FFF79EFF204601F0CFF8314605460246204601F08BF9204601F0BEF80028FAD1284670BD38B5044D0024285D013402F009FA402CF9D138BDE9 | ||||
| :40020000A081FF1F08B502F023FC002002F02CFC02F03EFC02F048FC80B208BD10B50446012002F03BF8642002F02AFAFFF7EAFF2080002002F032F8642002F021FAFFF7ED | ||||
| :40024000E1FF608010BD08B502F02EFD002002F037FD02F049FD02F053FD80B208BD10B50446FFF796FF322002F00AFAFFF7EBFF20800020FFF774FF322002F001FAFFF740 | ||||
| :40028000E2FF608010BD0FB400B593B014AB53F8042B402102A8019302F0AAFE02A802F04AF802F054F813B05DF804EB04B0704710B5044601780648FFF7E5FF0420FFF72B | ||||
| :4002C00023FF62782146BDE81040042001F0A0B83438000007B50023ADF804308DF80600032301A88DF80530FFF7E2FF03B05DF804FB000010B5074C94F8583043B10020E3 | ||||
| :4003000001F0A8FF002002F03BFD002384F8583010BD00BF8881FF1F38B5104D837895F85B2004469A4204D0FFF7E4FF002385F85E302368C5F859302279094B1A71A3784D | ||||
| :40034000002B14BF0220012002F01AFDE07802F011FD2079BDE8384002F048BD8881FF1FE181FF1F38B50D4C94F8585065B904F15900FFF7D1FF012001F06CFF4FF47A7031 | ||||
| :4003800002F07EF984F85E50E3682366012384F85830BDE8384002F0B1B900BF8881FF1FF8B51E4C0646FFF7DDFF94F85E3003B15EB91B48FFF767FFFFF7EBFE0120002353 | ||||
| :4003C00084F85E00636602F071F93246616E1548FFF759FF114D0027636E9E4216D001F03FFF00B16F66636E9E4205DD0020FFF7B7FE6B6E013305E005DA0120FFF7B0FE47 | ||||
| :400400006B6E013B6B6602F079F9E5E7322002F037F9BDE8F8400448FFF735BF8881FF1F4138000048380000653800002DE9F04F99B062B602F0CCF99949042002F0F0F914 | ||||
| :40044000984801F019FF984802F0BCFC974801F04DFF02F09DFB02F06FFA002002F090FC01F068FF0221002000F030FF904C012001F0A8F8002384F85B30FFF773FFFFF79A | ||||
| :4004800088FE84F86800FFF735FF012384F85B30FFF768FFFFF77DFE84F86900FFF72AFF844B94F86800844994F869202546002A14BF0A461A46002808BF19467F48FFF7E3 | ||||
| :4004C000E2FE0321084602F0F9F8264602F016F994F8583043B12A6EEB689B1A41F28832934201D9FFF706FF00F028FF18B97448FFF7C9FE04E000F027FF0028F7D10BE0E5 | ||||
| :4005000000F01CFF10B902F0F9F8F9E76D48FFF7BAFE032001F042F8032000F021FF0128D4D16948FFF7F8FE68490320FFF73FFE94F86A106648FFF7A6FE94F86A30023B1D | ||||
| :40054000142B00F2AB83DFE813F01500A9031E00A9032400A9034600A9036C00A903CF00A903AA01A903E202A9030103A9030803A903220303238DF820308DF821300E23FD | ||||
| :400580008DF82230FFE294F86C00FFF709FF514BF6E2FFF7E7FE00236372E068627A02F0FF0132B9EB681B1AB3F57A7FF6DD0B4608E03BB100227272F168627A12B9EB68CB | ||||
| :4005C0005B1AFAE707228DF8202004228DF82120ADF82230D7E20220FFF796FD4FF000080DF1200A02F08AF84FF480790027C9EB0803DA1907F80A200137402FF9D10220BC | ||||
| :40060000FFF782FD3A465146022000F001FFB9F10109EBD108F10108B8F1400FE2D12E4B38E04FF0010A4FF000080DF1200B02F065F84FF0000959460120FFF7B8FD08EBBF | ||||
| :40064000090300270493049B1BF807203B44DBB2934209D08DE80C0041463B464A461F48FFF711FE4FF0000A0137402FEBD109F10109B9F5807FDED108F10108B8F1400F92 | ||||
| :40068000D5D151461648FFF7FEFDBAF1000F00F00E81144B1B8807A8ADF81C3074E200BF19010000F900000091000000C50000008881FF1F77380000733800007A38000022 | ||||
| :4006C00092380000A5380000E181FF1FF281FF1FAF3800002438000026380000BE380000DA3800002838000094F86C0001F0D6FD606EFFF755FE02F0E7FBB24BDFF8E0825C | ||||
| :400700001A78002702F0FB021A701A7842F001021A701A7802F0FE021A701A7802F0FE021A7002F0D5FB0220FFF7EEFC012141F6FF734FF48042084602F028FB84F8AA00FD | ||||
| :4007400001F04AFF08F807000137402FF8D1DFF894A200270AF199091FFA89F80137402F14BF3A4600221AF8010F22440623127E402101F065FF424646F24A519AF800005D | ||||
| :4007800001F070FF08F14008402F1FFA88F8E5D196F86D3033B100237372637A002BFCD00023737200234FF0FF32236062602372236894F8AA002344197E01F0C5FE94F87B | ||||
| :4007C000AA0001F083FE012194F8AA0001F056FE2368002BFCD0002398467360D6F80CA0012701F08BFFE368B4F86E20CAEB030393420DD367B1042195F8AA0001F0B0FEC5 | ||||
| :4008000094F8AA0001F0BCFE0028F9D107463072237AFBB96A682B689A4202D1002FE0D118E00220FFF770FC6968402209EB8111022000F0EDFD6A68634B01321340002B4F | ||||
| :40084000BEBF03F1FF3363F03F03013308F101086360C6E70220277AFFF756FC00221146022000F0D5FDFFB20220FFF74DFCFFF7BDFC37B15548FFF706FD0220FFF72AFDB4 | ||||
| :4008800006E0534B08A81B88ADF82030FFF710FD627A4146237A4F48FFF7F5FC01E24E48FFF7F1FCD4F86E7017F03F0701D00320F5E1012001F0F8FC95F86C0001F0EEFCF4 | ||||
| :4008C00002F002FB454BDFF818811A7842F004021A701A7842F001021A701A7802F0FE021A701A7802F0FE021A7002F0F1FA686EFFF756FD01214FF4804341F6FF7208462E | ||||
| :4009000001F0D8FC85F8AA0001F066FE08F807000137402FF8D1DFF8CC90002709F199031FFA83F804930137402F14BF3A46002219F8010F22440523127E402101F080FEB9 | ||||
| :40094000414646F24C4299F8000001F08BFE08F14008402F1FFA88F8E5D100274FF0FF33376098467360BB463B46D6F86E9037725FEA99190CBF4FF0010A4FF0000A216867 | ||||
| :40098000114A01310A40002ABCBF02F1FF3262F03F026068B8BF013282426BD02BB1227A002A76D16A7A002A73D12068049A059302EB8010BAF1000F16D040223F2102F0C9 | ||||
| :4009C000E3FA1CE09A6500403F000080E43800002A380000FE380000113900009C640040A081FF1F9F81FF1F014601370120FFF7DEFBC7EB0903D3F1000A4AEB030A21689F | ||||
| :400A0000AB4A01310A40002ABEBF02F1FF3262F03F02013222606268059B01322AD12A683F2A27D14FF00008C5F8048001F070FC85F808806B6895F8AA002B44197E01F0BC | ||||
| :400A400083FD95F8AA0001F041FD012195F8AA0001F014FD85F80980637A002BFCD04FF00008012086F8098001F05EFC404601F01BFC00E023B1237A5BB96B7A4BB90123A1 | ||||
| :400A8000626842453FF47BAF0BF1010BD5F8048075E701F043FC012001F006FC002001F043FC042194F8AA0001F05AFD94F8AA0001F066FD0028F9D196F8AA0001F0F4FC07 | ||||
| :400AC000737A327A0293012303920193CDF800A05B463A4649467748FFF7D5FBBAF1000F08D0FFF783FB237A63B17348FFF7CBFB0220D4E0B945F4D070490120FFF757FBF9 | ||||
| :400B00000137F7E76E48FFF7BEFB6E4B38E094F86C0001F0C3FB606EFFF742FC6A48FFF7B2FB00236372637A002BFCD0012001F0FBFB00237372637A002BFCD0002001F0AA | ||||
| :400B4000F3FB6248FFF79FFB614B19E0002084F85E00FFF725FC5F4B12E094F8683023B195F869200AB985F86C2094F869201AB113B9012385F86C305748FFF7CDFB574B39 | ||||
| :400B80001B88ADF8203008A8FFF792FB89E0FFF7B1FB02F07BF8002002F01EF82A2701F049FF002001F0ECFE3A46002108A802F0EBF917238DF820308DF8217001F09EFD75 | ||||
| :400BC000002001F047FB002002F0DAF8C82001F057FD0DF12200FFF721FB0DF13600FFF73EFB01F08BFD012002F0CAF8322001F047FD0DF12600FFF711FB0DF13A00FFF7D3 | ||||
| :400C00002EFB012001F026FB4FF4967001F038FD01F074FD0DF12E00FFF700FB0DF14200FFF71DFB002001F015FB4FF4967001F027FD01F063FD022002F0A2F8322001F05B | ||||
| :400C40001FFD0DEB0700FFF7E9FA0DF13E00FFF706FB012001F0FEFA4FF4967001F010FD01F04CFD0DF13200FFF7D8FA0DF14600FFF7F5FA002001F0EDFA4FF4967001F06F | ||||
| :400C8000FFFC01F03BFD002002F07AF8002384F85E3001F07DFF01F04FFE74E70120FFF719FB032000F07AFC0D48FFF7ECFA0DE43F0000801B3900004B3900003892FF1F04 | ||||
| :400CC000553900002C3800005D3900006B3900002E38000030380000F281FF1F32380000783900002DE9F04172B6884B61221A70A3F5F06301221A801924854A9C7092E8C5 | ||||
| :400D000003008033062283F8002283E80300522203F580731A707F4B7F4A1B787F4EDBB2137040F618027E4B00251A8041F2512223F8022C33784FF4F07003F0010343EAA5 | ||||
| :400D4000450502F0B9F8013C05F003052ED0032DF0D1744B4FF480721A8007221A70724A002548211570917002221D705D7103F8032C0422DA716D4A6D4C13786D4E43F049 | ||||
| :400D80000103137012F8013C062743F0030302F8013C2378012243F0800323705B4B1A70654A137843F02003137000E0FEE707FB056300219A881868013502F0E5F8072D53 | ||||
| :400DC000F5D15E485E4E002550F8041F05F1105303F1440221F0FF074533C9B20B4452005B0002329A4206D012F802EC12F801CC0EF807C0F5E7B0420D44E5D1514A00239D | ||||
| :400E000013609360136193614F4B504F1A68504BDFF888811A604F4B1A684F4B1A604F4A137843F002031370137C43F0020313742378A2F5863243F040032370413A1378DE | ||||
| :400E400043F010031370464A464B07CA03C31A80454A2833106843F8250C127903F8212C424A07CA03C31A80414AE83B07CA03C31A80404A083307CA03C31A803E4A3F4B12 | ||||
| :400E8000A2F5616203CBC2F8100EC2F8141E1378042043F008031370394B02F5AA521B783D78DBB298F80060EDB203F007010C321B091170F6B2537045F003033B7046F096 | ||||
| :400EC000030388F800302F4B48221A702E4A402313702E49937013729372082382F81F3220220A7048710A72294A0A20137001F0DDFB284B88F8006044223D70264D1A7039 | ||||
| :400F000094E80F0007C52B80BDE8F08100480040B00900480F010049A146004025420040224200400440004006400040A2430040A04300407D390000E8460040FCFFFF478E | ||||
| :400F40008400004800760040B8090048F846004020760040BC090048287600400350014070090048C05100407C09004884090048900900489C09004832510040A8090048D5 | ||||
| :400F8000CF0100491D51004001590040235B0040585B004076580040B0430040F946004008B501F0C5FF03680C2B00D1FEE7FEE7084908B50B68084A1844821A802A01DC5E | ||||
| :400FC000086005E001F0B4FF0C2303604FF0FF33184608BDCC80FF1F8893FF1F80B51148114B0025C0B1A3F1100192C922460439161BB74204D051F8046F42F8046BF7E7D1 | ||||
| :40100000114653F8046C8C1AA64202D041F8045BF9E701381033E5E701F090FFFFF706FAFEE700BF010000004C3B0000124A134B10B51A60124A134C1368134843F40073A8 | ||||
| :4010400013600023032B98BF54F823204FEA830188BF0E4A0133302B4250F3D10C4B1A780C4B1A700C4B084A1A60FFF73BFEBDE8104001F0EDB900BF0004FA050CED00E042 | ||||
| :4010800014ED00E0000000000080FF1FA10F0000BC760040C080FF1F08ED00E0F8B501F013FF4B4A01271378022643F001031370137C484C43F001031374474B02F5E352E3 | ||||
| :4010C0001F700B3203F8946C1378054603F07F031370002001F0EAFA2378404A03F0F90323701378384603F0DF03137023783B43237001F0DBFA282001F0D8FA384B3046E8 | ||||
| :401100001A7802F07F021A701A7802F0BF021A7023783343237001F0C9FA2378314A43F0040323700023137053702F4AFF2199540133092BFBD1284601F0CAFE072117206D | ||||
| :4011400001F0FCFA2949172001F0EAFA0721182001F0F4FA2649182001F0E2FA0721152001F0ECFA2349152001F0DAFA0721052001F0E4FA2049052001F0D2FA0721062008 | ||||
| :4011800001F0DCFA1D49062001F0CAFA0721084601F0D4FA1A49072001F0C2FA0721082001F0CCFA1749082001F0BAFA0021162001F0C4FA1449162001F0B2FA07210C20FD | ||||
| :4011C00001F0BCFABDE8F84010490C2001F0A8BAA5430040944300409D60004012600040F851004084600040AD92FF1F6B1A0000A5180000691A00009D190000C9190000FE | ||||
| :40120000F9190000311A0000711A0000E51A0000214B224A10B5187000231370204A40201370204A0F2413701F4A13701F4A13701F4A13701F4A13701F4B4FF400021A60B6 | ||||
| :401240004FF080721A604FF400121A6020221A601860802018604FF480701860174804704FF480001860164B1A70933B19B91A7802F0FE0202E01A7842F001021A70114B51 | ||||
| :4012800003221A70802203F8202C012001F014FE0D4B04221A7010BDC892FF1FCE92FF1FCC92FF1FCD92FF1FC992FF1FB892FF1FCB92FF1F4093FF1F00E100E09E60004062 | ||||
| :4012C0009C600040286000401260004070B5074C054623780E461BB9FFF7E0FE0123237031462846BDE87040FFF792BF7892FF1F0A4A002313700A4A13700A4A13700A4A82 | ||||
| :4013000013700A4A13700A4A13700A4A13700A4B03221A70802203F8202C7047CE92FF1FCC92FF1FCD92FF1FC992FF1FB892FF1FCB92FF1F4093FF1F28600040014B187899 | ||||
| :40134000704700BFCD92FF1F044B1A7802F0FF001AB118780022C0B21A707047CC92FF1F024A0C2303FB002040787047D492FF1F431E072B0CD8074A064B00010344805C33 | ||||
| :401380005B7800F00F0043EA0020023880B2704700207047FC5F00401A4A38B50C2303FB00231B79090C13F0800F00F1FF35044619BF8AB24FF480438BB24FF48042032DA2 | ||||
| :4013C00018D8DFE805F002070C110021084601F01BF80DE00021084600F0FAFF08E00021084600F0D9FF03E00021084600F0B8FF054B1855EDB2072D03D801F0EDF8034BBC | ||||
| :40140000185538BDD492FF1FA492FF1FAD92FF1F431E072B2DE9F0470446894615465CD82F4F0C2202FB0072D388DFF8B8A09BB2C3F500739D424FF00C0303FB007388BF8B | ||||
| :40144000D588DB7884BFC5F50075ADB2254A43EA15230601B354B244EBB28AF80130224B1A5C9846FF2A01D1FFF796FF0C2303FB047200215170B9F1000F28D03DB31B4FEC | ||||
| :40148000385D01F011F811232946FE2218F8040001F0D6F806F5C04278321FFA89F118F8040001F0DFF8124D18F80410385D01F04BF80121385D00F0E1FF735D43F0020316 | ||||
| :4014C0007355735D03F0FD037355BDE8F08703FB04746379DBB28AF80230BDE8F08700BFD492FF1FFC5F0040AD92FF1FA492FF1F706000402DE9F047044615468846002946 | ||||
| :4015000040D0431E072B3FD8FFF732FFA84203D22046FFF72DFF05461D4E335DFF2B03D141462046FFF738FFDFF868A027011AF8040000F0B9FF1223FE222946305D01F01E | ||||
| :401540007FF807F5C0411FFA88F27831305D01F089F8DFF84490315D1AF8040000F0F4FF01211AF8040000F089FF17F8093043F0020307F8093017F8093003F0FD0307F8E8 | ||||
| :40158000093002E00D4600E000252846BDE8F087AD92FF1FA492FF1F70600040431E072B0AD8064A0C2303FB002300225A705A79034BD2B200011A54704700BFD492FF1F5E | ||||
| :4015C000FE5F0040431E072B9FBF024B000108221A547047FE5F004030B51A4A1A491B4D0878138803449BB21380194A00231488D8B2A4B27CB1082B0CD050680078C0B2ED | ||||
| :40160000E85450680133013050601088013880B21080ECE718460B780E4C082B0E4A00D040B10E4D2B7883F080032B700F232370022301E0022323701370094B18700870CB | ||||
| :4016400030BD00BF4493FF1F4093FF1F00600040BC92FF1FB992FF1FCE92FF1FCA92FF1F4193FF1F074B02221A70074B80221A70064B0F221A70064A00231370054A012089 | ||||
| :4016800013707047CE92FF1FCA92FF1FB992FF1F4093FF1F4193FF1F30B5164B16491B780A8803F00F03023BDBB21A4492B20A80124C134A0020118889B279B173B155682D | ||||
| :4016C000215C013BC9B229705168DBB20131516011880130013989B21180ECE7094A1370094A137883F080031370084B0B221A7030BD00BF296000404493FF1F0060004010 | ||||
| :40170000BC92FF1F4193FF1FCA92FF1FB992FF1F064A06231370064A01201370054B80221A70054B00221A70704700BFCE92FF1FB992FF1FCA92FF1F4193FF1F054B9A68E5 | ||||
| :401740003AB19A68044910709A680988518000229A607047BC92FF1F4493FF1F08B5124B1A78D2B21A701B78DBB21A0602D50F4A137008BD0220FFF7E1FF0D4B1B7803F0CF | ||||
| :401780006003202B05D0402B06D043B900F012FC04E001F0A1FB01E000F046FD10B9034B03221A7008BD00BF28600040B992FF1F0060004008B5084A084B0120197813881C | ||||
| :4017C0000B449BB21380064B00221A70FFF7B6FF044B03221A7008BD4493FF1F4093FF1FCE92FF1FB992FF1F08B50C4B1B78DBB2042B07D0062B09D0022B0DD1BDE8084046 | ||||
| :40180000FFF7D8BFBDE80840FFF746BF0320FFF795FF034B03221A7008BD00BFCE92FF1FB992FF1F08B5054B002201201A70FFF785FF034B03221A7008BD00BFCE92FF1FCB | ||||
| :40184000B992FF1F08B50A4B1A7832B11A78094942F080020A7000221A70074B002201201A70FFF76BFF054B03221A7008BD00BFB892FF1F08600040CE92FF1FB992FF1FC1 | ||||
| :40188000074B1B78DBB2042B05D0062B05D0022B05D1FFF7A1BEFFF7C5BFFFF7D3BF7047CE92FF1F38B51D4C2378DBB2DD0634D518060AD503F00F03012B2ED1FFF74EFF43 | ||||
| :4018C000174B1B78190609D538BD5A0602D5FFF7D7FF03E09D0620D5FFF786FF23781B061BD4104B1A78104B1B7813430F4A13701278934211D10A4A0849154613782078EC | ||||
| :40190000DBB2000605D41378DBB20B700B7803F00F0328788342F1D138BD38BD28600040B992FF1FCA92FF1F4193FF1F29600040054A00231380054A916819B191680B701E | ||||
| :4019400092685380704700BF4493FF1FBC92FF1F0E4808B503889BB213B9FFF783FE13E00B4B02221A700B4B00221A70FFF7E0FF094AD1799379028843EA012392B293422A | ||||
| :4019800038BF0380FFF728FE012008BDBC92FF1FCE92FF1FCA92FF1F00600040084B01221A700F3B9B7C074B1A7B02F00302012A1EBFDA7B82F08002DA7301225A73704723 | ||||
| :4019C0000B600040D492FF1F094B02221A700F3B93F82230074B1A7E02F00302012A1EBFDA7E82F08002DA7601225A76704700BF0B600040D492FF1F0B4B04221A700F3B22 | ||||
| :401A000093F83230094B93F8242002F00302012A1EBF93F8272082F0800283F82720012283F82520704700BF0B600040D492FF1F0B4B08221A700F3B93F84230094B93F857 | ||||
| :401A4000302002F00302012A1EBF93F8332082F0800283F83320012283F83120704700BF0B600040D492FF1F7047FFF741BC0000F0B5184B184E19780C27C9B201234FF029 | ||||
| :401A8000000C31B3CA0720D5144A4FEA031E7244947850782040C5070DD507FB03652C79240608D5147804F0FE0414706D790C4CEDB204F80E50840706D507FB0364257960 | ||||
| :401AC0002D0658BF84F801C090700133DBB24908D7E7F0BD9F600040D492FF1F70600040FE5F004000F0ACBC70B50446184B88B003AA03F11006154618685968083303C5BA | ||||
| :401B0000B3422A46F7D11B782B70FCB12223237001AD03232846637000F08AFE002220461146AB5C08AC04EB131414F8144C03F00F03847008AC234413F8143C0132082A48 | ||||
| :401B4000C1700371417100F10400EAD108B070BDA73900002DE9F0431C4D01222E460C201F274FF0800E4FF0080C194B00FB02581401234418705F70164998F80590214449 | ||||
| :401B8000B9F1000F07D098F8044024064CBF887081F802C001E081F802E000FB0261CC880132E4B29C71CC88092AC4F30724DC71CC88E4B21C71C988C1F307215971D4D1CC | ||||
| :401BC000054BFF221A70BDE8F08300BFD492FF1F70600040FC5F00400A600040064B074A1B7802EBC30253681A7C824286BF03EBC003586900207047C892FF1F083A0000F6 | ||||
| :401C00002DE9F84F424B1A78002A7ED01878414D0138C0B2FFF7E2FFA8463F4AC3681478007ADFF800C1E4B203EBC0000C2600274FF0010E834268D01A78A24263D11CF82A | ||||
| :401C40000420597891425ED19A7893F8039002F07F0206FB02FA05EB0A01CF7093F802B009F0030981F804B093F803B005F80AB0B3F804A0A1F808A093F902A0BAF1000FB7 | ||||
| :401C80000BDAB9F1010F0CBF4FF007094FF00D0981F8059081F801E009E0B9F1010F0CBF4FF005094FF0090981F805904F704FEA02191A4906FB0282494481F802E0B2F807 | ||||
| :401CC00008A0CAF3072A81F800A0B2F808A05FFA8AFA81F801A0B2F806A011495FFA8AFA494481F806A0B2F80690C9F3072981F80790B2F806905FFA89F981F80490D288FB | ||||
| :401D0000C2F307224A71083394E7BDE8F88F00BFCD92FF1FD492FF1FC992FF1FFC5F004070600040BA92FF1F08B5064B18780138C0B2FFF753FF20B143681B7900EBC3008B | ||||
| :401D4000406908BDCD92FF1F00212DE9F84F0B464E4E0C2707FB01F401313219092933554FF000059370494CD3701381937253705371EFD118B1464B1D70464B1D70464B17 | ||||
| :401D80001A78002A7FD0187801250138C0B2FFF725FFA8464368DFF8F8E0DB790C2713F0400F3E4B4FF0000C1A7814BF42F0010202F0FE021A70027AD20007FB0541C368D1 | ||||
| :401DC00003EB02094B4531D093F802A00AF07F06AE4229D10E89B3F804B0B6B25E4538BFA1F808B01E7893F801B01EF80660B3451AD181F804A0DE780E7093F902A0DE78D4 | ||||
| :401E0000BAF1000F06F0030607DA012E0CBF07260D264E7181F8018006E0012E0CBF052609264E7181F801C00833CBE70135092DC3D1C1680A328B1C0A440C20083393423F | ||||
| :401E400009D013F8081C13F80A5C01F07F0100FB01418D72F2E7FFF767FF114B0121186000230C2000FB0142D3801289013113449BB203F00102134409299BB2F2D1BDE88C | ||||
| :401E8000F84FFFF767BEBDE8F88F00BFD492FF1FBA92FF1F4293FF1FCD92FF1FCB92FF1FD092FF1F114B1B7903F07F035A1E072A19D80F490C2202FB031291781B0141F08F | ||||
| :401EC000010191700021D170517841F002015170127912F0800F074A1A4414BF8D2389239370FFF715BC0020704700BF00600040D492FF1FFC5F004030B4194B1A7902F0D9 | ||||
| :401F00007F02531E072B27D8164B0C2404FB02339978154D01F0FE0199700021D97029461201505D114400F07F0050555A7802F0FD025A701A795B78120605D5012B01D168 | ||||
| :401F40008C7006E00D2303E0012B0CBF082309238B7030BCFFF7DCBB002030BC704700BF00600040D492FF1FFC5F004010B50D4B0D4C21791878C9B20138C0B2FFF72EFE81 | ||||
| :401F800043681B798B4201D2012909D8074A0848535CDBB24354A3780120DBB2535410BD002010BDCD92FF1F00600040BA92FF1F4293FF1F38B58A4A8A4C13780021DBB24F | ||||
| :401FC00021801806517840F18D800A2900F20581DFE811F05D00030103010301030103010B0003017E0003018200D3787C49012B09D17D4B1A787D4B03EBC2035B685B68B3 | ||||
| :402000006360122310E0CB78022B12D18878FFF7E5FD002800F0E180436863606368DA7863689B7843EA02232380BDE83840FFF78FBCCB78032B26D16D4B00228878D5B28F | ||||
| :40204000854209D3664A91786A4AEE2908BF1346634A917881B106E0187801320028F1D018780344EAE764499278097C914203D16248FFF739FD614B1A78002A00F0AD80B9 | ||||
| :402080001A78228018E0BDE8384000F025BF13F0030313D0022B40F0A0802380504B0C211B7903F07F02564B01FB02339A78554BD2B21A7000225A706360B6E70222228083 | ||||
| :4020C000514A11784F4AC9B2117053706260ACE7012323804D4BEFE70123238013794C4A1344E9E701390A2977D8DFE801F037764F76067676760A7620009378454ADBB2B5 | ||||
| :402100005AE0937803F0FF0153B9404B1A7891425FD01970404B01201870FFF715FE58E0481EC0B2FFF75AFD0028EED155E0FFF71DFF002851D02A4A384913791279DBB209 | ||||
| :40214000D2B20A70364A3249D25CCB5C9A4240D0314B01221A70FFF753FD3AE003F00303012B2BD009D3022B37D11D4B9B78002B33D1BDE83840FFF7BFBE194B9B78012B8E | ||||
| :402180002BD1214A137803F0FD0315E003F00303012B13D008D3022B1FD1114B9B78E3B9BDE83840FFF77EBE0D4B9B78012B14D1154A137843F0020313700AE0084B1A79FA | ||||
| :4021C0005AB998781B791749DBB2CA5C22EA0002CA54BDE83840FFF79BBA002038BD00BF00600040BC92FF1FC892FF1F083A00006C3A0000F4390000DF3A00006093FF1FEA | ||||
| :40220000D492FF1F7992FF1FCB92FF1FCD92FF1FBA92FF1FB892FF1FCC92FF1FC992FF1F4293FF1FCF92FF1F074B1A78120609D55B78012B06D1054B054A5A6012781A8093 | ||||
| :40224000FFF786BB0020704700600040BC92FF1FCC390000014B1870704700BF78640040014B1878704700BF6B650040014B1870704700BF79640040064A0123136002F631 | ||||
| :4022800088321268E0211064034A1170A2F540721360704780E100E000E400E0014B1870704700BF79650040014B1870704700BF7D64004073B515461E460B4C05230022D4 | ||||
| :4022C000019200920A4601461846237000F064F932462946207800F01FF90221207800F009F9207802B070BDD080FF1F064A0423136002F688321268E0219064034A1170F2 | ||||
| :40230000A2F202321360704780E100E002E400E0014B04221A60704700E100E0014B04221A60704780E100E0014B1870704700BF7B650040704738B505460078012428B18D | ||||
| :4023400000F062FD285D0134E4B2F8E738BD08B50D2000F059FDBDE808400A2000F054BDF7B516461F460B4C00230325019300930A4601462846257000F00EF93A463146E4 | ||||
| :40238000207800F0C9F80221207800F0B3F8207803B0F0BDE080FF1FF7B516461F460B4C00230225019300930A4601462846257000F0F2F83A463146207800F0ADF82946CC | ||||
| :4023C000207800F097F8207803B0F0BDE180FF1FF7B516461F460B4C00230125019300930A4601462846257000F0D6F83A463146207800F091F80221207800F07BF8207805 | ||||
| :4024000003B0F0BDE280FF1F73B515461E460B4C0023019300930A4601461846237000F0BBF832462946207800F076F80221207800F060F8207802B070BD00BFE380FF1F72 | ||||
| :40244000024B1878C0F38010704700BF8F450040074A7F23802113705170064A013BDBB202F80839002BF9D1034A1370704700BFE480FF1FF87B00400078004017280FD838 | ||||
| :40248000084B0001C25C11B142F0200201E002F0DF02C254C25C42F00102C25400207047012070471070004017280BD8064B0001C25C02F0FE02C254C25C02F0DF02C25451 | ||||
| :4024C00000207047012070471070004017280DD8074900010B4603441A7942F004021A71435C43F00103435400207047012070471070004017280BD8064A0001835C490093 | ||||
| :4025000003F0F10301F00E011943815400207047012070471070004041F6FF73994208BF4FF400519A4208BF4FF4005217289FBFC00000F1804000F5EC4081809ABFC28032 | ||||
| :40254000002001207047000017289FBF034B00011954002088BF0120704700BF1970004017289FBF054B00011A5C01F007019DBF1143195400200120704700BF147000404E | ||||
| :4025800017289FBF034B0001185C00F0070088BFFF20704714700040172810B51AD8C00001F07F0100F1804441EAC21204F5EC44D2B222709DF8082003F00F0343EA0213C5 | ||||
| :4025C000DBB263709DF80C30002003F00F03A370E07010BD012010BD10B500F075FC0A4A5378182B0AD91478013B5370E30003F1804303F5F0431B78137000E0FF2400F0A3 | ||||
| :4026000067FC204610BD00BFE480FF1F030610B5044611D400F058FC084AE300117803F1804303F5F04319705378147001335370BDE8104000F04CBC10BD00BFE480FF1F18 | ||||
| :4026400030B504060CD411F4704509D1C40004F1804404F5F0442180A270E370284630BD012030BD03065FBFC00000F1804000F5F04081805ABFC2800020012070470000CD | ||||
| :4026800038B50446084DB4F5004F05D9286800F013FCA4F50044F6E7034B58686043BDE8384000F009BC00BFEC80FF1F024B1B7A584300F001BC00BFEC80FF1F0E4B00F0E7 | ||||
| :4026C00003001A78490102F0FC02104318701A7801F0600142F080021A701A7802F07F021A701A7802F09F020A431A701A7842F010021A70704700BF83430040014B012238 | ||||
| :402700001A70704784430040044B00F00F021B6853F8220043F82210704700BF08ED00E0054A00F01F00126800F1100352F8230042F82310704700BF08ED00E000F01F0049 | ||||
| :4027400000F16040490100F56440C9B2017070470F4B10B50F4900240F205C609C60DC601C615C61FFF7D0FF0B4A136843F0040313600A4B4FF47A72DB68B3FBF2F3084A5C | ||||
| :402780001360084B4FF400421C60C3F8E82010BD7C92FF1FFD27000010E000E0EC80FF1F14E000E018E000E0024A136843F002031360704710E000E008B5FFF7F5FF034A7F | ||||
| :4027C000136843F00103136008BD00BF10E000E010B5054CA3691BB9FFF7BAFF0123A361BDE81040FFF7E8BF7C92FF1F024B1868C0F30040704700BF10E000E038B5FFF7EC | ||||
| :40280000F5FF012808D1054D002455F8243003B198470134052CF8D138BD00BF8092FF1F024B03EB80035868596070477C92FF1F134B144A1B78DBB20360127843EA0223B0 | ||||
| :40284000114A0360127843EA0243104A0360127843EA026303600E4B0E4A1B78DBB24360127843EA02230C4A4360127843EA02430A4A4360127843EA02634360704700BFF1 | ||||
| :402880000301004904010049EC460040020100490101004900010049050100490601004910B500F011FB204A044613780A2043F002031370137C43F00203137412F80A3C08 | ||||
| :4028C00043F0010302F80A3C937943F00103937102F5AB52137843F003031370134B18221A7013F8012C42F0400203F8012C13F8012C02F0FC0203F8012CCE2203F8062C7C | ||||
| :40290000A3F597530222183B1A70094A137843F008031370FFF7CAFE064B10222046BDE810401A6000F0D4BAAB4300400E5900402F5B004080E200E008B500F0C5FA0F4A3B | ||||
| :40294000137803F0FE031370A2F5AA521D3A137803F0FD031370137C03F0FD03137412F80A3C03F0FE0302F80A3C937903F0FE039371BDE8084000F0ABBA00BF0859004037 | ||||
| :40298000044A137803F03F0343EA8010C0B21070704700BF08590040082804D00A280CBF8223C22300E0422308380E4AC0B20428137098BF0C4B4FF0000298BF33F9101028 | ||||
| :4029C0000A4B88BF11461A8042F210734B4341F2883103F6C41393FBF1F305490B60054B1A8070470A590040B83900004A93FF1F4C93FF1F5093FF1F08B5102000F0A6F974 | ||||
| :402A000007210420FFF79AFE07490420FFF788FE064A0C20137843F006031370FFF7BCFF034B00221A8008BDF12A0000095900404893FF1F10B5054C23781BB9FFF7DCFF7A | ||||
| :402A400001232370BDE81040FFF72ABF9892FF1F044B1A7802F0FB021A701A7842F001021A7070470859004010B5084B1C7814F0010403D10028F9D0002404E02046FFF7A2 | ||||
| :402A800015FE024B1B78204610BD00BF09590040034A044B1B881088181A00B2704700BF5093FF1FA25B00400E4A13881BB223B111880A2309B2594301E00B4B19680B4B61 | ||||
| :402AC0001B88C01A42F2107300B203FB00F2022391FBF3F30028D8BF5B42134493FBF1F000B270474A93FF1F4C93FF1F4893FF1F7047000010B500F0E7F9214A0446137861 | ||||
| :402B00000A2043F001031370137C43F00103137412F80A3C43F0020302F80A3C937943F00203937102F5AA521832137843F003031370144B18221A7013F8012C42F0400201 | ||||
| :402B400003F8012C13F8012C02F0FC0203F8012CCE2203F8062CA3F597530222123B1A70094A137843F008031370FFF79FFD074B08222046BDE810401A6000F0A9B900BFB0 | ||||
| :402B8000AB43004006590040275B004080E200E008B500F099F90F4A137803F0FE031370A2F5AA52153A137803F0FE031370137C03F0FE03137412F80A3C03F0FD0302F87F | ||||
| :402BC0000A3C937903F0FD039371BDE8084000F07FB900BF00590040044A137803F03F0343EA8010C0B21070704700BF00590040082804D00A280CBF8223C22300E0422383 | ||||
| :402C000008380E4AC0B20428137098BF0C4B4FF0000298BF33F910100A4B88BF11461A8042F210734B4341F2883103F6C41393FBF1F305490B60054B1A8070470259004054 | ||||
| :402C4000C23900005693FF1F5C93FF1F5493FF1F08B5102000F084F807210320FFF76EFD07490320FFF75CFD064A0C20137843F006031370FFF7BCFF034B00221A8008BD33 | ||||
| :402C8000492D0000015900405893FF1F10B5054C23781BB9FFF7DCFF01232370BDE81040FFF728BF9992FF1F044B1A7802F0FB021A701A7842F001021A70704700590040D8 | ||||
| :402CC00010B5084B1C7814F0010403D10028F9D0002404E02046FFF7E9FC024B1B78204610BD00BF01590040034A044B1B881088181A00B2704700BF5493FF1FA05B004034 | ||||
| :402D00000E4A13881BB223B111880A2309B2594301E00B4B19680B4B1B88C01A42F2107300B203FB00F2022391FBF3F30028D8BF5B42134493FBF1F000B270475693FF1FD5 | ||||
| :402D40005C93FF1F5893FF1F70470000034A00F0F800137803431370704700BF02410040034A00F0F800137803431370704700BF06410040014B1870704700BF7A65004015 | ||||
| :402D8000014B1870704700BF7E64004073B515461E460B4C04230022019200920A46014618462370FFF7F8FB324629462078FFF7B3FB02212078FFF79DFB207802B070BDA7 | ||||
| :402DC000FC80FF1F074A0223136002F688321268E0215064044A11706FF440710A441360704700BF80E100E001E400E0014B1870704700BF7A640040014B1870704700BF9D | ||||
| :402E00007B64004000000000FEB5494652465B460EB40746244909688A46244A12682448022100F071F8030020480068C018204900F06AF8143883460121C9430C4601254A | ||||
| :402E4000002600F041F8814651460B7823400B705846013000F030F83800F04028400B78234003430B70584600F026F80136072EF2D9002001300138013001200B78234041 | ||||
| :402E800003430B705846043000F016F8484600F01FF800BF00BF00BF0EBC894692469B46FEBD00BFAFF30080D480FF1FF880FF1F00C20100000000000230800803D000BFAA | ||||
| :402EC00001380046FCD17047EFF3108072B6704780F31088704700BF094A137803F00303012B0AD0022B09D113790C2103F07F02044B01FB02339B7A00E013790020704714 | ||||
| :402F000000600040D492FF1F002902D0B0FBF1F0704708B14FF0FF3000F008B80029F8D00246B0FBF1F000FB11217047704700BF014B1868704700BF6081FF1F0E4B70B57A | ||||
| :402F40001E460E4C0025E41AA410A54204D056F8253098470135F8E700F0DEFD084B094C1E46E41AA4100025A54204D056F8253098470135F8E770BD243B0000243B00007F | ||||
| :402F8000243B00002C3B000003460244934202D003F8011BFAE7704730B5141E05469BB0184604DA8B232B604FF0FF301DE04FF40273ADF80C300CBF234604F1FF33029350 | ||||
| :402FC00005934FF6FF7300910491ADF80E3002461E9B6946284600F073F8431CBCBF8B232B6014B1009B00221A701BB030BD000007B5009313460A46014603480068FFF741 | ||||
| :40300000CBFF03B05DF804FB6081FF1F2DE9F0478E6882469E420C46914698463ED88A8912F4906F3AD02568096902236F1A656905EB450595FBF3F57B1C43449D4238BF75 | ||||
| :403040001D4653050FD5294600F04AFB064698B13A46216900F0D2FAA38923F4906343F08003A38113E02A4600F098FB064670B92169504600F0E8FA0C23CAF80030A38908 | ||||
| :403080004FF0FF3043F04003A381BDE8F08726613E44266046466561ED1BA560464528BF464649463246206800F0B3FAA36800209B1BA36023681E442660BDE8F087000061 | ||||
| :4030C0002DE9F04F9DB003938B8980461C060D4616460DD50B695BB9402100F001FB2860286118B90C23C8F80030CDE040236B610023099320238DF82930DFF89CB1302302 | ||||
| :403100008DF82A3037463C4614F8013B1BB9B7EB060910D003E0252BF9D02746F3E74B46324629464046FFF771FF013000F0A780099B4B4409933B78002B00F0A080002335 | ||||
| :403140004FF0FF3204930793059206938DF853301A930126052221784E4800F041FA671C049B38B14B4A3C46801A06FA00F018430490EFE7D90644BF20228DF853201A0773 | ||||
| :4031800044BF2B228DF8532022782A2A03D0079A00210A200BE0039A111D12680391002A10DA524243F00200079204900BE027463B780134303B092B03D800FB0232012141 | ||||
| :4031C000F5E701B107923B782E2B1ED17B782A2B0AD1039B02371A1D1B680392002BB8BF4FF0FF33059310E0002319460593781C0A2407463A780130303A092A03D804FB46 | ||||
| :4032000001210123F5E703B1059103223978224800F0E6F940B14023CBEB000003FA00F0049B013718430490397806221B487E1C8DF8281000F0D4F988B1194B33B9039BDF | ||||
| :40324000073323F007030833039314E003AB00932A46144B04A94046AFF3008007E003AB00932A460F4B04A9404600F093F8B0F1FF3F824603D0099B5344099342E7AB897F | ||||
| :403280005B0601D4099801E04FF0FF301DB0BDE8F08F00BFF33A0000F93A0000FD3A0000000000000D3000002DE9F04791461F460A698B6806469342B8BF1346C9F8003093 | ||||
| :4032C00091F843200C46DDF8208012B10133C9F800302368990642BFD9F800300233C9F80030256815F0060510D104F1190A07E00123524639463046C04701301AD001355B | ||||
| :40330000E368D9F800209B1A9D42F1DB94F843302268003318BF012392060FD5E118302081F843005A1C94F845102244023382F8431003E04FF0FF30BDE8F08704F1430253 | ||||
| :4033400039463046C0470130F4D02268D9F80050E36802F00602042A08BF5D1B2269A3680CBF25EAE57500259342C4BF9B1AED184FF000091A344D4509D0012322463946F2 | ||||
| :403380003046C0470130D5D009F10109F3E70020BDE8F0872DE9F04317460A7E85B06E2A984606460C460C9B01F1430E00F0AE8011D8632A22D009D8002A00F0BB80582A01 | ||||
| :4033C00040F0CA8081F84520834955E0642A1ED0692A1CD0C0E0732A00F0B08009D86F2A2ED0702A40F0B8800A6842F020020A603EE0752A24D0782A3AD0ADE01A6801F114 | ||||
| :403400004205111D1960136884F84230A8E021681A6811F0800F02D0111D196008E011F0400F02F10401196002D0B2F9003000E01368002B3CDA2D225B4284F8432037E0C5 | ||||
| :4034400021681A6811F0800F02D0111D196007E011F0400F02F10401196001D0138800E01368227E5C496F2A14BF0A2208221BE078225A4984F845202268186812F0800F0E | ||||
| :4034800000F104051D6003D1550601D5038800E00368D00744BF42F0200222601BB9226822F0200222601022002084F8430001E049490A226568002DA56008DB206820F0CC | ||||
| :4034C000040020602BB9002D7DD175460CE0002B79D07546B3FBF2F002FB1033CB5C05F8013D03460028F5D1082A0BD12368DA0708D5236962689A42DEBF302305F8013CF7 | ||||
| :4035000005F1FF35C5EB0E0323612EE008681A6810F0800F496903D0101D1860136808E010F0400F02F104001860136801D0198000E0196000232361754616E01A68111DFC | ||||
| :403540001960156800216268284600F049F808B1401B6060636804E004F1420584F8422001232361002384F84330CDF800803B4603AA21463046FFF797FE013002D14FF056 | ||||
| :40358000FF3026E023692A4639463046C0470130F5D023689B0710D5002504F1190907E001234A4639463046C0470130E7D00135E368039A9B1A9D42F2DBE068039B9842DC | ||||
| :4035C000B8BF184605E00B7804F1420584F842308AE705B0BDE8F083A7390000043B000010B5C9B202449042034605D01C7801308C42F8D1184610BD002010BD10B5431EF7 | ||||
| :403600000A44914204D011F8014B03F8014FF8E710BD884210B501EB020301D8421E0BE09842FBD28118D21AD34204D013F8014D01F8014DF8E710BD994204D011F8014B40 | ||||
| :4036400002F8014FF8E710BD38B50546002944D051F8043C0C1F002BB8BFE41800F0D4F81E4A1368114613B96360146030E0A3420DD92268A018834201BF18685B68121885 | ||||
| :40368000226063600C6023E0A24203D813465A68002AF9D118681918A1420BD12168014458188242196013D110685268014419605A600DE002D90C232B6009E021686018A3 | ||||
| :4036C000824201BF106852680918216062605C602846BDE8384000F098B838BDA092FF1F70B5CD1C25F0030508350C2D38BF0C25002D064601DBA94202D90C23336046E018 | ||||
| :4037000000F082F8234B1C681A462146A1B10B685B1B0ED40B2B03D90B60CC18CD501EE08C420BBF63684B681360636018BF0C4615E00C464968E9E7174C23681BB9304658 | ||||
| :4037400000F052F820602946304600F04DF8431C18D0C41C24F00304A0420DD12560304600F053F804F10B00231D20F00700C31A0ED05A42E25070BD211A304600F034F863 | ||||
| :403780000130EBD10C233360304600F03EF8002070BD00BFA092FF1F9C92FF1FF8B5074615460E4621B91146BDE8F840FFF798BF1AB9FFF749FF2846F8BD00F027F8854208 | ||||
| :4037C0000ED929463846FFF78BFF044650B131462A46FFF713FF31463846FFF735FF01E03046F8BD2046F8BD38B5064C0023054608462360FDF7DCFB431C02D1236803B13B | ||||
| :403800002B6038BD8493FF1F7047704751F8040C0028BEBF091851F8043CC0180438704700000000050209020B020D020F021102130215027265706C792030782530327881 | ||||
| :4038400000686F6D696E6700626567696E6E696E67207365656B2066726F6D20256420746F2025640066696E6973686564207365656B00796573006E6F00647269766520AA | ||||
| :40388000303A20257320647269766520313A2025730057616974696E6720666F72205553422E2E2E0055534220726561647900636F6D6D616E64203078253032780066610F | ||||
| :4038C000696C2025642B25642B2564203D3D2025642C206E6F74202564007061737365643D256400756E64657272756E206166746572202564207061636B65747300636FE8 | ||||
| :40390000756E743D256420693D256420643D256400636D645F777269746500703D25642063723D25642063773D256420663D256420773D256420696E6465783D2564207526 | ||||
| :403940006E64657272756E3D256400756E64657272756E2100737563636573730073746172742065726173696E670073746F702065726173696E670069646C650000510001 | ||||
| :4039800040100040510040300000000140001000140140000800400140000A004C014000020050014020003031323334353637383941424344454600000100000004000096 | ||||
| :4039C00000100001000000040000001028000000000104000100000000000000000157494E5553420000303030303100000000000000000012034D0053004600540031002A | ||||
| :403A0000300030000100000001000000103A000001000000DF3A0000000000000000000001000000283A000001000000B13A0000040000004A3A00000000000000000000E9 | ||||
| :403A400000000000483A0000FF00000001024000FF00000082024000FF00000003034000FF00000084034000FF00020304030904160346006C007500780045006E006700CA | ||||
| :403A800069006E0065002A0343006F0077006C00610072006B00200054006500630068006E006F006C006F0067006900650073000009022E0001010080320904000004FFC9 | ||||
| :403AC00000000107050102400000070582024000000705030340000A0705840340000A12010002FF0001080912006E0100020180014300232D302B2000686C4C00656667E2 | ||||
| :403B0000454647003031323334353637383961626364656600000000F8B500BFF8BC08BC9E467047590000002D100000F8B500BFF8BC08BC9E46704735000000503B0000FD | ||||
| :403B4000C880FF1FA00000002012000000000000000000008893FF1FFF000000675000400C00000007000000FFFFFFFF7F8000003F0000000000007D00FA000040000000DA | ||||
| :403B80000090D003FF0000000000000000000000000000000000000000000000000000000000000000000000F13A0000000000000000000000000000000000000000000078 | ||||
| :403BC000000000000000000000000000000000000000000000000000000000000000000000000000000000000081FF1F000000000000000000000000000000000000000026 | ||||
| :403C00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000084 | ||||
| :403C40000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000044 | ||||
| :403C80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004 | ||||
| :403CC00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000C4 | ||||
| :403D00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000083 | ||||
| :403D40000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000043 | ||||
| :403D80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 | ||||
| :403DC00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000C3 | ||||
| :403E00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000082 | ||||
| :403E40000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000042 | ||||
| :403E80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002 | ||||
| :403EC00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000C2 | ||||
| @@ -4098,68 +4098,68 @@ | ||||
| :40FF80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041 | ||||
| :40FFC0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 | ||||
| :0200000480007A | ||||
| :400000000145004008520040015B004001650040010101404D0201403D0301404C0401404D0501404D060140500701404B0801404B0901404B0A0140500B0140470C0140CB | ||||
| :40004000500D0140520E0140350F014046140140541501404B160140561701404718014044190140591A0140571B01400A400140104101400E4201400943014004440140BE | ||||
| :400080000D4501400A4601400F470140094801400F4901401B4C0140084D014008500140045101407E0208440905108011821801600C610A7C4027212A0A8C8000010109B1 | ||||
| :4000C0000202040805090808090F0B100C080D010F02100F1120140416011709180819101B0E1D011E01210422082301240829092A0E2C0D320F331F35203B083E043F1020 | ||||
| :400100005608580459045B045C905D905F01850287018C01900F9401960898249A089E07A008A101A222A302AA08AE10B01FB101B302B420B90ABE10BF05C202C70EC810AC | ||||
| :40014000C9FFCAFFCBFFCF83D804D904DA04DB04DC09DD09DF01030204A10620074008010A060B200C800D100E400F2010421110150416821720180419011E10202021010F | ||||
| :40018000262027202A012C042E023508376138083E583F0240045208588859215A025D4060026108621265806F0180068140874088408A088E209880C0F1C2FFC4FBCAA1EC | ||||
| :4001C000CCF0CEF2D004D61FD81FE20CE6C5EE82010D04020601070109080C010D080E0E100F130E150F161019081C201D082101220F2302240125042604270128012908CA | ||||
| :400200002A082C012F08301F3220330F3E043F045608580459045B045C095D905F01810182088302840885028A108B018C088D038F049102920194049701982099029A1FB5 | ||||
| :400240009C089D02A202A302A408A501A704A808A902AC1FAD03AE20B107B43FBF01D804D904DB04DC09DF0100400108048006A0070809880A400C810E080F20100511082C | ||||
| :40028000130115251740185019011B011E081F20210827402AA02B902C052D022F20308031213208350136803728388039243B013D083E4A3F2158405C105D806180851076 | ||||
| :4002C00087029102938094A195349644972099809B209C0C9D089EBAA480A602A713A908AC03B010B520B601C0F5C2FDC4FFCAFFCCFFCEFFD638D808E20AE648E880EA03A0 | ||||
| :40030000EE820003010D050506010801090C0B020C010D0D1001111012021602170D1801190D1C011D0D2201230D2401250D280129092C012D012E022F02310C3510360355 | ||||
| :4003400037033E403F51580459045B045F0180208102820F8404860A882F89028D028EA09204948095039640970C98049A099E10A020A102A20FA480A802AC01AD0AAF0550 | ||||
| :40038000B060B108B21FB306B480B501B61FBE10BF01D804D904DB04DC99DF01000902080302048A0708082209880C800D100F9011501305158016A01710180919041A08AD | ||||
| :4003C0001BD21D80210923042440254026102B422C042D012E402F20310836843721380239803A103D203E083F825D015F0169506AA06F0178017B807D027F8080048604BE | ||||
| :4004000089108A028F01938094A19525964497219B209C0D9D0A9EA89F08A321A480A520A68AA790AD01B040B210C0FFC2FFC4FFCAF9CCF2CEFDE242E401EA01000103027E | ||||
| :4004400004E0050108010A080B020CE00F02100F1280130814481602170218201B021E071F02200422482302261027022A082B042F10311F34E0361F382039023F015804DF | ||||
| :4004800059045B045C095F0180038109840387318A018B098C038F06900391129309940395099712980399409E02A003A309A603A709A803A909AC03AD49AF24B338B40349 | ||||
| :4004C000B540B707BB88BE10D804D904DB04DC90DF010080012002800320048A052008180A010B400C020D080E0610021325172918081E061F802002215423252480284155 | ||||
| :4005000029202B202C872D202F203108321233013448350137A0380239883B103C803E043F115A806E408340860287048A0690029289935094019704981A99019B889C84CD | ||||
| :400540009D209F20A0C2A108A280A328A401AB10B204C0FFC2FFC47FCAFFCCF7CEFFD608E080E620EA85EE2002800404050D064808200A400C0111011210144816021A07E2 | ||||
| :400580001B051C401E202608280129102A082C0F2D0A3020310C32C03303341F362037103A083E413F4056085804590B5B045C995D905F01822083018607870F88218A0825 | ||||
| :4005C0008B018C218F019210930E9428964297059AC89B039F01A02FA280A301A444A628A709A90FAA20AD0FB105B21FB4E0B503B709BA20BF51D804D904DC09DF010001EA | ||||
| :400600000184030805A4078009090A060D080E881006121015141701180219811A051B481D041E081F20210422412501264027082B052C822F2432113408350137A03908B7 | ||||
| :400640003C823D043F144410450858805B10630A64086610780284018601911092289358950896019704980A9B819D249F20A0C2A108A280A401A761A840AF11B040B504F1 | ||||
| :40068000B702C0FFC27FC477CAFCCCF5CEF2D60CD80CDE01E202E640E880EA10EE4002080349077F08010A280B090C2F0F091001117F1408160217091A071B091E401F2962 | ||||
| :4006C000221023722709280429782A282B042F19310732603348341F352837183F55580459045B045C095F01802081048440850186A088418A088C4F8E808F04920794041B | ||||
| :40070000966898689A029B019C41A208A610AA40AD02B01FB304B503B6E0BA80BF04D608D804D904DB04DC99DD90DF010128024003010521070109040A810B080D080E0633 | ||||
| :400740000F80128013181608170218821A801D081E041F14221423102601271A2B012D042E012F253210341036843721380239083A403C023D1A3E0A3F54584060026240FE | ||||
| :4007800068026B016F0A831886408B048C018D089342951496019714980899019B809C109D209E0A9F21A0C0A284A402A509A74AB308B504C0DFC2FFC45ECAF8CCF4CEFBE6 | ||||
| :4007C000D608D808E010E280E644EE820002012F020103800402060107070A060B200C020E010FC81002120114071528174218021A011B101C021E012121220523082544DD | ||||
| :400800002607272829212A012C0731E03207331F3B023E04580459045C905F0182698502861988198E198F119019924493049419962298229A199B089C19A20EA306A61923 | ||||
| :40084000A702A910AA19AB01AD01AE19AF10B070B208B301B407B510B607B70EB928BAA2BB80BE04BF14D804D904DB04DC99DF010082012402400521060207200810094941 | ||||
| :400880000B200C020D090E010F04104213141514164017801A201C821D011E281F012010210423C025442680270829202A082B402C802F1A30803108329034483614378162 | ||||
| :4008C000390A3B503D403F046D408C10C0FFC2FFC4FFCAF7CCA6CE5FE210010E04080508060409080C0D0E020F08110812091504180819081A021D081E04200423012702A7 | ||||
| :4009000029082D08300C320C330F34033A0A3F045608580459045B045C095D905F01801382048402871088028B1F8C088E018F1F901991019202951F96099A089B049C0273 | ||||
| :400940009D1FA001A20CA308A602A720A802AB02AC1BAD1FB210B40FB73FBB80BE14D804D904DC90DF010108021104020540060807200A040B810D110F2211021405161004 | ||||
| :400980001702190A1A041E201F20210425402680270229442A212C802E202F2130803120320433113545371039163A803B033D843F2058806002680D6A508101821084A1C0 | ||||
| :4009C000880289028B048E5090029134922893859508980599459AA99B219C229D0AA080A121A311A40CA690AA88AD80AF10B111B504B648C0F5C2FBC4F8CAFFCCFFCE7FAE | ||||
| :400A0000D608D808E248E401E602E809EE030001062008010A7E0D010E08107F167F1A041E1020022101247E26012A402C7F3501367F3B303E40580459045B045C905F0179 | ||||
| :400A4000804484118708881189078C078E088F109211941195A5974298119B429C119F21A011A307A433A5C6A644A721A878AA02AC20AD84AE02B3E0B51FB67FB71FB9A0BC | ||||
| :400A8000BE40C004C5E0C6C0C80AC9FFCAFFCBFFD004D601D804D904DA04DB04DC90DD09DF01E2C001160201030204020540071409A80B400C810D200F2010041141130440 | ||||
| :400AC00015A016A019801F80214023152510270428222B402F8030083250384039083B103D8041014B025210688069756B116C016E406F02705071E972A07348810A8204C4 | ||||
| :400B00008404850487048A108C509040910292A8938094A295A496409733980199049B209C269D0A9EB89F18A141A351A484A530A68CA808B210B540C0FFC2FFC4FFCA8B79 | ||||
| :400B4000CC0ECE1ED001E003E208E402EA40EE060601083109100D0C0E080F021040130116021702180319011A101E0420382304240325082608290A2B042C022E2130400E | ||||
| :400B8000310F3207351036383A803E013F10580459045B045C995F018001830C8401870188018A028B078C018F019001930194019701980199079E019F01A001A108A302BA | ||||
| :400BC000A601A701A801AB01AC01AE02AF01B507B603B708BE40BF50D804D904DF0100820201032A05480608081909800B400D080E461002128013241501174818011D4E2B | ||||
| :400C00001E01218022102408260228082BA22C082E022F103011328436063710380239A83D103F806D5080048280850186058C208D01900291A89248934494019620981A26 | ||||
| :400C40009A029B609C809D20A043A284A328AB80B604C0EFC2FFC4BFCAEFCCEFCE3FE080E451E8C0EE02000801010201050108040B010C010D010E081101130217011901F5 | ||||
| :400C80001A011D01210123022401250129012A022D01300332043303340836083A023E543F0440434502480149FF4AFF4BFF4D204EF05110580459045A045C095D095F017F | ||||
| :400CC0006108624063406480664067408004840885CC86018722881F8C048D01900493119401961E9722980499F19C019E10A004A344A588A604A824A9AAAA19AB44AC0134 | ||||
| :400D0000AE22B020B30FB50EB61FB7F0BE41BF10D804D90BDC90DF01002001020301058907080B040C200D090E011010120816801764181019221A0A1B801D021E0222083E | ||||
| :400D400025602711280929022B202C082E022F10301232843606371039A83A013D884010410248107C0283408520881089088B308C088D448F4091EA920193049602972033 | ||||
| :400D8000981B99819A839B0C9D209F10A022A108A286A320A408A601A7C0A904AB04AD01AE01B080B18AB608B708C0FBC2F2C4F6CAEFCCEFCE5FD003DE80E0A0E240E47094 | ||||
| :400DC000E602E890ECC01B011F0231203302368037083B40C630CCF0CE103088364037043A023C2088108F0893809F08A520AE80AF41B340CCF0CE60EE4053405640840897 | ||||
| :400E00008C8093809A409E029F04A488A520A6C0B2C0D460E2408E0292029E02A520A6C0AB04AE01EA80EE4015027B02C404DC015940670882108E4191029720AF10B7020E | ||||
| :400E4000D401D801E008E602EC021A4085408D049102966097289D40A201C608E60209440F4191029420962097299C409D40A201A544A810AB01B040C20FEA0126809202EF | ||||
| :400E8000A320A520A680AE40B720C820EE405280572079407E01828085208D409202A320A520D460DC80DE20E210E62004200A200C400F401F1050805B405E025F8083408D | ||||
| :400EC000894091029420962097209C409D40A201AF40B304C001C20DC601D405D605E001E801850188809102A480B3C0E401EA04EC04010109010B010D010F0111011B01BF | ||||
| :400F00001D0100FF01AB020211050000BF0000A09F001F000000000000000000100000004000000000000000C0000000FF0000B847004700000100008000000282008200D5 | ||||
| :400F400000000000000303000300000027001801270018010004000000050000000000000000000000000000000000000000000000000000000000000000000000000000DF | ||||
| :400000000145004008520040015B0040016400400101014003050140030701404E0801404A0901406C0A0140550B01405A0C0140490D01405A0E0140340F0140041701403E | ||||
| :40004000471801405A1901404F1A01404C1B01400C4001400A4101400F4201400D430140044401400C450140064601400C4701400F4801400B490140194C0140074D0140FA | ||||
| :4000800005500140045101407E02080509411080118219026006610A7C4027212A0AE280E640EA05EE10E620EA01EE8C00180220041806E009020A100C010E02100111076F | ||||
| :4000C00012041407150216F8170118801A181B011C181E4020FF260828012A062E072F0630FF330335043B083E01580459045B045C905F0181408210833085E18680870885 | ||||
| :4001000088018A248B108C7C8E828F1091FC92039302961097039B109D209E109FDCA180A210A330A401A648A9E1AA1CAB04AE10B01FB31FB4F0B7E0BA20D608D80BD90B5D | ||||
| :40014000DB04DC99DD90DF01012003A20404055208040AA10B010D080EA80F0210201280135015041680175919011A801B301E402180228424202514260429202B802F0167 | ||||
| :400180003180321433023614370138083B513D2058105980600A68026B046D4078018410884091209358942C9540970199729B599C019F04A240A301A58CA628A792A901F2 | ||||
| :4001C000AA10B010C0FFC2FDC4FFCA15CCEFCE2FD60CD80CDE01E622E804EE8C004801400311044805F10708081009100A200BE10C5A0E200F0E10C01201144818481C02F7 | ||||
| :400200001D201E041F112180224023112448288629F12A782B022DF12E042F04303F310F328033F0344038023B023E1440254520480249FF4AFF4BFF4D204EF0511058045A | ||||
| :40024000590B5A045B045C995D095F01610862406340648066406740800481018220830E8404861088808A048BC08D018E0291EF92029403952F96FC974099019A049B04BE | ||||
| :400280009C049D809E409F2FA0FFA101A302A404A6F9A710A804A901AA08AB08AC01AE02AF20B4FFB51FB7E0BE10D804D904DB04DC90DF01004401020204042405020606B2 | ||||
| :4002C000084809200A800B280D280E800F021180128813081408174918401A041B051F2023502680270829202B822C802E802F28318034403608375138083B513D903E02AA | ||||
| :4003000042044620470849014A0268056E507801830489108A808E409120928093209540965099729A829B519C019D019E209F04A090A160A242A308A405A50CA628A7130E | ||||
| :40034000A840AA01B540C0FFC2FFC4FFCAFDCCF8CEBFD004D208DE01E404E640EE1000800102027E044006100702083E09010A400C400E020F041040111812201320147E22 | ||||
| :400380001703188019021C401D081E04210222012502284029022A082D202F1830FF310833203507371039203E013F05400247EC483049FF4AFF4BFF5004560158045904C1 | ||||
| :4003C0005A045B045C905D095F0162C080368209842D8612880789028B018C3F9209961299019B029C24A104A480A640A840AA80AEC0B040B104B238B301B407B680B7021B | ||||
| :40040000B882B988BE41BF45D80BD904DB04DC09DF01001A010403820408060A07400A700B410C800D280E80102011501711189019A01C80202021402202253026802760C1 | ||||
| :4004400029012D022E202F11302036A939103C803D283F02472056056A806B016C946D806EA06F18768A780189C08A1091309323942895049620974099129E249F45A0205B | ||||
| :40048000A201A480A55CA668A79BA820A950AA80B080B640C0FFC2FDC457CAF1CCF4CEF4D020DE0100020140020C04100550072008040A080E010F10107211041280130203 | ||||
| :4004C000140E150816F018101B201C801E20201021602310244025022680270528102C082D072E0430FF310133703506370838023F445608580459045B045C995D905F0174 | ||||
| :40050000810C82078340840185808604870C88018A028B048C408EA08F02900191FF9457950397FC9840990C9A909B109C019D019E069F02A057A302A50CA7F1A840AB0883 | ||||
| :40054000AD0CAE08AF20B030B1FFB40FB6C0BF01D804D904DC09DF010220034904280540074009180A410C800D080E881004118812801604178119021A401D501E021F114A | ||||
| :400580002112224427802B922C842E602F103102321033043628374139043B413DA83E013F025880630169908A048E048F01C0FFC2FFC4DFCAFBCCF7CEFBD608D808E280A8 | ||||
| :4005C000E404E680EA08EE0B011406410714080109140A120B080CF10E040F201241150A16411714180119041A281C801D0A1E01211422412504264E29042B102D182F0158 | ||||
| :40060000320F3307353836F039083A085608580859045B045C995D905F018210846088018A048C7C8D018E02921C96039A109C409D04A210A401A608AA10AD02AE10B1016E | ||||
| :40064000B21FB304B440B502B620BF15D80BD904DB04DC09DF01012803810524070108100A120B800C200E060F50102011011280135014101501170418081A161E021F885A | ||||
| :4006800020202101221024042518262828022D062E802F0430043240330C35103608374039803D283E403F0258405A205D505F086401650867066A806C016F0378017F01D2 | ||||
| :4006C000814083088501912492489358940C96019702984299339A809B409C059D80A104A280A301A460A508A628A782AC02B048C0EFC2FFC43FCAF8CC78CEF8D67CD870F3 | ||||
| :40070000DE11E204E402E680EE0B01FC02900302042005C106C0072808C10A240B900CFC0E020F901120120313C018011A481B901E901F032290239C2690279029012A9012 | ||||
| :400740002B442E9C2F9031E034E0361F371F3A203B02420245E0480249FF4AFF4BFF4F83580B590B5A045B045C995D095F01821084618501860888618A04921096109A0394 | ||||
| :400780009C409E30A07CA202A61CA820AA50AC80B080B101B260B41FB660BE01BF01D808D904DB04DC09DF01012002C0036204080520074008020A050C400E0A0F50105066 | ||||
| :4007C0001350141015401608170519401B301C041D041E491F4022422780284029242A4830103242380A3B503F044110484059015A985F80600661406202632069806D40BA | ||||
| :4008000078017F018240900A9120921C9356958096019780980199219B059D04A281A302A440AD10B010B580C07FC2FBC4FFCA0FCC0DCE4FD004D61FD80FDE11E004EE085F | ||||
| :400840001A401F083328360437103A406A406B108B20C630CCF0CE1032043380364037023A013E809E40A604CCF0CE60502055108D2096089EC09F02A020A110A644A7809D | ||||
| :40088000A910AA01B420D460EAA08A809EC09F02A002A120A202A640A780AA06AE04B002EA80EE3014107310C404DC01530164108B1090109710B010B410D401D801E4017C | ||||
| :4008C000E808EA041B048301901097029C10C60808080B080E020F408710903097089C10A810AB04AF04C20F240280018A409A209E40A002A120A202AB02AE60AF80C820D3 | ||||
| :40090000E420EA10EED051205202722074029A20A002A120A202D4A0DC80DE2005400B200C800E401F40501056205C106120824084108B40903097209C10AA01AC08AF40A1 | ||||
| :40094000C001C20DC601D406D604D802E60182209E20AD40B120B480EC01EE0201010D010F0111011D0100FF01AB020211050000BF0000A09F001F0000000000000000004A | ||||
| :40098000100000004000000000000000C0000000FF0000B84700470000010000800000028200820000000000000303000300000027001801270018010004000000050000C9 | ||||
| :4009C00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000F7 | ||||
| :400A000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000B6 | ||||
| :400A40000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000076 | ||||
| :400A80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000036 | ||||
| :400AC00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000F6 | ||||
| :400B000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000B5 | ||||
| :400B40000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000075 | ||||
| :400B80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000035 | ||||
| :400BC00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000F5 | ||||
| :400C000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000B4 | ||||
| :400C40000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000074 | ||||
| :400C80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000034 | ||||
| :400CC00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000F4 | ||||
| :400D000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000B3 | ||||
| :400D40000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000073 | ||||
| :400D80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000033 | ||||
| :400DC00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000F3 | ||||
| :400E000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000B2 | ||||
| :400E40000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000072 | ||||
| :400E80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000032 | ||||
| :400EC00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000F2 | ||||
| :400F000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000B1 | ||||
| :400F40000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000071 | ||||
| :400F80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000031 | ||||
| :400FC00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000F1 | ||||
| :4010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000B0 | ||||
| @@ -4615,12 +4615,12 @@ | ||||
| :0200000490105A | ||||
| :04000000BC90ACAF55 | ||||
| :0200000490303A | ||||
| :02000000A35308 | ||||
| :02000000861365 | ||||
| :0200000490402A | ||||
| :4000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000C0 | ||||
| :400040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080 | ||||
| :400080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040 | ||||
| :4000C0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 | ||||
| :0200000490501A | ||||
| :0C00000000012E16106900002E31B3BC68 | ||||
| :0C00000000012E16106900002E2F967CC7 | ||||
| :00000001FF | ||||
| @@ -848,6 +848,7 @@ | ||||
|       <Data key="efd5f185-0c32-4824-ba72-3ceb5356f5a7" value="Clock_1" /> | ||||
|     </Group> | ||||
|     <Group key="Pin"> | ||||
|       <Data key="3e1862bb-be82-47b0-9549-7ebfe76b6f7b" value="Pin_2" /> | ||||
|       <Data key="4a398466-709f-4228-9500-96178658e13e" value="RDATA" /> | ||||
|       <Data key="5a3407c1-b434-4438-a7b4-b9dfd2280495" value="MOTEA" /> | ||||
|       <Data key="8d318d8b-cf7b-4b6b-b02c-ab1c5c49d0ba" value="SW1" /> | ||||
| @@ -858,6 +859,7 @@ | ||||
|       <Data key="472f8fdb-f772-44fb-8897-cc690694237b" value="WDATA" /> | ||||
|       <Data key="736cb12b-c863-43d4-a8f0-42f06023f8b5" value="SIDE1" /> | ||||
|       <Data key="4249c923-fcff-453b-8629-bec6fddd00c1" value="STEP" /> | ||||
|       <Data key="27315b0e-6a8c-4b7f-be77-73ab434fa803" value="Pin_1" /> | ||||
|       <Data key="1425177d-0d0e-4468-8bcc-e638e5509a9b" value="UartRx" /> | ||||
|       <Data key="a5d987c6-e45b-45b9-ad93-656fab06d720" value="TRK00" /> | ||||
|       <Data key="a93ef5b3-00f4-42c0-8fad-0e275a7e2537" value="MOTEB" /> | ||||
| @@ -3963,6 +3965,11 @@ | ||||
|     </Group> | ||||
|   </Group> | ||||
|   <Group key="Pin2"> | ||||
|     <Group key="3e1862bb-be82-47b0-9549-7ebfe76b6f7b"> | ||||
|       <Group key="0"> | ||||
|         <Data key="Port Format" value="0,6" /> | ||||
|       </Group> | ||||
|     </Group> | ||||
|     <Group key="4a398466-709f-4228-9500-96178658e13e"> | ||||
|       <Group key="0"> | ||||
|         <Data key="Port Format" value="1,5" /> | ||||
| @@ -4064,6 +4071,11 @@ | ||||
|         <Data key="Port Format" value="1,0" /> | ||||
|       </Group> | ||||
|     </Group> | ||||
|     <Group key="27315b0e-6a8c-4b7f-be77-73ab434fa803"> | ||||
|       <Group key="0"> | ||||
|         <Data key="Port Format" value="0,7" /> | ||||
|       </Group> | ||||
|     </Group> | ||||
|     <Group key="1425177d-0d0e-4468-8bcc-e638e5509a9b"> | ||||
|       <Group key="0"> | ||||
|         <Data key="Port Format" value="12,6" /> | ||||
|   | ||||
| @@ -39,20 +39,6 @@ | ||||
| <build_action v="HEADER;;;;" /> | ||||
| <PropertyDeltas /> | ||||
| </CyGuid_8b8ab257-35d3-4473-b57b-36315200b38b> | ||||
| <CyGuid_8b8ab257-35d3-4473-b57b-36315200b38b type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtFileSerialize" version="3" xml_contents_version="1"> | ||||
| <CyGuid_31768f72-0253-412b-af77-e7dba74d1330 type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtItemSerialize" version="2" name="crunch.c" persistent="..\lib\common\crunch.c"> | ||||
| <Hidden v="False" /> | ||||
| </CyGuid_31768f72-0253-412b-af77-e7dba74d1330> | ||||
| <build_action v="SOURCE_C;;;;" /> | ||||
| <PropertyDeltas /> | ||||
| </CyGuid_8b8ab257-35d3-4473-b57b-36315200b38b> | ||||
| <CyGuid_8b8ab257-35d3-4473-b57b-36315200b38b type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtFileSerialize" version="3" xml_contents_version="1"> | ||||
| <CyGuid_31768f72-0253-412b-af77-e7dba74d1330 type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtItemSerialize" version="2" name="crunch.h" persistent="..\lib\common\crunch.h"> | ||||
| <Hidden v="False" /> | ||||
| </CyGuid_31768f72-0253-412b-af77-e7dba74d1330> | ||||
| <build_action v="HEADER;;;;" /> | ||||
| <PropertyDeltas /> | ||||
| </CyGuid_8b8ab257-35d3-4473-b57b-36315200b38b> | ||||
| </dependencies> | ||||
| </CyGuid_0820c2e7-528d-4137-9a08-97257b946089> | ||||
| </CyGuid_2f73275c-45bf-46ba-b3b1-00a2fe0c8dd8> | ||||
| @@ -2795,6 +2781,72 @@ | ||||
| </CyGuid_2f73275c-45bf-46ba-b3b1-00a2fe0c8dd8> | ||||
| <filters /> | ||||
| </CyGuid_ebc4f06d-207f-49c2-a540-72acf4adabc0> | ||||
| <CyGuid_ebc4f06d-207f-49c2-a540-72acf4adabc0 type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtFolderSerialize" version="3"> | ||||
| <CyGuid_2f73275c-45bf-46ba-b3b1-00a2fe0c8dd8 type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtBaseContainerSerialize" version="1"> | ||||
| <CyGuid_31768f72-0253-412b-af77-e7dba74d1330 type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtItemSerialize" version="2" name="Pin_2" persistent=""> | ||||
| <Hidden v="True" /> | ||||
| </CyGuid_31768f72-0253-412b-af77-e7dba74d1330> | ||||
| <CyGuid_0820c2e7-528d-4137-9a08-97257b946089 type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtItemListSerialize" version="2"> | ||||
| <dependencies> | ||||
| <CyGuid_8b8ab257-35d3-4473-b57b-36315200b38b type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtFileSerialize" version="3" xml_contents_version="1"> | ||||
| <CyGuid_31768f72-0253-412b-af77-e7dba74d1330 type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtItemSerialize" version="2" name="Pin_2_aliases.h" persistent="Generated_Source\PSoC5\Pin_2_aliases.h"> | ||||
| <Hidden v="True" /> | ||||
| </CyGuid_31768f72-0253-412b-af77-e7dba74d1330> | ||||
| <build_action v="HEADER;;;;" /> | ||||
| <PropertyDeltas /> | ||||
| </CyGuid_8b8ab257-35d3-4473-b57b-36315200b38b> | ||||
| <CyGuid_8b8ab257-35d3-4473-b57b-36315200b38b type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtFileSerialize" version="3" xml_contents_version="1"> | ||||
| <CyGuid_31768f72-0253-412b-af77-e7dba74d1330 type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtItemSerialize" version="2" name="Pin_2.c" persistent="Generated_Source\PSoC5\Pin_2.c"> | ||||
| <Hidden v="True" /> | ||||
| </CyGuid_31768f72-0253-412b-af77-e7dba74d1330> | ||||
| <build_action v="SOURCE_C;CortexM3;;;" /> | ||||
| <PropertyDeltas /> | ||||
| </CyGuid_8b8ab257-35d3-4473-b57b-36315200b38b> | ||||
| <CyGuid_8b8ab257-35d3-4473-b57b-36315200b38b type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtFileSerialize" version="3" xml_contents_version="1"> | ||||
| <CyGuid_31768f72-0253-412b-af77-e7dba74d1330 type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtItemSerialize" version="2" name="Pin_2.h" persistent="Generated_Source\PSoC5\Pin_2.h"> | ||||
| <Hidden v="True" /> | ||||
| </CyGuid_31768f72-0253-412b-af77-e7dba74d1330> | ||||
| <build_action v="HEADER;;;;" /> | ||||
| <PropertyDeltas /> | ||||
| </CyGuid_8b8ab257-35d3-4473-b57b-36315200b38b> | ||||
| </dependencies> | ||||
| </CyGuid_0820c2e7-528d-4137-9a08-97257b946089> | ||||
| </CyGuid_2f73275c-45bf-46ba-b3b1-00a2fe0c8dd8> | ||||
| <filters /> | ||||
| </CyGuid_ebc4f06d-207f-49c2-a540-72acf4adabc0> | ||||
| <CyGuid_ebc4f06d-207f-49c2-a540-72acf4adabc0 type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtFolderSerialize" version="3"> | ||||
| <CyGuid_2f73275c-45bf-46ba-b3b1-00a2fe0c8dd8 type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtBaseContainerSerialize" version="1"> | ||||
| <CyGuid_31768f72-0253-412b-af77-e7dba74d1330 type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtItemSerialize" version="2" name="Pin_1" persistent=""> | ||||
| <Hidden v="True" /> | ||||
| </CyGuid_31768f72-0253-412b-af77-e7dba74d1330> | ||||
| <CyGuid_0820c2e7-528d-4137-9a08-97257b946089 type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtItemListSerialize" version="2"> | ||||
| <dependencies> | ||||
| <CyGuid_8b8ab257-35d3-4473-b57b-36315200b38b type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtFileSerialize" version="3" xml_contents_version="1"> | ||||
| <CyGuid_31768f72-0253-412b-af77-e7dba74d1330 type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtItemSerialize" version="2" name="Pin_1_aliases.h" persistent="Generated_Source\PSoC5\Pin_1_aliases.h"> | ||||
| <Hidden v="True" /> | ||||
| </CyGuid_31768f72-0253-412b-af77-e7dba74d1330> | ||||
| <build_action v="HEADER;;;;" /> | ||||
| <PropertyDeltas /> | ||||
| </CyGuid_8b8ab257-35d3-4473-b57b-36315200b38b> | ||||
| <CyGuid_8b8ab257-35d3-4473-b57b-36315200b38b type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtFileSerialize" version="3" xml_contents_version="1"> | ||||
| <CyGuid_31768f72-0253-412b-af77-e7dba74d1330 type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtItemSerialize" version="2" name="Pin_1.c" persistent="Generated_Source\PSoC5\Pin_1.c"> | ||||
| <Hidden v="True" /> | ||||
| </CyGuid_31768f72-0253-412b-af77-e7dba74d1330> | ||||
| <build_action v="SOURCE_C;CortexM3;;;" /> | ||||
| <PropertyDeltas /> | ||||
| </CyGuid_8b8ab257-35d3-4473-b57b-36315200b38b> | ||||
| <CyGuid_8b8ab257-35d3-4473-b57b-36315200b38b type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtFileSerialize" version="3" xml_contents_version="1"> | ||||
| <CyGuid_31768f72-0253-412b-af77-e7dba74d1330 type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtItemSerialize" version="2" name="Pin_1.h" persistent="Generated_Source\PSoC5\Pin_1.h"> | ||||
| <Hidden v="True" /> | ||||
| </CyGuid_31768f72-0253-412b-af77-e7dba74d1330> | ||||
| <build_action v="HEADER;;;;" /> | ||||
| <PropertyDeltas /> | ||||
| </CyGuid_8b8ab257-35d3-4473-b57b-36315200b38b> | ||||
| </dependencies> | ||||
| </CyGuid_0820c2e7-528d-4137-9a08-97257b946089> | ||||
| </CyGuid_2f73275c-45bf-46ba-b3b1-00a2fe0c8dd8> | ||||
| <filters /> | ||||
| </CyGuid_ebc4f06d-207f-49c2-a540-72acf4adabc0> | ||||
| </dependencies> | ||||
| </CyGuid_0820c2e7-528d-4137-9a08-97257b946089> | ||||
| </CyGuid_2f73275c-45bf-46ba-b3b1-00a2fe0c8dd8> | ||||
| @@ -3380,6 +3432,6 @@ | ||||
| </ignored_deps> | ||||
| </CyGuid_495451fe-d201-4d01-b22d-5d3f5609ac37> | ||||
| <boot_component v="" /> | ||||
| <current_generation v="138" /> | ||||
| <current_generation v="150" /> | ||||
| </CyGuid_fec8f9e8-2365-4bdb-96d3-a4380222e01b> | ||||
| </CyXmlSerializer> | ||||
| @@ -1,7 +1,6 @@ | ||||
|  | ||||
| //`#start header` -- edit after this line, do not edit this line | ||||
| `include "cypress.v" | ||||
| `include "../SuperCounter/SuperCounter.v" | ||||
|  | ||||
| //`#end` -- edit above this line, do not edit this line | ||||
| // Generated on 12/11/2019 at 21:18 | ||||
| @@ -9,7 +8,7 @@ | ||||
| module Sampler ( | ||||
| 	output [2:0] debug_state, | ||||
| 	output reg [7:0] opcode, | ||||
| 	output  req, | ||||
| 	output  reg       req, | ||||
| 	input   clock, | ||||
| 	input   index, | ||||
| 	input   rdata, | ||||
| @@ -19,90 +18,63 @@ module Sampler ( | ||||
|  | ||||
| //`#start body` -- edit after this line, do not edit this line | ||||
|  | ||||
| localparam STATE_RESET = 0; | ||||
| localparam STATE_WAITING = 1; | ||||
| localparam STATE_OPCODE = 2; | ||||
| // NOTE: Reset pulse is used in both clock domains, and must be long enough | ||||
| // to be detected in both. | ||||
|  | ||||
| reg [1:0] state; | ||||
| reg [6:0] counter; | ||||
| reg [5:0] counter; | ||||
|  | ||||
| reg oldsampleclock; | ||||
| wire sampleclocked; | ||||
| assign sampleclocked = !oldsampleclock && sampleclock; | ||||
| reg index_q; | ||||
| reg rdata_q; | ||||
|  | ||||
| reg oldindex; | ||||
| wire indexed; | ||||
| assign indexed = !oldindex && index; | ||||
| reg index_edge; | ||||
| reg rdata_edge; | ||||
|  | ||||
| wire rdataed; | ||||
| reg oldrdata; | ||||
| assign rdataed = !oldrdata && rdata; | ||||
| reg req_toggle; | ||||
|  | ||||
| assign req = (state == STATE_OPCODE); | ||||
|  | ||||
| always @(posedge clock) | ||||
| always @(posedge sampleclock) | ||||
| begin | ||||
|     if (reset) | ||||
|     begin | ||||
|         state <= STATE_RESET; | ||||
|         opcode <= 0; | ||||
|         oldsampleclock <= 0; | ||||
|         oldindex <= 0; | ||||
|         oldrdata <= 0; | ||||
|         index_edge <= 0; | ||||
|         rdata_edge <= 0; | ||||
|         index_q <= 0; | ||||
|         rdata_q <= 0; | ||||
|         counter <= 0; | ||||
|         req_toggle <= 0; | ||||
|     end | ||||
|     else | ||||
|         case (state) | ||||
|             STATE_RESET: | ||||
|                 state <= STATE_WAITING; | ||||
|              | ||||
|             STATE_WAITING: | ||||
|             begin | ||||
|                 /* If something has happened, emit any necessary interval byte. */ | ||||
|                 if ((rdataed || indexed) && (counter != 0)) | ||||
|                 begin | ||||
|                     opcode <= {0, counter}; | ||||
|                     state <= STATE_OPCODE; | ||||
|                 end | ||||
|                 else if (indexed) | ||||
|                 begin | ||||
|                     oldindex <= 1; | ||||
|                     opcode <= 8'h81; | ||||
|                     state <= STATE_OPCODE; | ||||
|                 end | ||||
|                 else if (rdataed) | ||||
|                 begin | ||||
|                     oldrdata <= 1; | ||||
|                     opcode <= 8'h80; | ||||
|                     state <= STATE_OPCODE; | ||||
|                 end | ||||
|                 else if (sampleclocked) | ||||
|                 begin | ||||
|                     oldsampleclock <= 1; | ||||
|                     if (counter == 7'h7f) | ||||
|                     begin | ||||
|                         opcode <= {0, counter}; | ||||
|                         state <= STATE_OPCODE; | ||||
|                     end | ||||
|                     counter <= counter + 1; | ||||
|                 end | ||||
|                  | ||||
|                 /* Reset state once we've done the thing. */ | ||||
|                  | ||||
|                 if (oldrdata && !rdata) | ||||
|                     oldrdata <= 0; | ||||
|                 if (oldindex && !index) | ||||
|                     oldindex <= 0; | ||||
|                 if (oldsampleclock && !sampleclock) | ||||
|                     oldsampleclock <= 0; | ||||
|             end | ||||
|              | ||||
|             STATE_OPCODE: /* opcode or interval byte sent here */ | ||||
|             begin | ||||
|                 state <= STATE_WAITING; | ||||
|                 counter <= 0; | ||||
|             end | ||||
|         endcase | ||||
|     begin | ||||
|         /* Both index and rdata are active high -- positive-going edges | ||||
|          * indicate the start of an index pulse and read pulse, respectively. | ||||
|          */ | ||||
|           | ||||
|         index_edge <= index && !index_q; | ||||
|         index_q <= index; | ||||
|          | ||||
|         rdata_edge <= rdata && !rdata_q; | ||||
|         rdata_q <= rdata; | ||||
|          | ||||
|         if (rdata_edge || index_edge || (counter == 6'h3f)) begin | ||||
|             opcode <= { rdata_edge, index_edge, counter }; | ||||
|             req_toggle <= ~req_toggle; | ||||
|             counter <= 1;   /* remember to count this tick */ | ||||
|         end else begin | ||||
|             counter <= counter + 1; | ||||
|         end | ||||
|     end | ||||
| end | ||||
|  | ||||
| reg req_toggle_q; | ||||
|  | ||||
| always @(posedge clock) | ||||
| begin | ||||
|     if (reset) begin | ||||
|         req_toggle_q <= 0; | ||||
|         req <= 0; | ||||
|     end else begin | ||||
|         req_toggle_q <= req_toggle; | ||||
|         req <= (req_toggle != req_toggle_q); | ||||
|     end | ||||
| end | ||||
|  | ||||
| //`#end` -- edit above this line, do not edit this line | ||||
|   | ||||
| @@ -19,19 +19,15 @@ module Sequencer ( | ||||
| //`#start body` -- edit after this line, do not edit this line | ||||
|  | ||||
| localparam STATE_LOAD = 0; | ||||
| localparam STATE_WAITING = 1; | ||||
| localparam STATE_PULSING = 2; | ||||
| localparam STATE_INDEXING = 3; | ||||
| localparam STATE_WRITING = 1; | ||||
|  | ||||
| localparam OPCODE_PULSE = 8'h80; | ||||
| localparam OPCODE_INDEX = 8'h81; | ||||
|  | ||||
| reg [1:0] state; | ||||
| reg [6:0] countdown; | ||||
| reg state; | ||||
| reg [5:0] countdown; | ||||
| reg pulsepending; | ||||
|  | ||||
| assign req = (!reset && (state == STATE_LOAD)); | ||||
| assign wdata = (state == STATE_PULSING); | ||||
| assign debug_state = state; | ||||
| assign wdata = (!reset && (state == STATE_WRITING) && (countdown == 0) && pulsepending); | ||||
| assign debug_state = 0; | ||||
|  | ||||
| reg olddataclock; | ||||
| wire dataclocked; | ||||
| @@ -52,49 +48,39 @@ begin | ||||
|     begin | ||||
|         state <= STATE_LOAD; | ||||
|         countdown <= 0; | ||||
|         pulsepending <= 0; | ||||
|         oldsampleclock <= 0; | ||||
|     end | ||||
|     else | ||||
|     begin | ||||
|         if (!oldsampleclock && sampleclock) | ||||
|             sampleclocked <= 1; | ||||
|         oldsampleclock <= sampleclock; | ||||
|          | ||||
|              | ||||
|         case (state) | ||||
|             STATE_LOAD: | ||||
|                 /* Wait for a posedge on dataclocked, indicating an opcode has | ||||
|             begin | ||||
|                 /* A posedge on dataclocked indicates that another opcode has | ||||
|                  * arrived. */ | ||||
|                 if (dataclocked) | ||||
|                     case (opcode) | ||||
|                         OPCODE_PULSE: | ||||
|                             state <= STATE_PULSING; | ||||
|                          | ||||
|                         OPCODE_INDEX: | ||||
|                             state <= STATE_INDEXING; | ||||
|                          | ||||
|                         default: | ||||
|                         begin | ||||
|                             countdown <= opcode[6:0]; | ||||
|                             state <= STATE_WAITING; | ||||
|                         end | ||||
|                     endcase | ||||
|                 begin | ||||
|                     pulsepending <= opcode[7]; | ||||
|                     countdown <= opcode[5:0] - 1; /* compensate for delay in last tick */ | ||||
|                     state <= STATE_WRITING; | ||||
|                 end | ||||
|             end | ||||
|              | ||||
|             STATE_WAITING: | ||||
|             STATE_WRITING: | ||||
|             begin | ||||
|                 if (sampleclocked) | ||||
|                 begin | ||||
|                     sampleclocked <= 0; | ||||
|                     countdown <= countdown - 1; | ||||
|                     /* Nasty fudge factor here to account for one to two | ||||
|                      * sample ticks lost per pulse. */ | ||||
|                     if (countdown <= 2) | ||||
|                     if (countdown == 0) | ||||
|                         state <= STATE_LOAD; | ||||
|                     else | ||||
|                         countdown <= countdown - 1; | ||||
|                     sampleclocked <= 0; | ||||
|                 end | ||||
|              | ||||
|             STATE_PULSING: | ||||
|                 state <= STATE_LOAD; | ||||
|              | ||||
|             STATE_INDEXING: | ||||
|                 if (indexed) | ||||
|                     state <= STATE_LOAD; | ||||
|             end | ||||
|         endcase | ||||
|     end | ||||
| end | ||||
|   | ||||
										
											Binary file not shown.
										
									
								
							| @@ -5,7 +5,6 @@ | ||||
| #include <setjmp.h> | ||||
| #include "project.h" | ||||
| #include "../protocol.h" | ||||
| #include "../lib/common/crunch.h" | ||||
|  | ||||
| #define MOTOR_ON_TIME 5000 /* milliseconds */ | ||||
| #define STEP_INTERVAL_TIME 6 /* ms */ | ||||
| @@ -17,6 +16,9 @@ | ||||
| #define STEP_TOWARDS0 1 | ||||
| #define STEP_AWAYFROM0 0 | ||||
|  | ||||
| static bool drive0_present; | ||||
| static bool drive1_present; | ||||
|  | ||||
| static volatile uint32_t clock = 0; /* ms */ | ||||
| static volatile bool index_irq = false; | ||||
|  | ||||
| @@ -31,7 +33,6 @@ static struct set_drive_frame current_drive_flags; | ||||
| static uint8_t td[BUFFER_COUNT]; | ||||
| static uint8_t dma_buffer[BUFFER_COUNT][BUFFER_SIZE] __attribute__((aligned())); | ||||
| static uint8_t usb_buffer[BUFFER_SIZE] __attribute__((aligned())); | ||||
| static uint8_t xfer_buffer[BUFFER_SIZE] __attribute__((aligned())); | ||||
| static uint8_t dma_channel; | ||||
| #define NEXT_BUFFER(b) (((b)+1) % BUFFER_COUNT) | ||||
|  | ||||
| @@ -42,6 +43,8 @@ static volatile bool dma_underrun = false; | ||||
| #define DECLARE_REPLY_FRAME(STRUCT, TYPE) \ | ||||
|     STRUCT r = {.f = { .type = TYPE, .size = sizeof(STRUCT) }} | ||||
|  | ||||
| static void stop_motor(void); | ||||
|  | ||||
| static void system_timer_cb(void) | ||||
| { | ||||
|     CyGlobalIntDisable; | ||||
| @@ -104,7 +107,10 @@ static void print(const char* msg, ...) | ||||
| static void set_drive_flags(struct set_drive_frame* flags) | ||||
| { | ||||
|     if (current_drive_flags.drive != flags->drive) | ||||
|     { | ||||
|         stop_motor(); | ||||
|         homed = false; | ||||
|     } | ||||
|      | ||||
|     current_drive_flags = *flags; | ||||
|     DRIVESELECT_REG_Write(flags->drive ? 2 : 1); /* select drive 1 or 0 */ | ||||
| @@ -143,6 +149,12 @@ static void wait_until_writeable(int ep) | ||||
|         ; | ||||
| } | ||||
|  | ||||
| static void wait_until_readable(int ep) | ||||
| { | ||||
|     while (USBFS_GetEPState(ep) != USBFS_OUT_BUFFER_FULL) | ||||
|         ; | ||||
| } | ||||
|  | ||||
| static void send_reply(struct any_frame* f) | ||||
| { | ||||
|     print("reply 0x%02x", f->f.type); | ||||
| @@ -160,9 +172,15 @@ static void send_error(int code) | ||||
| /* buffer must be big enough for a frame */ | ||||
| static int usb_read(int ep, uint8_t buffer[FRAME_SIZE]) | ||||
| { | ||||
|     if (USBFS_GetEPState(ep) != USBFS_OUT_BUFFER_FULL) | ||||
|     { | ||||
|         USBFS_EnableOutEP(ep); | ||||
|         wait_until_readable(ep); | ||||
|     } | ||||
|  | ||||
|     int length = USBFS_GetEPCount(ep); | ||||
|     USBFS_ReadOutEP(ep, buffer, length); | ||||
|     while (USBFS_GetEPState(ep) == USBFS_OUT_BUFFER_FULL) | ||||
|     while (USBFS_GetEPState(ep) != USBFS_OUT_BUFFER_EMPTY) | ||||
|         ; | ||||
|     return length; | ||||
| } | ||||
| @@ -184,19 +202,19 @@ static void step(int dir) | ||||
|     CyDelay(STEP_INTERVAL_TIME); | ||||
| } | ||||
|  | ||||
| static void home(void) | ||||
| /* returns true if it looks like a drive is attached */ | ||||
| static bool home(void) | ||||
| { | ||||
|     for (int i=0; i<100; i++) | ||||
|     { | ||||
|         /* Don't keep stepping forever, because if a drive's | ||||
|          * not connected bad things happen. */ | ||||
|         if (TRACK0_REG_Read()) | ||||
|             break; | ||||
|             return true; | ||||
|         step(STEP_TOWARDS0); | ||||
|     } | ||||
|      | ||||
|     /* Step to -1, which should be a nop, to reset the disk on disk change. */ | ||||
|     step(STEP_TOWARDS0); | ||||
|     return false; | ||||
| } | ||||
|  | ||||
| static void seek_to(int track) | ||||
| @@ -311,13 +329,7 @@ static void cmd_bulk_read_test(struct any_frame* f) | ||||
|         CyWdtClear(); | ||||
|         for (int y=0; y<256; y++) | ||||
|         { | ||||
|             USBFS_EnableOutEP(FLUXENGINE_DATA_OUT_EP_NUM); | ||||
|             while (USBFS_GetEPState(FLUXENGINE_DATA_OUT_EP_NUM) != USBFS_OUT_BUFFER_FULL) | ||||
|                 ; | ||||
|             USBFS_ReadOutEP(FLUXENGINE_DATA_OUT_EP_NUM, buffer, sizeof(buffer)); | ||||
|             while (USBFS_GetEPState(FLUXENGINE_DATA_OUT_EP_NUM) != USBFS_OUT_BUFFER_EMPTY) | ||||
|                 ; | ||||
|              | ||||
|             usb_read(FLUXENGINE_DATA_OUT_EP_NUM, buffer); | ||||
|             for (unsigned z=0; z<sizeof(buffer); z++) | ||||
|             { | ||||
|                 if (buffer[z] != (uint8)(x+y+z)) | ||||
| @@ -348,7 +360,7 @@ static void deinit_dma(void) | ||||
| static void init_capture_dma(void) | ||||
| { | ||||
|     dma_channel = SAMPLER_DMA_DmaInitialize( | ||||
|         2 /* bytes */, | ||||
|         1 /* bytes */, | ||||
|         true /* request per burst */,  | ||||
|         HI16(CYDEV_PERIPH_BASE), | ||||
|         HI16(CYDEV_SRAM_BASE)); | ||||
| @@ -395,10 +407,6 @@ static void cmd_read(struct read_frame* f) | ||||
|         index_irq = false; | ||||
|     } | ||||
|      | ||||
|     crunch_state_t cs = {}; | ||||
|     cs.outputptr = xfer_buffer; | ||||
|     cs.outputlen = BUFFER_SIZE; | ||||
|      | ||||
|     dma_writing_to_td = 0; | ||||
|     dma_reading_from_td = -1; | ||||
|     dma_underrun = false; | ||||
| @@ -455,51 +463,18 @@ static void cmd_read(struct read_frame* f) | ||||
|         { | ||||
|             /* Otherwise, there's a block waiting, so attempt to send it. */ | ||||
|              | ||||
|             uint8_t dma_buffer_usage = 0; | ||||
|             while (dma_buffer_usage < BUFFER_SIZE) | ||||
|             { | ||||
|                 cs.inputptr = dma_buffer[dma_reading_from_td] + dma_buffer_usage; | ||||
|                 cs.inputlen = BUFFER_SIZE - dma_buffer_usage; | ||||
|                 crunch(&cs); | ||||
|                 dma_buffer_usage += BUFFER_SIZE - cs.inputlen; | ||||
|                 count++; | ||||
|                  | ||||
|                 /* If there is no available space in the output buffer, flush the buffer via | ||||
|                  * USB and go again. */ | ||||
|                 if (cs.outputlen == 0) | ||||
|                 { | ||||
|                     wait_until_writeable(FLUXENGINE_DATA_IN_EP_NUM); | ||||
|                     memcpy(usb_buffer, xfer_buffer, FRAME_SIZE); | ||||
|                     USBFS_LoadInEP(FLUXENGINE_DATA_IN_EP_NUM, usb_buffer, BUFFER_SIZE); | ||||
|                      | ||||
|                     cs.outputptr = xfer_buffer; | ||||
|                     cs.outputlen = BUFFER_SIZE; | ||||
|                 } | ||||
|             } | ||||
|             wait_until_writeable(FLUXENGINE_DATA_IN_EP_NUM); | ||||
|             USBFS_LoadInEP(FLUXENGINE_DATA_IN_EP_NUM, dma_buffer[dma_reading_from_td], BUFFER_SIZE); | ||||
|             count++; | ||||
|             dma_reading_from_td = NEXT_BUFFER(dma_reading_from_td); | ||||
|         } | ||||
|     } | ||||
| abort:; | ||||
|     bool saved_dma_underrun = dma_underrun; | ||||
|  | ||||
|     donecrunch(&cs); | ||||
|     /* Terminate the transfer (all transfers are an exact number of fragments). */ | ||||
|     wait_until_writeable(FLUXENGINE_DATA_IN_EP_NUM); | ||||
|     /* If there's a complete packet waiting, send it. */ | ||||
|     if (cs.outputlen != BUFFER_SIZE) | ||||
|     { | ||||
|         USBFS_LoadInEP(FLUXENGINE_DATA_IN_EP_NUM, usb_buffer, BUFFER_SIZE); | ||||
|         wait_until_writeable(FLUXENGINE_DATA_IN_EP_NUM); | ||||
|     } | ||||
|     if ((cs.outputlen != 0) && (cs.outputlen != BUFFER_SIZE)) | ||||
|     { | ||||
|         /* If there's a partial packet waiting, send it; this will also terminate the transfer. */ | ||||
|         USBFS_LoadInEP(FLUXENGINE_DATA_IN_EP_NUM, usb_buffer, BUFFER_SIZE-cs.outputlen); | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         /* Otherwise just terminate the transfer. */ | ||||
|         USBFS_LoadInEP(FLUXENGINE_DATA_IN_EP_NUM, NULL, 0); | ||||
|     } | ||||
|     USBFS_LoadInEP(FLUXENGINE_DATA_IN_EP_NUM, NULL, 0); | ||||
|     wait_until_writeable(FLUXENGINE_DATA_IN_EP_NUM); | ||||
|     deinit_dma(); | ||||
|  | ||||
| @@ -562,37 +537,18 @@ static void cmd_write(struct write_frame* f) | ||||
|  | ||||
|     init_replay_dma(); | ||||
|     bool writing = false; /* to the disk */ | ||||
|     bool finished = false; | ||||
|     int packets = f->bytes_to_write / FRAME_SIZE; | ||||
|     bool finished = (packets == 0); | ||||
|     int count_written = 0; | ||||
|     int count_read = 0; | ||||
|     int packetwaiting = 0; | ||||
|     dma_writing_to_td = 0; | ||||
|     dma_reading_from_td = -1; | ||||
|     dma_underrun = false; | ||||
|  | ||||
|     crunch_state_t cs = {}; | ||||
|     cs.outputlen = BUFFER_SIZE; | ||||
|     USBFS_EnableOutEP(FLUXENGINE_DATA_OUT_EP_NUM); | ||||
|      | ||||
|     int old_reading_from_td = -1; | ||||
|     for (;;) | ||||
|     { | ||||
|         CyWdtClear(); | ||||
|  | ||||
|         /* Make sure that we always have a USB read in progress whenever possible. */ | ||||
|          | ||||
|         if (!finished && !packetwaiting) | ||||
|         { | ||||
|             /* There is no read in progress; has data arrived in the external USB buffer? */ | ||||
|              | ||||
|             if (USBFS_GetEPState(FLUXENGINE_DATA_OUT_EP_NUM) == USBFS_OUT_BUFFER_FULL) | ||||
|             { | ||||
|                 /* Yes, data has arrived, so initiate the copy. */ | ||||
|                  | ||||
|                 packetwaiting = USBFS_ReadOutEP(FLUXENGINE_DATA_OUT_EP_NUM, usb_buffer, FRAME_SIZE); | ||||
|             } | ||||
|         } | ||||
|         //CyWdtClear(); | ||||
|  | ||||
|         /* Read data from USB into the buffers. */ | ||||
|          | ||||
| @@ -601,59 +557,22 @@ static void cmd_write(struct write_frame* f) | ||||
|             if (writing && (dma_underrun || index_irq)) | ||||
|                 goto abort; | ||||
|              | ||||
|             /* Read crunched data, if necessary. */ | ||||
|              | ||||
|             if (cs.inputlen == 0) | ||||
|             uint8_t* buffer = dma_buffer[dma_writing_to_td]; | ||||
|             if (finished) | ||||
|             { | ||||
|                 if (finished) | ||||
|                 { | ||||
|                     /* There's no more data to read, so fake some. */ | ||||
|                      | ||||
|                     for (int i=0; i<BUFFER_SIZE; i++) | ||||
|                         xfer_buffer[i+0] = 0x7f; | ||||
|                     cs.inputptr = xfer_buffer; | ||||
|                     cs.inputlen = BUFFER_SIZE; | ||||
|                 } | ||||
|                 else if (packetwaiting) | ||||
|                 { | ||||
|                     /* There's a USB read into usb_buffer in progress, so check if it's finished. */ | ||||
|                      | ||||
|                     if (USBFS_GetEPState(FLUXENGINE_DATA_OUT_EP_NUM) == USBFS_OUT_BUFFER_EMPTY) | ||||
|                     { | ||||
|                         /* It's done, so copy out the data. */ | ||||
|                          | ||||
|                         memcpy(xfer_buffer, usb_buffer, FRAME_SIZE); | ||||
|                         cs.inputptr = xfer_buffer; | ||||
|                         cs.inputlen = packetwaiting; | ||||
|  | ||||
|                         count_read++; | ||||
|                         if ((packetwaiting < FRAME_SIZE) || (count_read == packets)) | ||||
|                             finished = true; | ||||
|                         else | ||||
|                         { | ||||
|                             /* Wait for more USB data to show up. */ | ||||
|                              | ||||
|                             packetwaiting = 0; | ||||
|                             USBFS_EnableOutEP(FLUXENGINE_DATA_OUT_EP_NUM); | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|                 /* There's no more data to read, so fake some. */ | ||||
|                  | ||||
|                 memset(buffer, 0x3f, BUFFER_SIZE); | ||||
|             } | ||||
|              | ||||
|             /* If there *is* data waiting in the buffer, uncrunch it. */ | ||||
|              | ||||
|             if (cs.inputlen != 0) | ||||
|             else | ||||
|             { | ||||
|                 cs.outputptr = dma_buffer[dma_writing_to_td] + BUFFER_SIZE - cs.outputlen; | ||||
|                 uncrunch(&cs); | ||||
|                 if (cs.outputlen == 0) | ||||
|                 { | ||||
|                     /* Completed a DMA buffer; queue it for writing. */ | ||||
|                      | ||||
|                     dma_writing_to_td = NEXT_BUFFER(dma_writing_to_td); | ||||
|                     cs.outputlen = BUFFER_SIZE; | ||||
|                 } | ||||
|                 (void) usb_read(FLUXENGINE_DATA_OUT_EP_NUM, buffer); | ||||
|                 count_read++; | ||||
|                  | ||||
|                 if (count_read == packets) | ||||
|                     finished = true; | ||||
|             } | ||||
|             dma_writing_to_td = NEXT_BUFFER(dma_writing_to_td); | ||||
|              | ||||
|             /* Once all the buffers are full, start writing. */ | ||||
|              | ||||
| @@ -693,7 +612,6 @@ static void cmd_write(struct write_frame* f) | ||||
|         } | ||||
|     } | ||||
| abort: | ||||
|     print("done %d %d", dma_reading_from_td, dma_writing_to_td); | ||||
|     SEQUENCER_DMA_FINISHED_IRQ_Disable(); | ||||
|  | ||||
|     SEQUENCER_CONTROL_Write(1); /* reset */ | ||||
| @@ -713,27 +631,21 @@ abort: | ||||
|          * easier than trying to terminate the connection. */ | ||||
|         while (count_read != packets) | ||||
|         { | ||||
|             if (USBFS_GetEPState(FLUXENGINE_DATA_OUT_EP_NUM) == USBFS_OUT_BUFFER_FULL) | ||||
|             { | ||||
|                 int length = usb_read(FLUXENGINE_DATA_OUT_EP_NUM, usb_buffer); | ||||
|                 if (length < FRAME_SIZE) | ||||
|                     break; | ||||
|                 USBFS_EnableOutEP(FLUXENGINE_DATA_OUT_EP_NUM); | ||||
|                 count_read++; | ||||
|             } | ||||
|             (void) usb_read(FLUXENGINE_DATA_OUT_EP_NUM, usb_buffer); | ||||
|             count_read++; | ||||
|         } | ||||
|         USBFS_DisableOutEP(FLUXENGINE_DATA_OUT_EP_NUM); | ||||
|     } | ||||
|      | ||||
|     deinit_dma(); | ||||
|     print("write finished"); | ||||
|      | ||||
|     if (dma_underrun) | ||||
|     { | ||||
|         print("underrun!"); | ||||
|         send_error(F_ERROR_UNDERRUN); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     print("success"); | ||||
|     DECLARE_REPLY_FRAME(struct any_frame, F_FRAME_WRITE_REPLY); | ||||
|     send_reply((struct any_frame*) &r); | ||||
| } | ||||
| @@ -761,6 +673,10 @@ static void cmd_erase(struct erase_frame* f) | ||||
|  | ||||
| static void cmd_set_drive(struct set_drive_frame* f) | ||||
| { | ||||
|     if (drive0_present && !drive1_present) | ||||
|         f->drive = 0; | ||||
|     if (drive1_present && !drive0_present) | ||||
|         f->drive = 1; | ||||
|     set_drive_flags(f); | ||||
|      | ||||
|     DECLARE_REPLY_FRAME(struct any_frame, F_FRAME_SET_DRIVE_REPLY); | ||||
| @@ -914,6 +830,21 @@ static void handle_command(void) | ||||
|     } | ||||
| } | ||||
|  | ||||
| static void detect_drives(void) | ||||
| { | ||||
|     current_drive_flags.drive = 0; | ||||
|     start_motor(); | ||||
|     drive0_present = home(); | ||||
|     stop_motor(); | ||||
|      | ||||
|     current_drive_flags.drive = 1; | ||||
|     start_motor(); | ||||
|     drive1_present = home(); | ||||
|     stop_motor(); | ||||
|      | ||||
|     print("drive 0: %s drive 1: %s", drive0_present ? "yes" : "no", drive1_present ? "yes" : "no"); | ||||
| } | ||||
|  | ||||
| int main(void) | ||||
| { | ||||
|     CyGlobalIntEnable; | ||||
| @@ -927,11 +858,11 @@ int main(void) | ||||
|     DRIVESELECT_REG_Write(0); | ||||
|     UART_Start(); | ||||
|     USBFS_Start(0, USBFS_DWR_VDDD_OPERATION); | ||||
|     USBFS_DisableOutEP(FLUXENGINE_DATA_OUT_EP_NUM); | ||||
|      | ||||
|     detect_drives(); | ||||
|     CyWdtStart(CYWDT_1024_TICKS, CYWDT_LPMODE_DISABLED); | ||||
|      | ||||
|     /* UART_PutString("GO\r"); */ | ||||
|  | ||||
|     for (;;) | ||||
|     { | ||||
|         CyWdtClear(); | ||||
| @@ -947,7 +878,7 @@ int main(void) | ||||
|         { | ||||
|             print("Waiting for USB..."); | ||||
|             while (!USBFS_GetConfiguration()) | ||||
|                 ; | ||||
|                 CyWdtClear(); | ||||
|             print("USB ready"); | ||||
|             USBFS_EnableOutEP(FLUXENGINE_CMD_OUT_EP_NUM); | ||||
|         } | ||||
|   | ||||
							
								
								
									
										2
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								Makefile
									
									
									
									
									
								
							| @@ -39,7 +39,7 @@ CFLAGS += -Ilib -Idep/fmt -Iarch | ||||
| export OBJDIR = .obj | ||||
|  | ||||
| all: .obj/build.ninja | ||||
| 	@ninja -f .obj/build.ninja -v | ||||
| 	@ninja -f .obj/build.ninja | ||||
|  | ||||
| clean: | ||||
| 	@echo CLEAN | ||||
|   | ||||
							
								
								
									
										15
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										15
									
								
								README.md
									
									
									
									
									
								
							| @@ -24,17 +24,10 @@ 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> | ||||
|  | ||||
| **Important note.** On 2019-02-09 I did a hardware redesign and moved the pins on | ||||
| the board. Sorry for the inconvenience, but it means you don't have to modify | ||||
| the board any more to make it work. If you built the hardware prior to then, | ||||
| you'll need to adjust it. | ||||
|  | ||||
| **Another important note.** On 2019-07-03 I've revamped the build process and | ||||
| the (command line) user interface. It should be much nicer now, not least in | ||||
| that there's a single client binary with all the functionality in it. The | ||||
| interface is a little different, but not much. The build process is now | ||||
| better (simpler). See [the building](doc/building.md) and | ||||
| [using](doc/using.md) pages for more details. | ||||
| **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 | ||||
| inconvenience. | ||||
|  | ||||
| Where? | ||||
| ------ | ||||
|   | ||||
| @@ -20,6 +20,8 @@ public: | ||||
|  | ||||
|     RecordType advanceToNextRecord(); | ||||
|     void decodeSectorRecord(); | ||||
|  | ||||
| 	std::set<unsigned> requiredSectors(Track& track) const; | ||||
| }; | ||||
|  | ||||
| class AmigaEncoder : public AbstractEncoder | ||||
|   | ||||
| @@ -32,6 +32,8 @@ AbstractDecoder::RecordType AmigaDecoder::advanceToNextRecord() | ||||
| void AmigaDecoder::decodeSectorRecord() | ||||
| { | ||||
|     const auto& rawbits = readRawBits(AMIGA_RECORD_SIZE*16); | ||||
| 	if (rawbits.size() < (AMIGA_RECORD_SIZE*16)) | ||||
| 		return; | ||||
|     const auto& rawbytes = toBytes(rawbits).slice(0, AMIGA_RECORD_SIZE*2); | ||||
|     const auto& bytes = decodeFmMfm(rawbits).slice(0, AMIGA_RECORD_SIZE); | ||||
|  | ||||
| @@ -56,3 +58,10 @@ void AmigaDecoder::decodeSectorRecord() | ||||
|     _sector->data.writer().append(amigaDeinterleave(ptr, 512)).append(recoveryinfo); | ||||
|     _sector->status = (gotdatachecksum == wanteddatachecksum) ? Sector::OK : Sector::BAD_CHECKSUM; | ||||
| } | ||||
|  | ||||
| std::set<unsigned> AmigaDecoder::requiredSectors(Track& track) const | ||||
| { | ||||
| 	static std::set<unsigned> sectors = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; | ||||
| 	return sectors; | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -9,7 +9,8 @@ | ||||
| #define BROTHER_DATA_RECORD_CHECKSUM     3 | ||||
| #define BROTHER_DATA_RECORD_ENCODED_SIZE 415 | ||||
|  | ||||
| #define BROTHER_TRACKS_PER_DISK          78 | ||||
| #define BROTHER_TRACKS_PER_240KB_DISK    78 | ||||
| #define BROTHER_TRACKS_PER_120KB_DISK    39 | ||||
| #define BROTHER_SECTORS_PER_TRACK        12 | ||||
|  | ||||
| class Sector; | ||||
| @@ -28,8 +29,16 @@ public: | ||||
| class BrotherEncoder : public AbstractEncoder | ||||
| { | ||||
| public: | ||||
| 	BrotherEncoder(int format, int bias): | ||||
| 		_format(format), | ||||
| 		_bias(bias) | ||||
| 	{} | ||||
|  | ||||
| 	virtual ~BrotherEncoder() {} | ||||
|  | ||||
| private: | ||||
| 	int _format; | ||||
| 	int _bias; | ||||
| public: | ||||
|     std::unique_ptr<Fluxmap> encode(int physicalTrack, int physicalSide, const SectorSet& allSectors); | ||||
| }; | ||||
|   | ||||
| @@ -129,9 +129,25 @@ static int charToInt(char c) | ||||
| std::unique_ptr<Fluxmap> BrotherEncoder::encode( | ||||
| 	int physicalTrack, int physicalSide, const SectorSet& allSectors) | ||||
| { | ||||
| 	if ((physicalTrack < 0) || (physicalTrack >= BROTHER_TRACKS_PER_DISK) | ||||
|         || (physicalSide != 0)) | ||||
| 	int logicalTrack; | ||||
| 	if (physicalSide != 0) | ||||
| 		return std::unique_ptr<Fluxmap>(); | ||||
| 	physicalTrack -= _bias; | ||||
| 	switch (_format) | ||||
| 	{ | ||||
| 		case 120: | ||||
| 			if ((physicalTrack < 0) || (physicalTrack >= (BROTHER_TRACKS_PER_120KB_DISK*2)) | ||||
| 					|| (physicalTrack & 1)) | ||||
| 				return std::unique_ptr<Fluxmap>(); | ||||
| 			logicalTrack = physicalTrack/2; | ||||
| 			break; | ||||
|  | ||||
| 		case 240: | ||||
| 			if ((physicalTrack < 0) || (physicalTrack >= BROTHER_TRACKS_PER_240KB_DISK)) | ||||
| 				return std::unique_ptr<Fluxmap>(); | ||||
| 			logicalTrack = physicalTrack; | ||||
| 			break; | ||||
| 	} | ||||
|  | ||||
| 	int bitsPerRevolution = 200000.0 / clockRateUs; | ||||
| 	const std::string& skew = sectorSkew.get(); | ||||
| @@ -146,10 +162,10 @@ std::unique_ptr<Fluxmap> BrotherEncoder::encode( | ||||
| 		double dataMs = headerMs + postHeaderSpacingMs; | ||||
| 		unsigned dataCursor = dataMs*1e3 / clockRateUs; | ||||
|  | ||||
| 		const auto& sectorData = allSectors.get(physicalTrack, 0, sectorId); | ||||
| 		const auto& sectorData = allSectors.get(logicalTrack, 0, sectorId); | ||||
|  | ||||
| 		fillBitmapTo(bits, cursor, headerCursor, { true, false }); | ||||
| 		write_sector_header(bits, cursor, physicalTrack, sectorId); | ||||
| 		write_sector_header(bits, cursor, logicalTrack, sectorId); | ||||
| 		fillBitmapTo(bits, cursor, dataCursor, { true, false }); | ||||
| 		write_sector_data(bits, cursor, sectorData->data); | ||||
| 	} | ||||
|   | ||||
| @@ -57,11 +57,11 @@ const FluxPattern FM_TRS80DAM1_PATTERN(16, 0xf56b); | ||||
|  | ||||
| /*  | ||||
|  * TRS80DAM2 record: | ||||
|  * flux:   XXXX-X-X-XX-XXX- = 0xf56c | ||||
|  * flux:   XXXX-X-X-XX-XXX- = 0xf56e | ||||
|  * clock:  X X - - - X X X  = 0xc7 | ||||
|  * data:    X X X X X - X - = 0xfa | ||||
|  */ | ||||
| const FluxPattern FM_TRS80DAM2_PATTERN(16, 0xf56c); | ||||
| const FluxPattern FM_TRS80DAM2_PATTERN(16, 0xf56e); | ||||
|  | ||||
| /* MFM record separator: | ||||
|  * 0xA1 is: | ||||
|   | ||||
| @@ -205,6 +205,7 @@ std::unique_ptr<Fluxmap> IbmEncoder::encode( | ||||
|  | ||||
| 			Bytes truncatedData = sectorData->data.slice(0, _parameters.sectorSize); | ||||
| 			bw += truncatedData; | ||||
| 			hexdump(std::cout, data.slice(0, 64)); | ||||
| 			uint16_t crc = crc16(CCITT_POLY, data); | ||||
| 			bw.write_be16(crc); | ||||
|  | ||||
|   | ||||
| @@ -32,18 +32,24 @@ struct IbmIdam | ||||
| class IbmDecoder : public AbstractDecoder | ||||
| { | ||||
| public: | ||||
|     IbmDecoder(unsigned sectorBase, bool ignoreSideByte=false): | ||||
|     IbmDecoder(unsigned sectorBase, bool ignoreSideByte=false, | ||||
| 			const std::set<unsigned> requiredSectors=std::set<unsigned>()): | ||||
|         _sectorBase(sectorBase), | ||||
|         _ignoreSideByte(ignoreSideByte) | ||||
|         _ignoreSideByte(ignoreSideByte), | ||||
| 		_requiredSectors(requiredSectors) | ||||
|     {} | ||||
|  | ||||
|     RecordType advanceToNextRecord(); | ||||
|     void decodeSectorRecord(); | ||||
|     void decodeDataRecord(); | ||||
|  | ||||
| 	std::set<unsigned> requiredSectors(Track& track) const | ||||
| 	{ return _requiredSectors; } | ||||
|  | ||||
| private: | ||||
|     unsigned _sectorBase; | ||||
|     bool _ignoreSideByte; | ||||
| 	std::set<unsigned> _requiredSectors; | ||||
|     unsigned _currentSectorSize; | ||||
|     unsigned _currentHeaderLength; | ||||
| }; | ||||
|   | ||||
| @@ -184,3 +184,25 @@ void MacintoshDecoder::decodeDataRecord() | ||||
|     _sector->data.clear(); | ||||
|     _sector->data.writer().append(userData.slice(12, 512)).append(userData.slice(0, 12)); | ||||
| } | ||||
|  | ||||
| std::set<unsigned> MacintoshDecoder::requiredSectors(Track& track) const | ||||
| { | ||||
| 	int count; | ||||
| 	if (track.physicalTrack < 16) | ||||
| 		count = 12; | ||||
| 	else if (track.physicalTrack < 32) | ||||
| 		count = 11; | ||||
| 	else if (track.physicalTrack < 48) | ||||
| 		count = 10; | ||||
| 	else if (track.physicalTrack < 64) | ||||
| 		count = 9; | ||||
| 	else | ||||
| 		count = 8; | ||||
|  | ||||
| 	std::set<unsigned> sectors; | ||||
| 	while (count--) | ||||
| 		sectors.insert(count); | ||||
| 	return sectors; | ||||
| } | ||||
|  | ||||
|  | ||||
|   | ||||
| @@ -18,6 +18,8 @@ public: | ||||
|     RecordType advanceToNextRecord(); | ||||
|     void decodeSectorRecord(); | ||||
|     void decodeDataRecord(); | ||||
|  | ||||
| 	std::set<unsigned> requiredSectors(Track& track) const; | ||||
| }; | ||||
|  | ||||
| #endif | ||||
|   | ||||
							
								
								
									
										182
									
								
								doc/building.md
									
									
									
									
									
								
							
							
						
						
									
										182
									
								
								doc/building.md
									
									
									
									
									
								
							| @@ -25,6 +25,8 @@ This is the physical stuff you'll need. | ||||
|     connector](https://eu.mouser.com/ProductDetail/Amphenol-FCI/86130342114345E1LF?qs=%2Fha2pyFadug%252BpMTyxmFhglPPVKuWXYuFpPNgq%252BsrzhDnXxo8B28k7UCGc7F%2FXjsi) | ||||
|     (or one of the other myriad compatible connectors; there's a billion). | ||||
|  | ||||
|   - A floppy drive cable, preferably one with two connectors and a twist. | ||||
|  | ||||
|   - A suitable power supply. 3.5" floppy drives use 5V at about an amp | ||||
|     (usually less) --- sadly, too much to power from USB. 5.25" floppy drives | ||||
|     also require 12V. An old but decent quality PC power supply is ideal, as | ||||
| @@ -48,7 +50,7 @@ All you need to do is attach your chosen connector to the board. You'll need | ||||
| to make sure that pin 2 on the cable is connected to pin 2.7 on the board, | ||||
| and pin 34 to pin 1.7 on the board (and of course all the ones in between). | ||||
| Apart from grounding the board (see below), this is literally all there is to | ||||
| it. | ||||
| it. The actual pinout is described in detail below. | ||||
|  | ||||
| The pads are small, but soldering them isn't too bad with a needle-nosed | ||||
| soldering iron tip. | ||||
| @@ -173,6 +175,7 @@ pattern. Press and hold the little button near the light for five seconds | ||||
| until the light stays solidly on. Now you should be able to acquire | ||||
| the port and proceed normally. | ||||
|  | ||||
|  | ||||
| ## Building the client | ||||
|  | ||||
| The client software is where the intelligence, such as it is, is. It's pretty | ||||
| @@ -181,12 +184,12 @@ 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`. | ||||
|   - 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`. | ||||
| 	`mingw-w64-i686-sqlite3`, `mingw-w64-i686-zlib`, `mingw-w64-i686-gcc`. | ||||
|  | ||||
| These lists are not necessarily exhaustive --- plaese [get in | ||||
| These lists are not necessarily exhaustive --- please [get in | ||||
| touch](https://github.com/davidgiven/fluxengine/issues/new) if I've missed | ||||
| anything. | ||||
|  | ||||
| @@ -197,11 +200,176 @@ dependencies and you should be able to put it anywhere. | ||||
| If it doesn't build, please [get in | ||||
| touch](https://github.com/davidgiven/fluxengine/issues/new). | ||||
|  | ||||
|  | ||||
| ## Connecting it up | ||||
|  | ||||
| You should now have a working board, so it's time to test it. | ||||
|  | ||||
|   1. Plug the motherboard end of your floppy disk cable into the FluxEngine. | ||||
|       | ||||
|      The **red stripe goes on the right**. The **lower set of | ||||
|      holes connect to the board**. See the pinout below. | ||||
|  | ||||
|      If you're using header pins, the upper row of holes in the connector | ||||
|      should overhang the edge of the board. If you're using a floppy drive | ||||
|      motherboard connector, you're golden, of course (unless you have one of | ||||
|      those annoying unkeyed cables, or have accidentally soldered the | ||||
|      connector on in the wrong place --- don't laugh, I've done it.) | ||||
|  | ||||
|   2. Plug the drive end of your floppy disk cable into the drive (or drives). | ||||
|  | ||||
|      Floppy disk cables typically have [two pairs of floppy disk drive | ||||
|      connectors with a twist between | ||||
|      them](http://www.nullmodem.com/Floppy.htm). (Each pair has one connector | ||||
|      for a 3.5" drive and a different one for a 5.25" drive.) (Some cables | ||||
|      are cheap and just have the 3.5" connectors. Some are _very_ cheap and | ||||
|      have a single 3.5" connector, after the twist.) | ||||
|       | ||||
|      If you have **two** drives, plug them into both connectors. FluxEngine, | ||||
|      sadly, non-standard disk numbering (there are reasons). Drive 0 is the | ||||
|      one nearest the motherboard; that is, before the twist. Drive 1 is the | ||||
|      one at the end of the cable; that is, after the twist. Drive 0 is the | ||||
|      default. You can tell the client to select drive 1 by using `-s :d=1`. | ||||
|  | ||||
|      If you have **one** drive, you may plug it into _either_ connector. | ||||
|      FluxEngine will autodetect it and treat it as drive 0. However, you'll | ||||
|      get the most reliable electrical signal if you plug it in at the end of | ||||
|      the cable. | ||||
|  | ||||
|      **A note on termination:** some 5.25" drives require jumper configuration | ||||
|      to tell them whether they're at the end of the cable or in the middle of | ||||
|      the cable. 3.5" drives don't, and my 5.25" drives don't, so I can't | ||||
|      advise there. Consult your drive datasheet for details. | ||||
|  | ||||
|   3. **Important.** Make sure that no disk you care about is in the drive. | ||||
| 	 (Because if your wiring is wrong and a disk is inserted, you'll corrupt | ||||
| 	 it.) | ||||
|  | ||||
|   4. Connect the floppy drive to power. Nothing should happen. If you've | ||||
| 	 connected something in backwards, you'll see the drive light up, the motor | ||||
| 	 start, and if you didn't take the disk out, one track has just been wiped. | ||||
| 	 If this happens, check your wiring. | ||||
|  | ||||
|   5. Strip off the little piece of protective plastic on the USB socket on the | ||||
| 	 board --- the little socket at the end, not the big programmer plug. | ||||
|  | ||||
|   6. Connect the FluxEngine to your PC via USB. | ||||
|  | ||||
|   7. Insert a scratch disk and do `fluxengine rpm` from the shell. The motor | ||||
|      should work and it'll tell you that the disk is spinning at about 300 | ||||
|      rpm for a 3.5" disk, or 360 rpm for a 5.25" disk. If it doesn't, please | ||||
|      [get in touch](https://github.com/davidgiven/fluxengine/issues/new). | ||||
|  | ||||
|   8. Do `fluxengine test bandwidth` from the shell. It'll measure your USB | ||||
| 	 bandwidth. Ideally you should be getting above 800kB/s in both directions. | ||||
| 	 FluxEngine needs about 300kB/s for a DD disk and about 600kB/s for a HD | ||||
| 	 disk, so if you're getting less than this, try a different USB port. | ||||
|  | ||||
|   9. Insert a standard PC formatted floppy disk into the drive (probably a good | ||||
|      idea to remove the old disk first). Then do `fluxengine read ibm`. It | ||||
|      should read the disk, emitting copious diagnostics, and spit out an | ||||
|      `ibm.img` file containing the decoded disk image (either 1440kB or 720kB | ||||
|      depending). | ||||
|  | ||||
|  10. Profit! | ||||
|  | ||||
| ## Technical details | ||||
|  | ||||
| The board pinout and the way it's connected to the floppy bus is described | ||||
| below. | ||||
|  | ||||
| ```ditaa | ||||
| :-E -s 0.75 | ||||
|                  +-----+ | ||||
|                  ||||||| | ||||
|             +----+-----+----+ | ||||
|             +cAAA           + | ||||
|             +  Debug board  + | ||||
|             +----+-----+----+ | ||||
|             + GND|cDDD | VDD+   | ||||
|             +----+     +----+ | ||||
| INDEX300 ---+ 3.0|     | GND+--------------------------+ | ||||
|             +----+     +----+                 +--+--+  | | ||||
| INDEX360 ---+ 3.1|     | 1.7+------ DISKCHG --+34+33+--+ | ||||
|             +----+     +----+                 +--+--+ | ||||
|             + 3.2|     | 1.6+------- SIDE1 ---+32+31+ | ||||
|             +----+     +----+                 +--+--+ | ||||
|             + 3.3|     | 1.5+------- RDATA ---+30+29+ | ||||
|             +----+     +----+                 +--+--+ | ||||
|             + 3.4|     | 1.4+-------- WPT ----+28+27+ | ||||
|             +----+     +----+                 +--+--+ | ||||
|             + 3.5|     | 1.3+------- TRK00 ---+26+25+ | ||||
|             +----+     +----+                 +--+--+ | ||||
|             + 3.6|     | 1.2+------- WGATE ---+24+23+ | ||||
|             +----+     +----+                 +--+--+ | ||||
|             + 3.7|     | 1.1+------- WDATA ---+22+21+ | ||||
|             +----+     +----+                 +--+--+ | ||||
|             +15.0|     | 1.0+------- STEP ----+20+19+ | ||||
|             +----+     +----+                 +--+--+ | ||||
|             +15.1|     |12.0+-------- DIR ----+18+17+ | ||||
|             +----+     +----+                 +--+--+ | ||||
|             +15.2|     |12.1+------- MOTEB ---+16+15+ | ||||
|             +----+     +----+                 +--+--+ | ||||
|             +15.3|     |12.2+------- DRVSA ---+14+13+ | ||||
|             +----+     +----+                 +--+--+ | ||||
|             +15.4|     |12.3+------- DRVSB ---+12+11+ | ||||
|             +----+     +----+                 +--+--+ | ||||
|             +15.5|     |12.4+------- MOTEA ---+10+9 + | ||||
|             +----+     +----+                 +--+--+ | ||||
|             + 0.0|     |12.5+------- INDEX ---+8 +7 + | ||||
|             +----+     +----+                 +--+--+ | ||||
|             + 0.1|     |12.6+-------- n/c ----+6 +5 + | ||||
|             +----+     +----+                 +--+--+ | ||||
|             + 0.2|     |12.7+- TX --- n/c ----+4 +3 + | ||||
|             +----+     +----+                 +--+--+ | ||||
|             + 0.3|     | 2.7+------- REDWC ---+2 +1 + | ||||
|             +----+     +----+                 +--+--+ | ||||
|             + 0.4|     | 2.6+   | ||||
|             +----+     +----+                FDD socket | ||||
|             + 0.5|     | 2.5+   | ||||
|             +----+     +----+ | ||||
|             + 0.6|     | 2.4+    TX: debug UART from board | ||||
|             +----+     +----+ | ||||
|             + 0.7|     | 2.3+ | ||||
|             +----+     +----+ | ||||
|             + RST|     | 2.2+   | ||||
|             +----+     +----+ | ||||
|             + GND|     | 2.1+   | ||||
|             +----+ USB +----+ | ||||
|             + VDD+-----+ 2.0+   | ||||
|             +----+-----+----+ | ||||
|                PSoC5 board | ||||
| ``` | ||||
|  | ||||
| Notes: | ||||
|  | ||||
|   - `TX` is the debug UART port. It's on pin 12.7 because the board routes it | ||||
|   to the USB serial port on the programmer, so you can get debug information | ||||
|   from the FluxEngine by just plugging the programming end into a USB port | ||||
|   and using a serial terminal at 115200 baud. If you solder a floppy drive | ||||
|   connector on, then it'll end up connected to pin 4 of the floppy drive bus, | ||||
|   which is usually not connected. It's possible that some floppy drives do, | ||||
|   in fact, use this pin. You may wish to remove pin 4 from the floppy drive | ||||
|   socket before attaching it to the FluxEngine to make sure that this pin is | ||||
|   not connected; however, so far I have not found any drives for which this | ||||
|   is necessary. If you do find one, _please_ [get in | ||||
|   touch](https://github.com/davidgiven/fluxengine/issues/new) so I can | ||||
|   document it. | ||||
|  | ||||
|   - The `GND` pin only really needs to be connected to one of the floppy bus | ||||
|   ground pins; pin 33 is the closest. For extra safety, you can bridge all | ||||
|   the odd numbered pins together and ground them all if you like. | ||||
|  | ||||
|   - `INDEX300` and `INDEX360` are optional output pins which generate fake | ||||
|   timing pulses for 300 and 360 RPM drives. These are useful for certain | ||||
|   rather exotic things. See the section on flippy disks [in the FAQ](faq.md) | ||||
|   for more details; you can normally ignore these. | ||||
|  | ||||
| ## Next steps | ||||
|  | ||||
| The board's now assembled and programmed. Plug it into your drive, strip the | ||||
| plastic off the little USB connector and plug that into your computer, and | ||||
| you're ready to start using it. | ||||
| You should now be ready to go. You'll want to read [the client | ||||
| documentation](using.md) for information about how to actually do interesting | ||||
| things. | ||||
|  | ||||
| I _do_ make updates to the firmware whenever necessary, so you may need to | ||||
| reprogram it at intervals; you may want to take this into account if you | ||||
|   | ||||
| @@ -14,10 +14,12 @@ Apparently about 20% of Brother word processors have alignment issues which | ||||
| means that the disks can't be read by FluxEngine (because the tracks on the | ||||
| disk don't line up with the position of the head in a PC drive). The word | ||||
| processors themselves solved this by microstepping until they found where the | ||||
| real track is, but normal PC drives aren't capable of doing this. | ||||
| Particularly with the 120kB disks, you might want to fiddle with the start | ||||
| track (e.g. `:t=0-79x2`) to get a clean read. Keep an eye on the bad sector | ||||
| map that's dumped at the end of a read. | ||||
| real track is, but normal PC drives aren't capable of doing this.  Particularly | ||||
| with the 120kB disks, you might want to fiddle with the start track (e.g. | ||||
| `:t=0-79x2`) to get a clean read. Keep an eye on the bad sector map that's | ||||
| dumped at the end of a read. My word processor likes to put logical track 0 on | ||||
| physical track 3, which means that logical track 77 is on physical track 80; | ||||
| luckily my PC drive can access track 80. | ||||
|  | ||||
| Using FluxEngine to *write* disks isn't a problem, so the | ||||
| simplest solution is to use FluxEngine to create a new disk, with the tracks | ||||
| @@ -30,7 +32,7 @@ If you find one of these misaligned disks then *please* [get in | ||||
| touch](https://github.com/davidgiven/fluxengine/issues/new); I want to | ||||
| investigate. | ||||
|  | ||||
| Reading discs | ||||
| Reading disks | ||||
| ------------- | ||||
|  | ||||
| Just do: | ||||
| @@ -41,7 +43,7 @@ fluxengine read brother | ||||
|  | ||||
| You should end up with a `brother.img` which is 239616 bytes long. | ||||
|  | ||||
| Writing discs | ||||
| Writing disks | ||||
| ------------- | ||||
|  | ||||
| Just do: | ||||
| @@ -53,6 +55,27 @@ fluxengine write brother | ||||
| ...and it'll write a `brother.img` file which is 239616 bytes long to the | ||||
| disk. (Use `-i` to specify a different input filename.) | ||||
|  | ||||
| Dealing with misaligned disks | ||||
| ----------------------------- | ||||
|  | ||||
| While FluxEngine can't read misaligned disks directly, Brother word processors | ||||
| _can_. If you have access to a compatible word processor, there's a fairly | ||||
| simple workaround to allow you to extract the data: | ||||
|  | ||||
|   1. Format a disk using FluxEngine (by simply writing a blank filesystem image | ||||
| 	 to a disk). This will have the correct alignment to work on a PC drive. | ||||
|  | ||||
|   2. Use a word processor to copy the misaligned disk to the newly formatted | ||||
| 	 disk. The machine will happily adjust itself to both sets of alignments. | ||||
|  | ||||
|   3. Use FluxEngine to read the data off the correctly aligned disk. | ||||
|  | ||||
| I realise this is rather unsatisfactory, as the Brother hardware is becoming | ||||
| rarer and they cope rather badly with damaged disks, but this is a limitation | ||||
| of the hardware of normal PC drives. (It _is_ possible to deliberately misalign | ||||
| a drive to make it match up with a bad disk, but this is for experts only --- I | ||||
| wouldn't dare.) | ||||
|  | ||||
| Low level format | ||||
| ---------------- | ||||
|  | ||||
| @@ -60,14 +83,6 @@ The drive is a single-sided 3.5" drive spinning at not 300 rpm (I don't know | ||||
| the precise speed yet but FluxEngine doesn't care). The 240kB disks have 78 | ||||
| tracks and the 120kB disks have 39. | ||||
|  | ||||
| The Brother drive alignment is kinda variable; when you put the disk in the | ||||
| drive it seeks all the way to physical track 0 and then starts searching for | ||||
| something which looks like data. My machine likes to put logical track 0 on | ||||
| physical track 3. FluxEngine puts logical track 0 on physical track 0 for | ||||
| simplicity, which works fine (at least on my machine). If this doesn't work | ||||
| for you, [get in touch](https://github.com/davidgiven/fluxengine/issues/new); | ||||
| there are potential workarounds. | ||||
|  | ||||
| Each track has 12 256-byte sectors. The drive ignores the index hole so they're | ||||
| lined up all anyhow. As FluxEngine can only read from index to index, it | ||||
| actually reads two complete revolutions and reassembles the sectors from that. | ||||
| @@ -138,7 +153,8 @@ mcopy -i brother.img ::brother.doc linux.doc | ||||
| ``` | ||||
|  | ||||
| The word processor checks the media byte, unfortunately, so you'll need to | ||||
| change it back to 0x58 before writing an image to disk. | ||||
| change it back to 0x58 before writing an image to disk. Just run | ||||
| `brother240tool` on the image again and it will flip it back. | ||||
|  | ||||
| The file format is not WP-1, and currently remains completely unknown, | ||||
| although it's probably related. If anyone knows anything about this, please | ||||
|   | ||||
| @@ -41,19 +41,28 @@ of the disk image will vary depending on the format. | ||||
|  | ||||
| Configuration options you'll want include: | ||||
|  | ||||
|   - `--sector-id-base`: specifies the ID of the first sector; this defaults | ||||
|     to 1. Some formats (like the Acorn ones) start at 0. This can't be | ||||
|   - `--ibm-sector-id-base=N`: specifies the ID of the first sector; this defaults | ||||
| 	to 1. Some formats (like the Acorn ones) start at 0. This can't be | ||||
| 	autodetected because FluxEngine can't distinguish between a disk which | ||||
| 	starts at sector 1 and a disk which starts at sector 0 but all the sector | ||||
| 	0s are missing. | ||||
|  | ||||
|   - `--ignore-side-byte`: each sector header describes the location of the | ||||
|   - `--ibm-ignore-side-byte=true|false`: each sector header describes the location of the | ||||
| 	sector: sector ID, track and side. Some formats use the wrong side ID, so | ||||
| 	the sectors on side 1 are labelled as belonging to side 0. This causes | ||||
| 	FluxEngine to see duplicate sectors (as it can't distinguish between the | ||||
| 	two sides). This option tells FluxEngine to ignore the side byte completely | ||||
| 	and use the physical side instead. | ||||
|  | ||||
|   - `--ibm-required-sectors=range`: if you know how many sectors to expect per | ||||
| 	track, you can improve reads by telling FluxEngine what to expect here. If | ||||
| 	a track is read and a sector on this list is _not_ present, then FluxEngine | ||||
| 	assumes the read failed and will retry. This avoids the situation where | ||||
| 	FluxEngine can't tell the difference between a sector missing because it's | ||||
| 	bad or a sector missing because it was never written in the first place. If | ||||
| 	sectors are seen outside the range here, it will still be read. You can use | ||||
| 	the same syntax as for track specifiers: e.g. `0-9`, `0,1,2,3`, etc. | ||||
|  | ||||
|  | ||||
| Writing disks | ||||
| ------------- | ||||
|   | ||||
| @@ -22,19 +22,17 @@ FluxEngine, where a different datapath state machine thingy (the PSoC5LP has | ||||
| 24, all independently programmable) to interpret the bytecodes, generate a | ||||
| stream of pulses to the disk. | ||||
|  | ||||
| The bytecode format represents an interval between pulses as a byte, a pulse | ||||
| as a byte, and the index hole as a byte. Timer overflows are handled by | ||||
| sending multiple intervals in a row. However, the USB transport applies a | ||||
| simple compression system to this in order to get the USB bandwidth down to | ||||
| something manageable. | ||||
| The bytecode format is very simple with a six-bit interval since the previous | ||||
| event in the lower six bits and the top two bits are set of a pulse or an index | ||||
| hole (or both, or neither). | ||||
|  | ||||
| An HD floppy has a nominal pulse frequency of 500kHz, and we use a sample | ||||
| clock of 12MHz (every 83ns). This means that our 500kHz pulses will have an | ||||
| average interval of 24. This gives us more than enough resolution. At this | ||||
| speed, in the 200ms that a 3.5" disk takes to rotate, we will see about | ||||
| 100,000 pulses. Each one is encoded as two bytes, one for the interval and | ||||
| one to generate the pulse; so that revolution generates 200kB of data. | ||||
| (Extremely approximately. The actual figure is less.) | ||||
| 100,000 pulses. Each one is encoded as a single byte; so that revolution | ||||
| generates 100kB of data.  (Extremely approximately. The actual figure varies | ||||
| depending on what data is stored on the disk.) | ||||
|  | ||||
| (The clock needs to be absolutely rock solid or we get jitter which makes the | ||||
| data difficult to analyse, so 12 was chosen to be derivable from the | ||||
|   | ||||
							
								
								
									
										218
									
								
								doc/using.md
									
									
									
									
									
								
							
							
						
						
									
										218
									
								
								doc/using.md
									
									
									
									
									
								
							| @@ -1,78 +1,8 @@ | ||||
| Using a FluxEngine | ||||
| ================== | ||||
|  | ||||
| So you've [built the hardware](building.md)! What now? | ||||
|  | ||||
| ## Connecting it up | ||||
|  | ||||
| In order to do anything useful, you have to plug it in to a floppy disk drive (or two). | ||||
|  | ||||
|   1. Plug the motherboard end of your floppy disk cable into the FluxEngine. | ||||
|       | ||||
|      The **red stripe goes on the right**. The **lower set of | ||||
|      holes connect to the board**. (Pin 2 of the connector needs to connect | ||||
|      to pin 2.7 on the board.) | ||||
|  | ||||
|      If you're using header pins, the upper row of holes in the connector | ||||
|      should overhang the edge of the board. If you're using a floppy drive | ||||
|      motherboard connector, you're golden, of course (unless you have one of | ||||
|      those annoying unkeyed cables, or have accidentally soldered the | ||||
|      connector on in the wrong place --- don't laugh, I've done it.) | ||||
|  | ||||
|   2. Plug the drive end of your floppy disk cable into the drive (or drives). | ||||
|  | ||||
|      Floppy disk cables typically have [two pairs of floppy disk drive | ||||
|      connectors with a twist between | ||||
|      them](http://www.nullmodem.com/Floppy.htm). (Each pair has one connector | ||||
|      for a 3.5" drive and a different one for a 5.25" drive.) (Some cables | ||||
|      are cheap and just have the 3.5" connectors. Some are _very_ cheap and | ||||
|      have a single 3.5" connector, after the twist.) | ||||
|       | ||||
|      FluxEngine uses, sadly, non-standard disk numbering (there are reasons). | ||||
|      Drive 0 is the one nearest the motherboard; that is, before the twist. | ||||
|      Drive 1 is the one at the end of the cable; that is, after the twist. | ||||
|      Drive 0 is the default. If you only have one drive, remember to plug the | ||||
|      drive into the connector _before_ the twist. (Or use `-s :d=1` to select | ||||
|      drive 1 when working with disks.) | ||||
|  | ||||
|   3. **Important.** Make sure that no disk you care about is in the drive. | ||||
|      (Because if your wiring is wrong and a disk is inserted, you'll corrupt it.) | ||||
|  | ||||
|   4. Connect the floppy drive to power. Nothing should happen. If you've | ||||
|      connected something in backwards, you'll see the drive light up, the | ||||
|      motor start, and if you didn't take the disk out, one track has just | ||||
|      been wiped. If this happens, check your wiring. | ||||
|  | ||||
|   5. Connect the FluxEngine to your PC via USB --- using the little socket on | ||||
|      the board, not the big programmer plug. | ||||
|  | ||||
|   6. Insert a scratch disk and do `fluxengine rpm` from the shell. The motor | ||||
|      should work and it'll tell you that the disk is spinning at about 300 | ||||
|      rpm for a 3.5" disk, or 360 rpm for a 5.25" disk. If it doesn't, please | ||||
|      [get in touch](https://github.com/davidgiven/fluxengine/issues/new). | ||||
|  | ||||
|   7. Do `fluxengine test bandwidth` from the shell. It'll measure your USB | ||||
|      bandwidth. Ideally you should be getting above 900kB/s. FluxEngine needs | ||||
|      about 850kB/s, so if you're getting less than this, try a different USB | ||||
|      port. | ||||
|  | ||||
|   8. Insert a standard PC formatted floppy disk into the drive (probably a good | ||||
|      idea to remove the old disk first). Then do `fluxengine read ibm`. It | ||||
|      should read the disk, emitting copious diagnostics, and spit out an | ||||
|      `ibm.img` file containing the decoded disk image (either 1440kB or 720kB | ||||
|      depending). | ||||
|  | ||||
|   9. Profit! | ||||
|  | ||||
| ## Bonus hardware features | ||||
|  | ||||
| For advanced users, the board has a few extra signals which are useful for special purposes. | ||||
|  | ||||
|   - Pin 3[0] produces short pulses every 200ms. This is useful for spoofing | ||||
|     index signals to 300 RPM drives; for example, to read flippy disks. | ||||
|  | ||||
|   - Pin 3[1] is the same, but produces the pulses every 166ms; this works with | ||||
|     360 RPM drives. | ||||
| So you've [built the hardware](building.md), programmed and tested it! What | ||||
| now? | ||||
|  | ||||
| ## The programs | ||||
|  | ||||
| @@ -81,10 +11,33 @@ moving too quickly for the documentation to keep up. It does respond to | ||||
| `--help` or `help` depending on context. There are some common properties, | ||||
| described below. | ||||
|  | ||||
| ### Core concepts | ||||
|  | ||||
| FluxEngine fundamentally takes file system images and puts them on disk; or | ||||
| reads the disk and produces a file system image. | ||||
|  | ||||
| A file system image typically has the extension `.img`. It contains a | ||||
| sector-by-sector record of the _decoded_ data on the disk. For example, on a | ||||
| disk with 512 byte sectors, one sector will occupy 512 bytes. These are | ||||
| typically what you want in everyday life. | ||||
|  | ||||
| FluxEngine can also record the raw magnetic data on the disk into a file, which | ||||
| we call a _flux file_. This contains all the low-level data which the drive | ||||
| produced as the disk rotated. These are continuous streams of samples from the | ||||
| disk and are completely useless in day-to-day life. FluxEngine uses its own | ||||
| format for this, `.flux`, although it's capable of limited interchange with | ||||
| Kryoflux, Supercard Pro and Catweasel files. A flux file will typically contain | ||||
| from 80 to 150 kilobytes of data per track. | ||||
|  | ||||
| In general, FluxEngine can use either a real disk or a flux file | ||||
| interchangeably: you can specify either at (very nearly) any time. A very | ||||
| common workflow is to read a disk to a flux file, and then reread from the flux | ||||
| file while changing the decoder options, to save disk wear. It's also much faster. | ||||
|  | ||||
| ### Source and destination specifiers | ||||
|  | ||||
| When reading from or writing to _a disk_ (or a file pretending to be a disk), | ||||
| use the `--source` (`-s`) and `--dest` (`-d`) options to tell FluxEngine | ||||
| When reading from or writing _flux_ (either from or to a real disk, or a flux | ||||
| file), use the `--source` (`-s`) and `--dest` (`-d`) options to tell FluxEngine | ||||
| which bits of the disk you want to access. These use a common syntax: | ||||
|  | ||||
| ``` | ||||
| @@ -94,7 +47,7 @@ fluxengine read ibm -s fakedisk.flux:t=0-79:s=0 | ||||
|   - To access a real disk, leave out the filename (so `:t=0-79:s=0`). | ||||
|  | ||||
|   - To access only some tracks, use the `t=` modifier. To access only some | ||||
|     sides, use the `s=` modifier. To change drives, use `d=`. | ||||
|     sides, use the `s=` modifier. | ||||
|  | ||||
|   - Inside a modifier, you can use a comma separated list of ranges. So | ||||
|     `:t=0-3` and `:t=0,1,2,3` are equivalent. | ||||
| @@ -120,18 +73,15 @@ If you _don't_ specify a modifier, you'll get the default, which should be | ||||
| sensible for the command you're using. | ||||
|  | ||||
| **Important note:** FluxEngine _always_ uses zero-based units (even if the | ||||
| *disk format says otherwise). | ||||
| disk format says otherwise). | ||||
|  | ||||
| ### Input and output specifiers | ||||
|  | ||||
| These use a very similar syntax to the source and destination specifiers | ||||
| (because they're based on the same microformat library!) but are used for | ||||
| input and output _images_: i.e. nicely lined up arrays of sectors which you | ||||
| can actually do something with. | ||||
|  | ||||
| Use `--input` (`-i`) or `--output` (`-o`) as appropriate to tell FluxEngine | ||||
| where you want to read from or write to. The actual format is autodetected | ||||
| based on the extension: | ||||
| When reading or writing _file system images_, use the `--input` (`-i`) and | ||||
| `--output` (`-o`) options to specify the file and file format. These use a very | ||||
| similar syntax to the source and destination specifiers (because they're based | ||||
| on the same microformat library!) but with different specifiers. Also, the | ||||
| exact format varies according to the extension: | ||||
|  | ||||
|   - `.img` or `.adf`: raw sector images in CHS order. Append | ||||
|     `:c=80:h=2:s=9:b=512` to set the geometry; that specifies 80 cylinders, 2 | ||||
| @@ -191,17 +141,23 @@ here.](http://www.retrotechnology.com/herbs_stuff/guzis.html) | ||||
| These flags apply to many operations and are useful for modifying the overall | ||||
| behaviour. | ||||
|  | ||||
|   - `--revolutions=X`: when reading, spin the disk X times. Many formats | ||||
|   require `--revolutions=2` (which should happen automatically); or you can | ||||
|   increase the number to sample more data. | ||||
|   - `--revolutions=X`: when reading, spin the disk X times. X can be a floating | ||||
| 	point number. The default is usually 1.25. Some formats default to 1. | ||||
| 	Increasing the number will sample more data, and can be useful on dubious | ||||
| 	disks to try and get a better read. | ||||
|  | ||||
|   - `--sync-with-index=true|false`: wait for an index pulse before starting to | ||||
| 	read the disk. (Ignored for write operations.) By default FluxEngine | ||||
| 	doesn't, as it makes reads faster, but when diagnosing disk problems it's | ||||
| 	helpful to have all your data start at the same place each time. | ||||
|  | ||||
|   - `--index-source=X`, `--write-index-source=X`: set the source of index | ||||
|   pulses when reading or writing respectively. This is for use with drives | ||||
|   which don't produce index pulse data. Use 0 to get index pulses from the | ||||
|   drive, 1 to fake 300RPM pulses, or 2 to fake 360RPM pulses. Note this has | ||||
|   no effect on the _drive_, so it doesn't help with flippy disks, but is | ||||
|   useful for using very old drives with FluxEngine itself. If you use this | ||||
|   option, then any index marks in the sampled flux are, of course, garbage. | ||||
| 	pulses when reading or writing respectively. This is for use with drives | ||||
| 	which don't produce index pulse data. Use 0 to get index pulses from the | ||||
| 	drive, 1 to fake 300RPM pulses, or 2 to fake 360RPM pulses. Note this has | ||||
| 	no effect on the _drive_, so it doesn't help with flippy disks, but is | ||||
| 	useful for using very old drives with FluxEngine itself. If you use this | ||||
| 	option, then any index marks in the sampled flux are, of course, garbage. | ||||
|  | ||||
| ### The commands | ||||
|  | ||||
| @@ -211,60 +167,62 @@ installed anywhere and after building you'll find them in the `.obj` | ||||
| directory. | ||||
|  | ||||
|   - `fluxengine erase`: wipes (all or part of) a disk --- erases it without | ||||
|   writing a pulsetrain. | ||||
| 	writing a pulsetrain. | ||||
|  | ||||
|   - `fluxengine inspect`: dumps the raw pulsetrain / bitstream to stdout. | ||||
|   Mainly useful for debugging. | ||||
| 	Mainly useful for debugging. | ||||
|  | ||||
|   - `fluxengine read *`: reads various formats of disk. See the per-format | ||||
|   documentation linked from the table above. These all take an optional | ||||
|   `--write-flux` option which will cause the raw flux to be written to the | ||||
|   specified file. There are various `--dump` options for showing raw data | ||||
|   during the decode process. | ||||
| 	documentation linked from the table [in the index page](../README.md). | ||||
| 	These all take an optional `--write-flux` option which will cause the raw | ||||
| 	flux to be written to the specified file as well as the normal decode. | ||||
| 	There are various `--dump` options for showing raw data during the decode | ||||
| 	process, and `--write-csv` will write a copious CSV report of the state of | ||||
| 	every sector in the file in machine-readable format. | ||||
|  | ||||
|   - `fluxengine write *`: writes various formats of disk. Again, see the | ||||
|   per-format documentation above. | ||||
| 	per-format documentation [in the index page](../README.md). | ||||
|  | ||||
|   - `fluxengine writeflux`: writes raw flux files. This is much less useful | ||||
|   than you might think: you can't write flux files read from a disk to | ||||
|   another disk. (See the [FAQ](faq.md) for more information.) It's mainly | ||||
|   useful for flux files synthesised by the other `fluxengine write` commands. | ||||
| 	than you might think: you can't reliably write flux files read from a disk | ||||
| 	to another disk. (See the [FAQ](faq.md) for more information.) It's mainly | ||||
| 	useful for flux files synthesised by the other `fluxengine write` commands. | ||||
|  | ||||
|   - `fluxengine writetestpattern`: writes regular pulses (at a configurable | ||||
|   interval) to the disk. Useful for testing drive jitter, erasing disks in a | ||||
|   more secure fashion, or simply debugging. Goes well with `fluxengine | ||||
|   inspect`. | ||||
| 	interval) to the disk. Useful for testing drive jitter, erasing disks in a | ||||
| 	more secure fashion, or simply debugging. Goes well with `fluxengine | ||||
| 	inspect`. | ||||
|  | ||||
|   - `fluxengine rpm`: measures the RPM of the drive (requires a disk in the | ||||
|   drive). Mainly useful for testing. | ||||
| 	drive). Mainly useful for testing. | ||||
|  | ||||
|   - `fluxengine seek`: moves the head. Mainly useful for finding out whether | ||||
|   your drive can seek to track 82. (Mine can't.) | ||||
| 	your drive can seek to track 82. (Mine can't.) | ||||
|  | ||||
|   - `fluxengine test bandwidth`: measures your USB throughput. You need about | ||||
|   600kB/s for FluxEngine to work for DD disks, and 900 to 950kB/s for HD | ||||
|   disks. You don't need a disk in the drive for this one. | ||||
|   - `fluxengine test bandwidth`: measures your USB throughput.  You don't need | ||||
| 	a disk in the drive for this one. | ||||
|  | ||||
|   - `fluxengine test voltages`: measures your FDD bus signal voltages, which | ||||
|   is useful for testing for termination issues. | ||||
|   - `fluxengine test voltages`: measures your FDD bus signal voltages, which is | ||||
| 	useful for testing for termination issues. | ||||
|  | ||||
|   - `fluxengine upgradefluxfile`: occasionally I need to upgrade the flux | ||||
|   file format in a non-backwards-compatible way; this tool will upgrade flux | ||||
|   files to the new format. | ||||
|   - `fluxengine upgradefluxfile`: occasionally I need to upgrade the flux file | ||||
| 	format in a non-backwards-compatible way; this tool will upgrade flux files | ||||
| 	to the new format. | ||||
|  | ||||
|   - `fluxengine convert`: converts flux files from various formats to various | ||||
|   other formats. You can use this to convert Catweasel flux files to | ||||
|   FluxEngine's native format, FluxEngine flux files to various other formats | ||||
|   useful for debugging (including VCD which can be loaded into | ||||
|   [sigrok](http://sigrok.org)), and bidirectional conversion to and from | ||||
|   Supercard Pro `.scp` format. | ||||
| 	other formats. You can use this to convert Catweasel flux files to | ||||
| 	FluxEngine's native format, FluxEngine flux files to various other formats | ||||
| 	useful for debugging (including VCD which can be loaded into | ||||
| 	[sigrok](http://sigrok.org)), and bidirectional conversion to and from | ||||
| 	Supercard Pro `.scp` format. | ||||
|  | ||||
|   **Important SCP note:** import (`fluxengine convert scptoflux`) should be | ||||
|   fairly robust, but export (`fluxengine convert fluxtoscp`) should only be | ||||
|   done with great caution as FluxEngine files contain features which can't be | ||||
|   represented very well in `.scp` format and they're probably pretty dubious. | ||||
|   As ever, please [get in | ||||
|   touch](https://github.com/davidgiven/fluxengine/issues/new) with any reports. | ||||
| 	**Important SCP note:** import (`fluxengine convert scptoflux`) should be | ||||
| 	fairly robust, but export (`fluxengine convert fluxtoscp`) should only be | ||||
| 	done with great caution as FluxEngine files contain features which can't be | ||||
| 	represented very well in `.scp` format and they're probably pretty dubious. | ||||
| 	As ever, please [get in | ||||
| 	touch](https://github.com/davidgiven/fluxengine/issues/new) with any | ||||
| 	reports. | ||||
|  | ||||
| Commands which normally take `--source` or `--dest` get a sensible default if | ||||
| left unspecified. `fluxengine read ibm` on its own will read drive 0 and | ||||
| @@ -290,8 +248,10 @@ disk). For a 5.25" disk, use `--visualiser-period=166`. | ||||
| Supplied with FluxEngine, but not part of FluxEngine, are some little tools I | ||||
| wrote to do useful things. These are built alongside FluxEngine. | ||||
|  | ||||
|   - `brother120tool`: extracts files from a 120kB Brother filesystem image. | ||||
|  | ||||
|   - `brother120tool`, `brother240tool`: does things to Brother word processor | ||||
| 	disks. These are [documented on the Brother disk format | ||||
| 	page](disk-brother.md). | ||||
|    | ||||
| ## The recommended workflow | ||||
|  | ||||
| So you've just received, say, a huge pile of old Brother word processor disks | ||||
|   | ||||
							
								
								
									
										60
									
								
								lib/bytes.cc
									
									
									
									
									
								
							
							
						
						
									
										60
									
								
								lib/bytes.cc
									
									
									
									
									
								
							| @@ -1,7 +1,6 @@ | ||||
| #include "globals.h" | ||||
| #include "bytes.h" | ||||
| #include "fmt/format.h" | ||||
| #include "common/crunch.h" | ||||
| #include <fstream> | ||||
| #include <zlib.h> | ||||
|  | ||||
| @@ -249,60 +248,6 @@ Bytes Bytes::decompress() const | ||||
|     return output; | ||||
| } | ||||
|  | ||||
| Bytes Bytes::crunch() const | ||||
| { | ||||
|     Bytes output; | ||||
|     ByteWriter bw(output); | ||||
|     Bytes outputBuffer(1024*1024); | ||||
|  | ||||
|     crunch_state_t cs = {}; | ||||
|     cs.inputptr = begin(); | ||||
|     cs.inputlen = size(); | ||||
|  | ||||
|     do | ||||
|     { | ||||
|         cs.outputptr = outputBuffer.begin(); | ||||
|         cs.outputlen = outputBuffer.size(); | ||||
|  | ||||
|         ::crunch(&cs); | ||||
|         bw += outputBuffer.slice(0, outputBuffer.size() - cs.outputlen); | ||||
|     } | ||||
|     while (cs.inputlen != 0); | ||||
|     cs.outputptr = outputBuffer.begin(); | ||||
|     cs.outputlen = outputBuffer.size(); | ||||
|     donecrunch(&cs); | ||||
|     bw += outputBuffer.slice(0, outputBuffer.size() - cs.outputlen); | ||||
|  | ||||
|     return output; | ||||
| } | ||||
|  | ||||
| Bytes Bytes::uncrunch() const | ||||
| { | ||||
|     Bytes output; | ||||
|     ByteWriter bw(output); | ||||
|     Bytes outputBuffer(1024*1024); | ||||
|  | ||||
|     crunch_state_t cs = {}; | ||||
|     cs.inputptr = begin(); | ||||
|     cs.inputlen = size(); | ||||
|  | ||||
|     do | ||||
|     { | ||||
|         cs.outputptr = outputBuffer.begin(); | ||||
|         cs.outputlen = outputBuffer.size(); | ||||
|  | ||||
|         ::uncrunch(&cs); | ||||
|         bw += outputBuffer.slice(0, outputBuffer.size() - cs.outputlen); | ||||
|     } | ||||
|     while (cs.inputlen != 0); | ||||
|     cs.outputptr = outputBuffer.begin(); | ||||
|     cs.outputlen = outputBuffer.size(); | ||||
|     doneuncrunch(&cs); | ||||
|     bw += outputBuffer.slice(0, outputBuffer.size() - cs.outputlen); | ||||
|  | ||||
|     return output; | ||||
| } | ||||
|  | ||||
| void Bytes::writeToFile(const std::string& filename) const | ||||
| { | ||||
|     std::ofstream f(filename, std::ios::out | std::ios::binary); | ||||
| @@ -313,6 +258,11 @@ void Bytes::writeToFile(const std::string& filename) const | ||||
|     f.close(); | ||||
| } | ||||
|  | ||||
| void Bytes::writeTo(std::ostream& stream) const | ||||
| { | ||||
| 	stream.write((const char*) cbegin(), size()); | ||||
| } | ||||
|  | ||||
| ByteReader Bytes::reader() const | ||||
| { | ||||
|     return ByteReader(*this); | ||||
|   | ||||
| @@ -51,14 +51,13 @@ public: | ||||
|     Bytes swab() const; | ||||
|     Bytes compress() const; | ||||
|     Bytes decompress() const; | ||||
|     Bytes crunch() const; | ||||
|     Bytes uncrunch() const; | ||||
| 	std::vector<bool> toBits() const; | ||||
|  | ||||
|     ByteReader reader() const; | ||||
|     ByteWriter writer(); | ||||
|  | ||||
|     void writeToFile(const std::string& filename) const; | ||||
| 	void writeTo(std::ostream& stream) const; | ||||
|  | ||||
| private: | ||||
|     std::shared_ptr<std::vector<uint8_t>> _data; | ||||
|   | ||||
| @@ -1,125 +0,0 @@ | ||||
| #include <stdint.h> | ||||
| #include <stdbool.h> | ||||
| #include "crunch.h" | ||||
|  | ||||
| void crunch(crunch_state_t* state) | ||||
| { | ||||
|     while (state->inputlen && state->outputlen) | ||||
|     { | ||||
|         uint8_t data = *state->inputptr++; | ||||
|         state->inputlen--; | ||||
|  | ||||
| 		if (data == 0x80) | ||||
| 		{ | ||||
| 			/* Multiple 0x80s in a row get swallowed as they're | ||||
| 			 * meaningless. */ | ||||
| 			state->haspending = true; | ||||
| 		} | ||||
|         else if (data & 0x80) | ||||
|         { | ||||
| 			if (state->haspending) | ||||
| 			{ | ||||
| 				state->fifo = (state->fifo << 3) | 4; | ||||
| 				state->fifolen += 3; | ||||
| 				state->haspending = false; | ||||
| 			} | ||||
|  | ||||
|             state->fifo = (state->fifo << 3) | 4 | (data & 1); | ||||
|             state->fifolen += 3; | ||||
|         } | ||||
|         else | ||||
|         { | ||||
| 			if (state->haspending && (data >= 0x40)) | ||||
| 			{ | ||||
| 				state->fifo = (state->fifo << 3) | 4; | ||||
| 				state->fifolen += 3; | ||||
| 				state->haspending = false; | ||||
| 			} | ||||
| 				 | ||||
| 			state->fifo = (state->fifo << 8) | data; | ||||
| 			if (state->haspending) | ||||
| 				state->fifo |= 0xc0; | ||||
| 			state->haspending = false; | ||||
|             state->fifolen += 8; | ||||
|         } | ||||
|  | ||||
|         if (state->fifolen >= 8) | ||||
|         { | ||||
|             data = state->fifo >> (state->fifolen - 8); | ||||
|             *state->outputptr++ = data; | ||||
|             state->outputlen--; | ||||
|             state->fifolen -= 8; | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| void donecrunch(crunch_state_t* state) | ||||
| { | ||||
|     if (state->fifolen > 0) | ||||
|     { | ||||
|         uint8_t b = 0; | ||||
|         state->inputptr = &b; | ||||
|         state->inputlen = 1; | ||||
|         crunch(state); | ||||
|     } | ||||
| } | ||||
|  | ||||
| void uncrunch(crunch_state_t* state) | ||||
| { | ||||
|     while (state->inputlen && state->outputlen) | ||||
|     { | ||||
| 		if (state->haspending) | ||||
| 		{ | ||||
| 			*state->outputptr++ = state->pendingbyte; | ||||
| 			state->outputlen--; | ||||
| 			state->haspending = false; | ||||
| 			continue; | ||||
| 		} | ||||
|  | ||||
|         if (state->fifolen < 8) | ||||
|         { | ||||
|             if (state->inputlen) | ||||
|             { | ||||
|                 state->fifo = (state->fifo << 8) | *state->inputptr++; | ||||
|                 state->inputlen--; | ||||
|                 state->fifolen += 8; | ||||
|             } | ||||
|             else | ||||
|                 state->fifo <<= 8; | ||||
|         } | ||||
|  | ||||
|         uint8_t data = state->fifo >> (state->fifolen - 8); | ||||
| 		switch (data & 0xc0) | ||||
| 		{ | ||||
| 			case 0x80: | ||||
| 				data = ((data >> 5) & 0x01) | 0x80; | ||||
| 				state->fifolen -= 3; | ||||
| 				break; | ||||
|  | ||||
| 			case 0xc0: | ||||
| 				state->haspending = true; | ||||
| 				state->pendingbyte = data & 0x3f; | ||||
| 				data = 0x80; | ||||
| 				/* fall through */ | ||||
| 			default: | ||||
| 				state->fifolen -= 8; | ||||
| 		} | ||||
|  | ||||
|         if (data) | ||||
|         { | ||||
|             *state->outputptr++ = data; | ||||
|             state->outputlen--; | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| void doneuncrunch(crunch_state_t* state) | ||||
| { | ||||
|     if (state->fifolen > 0) | ||||
|     { | ||||
|         uint8_t b = 0; | ||||
|         state->inputptr = &b; | ||||
|         state->inputlen = 1; | ||||
|         uncrunch(state); | ||||
|     } | ||||
| } | ||||
| @@ -1,48 +0,0 @@ | ||||
| #ifndef CRUNCH_H | ||||
| #define CRUNCH_H | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| #endif | ||||
|  | ||||
| #include <stdint.h> | ||||
|  | ||||
| /* To save bandwidth, we compress the byte stream from the sampler when | ||||
|  * sending it over USB. The encoding used is: | ||||
|  *  | ||||
|  * 0nnn.nnnn: value 0x00..0x7f | ||||
|  * 11nn.nnnn: value 0x80 then 0x00..0x3f | ||||
|  * 10n      : value 0x80|n | ||||
|  * | ||||
|  * The end of the buffer is terminated with zeroes, which are ignored | ||||
|  * (not written to the output). | ||||
|  *  | ||||
|  * This saves ~40%, which gets us in under the bandwidth cap. | ||||
|  */ | ||||
|      | ||||
| typedef struct crunch_state_t | ||||
| { | ||||
|     const uint8_t* inputptr; | ||||
|     uint32_t inputlen; | ||||
|     uint8_t* outputptr; | ||||
|     uint32_t outputlen; | ||||
|     uint32_t fifo; | ||||
|     uint8_t fifolen; | ||||
| 	bool haspending; | ||||
| 	uint8_t pendingbyte; | ||||
| } | ||||
| crunch_state_t; | ||||
|  | ||||
| /* Crunches as much as possible and then stops. */ | ||||
| extern void crunch(crunch_state_t* state); | ||||
| extern void donecrunch(crunch_state_t* state); | ||||
|  | ||||
| /* Uncrunches as much as possible and then stops. */ | ||||
| extern void uncrunch(crunch_state_t* state); | ||||
| extern void doneuncrunch(crunch_state_t* state); | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
|  | ||||
| #endif | ||||
| @@ -15,34 +15,31 @@ std::vector<std::string> DataSpec::split( | ||||
| { | ||||
|     std::vector<std::string> ret; | ||||
|  | ||||
|     size_t start = 0; | ||||
|     size_t end = 0; | ||||
|     size_t len = 0; | ||||
|     do | ||||
|     { | ||||
|         end = s.find(delimiter,start);  | ||||
|         len = end - start; | ||||
|         std::string token = s.substr(start, len); | ||||
|         ret.emplace_back( token ); | ||||
|         start += len + delimiter.length(); | ||||
|     } | ||||
|     while (end != std::string::npos); | ||||
| 	if (!s.empty()) | ||||
| 	{ | ||||
| 		size_t start = 0; | ||||
| 		size_t end = 0; | ||||
| 		size_t len = 0; | ||||
| 		do | ||||
| 		{ | ||||
| 			end = s.find(delimiter,start);  | ||||
| 			len = end - start; | ||||
| 			std::string token = s.substr(start, len); | ||||
| 			ret.emplace_back( token ); | ||||
| 			start += len + delimiter.length(); | ||||
| 		} | ||||
| 		while (end != std::string::npos); | ||||
| 	} | ||||
|  | ||||
|     return ret; | ||||
| } | ||||
|  | ||||
| DataSpec::Modifier DataSpec::parseMod(const std::string& spec) | ||||
| std::set<unsigned> DataSpec::parseRange(const std::string& data) | ||||
| { | ||||
|     static const std::regex MOD_REGEX("([a-z]*)=([-x+0-9,]*)"); | ||||
|     static const std::regex DATA_REGEX("([0-9]+)(?:(?:-([0-9]+))|(?:\\+([0-9]+)))?(?:x([0-9]+))?"); | ||||
| 	static const std::regex DATA_REGEX("([0-9]+)(?:(?:-([0-9]+))|(?:\\+([0-9]+)))?(?:x([0-9]+))?"); | ||||
|  | ||||
|     std::smatch match; | ||||
|     if (!std::regex_match(spec, match, MOD_REGEX)) | ||||
|         Error() << "invalid data modifier syntax '" << spec << "'"; | ||||
|      | ||||
|     Modifier m; | ||||
|     m.name = match[1]; | ||||
|     m.source = spec; | ||||
|     for (auto& data : split(match[2], ",")) | ||||
| 	std::set<unsigned> result; | ||||
|     for (auto& data : split(data, ",")) | ||||
|     { | ||||
|         int start = 0; | ||||
|         int count = 1; | ||||
| @@ -64,9 +61,24 @@ DataSpec::Modifier DataSpec::parseMod(const std::string& spec) | ||||
|             Error() << "mod '" << data << "' specifies an illegal quantity"; | ||||
|  | ||||
|         for (int i = start; i < (start+count); i += step) | ||||
|             m.data.insert(i); | ||||
|             result.insert(i); | ||||
|     } | ||||
|  | ||||
|     return result; | ||||
| } | ||||
|  | ||||
| DataSpec::Modifier DataSpec::parseMod(const std::string& spec) | ||||
| { | ||||
| 	static const std::regex MOD_REGEX("([a-z]*)=([-x+0-9,]*)"); | ||||
|  | ||||
|     std::smatch match; | ||||
|     if (!std::regex_match(spec, match, MOD_REGEX)) | ||||
|         Error() << "invalid data modifier syntax '" << spec << "'"; | ||||
|      | ||||
|     Modifier m; | ||||
|     m.name = match[1]; | ||||
|     m.source = spec; | ||||
| 	m.data = parseRange(match[2]); | ||||
|     return m; | ||||
| } | ||||
|  | ||||
| @@ -74,7 +86,7 @@ void DataSpec::set(const std::string& spec) | ||||
| { | ||||
|     std::vector<std::string> words = split(spec, ":"); | ||||
|     if (words.size() == 0) | ||||
|         Error() << "empty data specification (you have to specify *something*)"; | ||||
| 		return; | ||||
|  | ||||
|     filename = words[0]; | ||||
|     if (words.size() > 1) | ||||
|   | ||||
| @@ -34,6 +34,8 @@ public: | ||||
| public: | ||||
|     static std::vector<std::string> split( | ||||
|         const std::string& s, const std::string& delimiter); | ||||
| 	static std::set<unsigned> parseRange(const std::string& spec); | ||||
|  | ||||
|     static Modifier parseMod(const std::string& spec); | ||||
|  | ||||
| public: | ||||
| @@ -117,4 +119,34 @@ private: | ||||
|     DataSpec _value; | ||||
| }; | ||||
|  | ||||
| class RangeFlag : public Flag | ||||
| { | ||||
| public: | ||||
|     RangeFlag(const std::vector<std::string>& names, const std::string helptext, | ||||
|             const std::string& defaultValue): | ||||
|         Flag(names, helptext), | ||||
| 		_stringValue(defaultValue), | ||||
|         _value(DataSpec::parseRange(defaultValue)) | ||||
|     {} | ||||
|  | ||||
|     const std::set<unsigned>& get() const | ||||
|     { checkInitialised(); return _value; } | ||||
|  | ||||
|     operator const std::set<unsigned>& () const | ||||
|     { return get(); } | ||||
|  | ||||
|     bool hasArgument() const { return true; } | ||||
|     const std::string defaultValueAsString() const { return _stringValue; } | ||||
|  | ||||
|     void set(const std::string& value) | ||||
| 	{ | ||||
| 		_stringValue = value; | ||||
| 		_value = DataSpec::parseRange(value); | ||||
| 	} | ||||
|  | ||||
| private: | ||||
| 	std::string _stringValue; | ||||
|     std::set<unsigned> _value; | ||||
| }; | ||||
|  | ||||
| #endif | ||||
|   | ||||
| @@ -35,7 +35,7 @@ void AbstractDecoder::decodeToSectors(Track& track) | ||||
|             return; | ||||
|         if ((r == UNKNOWN_RECORD) || (r == DATA_RECORD)) | ||||
|         { | ||||
|             fmr.readNextMatchingOpcode(F_OP_PULSE); | ||||
|             fmr.findEvent(F_BIT_PULSE); | ||||
|             continue; | ||||
|         } | ||||
|  | ||||
| @@ -56,7 +56,7 @@ void AbstractDecoder::decodeToSectors(Track& track) | ||||
| 				r = advanceToNextRecord(); | ||||
| 				if (r != UNKNOWN_RECORD) | ||||
| 					break; | ||||
| 				if (fmr.readNextMatchingOpcode(F_OP_PULSE) == 0) | ||||
| 				if (fmr.findEvent(F_BIT_PULSE) == 0) | ||||
|                     break; | ||||
| 			} | ||||
|             recordStart = fmr.tell(); | ||||
| @@ -88,3 +88,10 @@ void AbstractDecoder::pushRecord(const Fluxmap::Position& start, const Fluxmap:: | ||||
|     _track->rawrecords.push_back(record); | ||||
|     _fmr->seek(here); | ||||
| } | ||||
|  | ||||
| std::set<unsigned> AbstractDecoder::requiredSectors(Track& track) const | ||||
| { | ||||
| 	static std::set<unsigned> empty; | ||||
| 	return empty; | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -52,6 +52,11 @@ public: | ||||
|     void seek(const Fluxmap::Position& pos) | ||||
|     { return _fmr->seek(pos); }  | ||||
|  | ||||
| 	/* Returns a set of sectors required to exist on this track. If the reader | ||||
| 	 * sees any missing, it will consider this to be an error and will retry | ||||
| 	 * the read. */ | ||||
| 	virtual std::set<unsigned> requiredSectors(Track& track) const; | ||||
|  | ||||
| protected: | ||||
|     virtual void beginTrack() {}; | ||||
|     virtual RecordType advanceToNextRecord() = 0; | ||||
|   | ||||
| @@ -30,16 +30,15 @@ static DoubleFlag minimumClockUs( | ||||
|     "Refuse to detect clocks shorter than this, to avoid false positives.", | ||||
|     0.75); | ||||
|  | ||||
| int FluxmapReader::readOpcode(unsigned& ticks) | ||||
| uint8_t FluxmapReader::getNextEvent(unsigned& ticks) | ||||
| { | ||||
|     ticks = 0; | ||||
|  | ||||
|     while (!eof()) | ||||
|     { | ||||
|         uint8_t b = _bytes[_pos.bytes++]; | ||||
|         if (b < 0x80) | ||||
|             ticks += b; | ||||
|         else | ||||
| 		ticks += b & 0x3f; | ||||
| 		if (b & (F_BIT_PULSE|F_BIT_INDEX)) | ||||
|         { | ||||
|             _pos.ticks += ticks; | ||||
|             return b; | ||||
| @@ -47,21 +46,21 @@ int FluxmapReader::readOpcode(unsigned& ticks) | ||||
|     } | ||||
|  | ||||
|     _pos.ticks += ticks; | ||||
|     return -1; | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| unsigned FluxmapReader::readNextMatchingOpcode(uint8_t opcode) | ||||
| unsigned FluxmapReader::findEvent(uint8_t target) | ||||
| { | ||||
|     unsigned ticks = 0; | ||||
|  | ||||
|     for (;;) | ||||
|     { | ||||
|         unsigned thisTicks; | ||||
|         int op = readOpcode(thisTicks); | ||||
|         uint8_t bits = getNextEvent(thisTicks); | ||||
|         ticks += thisTicks; | ||||
|         if (op == -1) | ||||
|         if (eof()) | ||||
|             return 0; | ||||
|         if (op == opcode) | ||||
|         if (bits & target) | ||||
|             return ticks; | ||||
|     } | ||||
| } | ||||
| @@ -73,7 +72,7 @@ unsigned FluxmapReader::readInterval(nanoseconds_t clock) | ||||
|  | ||||
|     while (ticks < thresholdTicks) | ||||
|     { | ||||
|         unsigned thisTicks = readNextMatchingOpcode(F_OP_PULSE); | ||||
|         unsigned thisTicks = findEvent(F_BIT_PULSE); | ||||
|         if (!thisTicks) | ||||
|             break; | ||||
|         ticks += thisTicks; | ||||
| @@ -196,7 +195,7 @@ void FluxmapReader::seek(nanoseconds_t ns) | ||||
|     while (!eof() && (_pos.ticks < ticks)) | ||||
|     { | ||||
|         unsigned t; | ||||
|         readOpcode(t); | ||||
|         getNextEvent(t); | ||||
|     } | ||||
|     _pos.zeroes = 0; | ||||
| } | ||||
| @@ -237,7 +236,7 @@ nanoseconds_t FluxmapReader::seekToPattern(const FluxMatcher& pattern, const Flu | ||||
|             positions[i] = positions[i+1]; | ||||
|             candidates[i] = candidates[i+1]; | ||||
|         } | ||||
|         candidates[intervalCount] = readNextMatchingOpcode(F_OP_PULSE); | ||||
|         candidates[intervalCount] = findEvent(F_BIT_PULSE); | ||||
|         positions[intervalCount] = tell(); | ||||
|  | ||||
|     } | ||||
| @@ -248,7 +247,7 @@ nanoseconds_t FluxmapReader::seekToPattern(const FluxMatcher& pattern, const Flu | ||||
|  | ||||
| void FluxmapReader::seekToIndexMark() | ||||
| { | ||||
|     readNextMatchingOpcode(F_OP_INDEX); | ||||
|     findEvent(F_BIT_INDEX); | ||||
|     _pos.zeroes = 0; | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -96,8 +96,8 @@ public: | ||||
|         _pos = pos; | ||||
|     } | ||||
|  | ||||
|     int readOpcode(unsigned& ticks); | ||||
|     unsigned readNextMatchingOpcode(uint8_t opcode); | ||||
|     uint8_t getNextEvent(unsigned& ticks); | ||||
|     unsigned findEvent(uint8_t bits); | ||||
|     unsigned readInterval(nanoseconds_t clock); /* with debounce support */ | ||||
|  | ||||
|     /* Important! You can only reliably seek to 1 bits. */ | ||||
|   | ||||
| @@ -4,6 +4,9 @@ | ||||
|  | ||||
| Fluxmap& Fluxmap::appendBytes(const Bytes& bytes) | ||||
| { | ||||
| 	if (bytes.size() == 0) | ||||
| 		return *this; | ||||
|  | ||||
|     return appendBytes(&bytes[0], bytes.size()); | ||||
| } | ||||
|  | ||||
| @@ -15,8 +18,7 @@ Fluxmap& Fluxmap::appendBytes(const uint8_t* ptr, size_t len) | ||||
|     while (len--) | ||||
|     { | ||||
|         uint8_t byte = *ptr++; | ||||
|         if (byte < 0x80) | ||||
|             _ticks += byte; | ||||
| 		_ticks += byte & 0x3f; | ||||
|         bw.write_8(byte); | ||||
|     } | ||||
|  | ||||
| @@ -24,12 +26,19 @@ Fluxmap& Fluxmap::appendBytes(const uint8_t* ptr, size_t len) | ||||
|     return *this; | ||||
| } | ||||
|  | ||||
| uint8_t& Fluxmap::findLastByte() | ||||
| { | ||||
| 	if (_bytes.empty()) | ||||
| 		appendByte(0x00); | ||||
| 	return *(_bytes.end() - 1); | ||||
| } | ||||
|  | ||||
| Fluxmap& Fluxmap::appendInterval(uint32_t ticks) | ||||
| { | ||||
|     while (ticks >= 0x7f) | ||||
|     while (ticks >= 0x3f) | ||||
|     { | ||||
|         appendByte(0x7f); | ||||
|         ticks -= 0x7f; | ||||
|         appendByte(0x3f); | ||||
|         ticks -= 0x3f; | ||||
|     } | ||||
|     appendByte((uint8_t)ticks); | ||||
|     return *this; | ||||
| @@ -37,13 +46,13 @@ Fluxmap& Fluxmap::appendInterval(uint32_t ticks) | ||||
|  | ||||
| Fluxmap& Fluxmap::appendPulse() | ||||
| { | ||||
|     appendByte(0x80); | ||||
| 	findLastByte() |= 0x80; | ||||
|     return *this; | ||||
| } | ||||
|  | ||||
| Fluxmap& Fluxmap::appendIndex() | ||||
| { | ||||
|     appendByte(0x81); | ||||
| 	findLastByte() |= 0x40; | ||||
|     return *this; | ||||
| } | ||||
|  | ||||
| @@ -54,25 +63,26 @@ void Fluxmap::precompensate(int threshold_ticks, int amount_ticks) | ||||
|     for (unsigned i=0; i<_bytes.size(); i++) | ||||
|     { | ||||
|         uint8_t& prev = (i == 0) ? junk : _bytes[i-1]; | ||||
|         uint8_t curr = _bytes[i]; | ||||
| 		uint8_t prevticks = prev & 0x3f; | ||||
|         uint8_t currticks = _bytes[i] & 0x3f; | ||||
|  | ||||
|         if (curr < (3*threshold_ticks)) | ||||
|         if (currticks < (3*threshold_ticks)) | ||||
|         { | ||||
|             if ((prev <= threshold_ticks) && (curr > threshold_ticks)) | ||||
|             if ((prevticks <= threshold_ticks) && (currticks > threshold_ticks)) | ||||
|             { | ||||
|                 /* 01001; move the previous bit backwards. */ | ||||
|                 if (prev >= (1+amount_ticks)) | ||||
|                 if (prevticks >= (1+amount_ticks)) | ||||
|                     prev -= amount_ticks; | ||||
|                 if (curr <= (0x7f-amount_ticks)) | ||||
|                     curr += amount_ticks; | ||||
|                 if (currticks <= (0x7f-amount_ticks)) | ||||
|                     currticks += amount_ticks; | ||||
|             } | ||||
|             else if ((prev > threshold_ticks) && (curr <= threshold_ticks)) | ||||
|             else if ((prevticks > threshold_ticks) && (currticks <= threshold_ticks)) | ||||
|             { | ||||
|                 /* 00101; move the current bit forwards. */ | ||||
|                 if (prev <= (0x7f-amount_ticks)) | ||||
|                 if (prevticks <= (0x7f-amount_ticks)) | ||||
|                     prev += amount_ticks; | ||||
|                 if (curr >= (1+amount_ticks)) | ||||
|                     curr -= amount_ticks; | ||||
|                 if (currticks >= (1+amount_ticks)) | ||||
|                     currticks -= amount_ticks; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|   | ||||
| @@ -48,6 +48,9 @@ public: | ||||
|  | ||||
| 	void precompensate(int threshold_ticks, int amount_ticks); | ||||
|  | ||||
| private: | ||||
| 	uint8_t& findLastByte(); | ||||
|  | ||||
| private: | ||||
|     nanoseconds_t _duration = 0; | ||||
|     int _ticks = 0; | ||||
|   | ||||
| @@ -36,8 +36,7 @@ public: | ||||
|         usbSetDrive(_drive, high_density, indexMode); | ||||
|         usbSeek(track); | ||||
|  | ||||
|         Bytes crunched = fluxmap.rawBytes().crunch(); | ||||
|         return usbWrite(side, crunched); | ||||
|         return usbWrite(side, fluxmap.rawBytes()); | ||||
|     } | ||||
|  | ||||
| private: | ||||
|   | ||||
| @@ -50,9 +50,9 @@ public: | ||||
|     { | ||||
|         usbSetDrive(_drive, high_density, indexMode); | ||||
|         usbSeek(track); | ||||
|         Bytes crunched = usbRead(side, synced, revolutions * _oneRevolution); | ||||
|         Bytes data = usbRead(side, synced, revolutions * _oneRevolution); | ||||
|         auto fluxmap = std::make_unique<Fluxmap>(); | ||||
|         fluxmap->appendBytes(crunched.uncrunch()); | ||||
|         fluxmap->appendBytes(data); | ||||
|         return fluxmap; | ||||
|     } | ||||
|  | ||||
|   | ||||
							
								
								
									
										25
									
								
								lib/image.cc
									
									
									
									
									
								
							
							
						
						
									
										25
									
								
								lib/image.cc
									
									
									
									
									
								
							| @@ -1,25 +0,0 @@ | ||||
| #include "globals.h" | ||||
| #include "image.h" | ||||
| #include "flags.h" | ||||
| #include "dataspec.h" | ||||
| #include "sector.h" | ||||
| #include "sectorset.h" | ||||
| #include "imagereader/imagereader.h" | ||||
| #include "imagewriter/imagewriter.h" | ||||
| #include "fmt/format.h" | ||||
| #include <algorithm> | ||||
| #include <iostream> | ||||
| #include <fstream> | ||||
|  | ||||
| SectorSet readSectorsFromFile(const ImageSpec& spec) | ||||
| { | ||||
| 	return ImageReader::create(spec)->readImage(); | ||||
| } | ||||
|  | ||||
| void writeSectorsToFile(const SectorSet& sectors, const ImageSpec& spec) | ||||
| { | ||||
| 	std::unique_ptr<ImageWriter> writer(ImageWriter::create(sectors, spec)); | ||||
| 	writer->adjustGeometry(); | ||||
| 	writer->printMap(); | ||||
| 	writer->writeImage(); | ||||
| } | ||||
							
								
								
									
										14
									
								
								lib/image.h
									
									
									
									
									
								
							
							
						
						
									
										14
									
								
								lib/image.h
									
									
									
									
									
								
							| @@ -1,14 +0,0 @@ | ||||
| #ifndef IMAGE_H | ||||
| #define IMAGE_H | ||||
|  | ||||
| class SectorSet; | ||||
| class ImageSpec; | ||||
|  | ||||
| extern SectorSet readSectorsFromFile( | ||||
| 	const ImageSpec& filename); | ||||
|  | ||||
| extern void writeSectorsToFile( | ||||
| 	const SectorSet& sectors, | ||||
| 	const ImageSpec& filename); | ||||
|  | ||||
| #endif | ||||
| @@ -1,17 +1,19 @@ | ||||
| #include "globals.h" | ||||
| #include "image.h" | ||||
| #include "flags.h" | ||||
| #include "dataspec.h" | ||||
| #include "sector.h" | ||||
| #include "sectorset.h" | ||||
| #include "imagereader/imagereader.h" | ||||
| #include "fmt/format.h" | ||||
| #include <algorithm> | ||||
| #include <ctype.h> | ||||
|  | ||||
| std::map<std::string, ImageReader::Constructor> ImageReader::formats = | ||||
| { | ||||
| 	{".adf", ImageReader::createImgImageReader}, | ||||
| 	{".d81", ImageReader::createImgImageReader}, | ||||
| 	{".img", ImageReader::createImgImageReader}, | ||||
| 	{".ima", ImageReader::createImgImageReader}, | ||||
| }; | ||||
|  | ||||
| static bool ends_with(const std::string& value, const std::string& ending) | ||||
|   | ||||
| @@ -1,5 +1,4 @@ | ||||
| #include "globals.h" | ||||
| #include "image.h" | ||||
| #include "flags.h" | ||||
| #include "dataspec.h" | ||||
| #include "sector.h" | ||||
|   | ||||
| @@ -1,5 +1,4 @@ | ||||
| #include "globals.h" | ||||
| #include "image.h" | ||||
| #include "flags.h" | ||||
| #include "dataspec.h" | ||||
| #include "sector.h" | ||||
|   | ||||
| @@ -1,11 +1,12 @@ | ||||
| #include "globals.h" | ||||
| #include "image.h" | ||||
| #include "flags.h" | ||||
| #include "dataspec.h" | ||||
| #include "sector.h" | ||||
| #include "sectorset.h" | ||||
| #include "imagewriter/imagewriter.h" | ||||
| #include "fmt/format.h" | ||||
| #include <iostream> | ||||
| #include <fstream> | ||||
|  | ||||
| std::map<std::string, ImageWriter::Constructor> ImageWriter::formats = | ||||
| { | ||||
| @@ -63,6 +64,56 @@ void ImageWriter::adjustGeometry() | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void ImageWriter::writeCsv(const std::string& filename) | ||||
| { | ||||
| 	std::ofstream f(filename, std::ios::out); | ||||
| 	if (!f.is_open()) | ||||
| 		Error() << "cannot open CSV report file"; | ||||
|  | ||||
| 	f << "\"Physical track\"," | ||||
| 		"\"Physical side\"," | ||||
| 		"\"Logical track\"," | ||||
| 		"\"Logical side\"," | ||||
| 		"\"Logical sector\"," | ||||
| 		"\"Clock (ns)\"," | ||||
| 		"\"Header start (ns)\"," | ||||
| 		"\"Header end (ns)\"," | ||||
| 		"\"Data start (ns)\"," | ||||
| 		"\"Data end (ns)\"," | ||||
| 		"\"Raw data address (bytes)\"," | ||||
| 		"\"User payload length (bytes)\"," | ||||
| 		"\"Status\"" | ||||
| 		"\n"; | ||||
|  | ||||
| 	for (int track = 0; track < spec.cylinders; track++) | ||||
| 	{ | ||||
| 		for (int head = 0; head < spec.heads; head++) | ||||
| 		{ | ||||
| 			for (int sectorId = 0; sectorId < spec.sectors; sectorId++) | ||||
| 			{ | ||||
| 				f << fmt::format("{},{},", track, head); | ||||
| 				const auto& sector = sectors.get(track, head, sectorId); | ||||
| 				if (!sector) | ||||
| 					f << fmt::format(",,{},,,,,,,,MISSING\n", sectorId); | ||||
| 				else | ||||
| 					f << fmt::format("{},{},{},{},{},{},{},{},{},{},{}\n", | ||||
| 						sector->logicalTrack, | ||||
| 						sector->logicalSide, | ||||
| 						sector->logicalSector, | ||||
| 						sector->clock, | ||||
| 						sector->headerStartTime, | ||||
| 						sector->headerEndTime, | ||||
| 						sector->dataStartTime, | ||||
| 						sector->dataEndTime, | ||||
| 						sector->position.bytes, | ||||
| 						sector->data.size(), | ||||
| 						Sector::statusToString(sector->status) | ||||
| 					); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void ImageWriter::printMap() | ||||
| { | ||||
| 	int badSectors = 0; | ||||
|   | ||||
| @@ -35,6 +35,7 @@ private: | ||||
| public: | ||||
| 	virtual void adjustGeometry(); | ||||
| 	void printMap(); | ||||
| 	void writeCsv(const std::string& filename); | ||||
| 	virtual void writeImage() = 0; | ||||
|  | ||||
| protected: | ||||
|   | ||||
| @@ -1,5 +1,4 @@ | ||||
| #include "globals.h" | ||||
| #include "image.h" | ||||
| #include "flags.h" | ||||
| #include "dataspec.h" | ||||
| #include "sector.h" | ||||
| @@ -47,7 +46,7 @@ public: | ||||
| 					if (sector) | ||||
| 					{ | ||||
| 						outputFile.seekp(sector->logicalTrack*trackSize + sector->logicalSide*headSize + sector->logicalSector*numBytes, std::ios::beg); | ||||
| 						outputFile.write((const char*) sector->data.cbegin(), sector->data.size()); | ||||
| 						sector->data.slice(0, numBytes).writeTo(outputFile); | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
|   | ||||
| @@ -1,5 +1,4 @@ | ||||
| #include "globals.h" | ||||
| #include "image.h" | ||||
| #include "flags.h" | ||||
| #include "dataspec.h" | ||||
| #include "sector.h" | ||||
|   | ||||
| @@ -12,12 +12,13 @@ | ||||
| #include "sectorset.h" | ||||
| #include "visualiser.h" | ||||
| #include "record.h" | ||||
| #include "image.h" | ||||
| #include "bytes.h" | ||||
| #include "decoders/rawbits.h" | ||||
| #include "track.h" | ||||
| #include "imagewriter/imagewriter.h" | ||||
| #include "fmt/format.h" | ||||
| #include <iostream> | ||||
| #include <fstream> | ||||
|  | ||||
| FlagGroup readerFlags | ||||
| { | ||||
| @@ -68,6 +69,11 @@ static SettableFlag highDensityFlag( | ||||
| 	{ "--high-density", "--hd" }, | ||||
| 	"set the drive to high density mode"); | ||||
|  | ||||
| static StringFlag csvFile( | ||||
| 	{ "--write-csv" }, | ||||
| 	"write a CSV report of the disk state", | ||||
| 	""); | ||||
|  | ||||
| static std::unique_ptr<FluxSink> outputFluxSink; | ||||
|  | ||||
| void setReaderDefaultSource(const std::string& source) | ||||
| @@ -85,6 +91,16 @@ void setReaderRevolutions(int revolutions) | ||||
| 	setHardwareFluxSourceRevolutions(revolutions); | ||||
| } | ||||
|  | ||||
| static void writeSectorsToFile(const SectorSet& sectors, const ImageSpec& spec) | ||||
| { | ||||
| 	std::unique_ptr<ImageWriter> writer(ImageWriter::create(sectors, spec)); | ||||
| 	writer->adjustGeometry(); | ||||
| 	writer->printMap(); | ||||
| 	if (!csvFile.get().empty()) | ||||
| 		writer->writeCsv(csvFile.get()); | ||||
| 	writer->writeImage(); | ||||
| } | ||||
|  | ||||
| void Track::readFluxmap() | ||||
| { | ||||
| 	std::cout << fmt::format("{0:>3}.{1}: ", physicalTrack, physicalSide) << std::flush; | ||||
| @@ -176,8 +192,6 @@ void readDiskCommand(AbstractDecoder& decoder) | ||||
| 			decoder.decodeToSectors(*track); | ||||
|  | ||||
| 			std::cout << "       "; | ||||
| 			if (!track->sectors.empty()) | ||||
| 			{ | ||||
| 				std::cout << fmt::format("{} records, {} sectors; ", | ||||
| 					track->rawrecords.size(), | ||||
| 					track->sectors.size()); | ||||
| @@ -193,9 +207,12 @@ void readDiskCommand(AbstractDecoder& decoder) | ||||
| 				} | ||||
|  | ||||
| 				bool hasBadSectors = false; | ||||
| 				std::set<unsigned> requiredSectors = decoder.requiredSectors(*track); | ||||
| 				for (const auto& i : readSectors) | ||||
| 				{ | ||||
| 					const auto& sector = i.second; | ||||
| 					requiredSectors.erase(sector->logicalSector); | ||||
|  | ||||
| 					if (sector->status != Sector::OK) | ||||
| 					{ | ||||
| 						std::cout << std::endl | ||||
| @@ -204,6 +221,12 @@ void readDiskCommand(AbstractDecoder& decoder) | ||||
| 						hasBadSectors = true; | ||||
| 					} | ||||
| 				} | ||||
| 				for (unsigned logicalSector : requiredSectors) | ||||
| 				{ | ||||
| 					std::cout << "\n" | ||||
| 					          << "       Required sector " << logicalSector << " missing; "; | ||||
| 					hasBadSectors = true; | ||||
| 				} | ||||
|  | ||||
| 				if (hasBadSectors) | ||||
| 					failures = false; | ||||
| @@ -213,7 +236,6 @@ void readDiskCommand(AbstractDecoder& decoder) | ||||
|  | ||||
| 				if (!hasBadSectors) | ||||
| 					break; | ||||
| 			} | ||||
|  | ||||
| 			if (!track->fluxsource->retryable()) | ||||
| 				break; | ||||
| @@ -239,13 +261,13 @@ void readDiskCommand(AbstractDecoder& decoder) | ||||
|         if (dumpSectors) | ||||
|         { | ||||
|             std::cout << "\nDecoded sectors follow:\n\n"; | ||||
|             for (auto& i : readSectors) | ||||
|             for (auto& sector : track->sectors) | ||||
|             { | ||||
|                 auto& sector = i.second; | ||||
| 				std::cout << fmt::format("{}.{:02}.{:02}: I+{:.2f}us with {:.2f}us clock\n", | ||||
|                             sector->logicalTrack, sector->logicalSide, sector->logicalSector, | ||||
|                             sector->position.ns() / 1000.0, sector->clock / 1000.0); | ||||
| 				hexdump(std::cout, sector->data); | ||||
| 				std::cout << fmt::format("{}.{:02}.{:02}: I+{:.2f}us with {:.2f}us clock: status {}\n", | ||||
|                             sector.logicalTrack, sector.logicalSide, sector.logicalSector, | ||||
|                             sector.position.ns() / 1000.0, sector.clock / 1000.0, | ||||
| 							sector.status); | ||||
| 				hexdump(std::cout, sector.data); | ||||
| 				std::cout << std::endl; | ||||
|             } | ||||
|         } | ||||
| @@ -274,7 +296,7 @@ void readDiskCommand(AbstractDecoder& decoder) | ||||
|  | ||||
| 	if (!visualise.get().empty()) | ||||
| 		visualiseSectorsToFile(allSectors, visualise.get()); | ||||
|  | ||||
| 	 | ||||
|     writeSectorsToFile(allSectors, outputSpec); | ||||
| 	if (failures) | ||||
| 		std::cerr << "Warning: some sectors could not be decoded." << std::endl; | ||||
|   | ||||
| @@ -1,5 +1,4 @@ | ||||
| #include "globals.h" | ||||
| #include "image.h" | ||||
| #include "sector.h" | ||||
| #include "sectorset.h" | ||||
|  | ||||
|   | ||||
| @@ -10,8 +10,9 @@ enum | ||||
|     FLUX_VERSION_0, /* without properties table */ | ||||
|     FLUX_VERSION_1, | ||||
|     FLUX_VERSION_2, /* new bytecode with index marks */ | ||||
| 	FLUX_VERSION_3, /* simplified bytecode with six-bit timer */ | ||||
|  | ||||
|     FLUX_VERSION_CURRENT = 2, | ||||
|     FLUX_VERSION_CURRENT = FLUX_VERSION_3, | ||||
| }; | ||||
|  | ||||
| extern void sqlCheck(sqlite3* db, int i); | ||||
|   | ||||
| @@ -3,7 +3,6 @@ | ||||
| #include "protocol.h" | ||||
| #include "fluxmap.h" | ||||
| #include "bytes.h" | ||||
| #include "common/crunch.h" | ||||
| #include <libusb.h> | ||||
| #include "fmt/format.h" | ||||
|  | ||||
| @@ -154,10 +153,13 @@ nanoseconds_t usbGetRotationalPeriod(void) | ||||
|  | ||||
| static int large_bulk_transfer(int ep, Bytes& bytes) | ||||
| { | ||||
|     if (bytes.size() == 0) | ||||
|         return 0; | ||||
|  | ||||
|     int len; | ||||
|     int i = libusb_bulk_transfer(device, ep, bytes.begin(), bytes.size(), &len, TIMEOUT); | ||||
|     if (i < 0) | ||||
|         Error() << "data transfer failed: " << usberror(i); | ||||
|         Error() << fmt::format("data transfer failed at {} bytes: {}", len, usberror(i)); | ||||
|     return len; | ||||
| } | ||||
|  | ||||
| @@ -276,7 +278,6 @@ void usbWrite(int side, const Bytes& bytes) | ||||
|     ((uint8_t*)&f.bytes_to_write)[3] = safelen >> 24; | ||||
|  | ||||
|     usb_cmd_send(&f, f.f.size); | ||||
|  | ||||
|     large_bulk_transfer(FLUXENGINE_DATA_OUT_EP, safeBytes); | ||||
|      | ||||
|     await_reply<struct any_frame>(F_FRAME_WRITE_REPLY); | ||||
|   | ||||
| @@ -1,6 +1,5 @@ | ||||
| #define _USE_MATH_DEFINES | ||||
| #include "globals.h" | ||||
| #include "image.h" | ||||
| #include "sector.h" | ||||
| #include "sectorset.h" | ||||
| #include "visualiser.h" | ||||
|   | ||||
| @@ -9,13 +9,13 @@ | ||||
| #include "encoders/encoders.h" | ||||
| #include "fluxsource/fluxsource.h" | ||||
| #include "fluxsink/fluxsink.h" | ||||
| #include "imagereader/imagereader.h" | ||||
| #include "fmt/format.h" | ||||
| #include "record.h" | ||||
| #include "image.h" | ||||
| #include "sector.h" | ||||
| #include "sectorset.h" | ||||
|  | ||||
| FlagGroup writerFlags { &hardwareFluxSourceFlags, &hardwareFluxSinkFlags }; | ||||
| FlagGroup writerFlags { &hardwareFluxSourceFlags, &sqliteFluxSinkFlags, &hardwareFluxSinkFlags }; | ||||
|  | ||||
| static DataSpecFlag dest( | ||||
|     { "--dest", "-d" }, | ||||
| @@ -43,6 +43,11 @@ void setWriterDefaultInput(const std::string& input) | ||||
|     ::input.set(input); | ||||
| } | ||||
|  | ||||
| static SectorSet readSectorsFromFile(const ImageSpec& spec) | ||||
| { | ||||
| 	return ImageReader::create(spec)->readImage(); | ||||
| } | ||||
|  | ||||
| void writeTracks( | ||||
| 	const std::function<std::unique_ptr<Fluxmap>(int track, int side)> producer) | ||||
| { | ||||
| @@ -53,19 +58,7 @@ void writeTracks( | ||||
| 	setHardwareFluxSourceDensity(highDensityFlag); | ||||
| 	setHardwareFluxSinkDensity(highDensityFlag); | ||||
|  | ||||
| 	if (!spec.filename.empty()) | ||||
| 	{ | ||||
| 		outdb = sqlOpen(spec.filename, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE); | ||||
| 		sqlPrepareFlux(outdb); | ||||
| 		sqlStmt(outdb, "BEGIN;"); | ||||
|         sqlWriteIntProperty(outdb, "version", FLUX_VERSION_CURRENT); | ||||
| 		atexit([]() | ||||
| 			{ | ||||
| 				sqlStmt(outdb, "COMMIT;"); | ||||
| 				sqlClose(outdb); | ||||
| 			} | ||||
| 		); | ||||
| 	} | ||||
| 	std::shared_ptr<FluxSink> fluxSink = FluxSink::create(spec); | ||||
|  | ||||
|     for (const auto& location : spec.locations) | ||||
|     { | ||||
| @@ -73,31 +66,16 @@ void writeTracks( | ||||
|         std::unique_ptr<Fluxmap> fluxmap = producer(location.track, location.side); | ||||
|         if (!fluxmap) | ||||
|         { | ||||
|             if (!outdb) | ||||
|             { | ||||
|                 std::cout << "erasing\n"; | ||||
|                 usbSeek(location.track); | ||||
|                 usbErase(location.side); | ||||
|             } | ||||
|             else | ||||
|                 std::cout << "skipping\n"; | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             /* Precompensation actually seems to make things worse, so let's leave | ||||
|              * it disabled for now. */ | ||||
|             //fluxmap->precompensate(PRECOMPENSATION_THRESHOLD_TICKS, 2); | ||||
|             if (outdb) | ||||
|                 sqlWriteFlux(outdb, location.track, location.side, *fluxmap); | ||||
|             else | ||||
|             { | ||||
|                 Bytes crunched = fluxmap->rawBytes().crunch(); | ||||
|                 usbSeek(location.track); | ||||
|                 usbWrite(location.side, crunched); | ||||
|             } | ||||
|             std::cout << fmt::format( | ||||
|                 "{0} ms in {1} bytes", int(fluxmap->duration()/1e6), fluxmap->bytes()) << std::endl; | ||||
|             /* Create an empty fluxmap for writing. */ | ||||
|             fluxmap.reset(new Fluxmap()); | ||||
|         } | ||||
|  | ||||
|         /* Precompensation actually seems to make things worse, so let's leave | ||||
|             * it disabled for now. */ | ||||
|         //fluxmap->precompensate(PRECOMPENSATION_THRESHOLD_TICKS, 2); | ||||
|         fluxSink->writeFlux(location.track, location.side, *fluxmap); | ||||
|         std::cout << fmt::format( | ||||
|             "{0} ms in {1} bytes", int(fluxmap->duration()/1e6), fluxmap->bytes()) << std::endl; | ||||
|     } | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -174,7 +174,6 @@ buildlibrary libbackend.a \ | ||||
|     arch/victor9k/decoder.cc \ | ||||
|     arch/zilogmcz/decoder.cc \ | ||||
|     lib/bytes.cc \ | ||||
|     lib/common/crunch.c \ | ||||
|     lib/crc.cc \ | ||||
|     lib/dataspec.cc \ | ||||
|     lib/decoders/decoders.cc \ | ||||
| @@ -193,7 +192,6 @@ buildlibrary libbackend.a \ | ||||
|     lib/fluxsource/streamfluxsource.cc \ | ||||
|     lib/globals.cc \ | ||||
|     lib/hexdump.cc \ | ||||
|     lib/image.cc \ | ||||
|     lib/ldbs.cc \ | ||||
|     lib/reader.cc \ | ||||
|     lib/sector.cc \ | ||||
| @@ -263,7 +261,6 @@ buildsimpleprogram brother240tool \ | ||||
| runtest bitaccumulator-test tests/bitaccumulator.cc | ||||
| runtest bytes-test          tests/bytes.cc | ||||
| runtest compression-test    tests/compression.cc | ||||
| runtest crunch-test         tests/crunch.cc | ||||
| runtest dataspec-test       tests/dataspec.cc | ||||
| runtest flags-test          tests/flags.cc | ||||
| runtest fluxpattern-test    tests/fluxpattern.cc | ||||
|   | ||||
| @@ -3,7 +3,7 @@ | ||||
|  | ||||
| enum  | ||||
| { | ||||
|     FLUXENGINE_VERSION = 12, | ||||
|     FLUXENGINE_VERSION = 14, | ||||
|  | ||||
|     FLUXENGINE_VID = 0x1209, | ||||
|     FLUXENGINE_PID = 0x6e00, | ||||
| @@ -86,8 +86,8 @@ enum | ||||
|  | ||||
| enum | ||||
| { | ||||
|     F_OP_PULSE = 0x80, | ||||
|     F_OP_INDEX = 0x81 | ||||
|     F_BIT_PULSE = 0x80, | ||||
|     F_BIT_INDEX = 0x40 | ||||
| }; | ||||
|  | ||||
| struct frame_header | ||||
|   | ||||
| @@ -81,14 +81,14 @@ int mainConvertFluxToAu(int argc, const char* argv[]) | ||||
|         while (!fmr.eof()) | ||||
|         { | ||||
|             unsigned ticks; | ||||
|             int op = fmr.readOpcode(ticks); | ||||
|             if (op == -1) | ||||
|             uint8_t bits = fmr.getNextEvent(ticks); | ||||
|             if (fmr.eof()) | ||||
|                 break; | ||||
|             timestamp += ticks; | ||||
|  | ||||
|             if (op == F_OP_PULSE) | ||||
|             if (bits & F_BIT_PULSE) | ||||
|                 data[timestamp*channels + 0] = 0x7f; | ||||
|             if (withIndex && (op == F_OP_INDEX)) | ||||
|             if (withIndex && (bits & F_BIT_INDEX)) | ||||
|                 data[timestamp*channels + 1] = 0x7f; | ||||
|         } | ||||
|  | ||||
|   | ||||
| @@ -125,43 +125,34 @@ int mainConvertFluxToScp(int argc, const char* argv[]) | ||||
|             while (revolution < 5) | ||||
|             { | ||||
|                 unsigned ticks; | ||||
|                 int opcode = fmr.readOpcode(ticks); | ||||
|                 if (ticks) | ||||
|                 { | ||||
|                     ticksSinceLastPulse += ticks; | ||||
|                     totalTicks += ticks; | ||||
|                     revTicks += ticks; | ||||
|                 } | ||||
|                 uint8_t bits = fmr.getNextEvent(ticks); | ||||
| 				ticksSinceLastPulse += ticks; | ||||
| 				totalTicks += ticks; | ||||
| 				revTicks += ticks; | ||||
|  | ||||
|                 switch (opcode) | ||||
|                 { | ||||
|                     case -1: /* end of flux, treat like an index marker */ | ||||
|                     case F_OP_INDEX: | ||||
|                     { | ||||
|                         auto* revheader = &trackheader.revolution[revolution]; | ||||
|                         write_le32(revheader->offset, startOffset + sizeof(ScpTrack)); | ||||
|                         write_le32(revheader->length, (fluxdataWriter.pos - startOffset) / 2); | ||||
|                         write_le32(revheader->index, revTicks * NS_PER_TICK / 25); | ||||
|                         revolution++; | ||||
|                         revheader++; | ||||
|                         revTicks = 0; | ||||
|                         startOffset = fluxdataWriter.pos; | ||||
|                         break; | ||||
|                     } | ||||
| 				if (fmr.eof() || (bits & F_BIT_INDEX)) | ||||
| 				{ | ||||
| 					auto* revheader = &trackheader.revolution[revolution]; | ||||
| 					write_le32(revheader->offset, startOffset + sizeof(ScpTrack)); | ||||
| 					write_le32(revheader->length, (fluxdataWriter.pos - startOffset) / 2); | ||||
| 					write_le32(revheader->index, revTicks * NS_PER_TICK / 25); | ||||
| 					revolution++; | ||||
| 					revheader++; | ||||
| 					revTicks = 0; | ||||
| 					startOffset = fluxdataWriter.pos; | ||||
| 				} | ||||
|  | ||||
|                     case F_OP_PULSE: | ||||
|                     { | ||||
|                         unsigned t = ticksSinceLastPulse * NS_PER_TICK / 25; | ||||
|                         while (t >= 0x10000) | ||||
|                         { | ||||
|                             fluxdataWriter.write_be16(0); | ||||
|                             t -= 0x10000; | ||||
|                         } | ||||
|                         fluxdataWriter.write_be16(t); | ||||
|                         ticksSinceLastPulse = 0; | ||||
|                         break; | ||||
|                     } | ||||
|                 } | ||||
| 				if (bits & F_BIT_PULSE) | ||||
| 				{ | ||||
| 					unsigned t = ticksSinceLastPulse * NS_PER_TICK / 25; | ||||
| 					while (t >= 0x10000) | ||||
| 					{ | ||||
| 						fluxdataWriter.write_be16(0); | ||||
| 						t -= 0x10000; | ||||
| 					} | ||||
| 					fluxdataWriter.write_be16(t); | ||||
| 					ticksSinceLastPulse = 0; | ||||
| 				} | ||||
|             } | ||||
|  | ||||
|             write_le32(fileheader.track[strack], trackdataWriter.pos + sizeof(ScpHeader)); | ||||
|   | ||||
| @@ -59,8 +59,8 @@ int mainConvertFluxToVcd(int argc, const char* argv[]) | ||||
|     while (!fmr.eof()) | ||||
|     { | ||||
|         unsigned ticks; | ||||
|         int op = fmr.readOpcode(ticks); | ||||
|         if (op == -1) | ||||
|         uint8_t bits = fmr.getNextEvent(ticks); | ||||
|         if (fmr.eof()) | ||||
|             break; | ||||
|  | ||||
|         unsigned newtimestamp = timestamp + ticks; | ||||
| @@ -71,9 +71,9 @@ int mainConvertFluxToVcd(int argc, const char* argv[]) | ||||
|             of << fmt::format("#{} ", (uint64_t)(timestamp * NS_PER_TICK)); | ||||
|         } | ||||
|  | ||||
|         if (op == F_OP_PULSE) | ||||
|         if (bits & F_BIT_PULSE) | ||||
|             of << "1p "; | ||||
|         if (op == F_OP_INDEX) | ||||
|         if (bits & F_BIT_INDEX) | ||||
|             of << "1i "; | ||||
|  | ||||
|         lasttimestamp = timestamp; | ||||
|   | ||||
| @@ -4,7 +4,6 @@ | ||||
| #include "fluxmap.h" | ||||
| #include "decoders/fluxmapreader.h" | ||||
| #include "decoders/decoders.h" | ||||
| #include "image.h" | ||||
| #include "protocol.h" | ||||
| #include "decoders/rawbits.h" | ||||
| #include "record.h" | ||||
| @@ -73,7 +72,7 @@ static nanoseconds_t guessClock(const Fluxmap& fluxmap) | ||||
|  | ||||
|     while (!fr.eof()) | ||||
|     { | ||||
|         unsigned interval = fr.readNextMatchingOpcode(F_OP_PULSE); | ||||
|         unsigned interval = fr.findEvent(F_BIT_PULSE); | ||||
|         if (interval > 0xff) | ||||
|             continue; | ||||
|         buckets[interval]++; | ||||
| @@ -156,7 +155,11 @@ static nanoseconds_t guessClock(const Fluxmap& fluxmap) | ||||
| 				s += BLOCK_ELEMENTS[8]; | ||||
| 			s += BLOCK_ELEMENTS[bar & 7]; | ||||
|  | ||||
| 			std::cout << fmt::format("{:.2f} {:6} {}", (double)i * US_PER_TICK, value, s); | ||||
| 			std::cout << fmt::format("{: 3} {:.2f} {:6} {}", | ||||
| 					i, | ||||
| 					(double)i * US_PER_TICK, | ||||
| 					value, | ||||
| 					s); | ||||
| 			std::cout << std::endl; | ||||
| 		} | ||||
| 	} | ||||
| @@ -186,6 +189,12 @@ int mainInspect(int argc, const char* argv[]) | ||||
| 	auto& track = *tracks.begin(); | ||||
| 	track->readFluxmap(); | ||||
|  | ||||
| 	std::cout << fmt::format("0x{:x} bytes of data in {:.3f}ms\n", | ||||
| 			track->fluxmap->bytes(), | ||||
| 			track->fluxmap->duration() / 1e6); | ||||
| 	std::cout << fmt::format("Required USB bandwidth: {}kB/s\n", | ||||
| 			track->fluxmap->bytes()/1024.0 / (track->fluxmap->duration() / 1e9)); | ||||
|  | ||||
| 	nanoseconds_t clockPeriod = guessClock(*track->fluxmap); | ||||
| 	std::cout << fmt::format("{:.2f} us clock detected.", (double)clockPeriod/1000.0) << std::flush; | ||||
|  | ||||
| @@ -209,7 +218,7 @@ int mainInspect(int argc, const char* argv[]) | ||||
| 		nanoseconds_t lasttransition = 0; | ||||
| 		while (!fmr.eof()) | ||||
| 		{ | ||||
| 			ticks += fmr.readNextMatchingOpcode(F_OP_PULSE); | ||||
| 			ticks += fmr.findEvent(F_BIT_PULSE); | ||||
|  | ||||
| 			nanoseconds_t transition = ticks*NS_PER_TICK; | ||||
| 			nanoseconds_t next; | ||||
|   | ||||
| @@ -3,7 +3,6 @@ | ||||
| #include "reader.h" | ||||
| #include "fluxmap.h" | ||||
| #include "decoders/decoders.h" | ||||
| #include "image.h" | ||||
| #include "sector.h" | ||||
| #include "sectorset.h" | ||||
| #include "record.h" | ||||
|   | ||||
| @@ -3,7 +3,6 @@ | ||||
| #include "reader.h" | ||||
| #include "fluxmap.h" | ||||
| #include "decoders/decoders.h" | ||||
| #include "image.h" | ||||
| #include "sector.h" | ||||
| #include "sectorset.h" | ||||
| #include "record.h" | ||||
|   | ||||
| @@ -6,7 +6,6 @@ | ||||
| #include "amiga/amiga.h" | ||||
| #include "sector.h" | ||||
| #include "sectorset.h" | ||||
| #include "image.h" | ||||
| #include "record.h" | ||||
| #include "fmt/format.h" | ||||
| #include <fstream> | ||||
|   | ||||
| @@ -3,7 +3,6 @@ | ||||
| #include "reader.h" | ||||
| #include "fluxmap.h" | ||||
| #include "decoders/decoders.h" | ||||
| #include "image.h" | ||||
| #include "sector.h" | ||||
| #include "sectorset.h" | ||||
| #include "record.h" | ||||
|   | ||||
| @@ -6,7 +6,6 @@ | ||||
| #include "apple2/apple2.h" | ||||
| #include "sector.h" | ||||
| #include "sectorset.h" | ||||
| #include "image.h" | ||||
| #include "record.h" | ||||
| #include "fmt/format.h" | ||||
| #include <fstream> | ||||
|   | ||||
| @@ -7,7 +7,6 @@ | ||||
| #include "brother/brother.h" | ||||
| #include "sector.h" | ||||
| #include "sectorset.h" | ||||
| #include "image.h" | ||||
| #include "record.h" | ||||
| #include "fmt/format.h" | ||||
| #include <fstream> | ||||
|   | ||||
| @@ -6,7 +6,6 @@ | ||||
| #include "c64/c64.h" | ||||
| #include "sector.h" | ||||
| #include "sectorset.h" | ||||
| #include "image.h" | ||||
| #include "record.h" | ||||
| #include "fmt/format.h" | ||||
| #include <fstream> | ||||
|   | ||||
| @@ -3,7 +3,6 @@ | ||||
| #include "reader.h" | ||||
| #include "fluxmap.h" | ||||
| #include "decoders/decoders.h" | ||||
| #include "image.h" | ||||
| #include "sector.h" | ||||
| #include "sectorset.h" | ||||
| #include "record.h" | ||||
|   | ||||
| @@ -6,7 +6,6 @@ | ||||
| #include "f85/f85.h" | ||||
| #include "sector.h" | ||||
| #include "sectorset.h" | ||||
| #include "image.h" | ||||
| #include "record.h" | ||||
| #include "fmt/format.h" | ||||
| #include <fstream> | ||||
|   | ||||
| @@ -3,7 +3,6 @@ | ||||
| #include "reader.h" | ||||
| #include "fluxmap.h" | ||||
| #include "decoders/decoders.h" | ||||
| #include "image.h" | ||||
| #include "sector.h" | ||||
| #include "sectorset.h" | ||||
| #include "record.h" | ||||
|   | ||||
| @@ -3,32 +3,37 @@ | ||||
| #include "reader.h" | ||||
| #include "fluxmap.h" | ||||
| #include "decoders/decoders.h" | ||||
| #include "image.h" | ||||
| #include "sector.h" | ||||
| #include "sectorset.h" | ||||
| #include "record.h" | ||||
| #include "dataspec.h" | ||||
| #include "ibm/ibm.h" | ||||
| #include "fmt/format.h" | ||||
|  | ||||
| static FlagGroup flags { &readerFlags }; | ||||
|  | ||||
| static IntFlag sectorIdBase( | ||||
| 	{ "--sector-id-base" }, | ||||
| 	{ "--ibm-sector-id-base" }, | ||||
| 	"Sector ID of the first sector.", | ||||
| 	1); | ||||
|  | ||||
| static BoolFlag ignoreSideByte( | ||||
| 	{ "--ignore-side-byte" }, | ||||
| 	{ "--ibm-ignore-side-byte" }, | ||||
| 	"Ignore the side byte in the sector ID, and use the physical side instead.", | ||||
| 	false); | ||||
|  | ||||
| static RangeFlag requiredSectors( | ||||
| 	{ "--ibm-required-sectors" }, | ||||
| 	"A comma seperated list or range of sectors which must be on each track.", | ||||
| 	""); | ||||
|  | ||||
| int mainReadIBM(int argc, const char* argv[]) | ||||
| { | ||||
| 	setReaderDefaultSource(":t=0-79:s=0-1"); | ||||
| 	setReaderDefaultOutput("ibm.img"); | ||||
|     flags.parseFlags(argc, argv); | ||||
|  | ||||
| 	IbmDecoder decoder(sectorIdBase, ignoreSideByte); | ||||
| 	IbmDecoder decoder(sectorIdBase, ignoreSideByte, requiredSectors); | ||||
| 	readDiskCommand(decoder); | ||||
|     return 0; | ||||
| } | ||||
|   | ||||
| @@ -6,7 +6,6 @@ | ||||
| #include "macintosh/macintosh.h" | ||||
| #include "sector.h" | ||||
| #include "sectorset.h" | ||||
| #include "image.h" | ||||
| #include "record.h" | ||||
| #include "fmt/format.h" | ||||
| #include <fstream> | ||||
|   | ||||
| @@ -4,7 +4,6 @@ | ||||
| #include "fluxmap.h" | ||||
| #include "decoders/decoders.h" | ||||
| #include "mx/mx.h" | ||||
| #include "image.h" | ||||
| #include "sector.h" | ||||
| #include "sectorset.h" | ||||
| #include "record.h" | ||||
|   | ||||
| @@ -6,7 +6,6 @@ | ||||
| #include "victor9k/victor9k.h" | ||||
| #include "sector.h" | ||||
| #include "sectorset.h" | ||||
| #include "image.h" | ||||
| #include "record.h" | ||||
| #include "fmt/format.h" | ||||
| #include <fstream> | ||||
|   | ||||
| @@ -3,7 +3,6 @@ | ||||
| #include "reader.h" | ||||
| #include "fluxmap.h" | ||||
| #include "decoders/decoders.h" | ||||
| #include "image.h" | ||||
| #include "sector.h" | ||||
| #include "sectorset.h" | ||||
| #include "record.h" | ||||
|   | ||||
| @@ -6,7 +6,7 @@ | ||||
|  | ||||
| static sqlite3* db; | ||||
|  | ||||
| static void update_version_1_to_2() | ||||
| static void update_version_1_to_3() | ||||
| { | ||||
|     for (const auto i : sqlFindFlux(db)) | ||||
|     { | ||||
| @@ -33,6 +33,44 @@ static void update_version_1_to_2() | ||||
|     std::cout << std::endl; | ||||
| } | ||||
|  | ||||
| static void update_version_2_to_3() | ||||
| { | ||||
| 	for (const auto i : sqlFindFlux(db)) | ||||
| 	{ | ||||
| 		Fluxmap after; | ||||
|         const auto before = sqlReadFlux(db, i.first, i.second); | ||||
|  | ||||
|         /* Remember, before does not contain valid opcodes! */ | ||||
|         unsigned pending = 0; | ||||
|         for (uint8_t b : before->rawBytes()) | ||||
|         { | ||||
| 			switch (b) | ||||
| 			{ | ||||
| 				case 0x80: /* pulse */ | ||||
| 					after.appendInterval(pending); | ||||
| 					after.appendPulse(); | ||||
| 					pending = 0; | ||||
| 					break; | ||||
|  | ||||
| 				case 0x81: /* index */ | ||||
| 					after.appendInterval(pending); | ||||
| 					after.appendIndex(); | ||||
| 					pending = 0; | ||||
| 					break; | ||||
|  | ||||
| 				default: | ||||
| 					pending += b; | ||||
| 					break; | ||||
| 			} | ||||
|         } | ||||
| 		after.appendInterval(pending); | ||||
|  | ||||
|         sqlWriteFlux(db, i.first, i.second, after); | ||||
|         std::cout << '.' << std::flush; | ||||
|     } | ||||
|     std::cout << std::endl; | ||||
| } | ||||
|  | ||||
| int mainUpgradeFluxFile(int argc, const char* argv[]) | ||||
| { | ||||
|     if (argc != 2) | ||||
| @@ -71,14 +109,24 @@ int mainUpgradeFluxFile(int argc, const char* argv[]) | ||||
|  | ||||
|     if (version == FLUX_VERSION_1) | ||||
|     { | ||||
|         std::cout << "Upgrading to version 2\n"; | ||||
|         std::cout << "Upgrading to version 3\n"; | ||||
|         sqlStmt(db, "BEGIN;"); | ||||
|         update_version_1_to_2(); | ||||
|         version = FLUX_VERSION_2; | ||||
|         update_version_1_to_3(); | ||||
|         version = FLUX_VERSION_3; | ||||
|         sqlWriteIntProperty(db, "version", version); | ||||
|         sqlStmt(db, "COMMIT;"); | ||||
|     } | ||||
|  | ||||
| 	if (version == FLUX_VERSION_2) | ||||
| 	{ | ||||
|         std::cout << "Upgrading to version 3\n"; | ||||
|         sqlStmt(db, "BEGIN;"); | ||||
|         update_version_2_to_3(); | ||||
|         version = FLUX_VERSION_3; | ||||
|         sqlWriteIntProperty(db, "version", version); | ||||
|         sqlStmt(db, "COMMIT;"); | ||||
| 	} | ||||
|  | ||||
|     std::cout << "Vacuuming\n"; | ||||
|     sqlStmt(db, "VACUUM;"); | ||||
|     std::cout << "Upgrade done\n"; | ||||
|   | ||||
| @@ -4,7 +4,6 @@ | ||||
| #include "amiga/amiga.h" | ||||
| #include "writer.h" | ||||
| #include "fmt/format.h" | ||||
| #include "image.h" | ||||
| #include <fstream> | ||||
|  | ||||
| static FlagGroup flags { &writerFlags, &amigaEncoderFlags }; | ||||
|   | ||||
| @@ -5,18 +5,31 @@ | ||||
| #include "brother/brother.h" | ||||
| #include "writer.h" | ||||
| #include "fmt/format.h" | ||||
| #include "image.h" | ||||
| #include <fstream> | ||||
|  | ||||
| static FlagGroup flags { &writerFlags, &brotherEncoderFlags }; | ||||
|  | ||||
| static int brotherFormat = 240; | ||||
| static ActionFlag preset120( | ||||
| 	{ "--brother-preset-120" }, | ||||
| 	"Write the Brother 120kB format instead of the 240kB one.", | ||||
| 	[] { | ||||
| 		setWriterDefaultInput(":c=39:h=1:s=12:b=256"); | ||||
| 		brotherFormat = 120; | ||||
| 	}); | ||||
|  | ||||
| static IntFlag bias( | ||||
| 	{ "--brother-track-bias" }, | ||||
| 	"Shift the entire format this many tracks on the disk.", | ||||
| 	0); | ||||
|  | ||||
| int mainWriteBrother(int argc, const char* argv[]) | ||||
| { | ||||
|     setWriterDefaultInput(":c=78:h=1:s=12:b=256"); | ||||
| 	setWriterDefaultDest(":d=0:t=0-77:s=0"); | ||||
|     flags.parseFlags(argc, argv); | ||||
|  | ||||
| 	BrotherEncoder encoder; | ||||
| 	BrotherEncoder encoder(brotherFormat, bias); | ||||
| 	writeDiskCommand(encoder); | ||||
|  | ||||
|     return 0; | ||||
|   | ||||
| @@ -5,7 +5,6 @@ | ||||
| #include "ibm/ibm.h" | ||||
| #include "writer.h" | ||||
| #include "fmt/format.h" | ||||
| #include "image.h" | ||||
| #include <fstream> | ||||
|  | ||||
| static FlagGroup flags { &writerFlags }; | ||||
|   | ||||
| @@ -1,43 +0,0 @@ | ||||
| #include "globals.h" | ||||
| #include "bytes.h" | ||||
| #include "common/crunch.h" | ||||
|  | ||||
| static uint8_t outputbuffer[64]; | ||||
|  | ||||
| static void test_crunch() | ||||
| { | ||||
|     crunch_state_t cs = {}; | ||||
|     Bytes inputdata = { 0x01, 0x7f, 0x80, 0x05, 0x80, 0x81, 0x01 }; | ||||
|     cs.inputptr = inputdata.begin(); | ||||
|     cs.inputlen = inputdata.size(); | ||||
|     cs.outputptr = outputbuffer; | ||||
|     cs.outputlen = 64; | ||||
|     crunch(&cs); | ||||
|     donecrunch(&cs); | ||||
|     Bytes outputdata(outputbuffer, cs.outputptr - outputbuffer); | ||||
|  | ||||
|     assert((outputdata == Bytes{ 0x01, 0x7f, 0xc5, 0x94, 0x04 })); | ||||
| } | ||||
|  | ||||
| static void test_uncrunch() | ||||
| { | ||||
|     crunch_state_t cs = {}; | ||||
|     Bytes inputdata = { 0x01, 0x7f, 0xc5, 0x94, 0x04 }; | ||||
|     cs.inputptr = inputdata.begin(); | ||||
|     cs.inputlen = inputdata.size(); | ||||
|     cs.outputptr = outputbuffer; | ||||
|     cs.outputlen = 64; | ||||
|     uncrunch(&cs); | ||||
|     doneuncrunch(&cs); | ||||
|     Bytes outputdata(outputbuffer, cs.outputptr - outputbuffer); | ||||
|  | ||||
|     assert((outputdata == Bytes { 0x01, 0x7f, 0x80, 0x05, 0x80, 0x81, 0x01 })); | ||||
| } | ||||
|  | ||||
| int main(int argc, const char* argv[]) | ||||
| { | ||||
|     test_crunch(); | ||||
|     test_uncrunch(); | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| @@ -13,6 +13,28 @@ static void test_split(void) | ||||
|         == std::vector<std::string>{"", "2", ""})); | ||||
|     assert((DataSpec::split("2", ",") | ||||
|         == std::vector<std::string>{"2"})); | ||||
|     assert((DataSpec::split("", ",") | ||||
|         == std::vector<std::string>())); | ||||
| } | ||||
|  | ||||
| static void test_parserange(void) | ||||
| { | ||||
|     assert(DataSpec::parseRange("") | ||||
|         == std::set<unsigned>()); | ||||
|     assert(DataSpec::parseRange("1") | ||||
|         == std::set<unsigned>({1})); | ||||
|     assert(DataSpec::parseRange("1,3,5") | ||||
|         == std::set<unsigned>({1, 3, 5})); | ||||
|     assert(DataSpec::parseRange("1,1,1") | ||||
|         == std::set<unsigned>({1})); | ||||
|     assert(DataSpec::parseRange("2-3") | ||||
|         == std::set<unsigned>({2, 3})); | ||||
|     assert(DataSpec::parseRange("2+3") | ||||
|         == std::set<unsigned>({2, 3, 4})); | ||||
|     assert(DataSpec::parseRange("2+3x2") | ||||
|         == std::set<unsigned>({2, 4})); | ||||
|     assert(DataSpec::parseRange("9,2+3x2") | ||||
|         == std::set<unsigned>({2, 4, 9})); | ||||
| } | ||||
|  | ||||
| static void test_parsemod(void) | ||||
| @@ -104,6 +126,7 @@ static void test_imagespec(void) | ||||
| int main(int argc, const char* argv[]) | ||||
| { | ||||
|     test_split(); | ||||
| 	test_parserange(); | ||||
|     test_parsemod(); | ||||
|     test_fluxspec(); | ||||
|     test_imagespec(); | ||||
|   | ||||
| @@ -49,43 +49,43 @@ static void test_stream_reader() | ||||
|     /* Simple one-byte intervals */ | ||||
|     test_convert( | ||||
|         Bytes{ 0x20, 0x20, 0x20, 0x20 }, | ||||
|         Bytes{ 0x0f, 0x80, 0x0f, 0x80, 0x0f, 0x80, 0x0f, 0x80 } | ||||
|         Bytes{ 0x8f, 0x8f, 0x8f, 0x8f } | ||||
|     ); | ||||
|  | ||||
|     /* One-and-a-half-byte intervals */ | ||||
|     test_convert( | ||||
|         Bytes{ 0x20, 0x00, 0x10, 0x20, 0x01, 0x10, 0x20 }, | ||||
|         Bytes{ 0x0f, 0x80, 0x07, 0x80, 0x0f, 0x80, 0x7f, 0x08, 0x80, 0x0f, 0x80 } | ||||
|         Bytes{ 0x8f, 0x87, 0x8f, 0x3f, 0x3f, 0x89, 0x8f } | ||||
|     ); | ||||
|  | ||||
|     /* Two-byte intervals */ | ||||
|     test_convert( | ||||
|         Bytes{ 0x20, 0x0c, 0x00, 0x10, 0x20, 0x0c, 0x01, 0x10, 0x20 }, | ||||
|         Bytes{ 0x0f, 0x80, 0x07, 0x80, 0x0f, 0x80, 0x7f, 0x08, 0x80, 0x0f, 0x80 } | ||||
|         Bytes{ 0x8f, 0x87, 0x8f, 0x3f, 0x3f, 0x89, 0x8f } | ||||
|     ); | ||||
|  | ||||
|     /* Overflow */ | ||||
|     test_convert( | ||||
|         Bytes{ 0x20, 0x0b, 0x10, 0x20 }, | ||||
|         Bytes{ 0x0f, 0x80 } + (Bytes{ 0x7f } * 0x101) + Bytes{ 0x63, 0x80, 0x0f, 0x80 } | ||||
|         Bytes{ 0x8f } + (Bytes{ 0x3f } * 0x207) + Bytes{ 0xa9, 0x8f } | ||||
|     ); | ||||
|  | ||||
|     /* Single-byte nop */ | ||||
|     test_convert( | ||||
|         Bytes{ 0x20, 0x08, 0x20 }, | ||||
|         Bytes{ 0x0f, 0x80, 0x0f, 0x80 } | ||||
|         Bytes{ 0x8f, 0x8f } | ||||
|     ); | ||||
|  | ||||
|     /* Double-byte nop */ | ||||
|     test_convert( | ||||
|         Bytes{ 0x20, 0x09, 0xde, 0x20 }, | ||||
|         Bytes{ 0x0f, 0x80, 0x0f, 0x80 } | ||||
|         Bytes{ 0x8f, 0x8f } | ||||
|     ); | ||||
|  | ||||
|     /* Triple-byte nop */ | ||||
|     test_convert( | ||||
|         Bytes{ 0x20, 0x0a, 0xde, 0xad, 0x20 }, | ||||
|         Bytes{ 0x0f, 0x80, 0x0f, 0x80 } | ||||
|         Bytes{ 0x8f, 0x8f } | ||||
|     ); | ||||
|  | ||||
|     /* OOB block */ | ||||
| @@ -98,7 +98,7 @@ static void test_stream_reader() | ||||
|             0x55, /* payload */ | ||||
|             0x20 /* data continues */ | ||||
|         }, | ||||
|         Bytes{ 0x0f, 0x80, 0x0f, 0x80 } | ||||
|         Bytes{ 0x8f, 0x8f } | ||||
|     ); | ||||
| } | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user