mirror of
				https://github.com/davidgiven/fluxengine.git
				synced 2025-10-31 11:17:01 -07:00 
			
		
		
		
	Compare commits
	
		
			1077 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					1f5903a9a0 | ||
| 
						 | 
					bb073b6bb3 | ||
| 
						 | 
					516241f8f5 | ||
| 
						 | 
					c61effb54f | ||
| 
						 | 
					346d989944 | ||
| 
						 | 
					e52db4a837 | ||
| 
						 | 
					4e317643bc | ||
| 
						 | 
					5f520bf375 | ||
| 
						 | 
					2efe521b3a | ||
| 
						 | 
					5c21103646 | ||
| 
						 | 
					9444696f37 | ||
| 
						 | 
					082fe4e787 | ||
| 
						 | 
					5e13cf23f9 | ||
| 
						 | 
					8f98a1f557 | ||
| 
						 | 
					5b21e8798b | ||
| 
						 | 
					b9ef5b7db8 | ||
| 
						 | 
					9867f8c302 | ||
| 
						 | 
					315889faf6 | ||
| 
						 | 
					798e8fee89 | ||
| 
						 | 
					e1c49db329 | ||
| 
						 | 
					dae9537472 | ||
| 
						 | 
					1330d56cdd | ||
| 
						 | 
					6ce3ce20d0 | ||
| 
						 | 
					362c5ee9b0 | ||
| 
						 | 
					0f34ce0278 | ||
| 
						 | 
					0c27c7c4c8 | ||
| 
						 | 
					9db6efe7a2 | ||
| 
						 | 
					8b8a22d7fb | ||
| 
						 | 
					0a70344bc1 | ||
| 
						 | 
					e77d01911c | ||
| 
						 | 
					d4c0853e1f | ||
| 
						 | 
					363a4e959c | ||
| 
						 | 
					9336a04681 | ||
| 
						 | 
					214ff38749 | ||
| 
						 | 
					a8f3c01d8b | ||
| 
						 | 
					4da6585ef9 | ||
| 
						 | 
					df40100feb | ||
| 
						 | 
					f2d92e93fb | ||
| 
						 | 
					b4d8d569d2 | ||
| 
						 | 
					854b3e9c59 | ||
| 
						 | 
					28ca2b72f1 | ||
| 
						 | 
					7781c8179f | ||
| 
						 | 
					69ece3ffa0 | ||
| 
						 | 
					53adcd92ed | ||
| 
						 | 
					2bef6ca646 | ||
| 
						 | 
					bab350d771 | ||
| 
						 | 
					048dac223f | ||
| 
						 | 
					b7634da310 | ||
| 
						 | 
					882c92c64a | ||
| 
						 | 
					4592dbe28b | ||
| 
						 | 
					edc0f21ae7 | ||
| 
						 | 
					8715b7f6c1 | ||
| 
						 | 
					99511910dd | ||
| 
						 | 
					a03478b011 | ||
| 
						 | 
					5c428e1f07 | ||
| 
						 | 
					ee57615735 | ||
| 
						 | 
					67300e5769 | ||
| 
						 | 
					873e05051c | ||
| 
						 | 
					4daaec46a7 | ||
| 
						 | 
					dd8cc7bfd4 | ||
| 
						 | 
					5568ac382f | ||
| 
						 | 
					dcdb3e4455 | ||
| 
						 | 
					17b29b1626 | ||
| 
						 | 
					dcfcc6271c | ||
| 
						 | 
					1d77ba6429 | ||
| 
						 | 
					ff5f019ac1 | ||
| 
						 | 
					e61eeb8c6f | ||
| 
						 | 
					68d22e7f54 | ||
| 
						 | 
					790f0a42e3 | ||
| 
						 | 
					08e9e508cc | ||
| 
						 | 
					ad1a8d608f | ||
| 
						 | 
					d74ed71023 | ||
| 
						 | 
					0c7f9e0888 | ||
| 
						 | 
					ba5f6528a8 | ||
| 
						 | 
					65cf552ec2 | ||
| 
						 | 
					715c0a0c42 | ||
| 
						 | 
					9e383575d1 | ||
| 
						 | 
					d84c366480 | ||
| 
						 | 
					42e6c11081 | ||
| 
						 | 
					9ba3f90f1e | ||
| 
						 | 
					24ff51274b | ||
| 
						 | 
					4c4c752827 | ||
| 
						 | 
					5022b67e4a | ||
| 
						 | 
					6b990a9f51 | ||
| 
						 | 
					e69ce3b8df | ||
| 
						 | 
					cf537b6222 | ||
| 
						 | 
					9d1160faff | ||
| 
						 | 
					ed4067f194 | ||
| 
						 | 
					d4b55cd8f5 | ||
| 
						 | 
					baaeb0bca7 | ||
| 
						 | 
					466c3c34e5 | ||
| 
						 | 
					099d7969ca | ||
| 
						 | 
					5adfa95a85 | ||
| 
						 | 
					bfa0846ad0 | ||
| 
						 | 
					7099264334 | ||
| 
						 | 
					69b44e7968 | ||
| 
						 | 
					fe39977ff7 | ||
| 
						 | 
					b9fc8de5b5 | ||
| 
						 | 
					f7b8022d3a | ||
| 
						 | 
					a62346c515 | ||
| 
						 | 
					e372d757ad | ||
| 
						 | 
					ab1b10f935 | ||
| 
						 | 
					8e918706dc | ||
| 
						 | 
					76450d00bf | ||
| 
						 | 
					ee53542e18 | ||
| 
						 | 
					db004bc787 | ||
| 
						 | 
					71a7f3554e | ||
| 
						 | 
					5c3f422a53 | ||
| 
						 | 
					2fe0cec04a | ||
| 
						 | 
					de59e781b5 | ||
| 
						 | 
					8c77af651b | ||
| 
						 | 
					638f6928cf | ||
| 
						 | 
					ccc8e597a7 | ||
| 
						 | 
					585f19d884 | ||
| 
						 | 
					bb2b7d7df6 | ||
| 
						 | 
					e75d218438 | ||
| 
						 | 
					7f81b554fd | ||
| 
						 | 
					2490f19a1a | ||
| 
						 | 
					30f382bf22 | ||
| 
						 | 
					ad03c187cf | ||
| 
						 | 
					06560b5a5a | ||
| 
						 | 
					7c40093698 | ||
| 
						 | 
					d37c75d703 | ||
| 
						 | 
					82bfb9a303 | ||
| 
						 | 
					01682101a6 | ||
| 
						 | 
					3c46f787b1 | ||
| 
						 | 
					591d200283 | ||
| 
						 | 
					195534c21e | ||
| 
						 | 
					0f9d851a29 | ||
| 
						 | 
					18a03baf99 | ||
| 
						 | 
					5e06db4a52 | ||
| 
						 | 
					bf78508ef7 | ||
| 
						 | 
					137c0340fb | ||
| 
						 | 
					e6d9de2d80 | ||
| 
						 | 
					d9b319eaed | ||
| 
						 | 
					f2e713bde3 | ||
| 
						 | 
					94e2e494c9 | ||
| 
						 | 
					5af408e1d1 | ||
| 
						 | 
					77bdc727ab | ||
| 
						 | 
					eb26426424 | ||
| 
						 | 
					f624bb6e5b | ||
| 
						 | 
					4a8fb9288c | ||
| 
						 | 
					f8f5873973 | ||
| 
						 | 
					5f4903f2d1 | ||
| 
						 | 
					b02a894663 | ||
| 
						 | 
					510b530551 | ||
| 
						 | 
					c36662205b | ||
| 
						 | 
					a2ffe06792 | ||
| 
						 | 
					0f56108bf5 | ||
| 
						 | 
					199cefdb71 | ||
| 
						 | 
					1bdeaa326c | ||
| 
						 | 
					cce8cfe88d | ||
| 
						 | 
					bcfc0217dc | ||
| 
						 | 
					7cfa080220 | ||
| 
						 | 
					45ebc0f40f | ||
| 
						 | 
					38d575eda7 | ||
| 
						 | 
					9cb284583b | ||
| 
						 | 
					137b921e8d | ||
| 
						 | 
					8c876f555d | ||
| 
						 | 
					0988dd524b | ||
| 
						 | 
					2dc649ef09 | ||
| 
						 | 
					baf02cb849 | ||
| 
						 | 
					51fa3c5293 | ||
| 
						 | 
					134dd6c37d | ||
| 
						 | 
					d766e1f9a9 | ||
| 
						 | 
					d298f5b16e | ||
| 
						 | 
					ed634fbbf6 | ||
| 
						 | 
					4c776d584b | ||
| 
						 | 
					c2c04862a2 | ||
| 
						 | 
					ccd9539015 | ||
| 
						 | 
					624c597735 | ||
| 
						 | 
					9300aa79c3 | ||
| 
						 | 
					9e522c7da2 | ||
| 
						 | 
					ef60bfff6b | ||
| 
						 | 
					635c6c7bfe | ||
| 
						 | 
					df6e47fa50 | ||
| 
						 | 
					654cdcd3d1 | ||
| 
						 | 
					a633b73e12 | ||
| 
						 | 
					ba93dae240 | ||
| 
						 | 
					8e0ca85d1e | ||
| 
						 | 
					56a4926bd3 | ||
| 
						 | 
					6a2aae4ef2 | ||
| 
						 | 
					ec68ce3bfa | ||
| 
						 | 
					a777a5be30 | ||
| 
						 | 
					b553a8b1fb | ||
| 
						 | 
					b119e1f72d | ||
| 
						 | 
					7345d3e6c1 | ||
| 
						 | 
					e9b7a7bb52 | ||
| 
						 | 
					2022732dd9 | ||
| 
						 | 
					63544647b6 | ||
| 
						 | 
					6b62585ad5 | ||
| 
						 | 
					14027210f7 | ||
| 
						 | 
					3df17b23b8 | ||
| 
						 | 
					cbf3f56562 | ||
| 
						 | 
					1f74d9189f | ||
| 
						 | 
					137658d1d6 | ||
| 
						 | 
					5b627bd2b1 | ||
| 
						 | 
					38ff08885a | ||
| 
						 | 
					a89993aabb | ||
| 
						 | 
					d6353403e2 | ||
| 
						 | 
					bc62ee04c0 | ||
| 
						 | 
					d3ff836b63 | ||
| 
						 | 
					a7aac5578e | ||
| 
						 | 
					add5a141d3 | ||
| 
						 | 
					330410ec61 | ||
| 
						 | 
					d0f49dcfa6 | ||
| 
						 | 
					124f6ab7cb | ||
| 
						 | 
					471f63592e | ||
| 
						 | 
					50e210c72f | ||
| 
						 | 
					d3396aa535 | ||
| 
						 | 
					5ed8b838bc | ||
| 
						 | 
					d1757eacc2 | ||
| 
						 | 
					0692e5f5d5 | ||
| 
						 | 
					e4204196cd | ||
| 
						 | 
					241d4342e4 | ||
| 
						 | 
					c04cbc631c | ||
| 
						 | 
					29b273ad7b | ||
| 
						 | 
					9720dab2f6 | ||
| 
						 | 
					bddc64a324 | ||
| 
						 | 
					eb324f14de | ||
| 
						 | 
					b78a057c81 | ||
| 
						 | 
					5751725213 | ||
| 
						 | 
					f194392f99 | ||
| 
						 | 
					fea62178af | ||
| 
						 | 
					33ef4ce8de | ||
| 
						 | 
					3728120f95 | ||
| 
						 | 
					2944b9b3f6 | ||
| 
						 | 
					3430574364 | ||
| 
						 | 
					fc5a5212c0 | ||
| 
						 | 
					20f724ed13 | ||
| 
						 | 
					94c1d21938 | ||
| 
						 | 
					a1a9666b6f | ||
| 
						 | 
					0551ddc276 | ||
| 
						 | 
					049ffd3b04 | ||
| 
						 | 
					c28f757c5c | ||
| 
						 | 
					91dbb86e64 | ||
| 
						 | 
					27a04ee22b | ||
| 
						 | 
					5cefce9922 | ||
| 
						 | 
					8fb4c90bed | ||
| 
						 | 
					81753669cc | ||
| 
						 | 
					0a0a72bcf3 | ||
| 
						 | 
					c4a6e3e063 | ||
| 
						 | 
					1138e6b77f | ||
| 
						 | 
					030f9218d6 | ||
| 
						 | 
					2fff32e8f2 | ||
| 
						 | 
					5b2aa9926f | ||
| 
						 | 
					921e178e83 | ||
| 
						 | 
					25ffd900c8 | ||
| 
						 | 
					7ea4e116cc | ||
| 
						 | 
					a9daec36f5 | ||
| 
						 | 
					cebc7c6cd2 | ||
| 
						 | 
					3f85c9f006 | ||
| 
						 | 
					ed5efd7b87 | ||
| 
						 | 
					4984a53bfd | ||
| 
						 | 
					b0c77653a2 | ||
| 
						 | 
					909f0d628b | ||
| 
						 | 
					e27e3ada92 | ||
| 
						 | 
					339ea3b5a4 | ||
| 
						 | 
					9bd8b8915e | ||
| 
						 | 
					35008656a9 | ||
| 
						 | 
					825089458f | ||
| 
						 | 
					4a086d94b7 | ||
| 
						 | 
					0aeddf7e98 | ||
| 
						 | 
					4922d1deb4 | ||
| 
						 | 
					86d0893261 | ||
| 
						 | 
					e4c67f18bd | ||
| 
						 | 
					d07c5a94e1 | ||
| 
						 | 
					a91dee27e7 | ||
| 
						 | 
					e3219087c9 | ||
| 
						 | 
					cc9ec84aec | ||
| 
						 | 
					a33cc5710c | ||
| 
						 | 
					c2b148288a | ||
| 
						 | 
					a483567564 | ||
| 
						 | 
					bd99bc6d94 | ||
| 
						 | 
					8f79071aad | ||
| 
						 | 
					ef9071049b | ||
| 
						 | 
					60e1ab8cca | ||
| 
						 | 
					d3dbfd3154 | ||
| 
						 | 
					ee2dffb498 | ||
| 
						 | 
					6d9510cc65 | ||
| 
						 | 
					49f0f5d000 | ||
| 
						 | 
					d8528d889a | ||
| 
						 | 
					ec439a5f2a | ||
| 
						 | 
					d88110488e | ||
| 
						 | 
					2f4b15293a | ||
| 
						 | 
					3d71f32587 | ||
| 
						 | 
					5136dda598 | ||
| 
						 | 
					d26940304b | ||
| 
						 | 
					f9f11b4966 | ||
| 
						 | 
					1297b568ba | ||
| 
						 | 
					fd10840cc0 | ||
| 
						 | 
					7e86be979d | ||
| 
						 | 
					731d1efcc4 | ||
| 
						 | 
					dfda8be30c | ||
| 
						 | 
					7dd1b6d8e9 | ||
| 
						 | 
					ec1bcdb9e5 | ||
| 
						 | 
					c0f46d2bd4 | ||
| 
						 | 
					615dca3130 | ||
| 
						 | 
					9cf9597c54 | ||
| 
						 | 
					e24ee648e7 | ||
| 
						 | 
					e3518dc389 | ||
| 
						 | 
					693ba20606 | ||
| 
						 | 
					b947c6c186 | ||
| 
						 | 
					7f8ecb8514 | ||
| 
						 | 
					4df6afa9c1 | ||
| 
						 | 
					d0620f8efe | ||
| 
						 | 
					2b1a6dbb03 | ||
| 
						 | 
					c6ef667c3f | ||
| 
						 | 
					8c1d1bec93 | ||
| 
						 | 
					8be174e65a | ||
| 
						 | 
					6d37fafb02 | ||
| 
						 | 
					46ce882daa | ||
| 
						 | 
					6d14cbdb9b | ||
| 
						 | 
					4bf6b433ae | ||
| 
						 | 
					87a1b2e6f8 | ||
| 
						 | 
					c6ee48ec85 | ||
| 
						 | 
					b58a6b1649 | ||
| 
						 | 
					bd9736df93 | ||
| 
						 | 
					3b9c966e3d | ||
| 
						 | 
					96c9a89171 | ||
| 
						 | 
					c374ffd15e | ||
| 
						 | 
					c53109e1a1 | ||
| 
						 | 
					4598b3a7a6 | ||
| 
						 | 
					cf975b74bf | ||
| 
						 | 
					5d65dcf3c8 | ||
| 
						 | 
					f299ec1f8d | ||
| 
						 | 
					6677034774 | ||
| 
						 | 
					3c7c4639a9 | ||
| 
						 | 
					7e9a1268a5 | ||
| 
						 | 
					a60b8e68ca | ||
| 
						 | 
					b2161aa67e | ||
| 
						 | 
					d1fffb1d08 | ||
| 
						 | 
					52d66d9555 | ||
| 
						 | 
					66f2d359e2 | ||
| 
						 | 
					8327f33ee6 | ||
| 
						 | 
					d4a94551d9 | ||
| 
						 | 
					d2a545d83e | ||
| 
						 | 
					aee4eac271 | ||
| 
						 | 
					cbeddb11bc | ||
| 
						 | 
					4c51cf8316 | ||
| 
						 | 
					345cd6bd92 | ||
| 
						 | 
					48540245b5 | ||
| 
						 | 
					088bd9434d | ||
| 
						 | 
					8ba8c58377 | ||
| 
						 | 
					4ae43d0503 | ||
| 
						 | 
					00fdb90adf | ||
| 
						 | 
					f8257e697a | ||
| 
						 | 
					0ddfd3bead | ||
| 
						 | 
					4797d1ea10 | ||
| 
						 | 
					d20ce3dde7 | ||
| 
						 | 
					ef5f7ec9c3 | ||
| 
						 | 
					69c60c4026 | ||
| 
						 | 
					2f4f2083ba | ||
| 
						 | 
					77ada0471b | ||
| 
						 | 
					00cab46a0d | ||
| 
						 | 
					7f7460f3f3 | ||
| 
						 | 
					c225eef9ad | ||
| 
						 | 
					460f920502 | ||
| 
						 | 
					c7677e5514 | ||
| 
						 | 
					12fb39baa9 | ||
| 
						 | 
					201fd22861 | ||
| 
						 | 
					d0fb85e712 | ||
| 
						 | 
					81cbd00cc8 | ||
| 
						 | 
					4a565b5ea0 | ||
| 
						 | 
					82f61eee12 | ||
| 
						 | 
					88fc7ff9c3 | ||
| 
						 | 
					8eb17bf104 | ||
| 
						 | 
					9a8fc80220 | ||
| 
						 | 
					e5e652fad2 | ||
| 
						 | 
					924d077315 | ||
| 
						 | 
					44a7505295 | ||
| 
						 | 
					b1a6fa4084 | ||
| 
						 | 
					0665fc0a6f | ||
| 
						 | 
					4bf5fd49d6 | ||
| 
						 | 
					0a6bc99ecd | ||
| 
						 | 
					45cc617fc5 | ||
| 
						 | 
					6dc5eabdf0 | ||
| 
						 | 
					48d3bc55bf | ||
| 
						 | 
					6b7e81d7fb | ||
| 
						 | 
					dce6248193 | ||
| 
						 | 
					0e349ede4c | ||
| 
						 | 
					60117471a7 | ||
| 
						 | 
					3c23e7b047 | ||
| 
						 | 
					b48e1ba9e0 | ||
| 
						 | 
					1267191e8e | ||
| 
						 | 
					65a43b64ae | ||
| 
						 | 
					09e446a26e | ||
| 
						 | 
					2ecb3059e5 | ||
| 
						 | 
					237cb42695 | ||
| 
						 | 
					49b6bbff37 | ||
| 
						 | 
					5e05083008 | ||
| 
						 | 
					339e9cca10 | ||
| 
						 | 
					d441ad8875 | ||
| 
						 | 
					72fc6bf913 | ||
| 
						 | 
					fcf278c61c | ||
| 
						 | 
					890404ded5 | ||
| 
						 | 
					6fd9b47c45 | ||
| 
						 | 
					003651ec68 | ||
| 
						 | 
					c63a761ca4 | ||
| 
						 | 
					32dcd1551b | ||
| 
						 | 
					90fbdd5fab | ||
| 
						 | 
					1fea200582 | ||
| 
						 | 
					55b8a62f64 | ||
| 
						 | 
					a8906bf58f | ||
| 
						 | 
					0d6b9263d4 | ||
| 
						 | 
					f091a54ca6 | ||
| 
						 | 
					5262929c16 | ||
| 
						 | 
					c1ca8a3ae6 | ||
| 
						 | 
					a7e36472d5 | ||
| 
						 | 
					538a22e2f7 | ||
| 
						 | 
					0c40a3e79c | ||
| 
						 | 
					3cb098f9ba | ||
| 
						 | 
					ea1ab029f3 | ||
| 
						 | 
					92a76a6d39 | ||
| 
						 | 
					c451950dbf | ||
| 
						 | 
					644adc43ed | ||
| 
						 | 
					63a7340c21 | ||
| 
						 | 
					6824f00867 | ||
| 
						 | 
					3cb48b40aa | ||
| 
						 | 
					dda713a6be | ||
| 
						 | 
					415aa82a6f | ||
| 
						 | 
					4ae664fd93 | ||
| 
						 | 
					5d1e304642 | ||
| 
						 | 
					6b228d7a0a | ||
| 
						 | 
					085ad5f2a4 | ||
| 
						 | 
					e40e6bd07f | ||
| 
						 | 
					a6db36e7b3 | ||
| 
						 | 
					1a4caccd07 | ||
| 
						 | 
					7f1017ebd9 | ||
| 
						 | 
					f792cd2677 | ||
| 
						 | 
					1361cab603 | ||
| 
						 | 
					05b784d203 | ||
| 
						 | 
					542c3e38f5 | ||
| 
						 | 
					bcdead1eca | ||
| 
						 | 
					a79a927a13 | ||
| 
						 | 
					5bcc9071f6 | ||
| 
						 | 
					88869ff6d4 | ||
| 
						 | 
					1655505b95 | ||
| 
						 | 
					9abfa3726e | ||
| 
						 | 
					89a4abf9cf | ||
| 
						 | 
					854afc6de3 | ||
| 
						 | 
					03048797c5 | ||
| 
						 | 
					2478ccd8ef | ||
| 
						 | 
					827cfd818e | ||
| 
						 | 
					b0e0cd6a1f | ||
| 
						 | 
					003e919bd5 | ||
| 
						 | 
					56dadfc228 | ||
| 
						 | 
					b70603e92b | ||
| 
						 | 
					6294bc4505 | ||
| 
						 | 
					326bc931ad | ||
| 
						 | 
					734913f638 | ||
| 
						 | 
					157a525ec1 | ||
| 
						 | 
					352abe07d8 | ||
| 
						 | 
					0111ed37ba | ||
| 
						 | 
					079c4c955c | ||
| 
						 | 
					922715480e | ||
| 
						 | 
					99ca175e9a | ||
| 
						 | 
					c1fefb7e13 | ||
| 
						 | 
					31495d484d | ||
| 
						 | 
					1c6ae0bd88 | ||
| 
						 | 
					177aadbb45 | ||
| 
						 | 
					a6868acfa0 | ||
| 
						 | 
					907d46a28b | ||
| 
						 | 
					87dda265f4 | ||
| 
						 | 
					7106882212 | ||
| 
						 | 
					59e5f3d27e | ||
| 
						 | 
					b2eba66bff | ||
| 
						 | 
					b8b5509d49 | ||
| 
						 | 
					e667e302dc | ||
| 
						 | 
					ba68a13712 | ||
| 
						 | 
					c562c6f23a | ||
| 
						 | 
					fad79e51ac | ||
| 
						 | 
					9438d68dae | ||
| 
						 | 
					39b761ea16 | ||
| 
						 | 
					64689cf59d | ||
| 
						 | 
					17f80e4e53 | ||
| 
						 | 
					4117e233b3 | ||
| 
						 | 
					6c0bb3781a | ||
| 
						 | 
					eb55fe1fe3 | ||
| 
						 | 
					dc396d5cf7 | ||
| 
						 | 
					80ec4407bc | ||
| 
						 | 
					1e45374d41 | ||
| 
						 | 
					92ae233f39 | ||
| 
						 | 
					d3f8eb09d0 | ||
| 
						 | 
					058ef8495b | ||
| 
						 | 
					e2ac8eb43c | ||
| 
						 | 
					56121e39e2 | ||
| 
						 | 
					57bc2c459b | ||
| 
						 | 
					311beacfff | ||
| 
						 | 
					67e9c65313 | ||
| 
						 | 
					9a0257caaa | ||
| 
						 | 
					a121fb8c6e | ||
| 
						 | 
					a044f9a4a4 | ||
| 
						 | 
					0b7a2d7b34 | ||
| 
						 | 
					07ba160119 | ||
| 
						 | 
					d887c86cd4 | ||
| 
						 | 
					372af03d9e | ||
| 
						 | 
					aed6a6f142 | ||
| 
						 | 
					f5fa89bafe | ||
| 
						 | 
					6a1d181a34 | ||
| 
						 | 
					dbcd8c27c5 | ||
| 
						 | 
					2764be5d32 | ||
| 
						 | 
					d69c534614 | ||
| 
						 | 
					f436d6e48c | ||
| 
						 | 
					e49fcd12fa | ||
| 
						 | 
					f2699c4f1e | ||
| 
						 | 
					2319243444 | ||
| 
						 | 
					8e44e6625a | ||
| 
						 | 
					4cd87ab08a | ||
| 
						 | 
					98a125eb06 | ||
| 
						 | 
					7c690695b9 | ||
| 
						 | 
					066a12edaa | ||
| 
						 | 
					4c0971800d | ||
| 
						 | 
					c375b73db9 | ||
| 
						 | 
					a392b84d9b | ||
| 
						 | 
					34f034c6c4 | ||
| 
						 | 
					f5640b970b | ||
| 
						 | 
					b7028f20e6 | ||
| 
						 | 
					0cb059e59f | ||
| 
						 | 
					8d90a974c6 | ||
| 
						 | 
					d44b83e60d | ||
| 
						 | 
					ac7493fdc0 | ||
| 
						 | 
					c6c2553b42 | ||
| 
						 | 
					7d5460f8d1 | ||
| 
						 | 
					f9fa8a3616 | ||
| 
						 | 
					6c117df0a3 | ||
| 
						 | 
					b8bf08eace | ||
| 
						 | 
					027af76d5d | ||
| 
						 | 
					b7eee599f4 | ||
| 
						 | 
					42a350156a | ||
| 
						 | 
					f382b70cdf | ||
| 
						 | 
					f753929e87 | ||
| 
						 | 
					b3c5ab0b4e | ||
| 
						 | 
					9d8adcc511 | ||
| 
						 | 
					1afa9ce697 | ||
| 
						 | 
					b91edac0ba | ||
| 
						 | 
					5d6f031973 | ||
| 
						 | 
					72c56ee337 | ||
| 
						 | 
					72498a200a | ||
| 
						 | 
					1e9e95754c | ||
| 
						 | 
					eb99cd895c | ||
| 
						 | 
					5625cf5254 | ||
| 
						 | 
					9c6dc0a2f8 | ||
| 
						 | 
					3458874a68 | ||
| 
						 | 
					4e93b43d8d | ||
| 
						 | 
					b895545ec3 | ||
| 
						 | 
					92316c4d83 | ||
| 
						 | 
					af71409cab | ||
| 
						 | 
					df5a60d946 | ||
| 
						 | 
					0181ab1c03 | ||
| 
						 | 
					1a5ccca67a | ||
| 
						 | 
					99e1a90729 | ||
| 
						 | 
					54e11e96e9 | ||
| 
						 | 
					b339a776fc | ||
| 
						 | 
					db1a84b490 | ||
| 
						 | 
					3256b4f627 | ||
| 
						 | 
					c16ab349b1 | ||
| 
						 | 
					a981cb72d0 | ||
| 
						 | 
					5251a5f195 | ||
| 
						 | 
					917d5d2dd2 | ||
| 
						 | 
					983f6caf46 | ||
| 
						 | 
					c9a58e9d57 | ||
| 
						 | 
					c5fd24496f | ||
| 
						 | 
					0d502933ae | ||
| 
						 | 
					cc4bb3a5ec | ||
| 
						 | 
					b42f82ecb1 | ||
| 
						 | 
					b6beaae7da | ||
| 
						 | 
					e698900497 | ||
| 
						 | 
					bbad2fc1ba | ||
| 
						 | 
					e9f5087eb6 | ||
| 
						 | 
					c1caa22524 | ||
| 
						 | 
					5303903f89 | ||
| 
						 | 
					27d520e42a | ||
| 
						 | 
					8607f4af57 | ||
| 
						 | 
					f0ec8bd5b9 | ||
| 
						 | 
					9007e264cf | ||
| 
						 | 
					529bd6fa33 | ||
| 
						 | 
					eb8827bdf2 | ||
| 
						 | 
					be78d91a07 | ||
| 
						 | 
					20b7008994 | ||
| 
						 | 
					84d7b1d4ba | ||
| 
						 | 
					0154ed46e8 | ||
| 
						 | 
					5a11fa4704 | ||
| 
						 | 
					8b9e153ac4 | ||
| 
						 | 
					badc7366c2 | ||
| 
						 | 
					24ef479913 | ||
| 
						 | 
					1dd94a7d82 | ||
| 
						 | 
					40d5d92dbc | ||
| 
						 | 
					0cc3433d6d | ||
| 
						 | 
					0e157af8d9 | ||
| 
						 | 
					0e719c2b86 | ||
| 
						 | 
					82fd336792 | ||
| 
						 | 
					e733dc90d8 | ||
| 
						 | 
					9985d80432 | ||
| 
						 | 
					7177a781dc | ||
| 
						 | 
					498558c2b1 | ||
| 
						 | 
					c8e6795a90 | ||
| 
						 | 
					1edc51c067 | ||
| 
						 | 
					6f7054c4b2 | ||
| 
						 | 
					03d2a3a685 | ||
| 
						 | 
					1d4dccf454 | ||
| 
						 | 
					cb93890d13 | ||
| 
						 | 
					f39b2801b8 | ||
| 
						 | 
					073a8f5fbd | ||
| 
						 | 
					669c19882a | ||
| 
						 | 
					43ca6437ab | ||
| 
						 | 
					e61a1ea582 | ||
| 
						 | 
					a477655270 | ||
| 
						 | 
					88e1acfdff | ||
| 
						 | 
					39e1dcb900 | ||
| 
						 | 
					2489b93de8 | ||
| 
						 | 
					8eb25a911d | ||
| 
						 | 
					2d5e91b853 | ||
| 
						 | 
					4f8c68c40d | ||
| 
						 | 
					9a5c66a311 | ||
| 
						 | 
					69bb6a74b8 | ||
| 
						 | 
					7aa5fc91cf | ||
| 
						 | 
					de0b53de62 | ||
| 
						 | 
					a1df18e3ca | ||
| 
						 | 
					6a4c85245d | ||
| 
						 | 
					52a121c9ed | ||
| 
						 | 
					2acda695ba | ||
| 
						 | 
					89953d9e84 | ||
| 
						 | 
					7054a0eded | ||
| 
						 | 
					6105e16b28 | ||
| 
						 | 
					eb9d0dbbd4 | ||
| 
						 | 
					567b074792 | ||
| 
						 | 
					416c70f5e5 | ||
| 
						 | 
					30681dfa2c | ||
| 
						 | 
					c5b78ffa99 | ||
| 
						 | 
					cb5e859c34 | ||
| 
						 | 
					4470fb4312 | ||
| 
						 | 
					da11fad696 | ||
| 
						 | 
					72ae4b2b53 | ||
| 
						 | 
					b8e72039b9 | ||
| 
						 | 
					878ccd5128 | ||
| 
						 | 
					45e0946b6b | ||
| 
						 | 
					b57af55b8a | ||
| 
						 | 
					677ee5da91 | ||
| 
						 | 
					a6526ccc13 | ||
| 
						 | 
					8323593720 | ||
| 
						 | 
					dd00a69018 | ||
| 
						 | 
					4d7ddf3d9e | ||
| 
						 | 
					fbc39a41f8 | ||
| 
						 | 
					3e934a8527 | ||
| 
						 | 
					bc474724c6 | ||
| 
						 | 
					553eccf029 | ||
| 
						 | 
					63e344d6cf | ||
| 
						 | 
					0dc992561e | ||
| 
						 | 
					77006d5736 | ||
| 
						 | 
					359f5583a6 | ||
| 
						 | 
					58dbb1c7ef | ||
| 
						 | 
					47ac8238f7 | ||
| 
						 | 
					fa760b702c | ||
| 
						 | 
					2a6ebe2c04 | ||
| 
						 | 
					3e97faa704 | ||
| 
						 | 
					a9e82676c7 | ||
| 
						 | 
					d755fd9c08 | ||
| 
						 | 
					c4f1d7bccb | ||
| 
						 | 
					b55ebe95d9 | ||
| 
						 | 
					cb5c0d5ebe | ||
| 
						 | 
					404f583dc2 | ||
| 
						 | 
					19cd5638ba | ||
| 
						 | 
					b917552ca5 | ||
| 
						 | 
					71deb14c85 | ||
| 
						 | 
					e9c1041d9b | ||
| 
						 | 
					ffece005c5 | ||
| 
						 | 
					ff5d22adbe | ||
| 
						 | 
					aaffe1b208 | ||
| 
						 | 
					b86d2466d2 | ||
| 
						 | 
					c2230d0462 | ||
| 
						 | 
					dc4e4aa9c7 | ||
| 
						 | 
					56e5b4e529 | ||
| 
						 | 
					3577812dd1 | ||
| 
						 | 
					256c42833a | ||
| 
						 | 
					372a9075d7 | ||
| 
						 | 
					9a5d0db3d4 | ||
| 
						 | 
					82fe952d7f | ||
| 
						 | 
					da8382236f | ||
| 
						 | 
					4d2d03b8fc | ||
| 
						 | 
					b025e6bb88 | ||
| 
						 | 
					521bbd4ea5 | ||
| 
						 | 
					95d5d42608 | ||
| 
						 | 
					90884d8877 | ||
| 
						 | 
					62258be400 | ||
| 
						 | 
					8cbdce1d5b | ||
| 
						 | 
					9099d59c08 | ||
| 
						 | 
					f6bcc37168 | ||
| 
						 | 
					0db1ddc788 | ||
| 
						 | 
					93821c8991 | ||
| 
						 | 
					195c4ca3e5 | ||
| 
						 | 
					f6023ebbd0 | ||
| 
						 | 
					41dde0e516 | ||
| 
						 | 
					07b1719b17 | ||
| 
						 | 
					d31399702b | ||
| 
						 | 
					601e220b18 | ||
| 
						 | 
					246e580bb5 | ||
| 
						 | 
					e141267cfb | ||
| 
						 | 
					eb21f33f99 | ||
| 
						 | 
					f91ddaeec7 | ||
| 
						 | 
					afc432078c | ||
| 
						 | 
					4ba30fcfec | ||
| 
						 | 
					d7fd99cad6 | ||
| 
						 | 
					eaab2a3ec4 | ||
| 
						 | 
					1f938457db | ||
| 
						 | 
					855a9d5224 | ||
| 
						 | 
					d1a9531175 | ||
| 
						 | 
					58aacd3f28 | ||
| 
						 | 
					4aee2732bc | ||
| 
						 | 
					24a3468928 | ||
| 
						 | 
					dff7502a92 | ||
| 
						 | 
					c34f4bff08 | ||
| 
						 | 
					5753cd4877 | ||
| 
						 | 
					0949cf254f | ||
| 
						 | 
					935a68d871 | ||
| 
						 | 
					7592556e4d | ||
| 
						 | 
					e3f06cbdd4 | ||
| 
						 | 
					5397482ca3 | ||
| 
						 | 
					eafb5d9f7f | ||
| 
						 | 
					5efbb38270 | ||
| 
						 | 
					c4603e1230 | ||
| 
						 | 
					c6fd31564d | ||
| 
						 | 
					c4d72d3c11 | ||
| 
						 | 
					d7ce10001b | ||
| 
						 | 
					4220a3fedd | ||
| 
						 | 
					65100a18d2 | ||
| 
						 | 
					d913b0910b | ||
| 
						 | 
					968184fa7a | ||
| 
						 | 
					7e2d300017 | ||
| 
						 | 
					6cf86a4797 | ||
| 
						 | 
					feb5eac02e | ||
| 
						 | 
					a107d4f17f | ||
| 
						 | 
					5e4c7719ff | ||
| 
						 | 
					00d30fe26b | ||
| 
						 | 
					f2083ed5e9 | ||
| 
						 | 
					6ac98d02a7 | ||
| 
						 | 
					8baf4ffd2f | ||
| 
						 | 
					632357ff9d | ||
| 
						 | 
					074714180b | ||
| 
						 | 
					bd62b7a9bf | ||
| 
						 | 
					49723d05cf | ||
| 
						 | 
					f75422a412 | ||
| 
						 | 
					5e8f35c94e | ||
| 
						 | 
					15eb88e922 | ||
| 
						 | 
					9a299b758a | ||
| 
						 | 
					21afc26b68 | ||
| 
						 | 
					5c68b47a29 | ||
| 
						 | 
					adff739a5d | ||
| 
						 | 
					0da3d8b231 | ||
| 
						 | 
					3c17e74f6d | ||
| 
						 | 
					bf35983ebb | ||
| 
						 | 
					cc31b325ea | ||
| 
						 | 
					7c0eb464c1 | ||
| 
						 | 
					8884ca09fa | ||
| 
						 | 
					287f0d8909 | ||
| 
						 | 
					26c20e2262 | ||
| 
						 | 
					b062582d15 | ||
| 
						 | 
					fb66e49a1f | ||
| 
						 | 
					79e37f2c18 | ||
| 
						 | 
					9ab1dae553 | ||
| 
						 | 
					c5ad0b4bec | ||
| 
						 | 
					606d1012d3 | ||
| 
						 | 
					45f2d98f3c | ||
| 
						 | 
					5cf15a9b11 | ||
| 
						 | 
					178aa9d32f | ||
| 
						 | 
					29f181f9bf | ||
| 
						 | 
					86c5cccb08 | ||
| 
						 | 
					ea8af83d61 | ||
| 
						 | 
					d303067deb | ||
| 
						 | 
					6e817e2d7c | ||
| 
						 | 
					16277f803c | ||
| 
						 | 
					ef55e10ff2 | ||
| 
						 | 
					aaccd648b3 | ||
| 
						 | 
					9596cbd85a | ||
| 
						 | 
					5b6320b61a | ||
| 
						 | 
					4de4fdc0d1 | ||
| 
						 | 
					77a0c9f341 | ||
| 
						 | 
					fc7859dc27 | ||
| 
						 | 
					39d6b0525f | ||
| 
						 | 
					51e091ded6 | ||
| 
						 | 
					52407848c1 | ||
| 
						 | 
					a6e2511e6b | ||
| 
						 | 
					422f3ba8c8 | ||
| 
						 | 
					276282e847 | ||
| 
						 | 
					7782e27cc5 | ||
| 
						 | 
					4f0a178984 | ||
| 
						 | 
					28ddda4635 | ||
| 
						 | 
					36e20ec396 | ||
| 
						 | 
					22e65227fb | ||
| 
						 | 
					9ea68b66f7 | ||
| 
						 | 
					7d93692468 | ||
| 
						 | 
					93121275ae | ||
| 
						 | 
					07b48b2e0d | ||
| 
						 | 
					294672d946 | ||
| 
						 | 
					ba3f806616 | ||
| 
						 | 
					9e4d99faca | ||
| 
						 | 
					e89648200b | ||
| 
						 | 
					3c305e8a37 | ||
| 
						 | 
					6cfe69634c | ||
| 
						 | 
					61be3714a5 | ||
| 
						 | 
					0aed615ee5 | ||
| 
						 | 
					6797037bdb | ||
| 
						 | 
					39f8b25fd8 | ||
| 
						 | 
					96214bf3fd | ||
| 
						 | 
					400cd87802 | ||
| 
						 | 
					00c458db1e | ||
| 
						 | 
					1454e200db | ||
| 
						 | 
					752875061c | ||
| 
						 | 
					78186d8a45 | ||
| 
						 | 
					a4ef434f11 | ||
| 
						 | 
					9842c9945d | ||
| 
						 | 
					6dcd97dedf | ||
| 
						 | 
					549a984eab | ||
| 
						 | 
					aa805f81e0 | ||
| 
						 | 
					93a67dadf6 | ||
| 
						 | 
					e9286f6ae9 | ||
| 
						 | 
					a31fcdb753 | ||
| 
						 | 
					0edca836f0 | ||
| 
						 | 
					8537f291b7 | ||
| 
						 | 
					46611ec720 | ||
| 
						 | 
					cbc3db8100 | ||
| 
						 | 
					7d5b07bf37 | ||
| 
						 | 
					5bd633d5bb | ||
| 
						 | 
					17fdad1d6e | ||
| 
						 | 
					1ad26671b0 | ||
| 
						 | 
					2dc5064409 | ||
| 
						 | 
					79eec41bcd | ||
| 
						 | 
					386d22a45e | ||
| 
						 | 
					d90fcbf7ad | ||
| 
						 | 
					c4e4520058 | ||
| 
						 | 
					dd49f01499 | ||
| 
						 | 
					2c698cee71 | ||
| 
						 | 
					87cb4b6d18 | ||
| 
						 | 
					2b7c747209 | ||
| 
						 | 
					707308b490 | ||
| 
						 | 
					ed1012bf07 | ||
| 
						 | 
					cc5b2bc27b | ||
| 
						 | 
					a1a7cfa735 | ||
| 
						 | 
					4624ff92df | ||
| 
						 | 
					47dde98728 | ||
| 
						 | 
					6f1031e95b | ||
| 
						 | 
					d5245e3784 | ||
| 
						 | 
					d97e72edb6 | ||
| 
						 | 
					23b9e9ef5f | ||
| 
						 | 
					02c7b86f85 | ||
| 
						 | 
					f796b6b40d | ||
| 
						 | 
					528454c361 | ||
| 
						 | 
					9ae3f7e61d | ||
| 
						 | 
					dd33922810 | ||
| 
						 | 
					b52fdb3155 | ||
| 
						 | 
					edf9f9e714 | ||
| 
						 | 
					38eda6ed3c | ||
| 
						 | 
					32f0c5dc09 | ||
| 
						 | 
					b45b45b1b3 | ||
| 
						 | 
					f1c60b7177 | ||
| 
						 | 
					2d8ff826f3 | ||
| 
						 | 
					d028db1ba3 | ||
| 
						 | 
					2d4e2b87bc | ||
| 
						 | 
					1d7a75c7b3 | ||
| 
						 | 
					65584a953d | ||
| 
						 | 
					4cbd19d2e5 | ||
| 
						 | 
					a59b59fea4 | ||
| 
						 | 
					5c063a9de3 | ||
| 
						 | 
					3666a7d7bd | ||
| 
						 | 
					8250112c7f | ||
| 
						 | 
					30957f4105 | ||
| 
						 | 
					eade2e279e | ||
| 
						 | 
					b4489b9402 | ||
| 
						 | 
					a67b7c80c1 | ||
| 
						 | 
					dfc0cdd0fa | ||
| 
						 | 
					d6faf5b074 | ||
| 
						 | 
					44ffa6a3b0 | ||
| 
						 | 
					168b78d9d7 | ||
| 
						 | 
					bd8f313ccb | ||
| 
						 | 
					4a0fc3d566 | ||
| 
						 | 
					8d04d17e39 | ||
| 
						 | 
					9f44b1e783 | ||
| 
						 | 
					1b15271fe2 | ||
| 
						 | 
					f451d3203c | ||
| 
						 | 
					c713d38c19 | ||
| 
						 | 
					4d51f9d097 | ||
| 
						 | 
					8750341862 | ||
| 
						 | 
					3a4fe086ea | ||
| 
						 | 
					212e457c4c | ||
| 
						 | 
					790e2b534f | ||
| 
						 | 
					48414f0ce9 | ||
| 
						 | 
					b5c3e75f10 | ||
| 
						 | 
					548e07ce17 | ||
| 
						 | 
					0aa0c6866c | ||
| 
						 | 
					3d4cf7df26 | ||
| 
						 | 
					c4ba180a0c | ||
| 
						 | 
					bd392b91b7 | ||
| 
						 | 
					042f7b0502 | ||
| 
						 | 
					0fc5f0ee7d | ||
| 
						 | 
					8cbef669b1 | ||
| 
						 | 
					f9004fb14c | ||
| 
						 | 
					40a42c65c1 | ||
| 
						 | 
					e14030e369 | ||
| 
						 | 
					c6cef191a7 | ||
| 
						 | 
					6ca9f83bfe | ||
| 
						 | 
					b3fcdc5f40 | ||
| 
						 | 
					c6591cc11a | ||
| 
						 | 
					e31ba479b2 | ||
| 
						 | 
					659b668012 | ||
| 
						 | 
					d69944dd8c | ||
| 
						 | 
					a25111e411 | ||
| 
						 | 
					6866d5d3fa | ||
| 
						 | 
					21b3d1c521 | ||
| 
						 | 
					f2bdd1cc49 | ||
| 
						 | 
					9f09794ae6 | ||
| 
						 | 
					6a1fb3d829 | ||
| 
						 | 
					631b9768af | ||
| 
						 | 
					a2d9db85cb | ||
| 
						 | 
					4cb9d0b50a | ||
| 
						 | 
					73f37ef289 | ||
| 
						 | 
					dbda19a209 | ||
| 
						 | 
					0d7de7bbc0 | ||
| 
						 | 
					649b78611c | ||
| 
						 | 
					22a21d76a4 | ||
| 
						 | 
					5668a74aef | ||
| 
						 | 
					482638601a | ||
| 
						 | 
					1bfe518f74 | ||
| 
						 | 
					eeb5ba40fb | ||
| 
						 | 
					33bd912476 | ||
| 
						 | 
					33f1084f0a | ||
| 
						 | 
					e8a9b7cae3 | ||
| 
						 | 
					f6b1d9c493 | ||
| 
						 | 
					624c34b378 | ||
| 
						 | 
					bc6753e5bf | ||
| 
						 | 
					c539debc84 | ||
| 
						 | 
					830f4cec0f | ||
| 
						 | 
					03dd9e6e83 | ||
| 
						 | 
					e8d1c90182 | ||
| 
						 | 
					0933dc1afa | ||
| 
						 | 
					610b7fe95c | ||
| 
						 | 
					a6bf6f901f | ||
| 
						 | 
					ca2e37e852 | ||
| 
						 | 
					d1ffaaa327 | ||
| 
						 | 
					8b7f551505 | ||
| 
						 | 
					759b3f8fcd | ||
| 
						 | 
					9ec56f1dfa | ||
| 
						 | 
					84e997949f | ||
| 
						 | 
					f82bd45fec | ||
| 
						 | 
					3863724007 | ||
| 
						 | 
					7e0ed9fe93 | ||
| 
						 | 
					945e3f3c5f | ||
| 
						 | 
					6f100219f7 | ||
| 
						 | 
					89688394f8 | ||
| 
						 | 
					091ef6d972 | ||
| 
						 | 
					e501c44985 | ||
| 
						 | 
					bc9b761903 | ||
| 
						 | 
					dfb461b05c | ||
| 
						 | 
					86f6a2f722 | ||
| 
						 | 
					77d6d0d5be | ||
| 
						 | 
					4946909c6d | ||
| 
						 | 
					2439736cb4 | ||
| 
						 | 
					8fb2ad1986 | ||
| 
						 | 
					1d7bbcec66 | ||
| 
						 | 
					6ac9d34aac | ||
| 
						 | 
					3369029e9a | ||
| 
						 | 
					11f411b745 | ||
| 
						 | 
					9bb6e15900 | ||
| 
						 | 
					d2a6b37f5f | ||
| 
						 | 
					0c1f6163f7 | ||
| 
						 | 
					6860317a58 | ||
| 
						 | 
					77257b0989 | ||
| 
						 | 
					8f35da5163 | ||
| 
						 | 
					82d8c40b5f | ||
| 
						 | 
					dbfc0f98c3 | ||
| 
						 | 
					ca15bf4a92 | ||
| 
						 | 
					3e4d4cc002 | ||
| 
						 | 
					4257544402 | ||
| 
						 | 
					83d44bd03e | ||
| 
						 | 
					745e0685a4 | ||
| 
						 | 
					d6db2128df | ||
| 
						 | 
					6e83ed5654 | ||
| 
						 | 
					a4f44933ec | ||
| 
						 | 
					fe080e1d90 | ||
| 
						 | 
					dd462873d2 | ||
| 
						 | 
					628fec2c92 | ||
| 
						 | 
					c4700f3cb8 | ||
| 
						 | 
					fac606c475 | ||
| 
						 | 
					5a0aadabc1 | ||
| 
						 | 
					283b9871cb | ||
| 
						 | 
					f9d88cc2a0 | ||
| 
						 | 
					c751810b84 | ||
| 
						 | 
					2dbc9c39b1 | ||
| 
						 | 
					a9933c7764 | ||
| 
						 | 
					ffcac3a12d | ||
| 
						 | 
					a4130e5f78 | ||
| 
						 | 
					de8f8b7d91 | ||
| 
						 | 
					b8c58b12fd | ||
| 
						 | 
					4af355e1f9 | ||
| 
						 | 
					0e7e9d5643 | ||
| 
						 | 
					fafadc3333 | ||
| 
						 | 
					752c92bb21 | ||
| 
						 | 
					45d7b284e3 | ||
| 
						 | 
					085fca7e31 | ||
| 
						 | 
					8744114790 | ||
| 
						 | 
					c658a764d0 | ||
| 
						 | 
					6a07ba850c | ||
| 
						 | 
					c4e29e74b2 | ||
| 
						 | 
					40bca8b38c | ||
| 
						 | 
					18af881fe5 | ||
| 
						 | 
					dfd97d9fc5 | ||
| 
						 | 
					ebd2c329ff | ||
| 
						 | 
					265b169d43 | ||
| 
						 | 
					d154b1464f | ||
| 
						 | 
					a32ea6e5f8 | ||
| 
						 | 
					d7b21bf07e | ||
| 
						 | 
					d120790da7 | ||
| 
						 | 
					bd854d29a4 | ||
| 
						 | 
					d06e3db90b | ||
| 
						 | 
					5ada533b06 | ||
| 
						 | 
					6f5e648751 | ||
| 
						 | 
					9ee5b3eaf3 | ||
| 
						 | 
					0560da246b | ||
| 
						 | 
					8b6b3ee3b8 | ||
| 
						 | 
					45fe83951a | ||
| 
						 | 
					57e5d8911d | ||
| 
						 | 
					5768a766b8 | ||
| 
						 | 
					051e9e38f3 | ||
| 
						 | 
					63a5954dfa | ||
| 
						 | 
					897931f273 | ||
| 
						 | 
					03e80b2f1c | ||
| 
						 | 
					53c8ec864c | ||
| 
						 | 
					5d3002f118 | ||
| 
						 | 
					5eeb52660c | ||
| 
						 | 
					3dfafaa278 | ||
| 
						 | 
					462bd9ae5e | ||
| 
						 | 
					dab0fcc7c0 | ||
| 
						 | 
					b8a3e8085e | ||
| 
						 | 
					c9d1d72ba3 | ||
| 
						 | 
					ccf5d513d2 | ||
| 
						 | 
					d157b7b05d | ||
| 
						 | 
					05981ac46c | ||
| 
						 | 
					08615a5954 | ||
| 
						 | 
					b6dbe26c7e | ||
| 
						 | 
					4f0d61b379 | ||
| 
						 | 
					9e5e494f88 | ||
| 
						 | 
					b15fd05e8d | ||
| 
						 | 
					faabc28d1b | ||
| 
						 | 
					4b815846ee | ||
| 
						 | 
					fe8be18c4c | ||
| 
						 | 
					519c30321d | ||
| 
						 | 
					77be88a5bb | ||
| 
						 | 
					8d04931f9f | ||
| 
						 | 
					3d1ee7a43e | ||
| 
						 | 
					2584a25527 | ||
| 
						 | 
					0647a82d38 | ||
| 
						 | 
					c56459c98c | ||
| 
						 | 
					7b0a4a057d | ||
| 
						 | 
					3c3e520594 | ||
| 
						 | 
					ce1daf6a2b | ||
| 
						 | 
					68314cd44d | ||
| 
						 | 
					17787b97d4 | ||
| 
						 | 
					da84297b2c | ||
| 
						 | 
					e3e3bb770d | ||
| 
						 | 
					9d4f180741 | ||
| 
						 | 
					316836d9f6 | ||
| 
						 | 
					aa3b0a117a | ||
| 
						 | 
					0f7df3281f | ||
| 
						 | 
					4a91a35799 | ||
| 
						 | 
					36c2263675 | ||
| 
						 | 
					28068d8d31 | ||
| 
						 | 
					0c3c08db36 | ||
| 
						 | 
					bb5d62fe69 | ||
| 
						 | 
					376270dd53 | ||
| 
						 | 
					9056b23eaa | ||
| 
						 | 
					634be4ae51 | ||
| 
						 | 
					422620f4fe | ||
| 
						 | 
					ebb5c17be4 | ||
| 
						 | 
					1e99fe5b04 | ||
| 
						 | 
					66f82f764d | ||
| 
						 | 
					08c1671f21 | ||
| 
						 | 
					3b95e56418 | ||
| 
						 | 
					ce5fcaf172 | 
							
								
								
									
										44
									
								
								.clang-format
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								.clang-format
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,44 @@
 | 
				
			|||||||
 | 
					---
 | 
				
			||||||
 | 
					AccessModifierOffset: -4
 | 
				
			||||||
 | 
					AlignAfterOpenBracket: DontAlign
 | 
				
			||||||
 | 
					AlignArrayOfStructures: Left
 | 
				
			||||||
 | 
					AlignEscapedNewlines: Left
 | 
				
			||||||
 | 
					AllowAllArgumentsOnNextLine: 'true'
 | 
				
			||||||
 | 
					AllowAllConstructorInitializersOnNextLine: 'false'
 | 
				
			||||||
 | 
					AllowAllParametersOfDeclarationOnNextLine: 'true'
 | 
				
			||||||
 | 
					AllowShortBlocksOnASingleLine: 'true'
 | 
				
			||||||
 | 
					AllowShortCaseLabelsOnASingleLine: 'false'
 | 
				
			||||||
 | 
					AllowShortFunctionsOnASingleLine: Empty
 | 
				
			||||||
 | 
					AllowShortIfStatementsOnASingleLine: Never
 | 
				
			||||||
 | 
					AllowShortLambdasOnASingleLine: None
 | 
				
			||||||
 | 
					AllowShortLoopsOnASingleLine: 'false'
 | 
				
			||||||
 | 
					AlwaysBreakAfterDefinitionReturnType: None
 | 
				
			||||||
 | 
					AlwaysBreakAfterReturnType: None
 | 
				
			||||||
 | 
					AlwaysBreakBeforeMultilineStrings: 'true'
 | 
				
			||||||
 | 
					AlwaysBreakTemplateDeclarations: 'Yes'
 | 
				
			||||||
 | 
					BinPackArguments: 'false'
 | 
				
			||||||
 | 
					BinPackParameters: 'false'
 | 
				
			||||||
 | 
					BreakBeforeBraces: Allman
 | 
				
			||||||
 | 
					BreakConstructorInitializers: 'AfterColon'
 | 
				
			||||||
 | 
					BreakInheritanceList: AfterColon
 | 
				
			||||||
 | 
					BreakStringLiterals: 'true'
 | 
				
			||||||
 | 
					ColumnLimit: '80'
 | 
				
			||||||
 | 
					ConstructorInitializerAllOnOneLineOrOnePerLine: 'true'
 | 
				
			||||||
 | 
					FixNamespaceComments: 'false'
 | 
				
			||||||
 | 
					IncludeBlocks: Preserve
 | 
				
			||||||
 | 
					IndentCaseLabels: 'true'
 | 
				
			||||||
 | 
					IndentWidth: '4'
 | 
				
			||||||
 | 
					IndentWrappedFunctionNames: 'false'
 | 
				
			||||||
 | 
					KeepEmptyLinesAtTheStartOfBlocks: 'true'
 | 
				
			||||||
 | 
					NamespaceIndentation: All
 | 
				
			||||||
 | 
					PointerAlignment: Left
 | 
				
			||||||
 | 
					ReflowComments: 'true'
 | 
				
			||||||
 | 
					SortIncludes: 'false'
 | 
				
			||||||
 | 
					SortUsingDeclarations: 'true'
 | 
				
			||||||
 | 
					SpaceAfterTemplateKeyword: 'true'
 | 
				
			||||||
 | 
					SpaceBeforeAssignmentOperators: 'true'
 | 
				
			||||||
 | 
					SpaceBeforeCtorInitializerColon: 'false'
 | 
				
			||||||
 | 
					SpaceBeforeInheritanceColon: 'true'
 | 
				
			||||||
 | 
					SpaceBeforeParens: ControlStatements
 | 
				
			||||||
 | 
					SpaceInEmptyParentheses: 'false'
 | 
				
			||||||
 | 
					...
 | 
				
			||||||
							
								
								
									
										86
									
								
								.github/workflows/ccpp.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										86
									
								
								.github/workflows/ccpp.yml
									
									
									
									
										vendored
									
									
								
							@@ -2,28 +2,48 @@ name: C/C++ CI
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
on: [push]
 | 
					on: [push]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					concurrency: 
 | 
				
			||||||
 | 
					  group: environment-${{ github.head_ref }}
 | 
				
			||||||
 | 
					  cancel-in-progress: true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
jobs:
 | 
					jobs:
 | 
				
			||||||
  build-linux:
 | 
					  build-linux:
 | 
				
			||||||
    runs-on: ubuntu-latest
 | 
					    runs-on: ubuntu-22.04
 | 
				
			||||||
    steps:
 | 
					    steps:
 | 
				
			||||||
    - uses: actions/checkout@v1
 | 
					    - uses: actions/checkout@v2
 | 
				
			||||||
      with:
 | 
					      with:
 | 
				
			||||||
        fetch-depth: 1
 | 
					        repository: 'davidgiven/fluxengine'
 | 
				
			||||||
 | 
					        path: 'fluxengine'
 | 
				
			||||||
 | 
					    - uses: actions/checkout@v2
 | 
				
			||||||
 | 
					      with:
 | 
				
			||||||
 | 
					        repository: 'davidgiven/fluxengine-testdata'
 | 
				
			||||||
 | 
					        path: 'fluxengine-testdata'
 | 
				
			||||||
    - name: apt
 | 
					    - name: apt
 | 
				
			||||||
      run: sudo apt update && sudo apt install libusb-1.0-0-dev libsqlite3-dev ninja-build protobuf-compiler
 | 
					      run: sudo apt update && sudo apt install libudev-dev libsqlite3-dev protobuf-compiler libwxgtk3.0-gtk3-dev libfmt-dev
 | 
				
			||||||
    - name: make
 | 
					    - name: make
 | 
				
			||||||
      run: make
 | 
					      run: CXXFLAGS="-Wp,-D_GLIBCXX_ASSERTIONS" make -j2 -C fluxengine
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  build-macos:
 | 
					  build-macos-current:
 | 
				
			||||||
    runs-on: macos-latest
 | 
					    runs-on: macos-latest
 | 
				
			||||||
    steps:
 | 
					    steps:
 | 
				
			||||||
    - uses: actions/checkout@v2
 | 
					    - uses: actions/checkout@v2
 | 
				
			||||||
      with:
 | 
					      with:
 | 
				
			||||||
        fetch-depth: 1
 | 
					        repository: 'davidgiven/fluxengine'
 | 
				
			||||||
 | 
					        path: 'fluxengine'
 | 
				
			||||||
 | 
					    - uses: actions/checkout@v2
 | 
				
			||||||
 | 
					      with:
 | 
				
			||||||
 | 
					        repository: 'davidgiven/fluxengine-testdata'
 | 
				
			||||||
 | 
					        path: 'fluxengine-testdata'
 | 
				
			||||||
    - name: brew
 | 
					    - name: brew
 | 
				
			||||||
      run: brew install sqlite pkg-config libusb ninja protobuf truncate
 | 
					      run: brew install sqlite pkg-config libusb protobuf wxwidgets fmt make coreutils dylibbundler libjpeg
 | 
				
			||||||
    - name: make
 | 
					    - name: make
 | 
				
			||||||
      run: make
 | 
					      run: gmake -j2 -C fluxengine
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    - name: Upload build artifacts
 | 
				
			||||||
 | 
					      uses: actions/upload-artifact@v2
 | 
				
			||||||
 | 
					      with:
 | 
				
			||||||
 | 
					        name: ${{ github.event.repository.name }}.${{ github.sha }}
 | 
				
			||||||
 | 
					        path: fluxengine.FluxEngine.pkg
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  build-windows:
 | 
					  build-windows:
 | 
				
			||||||
    runs-on: windows-latest
 | 
					    runs-on: windows-latest
 | 
				
			||||||
@@ -36,19 +56,47 @@ jobs:
 | 
				
			|||||||
        update: true
 | 
					        update: true
 | 
				
			||||||
        msystem: MINGW32
 | 
					        msystem: MINGW32
 | 
				
			||||||
        install: >-
 | 
					        install: >-
 | 
				
			||||||
 | 
					          diffutils
 | 
				
			||||||
          make
 | 
					          make
 | 
				
			||||||
          ninja
 | 
					          mingw-w64-i686-fmt
 | 
				
			||||||
          mingw-w64-i686-libusb
 | 
					 | 
				
			||||||
          mingw-w64-i686-sqlite3
 | 
					 | 
				
			||||||
          mingw-w64-i686-zlib
 | 
					 | 
				
			||||||
          mingw-w64-i686-gcc
 | 
					          mingw-w64-i686-gcc
 | 
				
			||||||
          zip
 | 
					          mingw-w64-i686-libusb
 | 
				
			||||||
 | 
					          mingw-w64-i686-pkg-config
 | 
				
			||||||
          mingw-w64-i686-protobuf
 | 
					          mingw-w64-i686-protobuf
 | 
				
			||||||
 | 
					          mingw-w64-i686-sqlite3
 | 
				
			||||||
 | 
					          mingw-w64-i686-wxWidgets
 | 
				
			||||||
 | 
					          mingw-w64-i686-zlib
 | 
				
			||||||
 | 
					          mingw-w64-i686-nsis
 | 
				
			||||||
 | 
					          zip
 | 
				
			||||||
          vim
 | 
					          vim
 | 
				
			||||||
    - uses: actions/checkout@v1
 | 
					    - name: update-protobuf
 | 
				
			||||||
      with:
 | 
					 | 
				
			||||||
        fetch-depth: 1
 | 
					 | 
				
			||||||
    - name: build
 | 
					 | 
				
			||||||
      run: |
 | 
					      run: |
 | 
				
			||||||
        make
 | 
					         pacman -U --noconfirm https://repo.msys2.org/mingw/mingw32/mingw-w64-i686-protobuf-21.9-1-any.pkg.tar.zst
 | 
				
			||||||
 | 
					    - uses: actions/checkout@v2
 | 
				
			||||||
 | 
					      with:
 | 
				
			||||||
 | 
					        repository: 'davidgiven/fluxengine'
 | 
				
			||||||
 | 
					        path: 'fluxengine'
 | 
				
			||||||
 | 
					    - uses: actions/checkout@v2
 | 
				
			||||||
 | 
					      with:
 | 
				
			||||||
 | 
					        repository: 'davidgiven/fluxengine-testdata'
 | 
				
			||||||
 | 
					        path: 'fluxengine-testdata'
 | 
				
			||||||
 | 
					    - name: build
 | 
				
			||||||
 | 
					      run: make -j2 -C fluxengine
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    - name: nsis
 | 
				
			||||||
 | 
					      run: |
 | 
				
			||||||
 | 
					        cd fluxengine
 | 
				
			||||||
 | 
					        strip fluxengine.exe -o fluxengine-stripped.exe
 | 
				
			||||||
 | 
					        strip fluxengine-gui.exe -o fluxengine-gui-stripped.exe
 | 
				
			||||||
 | 
					        makensis -v2 -nocd -dOUTFILE=fluxengine-installer.exe extras/windows-installer.nsi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    - name: zip
 | 
				
			||||||
 | 
					      run: |
 | 
				
			||||||
 | 
					        cd fluxengine
 | 
				
			||||||
 | 
					        zip -9 fluxengine-windows.zip fluxengine.exe fluxengine-gui.exe upgrade-flux-file.exe brother120tool.exe brother240tool.exe FluxEngine.cydsn/CortexM3/ARM_GCC_541/Release/FluxEngine.hex fluxengine-installer.exe
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    - name: Upload build artifacts
 | 
				
			||||||
 | 
					      uses: actions/upload-artifact@v2
 | 
				
			||||||
 | 
					      with:
 | 
				
			||||||
 | 
					        name: ${{ github.event.repository.name }}.${{ github.sha }}
 | 
				
			||||||
 | 
					        path: fluxengine/fluxengine-windows.zip
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										84
									
								
								.github/workflows/release.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										84
									
								
								.github/workflows/release.yml
									
									
									
									
										vendored
									
									
								
							@@ -1,5 +1,9 @@
 | 
				
			|||||||
name: Autorelease
 | 
					name: Autorelease
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					concurrency: 
 | 
				
			||||||
 | 
					  group: environment-${{ github.head_ref }}
 | 
				
			||||||
 | 
					  cancel-in-progress: true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
on:
 | 
					on:
 | 
				
			||||||
  push:
 | 
					  push:
 | 
				
			||||||
    branches:
 | 
					    branches:
 | 
				
			||||||
@@ -17,33 +21,51 @@ jobs:
 | 
				
			|||||||
        update: true
 | 
					        update: true
 | 
				
			||||||
        msystem: MINGW32
 | 
					        msystem: MINGW32
 | 
				
			||||||
        install: >-
 | 
					        install: >-
 | 
				
			||||||
 | 
					          diffutils
 | 
				
			||||||
          make
 | 
					          make
 | 
				
			||||||
          ninja
 | 
					          mingw-w64-i686-fmt
 | 
				
			||||||
          mingw-w64-i686-libusb
 | 
					 | 
				
			||||||
          mingw-w64-i686-sqlite3
 | 
					 | 
				
			||||||
          mingw-w64-i686-zlib
 | 
					 | 
				
			||||||
          mingw-w64-i686-gcc
 | 
					          mingw-w64-i686-gcc
 | 
				
			||||||
          zip
 | 
					          mingw-w64-i686-libusb
 | 
				
			||||||
 | 
					          mingw-w64-i686-pkg-config
 | 
				
			||||||
          mingw-w64-i686-protobuf
 | 
					          mingw-w64-i686-protobuf
 | 
				
			||||||
 | 
					          mingw-w64-i686-sqlite3
 | 
				
			||||||
 | 
					          mingw-w64-i686-wxWidgets
 | 
				
			||||||
 | 
					          mingw-w64-i686-zlib
 | 
				
			||||||
 | 
					          mingw-w64-i686-nsis
 | 
				
			||||||
 | 
					          zip
 | 
				
			||||||
          vim
 | 
					          vim
 | 
				
			||||||
    - uses: actions/checkout@v2
 | 
					    - uses: actions/checkout@v3
 | 
				
			||||||
      with:
 | 
					
 | 
				
			||||||
        fetch-depth: 1
 | 
					    - name: update-protobuf
 | 
				
			||||||
 | 
					      run: |
 | 
				
			||||||
 | 
					         pacman -U --noconfirm https://repo.msys2.org/mingw/mingw32/mingw-w64-i686-protobuf-21.9-1-any.pkg.tar.zst
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    - name: build
 | 
					    - name: build
 | 
				
			||||||
      run: |
 | 
					      run: |
 | 
				
			||||||
        make
 | 
					        make -j2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    - name: nsis
 | 
				
			||||||
 | 
					      run: |
 | 
				
			||||||
 | 
					        strip fluxengine.exe -o fluxengine-stripped.exe
 | 
				
			||||||
 | 
					        strip fluxengine-gui.exe -o fluxengine-gui-stripped.exe
 | 
				
			||||||
 | 
					        makensis -v2 -nocd -dOUTFILE=fluxengine-installer.exe extras/windows-installer.nsi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    - name: zip
 | 
					    - name: zip
 | 
				
			||||||
      run: |
 | 
					      run: |
 | 
				
			||||||
        zip -9 fluxengine.zip fluxengine.exe brother120tool.exe brother240tool.exe FluxEngine.cydsn/CortexM3/ARM_GCC_541/Release/FluxEngine.hex
 | 
					        zip -9 fluxengine.zip fluxengine.exe fluxengine-gui.exe upgrade-flux-file.exe brother120tool.exe brother240tool.exe FluxEngine.cydsn/CortexM3/ARM_GCC_541/Release/FluxEngine.hex
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    - name: date
 | 
					    - name: date
 | 
				
			||||||
      run: |
 | 
					      run: |
 | 
				
			||||||
        echo "RELEASE_DATE=$(date --rfc-3339=date)" >> ${GITHUB_ENV}
 | 
					        echo "RELEASE_DATE=$(date --rfc-3339=date)" >> ${GITHUB_ENV}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    - name: tag
 | 
					    - name: tag
 | 
				
			||||||
      uses: EndBug/latest-tag@latest
 | 
					      uses: EndBug/latest-tag@latest
 | 
				
			||||||
      with:
 | 
					      with:
 | 
				
			||||||
        tag-name: dev
 | 
					        tag-name: dev
 | 
				
			||||||
 | 
					        force-branch: false
 | 
				
			||||||
      env:
 | 
					      env:
 | 
				
			||||||
        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
 | 
					        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    - name: delete-old-assets
 | 
					    - name: delete-old-assets
 | 
				
			||||||
      uses: mknejp/delete-release-assets@v1
 | 
					      uses: mknejp/delete-release-assets@v1
 | 
				
			||||||
      with:
 | 
					      with:
 | 
				
			||||||
@@ -51,13 +73,55 @@ jobs:
 | 
				
			|||||||
        tag: dev
 | 
					        tag: dev
 | 
				
			||||||
        assets: | 
 | 
					        assets: | 
 | 
				
			||||||
          fluxengine.zip
 | 
					          fluxengine.zip
 | 
				
			||||||
 | 
					          fluxengine-installer.exe
 | 
				
			||||||
        fail-if-no-assets: false
 | 
					        fail-if-no-assets: false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    - name: release
 | 
					    - name: release
 | 
				
			||||||
      uses: softprops/action-gh-release@v1
 | 
					      uses: softprops/action-gh-release@v1
 | 
				
			||||||
      with:
 | 
					      with:
 | 
				
			||||||
        name: Development build ${{ env.RELEASE_DATE }}
 | 
					        name: Development build ${{ env.RELEASE_DATE }}
 | 
				
			||||||
        files: |
 | 
					        files: |
 | 
				
			||||||
          fluxengine.zip
 | 
					          fluxengine.zip
 | 
				
			||||||
 | 
					          fluxengine-installer.exe
 | 
				
			||||||
        tag_name: dev
 | 
					        tag_name: dev
 | 
				
			||||||
      env:
 | 
					      env:
 | 
				
			||||||
        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
 | 
					        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  build-macos:
 | 
				
			||||||
 | 
					    runs-on: macos-latest
 | 
				
			||||||
 | 
					    steps:
 | 
				
			||||||
 | 
					    - uses: actions/checkout@v2
 | 
				
			||||||
 | 
					    - name: brew
 | 
				
			||||||
 | 
					      run: brew install sqlite pkg-config libusb protobuf wxwidgets fmt make coreutils dylibbundler libjpeg
 | 
				
			||||||
 | 
					    - name: make
 | 
				
			||||||
 | 
					      run: gmake
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    - name: tag
 | 
				
			||||||
 | 
					      uses: EndBug/latest-tag@latest
 | 
				
			||||||
 | 
					      with:
 | 
				
			||||||
 | 
					        tag-name: dev
 | 
				
			||||||
 | 
					        force-branch: false
 | 
				
			||||||
 | 
					      env:
 | 
				
			||||||
 | 
					        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    - name: delete-old-assets
 | 
				
			||||||
 | 
					      uses: mknejp/delete-release-assets@v1
 | 
				
			||||||
 | 
					      with:
 | 
				
			||||||
 | 
					        token: ${{ github.token }}
 | 
				
			||||||
 | 
					        tag: dev
 | 
				
			||||||
 | 
					        assets: | 
 | 
				
			||||||
 | 
					          FluxEngine.pkg
 | 
				
			||||||
 | 
					        fail-if-no-assets: false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    - name: release
 | 
				
			||||||
 | 
					      uses: softprops/action-gh-release@v1
 | 
				
			||||||
 | 
					      with:
 | 
				
			||||||
 | 
					        name: Development build ${{ env.RELEASE_DATE }}
 | 
				
			||||||
 | 
					        files: |
 | 
				
			||||||
 | 
					          FluxEngine.pkg
 | 
				
			||||||
 | 
					        tag_name: dev
 | 
				
			||||||
 | 
					      env:
 | 
				
			||||||
 | 
					        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										8
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										8
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -1,2 +1,10 @@
 | 
				
			|||||||
.obj
 | 
					.obj
 | 
				
			||||||
.project
 | 
					.project
 | 
				
			||||||
 | 
					/.ninja*
 | 
				
			||||||
 | 
					/brother120tool
 | 
				
			||||||
 | 
					/brother120tool-*
 | 
				
			||||||
 | 
					/brother240tool
 | 
				
			||||||
 | 
					/brother240tool-*
 | 
				
			||||||
 | 
					/fluxengine
 | 
				
			||||||
 | 
					/fluxengine-*
 | 
				
			||||||
 | 
					/upgrade-flux-file
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,250 +1,250 @@
 | 
				
			|||||||
:4000000000800020110000004110000041100000064A08B5136843F020031360044B1A6803F53F5302331A6001F028F8E8460040FA46004010B5054C237833B9044B13B163
 | 
					:400000000080002011000000A1100000A1100000064A08B5136843F020031360044B1A6803F53F5302331A6001F058F8E8460040FA46004010B5054C237833B9044B13B173
 | 
				
			||||||
:400040000448AFF300800123237010BD6881FF1F00000000C8380000084B10B51BB108490848AFF300800848036803B910BD074B002BFBD0BDE81040184700BF0000000041
 | 
					:400040000448AFF300800123237010BD6081FF1F00000000F0380000084B10B51BB108490848AFF300800848036803B910BD074B002BFBD0BDE81040184700BF0000000021
 | 
				
			||||||
:400080006C81FF1FC8380000C880FF1F000000000A4A0B4B116801310B40002BBEBF03F1FF3363F03F030133136011685368994202BF024B01221A72704700BF8881FF1FBC
 | 
					:400080006481FF1FF0380000C880FF1F000000000A4A0B4B116801310B40002BBEBF03F1FF3363F03F030133136011685368994202BF024B01221A72704700BF8081FF1FA4
 | 
				
			||||||
:4000C0003F0000800A4A0B4B516801310B40002BBEBF03F1FF3363F03F030133536051681368994202BF024B01221A72704700BF8881FF1F3F000080114BDA68196919B9FD
 | 
					:4000C0003F0000800A4A0B4B516801310B40002BBEBF03F1FF3363F03F030133536051681368994202BF024B01221A72704700BF8081FF1F3F000080114BDA68196919B905
 | 
				
			||||||
:4001000001221A75597514E09969521A19698A4294BF587D00201875187D094908B1002204E0086982428CBF002201224A75DA689A611B7D13B1002002F046B9704700BF70
 | 
					:4001000001221A75597514E09969521A19698A4294BF587D00201875187D094908B1002204E0086982428CBF002201224A75DA689A611B7D13B1002002F082B9704700BF34
 | 
				
			||||||
:400140008881FF1F10B5C4B2204601F059F90128FAD110BD08B572B60F4B0F49DA680132DA60DA690132C82A08BF0022DA611A6AD8690132A72A08BF00220A621B6A002B13
 | 
					:400140008081FF1F10B5C4B2204601F089F90128FAD110BD08B572B60F4B0F49DA680132DA60DA690132C82A08BF0022DA611A6AD8690132A72A08BF00220A621B6A002BEB
 | 
				
			||||||
:400180000CBF02230023002814BF184643F0010002F082FE62B608BD8881FF1F38B50446C5B2284602F0B2F8062002F0CFFA44F00200C0B202F0AAF8062002F0C7FA28460D
 | 
					:400180000CBF02230023002814BF184643F0010002F0DAFB62B608BD8081FF1F38B50446C5B2284602F0C4F8062002F099FD44F00200C0B202F0BCF8062002F091FD284602
 | 
				
			||||||
:4001C00002F0A4F8BDE83840062002F0A9BA10B5642402F095F828B9FFF7E0FF013CF8D1204610BD012010BD70B5C4B2054620460E4601F005F9012805D0204601F01EFA34
 | 
					:4001C00002F0B6F8BDE83840062002F073BD10B5642402F0A7F828B9FFF7E0FF013CF8D1204610BD012010BD70B5C4B2054620460E4601F035F9012805D0204601F04EFAE3
 | 
				
			||||||
:400200002846FFF79FFF204601F002F9314605460246204601F0BEF9204601F0F1F80028FAD1284670BD000038B5044D0024285D013402F03BFA402CF9D138BDAC81FF1FCB
 | 
					:400200002846FFF79FFF204601F032F9314605460246204601F0EEF9204601F021F90028FAD1284670BD000038B5044D0024285D013402F005FD402CF9D138BDA481FF1F75
 | 
				
			||||||
:4002400008B502F055FC002002F05EFC02F070FC02F07AFC80B208BD10B50446012002F06DF8642002F05CFAFFF7EAFF2080002002F064F8642002F053FAFFF7E1FF60809C
 | 
					:4002400008B502F0FDF9002002F006FA02F018FA02F022FA80B208BD10B50446012002F07FF8642002F026FDFFF7EAFF2080002002F076F8642002F01DFDFFF7E1FF608047
 | 
				
			||||||
:4002800010BD08B502F060FD002002F069FD02F07BFD02F085FD80B208BD10B50446FFF796FF322002F03CFAFFF7EBFF20800120FFF774FF322002F033FAFFF7E2FF6080D2
 | 
					:4002800010BD08B502F008FB002002F011FB02F023FB02F02DFB80B208BD10B50446FFF796FF322002F006FDFFF7EBFF20800120FFF774FF322002F0FDFCFFF7E2FF6080A1
 | 
				
			||||||
:4002C00010BD0FB400B593B014AB53F8042B402102A8019302F0E0FE02A802F07CF802F086F813B05DF804EB04B0704710B5044601780648FFF7E5FF0420FFF723FF627816
 | 
					:4002C00010BD0FB400B593B014AB53F8042B402102A8019302F0F4FE02A802F0BEF802F0C8F813B05DF804EB04B0704710B5044601780648FFF7E5FF0420FFF723FF62787E
 | 
				
			||||||
:400300002146BDE81040042001F0D2B8DC38000007B50023ADF804308DF80600032301A88DF80530FFF7E2FF03B05DF804FB000010B5074C94F8643043B1002001F0DAFFEE
 | 
					:400300002146BDE81040042001F002B90C3A000007B50023ADF804308DF80600032301A88DF80530FFF7E2FF03B05DF804FB000010B5074C94F8643043B1002001F0ECFF79
 | 
				
			||||||
:40034000002002F06DFD002384F8643010BD00BF8881FF1F38B5104D837895F8672004469A4204D0FFF7E4FF002385F86A302368C5F865302279094B1A71A378002B14BF45
 | 
					:40034000002002F083F8002384F8643010BD00BF8081FF1F38B5124D837895F8672004469A4204D0FFF7E4FF002385F86A302368C5F8653022790B4B1A71A378002B14BF38
 | 
				
			||||||
:400380000220012002F04CFDE07802F043FD2079BDE8384002F07ABD8881FF1FED81FF1F38B50D4C94F8645065B904F16500FFF7D1FF012001F09EFF4FF47A7002F0B0F968
 | 
					:400380000220012002F062F8E078B0FA80F0400902F0D4FA2079BDE8384002F0DBBA00BF8081FF1FE581FF1F38B50D4C94F8645065B904F16500FFF7CDFF012001F0ACFF17
 | 
				
			||||||
:4003C00084F86A50E368E366012384F86430BDE8384002F0E3B900BF8881FF1FF8B5214C0546FFF7DDFF94F86A3003B15DB91E48FFF767FFFFF7EBFE0120002384F86A007C
 | 
					:4003C0004FF47A7002F076FC84F86A50E368E366012384F86430BDE8384002F0A9BC00BF8081FF1FF8B5214C0546FFF7DDFF94F86A3003B15DB91E48FFF763FFFFF7E7FE5C
 | 
				
			||||||
:40040000236702F0A3F92A46216F1848FFF759FF144E0027236F9D4216D001F071FF00B13767236F9D4205DD0120FFF7B7FE336F013305E005DA0020FFF7B0FE336F013B0B
 | 
					:400400000120002384F86A00236702F069FC2A46216F1848FFF755FF144E0027236F9D4216D001F07FFF00B13767236F9D4205DD0120FFF7B3FE336F013305E005DA002094
 | 
				
			||||||
:40044000336702F0ABF9E5E7322002F069F92A2DCCBF0020012002F025FDBDE8F8400448FFF72FBF8881FF1FE9380000F03800000D3900002DE9F04F99B062B602F0F8F947
 | 
					:40044000FFF7ACFE336F013B336702F071FCE5E7322002F02FFC2A2DCCBF0020012002F07FFABDE8F8400448FFF72BBF8081FF1F193A0000203A00003D3A00002DE9F04F9B
 | 
				
			||||||
:400480009E49042002F01CFA9D4801F045FF9D4802F0E8FC9C4801F079FF02F0C9FB02F09BFA002002F0BCFC01F094FF0221002000F05CFF954C012001F0D4F8002384F890
 | 
					:4004800099B062B602F0BEFC9F49042002F0E2FC9E4801F053FF9E4801F084FF9D4801F0B1FF02F06DF902F03FF8002001F0CEFF01F0D2FF0221002000F088FF012001F05D
 | 
				
			||||||
:4004C0006730FFF76DFFFFF782FE84F87400FFF72FFF012384F86730FFF762FFFFF777FE84F87500FFF724FF894B94F87400894994F875202546002A14BF0A461A4600286F
 | 
					:4004C00001F9954D0321084602F012FC2E462C4602F02EFC95F8643043B1EA6EEB689B1A41F28832934201D9FFF722FF00F0A6FF18B98A48FFF7E5FE04E000F0A5FF0028D3
 | 
				
			||||||
:4005000008BF19468448FFF7DCFE0321084602F025F9264602F042F994F8643043B1EA6EEB689B1A41F28832934201D9FFF700FF00F054FF18B97948FFF7C3FE04E000F079
 | 
					:40050000F7D134E000F09AFF10B902F011FCF9E78348FFF7D6FE032001F0C0F88148FFF7D0FE002386F86730FFF73EFFFFF74FFE86F87400FFF7FCFE012386F86730FFF701
 | 
				
			||||||
:4005400053FF0028F7D10BE000F048FF10B902F025F9F9E77248FFF7B4FE032001F06EF8032000F04DFF0128D4D16E48FFF7F2FE6D490320FFF738FE94F876106B48FFF7F9
 | 
					:4005400033FFFFF744FE86F87500FFF7F1FE96F874007549754B96F87520002A14BF0A461A46002808BF19467148FFF7AAFE032000F076FF0128ABD16E48FFF7EBFE6E49CB
 | 
				
			||||||
:40058000A0FE94F87630023B142B00F2D683DFE813F01500D4031E00D4032400D4035000D4037600D403D900D403C101D4030803D4032C03D4033303D4034D0303238DF851
 | 
					:400580000320FFF731FE94F876106C48FFF799FE94F87630023B142B00F2D783DFE813F01500D5031E00D5032400D5035000D5037600D503DA00D503C201D5030903D50356
 | 
				
			||||||
:4005C00020308DF821300F238DF822302AE394F87800FFF703FF564B21E340F2DC57FFF7DFFE00232375E068227D02F0FF012AB9EB681B1ABB42F7DD0B4611E083B100227E
 | 
					:4005C0002D03D5033403D5034E0303238DF820308DF8213011238DF822302BE394F87800FFF700FF564B22E340F2DC57FFF7DCFE00232375E068227D02F0FF012AB9EB680B
 | 
				
			||||||
:40060000174696F87810F068277594F814E0BEF1000F02D1EB681B1AF7E701329142F3DA07228DF8202004228DF82120ADF82230F8E20220FFF786FD4FF000080DF1200A54
 | 
					:400600001B1ABB42F7DD0B4611E083B10022174696F87810F068277594F814E0BEF1000F02D1EB681B1AF7E701329142F3DA07228DF8202004228DF82120ADF82230F9E2BF
 | 
				
			||||||
:4006400002F0ACF84FF480790027C9EB0803DA1907F80A200137402FF9D10220FFF772FD3A465146022000F023FFB9F10109EBD108F10108B8F1400FE2D12E4B38E04FF076
 | 
					:400640000220FFF77FFD4FF000080DF1200A02F06FFB4FF480790027C9EB0803DA1907F80A200137402FF9D10220FFF76BFD3A465146022000F04CFFB9F10109EBD108F10F
 | 
				
			||||||
:40068000010A4FF000080DF1200B02F087F84FF0000959460120FFF7A7FD08EB090300270493049B1BF807203B44DBB29A4209D08DE80C0041463B464A461F48FFF701FEE0
 | 
					:400680000108B8F1400FE2D12E4B38E04FF0010A4FF000080DF1200B02F04AFB4FF0000959460120FFF7A0FD08EB090300270493049B1BF807203B44DBB29A4209D08DE89D
 | 
				
			||||||
:4006C0004FF0000A0137402FEBD109F10109B9F5807FDED108F10108B8F1400FD5D151461648FFF7EEFDBAF1000F00F01B81144B1B8807A8ADF81C3095E200BF5501000004
 | 
					:4006C0000C0041463B464A461F48FFF7FAFD4FF0000A0137402FEBD109F10109B9F5807FDED108F10108B8F1400FD5D151461748FFF7E7FDBAF1000F00F01C81144B1B883D
 | 
				
			||||||
:40070000F900000091000000C50000008881FF1F1F3900001B390000223900003A3900004D390000ED81FF1FFE81FF1F57390000CC380000CE380000663900008239000026
 | 
					:4007000007A8ADF81C3096E255010000F900000091000000C50000008081FF1F523A0000653A00006F3A00004B3A00004F3A0000823A0000E581FF1FF681FF1F9A3A000052
 | 
				
			||||||
:40074000D0380000206FFFF749FE94F8780001F0F5FD94F8780001F0D9FD02F009FCB94BDFF8FC821A78002702F0FB021A701A7842F001021A701A7802F0FE021A701A7880
 | 
					:40074000F4380000F6380000A93A0000C53A0000F8380000206FFFF745FE94F8780001F0FFFD94F8780001F0E3FD02F015FCB94BDFF8FC821A78002702F0FB021A701A785F
 | 
				
			||||||
:4007800002F0FE021A7002F0F7FB0220FFF7DAFC012141F6FF734FF48042084602F046FB84F8B60001F068FF08F807000137402FF8D1DFF8B0A200270AF195091FFA89F816
 | 
					:4007800042F001021A701A7802F0FE021A701A7802F0FE021A7002F003FC0220FFF7D2FC012141F6FF734FF48042084601F0DEFD84F8B60002F02AFA08F807000137402FA7
 | 
				
			||||||
:4007C0000137402F14BF3A4600221AF8010F2244062392F82420402101F082FF424646F240419AF8000001F08DFF08F14008402F1FFA88F8E4D196F8793053B196F87C30C8
 | 
					:4007C000F8D1DFF8B0A200270AF195091FFA89F80137402F14BF3A4600221AF8010F2244062392F82420402102F044FA424646F24E419AF8000002F04FFA08F14008402FB5
 | 
				
			||||||
:40080000336100233375237D002BFCD000233375336100234FF0FF32236062602372236894F8B600234493F8241001F0DDFE94F8B60001F09BFE012194F8B60001F06EFEAA
 | 
					:400800001FFA88F8E4D196F8793053B196F87C30336100233375237D002BFCD000233375336100234FF0FF32236062602372236894F8B600234493F8241002F09FF994F82A
 | 
				
			||||||
:400840002368002BFCD0002398467360D6F80CA0012701F0A3FFE368B4F87A20CAEB030393420DD367B1042195F8B60001F0C8FE94F8B60001F0D4FE0028F9D107463072CF
 | 
					:40084000B60002F05DF9012194F8B60002F030F92368002BFCD0002398467360D6F80CA0012702F065FAE368B4F87A20CAEB030393420DD367B1042195F8B60002F08AF9BC
 | 
				
			||||||
:40088000237AFBB96A682B689A4202D1002FE0D118E00220FFF756FC6968402209EB8111022000F005FE6A68674B01321340002BBEBF03F1FF3363F03F03013308F1010820
 | 
					:4008800094F8B60002F096F90028F9D107463072237AFBB96A682B689A4202D1002FE0D118E00220FFF74EFC6968402209EB8111022000F02DFE6A68674B01321340002BCA
 | 
				
			||||||
:4008C0006360C6E70220277AFFF73CFC00221146022000F0EDFD0220FFF734FCFFB2FFF7A3FC002001F012FD37B15848FFF7E9FC0220FFF70DFD06E0554B08A81B88ADF871
 | 
					:4008C000BEBF03F1FF3363F03F03013308F101086360C6E70220277AFFF734FC00221146022000F015FE0220FFF72CFCFFB2FFF79BFC002001F01CFD37B15848FFF7E1FC90
 | 
				
			||||||
:400900002030FFF7F3FC227D4146237A5148FFF7D8FC15E25048FFF7D4FCD4F87A7017F03F0701D0032009E2286FFFF757FD95F8780001F003FD95F8780001F0E7FC012054
 | 
					:400900000220FFF705FD06E0554B08A81B88ADF82030FFF7EBFC227D4146237A5148FFF7D0FC15E25048FFF7CCFCD4F87A7017F03F0701D0032009E2286FFFF753FD95F83B
 | 
				
			||||||
:4009400001F002FD02F014FB444BDFF814811A7842F004021A701A7842F001021A701A7802F0FE021A701A7802F0FE021A7002F003FB01214FF4804341F6FF72084601F0CB
 | 
					:40094000780001F00DFD95F8780001F0F1FC012001F098FD02F020FB444BDFF814811A7842F004021A701A7842F001021A701A7802F0FE021A701A7802F0FE021A7002F0BF
 | 
				
			||||||
:40098000E9FC85F8B60001F077FE08F807000137402FF8D1DFF8CC90002709F195031FFA83F804930137402F14BF3A46002219F8010F2244052392F82420402101F090FEB2
 | 
					:400980000FFB01214FF4804341F6FF72084601F01DFD85F8B60002F039F908F807000137402FF8D1DFF8CC90002709F195031FFA83F804930137402F14BF3A46002219F8F2
 | 
				
			||||||
:4009C000414646F2475299F8000001F09BFE08F14008402F1FFA88F8E4D100274FF0FF33376098467360BB463B46D6F87A9037725FEA99190CBF4FF0010A4FF0000A2168C1
 | 
					:4009C000010F2244052392F82420402102F052F9414646F2484299F8000002F05DF908F14008402F1FFA88F8E4D100274FF0FF33376098467360BB463B46D6F87A903772EA
 | 
				
			||||||
:400A0000114A01310A40002ABCBF02F1FF3262F03F026068B8BF013282426FD02BB1227A002A7AD12A7D002A77D12068049A059302EB8010BAF1000F16D040223F2102F079
 | 
					:400A00005FEA99190CBF4FF0010A4FF0000A2168114A01310A40002ABCBF02F1FF3262F03F026068B8BF013282426FD02BB1227A002A7AD12A7D002A77D12068049A059368
 | 
				
			||||||
:400A4000F7FA1CE0906400403F0000808C390000D2380000A6390000B939000097650040AC81FF1FAB81FF1F014601370120FFF7BBFBC7EB0903D3F1000A4AEB030A216882
 | 
					:400A400002EB8010BAF1000F16D040223F2102F003FB1CE09E6400403F000080CF3A0000FA380000E93A0000FC3A000098640040A481FF1FA381FF1F014601370120FFF7BF
 | 
				
			||||||
:400A8000B34A01310A40002ABEBF02F1FF3262F03F02013222606268059B01322ED12A683F2A2BD14FF00008C5F8048001F080FC85F808806B6895F8B6002B4493F82410D9
 | 
					:400A8000B3FBC7EB0903D3F1000A4AEB030A2168B34A01310A40002ABEBF02F1FF3262F03F02013222606268059B01322ED12A683F2A2BD14FF00008C5F8048001F0B4FCE9
 | 
				
			||||||
:400AC00001F092FD95F8B60001F050FD012195F8B60001F023FD95F87E302B6185F81480237D002BFCD04FF00008012086F8148001F06AFC404601F027FC00E023B1237A54
 | 
					:400AC00085F808806B6895F8B6002B4493F8241002F054F895F8B60002F012F8012195F8B60001F0E5FF95F87E302B6185F81480237D002BFCD04FF00008012086F814800D
 | 
				
			||||||
:400B00005BB92B7D4BB90123626842453FF477AF0BF1010BD5F8048071E701F04FFC012001F012FC002001F04FFC042194F8B60001F066FD94F8B60001F072FD8046002873
 | 
					:400B000001F09EFC404601F0BDFC00E023B1237A5BB92B7D4BB90123626842453FF477AF0BF1010BD5F8048071E701F083FC012001F0A8FC002001F083FC042194F8B6004D
 | 
				
			||||||
:400B4000F8D196F8B60001F0FFFC337D327A0293012303920193CDF800A05B463A4649467C48FFF7AEFBC6F81080BAF1000F0BD0FFF75AFB002001F0C9FB237A63B1764854
 | 
					:400B400002F028F894F8B60002F034F880460028F8D196F8B60001F0C1FF337D327A0293012303920193CDF800A05B463A4649467C48FFF7A6FBC6F81080BAF1000F0BD0C6
 | 
				
			||||||
:400B8000FFF79FFB0220D9E0B945F1D073490120FFF72AFB0137F7E77148FFF792FB714B3DE094F8780001F0C9FB206FFFF716FC6D48FFF786FB94F87930236100232375F8
 | 
					:400B8000FFF752FB002001F0D3FB237A63B17648FFF797FB0220D9E0B945F1D073490120FFF722FB0137F7E77148FFF78AFB714B3DE094F8780001F0D3FB206FFFF712FC19
 | 
				
			||||||
:400BC000237D002BFCD0012001F0FEFB00233375237D002BFCD0002001F0F6FB002363483361FFF76EFB624B19E0002084F86A00FFF7F4FB5F4B12E094F8743023B195F870
 | 
					:400BC0006D48FFF77EFB94F87930236100232375237D002BFCD0012001F032FC00233375237D002BFCD0002001F02AFC002363483361FFF766FB624B19E0002084F86A0088
 | 
				
			||||||
:400C000075200AB985F8782094F875201AB113B9012385F878305848FFF79CFB574B1B88ADF8203008A8FFF761FB89E0FFF780FB02F07CF8002002F01FF82A2701F04AFFE9
 | 
					:400C0000FFF7F0FB5F4B12E094F8743023B195F875200AB985F8782094F875201AB113B9012385F878305848FFF794FB574B1B88ADF8203008A8FFF759FB89E0FFF778FB0D
 | 
				
			||||||
:400C4000002001F0EDFE3A46002108A802F0F0F917238DF820308DF8217001F09FFD002001F048FB002002F0DBF8C82001F058FD0DF12200FFF7F0FA0DF13600FFF70DFB01
 | 
					:400C400001F01CFE002001F0BFFD2A2701F0EAFC002001F08DFC3A46002108A802F0FCF917238DF820308DF8217002F061F8002001F052FB002001F0E9FBC82002F01AF8F3
 | 
				
			||||||
:400C800001F08CFD012002F0CBF8322001F048FD0DF12600FFF7E0FA0DF13A00FFF7FDFA012001F027FB4FF4967001F039FD01F075FD0DF12E00FFF7CFFA0DF14200FFF71B
 | 
					:400C80000DF12200FFF7E8FA0DF13600FFF705FB02F04EF8012001F0D9FB322002F00AF80DF12600FFF7D8FA0DF13A00FFF7F5FA012001F031FB4FF4967001F0FBFF02F041
 | 
				
			||||||
:400CC000ECFA002001F016FB4FF4967001F028FD01F064FD022002F0A3F8322001F020FD0DEB0700FFF7B8FA0DF13E00FFF7D5FA012001F0FFFA4FF4967001F011FD01F040
 | 
					:400CC00037F80DF12E00FFF7C7FA0DF14200FFF7E4FA002001F020FB4FF4967001F0EAFF02F026F8022001F0B1FB322001F0E2FF0DEB0700FFF7B0FA0DF13E00FFF7CDFAF4
 | 
				
			||||||
:400D00004DFD0DF13200FFF7A7FA0DF14600FFF7C4FA002001F0EEFA4FF4967001F000FD01F03CFD002002F07BF8002384F86A3001F07EFF01F050FE74E70120FFF7E8FA91
 | 
					:400D0000012001F009FB4FF4967001F0D3FF02F00FF80DF13200FFF79FFA0DF14600FFF7BCFA002001F0F8FA4FF4967001F0C2FF01F0FEFF002001F089FB002384F86A302F
 | 
				
			||||||
:400D4000032000F07BFC0E48FFF7BBFAFFF7E2BB3F000080C3390000F33900004092FF1FFD390000D4380000053A0000133A0000D6380000D8380000FE81FF1FDA380000E3
 | 
					:400D400001F01EFD01F0F0FB74E70120FFF7E0FA032000F0A3FC0E48FFF7B3FAFFF7B8BB3F000080063B0000363B00003892FF1F403B0000FC380000483B0000563B00000F
 | 
				
			||||||
:400D8000203A00002DE9F04172B6884B61221A70A3F5F06301221A801924854A9C7092E803008033062283F8002283E80300522203F580731A707F4B7F4A1B787F4EDBB2FE
 | 
					:400D8000FE38000000390000F681FF1F02390000633B00000F4B1A78120616D55878C0B2012814D11B79DBB2042B02D0052B05D07047094A094B5A60282203E0084A074B07
 | 
				
			||||||
:400DC000137040F618027E4B00251A8041F2512223F8022C33784FF4F07003F0010343EA450502F0BDF8013C05F003052ED0032DF0D1744B4FF480721A8007221A70724A20
 | 
					:400DC0005A60E0221A8000F043BE002070470120704700BF0060004004390000BC92FF1F2C3900002DE9F04172B6884B61221A70A3F5F06301221A801924854A9C7092E807
 | 
				
			||||||
:400E0000002548211570917002221D705D7103F8032C0422DA716D4A6D4C13786D4E43F00103137012F8013C062743F0030302F8013C2378012243F0800323705B4B1A70F9
 | 
					:400E000003008033062283F8002283E80300522203F580731A707F4B7F4A1B787F4EDBB2137040F618027E4B00251A8041F2512223F8022C33784FF4F07003F0010343EAA4
 | 
				
			||||||
:400E4000654A137843F02003137000E0FEE707FB056300219A881868013502F0E9F8072DF5D15E485E4E002550F8041F05F1105303F1480221F0FF074933C9B20B44520042
 | 
					:400E4000450502F0A1F8013C05F003052ED0032DF0D1744B4FF480721A8007221A70724A002548211570917002221D705D7103F8032C0422DA716D4A6D4C13786D4E43F060
 | 
				
			||||||
:400E80005B0002329A4206D012F802EC12F801CC0EF807C0F5E7B0420D44E5D1514A002313609360136193614F4B504F1A68504BDFF888811A604F4B1A684F4B1A604F4A7B
 | 
					:400E80000103137012F8013C062743F0030302F8013C2378012243F0800323705B4B1A70654A137843F02003137000E0FEE707FB056300219A881868013502F0CDF8072D6A
 | 
				
			||||||
:400EC000137843F002031370137C43F0020313742378A2F5863243F040032370413A137843F010031370464A464B07CA03C31A80454A2833106843F8250C127903F8212CA9
 | 
					:400EC000F5D15E485E4E002550F8041F05F1105303F14A0221F0FF074B33C9B20B4452005B0002329A4206D012F802EC12F801CC0EF807C0F5E7B0420D44E5D1514A002390
 | 
				
			||||||
:400F0000424A07CA03C31A80414AE83B07CA03C31A80404A083307CA03C31A803E4A3F4BA2F5616203CBC2F8100EC2F8141E1378042043F008031370394B02F5AA521B78A7
 | 
					:400F000013609360136193614F4B504F1A68504BDFF888811A604F4B1A684F4B1A604F4A137843F002031370137C43F0020313742378A2F5863243F040032370413A1378DD
 | 
				
			||||||
:400F40003D78DBB298F80060EDB203F007010C321B091170F6B2537045F003033B7046F0030388F800302F4B48221A702E4A402313702E49937013729372082382F81F32BF
 | 
					:400F400043F010031370464A464B07CA03C31A80454A2833106843F8250C127903F8212C424A07CA03C31A80414AE83B07CA03C31A80404A083307CA03C31A803E4A3F4B11
 | 
				
			||||||
:400F800020220A7048710A72294A0A20137001F0DDFB284B88F8006044223D70264D1A7094E80F0007C52B80BDE8F081004800404C0A00480F010049A1460040254200408F
 | 
					:400F8000A2F5616203CBC2F8100EC2F8141E1378042043F008031370394B02F5AA521B783D78DBB298F80060EDB203F007010C321B091170F6B2537045F003033B7046F095
 | 
				
			||||||
:400FC000224200400440004006400040A2430040A0430040253A0000E8460040FCFFFF478C00004800760040540A0048F846004020760040580A004828760040035001404D
 | 
					:400FC000030388F800302F4B48221A702E4A402313702E49937013729372082382F81F3220220A7048710A72294A0A20137001F077FE284B88F8006044223D70264D1A709B
 | 
				
			||||||
:401000000C0A0048C0510040180A0048200A00482C0A0048380A004832510040440A0048CF0100491D51004001590040235B0040585B004076580040B0430040F9460040F2
 | 
					:4010000094E80F0007C52B80BDE8F08100480040680A00480F010049A146004025420040224200400440004006400040A2430040A0430040683B0000E8460040FCFFFF47E7
 | 
				
			||||||
:4010400008B501F0C9FF03680C2B00D1FEE7FEE7084908B50B68084A1844821A802A01DC086005E001F0B8FF0C2303604FF0FF33184608BDCC80FF1F9093FF1F80B5114817
 | 
					:401040009000004800760040700A0048F846004020760040740A00482876004003500140280A0048C0510040340A00483C0A0048480A0048540A004832510040600A004800
 | 
				
			||||||
:40108000114B0025C0B1A3F1100192C922460439161BB74204D051F8046F42F8046BF7E7114653F8046C8C1AA64202D041F8045BF9E701381033E5E701F094FFFFF7DAF9D9
 | 
					:40108000CF0100491D51004001590040235B0040585B004076580040B0430040F946004008B501F0ADFF03680C2B00D1FEE7FEE7084908B50B68084A1844821A802A01DC75
 | 
				
			||||||
:4010C000FEE700BF01000000F43B0000124A134B10B51A60124A134C1368134843F4007313600023032B98BF54F823204FEA830188BF0E4A0133302B4250F3D10C4B1A7814
 | 
					:4010C000086005E001F09CFF0C2303604FF0FF33184608BDCC80FF1F8893FF1F80B51148114B0025C0B1A3F1100192C922460439161BB74204D051F8046F42F8046BF7E7E8
 | 
				
			||||||
:401100000C4B1A700C4B084A1A60FFF73BFEBDE8104001F0EDB900BF0004FA050CED00E014ED00E0000000000080FF1F41100000BC760040C080FF1F08ED00E0F8B501F042
 | 
					:40110000114653F8046C8C1AA64202D041F8045BF9E701381033E5E701F078FFFFF7AEF9FEE700BF01000000FC3C0000124A134B10B51A60124A134C1368134843F4007367
 | 
				
			||||||
:4011400017FF4B4A01271378022643F001031370137C484C43F001031374474B02F5E3521F700B3203F8946C1378054603F07F031370002001F0EAFA2378404A03F0F903F2
 | 
					:4011400013600023032B98BF54F823204FEA830188BF0E4A0133302B4250F3D10C4B1A780C4B1A700C4B084A1A60FFF73BFEBDE8104001F087BC00BF0004FA050CED00E0A4
 | 
				
			||||||
:4011800023701378384603F0DF03137023783B43237001F0DBFA282001F0D8FA384B30461A7802F07F021A701A7802F0BF021A7023783343237001F0C9FA2378314A43F0C6
 | 
					:4011800014ED00E0000000000080FF1FA1100000BC760040C080FF1F08ED00E0F8B501F0FBFE4B4A01271378022643F001031370137C484C43F001031374474B02F5E352FA
 | 
				
			||||||
:4011C000040323700023137053702F4AFF2199540133092BFBD1284601F0CEFE0721172001F0FCFA2949172001F0EAFA0721182001F0F4FA2649182001F0E2FA0721152033
 | 
					:4011C0001F700B3203F8946C1378054603F07F031370002001F084FD2378404A03F0F90323701378384603F0DF03137023783B43237001F075FD282001F072FD384B304610
 | 
				
			||||||
:4012000001F0ECFA2349152001F0DAFA0721052001F0E4FA2049052001F0D2FA0721062001F0DCFA1D49062001F0CAFA0721084601F0D4FA1A49072001F0C2FA07210820F8
 | 
					:401200001A7802F07F021A701A7802F0BF021A7023783343237001F063FD2378314A43F0040323700023137053702F4AFF2199540133092BFBD1284601F0B2FE07211720E7
 | 
				
			||||||
:4012400001F0CCFA1749082001F0BAFA0021162001F0C4FA1449162001F0B2FA07210C2001F0BCFABDE8F84010490C2001F0A8BAA5430040944300409D6000401260004076
 | 
					:4012400001F096FD2949172001F084FD0721182001F08EFD2649182001F07CFD0721152001F086FD2349152001F074FD0721052001F07EFD2049052001F06CFD072106201F
 | 
				
			||||||
:40128000F851004084600040B592FF1F0B1B000045190000091B00003D1A0000691A0000991A0000D11A0000111B0000851B0000214B224A10B5187000231370204A40209B
 | 
					:4012800001F076FD1D49062001F064FD0721084601F06EFD1A49072001F05CFD0721082001F066FD1749082001F054FD0021162001F05EFD1449162001F04CFD07210C2014
 | 
				
			||||||
:4012C0001370204A0F2413701F4A13701F4A13701F4A13701F4A13701F4B4FF400021A604FF080721A604FF400121A6020221A601860802018604FF480701860174804702E
 | 
					:4012C00001F056FDBDE8F84010490C2001F042BDA5430040944300409D60004012600040F851004084600040AD92FF1F6B1B0000A5190000691B00009D1A0000C91A0000BE
 | 
				
			||||||
:401300004FF480001860164B1A70933B19B91A7802F0FE0202E01A7842F001021A70114B03221A70802203F8202C012001F018FE0D4B04221A7010BDD092FF1FD692FF1F39
 | 
					:40130000F91A0000311B0000711B0000E51B0000214B224A10B5187000231370204A40201370204A0F2413701F4A13701F4A13701F4A13701F4A13701F4B4FF400021A60B1
 | 
				
			||||||
:40134000D492FF1FD592FF1FD192FF1FC092FF1FD392FF1F4893FF1F00E100E09E6000409C600040286000401260004070B5074C054623780E461BB9FFF7E0FE0123237031
 | 
					:401340004FF080721A604FF400121A6020221A601860802018604FF480701860174804704FF480001860164B1A70933B19B91A7802F0FE0202E01A7842F001021A70114B50
 | 
				
			||||||
:4013800031462846BDE87040FFF792BF8092FF1F0A4A002313700A4A13700A4A13700A4A13700A4A13700A4A13700A4A13700A4B03221A70802203F8202C7047D692FF1F4E
 | 
					:4013800003221A70802203F8202C012001F0FCFD0D4B04221A7010BDC892FF1FCE92FF1FCC92FF1FCD92FF1FC992FF1FB892FF1FCB92FF1F4093FF1F00E100E09E6000407A
 | 
				
			||||||
:4013C000D492FF1FD592FF1FD192FF1FC092FF1FD392FF1F4893FF1F28600040014B1878704700BFD592FF1F044B1A7802F0FF001AB118780022C0B21A707047D492FF1F52
 | 
					:4013C0009C600040286000401260004070B5074C054623780E461BB9FFF7E0FE0123237031462846BDE87040FFF792BF7892FF1F0A4A002313700A4A13700A4A13700A4A81
 | 
				
			||||||
:40140000024A0C2303FB002040787047DC92FF1F431E072B0CD8074A064B00010344805C5B7800F00F0043EA0020023880B2704700207047FC5F00401A4A38B50C2303FBA9
 | 
					:4014000013700A4A13700A4A13700A4A13700A4B03221A70802203F8202C7047CE92FF1FCC92FF1FCD92FF1FC992FF1FB892FF1FCB92FF1F4093FF1F28600040014B187898
 | 
				
			||||||
:4014400000231B79090C13F0800F00F1FF35044619BF8AB24FF480438BB24FF48042032D18D8DFE805F002070C110021084601F01BF80DE00021084600F0FAFF08E0002180
 | 
					:40144000704700BFCD92FF1F044B1A7802F0FF001AB118780022C0B21A707047CC92FF1F024A0C2303FB002040787047D492FF1F431E072B0CD8074A064B00010344805C32
 | 
				
			||||||
:40148000084600F0D9FF03E00021084600F0B8FF054B1855EDB2072D03D801F0EDF8034B185538BDDC92FF1FAC92FF1FB592FF1F431E072B2DE9F0470446894615465CD857
 | 
					:401480005B7800F00F0043EA0020023880B2704700207047FC5F00401A4A38B50C2303FB00231B79090C13F0800F00F1FF35044619BF8AB24FF480438BB24FF48042032DA1
 | 
				
			||||||
:4014C0002F4F0C2202FB0072D388DFF8B8A09BB2C3F500739D424FF00C0303FB007388BFD588DB7884BFC5F50075ADB2254A43EA15230601B354B244EBB28AF80130224BD4
 | 
					:4014C00018D8DFE805F002070C110021084601F0A1FA0DE00021084601F080FA08E00021084601F05FFA03E00021084601F03EFA054B1855EDB2072D03D801F087FB034B10
 | 
				
			||||||
:401500001A5C9846FF2A01D1FFF796FF0C2303FB047200215170B9F1000F28D03DB31B4F385D01F011F811232946FE2218F8040001F0D6F806F5C04278321FFA89F118F8D2
 | 
					:40150000185538BDD492FF1FA492FF1FAD92FF1F431E072B2DE9F0470446894615465CD82F4F0C2202FB0072D388DFF8B8A09BB2C3F500739D424FF00C0303FB007388BF8A
 | 
				
			||||||
:40154000040001F0DFF8124D18F80410385D01F04BF80121385D00F0E1FF735D43F002037355735D03F0FD037355BDE8F08703FB04746379DBB28AF80230BDE8F08700BFE7
 | 
					:40154000D588DB7884BFC5F50075ADB2254A43EA15230601B354B244EBB28AF80130224B1A5C9846FF2A01D1FFF796FF0C2303FB047200215170B9F1000F28D03DB31B4FEB
 | 
				
			||||||
:40158000DC92FF1FFC5F0040B592FF1FAC92FF1F706000402DE9F047044615468846002940D0431E072B3FD8FFF732FFA84203D22046FFF72DFF05461D4E335DFF2B03D1DE
 | 
					:40158000385D01F0ABFA11232946FE2218F8040001F070FB06F5C04278321FFA89F118F8040001F079FB124D18F80410385D01F0E5FA0121385D01F07BFA735D43F002030D
 | 
				
			||||||
:4015C00041462046FFF738FFDFF868A027011AF8040000F0B9FF1223FE222946305D01F07FF807F5C0411FFA88F27831305D01F089F8DFF84490315D1AF8040000F0F4FFE9
 | 
					:4015C0007355735D03F0FD037355BDE8F08703FB04746379DBB28AF80230BDE8F08700BFD492FF1FFC5F0040AD92FF1FA492FF1F706000402DE9F047044615468846002945
 | 
				
			||||||
:4016000001211AF8040000F089FF17F8093043F0020307F8093017F8093003F0FD0307F8093002E00D4600E000252846BDE8F087B592FF1FAC92FF1F70600040431E072BA7
 | 
					:4016000040D0431E072B3FD8FFF732FFA84203D22046FFF72DFF05461D4E335DFF2B03D141462046FFF738FFDFF868A027011AF8040001F053FA1223FE222946305D01F087
 | 
				
			||||||
:401640000AD8064A0C2303FB002300225A705A79034BD2B200011A54704700BFDC92FF1FFE5F0040431E072B9FBF024B000108221A547047FE5F004030B51A4A1A491B4D0A
 | 
					:4016400019FB07F5C0411FFA88F27831305D01F023FBDFF84490315D1AF8040001F08EFA01211AF8040001F023FA17F8093043F0020307F8093017F8093003F0FD0307F881
 | 
				
			||||||
:401680000878138803449BB21380194A00231488D8B2A4B27CB1082B0CD050680078C0B2E85450680133013050601088013880B21080ECE718460B780E4C082B0E4A00D003
 | 
					:40168000093002E00D4600E000252846BDE8F087AD92FF1FA492FF1F70600040431E072B0AD8064A0C2303FB002300225A705A79034BD2B200011A54704700BFD492FF1F5D
 | 
				
			||||||
:4016C00040B10E4D2B7883F080032B700F232370022301E0022323701370094B1870087030BD00BF4C93FF1F4893FF1F00600040C492FF1FC192FF1FD692FF1FD292FF1FE1
 | 
					:4016C000FE5F0040431E072B9FBF024B000108221A547047FE5F004030B51A4A1A491B4D0878138803449BB21380194A00231488D8B2A4B27CB1082B0CD050680078C0B2EC
 | 
				
			||||||
:401700004993FF1F074B02221A70074B80221A70064B0F221A70064A00231370054A012013707047D692FF1FD292FF1FC192FF1F4893FF1F4993FF1F30B5164B16491B78E1
 | 
					:40170000E85450680133013050601088013880B21080ECE718460B780E4C082B0E4A00D040B10E4D2B7883F080032B700F232370022301E0022323701370094B18700870CA
 | 
				
			||||||
:401740000A8803F00F03023BDBB21A4492B20A80124C134A0020118889B279B173B15568215C013BC9B229705168DBB20131516011880130013989B21180ECE7094A1370B3
 | 
					:4017400030BD00BF4493FF1F4093FF1F00600040BC92FF1FB992FF1FCE92FF1FCA92FF1F4193FF1F074B02221A70074B80221A70064B0F221A70064A00231370054A012088
 | 
				
			||||||
:40178000094A137883F080031370084B0B221A7030BD00BF296000404C93FF1F00600040C492FF1F4993FF1FD292FF1FC192FF1F064A06231370064A01201370054B802273
 | 
					:4017800013707047CE92FF1FCA92FF1FB992FF1F4093FF1F4193FF1F30B5164B16491B780A8803F00F03023BDBB21A4492B20A80124C134A0020118889B279B173B155682C
 | 
				
			||||||
:4017C0001A70054B00221A70704700BFD692FF1FC192FF1FD292FF1F4993FF1F054B9A683AB19A68044910709A680988518000229A607047C492FF1F4C93FF1F08B5124BAC
 | 
					:4017C000215C013BC9B229705168DBB20131516011880130013989B21180ECE7094A1370094A137883F080031370084B0B221A7030BD00BF296000404493FF1F006000400F
 | 
				
			||||||
:401800001A78D2B21A701B78DBB21A0602D50F4A137008BD0220FFF7E1FF0D4B1B7803F06003202B05D0402B06D043B900F012FC04E001F0A5FB01E000F046FD10B9034B1C
 | 
					:40180000BC92FF1F4193FF1FCA92FF1FB992FF1F064A06231370064A01201370054B80221A70054B00221A70704700BFCE92FF1FB992FF1FCA92FF1F4193FF1F054B9A68E4
 | 
				
			||||||
:4018400003221A7008BD00BF28600040C192FF1F0060004008B5084A084B0120197813880B449BB21380064B00221A70FFF7B6FF044B03221A7008BD4C93FF1F4893FF1F1D
 | 
					:401840003AB19A68044910709A680988518000229A607047BC92FF1F4493FF1F08B5124B1A78D2B21A701B78DBB21A0602D50F4A137008BD0220FFF7E1FF0D4B1B7803F0CE
 | 
				
			||||||
:40188000D692FF1FC192FF1F08B50C4B1B78DBB2042B07D0062B09D0022B0DD1BDE80840FFF7D8BFBDE80840FFF746BF0320FFF795FF034B03221A7008BD00BFD692FF1FCC
 | 
					:401880006003202B05D0402B06D043B900F012FC04E001F089FB01E0FFF77CFA10B9034B03221A7008BD00BF28600040B992FF1F0060004008B5084A084B012019781388FA
 | 
				
			||||||
:4018C000C192FF1F08B5054B002201201A70FFF785FF034B03221A7008BD00BFD692FF1FC192FF1F08B50A4B1A7832B11A78094942F080020A7000221A70074B00220120D1
 | 
					:4018C0000B449BB21380064B00221A70FFF7B6FF044B03221A7008BD4493FF1F4093FF1FCE92FF1FB992FF1F08B50C4B1B78DBB2042B07D0062B09D0022B0DD1BDE8084045
 | 
				
			||||||
:401900001A70FFF76BFF054B03221A7008BD00BFC092FF1F08600040D692FF1FC192FF1F074B1B78DBB2042B05D0062B05D0022B05D1FFF7A1BEFFF7C5BFFFF7D3BF70479E
 | 
					:40190000FFF7D8BFBDE80840FFF746BF0320FFF795FF034B03221A7008BD00BFCE92FF1FB992FF1F08B5054B002201201A70FFF785FF034B03221A7008BD00BFCE92FF1FCA
 | 
				
			||||||
:40194000D692FF1F38B51D4C2378DBB2DD0634D518060AD503F00F03012B2ED1FFF74EFF174B1B78190609D538BD5A0602D5FFF7D7FF03E09D0620D5FFF786FF23781B066B
 | 
					:40194000B992FF1F08B50A4B1A7832B11A78094942F080020A7000221A70074B002201201A70FFF76BFF054B03221A7008BD00BFB892FF1F08600040CE92FF1FB992FF1FC0
 | 
				
			||||||
:401980001BD4104B1A78104B1B7813430F4A13701278934211D10A4A0849154613782078DBB2000605D41378DBB20B700B7803F00F0328788342F1D138BD38BD2860004067
 | 
					:40198000074B1B78DBB2042B05D0062B05D0022B05D1FFF7A1BEFFF7C5BFFFF7D3BF7047CE92FF1F38B51D4C2378DBB2DD0634D518060AD503F00F03012B2ED1FFF74EFF42
 | 
				
			||||||
:4019C000C192FF1FD292FF1F4993FF1F29600040054A00231380054A916819B191680B7092685380704700BF4C93FF1FC492FF1F0E4808B503889BB213B9FFF783FE13E0D1
 | 
					:4019C000174B1B78190609D538BD5A0602D5FFF7D7FF03E09D0620D5FFF786FF23781B061BD4104B1A78104B1B7813430F4A13701278934211D10A4A0849154613782078EB
 | 
				
			||||||
:401A00000B4B02221A700B4B00221A70FFF7E0FF094AD1799379028843EA012392B2934238BF0380FFF728FE012008BDC492FF1FD692FF1FD292FF1F00600040084B012220
 | 
					:401A0000DBB2000605D41378DBB20B700B7803F00F0328788342F1D138BD38BD28600040B992FF1FCA92FF1F4193FF1F29600040054A00231380054A916819B191680B701D
 | 
				
			||||||
:401A40001A700F3B9B7C074B1A7B02F00302012A1EBFDA7B82F08002DA7301225A7370470B600040DC92FF1F094B02221A700F3B93F82230074B1A7E02F00302012A1EBF0F
 | 
					:401A400092685380704700BF4493FF1FBC92FF1F0E4808B503889BB213B9FFF783FE13E00B4B02221A700B4B00221A70FFF7E0FF094AD1799379028843EA012392B2934229
 | 
				
			||||||
:401A8000DA7E82F08002DA7601225A76704700BF0B600040DC92FF1F0B4B04221A700F3B93F83230094B93F8242002F00302012A1EBF93F8272082F0800283F827200122E0
 | 
					:401A800038BF0380FFF728FE012008BDBC92FF1FCE92FF1FCA92FF1F00600040084B01221A700F3B9B7C074B1A7B02F00302012A1EBFDA7B82F08002DA7301225A73704722
 | 
				
			||||||
:401AC00083F82520704700BF0B600040DC92FF1F0B4B08221A700F3B93F84230094B93F8302002F00302012A1EBF93F8332082F0800283F83320012283F83120704700BFF5
 | 
					:401AC0000B600040D492FF1F094B02221A700F3B93F82230074B1A7E02F00302012A1EBFDA7E82F08002DA7601225A76704700BF0B600040D492FF1F0B4B04221A700F3B21
 | 
				
			||||||
:401B00000B600040DC92FF1F7047FFF741BC0000F0B5184B184E19780C27C9B201234FF0000C31B3CA0720D5144A4FEA031E7244947850782040C5070DD507FB03652C799F
 | 
					:401B000093F83230094B93F8242002F00302012A1EBF93F8272082F0800283F82720012283F82520704700BF0B600040D492FF1F0B4B08221A700F3B93F84230094B93F856
 | 
				
			||||||
:401B4000240608D5147804F0FE0414706D790C4CEDB204F80E50840706D507FB036425792D0658BF84F801C090700133DBB24908D7E7F0BD9F600040DC92FF1F70600040D5
 | 
					:401B4000302002F00302012A1EBF93F8332082F0800283F83320012283F83120704700BF0B600040D492FF1F7047FFF741BC0000F0B5184B184E19780C27C9B201234FF028
 | 
				
			||||||
:401B8000FE5F004000F0ACBC70B50446184B88B003AA03F11006154618685968083303C5B3422A46F7D11B782B70FCB12223237001AD03232846637000F08AFE00222046DB
 | 
					:401B8000000C31B3CA0720D5144A4FEA031E7244947850782040C5070DD507FB03652C79240608D5147804F0FE0414706D790C4CEDB204F80E50840706D507FB036425795F
 | 
				
			||||||
:401BC0001146AB5C08AC04EB131414F8144C03F00F03847008AC234413F8143C0132082AC1700371417100F10400EAD108B070BD4F3A00002DE9F0431C4D01222E460C2093
 | 
					:401BC0002D0658BF84F801C090700133DBB24908D7E7F0BD9F600040D492FF1F70600040FE5F004000F032BF70B50446184B88B003AA03F11006154618685968083303C530
 | 
				
			||||||
:401C00001F274FF0800E4FF0080C194B00FB02581401234418705F70164998F805902144B9F1000F07D098F8044024064CBF887081F802C001E081F802E000FB0261CC880F
 | 
					:401C0000B3422A46F7D11B782B70FCB12223237001AD03232846637001F024F9002220461146AB5C08AC04EB131414F8144C03F00F03847008AC234413F8143C0132082AB1
 | 
				
			||||||
:401C40000132E4B29C71CC88092AC4F30724DC71CC88E4B21C71C988C1F307215971D4D1054BFF221A70BDE8F08300BFDC92FF1F70600040FC5F00400A600040064B074A70
 | 
					:401C4000C1700371417100F10400EAD108B070BD923B00002DE9F0431C4D01222E460C201F274FF0800E4FF0080C194B00FB02581401234418705F70164998F8059021445B
 | 
				
			||||||
:401C80001B7802EBC30253681A7C824286BF03EBC003586900207047D092FF1FB03A00002DE9F84F424B1A78002A7ED01878414D0138C0B2FFF7E2FFA8463F4AC368147810
 | 
					:401C8000B9F1000F07D098F8044024064CBF887081F802C001E081F802E000FB0261CC880132E4B29C71CC88092AC4F30724DC71CC88E4B21C71C988C1F307215971D4D1CB
 | 
				
			||||||
:401CC000007ADFF800C1E4B203EBC0000C2600274FF0010E834268D01A78A24263D11CF80420597891425ED19A7893F8039002F07F0206FB02FA05EB0A01CF7093F802B01E
 | 
					:401CC000054BFF221A70BDE8F08300BFD492FF1F70600040FC5F00400A600040064B074A1B7802EBC30253681A7C824286BF03EBC003586900207047C892FF1FB83B000044
 | 
				
			||||||
:401D000009F0030981F804B093F803B005F80AB0B3F804A0A1F808A093F902A0BAF1000F0BDAB9F1010F0CBF4FF007094FF00D0981F8059081F801E009E0B9F1010F0CBF20
 | 
					:401D00002DE9F84F424B1A78002A7ED01878414D0138C0B2FFF7E2FFA8463F4AC3681478007ADFF800C1E4B203EBC0000C2600274FF0010E834268D01A78A24263D11CF829
 | 
				
			||||||
:401D40004FF005094FF0090981F805904F704FEA02191A4906FB0282494481F802E0B2F808A0CAF3072A81F800A0B2F808A05FFA8AFA81F801A0B2F806A011495FFA8AFAAB
 | 
					:401D40000420597891425ED19A7893F8039002F07F0206FB02FA05EB0A01CF7093F802B009F0030981F804B093F803B005F80AB0B3F804A0A1F808A093F902A0BAF1000FB6
 | 
				
			||||||
:401D8000494481F806A0B2F80690C9F3072981F80790B2F806905FFA89F981F80490D288C2F307224A71083394E7BDE8F88F00BFD592FF1FDC92FF1FD192FF1FFC5F004052
 | 
					:401D80000BDAB9F1010F0CBF4FF007094FF00D0981F8059081F801E009E0B9F1010F0CBF4FF005094FF0090981F805904F704FEA02191A4906FB0282494481F802E0B2F806
 | 
				
			||||||
:401DC00070600040C292FF1F08B5064B18780138C0B2FFF753FF20B143681B7900EBC300406908BDD592FF1F00212DE9F84F0B464E4E0C2707FB01F4013132190929335553
 | 
					:401DC00008A0CAF3072A81F800A0B2F808A05FFA8AFA81F801A0B2F806A011495FFA8AFA494481F806A0B2F80690C9F3072981F80790B2F806905FFA89F981F80490D288FA
 | 
				
			||||||
:401E00004FF000059370494CD3701381937253705371EFD118B1464B1D70464B1D70464B1A78002A7FD0187801250138C0B2FFF725FFA8464368DFF8F8E0DB790C2713F0B5
 | 
					:401E0000C2F307224A71083394E7BDE8F88F00BFCD92FF1FD492FF1FC992FF1FFC5F004070600040BA92FF1F08B5064B18780138C0B2FFF753FF20B143681B7900EBC3008A
 | 
				
			||||||
:401E4000400F3E4B4FF0000C1A7814BF42F0010202F0FE021A70027AD20007FB0541C36803EB02094B4531D093F802A00AF07F06AE4229D10E89B3F804B0B6B25E4538BF50
 | 
					:401E4000406908BDCD92FF1F00212DE9F84F0B464E4E0C2707FB01F401313219092933554FF000059370494CD3701381937253705371EFD118B1464B1D70464B1D70464B16
 | 
				
			||||||
:401E8000A1F808B01E7893F801B01EF80660B3451AD181F804A0DE780E7093F902A0DE78BAF1000F06F0030607DA012E0CBF07260D264E7181F8018006E0012E0CBF052673
 | 
					:401E80001A78002A7FD0187801250138C0B2FFF725FFA8464368DFF8F8E0DB790C2713F0400F3E4B4FF0000C1A7814BF42F0010202F0FE021A70027AD20007FB0541C368D0
 | 
				
			||||||
:401EC00009264E7181F801C00833CBE70135092DC3D1C1680A328B1C0A440C200833934209D013F8081C13F80A5C01F07F0100FB01418D72F2E7FFF767FF114B01211860E6
 | 
					:401EC00003EB02094B4531D093F802A00AF07F06AE4229D10E89B3F804B0B6B25E4538BFA1F808B01E7893F801B01EF80660B3451AD181F804A0DE780E7093F902A0DE78D3
 | 
				
			||||||
:401F000000230C2000FB0142D3801289013113449BB203F00102134409299BB2F2D1BDE8F84FFFF767BEBDE8F88F00BFDC92FF1FC292FF1F4A93FF1FD592FF1FD392FF1FCE
 | 
					:401F0000BAF1000F06F0030607DA012E0CBF07260D264E7181F8018006E0012E0CBF052609264E7181F801C00833CBE70135092DC3D1C1680A328B1C0A440C20083393423E
 | 
				
			||||||
:401F4000D892FF1F114B1B7903F07F035A1E072A19D80F490C2202FB031291781B0141F0010191700021D170517841F002015170127912F0800F074A1A4414BF8D238923CF
 | 
					:401F400009D013F8081C13F80A5C01F07F0100FB01418D72F2E7FFF767FF114B0121186000230C2000FB0142D3801289013113449BB203F00102134409299BB2F2D1BDE88B
 | 
				
			||||||
:401F80009370FFF715BC0020704700BF00600040DC92FF1FFC5F004030B4194B1A7902F07F02531E072B27D8164B0C2404FB02339978154D01F0FE0199700021D970294600
 | 
					:401F8000F84FFFF767BEBDE8F88F00BFD492FF1FBA92FF1F4293FF1FCD92FF1FCB92FF1FD092FF1F114B1B7903F07F035A1E072A19D80F490C2202FB031291781B0141F08E
 | 
				
			||||||
:401FC0001201505D114400F07F0050555A7802F0FD025A701A795B78120605D5012B01D18C7006E00D2303E0012B0CBF082309238B7030BCFFF7DCBB002030BC704700BF9C
 | 
					:401FC000010191700021D170517841F002015170127912F0800F074A1A4414BF8D2389239370FFF715BC0020704700BF00600040D492FF1FFC5F004030B4194B1A7902F0D8
 | 
				
			||||||
:4020000000600040DC92FF1FFC5F004010B50D4B0D4C21791878C9B20138C0B2FFF72EFE43681B798B4201D2012909D8074A0848535CDBB24354A3780120DBB2535410BD56
 | 
					:402000007F02531E072B27D8164B0C2404FB02339978154D01F0FE0199700021D97029461201505D114400F07F0050555A7802F0FD025A701A795B78120605D5012B01D167
 | 
				
			||||||
:40204000002010BDD592FF1F00600040C292FF1F4A93FF1F38B58A4A8A4C13780021DBB221801806517840F18D800A2900F20581DFE811F05D000301030103010301030167
 | 
					:402040008C7006E00D2303E0012B0CBF082309238B7030BCFFF7DCBB002030BC704700BF00600040D492FF1FFC5F004010B50D4B0D4C21791878C9B20138C0B2FFF72EFE80
 | 
				
			||||||
:402080000B0003017E0003018200D3787C49012B09D17D4B1A787D4B03EBC2035B685B686360122310E0CB78022B12D18878FFF7E5FD002800F0E180436863606368DA7885
 | 
					:4020800043681B798B4201D2012909D8074A0848535CDBB24354A3780120DBB2535410BD002010BDCD92FF1F00600040BA92FF1F4293FF1F38B5874A874C13780021DBB254
 | 
				
			||||||
:4020C00063689B7843EA02232380BDE83840FFF78FBCCB78032B26D16D4B00228878D5B2854209D3664A91786A4AEE2908BF1346634A917881B106E0187801320028F1D025
 | 
					:4020C00021801806517840F188800A2900F20081DFE811F05800FE00FE00FE00FE00FE000B00FE007900FE007D00D3787949012B09D17A4B1A787A4B03EBC2035B685B68FE
 | 
				
			||||||
:4021000018780344EAE764499278097C914203D16248FFF739FD614B1A78002A00F0AD801A78228018E0BDE8384000F029BF13F0030313D0022B40F0A0802380504B0C21C4
 | 
					:402100006360122310E0CB78022B12D18878FFF7E5FD002800F0DC80436863606368DA7863689B7843EA02232380BDE83840FFF78FBCCB78032B21D16A4B00228878D5B29B
 | 
				
			||||||
:402140001B7903F07F02564B01FB02339A78554BD2B21A7000225A706360B6E702222280514A11784F4AC9B2117053706260ACE7012323804D4BEFE70123238013794C4AC4
 | 
					:40214000854203D3634A92783AB910E0187801320028F7D018780344F0E75E4A62499278097C914203D16148FFF73EFD5F4B1A78002A00F0AD801A78228018E0BDE8384099
 | 
				
			||||||
:402180001344E9E701390A2977D8DFE801F037764F76067676760A7620009378454ADBB25AE0937803F0FF0153B9404B1A7891425FD01970404B01201870FFF715FE58E082
 | 
					:4021800000F012BF13F0030313D0022B40F0A0802380504B0C211B7903F07F02544B01FB02339A78534BD2B21A7000225A706360BBE702222280504A11784E4AC9B2117026
 | 
				
			||||||
:4021C000481EC0B2FFF75AFD0028EED155E0FFF71DFF002851D02A4A384913791279DBB2D2B20A70364A3249D25CCB5C9A4240D0314B01221A70FFF753FD3AE003F00303EE
 | 
					:4021C00053706260B1E7012323804C4BEFE70123238013794A4A1344E9E701390A2977D8DFE801F037764F76067676760A7620009378444ADBB25AE0937803F0FF0153B928
 | 
				
			||||||
:40220000012B2BD009D3022B37D11D4B9B78002B33D1BDE83840FFF7BFBE194B9B78012B2BD1214A137803F0FD0315E003F00303012B13D008D3022B1FD1114B9B78E3B9A4
 | 
					:402200003E4B1A7891425FD019703F4B01201870FFF71AFE58E0481EC0B2FFF75FFD0028EED155E0FFF722FF002851D0294A374913791279DBB2D2B20A70354A3049D25C1E
 | 
				
			||||||
:40224000BDE83840FFF77EBE0D4B9B78012B14D1154A137843F0020313700AE0084B1A795AB998781B791749DBB2CA5C22EA0002CA54BDE83840FFF79BBA002038BD00BFEC
 | 
					:40224000CB5C9A4240D0304B01221A70FFF758FD3AE003F00303012B2BD009D3022B37D11C4B9B78002B33D1BDE83840FFF7C4BE184B9B78012B2BD11F4A137803F0FD03CA
 | 
				
			||||||
:4022800000600040C492FF1FD092FF1FB03A0000143B00009C3A0000873B00006893FF1FDC92FF1F8192FF1FD392FF1FD592FF1FC292FF1FC092FF1FD492FF1FD192FF1FF4
 | 
					:4022800015E003F00303012B13D008D3022B1FD1104B9B78E3B9BDE83840FFF783BE0D4B9B78012B14D1144A137843F0020313700AE0084B1A795AB998781B791549DBB239
 | 
				
			||||||
:4022C0004A93FF1FD792FF1F074B1A78120609D55B78012B06D1054B054A5A6012781A80FFF786BB0020704700600040C492FF1F743A0000014B1870704700BF76650040FA
 | 
					:4022C000CA5C22EA0002CA54BDE83840FFF7A0BA002038BD00600040BC92FF1FC892FF1FB83B00001C3C00008F3C00006093FF1FD492FF1F7992FF1FCB92FF1FCD92FF1FBA
 | 
				
			||||||
:40230000014B1878704700BF67640040014B1870704700BF77640040064A0123136002F688321268E0211064034A1170A2F540721360704780E100E000E400E0014B187039
 | 
					:40230000BA92FF1FB892FF1FCC92FF1FC992FF1F4293FF1FCF92FF1F014B1870704700BF72640040014B1878704700BF68650040014B1870704700BF7A650040064A0123C8
 | 
				
			||||||
:40234000704700BF74640040014B1870704700BF7565004073B515461E460B4C05230022019200920A4601461846237000F064F932462946207800F01FF90221207800F0B7
 | 
					:40234000136002F688321268E0211064034A1170A2F540721360704780E100E000E400E0014B1870704700BF7A64004073B515461E460B4C04230022019200920A46014658
 | 
				
			||||||
:4023800009F9207802B070BDD080FF1F064A0423136002F688321268E0219064034A1170A2F202321360704780E100E002E400E0014B04221A60704700E100E0014B04228E
 | 
					:402380001846237000F022FC32462946207800F0DDFB0221207800F0C7FB207802B070BDD080FF1F074A0223136002F688321268E0215064044A11706FF440710A44136017
 | 
				
			||||||
:4023C0001A60704780E100E0014B1870704700BF74650040704738B505460078012428B100F066FD285D0134E4B2F8E738BD08B50D2000F05DFDBDE808400A2000F058BDDC
 | 
					:4023C000704700BF80E100E001E400E073B515461E460B4C05230022019200920A4601461846237000F0F2FB32462946207800F0ADFB0221207800F097FB207802B070BD84
 | 
				
			||||||
:40240000F7B516461F460B4C00230325019300930A4601462846257000F00EF93A463146207800F0C9F80221207800F0B3F8207803B0F0BDE080FF1FF7B516461F460B4C05
 | 
					:40240000D180FF1F064A0423136002F688321268E0219064034A1170A2F202321360704780E100E002E400E0014B04221A60704700E100E0014B04221A60704780E100E013
 | 
				
			||||||
:4024400000230225019300930A4601462846257000F0F2F83A463146207800F0ADF82946207800F097F8207803B0F0BDE180FF1FF7B516461F460B4C002301250193009322
 | 
					:40244000014B1870704700BF7B650040014B1870704700BF73640040704738B505460078012428B100F038FD285D0134E4B2F8E738BD08B50D2000F02FFDBDE808400A20C6
 | 
				
			||||||
:402480000A4601462846257000F0D6F83A463146207800F091F80221207800F07BF8207803B0F0BDE280FF1F73B515461E460B4C0023019300930A4601461846237000F026
 | 
					:4024800000F02ABD014B1870704700BF7865004010B500F081FD204A044613780A2043F002031370137C43F00203137412F80A3C43F0010302F80A3C937943F0010393712B
 | 
				
			||||||
:4024C000BBF832462946207800F076F80221207800F060F8207802B070BD00BFE380FF1F024B1878C0F38010704700BF8F450040074A7F23802113705170064A013BDBB2F7
 | 
					:4024C00002F5AB52137843F003031370134B18221A7013F8012C42F0400203F8012C13F8012C02F0FC0203F8012CCE2203F8062CA3F597530222183B1A70094A137843F0AA
 | 
				
			||||||
:4025000002F80839002BF9D1034A1370704700BFE480FF1FF87B00400078004017280FD8084B0001C25C11B142F0200201E002F0DF02C254C25C42F00102C2540020704780
 | 
					:402500000803137000F0ECFB064B10222046BDE810401A6000F044BDAB4300400E5900402F5B004080E200E008B500F035FD0F4A137803F0FE031370A2F5AA521D3A13785D
 | 
				
			||||||
:40254000012070471070004017280BD8064B0001C25C02F0FE02C254C25C02F0DF02C25400207047012070471070004017280DD8074900010B4603441A7942F004021A7150
 | 
					:4025400003F0FD031370137C03F0FD03137412F80A3C03F0FE0302F80A3C937903F0FE039371BDE8084000F01BBD00BF08590040044A137803F03F0343EA8010C0B2107082
 | 
				
			||||||
:40258000435C43F00103435400207047012070471070004017280BD8064A0001835C490003F0F10301F00E011943815400207047012070471070004041F6FF73994208BFD2
 | 
					:40258000704700BF08590040082804D00A280CBF8223C22300E0422308380E4AC0B20428137098BF0C4B4FF0000298BF33F910100A4B88BF11461A8042F210734B4341F2E4
 | 
				
			||||||
:4025C0004FF400519A4208BF4FF4005217289FBFC00000F1804000F5EC4081809ABFC280002001207047000017289FBF034B00011954002088BF0120704700BF197000402C
 | 
					:4025C000883103F6C41393FBF1F305490B60054B1A8070470A590040A43B00004A93FF1F4C93FF1F5093FF1F08B5102000F036FA0721042000F0BCFB0749042000F0AAFB02
 | 
				
			||||||
:4026000017289FBF054B00011A5C01F007019DBF1143195400200120704700BF1470004017289FBF034B0001185C00F0070088BFFF20704714700040172810B51AD8C000B7
 | 
					:40260000064A0C20137843F006031370FFF7BCFF034B00221A8008BDE1260000095900404893FF1F10B5054C23781BB9FFF7DCFF01232370BDE81040FFF72ABF7B92FF1FA6
 | 
				
			||||||
:4026400001F07F0100F1804441EAC21204F5EC44D2B222709DF8082003F00F0343EA0213DBB263709DF80C30002003F00F03A370E07010BD012010BD10B500F079FC0A4A00
 | 
					:40264000044B1A7802F0FB021A701A7842F001021A7070470859004010B5084B1C7814F0010403D10028F9D0002404E0204600F037FB024B1B78204610BD00BF09590040D9
 | 
				
			||||||
:402680005378182B0AD91478013B5370E30003F1804303F5F0431B78137000E0FF2400F06BFC204610BD00BFE480FF1F030610B5044611D400F05CFC084AE300117803F1FE
 | 
					:40268000034A044B1B881088181A00B2704700BF5093FF1FA25B00400E4A13881BB223B111880A2309B2594301E00B4B19680B4B1B88C01A42F2107300B203FB00F20223F1
 | 
				
			||||||
:4026C000804303F5F04319705378147001335370BDE8104000F050BC10BD00BFE480FF1F30B504060CD411F4704509D1C40004F1804404F5F0442180A270E370284630BDB0
 | 
					:4026C00091FBF3F30028D8BF5B42134493FBF1F000B270474A93FF1F4C93FF1F4893FF1F7047000010B500F057FC214A044613780A2043F001031370137C43F001031374BC
 | 
				
			||||||
:40270000012030BD03065FBFC00000F1804000F5F04081805ABFC280002001207047000038B50446084DB4F5004F05D9286800F017FCA4F50044F6E7034B58686043BDE875
 | 
					:4027000012F80A3C43F0020302F80A3C937943F00203937102F5AA521832137843F003031370144B18221A7013F8012C42F0400203F8012C13F8012C02F0FC0203F8012CBE
 | 
				
			||||||
:40274000384000F00DBC00BFEC80FF1F024B1B7A584300F005BC00BFEC80FF1F0E4B00F003001A78490102F0FC02104318701A7801F0600142F080021A701A7802F07F024E
 | 
					:40274000CE2203F8062CA3F597530222123B1A70094A137843F00803137000F0C1FA074B08222046BDE810401A6000F019BC00BFAB43004006590040275B004080E200E0CF
 | 
				
			||||||
:402780001A701A7802F09F020A431A701A7842F010021A70704700BF83430040014B01221A70704784430040044B00F00F021B6853F8220043F82210704700BF08ED00E008
 | 
					:4027800008B500F009FC0F4A137803F0FE031370A2F5AA52153A137803F0FE031370137C03F0FE03137412F80A3C03F0FD0302F80A3C937903F0FD039371BDE8084000F0BB
 | 
				
			||||||
:4027C000054A00F01F00126800F1100352F8230042F82310704700BF08ED00E000F01F0000F16040490100F56440C9B2017070470F4B10B50F4900240F205C609C60DC60F4
 | 
					:4027C000EFBB00BF00590040044A137803F03F0343EA8010C0B21070704700BF00590040082804D00A280CBF8223C22300E0422308380E4AC0B20428137098BF0C4B4FF095
 | 
				
			||||||
:402800001C615C61FFF7D0FF0B4A136843F0040313600A4B4FF47A72DB68B3FBF2F3084A1360084B4FF400421C60C3F8E82010BD8492FF1F9D28000010E000E0EC80FF1FC6
 | 
					:40280000000298BF33F910100A4B88BF11461A8042F210734B4341F2883103F6C41393FBF1F305490B60054B1A80704702590040AE3B00005693FF1F5C93FF1F5493FF1FFC
 | 
				
			||||||
:4028400014E000E018E000E0024A136843F002031360704710E000E008B5FFF7F5FF034A136843F00103136008BD00BF10E000E010B5054CA3691BB9FFF7BAFF0123A36179
 | 
					:4028400008B5102000F014F90721032000F090FA0749032000F07EFA064A0C20137843F006031370FFF7BCFF034B00221A8008BD39290000015900405893FF1F10B5054C6D
 | 
				
			||||||
:40288000BDE81040FFF7E8BF8492FF1F024B1868C0F30040704700BF10E000E038B5FFF7F5FF012808D1054D002455F8243003B198470134052CF8D138BD00BF8892FF1FAE
 | 
					:4028800023781BB9FFF7DCFF01232370BDE81040FFF728BF7C92FF1F044B1A7802F0FB021A701A7842F001021A7070470059004010B5084B1C7814F0010403D10028F9D0AE
 | 
				
			||||||
:4028C000024B03EB80035868596070478492FF1F134B144A1B78DBB20360127843EA0223114A0360127843EA0243104A0360127843EA026303600E4B0E4A1B78DBB2436031
 | 
					:4028C000002404E0204600F00BFA024B1B78204610BD00BF01590040034A044B1B881088181A00B2704700BF5493FF1FA05B00400E4A13881BB223B111880A2309B25943E7
 | 
				
			||||||
:40290000127843EA02230C4A4360127843EA02430A4A4360127843EA02634360704700BF0301004904010049EC46004002010049010100490001004905010049060100490D
 | 
					:4029000001E00B4B19680B4B1B88C01A42F2107300B203FB00F2022391FBF3F30028D8BF5B42134493FBF1F000B270475693FF1F5C93FF1F5893FF1F70470000014B1870E9
 | 
				
			||||||
:4029400010B500F015FB204A044613780A2043F002031370137C43F00203137412F80A3C43F0010302F80A3C937943F00103937102F5AB52137843F003031370134B18223F
 | 
					:40294000704700BF7B640040014B1870704700BF7F640040014B1870704700BF7C640040014B1870704700BF7E640040F7B516461F460B4C00230325019300930A460146B2
 | 
				
			||||||
:402980001A7013F8012C42F0400203F8012C13F8012C02F0FC0203F8012CCE2203F8062CA3F597530222183B1A70094A137843F008031370FFF7CAFE064B10222046BDE8DE
 | 
					:402980002846257000F022F93A463146207800F0DDF80221207800F0C7F8207803B0F0BDE080FF1FF7B516461F460B4C00230225019300930A4601462846257000F006F917
 | 
				
			||||||
:4029C00010401A6000F0D8BAAB4300400E5900402F5B004080E200E008B500F0C9FA0F4A137803F0FE031370A2F5AA521D3A137803F0FD031370137C03F0FD03137412F8E1
 | 
					:4029C0003A463146207800F0C1F82946207800F0ABF8207803B0F0BDE180FF1FF7B516461F460B4C00230125019300930A4601462846257000F0EAF83A463146207800F06F
 | 
				
			||||||
:402A00000A3C03F0FE0302F80A3C937903F0FE039371BDE8084000F0AFBA00BF08590040044A137803F03F0343EA8010C0B21070704700BF08590040082804D00A280CBF9D
 | 
					:402A0000A5F80221207800F08FF8207803B0F0BDE280FF1F73B515461E460B4C0023019300930A4601461846237000F0CFF832462946207800F08AF80221207800F074F880
 | 
				
			||||||
:402A40008223C22300E0422308380E4AC0B20428137098BF0C4B4FF0000298BF33F910100A4B88BF11461A8042F210734B4341F2883103F6C41393FBF1F305490B60054B33
 | 
					:402A4000207802B070BD00BFE380FF1F024B1878C0F38010704700BF8F450040034A00F0F800137803431370704700BF02410040034A00F0F800137803431370704700BF74
 | 
				
			||||||
:402A80001A8070470A590040603A00005293FF1F5493FF1F5893FF1F08B5102000F0A6F907210420FFF79AFE07490420FFF788FE064A0C20137843F006031370FFF7BCFFBA
 | 
					:402A800006410040074A7F23802113705170064A013BDBB202F80839002BF9D1034A1370704700BFE480FF1FF87B00400078004017280FD8084B0001C25C11B142F020028D
 | 
				
			||||||
:402AC000034B00221A8008BD912B0000095900405093FF1F10B5054C23781BB9FFF7DCFF01232370BDE81040FFF72ABFA092FF1F044B1A7802F0FB021A701A7842F0010256
 | 
					:402AC00001E002F0DF02C254C25C42F00102C25400207047012070471070004017280BD8064B0001C25C02F0FE02C254C25C02F0DF02C25400207047012070471070004024
 | 
				
			||||||
:402B00001A7070470859004010B5084B1C7814F0010403D10028F9D0002404E02046FFF715FE024B1B78204610BD00BF09590040034A044B1B881088181A00B2704700BF1D
 | 
					:402B000017280DD8074900010B4603441A7942F004021A71435C43F00103435400207047012070471070004017280BD8064A0001835C490003F0F10301F00E0119438154A3
 | 
				
			||||||
:402B40005893FF1FA25B00400E4A13881BB223B111880A2309B2594301E00B4B19680B4B1B88C01A42F2107300B203FB00F2022391FBF3F30028D8BF5B42134493FBF1F0C1
 | 
					:402B400000207047012070471070004041F6FF73994208BF4FF400519A4208BF4FF4005217289FBFC00000F1804000F5EC4081809ABFC280002001207047000017289FBF6F
 | 
				
			||||||
:402B800000B270475293FF1F5493FF1F5093FF1F7047000010B500F0EBF9214A044613780A2043F001031370137C43F00103137412F80A3C43F0020302F80A3C937943F0DB
 | 
					:402B8000034B00011954002088BF0120704700BF1970004017289FBF054B00011A5C01F007019DBF1143195400200120704700BF1470004017289FBF034B0001185C00F04D
 | 
				
			||||||
:402BC0000203937102F5AA521832137843F003031370144B18221A7013F8012C42F0400203F8012C13F8012C02F0FC0203F8012CCE2203F8062CA3F597530222123B1A7067
 | 
					:402BC000070088BFFF20704714700040172810B51AD8C00001F07F0100F1804441EAC21204F5EC44D2B222709DF8082003F00F0343EA0213DBB263709DF80C30002003F08B
 | 
				
			||||||
:402C0000094A137843F008031370FFF79FFD074B08222046BDE810401A6000F0ADB900BFAB43004006590040275B004080E200E008B500F09DF90F4A137803F0FE0313708E
 | 
					:402C00000F03A370E07010BD012010BD10B500F0C3F90A4A5378182B0AD91478013B5370E30003F1804303F5F0431B78137000E0FF2400F0B5F9204610BD00BFE480FF1F33
 | 
				
			||||||
:402C4000A2F5AA52153A137803F0FE031370137C03F0FE03137412F80A3C03F0FD0302F80A3C937903F0FD039371BDE8084000F083B900BF00590040044A137803F03F0361
 | 
					:402C4000030610B5044611D400F0A6F9084AE300117803F1804303F5F04319705378147001335370BDE8104000F09AB910BD00BFE480FF1F30B504060CD411F4704509D1B0
 | 
				
			||||||
:402C800043EA8010C0B21070704700BF00590040082804D00A280CBF8223C22300E0422308380E4AC0B20428137098BF0C4B4FF0000298BF33F910100A4B88BF11461A80AE
 | 
					:402C8000C40004F1804404F5F0442180A270E370284630BD012030BD03065FBFC00000F1804000F5F04081805ABFC280002001207047000038B50446084DB4F5004F05D988
 | 
				
			||||||
:402CC00042F210734B4341F2883103F6C41393FBF1F305490B60054B1A807047025900406A3A00005E93FF1F6493FF1F5C93FF1F08B5102000F084F807210320FFF76EFD92
 | 
					:402CC000286800F061F9A4F50044F6E7034B58686043BDE8384000F057B900BFEC80FF1F024B1B7A584300F04FB900BFEC80FF1F0E4B00F003001A78490102F0FC02104300
 | 
				
			||||||
:402D000007490320FFF75CFD064A0C20137843F006031370FFF7BCFF034B00221A8008BDE92D0000015900406093FF1F10B5054C23781BB9FFF7DCFF01232370BDE81040C8
 | 
					:402D000018701A7801F0600142F080021A701A7802F07F021A701A7802F09F020A431A701A7842F010021A70704700BF83430040014B01221A70704784430040044B00F08C
 | 
				
			||||||
:402D4000FFF728BFA192FF1F044B1A7802F0FB021A701A7842F001021A7070470059004010B5084B1C7814F0010403D10028F9D0002404E02046FFF7E9FC024B1B78204621
 | 
					:402D40000F021B6853F8220043F82210704700BF08ED00E0054A00F01F00126800F1100352F8230042F82310704700BF08ED00E000F01F0000F16040490100F56440C9B29B
 | 
				
			||||||
:402D800010BD00BF01590040034A044B1B881088181A00B2704700BF5C93FF1FA05B00400E4A13881BB223B111880A2309B2594301E00B4B19680B4B1B88C01A42F2107381
 | 
					:402D8000017070470F4B10B50F4900240F205C609C60DC601C615C61FFF7D0FF0B4A136843F0040313600A4B4FF47A72DB68B3FBF2F3084A1360084B4FF400421C60C3F883
 | 
				
			||||||
:402DC00000B203FB00F2022391FBF3F30028D8BF5B42134493FBF1F000B270475E93FF1F6493FF1F6093FF1F70470000034A00F0F800137803431370704700BF02410040A1
 | 
					:402DC000E82010BD8092FF1F312E000010E000E0EC80FF1F14E000E018E000E0024A136843F002031360704710E000E008B5FFF7F5FF034A136843F00103136008BD00BFD3
 | 
				
			||||||
:402E0000034A00F0F800137803431370704700BF06410040014B1870704700BF72640040014B1870704700BF7864004073B515461E460B4C04230022019200920A46014603
 | 
					:402E000010E000E010B5054CA3691BB9FFF7BAFF0123A361BDE81040FFF7E8BF8092FF1F024B1868C0F30040704700BF10E000E038B5FFF7F5FF012808D1054D002455F891
 | 
				
			||||||
:402E400018462370FFF7F8FB324629462078FFF7B3FB02212078FFF79DFB207802B070BDFC80FF1F074A0223136002F688321268E0215064044A11706FF440710A4413608D
 | 
					:402E4000243003B198470134052CF8D138BD00BF8492FF1F024B03EB80035868596070478092FF1F134B144A1B78DBB20360127843EA0223114A0360127843EA0243104A07
 | 
				
			||||||
:402E8000704700BF80E100E001E400E0014B1870704700BF75640040014B1870704700BF76640040014B1870704700BF79640040FEB5494652465B460EB407462449096800
 | 
					:402E80000360127843EA026303600E4B0E4A1B78DBB24360127843EA02230C4A4360127843EA02430A4A4360127843EA02634360704700BF0301004904010049EC460040B2
 | 
				
			||||||
:402EC0008A46244A12682448022100F071F8030020480068C018204900F06AF8143883460121C9430C460125002600F041F8814651460B7823400B705846013000F030F81C
 | 
					:402EC000020100490101004900010049050100490601004900000000FEB5494652465B460EB40746244909688A46244A12682448022100F071F8030020480068C018204936
 | 
				
			||||||
:402F00003800F04028400B78234003430B70584600F026F80136072EF2D9002001300138013001200B78234003430B705846043000F016F8484600F01FF800BF00BF00BF12
 | 
					:402F000000F06AF8143883460121C9430C460125002600F041F8814651460B7823400B705846013000F030F83800F04028400B78234003430B70584600F026F80136072E00
 | 
				
			||||||
:402F40000EBC894692469B46FEBD00BFAFF30080D480FF1FF880FF1F00C20100000000000230800803D000BF01380046FCD17047EFF3108072B6704780F31088704700BF77
 | 
					:402F4000F2D9002001300138013001200B78234003430B705846043000F016F8484600F01FF800BF00BF00BF0EBC894692469B46FEBD00BFAFF30080D480FF1FF880FF1F6B
 | 
				
			||||||
:402F8000094A137803F00303012B0AD0022B09D113790C2103F07F02044B01FB02339B7A00E013790020704700600040DC92FF1F002902D0B0FBF1F0704708B14FF0FF3097
 | 
					:402F800000C20100000000000230800803D000BF01380046FCD17047EFF3108072B6704780F31088704700BF094A137803F00303012B0AD0022B09D113790C2103F07F021C
 | 
				
			||||||
:402FC00000F008B80029F8D00246B0FBF1F000FB11217047704700BF014B1868704700BF6081FF1F0E4B70B51E460E4C0025E41AA410A54204D056F8253098470135F8E75C
 | 
					:402FC000044B01FB02339B7A00E013790020704700600040D492FF1F002902D0B0FBF1F0704708B14FF0FF3000F008B80029F8D00246B0FBF1F000FB11217047704700BFA1
 | 
				
			||||||
:4030000000F0DEFD084B094C1E46E41AA4100025A54204D056F8253098470135F8E770BDCC3B0000CC3B0000CC3B0000D43B000003460244934202D003F8011BFAE770475A
 | 
					:40300000014B1868704700BF5C81FF1F0E4B70B51E460E4C0025E41AA410A54204D056F8253098470135F8E700F04EFE084B094C1E46E41AA4100025A54204D056F8253071
 | 
				
			||||||
:4030400030B5141E05469BB0184604DA8B232B604FF0FF301DE04FF40273ADF80C300CBF234604F1FF33029305934FF6FF7300910491ADF80E3002461E9B6946284600F0D4
 | 
					:4030400098470135F8E770BDD43C0000D43C0000D43C0000DC3C000003460244934202D003F8011BFAE7704730B5141E05469BB0184604DA8B232B604FF0FF301DE04FF432
 | 
				
			||||||
:4030800073F8431CBCBF8B232B6014B1009B00221A701BB030BD000007B5009313460A46014603480068FFF7CBFF03B05DF804FB6081FF1F2DE9F0478E6882469E420C46D9
 | 
					:403080000273ADF80C300CBF234604F1FF33029305934FF6FF7300910491ADF80E3002461E9B6946284600F073F8431CBCBF8B232B6014B1009B00221A701BB030BD000022
 | 
				
			||||||
:4030C000914698463ED88A8912F4906F3AD02568096902236F1A656905EB450595FBF3F57B1C43449D4238BF1D4653050FD5294600F04AFB064698B13A46216900F0D2FA24
 | 
					:4030C00007B5009313460A46014603480068FFF7CBFF03B05DF804FB5C81FF1F2DE9F0478E6882469E420C46914698463ED88A8912F4906F3AD02568096902236F1A656977
 | 
				
			||||||
:40310000A38923F4906343F08003A38113E02A4600F098FB064670B92169504600F0E8FA0C23CAF80030A3894FF0FF3043F04003A381BDE8F08726613E44266046466561E0
 | 
					:4031000005EB450595FBF3F57B1C43449D4238BF1D4653050FD5294600F04AFB064698B13A46216900F0D2FAA38923F4906343F08003A38113E02A4600F098FB064670B9E0
 | 
				
			||||||
:40314000ED1BA560464528BF464649463246206800F0B3FAA36800209B1BA36023681E442660BDE8F08700002DE9F04F9DB003938B8980461C060D4616460DD50B695BB958
 | 
					:403140002169504600F0E8FA0C23CAF80030A3894FF0FF3043F04003A381BDE8F08726613E44266046466561ED1BA560464528BF464649463246206800F0B3FAA3680020A9
 | 
				
			||||||
:40318000402100F001FB2860286118B90C23C8F80030CDE040236B610023099320238DF82930DFF89CB130238DF82A3037463C4614F8013B1BB9B7EB060910D003E0252BD0
 | 
					:403180009B1BA36023681E442660BDE8F08700002DE9F04F9DB003938B8980461C060D4616460DD50B695BB9402100F001FB2860286118B90C23C8F80030CDE040236B6150
 | 
				
			||||||
:4031C000F9D02746F3E74B46324629464046FFF771FF013000F0A780099B4B4409933B78002B00F0A08000234FF0FF3204930793059206938DF853301A93012605222178C6
 | 
					:4031C0000023099320238DF82930DFF89CB130238DF82A3037463C4614F8013B1BB9B7EB060910D003E0252BF9D02746F3E74B46324629464046FFF771FF013000F0A780FE
 | 
				
			||||||
:403200004E4800F041FA671C049B38B14B4A3C46801A06FA00F018430490EFE7D90644BF20228DF853201A0744BF2B228DF8532022782A2A03D0079A00210A200BE0039AA2
 | 
					:40320000099B4B4409933B78002B00F0A08000234FF0FF3204930793059206938DF853301A930126052221784E4800F041FA671C049B38B14B4A3C46801A06FA00F0184379
 | 
				
			||||||
:40324000111D12680391002A10DA524243F00200079204900BE027463B780134303B092B03D800FB02320121F5E701B107923B782E2B1ED17B782A2B0AD1039B02371A1DAA
 | 
					:403240000490EFE7D90644BF20228DF853201A0744BF2B228DF8532022782A2A03D0079A00210A200BE0039A111D12680391002A10DA524243F00200079204900BE027468C
 | 
				
			||||||
:403280001B680392002BB8BF4FF0FF33059310E0002319460593781C0A2407463A780130303A092A03D804FB01210123F5E703B1059103223978224800F0E6F940B1402309
 | 
					:403280003B780134303B092B03D800FB02320121F5E701B107923B782E2B1ED17B782A2B0AD1039B02371A1D1B680392002BB8BF4FF0FF33059310E0002319460593781CA7
 | 
				
			||||||
:4032C000CBEB000003FA00F0049B013718430490397806221B487E1C8DF8281000F0D4F988B1194B33B9039B073323F007030833039314E003AB00932A46144B04A940468F
 | 
					:4032C0000A2407463A780130303A092A03D804FB01210123F5E703B1059103223978224800F0E6F940B14023CBEB000003FA00F0049B013718430490397806221B487E1CEB
 | 
				
			||||||
:40330000AFF3008007E003AB00932A460F4B04A9404600F093F8B0F1FF3F824603D0099B5344099342E7AB895B0601D4099801E04FF0FF301DB0BDE8F08F00BF9B3B000071
 | 
					:403300008DF8281000F0D4F988B1194B33B9039B073323F007030833039314E003AB00932A46144B04A94046AFF3008007E003AB00932A460F4B04A9404600F093F8B0F12A
 | 
				
			||||||
:40334000A13B0000A53B000000000000B53000002DE9F04791461F460A698B6806469342B8BF1346C9F8003091F843200C46DDF8208012B10133C9F800302368990642BF15
 | 
					:40334000FF3F824603D0099B5344099342E7AB895B0601D4099801E04FF0FF301DB0BDE8F08F00BFA33C0000A93C0000AD3C000000000000DD3000002DE9F04791461F4627
 | 
				
			||||||
:40338000D9F800300233C9F80030256815F0060510D104F1190A07E00123524639463046C04701301AD00135E368D9F800209B1A9D42F1DB94F843302268003318BF01230D
 | 
					:403380000A698B6806469342B8BF1346C9F8003091F843200C46DDF8208012B10133C9F800302368990642BFD9F800300233C9F80030256815F0060510D104F1190A07E05B
 | 
				
			||||||
:4033C00092060FD5E118302081F843005A1C94F845102244023382F8431003E04FF0FF30BDE8F08704F1430239463046C0470130F4D02268D9F80050E36802F00602042AD7
 | 
					:4033C0000123524639463046C04701301AD00135E368D9F800209B1A9D42F1DB94F843302268003318BF012392060FD5E118302081F843005A1C94F845102244023382F884
 | 
				
			||||||
:4034000008BF5D1B2269A3680CBF25EAE57500259342C4BF9B1AED184FF000091A344D4509D00123224639463046C0470130D5D009F10109F3E70020BDE8F0872DE9F0438A
 | 
					:40340000431003E04FF0FF30BDE8F08704F1430239463046C0470130F4D02268D9F80050E36802F00602042A08BF5D1B2269A3680CBF25EAE57500259342C4BF9B1AED1843
 | 
				
			||||||
:4034400017460A7E85B06E2A984606460C460C9B01F1430E00F0AE8011D8632A22D009D8002A00F0BB80582A40F0CA8081F84520834955E0642A1ED0692A1CD0C0E0732A65
 | 
					:403440004FF000091A344D4509D00123224639463046C0470130D5D009F10109F3E70020BDE8F0872DE9F04317460A7E85B06E2A984606460C460C9B01F1430E00F0AE8054
 | 
				
			||||||
:4034800000F0B08009D86F2A2ED0702A40F0B8800A6842F020020A603EE0752A24D0782A3AD0ADE01A6801F14205111D1960136884F84230A8E021681A6811F0800F02D098
 | 
					:4034800011D8632A22D009D8002A00F0BB80582A40F0CA8081F84520834955E0642A1ED0692A1CD0C0E0732A00F0B08009D86F2A2ED0702A40F0B8800A6842F020020A6091
 | 
				
			||||||
:4034C000111D196008E011F0400F02F10401196002D0B2F9003000E01368002B3CDA2D225B4284F8432037E021681A6811F0800F02D0111D196007E011F0400F02F104010E
 | 
					:4034C0003EE0752A24D0782A3AD0ADE01A6801F14205111D1960136884F84230A8E021681A6811F0800F02D0111D196008E011F0400F02F10401196002D0B2F9003000E045
 | 
				
			||||||
:40350000196001D0138800E01368227E5C496F2A14BF0A2208221BE078225A4984F845202268186812F0800F00F104051D6003D1550601D5038800E00368D00744BF42F032
 | 
					:403500001368002B3CDA2D225B4284F8432037E021681A6811F0800F02D0111D196007E011F0400F02F10401196001D0138800E01368227E5C496F2A14BF0A2208221BE068
 | 
				
			||||||
:40354000200222601BB9226822F0200222601022002084F8430001E049490A226568002DA56008DB206820F0040020602BB9002D7DD175460CE0002B79D07546B3FBF2F020
 | 
					:4035400078225A4984F845202268186812F0800F00F104051D6003D1550601D5038800E00368D00744BF42F0200222601BB9226822F0200222601022002084F8430001E08A
 | 
				
			||||||
:4035800002FB1033CB5C05F8013D03460028F5D1082A0BD12368DA0708D5236962689A42DEBF302305F8013C05F1FF35C5EB0E0323612EE008681A6810F0800F496903D0FC
 | 
					:4035800049490A226568002DA56008DB206820F0040020602BB9002D7DD175460CE0002B79D07546B3FBF2F002FB1033CB5C05F8013D03460028F5D1082A0BD12368DA0737
 | 
				
			||||||
:4035C000101D1860136808E010F0400F02F104001860136801D0198000E0196000232361754616E01A68111D1960156800216268284600F049F808B1401B6060636804E0BC
 | 
					:4035C00008D5236962689A42DEBF302305F8013C05F1FF35C5EB0E0323612EE008681A6810F0800F496903D0101D1860136808E010F0400F02F104001860136801D0198064
 | 
				
			||||||
:4036000004F1420584F8422001232361002384F84330CDF800803B4603AA21463046FFF797FE013002D14FF0FF3026E023692A4639463046C0470130F5D023689B0710D563
 | 
					:4036000000E0196000232361754616E01A68111D1960156800216268284600F049F808B1401B6060636804E004F1420584F8422001232361002384F84330CDF800803B468C
 | 
				
			||||||
:40364000002504F1190907E001234A4639463046C0470130E7D00135E368039A9B1A9D42F2DBE068039B9842B8BF184605E00B7804F1420584F842308AE705B0BDE8F083AB
 | 
					:4036400003AA21463046FFF797FE013002D14FF0FF3026E023692A4639463046C0470130F5D023689B0710D5002504F1190907E001234A4639463046C0470130E7D00135CC
 | 
				
			||||||
:403680004F3A0000AC3B000010B5C9B202449042034605D01C7801308C42F8D1184610BD002010BD10B5431E0A44914204D011F8014B03F8014FF8E710BD884210B501EBCE
 | 
					:40368000E368039A9B1A9D42F2DBE068039B9842B8BF184605E00B7804F1420584F842308AE705B0BDE8F083923B0000B43C000010B5C9B202449042034605D01C78013064
 | 
				
			||||||
:4036C000020301D8421E0BE09842FBD28118D21AD34204D013F8014D01F8014DF8E710BD994204D011F8014B02F8014FF8E710BD38B50546002944D051F8043C0C1F002BF2
 | 
					:4036C0008C42F8D1184610BD002010BD10B5431E0A44914204D011F8014B03F8014FF8E710BD884210B501EB020301D8421E0BE09842FBD28118D21AD34204D013F8014DA2
 | 
				
			||||||
:40370000B8BFE41800F0D4F81E4A1368114613B96360146030E0A3420DD92268A018834201BF18685B681218226063600C6023E0A24203D813465A68002AF9D118681918DB
 | 
					:4037000001F8014DF8E710BD994204D011F8014B02F8014FF8E710BD38B50546002944D051F8043C0C1F002BB8BFE41800F0D4F81E4A1368114613B96360146030E0A342E7
 | 
				
			||||||
:40374000A1420BD12168014458188242196013D110685268014419605A600DE002D90C232B6009E021686018824201BF106852680918216062605C602846BDE8384000F0C4
 | 
					:403740000DD92268A018834201BF18685B681218226063600C6023E0A24203D813465A68002AF9D118681918A1420BD12168014458188242196013D11068526801441960EE
 | 
				
			||||||
:4037800098B838BDA892FF1F70B5CD1C25F0030508350C2D38BF0C25002D064601DBA94202D90C23336046E000F082F8234B1C681A462146A1B10B685B1B0ED40B2B03D94E
 | 
					:403780005A600DE002D90C232B6009E021686018824201BF106852680918216062605C602846BDE8384000F098B838BDA092FF1F70B5CD1C25F0030508350C2D38BF0C2534
 | 
				
			||||||
:4037C0000B60CC18CD501EE08C420BBF63684B681360636018BF0C4615E00C464968E9E7174C23681BB9304600F052F820602946304600F04DF8431C18D0C41C24F00304D4
 | 
					:4037C000002D064601DBA94202D90C23336046E000F082F8234B1C681A462146A1B10B685B1B0ED40B2B03D90B60CC18CD501EE08C420BBF63684B681360636018BF0C4695
 | 
				
			||||||
:40380000A0420DD12560304600F053F804F10B00231D20F00700C31A0ED05A42E25070BD211A304600F034F80130EBD10C233360304600F03EF8002070BD00BFA892FF1F09
 | 
					:4038000015E00C464968E9E7174C23681BB9304600F052F820602946304600F04DF8431C18D0C41C24F00304A0420DD12560304600F053F804F10B00231D20F00700C31A48
 | 
				
			||||||
:40384000A492FF1FF8B5074615460E4621B91146BDE8F840FFF798BF1AB9FFF749FF2846F8BD00F027F885420ED929463846FFF78BFF044650B131462A46FFF713FF3146E1
 | 
					:403840000ED05A42E25070BD211A304600F034F80130EBD10C233360304600F03EF8002070BD00BFA092FF1F9C92FF1FF8B5074615460E4621B91146BDE8F840FFF798BFAB
 | 
				
			||||||
:403880003846FFF735FF01E03046F8BD2046F8BD38B5064C0023054608462360FDF7D8FB431C02D1236803B12B6038BD8C93FF1F7047704751F8040C0028BEBF091851F8F0
 | 
					:403880001AB9FFF749FF2846F8BD00F027F885420ED929463846FFF78BFF044650B131462A46FFF713FF31463846FFF735FF01E03046F8BD2046F8BD38B5064C002305467D
 | 
				
			||||||
:4038C000043CC0180438704700000000050209020B020D020F021102130215027265706C792030782530327800686F6D696E6700626567696E6E696E67207365656B2066CB
 | 
					:4038C00008462360FDF7F4FB431C02D1236803B12B6038BD8493FF1F7047704751F8040C0028BEBF091851F8043CC0180438704700000000050209020B020D020F021102BB
 | 
				
			||||||
:40390000726F6D20256420746F2025640066696E6973686564207365656B00796573006E6F00647269766520303A20257320647269766520313A2025730057616974696E5F
 | 
					:403900001302150228000000000104000100000000000000000157494E55534200003030303031000000000000000000E0000000000105000100D6000000070000002A0075
 | 
				
			||||||
:403940006720666F72205553422E2E2E0055534220726561647900636F6D6D616E6420307825303278006661696C2025642B25642B2564203D3D2025642C206E6F7420254E
 | 
					:4039400044006500760069006300650049006E0074006500720066006100630065004700550049004400730000009E0000007B00330064003200370035006300660065004E
 | 
				
			||||||
:4039800064007061737365643D256400756E64657272756E206166746572202564207061636B65747300636F756E743D256420693D256420643D256400636D645F77726997
 | 
					:403980002D0035003400330035002D0034006400640035002D0061006300630061002D003900660062003900390035006500320066003600330038007D0000007B00330058
 | 
				
			||||||
:4039C000746500703D25642063723D25642063773D256420663D256420773D256420696E6465783D256420756E64657272756E3D256400756E64657272756E21007375635E
 | 
					:4039C00064003200370035006300660065002D0035003400330035002D0034006400640035002D0061006300630061002D00390066006200390039003500650032006600B4
 | 
				
			||||||
:403A0000636573730073746172742065726173696E670073746F702065726173696E670069646C6500005100401000405100403000000001400010001401400008004001A3
 | 
					:403A00003600330038007D00000000007265706C792030782530327800686F6D696E6700626567696E6E696E67207365656B2066726F6D20256420746F2025640066696E14
 | 
				
			||||||
:403A400040000A004C0140000200500140200030313233343536373839414243444546000001000000040000001000010000000400000010280000000001040001000000C2
 | 
					:403A40006973686564207365656B00796573006E6F0057616974696E6720666F72205553422E2E2E00555342207265616479005363616E6E696E67206472697665732E2E1C
 | 
				
			||||||
:403A800000000000000157494E5553420000303030303100000000000000000012034D005300460054003100300030000100000001000000B83A000001000000873B0000A5
 | 
					:403A80002E00647269766520303A20257320647269766520313A20257300636F6D6D616E6420307825303278006661696C2025642B25642B2564203D3D2025642C206E6F40
 | 
				
			||||||
:403AC000000000000000000001000000D03A000001000000593B000004000000F23A0000000000000000000000000000F03A0000FF00000001024000FF00000082024000C7
 | 
					:403AC00074202564007061737365643D256400756E64657272756E206166746572202564207061636B65747300636F756E743D256420693D256420643D256400636D645FEF
 | 
				
			||||||
:403B0000FF00000003034000FF00000084034000FF00020304030904160346006C007500780045006E00670069006E0065002A0343006F0077006C00610072006B00200034
 | 
					:403B0000777269746500703D25642063723D25642063773D256420663D256420773D256420696E6465783D256420756E64657272756E3D256400756E64657272756E210015
 | 
				
			||||||
:403B400054006500630068006E006F006C006F0067006900650073000009022E0001010080320904000004FF00000107050102400000070582024000000705030340000AE8
 | 
					:403B4000737563636573730073746172742065726173696E670073746F702065726173696E670069646C650000510040100040510040300000000140001000140140000858
 | 
				
			||||||
:403B80000705840340000A12010002FF0001080912006E0100020180014300232D302B2000686C4C0065666745464700303132333435363738396162636465660000000069
 | 
					:403B800000400140000A004C01400002005001402000303132333435363738394142434445460000000100000004000000100001000000040000001001000000C03B000072
 | 
				
			||||||
:403BC000F8B500BFF8BC08BC9E46704759000000CD100000F8B500BFF8BC08BC9E46704735000000F83B0000C880FF1FA00000002812000000000000000000009093FF1FA8
 | 
					:403BC000010000008F3C0000000000000000000001000000D83B000001000000613C000004000000FA3B0000000000000000000000000000F83B0000FF0000000102400099
 | 
				
			||||||
:403C0000FF000000675000400C00000007000000FFFFFFFF7F8000003F0000000000007D00FA0000400000000090D003FF0000000000000000000000000000000000000028
 | 
					:403C0000FF00000082024000FF00000003034000FF00000084034000FF00020304030904160346006C007500780045006E00670069006E0065002A0343006F0077006C00CE
 | 
				
			||||||
:403C400000000000000000000000000000000000993B0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000070
 | 
					:403C4000610072006B00200054006500630068006E006F006C006F0067006900650073000009022E0001010080320904000004FF00000107050102400000070582024000E5
 | 
				
			||||||
:403C8000000000000000000000000000000000000081FF1F000000000000000000000000000000000000000000000000000000000000000000000000000000000000000065
 | 
					:403C8000000705030340000A0705840340000A12010002FF0001080912006E0100020180014300232D302B2000686C4C00656667454647003031323334353637383961629E
 | 
				
			||||||
:403CC00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000C4
 | 
					:403CC0006364656600000000F8B500BFF8BC08BC9E467047590000002D110000F8B500BFF8BC08BC9E46704735000000003D0000C880FF1F980000002812000000000000F3
 | 
				
			||||||
:403D00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000083
 | 
					:403D0000000000008893FF1FFFFF0000675000400C00000007000000FFFFFFFF7F8000003F0000000000007D00FA0000400000000090D003000000000000000000000000EE
 | 
				
			||||||
:403D40000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000043
 | 
					:403D40000000000000000000000000000000000000000000A13C00000000000000000000000000000000000000000000000000000000000000000000000000000000000066
 | 
				
			||||||
:403D80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003
 | 
					:403D80000000000000000000000000000000000000000000FC80FF1F0000000000000000000000000000000000000000000000000000000000000000000000000000000069
 | 
				
			||||||
:403DC00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000C3
 | 
					:403DC00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000C3
 | 
				
			||||||
:403E00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000082
 | 
					:403E00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000082
 | 
				
			||||||
:403E40000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000042
 | 
					:403E40000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000042
 | 
				
			||||||
@@ -4098,48 +4098,48 @@
 | 
				
			|||||||
:40FF80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041
 | 
					:40FF80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041
 | 
				
			||||||
:40FFC0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001
 | 
					:40FFC0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001
 | 
				
			||||||
:0200000480007A
 | 
					:0200000480007A
 | 
				
			||||||
:400000000145004009520040015B00400165004047000140380101404E0201404703014046040140440501404C060140490701402C08014031090140040B0140030D014075
 | 
					:400000000145004008520040015B004001650040020101402C0201402D0301400F0501400B0701406308014056090140570A01404A0B0140500C01404A0D0140480E014042
 | 
				
			||||||
:400040006C14014057150140591601404B17014011190140071B01400B400140104101400C4201400F43014002440140054501400A4601400B4701400C480140104901404C
 | 
					:40004000390F01400415014004170140671801404B190140361A0140471B01400D40014010410140134201400D43014004440140064501400A460140084701400B48014097
 | 
				
			||||||
:40008000174C01400C4D014006500140045101407E02080409021082110218021904601561137C402721240A02E40303040E0520064107C00A840B900E840F901001120693
 | 
					:4000800010490140144C01400C4D014006500140045101407E02080109441180180219016009610A7C402721290AE204E6080F011001150126012E012F013001310138026A
 | 
				
			||||||
:4000C00013901684179019011A841B481C081DFC1E221F0221C122182324268427902B9C2CE72E10300733E0351F36F83A023B084204460E480449FF4AFF4BFF4F83580B46
 | 
					:4000C00039023E013F01580459045B045F01810883048C018D0E910194029701A404AD04AE04AF0AB004B102B301B402B50CB601B802B908BE51BF04D608D804D909DB0401
 | 
				
			||||||
:40010000590B5A045B045C995D095F01868088028A8190E7921094019686980F9A409C0F9E20A2E0A618A804AA81AE80B207B4F8D80BDC09DF010022022003010524084089
 | 
					:40010000DC90DD90DF01020208080C02100213081540170818081A801B801C80200821012210231026012A802C02300233043708388039023D405840600268026B0C6D4004
 | 
				
			||||||
:4001400009080A080B400C420D200E2010021108130215801610172119011A011C241E201F0C210422082308284029042B88312032643301382039883A013B804240528017
 | 
					:40014000782088028B109840B040C001C214C4A5CA18CC43CE19D608D808DE04E208E68080088201928094809C289E80A201A602B044B380B404B610E604EA01EE44804068
 | 
				
			||||||
:400180005A215B4A600461016218634278027C028280C06FC2FFC4FDCA07CC0FCE0FD001D60FD80FDE8103140404050806110710081F0A800C010E1E0FE4101F124015102D
 | 
					:40018000842094809C209E80A602AA40E211E608EA01EE0C00800121020403020403052106FC0704080109210A020B080C040E100F4010FF11011404152F162019201A0495
 | 
				
			||||||
:4001C00016E0178218021A111B141C1F1E20211023212408261127142B142D1F2F4032F0330F360F37F03A083B80580B590B5B045C995F018203830884618608873088204C
 | 
					:4001C0001B011C041D211EF91F0E220224042608271028042A402B2F2D0F2E02311F336034FF39083A0C3E104003450C470E481149FF4AFF4BFF50045609581859045A044E
 | 
				
			||||||
:4002000089108A508B828DC78E108F2892109304961C97C49A109B04A061A110A204A341A440A630A704AB04AC7CAE02AF04B01FB30FB460B5F4BB08D80BD90BDB04DC99FF
 | 
					:400200005B045C995D995F0162C081028407850186388702880189048C028D048E04902091049208940895029610983F99029C089D049E30A105A503A704A802A902AA0417
 | 
				
			||||||
:40024000DF01012A02200301040805400708081009080B8C0C420E200F04104211081504180819221A0C1B011C221D4C1E211F4820042218242025442731285029402B8839
 | 
					:40024000AC3FAD02B43FB507B63FBF10D608D804D904DB04DC09DD90DF010010010803010490050909240A420C030E020F24100A15081602172119401A021B501E101F107B
 | 
				
			||||||
:400280002C022E042F883204331134103508380439813A103D8C3E016230680269806A806D4078027C029308942096E897809C029D249F61A403A50CA620A781AA01AB0889
 | 
					:400280002120242025052603272029982B402C022F18300831803202332035983701388039013B183C803D113E0447084F0856085A805F4062806302670269806B026C0881
 | 
				
			||||||
:4002C000C0EFC2FEC42DCAFFCC67CEDFDE81E208021004400620080C0C010E0210081101140818051A081C04200828202AC02CE02F0130603280341E3501360138203E40ED
 | 
					:4002C0006D116E846F21759076467F01814087018E08908094209581971499049C019DC99E449F03A382A408A682A729C0F7C2FFC4F3CA7FCCFFCEFFD040D618D818DE1080
 | 
				
			||||||
:400300005608580459045B045C995D905F0181608209842487108A128B108F10903F93039407950197089B1C9D40A036A209A310A710A82DA901AA12AB04AC40AD7CAF0220
 | 
					:40030000E210EA01EE0C0101041205010624084209800A100B200C040D700F80107011081201130414061508170219071A081B081D801E601F102140221023802404250F16
 | 
				
			||||||
:40034000B11FB238B440B540B607B720BE10D608D80BD90BDB04DC99DD90DF01000201280302040A070409980B800C020E20104212081550170119281A401B401E201FA0A5
 | 
					:4003400027F028042B0F2C802D01300F320F348035FF3670380A3B0C3E103F105804590A5B045C995F01824185F186418704888089208A018B118CF18E0291F1924E930218
 | 
				
			||||||
:4003800022102662274828022C022E052F043302364237283C203D803F0558805D80600267016B026D106F017C0287208B848F4091409205930496409B209C029F48A0124A
 | 
					:40038000954096419711980199109A149BE19F0EA1F1A308A580A641A711A801AA28B00FB10FB3F0B4F0BA02BB02D80BD90BDB04DC99DF010108020203080510076208017B
 | 
				
			||||||
:4003C000A140A208A620A780AD01AE08C07FC23FC4DBCAF8CCF1CEF0D618D818DE80E208E408EA040104020F0440068008700A800C800E200F0110011106130114081602E9
 | 
					:4003C00009200A220D020E1410021240131414081508188819041A221B821C801D121F1021282501277029892B082D022F103008314033213608376238A039013A043E1454
 | 
				
			||||||
:40040000170218011C0F1EF0200124072608288029052A102B022C082E04310736FF3E403F01580459045B045F018001811C820283E18402852087C0880489828B218C0248
 | 
					:4004000068026D407A107E80800481408D108F019108921495809702980899029D109F72A218A440A509A701A809B340B408B502B640C0F7C27FC46FCACFCCFFCE6FDE8298
 | 
				
			||||||
:400440008D088F10900491FF940495089710980599029C049D04A002A1FCA402A520A740A802AC03AE04AF02B007B3FCB503BB20BE01D804D904DB04DC90DF010081012440
 | 
					:40044000E401E8F0EC20EE40020103C4070808050A020B040C380D200F82101011C7120813181602170418081A301B041F302520274128042B042C062E012F043020320715
 | 
				
			||||||
:4004800004450520084009080A080B810C080D010E020F041008120113861544172219011C0220042114222C23282740280229012B202D1030083180321033023705396892
 | 
					:40048000330F341837F43B083E04580459085B045C995F0182108303840285628604870489208A108B508DFC8E108F0192039420964097809A109B1C9C409E209F10A07C22
 | 
				
			||||||
:4004C0003A013D82588068066C016D806F048004810184048F0191109220940A9780980299209B019C409F04A401A598A702A880A980AF02C0FFC2FFC4FFCA2BCCCFCE9F8E
 | 
					:4004C000A162A201A308A61CA710A940AA10AB30AC02AE08AF10B01FB11FB360B460B780D808D908DC99DF0100A001800204036004020706081009080A800B010C080E8878
 | 
				
			||||||
:40050000D608E24CE402E605EA04EC02EE0C06010B0410041304160119021C022101240829042C013001310232043304340236083701380239083E553F45560858045904A9
 | 
					:400500001218134215401608180419201A841B201C081EA02105220923112504268429922A242D802E102F20301031083350340136883722380439823B103D0A3E203F4070
 | 
				
			||||||
:400540005B045D905F0183018A029501A401AC02B401B501B602B880B920BE50BF10D804D904DB04DF01030804080D800F50100212101410154019101A021E2A1F022210BD
 | 
					:40054000611062106D406F047B037F028A08900292509508968297129C019D329F62A018A444A501A690A721C0DFC27FC4CFCA7FCCFECEFFDE18E020E208EA8000020120A4
 | 
				
			||||||
:40058000250226882C802F083308372138023F10584059105DA45E01645266106A406C076D406F09800282C085808608890293409980AF40C022C2B0C4A5CAA0CCA2CE2157
 | 
					:40058000024803C004C20502062407440A030B900E9011FC129013011690170318201AC01B901E901F9020FC21C222012328269027902A9C2B9C2F90321F331F34E037E015
 | 
				
			||||||
:4005C000D6FCD8F0EA04EE0C9980E208E448EA049980B180E208018002200608070108280B100C020D210E2C1028110F1434152117081828192F1C101E021F2F202821210D
 | 
					:4005C0003A203B80420647E0482049FF4AFF4BFF4F83580859085A045B045C995D095F0180E28208861088E28A049210942096D09A03A0FCA201A440A630A880AA30AE1C91
 | 
				
			||||||
:40060000230224022740282829212B042C202D212E012F0E321F336035803620371F39083E443F1040524720482049FF4AFF4BFF4D204EF05110580459045A045B045C9038
 | 
					:40060000B2E0B41FD808DB04DC09DF01009001C6032005260610072009010A140B420D200E100F40121013121548171218101A241B101C201D201E101F0820022204230148
 | 
				
			||||||
:400640005D095F01610862406340648066406740800F810183028503861087FC88208A018B048C208DFF8E0290039302942395809608970499049A409B209D049E2F9FF9AF
 | 
					:4006400029862B08300131103204335039043B1148054A0252015AAA6120628263206A406C097B037F0282018610C07FC27FC4FECA0FCC0FCE07D204D60FD80FDE188A02E6
 | 
				
			||||||
:40068000A023A104A20CA308A423A504A604A740A82FA904AB10AF02B060B3FFB460B61FB822BF04D804D904DB04DC09DF01012202200301040205040608070209880A04D5
 | 
					:40068000A602E604EE02A602B680E401EE020010022003020406063807040802090C0A040BF10C080D0C0F20100813081408150C17101808190C1B401C081F0221802204B3
 | 
				
			||||||
:4006C0000B800C080D800E48118012081305144015051610171019881C401D401E041F602118228023112410284129082A102D202E402F6030083240331234013680372A63
 | 
					:4006C000230C250327FC281A29012A202B022DFF2E01303F31FF3E013F01580459045B045F0181238280830C842286CC870188308A028B2F8CC88D0F9123924894C8952367
 | 
				
			||||||
:40070000381039423A083C063D803F1041104980510159025A0269806C016D806F0285018D409004914592C2930494429604979199249A089B3B9D40A009A180A22CA548B8
 | 
					:40070000970898D499239B049CC89F10A0C8A120A302A4C8A52FA802AB40AC80AE01B080B261B31FB41FB560B760B808B9A0BE11C046C620C808C9FFCAFFCBFFCD20CEF004
 | 
				
			||||||
:40074000A722AC02B704C0FFC2FFC47FCAFFCCFFCEFFD004D208E402E808EE1200FF01880403054606FC07B8080C09880A100C0C0EF10F0112081510160417A0180C198849
 | 
					:40074000D110D804D904DA04DB04DC99DD09DF01E108E240E340E480E640E7400010010803820490050909080A420B040E020F941002110A120415401721184019181C80B4
 | 
				
			||||||
:400780001A401C011D421E021F04218822022480259A260C2720280C29882A202E022F0431C132FF333F35C137C139A23E043F04580459045B045C905F01800282058521EF
 | 
					:40078000218C2314274029182A022D4A2F0830083361350436413720381039413A043D013F9440404A085010584059205F806C026D4082409080910192029410950896C023
 | 
				
			||||||
:4007C000870288028C0291279403950896049B389D049F01A118A340A706AC02AF01B006B107B310B401B560B708BE10BF40C006C5ECC803C9FFCAFFCBFFD004D601D8046C
 | 
					:4007C000971C99049A069B219D099F08A008A105A2C1A3E6A442A580A708B340B610C0FFC2FFC4DFCAF7CCFFCEFFD001D204D61CEE120008060209020D01100411041202D8
 | 
				
			||||||
:40080000D904DA04DB04DC99DD09DF01E2C00020010203020406056007100A200C010D800E040F1013801542172819131D042003218022D5240425102605278128102901DB
 | 
					:4008000018041F04220428012C063006310132013302340835043A023E143F055608580459045B045C995D905F0181028405881090019236930198019C319E0AAC05AD012B
 | 
				
			||||||
:400840002A802D202E402F603180321433023680372838043C043D803F11481049104B0264016701684869476A406C02728873068410860194419546978799209B2C9F827A
 | 
					:40084000B00CB102B210B420B501B603BE04BF11D608D804D904DB04DC09DD90DF0101080240051809200A400E820F08100811401280154019231A501C101D101E821F0E2C
 | 
				
			||||||
:40088000A228A448A598A601A722AB40B002B481C0FBC2F4C4F1CAFBCC7FCEF2D204E220E604EA4082108A018E048F029222960197109D209F20A214A302B080B104B6017C
 | 
					:4008800020402120220827882F02300232803601382039803F0158205A805F40600862406701680869806F0180408210844887408B018E4090209140941096409708982064
 | 
				
			||||||
:4008C000E220EA10EC808F209F20AF10B211B520E412EE021B011F083240330836843B408140C630CCF0CE10E62030803204358037083A023D408480914096809740A6046A
 | 
					:4008C00099089C409D239F88A002A280A304A608A708B020B410C06CC2DAC48BCA10CC89CE8CD61CD81CE001E622EE021B011F083140330836843B4083408540C630CCF07B
 | 
				
			||||||
:40090000AE80AF01CCF0CE60E210508057208580968897409D809E02A604AB08D460E210EA20832284808E02968097409E02A480A620A720AA24AE04E230E620EC80EE30D9
 | 
					:40090000CE10E220E61030803204364037043A083F80848088029740A340A604AE80AF01CCF0CE60E2105004570880049002960897409A049E089F04A002A120A644A80182
 | 
				
			||||||
:400940001501C4045D828740B101D605EE011B04850287108D8097809D82A480A880C608E4020B880C800F108A109798A480A740AB44AF04C20FE404262080018A01974061
 | 
					:40094000AA04B520D460E680EA80EE208E08900297409A049E08A002A120A640AA04AB0CAE04EA80EEB014407008C404DC0160808740A408B040D802EA011B0482209780E6
 | 
				
			||||||
:40098000A280A302A620AA40B680C820E620EE8052805302551070017E0190029202A110A280A302AF40B510D4E0DC80DE20EE40052008040E020F801F1053805610588014
 | 
					:400980009940B008B140B480C608E809EC040B880F4197899940A220AB05AF04C20F24088004900297409A04A002A120AE40C820E480EE4050015120560470027F018301EC
 | 
				
			||||||
:4009C00063028E208F809A109D20A740B120C001C20DC601D407D602E002E402EA04762084809A209C80AF10B004B301B601DE04E801EA08EE01010109010B010D011101C4
 | 
					:4009C00090029A04A002A120AF40D4E0DC80DE20E620EE40070208080D010E021F10520854085940622095029940A220AF40B101C001C20DC601D407D802EA04800887021E
 | 
				
			||||||
:400A00001B0100FF01AB020211050000BF0000A09F001F000000000000000000100000004000000000000000C0000000FF0000B847004700000100008000000282008200DC
 | 
					:400A00008E019B02A201A408AF10B008B608E208EA01EC02010109010D010F0111011D0100FF01AB02021105BF0000A09F001F0000000000000000001000000040000000B7
 | 
				
			||||||
:400A400000000000000707000700000027001801270018010004000000050000000000000000000000000000000000000000000000000000000000000000000000000000D8
 | 
					:400A400000000000C0000000FF0000B84700470000010000800000008000800000000000000707000700000027001801270018010004000000050000000000000000000052
 | 
				
			||||||
:400A80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000036
 | 
					:400A80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000036
 | 
				
			||||||
:400AC00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000F6
 | 
					:400AC00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000F6
 | 
				
			||||||
:400B000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000B5
 | 
					:400B000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000B5
 | 
				
			||||||
@@ -4615,12 +4615,12 @@
 | 
				
			|||||||
:0200000490105A
 | 
					:0200000490105A
 | 
				
			||||||
:04000000BC90ACAF55
 | 
					:04000000BC90ACAF55
 | 
				
			||||||
:0200000490303A
 | 
					:0200000490303A
 | 
				
			||||||
:02000000FEBF41
 | 
					:0200000021B02D
 | 
				
			||||||
:0200000490402A
 | 
					:0200000490402A
 | 
				
			||||||
:4000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000C0
 | 
					:4000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000C0
 | 
				
			||||||
:400040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080
 | 
					:400040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080
 | 
				
			||||||
:400080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040
 | 
					:400080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040
 | 
				
			||||||
:4000C0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
 | 
					:4000C0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
 | 
				
			||||||
:0200000490501A
 | 
					:0200000490501A
 | 
				
			||||||
:0C00000000012E16106900002E300F28A1
 | 
					:0C00000000012E16106900002E3032198D
 | 
				
			||||||
:00000001FF
 | 
					:00000001FF
 | 
				
			||||||
@@ -816,7 +816,7 @@
 | 
				
			|||||||
    <Group key="v1">
 | 
					    <Group key="v1">
 | 
				
			||||||
      <Data key="cy_boot" value="cy_boot_v6_10" />
 | 
					      <Data key="cy_boot" value="cy_boot_v6_10" />
 | 
				
			||||||
      <Data key="Em_EEPROM_Dynamic" value="Em_EEPROM_Dynamic_v2_20" />
 | 
					      <Data key="Em_EEPROM_Dynamic" value="Em_EEPROM_Dynamic_v2_20" />
 | 
				
			||||||
      <Data key="LIN_Dynamic" value="LIN_Dynamic_v5_0" />
 | 
					      <Data key="LIN_Dynamic" value="LIN_Dynamic_v6_0" />
 | 
				
			||||||
    </Group>
 | 
					    </Group>
 | 
				
			||||||
  </Group>
 | 
					  </Group>
 | 
				
			||||||
  <Data key="DataVersionKey" value="2" />
 | 
					  <Data key="DataVersionKey" value="2" />
 | 
				
			||||||
 
 | 
				
			|||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -23,36 +23,49 @@ module Sampler (
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
reg [5:0] counter;
 | 
					reg [5:0] counter;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
reg index_q;
 | 
					 | 
				
			||||||
reg rdata_q;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
reg index_edge;
 | 
					reg index_edge;
 | 
				
			||||||
reg rdata_edge;
 | 
					reg rdata_edge;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
reg req_toggle;
 | 
					reg req_toggle;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					reg rdata_toggle;
 | 
				
			||||||
 | 
					reg old_rdata_toggle;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					reg index_toggle;
 | 
				
			||||||
 | 
					reg old_index_toggle;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					always @(posedge rdata)
 | 
				
			||||||
 | 
					begin
 | 
				
			||||||
 | 
					    rdata_toggle <= ~rdata_toggle;
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					always @(posedge index)
 | 
				
			||||||
 | 
					begin
 | 
				
			||||||
 | 
					    index_toggle <= ~index_toggle;
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
always @(posedge sampleclock)
 | 
					always @(posedge sampleclock)
 | 
				
			||||||
begin
 | 
					begin
 | 
				
			||||||
    if (reset)
 | 
					    if (reset)
 | 
				
			||||||
    begin
 | 
					    begin
 | 
				
			||||||
 | 
					        old_rdata_toggle <= 0;
 | 
				
			||||||
 | 
					        old_index_toggle <= 0;
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
        index_edge <= 0;
 | 
					        index_edge <= 0;
 | 
				
			||||||
        rdata_edge <= 0;
 | 
					        rdata_edge <= 0;
 | 
				
			||||||
        index_q <= 0;
 | 
					 | 
				
			||||||
        rdata_q <= 0;
 | 
					 | 
				
			||||||
        counter <= 0;
 | 
					        counter <= 0;
 | 
				
			||||||
        req_toggle <= 0;
 | 
					        req_toggle <= 0;
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
    else
 | 
					    else
 | 
				
			||||||
    begin
 | 
					    begin
 | 
				
			||||||
        /* Both index and rdata are active high -- positive-going edges
 | 
					        /* If data_toggle or index_toggle have changed state, this means that they've
 | 
				
			||||||
         * indicate the start of an index pulse and read pulse, respectively.
 | 
					         * gone high since the last sampleclock. */
 | 
				
			||||||
         */
 | 
					 | 
				
			||||||
         
 | 
					         
 | 
				
			||||||
        index_edge <= index && !index_q;
 | 
					        index_edge <= index_toggle != old_index_toggle;
 | 
				
			||||||
        index_q <= index;
 | 
					        old_index_toggle <= index_toggle;
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        rdata_edge <= rdata && !rdata_q;
 | 
					        rdata_edge <= rdata_toggle != old_rdata_toggle;
 | 
				
			||||||
        rdata_q <= rdata;
 | 
					        old_rdata_toggle <= rdata_toggle;
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        if (rdata_edge || index_edge || (counter == 6'h3f)) begin
 | 
					        if (rdata_edge || index_edge || (counter == 6'h3f)) begin
 | 
				
			||||||
            opcode <= { rdata_edge, index_edge, counter };
 | 
					            opcode <= { rdata_edge, index_edge, counter };
 | 
				
			||||||
 
 | 
				
			|||||||
										
											Binary file not shown.
										
									
								
							@@ -147,7 +147,7 @@ static void set_drive_flags(struct set_drive_frame* flags)
 | 
				
			|||||||
    
 | 
					    
 | 
				
			||||||
    current_drive_flags = *flags;
 | 
					    current_drive_flags = *flags;
 | 
				
			||||||
    DRIVESELECT_REG_Write(flags->drive ? 2 : 1); /* select drive 1 or 0 */
 | 
					    DRIVESELECT_REG_Write(flags->drive ? 2 : 1); /* select drive 1 or 0 */
 | 
				
			||||||
    DENSITY_REG_Write(flags->high_density); /* density bit */
 | 
					    DENSITY_REG_Write(!flags->high_density); /* double density bit */
 | 
				
			||||||
    INDEX_REG_Write(flags->index_mode);
 | 
					    INDEX_REG_Write(flags->index_mode);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -221,7 +221,7 @@ static int usb_read(int ep, uint8_t buffer[FRAME_SIZE])
 | 
				
			|||||||
static void cmd_get_version(struct any_frame* f)
 | 
					static void cmd_get_version(struct any_frame* f)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    DECLARE_REPLY_FRAME(struct version_frame, F_FRAME_GET_VERSION_REPLY);
 | 
					    DECLARE_REPLY_FRAME(struct version_frame, F_FRAME_GET_VERSION_REPLY);
 | 
				
			||||||
    r.version = FLUXENGINE_VERSION;
 | 
					    r.version = FLUXENGINE_PROTOCOL_VERSION;
 | 
				
			||||||
    send_reply((struct any_frame*) &r);
 | 
					    send_reply((struct any_frame*) &r);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -905,7 +905,6 @@ int main(void)
 | 
				
			|||||||
    USBFS_Start(0, USBFS_DWR_VDDD_OPERATION);
 | 
					    USBFS_Start(0, USBFS_DWR_VDDD_OPERATION);
 | 
				
			||||||
    USBFS_DisableOutEP(FLUXENGINE_DATA_OUT_EP_NUM);
 | 
					    USBFS_DisableOutEP(FLUXENGINE_DATA_OUT_EP_NUM);
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    detect_drives();
 | 
					 | 
				
			||||||
    CyWdtStart(CYWDT_1024_TICKS, CYWDT_LPMODE_DISABLED);
 | 
					    CyWdtStart(CYWDT_1024_TICKS, CYWDT_LPMODE_DISABLED);
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    for (;;)
 | 
					    for (;;)
 | 
				
			||||||
@@ -926,6 +925,8 @@ int main(void)
 | 
				
			|||||||
                CyWdtClear();
 | 
					                CyWdtClear();
 | 
				
			||||||
            print("USB ready");
 | 
					            print("USB ready");
 | 
				
			||||||
            USBFS_EnableOutEP(FLUXENGINE_CMD_OUT_EP_NUM);
 | 
					            USBFS_EnableOutEP(FLUXENGINE_CMD_OUT_EP_NUM);
 | 
				
			||||||
 | 
					            print("Scanning drives...");
 | 
				
			||||||
 | 
					            detect_drives();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        if (USBFS_GetEPState(FLUXENGINE_CMD_OUT_EP_NUM) == USBFS_OUT_BUFFER_FULL)
 | 
					        if (USBFS_GetEPState(FLUXENGINE_CMD_OUT_EP_NUM) == USBFS_OUT_BUFFER_FULL)
 | 
				
			||||||
@@ -937,3 +938,75 @@ int main(void)
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const uint8_t USBFS_MSOS_CONFIGURATION_DESCR[USBFS_MSOS_CONF_DESCR_LENGTH] = {
 | 
				
			||||||
 | 
					/*  Length of the descriptor 4 bytes       */   0x28u, 0x00u, 0x00u, 0x00u,
 | 
				
			||||||
 | 
					/*  Version of the descriptor 2 bytes      */   0x00u, 0x01u,
 | 
				
			||||||
 | 
					/*  wIndex - Fixed:INDEX_CONFIG_DESCRIPTOR */   0x04u, 0x00u,
 | 
				
			||||||
 | 
					/*  bCount - Count of device functions.    */   0x01u,
 | 
				
			||||||
 | 
					/*  Reserved : 7 bytes                     */   0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
 | 
				
			||||||
 | 
					/*  bFirstInterfaceNumber                  */   0x00u,
 | 
				
			||||||
 | 
					/*  Reserved                               */   0x01u,
 | 
				
			||||||
 | 
					/*  compatibleId - "WINUSB\0\0"            */   'W', 'I', 'N', 'U', 'S', 'B', 0, 0,
 | 
				
			||||||
 | 
					/*  subcompatibleID - "00001\0\0"          */   '0', '0', '0', '0', '1',
 | 
				
			||||||
 | 
					                                                0x00u, 0x00u, 0x00u,
 | 
				
			||||||
 | 
					/*  Reserved : 6 bytes                     */   0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const uint8_t USBFS_MSOS_EXTENDED_PROPERTIES_DESCR[224] = {
 | 
				
			||||||
 | 
					    /* Length; 4 bytes       */   224, 0, 0, 0,
 | 
				
			||||||
 | 
					    /* Version; 2 bytes      */   0x00, 0x01, /* 1.0 */
 | 
				
			||||||
 | 
					    /* wIndex                */   0x05, 0x00,
 | 
				
			||||||
 | 
					    /* Number of sections    */   0x01, 0x00,
 | 
				
			||||||
 | 
					    /* Property section size */   214, 0, 0, 0,
 | 
				
			||||||
 | 
					    /* Property data type    */   0x07, 0x00, 0x00, 0x00, /* 7 = REG_MULTI_SZ Unicode */
 | 
				
			||||||
 | 
					    /* Property name length  */   42, 0,
 | 
				
			||||||
 | 
					    /* Property name         */   'D', 0, 'e', 0, 'v', 0, 'i', 0, 'c', 0, 'e', 0,
 | 
				
			||||||
 | 
					                                  'I', 0, 'n', 0, 't', 0, 'e', 0, 'r', 0, 'f', 0,
 | 
				
			||||||
 | 
					                                  'a', 0, 'c', 0, 'e', 0, 'G', 0, 'U', 0, 'I', 0,
 | 
				
			||||||
 | 
					                                  'D', 0, 's', 0, 0,   0,
 | 
				
			||||||
 | 
					    /* Property data length  */   158, 0, 0, 0,
 | 
				
			||||||
 | 
					    /* GUID #1 data          */   '{', 0, '3', 0, 'd', 0, '2', 0, '7', 0, '5', 0,
 | 
				
			||||||
 | 
					                                  'c', 0, 'f', 0, 'e', 0, '-', 0, '5', 0, '4', 0,
 | 
				
			||||||
 | 
					                                  '3', 0, '5', 0, '-', 0, '4', 0, 'd', 0, 'd', 0,
 | 
				
			||||||
 | 
					                                  '5', 0, '-', 0, 'a', 0, 'c', 0, 'c', 0, 'a', 0,
 | 
				
			||||||
 | 
					                                  '-', 0, '9', 0, 'f', 0, 'b', 0, '9', 0, '9', 0,
 | 
				
			||||||
 | 
					                                  '5', 0, 'e', 0, '2', 0, 'f', 0, '6', 0, '3', 0,
 | 
				
			||||||
 | 
					                                  '8', 0, '}', 0, '\0', 0,
 | 
				
			||||||
 | 
					    /* GUID #2 data          */   '{', 0, '3', 0, 'd', 0, '2', 0, '7', 0, '5', 0,
 | 
				
			||||||
 | 
					                                  'c', 0, 'f', 0, 'e', 0, '-', 0, '5', 0, '4', 0,
 | 
				
			||||||
 | 
					                                  '3', 0, '5', 0, '-', 0, '4', 0, 'd', 0, 'd', 0,
 | 
				
			||||||
 | 
					                                  '5', 0, '-', 0, 'a', 0, 'c', 0, 'c', 0, 'a', 0,
 | 
				
			||||||
 | 
					                                  '-', 0, '9', 0, 'f', 0, 'b', 0, '9', 0, '9', 0,
 | 
				
			||||||
 | 
					                                  '5', 0, 'e', 0, '2', 0, 'f', 0, '6', 0, '3', 0,
 | 
				
			||||||
 | 
					                                  '8', 0, '}', 0, '\0', 0, '\0', 0
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					uint8 USBFS_HandleVendorRqst(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (!(USBFS_bmRequestTypeReg & USBFS_RQST_DIR_D2H))
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    switch (USBFS_bRequestReg)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        case USBFS_GET_EXTENDED_CONFIG_DESCRIPTOR:
 | 
				
			||||||
 | 
					            switch (USBFS_wIndexLoReg)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                case 4:
 | 
				
			||||||
 | 
					                    USBFS_currentTD.pData = (volatile uint8 *) &USBFS_MSOS_CONFIGURATION_DESCR[0u];
 | 
				
			||||||
 | 
					                    USBFS_currentTD.count = USBFS_MSOS_CONFIGURATION_DESCR[0u];
 | 
				
			||||||
 | 
					                    return USBFS_InitControlRead();
 | 
				
			||||||
 | 
					                    
 | 
				
			||||||
 | 
					                case 5:
 | 
				
			||||||
 | 
					                    USBFS_currentTD.pData = (volatile uint8 *) &USBFS_MSOS_EXTENDED_PROPERTIES_DESCR[0u];
 | 
				
			||||||
 | 
					                    USBFS_currentTD.count = USBFS_MSOS_EXTENDED_PROPERTIES_DESCR[0u];
 | 
				
			||||||
 | 
					                    return USBFS_InitControlRead();
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        default:
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,18 +0,0 @@
 | 
				
			|||||||
const READ = 1
 | 
					 | 
				
			||||||
const WRITE = 2
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
filename = "Generated_Source\PSoC5\USBFS_descr.c"
 | 
					 | 
				
			||||||
set fso = CreateObject("Scripting.FileSystemObject")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
set file = fso.OpenTextFile(filename, READ)
 | 
					 | 
				
			||||||
text = file.ReadAll
 | 
					 | 
				
			||||||
file.Close
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
set r = New RegExp
 | 
					 | 
				
			||||||
r.MultiLine = True
 | 
					 | 
				
			||||||
r.Pattern = "/\* +compatibleID.*\n.*"
 | 
					 | 
				
			||||||
text = r.replace(text, "'W', 'I', 'N', 'U', 'S', 'B', 0, 0,")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
set file = fso.CreateTextFile(filename, True)
 | 
					 | 
				
			||||||
file.Write text
 | 
					 | 
				
			||||||
file.Close
 | 
					 | 
				
			||||||
							
								
								
									
										331
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										331
									
								
								Makefile
									
									
									
									
									
								
							@@ -1,66 +1,299 @@
 | 
				
			|||||||
PACKAGES = zlib sqlite3 libusb-1.0 protobuf
 | 
					#Special Windows settings.
 | 
				
			||||||
 | 
					 | 
				
			||||||
export CFLAGS = -x c++ --std=gnu++2a -ffunction-sections -fdata-sections \
 | 
					 | 
				
			||||||
	-Wno-deprecated-enum-enum-conversion \
 | 
					 | 
				
			||||||
	-Wno-deprecated-enum-float-conversion
 | 
					 | 
				
			||||||
export LDFLAGS = -pthread
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export COPTFLAGS = -Os
 | 
					 | 
				
			||||||
export LDOPTFLAGS = -Os
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export CDBGFLAGS = -O0 -g
 | 
					 | 
				
			||||||
export LDDBGFLAGS = -O0 -g
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
ifeq ($(OS), Windows_NT)
 | 
					ifeq ($(OS), Windows_NT)
 | 
				
			||||||
export PROTOC = /mingw32/bin/protoc
 | 
						MINGWBIN = /mingw32/bin
 | 
				
			||||||
export CXX = /mingw32/bin/g++
 | 
						CCPREFIX = $(MINGWBIN)/
 | 
				
			||||||
export AR = /mingw32/bin/ar rc
 | 
						LUA = $(MINGWBIN)/lua
 | 
				
			||||||
export RANLIB = /mingw32/bin/ranlib
 | 
						PKG_CONFIG = $(MINGWBIN)/pkg-config
 | 
				
			||||||
export STRIP = /mingw32/bin/strip
 | 
						WX_CONFIG = /usr/bin/sh $(MINGWBIN)/wx-config --static=yes
 | 
				
			||||||
export CFLAGS += -I/mingw32/include/libusb-1.0 -I/mingw32/include
 | 
						PROTOC = $(MINGWBIN)/protoc
 | 
				
			||||||
export LDFLAGS +=
 | 
						PLATFORM = WINDOWS
 | 
				
			||||||
export LIBS += -L/mingw32/lib -static -lz -lsqlite3 -lusb-1.0 -lprotobuf
 | 
						LDFLAGS += \
 | 
				
			||||||
export EXTENSION = .exe
 | 
							-static
 | 
				
			||||||
else
 | 
						CXXFLAGS += \
 | 
				
			||||||
 | 
							-std=c++17 \
 | 
				
			||||||
 | 
							-fext-numeric-literals \
 | 
				
			||||||
 | 
							-Wno-deprecated-enum-float-conversion \
 | 
				
			||||||
 | 
							-Wno-deprecated-enum-enum-conversion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
packages-exist = $(shell pkg-config --exists $(PACKAGES) && echo yes)
 | 
					#Required to get the gcc run - time libraries on the path.
 | 
				
			||||||
ifneq ($(packages-exist),yes)
 | 
						export PATH := $(PATH):$(MINGWBIN)
 | 
				
			||||||
$(warning These pkg-config packages are installed: $(shell pkg-config --list-all | sort | awk '{print $$1}'))
 | 
						EXT ?= .exe
 | 
				
			||||||
$(error You must have these pkg-config packages installed: $(PACKAGES))
 | 
					 | 
				
			||||||
endif
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export PROTOC = protoc
 | 
					#Special OSX settings.
 | 
				
			||||||
export CXX = g++
 | 
					 | 
				
			||||||
export AR = ar rc
 | 
					 | 
				
			||||||
export RANLIB = ranlib
 | 
					 | 
				
			||||||
export STRIP = strip
 | 
					 | 
				
			||||||
export CFLAGS += $(shell pkg-config --cflags $(PACKAGES))
 | 
					 | 
				
			||||||
export LDFLAGS +=
 | 
					 | 
				
			||||||
export LIBS += $(shell pkg-config --libs $(PACKAGES))
 | 
					 | 
				
			||||||
export EXTENSION =
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
ifeq ($(shell uname),Darwin)
 | 
					ifeq ($(shell uname),Darwin)
 | 
				
			||||||
AR = ar rcS
 | 
						PLATFORM = OSX
 | 
				
			||||||
RANLIB += -c -no_warning_for_no_symbols
 | 
						LDFLAGS += \
 | 
				
			||||||
 | 
							-framework IOKit \
 | 
				
			||||||
 | 
							-framework Foundation
 | 
				
			||||||
endif
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#Check the Make version.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ifeq ($(findstring 4.,$(MAKE_VERSION)),)
 | 
				
			||||||
 | 
					$(error You need GNU Make 4.x for this (if you're on OSX, use gmake).)
 | 
				
			||||||
endif
 | 
					endif
 | 
				
			||||||
export XXD = xxd
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
CFLAGS += -Ilib -Idep/fmt -Iarch
 | 
					#Normal settings.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export OBJDIR = .obj
 | 
					OBJDIR ?= .obj
 | 
				
			||||||
 | 
					CCPREFIX ?=
 | 
				
			||||||
 | 
					LUA ?= lua
 | 
				
			||||||
 | 
					CC ?= $(CCPREFIX)gcc
 | 
				
			||||||
 | 
					CXX ?= $(CCPREFIX)g++
 | 
				
			||||||
 | 
					AR ?= $(CCPREFIX)ar
 | 
				
			||||||
 | 
					PKG_CONFIG ?= pkg-config
 | 
				
			||||||
 | 
					WX_CONFIG ?= wx-config
 | 
				
			||||||
 | 
					PROTOC ?= protoc
 | 
				
			||||||
 | 
					CFLAGS ?= -g -O3
 | 
				
			||||||
 | 
					CXXFLAGS += -std=c++17
 | 
				
			||||||
 | 
					LDFLAGS ?=
 | 
				
			||||||
 | 
					PLATFORM ?= UNIX
 | 
				
			||||||
 | 
					TESTS ?= yes
 | 
				
			||||||
 | 
					EXT ?=
 | 
				
			||||||
 | 
					DESTDIR ?=
 | 
				
			||||||
 | 
					PREFIX ?= /usr/local
 | 
				
			||||||
 | 
					BINDIR ?= $(PREFIX)/bin
 | 
				
			||||||
 | 
					
 | 
				
			||||||
all: .obj/build.ninja
 | 
					CFLAGS += \
 | 
				
			||||||
	@ninja -f .obj/build.ninja -k 0
 | 
						-Iarch \
 | 
				
			||||||
	@if command -v cscope > /dev/null; then cscope -bRq; fi
 | 
						-Ilib \
 | 
				
			||||||
 | 
						-I. \
 | 
				
			||||||
 | 
						-I$(OBJDIR)/arch \
 | 
				
			||||||
 | 
						-I$(OBJDIR)/lib \
 | 
				
			||||||
 | 
						-I$(OBJDIR) \
 | 
				
			||||||
 | 
						-Wno-deprecated-declarations \
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					LDFLAGS += \
 | 
				
			||||||
 | 
						-lz \
 | 
				
			||||||
 | 
						-lfmt
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.SUFFIXES:
 | 
				
			||||||
 | 
					.DELETE_ON_ERROR:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					define nl
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					endef
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					empty :=
 | 
				
			||||||
 | 
					space := $(empty) $(empty)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use-library = $(eval $(use-library-impl))
 | 
				
			||||||
 | 
					define use-library-impl
 | 
				
			||||||
 | 
					$1: $(call $3_LIB)
 | 
				
			||||||
 | 
					$1: private LDFLAGS += $(call $3_LDFLAGS)
 | 
				
			||||||
 | 
					$2: private CFLAGS += $(call $3_CFLAGS)
 | 
				
			||||||
 | 
					endef
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use-pkgconfig = $(eval $(use-pkgconfig-impl))
 | 
				
			||||||
 | 
					define use-pkgconfig-impl
 | 
				
			||||||
 | 
					ifneq ($(strip $(shell $(PKG_CONFIG) $3; echo $$?)),0)
 | 
				
			||||||
 | 
					$$(error Missing required pkg-config dependency: $3)
 | 
				
			||||||
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$(1): private LDFLAGS += $(shell $(PKG_CONFIG) --libs $(3))
 | 
				
			||||||
 | 
					$(2): private CFLAGS += $(shell $(PKG_CONFIG) --cflags $(3))
 | 
				
			||||||
 | 
					endef
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.PHONY: all binaries tests clean install install-bin
 | 
				
			||||||
 | 
					all: binaries tests docs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					PROTOS = \
 | 
				
			||||||
 | 
						arch/aeslanier/aeslanier.proto \
 | 
				
			||||||
 | 
						arch/agat/agat.proto \
 | 
				
			||||||
 | 
						arch/amiga/amiga.proto \
 | 
				
			||||||
 | 
						arch/apple2/apple2.proto \
 | 
				
			||||||
 | 
						arch/brother/brother.proto \
 | 
				
			||||||
 | 
						arch/c64/c64.proto \
 | 
				
			||||||
 | 
						arch/f85/f85.proto \
 | 
				
			||||||
 | 
						arch/fb100/fb100.proto \
 | 
				
			||||||
 | 
						arch/ibm/ibm.proto \
 | 
				
			||||||
 | 
						arch/macintosh/macintosh.proto \
 | 
				
			||||||
 | 
						arch/micropolis/micropolis.proto \
 | 
				
			||||||
 | 
						arch/mx/mx.proto \
 | 
				
			||||||
 | 
						arch/northstar/northstar.proto \
 | 
				
			||||||
 | 
						arch/rolandd20/rolandd20.proto \
 | 
				
			||||||
 | 
						arch/smaky6/smaky6.proto \
 | 
				
			||||||
 | 
						arch/tids990/tids990.proto \
 | 
				
			||||||
 | 
						arch/victor9k/victor9k.proto \
 | 
				
			||||||
 | 
						arch/zilogmcz/zilogmcz.proto \
 | 
				
			||||||
 | 
						lib/common.proto \
 | 
				
			||||||
 | 
						lib/config.proto \
 | 
				
			||||||
 | 
						lib/decoders/decoders.proto \
 | 
				
			||||||
 | 
						lib/drive.proto \
 | 
				
			||||||
 | 
						lib/encoders/encoders.proto \
 | 
				
			||||||
 | 
						lib/fl2.proto \
 | 
				
			||||||
 | 
						lib/fluxsink/fluxsink.proto \
 | 
				
			||||||
 | 
						lib/fluxsource/fluxsource.proto \
 | 
				
			||||||
 | 
						lib/imagereader/imagereader.proto \
 | 
				
			||||||
 | 
						lib/imagewriter/imagewriter.proto \
 | 
				
			||||||
 | 
						lib/layout.proto \
 | 
				
			||||||
 | 
						lib/usb/usb.proto \
 | 
				
			||||||
 | 
						lib/vfs/vfs.proto \
 | 
				
			||||||
 | 
						tests/testproto.proto \
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					PROTO_HDRS = $(patsubst %.proto, $(OBJDIR)/%.pb.h, $(PROTOS))
 | 
				
			||||||
 | 
					PROTO_SRCS = $(patsubst %.proto, $(OBJDIR)/%.pb.cc, $(PROTOS))
 | 
				
			||||||
 | 
					PROTO_OBJS = $(patsubst %.cc, %.o, $(PROTO_SRCS))
 | 
				
			||||||
 | 
					PROTO_CFLAGS = $(shell $(PKG_CONFIG) --cflags protobuf)
 | 
				
			||||||
 | 
					$(PROTO_SRCS): | $(PROTO_HDRS)
 | 
				
			||||||
 | 
					$(PROTO_OBJS): CFLAGS += $(PROTO_CFLAGS)
 | 
				
			||||||
 | 
					PROTO_LIB = $(OBJDIR)/libproto.a
 | 
				
			||||||
 | 
					$(PROTO_LIB): $(PROTO_OBJS)
 | 
				
			||||||
 | 
					PROTO_LDFLAGS = $(shell $(PKG_CONFIG) --libs protobuf) -pthread
 | 
				
			||||||
 | 
					.PRECIOUS: $(PROTO_HDRS) $(PROTO_SRCS)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					include dep/agg/build.mk
 | 
				
			||||||
 | 
					include dep/libusbp/build.mk
 | 
				
			||||||
 | 
					include dep/stb/build.mk
 | 
				
			||||||
 | 
					include dep/emu/build.mk
 | 
				
			||||||
 | 
					include dep/fatfs/build.mk
 | 
				
			||||||
 | 
					include dep/adflib/build.mk
 | 
				
			||||||
 | 
					include dep/hfsutils/build.mk
 | 
				
			||||||
 | 
					include scripts/build.mk
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					include lib/build.mk
 | 
				
			||||||
 | 
					include arch/build.mk
 | 
				
			||||||
 | 
					include src/build.mk
 | 
				
			||||||
 | 
					include src/gui/build.mk
 | 
				
			||||||
 | 
					include tools/build.mk
 | 
				
			||||||
 | 
					include tests/build.mk
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					do-encodedecodetest = $(eval $(do-encodedecodetest-impl))
 | 
				
			||||||
 | 
					define do-encodedecodetest-impl
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					tests: $(OBJDIR)/$1$$(subst $$(space),_,$3).flux.encodedecode
 | 
				
			||||||
 | 
					$(OBJDIR)/$1$$(subst $$(space),_,$3).flux.encodedecode: scripts/encodedecodetest.sh $(FLUXENGINE_BIN) $2
 | 
				
			||||||
 | 
						@mkdir -p $(dir $$@)
 | 
				
			||||||
 | 
						@echo ENCODEDECODETEST $1 flux $(FLUXENGINE_BIN) $2 $3
 | 
				
			||||||
 | 
						@scripts/encodedecodetest.sh $1 flux $(FLUXENGINE_BIN) $2 $3 > $$@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					tests: $(OBJDIR)/$1$$(subst $$(space),_,$3).scp.encodedecode
 | 
				
			||||||
 | 
					$(OBJDIR)/$1$$(subst $$(space),_,$3).scp.encodedecode: scripts/encodedecodetest.sh $(FLUXENGINE_BIN) $2
 | 
				
			||||||
 | 
						@mkdir -p $(dir $$@)
 | 
				
			||||||
 | 
						@echo ENCODEDECODETEST $1 scp $(FLUXENGINE_BIN) $2 $3
 | 
				
			||||||
 | 
						@scripts/encodedecodetest.sh $1 scp $(FLUXENGINE_BIN) $2 $3 > $$@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					endef
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$(call do-encodedecodetest,agat,,--drive.tpi=96)
 | 
				
			||||||
 | 
					$(call do-encodedecodetest,amiga,,--drive.tpi=135)
 | 
				
			||||||
 | 
					$(call do-encodedecodetest,apple2,,--140 --drive.tpi=96)
 | 
				
			||||||
 | 
					$(call do-encodedecodetest,atarist,,--360 --drive.tpi=135)
 | 
				
			||||||
 | 
					$(call do-encodedecodetest,atarist,,--370 --drive.tpi=135)
 | 
				
			||||||
 | 
					$(call do-encodedecodetest,atarist,,--400 --drive.tpi=135)
 | 
				
			||||||
 | 
					$(call do-encodedecodetest,atarist,,--410 --drive.tpi=135)
 | 
				
			||||||
 | 
					$(call do-encodedecodetest,atarist,,--720 --drive.tpi=135)
 | 
				
			||||||
 | 
					$(call do-encodedecodetest,atarist,,--740 --drive.tpi=135)
 | 
				
			||||||
 | 
					$(call do-encodedecodetest,atarist,,--800 --drive.tpi=135)
 | 
				
			||||||
 | 
					$(call do-encodedecodetest,atarist,,--820 --drive.tpi=135)
 | 
				
			||||||
 | 
					$(call do-encodedecodetest,bk)
 | 
				
			||||||
 | 
					$(call do-encodedecodetest,brother,,--120 --drive.tpi=135)
 | 
				
			||||||
 | 
					$(call do-encodedecodetest,brother,,--240 --drive.tpi=135)
 | 
				
			||||||
 | 
					$(call do-encodedecodetest,commodore,scripts/commodore1541_test.textpb,--171 --drive.tpi=96)
 | 
				
			||||||
 | 
					$(call do-encodedecodetest,commodore,scripts/commodore1541_test.textpb,--192 --drive.tpi=96)
 | 
				
			||||||
 | 
					$(call do-encodedecodetest,commodore,,--800 --drive.tpi=135)
 | 
				
			||||||
 | 
					$(call do-encodedecodetest,commodore,,--1620 --drive.tpi=135)
 | 
				
			||||||
 | 
					$(call do-encodedecodetest,hplif,,--264 --drive.tpi=135)
 | 
				
			||||||
 | 
					$(call do-encodedecodetest,hplif,,--616 --drive.tpi=135)
 | 
				
			||||||
 | 
					$(call do-encodedecodetest,hplif,,--770 --drive.tpi=135)
 | 
				
			||||||
 | 
					$(call do-encodedecodetest,ibm,,--1200 --drive.tpi=96)
 | 
				
			||||||
 | 
					$(call do-encodedecodetest,ibm,,--1232 --drive.tpi=96)
 | 
				
			||||||
 | 
					$(call do-encodedecodetest,ibm,,--1440 --drive.tpi=135)
 | 
				
			||||||
 | 
					$(call do-encodedecodetest,ibm,,--1680 --drive.tpi=135)
 | 
				
			||||||
 | 
					$(call do-encodedecodetest,ibm,,--180 --drive.tpi=96)
 | 
				
			||||||
 | 
					$(call do-encodedecodetest,ibm,,--160 --drive.tpi=96)
 | 
				
			||||||
 | 
					$(call do-encodedecodetest,ibm,,--320 --drive.tpi=96)
 | 
				
			||||||
 | 
					$(call do-encodedecodetest,ibm,,--360 --drive.tpi=96)
 | 
				
			||||||
 | 
					$(call do-encodedecodetest,ibm,,--720_96 --drive.tpi=96)
 | 
				
			||||||
 | 
					$(call do-encodedecodetest,ibm,,--720_135 --drive.tpi=135)
 | 
				
			||||||
 | 
					$(call do-encodedecodetest,mac,scripts/mac400_test.textpb,--400 --drive.tpi=135)
 | 
				
			||||||
 | 
					$(call do-encodedecodetest,mac,scripts/mac800_test.textpb,--800 --drive.tpi=135)
 | 
				
			||||||
 | 
					$(call do-encodedecodetest,n88basic,,--drive.tpi=96)
 | 
				
			||||||
 | 
					$(call do-encodedecodetest,rx50,,--drive.tpi=96)
 | 
				
			||||||
 | 
					$(call do-encodedecodetest,tids990,,--drive.tpi=48)
 | 
				
			||||||
 | 
					$(call do-encodedecodetest,victor9k,,--612 --drive.tpi=96)
 | 
				
			||||||
 | 
					$(call do-encodedecodetest,victor9k,,--1224 --drive.tpi=96)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					do-corpustest = $(eval $(do-corpustest-impl))
 | 
				
			||||||
 | 
					define do-corpustest-impl
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					tests: $(OBJDIR)/corpustest/$2
 | 
				
			||||||
 | 
					$(OBJDIR)/corpustest/$2: $(FLUXENGINE_BIN) \
 | 
				
			||||||
 | 
							../fluxengine-testdata/data/$1 ../fluxengine-testdata/data/$2
 | 
				
			||||||
 | 
						@mkdir -p $(OBJDIR)/corpustest
 | 
				
			||||||
 | 
						@echo CORPUSTEST $1 $2 $3
 | 
				
			||||||
 | 
						@$(FLUXENGINE_BIN) read $3 -s ../fluxengine-testdata/data/$1 -o $$@ > $$@.log
 | 
				
			||||||
 | 
						@cmp $$@ ../fluxengine-testdata/data/$2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					endef
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ifneq ($(wildcard ../fluxengine-testdata/data),)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$(call do-corpustest,amiga.flux,amiga.adf,amiga --drive.tpi=135)
 | 
				
			||||||
 | 
					$(call do-corpustest,atarist360.flux,atarist360.st,atarist --360 --drive.tpi=135)
 | 
				
			||||||
 | 
					$(call do-corpustest,atarist720.flux,atarist720.st,atarist --720 --drive.tpi=135)
 | 
				
			||||||
 | 
					$(call do-corpustest,brother120.flux,brother120.img,brother --120 --drive.tpi=135)
 | 
				
			||||||
 | 
					$(call do-corpustest,cmd-fd2000.flux,cmd-fd2000.img,commodore --1620 --drive.tpi=135)
 | 
				
			||||||
 | 
					$(call do-corpustest,ibm1232.flux,ibm1232.img,ibm --1232 --drive.tpi=96)
 | 
				
			||||||
 | 
					$(call do-corpustest,ibm1440.flux,ibm1440.img,ibm --1440 --drive.tpi=135)
 | 
				
			||||||
 | 
					$(call do-corpustest,mac800.flux,mac800.dsk,mac --800 --drive.tpi=135)
 | 
				
			||||||
 | 
					$(call do-corpustest,micropolis315.flux,micropolis315.img,micropolis --315 --drive.tpi=100)
 | 
				
			||||||
 | 
					$(call do-corpustest,northstar87-synthetic.flux,northstar87-synthetic.nsi,northstar --87 --drive.tpi=48)
 | 
				
			||||||
 | 
					$(call do-corpustest,northstar175-synthetic.flux,northstar175-synthetic.nsi,northstar --175 --drive.tpi=48)
 | 
				
			||||||
 | 
					$(call do-corpustest,northstar350-synthetic.flux,northstar350-synthetic.nsi,northstar --350 --drive.tpi=48)
 | 
				
			||||||
 | 
					$(call do-corpustest,victor9k_ss.flux,victor9k_ss.img,victor9k --612 --drive.tpi=96)
 | 
				
			||||||
 | 
					$(call do-corpustest,victor9k_ds.flux,victor9k_ds.img,victor9k --1224 --drive.tpi=96)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$(OBJDIR)/%.a:
 | 
				
			||||||
 | 
						@mkdir -p $(dir $@)
 | 
				
			||||||
 | 
						@echo AR $@
 | 
				
			||||||
 | 
						@$(AR) rc $@ $^
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					%.exe:
 | 
				
			||||||
 | 
						@mkdir -p $(dir $@)
 | 
				
			||||||
 | 
						@echo LINK $@
 | 
				
			||||||
 | 
						@$(CXX) -o $@ $(filter %.o,$^) $(filter %.a,$^) $(LDFLAGS) $(filter %.a,$^) $(LDFLAGS)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$(OBJDIR)/%.o: %.cpp
 | 
				
			||||||
 | 
						@mkdir -p $(dir $@)
 | 
				
			||||||
 | 
						@echo CXX $<
 | 
				
			||||||
 | 
						@$(CXX) $(CFLAGS) $(CXXFLAGS) -MMD -MP -MF $(@:.o=.d) -c -o $@ $<
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$(OBJDIR)/%.o: %.cc
 | 
				
			||||||
 | 
						@mkdir -p $(dir $@)
 | 
				
			||||||
 | 
						@echo CXX $<
 | 
				
			||||||
 | 
						@$(CXX) $(CFLAGS) $(CXXFLAGS) -MMD -MP -MF $(@:.o=.d) -c -o $@ $<
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$(OBJDIR)/%.o: $(OBJDIR)/%.cc
 | 
				
			||||||
 | 
						@mkdir -p $(dir $@)
 | 
				
			||||||
 | 
						@echo CXX $<
 | 
				
			||||||
 | 
						@$(CXX) $(CFLAGS) $(CXXFLAGS) -MMD -MP -MF $(@:.o=.d) -c -o $@ $<
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$(OBJDIR)/%.o: %.c
 | 
				
			||||||
 | 
						@mkdir -p $(dir $@)
 | 
				
			||||||
 | 
						@echo CC $<
 | 
				
			||||||
 | 
						@$(CC) $(CFLAGS) $(CFLAGS) -MMD -MP -MF $(@:.o=.d) -c -o $@ $<
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$(OBJDIR)/%.pb.h: %.proto
 | 
				
			||||||
 | 
						@mkdir -p $(dir $@)
 | 
				
			||||||
 | 
						@echo PROTOC $@
 | 
				
			||||||
 | 
						@$(PROTOC) -I. --cpp_out=$(OBJDIR) $<
 | 
				
			||||||
 | 
					
 | 
				
			||||||
clean:
 | 
					clean:
 | 
				
			||||||
	@echo CLEAN
 | 
						rm -rf $(OBJDIR)
 | 
				
			||||||
	@rm -rf $(OBJDIR)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
.obj/build.ninja: mkninja.sh Makefile
 | 
					install: install-bin # install-man install-docs ...
 | 
				
			||||||
	@echo MKNINJA $@
 | 
					 | 
				
			||||||
	@mkdir -p $(OBJDIR)
 | 
					 | 
				
			||||||
	@sh $< > $@
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					install-bin: fluxengine$(EXT) fluxengine-gui$(EXT) brother120tool$(EXT) brother240tool$(EXT) upgrade-flux-file$(EXT)
 | 
				
			||||||
 | 
						install -d "$(DESTDIR)$(BINDIR)"
 | 
				
			||||||
 | 
						for target in $^; do \
 | 
				
			||||||
 | 
							install $$target "$(DESTDIR)$(BINDIR)/$$target"; \
 | 
				
			||||||
 | 
						done
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-include $(OBJS:%.o=%.d)
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										178
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										178
									
								
								README.md
									
									
									
									
									
								
							@@ -2,12 +2,17 @@ FluxEngine
 | 
				
			|||||||
==========
 | 
					==========
 | 
				
			||||||
 | 
					
 | 
				
			||||||
(If you're reading this on GitHub, the formatting's a bit messed up. [Try the
 | 
					(If you're reading this on GitHub, the formatting's a bit messed up. [Try the
 | 
				
			||||||
version on cowlark.com instead.](http://cowlark.com/fluxengine/)
 | 
					version on cowlark.com instead.](http://cowlark.com/fluxengine/))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
**Breaking news!** As of 2021-05-21, the command line environment has changed
 | 
					**Breaking news!** As of 2022-09-09, there's new [filesystem
 | 
				
			||||||
_substantially_ (to make it more consistent and flexible, and allow some new
 | 
					support](doc/filesystem.md). Read (and sometimes write) files directly from
 | 
				
			||||||
backend features like multi-format IBM scheme disks, which are popular with
 | 
					(and to) your disks, with eight different file systems! It works in the GUI,
 | 
				
			||||||
CP/M). If things don't work the way you expect, please check the documentation.
 | 
					too, which is available for Linux (and other Unix clones), Windows and OSX. See
 | 
				
			||||||
 | 
					the details below.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<div style="text-align: center">
 | 
				
			||||||
 | 
					<a href="doc/screenshot.jpg"><img src="doc/screenshot.jpg" style="width:60%" alt="screenshot of the GUI in action"></a>
 | 
				
			||||||
 | 
					</div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
What?
 | 
					What?
 | 
				
			||||||
-----
 | 
					-----
 | 
				
			||||||
@@ -30,18 +35,13 @@ Don't believe me? Watch the demo reel!
 | 
				
			|||||||
</div>
 | 
					</div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
**New!** The FluxEngine client software now works with
 | 
					**New!** The FluxEngine client software now works with
 | 
				
			||||||
[GreaseWeazle](https://github.com/keirf/Greaseweazle/wiki) hardware. So, if you
 | 
					[Greaseweazle](https://github.com/keirf/Greaseweazle/wiki) hardware. So, if you
 | 
				
			||||||
can't find a PSoC5 development kit, or don't want to use the Cypress Windows
 | 
					can't find a PSoC5 development kit, or don't want to use the Cypress Windows
 | 
				
			||||||
tools for programming it, you can use one of these instead. Very nearly all
 | 
					tools for programming it, you can use one of these instead. Very nearly all
 | 
				
			||||||
FluxEngine features are available with the GreaseWeazle and it works out-of-the
 | 
					FluxEngine features are available with the Greaseweazle and it works out-of-the
 | 
				
			||||||
box. See the [dedicated GreaseWeazle documentation page](doc/greaseweazle.md)
 | 
					box. See the [dedicated Greaseweazle documentation page](doc/greaseweazle.md)
 | 
				
			||||||
for more information.
 | 
					for more information.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
**Important note.** On 2020-04-02 I changed the bytecode format (and firmware).
 | 
					 | 
				
			||||||
Flux files will need to be upgraded with `fluxengine upgradefluxfile`. The new
 | 
					 | 
				
			||||||
format should be more reliable and use way, way less bandwidth. Sorry for the
 | 
					 | 
				
			||||||
inconvenience.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Where?
 | 
					Where?
 | 
				
			||||||
------
 | 
					------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -65,71 +65,83 @@ following friendly articles:
 | 
				
			|||||||
  - [Using a FluxEngine](doc/using.md) ∾ what to do with your new hardware ∾
 | 
					  - [Using a FluxEngine](doc/using.md) ∾ what to do with your new hardware ∾
 | 
				
			||||||
    flux files and image files ∾ knowing what you're doing
 | 
					    flux files and image files ∾ knowing what you're doing
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  - [Using GreaseWeazle hardware with the FluxEngine client
 | 
					  - [Using Greaseweazle hardware with the FluxEngine client
 | 
				
			||||||
	software](doc/greaseweazle.md) ∾ what works ∾ what doesn't work ∾ where to
 | 
					    software](doc/greaseweazle.md) ∾ what works ∾ what doesn't work ∾ where to
 | 
				
			||||||
	go for help
 | 
					    go for help
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  - [Configuring for your drive](doc/drives.md) ∾ but I don't have a 80 track
 | 
				
			||||||
 | 
					    drive! ∾ reading and writing 40 track disks ∾ Shugart and Apple II
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  - [Direct filesystem access](doc/filesystem.md) ∾ imaging files is a pain
 | 
				
			||||||
 | 
					    ∾ accessing files directly ∾ features and limitation ∾ it works on disk
 | 
				
			||||||
 | 
					    images too, you say?
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
  - [Troubleshooting dubious disks](doc/problems.md) ∾ it's not an exact
 | 
					  - [Troubleshooting dubious disks](doc/problems.md) ∾ it's not an exact
 | 
				
			||||||
	science ∾ the sector map ∾ clock detection and the histogram
 | 
					    science ∾ the sector map ∾ clock detection and the histogram
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  - [Checking your drive](doc/driveresponse.md) ∾ you can't do that with that ∾
 | 
					  - [Disk densities](doc/driveresponse.md) ∾ what's the difference between an HD
 | 
				
			||||||
	measuring your drive's ability to work with exotic formats
 | 
					    and DD disk? ∾ you can't do that with that ∾ measuring your drive's ability to
 | 
				
			||||||
 | 
					    work with exotic formats ∾ I think my drive is broken
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Which?
 | 
					Which?
 | 
				
			||||||
------
 | 
					------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
The current support state is as follows.
 | 
					The current support state is as follows.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Dinosaurs (🦖) have yet to be observed in real life --- I've written the
 | 
					Dinosaurs (🦖) have yet to be observed in real life --- I've written the encoder
 | 
				
			||||||
decoder based on Kryoflux (or other) dumps I've found. I don't (yet) have
 | 
					and/or decoder based on Kryoflux (or other) dumps I've found. I don't (yet) have
 | 
				
			||||||
real, physical disks in my hand to test the capture process.
 | 
					real, physical disks in my hand to test the capture process, or hardware to
 | 
				
			||||||
 | 
					verify that written disks work.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Unicorns (🦄) are completely real --- this means that I've read actual,
 | 
					Unicorns (🦄) are completely real --- this means that I've read actual, physical
 | 
				
			||||||
physical disks with these formats and so know they work (or had reports from
 | 
					disks with these formats and/or written real, physical disks and then used them
 | 
				
			||||||
people who've had it work).
 | 
					on real hardware, and so know they work (or had reports from people who've had
 | 
				
			||||||
 | 
					it work).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### Old disk formats
 | 
					If a filesystem is listed, this means that FluxEngine natively supports that
 | 
				
			||||||
 | 
					particular filesystem and can read (and sometimes write, support varies) files
 | 
				
			||||||
 | 
					directly from disks, flux files or disk images. Some formats have multiple
 | 
				
			||||||
 | 
					choices because they can store multiple types of file system.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| Format                                    | Read? | Write? | Notes |
 | 
					<!-- FORMATSSTART -->
 | 
				
			||||||
|:------------------------------------------|:-----:|:------:|-------|
 | 
					<!-- This section is automatically generated. Do not edit. -->
 | 
				
			||||||
| [IBM PC compatible](doc/disk-ibm.md)      |  🦄   |   🦄   | and compatibles (like the Atari ST) |
 | 
					
 | 
				
			||||||
| [Acorn ADFS](doc/disk-acornadfs.md)       |  🦄   |   🦖*  | single- and double- sided           |
 | 
					| Profile | Format | Read? | Write? | Filesystem? |
 | 
				
			||||||
| [Acorn DFS](doc/disk-acorndfs.md)         |  🦄   |   🦖*  |                                     |
 | 
					|:--------|:-------|:-----:|:------:|:------------|
 | 
				
			||||||
| [Ampro Little Board](doc/disk-ampro.md)   |  🦖   |   🦖*  |                                     |
 | 
					| [`acornadfs`](doc/disk-acornadfs.md) | Acorn ADFS: BBC Micro, Archimedes | 🦖 |  |  |
 | 
				
			||||||
| [Apple II DOS 3.3](doc/disk-apple2.md)    |  🦄   |        | doesn't do logical sector remapping |
 | 
					| [`acorndfs`](doc/disk-acorndfs.md) | Acorn DFS: Acorn Atom, BBC Micro series | 🦄 |  | ACORNDFS  |
 | 
				
			||||||
| [Amiga](doc/disk-amiga.md)                |  🦄   |   🦄   |                                     |
 | 
					| [`aeslanier`](doc/disk-aeslanier.md) | AES Lanier "No Problem": 616kB 5.25" 77-track SSDD hard sectored | 🦖 |  |  |
 | 
				
			||||||
| [Commodore 64 1541/1581](doc/disk-c64.md) |  🦄   |   🦄   | and probably the other formats      |
 | 
					| [`agat`](doc/disk-agat.md) | Agat: 840kB 5.25" 80-track DS | 🦖 | 🦖 |  |
 | 
				
			||||||
| [Brother 120kB](doc/disk-brother.md)      |  🦄   |   🦖   |                                     |
 | 
					| [`amiga`](doc/disk-amiga.md) | Amiga: 880kB 3.5" DSDD | 🦄 | 🦄 | AMIGAFFS  |
 | 
				
			||||||
| [Brother 240kB](doc/disk-brother.md)      |  🦄   |   🦄   |                                     |
 | 
					| [`ampro`](doc/disk-ampro.md) | Ampro Little Board: CP/M | 🦖 |  | CPMFS  |
 | 
				
			||||||
| [Brother FB-100](doc/disk-fb100.md)       |  🦖   |        | Tandy Model 100, Husky Hunter, knitting machines |
 | 
					| [`apple2`](doc/disk-apple2.md) | Apple II: Prodos, Appledos, and CP/M | 🦄 | 🦄 | APPLEDOS CPMFS PRODOS  |
 | 
				
			||||||
| [Macintosh 800kB](doc/disk-macintosh.md)  |  🦄   |   🦄   | and probably the 400kB too          |
 | 
					| [`atarist`](doc/disk-atarist.md) | Atari ST: Almost PC compatible | 🦄 | 🦄 |  |
 | 
				
			||||||
| [TRS-80](doc/disk-trs80.md)               |  🦖   |   🦖*  | a minor variation of the IBM scheme |
 | 
					| [`bk`](doc/disk-bk.md) | BK: 800kB 5.25"/3.5" 80-track 10-sector DSDD | 🦖 | 🦖 |  |
 | 
				
			||||||
 | 
					| [`brother`](doc/disk-brother.md) | Brother word processors: GCR family | 🦄 | 🦄 | BROTHER120 FATFS  |
 | 
				
			||||||
 | 
					| [`commodore`](doc/disk-commodore.md) | Commodore: 1541, 1581, 8050 and variations | 🦄 | 🦄 | CBMFS  |
 | 
				
			||||||
 | 
					| [`eco1`](doc/disk-eco1.md) | VDS Eco1: CP/M; 1210kB 77-track mixed format DSHD | 🦖 |  | CPMFS  |
 | 
				
			||||||
 | 
					| [`epsonpf10`](doc/disk-epsonpf10.md) | Epson PF-10: CP/M; 3.5" 40-track DSDD | 🦖 |  | CPMFS  |
 | 
				
			||||||
 | 
					| [`f85`](doc/disk-f85.md) | Durango F85: 461kB 5.25" 77-track SS | 🦖 |  |  |
 | 
				
			||||||
 | 
					| [`fb100`](doc/disk-fb100.md) | Brother FB-100: 100kB 3.5" 40-track SSSD | 🦖 |  |  |
 | 
				
			||||||
 | 
					| [`hplif`](doc/disk-hplif.md) | Hewlett-Packard LIF: a variety of disk formats used by HP | 🦄 | 🦄 | LIF  |
 | 
				
			||||||
 | 
					| [`ibm`](doc/disk-ibm.md) | IBM PC: Generic PC 3.5"/5.25" disks | 🦄 | 🦄 | FATFS  |
 | 
				
			||||||
 | 
					| [`icl30`](doc/disk-icl30.md) | ICL Model 30: CP/M; 263kB 35-track DSSD | 🦖 |  | CPMFS  |
 | 
				
			||||||
 | 
					| [`mac`](doc/disk-mac.md) | Macintosh: 400kB/800kB 3.5" GCR | 🦄 | 🦄 | MACHFS  |
 | 
				
			||||||
 | 
					| [`micropolis`](doc/disk-micropolis.md) | Micropolis: 100tpi MetaFloppy disks | 🦄 | 🦄 |  |
 | 
				
			||||||
 | 
					| [`mx`](doc/disk-mx.md) | DVK MX: Soviet-era PDP-11 clone | 🦖 |  |  |
 | 
				
			||||||
 | 
					| [`n88basic`](doc/disk-n88basic.md) | N88-BASIC: PC8800/PC98 5.25" 77-track 26-sector DSHD | 🦄 | 🦄 |  |
 | 
				
			||||||
 | 
					| [`northstar`](doc/disk-northstar.md) | Northstar: 5.25" hard sectored | 🦄 | 🦄 |  |
 | 
				
			||||||
 | 
					| [`psos`](doc/disk-psos.md) | pSOS: 800kB DSDD with PHILE | 🦄 | 🦄 | PHILE  |
 | 
				
			||||||
 | 
					| [`rolandd20`](doc/disk-rolandd20.md) | Roland D20: 3.5" electronic synthesiser disks | 🦖 |  |  |
 | 
				
			||||||
 | 
					| [`rx50`](doc/disk-rx50.md) | Digital RX50: 400kB 5.25" 80-track 10-sector SSDD | 🦖 | 🦖 |  |
 | 
				
			||||||
 | 
					| [`smaky6`](doc/disk-smaky6.md) | Smaky 6: 308kB 5.25" 77-track 16-sector SSDD, hard sectored | 🦖 |  | SMAKY6  |
 | 
				
			||||||
 | 
					| [`tids990`](doc/disk-tids990.md) | Texas Instruments DS990: 1126kB 8" DSSD | 🦖 | 🦖 |  |
 | 
				
			||||||
 | 
					| [`tiki`](doc/disk-tiki.md) | Tiki 100: CP/M |  |  | CPMFS  |
 | 
				
			||||||
 | 
					| [`victor9k`](doc/disk-victor9k.md) | Victor 9000 / Sirius One: 1224kB 5.25" DSDD GCR | 🦖 | 🦖 |  |
 | 
				
			||||||
 | 
					| [`zilogmcz`](doc/disk-zilogmcz.md) | Zilog MCZ: 320kB 8" 77-track SSSD hard-sectored | 🦖 |  | ZDOS  |
 | 
				
			||||||
{: .datatable }
 | 
					{: .datatable }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
`*`: these formats are variations of the generic IBM format, and since the
 | 
					<!-- FORMATSEND -->
 | 
				
			||||||
IBM writer is completely generic, it should be configurable for these
 | 
					 | 
				
			||||||
formats... theoretically. I don't have the hardware to try it.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
### Even older disk formats
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
These formats are for particularly old, weird architectures, even by the
 | 
					 | 
				
			||||||
standards of floppy disks. They've largely been implemented from single flux
 | 
					 | 
				
			||||||
files with no access to physical hardware. Typically the reads were pretty
 | 
					 | 
				
			||||||
bad and I've had to make a number of guesses as to how things work. They do,
 | 
					 | 
				
			||||||
at least, check the CRC so what data's there is probably good.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
| Format                                   | Read? | Write? | Notes |
 | 
					 | 
				
			||||||
|:-----------------------------------------|:-----:|:------:|-------|
 | 
					 | 
				
			||||||
| [AES Superplus / No Problem](doc/disk-aeslanier.md) |  🦖   | | hard sectors! |
 | 
					 | 
				
			||||||
| [Durango F85](doc/disk-durangof85.md)    |  🦖   |        | 5.25" |
 | 
					 | 
				
			||||||
| [DVK MX](doc/disk-mx.md)                 |  🦖   |        | Soviet PDP-11 clone |
 | 
					 | 
				
			||||||
| [VDS Eco1](doc/disk-eco1.md)             |  🦖   |        | 8" mixed format |
 | 
					 | 
				
			||||||
| [Micropolis](doc/disk-micropolis.md)     |  🦄   |        | Micropolis 100tpi drives |
 | 
					 | 
				
			||||||
| [Northstar(doc/disk-northstar.md)        |  🦖   |   🦖   | 5.25" hard sectors |
 | 
					 | 
				
			||||||
| [TI DS990 FD1000](doc/disk-tids990.md)   |  🦄   |  🦄    | 8" |
 | 
					 | 
				
			||||||
| [Victor 9000](doc/disk-victor9k.md)      |  🦖   |        | 8" |
 | 
					 | 
				
			||||||
| [Zilog MCZ](doc/disk-zilogmcz.md)        |  🦖   |        | 8" _and_ hard sectors |
 | 
					 | 
				
			||||||
{: .datatable }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
### Notes
 | 
					### Notes
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -146,7 +158,7 @@ at least, check the CRC so what data's there is probably good.
 | 
				
			|||||||
    There hasn't been a lot of demand for this yet; if you have a pressing
 | 
					    There hasn't been a lot of demand for this yet; if you have a pressing
 | 
				
			||||||
    need to write weird disks, [please
 | 
					    need to write weird disks, [please
 | 
				
			||||||
    ask](https://github.com/davidgiven/fluxengine/issues/new). I haven't
 | 
					    ask](https://github.com/davidgiven/fluxengine/issues/new). I haven't
 | 
				
			||||||
    implement write support for PC disks because they're boring and I'm lazy,
 | 
					    implemented write support for PC disks because they're boring and I'm lazy,
 | 
				
			||||||
    and also because they vary so much that figuring out how to specify them
 | 
					    and also because they vary so much that figuring out how to specify them
 | 
				
			||||||
    is hard.
 | 
					    is hard.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -200,17 +212,12 @@ There may or may not be anything interesting there.
 | 
				
			|||||||
License
 | 
					License
 | 
				
			||||||
-------
 | 
					-------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Everything here _except the contents of the `dep` directory_ is © 2019 David
 | 
					Everything here _except the contents of the `dep` directory_ is © 2022 The
 | 
				
			||||||
Given and is licensed under the MIT open source license. Please see
 | 
					FluxEngine Authors (mostly me, David Given; see the VCS history for the other
 | 
				
			||||||
 | 
					people) and is licensed under the MIT open source license. Please see
 | 
				
			||||||
[COPYING](COPYING) for the full text. The tl;dr is: you can do what you like
 | 
					[COPYING](COPYING) for the full text. The tl;dr is: you can do what you like
 | 
				
			||||||
with it provided you don't claim you wrote it.
 | 
					with it provided you don't claim you wrote it.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
As an exception, `dep/fmt` contains a copy of [fmt](http://fmtlib.net),
 | 
					 | 
				
			||||||
maintained by Victor Zverovich (`vitaut <https://github.com/vitaut>`) and
 | 
					 | 
				
			||||||
Jonathan Müller (`foonathan <https://github.com/foonathan>`) with
 | 
					 | 
				
			||||||
contributions from many other people. It is licensed under the terms of the
 | 
					 | 
				
			||||||
BSD license. Please see the contents of the directory for the full text.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
As an exception, `dep/emu` contains parts of the OpenBSD C library
 | 
					As an exception, `dep/emu` contains parts of the OpenBSD C library
 | 
				
			||||||
code, maintained by Todd Miller and William A. Rowe (and probably others). It is licensed
 | 
					code, maintained by Todd Miller and William A. Rowe (and probably others). It is licensed
 | 
				
			||||||
under the terms of the 3-clause BSD license. Please see the contents of the
 | 
					under the terms of the 3-clause BSD license. Please see the contents of the
 | 
				
			||||||
@@ -228,5 +235,28 @@ text.
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
As an exception, `dep/snowhouse` contains the snowhouse assertion library,
 | 
					As an exception, `dep/snowhouse` contains the snowhouse assertion library,
 | 
				
			||||||
taken from https://github.com/banditcpp/snowhouse. It is Boost Standard License
 | 
					taken from https://github.com/banditcpp/snowhouse. It is Boost Standard License
 | 
				
			||||||
1.0 licensed. Please see the contents of the directory for the full text.
 | 
					1.0 licensed. Please see the contents of the directory for the full text. Note
 | 
				
			||||||
 | 
					that this is only used during the build and no code ends up in the output
 | 
				
			||||||
 | 
					binaries.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					As an exception, `dep/libusbp` contains the libusbp library, taken from
 | 
				
			||||||
 | 
					https://github.com/pololu/libusbp. It is MIT licensed. Please see the contents
 | 
				
			||||||
 | 
					of the directory for the full text.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					As an exception, `dep/fatfs` contains the fatfs library, taken from
 | 
				
			||||||
 | 
					http://elm-chan.org/fsw/ff/00index_e.html. It is single-clause BSD licensed.
 | 
				
			||||||
 | 
					Please see the contents of the directory for the full text.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					As an exception, `dep/adflib` contains the adflib library, written by Laurent
 | 
				
			||||||
 | 
					Clevy et al, taken from https://github.com/lclevy/ADFlib. It is GPL 2.0
 | 
				
			||||||
 | 
					licensed. Please see the contents of the directory for the full text.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					As an exception, `dep/hfsutils` contains a partial copy of the hfsutils
 | 
				
			||||||
 | 
					package, written by Robert Leslie et al, taken from
 | 
				
			||||||
 | 
					https://www.mars.org/home/rob/proj/hfs. It is GPL 2.0 licensed. Please see the
 | 
				
			||||||
 | 
					contents of the directory for the full text.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					__Important:__ Because of all these exceptions, if you distribute the
 | 
				
			||||||
 | 
					FluxEngine package as a whole, you must comply with the terms of _all_ of the
 | 
				
			||||||
 | 
					licensing terms. This means that __effectively the FluxEngine package is
 | 
				
			||||||
 | 
					distributable under the terms of the GPL 2.0__.
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,9 +2,10 @@
 | 
				
			|||||||
#define AESLANIER_H
 | 
					#define AESLANIER_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define AESLANIER_RECORD_SEPARATOR 0x55555122
 | 
					#define AESLANIER_RECORD_SEPARATOR 0x55555122
 | 
				
			||||||
#define AESLANIER_SECTOR_LENGTH    256
 | 
					#define AESLANIER_SECTOR_LENGTH 256
 | 
				
			||||||
#define AESLANIER_RECORD_SIZE      (AESLANIER_SECTOR_LENGTH + 5)
 | 
					#define AESLANIER_RECORD_SIZE (AESLANIER_SECTOR_LENGTH + 5)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern std::unique_ptr<AbstractDecoder> createAesLanierDecoder(const DecoderProto& config);
 | 
					extern std::unique_ptr<Decoder> createAesLanierDecoder(
 | 
				
			||||||
 | 
					    const DecoderProto& config);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -11,69 +11,54 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
static const FluxPattern SECTOR_PATTERN(32, AESLANIER_RECORD_SEPARATOR);
 | 
					static const FluxPattern SECTOR_PATTERN(32, AESLANIER_RECORD_SEPARATOR);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* This is actually M2FM, rather than MFM, but it our MFM/FM decoder copes fine with it. */
 | 
					/* This is actually M2FM, rather than MFM, but it our MFM/FM decoder copes fine
 | 
				
			||||||
 | 
					 * with it. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static Bytes reverse_bits(const Bytes& input)
 | 
					class AesLanierDecoder : public Decoder
 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    Bytes output;
 | 
					 | 
				
			||||||
    ByteWriter bw(output);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    for (uint8_t b : input)
 | 
					 | 
				
			||||||
        bw.write_8(reverse_bits(b));
 | 
					 | 
				
			||||||
    return output;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class AesLanierDecoder : public AbstractDecoder
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
	AesLanierDecoder(const DecoderProto& config):
 | 
					    AesLanierDecoder(const DecoderProto& config): Decoder(config) {}
 | 
				
			||||||
		AbstractDecoder(config)
 | 
					 | 
				
			||||||
	{}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    RecordType advanceToNextRecord()
 | 
					    nanoseconds_t advanceToNextRecord() override
 | 
				
			||||||
	{
 | 
					    {
 | 
				
			||||||
		_sector->clock = _fmr->seekToPattern(SECTOR_PATTERN);
 | 
					        return seekToPattern(SECTOR_PATTERN);
 | 
				
			||||||
		if (_fmr->eof() || !_sector->clock)
 | 
					    }
 | 
				
			||||||
			return UNKNOWN_RECORD;
 | 
					 | 
				
			||||||
		return SECTOR_RECORD;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void decodeSectorRecord()
 | 
					    void decodeSectorRecord() override
 | 
				
			||||||
	{
 | 
					    {
 | 
				
			||||||
		/* Skip ID mark. */
 | 
					        /* Skip ID mark (we know it's a AESLANIER_RECORD_SEPARATOR). */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		readRawBits(16);
 | 
					        readRawBits(16);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		const auto& rawbits = readRawBits(AESLANIER_RECORD_SIZE*16);
 | 
					        const auto& rawbits = readRawBits(AESLANIER_RECORD_SIZE * 16);
 | 
				
			||||||
		const auto& bytes = decodeFmMfm(rawbits).slice(0, AESLANIER_RECORD_SIZE);
 | 
					        const auto& bytes =
 | 
				
			||||||
		const auto& reversed = reverse_bits(bytes);
 | 
					            decodeFmMfm(rawbits).slice(0, AESLANIER_RECORD_SIZE);
 | 
				
			||||||
 | 
					        const auto& reversed = bytes.reverseBits();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		_sector->logicalTrack = reversed[1];
 | 
					        _sector->logicalTrack = reversed[1];
 | 
				
			||||||
		_sector->logicalSide = 0;
 | 
					        _sector->logicalSide = 0;
 | 
				
			||||||
		_sector->logicalSector = reversed[2];
 | 
					        _sector->logicalSector = reversed[2];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* Check header 'checksum' (which seems far too simple to mean much). */
 | 
					        /* Check header 'checksum' (which seems far too simple to mean much). */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		{
 | 
					        {
 | 
				
			||||||
			uint8_t wanted = reversed[3];
 | 
					            uint8_t wanted = reversed[3];
 | 
				
			||||||
			uint8_t got = reversed[1] + reversed[2];
 | 
					            uint8_t got = reversed[1] + reversed[2];
 | 
				
			||||||
			if (wanted != got)
 | 
					            if (wanted != got)
 | 
				
			||||||
				return;
 | 
					                return;
 | 
				
			||||||
		}
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* Check data checksum, which also includes the header and is
 | 
					        /* Check data checksum, which also includes the header and is
 | 
				
			||||||
			* significantly better. */
 | 
					         * significantly better. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		_sector->data = reversed.slice(1, AESLANIER_SECTOR_LENGTH);
 | 
					        _sector->data = reversed.slice(1, AESLANIER_SECTOR_LENGTH);
 | 
				
			||||||
		uint16_t wanted = reversed.reader().seek(0x101).read_le16();
 | 
					        uint16_t wanted = reversed.reader().seek(0x101).read_le16();
 | 
				
			||||||
		uint16_t got = crc16ref(MODBUS_POLY_REF, _sector->data);
 | 
					        uint16_t got = crc16ref(MODBUS_POLY_REF, _sector->data);
 | 
				
			||||||
		_sector->status = (wanted == got) ? Sector::OK : Sector::BAD_CHECKSUM;
 | 
					        _sector->status = (wanted == got) ? Sector::OK : Sector::BAD_CHECKSUM;
 | 
				
			||||||
	}
 | 
					    }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
std::unique_ptr<AbstractDecoder> createAesLanierDecoder(const DecoderProto& config)
 | 
					std::unique_ptr<Decoder> createAesLanierDecoder(const DecoderProto& config)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return std::unique_ptr<AbstractDecoder>(new AesLanierDecoder(config));
 | 
					    return std::unique_ptr<Decoder>(new AesLanierDecoder(config));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										20
									
								
								arch/agat/agat.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								arch/agat/agat.cc
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,20 @@
 | 
				
			|||||||
 | 
					#include "globals.h"
 | 
				
			||||||
 | 
					#include "decoders/decoders.h"
 | 
				
			||||||
 | 
					#include "agat.h"
 | 
				
			||||||
 | 
					#include "bytes.h"
 | 
				
			||||||
 | 
					#include "fmt/format.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					uint8_t agatChecksum(const Bytes& bytes)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    uint16_t checksum = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (uint8_t b : bytes)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (checksum > 0xff)
 | 
				
			||||||
 | 
					            checksum = (checksum + 1) & 0xff;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        checksum += b;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return checksum & 0xff;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										19
									
								
								arch/agat/agat.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								arch/agat/agat.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,19 @@
 | 
				
			|||||||
 | 
					#ifndef AGAT_H
 | 
				
			||||||
 | 
					#define AGAT_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define AGAT_SECTOR_SIZE 256
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static constexpr uint64_t SECTOR_ID = 0x8924555549111444;
 | 
				
			||||||
 | 
					static constexpr uint64_t DATA_ID = 0x8924555514444911;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Encoder;
 | 
				
			||||||
 | 
					class EncoderProto;
 | 
				
			||||||
 | 
					class Decoder;
 | 
				
			||||||
 | 
					class DecoderProto;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern std::unique_ptr<Decoder> createAgatDecoder(const DecoderProto& config);
 | 
				
			||||||
 | 
					extern std::unique_ptr<Encoder> createAgatEncoder(const EncoderProto& config);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern uint8_t agatChecksum(const Bytes& bytes);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
							
								
								
									
										19
									
								
								arch/agat/agat.proto
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								arch/agat/agat.proto
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,19 @@
 | 
				
			|||||||
 | 
					syntax = "proto2";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import "lib/common.proto";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					message AgatDecoderProto {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					message AgatEncoderProto {
 | 
				
			||||||
 | 
						optional double target_clock_period_us = 1
 | 
				
			||||||
 | 
							[default=2.00, (help)="Data clock period of target format."];
 | 
				
			||||||
 | 
						optional double target_rotational_period_ms = 2
 | 
				
			||||||
 | 
							[default=200.0, (help)="Rotational period of target format."];
 | 
				
			||||||
 | 
						optional int32 post_index_gap_bytes = 3
 | 
				
			||||||
 | 
							[default=40, (help)="Post-index gap before first sector header."];
 | 
				
			||||||
 | 
						optional int32 pre_sector_gap_bytes = 4
 | 
				
			||||||
 | 
							[default=11, (help)="Gap before each sector header."];
 | 
				
			||||||
 | 
						optional int32 pre_data_gap_bytes = 5
 | 
				
			||||||
 | 
							[default=2, (help)="Gap before each sector data record."];
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										89
									
								
								arch/agat/decoder.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										89
									
								
								arch/agat/decoder.cc
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,89 @@
 | 
				
			|||||||
 | 
					#include "globals.h"
 | 
				
			||||||
 | 
					#include "decoders/decoders.h"
 | 
				
			||||||
 | 
					#include "agat.h"
 | 
				
			||||||
 | 
					#include "crc.h"
 | 
				
			||||||
 | 
					#include "fluxmap.h"
 | 
				
			||||||
 | 
					#include "decoders/fluxmapreader.h"
 | 
				
			||||||
 | 
					#include "sector.h"
 | 
				
			||||||
 | 
					#include "bytes.h"
 | 
				
			||||||
 | 
					#include "fmt/format.h"
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// clang-format off
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * data:    X  X  X  X   X  X  X  X   X  -  -  X   -  X  -  X   -  X  X  -   X  -  X  -  = 0xff956a
 | 
				
			||||||
 | 
					 * flux:   01 01 01 01  01 01 01 01  01 00 10 01  00 01 00 01  00 01 01 00  01 00 01 00  = 0x555549111444
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * data:    X  X  X  X   X  X  X  X   -  X  X  -   X  -  X  -   X  -  -  X   -  X  -  X  = 0xff6a95
 | 
				
			||||||
 | 
					 * flux:   01 01 01 01  01 01 01 01  00 01 01 00  01 00 01 00  01 00 10 01  00 01 00 01  = 0x555514444911
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Each pattern is prefixed with this one:
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * data:          -  -   -  X   -  -   X  - = 0x12
 | 
				
			||||||
 | 
					 * flux:    (10) 10 10  10 01  00 10  01 00 = 0xa924
 | 
				
			||||||
 | 
					 * magic:   (10) 10 00  10 01  00 10  01 00 = 0x8924
 | 
				
			||||||
 | 
					 *                  ^
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This seems to be generated by emitting A4 in MFM and then a single 0 bit to
 | 
				
			||||||
 | 
					 * shift it out of phase, so the data bits become clock bits and vice versa.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *           X - X - - X - -  = 0xA4
 | 
				
			||||||
 | 
					 *          0100010010010010  = MFM encoded
 | 
				
			||||||
 | 
					 *           1000100100100100 = with trailing zero
 | 
				
			||||||
 | 
					 *            - - - X - - X - = effective bitstream = 0x12
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					// clang-format on
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const FluxPattern SECTOR_PATTERN(64, SECTOR_ID);
 | 
				
			||||||
 | 
					static const FluxPattern DATA_PATTERN(64, DATA_ID);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const FluxMatchers ALL_PATTERNS = {&SECTOR_PATTERN, &DATA_PATTERN};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class AgatDecoder : public Decoder
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
					    AgatDecoder(const DecoderProto& config): Decoder(config) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    nanoseconds_t advanceToNextRecord() override
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return seekToPattern(ALL_PATTERNS);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void decodeSectorRecord() override
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (readRaw64() != SECTOR_ID)
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        auto bytes = decodeFmMfm(readRawBits(64)).slice(0, 4);
 | 
				
			||||||
 | 
					        if (bytes[3] != 0x5a)
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        _sector->logicalTrack = bytes[1] >> 1;
 | 
				
			||||||
 | 
					        _sector->logicalSector = bytes[2];
 | 
				
			||||||
 | 
					        _sector->logicalSide = bytes[1] & 1;
 | 
				
			||||||
 | 
					        _sector->status = Sector::DATA_MISSING; /* unintuitive but correct */
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void decodeDataRecord() override
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (readRaw64() != DATA_ID)
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Bytes bytes = decodeFmMfm(readRawBits((AGAT_SECTOR_SIZE + 2) * 16))
 | 
				
			||||||
 | 
					                          .slice(0, AGAT_SECTOR_SIZE + 2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (bytes[AGAT_SECTOR_SIZE + 1] != 0x5a)
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        _sector->data = bytes.slice(0, AGAT_SECTOR_SIZE);
 | 
				
			||||||
 | 
					        uint8_t wantChecksum = bytes[AGAT_SECTOR_SIZE];
 | 
				
			||||||
 | 
					        uint8_t gotChecksum = agatChecksum(_sector->data);
 | 
				
			||||||
 | 
					        _sector->status =
 | 
				
			||||||
 | 
					            (wantChecksum == gotChecksum) ? Sector::OK : Sector::BAD_CHECKSUM;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					std::unique_ptr<Decoder> createAgatDecoder(const DecoderProto& config)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    return std::unique_ptr<Decoder>(new AgatDecoder(config));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										118
									
								
								arch/agat/encoder.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										118
									
								
								arch/agat/encoder.cc
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,118 @@
 | 
				
			|||||||
 | 
					#include "lib/globals.h"
 | 
				
			||||||
 | 
					#include "lib/decoders/decoders.h"
 | 
				
			||||||
 | 
					#include "lib/encoders/encoders.h"
 | 
				
			||||||
 | 
					#include "agat.h"
 | 
				
			||||||
 | 
					#include "lib/crc.h"
 | 
				
			||||||
 | 
					#include "lib/readerwriter.h"
 | 
				
			||||||
 | 
					#include "lib/image.h"
 | 
				
			||||||
 | 
					#include "lib/layout.h"
 | 
				
			||||||
 | 
					#include "arch/agat/agat.pb.h"
 | 
				
			||||||
 | 
					#include "lib/encoders/encoders.pb.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class AgatEncoder : public Encoder
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
					    AgatEncoder(const EncoderProto& config):
 | 
				
			||||||
 | 
					        Encoder(config),
 | 
				
			||||||
 | 
					        _config(config.agat())
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private:
 | 
				
			||||||
 | 
					    void writeRawBits(uint64_t data, int width)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        _cursor += width;
 | 
				
			||||||
 | 
					        _lastBit = data & 1;
 | 
				
			||||||
 | 
					        for (int i = 0; i < width; i++)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            unsigned pos = _cursor - i - 1;
 | 
				
			||||||
 | 
					            if (pos < _bits.size())
 | 
				
			||||||
 | 
					                _bits[pos] = data & 1;
 | 
				
			||||||
 | 
					            data >>= 1;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void writeBytes(const Bytes& bytes)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        encodeMfm(_bits, _cursor, bytes, _lastBit);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void writeByte(uint8_t byte)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        Bytes b;
 | 
				
			||||||
 | 
					        b.writer().write_8(byte);
 | 
				
			||||||
 | 
					        writeBytes(b);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void writeFillerRawBytes(int count, uint16_t byte)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        for (int i = 0; i < count; i++)
 | 
				
			||||||
 | 
					            writeRawBits(byte, 16);
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void writeFillerBytes(int count, uint8_t byte)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        Bytes b{byte};
 | 
				
			||||||
 | 
					        for (int i = 0; i < count; i++)
 | 
				
			||||||
 | 
					            writeBytes(b);
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
					    std::unique_ptr<Fluxmap> encode(std::shared_ptr<const TrackInfo>& trackInfo,
 | 
				
			||||||
 | 
					        const std::vector<std::shared_ptr<const Sector>>& sectors,
 | 
				
			||||||
 | 
					        const Image& image) override
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        auto trackLayout = Layout::getLayoutOfTrack(
 | 
				
			||||||
 | 
					            trackInfo->logicalTrack, trackInfo->logicalSide);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        double clockRateUs = _config.target_clock_period_us() / 2.0;
 | 
				
			||||||
 | 
					        int bitsPerRevolution =
 | 
				
			||||||
 | 
					            (_config.target_rotational_period_ms() * 1000.0) / clockRateUs;
 | 
				
			||||||
 | 
					        _bits.resize(bitsPerRevolution);
 | 
				
			||||||
 | 
					        _cursor = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        writeFillerRawBytes(_config.post_index_gap_bytes(), 0xaaaa);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for (const auto& sector : sectors)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            /* Header */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            writeFillerRawBytes(_config.pre_sector_gap_bytes(), 0xaaaa);
 | 
				
			||||||
 | 
					            writeRawBits(SECTOR_ID, 64);
 | 
				
			||||||
 | 
					            writeByte(0x5a);
 | 
				
			||||||
 | 
					            writeByte((sector->logicalTrack << 1) | sector->logicalSide);
 | 
				
			||||||
 | 
					            writeByte(sector->logicalSector);
 | 
				
			||||||
 | 
					            writeByte(0x5a);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            /* Data */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            writeFillerRawBytes(_config.pre_data_gap_bytes(), 0xaaaa);
 | 
				
			||||||
 | 
					            auto data = sector->data.slice(0, AGAT_SECTOR_SIZE);
 | 
				
			||||||
 | 
					            writeRawBits(DATA_ID, 64);
 | 
				
			||||||
 | 
					            writeBytes(data);
 | 
				
			||||||
 | 
					            writeByte(agatChecksum(data));
 | 
				
			||||||
 | 
					            writeByte(0x5a);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (_cursor >= _bits.size())
 | 
				
			||||||
 | 
					            error("track data overrun");
 | 
				
			||||||
 | 
					        fillBitmapTo(_bits, _cursor, _bits.size(), {true, false});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        auto fluxmap = std::make_unique<Fluxmap>();
 | 
				
			||||||
 | 
					        fluxmap->appendBits(_bits,
 | 
				
			||||||
 | 
					            calculatePhysicalClockPeriod(_config.target_clock_period_us() * 1e3,
 | 
				
			||||||
 | 
					                _config.target_rotational_period_ms() * 1e6));
 | 
				
			||||||
 | 
					        return fluxmap;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private:
 | 
				
			||||||
 | 
					    const AgatEncoderProto& _config;
 | 
				
			||||||
 | 
					    uint32_t _cursor;
 | 
				
			||||||
 | 
					    bool _lastBit;
 | 
				
			||||||
 | 
					    std::vector<bool> _bits;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					std::unique_ptr<Encoder> createAgatEncoder(const EncoderProto& config)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    return std::unique_ptr<Encoder>(new AgatEncoder(config));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -18,61 +18,61 @@ uint32_t amigaChecksum(const Bytes& bytes)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
static uint8_t everyother(uint16_t x)
 | 
					static uint8_t everyother(uint16_t x)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	                  /* aabb ccdd eeff gghh */
 | 
					    /* aabb ccdd eeff gghh */
 | 
				
			||||||
	x &= 0x6666;      /* 0ab0 0cd0 0ef0 0gh0 */
 | 
					    x &= 0x6666; /* 0ab0 0cd0 0ef0 0gh0 */
 | 
				
			||||||
	x >>= 1;          /* 00ab 00cd 00ef 00gh */
 | 
					    x >>= 1;     /* 00ab 00cd 00ef 00gh */
 | 
				
			||||||
	x |= x << 2;      /* abab cdcd efef ghgh */
 | 
					    x |= x << 2; /* abab cdcd efef ghgh */
 | 
				
			||||||
	x &= 0x3c3c;      /* 00ab cd00 00ef gh00 */
 | 
					    x &= 0x3c3c; /* 00ab cd00 00ef gh00 */
 | 
				
			||||||
	x >>= 2;          /* 0000 abcd 0000 efgh */
 | 
					    x >>= 2;     /* 0000 abcd 0000 efgh */
 | 
				
			||||||
	x |= x >> 4;      /* 0000 abcd abcd efgh */
 | 
					    x |= x >> 4; /* 0000 abcd abcd efgh */
 | 
				
			||||||
	return x;
 | 
					    return x;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Bytes amigaInterleave(const Bytes& input)
 | 
					Bytes amigaInterleave(const Bytes& input)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	Bytes output;
 | 
					    Bytes output;
 | 
				
			||||||
	ByteWriter bw(output);
 | 
					    ByteWriter bw(output);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Write all odd bits. (Numbering starts at 0...) */
 | 
					    /* Write all odd bits. (Numbering starts at 0...) */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	{
 | 
					    {
 | 
				
			||||||
		ByteReader br(input);
 | 
					        ByteReader br(input);
 | 
				
			||||||
		while (!br.eof())
 | 
					        while (!br.eof())
 | 
				
			||||||
		{
 | 
					        {
 | 
				
			||||||
			uint16_t x = br.read_be16();
 | 
					            uint16_t x = br.read_be16();
 | 
				
			||||||
			x &= 0xaaaa;       /* a0b0 c0d0 e0f0 g0h0 */
 | 
					            x &= 0xaaaa;       /* a0b0 c0d0 e0f0 g0h0 */
 | 
				
			||||||
			x |= x >> 1;       /* aabb ccdd eeff gghh */
 | 
					            x |= x >> 1;       /* aabb ccdd eeff gghh */
 | 
				
			||||||
			x = everyother(x); /* 0000 0000 abcd efgh */
 | 
					            x = everyother(x); /* 0000 0000 abcd efgh */
 | 
				
			||||||
			bw.write_8(x);
 | 
					            bw.write_8(x);
 | 
				
			||||||
		}
 | 
					        }
 | 
				
			||||||
	}
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Write all even bits. */
 | 
					    /* Write all even bits. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	{
 | 
					    {
 | 
				
			||||||
		ByteReader br(input);
 | 
					        ByteReader br(input);
 | 
				
			||||||
		while (!br.eof())
 | 
					        while (!br.eof())
 | 
				
			||||||
		{
 | 
					        {
 | 
				
			||||||
			uint16_t x = br.read_be16();
 | 
					            uint16_t x = br.read_be16();
 | 
				
			||||||
			x &= 0x5555;       /* 0a0b 0c0d 0e0f 0g0h */
 | 
					            x &= 0x5555;       /* 0a0b 0c0d 0e0f 0g0h */
 | 
				
			||||||
			x |= x << 1;       /* aabb ccdd eeff gghh */
 | 
					            x |= x << 1;       /* aabb ccdd eeff gghh */
 | 
				
			||||||
			x = everyother(x); /* 0000 0000 abcd efgh */
 | 
					            x = everyother(x); /* 0000 0000 abcd efgh */
 | 
				
			||||||
			bw.write_8(x);
 | 
					            bw.write_8(x);
 | 
				
			||||||
		}
 | 
					        }
 | 
				
			||||||
	}
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return output;
 | 
					    return output;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Bytes amigaDeinterleave(const uint8_t*& input, size_t len)
 | 
					Bytes amigaDeinterleave(const uint8_t*& input, size_t len)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    assert(!(len & 1));
 | 
					    assert(!(len & 1));
 | 
				
			||||||
    const uint8_t* odds = &input[0];
 | 
					    const uint8_t* odds = &input[0];
 | 
				
			||||||
    const uint8_t* evens = &input[len/2];
 | 
					    const uint8_t* evens = &input[len / 2];
 | 
				
			||||||
    Bytes output;
 | 
					    Bytes output;
 | 
				
			||||||
    ByteWriter bw(output);
 | 
					    ByteWriter bw(output);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for (size_t i=0; i<len/2; i++)
 | 
					    for (size_t i = 0; i < len / 2; i++)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        uint8_t o = *odds++;
 | 
					        uint8_t o = *odds++;
 | 
				
			||||||
        uint8_t e = *evens++;
 | 
					        uint8_t e = *evens++;
 | 
				
			||||||
@@ -81,11 +81,15 @@ Bytes amigaDeinterleave(const uint8_t*& input, size_t len)
 | 
				
			|||||||
         * http://graphics.stanford.edu/~seander/bithacks.html#InterleaveBMN
 | 
					         * http://graphics.stanford.edu/~seander/bithacks.html#InterleaveBMN
 | 
				
			||||||
         */
 | 
					         */
 | 
				
			||||||
        uint16_t result =
 | 
					        uint16_t result =
 | 
				
			||||||
            (((e * 0x0101010101010101ULL & 0x8040201008040201ULL)
 | 
					            (((e * 0x0101010101010101ULL & 0x8040201008040201ULL) *
 | 
				
			||||||
                * 0x0102040810204081ULL >> 49) & 0x5555) |
 | 
					                     0x0102040810204081ULL >>
 | 
				
			||||||
            (((o * 0x0101010101010101ULL & 0x8040201008040201ULL)
 | 
					                 49) &
 | 
				
			||||||
                * 0x0102040810204081ULL >> 48) & 0xAAAA);
 | 
					                0x5555) |
 | 
				
			||||||
        
 | 
					            (((o * 0x0101010101010101ULL & 0x8040201008040201ULL) *
 | 
				
			||||||
 | 
					                     0x0102040810204081ULL >>
 | 
				
			||||||
 | 
					                 48) &
 | 
				
			||||||
 | 
					                0xAAAA);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        bw.write_be16(result);
 | 
					        bw.write_be16(result);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -95,6 +99,6 @@ Bytes amigaDeinterleave(const uint8_t*& input, size_t len)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
Bytes amigaDeinterleave(const Bytes& input)
 | 
					Bytes amigaDeinterleave(const Bytes& input)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	const uint8_t* ptr = input.cbegin();
 | 
					    const uint8_t* ptr = input.cbegin();
 | 
				
			||||||
	return amigaDeinterleave(ptr, input.size());
 | 
					    return amigaDeinterleave(ptr, input.size());
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,10 +7,10 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#define AMIGA_TRACKS_PER_DISK 80
 | 
					#define AMIGA_TRACKS_PER_DISK 80
 | 
				
			||||||
#define AMIGA_SECTORS_PER_TRACK 11
 | 
					#define AMIGA_SECTORS_PER_TRACK 11
 | 
				
			||||||
#define AMIGA_RECORD_SIZE 0x21f
 | 
					#define AMIGA_RECORD_SIZE 0x21c
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern std::unique_ptr<AbstractDecoder> createAmigaDecoder(const DecoderProto& config);
 | 
					extern std::unique_ptr<Decoder> createAmigaDecoder(const DecoderProto& config);
 | 
				
			||||||
extern std::unique_ptr<AbstractEncoder> createAmigaEncoder(const EncoderProto& config);
 | 
					extern std::unique_ptr<Encoder> createAmigaEncoder(const EncoderProto& config);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern uint32_t amigaChecksum(const Bytes& bytes);
 | 
					extern uint32_t amigaChecksum(const Bytes& bytes);
 | 
				
			||||||
extern Bytes amigaInterleave(const Bytes& input);
 | 
					extern Bytes amigaInterleave(const Bytes& input);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -11,75 +11,74 @@
 | 
				
			|||||||
#include <string.h>
 | 
					#include <string.h>
 | 
				
			||||||
#include <algorithm>
 | 
					#include <algorithm>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* 
 | 
					/*
 | 
				
			||||||
 * Amiga disks use MFM but it's not quite the same as IBM MFM. They only use
 | 
					 * Amiga disks use MFM but it's not quite the same as IBM MFM. They only use
 | 
				
			||||||
 * a single type of record with a different marker byte.
 | 
					 * a single type of record with a different marker byte.
 | 
				
			||||||
 * 
 | 
					 *
 | 
				
			||||||
 * See the big comment in the IBM MFM decoder for the gruesome details of how
 | 
					 * See the big comment in the IBM MFM decoder for the gruesome details of how
 | 
				
			||||||
 * MFM works.
 | 
					 * MFM works.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
         
 | 
					
 | 
				
			||||||
static const FluxPattern SECTOR_PATTERN(48, AMIGA_SECTOR_RECORD);
 | 
					static const FluxPattern SECTOR_PATTERN(48, AMIGA_SECTOR_RECORD);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class AmigaDecoder : public AbstractDecoder
 | 
					class AmigaDecoder : public Decoder
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
	AmigaDecoder(const DecoderProto& config):
 | 
					    AmigaDecoder(const DecoderProto& config):
 | 
				
			||||||
		AbstractDecoder(config),
 | 
					        Decoder(config),
 | 
				
			||||||
		_config(config.amiga())
 | 
					        _config(config.amiga())
 | 
				
			||||||
	{}
 | 
					    {
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    RecordType advanceToNextRecord() override
 | 
					    nanoseconds_t advanceToNextRecord() override
 | 
				
			||||||
	{
 | 
					    {
 | 
				
			||||||
		_sector->clock = _fmr->seekToPattern(SECTOR_PATTERN);
 | 
					        return seekToPattern(SECTOR_PATTERN);
 | 
				
			||||||
		if (_fmr->eof() || !_sector->clock)
 | 
					    }
 | 
				
			||||||
			return UNKNOWN_RECORD;
 | 
					 | 
				
			||||||
		return SECTOR_RECORD;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void decodeSectorRecord() override
 | 
					    void decodeSectorRecord() override
 | 
				
			||||||
	{
 | 
					    {
 | 
				
			||||||
		const auto& rawbits = readRawBits(AMIGA_RECORD_SIZE*16);
 | 
					        if (readRaw48() != AMIGA_SECTOR_RECORD)
 | 
				
			||||||
		if (rawbits.size() < (AMIGA_RECORD_SIZE*16))
 | 
					            return;
 | 
				
			||||||
			return;
 | 
					 | 
				
			||||||
		const auto& rawbytes = toBytes(rawbits).slice(0, AMIGA_RECORD_SIZE*2);
 | 
					 | 
				
			||||||
		const auto& bytes = decodeFmMfm(rawbits).slice(0, AMIGA_RECORD_SIZE);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		const uint8_t* ptr = bytes.begin() + 3;
 | 
					        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);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		Bytes header = amigaDeinterleave(ptr, 4);
 | 
					        const uint8_t* ptr = bytes.begin();
 | 
				
			||||||
		Bytes recoveryinfo = amigaDeinterleave(ptr, 16);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		_sector->logicalTrack = header[1] >> 1;
 | 
					        Bytes header = amigaDeinterleave(ptr, 4);
 | 
				
			||||||
		_sector->logicalSide = header[1] & 1;
 | 
					        Bytes recoveryinfo = amigaDeinterleave(ptr, 16);
 | 
				
			||||||
		_sector->logicalSector = header[2];
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		uint32_t wantedheaderchecksum = amigaDeinterleave(ptr, 4).reader().read_be32();
 | 
					        _sector->logicalTrack = header[1] >> 1;
 | 
				
			||||||
		uint32_t gotheaderchecksum = amigaChecksum(rawbytes.slice(6, 40));
 | 
					        _sector->logicalSide = header[1] & 1;
 | 
				
			||||||
		if (gotheaderchecksum != wantedheaderchecksum)
 | 
					        _sector->logicalSector = header[2];
 | 
				
			||||||
			return;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		uint32_t wanteddatachecksum = amigaDeinterleave(ptr, 4).reader().read_be32();
 | 
					        uint32_t wantedheaderchecksum =
 | 
				
			||||||
		uint32_t gotdatachecksum = amigaChecksum(rawbytes.slice(62, 1024));
 | 
					            amigaDeinterleave(ptr, 4).reader().read_be32();
 | 
				
			||||||
 | 
					        uint32_t gotheaderchecksum = amigaChecksum(rawbytes.slice(0, 40));
 | 
				
			||||||
 | 
					        if (gotheaderchecksum != wantedheaderchecksum)
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		Bytes data;
 | 
					        uint32_t wanteddatachecksum =
 | 
				
			||||||
		data.writer().append(amigaDeinterleave(ptr, 512)).append(recoveryinfo);
 | 
					            amigaDeinterleave(ptr, 4).reader().read_be32();
 | 
				
			||||||
		_sector->data = data;
 | 
					        uint32_t gotdatachecksum = amigaChecksum(rawbytes.slice(56, 1024));
 | 
				
			||||||
		_sector->status = (gotdatachecksum == wanteddatachecksum) ? Sector::OK : Sector::BAD_CHECKSUM;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	std::set<unsigned> requiredSectors(unsigned cylinder, unsigned head) const override
 | 
					        Bytes data;
 | 
				
			||||||
	{
 | 
					        data.writer().append(amigaDeinterleave(ptr, 512)).append(recoveryinfo);
 | 
				
			||||||
		static std::set<unsigned> sectors = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
 | 
					        _sector->data = data;
 | 
				
			||||||
		return sectors;
 | 
					        _sector->status = (gotdatachecksum == wanteddatachecksum)
 | 
				
			||||||
	}
 | 
					                              ? Sector::OK
 | 
				
			||||||
 | 
					                              : Sector::BAD_CHECKSUM;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
	const AmigaDecoderProto& _config;
 | 
					    const AmigaDecoderProto& _config;
 | 
				
			||||||
 | 
					    nanoseconds_t _clock;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
std::unique_ptr<AbstractDecoder> createAmigaDecoder(const DecoderProto& config)
 | 
					std::unique_ptr<Decoder> createAmigaDecoder(const DecoderProto& config)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return std::unique_ptr<AbstractDecoder>(new AmigaDecoder(config));
 | 
					    return std::unique_ptr<Decoder>(new AmigaDecoder(config));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,7 +3,7 @@
 | 
				
			|||||||
#include "encoders/encoders.h"
 | 
					#include "encoders/encoders.h"
 | 
				
			||||||
#include "amiga.h"
 | 
					#include "amiga.h"
 | 
				
			||||||
#include "crc.h"
 | 
					#include "crc.h"
 | 
				
			||||||
#include "writer.h"
 | 
					#include "readerwriter.h"
 | 
				
			||||||
#include "image.h"
 | 
					#include "image.h"
 | 
				
			||||||
#include "arch/amiga/amiga.pb.h"
 | 
					#include "arch/amiga/amiga.pb.h"
 | 
				
			||||||
#include "lib/encoders/encoders.pb.h"
 | 
					#include "lib/encoders/encoders.pb.h"
 | 
				
			||||||
@@ -12,151 +12,138 @@ static bool lastBit;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
static int charToInt(char c)
 | 
					static int charToInt(char c)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (isdigit(c))
 | 
					    if (isdigit(c))
 | 
				
			||||||
		return c - '0';
 | 
					        return c - '0';
 | 
				
			||||||
	return 10 + tolower(c) - 'a';
 | 
					    return 10 + tolower(c) - 'a';
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void write_bits(std::vector<bool>& bits, unsigned& cursor, const std::vector<bool>& src)
 | 
					static void write_bits(
 | 
				
			||||||
 | 
					    std::vector<bool>& bits, unsigned& cursor, const std::vector<bool>& src)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	for (bool bit : src)
 | 
					    for (bool bit : src)
 | 
				
			||||||
	{
 | 
					    {
 | 
				
			||||||
		if (cursor < bits.size())
 | 
					        if (cursor < bits.size())
 | 
				
			||||||
			lastBit = bits[cursor++] = bit;
 | 
					            lastBit = bits[cursor++] = bit;
 | 
				
			||||||
	}
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void write_bits(std::vector<bool>& bits, unsigned& cursor, uint64_t data, int width)
 | 
					static void write_bits(
 | 
				
			||||||
 | 
					    std::vector<bool>& bits, unsigned& cursor, uint64_t data, int width)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	cursor += width;
 | 
					    cursor += width;
 | 
				
			||||||
	lastBit = data & 1;
 | 
					    lastBit = data & 1;
 | 
				
			||||||
	for (int i=0; i<width; i++)
 | 
					    for (int i = 0; i < width; i++)
 | 
				
			||||||
	{
 | 
					    {
 | 
				
			||||||
		unsigned pos = cursor - i - 1;
 | 
					        unsigned pos = cursor - i - 1;
 | 
				
			||||||
		if (pos < bits.size())
 | 
					        if (pos < bits.size())
 | 
				
			||||||
			bits[pos] = data & 1;
 | 
					            bits[pos] = data & 1;
 | 
				
			||||||
		data >>= 1;
 | 
					        data >>= 1;
 | 
				
			||||||
	}
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void write_bits(std::vector<bool>& bits, unsigned& cursor, const Bytes& bytes)
 | 
					static void write_bits(
 | 
				
			||||||
 | 
					    std::vector<bool>& bits, unsigned& cursor, const Bytes& bytes)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	ByteReader br(bytes);
 | 
					    ByteReader br(bytes);
 | 
				
			||||||
	BitReader bitr(br);
 | 
					    BitReader bitr(br);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	while (!bitr.eof())
 | 
					    while (!bitr.eof())
 | 
				
			||||||
	{
 | 
					    {
 | 
				
			||||||
		if (cursor < bits.size())
 | 
					        if (cursor < bits.size())
 | 
				
			||||||
			bits[cursor++] = bitr.get();
 | 
					            bits[cursor++] = bitr.get();
 | 
				
			||||||
	}
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void write_sector(std::vector<bool>& bits, unsigned& cursor, const std::shared_ptr<Sector>& sector)
 | 
					static void write_sector(std::vector<bool>& bits,
 | 
				
			||||||
 | 
					    unsigned& cursor,
 | 
				
			||||||
 | 
					    const std::shared_ptr<const Sector>& sector)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if ((sector->data.size() != 512) && (sector->data.size() != 528))
 | 
					    if ((sector->data.size() != 512) && (sector->data.size() != 528))
 | 
				
			||||||
		Error() << "unsupported sector size --- you must pick 512 or 528";
 | 
					        error("unsupported sector size --- you must pick 512 or 528");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	uint32_t checksum = 0;
 | 
					    uint32_t checksum = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	auto write_interleaved_bytes = [&](const Bytes& bytes)
 | 
					    auto write_interleaved_bytes = [&](const Bytes& bytes)
 | 
				
			||||||
	{
 | 
					    {
 | 
				
			||||||
		Bytes interleaved = amigaInterleave(bytes);
 | 
					        Bytes interleaved = amigaInterleave(bytes);
 | 
				
			||||||
		Bytes mfm = encodeMfm(interleaved, lastBit);
 | 
					        Bytes mfm = encodeMfm(interleaved, lastBit);
 | 
				
			||||||
		checksum ^= amigaChecksum(mfm);
 | 
					        checksum ^= amigaChecksum(mfm);
 | 
				
			||||||
		checksum &= 0x55555555;
 | 
					        checksum &= 0x55555555;
 | 
				
			||||||
		write_bits(bits, cursor, mfm);
 | 
					        write_bits(bits, cursor, mfm);
 | 
				
			||||||
	};
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	auto write_interleaved_word = [&](uint32_t word)
 | 
					    auto write_interleaved_word = [&](uint32_t word)
 | 
				
			||||||
	{
 | 
					    {
 | 
				
			||||||
		Bytes b(4);
 | 
					        Bytes b(4);
 | 
				
			||||||
		b.writer().write_be32(word);
 | 
					        b.writer().write_be32(word);
 | 
				
			||||||
		write_interleaved_bytes(b);
 | 
					        write_interleaved_bytes(b);
 | 
				
			||||||
	};
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    write_bits(bits, cursor, AMIGA_SECTOR_RECORD, 6*8);
 | 
					    write_bits(bits, cursor, 0xaaaa, 2 * 8);
 | 
				
			||||||
 | 
					    write_bits(bits, cursor, AMIGA_SECTOR_RECORD, 6 * 8);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	checksum = 0;
 | 
					    checksum = 0;
 | 
				
			||||||
	Bytes header = 
 | 
					    Bytes header = {0xff, /* Amiga 1.0 format byte */
 | 
				
			||||||
		{
 | 
					        (uint8_t)((sector->logicalTrack << 1) | sector->logicalSide),
 | 
				
			||||||
			0xff, /* Amiga 1.0 format byte */
 | 
					        (uint8_t)sector->logicalSector,
 | 
				
			||||||
			(uint8_t) ((sector->logicalTrack<<1) | sector->logicalSide),
 | 
					        (uint8_t)(AMIGA_SECTORS_PER_TRACK - sector->logicalSector)};
 | 
				
			||||||
			(uint8_t) sector->logicalSector,
 | 
					    write_interleaved_bytes(header);
 | 
				
			||||||
			(uint8_t) (AMIGA_SECTORS_PER_TRACK - sector->logicalSector)
 | 
					    Bytes recoveryInfo(16);
 | 
				
			||||||
		};
 | 
					    if (sector->data.size() == 528)
 | 
				
			||||||
	write_interleaved_bytes(header);
 | 
					        recoveryInfo = sector->data.slice(512, 16);
 | 
				
			||||||
	Bytes recoveryInfo(16);
 | 
					    write_interleaved_bytes(recoveryInfo);
 | 
				
			||||||
	if (sector->data.size() == 528)
 | 
					    write_interleaved_word(checksum);
 | 
				
			||||||
		recoveryInfo = sector->data.slice(512, 16);
 | 
					 | 
				
			||||||
	write_interleaved_bytes(recoveryInfo);
 | 
					 | 
				
			||||||
	write_interleaved_word(checksum);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Bytes data = sector->data.slice(0, 512);
 | 
					    Bytes data = sector->data.slice(0, 512);
 | 
				
			||||||
	write_interleaved_word(amigaChecksum(encodeMfm(amigaInterleave(data), lastBit)));
 | 
					    write_interleaved_word(
 | 
				
			||||||
	write_interleaved_bytes(data);
 | 
					        amigaChecksum(encodeMfm(amigaInterleave(data), lastBit)));
 | 
				
			||||||
 | 
					    write_interleaved_bytes(data);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class AmigaEncoder : public AbstractEncoder
 | 
					class AmigaEncoder : public Encoder
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
	AmigaEncoder(const EncoderProto& config):
 | 
					    AmigaEncoder(const EncoderProto& config):
 | 
				
			||||||
		AbstractEncoder(config),
 | 
					        Encoder(config),
 | 
				
			||||||
		_config(config.amiga()) {}
 | 
					        _config(config.amiga())
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
	std::vector<std::shared_ptr<Sector>> collectSectors(int physicalTrack, int physicalSide, const Image& image) override
 | 
					    std::unique_ptr<Fluxmap> encode(std::shared_ptr<const TrackInfo>& trackInfo,
 | 
				
			||||||
	{
 | 
					        const std::vector<std::shared_ptr<const Sector>>& sectors,
 | 
				
			||||||
		std::vector<std::shared_ptr<Sector>> sectors;
 | 
					        const Image& image) override
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        /* Number of bits for one nominal revolution of a real 200ms Amiga disk.
 | 
				
			||||||
 | 
					         */
 | 
				
			||||||
 | 
					        int bitsPerRevolution = 200e3 / _config.clock_rate_us();
 | 
				
			||||||
 | 
					        std::vector<bool> bits(bitsPerRevolution);
 | 
				
			||||||
 | 
					        unsigned cursor = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if ((physicalTrack >= 0) && (physicalTrack < AMIGA_TRACKS_PER_DISK))
 | 
					        fillBitmapTo(bits,
 | 
				
			||||||
		{
 | 
					            cursor,
 | 
				
			||||||
			for (int sectorId=0; sectorId<AMIGA_SECTORS_PER_TRACK; sectorId++)
 | 
					            _config.post_index_gap_ms() * 1000 / _config.clock_rate_us(),
 | 
				
			||||||
			{
 | 
					            {true, false});
 | 
				
			||||||
				const auto& sector = image.get(physicalTrack, physicalSide, sectorId);
 | 
					        lastBit = false;
 | 
				
			||||||
				if (sector)
 | 
					 | 
				
			||||||
					sectors.push_back(sector);
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		return sectors;
 | 
					        for (const auto& sector : sectors)
 | 
				
			||||||
	}
 | 
					            write_sector(bits, cursor, sector);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    std::unique_ptr<Fluxmap> encode(int physicalTrack, int physicalSide,
 | 
					        if (cursor >= bits.size())
 | 
				
			||||||
			const std::vector<std::shared_ptr<Sector>>& sectors, const Image& image) override
 | 
					            error("track data overrun");
 | 
				
			||||||
	{
 | 
					        fillBitmapTo(bits, cursor, bits.size(), {true, false});
 | 
				
			||||||
		if ((physicalTrack < 0) || (physicalTrack >= AMIGA_TRACKS_PER_DISK))
 | 
					 | 
				
			||||||
			return std::unique_ptr<Fluxmap>();
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		int bitsPerRevolution = 200000.0 / _config.clock_rate_us();
 | 
					        auto fluxmap = std::make_unique<Fluxmap>();
 | 
				
			||||||
		std::vector<bool> bits(bitsPerRevolution);
 | 
					        fluxmap->appendBits(bits,
 | 
				
			||||||
		unsigned cursor = 0;
 | 
					            calculatePhysicalClockPeriod(_config.clock_rate_us() * 1e3, 200e6));
 | 
				
			||||||
 | 
					        return fluxmap;
 | 
				
			||||||
		fillBitmapTo(bits, cursor, _config.post_index_gap_ms() * 1000 / _config.clock_rate_us(), { true, false });
 | 
					    }
 | 
				
			||||||
		lastBit = false;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		for (int sectorId=0; sectorId<AMIGA_SECTORS_PER_TRACK; sectorId++)
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			const auto& sectorData = image.get(physicalTrack, physicalSide, sectorId);
 | 
					 | 
				
			||||||
			if (sectorData)
 | 
					 | 
				
			||||||
				write_sector(bits, cursor, sectorData);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (cursor >= bits.size())
 | 
					 | 
				
			||||||
			Error() << "track data overrun";
 | 
					 | 
				
			||||||
		fillBitmapTo(bits, cursor, bits.size(), { true, false });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		std::unique_ptr<Fluxmap> fluxmap(new Fluxmap);
 | 
					 | 
				
			||||||
		fluxmap->appendBits(bits, _config.clock_rate_us()*1e3);
 | 
					 | 
				
			||||||
		return fluxmap;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
	const AmigaEncoderProto& _config;
 | 
					    const AmigaEncoderProto& _config;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
std::unique_ptr<AbstractEncoder> createAmigaEncoder(const EncoderProto& config)
 | 
					std::unique_ptr<Encoder> createAmigaEncoder(const EncoderProto& config)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return std::unique_ptr<AbstractEncoder>(new AmigaEncoder(config));
 | 
					    return std::unique_ptr<Encoder>(new AmigaEncoder(config));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,13 +1,19 @@
 | 
				
			|||||||
#ifndef APPLE2_H
 | 
					#ifndef APPLE2_H
 | 
				
			||||||
#define APPLE2_H
 | 
					#define APPLE2_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define APPLE2_SECTOR_RECORD   0xd5aa96
 | 
					#include <memory.h>
 | 
				
			||||||
#define APPLE2_DATA_RECORD     0xd5aaad
 | 
					#include "decoders/decoders.h"
 | 
				
			||||||
 | 
					#include "encoders/encoders.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define APPLE2_SECTOR_LENGTH   256
 | 
					#define APPLE2_SECTOR_RECORD 0xd5aa96
 | 
				
			||||||
 | 
					#define APPLE2_DATA_RECORD 0xd5aaad
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define APPLE2_SECTOR_LENGTH 256
 | 
				
			||||||
#define APPLE2_ENCODED_SECTOR_LENGTH 342
 | 
					#define APPLE2_ENCODED_SECTOR_LENGTH 342
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern std::unique_ptr<AbstractDecoder> createApple2Decoder(const DecoderProto& config);
 | 
					#define APPLE2_SECTORS 16
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern std::unique_ptr<Decoder> createApple2Decoder(const DecoderProto& config);
 | 
				
			||||||
 | 
					extern std::unique_ptr<Encoder> createApple2Encoder(const EncoderProto& config);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,4 +1,22 @@
 | 
				
			|||||||
syntax = "proto2";
 | 
					syntax = "proto2";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
message Apple2DecoderProto {}
 | 
					import "lib/common.proto";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					message Apple2DecoderProto {
 | 
				
			||||||
 | 
						optional uint32 side_one_track_offset = 1
 | 
				
			||||||
 | 
							[ default = 0, (help) = "offset to apply to track numbers on side 1" ];
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					message Apple2EncoderProto
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    /* 245kHz. */
 | 
				
			||||||
 | 
					    optional double clock_period_us = 1
 | 
				
			||||||
 | 
					        [ default = 4, (help) = "clock rate on the real device" ];
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    /* Apple II disk drives spin at 300rpm. */
 | 
				
			||||||
 | 
					    optional double rotational_period_ms = 2
 | 
				
			||||||
 | 
					        [ default = 200.0, (help) = "rotational period on the real device" ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						optional uint32 side_one_track_offset = 3
 | 
				
			||||||
 | 
							[ default = 0, (help) = "offset to apply to track numbers on side 1" ];
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,6 +5,8 @@
 | 
				
			|||||||
#include "decoders/decoders.h"
 | 
					#include "decoders/decoders.h"
 | 
				
			||||||
#include "sector.h"
 | 
					#include "sector.h"
 | 
				
			||||||
#include "apple2.h"
 | 
					#include "apple2.h"
 | 
				
			||||||
 | 
					#include "arch/apple2/apple2.pb.h"
 | 
				
			||||||
 | 
					#include "lib/decoders/decoders.pb.h"
 | 
				
			||||||
#include "bytes.h"
 | 
					#include "bytes.h"
 | 
				
			||||||
#include "fmt/format.h"
 | 
					#include "fmt/format.h"
 | 
				
			||||||
#include <string.h>
 | 
					#include <string.h>
 | 
				
			||||||
@@ -12,22 +14,25 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
const FluxPattern SECTOR_RECORD_PATTERN(24, APPLE2_SECTOR_RECORD);
 | 
					const FluxPattern SECTOR_RECORD_PATTERN(24, APPLE2_SECTOR_RECORD);
 | 
				
			||||||
const FluxPattern DATA_RECORD_PATTERN(24, APPLE2_DATA_RECORD);
 | 
					const FluxPattern DATA_RECORD_PATTERN(24, APPLE2_DATA_RECORD);
 | 
				
			||||||
const FluxMatchers ANY_RECORD_PATTERN({ &SECTOR_RECORD_PATTERN, &DATA_RECORD_PATTERN });
 | 
					const FluxMatchers ANY_RECORD_PATTERN(
 | 
				
			||||||
 | 
					    {&SECTOR_RECORD_PATTERN, &DATA_RECORD_PATTERN});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int decode_data_gcr(uint8_t gcr)
 | 
					static int decode_data_gcr(uint8_t gcr)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    switch (gcr)
 | 
					    switch (gcr)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
		#define GCR_ENTRY(gcr, data) \
 | 
					#define GCR_ENTRY(gcr, data) \
 | 
				
			||||||
			case gcr: return data;
 | 
					    case gcr:                \
 | 
				
			||||||
		#include "data_gcr.h"
 | 
					        return data;
 | 
				
			||||||
		#undef GCR_ENTRY
 | 
					#include "data_gcr.h"
 | 
				
			||||||
 | 
					#undef GCR_ENTRY
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    return -1;
 | 
					    return -1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* This is extremely inspired by the MESS implementation, written by Nathan Woods
 | 
					/* This is extremely inspired by the MESS implementation, written by Nathan
 | 
				
			||||||
 * and R. Belmont: https://github.com/mamedev/mame/blob/7914a6083a3b3a8c243ae6c3b8cb50b023f21e0e/src/lib/formats/ap2_dsk.cpp
 | 
					 * Woods and R. Belmont:
 | 
				
			||||||
 | 
					 * https://github.com/mamedev/mame/blob/7914a6083a3b3a8c243ae6c3b8cb50b023f21e0e/src/lib/formats/ap2_dsk.cpp
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static Bytes decode_crazy_data(const uint8_t* inp, Sector::Status& status)
 | 
					static Bytes decode_crazy_data(const uint8_t* inp, Sector::Status& status)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -47,9 +52,11 @@ static Bytes decode_crazy_data(const uint8_t* inp, Sector::Status& status)
 | 
				
			|||||||
        {
 | 
					        {
 | 
				
			||||||
            /* 3 * 2 bit */
 | 
					            /* 3 * 2 bit */
 | 
				
			||||||
            output[i + 0] = ((checksum >> 1) & 0x01) | ((checksum << 1) & 0x02);
 | 
					            output[i + 0] = ((checksum >> 1) & 0x01) | ((checksum << 1) & 0x02);
 | 
				
			||||||
            output[i + 86] = ((checksum >> 3) & 0x01) | ((checksum >> 1) & 0x02);
 | 
					            output[i + 86] =
 | 
				
			||||||
 | 
					                ((checksum >> 3) & 0x01) | ((checksum >> 1) & 0x02);
 | 
				
			||||||
            if ((i + 172) < APPLE2_SECTOR_LENGTH)
 | 
					            if ((i + 172) < APPLE2_SECTOR_LENGTH)
 | 
				
			||||||
                output[i + 172] = ((checksum >> 5) & 0x01) | ((checksum >> 3) & 0x02);
 | 
					                output[i + 172] =
 | 
				
			||||||
 | 
					                    ((checksum >> 5) & 0x01) | ((checksum >> 3) & 0x02);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -64,63 +71,105 @@ static uint8_t combine(uint16_t word)
 | 
				
			|||||||
    return word & (word >> 7);
 | 
					    return word & (word >> 7);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Apple2Decoder : public AbstractDecoder
 | 
					class Apple2Decoder : public Decoder
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
	Apple2Decoder(const DecoderProto& config):
 | 
					    Apple2Decoder(const DecoderProto& config): Decoder(config) {}
 | 
				
			||||||
		AbstractDecoder(config)
 | 
					 | 
				
			||||||
	{}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    RecordType advanceToNextRecord()
 | 
					    nanoseconds_t advanceToNextRecord() override
 | 
				
			||||||
	{
 | 
					    {
 | 
				
			||||||
		const FluxMatcher* matcher = nullptr;
 | 
					        return seekToPattern(ANY_RECORD_PATTERN);
 | 
				
			||||||
		_sector->clock = _fmr->seekToPattern(ANY_RECORD_PATTERN, matcher);
 | 
					    }
 | 
				
			||||||
		if (matcher == &SECTOR_RECORD_PATTERN)
 | 
					 | 
				
			||||||
			return RecordType::SECTOR_RECORD;
 | 
					 | 
				
			||||||
		if (matcher == &DATA_RECORD_PATTERN)
 | 
					 | 
				
			||||||
			return RecordType::DATA_RECORD;
 | 
					 | 
				
			||||||
		return RecordType::UNKNOWN_RECORD;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void decodeSectorRecord()
 | 
					    void decodeSectorRecord() override
 | 
				
			||||||
	{
 | 
					    {
 | 
				
			||||||
		/* Skip ID (as we know it's a APPLE2_SECTOR_RECORD). */
 | 
					        if (readRaw24() != APPLE2_SECTOR_RECORD)
 | 
				
			||||||
		readRawBits(24);
 | 
					            return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* Read header. */
 | 
					        /* Read header. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		auto header = toBytes(readRawBits(8*8)).slice(0, 8);
 | 
					        auto header = toBytes(readRawBits(8 * 8)).slice(0, 8);
 | 
				
			||||||
		ByteReader br(header);
 | 
					        ByteReader br(header);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		uint8_t volume = combine(br.read_be16());
 | 
					        uint8_t volume = combine(br.read_be16());
 | 
				
			||||||
		_sector->logicalTrack = combine(br.read_be16());
 | 
					        _sector->logicalTrack = combine(br.read_be16());
 | 
				
			||||||
		_sector->logicalSector = combine(br.read_be16());
 | 
					        _sector->logicalSide = _sector->physicalSide;
 | 
				
			||||||
		uint8_t checksum = combine(br.read_be16());
 | 
					        _sector->logicalSector = combine(br.read_be16());
 | 
				
			||||||
		if (checksum == (volume ^ _sector->logicalTrack ^ _sector->logicalSector))
 | 
					        uint8_t checksum = combine(br.read_be16());
 | 
				
			||||||
			_sector->status = Sector::DATA_MISSING; /* unintuitive but correct */
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void decodeDataRecord()
 | 
					        // If the checksum is correct, upgrade the sector from MISSING
 | 
				
			||||||
	{
 | 
					        // to DATA_MISSING in anticipation of its data record
 | 
				
			||||||
		/* Check ID. */
 | 
					        if (checksum ==
 | 
				
			||||||
 | 
					            (volume ^ _sector->logicalTrack ^ _sector->logicalSector))
 | 
				
			||||||
 | 
					            _sector->status =
 | 
				
			||||||
 | 
					                Sector::DATA_MISSING; /* unintuitive but correct */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		Bytes bytes = toBytes(readRawBits(3*8)).slice(0, 3);
 | 
					        if (_sector->logicalSide == 1)
 | 
				
			||||||
		if (bytes.reader().read_be24() != APPLE2_DATA_RECORD)
 | 
					            _sector->logicalTrack -= _config.apple2().side_one_track_offset();
 | 
				
			||||||
			return;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* Read and decode data. */
 | 
					        /* Sanity check. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		unsigned recordLength = APPLE2_ENCODED_SECTOR_LENGTH + 2;
 | 
					        if (_sector->logicalTrack > 100)
 | 
				
			||||||
		bytes = toBytes(readRawBits(recordLength*8)).slice(0, recordLength);
 | 
					        {
 | 
				
			||||||
 | 
					            _sector->status = Sector::MISSING;
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		_sector->status = Sector::BAD_CHECKSUM;
 | 
					    void decodeDataRecord() override
 | 
				
			||||||
		_sector->data = decode_crazy_data(&bytes[0], _sector->status);
 | 
					    {
 | 
				
			||||||
	}
 | 
					        /* Check ID. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (readRaw24() != APPLE2_DATA_RECORD)
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Sometimes there's a 1-bit gap between APPLE2_DATA_RECORD and
 | 
				
			||||||
 | 
					        // the data itself.  This has been seen on real world disks
 | 
				
			||||||
 | 
					        // such as the Apple II Operating System Kit from Apple2Online.
 | 
				
			||||||
 | 
					        // However, I haven't seen it described in any of the various
 | 
				
			||||||
 | 
					        // references.
 | 
				
			||||||
 | 
					        //
 | 
				
			||||||
 | 
					        // This extra '0' bit would not affect the real disk interface,
 | 
				
			||||||
 | 
					        // as it was a '1' reaching the top bit of a shift register
 | 
				
			||||||
 | 
					        // that triggered a byte to be available, but it affects the
 | 
				
			||||||
 | 
					        // way the data is read here.
 | 
				
			||||||
 | 
					        //
 | 
				
			||||||
 | 
					        // While the floppies tested only seemed to need this applied
 | 
				
			||||||
 | 
					        // to the first byte of the data record, applying it
 | 
				
			||||||
 | 
					        // consistently to all of them doesn't seem to hurt, and
 | 
				
			||||||
 | 
					        // simplifies the code.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /* Read and decode data. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        auto readApple8 = [&]()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            auto result = 0;
 | 
				
			||||||
 | 
					            while ((result & 0x80) == 0)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                auto b = readRawBits(1);
 | 
				
			||||||
 | 
					                if (b.empty())
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                result = (result << 1) | b[0];
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            return result;
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        constexpr unsigned recordLength = APPLE2_ENCODED_SECTOR_LENGTH + 2;
 | 
				
			||||||
 | 
					        uint8_t bytes[recordLength];
 | 
				
			||||||
 | 
					        for (auto& byte : bytes)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            byte = readApple8();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Upgrade the sector from MISSING to BAD_CHECKSUM.
 | 
				
			||||||
 | 
					        // If decode_crazy_data succeeds, it upgrades the sector to
 | 
				
			||||||
 | 
					        // OK.
 | 
				
			||||||
 | 
					        _sector->status = Sector::BAD_CHECKSUM;
 | 
				
			||||||
 | 
					        _sector->data = decode_crazy_data(&bytes[0], _sector->status);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
std::unique_ptr<AbstractDecoder> createApple2Decoder(const DecoderProto& config)
 | 
					std::unique_ptr<Decoder> createApple2Decoder(const DecoderProto& config)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return std::unique_ptr<AbstractDecoder>(new Apple2Decoder(config));
 | 
					    return std::unique_ptr<Decoder>(new Apple2Decoder(config));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										192
									
								
								arch/apple2/encoder.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										192
									
								
								arch/apple2/encoder.cc
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,192 @@
 | 
				
			|||||||
 | 
					#include "globals.h"
 | 
				
			||||||
 | 
					#include "arch/apple2/apple2.h"
 | 
				
			||||||
 | 
					#include "decoders/decoders.h"
 | 
				
			||||||
 | 
					#include "encoders/encoders.h"
 | 
				
			||||||
 | 
					#include "sector.h"
 | 
				
			||||||
 | 
					#include "readerwriter.h"
 | 
				
			||||||
 | 
					#include "image.h"
 | 
				
			||||||
 | 
					#include "fmt/format.h"
 | 
				
			||||||
 | 
					#include "lib/encoders/encoders.pb.h"
 | 
				
			||||||
 | 
					#include <ctype.h>
 | 
				
			||||||
 | 
					#include "bytes.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int encode_data_gcr(uint8_t data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    switch (data)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					#define GCR_ENTRY(gcr, data) \
 | 
				
			||||||
 | 
					    case data:               \
 | 
				
			||||||
 | 
					        return gcr;
 | 
				
			||||||
 | 
					#include "data_gcr.h"
 | 
				
			||||||
 | 
					#undef GCR_ENTRY
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return -1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Apple2Encoder : public Encoder
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
					    Apple2Encoder(const EncoderProto& config):
 | 
				
			||||||
 | 
					        Encoder(config),
 | 
				
			||||||
 | 
					        _config(config.apple2())
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private:
 | 
				
			||||||
 | 
					    const Apple2EncoderProto& _config;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
					    std::unique_ptr<Fluxmap> encode(std::shared_ptr<const TrackInfo>& trackInfo,
 | 
				
			||||||
 | 
					        const std::vector<std::shared_ptr<const Sector>>& sectors,
 | 
				
			||||||
 | 
					        const Image& image) override
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        int bitsPerRevolution =
 | 
				
			||||||
 | 
					            (_config.rotational_period_ms() * 1e3) / _config.clock_period_us();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        std::vector<bool> bits(bitsPerRevolution);
 | 
				
			||||||
 | 
					        unsigned cursor = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for (const auto& sector : sectors)
 | 
				
			||||||
 | 
					            writeSector(bits, cursor, *sector);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (cursor >= bits.size())
 | 
				
			||||||
 | 
					            error("track data overrun by {} bits", cursor - bits.size());
 | 
				
			||||||
 | 
					        fillBitmapTo(bits, cursor, bits.size(), {true, false});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        std::unique_ptr<Fluxmap> fluxmap(new Fluxmap);
 | 
				
			||||||
 | 
					        fluxmap->appendBits(bits,
 | 
				
			||||||
 | 
					            calculatePhysicalClockPeriod(_config.clock_period_us() * 1e3,
 | 
				
			||||||
 | 
					                _config.rotational_period_ms() * 1e6));
 | 
				
			||||||
 | 
					        return fluxmap;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private:
 | 
				
			||||||
 | 
					    uint8_t volume_id = 254;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* This is extremely inspired by the MESS implementation, written by Nathan
 | 
				
			||||||
 | 
					     * Woods and R. Belmont:
 | 
				
			||||||
 | 
					     * https://github.com/mamedev/mame/blob/7914a6083a3b3a8c243ae6c3b8cb50b023f21e0e/src/lib/formats/ap2_dsk.cpp
 | 
				
			||||||
 | 
					     * as well as Understanding the Apple II (1983) Chapter 9
 | 
				
			||||||
 | 
					     * https://archive.org/details/Understanding_the_Apple_II_1983_Quality_Software/page/n230/mode/1up?view=theater
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void writeSector(
 | 
				
			||||||
 | 
					        std::vector<bool>& bits, unsigned& cursor, const Sector& sector) const
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if ((sector.status == Sector::OK) or
 | 
				
			||||||
 | 
					            (sector.status == Sector::BAD_CHECKSUM))
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            auto write_bit = [&](bool val)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                if (cursor <= bits.size())
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    bits[cursor] = val;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                cursor++;
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            auto write_bits = [&](uint32_t bits, int width)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                for (int i = width; i--;)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    write_bit(bits & (1u << i));
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            auto write_gcr44 = [&](uint8_t value)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                write_bits((value << 7) | value | 0xaaaa, 16);
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            auto write_gcr6 = [&](uint8_t value)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                write_bits(encode_data_gcr(value), 8);
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // The special "FF40" sequence is used to synchronize the receiving
 | 
				
			||||||
 | 
					            // shift register. It's written as "1111 1111 00"; FF indicates the
 | 
				
			||||||
 | 
					            // 8 consecutive 1-bits, while "40" indicates the total number of
 | 
				
			||||||
 | 
					            // microseconds.
 | 
				
			||||||
 | 
					            auto write_ff40 = [&](int n = 1)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                for (; n--;)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    write_bits(0xff << 2, 10);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // There is data to encode to disk.
 | 
				
			||||||
 | 
					            if ((sector.data.size() != APPLE2_SECTOR_LENGTH))
 | 
				
			||||||
 | 
					                error("unsupported sector size {} --- you must pick 256",
 | 
				
			||||||
 | 
					                    sector.data.size());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Write address syncing leader : A sequence of "FF40"s; 5 of them
 | 
				
			||||||
 | 
					            // are said to suffice to synchronize the decoder.
 | 
				
			||||||
 | 
					            // "FF40" indicates that the actual data written is "1111
 | 
				
			||||||
 | 
					            // 1111 00" i.e., 8 1s and a total of 40 microseconds
 | 
				
			||||||
 | 
					            //
 | 
				
			||||||
 | 
					            // In standard formatting, the first logical sector apparently gets
 | 
				
			||||||
 | 
					            // extra padding.
 | 
				
			||||||
 | 
					            write_ff40(sector.logicalSector == 0 ? 32 : 8);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            int track = sector.logicalTrack;
 | 
				
			||||||
 | 
					            if (sector.logicalSide == 1)
 | 
				
			||||||
 | 
					                track += _config.side_one_track_offset();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Write address field: APPLE2_SECTOR_RECORD + sector identifier +
 | 
				
			||||||
 | 
					            // DE AA EB
 | 
				
			||||||
 | 
					            write_bits(APPLE2_SECTOR_RECORD, 24);
 | 
				
			||||||
 | 
					            write_gcr44(volume_id);
 | 
				
			||||||
 | 
					            write_gcr44(track);
 | 
				
			||||||
 | 
					            write_gcr44(sector.logicalSector);
 | 
				
			||||||
 | 
					            write_gcr44(volume_id ^ track ^ sector.logicalSector);
 | 
				
			||||||
 | 
					            write_bits(0xDEAAEB, 24);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Write data syncing leader: FF40 + APPLE2_DATA_RECORD + sector
 | 
				
			||||||
 | 
					            // data + sum + DE AA EB (+ mystery bits cut off of the scan?)
 | 
				
			||||||
 | 
					            write_ff40(8);
 | 
				
			||||||
 | 
					            write_bits(APPLE2_DATA_RECORD, 24);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Convert the sector data to GCR, append the checksum, and write it
 | 
				
			||||||
 | 
					            // out
 | 
				
			||||||
 | 
					            constexpr auto TWOBIT_COUNT =
 | 
				
			||||||
 | 
					                0x56; // Size of the 'twobit' area at the start of the GCR data
 | 
				
			||||||
 | 
					            uint8_t checksum = 0;
 | 
				
			||||||
 | 
					            for (int i = 0; i < APPLE2_ENCODED_SECTOR_LENGTH; i++)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                int value;
 | 
				
			||||||
 | 
					                if (i >= TWOBIT_COUNT)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    value = sector.data[i - TWOBIT_COUNT] >> 2;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                else
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    uint8_t tmp = sector.data[i];
 | 
				
			||||||
 | 
					                    value = ((tmp & 1) << 1) | ((tmp & 2) >> 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    tmp = sector.data[i + TWOBIT_COUNT];
 | 
				
			||||||
 | 
					                    value |= ((tmp & 1) << 3) | ((tmp & 2) << 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    if (i + 2 * TWOBIT_COUNT < APPLE2_SECTOR_LENGTH)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        tmp = sector.data[i + 2 * TWOBIT_COUNT];
 | 
				
			||||||
 | 
					                        value |= ((tmp & 1) << 5) | ((tmp & 2) << 3);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                checksum ^= value;
 | 
				
			||||||
 | 
					                // assert(checksum & ~0x3f == 0);
 | 
				
			||||||
 | 
					                write_gcr6(checksum);
 | 
				
			||||||
 | 
					                checksum = value;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if (sector.status == Sector::BAD_CHECKSUM)
 | 
				
			||||||
 | 
					                checksum ^= 0x3f;
 | 
				
			||||||
 | 
					            write_gcr6(checksum);
 | 
				
			||||||
 | 
					            write_bits(0xDEAAEB, 24);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					std::unique_ptr<Encoder> createApple2Encoder(const EncoderProto& config)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    return std::unique_ptr<Encoder>(new Apple2Encoder(config));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -3,17 +3,19 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
/* Brother word processor format (or at least, one of them) */
 | 
					/* Brother word processor format (or at least, one of them) */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define BROTHER_SECTOR_RECORD            0xFFFFFD57
 | 
					#define BROTHER_SECTOR_RECORD 0xFFFFFD57
 | 
				
			||||||
#define BROTHER_DATA_RECORD              0xFFFFFDDB
 | 
					#define BROTHER_DATA_RECORD 0xFFFFFDDB
 | 
				
			||||||
#define BROTHER_DATA_RECORD_PAYLOAD      256
 | 
					#define BROTHER_DATA_RECORD_PAYLOAD 256
 | 
				
			||||||
#define BROTHER_DATA_RECORD_CHECKSUM     3
 | 
					#define BROTHER_DATA_RECORD_CHECKSUM 3
 | 
				
			||||||
#define BROTHER_DATA_RECORD_ENCODED_SIZE 415
 | 
					#define BROTHER_DATA_RECORD_ENCODED_SIZE 415
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define BROTHER_TRACKS_PER_240KB_DISK    78
 | 
					#define BROTHER_TRACKS_PER_240KB_DISK 78
 | 
				
			||||||
#define BROTHER_TRACKS_PER_120KB_DISK    39
 | 
					#define BROTHER_TRACKS_PER_120KB_DISK 39
 | 
				
			||||||
#define BROTHER_SECTORS_PER_TRACK        12
 | 
					#define BROTHER_SECTORS_PER_TRACK 12
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern std::unique_ptr<AbstractDecoder> createBrotherDecoder(const DecoderProto& config);
 | 
					extern std::unique_ptr<Decoder> createBrotherDecoder(
 | 
				
			||||||
extern std::unique_ptr<AbstractEncoder> createBrotherEncoder(const EncoderProto& config);
 | 
					    const DecoderProto& config);
 | 
				
			||||||
 | 
					extern std::unique_ptr<Encoder> createBrotherEncoder(
 | 
				
			||||||
 | 
					    const EncoderProto& config);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -12,9 +12,7 @@ message BrotherEncoderProto {
 | 
				
			|||||||
	optional double post_index_gap_ms = 2 [default = 1.0];
 | 
						optional double post_index_gap_ms = 2 [default = 1.0];
 | 
				
			||||||
	optional double sector_spacing_ms = 3 [default = 16.2];
 | 
						optional double sector_spacing_ms = 3 [default = 16.2];
 | 
				
			||||||
	optional double post_header_spacing_ms = 4 [default = 0.69];
 | 
						optional double post_header_spacing_ms = 4 [default = 0.69];
 | 
				
			||||||
	optional string sector_skew = 5 [default = "05a3816b4927"];
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	optional BrotherFormat format = 6 [default = BROTHER240];
 | 
						optional BrotherFormat format = 6 [default = BROTHER240];
 | 
				
			||||||
	optional int32 bias = 7 [default = 0];
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,13 +1,13 @@
 | 
				
			|||||||
GCR_ENTRY(0x55, 0) // 00000
 | 
					GCR_ENTRY(0x55, 0)  // 00000
 | 
				
			||||||
GCR_ENTRY(0x57, 1) // 00001
 | 
					GCR_ENTRY(0x57, 1)  // 00001
 | 
				
			||||||
GCR_ENTRY(0x5b, 2) // 00010
 | 
					GCR_ENTRY(0x5b, 2)  // 00010
 | 
				
			||||||
GCR_ENTRY(0x5d, 3) // 00011
 | 
					GCR_ENTRY(0x5d, 3)  // 00011
 | 
				
			||||||
GCR_ENTRY(0x5f, 4) // 00100 
 | 
					GCR_ENTRY(0x5f, 4)  // 00100
 | 
				
			||||||
GCR_ENTRY(0x6b, 5) // 00101
 | 
					GCR_ENTRY(0x6b, 5)  // 00101
 | 
				
			||||||
GCR_ENTRY(0x6d, 6) // 00110
 | 
					GCR_ENTRY(0x6d, 6)  // 00110
 | 
				
			||||||
GCR_ENTRY(0x6f, 7) // 00111
 | 
					GCR_ENTRY(0x6f, 7)  // 00111
 | 
				
			||||||
GCR_ENTRY(0x75, 8) // 01000
 | 
					GCR_ENTRY(0x75, 8)  // 01000
 | 
				
			||||||
GCR_ENTRY(0x77, 9) // 01001
 | 
					GCR_ENTRY(0x77, 9)  // 01001
 | 
				
			||||||
GCR_ENTRY(0x7b, 10) // 01010
 | 
					GCR_ENTRY(0x7b, 10) // 01010
 | 
				
			||||||
GCR_ENTRY(0x7d, 11) // 01011
 | 
					GCR_ENTRY(0x7d, 11) // 01011
 | 
				
			||||||
GCR_ENTRY(0x7f, 12) // 01100
 | 
					GCR_ENTRY(0x7f, 12) // 01100
 | 
				
			||||||
@@ -30,4 +30,3 @@ GCR_ENTRY(0xef, 28) // 11100
 | 
				
			|||||||
GCR_ENTRY(0xf5, 29) // 11101
 | 
					GCR_ENTRY(0xf5, 29) // 11101
 | 
				
			||||||
GCR_ENTRY(0xf7, 30) // 11110
 | 
					GCR_ENTRY(0xf7, 30) // 11110
 | 
				
			||||||
GCR_ENTRY(0xfb, 31) // 11111
 | 
					GCR_ENTRY(0xfb, 31) // 11111
 | 
				
			||||||
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,4 @@
 | 
				
			|||||||
#include "globals.h"
 | 
					#include "globals.h"
 | 
				
			||||||
#include "sql.h"
 | 
					 | 
				
			||||||
#include "fluxmap.h"
 | 
					#include "fluxmap.h"
 | 
				
			||||||
#include "decoders/fluxmapreader.h"
 | 
					#include "decoders/fluxmapreader.h"
 | 
				
			||||||
#include "decoders/decoders.h"
 | 
					#include "decoders/decoders.h"
 | 
				
			||||||
@@ -12,7 +11,8 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
const FluxPattern SECTOR_RECORD_PATTERN(32, BROTHER_SECTOR_RECORD);
 | 
					const FluxPattern SECTOR_RECORD_PATTERN(32, BROTHER_SECTOR_RECORD);
 | 
				
			||||||
const FluxPattern DATA_RECORD_PATTERN(32, BROTHER_DATA_RECORD);
 | 
					const FluxPattern DATA_RECORD_PATTERN(32, BROTHER_DATA_RECORD);
 | 
				
			||||||
const FluxMatchers ANY_RECORD_PATTERN({ &SECTOR_RECORD_PATTERN, &DATA_RECORD_PATTERN });
 | 
					const FluxMatchers ANY_RECORD_PATTERN(
 | 
				
			||||||
 | 
					    {&SECTOR_RECORD_PATTERN, &DATA_RECORD_PATTERN});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static std::vector<uint8_t> outputbuffer;
 | 
					static std::vector<uint8_t> outputbuffer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -33,91 +33,89 @@ static int decode_data_gcr(uint8_t gcr)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    switch (gcr)
 | 
					    switch (gcr)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
		#define GCR_ENTRY(gcr, data) \
 | 
					#define GCR_ENTRY(gcr, data) \
 | 
				
			||||||
			case gcr: return data;
 | 
					    case gcr:                \
 | 
				
			||||||
		#include "data_gcr.h"
 | 
					        return data;
 | 
				
			||||||
		#undef GCR_ENTRY
 | 
					#include "data_gcr.h"
 | 
				
			||||||
 | 
					#undef GCR_ENTRY
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    return -1;
 | 
					    return -1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int decode_header_gcr(uint16_t word)
 | 
					static int decode_header_gcr(uint16_t word)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	switch (word)
 | 
					    switch (word)
 | 
				
			||||||
	{
 | 
					    {
 | 
				
			||||||
		#define GCR_ENTRY(gcr, data) \
 | 
					#define GCR_ENTRY(gcr, data) \
 | 
				
			||||||
			case gcr: return data;
 | 
					    case gcr:                \
 | 
				
			||||||
		#include "header_gcr.h"
 | 
					        return data;
 | 
				
			||||||
		#undef GCR_ENTRY
 | 
					#include "header_gcr.h"
 | 
				
			||||||
	}                       
 | 
					#undef GCR_ENTRY
 | 
				
			||||||
	return -1;             
 | 
					    }
 | 
				
			||||||
 | 
					    return -1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class BrotherDecoder : public AbstractDecoder
 | 
					class BrotherDecoder : public Decoder
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
    BrotherDecoder(const DecoderProto& config):
 | 
					    BrotherDecoder(const DecoderProto& config): Decoder(config) {}
 | 
				
			||||||
		AbstractDecoder(config)
 | 
					 | 
				
			||||||
	{}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    RecordType advanceToNextRecord()
 | 
					    nanoseconds_t advanceToNextRecord() override
 | 
				
			||||||
	{
 | 
					    {
 | 
				
			||||||
		const FluxMatcher* matcher = nullptr;
 | 
					        return seekToPattern(ANY_RECORD_PATTERN);
 | 
				
			||||||
		_sector->clock = _fmr->seekToPattern(ANY_RECORD_PATTERN, matcher);
 | 
					    }
 | 
				
			||||||
		if (matcher == &SECTOR_RECORD_PATTERN)
 | 
					 | 
				
			||||||
			return RecordType::SECTOR_RECORD;
 | 
					 | 
				
			||||||
		if (matcher == &DATA_RECORD_PATTERN)
 | 
					 | 
				
			||||||
			return RecordType::DATA_RECORD;
 | 
					 | 
				
			||||||
		return RecordType::UNKNOWN_RECORD;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void decodeSectorRecord()
 | 
					    void decodeSectorRecord() override
 | 
				
			||||||
	{
 | 
					    {
 | 
				
			||||||
		readRawBits(32);
 | 
					        if (readRaw32() != BROTHER_SECTOR_RECORD)
 | 
				
			||||||
		const auto& rawbits = readRawBits(32);
 | 
					            return;
 | 
				
			||||||
		const auto& bytes = toBytes(rawbits).slice(0, 4);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		ByteReader br(bytes);
 | 
					        const auto& rawbits = readRawBits(32);
 | 
				
			||||||
		_sector->logicalTrack = decode_header_gcr(br.read_be16());
 | 
					        const auto& bytes = toBytes(rawbits).slice(0, 4);
 | 
				
			||||||
		_sector->logicalSector = decode_header_gcr(br.read_be16());
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* Sanity check the values read; there's no header checksum and
 | 
					        ByteReader br(bytes);
 | 
				
			||||||
			* occasionally we get garbage due to bit errors. */
 | 
					        _sector->logicalTrack = decode_header_gcr(br.read_be16());
 | 
				
			||||||
		if (_sector->logicalSector > 11)
 | 
					        _sector->logicalSector = decode_header_gcr(br.read_be16());
 | 
				
			||||||
			return;
 | 
					 | 
				
			||||||
		if (_sector->logicalTrack > 79)
 | 
					 | 
				
			||||||
			return;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		_sector->status = Sector::DATA_MISSING;
 | 
					        /* Sanity check the values read; there's no header checksum and
 | 
				
			||||||
	}
 | 
					         * occasionally we get garbage due to bit errors. */
 | 
				
			||||||
	
 | 
					        if (_sector->logicalSector > 11)
 | 
				
			||||||
    void decodeDataRecord()
 | 
					            return;
 | 
				
			||||||
	{
 | 
					        if (_sector->logicalTrack > 79)
 | 
				
			||||||
		readRawBits(32);
 | 
					            return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		const auto& rawbits = readRawBits(BROTHER_DATA_RECORD_ENCODED_SIZE*8);
 | 
					        _sector->status = Sector::DATA_MISSING;
 | 
				
			||||||
		const auto& rawbytes = toBytes(rawbits).slice(0, BROTHER_DATA_RECORD_ENCODED_SIZE);
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		Bytes bytes;
 | 
					    void decodeDataRecord() override
 | 
				
			||||||
		ByteWriter bw(bytes);
 | 
					    {
 | 
				
			||||||
		BitWriter bitw(bw);
 | 
					        if (readRaw32() != BROTHER_DATA_RECORD)
 | 
				
			||||||
		for (uint8_t b : rawbytes)
 | 
					            return;
 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			uint32_t nibble = decode_data_gcr(b);
 | 
					 | 
				
			||||||
			bitw.push(nibble, 5);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		bitw.flush();
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		_sector->data = bytes.slice(0, BROTHER_DATA_RECORD_PAYLOAD);
 | 
					        const auto& rawbits = readRawBits(BROTHER_DATA_RECORD_ENCODED_SIZE * 8);
 | 
				
			||||||
		uint32_t realCrc = crcbrother(_sector->data);
 | 
					        const auto& rawbytes =
 | 
				
			||||||
		uint32_t wantCrc = bytes.reader().seek(BROTHER_DATA_RECORD_PAYLOAD).read_be24();
 | 
					            toBytes(rawbits).slice(0, BROTHER_DATA_RECORD_ENCODED_SIZE);
 | 
				
			||||||
		_sector->status = (realCrc == wantCrc) ? Sector::OK : Sector::BAD_CHECKSUM;
 | 
					
 | 
				
			||||||
	}
 | 
					        Bytes bytes;
 | 
				
			||||||
 | 
					        ByteWriter bw(bytes);
 | 
				
			||||||
 | 
					        BitWriter bitw(bw);
 | 
				
			||||||
 | 
					        for (uint8_t b : rawbytes)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            uint32_t nibble = decode_data_gcr(b);
 | 
				
			||||||
 | 
					            bitw.push(nibble, 5);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        bitw.flush();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        _sector->data = bytes.slice(0, BROTHER_DATA_RECORD_PAYLOAD);
 | 
				
			||||||
 | 
					        uint32_t realCrc = crcbrother(_sector->data);
 | 
				
			||||||
 | 
					        uint32_t wantCrc =
 | 
				
			||||||
 | 
					            bytes.reader().seek(BROTHER_DATA_RECORD_PAYLOAD).read_be24();
 | 
				
			||||||
 | 
					        _sector->status =
 | 
				
			||||||
 | 
					            (realCrc == wantCrc) ? Sector::OK : Sector::BAD_CHECKSUM;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
std::unique_ptr<AbstractDecoder> createBrotherDecoder(const DecoderProto& config)
 | 
					std::unique_ptr<Decoder> createBrotherDecoder(const DecoderProto& config)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return std::unique_ptr<AbstractDecoder>(new BrotherDecoder(config));
 | 
					    return std::unique_ptr<Decoder>(new BrotherDecoder(config));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,210 +3,152 @@
 | 
				
			|||||||
#include "encoders/encoders.h"
 | 
					#include "encoders/encoders.h"
 | 
				
			||||||
#include "brother.h"
 | 
					#include "brother.h"
 | 
				
			||||||
#include "crc.h"
 | 
					#include "crc.h"
 | 
				
			||||||
#include "writer.h"
 | 
					#include "readerwriter.h"
 | 
				
			||||||
#include "image.h"
 | 
					#include "image.h"
 | 
				
			||||||
#include "arch/brother/brother.pb.h"
 | 
					#include "arch/brother/brother.pb.h"
 | 
				
			||||||
#include "lib/encoders/encoders.pb.h"
 | 
					#include "lib/encoders/encoders.pb.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int encode_header_gcr(uint16_t word)
 | 
					static int encode_header_gcr(uint16_t word)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	switch (word)
 | 
					    switch (word)
 | 
				
			||||||
	{
 | 
					    {
 | 
				
			||||||
		#define GCR_ENTRY(gcr, data) \
 | 
					#define GCR_ENTRY(gcr, data) \
 | 
				
			||||||
			case data: return gcr;
 | 
					    case data:               \
 | 
				
			||||||
		#include "header_gcr.h"
 | 
					        return gcr;
 | 
				
			||||||
		#undef GCR_ENTRY
 | 
					#include "header_gcr.h"
 | 
				
			||||||
	}                       
 | 
					#undef GCR_ENTRY
 | 
				
			||||||
	return -1;             
 | 
					    }
 | 
				
			||||||
 | 
					    return -1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int encode_data_gcr(uint8_t data)
 | 
					static int encode_data_gcr(uint8_t data)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	switch (data)
 | 
					    switch (data)
 | 
				
			||||||
	{
 | 
					    {
 | 
				
			||||||
		#define GCR_ENTRY(gcr, data) \
 | 
					#define GCR_ENTRY(gcr, data) \
 | 
				
			||||||
			case data: return gcr;
 | 
					    case data:               \
 | 
				
			||||||
		#include "data_gcr.h"
 | 
					        return gcr;
 | 
				
			||||||
		#undef GCR_ENTRY
 | 
					#include "data_gcr.h"
 | 
				
			||||||
	}                       
 | 
					#undef GCR_ENTRY
 | 
				
			||||||
	return -1;             
 | 
					    }
 | 
				
			||||||
 | 
					    return -1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void write_bits(std::vector<bool>& bits, unsigned& cursor, uint32_t data, int width)
 | 
					static void write_bits(
 | 
				
			||||||
 | 
					    std::vector<bool>& bits, unsigned& cursor, uint32_t data, int width)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	cursor += width;
 | 
					    cursor += width;
 | 
				
			||||||
	for (int i=0; i<width; i++)
 | 
					    for (int i = 0; i < width; i++)
 | 
				
			||||||
	{
 | 
					    {
 | 
				
			||||||
		unsigned pos = cursor - i - 1;
 | 
					        unsigned pos = cursor - i - 1;
 | 
				
			||||||
		if (pos < bits.size())
 | 
					        if (pos < bits.size())
 | 
				
			||||||
			bits[pos] = data & 1;
 | 
					            bits[pos] = data & 1;
 | 
				
			||||||
		data >>= 1;
 | 
					        data >>= 1;
 | 
				
			||||||
	}
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void write_sector_header(std::vector<bool>& bits, unsigned& cursor,
 | 
					static void write_sector_header(
 | 
				
			||||||
		int track, int sector)
 | 
					    std::vector<bool>& bits, unsigned& cursor, int track, int sector)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	write_bits(bits, cursor, 0xffffffff, 31);
 | 
					    write_bits(bits, cursor, 0xffffffff, 31);
 | 
				
			||||||
	write_bits(bits, cursor, BROTHER_SECTOR_RECORD, 32);
 | 
					    write_bits(bits, cursor, BROTHER_SECTOR_RECORD, 32);
 | 
				
			||||||
	write_bits(bits, cursor, encode_header_gcr(track), 16);
 | 
					    write_bits(bits, cursor, encode_header_gcr(track), 16);
 | 
				
			||||||
	write_bits(bits, cursor, encode_header_gcr(sector), 16);
 | 
					    write_bits(bits, cursor, encode_header_gcr(sector), 16);
 | 
				
			||||||
	write_bits(bits, cursor, encode_header_gcr(0x2f), 16);
 | 
					    write_bits(bits, cursor, encode_header_gcr(0x2f), 16);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void write_sector_data(std::vector<bool>& bits, unsigned& cursor, const Bytes& data)
 | 
					static void write_sector_data(
 | 
				
			||||||
 | 
					    std::vector<bool>& bits, unsigned& cursor, const Bytes& data)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	write_bits(bits, cursor, 0xffffffff, 32);
 | 
					    write_bits(bits, cursor, 0xffffffff, 32);
 | 
				
			||||||
	write_bits(bits, cursor, BROTHER_DATA_RECORD, 32);
 | 
					    write_bits(bits, cursor, BROTHER_DATA_RECORD, 32);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	uint16_t fifo = 0;
 | 
					    uint16_t fifo = 0;
 | 
				
			||||||
	int width = 0;
 | 
					    int width = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (data.size() != BROTHER_DATA_RECORD_PAYLOAD)
 | 
					    if (data.size() != BROTHER_DATA_RECORD_PAYLOAD)
 | 
				
			||||||
		Error() << "unsupported sector size";
 | 
					        error("unsupported sector size");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	auto write_byte = [&](uint8_t byte)
 | 
					    auto write_byte = [&](uint8_t byte)
 | 
				
			||||||
	{
 | 
					    {
 | 
				
			||||||
		fifo |= (byte << (8 - width));
 | 
					        fifo |= (byte << (8 - width));
 | 
				
			||||||
		width += 8;
 | 
					        width += 8;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		while (width >= 5)
 | 
					        while (width >= 5)
 | 
				
			||||||
		{
 | 
					        {
 | 
				
			||||||
			uint8_t quintet = fifo >> 11;
 | 
					            uint8_t quintet = fifo >> 11;
 | 
				
			||||||
			fifo <<= 5;
 | 
					            fifo <<= 5;
 | 
				
			||||||
			width -= 5;
 | 
					            width -= 5;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			write_bits(bits, cursor, encode_data_gcr(quintet), 8);
 | 
					            write_bits(bits, cursor, encode_data_gcr(quintet), 8);
 | 
				
			||||||
		}
 | 
					        }
 | 
				
			||||||
	};
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (uint8_t byte : data)
 | 
					    for (uint8_t byte : data)
 | 
				
			||||||
		write_byte(byte);
 | 
					        write_byte(byte);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	uint32_t realCrc = crcbrother(data);
 | 
					    uint32_t realCrc = crcbrother(data);
 | 
				
			||||||
	write_byte(realCrc>>16);
 | 
					    write_byte(realCrc >> 16);
 | 
				
			||||||
	write_byte(realCrc>>8);
 | 
					    write_byte(realCrc >> 8);
 | 
				
			||||||
	write_byte(realCrc);
 | 
					    write_byte(realCrc);
 | 
				
			||||||
	write_byte(0x58); /* magic */
 | 
					    write_byte(0x58); /* magic */
 | 
				
			||||||
    write_byte(0xd4);
 | 
					    write_byte(0xd4);
 | 
				
			||||||
    while (width != 0)
 | 
					    while (width != 0)
 | 
				
			||||||
        write_byte(0);
 | 
					        write_byte(0);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int charToInt(char c)
 | 
					class BrotherEncoder : public Encoder
 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	if (isdigit(c))
 | 
					 | 
				
			||||||
		return c - '0';
 | 
					 | 
				
			||||||
	return 10 + tolower(c) - 'a';
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class BrotherEncoder : public AbstractEncoder
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
	BrotherEncoder(const EncoderProto& config):
 | 
					    BrotherEncoder(const EncoderProto& config):
 | 
				
			||||||
		AbstractEncoder(config),
 | 
					        Encoder(config),
 | 
				
			||||||
		_config(config.brother())
 | 
					        _config(config.brother())
 | 
				
			||||||
	{}
 | 
					    {
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
	std::vector<std::shared_ptr<Sector>> collectSectors(int physicalTrack, int physicalSide, const Image& image) override
 | 
					    std::unique_ptr<Fluxmap> encode(std::shared_ptr<const TrackInfo>& trackInfo,
 | 
				
			||||||
	{
 | 
					        const std::vector<std::shared_ptr<const Sector>>& sectors,
 | 
				
			||||||
		std::vector<std::shared_ptr<Sector>> sectors;
 | 
					        const Image& image) override
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        int bitsPerRevolution = 200000.0 / _config.clock_rate_us();
 | 
				
			||||||
 | 
					        std::vector<bool> bits(bitsPerRevolution);
 | 
				
			||||||
 | 
					        unsigned cursor = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		int logicalTrack;
 | 
					        int sectorCount = 0;
 | 
				
			||||||
		if (physicalSide != 0)
 | 
					        for (const auto& sectorData : sectors)
 | 
				
			||||||
			return sectors;
 | 
					 | 
				
			||||||
		physicalTrack -= _config.bias();
 | 
					 | 
				
			||||||
		switch (_config.format())
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			case BROTHER120:
 | 
					 | 
				
			||||||
				if ((physicalTrack < 0) || (physicalTrack >= (BROTHER_TRACKS_PER_120KB_DISK*2))
 | 
					 | 
				
			||||||
						|| (physicalTrack & 1))
 | 
					 | 
				
			||||||
					return sectors;
 | 
					 | 
				
			||||||
				logicalTrack = physicalTrack/2;
 | 
					 | 
				
			||||||
				break;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			case BROTHER240:
 | 
					 | 
				
			||||||
				if ((physicalTrack < 0) || (physicalTrack >= BROTHER_TRACKS_PER_240KB_DISK))
 | 
					 | 
				
			||||||
					return sectors;
 | 
					 | 
				
			||||||
				logicalTrack = physicalTrack;
 | 
					 | 
				
			||||||
				break;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        for (int sectorId=0; sectorId<BROTHER_SECTORS_PER_TRACK; sectorId++)
 | 
					 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            const auto& sector = image.get(logicalTrack, 0, sectorId);
 | 
					            double headerMs = _config.post_index_gap_ms() +
 | 
				
			||||||
            if (sector)
 | 
					                              sectorCount * _config.sector_spacing_ms();
 | 
				
			||||||
                sectors.push_back(sector);
 | 
					            unsigned headerCursor = headerMs * 1e3 / _config.clock_rate_us();
 | 
				
			||||||
		}
 | 
					            double dataMs = headerMs + _config.post_header_spacing_ms();
 | 
				
			||||||
 | 
					            unsigned dataCursor = dataMs * 1e3 / _config.clock_rate_us();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		return sectors;
 | 
					            fillBitmapTo(bits, cursor, headerCursor, {true, false});
 | 
				
			||||||
	}
 | 
					            write_sector_header(bits,
 | 
				
			||||||
 | 
					                cursor,
 | 
				
			||||||
 | 
					                sectorData->logicalTrack,
 | 
				
			||||||
 | 
					                sectorData->logicalSector);
 | 
				
			||||||
 | 
					            fillBitmapTo(bits, cursor, dataCursor, {true, false});
 | 
				
			||||||
 | 
					            write_sector_data(bits, cursor, sectorData->data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    std::unique_ptr<Fluxmap> encode(int physicalTrack, int physicalSide,
 | 
					            sectorCount++;
 | 
				
			||||||
			const std::vector<std::shared_ptr<Sector>>& sectors, const Image& image) override
 | 
					        }
 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		int logicalTrack;
 | 
					 | 
				
			||||||
		if (physicalSide != 0)
 | 
					 | 
				
			||||||
			return std::unique_ptr<Fluxmap>();
 | 
					 | 
				
			||||||
		physicalTrack -= _config.bias();
 | 
					 | 
				
			||||||
		switch (_config.format())
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			case BROTHER120:
 | 
					 | 
				
			||||||
				if ((physicalTrack < 0) || (physicalTrack >= (BROTHER_TRACKS_PER_120KB_DISK*2))
 | 
					 | 
				
			||||||
						|| (physicalTrack & 1))
 | 
					 | 
				
			||||||
					return std::unique_ptr<Fluxmap>();
 | 
					 | 
				
			||||||
				logicalTrack = physicalTrack/2;
 | 
					 | 
				
			||||||
				break;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
			case BROTHER240:
 | 
					        if (cursor >= bits.size())
 | 
				
			||||||
				if ((physicalTrack < 0) || (physicalTrack >= BROTHER_TRACKS_PER_240KB_DISK))
 | 
					            error("track data overrun");
 | 
				
			||||||
					return std::unique_ptr<Fluxmap>();
 | 
					        fillBitmapTo(bits, cursor, bits.size(), {true, false});
 | 
				
			||||||
				logicalTrack = physicalTrack;
 | 
					 | 
				
			||||||
				break;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		int bitsPerRevolution = 200000.0 / _config.clock_rate_us();
 | 
					        std::unique_ptr<Fluxmap> fluxmap(new Fluxmap);
 | 
				
			||||||
		const std::string& skew = _config.sector_skew();
 | 
					        fluxmap->appendBits(bits, _config.clock_rate_us() * 1e3);
 | 
				
			||||||
		std::vector<bool> bits(bitsPerRevolution);
 | 
					        return fluxmap;
 | 
				
			||||||
		unsigned cursor = 0;
 | 
					    }
 | 
				
			||||||
 | 
					 | 
				
			||||||
		for (int sectorCount=0; sectorCount<BROTHER_SECTORS_PER_TRACK; sectorCount++)
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			int sectorId = charToInt(skew.at(sectorCount));
 | 
					 | 
				
			||||||
			double headerMs = _config.post_index_gap_ms() + sectorCount*_config.sector_spacing_ms();
 | 
					 | 
				
			||||||
			unsigned headerCursor = headerMs*1e3 / _config.clock_rate_us();
 | 
					 | 
				
			||||||
			double dataMs = headerMs + _config.post_header_spacing_ms();
 | 
					 | 
				
			||||||
			unsigned dataCursor = dataMs*1e3 / _config.clock_rate_us();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			const auto& sectorData = image.get(logicalTrack, 0, sectorId);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			fillBitmapTo(bits, cursor, headerCursor, { true, false });
 | 
					 | 
				
			||||||
			write_sector_header(bits, cursor, logicalTrack, sectorId);
 | 
					 | 
				
			||||||
			fillBitmapTo(bits, cursor, dataCursor, { true, false });
 | 
					 | 
				
			||||||
			write_sector_data(bits, cursor, sectorData->data);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (cursor >= bits.size())
 | 
					 | 
				
			||||||
			Error() << "track data overrun";
 | 
					 | 
				
			||||||
		fillBitmapTo(bits, cursor, bits.size(), { true, false });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// The pre-index gap is not normally reported.
 | 
					 | 
				
			||||||
		// std::cerr << "pre-index gap " << 200.0 - (double)cursor*clockRateUs/1e3 << std::endl;
 | 
					 | 
				
			||||||
		
 | 
					 | 
				
			||||||
		std::unique_ptr<Fluxmap> fluxmap(new Fluxmap);
 | 
					 | 
				
			||||||
		fluxmap->appendBits(bits, _config.clock_rate_us()*1e3);
 | 
					 | 
				
			||||||
		return fluxmap;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
	const BrotherEncoderProto& _config;
 | 
					    const BrotherEncoderProto& _config;
 | 
				
			||||||
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
std::unique_ptr<AbstractEncoder> createBrotherEncoder(const EncoderProto& config)
 | 
					std::unique_ptr<Encoder> createBrotherEncoder(const EncoderProto& config)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return std::unique_ptr<AbstractEncoder>(new BrotherEncoder(config));
 | 
					    return std::unique_ptr<Encoder>(new BrotherEncoder(config));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -76,4 +76,3 @@ GCR_ENTRY(0x6BAB, 74)
 | 
				
			|||||||
GCR_ENTRY(0xAD5F, 75)
 | 
					GCR_ENTRY(0xAD5F, 75)
 | 
				
			||||||
GCR_ENTRY(0xDBED, 76)
 | 
					GCR_ENTRY(0xDBED, 76)
 | 
				
			||||||
GCR_ENTRY(0x55BB, 77)
 | 
					GCR_ENTRY(0x55BB, 77)
 | 
				
			||||||
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										43
									
								
								arch/build.mk
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								arch/build.mk
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,43 @@
 | 
				
			|||||||
 | 
					LIBARCH_SRCS = \
 | 
				
			||||||
 | 
						arch/aeslanier/decoder.cc \
 | 
				
			||||||
 | 
						arch/agat/agat.cc \
 | 
				
			||||||
 | 
						arch/agat/decoder.cc \
 | 
				
			||||||
 | 
						arch/agat/encoder.cc \
 | 
				
			||||||
 | 
						arch/amiga/amiga.cc \
 | 
				
			||||||
 | 
						arch/amiga/decoder.cc \
 | 
				
			||||||
 | 
						arch/amiga/encoder.cc \
 | 
				
			||||||
 | 
						arch/apple2/decoder.cc \
 | 
				
			||||||
 | 
						arch/apple2/encoder.cc \
 | 
				
			||||||
 | 
						arch/brother/decoder.cc \
 | 
				
			||||||
 | 
						arch/brother/encoder.cc \
 | 
				
			||||||
 | 
						arch/c64/c64.cc \
 | 
				
			||||||
 | 
						arch/c64/decoder.cc \
 | 
				
			||||||
 | 
						arch/c64/encoder.cc \
 | 
				
			||||||
 | 
						arch/f85/decoder.cc \
 | 
				
			||||||
 | 
						arch/fb100/decoder.cc \
 | 
				
			||||||
 | 
						arch/ibm/decoder.cc \
 | 
				
			||||||
 | 
						arch/ibm/encoder.cc \
 | 
				
			||||||
 | 
						arch/macintosh/decoder.cc \
 | 
				
			||||||
 | 
						arch/macintosh/encoder.cc \
 | 
				
			||||||
 | 
						arch/micropolis/decoder.cc \
 | 
				
			||||||
 | 
						arch/micropolis/encoder.cc \
 | 
				
			||||||
 | 
						arch/mx/decoder.cc \
 | 
				
			||||||
 | 
						arch/northstar/decoder.cc \
 | 
				
			||||||
 | 
						arch/northstar/encoder.cc \
 | 
				
			||||||
 | 
						arch/rolandd20/decoder.cc \
 | 
				
			||||||
 | 
						arch/smaky6/decoder.cc \
 | 
				
			||||||
 | 
						arch/tids990/decoder.cc \
 | 
				
			||||||
 | 
						arch/tids990/encoder.cc \
 | 
				
			||||||
 | 
						arch/victor9k/decoder.cc \
 | 
				
			||||||
 | 
						arch/victor9k/encoder.cc \
 | 
				
			||||||
 | 
						arch/zilogmcz/decoder.cc \
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					LIBARCH_OBJS = $(patsubst %.cc, $(OBJDIR)/%.o, $(LIBARCH_SRCS))
 | 
				
			||||||
 | 
					OBJS += $(LIBARCH_OBJS)
 | 
				
			||||||
 | 
					$(LIBARCH_SRCS): | $(PROTO_HDRS)
 | 
				
			||||||
 | 
					$(LIBARCH_SRCS): CFLAGS += $(PROTO_CFLAGS)
 | 
				
			||||||
 | 
					LIBARCH_LIB = $(OBJDIR)/libarch.a
 | 
				
			||||||
 | 
					LIBARCH_LDFLAGS =
 | 
				
			||||||
 | 
					$(LIBARCH_LIB): $(LIBARCH_OBJS)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$(call use-pkgconfig, $(LIBARCH_LIB), $(LIBARCH_OBJS), fmt)
 | 
				
			||||||
							
								
								
									
										28
									
								
								arch/c64/c64.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								arch/c64/c64.cc
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,28 @@
 | 
				
			|||||||
 | 
					#include "globals.h"
 | 
				
			||||||
 | 
					#include "c64.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *   Track   Sectors/track   # Sectors   Storage in Bytes   Clock rate
 | 
				
			||||||
 | 
					 *   -----   -------------   ---------   ----------------   ----------
 | 
				
			||||||
 | 
					 *    1-17        21            357           7820             3.25
 | 
				
			||||||
 | 
					 *   18-24        19            133           7170             3.5
 | 
				
			||||||
 | 
					 *   25-30        18            108           6300             3.75
 | 
				
			||||||
 | 
					 *   31-40(*)     17             85           6020             4
 | 
				
			||||||
 | 
					 *                              ---
 | 
				
			||||||
 | 
					 *                              683 (for a 35 track image)
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The clock rate is normalised for a 200ms drive.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					nanoseconds_t clockPeriodForC64Track(unsigned track)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    constexpr double b = 8.0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (track < 17)
 | 
				
			||||||
 | 
					        return 26.0 / b;
 | 
				
			||||||
 | 
					    if (track < 24)
 | 
				
			||||||
 | 
					        return 28.0 / b;
 | 
				
			||||||
 | 
					    if (track < 30)
 | 
				
			||||||
 | 
					        return 30.0 / b;
 | 
				
			||||||
 | 
					    return 32.0 / b;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -4,11 +4,11 @@
 | 
				
			|||||||
#include "decoders/decoders.h"
 | 
					#include "decoders/decoders.h"
 | 
				
			||||||
#include "encoders/encoders.h"
 | 
					#include "encoders/encoders.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define C64_SECTOR_RECORD    0xffd49
 | 
					#define C64_SECTOR_RECORD 0xffd49
 | 
				
			||||||
#define C64_DATA_RECORD      0xffd57
 | 
					#define C64_DATA_RECORD 0xffd57
 | 
				
			||||||
#define C64_SECTOR_LENGTH    256
 | 
					#define C64_SECTOR_LENGTH 256
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Source: http://www.unusedino.de/ec64/technical/formats/g64.html 
 | 
					/* Source: http://www.unusedino.de/ec64/technical/formats/g64.html
 | 
				
			||||||
   1. Header sync       FF FF FF FF FF (40 'on' bits, not GCR)
 | 
					   1. Header sync       FF FF FF FF FF (40 'on' bits, not GCR)
 | 
				
			||||||
   2. Header info       52 54 B5 29 4B 7A 5E 95 55 55 (10 GCR bytes)
 | 
					   2. Header info       52 54 B5 29 4B 7A 5E 95 55 55 (10 GCR bytes)
 | 
				
			||||||
   3. Header gap        55 55 55 55 55 55 55 55 55 (9 bytes, never read)
 | 
					   3. Header gap        55 55 55 55 55 55 55 55 55 (9 bytes, never read)
 | 
				
			||||||
@@ -17,17 +17,21 @@
 | 
				
			|||||||
   6. Inter-sector gap  55 55 55 55...55 55 (4 to 12 bytes, never read)
 | 
					   6. Inter-sector gap  55 55 55 55...55 55 (4 to 12 bytes, never read)
 | 
				
			||||||
   1. Header sync       (SYNC for the next sector)
 | 
					   1. Header sync       (SYNC for the next sector)
 | 
				
			||||||
*/
 | 
					*/
 | 
				
			||||||
#define C64_HEADER_DATA_SYNC        0xFF
 | 
					#define C64_HEADER_DATA_SYNC 0xFF
 | 
				
			||||||
#define C64_HEADER_BLOCK_ID         0x08
 | 
					#define C64_HEADER_BLOCK_ID 0x08
 | 
				
			||||||
#define C64_DATA_BLOCK_ID           0x07
 | 
					#define C64_DATA_BLOCK_ID 0x07
 | 
				
			||||||
#define C64_HEADER_GAP              0x55
 | 
					#define C64_HEADER_GAP 0x55
 | 
				
			||||||
#define C64_INTER_SECTOR_GAP        0x55
 | 
					#define C64_INTER_SECTOR_GAP 0x55
 | 
				
			||||||
#define C64_PADDING                 0x0F
 | 
					#define C64_PADDING 0x0F
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define C64_TRACKS_PER_DISK         40
 | 
					#define C64_TRACKS_PER_DISK 40
 | 
				
			||||||
#define C64_BAM_TRACK               17
 | 
					#define C64_BAM_TRACK 17
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern std::unique_ptr<AbstractDecoder> createCommodore64Decoder(const DecoderProto& config);
 | 
					extern std::unique_ptr<Decoder> createCommodore64Decoder(
 | 
				
			||||||
extern std::unique_ptr<AbstractEncoder> createCommodore64Encoder(const EncoderProto& config);
 | 
					    const DecoderProto& config);
 | 
				
			||||||
 | 
					extern std::unique_ptr<Encoder> createCommodore64Encoder(
 | 
				
			||||||
 | 
					    const EncoderProto& config);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern nanoseconds_t clockPeriodForC64Track(unsigned track);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,7 +7,5 @@ message Commodore64DecoderProto {}
 | 
				
			|||||||
message Commodore64EncoderProto {
 | 
					message Commodore64EncoderProto {
 | 
				
			||||||
	optional double post_index_gap_us = 1 [default=0.0,
 | 
						optional double post_index_gap_us = 1 [default=0.0,
 | 
				
			||||||
		(help) = "post-index gap before first sector header."];
 | 
							(help) = "post-index gap before first sector header."];
 | 
				
			||||||
	optional double clock_compensation_factor = 2 [default=1.0,
 | 
					 | 
				
			||||||
		(help) = "scale the output clock by this much."];
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -13,16 +13,18 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
const FluxPattern SECTOR_RECORD_PATTERN(20, C64_SECTOR_RECORD);
 | 
					const FluxPattern SECTOR_RECORD_PATTERN(20, C64_SECTOR_RECORD);
 | 
				
			||||||
const FluxPattern DATA_RECORD_PATTERN(20, C64_DATA_RECORD);
 | 
					const FluxPattern DATA_RECORD_PATTERN(20, C64_DATA_RECORD);
 | 
				
			||||||
const FluxMatchers ANY_RECORD_PATTERN({ &SECTOR_RECORD_PATTERN, &DATA_RECORD_PATTERN });
 | 
					const FluxMatchers ANY_RECORD_PATTERN(
 | 
				
			||||||
 | 
					    {&SECTOR_RECORD_PATTERN, &DATA_RECORD_PATTERN});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int decode_data_gcr(uint8_t gcr)
 | 
					static int decode_data_gcr(uint8_t gcr)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    switch (gcr)
 | 
					    switch (gcr)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
		#define GCR_ENTRY(gcr, data) \
 | 
					#define GCR_ENTRY(gcr, data) \
 | 
				
			||||||
			case gcr: return data;
 | 
					    case gcr:                \
 | 
				
			||||||
		#include "data_gcr.h"
 | 
					        return data;
 | 
				
			||||||
		#undef GCR_ENTRY
 | 
					#include "data_gcr.h"
 | 
				
			||||||
 | 
					#undef GCR_ENTRY
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    return -1;
 | 
					    return -1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -37,11 +39,11 @@ static Bytes decode(const std::vector<bool>& bits)
 | 
				
			|||||||
    while (ii != bits.end())
 | 
					    while (ii != bits.end())
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        uint8_t inputfifo = 0;
 | 
					        uint8_t inputfifo = 0;
 | 
				
			||||||
        for (size_t i=0; i<5; i++)
 | 
					        for (size_t i = 0; i < 5; i++)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            if (ii == bits.end())
 | 
					            if (ii == bits.end())
 | 
				
			||||||
                break;
 | 
					                break;
 | 
				
			||||||
            inputfifo = (inputfifo<<1) | *ii++;
 | 
					            inputfifo = (inputfifo << 1) | *ii++;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        bitw.push(decode_data_gcr(inputfifo), 4);
 | 
					        bitw.push(decode_data_gcr(inputfifo), 4);
 | 
				
			||||||
@@ -51,56 +53,50 @@ static Bytes decode(const std::vector<bool>& bits)
 | 
				
			|||||||
    return output;
 | 
					    return output;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Commodore64Decoder : public AbstractDecoder
 | 
					class Commodore64Decoder : public Decoder
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
	Commodore64Decoder(const DecoderProto& config):
 | 
					    Commodore64Decoder(const DecoderProto& config): Decoder(config) {}
 | 
				
			||||||
		AbstractDecoder(config)
 | 
					 | 
				
			||||||
	{}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    RecordType advanceToNextRecord()
 | 
					    nanoseconds_t advanceToNextRecord() override
 | 
				
			||||||
	{
 | 
					    {
 | 
				
			||||||
		const FluxMatcher* matcher = nullptr;
 | 
					        return seekToPattern(ANY_RECORD_PATTERN);
 | 
				
			||||||
		_sector->clock = _fmr->seekToPattern(ANY_RECORD_PATTERN, matcher);
 | 
					    }
 | 
				
			||||||
		if (matcher == &SECTOR_RECORD_PATTERN)
 | 
					 | 
				
			||||||
			return RecordType::SECTOR_RECORD;
 | 
					 | 
				
			||||||
		if (matcher == &DATA_RECORD_PATTERN)
 | 
					 | 
				
			||||||
			return RecordType::DATA_RECORD;
 | 
					 | 
				
			||||||
		return RecordType::UNKNOWN_RECORD;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void decodeSectorRecord()
 | 
					    void decodeSectorRecord() override
 | 
				
			||||||
	{
 | 
					    {
 | 
				
			||||||
		readRawBits(20);
 | 
					        if (readRaw20() != C64_SECTOR_RECORD)
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		const auto& bits = readRawBits(5*10);
 | 
					        const auto& bits = readRawBits(5 * 10);
 | 
				
			||||||
		const auto& bytes = decode(bits).slice(0, 5);
 | 
					        const auto& bytes = decode(bits).slice(0, 5);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		uint8_t checksum = bytes[0];
 | 
					        uint8_t checksum = bytes[0];
 | 
				
			||||||
		_sector->logicalSector = bytes[1];
 | 
					        _sector->logicalSector = bytes[1];
 | 
				
			||||||
		_sector->logicalSide = 0;
 | 
					        _sector->logicalSide = 0;
 | 
				
			||||||
		_sector->logicalTrack = bytes[2] - 1;
 | 
					        _sector->logicalTrack = bytes[2] - 1;
 | 
				
			||||||
		if (checksum == xorBytes(bytes.slice(1, 4)))
 | 
					        if (checksum == xorBytes(bytes.slice(1, 4)))
 | 
				
			||||||
			_sector->status = Sector::DATA_MISSING; /* unintuitive but correct */
 | 
					            _sector->status =
 | 
				
			||||||
	}
 | 
					                Sector::DATA_MISSING; /* unintuitive but correct */
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void decodeDataRecord()
 | 
					    void decodeDataRecord() override
 | 
				
			||||||
	{
 | 
					    {
 | 
				
			||||||
		readRawBits(20);
 | 
					        if (readRaw20() != C64_DATA_RECORD)
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		const auto& bits = readRawBits(259*10);
 | 
					        const auto& bits = readRawBits(259 * 10);
 | 
				
			||||||
		const auto& bytes = decode(bits).slice(0, 259);
 | 
					        const auto& bytes = decode(bits).slice(0, 259);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		_sector->data = bytes.slice(0, C64_SECTOR_LENGTH);
 | 
					        _sector->data = bytes.slice(0, C64_SECTOR_LENGTH);
 | 
				
			||||||
		uint8_t gotChecksum = xorBytes(_sector->data);
 | 
					        uint8_t gotChecksum = xorBytes(_sector->data);
 | 
				
			||||||
		uint8_t wantChecksum = bytes[256];
 | 
					        uint8_t wantChecksum = bytes[256];
 | 
				
			||||||
		_sector->status = (wantChecksum == gotChecksum) ? Sector::OK : Sector::BAD_CHECKSUM;
 | 
					        _sector->status =
 | 
				
			||||||
	}
 | 
					            (wantChecksum == gotChecksum) ? Sector::OK : Sector::BAD_CHECKSUM;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
std::unique_ptr<AbstractDecoder> createCommodore64Decoder(const DecoderProto& config)
 | 
					std::unique_ptr<Decoder> createCommodore64Decoder(const DecoderProto& config)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return std::unique_ptr<AbstractDecoder>(new Commodore64Decoder(config));
 | 
					    return std::unique_ptr<Decoder>(new Commodore64Decoder(config));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,158 +4,101 @@
 | 
				
			|||||||
#include "c64.h"
 | 
					#include "c64.h"
 | 
				
			||||||
#include "crc.h"
 | 
					#include "crc.h"
 | 
				
			||||||
#include "sector.h"
 | 
					#include "sector.h"
 | 
				
			||||||
#include "writer.h"
 | 
					#include "readerwriter.h"
 | 
				
			||||||
#include "image.h"
 | 
					#include "image.h"
 | 
				
			||||||
#include "fmt/format.h"
 | 
					#include "fmt/format.h"
 | 
				
			||||||
#include "arch/c64/c64.pb.h"
 | 
					#include "arch/c64/c64.pb.h"
 | 
				
			||||||
#include "lib/encoders/encoders.pb.h"
 | 
					#include "lib/encoders/encoders.pb.h"
 | 
				
			||||||
 | 
					#include "lib/layout.h"
 | 
				
			||||||
#include <ctype.h>
 | 
					#include <ctype.h>
 | 
				
			||||||
#include "bytes.h"
 | 
					#include "bytes.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static bool lastBit;
 | 
					static bool lastBit;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static double clockRateUsForTrack(unsigned track)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    /*
 | 
					 | 
				
			||||||
     * Track   # Sectors/Track Speed Zone  bits/rotation       
 | 
					 | 
				
			||||||
     * 1 – 17          21          3       61,538.4
 | 
					 | 
				
			||||||
     * 18 – 24         19          2       57,142.8
 | 
					 | 
				
			||||||
     * 25 – 30         18          1       53,333.4
 | 
					 | 
				
			||||||
     * 31 – 35         17          0       50,000.0
 | 
					 | 
				
			||||||
    */
 | 
					 | 
				
			||||||
    if (track < 17)
 | 
					 | 
				
			||||||
        return 200000.0/61538.4;
 | 
					 | 
				
			||||||
    if (track < 24)
 | 
					 | 
				
			||||||
        return 200000.0/57142.8;
 | 
					 | 
				
			||||||
    if (track < 30)
 | 
					 | 
				
			||||||
        return 200000.0/53333.4;
 | 
					 | 
				
			||||||
    return 200000.0/50000.0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static unsigned sectorsForTrack(unsigned track)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    /*
 | 
					 | 
				
			||||||
     * Track   Sectors/track   # Sectors   Storage in Bytes
 | 
					 | 
				
			||||||
     *   -----   -------------   ---------   ----------------
 | 
					 | 
				
			||||||
     *    1-17        21            357           7820
 | 
					 | 
				
			||||||
     *   18-24        19            133           7170
 | 
					 | 
				
			||||||
     *   25-30        18            108           6300
 | 
					 | 
				
			||||||
     *   31-40(*)     17             85           6020
 | 
					 | 
				
			||||||
     *                              ---
 | 
					 | 
				
			||||||
     *                              683 (for a 35 track image)
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    if (track < 17)
 | 
					 | 
				
			||||||
        return 21;
 | 
					 | 
				
			||||||
    if (track < 24)
 | 
					 | 
				
			||||||
        return 19;
 | 
					 | 
				
			||||||
    if (track < 30)
 | 
					 | 
				
			||||||
        return 18;
 | 
					 | 
				
			||||||
    return 17;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int encode_data_gcr(uint8_t data)
 | 
					static int encode_data_gcr(uint8_t data)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    switch (data)
 | 
					    switch (data)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        #define GCR_ENTRY(gcr, data) \
 | 
					#define GCR_ENTRY(gcr, data) \
 | 
				
			||||||
            case data: return gcr;
 | 
					    case data:               \
 | 
				
			||||||
        #include "data_gcr.h"
 | 
					        return gcr;
 | 
				
			||||||
        #undef GCR_ENTRY
 | 
					#include "data_gcr.h"
 | 
				
			||||||
 | 
					#undef GCR_ENTRY
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    return -1;
 | 
					    return -1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void write_bits(std::vector<bool>& bits, unsigned& cursor, const std::vector<bool>& src)
 | 
					static void write_bits(
 | 
				
			||||||
 | 
					    std::vector<bool>& bits, unsigned& cursor, const std::vector<bool>& src)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    for (bool bit : src)  //Range-based for loop
 | 
					    for (bool bit : src) // Range-based for loop
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        if (cursor < bits.size())
 | 
					        if (cursor < bits.size())
 | 
				
			||||||
            bits[cursor++] = bit;
 | 
					            bits[cursor++] = bit;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void write_bits(std::vector<bool>& bits, unsigned& cursor, uint64_t data, int width)
 | 
					static void write_bits(
 | 
				
			||||||
 | 
					    std::vector<bool>& bits, unsigned& cursor, uint64_t data, int width)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    cursor += width;
 | 
					    cursor += width;
 | 
				
			||||||
    for (int i=0; i<width; i++)
 | 
					    for (int i = 0; i < width; i++)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        unsigned pos = cursor - i - 1;              
 | 
					        unsigned pos = cursor - i - 1;
 | 
				
			||||||
        if (pos < bits.size())
 | 
					        if (pos < bits.size())
 | 
				
			||||||
            bits[pos] = data & 1;
 | 
					            bits[pos] = data & 1;
 | 
				
			||||||
        data >>= 1;
 | 
					        data >>= 1;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void bindump(std::ostream& stream, std::vector<bool>& buffer)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    size_t pos = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    while ((pos < buffer.size()) and (pos <520))
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        stream << fmt::format("{:5d} : ", pos);
 | 
					 | 
				
			||||||
        for (int i=0; i<40; i++)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            if ((pos+i) < buffer.size())
 | 
					 | 
				
			||||||
                stream << fmt::format("{:01b}", (buffer[pos+i]));
 | 
					 | 
				
			||||||
            else
 | 
					 | 
				
			||||||
                stream << "-- ";
 | 
					 | 
				
			||||||
            if ((((pos + i + 1) % 8) == 0) and i != 0)
 | 
					 | 
				
			||||||
                stream << "  ";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        stream << std::endl;
 | 
					 | 
				
			||||||
        pos += 40;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
static std::vector<bool> encode_data(uint8_t input)
 | 
					static std::vector<bool> encode_data(uint8_t input)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    /*
 | 
					    /*
 | 
				
			||||||
    * Four 8-bit data bytes are converted to four 10-bit GCR bytes at a time by
 | 
					     * Four 8-bit data bytes are converted to four 10-bit GCR bytes at a time by
 | 
				
			||||||
    * the 1541 DOS.  RAM is only an 8-bit storage device though. This hardware
 | 
					     * the 1541 DOS.  RAM is only an 8-bit storage device though. This hardware
 | 
				
			||||||
    * limitation prevents a 10-bit GCR byte from being stored in a single
 | 
					     * limitation prevents a 10-bit GCR byte from being stored in a single
 | 
				
			||||||
    * memory location. Four 10-bit GCR bytes total 40 bits - a number evenly
 | 
					     * memory location. Four 10-bit GCR bytes total 40 bits - a number evenly
 | 
				
			||||||
    * divisible by our overriding 8-bit constraint. Commodore sub- divides the
 | 
					     * divisible by our overriding 8-bit constraint. Commodore sub- divides the
 | 
				
			||||||
    * 40 GCR bits into five 8-bit bytes to solve this dilemma. This explains
 | 
					     * 40 GCR bits into five 8-bit bytes to solve this dilemma. This explains
 | 
				
			||||||
    * why four 8-bit data bytes are converted to GCR form at a time. The
 | 
					     * why four 8-bit data bytes are converted to GCR form at a time. The
 | 
				
			||||||
    * following step by step example demonstrates how this bit manipulation is
 | 
					     * following step by step example demonstrates how this bit manipulation is
 | 
				
			||||||
    * performed by the DOS.
 | 
					     * performed by the DOS.
 | 
				
			||||||
    *
 | 
					     *
 | 
				
			||||||
    * STEP 1. Four 8-bit Data Bytes
 | 
					     * STEP 1. Four 8-bit Data Bytes
 | 
				
			||||||
    * $08 $10 $00 $12
 | 
					     * $08 $10 $00 $12
 | 
				
			||||||
    *
 | 
					     *
 | 
				
			||||||
    * STEP 2. Hexadecimal to Binary Conversion
 | 
					     * STEP 2. Hexadecimal to Binary Conversion
 | 
				
			||||||
    * 1. Binary Equivalents
 | 
					     * 1. Binary Equivalents
 | 
				
			||||||
    * $08       $10         $00         $12
 | 
					     * $08       $10         $00         $12
 | 
				
			||||||
    * 00001000  00010000    00000000    00010010
 | 
					     * 00001000  00010000    00000000    00010010
 | 
				
			||||||
    *
 | 
					     *
 | 
				
			||||||
    * STEP 3. Binary to GCR Conversion
 | 
					     * STEP 3. Binary to GCR Conversion
 | 
				
			||||||
    * 1. Four 8-bit Data Bytes
 | 
					     * 1. Four 8-bit Data Bytes
 | 
				
			||||||
    * 00001000 00010000 00000000 00010010
 | 
					     * 00001000 00010000 00000000 00010010
 | 
				
			||||||
    * 2. High and Low Nybbles
 | 
					     * 2. High and Low Nybbles
 | 
				
			||||||
    * 0000 1000 0001 0000 0000 0000 0001 0010
 | 
					     * 0000 1000 0001 0000 0000 0000 0001 0010
 | 
				
			||||||
    * 3. High and Low Nybble GCR Equivalents
 | 
					     * 3. High and Low Nybble GCR Equivalents
 | 
				
			||||||
    * 01010 01001 01011 01010 01010 01010 01011 10010
 | 
					     * 01010 01001 01011 01010 01010 01010 01011 10010
 | 
				
			||||||
    * 4. Four 10-bit GCR Bytes
 | 
					     * 4. Four 10-bit GCR Bytes
 | 
				
			||||||
    * 0101001001 0101101010 0101001010 0101110010
 | 
					     * 0101001001 0101101010 0101001010 0101110010
 | 
				
			||||||
    *
 | 
					     *
 | 
				
			||||||
    * STEP 4. 10-bit GCR to 8-bit GCR Conversion
 | 
					     * STEP 4. 10-bit GCR to 8-bit GCR Conversion
 | 
				
			||||||
    *   1. Concatenate Four 10-bit GCR Bytes
 | 
					     *   1. Concatenate Four 10-bit GCR Bytes
 | 
				
			||||||
    *   0101001001010110101001010010100101110010
 | 
					     *   0101001001010110101001010010100101110010
 | 
				
			||||||
    *   2. Five 8-bit Subdivisions
 | 
					     *   2. Five 8-bit Subdivisions
 | 
				
			||||||
    *   01010010 01010110 10100101 00101001 01110010
 | 
					     *   01010010 01010110 10100101 00101001 01110010
 | 
				
			||||||
    *
 | 
					     *
 | 
				
			||||||
    * STEP 5. Binary to Hexadecimal Conversion
 | 
					     * STEP 5. Binary to Hexadecimal Conversion
 | 
				
			||||||
    * 1. Hexadecimal Equivalents
 | 
					     * 1. Hexadecimal Equivalents
 | 
				
			||||||
    *   01010010    01010110    10100101    00101001    01110010
 | 
					     *   01010010    01010110    10100101    00101001    01110010
 | 
				
			||||||
    *   $52         $56         $A5         $29         $72
 | 
					     *   $52         $56         $A5         $29         $72
 | 
				
			||||||
    *
 | 
					     *
 | 
				
			||||||
    * STEP 6. Four 8-bit Data Bytes are Recorded as Five 8-bit GCR Bytes
 | 
					     * STEP 6. Four 8-bit Data Bytes are Recorded as Five 8-bit GCR Bytes
 | 
				
			||||||
    *   $08 $10 $00 $12
 | 
					     *   $08 $10 $00 $12
 | 
				
			||||||
    *
 | 
					     *
 | 
				
			||||||
    * are recorded as
 | 
					     * are recorded as
 | 
				
			||||||
    *   $52 $56 $A5 $29 $72
 | 
					     *   $52 $56 $A5 $29 $72
 | 
				
			||||||
    */
 | 
					     */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    std::vector<bool> output(10, false);
 | 
					    std::vector<bool> output(10, false);
 | 
				
			||||||
    uint8_t hi = 0;
 | 
					    uint8_t hi = 0;
 | 
				
			||||||
@@ -163,124 +106,109 @@ static std::vector<bool> encode_data(uint8_t input)
 | 
				
			|||||||
    uint8_t lo_GCR = 0;
 | 
					    uint8_t lo_GCR = 0;
 | 
				
			||||||
    uint8_t hi_GCR = 0;
 | 
					    uint8_t hi_GCR = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    //Convert the byte in high and low nibble
 | 
					    // Convert the byte in high and low nibble
 | 
				
			||||||
    lo = input >> 4; //get the lo nibble shift the bits 4 to the right          
 | 
					    lo = input >> 4; // get the lo nibble shift the bits 4 to the right
 | 
				
			||||||
    hi = input & 15; //get the hi nibble bij masking the lo bits (00001111)     
 | 
					    hi = input & 15; // get the hi nibble bij masking the lo bits (00001111)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    lo_GCR = encode_data_gcr(lo); // example value: 0000   GCR = 01010
 | 
				
			||||||
    lo_GCR = encode_data_gcr(lo);   //example value: 0000   GCR = 01010
 | 
					    hi_GCR = encode_data_gcr(hi); // example value: 1000   GCR = 01001
 | 
				
			||||||
    hi_GCR = encode_data_gcr(hi);   //example value: 1000   GCR = 01001
 | 
					    // output = [0,1,2,3,4,5,6,7,8,9]
 | 
				
			||||||
    //output = [0,1,2,3,4,5,6,7,8,9]
 | 
					    // value  = [0,1,0,1,0,0,1,0,0,1]
 | 
				
			||||||
    //value  = [0,1,0,1,0,0,1,0,0,1]
 | 
					    //           01010 01001
 | 
				
			||||||
    //          01010 01001
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    int b = 4;
 | 
					    int b = 4;
 | 
				
			||||||
    for (int i = 0; i < 10; i++)
 | 
					    for (int i = 0; i < 10; i++)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        if (i < 5) //01234
 | 
					        if (i < 5)                        // 01234
 | 
				
			||||||
        {       //i = 0 op 
 | 
					        {                                 // i = 0 op
 | 
				
			||||||
            output[4-i] = (lo_GCR & 1); //01010
 | 
					            output[4 - i] = (lo_GCR & 1); // 01010
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            //01010 -> & 00001 -> 00000 output[4] = 0
 | 
					            // 01010 -> & 00001 -> 00000 output[4] = 0
 | 
				
			||||||
            //00101 -> & 00001 -> 00001 output[3] = 1
 | 
					            // 00101 -> & 00001 -> 00001 output[3] = 1
 | 
				
			||||||
            //00010 -> & 00001 -> 00000 output[2] = 0
 | 
					            // 00010 -> & 00001 -> 00000 output[2] = 0
 | 
				
			||||||
            //00001 -> & 00001 -> 00001 output[1] = 1
 | 
					            // 00001 -> & 00001 -> 00001 output[1] = 1
 | 
				
			||||||
            //00000 -> & 00001 -> 00000 output[0] = 0
 | 
					            // 00000 -> & 00001 -> 00000 output[0] = 0
 | 
				
			||||||
            lo_GCR >>= 1;
 | 
					            lo_GCR >>= 1;
 | 
				
			||||||
        } else  
 | 
					        }
 | 
				
			||||||
 | 
					        else
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            output[i+b] = (hi_GCR & 1); //01001
 | 
					            output[i + b] = (hi_GCR & 1); // 01001
 | 
				
			||||||
            //01001 -> & 00001 -> 00001 output[9] = 1
 | 
					            // 01001 -> & 00001 -> 00001 output[9] = 1
 | 
				
			||||||
            //00100 -> & 00001 -> 00000 output[8] = 0
 | 
					            // 00100 -> & 00001 -> 00000 output[8] = 0
 | 
				
			||||||
            //00010 -> & 00001 -> 00000 output[7] = 0
 | 
					            // 00010 -> & 00001 -> 00000 output[7] = 0
 | 
				
			||||||
            //00001 -> & 00001 -> 00001 output[6] = 1
 | 
					            // 00001 -> & 00001 -> 00001 output[6] = 1
 | 
				
			||||||
            //00000 -> & 00001 -> 00000 output[5] = 0
 | 
					            // 00000 -> & 00001 -> 00000 output[5] = 0
 | 
				
			||||||
            hi_GCR >>= 1;
 | 
					            hi_GCR >>= 1;
 | 
				
			||||||
            b = b-2;
 | 
					            b = b - 2;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    return output;
 | 
					    return output;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Commodore64Encoder : public AbstractEncoder
 | 
					class Commodore64Encoder : public Encoder
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
	Commodore64Encoder(const EncoderProto& config):
 | 
					    Commodore64Encoder(const EncoderProto& config):
 | 
				
			||||||
        AbstractEncoder(config),
 | 
					        Encoder(config),
 | 
				
			||||||
		_config(config.c64())
 | 
					        _config(config.c64())
 | 
				
			||||||
	{}
 | 
					    {
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
	std::vector<std::shared_ptr<Sector>> collectSectors(int physicalTrack, int physicalSide, const Image& image) override
 | 
					    std::unique_ptr<Fluxmap> encode(std::shared_ptr<const TrackInfo>& trackInfo,
 | 
				
			||||||
	{
 | 
					        const std::vector<std::shared_ptr<const Sector>>& sectors,
 | 
				
			||||||
		std::vector<std::shared_ptr<Sector>> sectors;
 | 
					        const Image& image) override
 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (physicalSide == 0)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            int logicalTrack = physicalTrack / 2;
 | 
					 | 
				
			||||||
            unsigned numSectors = sectorsForTrack(logicalTrack);
 | 
					 | 
				
			||||||
            for (int sectorId=0; sectorId<numSectors; sectorId++)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                const auto& sector = image.get(logicalTrack, 0, sectorId);
 | 
					 | 
				
			||||||
                if (sector)
 | 
					 | 
				
			||||||
                    sectors.push_back(sector);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		return sectors;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    std::unique_ptr<Fluxmap> encode(int physicalTrack, int physicalSide,
 | 
					 | 
				
			||||||
            const std::vector<std::shared_ptr<Sector>>& sectors, const Image& image) override
 | 
					 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        /* The format ID Character # 1 and # 2 are in the .d64 image only present
 | 
					        /* The format ID Character # 1 and # 2 are in the .d64 image only
 | 
				
			||||||
         * in track 18 sector zero which contains the BAM info in byte 162 and 163.
 | 
					         * present in track 18 sector zero which contains the BAM info in byte
 | 
				
			||||||
         * it is written in every header of every sector and track. headers are not
 | 
					         * 162 and 163. it is written in every header of every sector and track.
 | 
				
			||||||
         * stored in a d64 disk image so we have to get it from track 18 which
 | 
					         * headers are not stored in a d64 disk image so we have to get it from
 | 
				
			||||||
         * contains the BAM.
 | 
					         * track 18 which contains the BAM.
 | 
				
			||||||
        */
 | 
					         */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (physicalSide != 0)
 | 
					        const auto& sectorData = image.get(
 | 
				
			||||||
            return std::unique_ptr<Fluxmap>();
 | 
					            C64_BAM_TRACK, 0, 0); // Read de BAM to get the DISK ID bytes
 | 
				
			||||||
 | 
					 | 
				
			||||||
        const auto& sectorData = image.get(C64_BAM_TRACK*2, 0, 0); //Read de BAM to get the DISK ID bytes
 | 
					 | 
				
			||||||
        if (sectorData)
 | 
					        if (sectorData)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            ByteReader br(sectorData->data);
 | 
					            ByteReader br(sectorData->data);
 | 
				
			||||||
            br.seek(162); //goto position of the first Disk ID Byte
 | 
					            br.seek(162); // goto position of the first Disk ID Byte
 | 
				
			||||||
            _formatByte1 = br.read_8();
 | 
					            _formatByte1 = br.read_8();
 | 
				
			||||||
            _formatByte2 = br.read_8();
 | 
					            _formatByte2 = br.read_8();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        else
 | 
					        else
 | 
				
			||||||
            _formatByte1 = _formatByte2 = 0;
 | 
					            _formatByte1 = _formatByte2 = 0;
 | 
				
			||||||
        
 | 
					 | 
				
			||||||
        int logicalTrack = physicalTrack / 2;
 | 
					 | 
				
			||||||
        double clockRateUs = clockRateUsForTrack(logicalTrack) * _config.clock_compensation_factor();
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        double clockRateUs = clockPeriodForC64Track(trackInfo->logicalTrack);
 | 
				
			||||||
        int bitsPerRevolution = 200000.0 / clockRateUs;
 | 
					        int bitsPerRevolution = 200000.0 / clockRateUs;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        std::vector<bool> bits(bitsPerRevolution);
 | 
					        std::vector<bool> bits(bitsPerRevolution);
 | 
				
			||||||
        unsigned cursor = 0;
 | 
					        unsigned cursor = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        fillBitmapTo(bits, cursor, _config.post_index_gap_us() / clockRateUs, { true, false });
 | 
					        fillBitmapTo(bits,
 | 
				
			||||||
 | 
					            cursor,
 | 
				
			||||||
 | 
					            _config.post_index_gap_us() / clockRateUs,
 | 
				
			||||||
 | 
					            {true, false});
 | 
				
			||||||
        lastBit = false;
 | 
					        lastBit = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        for (const auto& sector : sectors)
 | 
					        for (const auto& sector : sectors)
 | 
				
			||||||
            writeSector(bits, cursor, sector);
 | 
					            writeSector(bits, cursor, sector);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (cursor >= bits.size())
 | 
					        if (cursor >= bits.size())
 | 
				
			||||||
            Error() << fmt::format("track data overrun by {} bits", cursor - bits.size());
 | 
					            error("track data overrun by {} bits", cursor - bits.size());
 | 
				
			||||||
        fillBitmapTo(bits, cursor, bits.size(), { true, false });
 | 
					        fillBitmapTo(bits, cursor, bits.size(), {true, false});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        std::unique_ptr<Fluxmap> fluxmap(new Fluxmap);
 | 
					        std::unique_ptr<Fluxmap> fluxmap(new Fluxmap);
 | 
				
			||||||
        fluxmap->appendBits(bits, clockRateUs*1e3);
 | 
					        fluxmap->appendBits(
 | 
				
			||||||
 | 
					            bits, calculatePhysicalClockPeriod(clockRateUs * 1e3, 200e6));
 | 
				
			||||||
        return fluxmap;
 | 
					        return fluxmap;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
	void writeSector(std::vector<bool>& bits, unsigned& cursor, const std::shared_ptr<Sector>& sector) const
 | 
					    void writeSector(std::vector<bool>& bits,
 | 
				
			||||||
 | 
					        unsigned& cursor,
 | 
				
			||||||
 | 
					        std::shared_ptr<const Sector> sector) const
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        /* Source: http://www.unusedino.de/ec64/technical/formats/g64.html 
 | 
					        /* Source: http://www.unusedino.de/ec64/technical/formats/g64.html
 | 
				
			||||||
         * 1. Header sync       FF FF FF FF FF (40 'on' bits, not GCR)
 | 
					         * 1. Header sync       FF FF FF FF FF (40 'on' bits, not GCR)
 | 
				
			||||||
         * 2. Header info       52 54 B5 29 4B 7A 5E 95 55 55 (10 GCR bytes)
 | 
					         * 2. Header info       52 54 B5 29 4B 7A 5E 95 55 55 (10 GCR bytes)
 | 
				
			||||||
         * 3. Header gap        55 55 55 55 55 55 55 55 55 (9 bytes, never read)
 | 
					         * 3. Header gap        55 55 55 55 55 55 55 55 55 (9 bytes, never read)
 | 
				
			||||||
@@ -288,23 +216,26 @@ private:
 | 
				
			|||||||
         * 5. Data block        55...4A (325 GCR bytes)
 | 
					         * 5. Data block        55...4A (325 GCR bytes)
 | 
				
			||||||
         * 6. Inter-sector gap  55 55 55 55...55 55 (4 to 12 bytes, never read)
 | 
					         * 6. Inter-sector gap  55 55 55 55...55 55 (4 to 12 bytes, never read)
 | 
				
			||||||
         * 1. Header sync       (SYNC for the next sector)
 | 
					         * 1. Header sync       (SYNC for the next sector)
 | 
				
			||||||
        */
 | 
					         */
 | 
				
			||||||
        if ((sector->status == Sector::OK) or (sector->status == Sector::BAD_CHECKSUM))
 | 
					        if ((sector->status == Sector::OK) or
 | 
				
			||||||
 | 
					            (sector->status == Sector::BAD_CHECKSUM))
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            // There is data to encode to disk.
 | 
					            // There is data to encode to disk.
 | 
				
			||||||
            if ((sector->data.size() != C64_SECTOR_LENGTH))
 | 
					            if ((sector->data.size() != C64_SECTOR_LENGTH))
 | 
				
			||||||
                Error() << fmt::format("unsupported sector size {} --- you must pick 256", sector->data.size());    
 | 
					                error("unsupported sector size {} --- you must pick 256",
 | 
				
			||||||
 | 
					                    sector->data.size());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // 1. Write header Sync (not GCR)
 | 
					            // 1. Write header Sync (not GCR)
 | 
				
			||||||
            for (int i=0; i<6; i++)
 | 
					            for (int i = 0; i < 6; i++)
 | 
				
			||||||
                write_bits(bits, cursor, C64_HEADER_DATA_SYNC, 1*8); /* sync */
 | 
					                write_bits(
 | 
				
			||||||
 | 
					                    bits, cursor, C64_HEADER_DATA_SYNC, 1 * 8); /* sync */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // 2. Write Header info 10 GCR bytes
 | 
					            // 2. Write Header info 10 GCR bytes
 | 
				
			||||||
            /*
 | 
					            /*
 | 
				
			||||||
             * The 10 byte header info (#2) is GCR encoded and must be decoded  to
 | 
					             * The 10 byte header info (#2) is GCR encoded and must be decoded
 | 
				
			||||||
             * it's normal 8 bytes to be understood. Once decoded, its breakdown is
 | 
					             * to it's normal 8 bytes to be understood. Once decoded, its
 | 
				
			||||||
             * as follows:
 | 
					             * breakdown is as follows:
 | 
				
			||||||
             * 
 | 
					             *
 | 
				
			||||||
             * Byte $00 - header block ID           ($08)
 | 
					             * Byte $00 - header block ID           ($08)
 | 
				
			||||||
             *   01 - header block checksum 16  (EOR of $02-$05)
 | 
					             *   01 - header block checksum 16  (EOR of $02-$05)
 | 
				
			||||||
             *   02 - Sector
 | 
					             *   02 - Sector
 | 
				
			||||||
@@ -313,11 +244,14 @@ private:
 | 
				
			|||||||
             *   05 - Format ID byte #1
 | 
					             *   05 - Format ID byte #1
 | 
				
			||||||
             *   06-07 - $0F ("off" bytes)
 | 
					             *   06-07 - $0F ("off" bytes)
 | 
				
			||||||
             */
 | 
					             */
 | 
				
			||||||
            uint8_t encodedTrack = ((sector->logicalTrack) + 1); // C64 track numbering starts with 1. Fluxengine with 0.
 | 
					            uint8_t encodedTrack =
 | 
				
			||||||
 | 
					                ((sector->logicalTrack) +
 | 
				
			||||||
 | 
					                    1); // C64 track numbering starts with 1. Fluxengine with 0.
 | 
				
			||||||
            uint8_t encodedSector = sector->logicalSector;
 | 
					            uint8_t encodedSector = sector->logicalSector;
 | 
				
			||||||
            // uint8_t formatByte1 = C64_FORMAT_ID_BYTE1;
 | 
					            // uint8_t formatByte1 = C64_FORMAT_ID_BYTE1;
 | 
				
			||||||
            // uint8_t formatByte2 = C64_FORMAT_ID_BYTE2;
 | 
					            // uint8_t formatByte2 = C64_FORMAT_ID_BYTE2;
 | 
				
			||||||
            uint8_t headerChecksum = (encodedTrack ^ encodedSector ^ _formatByte1 ^ _formatByte2);
 | 
					            uint8_t headerChecksum =
 | 
				
			||||||
 | 
					                (encodedTrack ^ encodedSector ^ _formatByte1 ^ _formatByte2);
 | 
				
			||||||
            write_bits(bits, cursor, encode_data(C64_HEADER_BLOCK_ID));
 | 
					            write_bits(bits, cursor, encode_data(C64_HEADER_BLOCK_ID));
 | 
				
			||||||
            write_bits(bits, cursor, encode_data(headerChecksum));
 | 
					            write_bits(bits, cursor, encode_data(headerChecksum));
 | 
				
			||||||
            write_bits(bits, cursor, encode_data(encodedSector));
 | 
					            write_bits(bits, cursor, encode_data(encodedSector));
 | 
				
			||||||
@@ -328,22 +262,26 @@ private:
 | 
				
			|||||||
            write_bits(bits, cursor, encode_data(C64_PADDING));
 | 
					            write_bits(bits, cursor, encode_data(C64_PADDING));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // 3. Write header GAP not GCR
 | 
					            // 3. Write header GAP not GCR
 | 
				
			||||||
            for (int i=0; i<9; i++)
 | 
					            for (int i = 0; i < 9; i++)
 | 
				
			||||||
                write_bits(bits, cursor, C64_HEADER_GAP, 1*8); /* header gap */
 | 
					                write_bits(
 | 
				
			||||||
 | 
					                    bits, cursor, C64_HEADER_GAP, 1 * 8); /* header gap */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // 4. Write Data sync not GCR
 | 
					            // 4. Write Data sync not GCR
 | 
				
			||||||
            for (int i=0; i<6; i++)
 | 
					            for (int i = 0; i < 6; i++)
 | 
				
			||||||
                write_bits(bits, cursor, C64_HEADER_DATA_SYNC, 1*8); /* sync */
 | 
					                write_bits(
 | 
				
			||||||
 | 
					                    bits, cursor, C64_HEADER_DATA_SYNC, 1 * 8); /* sync */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // 5. Write data block 325 GCR bytes
 | 
					            // 5. Write data block 325 GCR bytes
 | 
				
			||||||
            /*
 | 
					            /*
 | 
				
			||||||
             * The 325 byte data block (#5) is GCR encoded and must be  decoded  to  its
 | 
					             * The 325 byte data block (#5) is GCR encoded and must be  decoded
 | 
				
			||||||
             * normal 260 bytes to be understood. The data block is made up of the following:
 | 
					             * to  its normal 260 bytes to be understood. The data block is made
 | 
				
			||||||
             * 
 | 
					             * up of the following:
 | 
				
			||||||
 | 
					             *
 | 
				
			||||||
             * Byte    $00 - data block ID ($07)
 | 
					             * Byte    $00 - data block ID ($07)
 | 
				
			||||||
             *      01-100 - 256 bytes data
 | 
					             *      01-100 - 256 bytes data
 | 
				
			||||||
             *      101 - data block checksum (EOR of $01-100)
 | 
					             *      101 - data block checksum (EOR of $01-100)
 | 
				
			||||||
             *      102-103 - $00 ("off" bytes, to make the sector size a multiple of 5)
 | 
					             *      102-103 - $00 ("off" bytes, to make the sector size a
 | 
				
			||||||
 | 
					             * multiple of 5)
 | 
				
			||||||
             */
 | 
					             */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            write_bits(bits, cursor, encode_data(C64_DATA_BLOCK_ID));
 | 
					            write_bits(bits, cursor, encode_data(C64_DATA_BLOCK_ID));
 | 
				
			||||||
@@ -353,29 +291,28 @@ private:
 | 
				
			|||||||
            for (i = 0; i < C64_SECTOR_LENGTH; i++)
 | 
					            for (i = 0; i < C64_SECTOR_LENGTH; i++)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                uint8_t val = br.read_8();
 | 
					                uint8_t val = br.read_8();
 | 
				
			||||||
                write_bits(bits, cursor, encode_data(val));     
 | 
					                write_bits(bits, cursor, encode_data(val));
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            write_bits(bits, cursor, encode_data(dataChecksum));
 | 
					            write_bits(bits, cursor, encode_data(dataChecksum));
 | 
				
			||||||
            write_bits(bits, cursor, encode_data(C64_PADDING));
 | 
					            write_bits(bits, cursor, encode_data(C64_PADDING));
 | 
				
			||||||
            write_bits(bits, cursor, encode_data(C64_PADDING));
 | 
					            write_bits(bits, cursor, encode_data(C64_PADDING));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            //6. Write inter-sector gap 9 - 12 bytes nor gcr
 | 
					            // 6. Write inter-sector gap 9 - 12 bytes nor gcr
 | 
				
			||||||
            for (int i=0; i<9; i++)
 | 
					            for (int i = 0; i < 9; i++)
 | 
				
			||||||
                write_bits(bits, cursor, C64_INTER_SECTOR_GAP, 1*8); /* sync */
 | 
					                write_bits(
 | 
				
			||||||
 | 
					                    bits, cursor, C64_INTER_SECTOR_GAP, 1 * 8); /* sync */
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
        
 | 
					
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
	const Commodore64EncoderProto& _config;
 | 
					    const Commodore64EncoderProto& _config;
 | 
				
			||||||
	uint8_t _formatByte1;
 | 
					    uint8_t _formatByte1;
 | 
				
			||||||
	uint8_t _formatByte2;
 | 
					    uint8_t _formatByte2;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
std::unique_ptr<AbstractEncoder> createCommodore64Encoder(const EncoderProto& config)
 | 
					std::unique_ptr<Encoder> createCommodore64Encoder(const EncoderProto& config)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return std::unique_ptr<AbstractEncoder>(new Commodore64Encoder(config));
 | 
					    return std::unique_ptr<Encoder>(new Commodore64Encoder(config));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// vim: sw=4 ts=4 et
 | 
					// vim: sw=4 ts=4 et
 | 
				
			||||||
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -13,16 +13,18 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
const FluxPattern SECTOR_RECORD_PATTERN(24, F85_SECTOR_RECORD);
 | 
					const FluxPattern SECTOR_RECORD_PATTERN(24, F85_SECTOR_RECORD);
 | 
				
			||||||
const FluxPattern DATA_RECORD_PATTERN(24, F85_DATA_RECORD);
 | 
					const FluxPattern DATA_RECORD_PATTERN(24, F85_DATA_RECORD);
 | 
				
			||||||
const FluxMatchers ANY_RECORD_PATTERN({ &SECTOR_RECORD_PATTERN, &DATA_RECORD_PATTERN });
 | 
					const FluxMatchers ANY_RECORD_PATTERN(
 | 
				
			||||||
 | 
					    {&SECTOR_RECORD_PATTERN, &DATA_RECORD_PATTERN});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int decode_data_gcr(uint8_t gcr)
 | 
					static int decode_data_gcr(uint8_t gcr)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    switch (gcr)
 | 
					    switch (gcr)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
		#define GCR_ENTRY(gcr, data) \
 | 
					#define GCR_ENTRY(gcr, data) \
 | 
				
			||||||
			case gcr: return data;
 | 
					    case gcr:                \
 | 
				
			||||||
		#include "data_gcr.h"
 | 
					        return data;
 | 
				
			||||||
		#undef GCR_ENTRY
 | 
					#include "data_gcr.h"
 | 
				
			||||||
 | 
					#undef GCR_ENTRY
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    return -1;
 | 
					    return -1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -37,11 +39,11 @@ static Bytes decode(const std::vector<bool>& bits)
 | 
				
			|||||||
    while (ii != bits.end())
 | 
					    while (ii != bits.end())
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        uint8_t inputfifo = 0;
 | 
					        uint8_t inputfifo = 0;
 | 
				
			||||||
        for (size_t i=0; i<5; i++)
 | 
					        for (size_t i = 0; i < 5; i++)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            if (ii == bits.end())
 | 
					            if (ii == bits.end())
 | 
				
			||||||
                break;
 | 
					                break;
 | 
				
			||||||
            inputfifo = (inputfifo<<1) | *ii++;
 | 
					            inputfifo = (inputfifo << 1) | *ii++;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        bitw.push(decode_data_gcr(inputfifo), 4);
 | 
					        bitw.push(decode_data_gcr(inputfifo), 4);
 | 
				
			||||||
@@ -51,63 +53,58 @@ static Bytes decode(const std::vector<bool>& bits)
 | 
				
			|||||||
    return output;
 | 
					    return output;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class DurangoF85Decoder : public AbstractDecoder
 | 
					class DurangoF85Decoder : public Decoder
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
	DurangoF85Decoder(const DecoderProto& config):
 | 
					    DurangoF85Decoder(const DecoderProto& config): Decoder(config) {}
 | 
				
			||||||
		AbstractDecoder(config)
 | 
					 | 
				
			||||||
	{}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    RecordType advanceToNextRecord()
 | 
					    nanoseconds_t advanceToNextRecord() override
 | 
				
			||||||
	{
 | 
					    {
 | 
				
			||||||
		const FluxMatcher* matcher = nullptr;
 | 
					        return seekToPattern(ANY_RECORD_PATTERN);
 | 
				
			||||||
		_sector->clock = _fmr->seekToPattern(ANY_RECORD_PATTERN, matcher);
 | 
					    }
 | 
				
			||||||
		if (matcher == &SECTOR_RECORD_PATTERN)
 | 
					 | 
				
			||||||
			return RecordType::SECTOR_RECORD;
 | 
					 | 
				
			||||||
		if (matcher == &DATA_RECORD_PATTERN)
 | 
					 | 
				
			||||||
			return RecordType::DATA_RECORD;
 | 
					 | 
				
			||||||
		return RecordType::UNKNOWN_RECORD;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void decodeSectorRecord()
 | 
					    void decodeSectorRecord() override
 | 
				
			||||||
	{
 | 
					    {
 | 
				
			||||||
		/* Skip sync bits and ID byte. */
 | 
					        /* Skip sync bits and ID byte. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		readRawBits(24);
 | 
					        if (readRaw24() != F85_SECTOR_RECORD)
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* Read header. */
 | 
					        /* Read header. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		const auto& bytes = decode(readRawBits(6*10));
 | 
					        const auto& bytes = decode(readRawBits(6 * 10));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		_sector->logicalSector = bytes[2];
 | 
					        _sector->logicalSector = bytes[2];
 | 
				
			||||||
		_sector->logicalSide = 0;
 | 
					        _sector->logicalSide = 0;
 | 
				
			||||||
		_sector->logicalTrack = bytes[0];
 | 
					        _sector->logicalTrack = bytes[0];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		uint16_t wantChecksum = bytes.reader().seek(4).read_be16();
 | 
					        uint16_t wantChecksum = bytes.reader().seek(4).read_be16();
 | 
				
			||||||
		uint16_t gotChecksum = crc16(CCITT_POLY, 0xef21, bytes.slice(0, 4));
 | 
					        uint16_t gotChecksum = crc16(CCITT_POLY, 0xef21, bytes.slice(0, 4));
 | 
				
			||||||
		if (wantChecksum == gotChecksum)
 | 
					        if (wantChecksum == gotChecksum)
 | 
				
			||||||
			_sector->status = Sector::DATA_MISSING; /* unintuitive but correct */
 | 
					            _sector->status =
 | 
				
			||||||
	}
 | 
					                Sector::DATA_MISSING; /* unintuitive but correct */
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void decodeDataRecord()
 | 
					    void decodeDataRecord() override
 | 
				
			||||||
	{
 | 
					    {
 | 
				
			||||||
		/* Skip sync bits ID byte. */
 | 
					        /* Skip sync bits ID byte. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		readRawBits(24);
 | 
					        if (readRaw24() != F85_DATA_RECORD)
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		const auto& bytes = decode(readRawBits((F85_SECTOR_LENGTH+3)*10))
 | 
					        const auto& bytes = decode(readRawBits((F85_SECTOR_LENGTH + 3) * 10))
 | 
				
			||||||
			.slice(0, F85_SECTOR_LENGTH+3);
 | 
					                                .slice(0, F85_SECTOR_LENGTH + 3);
 | 
				
			||||||
		ByteReader br(bytes);
 | 
					        ByteReader br(bytes);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		_sector->data = br.read(F85_SECTOR_LENGTH);
 | 
					        _sector->data = br.read(F85_SECTOR_LENGTH);
 | 
				
			||||||
		uint16_t wantChecksum = br.read_be16();
 | 
					        uint16_t wantChecksum = br.read_be16();
 | 
				
			||||||
		uint16_t gotChecksum = crc16(CCITT_POLY, 0xbf84, _sector->data);
 | 
					        uint16_t gotChecksum = crc16(CCITT_POLY, 0xbf84, _sector->data);
 | 
				
			||||||
		_sector->status = (wantChecksum == gotChecksum) ? Sector::OK : Sector::BAD_CHECKSUM;
 | 
					        _sector->status =
 | 
				
			||||||
	}
 | 
					            (wantChecksum == gotChecksum) ? Sector::OK : Sector::BAD_CHECKSUM;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
std::unique_ptr<AbstractDecoder> createDurangoF85Decoder(const DecoderProto& config)
 | 
					std::unique_ptr<Decoder> createDurangoF85Decoder(const DecoderProto& config)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return std::unique_ptr<AbstractDecoder>(new DurangoF85Decoder(config));
 | 
					    return std::unique_ptr<Decoder>(new DurangoF85Decoder(config));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,9 +2,10 @@
 | 
				
			|||||||
#define F85_H
 | 
					#define F85_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define F85_SECTOR_RECORD 0xffffce /* 1111 1111 1111 1111 1100 1110 */
 | 
					#define F85_SECTOR_RECORD 0xffffce /* 1111 1111 1111 1111 1100 1110 */
 | 
				
			||||||
#define F85_DATA_RECORD 0xffffcb /* 1111 1111 1111 1111 1100 1101 */
 | 
					#define F85_DATA_RECORD 0xffffcb   /* 1111 1111 1111 1111 1100 1101 */
 | 
				
			||||||
#define F85_SECTOR_LENGTH    512
 | 
					#define F85_SECTOR_LENGTH 512
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern std::unique_ptr<AbstractDecoder> createDurangoF85Decoder(const DecoderProto& config);
 | 
					extern std::unique_ptr<Decoder> createDurangoF85Decoder(
 | 
				
			||||||
 | 
					    const DecoderProto& config);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -14,10 +14,10 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
const FluxPattern SECTOR_ID_PATTERN(16, 0xabaa);
 | 
					const FluxPattern SECTOR_ID_PATTERN(16, 0xabaa);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* 
 | 
					/*
 | 
				
			||||||
 * Reverse engineered from a dump of the floppy drive's ROM. I have no idea how
 | 
					 * Reverse engineered from a dump of the floppy drive's ROM. I have no idea how
 | 
				
			||||||
 * it works.
 | 
					 * it works.
 | 
				
			||||||
 * 
 | 
					 *
 | 
				
			||||||
 * LF8BA:
 | 
					 * LF8BA:
 | 
				
			||||||
 *         clra
 | 
					 *         clra
 | 
				
			||||||
 *         staa    X00B0
 | 
					 *         staa    X00B0
 | 
				
			||||||
@@ -97,52 +97,46 @@ static uint16_t checksum(const Bytes& bytes)
 | 
				
			|||||||
    return (crchi << 8) | crclo;
 | 
					    return (crchi << 8) | crclo;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Fb100Decoder : public AbstractDecoder
 | 
					class Fb100Decoder : public Decoder
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
	Fb100Decoder(const DecoderProto& config):
 | 
					    Fb100Decoder(const DecoderProto& config): Decoder(config) {}
 | 
				
			||||||
		AbstractDecoder(config)
 | 
					 | 
				
			||||||
	{}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    RecordType advanceToNextRecord()
 | 
					    nanoseconds_t advanceToNextRecord() override
 | 
				
			||||||
	{
 | 
					    {
 | 
				
			||||||
		const FluxMatcher* matcher = nullptr;
 | 
					        return seekToPattern(SECTOR_ID_PATTERN);
 | 
				
			||||||
		_sector->clock = _fmr->seekToPattern(SECTOR_ID_PATTERN, matcher);
 | 
					    }
 | 
				
			||||||
		if (matcher == &SECTOR_ID_PATTERN)
 | 
					 | 
				
			||||||
			return RecordType::SECTOR_RECORD;
 | 
					 | 
				
			||||||
		return RecordType::UNKNOWN_RECORD;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void decodeSectorRecord()
 | 
					    void decodeSectorRecord() override
 | 
				
			||||||
	{
 | 
					    {
 | 
				
			||||||
		auto rawbits = readRawBits(FB100_RECORD_SIZE*16);
 | 
					        auto rawbits = readRawBits(FB100_RECORD_SIZE * 16);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		const Bytes bytes = decodeFmMfm(rawbits).slice(0, FB100_RECORD_SIZE);
 | 
					        const Bytes bytes = decodeFmMfm(rawbits).slice(0, FB100_RECORD_SIZE);
 | 
				
			||||||
		ByteReader br(bytes);
 | 
					        ByteReader br(bytes);
 | 
				
			||||||
		br.seek(1);
 | 
					        br.seek(1);
 | 
				
			||||||
		const Bytes id = br.read(FB100_ID_SIZE);
 | 
					        const Bytes id = br.read(FB100_ID_SIZE);
 | 
				
			||||||
		uint16_t wantIdCrc = br.read_be16();
 | 
					        uint16_t wantIdCrc = br.read_be16();
 | 
				
			||||||
		uint16_t gotIdCrc = checksum(id);
 | 
					        uint16_t gotIdCrc = checksum(id);
 | 
				
			||||||
		const Bytes payload = br.read(FB100_PAYLOAD_SIZE);
 | 
					        const Bytes payload = br.read(FB100_PAYLOAD_SIZE);
 | 
				
			||||||
		uint16_t wantPayloadCrc = br.read_be16();
 | 
					        uint16_t wantPayloadCrc = br.read_be16();
 | 
				
			||||||
		uint16_t gotPayloadCrc = checksum(payload);
 | 
					        uint16_t gotPayloadCrc = checksum(payload);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (wantIdCrc != gotIdCrc)
 | 
					        if (wantIdCrc != gotIdCrc)
 | 
				
			||||||
			return;
 | 
					            return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		uint8_t abssector = id[2];
 | 
					        uint8_t abssector = id[2];
 | 
				
			||||||
		_sector->logicalTrack = abssector >> 1;
 | 
					        _sector->logicalTrack = abssector >> 1;
 | 
				
			||||||
		_sector->logicalSide = 0;
 | 
					        _sector->logicalSide = 0;
 | 
				
			||||||
		_sector->logicalSector = abssector & 1;
 | 
					        _sector->logicalSector = abssector & 1;
 | 
				
			||||||
		_sector->data.writer().append(id.slice(5, 12)).append(payload);
 | 
					        _sector->data.writer().append(id.slice(5, 12)).append(payload);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		_sector->status = (wantPayloadCrc == gotPayloadCrc) ? Sector::OK : Sector::BAD_CHECKSUM;
 | 
					        _sector->status = (wantPayloadCrc == gotPayloadCrc)
 | 
				
			||||||
	}
 | 
					                              ? Sector::OK
 | 
				
			||||||
 | 
					                              : Sector::BAD_CHECKSUM;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
std::unique_ptr<AbstractDecoder> createFb100Decoder(const DecoderProto& config)
 | 
					std::unique_ptr<Decoder> createFb100Decoder(const DecoderProto& config)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return std::unique_ptr<AbstractDecoder>(new Fb100Decoder(config));
 | 
					    return std::unique_ptr<Decoder>(new Fb100Decoder(config));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,7 +5,6 @@
 | 
				
			|||||||
#define FB100_ID_SIZE 17
 | 
					#define FB100_ID_SIZE 17
 | 
				
			||||||
#define FB100_PAYLOAD_SIZE 0x500
 | 
					#define FB100_PAYLOAD_SIZE 0x500
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern std::unique_ptr<AbstractDecoder> createFb100Decoder(const DecoderProto& config);
 | 
					extern std::unique_ptr<Decoder> createFb100Decoder(const DecoderProto& config);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,24 +7,25 @@
 | 
				
			|||||||
#include "sector.h"
 | 
					#include "sector.h"
 | 
				
			||||||
#include "arch/ibm/ibm.pb.h"
 | 
					#include "arch/ibm/ibm.pb.h"
 | 
				
			||||||
#include "proto.h"
 | 
					#include "proto.h"
 | 
				
			||||||
 | 
					#include "lib/layout.h"
 | 
				
			||||||
#include <string.h>
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static_assert(std::is_trivially_copyable<IbmIdam>::value,
 | 
					static_assert(std::is_trivially_copyable<IbmIdam>::value,
 | 
				
			||||||
		"IbmIdam is not trivially copyable");
 | 
					    "IbmIdam is not trivially copyable");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * The markers at the beginning of records are special, and have
 | 
					 * The markers at the beginning of records are special, and have
 | 
				
			||||||
 * missing clock pulses, allowing them to be found by the logic.
 | 
					 * missing clock pulses, allowing them to be found by the logic.
 | 
				
			||||||
 * 
 | 
					 *
 | 
				
			||||||
 * IAM record:
 | 
					 * IAM record:
 | 
				
			||||||
 * flux:   XXXX-XXX-XXXX-X- = 0xf77a
 | 
					 * flux:   XXXX-XXX-XXXX-X- = 0xf77a
 | 
				
			||||||
 * clock:  X X - X - X X X  = 0xd7
 | 
					 * clock:  X X - X - X X X  = 0xd7
 | 
				
			||||||
 * data:    X X X X X X - - = 0xfc
 | 
					 * data:    X X X X X X - - = 0xfc
 | 
				
			||||||
 * 
 | 
					 *
 | 
				
			||||||
 * (We just ignore this one --- it's useless and optional.)
 | 
					 * (We just ignore this one --- it's useless and optional.)
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* 
 | 
					/*
 | 
				
			||||||
 * IDAM record:
 | 
					 * IDAM record:
 | 
				
			||||||
 * flux:   XXXX-X-X-XXXXXX- = 0xf57e
 | 
					 * flux:   XXXX-X-X-XXXXXX- = 0xf57e
 | 
				
			||||||
 * clock:  X X - - - X X X  = 0xc7
 | 
					 * clock:  X X - - - X X X  = 0xc7
 | 
				
			||||||
@@ -32,7 +33,7 @@ static_assert(std::is_trivially_copyable<IbmIdam>::value,
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
const FluxPattern FM_IDAM_PATTERN(16, 0xf57e);
 | 
					const FluxPattern FM_IDAM_PATTERN(16, 0xf57e);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* 
 | 
					/*
 | 
				
			||||||
 * DAM1 record:
 | 
					 * DAM1 record:
 | 
				
			||||||
 * flux:   XXXX-X-X-XX-X-X- = 0xf56a
 | 
					 * flux:   XXXX-X-X-XX-X-X- = 0xf56a
 | 
				
			||||||
 * clock:  X X - - - X X X  = 0xc7
 | 
					 * clock:  X X - - - X X X  = 0xc7
 | 
				
			||||||
@@ -40,7 +41,7 @@ const FluxPattern FM_IDAM_PATTERN(16, 0xf57e);
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
const FluxPattern FM_DAM1_PATTERN(16, 0xf56a);
 | 
					const FluxPattern FM_DAM1_PATTERN(16, 0xf56a);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* 
 | 
					/*
 | 
				
			||||||
 * DAM2 record:
 | 
					 * DAM2 record:
 | 
				
			||||||
 * flux:   XXXX-X-X-XX-XXXX = 0xf56f
 | 
					 * flux:   XXXX-X-X-XX-XXXX = 0xf56f
 | 
				
			||||||
 * clock:  X X - - - X X X  = 0xc7
 | 
					 * clock:  X X - - - X X X  = 0xc7
 | 
				
			||||||
@@ -48,7 +49,7 @@ const FluxPattern FM_DAM1_PATTERN(16, 0xf56a);
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
const FluxPattern FM_DAM2_PATTERN(16, 0xf56f);
 | 
					const FluxPattern FM_DAM2_PATTERN(16, 0xf56f);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* 
 | 
					/*
 | 
				
			||||||
 * TRS80DAM1 record:
 | 
					 * TRS80DAM1 record:
 | 
				
			||||||
 * flux:   XXXX-X-X-XX-X-XX = 0xf56b
 | 
					 * flux:   XXXX-X-X-XX-X-XX = 0xf56b
 | 
				
			||||||
 * clock:  X X - - - X X X  = 0xc7
 | 
					 * clock:  X X - - - X X X  = 0xc7
 | 
				
			||||||
@@ -56,7 +57,7 @@ const FluxPattern FM_DAM2_PATTERN(16, 0xf56f);
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
const FluxPattern FM_TRS80DAM1_PATTERN(16, 0xf56b);
 | 
					const FluxPattern FM_TRS80DAM1_PATTERN(16, 0xf56b);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* 
 | 
					/*
 | 
				
			||||||
 * TRS80DAM2 record:
 | 
					 * TRS80DAM2 record:
 | 
				
			||||||
 * flux:   XXXX-X-X-XX-XXX- = 0xf56e
 | 
					 * flux:   XXXX-X-X-XX-XXX- = 0xf56e
 | 
				
			||||||
 * clock:  X X - - - X X X  = 0xc7
 | 
					 * clock:  X X - - - X X X  = 0xc7
 | 
				
			||||||
@@ -72,122 +73,178 @@ const FluxPattern FM_TRS80DAM2_PATTERN(16, 0xf56e);
 | 
				
			|||||||
 *                       ^^^^^
 | 
					 *                       ^^^^^
 | 
				
			||||||
 * When shifted out of phase, the special 0xa1 byte becomes an illegal
 | 
					 * When shifted out of phase, the special 0xa1 byte becomes an illegal
 | 
				
			||||||
 * encoding (you can't do 10 00). So this can't be spoofed by user data.
 | 
					 * encoding (you can't do 10 00). So this can't be spoofed by user data.
 | 
				
			||||||
 * 
 | 
					 *
 | 
				
			||||||
 * shifted: 10 00 10 01 00 01 00 1
 | 
					 * shifted: 10 00 10 01 00 01 00 1
 | 
				
			||||||
 * 
 | 
					 *
 | 
				
			||||||
 * It's repeated three times.
 | 
					 * It's repeated three times.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
const FluxPattern MFM_PATTERN(48, 0x448944894489LL);
 | 
					const FluxPattern MFM_PATTERN(48, 0x448944894489LL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const FluxMatchers ANY_RECORD_PATTERN(
 | 
					const FluxMatchers ANY_RECORD_PATTERN({
 | 
				
			||||||
    {
 | 
					    &MFM_PATTERN,
 | 
				
			||||||
        &MFM_PATTERN,
 | 
					    &FM_IDAM_PATTERN,
 | 
				
			||||||
        &FM_IDAM_PATTERN,
 | 
					    &FM_DAM1_PATTERN,
 | 
				
			||||||
        &FM_DAM1_PATTERN,
 | 
					    &FM_DAM2_PATTERN,
 | 
				
			||||||
        &FM_DAM2_PATTERN,
 | 
					    &FM_TRS80DAM1_PATTERN,
 | 
				
			||||||
        &FM_TRS80DAM1_PATTERN,
 | 
					    &FM_TRS80DAM2_PATTERN,
 | 
				
			||||||
        &FM_TRS80DAM2_PATTERN,
 | 
					});
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
class IbmDecoder : public AbstractDecoder
 | 
					class IbmDecoder : public Decoder
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
    IbmDecoder(const DecoderProto& config):
 | 
					    IbmDecoder(const DecoderProto& config):
 | 
				
			||||||
		AbstractDecoder(config),
 | 
					        Decoder(config),
 | 
				
			||||||
		_config(config.ibm())
 | 
					        _config(config.ibm())
 | 
				
			||||||
    {}
 | 
					    {
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    RecordType advanceToNextRecord() override
 | 
					    nanoseconds_t advanceToNextRecord() override
 | 
				
			||||||
	{
 | 
					    {
 | 
				
			||||||
		const FluxMatcher* matcher = nullptr;
 | 
					        return seekToPattern(ANY_RECORD_PATTERN);
 | 
				
			||||||
		_sector->clock = _fmr->seekToPattern(ANY_RECORD_PATTERN, matcher);
 | 
					    }
 | 
				
			||||||
 | 
					 | 
				
			||||||
		/* If this is the MFM prefix byte, the the decoder is going to expect three
 | 
					 | 
				
			||||||
		 * extra bytes on the front of the header. */
 | 
					 | 
				
			||||||
		_currentHeaderLength = (matcher == &MFM_PATTERN) ? 3 : 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		Fluxmap::Position here = tell();
 | 
					 | 
				
			||||||
		resetFluxDecoder();
 | 
					 | 
				
			||||||
		if (_currentHeaderLength > 0)
 | 
					 | 
				
			||||||
			readRawBits(_currentHeaderLength*16);
 | 
					 | 
				
			||||||
		auto idbits = readRawBits(16);
 | 
					 | 
				
			||||||
		const Bytes idbytes = decodeFmMfm(idbits);
 | 
					 | 
				
			||||||
		uint8_t id = idbytes.slice(0, 1)[0];
 | 
					 | 
				
			||||||
		seek(here);
 | 
					 | 
				
			||||||
		
 | 
					 | 
				
			||||||
		switch (id)
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			case IBM_IDAM:
 | 
					 | 
				
			||||||
				return RecordType::SECTOR_RECORD;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			case IBM_DAM1:
 | 
					 | 
				
			||||||
			case IBM_DAM2:
 | 
					 | 
				
			||||||
			case IBM_TRS80DAM1:
 | 
					 | 
				
			||||||
			case IBM_TRS80DAM2:
 | 
					 | 
				
			||||||
				return RecordType::DATA_RECORD;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		return RecordType::UNKNOWN_RECORD;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void decodeSectorRecord() override
 | 
					    void decodeSectorRecord() override
 | 
				
			||||||
	{
 | 
					    {
 | 
				
			||||||
		unsigned recordSize = _currentHeaderLength + IBM_IDAM_LEN;
 | 
					        /* This is really annoying because the IBM record scheme has a
 | 
				
			||||||
		auto bits = readRawBits(recordSize*16);
 | 
					         * variable-sized header _and_ the checksum covers this header too. So
 | 
				
			||||||
		auto bytes = decodeFmMfm(bits).slice(0, recordSize);
 | 
					         * we have to read and decode a byte at a time until we know where the
 | 
				
			||||||
 | 
					         * record itself starts, saving the bytes for the checksumming later.
 | 
				
			||||||
 | 
					         */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		ByteReader br(bytes);
 | 
					        Bytes bytes;
 | 
				
			||||||
		br.seek(_currentHeaderLength);
 | 
					        ByteWriter bw(bytes);
 | 
				
			||||||
		br.read_8(); /* skip ID byte */
 | 
					 | 
				
			||||||
		_sector->logicalTrack = br.read_8();
 | 
					 | 
				
			||||||
		_sector->logicalSide = br.read_8();
 | 
					 | 
				
			||||||
		_sector->logicalSector = br.read_8();
 | 
					 | 
				
			||||||
		_currentSectorSize = 1 << (br.read_8() + 7);
 | 
					 | 
				
			||||||
		uint16_t wantCrc = br.read_be16();
 | 
					 | 
				
			||||||
		uint16_t gotCrc = crc16(CCITT_POLY, bytes.slice(0, _currentHeaderLength + 5));
 | 
					 | 
				
			||||||
		if (wantCrc == gotCrc)
 | 
					 | 
				
			||||||
			_sector->status = Sector::DATA_MISSING; /* correct but unintuitive */
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (_config.swap_sides())
 | 
					        auto readByte = [&]()
 | 
				
			||||||
			_sector->logicalSide ^= 1;
 | 
					        {
 | 
				
			||||||
		if (_config.ignore_side_byte())
 | 
					            auto bits = readRawBits(16);
 | 
				
			||||||
			_sector->logicalSide = _sector->physicalHead;
 | 
					            auto bytes = decodeFmMfm(bits).slice(0, 1);
 | 
				
			||||||
		if (_config.ignore_track_byte())
 | 
					            uint8_t byte = bytes[0];
 | 
				
			||||||
			_sector->logicalTrack = _sector->physicalCylinder;
 | 
					            bw.write_8(byte);
 | 
				
			||||||
	}
 | 
					            return byte;
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        uint8_t id = readByte();
 | 
				
			||||||
 | 
					        if (id == 0xa1)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            readByte();
 | 
				
			||||||
 | 
					            readByte();
 | 
				
			||||||
 | 
					            id = readByte();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (id != IBM_IDAM)
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        ByteReader br(bytes);
 | 
				
			||||||
 | 
					        br.seek(bw.pos);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        auto bits = readRawBits(IBM_IDAM_LEN * 16);
 | 
				
			||||||
 | 
					        bw += decodeFmMfm(bits).slice(0, IBM_IDAM_LEN);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        IbmDecoderProto::TrackdataProto trackdata;
 | 
				
			||||||
 | 
					        getTrackFormat(
 | 
				
			||||||
 | 
					            trackdata, _sector->physicalTrack, _sector->physicalSide);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        _sector->logicalTrack = br.read_8();
 | 
				
			||||||
 | 
					        _sector->logicalSide = br.read_8();
 | 
				
			||||||
 | 
					        _sector->logicalSector = br.read_8();
 | 
				
			||||||
 | 
					        _currentSectorSize = 1 << (br.read_8() + 7);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        uint16_t gotCrc = crc16(CCITT_POLY, bytes.slice(0, br.pos));
 | 
				
			||||||
 | 
					        uint16_t wantCrc = br.read_be16();
 | 
				
			||||||
 | 
					        if (wantCrc == gotCrc)
 | 
				
			||||||
 | 
					            _sector->status =
 | 
				
			||||||
 | 
					                Sector::DATA_MISSING; /* correct but unintuitive */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (trackdata.ignore_side_byte())
 | 
				
			||||||
 | 
					            _sector->logicalSide =
 | 
				
			||||||
 | 
					                Layout::remapSidePhysicalToLogical(_sector->physicalSide);
 | 
				
			||||||
 | 
					        _sector->logicalSide ^= trackdata.invert_side_byte();
 | 
				
			||||||
 | 
					        if (trackdata.ignore_track_byte())
 | 
				
			||||||
 | 
					            _sector->logicalTrack = _sector->physicalTrack;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for (int sector : trackdata.ignore_sector())
 | 
				
			||||||
 | 
					            if (_sector->logicalSector == sector)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                _sector->status = Sector::MISSING;
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void decodeDataRecord() override
 | 
					    void decodeDataRecord() override
 | 
				
			||||||
	{
 | 
					    {
 | 
				
			||||||
		unsigned recordLength = _currentHeaderLength + _currentSectorSize + 3;
 | 
					        /* This is the same deal as the sector record. */
 | 
				
			||||||
		auto bits = readRawBits(recordLength*16);
 | 
					 | 
				
			||||||
		auto bytes = decodeFmMfm(bits).slice(0, recordLength);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		ByteReader br(bytes);
 | 
					        Bytes bytes;
 | 
				
			||||||
		br.seek(_currentHeaderLength);
 | 
					        ByteWriter bw(bytes);
 | 
				
			||||||
		br.read_8(); /* skip ID byte */
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		_sector->data = br.read(_currentSectorSize);
 | 
					        auto readByte = [&]()
 | 
				
			||||||
		uint16_t wantCrc = br.read_be16();
 | 
					        {
 | 
				
			||||||
		uint16_t gotCrc = crc16(CCITT_POLY, bytes.slice(0, recordLength-2));
 | 
					            auto bits = readRawBits(16);
 | 
				
			||||||
		_sector->status = (wantCrc == gotCrc) ? Sector::OK : Sector::BAD_CHECKSUM;
 | 
					            auto bytes = decodeFmMfm(bits).slice(0, 1);
 | 
				
			||||||
	}
 | 
					            uint8_t byte = bytes[0];
 | 
				
			||||||
 | 
					            bw.write_8(byte);
 | 
				
			||||||
 | 
					            return byte;
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	std::set<unsigned> requiredSectors(unsigned cylinder, unsigned head) const override
 | 
					        uint8_t id = readByte();
 | 
				
			||||||
	{
 | 
					        if (id == 0xa1)
 | 
				
			||||||
		std::set<unsigned> s;
 | 
					        {
 | 
				
			||||||
		for (int sectorId : _config.sectors().sector())
 | 
					            readByte();
 | 
				
			||||||
			s.insert(sectorId);
 | 
					            readByte();
 | 
				
			||||||
		return s;
 | 
					            id = readByte();
 | 
				
			||||||
	}
 | 
					        }
 | 
				
			||||||
 | 
					        if ((id != IBM_DAM1) && (id != IBM_DAM2) && (id != IBM_TRS80DAM1) &&
 | 
				
			||||||
 | 
					            (id != IBM_TRS80DAM2))
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        ByteReader br(bytes);
 | 
				
			||||||
 | 
					        br.seek(bw.pos);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        auto bits = readRawBits((_currentSectorSize + 2) * 16);
 | 
				
			||||||
 | 
					        bw += decodeFmMfm(bits).slice(0, _currentSectorSize + 2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        _sector->data = br.read(_currentSectorSize);
 | 
				
			||||||
 | 
					        uint16_t gotCrc = crc16(CCITT_POLY, bytes.slice(0, br.pos));
 | 
				
			||||||
 | 
					        uint16_t wantCrc = br.read_be16();
 | 
				
			||||||
 | 
					        _sector->status =
 | 
				
			||||||
 | 
					            (wantCrc == gotCrc) ? Sector::OK : Sector::BAD_CHECKSUM;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        auto layout = Layout::getLayoutOfTrack(
 | 
				
			||||||
 | 
					            _sector->logicalTrack, _sector->logicalSide);
 | 
				
			||||||
 | 
					        if (_currentSectorSize != layout->sectorSize)
 | 
				
			||||||
 | 
					            std::cerr << fmt::format(
 | 
				
			||||||
 | 
					                "Warning: configured sector size for t{}.h{}.s{} is {} bytes "
 | 
				
			||||||
 | 
					                "but that seen on disk is {} bytes\n",
 | 
				
			||||||
 | 
					                _sector->logicalTrack,
 | 
				
			||||||
 | 
					                _sector->logicalSide,
 | 
				
			||||||
 | 
					                _sector->logicalSector,
 | 
				
			||||||
 | 
					                layout->sectorSize,
 | 
				
			||||||
 | 
					                _currentSectorSize);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
	const IbmDecoderProto& _config;
 | 
					    void getTrackFormat(IbmDecoderProto::TrackdataProto& trackdata,
 | 
				
			||||||
 | 
					        unsigned track,
 | 
				
			||||||
 | 
					        unsigned head) const
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        trackdata.Clear();
 | 
				
			||||||
 | 
					        for (const auto& f : _config.trackdata())
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (f.has_track() && (f.track() != track))
 | 
				
			||||||
 | 
					                continue;
 | 
				
			||||||
 | 
					            if (f.has_head() && (f.head() != head))
 | 
				
			||||||
 | 
					                continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            trackdata.MergeFrom(f);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private:
 | 
				
			||||||
 | 
					    const IbmDecoderProto& _config;
 | 
				
			||||||
    unsigned _currentSectorSize;
 | 
					    unsigned _currentSectorSize;
 | 
				
			||||||
    unsigned _currentHeaderLength;
 | 
					    unsigned _currentHeaderLength;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
std::unique_ptr<AbstractDecoder> createIbmDecoder(const DecoderProto& config)
 | 
					std::unique_ptr<Decoder> createIbmDecoder(const DecoderProto& config)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return std::unique_ptr<AbstractDecoder>(new IbmDecoder(config));
 | 
					    return std::unique_ptr<Decoder>(new IbmDecoder(config));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,11 +3,13 @@
 | 
				
			|||||||
#include "encoders/encoders.h"
 | 
					#include "encoders/encoders.h"
 | 
				
			||||||
#include "ibm.h"
 | 
					#include "ibm.h"
 | 
				
			||||||
#include "crc.h"
 | 
					#include "crc.h"
 | 
				
			||||||
#include "writer.h"
 | 
					#include "readerwriter.h"
 | 
				
			||||||
#include "image.h"
 | 
					#include "image.h"
 | 
				
			||||||
#include "arch/ibm/ibm.pb.h"
 | 
					#include "arch/ibm/ibm.pb.h"
 | 
				
			||||||
#include "lib/encoders/encoders.pb.h"
 | 
					#include "lib/encoders/encoders.pb.h"
 | 
				
			||||||
#include "fmt/format.h"
 | 
					#include "fmt/format.h"
 | 
				
			||||||
 | 
					#include "lib/proto.h"
 | 
				
			||||||
 | 
					#include "lib/layout.h"
 | 
				
			||||||
#include <ctype.h>
 | 
					#include <ctype.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* IAM record separator:
 | 
					/* IAM record separator:
 | 
				
			||||||
@@ -39,9 +41,9 @@
 | 
				
			|||||||
 *                       ^^^^^
 | 
					 *                       ^^^^^
 | 
				
			||||||
 * When shifted out of phase, the special 0xa1 byte becomes an illegal
 | 
					 * When shifted out of phase, the special 0xa1 byte becomes an illegal
 | 
				
			||||||
 * encoding (you can't do 10 00). So this can't be spoofed by user data.
 | 
					 * encoding (you can't do 10 00). So this can't be spoofed by user data.
 | 
				
			||||||
 * 
 | 
					 *
 | 
				
			||||||
 * shifted: 10 00 10 01 00 01 00 1
 | 
					 * shifted: 10 00 10 01 00 01 00 1
 | 
				
			||||||
 * 
 | 
					 *
 | 
				
			||||||
 * It's repeated three times.
 | 
					 * It's repeated three times.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
#define MFM_RECORD_SEPARATOR 0x4489
 | 
					#define MFM_RECORD_SEPARATOR 0x4489
 | 
				
			||||||
@@ -59,228 +61,222 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
static uint8_t decodeUint16(uint16_t raw)
 | 
					static uint8_t decodeUint16(uint16_t raw)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	Bytes b;
 | 
					    Bytes b;
 | 
				
			||||||
	ByteWriter bw(b);
 | 
					    ByteWriter bw(b);
 | 
				
			||||||
	bw.write_be16(raw);
 | 
					    bw.write_be16(raw);
 | 
				
			||||||
	return decodeFmMfm(b.toBits())[0];
 | 
					    return decodeFmMfm(b.toBits())[0];
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class IbmEncoder : public AbstractEncoder
 | 
					class IbmEncoder : public Encoder
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
	IbmEncoder(const EncoderProto& config):
 | 
					    IbmEncoder(const EncoderProto& config):
 | 
				
			||||||
		AbstractEncoder(config),
 | 
					        Encoder(config),
 | 
				
			||||||
		_config(config.ibm())
 | 
					        _config(config.ibm())
 | 
				
			||||||
	{}
 | 
					    {
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
	void writeRawBits(uint32_t data, int width)
 | 
					    void writeRawBits(uint32_t data, int width)
 | 
				
			||||||
	{
 | 
					    {
 | 
				
			||||||
		_cursor += width;
 | 
					        _cursor += width;
 | 
				
			||||||
		_lastBit = data & 1;
 | 
					        _lastBit = data & 1;
 | 
				
			||||||
		for (int i=0; i<width; i++)
 | 
					        for (int i = 0; i < width; i++)
 | 
				
			||||||
		{
 | 
					        {
 | 
				
			||||||
			unsigned pos = _cursor - i - 1;
 | 
					            unsigned pos = _cursor - i - 1;
 | 
				
			||||||
			if (pos < _bits.size())
 | 
					            if (pos < _bits.size())
 | 
				
			||||||
				_bits[pos] = data & 1;
 | 
					                _bits[pos] = data & 1;
 | 
				
			||||||
			data >>= 1;
 | 
					            data >>= 1;
 | 
				
			||||||
		}
 | 
					        }
 | 
				
			||||||
	}
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void getTrackFormat(IbmEncoderProto::TrackdataProto& trackdata, unsigned cylinder, unsigned head)
 | 
					    void getEncoderTrackData(IbmEncoderProto::TrackdataProto& trackdata,
 | 
				
			||||||
	{
 | 
					        unsigned track,
 | 
				
			||||||
		trackdata.Clear();
 | 
					        unsigned head)
 | 
				
			||||||
		for (const auto& f : _config.trackdata())
 | 
					    {
 | 
				
			||||||
		{
 | 
					        trackdata.Clear();
 | 
				
			||||||
			if (f.has_cylinder() && (f.cylinder() != cylinder))
 | 
					        for (const auto& f : _config.trackdata())
 | 
				
			||||||
				continue;
 | 
					        {
 | 
				
			||||||
			if (f.has_head() && (f.head() != head))
 | 
					            if (f.has_track() && (f.track() != track))
 | 
				
			||||||
				continue;
 | 
					                continue;
 | 
				
			||||||
 | 
					            if (f.has_head() && (f.head() != head))
 | 
				
			||||||
 | 
					                continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			trackdata.MergeFrom(f);
 | 
					            trackdata.MergeFrom(f);
 | 
				
			||||||
		}
 | 
					        }
 | 
				
			||||||
	}
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
	std::vector<std::shared_ptr<Sector>> collectSectors(int physicalTrack, int physicalSide, const Image& image) override
 | 
					    std::unique_ptr<Fluxmap> encode(std::shared_ptr<const TrackInfo>& trackInfo,
 | 
				
			||||||
	{
 | 
					        const std::vector<std::shared_ptr<const Sector>>& sectors,
 | 
				
			||||||
		std::vector<std::shared_ptr<Sector>> sectors;
 | 
					        const Image& image) override
 | 
				
			||||||
		IbmEncoderProto::TrackdataProto trackdata;
 | 
					    {
 | 
				
			||||||
		getTrackFormat(trackdata, physicalTrack, physicalSide);
 | 
					        IbmEncoderProto::TrackdataProto trackdata;
 | 
				
			||||||
 | 
					        getEncoderTrackData(
 | 
				
			||||||
 | 
					            trackdata, trackInfo->logicalTrack, trackInfo->logicalSide);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		int logicalSide = physicalSide ^ trackdata.swap_sides();
 | 
					        auto trackLayout = Layout::getLayoutOfTrack(
 | 
				
			||||||
		for (int sectorId : trackdata.sectors().sector())
 | 
					            trackInfo->logicalTrack, trackInfo->logicalSide);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        auto writeBytes = [&](const Bytes& bytes)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
			const auto& sector = image.get(physicalTrack, logicalSide, sectorId);
 | 
					            if (trackdata.use_fm())
 | 
				
			||||||
			if (sector)
 | 
					                encodeFm(_bits, _cursor, bytes);
 | 
				
			||||||
				sectors.push_back(sector);
 | 
					            else
 | 
				
			||||||
 | 
					                encodeMfm(_bits, _cursor, bytes, _lastBit);
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        auto writeFillerRawBytes = [&](int count, uint16_t byte)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            for (int i = 0; i < count; i++)
 | 
				
			||||||
 | 
					                writeRawBits(byte, 16);
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        auto writeFillerBytes = [&](int count, uint8_t byte)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            Bytes b{byte};
 | 
				
			||||||
 | 
					            for (int i = 0; i < count; i++)
 | 
				
			||||||
 | 
					                writeBytes(b);
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        double clockRateUs = trackdata.target_clock_period_us();
 | 
				
			||||||
 | 
					        if (!trackdata.use_fm())
 | 
				
			||||||
 | 
					            clockRateUs /= 2.0;
 | 
				
			||||||
 | 
					        int bitsPerRevolution =
 | 
				
			||||||
 | 
					            (trackdata.target_rotational_period_ms() * 1000.0) / clockRateUs;
 | 
				
			||||||
 | 
					        _bits.resize(bitsPerRevolution);
 | 
				
			||||||
 | 
					        _cursor = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        uint8_t idamUnencoded = decodeUint16(trackdata.idam_byte());
 | 
				
			||||||
 | 
					        uint8_t damUnencoded = decodeUint16(trackdata.dam_byte());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        uint8_t sectorSize = 0;
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            int s = trackLayout->sectorSize >> 7;
 | 
				
			||||||
 | 
					            while (s > 1)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                s >>= 1;
 | 
				
			||||||
 | 
					                sectorSize += 1;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		return sectors;
 | 
					        uint16_t gapFill = trackdata.gap_fill_byte();
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    std::unique_ptr<Fluxmap> encode(int physicalTrack, int physicalSide,
 | 
					        writeFillerRawBytes(trackdata.gap0(), gapFill);
 | 
				
			||||||
			const std::vector<std::shared_ptr<Sector>>& sectors, const Image& image) override
 | 
					        if (trackdata.emit_iam())
 | 
				
			||||||
	{
 | 
					        {
 | 
				
			||||||
		IbmEncoderProto::TrackdataProto trackdata;
 | 
					            writeFillerBytes(trackdata.use_fm() ? 6 : 12, 0x00);
 | 
				
			||||||
		getTrackFormat(trackdata, physicalTrack, physicalSide);
 | 
					            if (!trackdata.use_fm())
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                for (int i = 0; i < 3; i++)
 | 
				
			||||||
 | 
					                    writeRawBits(MFM_IAM_SEPARATOR, 16);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            writeRawBits(
 | 
				
			||||||
 | 
					                trackdata.use_fm() ? FM_IAM_RECORD : MFM_IAM_RECORD, 16);
 | 
				
			||||||
 | 
					            writeFillerRawBytes(trackdata.gap1(), gapFill);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		auto writeBytes = [&](const Bytes& bytes)
 | 
					        bool first = true;
 | 
				
			||||||
		{
 | 
					        for (const auto& sectorData : sectors)
 | 
				
			||||||
			if (trackdata.use_fm())
 | 
					        {
 | 
				
			||||||
				encodeFm(_bits, _cursor, bytes);
 | 
					            if (!first)
 | 
				
			||||||
			else
 | 
					                writeFillerRawBytes(trackdata.gap3(), gapFill);
 | 
				
			||||||
				encodeMfm(_bits, _cursor, bytes, _lastBit);
 | 
					            first = false;
 | 
				
			||||||
		};
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		auto writeFillerBytes = [&](int count, uint8_t byte)
 | 
					            /* Writing the sector and data records are fantastically annoying.
 | 
				
			||||||
		{
 | 
					             * The CRC is calculated from the *very start* of the record, and
 | 
				
			||||||
			Bytes bytes = { byte };
 | 
					             * include the malformed marker bytes. Our encoder doesn't know
 | 
				
			||||||
			for (int i=0; i<count; i++)
 | 
					             * about this, of course, with the result that we have to construct
 | 
				
			||||||
				writeBytes(bytes);
 | 
					             * the unencoded header, calculate the checksum, and then use the
 | 
				
			||||||
		};
 | 
					             * same logic to emit the bytes which require special encoding
 | 
				
			||||||
 | 
					             * before encoding the rest of the header normally. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		double clockRateUs = 1e3 / trackdata.clock_rate_khz();
 | 
					            {
 | 
				
			||||||
		if (!trackdata.use_fm())
 | 
					                Bytes header;
 | 
				
			||||||
			clockRateUs /= 2.0;
 | 
					                ByteWriter bw(header);
 | 
				
			||||||
		int bitsPerRevolution = (trackdata.track_length_ms() * 1000.0) / clockRateUs;
 | 
					 | 
				
			||||||
		_bits.resize(bitsPerRevolution);
 | 
					 | 
				
			||||||
		_cursor = 0;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		uint8_t idamUnencoded = decodeUint16(trackdata.idam_byte());
 | 
					                writeFillerBytes(trackdata.use_fm() ? 6 : 12, 0x00);
 | 
				
			||||||
		uint8_t damUnencoded = decodeUint16(trackdata.dam_byte());
 | 
					                if (!trackdata.use_fm())
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    for (int i = 0; i < 3; i++)
 | 
				
			||||||
 | 
					                        bw.write_8(MFM_RECORD_SEPARATOR_BYTE);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                bw.write_8(idamUnencoded);
 | 
				
			||||||
 | 
					                bw.write_8(sectorData->logicalTrack);
 | 
				
			||||||
 | 
					                bw.write_8(
 | 
				
			||||||
 | 
					                    sectorData->logicalSide ^ trackdata.invert_side_byte());
 | 
				
			||||||
 | 
					                bw.write_8(sectorData->logicalSector);
 | 
				
			||||||
 | 
					                bw.write_8(sectorSize);
 | 
				
			||||||
 | 
					                uint16_t crc = crc16(CCITT_POLY, header);
 | 
				
			||||||
 | 
					                bw.write_be16(crc);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		uint8_t sectorSize = 0;
 | 
					                int conventionalHeaderStart = 0;
 | 
				
			||||||
		{
 | 
					                if (!trackdata.use_fm())
 | 
				
			||||||
			int s = trackdata.sector_size() >> 7;
 | 
					                {
 | 
				
			||||||
			while (s > 1)
 | 
					                    for (int i = 0; i < 3; i++)
 | 
				
			||||||
			{
 | 
					                        writeRawBits(MFM_RECORD_SEPARATOR, 16);
 | 
				
			||||||
				s >>= 1;
 | 
					                    conventionalHeaderStart += 3;
 | 
				
			||||||
				sectorSize += 1;
 | 
					                }
 | 
				
			||||||
			}
 | 
					                writeRawBits(trackdata.idam_byte(), 16);
 | 
				
			||||||
		}
 | 
					                conventionalHeaderStart += 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		uint8_t gapFill = trackdata.use_fm() ? 0x00 : 0x4e;
 | 
					                writeBytes(header.slice(conventionalHeaderStart));
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		writeFillerBytes(trackdata.gap0(), gapFill);
 | 
					            writeFillerRawBytes(trackdata.gap2(), gapFill);
 | 
				
			||||||
		if (trackdata.emit_iam())
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			writeFillerBytes(trackdata.use_fm() ? 6 : 12, 0x00);
 | 
					 | 
				
			||||||
			if (!trackdata.use_fm())
 | 
					 | 
				
			||||||
			{
 | 
					 | 
				
			||||||
				for (int i=0; i<3; i++)
 | 
					 | 
				
			||||||
					writeRawBits(MFM_IAM_SEPARATOR, 16);
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			writeRawBits(trackdata.use_fm() ? FM_IAM_RECORD : MFM_IAM_RECORD, 16);
 | 
					 | 
				
			||||||
			writeFillerBytes(trackdata.gap1(), gapFill);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		int logicalSide = physicalSide ^ trackdata.swap_sides();
 | 
					            {
 | 
				
			||||||
		bool first = true;
 | 
					                Bytes data;
 | 
				
			||||||
		for (int sectorId : trackdata.sectors().sector())
 | 
					                ByteWriter bw(data);
 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			if (!first)
 | 
					 | 
				
			||||||
				writeFillerBytes(trackdata.gap3(), gapFill);
 | 
					 | 
				
			||||||
			first = false;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
			const auto& sectorData = image.get(physicalTrack, logicalSide, sectorId);
 | 
					                writeFillerBytes(trackdata.use_fm() ? 6 : 12, 0x00);
 | 
				
			||||||
			if (!sectorData)
 | 
					                if (!trackdata.use_fm())
 | 
				
			||||||
				continue;
 | 
					                {
 | 
				
			||||||
 | 
					                    for (int i = 0; i < 3; i++)
 | 
				
			||||||
 | 
					                        bw.write_8(MFM_RECORD_SEPARATOR_BYTE);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                bw.write_8(damUnencoded);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			/* Writing the sector and data records are fantastically annoying.
 | 
					                Bytes truncatedData =
 | 
				
			||||||
			 * The CRC is calculated from the *very start* of the record, and
 | 
					                    sectorData->data.slice(0, trackLayout->sectorSize);
 | 
				
			||||||
			 * include the malformed marker bytes. Our encoder doesn't know
 | 
					                bw += truncatedData;
 | 
				
			||||||
			 * about this, of course, with the result that we have to construct
 | 
					                uint16_t crc = crc16(CCITT_POLY, data);
 | 
				
			||||||
			 * the unencoded header, calculate the checksum, and then use the
 | 
					                bw.write_be16(crc);
 | 
				
			||||||
			 * same logic to emit the bytes which require special encoding
 | 
					 | 
				
			||||||
			 * before encoding the rest of the header normally. */
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
			{
 | 
					                int conventionalHeaderStart = 0;
 | 
				
			||||||
				Bytes header;
 | 
					                if (!trackdata.use_fm())
 | 
				
			||||||
				ByteWriter bw(header);
 | 
					                {
 | 
				
			||||||
 | 
					                    for (int i = 0; i < 3; i++)
 | 
				
			||||||
 | 
					                        writeRawBits(MFM_RECORD_SEPARATOR, 16);
 | 
				
			||||||
 | 
					                    conventionalHeaderStart += 3;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                writeRawBits(trackdata.dam_byte(), 16);
 | 
				
			||||||
 | 
					                conventionalHeaderStart += 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				writeFillerBytes(trackdata.use_fm() ? 6 : 12, 0x00);
 | 
					                writeBytes(data.slice(conventionalHeaderStart));
 | 
				
			||||||
				if (!trackdata.use_fm())
 | 
					            }
 | 
				
			||||||
				{
 | 
					        }
 | 
				
			||||||
					for (int i=0; i<3; i++)
 | 
					 | 
				
			||||||
						bw.write_8(MFM_RECORD_SEPARATOR_BYTE);
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
				bw.write_8(idamUnencoded);
 | 
					 | 
				
			||||||
				bw.write_8(sectorData->logicalTrack);
 | 
					 | 
				
			||||||
				bw.write_8(sectorData->logicalSide);
 | 
					 | 
				
			||||||
				bw.write_8(sectorData->logicalSector);
 | 
					 | 
				
			||||||
				bw.write_8(sectorSize);
 | 
					 | 
				
			||||||
				uint16_t crc = crc16(CCITT_POLY, header);
 | 
					 | 
				
			||||||
				bw.write_be16(crc);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
				int conventionalHeaderStart = 0;
 | 
					        if (_cursor >= _bits.size())
 | 
				
			||||||
				if (!trackdata.use_fm())
 | 
					            error("track data overrun");
 | 
				
			||||||
				{
 | 
					        while (_cursor < _bits.size())
 | 
				
			||||||
					for (int i=0; i<3; i++)
 | 
					            writeFillerRawBytes(1, gapFill);
 | 
				
			||||||
						writeRawBits(MFM_RECORD_SEPARATOR, 16);
 | 
					 | 
				
			||||||
					conventionalHeaderStart += 3;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
				}
 | 
					        std::unique_ptr<Fluxmap> fluxmap(new Fluxmap);
 | 
				
			||||||
				writeRawBits(trackdata.idam_byte(), 16);
 | 
					        fluxmap->appendBits(_bits,
 | 
				
			||||||
				conventionalHeaderStart += 1;
 | 
					            calculatePhysicalClockPeriod(clockRateUs * 1e3,
 | 
				
			||||||
 | 
					                trackdata.target_rotational_period_ms() * 1e6));
 | 
				
			||||||
				writeBytes(header.slice(conventionalHeaderStart));
 | 
					        return fluxmap;
 | 
				
			||||||
			}
 | 
					    }
 | 
				
			||||||
 | 
					 | 
				
			||||||
			writeFillerBytes(trackdata.gap2(), gapFill);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			{
 | 
					 | 
				
			||||||
				Bytes data;
 | 
					 | 
				
			||||||
				ByteWriter bw(data);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				writeFillerBytes(trackdata.use_fm() ? 6 : 12, 0x00);
 | 
					 | 
				
			||||||
				if (!trackdata.use_fm())
 | 
					 | 
				
			||||||
				{
 | 
					 | 
				
			||||||
					for (int i=0; i<3; i++)
 | 
					 | 
				
			||||||
						bw.write_8(MFM_RECORD_SEPARATOR_BYTE);
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
				bw.write_8(damUnencoded);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				Bytes truncatedData = sectorData->data.slice(0, trackdata.sector_size());
 | 
					 | 
				
			||||||
				bw += truncatedData;
 | 
					 | 
				
			||||||
				uint16_t crc = crc16(CCITT_POLY, data);
 | 
					 | 
				
			||||||
				bw.write_be16(crc);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				int conventionalHeaderStart = 0;
 | 
					 | 
				
			||||||
				if (!trackdata.use_fm())
 | 
					 | 
				
			||||||
				{
 | 
					 | 
				
			||||||
					for (int i=0; i<3; i++)
 | 
					 | 
				
			||||||
						writeRawBits(MFM_RECORD_SEPARATOR, 16);
 | 
					 | 
				
			||||||
					conventionalHeaderStart += 3;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
				writeRawBits(trackdata.dam_byte(), 16);
 | 
					 | 
				
			||||||
				conventionalHeaderStart += 1;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				writeBytes(data.slice(conventionalHeaderStart));
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (_cursor >= _bits.size())
 | 
					 | 
				
			||||||
			Error() << "track data overrun";
 | 
					 | 
				
			||||||
		while (_cursor < _bits.size())
 | 
					 | 
				
			||||||
			writeFillerBytes(1, gapFill);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		std::unique_ptr<Fluxmap> fluxmap(new Fluxmap);
 | 
					 | 
				
			||||||
		fluxmap->appendBits(_bits, clockRateUs*1e3);
 | 
					 | 
				
			||||||
		return fluxmap;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
	const IbmEncoderProto& _config;
 | 
					    const IbmEncoderProto& _config;
 | 
				
			||||||
	std::vector<bool> _bits;
 | 
					    std::vector<bool> _bits;
 | 
				
			||||||
	unsigned _cursor;
 | 
					    unsigned _cursor;
 | 
				
			||||||
	bool _lastBit;
 | 
					    bool _lastBit;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
std::unique_ptr<AbstractEncoder> createIbmEncoder(const EncoderProto& config)
 | 
					std::unique_ptr<Encoder> createIbmEncoder(const EncoderProto& config)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return std::unique_ptr<AbstractEncoder>(new IbmEncoder(config));
 | 
					    return std::unique_ptr<Encoder>(new IbmEncoder(config));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,35 +3,35 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
/* IBM format (i.e. ordinary PC floppies). */
 | 
					/* IBM format (i.e. ordinary PC floppies). */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define IBM_MFM_SYNC   0xA1   /* sync byte for MFM */
 | 
					#define IBM_MFM_SYNC 0xA1  /* sync byte for MFM */
 | 
				
			||||||
#define IBM_IAM        0xFC   /* start-of-track record */
 | 
					#define IBM_IAM 0xFC       /* start-of-track record */
 | 
				
			||||||
#define IBM_IAM_LEN    1      /* plus prologue */
 | 
					#define IBM_IAM_LEN 1      /* plus prologue */
 | 
				
			||||||
#define IBM_IDAM       0xFE   /* sector header */
 | 
					#define IBM_IDAM 0xFE      /* sector header */
 | 
				
			||||||
#define IBM_IDAM_LEN   7      /* plus prologue */
 | 
					#define IBM_IDAM_LEN 7     /* plus prologue */
 | 
				
			||||||
#define IBM_DAM1       0xF8   /* sector data (type 1) */
 | 
					#define IBM_DAM1 0xF8      /* sector data (type 1) */
 | 
				
			||||||
#define IBM_DAM2       0xFB   /* sector data (type 2) */
 | 
					#define IBM_DAM2 0xFB      /* sector data (type 2) */
 | 
				
			||||||
#define IBM_TRS80DAM1  0xF9   /* sector data (TRS-80 directory) */
 | 
					#define IBM_TRS80DAM1 0xF9 /* sector data (TRS-80 directory) */
 | 
				
			||||||
#define IBM_TRS80DAM2  0xFA   /* sector data (TRS-80 directory) */
 | 
					#define IBM_TRS80DAM2 0xFA /* sector data (TRS-80 directory) */
 | 
				
			||||||
#define IBM_DAM_LEN    1      /* plus prologue and user data */
 | 
					#define IBM_DAM_LEN 1      /* plus prologue and user data */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Length of a DAM record is determined by the previous sector header. */
 | 
					/* Length of a DAM record is determined by the previous sector header. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct IbmIdam
 | 
					struct IbmIdam
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    uint8_t id;
 | 
					    uint8_t id;
 | 
				
			||||||
    uint8_t cylinder;
 | 
					    uint8_t track;
 | 
				
			||||||
    uint8_t side;
 | 
					    uint8_t side;
 | 
				
			||||||
    uint8_t sector;
 | 
					    uint8_t sector;
 | 
				
			||||||
    uint8_t sectorSize;
 | 
					    uint8_t sectorSize;
 | 
				
			||||||
    uint8_t crc[2];
 | 
					    uint8_t crc[2];
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class AbstractEncoder;
 | 
					class Encoder;
 | 
				
			||||||
class AbstractDecoder;
 | 
					class Decoder;
 | 
				
			||||||
class DecoderProto;
 | 
					class DecoderProto;
 | 
				
			||||||
class EncoderProto;
 | 
					class EncoderProto;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern std::unique_ptr<AbstractDecoder> createIbmDecoder(const DecoderProto& config);
 | 
					extern std::unique_ptr<Decoder> createIbmDecoder(const DecoderProto& config);
 | 
				
			||||||
extern std::unique_ptr<AbstractEncoder> createIbmEncoder(const EncoderProto& config);
 | 
					extern std::unique_ptr<Encoder> createIbmEncoder(const EncoderProto& config);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,32 +2,30 @@ syntax = "proto2";
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import "lib/common.proto";
 | 
					import "lib/common.proto";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Next: 7
 | 
					 | 
				
			||||||
message IbmDecoderProto {
 | 
					message IbmDecoderProto {
 | 
				
			||||||
	message SectorsProto {
 | 
						// Next: 11
 | 
				
			||||||
		repeated int32 sector = 1            [(help) = "require these sectors to exist for a good read"];
 | 
						message TrackdataProto {
 | 
				
			||||||
 | 
							optional int32 track = 7              [(help) = "if set, the format applies only to this track"];
 | 
				
			||||||
 | 
							optional int32 head = 8                  [(help) = "if set, the format applies only to this head"];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							optional bool ignore_side_byte = 2       [default = false, (help) = "ignore side byte in sector header"];
 | 
				
			||||||
 | 
							optional bool ignore_track_byte = 6      [default = false, (help) = "ignore track byte in sector header"];
 | 
				
			||||||
 | 
							optional bool invert_side_byte = 4       [default = false, (help) = "invert the side byte in the sector header"];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							repeated int32 ignore_sector = 10        [(help) = "sectors with these IDs will not be read"];
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	optional bool ignore_side_byte = 2       [default = false, (help) = "ignore side byte in sector header"];
 | 
						repeated TrackdataProto trackdata = 1;
 | 
				
			||||||
	optional bool ignore_track_byte = 6      [default = false, (help) = "ignore track byte in sector header"];
 | 
					 | 
				
			||||||
	optional bool swap_sides = 4             [default = false, (help) = "put logical side 1 on physical side 0"];
 | 
					 | 
				
			||||||
	optional SectorsProto sectors = 5        [(help) = "require these sectors to exist for a good read"];
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
message IbmEncoderProto {
 | 
					message IbmEncoderProto {
 | 
				
			||||||
	// Next: 18
 | 
						// Next: 20
 | 
				
			||||||
	message TrackdataProto {
 | 
						message TrackdataProto {
 | 
				
			||||||
		message SectorsProto {
 | 
							optional int32 track = 15        [(help) = "if set, the format applies only to this track"];
 | 
				
			||||||
			repeated int32 sector = 1		[(help) = "write these sectors (in order) on each track"];
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		optional int32 cylinder = 15        [(help) = "if set, the format applies only to this track"];
 | 
					 | 
				
			||||||
		optional int32 head = 16            [(help) = "if set, the format applies only to this head"];
 | 
							optional int32 head = 16            [(help) = "if set, the format applies only to this head"];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		optional double track_length_ms = 1 [(help) = "length of track"];
 | 
					 | 
				
			||||||
		optional int32 sector_size = 2      [default=512, (help) = "number of bytes per sector"];
 | 
					 | 
				
			||||||
		optional bool emit_iam = 3          [default=true, (help) = "whether to emit an IAM record"];
 | 
							optional bool emit_iam = 3          [default=true, (help) = "whether to emit an IAM record"];
 | 
				
			||||||
		optional double clock_rate_khz = 5  [(help) = "data clock rate"];
 | 
							optional double target_clock_period_us = 5  [default=4, (help) = "data clock rate on target disk"];
 | 
				
			||||||
		optional bool use_fm = 6            [default=false, (help) = "whether to use FM encoding rather than MFM"];
 | 
							optional bool use_fm = 6            [default=false, (help) = "whether to use FM encoding rather than MFM"];
 | 
				
			||||||
		optional int32 idam_byte = 7        [default=0x5554, (help) = "16-bit raw bit pattern of IDAM byte"];
 | 
							optional int32 idam_byte = 7        [default=0x5554, (help) = "16-bit raw bit pattern of IDAM byte"];
 | 
				
			||||||
		optional int32 dam_byte = 8         [default=0x5545, (help) = "16-bit raw bit pattern of DAM byte"];
 | 
							optional int32 dam_byte = 8         [default=0x5545, (help) = "16-bit raw bit pattern of DAM byte"];
 | 
				
			||||||
@@ -35,8 +33,9 @@ message IbmEncoderProto {
 | 
				
			|||||||
		optional int32 gap1 = 10            [default=50, (help) = "size of gap 2 (the post-ID gap)"];
 | 
							optional int32 gap1 = 10            [default=50, (help) = "size of gap 2 (the post-ID gap)"];
 | 
				
			||||||
		optional int32 gap2 = 11            [default=22, (help) = "size of gap 3 (the pre-data gap)"];
 | 
							optional int32 gap2 = 11            [default=22, (help) = "size of gap 3 (the pre-data gap)"];
 | 
				
			||||||
		optional int32 gap3 = 12            [default=80, (help) = "size of gap 4 (the post-data or format gap)"];
 | 
							optional int32 gap3 = 12            [default=80, (help) = "size of gap 4 (the post-data or format gap)"];
 | 
				
			||||||
		optional bool swap_sides = 14       [default=false, (help) = "swap side bytes when writing"];
 | 
							optional bool invert_side_byte = 19 [default=false, (help) = "invert the side byte before writing"];
 | 
				
			||||||
		optional SectorsProto sectors = 17	[(help) = "write these sectors (in order) on each track"];
 | 
							optional int32 gap_fill_byte = 18   [default=0x9254, (help) = "16-bit raw bit pattern of gap fill byte"];
 | 
				
			||||||
 | 
							optional double target_rotational_period_ms = 1 [default=200, (help) = "rotational period of target disk"];
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	repeated TrackdataProto trackdata = 1;
 | 
						repeated TrackdataProto trackdata = 1;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -12,22 +12,25 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
const FluxPattern SECTOR_RECORD_PATTERN(24, MAC_SECTOR_RECORD);
 | 
					const FluxPattern SECTOR_RECORD_PATTERN(24, MAC_SECTOR_RECORD);
 | 
				
			||||||
const FluxPattern DATA_RECORD_PATTERN(24, MAC_DATA_RECORD);
 | 
					const FluxPattern DATA_RECORD_PATTERN(24, MAC_DATA_RECORD);
 | 
				
			||||||
const FluxMatchers ANY_RECORD_PATTERN({ &SECTOR_RECORD_PATTERN, &DATA_RECORD_PATTERN });
 | 
					const FluxMatchers ANY_RECORD_PATTERN(
 | 
				
			||||||
 | 
					    {&SECTOR_RECORD_PATTERN, &DATA_RECORD_PATTERN});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int decode_data_gcr(uint8_t gcr)
 | 
					static int decode_data_gcr(uint8_t gcr)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    switch (gcr)
 | 
					    switch (gcr)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
		#define GCR_ENTRY(gcr, data) \
 | 
					#define GCR_ENTRY(gcr, data) \
 | 
				
			||||||
			case gcr: return data;
 | 
					    case gcr:                \
 | 
				
			||||||
		#include "data_gcr.h"
 | 
					        return data;
 | 
				
			||||||
		#undef GCR_ENTRY
 | 
					#include "data_gcr.h"
 | 
				
			||||||
 | 
					#undef GCR_ENTRY
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    return -1;
 | 
					    return -1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* This is extremely inspired by the MESS implementation, written by Nathan Woods
 | 
					/* This is extremely inspired by the MESS implementation, written by Nathan
 | 
				
			||||||
 * and R. Belmont: https://github.com/mamedev/mame/blob/4263a71e64377db11392c458b580c5ae83556bc7/src/lib/formats/ap_dsk35.cpp
 | 
					 * Woods and R. Belmont:
 | 
				
			||||||
 | 
					 * https://github.com/mamedev/mame/blob/4263a71e64377db11392c458b580c5ae83556bc7/src/lib/formats/ap_dsk35.cpp
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static Bytes decode_crazy_data(const Bytes& input, Sector::Status& status)
 | 
					static Bytes decode_crazy_data(const Bytes& input, Sector::Status& status)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -41,7 +44,7 @@ static Bytes decode_crazy_data(const Bytes& input, Sector::Status& status)
 | 
				
			|||||||
    uint8_t b2[LOOKUP_LEN + 1];
 | 
					    uint8_t b2[LOOKUP_LEN + 1];
 | 
				
			||||||
    uint8_t b3[LOOKUP_LEN + 1];
 | 
					    uint8_t b3[LOOKUP_LEN + 1];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for (int i=0; i<=LOOKUP_LEN; i++)
 | 
					    for (int i = 0; i <= LOOKUP_LEN; i++)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        uint8_t w4 = br.read_8();
 | 
					        uint8_t w4 = br.read_8();
 | 
				
			||||||
        uint8_t w1 = br.read_8();
 | 
					        uint8_t w1 = br.read_8();
 | 
				
			||||||
@@ -122,97 +125,71 @@ uint8_t decode_side(uint8_t side)
 | 
				
			|||||||
    return !!(side & 0x20);
 | 
					    return !!(side & 0x20);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class MacintoshDecoder : public AbstractDecoder
 | 
					class MacintoshDecoder : public Decoder
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
	MacintoshDecoder(const DecoderProto& config):
 | 
					    MacintoshDecoder(const DecoderProto& config): Decoder(config) {}
 | 
				
			||||||
		AbstractDecoder(config)
 | 
					 | 
				
			||||||
	{}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    RecordType advanceToNextRecord()
 | 
					    nanoseconds_t advanceToNextRecord() override
 | 
				
			||||||
	{
 | 
					    {
 | 
				
			||||||
		const FluxMatcher* matcher = nullptr;
 | 
					        return seekToPattern(ANY_RECORD_PATTERN);
 | 
				
			||||||
		_sector->clock = _fmr->seekToPattern(ANY_RECORD_PATTERN, matcher);
 | 
					    }
 | 
				
			||||||
		if (matcher == &SECTOR_RECORD_PATTERN)
 | 
					 | 
				
			||||||
			return SECTOR_RECORD;
 | 
					 | 
				
			||||||
		if (matcher == &DATA_RECORD_PATTERN)
 | 
					 | 
				
			||||||
			return DATA_RECORD;
 | 
					 | 
				
			||||||
		return UNKNOWN_RECORD;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void decodeSectorRecord()
 | 
					    void decodeSectorRecord() override
 | 
				
			||||||
	{
 | 
					    {
 | 
				
			||||||
		/* Skip ID (as we know it's a MAC_SECTOR_RECORD). */
 | 
					        if (readRaw24() != MAC_SECTOR_RECORD)
 | 
				
			||||||
		readRawBits(24);
 | 
					            return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* Read header. */
 | 
					        /* Read header. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		auto header = toBytes(readRawBits(7*8)).slice(0, 7);
 | 
					        auto header = toBytes(readRawBits(7 * 8)).slice(0, 7);
 | 
				
			||||||
					
 | 
					 | 
				
			||||||
		uint8_t encodedTrack = decode_data_gcr(header[0]);
 | 
					 | 
				
			||||||
		if (encodedTrack != (_sector->physicalCylinder & 0x3f))
 | 
					 | 
				
			||||||
			return;
 | 
					 | 
				
			||||||
					
 | 
					 | 
				
			||||||
		uint8_t encodedSector = decode_data_gcr(header[1]);
 | 
					 | 
				
			||||||
		uint8_t encodedSide = decode_data_gcr(header[2]);
 | 
					 | 
				
			||||||
		uint8_t formatByte = decode_data_gcr(header[3]);
 | 
					 | 
				
			||||||
		uint8_t wantedsum = decode_data_gcr(header[4]);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (encodedSector > 11)
 | 
					        uint8_t encodedTrack = decode_data_gcr(header[0]);
 | 
				
			||||||
			return;
 | 
					        if (encodedTrack != (_sector->physicalTrack & 0x3f))
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		_sector->logicalTrack = _sector->physicalCylinder;
 | 
					        uint8_t encodedSector = decode_data_gcr(header[1]);
 | 
				
			||||||
		_sector->logicalSide = decode_side(encodedSide);
 | 
					        uint8_t encodedSide = decode_data_gcr(header[2]);
 | 
				
			||||||
		_sector->logicalSector = encodedSector;
 | 
					        uint8_t formatByte = decode_data_gcr(header[3]);
 | 
				
			||||||
		uint8_t gotsum = (encodedTrack ^ encodedSector ^ encodedSide ^ formatByte) & 0x3f;
 | 
					        uint8_t wantedsum = decode_data_gcr(header[4]);
 | 
				
			||||||
		if (wantedsum == gotsum)
 | 
					 | 
				
			||||||
			_sector->status = Sector::DATA_MISSING; /* unintuitive but correct */
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void decodeDataRecord()
 | 
					        if (encodedSector > 11)
 | 
				
			||||||
	{
 | 
					            return;
 | 
				
			||||||
		auto id = toBytes(readRawBits(24)).reader().read_be24();
 | 
					 | 
				
			||||||
		if (id != MAC_DATA_RECORD)
 | 
					 | 
				
			||||||
			return;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* Read data. */
 | 
					        _sector->logicalTrack = _sector->physicalTrack;
 | 
				
			||||||
 | 
					        _sector->logicalSide = decode_side(encodedSide);
 | 
				
			||||||
 | 
					        _sector->logicalSector = encodedSector;
 | 
				
			||||||
 | 
					        uint8_t gotsum =
 | 
				
			||||||
 | 
					            (encodedTrack ^ encodedSector ^ encodedSide ^ formatByte) & 0x3f;
 | 
				
			||||||
 | 
					        if (wantedsum == gotsum)
 | 
				
			||||||
 | 
					            _sector->status =
 | 
				
			||||||
 | 
					                Sector::DATA_MISSING; /* unintuitive but correct */
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		readRawBits(8); /* skip spare byte */
 | 
					    void decodeDataRecord() override
 | 
				
			||||||
		auto inputbuffer = toBytes(readRawBits(MAC_ENCODED_SECTOR_LENGTH*8))
 | 
					    {
 | 
				
			||||||
			.slice(0, MAC_ENCODED_SECTOR_LENGTH);
 | 
					        if (readRaw24() != MAC_DATA_RECORD)
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		for (unsigned i=0; i<inputbuffer.size(); i++)
 | 
					        /* Read data. */
 | 
				
			||||||
			inputbuffer[i] = decode_data_gcr(inputbuffer[i]);
 | 
					 | 
				
			||||||
			
 | 
					 | 
				
			||||||
		_sector->status = Sector::BAD_CHECKSUM;
 | 
					 | 
				
			||||||
		Bytes userData = decode_crazy_data(inputbuffer, _sector->status);
 | 
					 | 
				
			||||||
		_sector->data.clear();
 | 
					 | 
				
			||||||
		_sector->data.writer().append(userData.slice(12, 512)).append(userData.slice(0, 12));
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	std::set<unsigned> requiredSectors(unsigned cylinder, unsigned head) const
 | 
					        readRawBits(8); /* skip spare byte */
 | 
				
			||||||
	{
 | 
					        auto inputbuffer = toBytes(readRawBits(MAC_ENCODED_SECTOR_LENGTH * 8))
 | 
				
			||||||
		int count;
 | 
					                               .slice(0, MAC_ENCODED_SECTOR_LENGTH);
 | 
				
			||||||
		if (cylinder < 16)
 | 
					 | 
				
			||||||
			count = 12;
 | 
					 | 
				
			||||||
		else if (cylinder < 32)
 | 
					 | 
				
			||||||
			count = 11;
 | 
					 | 
				
			||||||
		else if (cylinder < 48)
 | 
					 | 
				
			||||||
			count = 10;
 | 
					 | 
				
			||||||
		else if (cylinder < 64)
 | 
					 | 
				
			||||||
			count = 9;
 | 
					 | 
				
			||||||
		else
 | 
					 | 
				
			||||||
			count = 8;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		std::set<unsigned> sectors;
 | 
					        for (unsigned i = 0; i < inputbuffer.size(); i++)
 | 
				
			||||||
		while (count--)
 | 
					            inputbuffer[i] = decode_data_gcr(inputbuffer[i]);
 | 
				
			||||||
			sectors.insert(count);
 | 
					
 | 
				
			||||||
		return sectors;
 | 
					        _sector->status = Sector::BAD_CHECKSUM;
 | 
				
			||||||
	}
 | 
					        Bytes userData = decode_crazy_data(inputbuffer, _sector->status);
 | 
				
			||||||
 | 
					        _sector->data.clear();
 | 
				
			||||||
 | 
					        _sector->data.writer()
 | 
				
			||||||
 | 
					            .append(userData.slice(12, 512))
 | 
				
			||||||
 | 
					            .append(userData.slice(0, 12));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
std::unique_ptr<AbstractDecoder> createMacintoshDecoder(const DecoderProto& config)
 | 
					std::unique_ptr<Decoder> createMacintoshDecoder(const DecoderProto& config)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return std::unique_ptr<AbstractDecoder>(new MacintoshDecoder(config));
 | 
					    return std::unique_ptr<Decoder>(new MacintoshDecoder(config));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,10 +3,11 @@
 | 
				
			|||||||
#include "encoders/encoders.h"
 | 
					#include "encoders/encoders.h"
 | 
				
			||||||
#include "macintosh.h"
 | 
					#include "macintosh.h"
 | 
				
			||||||
#include "crc.h"
 | 
					#include "crc.h"
 | 
				
			||||||
#include "writer.h"
 | 
					#include "readerwriter.h"
 | 
				
			||||||
#include "image.h"
 | 
					#include "image.h"
 | 
				
			||||||
#include "fmt/format.h"
 | 
					#include "fmt/format.h"
 | 
				
			||||||
#include "lib/encoders/encoders.pb.h"
 | 
					#include "lib/encoders/encoders.pb.h"
 | 
				
			||||||
 | 
					#include "lib/layout.h"
 | 
				
			||||||
#include "arch/macintosh/macintosh.pb.h"
 | 
					#include "arch/macintosh/macintosh.pb.h"
 | 
				
			||||||
#include <ctype.h>
 | 
					#include <ctype.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -14,44 +15,46 @@ static bool lastBit;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
static double clockRateUsForTrack(unsigned track)
 | 
					static double clockRateUsForTrack(unsigned track)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (track < 16)
 | 
					    if (track < 16)
 | 
				
			||||||
		return 2.623;
 | 
					        return 2.63;
 | 
				
			||||||
	if (track < 32)
 | 
					    if (track < 32)
 | 
				
			||||||
		return 2.861;
 | 
					        return 2.89;
 | 
				
			||||||
	if (track < 48)
 | 
					    if (track < 48)
 | 
				
			||||||
		return 3.148;
 | 
					        return 3.20;
 | 
				
			||||||
	if (track < 64)
 | 
					    if (track < 64)
 | 
				
			||||||
		return 3.497;
 | 
					        return 3.57;
 | 
				
			||||||
	return 3.934;
 | 
					    return 3.98;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static unsigned sectorsForTrack(unsigned track)
 | 
					static unsigned sectorsForTrack(unsigned track)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (track < 16)
 | 
					    if (track < 16)
 | 
				
			||||||
		return 12;
 | 
					        return 12;
 | 
				
			||||||
	if (track < 32)
 | 
					    if (track < 32)
 | 
				
			||||||
		return 11;
 | 
					        return 11;
 | 
				
			||||||
	if (track < 48)
 | 
					    if (track < 48)
 | 
				
			||||||
		return 10;
 | 
					        return 10;
 | 
				
			||||||
	if (track < 64)
 | 
					    if (track < 64)
 | 
				
			||||||
		return 9;
 | 
					        return 9;
 | 
				
			||||||
	return 8;
 | 
					    return 8;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int encode_data_gcr(uint8_t gcr)
 | 
					static int encode_data_gcr(uint8_t gcr)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    switch (gcr)
 | 
					    switch (gcr)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
		#define GCR_ENTRY(gcr, data) \
 | 
					#define GCR_ENTRY(gcr, data) \
 | 
				
			||||||
			case data: return gcr;
 | 
					    case data:               \
 | 
				
			||||||
		#include "data_gcr.h"
 | 
					        return gcr;
 | 
				
			||||||
		#undef GCR_ENTRY
 | 
					#include "data_gcr.h"
 | 
				
			||||||
 | 
					#undef GCR_ENTRY
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    return -1;
 | 
					    return -1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* This is extremely inspired by the MESS implementation, written by Nathan Woods
 | 
					/* This is extremely inspired by the MESS implementation, written by Nathan
 | 
				
			||||||
 * and R. Belmont: https://github.com/mamedev/mame/blob/4263a71e64377db11392c458b580c5ae83556bc7/src/lib/formats/ap_dsk35.cpp
 | 
					 * Woods and R. Belmont:
 | 
				
			||||||
 | 
					 * https://github.com/mamedev/mame/blob/4263a71e64377db11392c458b580c5ae83556bc7/src/lib/formats/ap_dsk35.cpp
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static Bytes encode_crazy_data(const Bytes& input)
 | 
					static Bytes encode_crazy_data(const Bytes& input)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -59,7 +62,7 @@ static Bytes encode_crazy_data(const Bytes& input)
 | 
				
			|||||||
    ByteWriter bw(output);
 | 
					    ByteWriter bw(output);
 | 
				
			||||||
    ByteReader br(input);
 | 
					    ByteReader br(input);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	uint8_t w1, w2, w3, w4;
 | 
					    uint8_t w1, w2, w3, w4;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    static const int LOOKUP_LEN = MAC_SECTOR_LENGTH / 3;
 | 
					    static const int LOOKUP_LEN = MAC_SECTOR_LENGTH / 3;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -67,92 +70,94 @@ static Bytes encode_crazy_data(const Bytes& input)
 | 
				
			|||||||
    uint8_t b2[LOOKUP_LEN + 1];
 | 
					    uint8_t b2[LOOKUP_LEN + 1];
 | 
				
			||||||
    uint8_t b3[LOOKUP_LEN + 1];
 | 
					    uint8_t b3[LOOKUP_LEN + 1];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	uint32_t c1 = 0;
 | 
					    uint32_t c1 = 0;
 | 
				
			||||||
	uint32_t c2 = 0;
 | 
					    uint32_t c2 = 0;
 | 
				
			||||||
	uint32_t c3 = 0;
 | 
					    uint32_t c3 = 0;
 | 
				
			||||||
	for (int j=0;; j++)
 | 
					    for (int j = 0;; j++)
 | 
				
			||||||
	{
 | 
					    {
 | 
				
			||||||
		c1 = (c1 & 0xff) << 1;
 | 
					        c1 = (c1 & 0xff) << 1;
 | 
				
			||||||
		if (c1 & 0x0100)
 | 
					        if (c1 & 0x0100)
 | 
				
			||||||
			c1++;
 | 
					            c1++;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		uint8_t val = br.read_8();
 | 
					        uint8_t val = br.read_8();
 | 
				
			||||||
		c3 += val;
 | 
					        c3 += val;
 | 
				
			||||||
		if (c1 & 0x0100)
 | 
					        if (c1 & 0x0100)
 | 
				
			||||||
		{
 | 
					        {
 | 
				
			||||||
			c3++;
 | 
					            c3++;
 | 
				
			||||||
			c1 &= 0xff;
 | 
					            c1 &= 0xff;
 | 
				
			||||||
		}
 | 
					        }
 | 
				
			||||||
		b1[j] = (val ^ c1) & 0xff;
 | 
					        b1[j] = (val ^ c1) & 0xff;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		val = br.read_8();
 | 
					        val = br.read_8();
 | 
				
			||||||
		c2 += val;
 | 
					        c2 += val;
 | 
				
			||||||
		if (c3 > 0xff)
 | 
					        if (c3 > 0xff)
 | 
				
			||||||
		{
 | 
					        {
 | 
				
			||||||
			c2++;
 | 
					            c2++;
 | 
				
			||||||
			c3 &= 0xff;
 | 
					            c3 &= 0xff;
 | 
				
			||||||
		}
 | 
					        }
 | 
				
			||||||
		b2[j] = (val ^ c3) & 0xff;
 | 
					        b2[j] = (val ^ c3) & 0xff;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (br.pos == 524)
 | 
					        if (br.pos == 524)
 | 
				
			||||||
			break;
 | 
					            break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		val = br.read_8();
 | 
					        val = br.read_8();
 | 
				
			||||||
		c1 += val;
 | 
					        c1 += val;
 | 
				
			||||||
		if (c2 > 0xff)
 | 
					        if (c2 > 0xff)
 | 
				
			||||||
		{
 | 
					        {
 | 
				
			||||||
			c1++;
 | 
					            c1++;
 | 
				
			||||||
			c2 &= 0xff;
 | 
					            c2 &= 0xff;
 | 
				
			||||||
		}
 | 
					        }
 | 
				
			||||||
		b3[j] = (val ^ c2) & 0xff;
 | 
					        b3[j] = (val ^ c2) & 0xff;
 | 
				
			||||||
	}
 | 
					    }
 | 
				
			||||||
	uint32_t c4 = ((c1 & 0xc0) >> 6) | ((c2 & 0xc0) >> 4) | ((c3 & 0xc0) >> 2);
 | 
					    uint32_t c4 = ((c1 & 0xc0) >> 6) | ((c2 & 0xc0) >> 4) | ((c3 & 0xc0) >> 2);
 | 
				
			||||||
	b3[LOOKUP_LEN] = 0;
 | 
					    b3[LOOKUP_LEN] = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (int i = 0; i <= LOOKUP_LEN; i++)
 | 
					    for (int i = 0; i <= LOOKUP_LEN; i++)
 | 
				
			||||||
	{
 | 
					    {
 | 
				
			||||||
		w1 = b1[i] & 0x3f;
 | 
					        w1 = b1[i] & 0x3f;
 | 
				
			||||||
		w2 = b2[i] & 0x3f;
 | 
					        w2 = b2[i] & 0x3f;
 | 
				
			||||||
		w3 = b3[i] & 0x3f;
 | 
					        w3 = b3[i] & 0x3f;
 | 
				
			||||||
		w4 =  ((b1[i] & 0xc0) >> 2);
 | 
					        w4 = ((b1[i] & 0xc0) >> 2);
 | 
				
			||||||
		w4 |= ((b2[i] & 0xc0) >> 4);
 | 
					        w4 |= ((b2[i] & 0xc0) >> 4);
 | 
				
			||||||
		w4 |= ((b3[i] & 0xc0) >> 6);
 | 
					        w4 |= ((b3[i] & 0xc0) >> 6);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		bw.write_8(w4);
 | 
					        bw.write_8(w4);
 | 
				
			||||||
		bw.write_8(w1);
 | 
					        bw.write_8(w1);
 | 
				
			||||||
		bw.write_8(w2);
 | 
					        bw.write_8(w2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (i != LOOKUP_LEN)
 | 
					        if (i != LOOKUP_LEN)
 | 
				
			||||||
			bw.write_8(w3);
 | 
					            bw.write_8(w3);
 | 
				
			||||||
	}
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bw.write_8(c4 & 0x3f);
 | 
					    bw.write_8(c4 & 0x3f);
 | 
				
			||||||
	bw.write_8(c3 & 0x3f);
 | 
					    bw.write_8(c3 & 0x3f);
 | 
				
			||||||
	bw.write_8(c2 & 0x3f);
 | 
					    bw.write_8(c2 & 0x3f);
 | 
				
			||||||
	bw.write_8(c1 & 0x3f);
 | 
					    bw.write_8(c1 & 0x3f);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return output;
 | 
					    return output;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void write_bits(std::vector<bool>& bits, unsigned& cursor, const std::vector<bool>& src)
 | 
					static void write_bits(
 | 
				
			||||||
 | 
					    std::vector<bool>& bits, unsigned& cursor, const std::vector<bool>& src)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	for (bool bit : src)
 | 
					    for (bool bit : src)
 | 
				
			||||||
	{
 | 
					    {
 | 
				
			||||||
		if (cursor < bits.size())
 | 
					        if (cursor < bits.size())
 | 
				
			||||||
			bits[cursor++] = bit;
 | 
					            bits[cursor++] = bit;
 | 
				
			||||||
	}
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void write_bits(std::vector<bool>& bits, unsigned& cursor, uint64_t data, int width)
 | 
					static void write_bits(
 | 
				
			||||||
 | 
					    std::vector<bool>& bits, unsigned& cursor, uint64_t data, int width)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	cursor += width;
 | 
					    cursor += width;
 | 
				
			||||||
	for (int i=0; i<width; i++)
 | 
					    for (int i = 0; i < width; i++)
 | 
				
			||||||
	{
 | 
					    {
 | 
				
			||||||
		unsigned pos = cursor - i - 1;
 | 
					        unsigned pos = cursor - i - 1;
 | 
				
			||||||
		if (pos < bits.size())
 | 
					        if (pos < bits.size())
 | 
				
			||||||
			bits[pos] = data & 1;
 | 
					            bits[pos] = data & 1;
 | 
				
			||||||
		data >>= 1;
 | 
					        data >>= 1;
 | 
				
			||||||
	}
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static uint8_t encode_side(uint8_t track, uint8_t side)
 | 
					static uint8_t encode_side(uint8_t track, uint8_t side)
 | 
				
			||||||
@@ -161,103 +166,93 @@ static uint8_t encode_side(uint8_t track, uint8_t side)
 | 
				
			|||||||
     * bit 5) and also whether we're above track 0x3f (in bit 0).
 | 
					     * bit 5) and also whether we're above track 0x3f (in bit 0).
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return (side ? 0x20 : 0x00) | ((track>0x3f) ? 0x01 : 0x00);
 | 
					    return (side ? 0x20 : 0x00) | ((track > 0x3f) ? 0x01 : 0x00);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void write_sector(std::vector<bool>& bits, unsigned& cursor, const std::shared_ptr<Sector>& sector)
 | 
					static void write_sector(std::vector<bool>& bits,
 | 
				
			||||||
 | 
					    unsigned& cursor,
 | 
				
			||||||
 | 
					    const std::shared_ptr<const Sector>& sector)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if ((sector->data.size() != 512) && (sector->data.size() != 524))
 | 
					    if ((sector->data.size() != 512) && (sector->data.size() != 524))
 | 
				
			||||||
		Error() << "unsupported sector size --- you must pick 512 or 524";
 | 
					        error("unsupported sector size --- you must pick 512 or 524");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	write_bits(bits, cursor, 0xff, 1*8); /* pad byte */
 | 
					    write_bits(bits, cursor, 0xff, 1 * 8); /* pad byte */
 | 
				
			||||||
	for (int i=0; i<7; i++)
 | 
					    for (int i = 0; i < 7; i++)
 | 
				
			||||||
		write_bits(bits, cursor, 0xff3fcff3fcffLL, 6*8); /* sync */
 | 
					        write_bits(bits, cursor, 0xff3fcff3fcffLL, 6 * 8); /* sync */
 | 
				
			||||||
	write_bits(bits, cursor, MAC_SECTOR_RECORD, 3*8);
 | 
					    write_bits(bits, cursor, MAC_SECTOR_RECORD, 3 * 8);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    uint8_t encodedTrack = sector->logicalTrack & 0x3f;
 | 
					    uint8_t encodedTrack = sector->logicalTrack & 0x3f;
 | 
				
			||||||
	uint8_t encodedSector = sector->logicalSector;
 | 
					    uint8_t encodedSector = sector->logicalSector;
 | 
				
			||||||
	uint8_t encodedSide = encode_side(sector->logicalTrack, sector->logicalSide);
 | 
					    uint8_t encodedSide =
 | 
				
			||||||
	uint8_t formatByte = MAC_FORMAT_BYTE;
 | 
					        encode_side(sector->logicalTrack, sector->logicalSide);
 | 
				
			||||||
	uint8_t headerChecksum = (encodedTrack ^ encodedSector ^ encodedSide ^ formatByte) & 0x3f;
 | 
					    uint8_t formatByte = MAC_FORMAT_BYTE;
 | 
				
			||||||
 | 
					    uint8_t headerChecksum =
 | 
				
			||||||
 | 
					        (encodedTrack ^ encodedSector ^ encodedSide ^ formatByte) & 0x3f;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	write_bits(bits, cursor, encode_data_gcr(encodedTrack), 1*8);
 | 
					    write_bits(bits, cursor, encode_data_gcr(encodedTrack), 1 * 8);
 | 
				
			||||||
	write_bits(bits, cursor, encode_data_gcr(encodedSector), 1*8);
 | 
					    write_bits(bits, cursor, encode_data_gcr(encodedSector), 1 * 8);
 | 
				
			||||||
	write_bits(bits, cursor, encode_data_gcr(encodedSide), 1*8);
 | 
					    write_bits(bits, cursor, encode_data_gcr(encodedSide), 1 * 8);
 | 
				
			||||||
	write_bits(bits, cursor, encode_data_gcr(formatByte), 1*8);
 | 
					    write_bits(bits, cursor, encode_data_gcr(formatByte), 1 * 8);
 | 
				
			||||||
	write_bits(bits, cursor, encode_data_gcr(headerChecksum), 1*8);
 | 
					    write_bits(bits, cursor, encode_data_gcr(headerChecksum), 1 * 8);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	write_bits(bits, cursor, 0xdeaaff, 3*8);
 | 
					    write_bits(bits, cursor, 0xdeaaff, 3 * 8);
 | 
				
			||||||
	write_bits(bits, cursor, 0xff3fcff3fcffLL, 6*8); /* sync */
 | 
					    write_bits(bits, cursor, 0xff3fcff3fcffLL, 6 * 8); /* sync */
 | 
				
			||||||
	write_bits(bits, cursor, MAC_DATA_RECORD, 3*8);
 | 
					    write_bits(bits, cursor, MAC_DATA_RECORD, 3 * 8);
 | 
				
			||||||
	write_bits(bits, cursor, encode_data_gcr(sector->logicalSector), 1*8);
 | 
					    write_bits(bits, cursor, encode_data_gcr(sector->logicalSector), 1 * 8);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Bytes wireData;
 | 
					    Bytes wireData;
 | 
				
			||||||
	wireData.writer().append(sector->data.slice(512, 12)).append(sector->data.slice(0, 512));
 | 
					    wireData.writer()
 | 
				
			||||||
	for (uint8_t b : encode_crazy_data(wireData))
 | 
					        .append(sector->data.slice(512, 12))
 | 
				
			||||||
		write_bits(bits, cursor, encode_data_gcr(b), 1*8);
 | 
					        .append(sector->data.slice(0, 512));
 | 
				
			||||||
 | 
					    for (uint8_t b : encode_crazy_data(wireData))
 | 
				
			||||||
 | 
					        write_bits(bits, cursor, encode_data_gcr(b), 1 * 8);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	write_bits(bits, cursor, 0xdeaaff, 3*8);
 | 
					    write_bits(bits, cursor, 0xdeaaff, 3 * 8);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class MacintoshEncoder : public AbstractEncoder
 | 
					class MacintoshEncoder : public Encoder
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
	MacintoshEncoder(const EncoderProto& config):
 | 
					    MacintoshEncoder(const EncoderProto& config):
 | 
				
			||||||
		AbstractEncoder(config),
 | 
					        Encoder(config),
 | 
				
			||||||
		_config(config.macintosh())
 | 
					        _config(config.macintosh())
 | 
				
			||||||
	{}
 | 
					    {
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
	std::vector<std::shared_ptr<Sector>> collectSectors(int physicalTrack, int physicalSide, const Image& image) override
 | 
					    std::unique_ptr<Fluxmap> encode(std::shared_ptr<const TrackInfo>& trackInfo,
 | 
				
			||||||
	{
 | 
					        const std::vector<std::shared_ptr<const Sector>>& sectors,
 | 
				
			||||||
		std::vector<std::shared_ptr<Sector>> sectors;
 | 
					        const Image& image) override
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        double clockRateUs = clockRateUsForTrack(trackInfo->logicalTrack);
 | 
				
			||||||
 | 
					        int bitsPerRevolution = 200000.0 / clockRateUs;
 | 
				
			||||||
 | 
					        std::vector<bool> bits(bitsPerRevolution);
 | 
				
			||||||
 | 
					        unsigned cursor = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if ((physicalTrack >= 0) && (physicalTrack < MAC_TRACKS_PER_DISK))
 | 
					        fillBitmapTo(bits,
 | 
				
			||||||
        {
 | 
					            cursor,
 | 
				
			||||||
            unsigned numSectors = sectorsForTrack(physicalTrack);
 | 
					            _config.post_index_gap_us() / clockRateUs,
 | 
				
			||||||
            for (int sectorId=0; sectorId<numSectors; sectorId++)
 | 
					            {true, false});
 | 
				
			||||||
            {
 | 
					        lastBit = false;
 | 
				
			||||||
                const auto& sector = image.get(physicalTrack, physicalSide, sectorId);
 | 
					 | 
				
			||||||
                if (sector)
 | 
					 | 
				
			||||||
                    sectors.push_back(sector);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		return sectors;
 | 
					        for (const auto& sector : sectors)
 | 
				
			||||||
	}
 | 
					            write_sector(bits, cursor, sector);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    std::unique_ptr<Fluxmap> encode(int physicalTrack, int physicalSide,
 | 
					        if (cursor >= bits.size())
 | 
				
			||||||
			const std::vector<std::shared_ptr<Sector>>& sectors, const Image& image) override
 | 
					            error("track data overrun by {} bits", cursor - bits.size());
 | 
				
			||||||
	{
 | 
					        fillBitmapTo(bits, cursor, bits.size(), {true, false});
 | 
				
			||||||
		if ((physicalTrack < 0) || (physicalTrack >= MAC_TRACKS_PER_DISK))
 | 
					 | 
				
			||||||
			return std::unique_ptr<Fluxmap>();
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		double clockRateUs = clockRateUsForTrack(physicalTrack) * _config.clock_compensation_factor();
 | 
					        std::unique_ptr<Fluxmap> fluxmap(new Fluxmap);
 | 
				
			||||||
		int bitsPerRevolution = 200000.0 / clockRateUs;
 | 
					        fluxmap->appendBits(
 | 
				
			||||||
		std::vector<bool> bits(bitsPerRevolution);
 | 
					            bits, calculatePhysicalClockPeriod(clockRateUs * 1e3, 200e6));
 | 
				
			||||||
		unsigned cursor = 0;
 | 
					        return fluxmap;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
		fillBitmapTo(bits, cursor, _config.post_index_gap_us() / clockRateUs, { true, false });
 | 
					 | 
				
			||||||
		lastBit = false;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		for (const auto& sector : sectors)
 | 
					 | 
				
			||||||
			write_sector(bits, cursor, sector);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (cursor >= bits.size())
 | 
					 | 
				
			||||||
			Error() << fmt::format("track data overrun by {} bits", cursor - bits.size());
 | 
					 | 
				
			||||||
		fillBitmapTo(bits, cursor, bits.size(), { true, false });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		std::unique_ptr<Fluxmap> fluxmap(new Fluxmap);
 | 
					 | 
				
			||||||
		fluxmap->appendBits(bits, clockRateUs*1e3);
 | 
					 | 
				
			||||||
		return fluxmap;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
	const MacintoshEncoderProto& _config;
 | 
					    const MacintoshEncoderProto& _config;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
std::unique_ptr<AbstractEncoder> createMacintoshEncoder(const EncoderProto& config)
 | 
					std::unique_ptr<Encoder> createMacintoshEncoder(const EncoderProto& config)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return std::unique_ptr<AbstractEncoder>(new MacintoshEncoder(config));
 | 
					    return std::unique_ptr<Encoder>(new MacintoshEncoder(config));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,22 +1,23 @@
 | 
				
			|||||||
#ifndef MACINTOSH_H
 | 
					#ifndef MACINTOSH_H
 | 
				
			||||||
#define MACINTOSH_H
 | 
					#define MACINTOSH_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define MAC_SECTOR_RECORD   0xd5aa96 /* 1101 0101 1010 1010 1001 0110 */
 | 
					#define MAC_SECTOR_RECORD 0xd5aa96 /* 1101 0101 1010 1010 1001 0110 */
 | 
				
			||||||
#define MAC_DATA_RECORD     0xd5aaad /* 1101 0101 1010 1010 1010 1101 */
 | 
					#define MAC_DATA_RECORD 0xd5aaad   /* 1101 0101 1010 1010 1010 1101 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define MAC_SECTOR_LENGTH   524 /* yes, really */
 | 
					#define MAC_SECTOR_LENGTH 524 /* yes, really */
 | 
				
			||||||
#define MAC_ENCODED_SECTOR_LENGTH 703
 | 
					#define MAC_ENCODED_SECTOR_LENGTH 703
 | 
				
			||||||
#define MAC_FORMAT_BYTE     0x22
 | 
					#define MAC_FORMAT_BYTE 0x22
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define MAC_TRACKS_PER_DISK 80
 | 
					#define MAC_TRACKS_PER_DISK 80
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class AbstractEncoder;
 | 
					class Encoder;
 | 
				
			||||||
class AbstractDecoder;
 | 
					class Decoder;
 | 
				
			||||||
class DecoderProto;
 | 
					class DecoderProto;
 | 
				
			||||||
class EncoderProto;
 | 
					class EncoderProto;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern std::unique_ptr<AbstractDecoder> createMacintoshDecoder(const DecoderProto& config);
 | 
					extern std::unique_ptr<Decoder> createMacintoshDecoder(
 | 
				
			||||||
extern std::unique_ptr<AbstractEncoder> createMacintoshEncoder(const EncoderProto& config);
 | 
					    const DecoderProto& config);
 | 
				
			||||||
 | 
					extern std::unique_ptr<Encoder> createMacintoshEncoder(
 | 
				
			||||||
 | 
					    const EncoderProto& config);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,8 +7,5 @@ message MacintoshDecoderProto {}
 | 
				
			|||||||
message MacintoshEncoderProto {
 | 
					message MacintoshEncoderProto {
 | 
				
			||||||
	optional double post_index_gap_us = 1 [default = 0.0,
 | 
						optional double post_index_gap_us = 1 [default = 0.0,
 | 
				
			||||||
		(help) = "post-index gap before first sector header (microseconds)."];
 | 
							(help) = "post-index gap before first sector header (microseconds)."];
 | 
				
			||||||
 | 
					 | 
				
			||||||
	optional double clock_compensation_factor = 2 [default = 1.0,
 | 
					 | 
				
			||||||
		(help) = "scale the output clock by this much."];
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,70 +6,202 @@
 | 
				
			|||||||
#include "micropolis.h"
 | 
					#include "micropolis.h"
 | 
				
			||||||
#include "bytes.h"
 | 
					#include "bytes.h"
 | 
				
			||||||
#include "fmt/format.h"
 | 
					#include "fmt/format.h"
 | 
				
			||||||
 | 
					#include "lib/decoders/decoders.pb.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* The sector has a preamble of MFM 0x00s and uses 0xFF as a sync pattern. */
 | 
					/* The sector has a preamble of MFM 0x00s and uses 0xFF as a sync pattern.
 | 
				
			||||||
static const FluxPattern SECTOR_SYNC_PATTERN(32, 0xaaaa5555);
 | 
					 *
 | 
				
			||||||
 | 
					 * 00        00        00        F         F
 | 
				
			||||||
 | 
					 * 0000 0000 0000 0000 0000 0000 0101 0101 0101 0101
 | 
				
			||||||
 | 
					 * A    A    A    A    A    A    5    5    5    5
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static const FluxPattern SECTOR_SYNC_PATTERN(64, 0xAAAAAAAAAAAA5555LL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Adds all bytes, with carry. */
 | 
					/* Pattern to skip past current SYNC. */
 | 
				
			||||||
uint8_t micropolisChecksum(const Bytes& bytes) {
 | 
					static const FluxPattern SECTOR_ADVANCE_PATTERN(64, 0xAAAAAAAAAAAAAAAALL);
 | 
				
			||||||
	ByteReader br(bytes);
 | 
					
 | 
				
			||||||
	uint16_t sum = 0;
 | 
					/* Standard Micropolis checksum.  Adds all bytes, with carry. */
 | 
				
			||||||
	while (!br.eof()) {
 | 
					uint8_t micropolisChecksum(const Bytes& bytes)
 | 
				
			||||||
		if (sum > 0xFF) {
 | 
					{
 | 
				
			||||||
			sum -= 0x100 - 1;
 | 
					    ByteReader br(bytes);
 | 
				
			||||||
		}
 | 
					    uint16_t sum = 0;
 | 
				
			||||||
		sum += br.read_8();
 | 
					    while (!br.eof())
 | 
				
			||||||
	}
 | 
					    {
 | 
				
			||||||
	/* The last carry is ignored */
 | 
					        if (sum > 0xFF)
 | 
				
			||||||
	return sum & 0xFF;
 | 
					        {
 | 
				
			||||||
 | 
					            sum -= 0x100 - 1;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        sum += br.read_8();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    /* The last carry is ignored */
 | 
				
			||||||
 | 
					    return sum & 0xFF;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class MicropolisDecoder : public AbstractDecoder
 | 
					/* Vector MZOS does not use the standard Micropolis checksum.
 | 
				
			||||||
 | 
					 * The checksum is initially 0.
 | 
				
			||||||
 | 
					 * For each data byte in the 256-byte payload, rotate left,
 | 
				
			||||||
 | 
					 * carrying bit 7 to bit 0.  XOR with the current checksum.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Unlike the Micropolis checksum, this does not cover the 12-byte
 | 
				
			||||||
 | 
					 * header (track, sector, 10 OS-specific bytes.)
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					uint8_t mzosChecksum(const Bytes& bytes)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    ByteReader br(bytes);
 | 
				
			||||||
 | 
					    uint8_t checksum = 0;
 | 
				
			||||||
 | 
					    uint8_t databyte;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    while (!br.eof())
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        databyte = br.read_8();
 | 
				
			||||||
 | 
					        checksum ^= ((databyte << 1) | (databyte >> 7));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return checksum;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class MicropolisDecoder : public Decoder
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
	MicropolisDecoder(const DecoderProto& config):
 | 
					    MicropolisDecoder(const DecoderProto& config):
 | 
				
			||||||
		AbstractDecoder(config)
 | 
					        Decoder(config),
 | 
				
			||||||
	{}
 | 
					        _config(config.micropolis())
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        _checksumType = _config.checksum_type();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	RecordType advanceToNextRecord()
 | 
					    nanoseconds_t advanceToNextRecord() override
 | 
				
			||||||
	{
 | 
					    {
 | 
				
			||||||
		_fmr->seekToIndexMark();
 | 
					        nanoseconds_t now = tell().ns();
 | 
				
			||||||
		const FluxMatcher* matcher = nullptr;
 | 
					 | 
				
			||||||
		_sector->clock = _fmr->seekToPattern(SECTOR_SYNC_PATTERN, matcher);
 | 
					 | 
				
			||||||
		if (matcher == &SECTOR_SYNC_PATTERN) {
 | 
					 | 
				
			||||||
			readRawBits(16);
 | 
					 | 
				
			||||||
			return SECTOR_RECORD;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		return UNKNOWN_RECORD;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void decodeSectorRecord()
 | 
					        /* For all but the first sector, seek to the next sector pulse.
 | 
				
			||||||
	{
 | 
					         * The first sector does not contain the sector pulse in the fluxmap.
 | 
				
			||||||
		auto rawbits = readRawBits(MICROPOLIS_ENCODED_SECTOR_SIZE*16);
 | 
					         */
 | 
				
			||||||
		auto bytes = decodeFmMfm(rawbits).slice(0, MICROPOLIS_ENCODED_SECTOR_SIZE);
 | 
					        if (now != 0)
 | 
				
			||||||
		ByteReader br(bytes);
 | 
					        {
 | 
				
			||||||
 | 
					            seekToIndexMark();
 | 
				
			||||||
 | 
					            now = tell().ns();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		br.read_8();  /* sync */
 | 
					        /* Discard a possible partial sector at the end of the track.
 | 
				
			||||||
		_sector->logicalTrack = br.read_8();
 | 
					         * This partial sector could be mistaken for a conflicted sector, if
 | 
				
			||||||
		_sector->logicalSide = _sector->physicalHead;
 | 
					         * whatever data read happens to match the checksum of 0, which is
 | 
				
			||||||
		_sector->logicalSector = br.read_8();
 | 
					         * rare, but has been observed on some disks.
 | 
				
			||||||
		if (_sector->logicalSector > 15)
 | 
					         */
 | 
				
			||||||
			return;
 | 
					        if (now > (getFluxmapDuration() - 12.5e6))
 | 
				
			||||||
		if (_sector->logicalTrack > 77)
 | 
					        {
 | 
				
			||||||
			return;
 | 
					            seekToIndexMark();
 | 
				
			||||||
 | 
					            return 0;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		br.read(10);  /* OS data or padding */
 | 
					        nanoseconds_t clock = seekToPattern(SECTOR_SYNC_PATTERN);
 | 
				
			||||||
		_sector->data = br.read(256);
 | 
					 | 
				
			||||||
		uint8_t wantChecksum = br.read_8();
 | 
					 | 
				
			||||||
		uint8_t gotChecksum = micropolisChecksum(bytes.slice(1, 2+266));
 | 
					 | 
				
			||||||
		br.read(5);  /* 4 byte ECC and ECC-present flag */
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		_sector->status = (wantChecksum == gotChecksum) ? Sector::OK : Sector::BAD_CHECKSUM;
 | 
					        auto syncDelta = tell().ns() - now;
 | 
				
			||||||
	}
 | 
					        /* Due to the weak nature of the Micropolis SYNC patern,
 | 
				
			||||||
 | 
					         * it's possible to detect a false SYNC during the gap
 | 
				
			||||||
 | 
					         * between the sector pulse and the write gate.  If the SYNC
 | 
				
			||||||
 | 
					         * is detected less than 100uS after the sector pulse, search
 | 
				
			||||||
 | 
					         * for another valid SYNC.
 | 
				
			||||||
 | 
					         *
 | 
				
			||||||
 | 
					         * Reference: Vector Micropolis Disk Controller Board Technical
 | 
				
			||||||
 | 
					         * Information Manual, pp. 1-16.
 | 
				
			||||||
 | 
					         */
 | 
				
			||||||
 | 
					        if ((syncDelta > 0) && (syncDelta < 100e3))
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            seekToPattern(SECTOR_ADVANCE_PATTERN);
 | 
				
			||||||
 | 
					            clock = seekToPattern(SECTOR_SYNC_PATTERN);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        _sector->headerStartTime = tell().ns();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /* seekToPattern() can skip past the index hole, if this happens
 | 
				
			||||||
 | 
					         * too close to the end of the Fluxmap, discard the sector.
 | 
				
			||||||
 | 
					         */
 | 
				
			||||||
 | 
					        if (_sector->headerStartTime > (getFluxmapDuration() - 12.5e6))
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return 0;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return clock;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void decodeSectorRecord() override
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        readRawBits(48);
 | 
				
			||||||
 | 
					        auto rawbits = readRawBits(MICROPOLIS_ENCODED_SECTOR_SIZE * 16);
 | 
				
			||||||
 | 
					        auto bytes =
 | 
				
			||||||
 | 
					            decodeFmMfm(rawbits).slice(0, MICROPOLIS_ENCODED_SECTOR_SIZE);
 | 
				
			||||||
 | 
					        ByteReader br(bytes);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        int syncByte = br.read_8(); /* sync */
 | 
				
			||||||
 | 
					        if (syncByte != 0xFF)
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        _sector->logicalTrack = br.read_8();
 | 
				
			||||||
 | 
					        _sector->logicalSide = _sector->physicalSide;
 | 
				
			||||||
 | 
					        _sector->logicalSector = br.read_8();
 | 
				
			||||||
 | 
					        if (_sector->logicalSector > 15)
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        if (_sector->logicalTrack > 76)
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        if (_sector->logicalTrack != _sector->physicalTrack)
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        br.read(10); /* OS data or padding */
 | 
				
			||||||
 | 
					        auto data = br.read(MICROPOLIS_PAYLOAD_SIZE);
 | 
				
			||||||
 | 
					        uint8_t wantChecksum = br.read_8();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /* If not specified, automatically determine the checksum type.
 | 
				
			||||||
 | 
					         * Once the checksum type is determined, it will be used for the
 | 
				
			||||||
 | 
					         * entire disk.
 | 
				
			||||||
 | 
					         */
 | 
				
			||||||
 | 
					        if (_checksumType == MicropolisDecoderProto::AUTO)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            /* Calculate both standard Micropolis (MDOS, CP/M, OASIS) and MZOS
 | 
				
			||||||
 | 
					             * checksums */
 | 
				
			||||||
 | 
					            if (wantChecksum == micropolisChecksum(bytes.slice(1, 2 + 266)))
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                _checksumType = MicropolisDecoderProto::MICROPOLIS;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else if (wantChecksum ==
 | 
				
			||||||
 | 
					                     mzosChecksum(bytes.slice(
 | 
				
			||||||
 | 
					                         MICROPOLIS_HEADER_SIZE, MICROPOLIS_PAYLOAD_SIZE)))
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                _checksumType = MicropolisDecoderProto::MZOS;
 | 
				
			||||||
 | 
					                std::cout << "Note: MZOS checksum detected." << std::endl;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        uint8_t gotChecksum;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (_checksumType == MicropolisDecoderProto::MZOS)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            gotChecksum = mzosChecksum(
 | 
				
			||||||
 | 
					                bytes.slice(MICROPOLIS_HEADER_SIZE, MICROPOLIS_PAYLOAD_SIZE));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            gotChecksum = micropolisChecksum(bytes.slice(1, 2 + 266));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        br.read(5); /* 4 byte ECC and ECC-present flag */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (_config.sector_output_size() == MICROPOLIS_PAYLOAD_SIZE)
 | 
				
			||||||
 | 
					            _sector->data = data;
 | 
				
			||||||
 | 
					        else if (_config.sector_output_size() == MICROPOLIS_ENCODED_SECTOR_SIZE)
 | 
				
			||||||
 | 
					            _sector->data = bytes;
 | 
				
			||||||
 | 
					        else
 | 
				
			||||||
 | 
					            error("Sector output size may only be 256 or 275");
 | 
				
			||||||
 | 
					        _sector->status =
 | 
				
			||||||
 | 
					            (wantChecksum == gotChecksum) ? Sector::OK : Sector::BAD_CHECKSUM;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private:
 | 
				
			||||||
 | 
					    const MicropolisDecoderProto& _config;
 | 
				
			||||||
 | 
					    MicropolisDecoderProto_ChecksumType
 | 
				
			||||||
 | 
					        _checksumType; /* -1 = auto, 1 = Micropolis, 2=MZOS */
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
std::unique_ptr<AbstractDecoder> createMicropolisDecoder(const DecoderProto& config)
 | 
					std::unique_ptr<Decoder> createMicropolisDecoder(const DecoderProto& config)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return std::unique_ptr<AbstractDecoder>(new MicropolisDecoder(config));
 | 
					    return std::unique_ptr<Decoder>(new MicropolisDecoder(config));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,108 +6,106 @@
 | 
				
			|||||||
#include "image.h"
 | 
					#include "image.h"
 | 
				
			||||||
#include "lib/encoders/encoders.pb.h"
 | 
					#include "lib/encoders/encoders.pb.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void write_sector(std::vector<bool>& bits, unsigned& cursor, const std::shared_ptr<Sector>& sector)
 | 
					static void write_sector(std::vector<bool>& bits,
 | 
				
			||||||
 | 
					    unsigned& cursor,
 | 
				
			||||||
 | 
					    const std::shared_ptr<const Sector>& sector)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if ((sector->data.size() != 256) && (sector->data.size() != MICROPOLIS_ENCODED_SECTOR_SIZE))
 | 
					    if ((sector->data.size() != 256) &&
 | 
				
			||||||
		Error() << "unsupported sector size --- you must pick 256 or 275";
 | 
					        (sector->data.size() != MICROPOLIS_ENCODED_SECTOR_SIZE))
 | 
				
			||||||
 | 
					        error("unsupported sector size --- you must pick 256 or 275");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	int fullSectorSize = 40 + MICROPOLIS_ENCODED_SECTOR_SIZE + 40 + 35;
 | 
					    int fullSectorSize = 40 + MICROPOLIS_ENCODED_SECTOR_SIZE + 40 + 35;
 | 
				
			||||||
	auto fullSector = std::make_shared<std::vector<uint8_t>>();
 | 
					    auto fullSector = std::make_shared<std::vector<uint8_t>>();
 | 
				
			||||||
	fullSector->reserve(fullSectorSize);
 | 
					    fullSector->reserve(fullSectorSize);
 | 
				
			||||||
	/* sector preamble */
 | 
					    /* sector preamble */
 | 
				
			||||||
	for (int i=0; i<40; i++)
 | 
					    for (int i = 0; i < 40; i++)
 | 
				
			||||||
		fullSector->push_back(0);
 | 
					        fullSector->push_back(0);
 | 
				
			||||||
	Bytes sectorData;
 | 
					    Bytes sectorData;
 | 
				
			||||||
	if (sector->data.size() == MICROPOLIS_ENCODED_SECTOR_SIZE)
 | 
					    if (sector->data.size() == MICROPOLIS_ENCODED_SECTOR_SIZE)
 | 
				
			||||||
		sectorData = sector->data;
 | 
					    {
 | 
				
			||||||
	else
 | 
					        if (sector->data[0] != 0xFF)
 | 
				
			||||||
	{
 | 
					            error(
 | 
				
			||||||
		ByteWriter writer(sectorData);
 | 
					                "275 byte sector doesn't start with sync byte 0xFF. "
 | 
				
			||||||
		writer.write_8(0xff); /* Sync */
 | 
					                "Corrupted sector");
 | 
				
			||||||
		writer.write_8(sector->logicalTrack);
 | 
					        uint8_t wantChecksum = sector->data[1 + 2 + 266];
 | 
				
			||||||
		writer.write_8(sector->logicalSector);
 | 
					        uint8_t gotChecksum =
 | 
				
			||||||
		for (int i=0; i<10; i++)
 | 
					            micropolisChecksum(sector->data.slice(1, 2 + 266));
 | 
				
			||||||
			writer.write_8(0); /* Padding */
 | 
					        if (wantChecksum != gotChecksum)
 | 
				
			||||||
		writer += sector->data;
 | 
					            std::cerr << "Warning: checksum incorrect. Sector: "
 | 
				
			||||||
		writer.write_8(micropolisChecksum(sectorData.slice(1)));
 | 
					                      << sector->logicalSector << std::endl;
 | 
				
			||||||
		for (int i=0; i<5; i++)
 | 
					        sectorData = sector->data;
 | 
				
			||||||
			writer.write_8(0); /* 4 byte ECC and ECC not present flag */
 | 
					    }
 | 
				
			||||||
	}
 | 
					    else
 | 
				
			||||||
	for (uint8_t b : sectorData)
 | 
					    {
 | 
				
			||||||
		fullSector->push_back(b);
 | 
					        ByteWriter writer(sectorData);
 | 
				
			||||||
	/* sector postamble */
 | 
					        writer.write_8(0xff); /* Sync */
 | 
				
			||||||
	for (int i=0; i<40; i++)
 | 
					        writer.write_8(sector->logicalTrack);
 | 
				
			||||||
		fullSector->push_back(0);
 | 
					        writer.write_8(sector->logicalSector);
 | 
				
			||||||
	/* filler */
 | 
					        for (int i = 0; i < 10; i++)
 | 
				
			||||||
	for (int i=0; i<35; i++)
 | 
					            writer.write_8(0); /* Padding */
 | 
				
			||||||
		fullSector->push_back(0);
 | 
					        writer += sector->data;
 | 
				
			||||||
 | 
					        writer.write_8(micropolisChecksum(sectorData.slice(1)));
 | 
				
			||||||
 | 
					        for (int i = 0; i < 5; i++)
 | 
				
			||||||
 | 
					            writer.write_8(0); /* 4 byte ECC and ECC not present flag */
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    for (uint8_t b : sectorData)
 | 
				
			||||||
 | 
					        fullSector->push_back(b);
 | 
				
			||||||
 | 
					    /* sector postamble */
 | 
				
			||||||
 | 
					    for (int i = 0; i < 40; i++)
 | 
				
			||||||
 | 
					        fullSector->push_back(0);
 | 
				
			||||||
 | 
					    /* filler */
 | 
				
			||||||
 | 
					    for (int i = 0; i < 35; i++)
 | 
				
			||||||
 | 
					        fullSector->push_back(0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (fullSector->size() != fullSectorSize)
 | 
					    if (fullSector->size() != fullSectorSize)
 | 
				
			||||||
		Error() << "sector mismatched length";
 | 
					        error("sector mismatched length");
 | 
				
			||||||
	bool lastBit = false;
 | 
					    bool lastBit = false;
 | 
				
			||||||
	encodeMfm(bits, cursor, fullSector, lastBit);
 | 
					    encodeMfm(bits, cursor, fullSector, lastBit);
 | 
				
			||||||
	/* filler */
 | 
					    /* filler */
 | 
				
			||||||
	for (int i=0; i<5; i++)
 | 
					    for (int i = 0; i < 5; i++)
 | 
				
			||||||
	{
 | 
					    {
 | 
				
			||||||
		bits[cursor++] = 1;
 | 
					        bits[cursor++] = 1;
 | 
				
			||||||
		bits[cursor++] = 0;
 | 
					        bits[cursor++] = 0;
 | 
				
			||||||
	}
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class MicropolisEncoder : public AbstractEncoder
 | 
					class MicropolisEncoder : public Encoder
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
	MicropolisEncoder(const EncoderProto& config):
 | 
					    MicropolisEncoder(const EncoderProto& config):
 | 
				
			||||||
		AbstractEncoder(config),
 | 
					        Encoder(config),
 | 
				
			||||||
		_config(config.micropolis())
 | 
					        _config(config.micropolis())
 | 
				
			||||||
	{}
 | 
					    {
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	std::vector<std::shared_ptr<Sector>> collectSectors(int physicalTrack, int physicalSide, const Image& image) override
 | 
					    std::unique_ptr<Fluxmap> encode(std::shared_ptr<const TrackInfo>& trackInfo,
 | 
				
			||||||
	{
 | 
					        const std::vector<std::shared_ptr<const Sector>>& sectors,
 | 
				
			||||||
		std::vector<std::shared_ptr<Sector>> sectors;
 | 
					        const Image& image) override
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        int bitsPerRevolution =
 | 
				
			||||||
 | 
					            (_config.rotational_period_ms() * 1e3) / _config.clock_period_us();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if ((physicalTrack >= 0) && (physicalTrack < 77))
 | 
					        std::vector<bool> bits(bitsPerRevolution);
 | 
				
			||||||
		{
 | 
					        unsigned cursor = 0;
 | 
				
			||||||
			for (int sectorId = 0; sectorId < 16; sectorId++)
 | 
					 | 
				
			||||||
			{
 | 
					 | 
				
			||||||
				const auto& sector = image.get(physicalTrack, physicalSide, sectorId);
 | 
					 | 
				
			||||||
				if (sector)
 | 
					 | 
				
			||||||
					sectors.push_back(sector);
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		return sectors;
 | 
					        for (const auto& sectorData : sectors)
 | 
				
			||||||
	}
 | 
					            write_sector(bits, cursor, sectorData);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	std::unique_ptr<Fluxmap> encode(int physicalTrack, int physicalSide,
 | 
					        if (cursor != bits.size())
 | 
				
			||||||
			const std::vector<std::shared_ptr<Sector>>& sectors, const Image& image) override
 | 
					            error("track data mismatched length");
 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		int bitsPerRevolution = 100000;
 | 
					 | 
				
			||||||
		double clockRateUs = 2.00;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if ((physicalTrack < 0) || (physicalTrack >= 77) || sectors.empty())
 | 
					        std::unique_ptr<Fluxmap> fluxmap(new Fluxmap);
 | 
				
			||||||
			return std::unique_ptr<Fluxmap>();
 | 
					        fluxmap->appendBits(bits,
 | 
				
			||||||
 | 
					            calculatePhysicalClockPeriod(_config.clock_period_us() * 1e3,
 | 
				
			||||||
		std::vector<bool> bits(bitsPerRevolution);
 | 
					                _config.rotational_period_ms() * 1e6));
 | 
				
			||||||
		unsigned cursor = 0;
 | 
					        return fluxmap;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
		for (const auto& sectorData : sectors)
 | 
					 | 
				
			||||||
			write_sector(bits, cursor, sectorData);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (cursor != bits.size())
 | 
					 | 
				
			||||||
			Error() << "track data mismatched length";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		std::unique_ptr<Fluxmap> fluxmap(new Fluxmap);
 | 
					 | 
				
			||||||
		fluxmap->appendBits(bits, clockRateUs * 1e3);
 | 
					 | 
				
			||||||
		return fluxmap;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
	const MicropolisEncoderProto& _config;
 | 
					    const MicropolisEncoderProto& _config;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
std::unique_ptr<AbstractEncoder> createMicropolisEncoder(const EncoderProto& config)
 | 
					std::unique_ptr<Encoder> createMicropolisEncoder(const EncoderProto& config)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return std::unique_ptr<AbstractEncoder>(new MicropolisEncoder(config));
 | 
					    return std::unique_ptr<Encoder>(new MicropolisEncoder(config));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,15 +1,20 @@
 | 
				
			|||||||
#ifndef MICROPOLIS_H
 | 
					#ifndef MICROPOLIS_H
 | 
				
			||||||
#define MICROPOLIS_H
 | 
					#define MICROPOLIS_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define MICROPOLIS_ENCODED_SECTOR_SIZE (1+2+266+6)
 | 
					#define MICROPOLIS_PAYLOAD_SIZE (256)
 | 
				
			||||||
 | 
					#define MICROPOLIS_HEADER_SIZE (1 + 2 + 10)
 | 
				
			||||||
 | 
					#define MICROPOLIS_ENCODED_SECTOR_SIZE \
 | 
				
			||||||
 | 
					    (MICROPOLIS_HEADER_SIZE + MICROPOLIS_PAYLOAD_SIZE + 6)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class AbstractDecoder;
 | 
					class Decoder;
 | 
				
			||||||
class AbstractEncoder;
 | 
					class Encoder;
 | 
				
			||||||
class EncoderProto;
 | 
					class EncoderProto;
 | 
				
			||||||
class DecoderProto;
 | 
					class DecoderProto;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern std::unique_ptr<AbstractDecoder> createMicropolisDecoder(const DecoderProto& config);
 | 
					extern std::unique_ptr<Decoder> createMicropolisDecoder(
 | 
				
			||||||
extern std::unique_ptr<AbstractEncoder> createMicropolisEncoder(const EncoderProto& config);
 | 
					    const DecoderProto& config);
 | 
				
			||||||
 | 
					extern std::unique_ptr<Encoder> createMicropolisEncoder(
 | 
				
			||||||
 | 
					    const EncoderProto& config);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern uint8_t micropolisChecksum(const Bytes& bytes);
 | 
					extern uint8_t micropolisChecksum(const Bytes& bytes);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,24 @@
 | 
				
			|||||||
syntax = "proto2";
 | 
					syntax = "proto2";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
message MicropolisDecoderProto {}
 | 
					import "lib/common.proto";
 | 
				
			||||||
message MicropolisEncoderProto {}
 | 
					
 | 
				
			||||||
 | 
					message MicropolisDecoderProto {
 | 
				
			||||||
 | 
						enum ChecksumType {
 | 
				
			||||||
 | 
							AUTO = 0;
 | 
				
			||||||
 | 
							MICROPOLIS = 1;
 | 
				
			||||||
 | 
							MZOS = 2;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						optional int32 sector_output_size = 1 [default = 256,
 | 
				
			||||||
 | 
							(help) = "How much of the raw sector should be saved. Must be 256 or 275"];
 | 
				
			||||||
 | 
						optional ChecksumType checksum_type = 2 [default = AUTO,
 | 
				
			||||||
 | 
							(help) = "Checksum type to use: AUTO, MICROPOLIS, MZOS"];
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					message MicropolisEncoderProto {
 | 
				
			||||||
 | 
					    optional double clock_period_us = 1
 | 
				
			||||||
 | 
					        [ default = 2.0, (help) = "clock rate on the real device" ];
 | 
				
			||||||
 | 
					    optional double rotational_period_ms = 2
 | 
				
			||||||
 | 
					        [ default = 200.0, (help) = "rotational period on the real device" ];
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -16,78 +16,68 @@ const int SECTOR_SIZE = 256;
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* FM beginning of track marker:
 | 
					/* FM beginning of track marker:
 | 
				
			||||||
 | 
					 *         0         0         f         3 decoded nibbles
 | 
				
			||||||
 | 
					 *  0 0  0 0  0 0  0 0  1 1  1 1  0 0  1 1
 | 
				
			||||||
 * 1010 1010 1010 1010 1111 1111 1010 1111
 | 
					 * 1010 1010 1010 1010 1111 1111 1010 1111
 | 
				
			||||||
 *    a    a    a    a    f    f    a    f
 | 
					 *    a    a    a    a    f    f    a    f encoded nibbles
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
const FluxPattern ID_PATTERN(32, 0xaaaaffaf);
 | 
					const FluxPattern ID_PATTERN(32, 0xaaaaffaf);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class MxDecoder : public AbstractDecoder
 | 
					class MxDecoder : public Decoder
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
	MxDecoder(const DecoderProto& config):
 | 
					    MxDecoder(const DecoderProto& config): Decoder(config) {}
 | 
				
			||||||
		AbstractDecoder(config)
 | 
					 | 
				
			||||||
	{}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void beginTrack()
 | 
					    void beginTrack() override
 | 
				
			||||||
	{
 | 
					    {
 | 
				
			||||||
		_currentSector = -1;
 | 
					        _clock = _sector->clock = seekToPattern(ID_PATTERN);
 | 
				
			||||||
		_clock = 0;
 | 
					        _currentSector = 0;
 | 
				
			||||||
	}
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    RecordType advanceToNextRecord()
 | 
					    nanoseconds_t advanceToNextRecord() override
 | 
				
			||||||
	{
 | 
					    {
 | 
				
			||||||
		if (_currentSector == -1)
 | 
					        if (_currentSector == 11)
 | 
				
			||||||
		{
 | 
					        {
 | 
				
			||||||
			/* First sector in the track: look for the sync marker. */
 | 
					            /* That was the last sector on the disk. */
 | 
				
			||||||
			const FluxMatcher* matcher = nullptr;
 | 
					            return 0;
 | 
				
			||||||
			_sector->clock = _clock = _fmr->seekToPattern(ID_PATTERN, matcher);
 | 
					        }
 | 
				
			||||||
			readRawBits(32); /* skip the ID mark */
 | 
					        else
 | 
				
			||||||
			_logicalTrack = decodeFmMfm(readRawBits(32)).slice(0, 32).reader().read_be16();
 | 
					            return _clock;
 | 
				
			||||||
		}
 | 
					    }
 | 
				
			||||||
		else if (_currentSector == 10)
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			/* That was the last sector on the disk. */
 | 
					 | 
				
			||||||
			return UNKNOWN_RECORD;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		else
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			/* Otherwise we assume the clock from the first sector is still valid.
 | 
					 | 
				
			||||||
			 * The decoder framwork will automatically stop when we hit the end of
 | 
					 | 
				
			||||||
			 * the track. */
 | 
					 | 
				
			||||||
			_sector->clock = _clock;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		_currentSector++;
 | 
					    void decodeSectorRecord() override
 | 
				
			||||||
		return SECTOR_RECORD;
 | 
					    {
 | 
				
			||||||
	}
 | 
					        /* Skip the ID pattern and track word, which is only present on the
 | 
				
			||||||
 | 
					         * first sector. We don't trust the track word because some driver
 | 
				
			||||||
 | 
					         * don't write it correctly. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void decodeSectorRecord()
 | 
					        if (_currentSector == 0)
 | 
				
			||||||
	{
 | 
					            readRawBits(64);
 | 
				
			||||||
		auto bits = readRawBits((SECTOR_SIZE+2)*16);
 | 
					 | 
				
			||||||
		auto bytes = decodeFmMfm(bits).slice(0, SECTOR_SIZE+2).swab();
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		uint16_t gotChecksum = 0;
 | 
					        auto bits = readRawBits((SECTOR_SIZE + 2) * 16);
 | 
				
			||||||
		ByteReader br(bytes);
 | 
					        auto bytes = decodeFmMfm(bits).slice(0, SECTOR_SIZE + 2);
 | 
				
			||||||
		for (int i=0; i<(SECTOR_SIZE/2); i++)
 | 
					 | 
				
			||||||
			gotChecksum += br.read_le16();
 | 
					 | 
				
			||||||
		uint16_t wantChecksum = br.read_le16();
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		_sector->logicalTrack = _logicalTrack;
 | 
					        uint16_t gotChecksum = 0;
 | 
				
			||||||
		_sector->logicalSide = _sector->physicalHead;
 | 
					        ByteReader br(bytes);
 | 
				
			||||||
		_sector->logicalSector = _currentSector;
 | 
					        for (int i = 0; i < (SECTOR_SIZE / 2); i++)
 | 
				
			||||||
		_sector->data = bytes.slice(0, SECTOR_SIZE);
 | 
					            gotChecksum += br.read_be16();
 | 
				
			||||||
		_sector->status = (gotChecksum == wantChecksum) ? Sector::OK : Sector::BAD_CHECKSUM;
 | 
					        uint16_t wantChecksum = br.read_be16();
 | 
				
			||||||
	}
 | 
					
 | 
				
			||||||
 | 
					        _sector->logicalTrack = _sector->physicalTrack;
 | 
				
			||||||
 | 
					        _sector->logicalSide = _sector->physicalSide;
 | 
				
			||||||
 | 
					        _sector->logicalSector = _currentSector;
 | 
				
			||||||
 | 
					        _sector->data = bytes.slice(0, SECTOR_SIZE).swab();
 | 
				
			||||||
 | 
					        _sector->status =
 | 
				
			||||||
 | 
					            (gotChecksum == wantChecksum) ? Sector::OK : Sector::BAD_CHECKSUM;
 | 
				
			||||||
 | 
					        _currentSector++;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
    nanoseconds_t _clock;
 | 
					    nanoseconds_t _clock;
 | 
				
			||||||
    int _currentSector;
 | 
					    int _currentSector;
 | 
				
			||||||
    int _logicalTrack;
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
std::unique_ptr<AbstractDecoder> createMxDecoder(const DecoderProto& config)
 | 
					std::unique_ptr<Decoder> createMxDecoder(const DecoderProto& config)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return std::unique_ptr<AbstractDecoder>(new MxDecoder(config));
 | 
					    return std::unique_ptr<Decoder>(new MxDecoder(config));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,6 +3,6 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include "decoders/decoders.h"
 | 
					#include "decoders/decoders.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern std::unique_ptr<AbstractDecoder> createMxDecoder(const DecoderProto& config);
 | 
					extern std::unique_ptr<Decoder> createMxDecoder(const DecoderProto& config);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -21,6 +21,8 @@
 | 
				
			|||||||
#include "lib/decoders/decoders.pb.h"
 | 
					#include "lib/decoders/decoders.pb.h"
 | 
				
			||||||
#include "fmt/format.h"
 | 
					#include "fmt/format.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define MFM_ID 0xaaaaaaaaaaaa5545LL
 | 
				
			||||||
 | 
					#define FM_ID 0xaaaaaaaaaaaaffefLL
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * MFM sectors have 32 bytes of 00's followed by two sync characters,
 | 
					 * MFM sectors have 32 bytes of 00's followed by two sync characters,
 | 
				
			||||||
 * specified in the North Star MDS manual as 0xFBFB.
 | 
					 * specified in the North Star MDS manual as 0xFBFB.
 | 
				
			||||||
@@ -33,164 +35,152 @@
 | 
				
			|||||||
 * 0000 0000 0000 0000 0000 0000 0101 0101 0100 0101
 | 
					 * 0000 0000 0000 0000 0000 0000 0101 0101 0100 0101
 | 
				
			||||||
 * A    A    A    A    A    A    5    5    4    5
 | 
					 * A    A    A    A    A    A    5    5    4    5
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static const FluxPattern MFM_PATTERN(64, 0xAAAAAAAAAAAA5545LL);
 | 
					static const FluxPattern MFM_PATTERN(64, MFM_ID);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* FM sectors have 16 bytes of 00's followed by 0xFB.
 | 
					/* FM sectors have 16 bytes of 00's followed by 0xFB.
 | 
				
			||||||
 * 00        FB
 | 
					 * 00        FB
 | 
				
			||||||
 * 0000 0000 1111 1111 1110 1111
 | 
					 * 0000 0000 1111 1111 1110 1111
 | 
				
			||||||
 * A    A    F    F    E    F
 | 
					 * A    A    F    F    E    F
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static const FluxPattern FM_PATTERN(64, 0xAAAAAAAAAAAAFFEFLL);
 | 
					static const FluxPattern FM_PATTERN(64, FM_ID);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const FluxMatchers ANY_SECTOR_PATTERN(
 | 
					const FluxMatchers ANY_SECTOR_PATTERN({
 | 
				
			||||||
	{
 | 
					    &MFM_PATTERN,
 | 
				
			||||||
		&MFM_PATTERN,
 | 
					    &FM_PATTERN,
 | 
				
			||||||
		&FM_PATTERN,
 | 
					});
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Checksum is initially 0.
 | 
					/* Checksum is initially 0.
 | 
				
			||||||
 * For each data byte, XOR with the current checksum.
 | 
					 * For each data byte, XOR with the current checksum.
 | 
				
			||||||
 * Rotate checksum left, carrying bit 7 to bit 0.
 | 
					 * Rotate checksum left, carrying bit 7 to bit 0.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
uint8_t northstarChecksum(const Bytes& bytes) {
 | 
					uint8_t northstarChecksum(const Bytes& bytes)
 | 
				
			||||||
	ByteReader br(bytes);
 | 
					{
 | 
				
			||||||
	uint8_t checksum = 0;
 | 
					    ByteReader br(bytes);
 | 
				
			||||||
 | 
					    uint8_t checksum = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	while (!br.eof()) {
 | 
					    while (!br.eof())
 | 
				
			||||||
		checksum ^= br.read_8();
 | 
					    {
 | 
				
			||||||
		checksum = ((checksum << 1) | ((checksum >> 7)));
 | 
					        checksum ^= br.read_8();
 | 
				
			||||||
	}
 | 
					        checksum = ((checksum << 1) | ((checksum >> 7)));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return checksum;
 | 
					    return checksum;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class NorthstarDecoder : public AbstractDecoder
 | 
					class NorthstarDecoder : public Decoder
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
	NorthstarDecoder(const DecoderProto& config):
 | 
					    NorthstarDecoder(const DecoderProto& config):
 | 
				
			||||||
		AbstractDecoder(config),
 | 
					        Decoder(config),
 | 
				
			||||||
		_config(config.northstar())
 | 
					        _config(config.northstar())
 | 
				
			||||||
	{}
 | 
					    {
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Search for FM or MFM sector record */
 | 
					    /* Search for FM or MFM sector record */
 | 
				
			||||||
	RecordType advanceToNextRecord() override
 | 
					    nanoseconds_t advanceToNextRecord() override
 | 
				
			||||||
	{
 | 
					    {
 | 
				
			||||||
		nanoseconds_t now = _fmr->tell().ns();
 | 
					        nanoseconds_t now = tell().ns();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* For all but the first sector, seek to the next sector pulse.
 | 
					        /* For all but the first sector, seek to the next sector pulse.
 | 
				
			||||||
		 * The first sector does not contain the sector pulse in the fluxmap.
 | 
					         * The first sector does not contain the sector pulse in the fluxmap.
 | 
				
			||||||
		 */
 | 
					         */
 | 
				
			||||||
		if (now != 0) {
 | 
					        if (now != 0)
 | 
				
			||||||
			_fmr->seekToIndexMark();
 | 
					        {
 | 
				
			||||||
			now = _fmr->tell().ns();
 | 
					            seekToIndexMark();
 | 
				
			||||||
		}
 | 
					            now = tell().ns();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* Discard a possible partial sector at the end of the track.
 | 
					        /* Discard a possible partial sector at the end of the track.
 | 
				
			||||||
		 * This partial sector could be mistaken for a conflicted sector, if
 | 
					         * This partial sector could be mistaken for a conflicted sector, if
 | 
				
			||||||
		 * whatever data read happens to match the checksum of 0, which is
 | 
					         * whatever data read happens to match the checksum of 0, which is
 | 
				
			||||||
		 * rare, but has been observed on some disks.
 | 
					         * rare, but has been observed on some disks.
 | 
				
			||||||
		 */
 | 
					         */
 | 
				
			||||||
		if (now > (_fmr->getDuration() - 21e6)) {
 | 
					        if (now > (getFluxmapDuration() - 21e6))
 | 
				
			||||||
			_fmr->seekToIndexMark();
 | 
					        {
 | 
				
			||||||
			return(UNKNOWN_RECORD);
 | 
					            seekToIndexMark();
 | 
				
			||||||
		}
 | 
					            return 0;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		int msSinceIndex = std::round(now / 1e6);
 | 
					        int msSinceIndex = std::round(now / 1e6);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		const FluxMatcher* matcher = nullptr;
 | 
					        /* Note that the seekToPattern ignores the sector pulses, so if
 | 
				
			||||||
 | 
					         * a sector is not found for some reason, the seek will advance
 | 
				
			||||||
 | 
					         * past one or more sector pulses.  For this reason, calculate
 | 
				
			||||||
 | 
					         * _hardSectorId after the sector header is found.
 | 
				
			||||||
 | 
					         */
 | 
				
			||||||
 | 
					        nanoseconds_t clock = seekToPattern(ANY_SECTOR_PATTERN);
 | 
				
			||||||
 | 
					        _sector->headerStartTime = tell().ns();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* Note that the seekToPattern ignores the sector pulses, so if
 | 
					        /* Discard a possible partial sector. */
 | 
				
			||||||
		 * a sector is not found for some reason, the seek will advance
 | 
					        if (_sector->headerStartTime > (getFluxmapDuration() - 21e6))
 | 
				
			||||||
		 * past one or more sector pulses.  For this reason, calculate
 | 
					        {
 | 
				
			||||||
		 * _hardSectorId after the sector header is found.
 | 
					            return 0;
 | 
				
			||||||
		 */
 | 
					        }
 | 
				
			||||||
		_sector->clock = _fmr->seekToPattern(ANY_SECTOR_PATTERN, matcher);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		int sectorFoundTimeRaw = std::round((_fmr->tell().ns()) / 1e6);
 | 
					        int sectorFoundTimeRaw = std::round(_sector->headerStartTime / 1e6);
 | 
				
			||||||
		int sectorFoundTime;
 | 
					        int sectorFoundTime;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* Round time to the nearest 20ms */
 | 
					        /* Round time to the nearest 20ms */
 | 
				
			||||||
		if ((sectorFoundTimeRaw % 20) < 10) {
 | 
					        if ((sectorFoundTimeRaw % 20) < 10)
 | 
				
			||||||
			sectorFoundTime = (sectorFoundTimeRaw / 20) * 20;
 | 
					        {
 | 
				
			||||||
		}
 | 
					            sectorFoundTime = (sectorFoundTimeRaw / 20) * 20;
 | 
				
			||||||
		else {
 | 
					        }
 | 
				
			||||||
			sectorFoundTime = ((sectorFoundTimeRaw + 20) / 20) * 20;
 | 
					        else
 | 
				
			||||||
		}
 | 
					        {
 | 
				
			||||||
 | 
					            sectorFoundTime = ((sectorFoundTimeRaw + 20) / 20) * 20;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* Calculate the sector ID based on time since the index */
 | 
					        /* Calculate the sector ID based on time since the index */
 | 
				
			||||||
		_hardSectorId = (sectorFoundTime / 20) % 10;
 | 
					        _hardSectorId = (sectorFoundTime / 20) % 10;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	//	std::cout << fmt::format(
 | 
					        return clock;
 | 
				
			||||||
	//		"Sector ID {}: hole at {}ms, sector start at {}ms",
 | 
					    }
 | 
				
			||||||
	//		_hardSectorId, msSinceIndex, sectorFoundTimeRaw) << std::endl;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (matcher == &MFM_PATTERN) {
 | 
					    void decodeSectorRecord() override
 | 
				
			||||||
			_sectorType = SECTOR_TYPE_MFM;
 | 
					    {
 | 
				
			||||||
			readRawBits(48);
 | 
					        uint64_t id = toBytes(readRawBits(64)).reader().read_be64();
 | 
				
			||||||
			return SECTOR_RECORD;
 | 
					        unsigned recordSize, payloadSize, headerSize;
 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (matcher == &FM_PATTERN) {
 | 
					        if (id == MFM_ID)
 | 
				
			||||||
			_sectorType = SECTOR_TYPE_FM;
 | 
					        {
 | 
				
			||||||
			readRawBits(48);
 | 
					            recordSize = NORTHSTAR_ENCODED_SECTOR_SIZE_DD;
 | 
				
			||||||
			return SECTOR_RECORD;
 | 
					            payloadSize = NORTHSTAR_PAYLOAD_SIZE_DD;
 | 
				
			||||||
		}
 | 
					            headerSize = NORTHSTAR_HEADER_SIZE_DD;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            recordSize = NORTHSTAR_ENCODED_SECTOR_SIZE_SD;
 | 
				
			||||||
 | 
					            payloadSize = NORTHSTAR_PAYLOAD_SIZE_SD;
 | 
				
			||||||
 | 
					            headerSize = NORTHSTAR_HEADER_SIZE_SD;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		return UNKNOWN_RECORD;
 | 
					        auto rawbits = readRawBits(recordSize * 16);
 | 
				
			||||||
	}
 | 
					        auto bytes = decodeFmMfm(rawbits).slice(0, recordSize);
 | 
				
			||||||
 | 
					        ByteReader br(bytes);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void decodeSectorRecord() override
 | 
					        _sector->logicalSide = _sector->physicalSide;
 | 
				
			||||||
	{
 | 
					        _sector->logicalSector = _hardSectorId;
 | 
				
			||||||
		unsigned recordSize, payloadSize, headerSize;
 | 
					        _sector->logicalTrack = _sector->physicalTrack;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (_sectorType == SECTOR_TYPE_MFM) {
 | 
					        if (headerSize == NORTHSTAR_HEADER_SIZE_DD)
 | 
				
			||||||
			recordSize = NORTHSTAR_ENCODED_SECTOR_SIZE_DD;
 | 
					        {
 | 
				
			||||||
			payloadSize = NORTHSTAR_PAYLOAD_SIZE_DD;
 | 
					            br.read_8(); /* MFM second Sync char, usually 0xFB */
 | 
				
			||||||
			headerSize = NORTHSTAR_HEADER_SIZE_DD;
 | 
					        }
 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		else {
 | 
					 | 
				
			||||||
			recordSize = NORTHSTAR_ENCODED_SECTOR_SIZE_SD;
 | 
					 | 
				
			||||||
			payloadSize = NORTHSTAR_PAYLOAD_SIZE_SD;
 | 
					 | 
				
			||||||
			headerSize = NORTHSTAR_HEADER_SIZE_SD;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		auto rawbits = readRawBits(recordSize * 16);
 | 
					        _sector->data = br.read(payloadSize);
 | 
				
			||||||
		auto bytes = decodeFmMfm(rawbits).slice(0, recordSize);
 | 
					        uint8_t wantChecksum = br.read_8();
 | 
				
			||||||
		ByteReader br(bytes);
 | 
					        uint8_t gotChecksum =
 | 
				
			||||||
		uint8_t sync_char;
 | 
					            northstarChecksum(bytes.slice(headerSize - 1, payloadSize));
 | 
				
			||||||
 | 
					        _sector->status =
 | 
				
			||||||
		_sector->logicalSide = _sector->physicalHead;
 | 
					            (wantChecksum == gotChecksum) ? Sector::OK : Sector::BAD_CHECKSUM;
 | 
				
			||||||
		_sector->logicalSector = _hardSectorId;
 | 
					    }
 | 
				
			||||||
		_sector->logicalTrack = _sector->physicalCylinder;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		sync_char = br.read_8();	/* Sync char: 0xFB */
 | 
					 | 
				
			||||||
		if (_sectorType == SECTOR_TYPE_MFM) {
 | 
					 | 
				
			||||||
			sync_char = br.read_8();/* MFM second Sync char, usually 0xFB */
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		_sector->data = br.read(payloadSize);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		uint8_t wantChecksum = br.read_8();
 | 
					 | 
				
			||||||
		uint8_t gotChecksum = northstarChecksum(bytes.slice(headerSize, payloadSize));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		_sector->status = (wantChecksum == gotChecksum) ? Sector::OK : Sector::BAD_CHECKSUM;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	std::set<unsigned> requiredSectors(unsigned cylinder, unsigned head) const override
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		static std::set<unsigned> sectors = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
 | 
					 | 
				
			||||||
		return sectors;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
	const NorthstarDecoderProto& _config;
 | 
					    const NorthstarDecoderProto& _config;
 | 
				
			||||||
	uint8_t _sectorType = SECTOR_TYPE_MFM;
 | 
					    uint8_t _hardSectorId;
 | 
				
			||||||
	uint8_t _hardSectorId;
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
std::unique_ptr<AbstractDecoder> createNorthstarDecoder(const DecoderProto& config)
 | 
					std::unique_ptr<Decoder> createNorthstarDecoder(const DecoderProto& config)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return std::unique_ptr<AbstractDecoder>(new NorthstarDecoder(config));
 | 
					    return std::unique_ptr<Decoder>(new NorthstarDecoder(config));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -12,155 +12,157 @@
 | 
				
			|||||||
#define GAP_FILL_SIZE_DD 62
 | 
					#define GAP_FILL_SIZE_DD 62
 | 
				
			||||||
#define PRE_HEADER_GAP_FILL_SIZE_DD 16
 | 
					#define PRE_HEADER_GAP_FILL_SIZE_DD 16
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define GAP1_FILL_BYTE	(0x4F)
 | 
					#define GAP1_FILL_BYTE (0x4F)
 | 
				
			||||||
#define GAP2_FILL_BYTE	(0x4F)
 | 
					#define GAP2_FILL_BYTE (0x4F)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define TOTAL_SECTOR_BYTES ()
 | 
					#define TOTAL_SECTOR_BYTES ()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void write_sector(std::vector<bool>& bits, unsigned& cursor, const std::shared_ptr<Sector>& sector)
 | 
					static void write_sector(std::vector<bool>& bits,
 | 
				
			||||||
 | 
					    unsigned& cursor,
 | 
				
			||||||
 | 
					    const std::shared_ptr<const Sector>& sector)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int preambleSize = 0;
 | 
					    int preambleSize = 0;
 | 
				
			||||||
	int encodedSectorSize = 0;
 | 
					    int encodedSectorSize = 0;
 | 
				
			||||||
	int gapFillSize = 0;
 | 
					    int gapFillSize = 0;
 | 
				
			||||||
	int preHeaderGapFillSize = 0;
 | 
					    int preHeaderGapFillSize = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool doubleDensity;
 | 
					    bool doubleDensity;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	switch (sector->data.size()) {
 | 
					    switch (sector->data.size())
 | 
				
			||||||
	case NORTHSTAR_PAYLOAD_SIZE_SD:
 | 
					    {
 | 
				
			||||||
		preambleSize = NORTHSTAR_PREAMBLE_SIZE_SD;
 | 
					        case NORTHSTAR_PAYLOAD_SIZE_SD:
 | 
				
			||||||
		encodedSectorSize = PRE_HEADER_GAP_FILL_SIZE_SD + NORTHSTAR_ENCODED_SECTOR_SIZE_SD + GAP_FILL_SIZE_SD;
 | 
					            preambleSize = NORTHSTAR_PREAMBLE_SIZE_SD;
 | 
				
			||||||
		gapFillSize = GAP_FILL_SIZE_SD;
 | 
					            encodedSectorSize = PRE_HEADER_GAP_FILL_SIZE_SD +
 | 
				
			||||||
		preHeaderGapFillSize = PRE_HEADER_GAP_FILL_SIZE_SD;
 | 
					                                NORTHSTAR_ENCODED_SECTOR_SIZE_SD +
 | 
				
			||||||
		doubleDensity = false;
 | 
					                                GAP_FILL_SIZE_SD;
 | 
				
			||||||
		break;
 | 
					            gapFillSize = GAP_FILL_SIZE_SD;
 | 
				
			||||||
	case NORTHSTAR_PAYLOAD_SIZE_DD:
 | 
					            preHeaderGapFillSize = PRE_HEADER_GAP_FILL_SIZE_SD;
 | 
				
			||||||
		preambleSize = NORTHSTAR_PREAMBLE_SIZE_DD;
 | 
					            doubleDensity = false;
 | 
				
			||||||
		encodedSectorSize = PRE_HEADER_GAP_FILL_SIZE_DD + NORTHSTAR_ENCODED_SECTOR_SIZE_DD + GAP_FILL_SIZE_DD;
 | 
					            break;
 | 
				
			||||||
		gapFillSize = GAP_FILL_SIZE_DD;
 | 
					        case NORTHSTAR_PAYLOAD_SIZE_DD:
 | 
				
			||||||
		preHeaderGapFillSize = PRE_HEADER_GAP_FILL_SIZE_DD;
 | 
					            preambleSize = NORTHSTAR_PREAMBLE_SIZE_DD;
 | 
				
			||||||
		doubleDensity = true;
 | 
					            encodedSectorSize = PRE_HEADER_GAP_FILL_SIZE_DD +
 | 
				
			||||||
		break;
 | 
					                                NORTHSTAR_ENCODED_SECTOR_SIZE_DD +
 | 
				
			||||||
	default:
 | 
					                                GAP_FILL_SIZE_DD;
 | 
				
			||||||
		Error() << "unsupported sector size --- you must pick 256 or 512";
 | 
					            gapFillSize = GAP_FILL_SIZE_DD;
 | 
				
			||||||
		break;
 | 
					            preHeaderGapFillSize = PRE_HEADER_GAP_FILL_SIZE_DD;
 | 
				
			||||||
	}
 | 
					            doubleDensity = true;
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        default:
 | 
				
			||||||
 | 
					            error("unsupported sector size --- you must pick 256 or 512");
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	int fullSectorSize = preambleSize + encodedSectorSize;
 | 
					    int fullSectorSize = preambleSize + encodedSectorSize;
 | 
				
			||||||
	auto fullSector = std::make_shared<std::vector<uint8_t>>();
 | 
					    auto fullSector = std::make_shared<std::vector<uint8_t>>();
 | 
				
			||||||
	fullSector->reserve(fullSectorSize);
 | 
					    fullSector->reserve(fullSectorSize);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* sector gap after index pulse */
 | 
					    /* sector gap after index pulse */
 | 
				
			||||||
	for (int i = 0; i < preHeaderGapFillSize; i++)
 | 
					    for (int i = 0; i < preHeaderGapFillSize; i++)
 | 
				
			||||||
		fullSector->push_back(GAP1_FILL_BYTE);
 | 
					        fullSector->push_back(GAP1_FILL_BYTE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* sector preamble */
 | 
					    /* sector preamble */
 | 
				
			||||||
	for (int i = 0; i < preambleSize; i++)
 | 
					    for (int i = 0; i < preambleSize; i++)
 | 
				
			||||||
		fullSector->push_back(0);
 | 
					        fullSector->push_back(0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Bytes sectorData;
 | 
					    Bytes sectorData;
 | 
				
			||||||
	if (sector->data.size() == encodedSectorSize)
 | 
					    if (sector->data.size() == encodedSectorSize)
 | 
				
			||||||
		sectorData = sector->data;
 | 
					        sectorData = sector->data;
 | 
				
			||||||
	else {
 | 
					    else
 | 
				
			||||||
		ByteWriter writer(sectorData);
 | 
					    {
 | 
				
			||||||
		writer.write_8(0xFB);     /* sync character */
 | 
					        ByteWriter writer(sectorData);
 | 
				
			||||||
		if (doubleDensity == true) {
 | 
					        writer.write_8(0xFB); /* sync character */
 | 
				
			||||||
			writer.write_8(0xFB); /* Double-density has two sync characters */
 | 
					        if (doubleDensity == true)
 | 
				
			||||||
		}
 | 
					        {
 | 
				
			||||||
		writer += sector->data;
 | 
					            writer.write_8(0xFB); /* Double-density has two sync characters */
 | 
				
			||||||
		if (doubleDensity == true) {
 | 
					        }
 | 
				
			||||||
			writer.write_8(northstarChecksum(sectorData.slice(2)));
 | 
					        writer += sector->data;
 | 
				
			||||||
		} else {
 | 
					        if (doubleDensity == true)
 | 
				
			||||||
			writer.write_8(northstarChecksum(sectorData.slice(1)));
 | 
					        {
 | 
				
			||||||
		}
 | 
					            writer.write_8(northstarChecksum(sectorData.slice(2)));
 | 
				
			||||||
	}
 | 
					        }
 | 
				
			||||||
	for (uint8_t b : sectorData)
 | 
					        else
 | 
				
			||||||
		fullSector->push_back(b);
 | 
					        {
 | 
				
			||||||
 | 
					            writer.write_8(northstarChecksum(sectorData.slice(1)));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    for (uint8_t b : sectorData)
 | 
				
			||||||
 | 
					        fullSector->push_back(b);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (sector->logicalSector != 9) {
 | 
					    if (sector->logicalSector != 9)
 | 
				
			||||||
		/* sector postamble */
 | 
					    {
 | 
				
			||||||
		for (int i = 0; i < gapFillSize; i++)
 | 
					        /* sector postamble */
 | 
				
			||||||
			fullSector->push_back(GAP2_FILL_BYTE);
 | 
					        for (int i = 0; i < gapFillSize; i++)
 | 
				
			||||||
 | 
					            fullSector->push_back(GAP2_FILL_BYTE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (fullSector->size() != fullSectorSize)
 | 
					        if (fullSector->size() != fullSectorSize)
 | 
				
			||||||
			Error() << "sector mismatched length (" << sector->data.size() << ") expected: " << fullSector->size() << " got " << fullSectorSize;
 | 
					            error("sector mismatched length ({}); expected {}, got {}",
 | 
				
			||||||
	} else {
 | 
					                sector->data.size(),
 | 
				
			||||||
		/* sector postamble */
 | 
					                fullSector->size(),
 | 
				
			||||||
		for (int i = 0; i < gapFillSize; i++)
 | 
					                fullSectorSize);
 | 
				
			||||||
			fullSector->push_back(GAP2_FILL_BYTE);
 | 
					    }
 | 
				
			||||||
	}
 | 
					    else
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        /* sector postamble */
 | 
				
			||||||
 | 
					        for (int i = 0; i < gapFillSize; i++)
 | 
				
			||||||
 | 
					            fullSector->push_back(GAP2_FILL_BYTE);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool lastBit = false;
 | 
					    bool lastBit = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (doubleDensity == true) {
 | 
					    if (doubleDensity == true)
 | 
				
			||||||
		encodeMfm(bits, cursor, fullSector, lastBit);
 | 
					    {
 | 
				
			||||||
	}
 | 
					        encodeMfm(bits, cursor, fullSector, lastBit);
 | 
				
			||||||
	else {
 | 
					    }
 | 
				
			||||||
		encodeFm(bits, cursor, fullSector);
 | 
					    else
 | 
				
			||||||
	}
 | 
					    {
 | 
				
			||||||
 | 
					        encodeFm(bits, cursor, fullSector);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class NorthstarEncoder : public AbstractEncoder
 | 
					class NorthstarEncoder : public Encoder
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
	NorthstarEncoder(const EncoderProto& config):
 | 
					    NorthstarEncoder(const EncoderProto& config):
 | 
				
			||||||
		AbstractEncoder(config),
 | 
					        Encoder(config),
 | 
				
			||||||
		_config(config.northstar())
 | 
					        _config(config.northstar())
 | 
				
			||||||
	{}
 | 
					    {
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	std::vector<std::shared_ptr<Sector>> collectSectors(int physicalTrack, int physicalSide, const Image& image) override
 | 
					    std::unique_ptr<Fluxmap> encode(std::shared_ptr<const TrackInfo>& trackInfo,
 | 
				
			||||||
	{
 | 
					        const std::vector<std::shared_ptr<const Sector>>& sectors,
 | 
				
			||||||
		std::vector<std::shared_ptr<Sector>> sectors;
 | 
					        const Image& image) override
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        int bitsPerRevolution = 100000;
 | 
				
			||||||
 | 
					        double clockRateUs = _config.clock_period_us();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if ((physicalTrack >= 0) && (physicalTrack < 35))
 | 
					        const auto& sector = *sectors.begin();
 | 
				
			||||||
		{
 | 
					        if (sector->data.size() == NORTHSTAR_PAYLOAD_SIZE_SD)
 | 
				
			||||||
			for (int sectorId = 0; sectorId < 10; sectorId++)
 | 
					            bitsPerRevolution /= 2; // FM
 | 
				
			||||||
			{
 | 
					        else
 | 
				
			||||||
				const auto& sector = image.get(physicalTrack, physicalSide, sectorId);
 | 
					            clockRateUs /= 2.00;
 | 
				
			||||||
				if (sector)
 | 
					 | 
				
			||||||
					sectors.push_back(sector);
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		return sectors;
 | 
					        std::vector<bool> bits(bitsPerRevolution);
 | 
				
			||||||
	}
 | 
					        unsigned cursor = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	std::unique_ptr<Fluxmap> encode(int physicalTrack, int physicalSide,
 | 
					        for (const auto& sectorData : sectors)
 | 
				
			||||||
			const std::vector<std::shared_ptr<Sector>>& sectors, const Image& image) override
 | 
					            write_sector(bits, cursor, sectorData);
 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		int bitsPerRevolution = 100000;
 | 
					 | 
				
			||||||
		double clockRateUs = 4.00;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if ((physicalTrack < 0) || (physicalTrack >= 35) || sectors.empty())
 | 
					        if (cursor > bits.size())
 | 
				
			||||||
			return std::unique_ptr<Fluxmap>();
 | 
					            error("track data overrun");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		const auto& sector = *sectors.begin();
 | 
					        std::unique_ptr<Fluxmap> fluxmap(new Fluxmap);
 | 
				
			||||||
		if (sector->data.size() == NORTHSTAR_PAYLOAD_SIZE_SD) {
 | 
					        fluxmap->appendBits(bits,
 | 
				
			||||||
			bitsPerRevolution /= 2;		// FM
 | 
					            calculatePhysicalClockPeriod(
 | 
				
			||||||
		} else {
 | 
					                clockRateUs * 1e3, _config.rotational_period_ms() * 1e6));
 | 
				
			||||||
			clockRateUs /= 2.00;
 | 
					        return fluxmap;
 | 
				
			||||||
		}
 | 
					    }
 | 
				
			||||||
 | 
					 | 
				
			||||||
		std::vector<bool> bits(bitsPerRevolution);
 | 
					 | 
				
			||||||
		unsigned cursor = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		for (const auto& sectorData : sectors)
 | 
					 | 
				
			||||||
			write_sector(bits, cursor, sectorData);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (cursor > bits.size())
 | 
					 | 
				
			||||||
			Error() << "track data overrun";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		std::unique_ptr<Fluxmap> fluxmap(new Fluxmap);
 | 
					 | 
				
			||||||
		fluxmap->appendBits(bits, clockRateUs * 1e3);
 | 
					 | 
				
			||||||
		return fluxmap;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
	const NorthstarEncoderProto& _config;
 | 
					    const NorthstarEncoderProto& _config;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
std::unique_ptr<AbstractEncoder> createNorthstarEncoder(const EncoderProto& config)
 | 
					std::unique_ptr<Encoder> createNorthstarEncoder(const EncoderProto& config)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return std::unique_ptr<AbstractEncoder>(new NorthstarEncoder(config));
 | 
					    return std::unique_ptr<Encoder>(new NorthstarEncoder(config));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,8 @@
 | 
				
			|||||||
#ifndef NORTHSTAR_H
 | 
					#ifndef NORTHSTAR_H
 | 
				
			||||||
#define NORTHSTAR_H
 | 
					#define NORTHSTAR_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Northstar floppies are 10-hard sectored disks with a sector format as follows:
 | 
					/* Northstar floppies are 10-hard sectored disks with a sector format as
 | 
				
			||||||
 | 
					 * follows:
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * |----------------------------------|
 | 
					 * |----------------------------------|
 | 
				
			||||||
 * | SYNC Byte  | Payload  | Checksum |
 | 
					 * | SYNC Byte  | Payload  | Checksum |
 | 
				
			||||||
@@ -12,27 +13,30 @@
 | 
				
			|||||||
 *
 | 
					 *
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define NORTHSTAR_PREAMBLE_SIZE_SD		(16)
 | 
					#define NORTHSTAR_PREAMBLE_SIZE_SD (16)
 | 
				
			||||||
#define NORTHSTAR_PREAMBLE_SIZE_DD		(32)
 | 
					#define NORTHSTAR_PREAMBLE_SIZE_DD (32)
 | 
				
			||||||
#define NORTHSTAR_HEADER_SIZE_SD		(1)
 | 
					#define NORTHSTAR_HEADER_SIZE_SD (1)
 | 
				
			||||||
#define NORTHSTAR_HEADER_SIZE_DD		(2)
 | 
					#define NORTHSTAR_HEADER_SIZE_DD (2)
 | 
				
			||||||
#define NORTHSTAR_PAYLOAD_SIZE_SD		(256)
 | 
					#define NORTHSTAR_PAYLOAD_SIZE_SD (256)
 | 
				
			||||||
#define NORTHSTAR_PAYLOAD_SIZE_DD		(512)
 | 
					#define NORTHSTAR_PAYLOAD_SIZE_DD (512)
 | 
				
			||||||
#define NORTHSTAR_CHECKSUM_SIZE		(1)
 | 
					#define NORTHSTAR_CHECKSUM_SIZE (1)
 | 
				
			||||||
#define NORTHSTAR_ENCODED_SECTOR_SIZE_SD	(NORTHSTAR_HEADER_SIZE_SD + NORTHSTAR_PAYLOAD_SIZE_SD + NORTHSTAR_CHECKSUM_SIZE)
 | 
					#define NORTHSTAR_ENCODED_SECTOR_SIZE_SD                    \
 | 
				
			||||||
#define NORTHSTAR_ENCODED_SECTOR_SIZE_DD	(NORTHSTAR_HEADER_SIZE_DD + NORTHSTAR_PAYLOAD_SIZE_DD + NORTHSTAR_CHECKSUM_SIZE)
 | 
					    (NORTHSTAR_HEADER_SIZE_SD + NORTHSTAR_PAYLOAD_SIZE_SD + \
 | 
				
			||||||
 | 
					        NORTHSTAR_CHECKSUM_SIZE)
 | 
				
			||||||
 | 
					#define NORTHSTAR_ENCODED_SECTOR_SIZE_DD                    \
 | 
				
			||||||
 | 
					    (NORTHSTAR_HEADER_SIZE_DD + NORTHSTAR_PAYLOAD_SIZE_DD + \
 | 
				
			||||||
 | 
					        NORTHSTAR_CHECKSUM_SIZE)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define SECTOR_TYPE_MFM			(0)
 | 
					class Decoder;
 | 
				
			||||||
#define SECTOR_TYPE_FM				(1)
 | 
					class Encoder;
 | 
				
			||||||
 | 
					 | 
				
			||||||
class AbstractDecoder;
 | 
					 | 
				
			||||||
class AbstractEncoder;
 | 
					 | 
				
			||||||
class EncoderProto;
 | 
					class EncoderProto;
 | 
				
			||||||
class DecoderProto;
 | 
					class DecoderProto;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern uint8_t northstarChecksum(const Bytes& bytes);
 | 
					extern uint8_t northstarChecksum(const Bytes& bytes);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern std::unique_ptr<AbstractDecoder> createNorthstarDecoder(const DecoderProto& config);
 | 
					extern std::unique_ptr<Decoder> createNorthstarDecoder(
 | 
				
			||||||
extern std::unique_ptr<AbstractEncoder> createNorthstarEncoder(const EncoderProto& config);
 | 
					    const DecoderProto& config);
 | 
				
			||||||
 | 
					extern std::unique_ptr<Encoder> createNorthstarEncoder(
 | 
				
			||||||
 | 
					    const EncoderProto& config);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif /* NORTHSTAR */
 | 
					#endif /* NORTHSTAR */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,13 @@
 | 
				
			|||||||
syntax = "proto2";
 | 
					syntax = "proto2";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
message NorthstarDecoderProto {}
 | 
					import "lib/common.proto";
 | 
				
			||||||
message NorthstarEncoderProto {}
 | 
					
 | 
				
			||||||
 | 
					message NorthstarDecoderProto {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					message NorthstarEncoderProto {
 | 
				
			||||||
 | 
					    optional double clock_period_us = 1
 | 
				
			||||||
 | 
					        [ default = 4.0, (help) = "clock rate on the real device (for FM)" ];
 | 
				
			||||||
 | 
					    optional double rotational_period_ms = 2
 | 
				
			||||||
 | 
					        [ default = 166.0, (help) = "rotational period on the real device" ];
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										51
									
								
								arch/rolandd20/decoder.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								arch/rolandd20/decoder.cc
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,51 @@
 | 
				
			|||||||
 | 
					#include "lib/globals.h"
 | 
				
			||||||
 | 
					#include "lib/decoders/decoders.h"
 | 
				
			||||||
 | 
					#include "lib/crc.h"
 | 
				
			||||||
 | 
					#include "lib/fluxmap.h"
 | 
				
			||||||
 | 
					#include "lib/decoders/fluxmapreader.h"
 | 
				
			||||||
 | 
					#include "lib/sector.h"
 | 
				
			||||||
 | 
					#include "lib/bytes.h"
 | 
				
			||||||
 | 
					#include "rolandd20.h"
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Sector header record:
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * BF FF FF FF FF FF FE AB
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This encodes to:
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *    e    d    5    5    5    5    5    5
 | 
				
			||||||
 | 
					 * 1110 1101 0101 0101 0101 0101 0101 0101
 | 
				
			||||||
 | 
					 *    5    5    5    5    5    5    5    5
 | 
				
			||||||
 | 
					 * 0101 0101 0101 0101 0101 0101 0101 0101
 | 
				
			||||||
 | 
					 *    5    5    5    5    5    5    5    5
 | 
				
			||||||
 | 
					 * 0101 0101 0101 0101 0101 0101 0101 0101
 | 
				
			||||||
 | 
					 *    5    5    5    4    4    4    4    5
 | 
				
			||||||
 | 
					 * 0101 0101 0101 0100 0100 0100 0100 0101
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const FluxPattern SECTOR_PATTERN(64, 0xed55555555555555LL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class RolandD20Decoder : public Decoder
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
					    RolandD20Decoder(const DecoderProto& config): Decoder(config) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    nanoseconds_t advanceToNextRecord() override
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return seekToPattern(SECTOR_PATTERN);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void decodeSectorRecord() override
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        auto rawbits = readRawBits(256);
 | 
				
			||||||
 | 
					        const auto& bytes = decodeFmMfm(rawbits);
 | 
				
			||||||
 | 
					        fmt::print("{} ", _sector->clock);
 | 
				
			||||||
 | 
					        hexdump(std::cout, bytes);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					std::unique_ptr<Decoder> createRolandD20Decoder(const DecoderProto& config)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    return std::unique_ptr<Decoder>(new RolandD20Decoder(config));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										4
									
								
								arch/rolandd20/rolandd20.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								arch/rolandd20/rolandd20.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,4 @@
 | 
				
			|||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern std::unique_ptr<Decoder> createRolandD20Decoder(
 | 
				
			||||||
 | 
					    const DecoderProto& config);
 | 
				
			||||||
							
								
								
									
										5
									
								
								arch/rolandd20/rolandd20.proto
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								arch/rolandd20/rolandd20.proto
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,5 @@
 | 
				
			|||||||
 | 
					syntax = "proto2";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					message RolandD20DecoderProto {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										154
									
								
								arch/smaky6/decoder.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										154
									
								
								arch/smaky6/decoder.cc
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,154 @@
 | 
				
			|||||||
 | 
					#include "globals.h"
 | 
				
			||||||
 | 
					#include "fluxmap.h"
 | 
				
			||||||
 | 
					#include "decoders/fluxmapreader.h"
 | 
				
			||||||
 | 
					#include "protocol.h"
 | 
				
			||||||
 | 
					#include "decoders/decoders.h"
 | 
				
			||||||
 | 
					#include "sector.h"
 | 
				
			||||||
 | 
					#include "smaky6.h"
 | 
				
			||||||
 | 
					#include "bytes.h"
 | 
				
			||||||
 | 
					#include "crc.h"
 | 
				
			||||||
 | 
					#include "fmt/format.h"
 | 
				
			||||||
 | 
					#include "lib/decoders/decoders.pb.h"
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					#include <algorithm>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const FluxPattern SECTOR_PATTERN(32, 0x54892aaa);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Smaky6Decoder : public Decoder
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
					    Smaky6Decoder(const DecoderProto& config):
 | 
				
			||||||
 | 
					        Decoder(config),
 | 
				
			||||||
 | 
					        _config(config.smaky6())
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private:
 | 
				
			||||||
 | 
					    /* Returns the sector ID of the _current_ sector. */
 | 
				
			||||||
 | 
					    int advanceToNextSector()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        auto previous = tell();
 | 
				
			||||||
 | 
					        seekToIndexMark();
 | 
				
			||||||
 | 
					        auto now = tell();
 | 
				
			||||||
 | 
					        if ((now.ns() - previous.ns()) < 9e6)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            seekToIndexMark();
 | 
				
			||||||
 | 
					            auto next = tell();
 | 
				
			||||||
 | 
					            if ((next.ns() - now.ns()) < 9e6)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                /* We just found sector 0. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                _sectorId = 0;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                /* Spurious... */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                seek(now);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return _sectorId++;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
					    void beginTrack() override
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        /* Find the start-of-track index marks, which will be an interval
 | 
				
			||||||
 | 
					         * of about 6ms. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        seekToIndexMark();
 | 
				
			||||||
 | 
					        _sectorId = 99;
 | 
				
			||||||
 | 
					        for (;;)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            auto pos = tell();
 | 
				
			||||||
 | 
					            advanceToNextSector();
 | 
				
			||||||
 | 
					            if (_sectorId < 99)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                seek(pos);
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (eof())
 | 
				
			||||||
 | 
					                return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /* Now we know where to start counting, start finding sectors. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        _sectorStarts.clear();
 | 
				
			||||||
 | 
					        for (;;)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            auto now = tell();
 | 
				
			||||||
 | 
					            if (eof())
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            int id = advanceToNextSector();
 | 
				
			||||||
 | 
					            if (id < 16)
 | 
				
			||||||
 | 
					                _sectorStarts.push_back(std::make_pair(id, now));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        _sectorIndex = 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    nanoseconds_t advanceToNextRecord() override
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (_sectorIndex == _sectorStarts.size())
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            seekToIndexMark();
 | 
				
			||||||
 | 
					            return 0;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const auto& p = _sectorStarts[_sectorIndex++];
 | 
				
			||||||
 | 
					        _sectorId = p.first;
 | 
				
			||||||
 | 
					        seek(p.second);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        nanoseconds_t clock = seekToPattern(SECTOR_PATTERN);
 | 
				
			||||||
 | 
					        _sector->headerStartTime = tell().ns();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return clock;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void decodeSectorRecord() override
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        readRawBits(33);
 | 
				
			||||||
 | 
					        const auto& rawbits = readRawBits(SMAKY6_RECORD_SIZE * 16);
 | 
				
			||||||
 | 
					        if (rawbits.size() < SMAKY6_SECTOR_SIZE)
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        const auto& rawbytes =
 | 
				
			||||||
 | 
					            toBytes(rawbits).slice(0, SMAKY6_RECORD_SIZE * 16);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /* The Smaky bytes are stored backwards! Backwards! */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const auto& bytes =
 | 
				
			||||||
 | 
					            decodeFmMfm(rawbits).slice(0, SMAKY6_RECORD_SIZE).reverseBits();
 | 
				
			||||||
 | 
					        ByteReader br(bytes);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        uint8_t track = br.read_8();
 | 
				
			||||||
 | 
					        Bytes data = br.read(SMAKY6_SECTOR_SIZE);
 | 
				
			||||||
 | 
					        uint8_t wantedChecksum = br.read_8();
 | 
				
			||||||
 | 
					        uint8_t gotChecksum = sumBytes(data) & 0xff;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (track != _sector->physicalTrack)
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        _sector->logicalTrack = _sector->physicalTrack;
 | 
				
			||||||
 | 
					        _sector->logicalSide = _sector->physicalSide;
 | 
				
			||||||
 | 
					        _sector->logicalSector = _sectorId;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        _sector->data = data;
 | 
				
			||||||
 | 
					        _sector->status =
 | 
				
			||||||
 | 
					            (wantedChecksum == gotChecksum) ? Sector::OK : Sector::BAD_CHECKSUM;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private:
 | 
				
			||||||
 | 
					    const Smaky6DecoderProto& _config;
 | 
				
			||||||
 | 
					    nanoseconds_t _startOfTrack;
 | 
				
			||||||
 | 
					    std::vector<std::pair<int, Fluxmap::Position>> _sectorStarts;
 | 
				
			||||||
 | 
					    int _sectorId;
 | 
				
			||||||
 | 
					    int _sectorIndex;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					std::unique_ptr<Decoder> createSmaky6Decoder(const DecoderProto& config)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    return std::unique_ptr<Decoder>(new Smaky6Decoder(config));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										9
									
								
								arch/smaky6/smaky6.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								arch/smaky6/smaky6.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
				
			|||||||
 | 
					#ifndef SMAKY6_H
 | 
				
			||||||
 | 
					#define SMAKY6_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define SMAKY6_SECTOR_SIZE 256
 | 
				
			||||||
 | 
					#define SMAKY6_RECORD_SIZE (1 + SMAKY6_SECTOR_SIZE + 1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern std::unique_ptr<Decoder> createSmaky6Decoder(const DecoderProto& config);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
							
								
								
									
										6
									
								
								arch/smaky6/smaky6.proto
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								arch/smaky6/smaky6.proto
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,6 @@
 | 
				
			|||||||
 | 
					syntax = "proto2";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import "lib/common.proto";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					message Smaky6DecoderProto {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -23,76 +23,78 @@
 | 
				
			|||||||
 * When shifted out of phase, the special 0xa1 byte becomes an illegal
 | 
					 * When shifted out of phase, the special 0xa1 byte becomes an illegal
 | 
				
			||||||
 * encoding (you can't do 10 00). So this can't be spoofed by user data.
 | 
					 * encoding (you can't do 10 00). So this can't be spoofed by user data.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					const uint16_t SECTOR_ID = 0x550a;
 | 
				
			||||||
const FluxPattern SECTOR_RECORD_PATTERN(32, 0x11112244);
 | 
					const FluxPattern SECTOR_RECORD_PATTERN(32, 0x11112244);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Data record:
 | 
					 * Data record:
 | 
				
			||||||
 * data:    0  1  0  1  0  1  0  1 .0  0  0  0  1  0  1  1  = 0x550c
 | 
					 * data:    0  1  0  1  0  1  0  1 .0  0  0  0  1  0  1  1  = 0x550b
 | 
				
			||||||
 * mfm:     00 01 00 01 00 01 00 01.00 10 10 10 01 00 01 01 = 0x11112a45
 | 
					 * mfm:     00 01 00 01 00 01 00 01.00 10 10 10 01 00 01 01 = 0x11112a45
 | 
				
			||||||
 * special: 00 01 00 01 00 01 00 01.00 10 00 10 01 00 01 01 = 0x11112245
 | 
					 * special: 00 01 00 01 00 01 00 01.00 10 00 10 01 00 01 01 = 0x11112245
 | 
				
			||||||
 *                                        ^^
 | 
					 *                                        ^^
 | 
				
			||||||
 * When shifted out of phase, the special 0xa1 byte becomes an illegal
 | 
					 * When shifted out of phase, the special 0xa1 byte becomes an illegal
 | 
				
			||||||
 * encoding (you can't do 10 00). So this can't be spoofed by user data.
 | 
					 * encoding (you can't do 10 00). So this can't be spoofed by user data.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					const uint16_t DATA_ID = 0x550b;
 | 
				
			||||||
const FluxPattern DATA_RECORD_PATTERN(32, 0x11112245);
 | 
					const FluxPattern DATA_RECORD_PATTERN(32, 0x11112245);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const FluxMatchers ANY_RECORD_PATTERN({ &SECTOR_RECORD_PATTERN, &DATA_RECORD_PATTERN });
 | 
					const FluxMatchers ANY_RECORD_PATTERN(
 | 
				
			||||||
 | 
					    {&SECTOR_RECORD_PATTERN, &DATA_RECORD_PATTERN});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Tids990Decoder : public AbstractDecoder
 | 
					class Tids990Decoder : public Decoder
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
	Tids990Decoder(const DecoderProto& config):
 | 
					    Tids990Decoder(const DecoderProto& config): Decoder(config) {}
 | 
				
			||||||
		AbstractDecoder(config)
 | 
					 | 
				
			||||||
	{}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    RecordType advanceToNextRecord()
 | 
					    nanoseconds_t advanceToNextRecord() override
 | 
				
			||||||
	{
 | 
					    {
 | 
				
			||||||
		const FluxMatcher* matcher = nullptr;
 | 
					        return seekToPattern(ANY_RECORD_PATTERN);
 | 
				
			||||||
		_sector->clock = _fmr->seekToPattern(ANY_RECORD_PATTERN, matcher);
 | 
					    }
 | 
				
			||||||
		if (matcher == &SECTOR_RECORD_PATTERN)
 | 
					 | 
				
			||||||
			return RecordType::SECTOR_RECORD;
 | 
					 | 
				
			||||||
		if (matcher == &DATA_RECORD_PATTERN)
 | 
					 | 
				
			||||||
			return RecordType::DATA_RECORD;
 | 
					 | 
				
			||||||
		return RecordType::UNKNOWN_RECORD;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void decodeSectorRecord()
 | 
					    void decodeSectorRecord() override
 | 
				
			||||||
	{
 | 
					    {
 | 
				
			||||||
		auto bits = readRawBits(TIDS990_SECTOR_RECORD_SIZE*16);
 | 
					        auto bits = readRawBits(TIDS990_SECTOR_RECORD_SIZE * 16);
 | 
				
			||||||
		auto bytes = decodeFmMfm(bits).slice(0, TIDS990_SECTOR_RECORD_SIZE);
 | 
					        auto bytes = decodeFmMfm(bits).slice(0, TIDS990_SECTOR_RECORD_SIZE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		ByteReader br(bytes);
 | 
					        ByteReader br(bytes);
 | 
				
			||||||
		uint16_t gotChecksum = crc16(CCITT_POLY, bytes.slice(1, TIDS990_SECTOR_RECORD_SIZE-3));
 | 
					        if (br.read_be16() != SECTOR_ID)
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		br.seek(2);
 | 
					        uint16_t gotChecksum =
 | 
				
			||||||
		_sector->logicalSide = br.read_8() >> 3;
 | 
					            crc16(CCITT_POLY, bytes.slice(1, TIDS990_SECTOR_RECORD_SIZE - 3));
 | 
				
			||||||
		_sector->logicalTrack = br.read_8();
 | 
					 | 
				
			||||||
		br.read_8(); /* number of sectors per track */
 | 
					 | 
				
			||||||
		_sector->logicalSector = br.read_8();
 | 
					 | 
				
			||||||
		br.read_be16(); /* sector size */
 | 
					 | 
				
			||||||
		uint16_t wantChecksum = br.read_be16();
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (wantChecksum == gotChecksum)
 | 
					        _sector->logicalSide = br.read_8() >> 3;
 | 
				
			||||||
			_sector->status = Sector::DATA_MISSING; /* correct but unintuitive */
 | 
					        _sector->logicalTrack = br.read_8();
 | 
				
			||||||
	}
 | 
					        br.read_8(); /* number of sectors per track */
 | 
				
			||||||
 | 
					        _sector->logicalSector = br.read_8();
 | 
				
			||||||
 | 
					        br.read_be16(); /* sector size */
 | 
				
			||||||
 | 
					        uint16_t wantChecksum = br.read_be16();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void decodeDataRecord()
 | 
					        if (wantChecksum == gotChecksum)
 | 
				
			||||||
	{
 | 
					            _sector->status =
 | 
				
			||||||
		auto bits = readRawBits(TIDS990_DATA_RECORD_SIZE*16);
 | 
					                Sector::DATA_MISSING; /* correct but unintuitive */
 | 
				
			||||||
		auto bytes = decodeFmMfm(bits).slice(0, TIDS990_DATA_RECORD_SIZE);
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		ByteReader br(bytes);
 | 
					    void decodeDataRecord() override
 | 
				
			||||||
		uint16_t gotChecksum = crc16(CCITT_POLY, bytes.slice(1, TIDS990_DATA_RECORD_SIZE-3));
 | 
					    {
 | 
				
			||||||
 | 
					        auto bits = readRawBits(TIDS990_DATA_RECORD_SIZE * 16);
 | 
				
			||||||
 | 
					        auto bytes = decodeFmMfm(bits).slice(0, TIDS990_DATA_RECORD_SIZE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		br.seek(2);
 | 
					        ByteReader br(bytes);
 | 
				
			||||||
		_sector->data = br.read(TIDS990_PAYLOAD_SIZE);
 | 
					        if (br.read_be16() != DATA_ID)
 | 
				
			||||||
		uint16_t wantChecksum = br.read_be16();
 | 
					            return;
 | 
				
			||||||
		_sector->status = (wantChecksum == gotChecksum) ? Sector::OK : Sector::BAD_CHECKSUM;
 | 
					
 | 
				
			||||||
	}
 | 
					        uint16_t gotChecksum =
 | 
				
			||||||
 | 
					            crc16(CCITT_POLY, bytes.slice(1, TIDS990_DATA_RECORD_SIZE - 3));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        _sector->data = br.read(TIDS990_PAYLOAD_SIZE);
 | 
				
			||||||
 | 
					        uint16_t wantChecksum = br.read_be16();
 | 
				
			||||||
 | 
					        _sector->status =
 | 
				
			||||||
 | 
					            (wantChecksum == gotChecksum) ? Sector::OK : Sector::BAD_CHECKSUM;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
std::unique_ptr<AbstractDecoder> createTids990Decoder(const DecoderProto& config)
 | 
					std::unique_ptr<Decoder> createTids990Decoder(const DecoderProto& config)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return std::unique_ptr<AbstractDecoder>(new Tids990Decoder(config));
 | 
					    return std::unique_ptr<Decoder>(new Tids990Decoder(config));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,7 +3,7 @@
 | 
				
			|||||||
#include "encoders/encoders.h"
 | 
					#include "encoders/encoders.h"
 | 
				
			||||||
#include "tids990.h"
 | 
					#include "tids990.h"
 | 
				
			||||||
#include "crc.h"
 | 
					#include "crc.h"
 | 
				
			||||||
#include "writer.h"
 | 
					#include "readerwriter.h"
 | 
				
			||||||
#include "image.h"
 | 
					#include "image.h"
 | 
				
			||||||
#include "arch/tids990/tids990.pb.h"
 | 
					#include "arch/tids990/tids990.pb.h"
 | 
				
			||||||
#include "lib/encoders/encoders.pb.h"
 | 
					#include "lib/encoders/encoders.pb.h"
 | 
				
			||||||
@@ -11,158 +11,141 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
static int charToInt(char c)
 | 
					static int charToInt(char c)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (isdigit(c))
 | 
					    if (isdigit(c))
 | 
				
			||||||
		return c - '0';
 | 
					        return c - '0';
 | 
				
			||||||
	return 10 + tolower(c) - 'a';
 | 
					    return 10 + tolower(c) - 'a';
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static uint8_t decodeUint16(uint16_t raw)
 | 
					static uint8_t decodeUint16(uint16_t raw)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	Bytes b;
 | 
					    Bytes b;
 | 
				
			||||||
	ByteWriter bw(b);
 | 
					    ByteWriter bw(b);
 | 
				
			||||||
	bw.write_be16(raw);
 | 
					    bw.write_be16(raw);
 | 
				
			||||||
	return decodeFmMfm(b.toBits())[0];
 | 
					    return decodeFmMfm(b.toBits())[0];
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Tids990Encoder : public AbstractEncoder
 | 
					class Tids990Encoder : public Encoder
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
	Tids990Encoder(const EncoderProto& config):
 | 
					    Tids990Encoder(const EncoderProto& config):
 | 
				
			||||||
		AbstractEncoder(config),
 | 
					        Encoder(config),
 | 
				
			||||||
		_config(config.tids990())
 | 
					        _config(config.tids990())
 | 
				
			||||||
	{}
 | 
					    {
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
	void writeRawBits(uint32_t data, int width)
 | 
					    void writeRawBits(uint32_t data, int width)
 | 
				
			||||||
	{
 | 
					    {
 | 
				
			||||||
		_cursor += width;
 | 
					        _cursor += width;
 | 
				
			||||||
		_lastBit = data & 1;
 | 
					        _lastBit = data & 1;
 | 
				
			||||||
		for (int i=0; i<width; i++)
 | 
					        for (int i = 0; i < width; i++)
 | 
				
			||||||
		{
 | 
					        {
 | 
				
			||||||
			unsigned pos = _cursor - i - 1;
 | 
					            unsigned pos = _cursor - i - 1;
 | 
				
			||||||
			if (pos < _bits.size())
 | 
					            if (pos < _bits.size())
 | 
				
			||||||
				_bits[pos] = data & 1;
 | 
					                _bits[pos] = data & 1;
 | 
				
			||||||
			data >>= 1;
 | 
					            data >>= 1;
 | 
				
			||||||
		}
 | 
					        }
 | 
				
			||||||
	}
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void writeBytes(const Bytes& bytes)
 | 
					    void writeBytes(const Bytes& bytes)
 | 
				
			||||||
	{
 | 
					    {
 | 
				
			||||||
		encodeMfm(_bits, _cursor, bytes, _lastBit);
 | 
					        encodeMfm(_bits, _cursor, bytes, _lastBit);
 | 
				
			||||||
	}
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void writeBytes(int count, uint8_t byte)
 | 
					    void writeBytes(int count, uint8_t byte)
 | 
				
			||||||
	{
 | 
					    {
 | 
				
			||||||
		Bytes bytes = { byte };
 | 
					        Bytes bytes = {byte};
 | 
				
			||||||
		for (int i=0; i<count; i++)
 | 
					        for (int i = 0; i < count; i++)
 | 
				
			||||||
			writeBytes(bytes);
 | 
					            writeBytes(bytes);
 | 
				
			||||||
	}
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
	std::vector<std::shared_ptr<Sector>> collectSectors(int physicalTrack, int physicalSide, const Image& image) override
 | 
					    std::unique_ptr<Fluxmap> encode(std::shared_ptr<const TrackInfo>& trackInfo,
 | 
				
			||||||
	{
 | 
					        const std::vector<std::shared_ptr<const Sector>>& sectors,
 | 
				
			||||||
		std::vector<std::shared_ptr<Sector>> sectors;
 | 
					        const Image& image) override
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        double clockRateUs = _config.clock_period_us() / 2.0;
 | 
				
			||||||
 | 
					        int bitsPerRevolution =
 | 
				
			||||||
 | 
					            (_config.rotational_period_ms() * 1000.0) / clockRateUs;
 | 
				
			||||||
 | 
					        _bits.resize(bitsPerRevolution);
 | 
				
			||||||
 | 
					        _cursor = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		for (char sectorChar : _config.sector_skew())
 | 
					        uint8_t am1Unencoded = decodeUint16(_config.am1_byte());
 | 
				
			||||||
 | 
					        uint8_t am2Unencoded = decodeUint16(_config.am2_byte());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        writeBytes(_config.gap1_bytes(), 0x55);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        bool first = true;
 | 
				
			||||||
 | 
					        for (const auto& sectorData : sectors)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
			int sectorId = charToInt(sectorChar);
 | 
					            if (!first)
 | 
				
			||||||
			const auto& sector = image.get(physicalTrack, physicalSide, sectorId);
 | 
					                writeBytes(_config.gap3_bytes(), 0x55);
 | 
				
			||||||
			if (sector)
 | 
					            first = false;
 | 
				
			||||||
				sectors.push_back(sector);
 | 
					
 | 
				
			||||||
 | 
					            /* Writing the sector and data records are fantastically annoying.
 | 
				
			||||||
 | 
					             * The CRC is calculated from the *very start* of the record, and
 | 
				
			||||||
 | 
					             * include the malformed marker bytes. Our encoder doesn't know
 | 
				
			||||||
 | 
					             * about this, of course, with the result that we have to construct
 | 
				
			||||||
 | 
					             * the unencoded header, calculate the checksum, and then use the
 | 
				
			||||||
 | 
					             * same logic to emit the bytes which require special encoding
 | 
				
			||||||
 | 
					             * before encoding the rest of the header normally. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                Bytes header;
 | 
				
			||||||
 | 
					                ByteWriter bw(header);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                writeBytes(12, 0x55);
 | 
				
			||||||
 | 
					                bw.write_8(am1Unencoded);
 | 
				
			||||||
 | 
					                bw.write_8(sectorData->logicalSide << 3);
 | 
				
			||||||
 | 
					                bw.write_8(sectorData->logicalTrack);
 | 
				
			||||||
 | 
					                bw.write_8(_config.sector_count());
 | 
				
			||||||
 | 
					                bw.write_8(sectorData->logicalSector);
 | 
				
			||||||
 | 
					                bw.write_be16(sectorData->data.size());
 | 
				
			||||||
 | 
					                uint16_t crc = crc16(CCITT_POLY, header);
 | 
				
			||||||
 | 
					                bw.write_be16(crc);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                writeRawBits(_config.am1_byte(), 16);
 | 
				
			||||||
 | 
					                writeBytes(header.slice(1));
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            writeBytes(_config.gap2_bytes(), 0x55);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                Bytes data;
 | 
				
			||||||
 | 
					                ByteWriter bw(data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                writeBytes(12, 0x55);
 | 
				
			||||||
 | 
					                bw.write_8(am2Unencoded);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                bw += sectorData->data;
 | 
				
			||||||
 | 
					                uint16_t crc = crc16(CCITT_POLY, data);
 | 
				
			||||||
 | 
					                bw.write_be16(crc);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                writeRawBits(_config.am2_byte(), 16);
 | 
				
			||||||
 | 
					                writeBytes(data.slice(1));
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		return sectors;
 | 
					        if (_cursor >= _bits.size())
 | 
				
			||||||
	}
 | 
					            error("track data overrun");
 | 
				
			||||||
 | 
					        while (_cursor < _bits.size())
 | 
				
			||||||
 | 
					            writeBytes(1, 0x55);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    std::unique_ptr<Fluxmap> encode(int physicalTrack, int physicalSide,
 | 
					        auto fluxmap = std::make_unique<Fluxmap>();
 | 
				
			||||||
			const std::vector<std::shared_ptr<Sector>>& sectors, const Image& image) override
 | 
					        fluxmap->appendBits(_bits,
 | 
				
			||||||
	{
 | 
					            calculatePhysicalClockPeriod(
 | 
				
			||||||
		double clockRateUs = 1e3 / _config.clock_rate_khz() / 2.0;
 | 
					                clockRateUs * 1e3, _config.rotational_period_ms() * 1e6));
 | 
				
			||||||
		int bitsPerRevolution = (_config.track_length_ms() * 1000.0) / clockRateUs;
 | 
					        return fluxmap;
 | 
				
			||||||
		_bits.resize(bitsPerRevolution);
 | 
					    }
 | 
				
			||||||
		_cursor = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		uint8_t am1Unencoded = decodeUint16(_config.am1_byte());
 | 
					 | 
				
			||||||
		uint8_t am2Unencoded = decodeUint16(_config.am2_byte());
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		writeBytes(_config.gap1_bytes(), 0x55);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		bool first = true;
 | 
					 | 
				
			||||||
		for (char sectorChar : _config.sector_skew())
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			int sectorId = charToInt(sectorChar);
 | 
					 | 
				
			||||||
			if (!first)
 | 
					 | 
				
			||||||
				writeBytes(_config.gap3_bytes(), 0x55);
 | 
					 | 
				
			||||||
			first = false;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			const auto& sectorData = image.get(physicalTrack, physicalSide, sectorId);
 | 
					 | 
				
			||||||
			if (!sectorData)
 | 
					 | 
				
			||||||
				Error() << fmt::format("format tried to find sector {} which wasn't in the input file", sectorId);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			/* Writing the sector and data records are fantastically annoying.
 | 
					 | 
				
			||||||
			 * The CRC is calculated from the *very start* of the record, and
 | 
					 | 
				
			||||||
			 * include the malformed marker bytes. Our encoder doesn't know
 | 
					 | 
				
			||||||
			 * about this, of course, with the result that we have to construct
 | 
					 | 
				
			||||||
			 * the unencoded header, calculate the checksum, and then use the
 | 
					 | 
				
			||||||
			 * same logic to emit the bytes which require special encoding
 | 
					 | 
				
			||||||
			 * before encoding the rest of the header normally. */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			{
 | 
					 | 
				
			||||||
				Bytes header;
 | 
					 | 
				
			||||||
				ByteWriter bw(header);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				writeBytes(12, 0x55);
 | 
					 | 
				
			||||||
				bw.write_8(am1Unencoded);
 | 
					 | 
				
			||||||
				bw.write_8(sectorData->logicalSide << 3);
 | 
					 | 
				
			||||||
				bw.write_8(sectorData->logicalTrack);
 | 
					 | 
				
			||||||
				bw.write_8(_config.sector_count());
 | 
					 | 
				
			||||||
				bw.write_8(sectorData->logicalSector);
 | 
					 | 
				
			||||||
				bw.write_be16(sectorData->data.size());
 | 
					 | 
				
			||||||
				uint16_t crc = crc16(CCITT_POLY, header);
 | 
					 | 
				
			||||||
				bw.write_be16(crc);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				writeRawBits(_config.am1_byte(), 16);
 | 
					 | 
				
			||||||
				writeBytes(header.slice(1));
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			writeBytes(_config.gap2_bytes(), 0x55);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			{
 | 
					 | 
				
			||||||
				Bytes data;
 | 
					 | 
				
			||||||
				ByteWriter bw(data);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				writeBytes(12, 0x55);
 | 
					 | 
				
			||||||
				bw.write_8(am2Unencoded);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				bw += sectorData->data;
 | 
					 | 
				
			||||||
				uint16_t crc = crc16(CCITT_POLY, data);
 | 
					 | 
				
			||||||
				bw.write_be16(crc);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				writeRawBits(_config.am2_byte(), 16);
 | 
					 | 
				
			||||||
				writeBytes(data.slice(1));
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (_cursor >= _bits.size())
 | 
					 | 
				
			||||||
			Error() << "track data overrun";
 | 
					 | 
				
			||||||
		while (_cursor < _bits.size())
 | 
					 | 
				
			||||||
			writeBytes(1, 0x55);
 | 
					 | 
				
			||||||
		
 | 
					 | 
				
			||||||
		std::unique_ptr<Fluxmap> fluxmap(new Fluxmap);
 | 
					 | 
				
			||||||
		fluxmap->appendBits(_bits, clockRateUs*1e3);
 | 
					 | 
				
			||||||
		return fluxmap;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
	const Tids990EncoderProto& _config;
 | 
					    const Tids990EncoderProto& _config;
 | 
				
			||||||
	std::vector<bool> _bits;
 | 
					    std::vector<bool> _bits;
 | 
				
			||||||
	unsigned _cursor;
 | 
					    unsigned _cursor;
 | 
				
			||||||
	bool _lastBit;
 | 
					    bool _lastBit;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
std::unique_ptr<AbstractEncoder> createTids990Encoder(const EncoderProto& config)
 | 
					std::unique_ptr<Encoder> createTids990Encoder(const EncoderProto& config)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return std::unique_ptr<AbstractEncoder>(new Tids990Encoder(config));
 | 
					    return std::unique_ptr<Encoder>(new Tids990Encoder(config));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,18 +1,18 @@
 | 
				
			|||||||
#ifndef TIDS990_H
 | 
					#ifndef TIDS990_H
 | 
				
			||||||
#define TIDS990_H
 | 
					#define TIDS990_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define TIDS990_PAYLOAD_SIZE       288 /* bytes */
 | 
					#define TIDS990_PAYLOAD_SIZE 288                            /* bytes */
 | 
				
			||||||
#define TIDS990_SECTOR_RECORD_SIZE 10 /* bytes */
 | 
					#define TIDS990_SECTOR_RECORD_SIZE 10                       /* bytes */
 | 
				
			||||||
#define TIDS990_DATA_RECORD_SIZE   (TIDS990_PAYLOAD_SIZE + 4) /* bytes */
 | 
					#define TIDS990_DATA_RECORD_SIZE (TIDS990_PAYLOAD_SIZE + 4) /* bytes */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class AbstractEncoder;
 | 
					class Encoder;
 | 
				
			||||||
class AbstractDecoder;
 | 
					class Decoder;
 | 
				
			||||||
class DecoderProto;
 | 
					class DecoderProto;
 | 
				
			||||||
class EncoderProto;
 | 
					class EncoderProto;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern std::unique_ptr<AbstractDecoder> createTids990Decoder(const DecoderProto& config);
 | 
					extern std::unique_ptr<Decoder> createTids990Decoder(
 | 
				
			||||||
extern std::unique_ptr<AbstractEncoder> createTids990Encoder(const EncoderProto& config);
 | 
					    const DecoderProto& config);
 | 
				
			||||||
 | 
					extern std::unique_ptr<Encoder> createTids990Encoder(
 | 
				
			||||||
 | 
					    const EncoderProto& config);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,12 +3,13 @@ syntax = "proto2";
 | 
				
			|||||||
import "lib/common.proto";
 | 
					import "lib/common.proto";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
message Tids990DecoderProto {}
 | 
					message Tids990DecoderProto {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
message Tids990EncoderProto {
 | 
					message Tids990EncoderProto {
 | 
				
			||||||
	optional double track_length_ms = 1 [ default = 166,
 | 
						optional double rotational_period_ms = 1 [ default = 166,
 | 
				
			||||||
		(help) = "length of a track" ];
 | 
							(help) = "length of a track" ];
 | 
				
			||||||
	optional int32 sector_count = 2 [ default = 26,
 | 
						optional int32 sector_count = 2 [ default = 26,
 | 
				
			||||||
		(help) = "number of sectors per track" ];
 | 
							(help) = "number of sectors per track" ];
 | 
				
			||||||
	optional double clock_rate_khz = 3 [ default = 500,
 | 
						optional double clock_period_us = 3 [ default = 2,
 | 
				
			||||||
		(help) = "clock rate of data to write" ];
 | 
							(help) = "clock rate of data to write" ];
 | 
				
			||||||
	optional int32 am1_byte = 4 [ default = 0x2244,
 | 
						optional int32 am1_byte = 4 [ default = 0x2244,
 | 
				
			||||||
		(help) = "16-bit RAW bit pattern to use for the AM1 ID byte" ];
 | 
							(help) = "16-bit RAW bit pattern to use for the AM1 ID byte" ];
 | 
				
			||||||
@@ -20,7 +21,5 @@ message Tids990EncoderProto {
 | 
				
			|||||||
		(help) = "size of gap 2 (the post-ID gap)" ];
 | 
							(help) = "size of gap 2 (the post-ID gap)" ];
 | 
				
			||||||
	optional int32 gap3_bytes = 8 [ default = 51,
 | 
						optional int32 gap3_bytes = 8 [ default = 51,
 | 
				
			||||||
		(help) = "size of gap 3 (the post-data or format gap)" ];
 | 
							(help) = "size of gap 3 (the post-data or format gap)" ];
 | 
				
			||||||
	optional string sector_skew = 9 [ default = "1mhc72nid83oje94pkfa50lgb6",
 | 
					 | 
				
			||||||
		(help) = "order to emit sectors" ];
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -13,16 +13,18 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
const FluxPattern SECTOR_RECORD_PATTERN(32, VICTOR9K_SECTOR_RECORD);
 | 
					const FluxPattern SECTOR_RECORD_PATTERN(32, VICTOR9K_SECTOR_RECORD);
 | 
				
			||||||
const FluxPattern DATA_RECORD_PATTERN(32, VICTOR9K_DATA_RECORD);
 | 
					const FluxPattern DATA_RECORD_PATTERN(32, VICTOR9K_DATA_RECORD);
 | 
				
			||||||
const FluxMatchers ANY_RECORD_PATTERN({ &SECTOR_RECORD_PATTERN, &DATA_RECORD_PATTERN });
 | 
					const FluxMatchers ANY_RECORD_PATTERN(
 | 
				
			||||||
 | 
					    {&SECTOR_RECORD_PATTERN, &DATA_RECORD_PATTERN});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int decode_data_gcr(uint8_t gcr)
 | 
					static int decode_data_gcr(uint8_t gcr)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    switch (gcr)
 | 
					    switch (gcr)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
		#define GCR_ENTRY(gcr, data) \
 | 
					#define GCR_ENTRY(gcr, data) \
 | 
				
			||||||
			case gcr: return data;
 | 
					    case gcr:                \
 | 
				
			||||||
		#include "data_gcr.h"
 | 
					        return data;
 | 
				
			||||||
		#undef GCR_ENTRY
 | 
					#include "data_gcr.h"
 | 
				
			||||||
 | 
					#undef GCR_ENTRY
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    return -1;
 | 
					    return -1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -37,11 +39,11 @@ static Bytes decode(const std::vector<bool>& bits)
 | 
				
			|||||||
    while (ii != bits.end())
 | 
					    while (ii != bits.end())
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        uint8_t inputfifo = 0;
 | 
					        uint8_t inputfifo = 0;
 | 
				
			||||||
        for (size_t i=0; i<5; i++)
 | 
					        for (size_t i = 0; i < 5; i++)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            if (ii == bits.end())
 | 
					            if (ii == bits.end())
 | 
				
			||||||
                break;
 | 
					                break;
 | 
				
			||||||
            inputfifo = (inputfifo<<1) | *ii++;
 | 
					            inputfifo = (inputfifo << 1) | *ii++;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        uint8_t decoded = decode_data_gcr(inputfifo);
 | 
					        uint8_t decoded = decode_data_gcr(inputfifo);
 | 
				
			||||||
@@ -52,73 +54,65 @@ static Bytes decode(const std::vector<bool>& bits)
 | 
				
			|||||||
    return output;
 | 
					    return output;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Victor9kDecoder : public AbstractDecoder
 | 
					class Victor9kDecoder : public Decoder
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
	Victor9kDecoder(const DecoderProto& config):
 | 
					    Victor9kDecoder(const DecoderProto& config): Decoder(config) {}
 | 
				
			||||||
		AbstractDecoder(config)
 | 
					 | 
				
			||||||
	{}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    RecordType advanceToNextRecord()
 | 
					    nanoseconds_t advanceToNextRecord() override
 | 
				
			||||||
	{
 | 
					    {
 | 
				
			||||||
		const FluxMatcher* matcher = nullptr;
 | 
					        return seekToPattern(ANY_RECORD_PATTERN);
 | 
				
			||||||
		_sector->clock = _fmr->seekToPattern(ANY_RECORD_PATTERN, matcher);
 | 
					    }
 | 
				
			||||||
		if (matcher == &SECTOR_RECORD_PATTERN)
 | 
					 | 
				
			||||||
			return SECTOR_RECORD;
 | 
					 | 
				
			||||||
		if (matcher == &DATA_RECORD_PATTERN)
 | 
					 | 
				
			||||||
			return DATA_RECORD;
 | 
					 | 
				
			||||||
		return UNKNOWN_RECORD;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void decodeSectorRecord()
 | 
					    void decodeSectorRecord() override
 | 
				
			||||||
	{
 | 
					    {
 | 
				
			||||||
		/* Skip the sync marker bit. */
 | 
					        /* Check the ID. */
 | 
				
			||||||
		readRawBits(22);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* Read header. */
 | 
					        if (readRaw32() != VICTOR9K_SECTOR_RECORD)
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		auto bytes = decode(readRawBits(4*10)).slice(0, 4);
 | 
					        /* Read header. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		uint8_t rawTrack = bytes[1];
 | 
					        auto bytes = decode(readRawBits(3 * 10)).slice(0, 3);
 | 
				
			||||||
		_sector->logicalSector = bytes[2];
 | 
					 | 
				
			||||||
		uint8_t gotChecksum = bytes[3];
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		_sector->logicalTrack = rawTrack & 0x7f;
 | 
					        uint8_t rawTrack = bytes[0];
 | 
				
			||||||
		_sector->logicalSide = rawTrack >> 7;
 | 
					        _sector->logicalSector = bytes[1];
 | 
				
			||||||
		uint8_t wantChecksum = bytes[1] + bytes[2];
 | 
					        uint8_t gotChecksum = bytes[2];
 | 
				
			||||||
		if ((_sector->logicalSector > 20) || (_sector->logicalTrack > 85) || (_sector->logicalSide > 1))
 | 
					 | 
				
			||||||
			return;
 | 
					 | 
				
			||||||
					
 | 
					 | 
				
			||||||
		if (wantChecksum == gotChecksum)
 | 
					 | 
				
			||||||
			_sector->status = Sector::DATA_MISSING; /* unintuitive but correct */
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void decodeDataRecord()
 | 
					        _sector->logicalTrack = rawTrack & 0x7f;
 | 
				
			||||||
	{
 | 
					        _sector->logicalSide = rawTrack >> 7;
 | 
				
			||||||
		/* Skip the sync marker bit. */
 | 
					        uint8_t wantChecksum = bytes[0] + bytes[1];
 | 
				
			||||||
		readRawBits(22);
 | 
					        if ((_sector->logicalSector > 20) || (_sector->logicalTrack > 85) ||
 | 
				
			||||||
 | 
					            (_sector->logicalSide > 1))
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* Read data. */
 | 
					        if (wantChecksum == gotChecksum)
 | 
				
			||||||
 | 
					            _sector->status =
 | 
				
			||||||
 | 
					                Sector::DATA_MISSING; /* unintuitive but correct */
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		auto bytes = decode(readRawBits((VICTOR9K_SECTOR_LENGTH+5)*10))
 | 
					    void decodeDataRecord() override
 | 
				
			||||||
			.slice(0, VICTOR9K_SECTOR_LENGTH+5);
 | 
					    {
 | 
				
			||||||
		ByteReader br(bytes);
 | 
					        /* Check the ID. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* Check that this is actually a data record. */
 | 
					        if (readRaw32() != VICTOR9K_DATA_RECORD)
 | 
				
			||||||
		
 | 
					            return;
 | 
				
			||||||
		if (br.read_8() != 8)
 | 
					 | 
				
			||||||
			return;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		_sector->data = br.read(VICTOR9K_SECTOR_LENGTH);
 | 
					        /* Read data. */
 | 
				
			||||||
		uint16_t gotChecksum = sumBytes(_sector->data);
 | 
					
 | 
				
			||||||
		uint16_t wantChecksum = br.read_le16();
 | 
					        auto bytes = decode(readRawBits((VICTOR9K_SECTOR_LENGTH + 4) * 10))
 | 
				
			||||||
		_sector->status = (gotChecksum == wantChecksum) ? Sector::OK : Sector::BAD_CHECKSUM;
 | 
					                         .slice(0, VICTOR9K_SECTOR_LENGTH + 4);
 | 
				
			||||||
	}
 | 
					        ByteReader br(bytes);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        _sector->data = br.read(VICTOR9K_SECTOR_LENGTH);
 | 
				
			||||||
 | 
					        uint16_t gotChecksum = sumBytes(_sector->data);
 | 
				
			||||||
 | 
					        uint16_t wantChecksum = br.read_le16();
 | 
				
			||||||
 | 
					        _sector->status =
 | 
				
			||||||
 | 
					            (gotChecksum == wantChecksum) ? Sector::OK : Sector::BAD_CHECKSUM;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
std::unique_ptr<AbstractDecoder> createVictor9kDecoder(const DecoderProto& config)
 | 
					std::unique_ptr<Decoder> createVictor9kDecoder(const DecoderProto& config)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return std::unique_ptr<AbstractDecoder>(new Victor9kDecoder(config));
 | 
					    return std::unique_ptr<Decoder>(new Victor9kDecoder(config));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,106 +4,126 @@
 | 
				
			|||||||
#include "victor9k.h"
 | 
					#include "victor9k.h"
 | 
				
			||||||
#include "crc.h"
 | 
					#include "crc.h"
 | 
				
			||||||
#include "sector.h"
 | 
					#include "sector.h"
 | 
				
			||||||
#include "writer.h"
 | 
					#include "readerwriter.h"
 | 
				
			||||||
#include "image.h"
 | 
					#include "image.h"
 | 
				
			||||||
#include "fmt/format.h"
 | 
					#include "fmt/format.h"
 | 
				
			||||||
#include "arch/victor9k/victor9k.pb.h"
 | 
					#include "arch/victor9k/victor9k.pb.h"
 | 
				
			||||||
#include "lib/encoders/encoders.pb.h"
 | 
					#include "lib/encoders/encoders.pb.h"
 | 
				
			||||||
 | 
					#include "lib/layout.h"
 | 
				
			||||||
#include <ctype.h>
 | 
					#include <ctype.h>
 | 
				
			||||||
#include "bytes.h"
 | 
					#include "bytes.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static bool lastBit;
 | 
					static bool lastBit;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void write_zero_bits(std::vector<bool>& bits, unsigned& cursor, unsigned count)
 | 
					static void write_zero_bits(
 | 
				
			||||||
 | 
					    std::vector<bool>& bits, unsigned& cursor, unsigned count)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    while (count--)
 | 
					    while (count--)
 | 
				
			||||||
	{
 | 
					    {
 | 
				
			||||||
		if (cursor < bits.size())
 | 
					        if (cursor < bits.size())
 | 
				
			||||||
			lastBit = bits[cursor++] = 0;
 | 
					            lastBit = bits[cursor++] = 0;
 | 
				
			||||||
	}
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void write_one_bits(std::vector<bool>& bits, unsigned& cursor, unsigned count)
 | 
					static void write_one_bits(
 | 
				
			||||||
 | 
					    std::vector<bool>& bits, unsigned& cursor, unsigned count)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    while (count--)
 | 
					    while (count--)
 | 
				
			||||||
	{
 | 
					    {
 | 
				
			||||||
		if (cursor < bits.size())
 | 
					        if (cursor < bits.size())
 | 
				
			||||||
			lastBit = bits[cursor++] = 1;
 | 
					            lastBit = bits[cursor++] = 1;
 | 
				
			||||||
	}
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void write_bits(std::vector<bool>& bits, unsigned& cursor, const std::vector<bool>& src)
 | 
					static void write_bits(
 | 
				
			||||||
 | 
					    std::vector<bool>& bits, unsigned& cursor, const std::vector<bool>& src)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	for (bool bit : src)
 | 
					    for (bool bit : src)
 | 
				
			||||||
	{
 | 
					    {
 | 
				
			||||||
		if (cursor < bits.size())
 | 
					        if (cursor < bits.size())
 | 
				
			||||||
			lastBit = bits[cursor++] = bit;
 | 
					            lastBit = bits[cursor++] = bit;
 | 
				
			||||||
	}
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void write_bits(std::vector<bool>& bits, unsigned& cursor, uint64_t data, int width)
 | 
					static void write_bits(
 | 
				
			||||||
 | 
					    std::vector<bool>& bits, unsigned& cursor, uint64_t data, int width)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	cursor += width;
 | 
					    cursor += width;
 | 
				
			||||||
	lastBit = data & 1;
 | 
					    lastBit = data & 1;
 | 
				
			||||||
	for (int i=0; i<width; i++)
 | 
					    for (int i = 0; i < width; i++)
 | 
				
			||||||
	{
 | 
					    {
 | 
				
			||||||
		unsigned pos = cursor - i - 1;
 | 
					        unsigned pos = cursor - i - 1;
 | 
				
			||||||
		if (pos < bits.size())
 | 
					        if (pos < bits.size())
 | 
				
			||||||
			bits[pos] = data & 1;
 | 
					            bits[pos] = data & 1;
 | 
				
			||||||
		data >>= 1;
 | 
					        data >>= 1;
 | 
				
			||||||
	}
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void write_bits(std::vector<bool>& bits, unsigned& cursor, const Bytes& bytes)
 | 
					static void write_bits(
 | 
				
			||||||
 | 
					    std::vector<bool>& bits, unsigned& cursor, const Bytes& bytes)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	ByteReader br(bytes);
 | 
					    ByteReader br(bytes);
 | 
				
			||||||
	BitReader bitr(br);
 | 
					    BitReader bitr(br);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	while (!bitr.eof())
 | 
					    while (!bitr.eof())
 | 
				
			||||||
	{
 | 
					    {
 | 
				
			||||||
		if (cursor < bits.size())
 | 
					        if (cursor < bits.size())
 | 
				
			||||||
			bits[cursor++] = bitr.get();
 | 
					            bits[cursor++] = bitr.get();
 | 
				
			||||||
	}
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int encode_data_gcr(uint8_t data)
 | 
					static int encode_data_gcr(uint8_t data)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    switch (data & 0x0f)
 | 
					    switch (data & 0x0f)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        #define GCR_ENTRY(gcr, data) \
 | 
					#define GCR_ENTRY(gcr, data) \
 | 
				
			||||||
            case data: return gcr;
 | 
					    case data:               \
 | 
				
			||||||
        #include "data_gcr.h"
 | 
					        return gcr;
 | 
				
			||||||
        #undef GCR_ENTRY
 | 
					#include "data_gcr.h"
 | 
				
			||||||
 | 
					#undef GCR_ENTRY
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    return -1;
 | 
					    return -1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void write_bytes(std::vector<bool>& bits, unsigned& cursor, const Bytes& bytes)
 | 
					static void write_byte(std::vector<bool>& bits, unsigned& cursor, uint8_t b)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    for (uint8_t b : bytes)
 | 
					    write_bits(bits, cursor, encode_data_gcr(b >> 4), 5);
 | 
				
			||||||
    {
 | 
					    write_bits(bits, cursor, encode_data_gcr(b), 5);
 | 
				
			||||||
        write_bits(bits, cursor, encode_data_gcr(b>>4), 5);
 | 
					 | 
				
			||||||
        write_bits(bits, cursor, encode_data_gcr(b),    5);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void write_sector(std::vector<bool>& bits, unsigned& cursor,
 | 
					static void write_bytes(
 | 
				
			||||||
		const Victor9kEncoderProto::TrackdataProto& trackdata,
 | 
					    std::vector<bool>& bits, unsigned& cursor, const Bytes& bytes)
 | 
				
			||||||
        const Sector& sector)
 | 
					{
 | 
				
			||||||
 | 
					    for (uint8_t b : bytes)
 | 
				
			||||||
 | 
					        write_byte(bits, cursor, b);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void write_gap(std::vector<bool>& bits, unsigned& cursor, int length)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    for (int i = 0; i < length / 10; i++)
 | 
				
			||||||
 | 
					        write_byte(bits, cursor, '0');
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void write_sector(std::vector<bool>& bits,
 | 
				
			||||||
 | 
					    unsigned& cursor,
 | 
				
			||||||
 | 
					    const Victor9kEncoderProto::TrackdataProto& trackdata,
 | 
				
			||||||
 | 
					    const Sector& sector)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    write_one_bits(bits, cursor, trackdata.pre_header_sync_bits());
 | 
					    write_one_bits(bits, cursor, trackdata.pre_header_sync_bits());
 | 
				
			||||||
    write_bits(bits, cursor, VICTOR9K_SECTOR_RECORD, 10);
 | 
					    write_bits(bits, cursor, VICTOR9K_SECTOR_RECORD, 10);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    uint8_t encodedTrack = sector.logicalTrack | (sector.logicalSide<<7);
 | 
					    uint8_t encodedTrack = sector.logicalTrack | (sector.logicalSide << 7);
 | 
				
			||||||
    uint8_t encodedSector = sector.logicalSector;
 | 
					    uint8_t encodedSector = sector.logicalSector;
 | 
				
			||||||
    write_bytes(bits, cursor, Bytes {
 | 
					    write_bytes(bits,
 | 
				
			||||||
        encodedTrack,
 | 
					        cursor,
 | 
				
			||||||
        encodedSector,
 | 
					        Bytes{
 | 
				
			||||||
        (uint8_t)(encodedTrack + encodedSector),
 | 
					            encodedTrack,
 | 
				
			||||||
    });
 | 
					            encodedSector,
 | 
				
			||||||
 | 
					            (uint8_t)(encodedTrack + encodedSector),
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    write_gap(bits, cursor, trackdata.post_header_gap_bits());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    write_zero_bits(bits, cursor, trackdata.post_header_gap_bits());
 | 
					 | 
				
			||||||
    write_one_bits(bits, cursor, trackdata.pre_data_sync_bits());
 | 
					    write_one_bits(bits, cursor, trackdata.pre_data_sync_bits());
 | 
				
			||||||
    write_bits(bits, cursor, VICTOR9K_DATA_RECORD, 10);
 | 
					    write_bits(bits, cursor, VICTOR9K_DATA_RECORD, 10);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -112,89 +132,79 @@ static void write_sector(std::vector<bool>& bits, unsigned& cursor,
 | 
				
			|||||||
    Bytes checksum(2);
 | 
					    Bytes checksum(2);
 | 
				
			||||||
    checksum.writer().write_le16(sumBytes(sector.data));
 | 
					    checksum.writer().write_le16(sumBytes(sector.data));
 | 
				
			||||||
    write_bytes(bits, cursor, checksum);
 | 
					    write_bytes(bits, cursor, checksum);
 | 
				
			||||||
 | 
					    write_gap(bits, cursor, trackdata.post_data_gap_bits());
 | 
				
			||||||
    write_zero_bits(bits, cursor, trackdata.post_data_gap_bits());
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Victor9kEncoder : public AbstractEncoder
 | 
					class Victor9kEncoder : public Encoder
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
	Victor9kEncoder(const EncoderProto& config):
 | 
					    Victor9kEncoder(const EncoderProto& config):
 | 
				
			||||||
        AbstractEncoder(config),
 | 
					        Encoder(config),
 | 
				
			||||||
		_config(config.victor9k())
 | 
					        _config(config.victor9k())
 | 
				
			||||||
	{}
 | 
					    {
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
 | 
					    void getTrackFormat(Victor9kEncoderProto::TrackdataProto& trackdata,
 | 
				
			||||||
 | 
					        unsigned track,
 | 
				
			||||||
 | 
					        unsigned head)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        trackdata.Clear();
 | 
				
			||||||
 | 
					        for (const auto& f : _config.trackdata())
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (f.has_min_track() && (track < f.min_track()))
 | 
				
			||||||
 | 
					                continue;
 | 
				
			||||||
 | 
					            if (f.has_max_track() && (track > f.max_track()))
 | 
				
			||||||
 | 
					                continue;
 | 
				
			||||||
 | 
					            if (f.has_head() && (head != f.head()))
 | 
				
			||||||
 | 
					                continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void getTrackFormat(Victor9kEncoderProto::TrackdataProto& trackdata, unsigned cylinder, unsigned head)
 | 
					            trackdata.MergeFrom(f);
 | 
				
			||||||
	{
 | 
					        }
 | 
				
			||||||
		trackdata.Clear();
 | 
					    }
 | 
				
			||||||
		for (const auto& f : _config.trackdata())
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			if (f.has_min_cylinder() && (cylinder < f.min_cylinder()))
 | 
					 | 
				
			||||||
				continue;
 | 
					 | 
				
			||||||
			if (f.has_max_cylinder() && (cylinder > f.max_cylinder()))
 | 
					 | 
				
			||||||
				continue;
 | 
					 | 
				
			||||||
			if (f.has_head() && (head != f.head()))
 | 
					 | 
				
			||||||
				continue;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			trackdata.MergeFrom(f);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
	std::vector<std::shared_ptr<Sector>> collectSectors(int physicalTrack, int physicalSide, const Image& image) override
 | 
					    std::unique_ptr<Fluxmap> encode(std::shared_ptr<const TrackInfo>& trackInfo,
 | 
				
			||||||
	{
 | 
					        const std::vector<std::shared_ptr<const Sector>>& sectors,
 | 
				
			||||||
		std::vector<std::shared_ptr<Sector>> sectors;
 | 
					        const Image& image) override
 | 
				
			||||||
 | 
					 | 
				
			||||||
		Victor9kEncoderProto::TrackdataProto trackdata;
 | 
					 | 
				
			||||||
		getTrackFormat(trackdata, physicalTrack, physicalSide);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        for (int i = 0; i < trackdata.sector_range().sector_count(); i++)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            int sectorId = trackdata.sector_range().start_sector() + i;
 | 
					 | 
				
			||||||
			const auto& sector = image.get(physicalTrack, physicalSide, sectorId);
 | 
					 | 
				
			||||||
			if (sector)
 | 
					 | 
				
			||||||
				sectors.push_back(sector);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		return sectors;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    std::unique_ptr<Fluxmap> encode(int physicalTrack, int physicalSide,
 | 
					 | 
				
			||||||
            const std::vector<std::shared_ptr<Sector>>& sectors, const Image& image) override
 | 
					 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
		Victor9kEncoderProto::TrackdataProto trackdata;
 | 
					        Victor9kEncoderProto::TrackdataProto trackdata;
 | 
				
			||||||
		getTrackFormat(trackdata, physicalTrack, physicalSide);
 | 
					        getTrackFormat(
 | 
				
			||||||
 | 
					            trackdata, trackInfo->logicalTrack, trackInfo->logicalSide);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        unsigned bitsPerRevolution = trackdata.original_data_rate_khz() * trackdata.original_period_ms();
 | 
					        unsigned bitsPerRevolution = (trackdata.rotational_period_ms() * 1e3) /
 | 
				
			||||||
 | 
					                                     trackdata.clock_period_us();
 | 
				
			||||||
        std::vector<bool> bits(bitsPerRevolution);
 | 
					        std::vector<bool> bits(bitsPerRevolution);
 | 
				
			||||||
        double clockRateUs = 166666.0 / bitsPerRevolution;
 | 
					        nanoseconds_t clockPeriod =
 | 
				
			||||||
 | 
					            calculatePhysicalClockPeriod(trackdata.clock_period_us() * 1e3,
 | 
				
			||||||
 | 
					                trackdata.rotational_period_ms() * 1e6);
 | 
				
			||||||
        unsigned cursor = 0;
 | 
					        unsigned cursor = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        fillBitmapTo(bits, cursor, trackdata.post_index_gap_us() / clockRateUs, { true, false });
 | 
					        fillBitmapTo(bits,
 | 
				
			||||||
 | 
					            cursor,
 | 
				
			||||||
 | 
					            trackdata.post_index_gap_us() * 1e3 / clockPeriod,
 | 
				
			||||||
 | 
					            {true, false});
 | 
				
			||||||
        lastBit = false;
 | 
					        lastBit = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        for (const auto& sector : sectors)
 | 
					        for (const auto& sector : sectors)
 | 
				
			||||||
            write_sector(bits, cursor, trackdata, *sector);
 | 
					            write_sector(bits, cursor, trackdata, *sector);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (cursor >= bits.size())
 | 
					        if (cursor >= bits.size())
 | 
				
			||||||
            Error() << fmt::format("track data overrun by {} bits", cursor - bits.size());
 | 
					            error("track data overrun by {} bits", cursor - bits.size());
 | 
				
			||||||
        fillBitmapTo(bits, cursor, bits.size(), { true, false });
 | 
					        fillBitmapTo(bits, cursor, bits.size(), {true, false});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        std::unique_ptr<Fluxmap> fluxmap(new Fluxmap);
 | 
					        std::unique_ptr<Fluxmap> fluxmap(new Fluxmap);
 | 
				
			||||||
        fluxmap->appendBits(bits, clockRateUs*1e3);
 | 
					        fluxmap->appendBits(bits, clockPeriod);
 | 
				
			||||||
        return fluxmap;
 | 
					        return fluxmap;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
	const Victor9kEncoderProto& _config;
 | 
					    const Victor9kEncoderProto& _config;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
std::unique_ptr<AbstractEncoder> createVictor9kEncoder(const EncoderProto& config)
 | 
					std::unique_ptr<Encoder> createVictor9kEncoder(const EncoderProto& config)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return std::unique_ptr<AbstractEncoder>(new Victor9kEncoder(config));
 | 
					    return std::unique_ptr<Encoder>(new Victor9kEncoder(config));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// vim: sw=4 ts=4 et
 | 
					// vim: sw=4 ts=4 et
 | 
				
			||||||
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,22 +1,26 @@
 | 
				
			|||||||
#ifndef VICTOR9K_H
 | 
					#ifndef VICTOR9K_H
 | 
				
			||||||
#define VICTOR9K_H
 | 
					#define VICTOR9K_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class AbstractEncoder;
 | 
					class Encoder;
 | 
				
			||||||
class AbstractDecoder;
 | 
					class Decoder;
 | 
				
			||||||
class EncoderProto;
 | 
					class EncoderProto;
 | 
				
			||||||
class DecoderProto;
 | 
					class DecoderProto;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* ... 1101 0101 0111
 | 
					/* ... 1101 0101 0111
 | 
				
			||||||
 *       ^^ ^^^^ ^^^^ ten bit IO byte */
 | 
					 *       ^^ ^^^^ ^^^^ ten bit IO byte */
 | 
				
			||||||
#define VICTOR9K_SECTOR_RECORD 0xfffffd57 
 | 
					#define VICTOR9K_SECTOR_RECORD 0xfffffd57
 | 
				
			||||||
 | 
					#define VICTOR9K_HEADER_ID 0x7
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* ... 1101 0100 1001
 | 
					/* ... 1101 0100 1001
 | 
				
			||||||
 *       ^^ ^^^^ ^^^^ ten bit IO byte */
 | 
					 *       ^^ ^^^^ ^^^^ ten bit IO byte */
 | 
				
			||||||
#define VICTOR9K_DATA_RECORD   0xfffffd49
 | 
					#define VICTOR9K_DATA_RECORD 0xfffffd49
 | 
				
			||||||
 | 
					#define VICTOR9K_DATA_ID 0x8
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define VICTOR9K_SECTOR_LENGTH 512
 | 
					#define VICTOR9K_SECTOR_LENGTH 512
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern std::unique_ptr<AbstractDecoder> createVictor9kDecoder(const DecoderProto& config);
 | 
					extern std::unique_ptr<Decoder> createVictor9kDecoder(
 | 
				
			||||||
extern std::unique_ptr<AbstractEncoder> createVictor9kEncoder(const EncoderProto& config);
 | 
					    const DecoderProto& config);
 | 
				
			||||||
 | 
					extern std::unique_ptr<Encoder> createVictor9kEncoder(
 | 
				
			||||||
 | 
					    const EncoderProto& config);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,28 +5,32 @@ import "lib/common.proto";
 | 
				
			|||||||
message Victor9kDecoderProto {}
 | 
					message Victor9kDecoderProto {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// NEXT: 12
 | 
					// NEXT: 12
 | 
				
			||||||
message Victor9kEncoderProto {
 | 
					message Victor9kEncoderProto
 | 
				
			||||||
	message TrackdataProto {
 | 
					{
 | 
				
			||||||
		message SectorRangeProto {
 | 
					    message TrackdataProto
 | 
				
			||||||
			optional int32 start_sector = 1 [(help) = "first sector ID on track"];
 | 
					    {
 | 
				
			||||||
			optional int32 sector_count = 2 [(help) = "number of sectors on track"];
 | 
					        optional int32 min_track = 1
 | 
				
			||||||
		}
 | 
					            [ (help) = "minimum track this format applies to" ];
 | 
				
			||||||
 | 
					        optional int32 max_track = 2
 | 
				
			||||||
 | 
					            [ (help) = "maximum track this format applies to" ];
 | 
				
			||||||
 | 
					        optional int32 head = 3
 | 
				
			||||||
 | 
					            [ (help) = "which head this format applies to" ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		optional int32 min_cylinder = 1            [(help) = "minimum cylinder this format applies to"];
 | 
					        optional double rotational_period_ms = 4
 | 
				
			||||||
		optional int32 max_cylinder = 2            [(help) = "maximum cylinder this format applies to"];
 | 
					            [ (help) = "original rotational period of this track" ];
 | 
				
			||||||
		optional int32 head = 3                    [(help) = "which head this format applies to"];
 | 
					        optional double clock_period_us = 5
 | 
				
			||||||
 | 
					            [ (help) = "original data rate of this track" ];
 | 
				
			||||||
 | 
					        optional double post_index_gap_us = 6
 | 
				
			||||||
 | 
					            [ (help) = "size of post-index gap" ];
 | 
				
			||||||
 | 
					        optional int32 pre_header_sync_bits = 10
 | 
				
			||||||
 | 
					            [ (help) = "number of sync bits before the sector header" ];
 | 
				
			||||||
 | 
					        optional int32 pre_data_sync_bits = 8
 | 
				
			||||||
 | 
					            [ (help) = "number of sync bits before the sector data" ];
 | 
				
			||||||
 | 
					        optional int32 post_data_gap_bits = 9
 | 
				
			||||||
 | 
					            [ (help) = "size of gap between data and the next header" ];
 | 
				
			||||||
 | 
					        optional int32 post_header_gap_bits = 11
 | 
				
			||||||
 | 
					            [ (help) = "size of gap between header and the data" ];
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		optional double original_period_ms = 4     [(help) = "original rotational period of this cylinder"];
 | 
					    repeated TrackdataProto trackdata = 1;
 | 
				
			||||||
		optional double original_data_rate_khz = 5 [(help) = "original data rate of this cylinder"];
 | 
					 | 
				
			||||||
		optional double post_index_gap_us = 6      [(help) = "size of post-index gap"];
 | 
					 | 
				
			||||||
		optional int32 pre_header_sync_bits = 10   [(help) = "number of sync bits before the sector header"];
 | 
					 | 
				
			||||||
		optional int32 pre_data_sync_bits = 8      [(help) = "number of sync bits before the sector data"];
 | 
					 | 
				
			||||||
		optional int32 post_data_gap_bits = 9      [(help) = "size of gap between data and the next header"];
 | 
					 | 
				
			||||||
		optional int32 post_header_gap_bits = 11   [(help) = "size of gap between header and the data"];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		optional SectorRangeProto sector_range = 7 [(help) = "write these sectors on each track"];
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	repeated TrackdataProto trackdata = 1;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -13,49 +13,43 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
static const FluxPattern SECTOR_START_PATTERN(16, 0xaaab);
 | 
					static const FluxPattern SECTOR_START_PATTERN(16, 0xaaab);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ZilogMczDecoder : public AbstractDecoder
 | 
					class ZilogMczDecoder : public Decoder
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
	ZilogMczDecoder(const DecoderProto& config):
 | 
					    ZilogMczDecoder(const DecoderProto& config): Decoder(config) {}
 | 
				
			||||||
		AbstractDecoder(config)
 | 
					 | 
				
			||||||
	{}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    RecordType advanceToNextRecord()
 | 
					    nanoseconds_t advanceToNextRecord() override
 | 
				
			||||||
	{
 | 
					    {
 | 
				
			||||||
		const FluxMatcher* matcher = nullptr;
 | 
					        seekToIndexMark();
 | 
				
			||||||
		_fmr->seekToIndexMark();
 | 
					        return seekToPattern(SECTOR_START_PATTERN);
 | 
				
			||||||
		_sector->clock = _fmr->seekToPattern(SECTOR_START_PATTERN, matcher);
 | 
					    }
 | 
				
			||||||
		if (matcher == &SECTOR_START_PATTERN)
 | 
					 | 
				
			||||||
			return SECTOR_RECORD;
 | 
					 | 
				
			||||||
		return UNKNOWN_RECORD;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void decodeSectorRecord()
 | 
					    void decodeSectorRecord() override
 | 
				
			||||||
	{
 | 
					    {
 | 
				
			||||||
		readRawBits(14);
 | 
					        readRawBits(14);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		auto rawbits = readRawBits(140*16);
 | 
					        auto rawbits = readRawBits(140 * 16);
 | 
				
			||||||
		auto bytes = decodeFmMfm(rawbits).slice(0, 140);
 | 
					        auto bytes = decodeFmMfm(rawbits).slice(0, 140);
 | 
				
			||||||
		ByteReader br(bytes);
 | 
					        ByteReader br(bytes);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		_sector->logicalSector = br.read_8() & 0x1f;
 | 
					        _sector->logicalSector = br.read_8() & 0x1f;
 | 
				
			||||||
		_sector->logicalSide = 0;
 | 
					        _sector->logicalSide = 0;
 | 
				
			||||||
		_sector->logicalTrack = br.read_8() & 0x7f;
 | 
					        _sector->logicalTrack = br.read_8() & 0x7f;
 | 
				
			||||||
		if (_sector->logicalSector > 31)
 | 
					        if (_sector->logicalSector > 31)
 | 
				
			||||||
			return;
 | 
					            return;
 | 
				
			||||||
		if (_sector->logicalTrack > 80)
 | 
					        if (_sector->logicalTrack > 80)
 | 
				
			||||||
			return;
 | 
					            return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		_sector->data = br.read(132);
 | 
					        _sector->data = br.read(132);
 | 
				
			||||||
		uint16_t wantChecksum = br.read_be16();
 | 
					        uint16_t wantChecksum = br.read_be16();
 | 
				
			||||||
		uint16_t gotChecksum = crc16(MODBUS_POLY, 0x0000, bytes.slice(0, 134));
 | 
					        uint16_t gotChecksum = crc16(MODBUS_POLY, 0x0000, bytes.slice(0, 134));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		_sector->status = (wantChecksum == gotChecksum) ? Sector::OK : Sector::BAD_CHECKSUM;
 | 
					        _sector->status =
 | 
				
			||||||
	}
 | 
					            (wantChecksum == gotChecksum) ? Sector::OK : Sector::BAD_CHECKSUM;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
std::unique_ptr<AbstractDecoder> createZilogMczDecoder(const DecoderProto& config)
 | 
					std::unique_ptr<Decoder> createZilogMczDecoder(const DecoderProto& config)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return std::unique_ptr<AbstractDecoder>(new ZilogMczDecoder(config));
 | 
					    return std::unique_ptr<Decoder>(new ZilogMczDecoder(config));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,8 +1,7 @@
 | 
				
			|||||||
#ifndef ZILOGMCZ_H
 | 
					#ifndef ZILOGMCZ_H
 | 
				
			||||||
#define ZILOGMCZ_H
 | 
					#define ZILOGMCZ_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern std::unique_ptr<AbstractDecoder> createZilogMczDecoder(const DecoderProto& config);
 | 
					extern std::unique_ptr<Decoder> createZilogMczDecoder(
 | 
				
			||||||
 | 
					    const DecoderProto& config);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										194
									
								
								build.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										194
									
								
								build.lua
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,194 @@
 | 
				
			|||||||
 | 
					vars.cflags = { "$(CFLAGS)" }
 | 
				
			||||||
 | 
					vars.cxxflags = { "$(CXXFLAGS)" }
 | 
				
			||||||
 | 
					vars.ldflags = { "-pthread" }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					include "build/protobuf.lua"
 | 
				
			||||||
 | 
					include "build/dependency.lua"
 | 
				
			||||||
 | 
					include "build/tests.lua"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					dependency {
 | 
				
			||||||
 | 
						name = "fmt_dep",
 | 
				
			||||||
 | 
						pkg_config = "fmt",
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					dependency {
 | 
				
			||||||
 | 
						name = "stb_dep",
 | 
				
			||||||
 | 
						pkg_config = "stb",
 | 
				
			||||||
 | 
						fallback = "dep/stb+stb"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					dependency {
 | 
				
			||||||
 | 
						name = "protobuf_dep",
 | 
				
			||||||
 | 
						pkg_config = "protobuf"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					dependency {
 | 
				
			||||||
 | 
						name = "zlib_dep",
 | 
				
			||||||
 | 
						pkg_config = "zlib"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					proto_cc_library {
 | 
				
			||||||
 | 
						name = "config_lib",
 | 
				
			||||||
 | 
						srcs = {
 | 
				
			||||||
 | 
							"./lib/common.proto",
 | 
				
			||||||
 | 
							"./lib/config.proto",
 | 
				
			||||||
 | 
							"./lib/decoders/decoders.proto",
 | 
				
			||||||
 | 
							"./lib/drive.proto",
 | 
				
			||||||
 | 
							"./lib/encoders/encoders.proto",
 | 
				
			||||||
 | 
							"./lib/fl2.proto",
 | 
				
			||||||
 | 
							"./lib/fluxsink/fluxsink.proto",
 | 
				
			||||||
 | 
							"./lib/fluxsource/fluxsource.proto",
 | 
				
			||||||
 | 
							"./lib/imagereader/imagereader.proto",
 | 
				
			||||||
 | 
							"./lib/imagewriter/imagewriter.proto",
 | 
				
			||||||
 | 
							"./lib/mapper.proto",
 | 
				
			||||||
 | 
							"./lib/usb/usb.proto",
 | 
				
			||||||
 | 
							"./arch/aeslanier/aeslanier.proto",
 | 
				
			||||||
 | 
							"./arch/agat/agat.proto",
 | 
				
			||||||
 | 
							"./arch/amiga/amiga.proto",
 | 
				
			||||||
 | 
							"./arch/apple2/apple2.proto",
 | 
				
			||||||
 | 
							"./arch/brother/brother.proto",
 | 
				
			||||||
 | 
							"./arch/c64/c64.proto",
 | 
				
			||||||
 | 
							"./arch/f85/f85.proto",
 | 
				
			||||||
 | 
							"./arch/fb100/fb100.proto",
 | 
				
			||||||
 | 
							"./arch/ibm/ibm.proto",
 | 
				
			||||||
 | 
							"./arch/macintosh/macintosh.proto",
 | 
				
			||||||
 | 
							"./arch/micropolis/micropolis.proto",
 | 
				
			||||||
 | 
							"./arch/mx/mx.proto",
 | 
				
			||||||
 | 
							"./arch/northstar/northstar.proto",
 | 
				
			||||||
 | 
							"./arch/rolandd20/rolandd20.proto",
 | 
				
			||||||
 | 
							"./arch/tids990/tids990.proto",
 | 
				
			||||||
 | 
							"./arch/victor9k/victor9k.proto",
 | 
				
			||||||
 | 
							"./arch/zilogmcz/zilogmcz.proto",
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					clibrary {
 | 
				
			||||||
 | 
						name = "protocol_lib",
 | 
				
			||||||
 | 
						hdrs = { "./protocol.h" }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					clibrary {
 | 
				
			||||||
 | 
						name = "libfluxengine",
 | 
				
			||||||
 | 
						srcs = {
 | 
				
			||||||
 | 
							"./arch/aeslanier/decoder.cc",
 | 
				
			||||||
 | 
							"./arch/agat/agat.cc",
 | 
				
			||||||
 | 
							"./arch/agat/decoder.cc",
 | 
				
			||||||
 | 
							"./arch/amiga/amiga.cc",
 | 
				
			||||||
 | 
							"./arch/amiga/decoder.cc",
 | 
				
			||||||
 | 
							"./arch/amiga/encoder.cc",
 | 
				
			||||||
 | 
							"./arch/apple2/decoder.cc",
 | 
				
			||||||
 | 
							"./arch/apple2/encoder.cc",
 | 
				
			||||||
 | 
							"./arch/brother/decoder.cc",
 | 
				
			||||||
 | 
							"./arch/brother/encoder.cc",
 | 
				
			||||||
 | 
							"./arch/c64/c64.cc",
 | 
				
			||||||
 | 
							"./arch/c64/decoder.cc",
 | 
				
			||||||
 | 
							"./arch/c64/encoder.cc",
 | 
				
			||||||
 | 
							"./arch/f85/decoder.cc",
 | 
				
			||||||
 | 
							"./arch/fb100/decoder.cc",
 | 
				
			||||||
 | 
							"./arch/ibm/decoder.cc",
 | 
				
			||||||
 | 
							"./arch/ibm/encoder.cc",
 | 
				
			||||||
 | 
							"./arch/macintosh/decoder.cc",
 | 
				
			||||||
 | 
							"./arch/macintosh/encoder.cc",
 | 
				
			||||||
 | 
							"./arch/micropolis/decoder.cc",
 | 
				
			||||||
 | 
							"./arch/micropolis/encoder.cc",
 | 
				
			||||||
 | 
							"./arch/mx/decoder.cc",
 | 
				
			||||||
 | 
							"./arch/northstar/decoder.cc",
 | 
				
			||||||
 | 
							"./arch/northstar/encoder.cc",
 | 
				
			||||||
 | 
							"./arch/rolandd20/rolandd20.cc",
 | 
				
			||||||
 | 
							"./arch/tids990/decoder.cc",
 | 
				
			||||||
 | 
							"./arch/tids990/encoder.cc",
 | 
				
			||||||
 | 
							"./arch/victor9k/decoder.cc",
 | 
				
			||||||
 | 
							"./arch/victor9k/encoder.cc",
 | 
				
			||||||
 | 
							"./arch/zilogmcz/decoder.cc",
 | 
				
			||||||
 | 
							"./lib/bitmap.cc",
 | 
				
			||||||
 | 
							"./lib/bytes.cc",
 | 
				
			||||||
 | 
							"./lib/crc.cc",
 | 
				
			||||||
 | 
							"./lib/csvreader.cc",
 | 
				
			||||||
 | 
							"./lib/decoders/decoders.cc",
 | 
				
			||||||
 | 
							"./lib/decoders/fluxdecoder.cc",
 | 
				
			||||||
 | 
							"./lib/decoders/fluxmapreader.cc",
 | 
				
			||||||
 | 
							"./lib/decoders/fmmfm.cc",
 | 
				
			||||||
 | 
							"./lib/encoders/encoders.cc",
 | 
				
			||||||
 | 
							"./lib/flags.cc",
 | 
				
			||||||
 | 
							"./lib/fluxmap.cc",
 | 
				
			||||||
 | 
							"./lib/fluxsink/aufluxsink.cc",
 | 
				
			||||||
 | 
							"./lib/fluxsink/fl2fluxsink.cc",
 | 
				
			||||||
 | 
							"./lib/fluxsink/fluxsink.cc",
 | 
				
			||||||
 | 
							"./lib/fluxsink/hardwarefluxsink.cc",
 | 
				
			||||||
 | 
							"./lib/fluxsink/scpfluxsink.cc",
 | 
				
			||||||
 | 
							"./lib/fluxsink/vcdfluxsink.cc",
 | 
				
			||||||
 | 
							"./lib/fluxsource/cwffluxsource.cc",
 | 
				
			||||||
 | 
							"./lib/fluxsource/erasefluxsource.cc",
 | 
				
			||||||
 | 
							"./lib/fluxsource/fl2fluxsource.cc",
 | 
				
			||||||
 | 
							"./lib/fluxsource/fluxsource.cc",
 | 
				
			||||||
 | 
							"./lib/fluxsource/hardwarefluxsource.cc",
 | 
				
			||||||
 | 
							"./lib/fluxsource/kryoflux.cc",
 | 
				
			||||||
 | 
							"./lib/fluxsource/kryofluxfluxsource.cc",
 | 
				
			||||||
 | 
							"./lib/fluxsource/scpfluxsource.cc",
 | 
				
			||||||
 | 
							"./lib/fluxsource/testpatternfluxsource.cc",
 | 
				
			||||||
 | 
							"./lib/globals.cc",
 | 
				
			||||||
 | 
							"./lib/hexdump.cc",
 | 
				
			||||||
 | 
							"./lib/image.cc",
 | 
				
			||||||
 | 
							"./lib/imagereader/d64imagereader.cc",
 | 
				
			||||||
 | 
							"./lib/imagereader/d88imagereader.cc",
 | 
				
			||||||
 | 
							"./lib/imagereader/dimimagereader.cc",
 | 
				
			||||||
 | 
							"./lib/imagereader/diskcopyimagereader.cc",
 | 
				
			||||||
 | 
							"./lib/imagereader/fdiimagereader.cc",
 | 
				
			||||||
 | 
							"./lib/imagereader/imagereader.cc",
 | 
				
			||||||
 | 
							"./lib/imagereader/imdimagereader.cc",
 | 
				
			||||||
 | 
							"./lib/imagereader/imgimagereader.cc",
 | 
				
			||||||
 | 
							"./lib/imagereader/jv3imagereader.cc",
 | 
				
			||||||
 | 
							"./lib/imagereader/nfdimagereader.cc",
 | 
				
			||||||
 | 
							"./lib/imagereader/nsiimagereader.cc",
 | 
				
			||||||
 | 
							"./lib/imagereader/td0imagereader.cc",
 | 
				
			||||||
 | 
							"./lib/imagewriter/d64imagewriter.cc",
 | 
				
			||||||
 | 
							"./lib/imagewriter/d88imagewriter.cc",
 | 
				
			||||||
 | 
							"./lib/imagewriter/diskcopyimagewriter.cc",
 | 
				
			||||||
 | 
							"./lib/imagewriter/imagewriter.cc",
 | 
				
			||||||
 | 
							"./lib/imagewriter/imgimagewriter.cc",
 | 
				
			||||||
 | 
							"./lib/imagewriter/ldbsimagewriter.cc",
 | 
				
			||||||
 | 
							"./lib/imagewriter/nsiimagewriter.cc",
 | 
				
			||||||
 | 
							"./lib/imagewriter/rawimagewriter.cc",
 | 
				
			||||||
 | 
							"./lib/imginputoutpututils.cc",
 | 
				
			||||||
 | 
							"./lib/ldbs.cc",
 | 
				
			||||||
 | 
							"./lib/logger.cc",
 | 
				
			||||||
 | 
							"./lib/mapper.cc",
 | 
				
			||||||
 | 
							"./lib/proto.cc",
 | 
				
			||||||
 | 
							"./lib/readerwriter.cc",
 | 
				
			||||||
 | 
							"./lib/sector.cc",
 | 
				
			||||||
 | 
							"./lib/usb/fluxengineusb.cc",
 | 
				
			||||||
 | 
							"./lib/usb/greaseweazle.cc",
 | 
				
			||||||
 | 
							"./lib/usb/greaseweazleusb.cc",
 | 
				
			||||||
 | 
							"./lib/usb/serial.cc",
 | 
				
			||||||
 | 
							"./lib/usb/usb.cc",
 | 
				
			||||||
 | 
							"./lib/usb/usbfinder.cc",
 | 
				
			||||||
 | 
							"./lib/utils.cc",
 | 
				
			||||||
 | 
							"protocol.h",
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						deps = {
 | 
				
			||||||
 | 
							"+config_lib",
 | 
				
			||||||
 | 
							"+protocol_lib",
 | 
				
			||||||
 | 
							"+fmt_dep",
 | 
				
			||||||
 | 
							"+protobuf_dep",
 | 
				
			||||||
 | 
							"+zlib_dep",
 | 
				
			||||||
 | 
							"dep/libusbp+libusbp",
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						dep_cflags = { "-Ilib", "-Iarch", "-I." },
 | 
				
			||||||
 | 
						vars = {
 | 
				
			||||||
 | 
							["+cflags"] = { "-Ilib", "-Iarch", "-I." }
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					installable {
 | 
				
			||||||
 | 
						name = "all",
 | 
				
			||||||
 | 
						map = {
 | 
				
			||||||
 | 
							["fluxengine"] = "src+fluxengine",
 | 
				
			||||||
 | 
							["fluxengine-gui"] = "src/gui+fluxengine",
 | 
				
			||||||
 | 
							["brother120tool"] = "tools+brother120tool",
 | 
				
			||||||
 | 
							["brother240tool"] = "tools+brother240tool",
 | 
				
			||||||
 | 
							["upgrade-flux-file"] = "tools+upgrade-flux-file",
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					include "tests/build.lua"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										251
									
								
								build/build.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										251
									
								
								build/build.lua
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,251 @@
 | 
				
			|||||||
 | 
					local OBJDIR = "$(OBJDIR)"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					local function objdir(e)
 | 
				
			||||||
 | 
						return concatpath(OBJDIR, e.cwd, e.name)
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					definerule("normalrule",
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							ins = { type="targets" },
 | 
				
			||||||
 | 
							deps = { type="targets", default={} },
 | 
				
			||||||
 | 
							outs = { type="targets", default={} },
 | 
				
			||||||
 | 
							outleaves = { type="strings" },
 | 
				
			||||||
 | 
							label = { type="string", optional=true },
 | 
				
			||||||
 | 
							objdir = { type="string", optional=true },
 | 
				
			||||||
 | 
							commands = { type="strings" },
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						function (e)
 | 
				
			||||||
 | 
							local dir = e.objdir or objdir(e)
 | 
				
			||||||
 | 
							local realouts = {}
 | 
				
			||||||
 | 
							for _, v in pairs(e.outleaves) do
 | 
				
			||||||
 | 
								realouts[#realouts+1] = concatpath(dir, v)
 | 
				
			||||||
 | 
							end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							local vars = inherit(e.vars, {
 | 
				
			||||||
 | 
								dir = dir
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							local result = simplerule {
 | 
				
			||||||
 | 
								name = e.name,
 | 
				
			||||||
 | 
								ins = e.ins,
 | 
				
			||||||
 | 
								deps = e.deps,
 | 
				
			||||||
 | 
								outs = concat(realouts, filenamesof(e.outs)),
 | 
				
			||||||
 | 
								label = e.label,
 | 
				
			||||||
 | 
								commands = e.commands,
 | 
				
			||||||
 | 
								vars = vars,
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							result.dir = dir
 | 
				
			||||||
 | 
							return result
 | 
				
			||||||
 | 
						end
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					local function is_clike(f)
 | 
				
			||||||
 | 
						return f:find("%.c$") or f:find("%.cc$") or f:find("%.cpp$")
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					definerule("cfile",
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							srcs = { type="targets" },
 | 
				
			||||||
 | 
							deps = { type="targets", default={} }
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						function (e)
 | 
				
			||||||
 | 
							local cflags = e.vars.cflags
 | 
				
			||||||
 | 
							local cxxflags = e.vars.cxxflags
 | 
				
			||||||
 | 
							for _, target in ipairs(targetsof(e.deps)) do
 | 
				
			||||||
 | 
								if target.is.clibrary then
 | 
				
			||||||
 | 
									cflags = concat(cflags, target.dep_cflags)
 | 
				
			||||||
 | 
									cxxflags = concat(cxxflags, target.dep_cxxflags)
 | 
				
			||||||
 | 
								end
 | 
				
			||||||
 | 
							end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							local src = filter(filenamesof(e.srcs), is_clike)
 | 
				
			||||||
 | 
							local cmd
 | 
				
			||||||
 | 
							local cxx = false
 | 
				
			||||||
 | 
							if src[1]:find("%.c$") then
 | 
				
			||||||
 | 
								cmd = "$(CC) -c -o %{outs[1]} %{ins[1]} %{hdrpaths} %{cflags}"
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
								cmd = "$(CXX) -c -o %{outs[1]} %{ins[1]} %{hdrpaths} %{cflags} %{cxxflags}"
 | 
				
			||||||
 | 
								cxx = true
 | 
				
			||||||
 | 
							end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							local outleaf = basename(e.name)..".o"
 | 
				
			||||||
 | 
							local rule = normalrule {
 | 
				
			||||||
 | 
								name = e.name,
 | 
				
			||||||
 | 
								cwd = e.cwd,
 | 
				
			||||||
 | 
								ins = e.srcs,
 | 
				
			||||||
 | 
								deps = e.deps,
 | 
				
			||||||
 | 
								outleaves = {outleaf},
 | 
				
			||||||
 | 
								label = e.label,
 | 
				
			||||||
 | 
								commands = cmd,
 | 
				
			||||||
 | 
								vars = {
 | 
				
			||||||
 | 
									hdrpaths = {},
 | 
				
			||||||
 | 
									cflags = cflags,
 | 
				
			||||||
 | 
									cxxflags = cxxflags,
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							rule.is.cxxfile = cxx
 | 
				
			||||||
 | 
							return rule
 | 
				
			||||||
 | 
						end
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					local function do_cfiles(e)
 | 
				
			||||||
 | 
						local outs = {}
 | 
				
			||||||
 | 
						local srcs = filenamesof(e.srcs)
 | 
				
			||||||
 | 
						for _, f in ipairs(sorted(filter(srcs, is_clike))) do
 | 
				
			||||||
 | 
							local ofile
 | 
				
			||||||
 | 
							if f:find(OBJDIR, 1, true) == 1 then
 | 
				
			||||||
 | 
								ofile = e.name.."/"..f:sub(#OBJDIR+1)..".o"
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
								ofile = e.name.."/"..f..".o"
 | 
				
			||||||
 | 
							end
 | 
				
			||||||
 | 
							outs[#outs+1] = cfile {
 | 
				
			||||||
 | 
								name = ofile,
 | 
				
			||||||
 | 
								srcs = { f },
 | 
				
			||||||
 | 
								deps = e.deps
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						end
 | 
				
			||||||
 | 
						return outs
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					definerule("clibrary",
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							srcs = { type="targets", default={} },
 | 
				
			||||||
 | 
							deps = { type="targets", default={} },
 | 
				
			||||||
 | 
							hdrs = { type="targets", default={} },
 | 
				
			||||||
 | 
							dep_cflags = { type="strings", default={} },
 | 
				
			||||||
 | 
							dep_cxxflags = { type="strings", default={} },
 | 
				
			||||||
 | 
							dep_ldflags = { type="strings", default={} },
 | 
				
			||||||
 | 
							dep_libs = { type="strings", default={} },
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						function (e)
 | 
				
			||||||
 | 
							local ins = do_cfiles(e)
 | 
				
			||||||
 | 
							local cxx = false
 | 
				
			||||||
 | 
							for _, f in ipairs(ins) do
 | 
				
			||||||
 | 
								if f.is.cxxfile then
 | 
				
			||||||
 | 
									cxx = true
 | 
				
			||||||
 | 
									break
 | 
				
			||||||
 | 
								end
 | 
				
			||||||
 | 
							end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							local mkdirs = {}
 | 
				
			||||||
 | 
							local copies = {}
 | 
				
			||||||
 | 
							local outs = {}
 | 
				
			||||||
 | 
							local function copy_file(src, dest)
 | 
				
			||||||
 | 
								mkdirs[#mkdirs+1] = "mkdir -p %{dir}/"..dirname(dest)
 | 
				
			||||||
 | 
								copies[#copies+1] = "cp "..src.." %{dir}/"..dest
 | 
				
			||||||
 | 
								outs[#outs+1] = objdir(e).."/"..dest
 | 
				
			||||||
 | 
							end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							local deps = {}
 | 
				
			||||||
 | 
							for k, v in pairs(e.hdrs) do
 | 
				
			||||||
 | 
								deps[#deps+1] = v
 | 
				
			||||||
 | 
								if type(k) == "number" then
 | 
				
			||||||
 | 
									v = filenamesof(v)
 | 
				
			||||||
 | 
									for _, v in ipairs(v) do
 | 
				
			||||||
 | 
										if not startswith(e.cwd, v) then
 | 
				
			||||||
 | 
											error(string.format("filename '%s' is not local to '%s' --- "..
 | 
				
			||||||
 | 
												"you'll have to specify the output filename manually", v, e.cwd))
 | 
				
			||||||
 | 
										end
 | 
				
			||||||
 | 
										copy_file(v, v:gsub("^"..e.cwd, ""))
 | 
				
			||||||
 | 
									end
 | 
				
			||||||
 | 
								else
 | 
				
			||||||
 | 
									v = filenamesof(v)
 | 
				
			||||||
 | 
									if #v ~= 1 then
 | 
				
			||||||
 | 
										error("each mapped hdrs item can only cope with a single file")
 | 
				
			||||||
 | 
									end
 | 
				
			||||||
 | 
									copy_file(v[1], k)
 | 
				
			||||||
 | 
								end
 | 
				
			||||||
 | 
							end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							ins = sorted(filenamesof(ins))
 | 
				
			||||||
 | 
							local has_ar = (#ins ~= 0)
 | 
				
			||||||
 | 
							local lib = normalrule {
 | 
				
			||||||
 | 
								name = e.name,
 | 
				
			||||||
 | 
								cwd = e.cwd,
 | 
				
			||||||
 | 
								ins = sorted(filenamesof(ins)),
 | 
				
			||||||
 | 
								deps = deps,
 | 
				
			||||||
 | 
								outs = outs,
 | 
				
			||||||
 | 
								outleaves = { e.name..".a" },
 | 
				
			||||||
 | 
								label = e.label,
 | 
				
			||||||
 | 
								commands = {
 | 
				
			||||||
 | 
									sorted(mkdirs),
 | 
				
			||||||
 | 
									sorted(copies),
 | 
				
			||||||
 | 
									has_ar and "rm -f %{outs[1]} && $(AR) cqs %{outs[1]} %{ins}" or {},
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							lib.dep_cflags = concat(e.dep_cflags, "-I"..lib.dir)
 | 
				
			||||||
 | 
							lib.dep_cxxflags = e.dep_cxxflags
 | 
				
			||||||
 | 
							lib.dep_ldflags = e.dep_ldflags
 | 
				
			||||||
 | 
							lib.dep_libs = concat(e.dep_libs, has_ar and matching(filenamesof(lib), "%.a$") or {})
 | 
				
			||||||
 | 
							lib.dep_cxx = cxx
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for _, d in pairs(targetsof(e.deps)) do
 | 
				
			||||||
 | 
								lib.dep_cflags = concat(lib.dep_cflags, d.dep_cflags)
 | 
				
			||||||
 | 
								lib.dep_cxxflags = concat(lib.dep_cxxflags, d.dep_cxxflags)
 | 
				
			||||||
 | 
								lib.dep_ldflags = concat(lib.dep_ldflags, d.dep_ldflags)
 | 
				
			||||||
 | 
								lib.dep_libs = concat(lib.dep_libs, d.dep_libs)
 | 
				
			||||||
 | 
								lib.dep_cxx = lib.dep_cxx or d.dep_cxx
 | 
				
			||||||
 | 
							end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return lib
 | 
				
			||||||
 | 
						end
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					definerule("cprogram",
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							srcs = { type="targets", default={} },
 | 
				
			||||||
 | 
							deps = { type="targets", default={} },
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						function (e)
 | 
				
			||||||
 | 
							local deps = e.deps
 | 
				
			||||||
 | 
							local ins = {}
 | 
				
			||||||
 | 
							local cxx = false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (#e.srcs > 0) then
 | 
				
			||||||
 | 
								local objs = do_cfiles(e)
 | 
				
			||||||
 | 
								for _, obj in pairs(objs) do
 | 
				
			||||||
 | 
									if obj.is.cxxfile then
 | 
				
			||||||
 | 
										cxx = true
 | 
				
			||||||
 | 
									end
 | 
				
			||||||
 | 
									ins[#ins+1] = obj
 | 
				
			||||||
 | 
								end
 | 
				
			||||||
 | 
							end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							local libs = {}
 | 
				
			||||||
 | 
							local cflags = {}
 | 
				
			||||||
 | 
							local cxxflags = {}
 | 
				
			||||||
 | 
							local ldflags = {}
 | 
				
			||||||
 | 
							for _, lib in pairs(e.deps) do
 | 
				
			||||||
 | 
								cflags = concat(cflags, lib.dep_cflags)
 | 
				
			||||||
 | 
								cxxflags = concat(cxxflags, lib.dep_cxxflags)
 | 
				
			||||||
 | 
								ldflags = concat(ldflags, lib.dep_ldflags)
 | 
				
			||||||
 | 
								libs = concat(libs, lib.dep_libs)
 | 
				
			||||||
 | 
								cxx = cxx or lib.dep_cxx
 | 
				
			||||||
 | 
							end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							local command
 | 
				
			||||||
 | 
							if cxx then
 | 
				
			||||||
 | 
								command = "$(CXX) $(LDFLAGS) %{ldflags} -o %{outs[1]} %{ins} %{libs} %{libs}"
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
								command = "$(CC) $(LDFLAGS) %{ldflags} -o %{outs[1]} %{ins} %{libs} %{libs}"
 | 
				
			||||||
 | 
							end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return normalrule {
 | 
				
			||||||
 | 
								name = e.name,
 | 
				
			||||||
 | 
								cwd = e.cwd,
 | 
				
			||||||
 | 
								deps = deps,
 | 
				
			||||||
 | 
								ins = ins,
 | 
				
			||||||
 | 
								outleaves = { e.name },
 | 
				
			||||||
 | 
								commands = { command },
 | 
				
			||||||
 | 
								vars = {
 | 
				
			||||||
 | 
									cflags = cflags,
 | 
				
			||||||
 | 
									cxxflags = cxxflags,
 | 
				
			||||||
 | 
									ldflags = ldflags,
 | 
				
			||||||
 | 
									libs = libs,
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						end
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										18
									
								
								build/tests.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								build/tests.lua
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,18 @@
 | 
				
			|||||||
 | 
					definerule("test",
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							srcs = { type="targets", default={} },
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						function (e)
 | 
				
			||||||
 | 
							if vars.TESTS == "yes" then
 | 
				
			||||||
 | 
								normalrule {
 | 
				
			||||||
 | 
									name = e.name,
 | 
				
			||||||
 | 
									ins = e.srcs,
 | 
				
			||||||
 | 
									outleaves = { "log.txt" },
 | 
				
			||||||
 | 
									commands = {
 | 
				
			||||||
 | 
										"%{ins} > %{outs}",
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							end
 | 
				
			||||||
 | 
						end
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										45
									
								
								dep/adflib/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								dep/adflib/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,45 @@
 | 
				
			|||||||
 | 
					# Object files
 | 
				
			||||||
 | 
					*.o
 | 
				
			||||||
 | 
					*.lo
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Libraries
 | 
				
			||||||
 | 
					.libs
 | 
				
			||||||
 | 
					*.lib
 | 
				
			||||||
 | 
					*.a
 | 
				
			||||||
 | 
					*.la
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Shared objects (inc. Windows DLLs)
 | 
				
			||||||
 | 
					*.dll
 | 
				
			||||||
 | 
					*.so
 | 
				
			||||||
 | 
					*.so.*
 | 
				
			||||||
 | 
					*.dylib
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Executables
 | 
				
			||||||
 | 
					*.exe
 | 
				
			||||||
 | 
					*.out
 | 
				
			||||||
 | 
					*.app
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# generated by autogen.sh
 | 
				
			||||||
 | 
					INSTALL
 | 
				
			||||||
 | 
					Makefile.in
 | 
				
			||||||
 | 
					aclocal.m4
 | 
				
			||||||
 | 
					autom4te.cache
 | 
				
			||||||
 | 
					compile
 | 
				
			||||||
 | 
					config.guess
 | 
				
			||||||
 | 
					config.h.in
 | 
				
			||||||
 | 
					config.sub
 | 
				
			||||||
 | 
					configure
 | 
				
			||||||
 | 
					depcomp
 | 
				
			||||||
 | 
					install-sh
 | 
				
			||||||
 | 
					ltmain.sh
 | 
				
			||||||
 | 
					missing
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# generated by configure
 | 
				
			||||||
 | 
					.deps
 | 
				
			||||||
 | 
					Makefile
 | 
				
			||||||
 | 
					adflib.pc
 | 
				
			||||||
 | 
					config.h
 | 
				
			||||||
 | 
					config.log
 | 
				
			||||||
 | 
					config.status
 | 
				
			||||||
 | 
					libtool
 | 
				
			||||||
 | 
					stamp-h1
 | 
				
			||||||
							
								
								
									
										13
									
								
								dep/adflib/AUTHORS
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								dep/adflib/AUTHORS
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,13 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					The main developper is 
 | 
				
			||||||
 | 
					 Laurent Clévy (laurent.clevy@club-internet.fr)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Contributors are:
 | 
				
			||||||
 | 
					 Bjarne Viksoe 
 | 
				
			||||||
 | 
					   (C++ wrapper, lot of bug fixes)
 | 
				
			||||||
 | 
					 Gary Harris 
 | 
				
			||||||
 | 
					   (bug fixes and W32 support)
 | 
				
			||||||
 | 
					 Dan Sutherland 
 | 
				
			||||||
 | 
					   (bug fixes and W32 support)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					See CHANGES.txt for detailed contributions.
 | 
				
			||||||
							
								
								
									
										339
									
								
								dep/adflib/COPYING
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										339
									
								
								dep/adflib/COPYING
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,339 @@
 | 
				
			|||||||
 | 
							    GNU GENERAL PUBLIC LICENSE
 | 
				
			||||||
 | 
							       Version 2, June 1991
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
 | 
				
			||||||
 | 
					 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 | 
				
			||||||
 | 
					 Everyone is permitted to copy and distribute verbatim copies
 | 
				
			||||||
 | 
					 of this license document, but changing it is not allowed.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								    Preamble
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  The licenses for most software are designed to take away your
 | 
				
			||||||
 | 
					freedom to share and change it.  By contrast, the GNU General Public
 | 
				
			||||||
 | 
					License is intended to guarantee your freedom to share and change free
 | 
				
			||||||
 | 
					software--to make sure the software is free for all its users.  This
 | 
				
			||||||
 | 
					General Public License applies to most of the Free Software
 | 
				
			||||||
 | 
					Foundation's software and to any other program whose authors commit to
 | 
				
			||||||
 | 
					using it.  (Some other Free Software Foundation software is covered by
 | 
				
			||||||
 | 
					the GNU Lesser General Public License instead.)  You can apply it to
 | 
				
			||||||
 | 
					your programs, too.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  When we speak of free software, we are referring to freedom, not
 | 
				
			||||||
 | 
					price.  Our General Public Licenses are designed to make sure that you
 | 
				
			||||||
 | 
					have the freedom to distribute copies of free software (and charge for
 | 
				
			||||||
 | 
					this service if you wish), that you receive source code or can get it
 | 
				
			||||||
 | 
					if you want it, that you can change the software or use pieces of it
 | 
				
			||||||
 | 
					in new free programs; and that you know you can do these things.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  To protect your rights, we need to make restrictions that forbid
 | 
				
			||||||
 | 
					anyone to deny you these rights or to ask you to surrender the rights.
 | 
				
			||||||
 | 
					These restrictions translate to certain responsibilities for you if you
 | 
				
			||||||
 | 
					distribute copies of the software, or if you modify it.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  For example, if you distribute copies of such a program, whether
 | 
				
			||||||
 | 
					gratis or for a fee, you must give the recipients all the rights that
 | 
				
			||||||
 | 
					you have.  You must make sure that they, too, receive or can get the
 | 
				
			||||||
 | 
					source code.  And you must show them these terms so they know their
 | 
				
			||||||
 | 
					rights.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  We protect your rights with two steps: (1) copyright the software, and
 | 
				
			||||||
 | 
					(2) offer you this license which gives you legal permission to copy,
 | 
				
			||||||
 | 
					distribute and/or modify the software.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Also, for each author's protection and ours, we want to make certain
 | 
				
			||||||
 | 
					that everyone understands that there is no warranty for this free
 | 
				
			||||||
 | 
					software.  If the software is modified by someone else and passed on, we
 | 
				
			||||||
 | 
					want its recipients to know that what they have is not the original, so
 | 
				
			||||||
 | 
					that any problems introduced by others will not reflect on the original
 | 
				
			||||||
 | 
					authors' reputations.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Finally, any free program is threatened constantly by software
 | 
				
			||||||
 | 
					patents.  We wish to avoid the danger that redistributors of a free
 | 
				
			||||||
 | 
					program will individually obtain patent licenses, in effect making the
 | 
				
			||||||
 | 
					program proprietary.  To prevent this, we have made it clear that any
 | 
				
			||||||
 | 
					patent must be licensed for everyone's free use or not licensed at all.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  The precise terms and conditions for copying, distribution and
 | 
				
			||||||
 | 
					modification follow.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							    GNU GENERAL PUBLIC LICENSE
 | 
				
			||||||
 | 
					   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  0. This License applies to any program or other work which contains
 | 
				
			||||||
 | 
					a notice placed by the copyright holder saying it may be distributed
 | 
				
			||||||
 | 
					under the terms of this General Public License.  The "Program", below,
 | 
				
			||||||
 | 
					refers to any such program or work, and a "work based on the Program"
 | 
				
			||||||
 | 
					means either the Program or any derivative work under copyright law:
 | 
				
			||||||
 | 
					that is to say, a work containing the Program or a portion of it,
 | 
				
			||||||
 | 
					either verbatim or with modifications and/or translated into another
 | 
				
			||||||
 | 
					language.  (Hereinafter, translation is included without limitation in
 | 
				
			||||||
 | 
					the term "modification".)  Each licensee is addressed as "you".
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Activities other than copying, distribution and modification are not
 | 
				
			||||||
 | 
					covered by this License; they are outside its scope.  The act of
 | 
				
			||||||
 | 
					running the Program is not restricted, and the output from the Program
 | 
				
			||||||
 | 
					is covered only if its contents constitute a work based on the
 | 
				
			||||||
 | 
					Program (independent of having been made by running the Program).
 | 
				
			||||||
 | 
					Whether that is true depends on what the Program does.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  1. You may copy and distribute verbatim copies of the Program's
 | 
				
			||||||
 | 
					source code as you receive it, in any medium, provided that you
 | 
				
			||||||
 | 
					conspicuously and appropriately publish on each copy an appropriate
 | 
				
			||||||
 | 
					copyright notice and disclaimer of warranty; keep intact all the
 | 
				
			||||||
 | 
					notices that refer to this License and to the absence of any warranty;
 | 
				
			||||||
 | 
					and give any other recipients of the Program a copy of this License
 | 
				
			||||||
 | 
					along with the Program.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					You may charge a fee for the physical act of transferring a copy, and
 | 
				
			||||||
 | 
					you may at your option offer warranty protection in exchange for a fee.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  2. You may modify your copy or copies of the Program or any portion
 | 
				
			||||||
 | 
					of it, thus forming a work based on the Program, and copy and
 | 
				
			||||||
 | 
					distribute such modifications or work under the terms of Section 1
 | 
				
			||||||
 | 
					above, provided that you also meet all of these conditions:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    a) You must cause the modified files to carry prominent notices
 | 
				
			||||||
 | 
					    stating that you changed the files and the date of any change.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    b) You must cause any work that you distribute or publish, that in
 | 
				
			||||||
 | 
					    whole or in part contains or is derived from the Program or any
 | 
				
			||||||
 | 
					    part thereof, to be licensed as a whole at no charge to all third
 | 
				
			||||||
 | 
					    parties under the terms of this License.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    c) If the modified program normally reads commands interactively
 | 
				
			||||||
 | 
					    when run, you must cause it, when started running for such
 | 
				
			||||||
 | 
					    interactive use in the most ordinary way, to print or display an
 | 
				
			||||||
 | 
					    announcement including an appropriate copyright notice and a
 | 
				
			||||||
 | 
					    notice that there is no warranty (or else, saying that you provide
 | 
				
			||||||
 | 
					    a warranty) and that users may redistribute the program under
 | 
				
			||||||
 | 
					    these conditions, and telling the user how to view a copy of this
 | 
				
			||||||
 | 
					    License.  (Exception: if the Program itself is interactive but
 | 
				
			||||||
 | 
					    does not normally print such an announcement, your work based on
 | 
				
			||||||
 | 
					    the Program is not required to print an announcement.)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					These requirements apply to the modified work as a whole.  If
 | 
				
			||||||
 | 
					identifiable sections of that work are not derived from the Program,
 | 
				
			||||||
 | 
					and can be reasonably considered independent and separate works in
 | 
				
			||||||
 | 
					themselves, then this License, and its terms, do not apply to those
 | 
				
			||||||
 | 
					sections when you distribute them as separate works.  But when you
 | 
				
			||||||
 | 
					distribute the same sections as part of a whole which is a work based
 | 
				
			||||||
 | 
					on the Program, the distribution of the whole must be on the terms of
 | 
				
			||||||
 | 
					this License, whose permissions for other licensees extend to the
 | 
				
			||||||
 | 
					entire whole, and thus to each and every part regardless of who wrote it.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Thus, it is not the intent of this section to claim rights or contest
 | 
				
			||||||
 | 
					your rights to work written entirely by you; rather, the intent is to
 | 
				
			||||||
 | 
					exercise the right to control the distribution of derivative or
 | 
				
			||||||
 | 
					collective works based on the Program.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					In addition, mere aggregation of another work not based on the Program
 | 
				
			||||||
 | 
					with the Program (or with a work based on the Program) on a volume of
 | 
				
			||||||
 | 
					a storage or distribution medium does not bring the other work under
 | 
				
			||||||
 | 
					the scope of this License.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  3. You may copy and distribute the Program (or a work based on it,
 | 
				
			||||||
 | 
					under Section 2) in object code or executable form under the terms of
 | 
				
			||||||
 | 
					Sections 1 and 2 above provided that you also do one of the following:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    a) Accompany it with the complete corresponding machine-readable
 | 
				
			||||||
 | 
					    source code, which must be distributed under the terms of Sections
 | 
				
			||||||
 | 
					    1 and 2 above on a medium customarily used for software interchange; or,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    b) Accompany it with a written offer, valid for at least three
 | 
				
			||||||
 | 
					    years, to give any third party, for a charge no more than your
 | 
				
			||||||
 | 
					    cost of physically performing source distribution, a complete
 | 
				
			||||||
 | 
					    machine-readable copy of the corresponding source code, to be
 | 
				
			||||||
 | 
					    distributed under the terms of Sections 1 and 2 above on a medium
 | 
				
			||||||
 | 
					    customarily used for software interchange; or,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    c) Accompany it with the information you received as to the offer
 | 
				
			||||||
 | 
					    to distribute corresponding source code.  (This alternative is
 | 
				
			||||||
 | 
					    allowed only for noncommercial distribution and only if you
 | 
				
			||||||
 | 
					    received the program in object code or executable form with such
 | 
				
			||||||
 | 
					    an offer, in accord with Subsection b above.)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The source code for a work means the preferred form of the work for
 | 
				
			||||||
 | 
					making modifications to it.  For an executable work, complete source
 | 
				
			||||||
 | 
					code means all the source code for all modules it contains, plus any
 | 
				
			||||||
 | 
					associated interface definition files, plus the scripts used to
 | 
				
			||||||
 | 
					control compilation and installation of the executable.  However, as a
 | 
				
			||||||
 | 
					special exception, the source code distributed need not include
 | 
				
			||||||
 | 
					anything that is normally distributed (in either source or binary
 | 
				
			||||||
 | 
					form) with the major components (compiler, kernel, and so on) of the
 | 
				
			||||||
 | 
					operating system on which the executable runs, unless that component
 | 
				
			||||||
 | 
					itself accompanies the executable.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					If distribution of executable or object code is made by offering
 | 
				
			||||||
 | 
					access to copy from a designated place, then offering equivalent
 | 
				
			||||||
 | 
					access to copy the source code from the same place counts as
 | 
				
			||||||
 | 
					distribution of the source code, even though third parties are not
 | 
				
			||||||
 | 
					compelled to copy the source along with the object code.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  4. You may not copy, modify, sublicense, or distribute the Program
 | 
				
			||||||
 | 
					except as expressly provided under this License.  Any attempt
 | 
				
			||||||
 | 
					otherwise to copy, modify, sublicense or distribute the Program is
 | 
				
			||||||
 | 
					void, and will automatically terminate your rights under this License.
 | 
				
			||||||
 | 
					However, parties who have received copies, or rights, from you under
 | 
				
			||||||
 | 
					this License will not have their licenses terminated so long as such
 | 
				
			||||||
 | 
					parties remain in full compliance.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  5. You are not required to accept this License, since you have not
 | 
				
			||||||
 | 
					signed it.  However, nothing else grants you permission to modify or
 | 
				
			||||||
 | 
					distribute the Program or its derivative works.  These actions are
 | 
				
			||||||
 | 
					prohibited by law if you do not accept this License.  Therefore, by
 | 
				
			||||||
 | 
					modifying or distributing the Program (or any work based on the
 | 
				
			||||||
 | 
					Program), you indicate your acceptance of this License to do so, and
 | 
				
			||||||
 | 
					all its terms and conditions for copying, distributing or modifying
 | 
				
			||||||
 | 
					the Program or works based on it.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  6. Each time you redistribute the Program (or any work based on the
 | 
				
			||||||
 | 
					Program), the recipient automatically receives a license from the
 | 
				
			||||||
 | 
					original licensor to copy, distribute or modify the Program subject to
 | 
				
			||||||
 | 
					these terms and conditions.  You may not impose any further
 | 
				
			||||||
 | 
					restrictions on the recipients' exercise of the rights granted herein.
 | 
				
			||||||
 | 
					You are not responsible for enforcing compliance by third parties to
 | 
				
			||||||
 | 
					this License.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  7. If, as a consequence of a court judgment or allegation of patent
 | 
				
			||||||
 | 
					infringement or for any other reason (not limited to patent issues),
 | 
				
			||||||
 | 
					conditions are imposed on you (whether by court order, agreement or
 | 
				
			||||||
 | 
					otherwise) that contradict the conditions of this License, they do not
 | 
				
			||||||
 | 
					excuse you from the conditions of this License.  If you cannot
 | 
				
			||||||
 | 
					distribute so as to satisfy simultaneously your obligations under this
 | 
				
			||||||
 | 
					License and any other pertinent obligations, then as a consequence you
 | 
				
			||||||
 | 
					may not distribute the Program at all.  For example, if a patent
 | 
				
			||||||
 | 
					license would not permit royalty-free redistribution of the Program by
 | 
				
			||||||
 | 
					all those who receive copies directly or indirectly through you, then
 | 
				
			||||||
 | 
					the only way you could satisfy both it and this License would be to
 | 
				
			||||||
 | 
					refrain entirely from distribution of the Program.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					If any portion of this section is held invalid or unenforceable under
 | 
				
			||||||
 | 
					any particular circumstance, the balance of the section is intended to
 | 
				
			||||||
 | 
					apply and the section as a whole is intended to apply in other
 | 
				
			||||||
 | 
					circumstances.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					It is not the purpose of this section to induce you to infringe any
 | 
				
			||||||
 | 
					patents or other property right claims or to contest validity of any
 | 
				
			||||||
 | 
					such claims; this section has the sole purpose of protecting the
 | 
				
			||||||
 | 
					integrity of the free software distribution system, which is
 | 
				
			||||||
 | 
					implemented by public license practices.  Many people have made
 | 
				
			||||||
 | 
					generous contributions to the wide range of software distributed
 | 
				
			||||||
 | 
					through that system in reliance on consistent application of that
 | 
				
			||||||
 | 
					system; it is up to the author/donor to decide if he or she is willing
 | 
				
			||||||
 | 
					to distribute software through any other system and a licensee cannot
 | 
				
			||||||
 | 
					impose that choice.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This section is intended to make thoroughly clear what is believed to
 | 
				
			||||||
 | 
					be a consequence of the rest of this License.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  8. If the distribution and/or use of the Program is restricted in
 | 
				
			||||||
 | 
					certain countries either by patents or by copyrighted interfaces, the
 | 
				
			||||||
 | 
					original copyright holder who places the Program under this License
 | 
				
			||||||
 | 
					may add an explicit geographical distribution limitation excluding
 | 
				
			||||||
 | 
					those countries, so that distribution is permitted only in or among
 | 
				
			||||||
 | 
					countries not thus excluded.  In such case, this License incorporates
 | 
				
			||||||
 | 
					the limitation as if written in the body of this License.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  9. The Free Software Foundation may publish revised and/or new versions
 | 
				
			||||||
 | 
					of the General Public License from time to time.  Such new versions will
 | 
				
			||||||
 | 
					be similar in spirit to the present version, but may differ in detail to
 | 
				
			||||||
 | 
					address new problems or concerns.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Each version is given a distinguishing version number.  If the Program
 | 
				
			||||||
 | 
					specifies a version number of this License which applies to it and "any
 | 
				
			||||||
 | 
					later version", you have the option of following the terms and conditions
 | 
				
			||||||
 | 
					either of that version or of any later version published by the Free
 | 
				
			||||||
 | 
					Software Foundation.  If the Program does not specify a version number of
 | 
				
			||||||
 | 
					this License, you may choose any version ever published by the Free Software
 | 
				
			||||||
 | 
					Foundation.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  10. If you wish to incorporate parts of the Program into other free
 | 
				
			||||||
 | 
					programs whose distribution conditions are different, write to the author
 | 
				
			||||||
 | 
					to ask for permission.  For software which is copyrighted by the Free
 | 
				
			||||||
 | 
					Software Foundation, write to the Free Software Foundation; we sometimes
 | 
				
			||||||
 | 
					make exceptions for this.  Our decision will be guided by the two goals
 | 
				
			||||||
 | 
					of preserving the free status of all derivatives of our free software and
 | 
				
			||||||
 | 
					of promoting the sharing and reuse of software generally.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								    NO WARRANTY
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
 | 
				
			||||||
 | 
					FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
 | 
				
			||||||
 | 
					OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
 | 
				
			||||||
 | 
					PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
 | 
				
			||||||
 | 
					OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 | 
				
			||||||
 | 
					MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
 | 
				
			||||||
 | 
					TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
 | 
				
			||||||
 | 
					PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
 | 
				
			||||||
 | 
					REPAIR OR CORRECTION.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
 | 
				
			||||||
 | 
					WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
 | 
				
			||||||
 | 
					REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
 | 
				
			||||||
 | 
					INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
 | 
				
			||||||
 | 
					OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
 | 
				
			||||||
 | 
					TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
 | 
				
			||||||
 | 
					YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
 | 
				
			||||||
 | 
					PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
 | 
				
			||||||
 | 
					POSSIBILITY OF SUCH DAMAGES.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							     END OF TERMS AND CONDITIONS
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						    How to Apply These Terms to Your New Programs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  If you develop a new program, and you want it to be of the greatest
 | 
				
			||||||
 | 
					possible use to the public, the best way to achieve this is to make it
 | 
				
			||||||
 | 
					free software which everyone can redistribute and change under these terms.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  To do so, attach the following notices to the program.  It is safest
 | 
				
			||||||
 | 
					to attach them to the start of each source file to most effectively
 | 
				
			||||||
 | 
					convey the exclusion of warranty; and each file should have at least
 | 
				
			||||||
 | 
					the "copyright" line and a pointer to where the full notice is found.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <one line to give the program's name and a brief idea of what it does.>
 | 
				
			||||||
 | 
					    Copyright (C) <year>  <name of author>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    This program is free software; you can redistribute it and/or modify
 | 
				
			||||||
 | 
					    it under the terms of the GNU General Public License as published by
 | 
				
			||||||
 | 
					    the Free Software Foundation; either version 2 of the License, or
 | 
				
			||||||
 | 
					    (at your option) any later version.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    This program is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
					    but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
					    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
				
			||||||
 | 
					    GNU General Public License for more details.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    You should have received a copy of the GNU General Public License along
 | 
				
			||||||
 | 
					    with this program; if not, write to the Free Software Foundation, Inc.,
 | 
				
			||||||
 | 
					    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Also add information on how to contact you by electronic and paper mail.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					If the program is interactive, make it output a short notice like this
 | 
				
			||||||
 | 
					when it starts in an interactive mode:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Gnomovision version 69, Copyright (C) year name of author
 | 
				
			||||||
 | 
					    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
 | 
				
			||||||
 | 
					    This is free software, and you are welcome to redistribute it
 | 
				
			||||||
 | 
					    under certain conditions; type `show c' for details.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The hypothetical commands `show w' and `show c' should show the appropriate
 | 
				
			||||||
 | 
					parts of the General Public License.  Of course, the commands you use may
 | 
				
			||||||
 | 
					be called something other than `show w' and `show c'; they could even be
 | 
				
			||||||
 | 
					mouse-clicks or menu items--whatever suits your program.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					You should also get your employer (if you work as a programmer) or your
 | 
				
			||||||
 | 
					school, if any, to sign a "copyright disclaimer" for the program, if
 | 
				
			||||||
 | 
					necessary.  Here is a sample; alter the names:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
 | 
				
			||||||
 | 
					  `Gnomovision' (which makes passes at compilers) written by James Hacker.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  <signature of Ty Coon>, 1 April 1989
 | 
				
			||||||
 | 
					  Ty Coon, President of Vice
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This General Public License does not permit incorporating your program into
 | 
				
			||||||
 | 
					proprietary programs.  If your program is a subroutine library, you may
 | 
				
			||||||
 | 
					consider it more useful to permit linking proprietary applications with the
 | 
				
			||||||
 | 
					library.  If this is what you want to do, use the GNU Lesser General
 | 
				
			||||||
 | 
					Public License instead of this License.
 | 
				
			||||||
							
								
								
									
										128
									
								
								dep/adflib/README
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										128
									
								
								dep/adflib/README
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,128 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The ADFlib is a free, portable and open implementation of the Amiga filesystem.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					initial release in 1999
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					It supports :
 | 
				
			||||||
 | 
					- floppy dumps
 | 
				
			||||||
 | 
					- multiple partitions harddisk dumps
 | 
				
			||||||
 | 
					- UAE hardfiles
 | 
				
			||||||
 | 
					- WinNT devices with the 'native driver' written by Dan Sutherland
 | 
				
			||||||
 | 
					- mount/unmount/create a device (real one or a dump file),
 | 
				
			||||||
 | 
					- mount/unmount/create a volume (partition),
 | 
				
			||||||
 | 
					- create/open/close/delete/rename/undel a file,
 | 
				
			||||||
 | 
					- read/write bytes from/to a file,
 | 
				
			||||||
 | 
					- create/delete/rename/move/undel a directory,
 | 
				
			||||||
 | 
					- get directory contents, change current directory, get parent directory
 | 
				
			||||||
 | 
					- use dir cache to get directory contents.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					It is written in portable C, and support the WinNT platform to access
 | 
				
			||||||
 | 
					real drives.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					See also : 
 | 
				
			||||||
 | 
					https://packages.debian.org/source/sid/unadf
 | 
				
			||||||
 | 
					https://www.cvedetails.com/cve/CVE-2016-1243/
 | 
				
			||||||
 | 
					https://www.cvedetails.com/cve/CVE-2016-1244/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					---
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					unADF is a unzip like for .ADF files :
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					unadf [-lrcsp -v n] dumpname.adf [files-with-path] [-d extractdir]
 | 
				
			||||||
 | 
					    -l : lists root directory contents
 | 
				
			||||||
 | 
					    -r : lists directory tree contents
 | 
				
			||||||
 | 
					    -c : use dircache data (must be used with -l)
 | 
				
			||||||
 | 
					    -s : display entries logical block pointer (must be used with -l)
 | 
				
			||||||
 | 
					    -m : display file comments, if exists (must be used with -l)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    -v n : mount volume #n instead of default #0 volume
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    -p : send extracted files to pipe (unadf -p dump.adf Pics/pic1.gif | xv -)
 | 
				
			||||||
 | 
					    -d dir : extract to 'dir' directory
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Credits:
 | 
				
			||||||
 | 
					--------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					main design and code             Laurent Clevy
 | 
				
			||||||
 | 
					Bug fixes and C++ wrapper        Bjarke Viksoe (adfwrapper.h)
 | 
				
			||||||
 | 
					WinNT native driver              Dan Sutherland and Gary Harris
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					New versions and contact e-mail can be found at : 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					http://lclevy.free.fr/adflib
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					COMPILATION
 | 
				
			||||||
 | 
					-----------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The following commands should automatically detect the system 
 | 
				
			||||||
 | 
					configuration and build the library and examples/unadf, 
 | 
				
			||||||
 | 
					the ADF extractor binary.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						./autogen.sh
 | 
				
			||||||
 | 
						./configure
 | 
				
			||||||
 | 
						make
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					FEATURES NEEDING FURTHER TESTS
 | 
				
			||||||
 | 
					------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* Native driver
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The NATIV_DIR variable is used to choose the (only one) target platform
 | 
				
			||||||
 | 
					of the native driver. The default is :
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					NATIV_DIR = ./Generic
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This one do not give access to any real device. The other one available is
 | 
				
			||||||
 | 
					Win32, to access real devices under WinNT.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* Win32DLL
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The 'prefix.h' is used to create the Win32 DLL version of the library.
 | 
				
			||||||
 | 
					If the WIN32DLL variable is defined in the library code, public functions
 | 
				
			||||||
 | 
					are preceded by the '__declspec(dllexport)' directive. If this same
 | 
				
			||||||
 | 
					variable is defined, the '__declspec(dllimport)' is put before the functions
 | 
				
			||||||
 | 
					prototypes in the 'adflib.h' library include file.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					FILES
 | 
				
			||||||
 | 
					-----
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					AUTHORS   Contributors
 | 
				
			||||||
 | 
					README			The file you are reading
 | 
				
			||||||
 | 
					TODO			Future improvements and bugfixes
 | 
				
			||||||
 | 
					CHANGES			Detailed changes
 | 
				
			||||||
 | 
					src/			main library files
 | 
				
			||||||
 | 
					src/win32/		WinNT native driver
 | 
				
			||||||
 | 
					src/generic/		native files templates
 | 
				
			||||||
 | 
					boot/			Bootblocks that might by used to put on floppy disks
 | 
				
			||||||
 | 
					doc/			The library developpers documentation 
 | 
				
			||||||
 | 
					doc/FAQ/		The Amiga Filesystem explained
 | 
				
			||||||
 | 
					examples/		unadf.c
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Possible bugs
 | 
				
			||||||
 | 
					-------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- in dircache updates
 | 
				
			||||||
 | 
					- when a volume is becoming full
 | 
				
			||||||
 | 
					- lost memory releases
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Please report any bugs or mistakes in the documentation !
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Have fun anyway !
 | 
				
			||||||
							
								
								
									
										2
									
								
								dep/adflib/UPSTREAM.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								dep/adflib/UPSTREAM.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,2 @@
 | 
				
			|||||||
 | 
					This is head of git downloaded from https://github.com/lclevy/ADFlib on
 | 
				
			||||||
 | 
					2022-08-28.
 | 
				
			||||||
							
								
								
									
										37
									
								
								dep/adflib/adf_nativ.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								dep/adflib/adf_nativ.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,37 @@
 | 
				
			|||||||
 | 
					#ifndef ADF_NATIV_H
 | 
				
			||||||
 | 
					#define ADF_NATIV_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef __cplusplus
 | 
				
			||||||
 | 
					extern "C" {
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "adf_str.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define NATIVE_FILE 8001
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct nativeDevice
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						FILE* fd;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct nativeFunctions
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    /* called by adfMount() */
 | 
				
			||||||
 | 
					    RETCODE (*adfInitDevice)(struct Device*, char*, BOOL);
 | 
				
			||||||
 | 
					    /* called by adfReadBlock() */
 | 
				
			||||||
 | 
					    RETCODE (*adfNativeReadSector)(struct Device*, int32_t, int, uint8_t*);
 | 
				
			||||||
 | 
					    /* called by adfWriteBlock() */
 | 
				
			||||||
 | 
					    RETCODE (*adfNativeWriteSector)(struct Device*, int32_t, int, uint8_t*);
 | 
				
			||||||
 | 
					    /* called by adfMount() */
 | 
				
			||||||
 | 
					    BOOL (*adfIsDevNative)(char*);
 | 
				
			||||||
 | 
					    /* called by adfUnMount() */
 | 
				
			||||||
 | 
					    RETCODE (*adfReleaseDevice)(struct Device*);
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern void adfInitNativeFct();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef __cplusplus
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
							
								
								
									
										22
									
								
								dep/adflib/build.mk
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								dep/adflib/build.mk
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,22 @@
 | 
				
			|||||||
 | 
					ADFLIB_SRCS = \
 | 
				
			||||||
 | 
						dep/adflib/src/adf_bitm.c \
 | 
				
			||||||
 | 
						dep/adflib/src/adf_cache.c \
 | 
				
			||||||
 | 
						dep/adflib/src/adf_dir.c \
 | 
				
			||||||
 | 
						dep/adflib/src/adf_disk.c \
 | 
				
			||||||
 | 
						dep/adflib/src/adf_dump.c \
 | 
				
			||||||
 | 
						dep/adflib/src/adf_env.c \
 | 
				
			||||||
 | 
						dep/adflib/src/adf_file.c \
 | 
				
			||||||
 | 
						dep/adflib/src/adf_hd.c \
 | 
				
			||||||
 | 
						dep/adflib/src/adf_link.c \
 | 
				
			||||||
 | 
						dep/adflib/src/adf_raw.c \
 | 
				
			||||||
 | 
						dep/adflib/src/adf_salv.c \
 | 
				
			||||||
 | 
						dep/adflib/src/adf_util.c \
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ADFLIB_OBJS = $(patsubst %.c, $(OBJDIR)/%.o, $(ADFLIB_SRCS))
 | 
				
			||||||
 | 
					$(ADFLIB_OBJS): CFLAGS += -Idep/adflib/src -Idep/adflib
 | 
				
			||||||
 | 
					ADFLIB_LIB = $(OBJDIR)/libadflib.a
 | 
				
			||||||
 | 
					$(ADFLIB_LIB): $(ADFLIB_OBJS)
 | 
				
			||||||
 | 
					ADFLIB_CFLAGS = -Idep/adflib/src
 | 
				
			||||||
 | 
					ADFLIB_LDFLAGS =
 | 
				
			||||||
 | 
					OBJS += $(ADFLIB_OBJS)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										2
									
								
								dep/adflib/config.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								dep/adflib/config.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,2 @@
 | 
				
			|||||||
 | 
					/* empty config.h to keep the source happy */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										44
									
								
								dep/adflib/src/Makefile.am
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								dep/adflib/src/Makefile.am
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,44 @@
 | 
				
			|||||||
 | 
					NATIVE_DIR = generic
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					lib_LTLIBRARIES = libadf.la
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					libadf_la_SOURCES = adf_hd.c \
 | 
				
			||||||
 | 
					                    adf_disk.c \
 | 
				
			||||||
 | 
					                    adf_raw.c \
 | 
				
			||||||
 | 
					                    adf_bitm.c \
 | 
				
			||||||
 | 
					                    adf_dump.c \
 | 
				
			||||||
 | 
					                    adf_util.c \
 | 
				
			||||||
 | 
					                    adf_env.c \
 | 
				
			||||||
 | 
					                    $(NATIVE_DIR)/adf_nativ.c \
 | 
				
			||||||
 | 
					                    adf_dir.c \
 | 
				
			||||||
 | 
					                    adf_file.c \
 | 
				
			||||||
 | 
					                    adf_cache.c \
 | 
				
			||||||
 | 
					                    adf_link.c \
 | 
				
			||||||
 | 
					                    adf_salv.c
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					include_HEADERS = adf_defs.h \
 | 
				
			||||||
 | 
					                  adf_blk.h \
 | 
				
			||||||
 | 
					                  adf_err.h \
 | 
				
			||||||
 | 
					                  adf_str.h \
 | 
				
			||||||
 | 
					                  adflib.h \
 | 
				
			||||||
 | 
					                  adf_bitm.h \
 | 
				
			||||||
 | 
					                  adf_cache.h \
 | 
				
			||||||
 | 
					                  adf_dir.h \
 | 
				
			||||||
 | 
					                  adf_disk.h \
 | 
				
			||||||
 | 
					                  adf_dump.h \
 | 
				
			||||||
 | 
					                  adf_env.h \
 | 
				
			||||||
 | 
					                  adf_file.h \
 | 
				
			||||||
 | 
					                  adf_hd.h \
 | 
				
			||||||
 | 
					                  adf_link.h \
 | 
				
			||||||
 | 
					                  adf_raw.h \
 | 
				
			||||||
 | 
					                  adf_salv.h \
 | 
				
			||||||
 | 
					                  adf_util.h \
 | 
				
			||||||
 | 
					                  defendian.h \
 | 
				
			||||||
 | 
					                  hd_blk.h \
 | 
				
			||||||
 | 
					                  prefix.h \
 | 
				
			||||||
 | 
					                  $(NATIVE_DIR)/adf_nativ.h
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					libadf_la_LDFLAGS = -version-info 0:12:0
 | 
				
			||||||
 | 
					AM_CPPFLAGS = -D_XOPEN_SOURCE -D_SVID_SOURCE -D_BSD_SOURCE -D_DEFAULT_SOURCE -D_GNU_SOURCE -I$(srcdir) -I$(srcdir)/$(NATIVE_DIR)
 | 
				
			||||||
 | 
					AM_CFLAGS = -std=c99 -pedantic -Wall
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										561
									
								
								dep/adflib/src/adf_bitm.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										561
									
								
								dep/adflib/src/adf_bitm.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,561 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *  ADF Library. (C) 1997-2002 Laurent Clevy
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  adf_bitm.c
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  $Id$
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  bitmap code
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  This file is part of ADFLib.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  ADFLib is free software; you can redistribute it and/or modify
 | 
				
			||||||
 | 
					 *  it under the terms of the GNU General Public License as published by
 | 
				
			||||||
 | 
					 *  the Free Software Foundation; either version 2 of the License, or
 | 
				
			||||||
 | 
					 *  (at your option) any later version.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  ADFLib is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
					 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
					 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
				
			||||||
 | 
					 *  GNU General Public License for more details.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  You should have received a copy of the GNU General Public License
 | 
				
			||||||
 | 
					 *  along with Foobar; if not, write to the Free Software
 | 
				
			||||||
 | 
					 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include"adf_raw.h"
 | 
				
			||||||
 | 
					#include"adf_bitm.h"
 | 
				
			||||||
 | 
					#include"adf_err.h"
 | 
				
			||||||
 | 
					#include"adf_disk.h"
 | 
				
			||||||
 | 
					#include"adf_util.h"
 | 
				
			||||||
 | 
					#include"defendian.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern uint32_t bitMask[32];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern struct Env adfEnv;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * adfUpdateBitmap
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					RETCODE adfUpdateBitmap(struct Volume *vol)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int i;
 | 
				
			||||||
 | 
					    struct bRootBlock root;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*printf("adfUpdateBitmap\n");*/
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					    if (adfReadRootBlock(vol, vol->rootBlock,&root)!=RC_OK)
 | 
				
			||||||
 | 
							return RC_ERROR;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    root.bmFlag = BM_INVALID;
 | 
				
			||||||
 | 
					    if (adfWriteRootBlock(vol,vol->rootBlock,&root)!=RC_OK)
 | 
				
			||||||
 | 
							return RC_ERROR;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for(i=0; i<vol->bitmapSize; i++)
 | 
				
			||||||
 | 
					    if (vol->bitmapBlocksChg[i]) {
 | 
				
			||||||
 | 
					        if (adfWriteBitmapBlock(vol, vol->bitmapBlocks[i], vol->bitmapTable[i])!=RC_OK)
 | 
				
			||||||
 | 
								return RC_ERROR;
 | 
				
			||||||
 | 
					  	    vol->bitmapBlocksChg[i] = FALSE;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    root.bmFlag = BM_VALID;
 | 
				
			||||||
 | 
					    adfTime2AmigaTime(adfGiveCurrentTime(),&(root.days),&(root.mins),&(root.ticks));
 | 
				
			||||||
 | 
					    if (adfWriteRootBlock(vol,vol->rootBlock,&root)!=RC_OK)
 | 
				
			||||||
 | 
							return RC_ERROR;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return RC_OK;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * adfCountFreeBlocks
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int32_t adfCountFreeBlocks(struct Volume* vol)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int32_t freeBlocks;
 | 
				
			||||||
 | 
					    int j;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						freeBlocks = 0L;
 | 
				
			||||||
 | 
					    for(j=vol->firstBlock+2; j<=(vol->lastBlock - vol->firstBlock); j++)
 | 
				
			||||||
 | 
					        if ( adfIsBlockFree(vol,j) )
 | 
				
			||||||
 | 
					            freeBlocks++;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return freeBlocks;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * adfReadBitmap
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					RETCODE adfReadBitmap(struct Volume* vol, int32_t nBlock, struct bRootBlock* root)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int32_t mapSize, nSect;
 | 
				
			||||||
 | 
						int32_t j, i;
 | 
				
			||||||
 | 
						struct bBitmapExtBlock bmExt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    mapSize = nBlock / (127*32);
 | 
				
			||||||
 | 
					    if ( (nBlock%(127*32))!=0 )
 | 
				
			||||||
 | 
					        mapSize++;
 | 
				
			||||||
 | 
					    vol->bitmapSize = mapSize;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    vol->bitmapTable = (struct bBitmapBlock**) malloc(sizeof(struct bBitmapBlock*)*mapSize);
 | 
				
			||||||
 | 
					    if (!vol->bitmapTable) { 
 | 
				
			||||||
 | 
							(*adfEnv.eFct)("adfReadBitmap : malloc, vol->bitmapTable");
 | 
				
			||||||
 | 
					        return RC_MALLOC;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
						vol->bitmapBlocks = (SECTNUM*) malloc(sizeof(SECTNUM)*mapSize);
 | 
				
			||||||
 | 
					    if (!vol->bitmapBlocks) {
 | 
				
			||||||
 | 
					        free(vol->bitmapTable);
 | 
				
			||||||
 | 
							(*adfEnv.eFct)("adfReadBitmap : malloc, vol->bitmapBlocks");
 | 
				
			||||||
 | 
					        return RC_MALLOC;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
						vol->bitmapBlocksChg = (BOOL*) malloc(sizeof(BOOL)*mapSize);
 | 
				
			||||||
 | 
					    if (!vol->bitmapBlocksChg) { 
 | 
				
			||||||
 | 
					        free(vol->bitmapTable); free(vol->bitmapBlocks);
 | 
				
			||||||
 | 
							(*adfEnv.eFct)("adfReadBitmap : malloc, vol->bitmapBlocks");
 | 
				
			||||||
 | 
					        return RC_MALLOC;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    for(i=0; i<mapSize; i++) {
 | 
				
			||||||
 | 
					        vol->bitmapBlocksChg[i] = FALSE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							vol->bitmapTable[i] = (struct bBitmapBlock*)malloc(sizeof(struct bBitmapBlock));
 | 
				
			||||||
 | 
							if (!vol->bitmapTable[i]) {
 | 
				
			||||||
 | 
					            free(vol->bitmapBlocksChg); free(vol->bitmapBlocks);
 | 
				
			||||||
 | 
					            for(j=0; j<i; j++) 
 | 
				
			||||||
 | 
					                free(vol->bitmapTable[j]);
 | 
				
			||||||
 | 
					            free(vol->bitmapTable);
 | 
				
			||||||
 | 
						        (*adfEnv.eFct)("adfReadBitmap : malloc, vol->bitmapBlocks");
 | 
				
			||||||
 | 
					            return RC_MALLOC;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						j=0; i=0;
 | 
				
			||||||
 | 
					    /* bitmap pointers in rootblock : 0 <= i <BM_SIZE */
 | 
				
			||||||
 | 
						while(i<BM_SIZE && root->bmPages[i]!=0) {
 | 
				
			||||||
 | 
							vol->bitmapBlocks[j] = nSect = root->bmPages[i];
 | 
				
			||||||
 | 
					        if ( !isSectNumValid(vol,nSect) ) {
 | 
				
			||||||
 | 
								(*adfEnv.wFct)("adfReadBitmap : sector out of range");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (adfReadBitmapBlock(vol, nSect, vol->bitmapTable[j])!=RC_OK) {
 | 
				
			||||||
 | 
					            adfFreeBitmap(vol);
 | 
				
			||||||
 | 
					            return RC_ERROR;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							j++; i++;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						nSect = root->bmExt;
 | 
				
			||||||
 | 
						while(nSect!=0) {
 | 
				
			||||||
 | 
					        /* bitmap pointers in bitmapExtBlock, j <= mapSize */
 | 
				
			||||||
 | 
					        if (adfReadBitmapExtBlock(vol, nSect, &bmExt)!=RC_OK) {
 | 
				
			||||||
 | 
					            adfFreeBitmap(vol);
 | 
				
			||||||
 | 
					            return RC_ERROR;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
							i=0;
 | 
				
			||||||
 | 
							while(i<127 && j<mapSize) {
 | 
				
			||||||
 | 
					            nSect = bmExt.bmPages[i];
 | 
				
			||||||
 | 
					            if ( !isSectNumValid(vol,nSect) )
 | 
				
			||||||
 | 
					                (*adfEnv.wFct)("adfReadBitmap : sector out of range");
 | 
				
			||||||
 | 
								vol->bitmapBlocks[j] = nSect;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (adfReadBitmapBlock(vol, nSect, vol->bitmapTable[j])!=RC_OK) {
 | 
				
			||||||
 | 
					                adfFreeBitmap(vol);
 | 
				
			||||||
 | 
					                return RC_ERROR;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
								i++; j++;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							nSect = bmExt.nextBlock;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return RC_OK;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * adfIsBlockFree
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					BOOL adfIsBlockFree(struct Volume* vol, SECTNUM nSect)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int sectOfMap = nSect-2;
 | 
				
			||||||
 | 
					    int block = sectOfMap/(127*32);
 | 
				
			||||||
 | 
					    int indexInMap = (sectOfMap/32)%127;
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
					/*printf("sect=%d block=%d ind=%d,  ",sectOfMap,block,indexInMap);
 | 
				
			||||||
 | 
					printf("bit=%d,  ",sectOfMap%32);
 | 
				
			||||||
 | 
					printf("bitm=%x,  ",bitMask[ sectOfMap%32]);
 | 
				
			||||||
 | 
					printf("res=%x,  ",vol->bitmapTable[ block ]->map[ indexInMap ]
 | 
				
			||||||
 | 
					        & bitMask[ sectOfMap%32 ]);
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					    return ( (vol->bitmapTable[ block ]->map[ indexInMap ]
 | 
				
			||||||
 | 
					        & bitMask[ sectOfMap%32 ])!=0 );
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * adfSetBlockFree OK
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void adfSetBlockFree(struct Volume* vol, SECTNUM nSect)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    uint32_t oldValue;
 | 
				
			||||||
 | 
					    int sectOfMap = nSect-2;
 | 
				
			||||||
 | 
					    int block = sectOfMap/(127*32);
 | 
				
			||||||
 | 
					    int indexInMap = (sectOfMap/32)%127;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*printf("sect=%d block=%d ind=%d,  ",sectOfMap,block,indexInMap);
 | 
				
			||||||
 | 
					printf("bit=%d,  ",sectOfMap%32);
 | 
				
			||||||
 | 
					*printf("bitm=%x,  ",bitMask[ sectOfMap%32]);*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    oldValue = vol->bitmapTable[ block ]->map[ indexInMap ];
 | 
				
			||||||
 | 
					/*printf("old=%x,  ",oldValue);*/
 | 
				
			||||||
 | 
					    vol->bitmapTable[ block ]->map[ indexInMap ]
 | 
				
			||||||
 | 
						    = oldValue | bitMask[ sectOfMap%32 ];
 | 
				
			||||||
 | 
					/*printf("new=%x,  ",vol->bitmapTable[ block ]->map[ indexInMap ]);*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    vol->bitmapBlocksChg[ block ] = TRUE;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * adfSetBlockUsed
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void adfSetBlockUsed(struct Volume* vol, SECTNUM nSect)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    uint32_t oldValue;
 | 
				
			||||||
 | 
					    int sectOfMap = nSect-2;
 | 
				
			||||||
 | 
					    int block = sectOfMap/(127*32);
 | 
				
			||||||
 | 
					    int indexInMap = (sectOfMap/32)%127;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    oldValue = vol->bitmapTable[ block ]->map[ indexInMap ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    vol->bitmapTable[ block ]->map[ indexInMap ]
 | 
				
			||||||
 | 
						    = oldValue & (~bitMask[ sectOfMap%32 ]);
 | 
				
			||||||
 | 
					    vol->bitmapBlocksChg[ block ] = TRUE;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * adfGet1FreeBlock
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					SECTNUM adfGet1FreeBlock(struct Volume *vol) {
 | 
				
			||||||
 | 
					    SECTNUM block[1];
 | 
				
			||||||
 | 
					    if (!adfGetFreeBlocks(vol,1,block))
 | 
				
			||||||
 | 
					        return(-1);
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					        return(block[0]);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * adfGetFreeBlocks
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					BOOL adfGetFreeBlocks(struct Volume* vol, int nbSect, SECTNUM* sectList)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int i, j;
 | 
				
			||||||
 | 
					    BOOL diskFull;
 | 
				
			||||||
 | 
					    int32_t block = vol->rootBlock;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    i = 0;
 | 
				
			||||||
 | 
					    diskFull = FALSE;
 | 
				
			||||||
 | 
					/*printf("lastblock=%ld\n",vol->lastBlock);*/
 | 
				
			||||||
 | 
						while( i<nbSect && !diskFull ) {
 | 
				
			||||||
 | 
					        if ( adfIsBlockFree(vol, block) ) {
 | 
				
			||||||
 | 
					            sectList[i] = block;
 | 
				
			||||||
 | 
								i++;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					/*        if ( block==vol->lastBlock )
 | 
				
			||||||
 | 
					            block = vol->firstBlock+2;*/
 | 
				
			||||||
 | 
					        if ( (block+vol->firstBlock)==vol->lastBlock )
 | 
				
			||||||
 | 
					            block = 2;
 | 
				
			||||||
 | 
					        else if (block==vol->rootBlock-1)
 | 
				
			||||||
 | 
					            diskFull = TRUE;
 | 
				
			||||||
 | 
					        else
 | 
				
			||||||
 | 
					            block++;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!diskFull)
 | 
				
			||||||
 | 
					        for(j=0; j<nbSect; j++)
 | 
				
			||||||
 | 
					            adfSetBlockUsed( vol, sectList[j] );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return (i==nbSect);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * adfCreateBitmap
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * create bitmap structure in vol
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					RETCODE adfCreateBitmap(struct Volume *vol)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int32_t nBlock, mapSize ;
 | 
				
			||||||
 | 
					    int i, j;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    nBlock = vol->lastBlock - vol->firstBlock +1 - 2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    mapSize = nBlock / (127*32);
 | 
				
			||||||
 | 
					    if ( (nBlock%(127*32))!=0 )
 | 
				
			||||||
 | 
					        mapSize++;
 | 
				
			||||||
 | 
					    vol->bitmapSize = mapSize;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    vol->bitmapTable = (struct bBitmapBlock**)malloc( sizeof(struct bBitmapBlock*)*mapSize );
 | 
				
			||||||
 | 
					    if (!vol->bitmapTable) {
 | 
				
			||||||
 | 
					        (*adfEnv.eFct)("adfCreateBitmap : malloc, vol->bitmapTable");
 | 
				
			||||||
 | 
					        return RC_MALLOC;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						vol->bitmapBlocksChg = (BOOL*) malloc(sizeof(BOOL)*mapSize);
 | 
				
			||||||
 | 
					    if (!vol->bitmapBlocksChg) {
 | 
				
			||||||
 | 
					        free(vol->bitmapTable);
 | 
				
			||||||
 | 
					        (*adfEnv.eFct)("adfCreateBitmap : malloc, vol->bitmapBlocksChg");
 | 
				
			||||||
 | 
					        return RC_MALLOC;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						vol->bitmapBlocks = (SECTNUM*) malloc(sizeof(SECTNUM)*mapSize);
 | 
				
			||||||
 | 
					    if (!vol->bitmapBlocks) {
 | 
				
			||||||
 | 
					        free(vol->bitmapTable); free(vol->bitmapBlocksChg);
 | 
				
			||||||
 | 
					        (*adfEnv.eFct)("adfCreateBitmap : malloc, vol->bitmapBlocks");
 | 
				
			||||||
 | 
					        return RC_MALLOC;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for(i=0; i<mapSize; i++) {
 | 
				
			||||||
 | 
					        vol->bitmapTable[i] = (struct bBitmapBlock*)malloc(sizeof(struct bBitmapBlock));
 | 
				
			||||||
 | 
					        if (!vol->bitmapTable[i]) {
 | 
				
			||||||
 | 
					            free(vol->bitmapTable); free(vol->bitmapBlocksChg);
 | 
				
			||||||
 | 
					            for(j=0; j<i; j++) 
 | 
				
			||||||
 | 
					                free(vol->bitmapTable[j]);
 | 
				
			||||||
 | 
					            free(vol->bitmapTable);
 | 
				
			||||||
 | 
								(*adfEnv.eFct)("adfCreateBitmap : malloc");
 | 
				
			||||||
 | 
					            return RC_MALLOC;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for(i=vol->firstBlock+2; i<=(vol->lastBlock - vol->firstBlock); i++)
 | 
				
			||||||
 | 
					        adfSetBlockFree(vol, i);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return RC_OK;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * adfWriteNewBitmap
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * write ext blocks and bitmap
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * uses vol->bitmapSize, 
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					RETCODE adfWriteNewBitmap(struct Volume *vol)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    struct bBitmapExtBlock bitme;
 | 
				
			||||||
 | 
					    SECTNUM *bitExtBlock;
 | 
				
			||||||
 | 
					    int n, i, k;
 | 
				
			||||||
 | 
					    int nExtBlock;
 | 
				
			||||||
 | 
					    int nBlock;
 | 
				
			||||||
 | 
					    SECTNUM *sectList;
 | 
				
			||||||
 | 
					    struct bRootBlock root;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sectList=(SECTNUM*)malloc(sizeof(SECTNUM)*vol->bitmapSize);
 | 
				
			||||||
 | 
					    if (!sectList) {
 | 
				
			||||||
 | 
							(*adfEnv.eFct)("adfCreateBitmap : sectList");
 | 
				
			||||||
 | 
					        return RC_MALLOC;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!adfGetFreeBlocks(vol, vol->bitmapSize, sectList)) {
 | 
				
			||||||
 | 
					        free(sectList);
 | 
				
			||||||
 | 
							return RC_ERROR;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
					    if (adfReadRootBlock(vol, vol->rootBlock, &root)!=RC_OK) {
 | 
				
			||||||
 | 
					        free(sectList);
 | 
				
			||||||
 | 
							return RC_ERROR;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    nBlock = 0;
 | 
				
			||||||
 | 
					    n = min( vol->bitmapSize, BM_SIZE );
 | 
				
			||||||
 | 
					    for(i=0; i<n; i++) {
 | 
				
			||||||
 | 
					        root.bmPages[i] = vol->bitmapBlocks[i] = sectList[i];
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    nBlock = n;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* for devices with more than 25*127 blocks == hards disks */
 | 
				
			||||||
 | 
					    if (vol->bitmapSize>BM_SIZE) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        nExtBlock = (vol->bitmapSize-BM_SIZE)/127;
 | 
				
			||||||
 | 
					        if ((vol->bitmapSize-BM_SIZE)%127)
 | 
				
			||||||
 | 
					            nExtBlock++;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        bitExtBlock=(SECTNUM*)malloc(sizeof(SECTNUM)*nExtBlock);
 | 
				
			||||||
 | 
					        if (!bitExtBlock) {
 | 
				
			||||||
 | 
					            free(sectList);
 | 
				
			||||||
 | 
								adfEnv.eFct("adfWriteNewBitmap : malloc failed");
 | 
				
			||||||
 | 
					            return RC_MALLOC;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (!adfGetFreeBlocks(vol, nExtBlock, bitExtBlock)) {  
 | 
				
			||||||
 | 
					           free(sectList); free(bitExtBlock);
 | 
				
			||||||
 | 
					           return RC_MALLOC;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        k = 0;
 | 
				
			||||||
 | 
					        root.bmExt = bitExtBlock[ k ];
 | 
				
			||||||
 | 
					        while( nBlock<vol->bitmapSize ) {
 | 
				
			||||||
 | 
					            i=0;
 | 
				
			||||||
 | 
					            while( i<127 && nBlock<vol->bitmapSize ) {
 | 
				
			||||||
 | 
					                bitme.bmPages[i] = vol->bitmapBlocks[nBlock] = sectList[i];
 | 
				
			||||||
 | 
					                i++;
 | 
				
			||||||
 | 
					                nBlock++;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if ( k+1<nExtBlock )
 | 
				
			||||||
 | 
					                bitme.nextBlock = bitExtBlock[ k+1 ];
 | 
				
			||||||
 | 
					            else
 | 
				
			||||||
 | 
					                bitme.nextBlock = 0;
 | 
				
			||||||
 | 
					            if (adfWriteBitmapExtBlock(vol, bitExtBlock[ k ], &bitme)!=RC_OK) {
 | 
				
			||||||
 | 
					                free(sectList); free(bitExtBlock);
 | 
				
			||||||
 | 
									return RC_ERROR;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            k++;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        free( bitExtBlock );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    free( sectList);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (adfWriteRootBlock(vol,vol->rootBlock,&root)!=RC_OK)
 | 
				
			||||||
 | 
					        return RC_ERROR;
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    return RC_OK;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * adfReadBitmapBlock
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * ENDIAN DEPENDENT
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					RETCODE
 | 
				
			||||||
 | 
					adfReadBitmapBlock(struct Volume* vol, SECTNUM nSect, struct bBitmapBlock* bitm)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						uint8_t buf[LOGICAL_BLOCK_SIZE];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*printf("bitmap %ld\n",nSect);*/
 | 
				
			||||||
 | 
						if (adfReadBlock(vol, nSect, buf)!=RC_OK)
 | 
				
			||||||
 | 
							return RC_ERROR;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						memcpy(bitm, buf, LOGICAL_BLOCK_SIZE);
 | 
				
			||||||
 | 
					#ifdef LITT_ENDIAN
 | 
				
			||||||
 | 
					    /* big to little = 68000 to x86 */
 | 
				
			||||||
 | 
					    swapEndian((uint8_t*)bitm, SWBL_BITMAP);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (bitm->checkSum!=adfNormalSum(buf,0,LOGICAL_BLOCK_SIZE))
 | 
				
			||||||
 | 
							(*adfEnv.wFct)("adfReadBitmapBlock : invalid checksum");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return RC_OK;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * adfWriteBitmapBlock
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * OK
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					RETCODE
 | 
				
			||||||
 | 
					adfWriteBitmapBlock(struct Volume* vol, SECTNUM nSect, struct bBitmapBlock* bitm)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    uint8_t buf[LOGICAL_BLOCK_SIZE];
 | 
				
			||||||
 | 
						uint32_t newSum;
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						memcpy(buf,bitm,LOGICAL_BLOCK_SIZE);
 | 
				
			||||||
 | 
					#ifdef LITT_ENDIAN
 | 
				
			||||||
 | 
					    /* little to big */
 | 
				
			||||||
 | 
					    swapEndian(buf, SWBL_BITMAP);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						newSum = adfNormalSum(buf, 0, LOGICAL_BLOCK_SIZE);
 | 
				
			||||||
 | 
					    swLong(buf,newSum);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*	dumpBlock((uint8_t*)buf);*/
 | 
				
			||||||
 | 
						if (adfWriteBlock(vol, nSect, (uint8_t*)buf)!=RC_OK)
 | 
				
			||||||
 | 
							return RC_ERROR;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return RC_OK;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * adfReadBitmapExtBlock
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * ENDIAN DEPENDENT
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					RETCODE
 | 
				
			||||||
 | 
					adfReadBitmapExtBlock(struct Volume* vol, SECTNUM nSect, struct bBitmapExtBlock* bitme)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						uint8_t buf[LOGICAL_BLOCK_SIZE];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (adfReadBlock(vol, nSect, buf)!=RC_OK)
 | 
				
			||||||
 | 
							return RC_ERROR;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						memcpy(bitme, buf, LOGICAL_BLOCK_SIZE);
 | 
				
			||||||
 | 
					#ifdef LITT_ENDIAN
 | 
				
			||||||
 | 
					    swapEndian((uint8_t*)bitme, SWBL_BITMAP);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return RC_OK;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * adfWriteBitmapExtBlock
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					RETCODE
 | 
				
			||||||
 | 
					adfWriteBitmapExtBlock(struct Volume* vol, SECTNUM nSect, struct bBitmapExtBlock* bitme)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						uint8_t buf[LOGICAL_BLOCK_SIZE];
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						memcpy(buf,bitme, LOGICAL_BLOCK_SIZE);
 | 
				
			||||||
 | 
					#ifdef LITT_ENDIAN
 | 
				
			||||||
 | 
					    /* little to big */
 | 
				
			||||||
 | 
					    swapEndian(buf, SWBL_BITMAPE);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*	dumpBlock((uint8_t*)buf);*/
 | 
				
			||||||
 | 
						if (adfWriteBlock(vol, nSect, (uint8_t*)buf)!=RC_OK)
 | 
				
			||||||
 | 
							return RC_ERROR;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return RC_OK;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * adfFreeBitmap
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void adfFreeBitmap(struct Volume* vol)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for(i=0; i<vol->bitmapSize; i++)
 | 
				
			||||||
 | 
					        free(vol->bitmapTable[i]);
 | 
				
			||||||
 | 
					    vol->bitmapSize = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    free(vol->bitmapTable);
 | 
				
			||||||
 | 
						vol->bitmapTable = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    free(vol->bitmapBlocks);
 | 
				
			||||||
 | 
						vol->bitmapBlocks = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    free(vol->bitmapBlocksChg);
 | 
				
			||||||
 | 
						vol->bitmapBlocksChg = 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*#######################################################################################*/
 | 
				
			||||||
							
								
								
									
										52
									
								
								dep/adflib/src/adf_bitm.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								dep/adflib/src/adf_bitm.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,52 @@
 | 
				
			|||||||
 | 
					#ifndef ADF_BITM_H
 | 
				
			||||||
 | 
					#define ADF_BITM_H
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *  ADF Library. (C) 1997-2002 Laurent Clevy
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  adf_bitm.h
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  $Id$
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  bitmap code
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  This file is part of ADFLib.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  ADFLib is free software; you can redistribute it and/or modify
 | 
				
			||||||
 | 
					 *  it under the terms of the GNU General Public License as published by
 | 
				
			||||||
 | 
					 *  the Free Software Foundation; either version 2 of the License, or
 | 
				
			||||||
 | 
					 *  (at your option) any later version.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  ADFLib is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
					 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
					 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
				
			||||||
 | 
					 *  GNU General Public License for more details.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  You should have received a copy of the GNU General Public License
 | 
				
			||||||
 | 
					 *  along with Foobar; if not, write to the Free Software
 | 
				
			||||||
 | 
					 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include"adf_str.h"
 | 
				
			||||||
 | 
					#include"prefix.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					RETCODE adfReadBitmapBlock(struct Volume*, SECTNUM nSect, struct bBitmapBlock*);
 | 
				
			||||||
 | 
					RETCODE adfWriteBitmapBlock(struct Volume*, SECTNUM nSect, struct bBitmapBlock*);
 | 
				
			||||||
 | 
					RETCODE adfReadBitmapExtBlock(struct Volume*, SECTNUM nSect, struct bBitmapExtBlock*);
 | 
				
			||||||
 | 
					RETCODE adfWriteBitmapExtBlock(struct Volume*, SECTNUM, struct bBitmapExtBlock* );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					SECTNUM adfGet1FreeBlock(struct Volume *vol);
 | 
				
			||||||
 | 
					RETCODE adfUpdateBitmap(struct Volume *vol);
 | 
				
			||||||
 | 
					PREFIX int32_t adfCountFreeBlocks(struct Volume* vol);
 | 
				
			||||||
 | 
					RETCODE adfReadBitmap(struct Volume* , SECTNUM nBlock, struct bRootBlock* root);
 | 
				
			||||||
 | 
					BOOL adfIsBlockFree(struct Volume* vol, SECTNUM nSect);
 | 
				
			||||||
 | 
					void adfSetBlockFree(struct Volume* vol, SECTNUM nSect);
 | 
				
			||||||
 | 
					void adfSetBlockUsed(struct Volume* vol, SECTNUM nSect);
 | 
				
			||||||
 | 
					BOOL adfGetFreeBlocks(struct Volume* vol, int nbSect, SECTNUM* sectList);
 | 
				
			||||||
 | 
					RETCODE adfCreateBitmap(struct Volume *vol);
 | 
				
			||||||
 | 
					RETCODE adfWriteNewBitmap(struct Volume *vol);
 | 
				
			||||||
 | 
					void adfFreeBitmap(struct Volume *vol);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* ADF_BITM_H */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*#######################################################################################*/
 | 
				
			||||||
							
								
								
									
										288
									
								
								dep/adflib/src/adf_blk.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										288
									
								
								dep/adflib/src/adf_blk.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,288 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *  ADF Library. (C) 1997-2002 Laurent Clevy
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  adf_blk.h
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  $Id$
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  general blocks structures
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  This file is part of ADFLib.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  ADFLib is free software; you can redistribute it and/or modify
 | 
				
			||||||
 | 
					 *  it under the terms of the GNU General Public License as published by
 | 
				
			||||||
 | 
					 *  the Free Software Foundation; either version 2 of the License, or
 | 
				
			||||||
 | 
					 *  (at your option) any later version.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  ADFLib is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
					 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
					 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
				
			||||||
 | 
					 *  GNU General Public License for more details.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  You should have received a copy of the GNU General Public License
 | 
				
			||||||
 | 
					 *  along with Foobar; if not, write to the Free Software
 | 
				
			||||||
 | 
					 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef ADF_BLK_H
 | 
				
			||||||
 | 
					#define ADF_BLK_H 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define ULONG   uint32_t
 | 
				
			||||||
 | 
					#define USHORT  uint16_t
 | 
				
			||||||
 | 
					#define UCHAR   uint8_t
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define LOGICAL_BLOCK_SIZE    512
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* ----- FILE SYSTEM ----- */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define FSMASK_FFS         1
 | 
				
			||||||
 | 
					#define FSMASK_INTL        2
 | 
				
			||||||
 | 
					#define FSMASK_DIRCACHE    4
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define isFFS(c)           ((c)&FSMASK_FFS)
 | 
				
			||||||
 | 
					#define isOFS(c)           (!((c)&FSMASK_FFS))
 | 
				
			||||||
 | 
					#define isINTL(c)          ((c)&FSMASK_INTL)
 | 
				
			||||||
 | 
					#define isDIRCACHE(c)      ((c)&FSMASK_DIRCACHE)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* ----- ENTRIES ----- */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* access constants */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define ACCMASK_D	(1<<0)
 | 
				
			||||||
 | 
					#define ACCMASK_E	(1<<1)
 | 
				
			||||||
 | 
					#define ACCMASK_W	(1<<2)
 | 
				
			||||||
 | 
					#define ACCMASK_R	(1<<3)
 | 
				
			||||||
 | 
					#define ACCMASK_A	(1<<4)
 | 
				
			||||||
 | 
					#define ACCMASK_P	(1<<5)
 | 
				
			||||||
 | 
					#define ACCMASK_S	(1<<6)
 | 
				
			||||||
 | 
					#define ACCMASK_H	(1<<7)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define hasD(c)    ((c)&ACCMASK_D)
 | 
				
			||||||
 | 
					#define hasE(c)    ((c)&ACCMASK_E)
 | 
				
			||||||
 | 
					#define hasW(c)    ((c)&ACCMASK_W)
 | 
				
			||||||
 | 
					#define hasR(c)    ((c)&ACCMASK_R)
 | 
				
			||||||
 | 
					#define hasA(c)    ((c)&ACCMASK_A)
 | 
				
			||||||
 | 
					#define hasP(c)	   ((c)&ACCMASK_P)
 | 
				
			||||||
 | 
					#define hasS(c)    ((c)&ACCMASK_S)
 | 
				
			||||||
 | 
					#define hasH(c)    ((c)&ACCMASK_H)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* ----- BLOCKS ----- */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* block constants */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define BM_VALID	-1
 | 
				
			||||||
 | 
					#define BM_INVALID	0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define HT_SIZE		72
 | 
				
			||||||
 | 
					#define BM_SIZE     25
 | 
				
			||||||
 | 
					#define MAX_DATABLK	72
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define MAXNAMELEN	30
 | 
				
			||||||
 | 
					#define MAXCMMTLEN	79
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* block primary and secondary types */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define T_HEADER	2
 | 
				
			||||||
 | 
					#define ST_ROOT		1
 | 
				
			||||||
 | 
					#define ST_DIR		2
 | 
				
			||||||
 | 
					#define ST_FILE		-3
 | 
				
			||||||
 | 
					#define ST_LFILE	-4
 | 
				
			||||||
 | 
					#define ST_LDIR		4
 | 
				
			||||||
 | 
					#define ST_LSOFT	3
 | 
				
			||||||
 | 
					#define T_LIST		16
 | 
				
			||||||
 | 
					#define T_DATA		8
 | 
				
			||||||
 | 
					#define T_DIRC		33
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*--- blocks structures --- */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct bBootBlock {
 | 
				
			||||||
 | 
					/*000*/	char	dosType[4];
 | 
				
			||||||
 | 
					/*004*/	ULONG	checkSum;
 | 
				
			||||||
 | 
					/*008*/	int32_t	rootBlock;
 | 
				
			||||||
 | 
					/*00c*/	UCHAR	data[500+512];
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct bRootBlock {
 | 
				
			||||||
 | 
					/*000*/	int32_t	type;
 | 
				
			||||||
 | 
					        int32_t	headerKey;
 | 
				
			||||||
 | 
					        int32_t	highSeq;
 | 
				
			||||||
 | 
					/*00c*/	int32_t	hashTableSize;
 | 
				
			||||||
 | 
					        int32_t	firstData;
 | 
				
			||||||
 | 
					/*014*/	ULONG	checkSum;
 | 
				
			||||||
 | 
					/*018*/	int32_t	hashTable[HT_SIZE];		/* hash table */
 | 
				
			||||||
 | 
					/*138*/	int32_t	bmFlag;				/* bitmap flag, -1 means VALID */
 | 
				
			||||||
 | 
					/*13c*/	int32_t	bmPages[BM_SIZE];
 | 
				
			||||||
 | 
					/*1a0*/	int32_t	bmExt;
 | 
				
			||||||
 | 
					/*1a4*/	int32_t	cDays; 	/* creation date FFS and OFS */
 | 
				
			||||||
 | 
					/*1a8*/	int32_t	cMins;
 | 
				
			||||||
 | 
					/*1ac*/	int32_t	cTicks;
 | 
				
			||||||
 | 
					/*1b0*/	char	nameLen;
 | 
				
			||||||
 | 
					/*1b1*/	char 	diskName[MAXNAMELEN+1];
 | 
				
			||||||
 | 
					        char	r2[8];
 | 
				
			||||||
 | 
					/*1d8*/	int32_t	days;		/* last access : days after 1 jan 1978 */
 | 
				
			||||||
 | 
					/*1dc*/	int32_t	mins;		/* hours and minutes in minutes */
 | 
				
			||||||
 | 
					/*1e0*/	int32_t	ticks;		/* 1/50 seconds */
 | 
				
			||||||
 | 
					/*1e4*/	int32_t	coDays;	/* creation date OFS */
 | 
				
			||||||
 | 
					/*1e8*/	int32_t	coMins;
 | 
				
			||||||
 | 
					/*1ec*/	int32_t	coTicks;
 | 
				
			||||||
 | 
					        int32_t	nextSameHash;	/* == 0 */
 | 
				
			||||||
 | 
					        int32_t	parent;		/* == 0 */
 | 
				
			||||||
 | 
					/*1f8*/	int32_t	extension;		/* FFS: first directory cache block */
 | 
				
			||||||
 | 
					/*1fc*/	int32_t	secType;	/* == 1 */
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct bFileHeaderBlock {
 | 
				
			||||||
 | 
					/*000*/	int32_t	type;		/* == 2 */
 | 
				
			||||||
 | 
					/*004*/	int32_t	headerKey;	/* current block number */
 | 
				
			||||||
 | 
					/*008*/	int32_t	highSeq;	/* number of data block in this hdr block */
 | 
				
			||||||
 | 
					/*00c*/	int32_t	dataSize;	/* == 0 */
 | 
				
			||||||
 | 
					/*010*/	int32_t	firstData;
 | 
				
			||||||
 | 
					/*014*/	ULONG	checkSum;
 | 
				
			||||||
 | 
					/*018*/	int32_t	dataBlocks[MAX_DATABLK];
 | 
				
			||||||
 | 
					/*138*/	int32_t	r1;
 | 
				
			||||||
 | 
					/*13c*/	int32_t	r2;
 | 
				
			||||||
 | 
					/*140*/	int32_t	access;	/* bit0=del, 1=modif, 2=write, 3=read */
 | 
				
			||||||
 | 
					/*144*/	uint32_t	byteSize;
 | 
				
			||||||
 | 
					/*148*/	char	commLen;
 | 
				
			||||||
 | 
					/*149*/	char	comment[MAXCMMTLEN+1];
 | 
				
			||||||
 | 
					        char	r3[91-(MAXCMMTLEN+1)];
 | 
				
			||||||
 | 
					/*1a4*/	int32_t	days;
 | 
				
			||||||
 | 
					/*1a8*/	int32_t	mins;
 | 
				
			||||||
 | 
					/*1ac*/	int32_t	ticks;
 | 
				
			||||||
 | 
					/*1b0*/	char	nameLen;
 | 
				
			||||||
 | 
					/*1b1*/	char	fileName[MAXNAMELEN+1];
 | 
				
			||||||
 | 
					        int32_t	r4;
 | 
				
			||||||
 | 
					/*1d4*/	int32_t	real;		/* unused == 0 */
 | 
				
			||||||
 | 
					/*1d8*/	int32_t	nextLink;	/* link chain */
 | 
				
			||||||
 | 
					        int32_t	r5[5];
 | 
				
			||||||
 | 
					/*1f0*/	int32_t	nextSameHash;	/* next entry with sane hash */
 | 
				
			||||||
 | 
					/*1f4*/	int32_t	parent;		/* parent directory */
 | 
				
			||||||
 | 
					/*1f8*/	int32_t	extension;	/* pointer to extension block */
 | 
				
			||||||
 | 
					/*1fc*/	int32_t	secType;	/* == -3 */
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*--- file header extension block structure ---*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct bFileExtBlock {
 | 
				
			||||||
 | 
					/*000*/	int32_t	type;		/* == 0x10 */
 | 
				
			||||||
 | 
					/*004*/	int32_t	headerKey;
 | 
				
			||||||
 | 
					/*008*/	int32_t	highSeq;
 | 
				
			||||||
 | 
					/*00c*/	int32_t	dataSize;	/* == 0 */
 | 
				
			||||||
 | 
					/*010*/	int32_t	firstData;	/* == 0 */
 | 
				
			||||||
 | 
					/*014*/	ULONG	checkSum;
 | 
				
			||||||
 | 
					/*018*/	int32_t	dataBlocks[MAX_DATABLK];
 | 
				
			||||||
 | 
					        int32_t	r[45];
 | 
				
			||||||
 | 
					        int32_t	info;		/* == 0 */
 | 
				
			||||||
 | 
					        int32_t	nextSameHash;	/* == 0 */
 | 
				
			||||||
 | 
					/*1f4*/	int32_t	parent;		/* header block */
 | 
				
			||||||
 | 
					/*1f8*/	int32_t	extension;	/* next header extension block */
 | 
				
			||||||
 | 
					/*1fc*/	int32_t	secType;	/* -3 */	
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct bDirBlock {
 | 
				
			||||||
 | 
					/*000*/	int32_t	type;		/* == 2 */
 | 
				
			||||||
 | 
					/*004*/	int32_t	headerKey;
 | 
				
			||||||
 | 
					/*008*/	int32_t	highSeq;	/* == 0 */
 | 
				
			||||||
 | 
					/*00c*/	int32_t	hashTableSize;	/* == 0 */
 | 
				
			||||||
 | 
					        int32_t	r1;		/* == 0 */
 | 
				
			||||||
 | 
					/*014*/	ULONG	checkSum;
 | 
				
			||||||
 | 
					/*018*/	int32_t	hashTable[HT_SIZE];		/* hash table */
 | 
				
			||||||
 | 
					        int32_t	r2[2];
 | 
				
			||||||
 | 
					/*140*/	int32_t	access;
 | 
				
			||||||
 | 
					        int32_t	r4;		/* == 0 */
 | 
				
			||||||
 | 
					/*148*/	char	commLen;
 | 
				
			||||||
 | 
					/*149*/	char	comment[MAXCMMTLEN+1];
 | 
				
			||||||
 | 
					        char	r5[91-(MAXCMMTLEN+1)];
 | 
				
			||||||
 | 
					/*1a4*/	int32_t	days;		/* last access */
 | 
				
			||||||
 | 
					/*1a8*/	int32_t	mins;
 | 
				
			||||||
 | 
					/*1ac*/	int32_t	ticks;
 | 
				
			||||||
 | 
					/*1b0*/	char	nameLen;
 | 
				
			||||||
 | 
					/*1b1*/	char 	dirName[MAXNAMELEN+1];
 | 
				
			||||||
 | 
					        int32_t	r6;
 | 
				
			||||||
 | 
					/*1d4*/	int32_t	real;		/* ==0 */
 | 
				
			||||||
 | 
					/*1d8*/	int32_t	nextLink;	/* link list */
 | 
				
			||||||
 | 
					        int32_t	r7[5];
 | 
				
			||||||
 | 
					/*1f0*/	int32_t	nextSameHash;
 | 
				
			||||||
 | 
					/*1f4*/	int32_t	parent;
 | 
				
			||||||
 | 
					/*1f8*/	int32_t	extension;		/* FFS : first directory cache */
 | 
				
			||||||
 | 
					/*1fc*/	int32_t	secType;	/* == 2 */
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct bOFSDataBlock{
 | 
				
			||||||
 | 
					/*000*/	int32_t	type;		/* == 8 */
 | 
				
			||||||
 | 
					/*004*/	int32_t	headerKey;	/* pointer to file_hdr block */
 | 
				
			||||||
 | 
					/*008*/	int32_t	seqNum;	/* file data block number */
 | 
				
			||||||
 | 
					/*00c*/	int32_t	dataSize;	/* <= 0x1e8 */
 | 
				
			||||||
 | 
					/*010*/	int32_t	nextData;	/* next data block */
 | 
				
			||||||
 | 
					/*014*/	ULONG	checkSum;
 | 
				
			||||||
 | 
					/*018*/	UCHAR	data[488];
 | 
				
			||||||
 | 
					/*200*/	};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* --- bitmap --- */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct bBitmapBlock {
 | 
				
			||||||
 | 
					/*000*/	ULONG	checkSum;
 | 
				
			||||||
 | 
					/*004*/	ULONG	map[127];
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct bBitmapExtBlock {
 | 
				
			||||||
 | 
					/*000*/	int32_t	bmPages[127];
 | 
				
			||||||
 | 
					/*1fc*/	int32_t	nextBlock;
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct bLinkBlock {
 | 
				
			||||||
 | 
					/*000*/	int32_t	type;		/* == 2 */
 | 
				
			||||||
 | 
					/*004*/	int32_t	headerKey;	/* self pointer */
 | 
				
			||||||
 | 
					        int32_t	r1[3];
 | 
				
			||||||
 | 
					/*014*/	ULONG	checkSum;
 | 
				
			||||||
 | 
					/*018*/	char	realName[64];
 | 
				
			||||||
 | 
					        int32_t	r2[83];
 | 
				
			||||||
 | 
					/*1a4*/	int32_t	days;		/* last access */
 | 
				
			||||||
 | 
					/*1a8*/	int32_t	mins;
 | 
				
			||||||
 | 
					/*1ac*/	int32_t	ticks;
 | 
				
			||||||
 | 
					/*1b0*/	char	nameLen;
 | 
				
			||||||
 | 
					/*1b1*/	char 	name[MAXNAMELEN+1];
 | 
				
			||||||
 | 
					        int32_t	r3;
 | 
				
			||||||
 | 
					/*1d4*/	int32_t	realEntry;
 | 
				
			||||||
 | 
					/*1d8*/	int32_t	nextLink;
 | 
				
			||||||
 | 
					        int32_t	r4[5];
 | 
				
			||||||
 | 
					/*1f0*/	int32_t	nextSameHash;
 | 
				
			||||||
 | 
					/*1f4*/	int32_t	parent;	
 | 
				
			||||||
 | 
					        int32_t	r5;
 | 
				
			||||||
 | 
					/*1fc*/	int32_t	secType;	/* == -4, 4, 3 */
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*--- directory cache block structure ---*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct bDirCacheBlock {
 | 
				
			||||||
 | 
					/*000*/	int32_t	type;		/* == 33 */
 | 
				
			||||||
 | 
					/*004*/	int32_t	headerKey;
 | 
				
			||||||
 | 
					/*008*/	int32_t	parent;
 | 
				
			||||||
 | 
					/*00c*/	int32_t	recordsNb;
 | 
				
			||||||
 | 
					/*010*/	int32_t	nextDirC;
 | 
				
			||||||
 | 
					/*014*/	ULONG	checkSum;
 | 
				
			||||||
 | 
					/*018*/	uint8_t records[488];
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* ADF_BLK_H */
 | 
				
			||||||
 | 
					/*##########################################################################*/
 | 
				
			||||||
							
								
								
									
										615
									
								
								dep/adflib/src/adf_cache.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										615
									
								
								dep/adflib/src/adf_cache.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,615 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *  ADF Library. (C) 1997-2002 Laurent Clevy
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  adf_cache.c
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  $Id$
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  directory cache code
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  This file is part of ADFLib.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  ADFLib is free software; you can redistribute it and/or modify
 | 
				
			||||||
 | 
					 *  it under the terms of the GNU General Public License as published by
 | 
				
			||||||
 | 
					 *  the Free Software Foundation; either version 2 of the License, or
 | 
				
			||||||
 | 
					 *  (at your option) any later version.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  ADFLib is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
					 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
					 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
				
			||||||
 | 
					 *  GNU General Public License for more details.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  You should have received a copy of the GNU General Public License
 | 
				
			||||||
 | 
					 *  along with Foobar; if not, write to the Free Software
 | 
				
			||||||
 | 
					 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */ 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include<stdlib.h>
 | 
				
			||||||
 | 
					#include<string.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include"adf_defs.h"
 | 
				
			||||||
 | 
					#include"adf_str.h"
 | 
				
			||||||
 | 
					#include"adf_err.h"
 | 
				
			||||||
 | 
					#include"defendian.h"
 | 
				
			||||||
 | 
					#include"adf_cache.h"
 | 
				
			||||||
 | 
					#include"adf_raw.h"
 | 
				
			||||||
 | 
					#include"adf_disk.h"
 | 
				
			||||||
 | 
					#include"adf_bitm.h"
 | 
				
			||||||
 | 
					#include"adf_util.h"
 | 
				
			||||||
 | 
					#include"adf_dir.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern struct Env adfEnv;
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					freeEntCache(struct CacheEntry *cEntry)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (cEntry->name!=NULL)
 | 
				
			||||||
 | 
					        free(cEntry->name);
 | 
				
			||||||
 | 
					    if (cEntry->comm!=NULL)
 | 
				
			||||||
 | 
					        free(cEntry->comm);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * adfGetDirEntCache
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * replace 'adfGetDirEnt'. returns a the dir contents based on the dircache list
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					struct List* adfGetDirEntCache(struct Volume *vol, SECTNUM dir, BOOL recurs)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct bEntryBlock parent;
 | 
				
			||||||
 | 
						struct bDirCacheBlock dirc;
 | 
				
			||||||
 | 
					    int offset, n;
 | 
				
			||||||
 | 
					    struct List *cell, *head;
 | 
				
			||||||
 | 
					    struct CacheEntry caEntry;
 | 
				
			||||||
 | 
					    struct Entry *entry;
 | 
				
			||||||
 | 
					    SECTNUM nSect;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (adfReadEntryBlock(vol,dir,&parent)!=RC_OK)
 | 
				
			||||||
 | 
					        return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    nSect = parent.extension;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    cell = head = NULL;
 | 
				
			||||||
 | 
					    do {
 | 
				
			||||||
 | 
					        /* one loop per cache block */
 | 
				
			||||||
 | 
					        n = offset = 0;
 | 
				
			||||||
 | 
						    if (adfReadDirCBlock(vol, nSect, &dirc)!=RC_OK)
 | 
				
			||||||
 | 
					            return NULL;
 | 
				
			||||||
 | 
					        while (n<dirc.recordsNb) {
 | 
				
			||||||
 | 
					            /* one loop per record */
 | 
				
			||||||
 | 
					            entry = (struct Entry*)malloc(sizeof(struct Entry));
 | 
				
			||||||
 | 
					            if (!entry) {
 | 
				
			||||||
 | 
					                adfFreeDirList(head);
 | 
				
			||||||
 | 
					                return NULL;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            adfGetCacheEntry(&dirc, &offset, &caEntry);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            /* converts a cache entry into a dir entry */
 | 
				
			||||||
 | 
					            entry->type = (int)caEntry.type;
 | 
				
			||||||
 | 
					            entry->name = strdup(caEntry.name);
 | 
				
			||||||
 | 
					            if (entry->name==NULL) {
 | 
				
			||||||
 | 
					                free(entry); adfFreeDirList(head);
 | 
				
			||||||
 | 
					                return NULL;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            entry->sector = caEntry.header;
 | 
				
			||||||
 | 
					            entry->comment = strdup(caEntry.comm);
 | 
				
			||||||
 | 
					            if (entry->comment==NULL) {
 | 
				
			||||||
 | 
					                free(entry->name); adfFreeDirList(head);
 | 
				
			||||||
 | 
					                return NULL;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            entry->size = caEntry.size;
 | 
				
			||||||
 | 
					            entry->access = caEntry.protect;
 | 
				
			||||||
 | 
					            adfDays2Date( caEntry.days, &(entry->year), &(entry->month), 
 | 
				
			||||||
 | 
					                &(entry->days) );
 | 
				
			||||||
 | 
					            entry->hour = caEntry.mins/60;
 | 
				
			||||||
 | 
					            entry->mins = caEntry.mins%60;
 | 
				
			||||||
 | 
					            entry->secs = caEntry.ticks/50;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            /* add it into the linked list */
 | 
				
			||||||
 | 
					            if (head==NULL)
 | 
				
			||||||
 | 
					                head = cell = newCell(NULL, (void*)entry); 
 | 
				
			||||||
 | 
					            else
 | 
				
			||||||
 | 
					                cell = newCell(cell, (void*)entry); 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (cell==NULL) {
 | 
				
			||||||
 | 
					                adfFreeEntry(entry);
 | 
				
			||||||
 | 
					                adfFreeDirList(head);
 | 
				
			||||||
 | 
					                return NULL;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (recurs && entry->type==ST_DIR)
 | 
				
			||||||
 | 
					                 cell->subdir = adfGetDirEntCache(vol,entry->sector,recurs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            n++;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        nSect = dirc.nextDirC;
 | 
				
			||||||
 | 
					    }while (nSect!=0);
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    return head;	
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * adfGetCacheEntry
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Returns a cache entry, starting from the offset p (the index into records[])
 | 
				
			||||||
 | 
					 * This offset is updated to the end of the returned entry.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void adfGetCacheEntry(struct bDirCacheBlock *dirc, int *p, struct CacheEntry *cEntry)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int ptr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ptr = *p;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*printf("p=%d\n",ptr);*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef LITT_ENDIAN
 | 
				
			||||||
 | 
					    cEntry->header = swapLong(dirc->records+ptr);
 | 
				
			||||||
 | 
					    cEntry->size = swapLong(dirc->records+ptr+4);
 | 
				
			||||||
 | 
					    cEntry->protect = swapLong(dirc->records+ptr+8);
 | 
				
			||||||
 | 
					    cEntry->days = swapShort(dirc->records+ptr+16);
 | 
				
			||||||
 | 
					    cEntry->mins = swapShort(dirc->records+ptr+18);
 | 
				
			||||||
 | 
					    cEntry->ticks = swapShort(dirc->records+ptr+20);
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					    cEntry->header = Long(dirc->records+ptr);
 | 
				
			||||||
 | 
					    cEntry->size = Long(dirc->records+ptr+4);
 | 
				
			||||||
 | 
					    cEntry->protect = Long(dirc->records+ptr+8);
 | 
				
			||||||
 | 
					    cEntry->days = Short(dirc->records+ptr+16);
 | 
				
			||||||
 | 
					    cEntry->mins = Short(dirc->records+ptr+18);
 | 
				
			||||||
 | 
					    cEntry->ticks = Short(dirc->records+ptr+20);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					    cEntry->type =(signed char) dirc->records[ptr+22];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    cEntry->nLen = dirc->records[ptr+23];
 | 
				
			||||||
 | 
					/*    cEntry->name = (char*)malloc(sizeof(char)*(cEntry->nLen+1));
 | 
				
			||||||
 | 
					    if (!cEntry->name)
 | 
				
			||||||
 | 
					         return;
 | 
				
			||||||
 | 
					*/    memcpy(cEntry->name, dirc->records+ptr+24, cEntry->nLen);
 | 
				
			||||||
 | 
					    cEntry->name[(int)(cEntry->nLen)]='\0';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    cEntry->cLen = dirc->records[ptr+24+cEntry->nLen];
 | 
				
			||||||
 | 
					    if (cEntry->cLen>0) {
 | 
				
			||||||
 | 
					/*        cEntry->comm =(char*)malloc(sizeof(char)*(cEntry->cLen+1));
 | 
				
			||||||
 | 
					        if (!cEntry->comm) {
 | 
				
			||||||
 | 
					            free( cEntry->name ); cEntry->name=NULL;
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					*/        memcpy(cEntry->comm,dirc->records+ptr+24+cEntry->nLen+1,cEntry->cLen);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					        cEntry->comm[(int)(cEntry->cLen)]='\0';
 | 
				
			||||||
 | 
					/*printf("cEntry->nLen %d cEntry->cLen %d %s\n",cEntry->nLen,cEntry->cLen,cEntry->name);*/
 | 
				
			||||||
 | 
					    *p  = ptr+24+cEntry->nLen+1+cEntry->cLen;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* the starting offset of each record must be even (68000 constraint) */ 
 | 
				
			||||||
 | 
					    if ((*p%2)!=0)
 | 
				
			||||||
 | 
					        *p=(*p)+1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * adfPutCacheEntry
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * remplaces one cache entry at the p offset, and returns its length
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int adfPutCacheEntry( struct bDirCacheBlock *dirc, int *p, struct CacheEntry *cEntry)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int ptr, l;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ptr = *p;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef LITT_ENDIAN
 | 
				
			||||||
 | 
					    swLong(dirc->records+ptr, cEntry->header);
 | 
				
			||||||
 | 
					    swLong(dirc->records+ptr+4, cEntry->size);
 | 
				
			||||||
 | 
					    swLong(dirc->records+ptr+8, cEntry->protect);
 | 
				
			||||||
 | 
					    swShort(dirc->records+ptr+16, cEntry->days);
 | 
				
			||||||
 | 
					    swShort(dirc->records+ptr+18, cEntry->mins);
 | 
				
			||||||
 | 
					    swShort(dirc->records+ptr+20, cEntry->ticks);
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					    memcpy(dirc->records+ptr,&(cEntry->header),4);
 | 
				
			||||||
 | 
					    memcpy(dirc->records+ptr+4,&(cEntry->size),4);
 | 
				
			||||||
 | 
					    memcpy(dirc->records+ptr+8,&(cEntry->protect),4);
 | 
				
			||||||
 | 
					    memcpy(dirc->records+ptr+16,&(cEntry->days),2);
 | 
				
			||||||
 | 
					    memcpy(dirc->records+ptr+18,&(cEntry->mins),2);
 | 
				
			||||||
 | 
					    memcpy(dirc->records+ptr+20,&(cEntry->ticks),2);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					    dirc->records[ptr+22] =(signed char)cEntry->type;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    dirc->records[ptr+23] = cEntry->nLen;
 | 
				
			||||||
 | 
					    memcpy(dirc->records+ptr+24, cEntry->name, cEntry->nLen);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    dirc->records[ptr+24+cEntry->nLen] = cEntry->cLen;
 | 
				
			||||||
 | 
					    memcpy(dirc->records+ptr+24+cEntry->nLen+1, cEntry->comm, cEntry->cLen);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*puts("adfPutCacheEntry");*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    l = 25+cEntry->nLen+cEntry->cLen;
 | 
				
			||||||
 | 
					    if ((l%2)==0)
 | 
				
			||||||
 | 
					        return l;
 | 
				
			||||||
 | 
					    else {
 | 
				
			||||||
 | 
					        dirc->records[ptr+l] =(char)0;
 | 
				
			||||||
 | 
					        return l+1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* ptr%2 must be == 0, if l%2==0, (ptr+l)%2==0 */ 
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * adfEntry2CacheEntry
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * converts one dir entry into a cache entry, and return its future length in records[]
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int adfEntry2CacheEntry(struct bEntryBlock *entry, struct CacheEntry *newEntry)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int entryLen;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* new entry */
 | 
				
			||||||
 | 
					    newEntry->header = entry->headerKey;
 | 
				
			||||||
 | 
					    if (entry->secType==ST_FILE)
 | 
				
			||||||
 | 
					        newEntry->size = entry->byteSize;
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					        newEntry->size = 0L;
 | 
				
			||||||
 | 
					    newEntry->protect = entry->access;
 | 
				
			||||||
 | 
					    newEntry->days = (short)entry->days;
 | 
				
			||||||
 | 
					    newEntry->mins = (short)entry->mins;
 | 
				
			||||||
 | 
					    newEntry->ticks  = (short)entry->ticks;
 | 
				
			||||||
 | 
					    newEntry->type = (signed char)entry->secType;
 | 
				
			||||||
 | 
					    newEntry->nLen = entry->nameLen;
 | 
				
			||||||
 | 
					    memcpy(newEntry->name, entry->name, newEntry->nLen);
 | 
				
			||||||
 | 
					    newEntry->name[(int)(newEntry->nLen)] = '\0';
 | 
				
			||||||
 | 
					    newEntry->cLen = entry->commLen;
 | 
				
			||||||
 | 
					    if (newEntry->cLen>0)
 | 
				
			||||||
 | 
					        memcpy(newEntry->comm, entry->comment, newEntry->cLen);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    entryLen = 24+newEntry->nLen+1+newEntry->cLen;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*printf("entry->name %d entry->comment %d\n",entry->nameLen,entry->commLen);
 | 
				
			||||||
 | 
					printf("newEntry->nLen %d newEntry->cLen %d\n",newEntry->nLen,newEntry->cLen);
 | 
				
			||||||
 | 
					*/    if ((entryLen%2)==0)
 | 
				
			||||||
 | 
					        return entryLen;
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					        return entryLen+1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * adfDelFromCache
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * delete one cache entry from its block. don't do 'records garbage collecting'
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					RETCODE adfDelFromCache(struct Volume *vol, struct bEntryBlock *parent, 
 | 
				
			||||||
 | 
					    SECTNUM headerKey)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    struct bDirCacheBlock dirc;
 | 
				
			||||||
 | 
					    SECTNUM nSect, prevSect;
 | 
				
			||||||
 | 
					    struct CacheEntry caEntry;
 | 
				
			||||||
 | 
					    int offset, oldOffset, n;
 | 
				
			||||||
 | 
					    BOOL found;
 | 
				
			||||||
 | 
					    int entryLen;
 | 
				
			||||||
 | 
					    int i;
 | 
				
			||||||
 | 
					    RETCODE rc = RC_OK;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    prevSect = -1;
 | 
				
			||||||
 | 
						nSect = parent->extension;
 | 
				
			||||||
 | 
					    found = FALSE;
 | 
				
			||||||
 | 
					    do {
 | 
				
			||||||
 | 
					        adfReadDirCBlock(vol, nSect, &dirc);
 | 
				
			||||||
 | 
					        offset = 0; n = 0;
 | 
				
			||||||
 | 
					        while(n < dirc.recordsNb && !found) {
 | 
				
			||||||
 | 
					            oldOffset = offset;
 | 
				
			||||||
 | 
					            adfGetCacheEntry(&dirc, &offset, &caEntry);
 | 
				
			||||||
 | 
					            found = (caEntry.header==headerKey);
 | 
				
			||||||
 | 
					            if (found) {
 | 
				
			||||||
 | 
					                entryLen = offset-oldOffset;
 | 
				
			||||||
 | 
					                if (dirc.recordsNb>1 || prevSect==-1) {
 | 
				
			||||||
 | 
					                    if (n<dirc.recordsNb-1) {
 | 
				
			||||||
 | 
					                        /* not the last of the block : switch the following records */
 | 
				
			||||||
 | 
					                        for(i=oldOffset; i<(488-entryLen); i++)
 | 
				
			||||||
 | 
					                            dirc.records[i] = dirc.records[i+entryLen];
 | 
				
			||||||
 | 
					                        /* and clear the following bytes */
 | 
				
			||||||
 | 
					                        for(i=488-entryLen; i<488; i++)
 | 
				
			||||||
 | 
					                            dirc.records[i] = 0;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    else {
 | 
				
			||||||
 | 
					                        /* the last record of this cache block */
 | 
				
			||||||
 | 
					                        for(i=oldOffset; i<offset; i++)
 | 
				
			||||||
 | 
					                            dirc.records[i] = 0;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    dirc.recordsNb--;
 | 
				
			||||||
 | 
					                    if (adfWriteDirCBlock(vol, dirc.headerKey, &dirc)!=RC_OK)
 | 
				
			||||||
 | 
											return -1;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                else {
 | 
				
			||||||
 | 
					                    /* dirc.recordsNb ==1 or == 0 , prevSect!=-1 : 
 | 
				
			||||||
 | 
					                    * the only record in this dirc block and a previous dirc block exists 
 | 
				
			||||||
 | 
					                    */
 | 
				
			||||||
 | 
					                    adfSetBlockFree(vol, dirc.headerKey);
 | 
				
			||||||
 | 
					                    adfReadDirCBlock(vol, prevSect, &dirc);
 | 
				
			||||||
 | 
					                    dirc.nextDirC = 0L;
 | 
				
			||||||
 | 
					                    adfWriteDirCBlock(vol, prevSect, &dirc);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    adfUpdateBitmap(vol);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            n++;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        prevSect = nSect;
 | 
				
			||||||
 | 
					        nSect = dirc.nextDirC;
 | 
				
			||||||
 | 
					    }while(nSect!=0 && !found);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!found)
 | 
				
			||||||
 | 
					        (*adfEnv.wFct)("adfUpdateCache : entry not found");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return rc;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * adfAddInCache
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					RETCODE adfAddInCache(struct Volume *vol, struct bEntryBlock *parent, 
 | 
				
			||||||
 | 
					    struct bEntryBlock *entry)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    struct bDirCacheBlock dirc, newDirc;
 | 
				
			||||||
 | 
					    SECTNUM nSect, nCache;
 | 
				
			||||||
 | 
					    struct CacheEntry caEntry, newEntry;
 | 
				
			||||||
 | 
					    int offset, n;
 | 
				
			||||||
 | 
					    int entryLen;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    entryLen = adfEntry2CacheEntry(entry, &newEntry);
 | 
				
			||||||
 | 
					/*printf("adfAddInCache--%4ld %2d %6ld %8lx %4d %2d:%02d:%02d %30s %22s\n",
 | 
				
			||||||
 | 
					    newEntry.header, newEntry.type, newEntry.size, newEntry.protect,
 | 
				
			||||||
 | 
					    newEntry.days, newEntry.mins/60, newEntry.mins%60, 
 | 
				
			||||||
 | 
						newEntry.ticks/50,
 | 
				
			||||||
 | 
						newEntry.name, newEntry.comm);
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					    nSect = parent->extension;
 | 
				
			||||||
 | 
					    do {
 | 
				
			||||||
 | 
					        if (adfReadDirCBlock(vol, nSect, &dirc)!=RC_OK)
 | 
				
			||||||
 | 
					            return RC_ERROR;
 | 
				
			||||||
 | 
					        offset = 0; n = 0;
 | 
				
			||||||
 | 
					/*printf("parent=%4ld\n",dirc.parent);*/
 | 
				
			||||||
 | 
					        while(n < dirc.recordsNb) {
 | 
				
			||||||
 | 
					            adfGetCacheEntry(&dirc, &offset, &caEntry);
 | 
				
			||||||
 | 
					/*printf("*%4ld %2d %6ld %8lx %4d %2d:%02d:%02d %30s %22s\n",
 | 
				
			||||||
 | 
					    caEntry.header, caEntry.type, caEntry.size, caEntry.protect,
 | 
				
			||||||
 | 
					    caEntry.days, caEntry.mins/60, caEntry.mins%60, 
 | 
				
			||||||
 | 
						caEntry.ticks/50,
 | 
				
			||||||
 | 
						caEntry.name, caEntry.comm);
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					            n++;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					/*        if (offset+entryLen<=488) {
 | 
				
			||||||
 | 
					            adfPutCacheEntry(&dirc, &offset, &newEntry);
 | 
				
			||||||
 | 
					            dirc.recordsNb++;
 | 
				
			||||||
 | 
					            adfWriteDirCBlock(vol, dirc.headerKey, &dirc);
 | 
				
			||||||
 | 
					            return rc;
 | 
				
			||||||
 | 
					        }*/
 | 
				
			||||||
 | 
					        nSect = dirc.nextDirC;
 | 
				
			||||||
 | 
					    }while(nSect!=0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* in the last block */
 | 
				
			||||||
 | 
					    if (offset+entryLen<=488) {
 | 
				
			||||||
 | 
					        adfPutCacheEntry(&dirc, &offset, &newEntry);
 | 
				
			||||||
 | 
					        dirc.recordsNb++;
 | 
				
			||||||
 | 
					/*printf("entry name=%s\n",newEntry.name);*/
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else {
 | 
				
			||||||
 | 
					        /* request one new block free */
 | 
				
			||||||
 | 
					        nCache = adfGet1FreeBlock(vol);
 | 
				
			||||||
 | 
					        if (nCache==-1) {
 | 
				
			||||||
 | 
					           (*adfEnv.wFct)("adfCreateDir : nCache==-1");
 | 
				
			||||||
 | 
					           return RC_VOLFULL;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /* create a new dircache block */
 | 
				
			||||||
 | 
					        memset(&newDirc,0,512);
 | 
				
			||||||
 | 
					        if (parent->secType==ST_ROOT)
 | 
				
			||||||
 | 
					            newDirc.parent = vol->rootBlock;
 | 
				
			||||||
 | 
					        else if (parent->secType==ST_DIR)
 | 
				
			||||||
 | 
					            newDirc.parent = parent->headerKey;
 | 
				
			||||||
 | 
					        else
 | 
				
			||||||
 | 
					            (*adfEnv.wFct)("adfAddInCache : unknown secType");
 | 
				
			||||||
 | 
					        newDirc.recordsNb = 0L;
 | 
				
			||||||
 | 
					        newDirc.nextDirC = 0L;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        adfPutCacheEntry(&dirc, &offset, &newEntry);
 | 
				
			||||||
 | 
					        newDirc.recordsNb++;
 | 
				
			||||||
 | 
					        if (adfWriteDirCBlock(vol, nCache, &newDirc)!=RC_OK)
 | 
				
			||||||
 | 
								return RC_ERROR;
 | 
				
			||||||
 | 
					        dirc.nextDirC = nCache;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					/*printf("dirc.headerKey=%ld\n",dirc.headerKey);*/
 | 
				
			||||||
 | 
					    if (adfWriteDirCBlock(vol, dirc.headerKey, &dirc)!=RC_OK)
 | 
				
			||||||
 | 
							return RC_ERROR;
 | 
				
			||||||
 | 
					/*if (strcmp(entry->name,"file_5u")==0)
 | 
				
			||||||
 | 
					dumpBlock(&dirc);
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					    return RC_OK;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * adfUpdateCache
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					RETCODE adfUpdateCache(struct Volume *vol, struct bEntryBlock *parent, 
 | 
				
			||||||
 | 
					    struct bEntryBlock *entry, BOOL entryLenChg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    struct bDirCacheBlock dirc;
 | 
				
			||||||
 | 
					    SECTNUM nSect;
 | 
				
			||||||
 | 
					    struct CacheEntry caEntry, newEntry;
 | 
				
			||||||
 | 
					    int offset, oldOffset, n;
 | 
				
			||||||
 | 
					    BOOL found;
 | 
				
			||||||
 | 
					    int i, oLen, nLen;
 | 
				
			||||||
 | 
					    int sLen; /* shift length */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    nLen = adfEntry2CacheEntry(entry, &newEntry);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    nSect = parent->extension;
 | 
				
			||||||
 | 
					    found = FALSE;
 | 
				
			||||||
 | 
					    do {
 | 
				
			||||||
 | 
					/*printf("dirc=%ld\n",nSect);*/
 | 
				
			||||||
 | 
					        if (adfReadDirCBlock(vol, nSect, &dirc)!=RC_OK)
 | 
				
			||||||
 | 
								return RC_ERROR;
 | 
				
			||||||
 | 
					        offset = 0; n = 0;
 | 
				
			||||||
 | 
					        /* search entry to update with its header_key */
 | 
				
			||||||
 | 
					        while(n < dirc.recordsNb && !found) {
 | 
				
			||||||
 | 
					            oldOffset = offset;
 | 
				
			||||||
 | 
					            /* offset is updated */
 | 
				
			||||||
 | 
					            adfGetCacheEntry(&dirc, &offset, &caEntry);
 | 
				
			||||||
 | 
					            oLen = offset-oldOffset;
 | 
				
			||||||
 | 
					            sLen = oLen-nLen;
 | 
				
			||||||
 | 
					/*printf("olen=%d nlen=%d\n",oLen,nLen);*/
 | 
				
			||||||
 | 
					            found = (caEntry.header==newEntry.header);
 | 
				
			||||||
 | 
					            if (found) {
 | 
				
			||||||
 | 
					                if (!entryLenChg || oLen==nLen) {
 | 
				
			||||||
 | 
					                    /* same length : remplace the old values */
 | 
				
			||||||
 | 
					                    adfPutCacheEntry(&dirc, &oldOffset, &newEntry);
 | 
				
			||||||
 | 
					/*if (entryLenChg) puts("oLen==nLen");*/
 | 
				
			||||||
 | 
					                    if (adfWriteDirCBlock(vol, dirc.headerKey, &dirc)!=RC_OK)
 | 
				
			||||||
 | 
					                        return RC_ERROR;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                else if (oLen>nLen) {
 | 
				
			||||||
 | 
					/*puts("oLen>nLen");*/
 | 
				
			||||||
 | 
					                    /* the new record is shorter, write it, 
 | 
				
			||||||
 | 
					                     * then shift down the following records 
 | 
				
			||||||
 | 
					                     */
 | 
				
			||||||
 | 
					                    adfPutCacheEntry(&dirc, &oldOffset, &newEntry);
 | 
				
			||||||
 | 
					                    for(i=oldOffset+nLen; i<(488-sLen); i++)
 | 
				
			||||||
 | 
					                        dirc.records[i] = dirc.records[i+sLen];
 | 
				
			||||||
 | 
					                    /* then clear the following bytes */
 | 
				
			||||||
 | 
					                    for(i=488-sLen; i<488; i++)
 | 
				
			||||||
 | 
					                        dirc.records[i] = (char)0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    if (adfWriteDirCBlock(vol, dirc.headerKey, &dirc)!=RC_OK)
 | 
				
			||||||
 | 
					                        return RC_ERROR;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                else {
 | 
				
			||||||
 | 
					                    /* the new record is larger */
 | 
				
			||||||
 | 
					/*puts("oLen<nLen");*/
 | 
				
			||||||
 | 
					                    adfDelFromCache(vol,parent,entry->headerKey);
 | 
				
			||||||
 | 
					                    adfAddInCache(vol,parent,entry);
 | 
				
			||||||
 | 
					/*puts("oLen<nLen end");*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            n++;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        nSect = dirc.nextDirC;
 | 
				
			||||||
 | 
					    }while(nSect!=0 && !found);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (found) {
 | 
				
			||||||
 | 
					        if (adfUpdateBitmap(vol)!=RC_OK)
 | 
				
			||||||
 | 
								return RC_ERROR;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					        (*adfEnv.wFct)("adfUpdateCache : entry not found");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return RC_OK;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * adfCreateEmptyCache
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					RETCODE adfCreateEmptyCache(struct Volume *vol, struct bEntryBlock *parent, SECTNUM nSect)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    struct bDirCacheBlock dirc;
 | 
				
			||||||
 | 
					    SECTNUM nCache;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (nSect==-1) {
 | 
				
			||||||
 | 
					        nCache = adfGet1FreeBlock(vol);
 | 
				
			||||||
 | 
					        if (nCache==-1) {
 | 
				
			||||||
 | 
					           (*adfEnv.wFct)("adfCreateDir : nCache==-1");
 | 
				
			||||||
 | 
					           return RC_VOLFULL;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					        nCache = nSect;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (parent->extension==0)
 | 
				
			||||||
 | 
							parent->extension = nCache;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    memset(&dirc,0, sizeof(struct bDirCacheBlock));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (parent->secType==ST_ROOT)
 | 
				
			||||||
 | 
					        dirc.parent = vol->rootBlock;
 | 
				
			||||||
 | 
					    else if (parent->secType==ST_DIR)
 | 
				
			||||||
 | 
					        dirc.parent = parent->headerKey;
 | 
				
			||||||
 | 
					    else {
 | 
				
			||||||
 | 
					        (*adfEnv.wFct)("adfCreateEmptyCache : unknown secType");
 | 
				
			||||||
 | 
					/*printf("secType=%ld\n",parent->secType);*/
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					    dirc.recordsNb = 0;
 | 
				
			||||||
 | 
					    dirc.nextDirC = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (adfWriteDirCBlock(vol, nCache, &dirc)!=RC_OK)
 | 
				
			||||||
 | 
							return RC_ERROR;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return RC_OK;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * adfReadDirCBlock
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					RETCODE adfReadDirCBlock(struct Volume *vol, SECTNUM nSect, struct bDirCacheBlock *dirc)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    uint8_t buf[512];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (adfReadBlock(vol, nSect, buf)!=RC_OK)
 | 
				
			||||||
 | 
							return RC_ERROR;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    memcpy(dirc,buf,512);
 | 
				
			||||||
 | 
					#ifdef LITT_ENDIAN
 | 
				
			||||||
 | 
					    swapEndian((uint8_t*)dirc,SWBL_CACHE);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					    if (dirc->checkSum!=adfNormalSum(buf,20,512))
 | 
				
			||||||
 | 
					        (*adfEnv.wFct)("adfReadDirCBlock : invalid checksum");
 | 
				
			||||||
 | 
					    if (dirc->type!=T_DIRC)
 | 
				
			||||||
 | 
					        (*adfEnv.wFct)("adfReadDirCBlock : T_DIRC not found");
 | 
				
			||||||
 | 
					    if (dirc->headerKey!=nSect)
 | 
				
			||||||
 | 
					        (*adfEnv.wFct)("adfReadDirCBlock : headerKey!=nSect");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return RC_OK;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * adfWriteDirCblock
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					RETCODE adfWriteDirCBlock(struct Volume* vol, int32_t nSect, struct bDirCacheBlock* dirc)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    uint8_t buf[LOGICAL_BLOCK_SIZE];
 | 
				
			||||||
 | 
					    uint32_t newSum;
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					    dirc->type = T_DIRC;
 | 
				
			||||||
 | 
					    dirc->headerKey = nSect; 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    memcpy(buf, dirc, LOGICAL_BLOCK_SIZE);
 | 
				
			||||||
 | 
					#ifdef LITT_ENDIAN
 | 
				
			||||||
 | 
					    swapEndian(buf, SWBL_CACHE);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    newSum = adfNormalSum(buf, 20, LOGICAL_BLOCK_SIZE);
 | 
				
			||||||
 | 
					    swLong(buf+20,newSum);
 | 
				
			||||||
 | 
					/*    *(int32_t*)(buf+20) = swapLong((uint8_t*)&newSum);*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (adfWriteBlock(vol, nSect, buf)!=RC_OK)
 | 
				
			||||||
 | 
							return RC_ERROR;
 | 
				
			||||||
 | 
					/*puts("adfWriteDirCBlock");*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return RC_OK;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*################################################################################*/
 | 
				
			||||||
							
								
								
									
										48
									
								
								dep/adflib/src/adf_cache.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								dep/adflib/src/adf_cache.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,48 @@
 | 
				
			|||||||
 | 
					#ifndef _ADF_CACHE_H
 | 
				
			||||||
 | 
					#define _ADF_CACHE_H 1
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *  ADF Library. (C) 1997-2002 Laurent Clevy
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  adf_cache.h
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  $Id$
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  directory cache code
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  This file is part of ADFLib.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  ADFLib is free software; you can redistribute it and/or modify
 | 
				
			||||||
 | 
					 *  it under the terms of the GNU General Public License as published by
 | 
				
			||||||
 | 
					 *  the Free Software Foundation; either version 2 of the License, or
 | 
				
			||||||
 | 
					 *  (at your option) any later version.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  ADFLib is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
					 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
					 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
				
			||||||
 | 
					 *  GNU General Public License for more details.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  You should have received a copy of the GNU General Public License
 | 
				
			||||||
 | 
					 *  along with Foobar; if not, write to the Free Software
 | 
				
			||||||
 | 
					 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "adf_str.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void adfGetCacheEntry(struct bDirCacheBlock *dirc, int *p, struct CacheEntry *cEntry);
 | 
				
			||||||
 | 
					int adfPutCacheEntry( struct bDirCacheBlock *dirc, int *p, struct CacheEntry *cEntry);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct List* adfGetDirEntCache(struct Volume *vol, SECTNUM dir, BOOL recurs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					RETCODE adfCreateEmptyCache(struct Volume *vol, struct bEntryBlock *parent, SECTNUM nSect);
 | 
				
			||||||
 | 
					RETCODE adfAddInCache(struct Volume *vol, struct bEntryBlock *parent, struct bEntryBlock *entry);
 | 
				
			||||||
 | 
					RETCODE adfUpdateCache(struct Volume *vol, struct bEntryBlock *parent, struct bEntryBlock *entry, BOOL);
 | 
				
			||||||
 | 
					RETCODE adfDelFromCache(struct Volume *vol, struct bEntryBlock *parent, SECTNUM);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					RETCODE adfReadDirCBlock(struct Volume *vol, SECTNUM nSect, struct bDirCacheBlock *dirc);
 | 
				
			||||||
 | 
					RETCODE adfWriteDirCBlock(struct Volume*, int32_t, struct bDirCacheBlock* dirc);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* _ADF_CACHE_H */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*##########################################################################*/
 | 
				
			||||||
							
								
								
									
										71
									
								
								dep/adflib/src/adf_defs.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								dep/adflib/src/adf_defs.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,71 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *  ADF Library. (C) 1997-2002 Laurent Clevy
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  adf_defs.h
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  $Id$
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  This file is part of ADFLib.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  ADFLib is free software; you can redistribute it and/or modify
 | 
				
			||||||
 | 
					 *  it under the terms of the GNU General Public License as published by
 | 
				
			||||||
 | 
					 *  the Free Software Foundation; either version 2 of the License, or
 | 
				
			||||||
 | 
					 *  (at your option) any later version.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  ADFLib is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
					 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
					 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
				
			||||||
 | 
					 *  GNU General Public License for more details.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  You should have received a copy of the GNU General Public License
 | 
				
			||||||
 | 
					 *  along with Foobar; if not, write to the Free Software
 | 
				
			||||||
 | 
					 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef _ADF_DEFS_H
 | 
				
			||||||
 | 
					#define _ADF_DEFS_H 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define ADFLIB_VERSION "0.7.11a"
 | 
				
			||||||
 | 
					#define ADFLIB_DATE "January 20th, 2007"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define SECTNUM int32_t
 | 
				
			||||||
 | 
					#define RETCODE int32_t
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define TRUE    1
 | 
				
			||||||
 | 
					#define FALSE   0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <stdint.h>
 | 
				
			||||||
 | 
					#define ULONG   uint32_t
 | 
				
			||||||
 | 
					#define USHORT  uint16_t
 | 
				
			||||||
 | 
					#define UCHAR   uint8_t
 | 
				
			||||||
 | 
					#define BOOL    int
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* defines max and min */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef max
 | 
				
			||||||
 | 
					#define max(a,b)        (a)>(b) ? (a) : (b)
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#ifndef min
 | 
				
			||||||
 | 
					#define min(a,b)        (a)<(b) ? (a) : (b)
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* (*byte) to (*short) and (*byte) to (*long) conversion */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define Short(p) ((p)[0]<<8 | (p)[1])
 | 
				
			||||||
 | 
					#define Long(p) (Short(p)<<16 | Short(p+2))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* swap short and swap long macros for little endian machines */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define swapShort(p) ((p)[0]<<8 | (p)[1])
 | 
				
			||||||
 | 
					#define swapLong(p) (swapShort(p)<<16 | swapShort(p+2))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* _ADF_DEFS_H */
 | 
				
			||||||
 | 
					/*##########################################################################*/
 | 
				
			||||||
							
								
								
									
										1066
									
								
								dep/adflib/src/adf_dir.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1066
									
								
								dep/adflib/src/adf_dir.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										70
									
								
								dep/adflib/src/adf_dir.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								dep/adflib/src/adf_dir.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,70 @@
 | 
				
			|||||||
 | 
					#ifndef ADF_DIR_H
 | 
				
			||||||
 | 
					#define ADF_DIR_H 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *  ADF Library. (C) 1997-2002 Laurent Clevy
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  adf_dir.h
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  $Id$
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  This file is part of ADFLib.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  ADFLib is free software; you can redistribute it and/or modify
 | 
				
			||||||
 | 
					 *  it under the terms of the GNU General Public License as published by
 | 
				
			||||||
 | 
					 *  the Free Software Foundation; either version 2 of the License, or
 | 
				
			||||||
 | 
					 *  (at your option) any later version.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  ADFLib is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
					 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
					 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
				
			||||||
 | 
					 *  GNU General Public License for more details.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  You should have received a copy of the GNU General Public License
 | 
				
			||||||
 | 
					 *  along with Foobar; if not, write to the Free Software
 | 
				
			||||||
 | 
					 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include"adf_str.h"
 | 
				
			||||||
 | 
					#include"adf_err.h"
 | 
				
			||||||
 | 
					#include"adf_defs.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include"prefix.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					PREFIX RETCODE adfToRootDir(struct Volume *vol);
 | 
				
			||||||
 | 
					BOOL isDirEmpty(struct bDirBlock *dir);
 | 
				
			||||||
 | 
					PREFIX RETCODE adfRemoveEntry(struct Volume *vol, SECTNUM pSect, char *name);
 | 
				
			||||||
 | 
					PREFIX struct List* adfGetDirEnt(struct Volume* vol, SECTNUM nSect );
 | 
				
			||||||
 | 
					PREFIX struct List* adfGetRDirEnt(struct Volume* vol, SECTNUM nSect, BOOL recurs );
 | 
				
			||||||
 | 
					PREFIX void adfFreeDirList(struct List* list);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					RETCODE adfEntBlock2Entry(struct bEntryBlock *entryBlk, struct Entry *entry);
 | 
				
			||||||
 | 
					PREFIX void adfFreeEntry(struct Entry *entry);
 | 
				
			||||||
 | 
					RETCODE adfCreateFile(struct Volume* vol, SECTNUM parent, char *name,
 | 
				
			||||||
 | 
					    struct bFileHeaderBlock *fhdr);
 | 
				
			||||||
 | 
					PREFIX RETCODE adfCreateDir(struct Volume* vol, SECTNUM parent, char* name);
 | 
				
			||||||
 | 
					SECTNUM adfCreateEntry(struct Volume *vol, struct bEntryBlock *dir, char *name, SECTNUM );
 | 
				
			||||||
 | 
					PREFIX RETCODE adfRenameEntry(struct Volume *vol, SECTNUM, char *old,SECTNUM,char *new);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					RETCODE adfReadEntryBlock(struct Volume* vol, SECTNUM nSect, struct bEntryBlock* ent);
 | 
				
			||||||
 | 
					RETCODE adfWriteDirBlock(struct Volume* vol, SECTNUM nSect, struct bDirBlock *dir);
 | 
				
			||||||
 | 
					RETCODE adfWriteEntryBlock(struct Volume* vol, SECTNUM nSect, struct bEntryBlock *ent);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					char* adfAccess2String(int32_t acc);
 | 
				
			||||||
 | 
					uint8_t adfIntlToUpper(uint8_t c);
 | 
				
			||||||
 | 
					int adfGetHashValue(uint8_t *name, BOOL intl);
 | 
				
			||||||
 | 
					void myToUpper( uint8_t *ostr, uint8_t *nstr, int,BOOL intl );
 | 
				
			||||||
 | 
					PREFIX RETCODE adfChangeDir(struct Volume* vol, char *name);
 | 
				
			||||||
 | 
					PREFIX RETCODE adfParentDir(struct Volume* vol);
 | 
				
			||||||
 | 
					PREFIX RETCODE adfSetEntryAccess(struct Volume*, SECTNUM, char*, int32_t);
 | 
				
			||||||
 | 
					PREFIX RETCODE adfSetEntryComment(struct Volume*, SECTNUM, char*, char*);
 | 
				
			||||||
 | 
					SECTNUM adfNameToEntryBlk(struct Volume *vol, int32_t ht[], char* name, 
 | 
				
			||||||
 | 
					    struct bEntryBlock *entry, SECTNUM *);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					PREFIX void printEntry(struct Entry* entry);
 | 
				
			||||||
 | 
					void adfFreeDirList(struct List* list);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* ADF_DIR_H */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										454
									
								
								dep/adflib/src/adf_disk.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										454
									
								
								dep/adflib/src/adf_disk.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,454 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *  ADF Library. (C) 1997-2002 Laurent Clevy
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  adf_disk.c
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  $Id$
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * logical disk/volume code
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  This file is part of ADFLib.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  ADFLib is free software; you can redistribute it and/or modify
 | 
				
			||||||
 | 
					 *  it under the terms of the GNU General Public License as published by
 | 
				
			||||||
 | 
					 *  the Free Software Foundation; either version 2 of the License, or
 | 
				
			||||||
 | 
					 *  (at your option) any later version.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  ADFLib is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
					 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
					 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
				
			||||||
 | 
					 *  GNU General Public License for more details.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  You should have received a copy of the GNU General Public License
 | 
				
			||||||
 | 
					 *  along with Foobar; if not, write to the Free Software
 | 
				
			||||||
 | 
					 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <limits.h>
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "adf_str.h"
 | 
				
			||||||
 | 
					#include "adf_disk.h"
 | 
				
			||||||
 | 
					#include "adf_raw.h"
 | 
				
			||||||
 | 
					#include "adf_hd.h"
 | 
				
			||||||
 | 
					#include "adf_bitm.h"
 | 
				
			||||||
 | 
					#include "adf_util.h"
 | 
				
			||||||
 | 
					#include "adf_nativ.h"
 | 
				
			||||||
 | 
					#include "adf_dump.h"
 | 
				
			||||||
 | 
					#include "adf_err.h"
 | 
				
			||||||
 | 
					#include "adf_cache.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern struct Env adfEnv;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					uint32_t bitMask[32] = { 
 | 
				
			||||||
 | 
					    0x1, 0x2, 0x4, 0x8,
 | 
				
			||||||
 | 
						0x10, 0x20, 0x40, 0x80,
 | 
				
			||||||
 | 
					    0x100, 0x200, 0x400, 0x800,
 | 
				
			||||||
 | 
						0x1000, 0x2000, 0x4000, 0x8000,
 | 
				
			||||||
 | 
						0x10000, 0x20000, 0x40000, 0x80000,
 | 
				
			||||||
 | 
						0x100000, 0x200000, 0x400000, 0x800000,
 | 
				
			||||||
 | 
						0x1000000, 0x2000000, 0x4000000, 0x8000000,
 | 
				
			||||||
 | 
						0x10000000, 0x20000000, 0x40000000, 0x80000000 };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					RETCODE adfInstallBootBlock(struct Volume *vol, uint8_t* code)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int i;
 | 
				
			||||||
 | 
					    struct bBootBlock boot;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (vol->dev->devType!=DEVTYPE_FLOPDD && vol->dev->devType!=DEVTYPE_FLOPHD)
 | 
				
			||||||
 | 
					        return RC_ERROR;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (adfReadBootBlock(vol, &boot)!=RC_OK)
 | 
				
			||||||
 | 
					        return RC_ERROR;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    boot.rootBlock = 880;
 | 
				
			||||||
 | 
					    for(i=0; i<1024-12; i++)         /* bootcode */
 | 
				
			||||||
 | 
					        boot.data[i] = code[i+12];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (adfWriteBootBlock(vol, &boot)!=RC_OK)
 | 
				
			||||||
 | 
							return RC_ERROR;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						vol->bootCode = TRUE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return RC_OK;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * isSectNumValid
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					BOOL isSectNumValid(struct Volume *vol, SECTNUM nSect)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    return( 0<=nSect && nSect<=(vol->lastBlock - vol->firstBlock) );
 | 
				
			||||||
 | 
					}	
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * adfVolumeInfo
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void adfVolumeInfo(struct Volume *vol)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct bRootBlock root;
 | 
				
			||||||
 | 
						char diskName[35];
 | 
				
			||||||
 | 
						int days,month,year;
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						if (adfReadRootBlock(vol, vol->rootBlock, &root)!=RC_OK)
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						memset(diskName, 0, 35);
 | 
				
			||||||
 | 
						memcpy(diskName, root.diskName, root.nameLen);
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						printf ("Name : %-30s\n",vol->volName);
 | 
				
			||||||
 | 
						printf ("Type : ");
 | 
				
			||||||
 | 
						switch(vol->dev->devType) {
 | 
				
			||||||
 | 
							case DEVTYPE_FLOPDD:
 | 
				
			||||||
 | 
								printf ("Floppy Double Density : 880 KBytes\n");
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case DEVTYPE_FLOPHD:
 | 
				
			||||||
 | 
								printf ("Floppy High Density : 1760 KBytes\n");
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case DEVTYPE_HARDDISK:
 | 
				
			||||||
 | 
								printf ("Hard Disk partition : %3.1f KBytes\n", 
 | 
				
			||||||
 | 
									(vol->lastBlock - vol->firstBlock +1) * 512.0/1024.0);
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case DEVTYPE_HARDFILE:
 | 
				
			||||||
 | 
								printf ("HardFile : %3.1f KBytes\n", 
 | 
				
			||||||
 | 
									(vol->lastBlock - vol->firstBlock +1) * 512.0/1024.0);
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							default:
 | 
				
			||||||
 | 
								printf ("Unknown devType!\n");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						printf ("Filesystem : ");
 | 
				
			||||||
 | 
						printf("%s ",isFFS(vol->dosType) ? "FFS" : "OFS");
 | 
				
			||||||
 | 
						if (isINTL(vol->dosType))
 | 
				
			||||||
 | 
							printf ("INTL ");
 | 
				
			||||||
 | 
						if (isDIRCACHE(vol->dosType))
 | 
				
			||||||
 | 
							printf ("DIRCACHE ");
 | 
				
			||||||
 | 
						putchar('\n');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    printf("Free blocks = %d\n", adfCountFreeBlocks(vol));
 | 
				
			||||||
 | 
					    if (vol->readOnly)
 | 
				
			||||||
 | 
					        printf("Read only\n");
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					        printf("Read/Write\n");
 | 
				
			||||||
 | 
					 	
 | 
				
			||||||
 | 
					    /* created */
 | 
				
			||||||
 | 
						adfDays2Date(root.coDays, &year, &month, &days);
 | 
				
			||||||
 | 
					    printf ("created %d/%02d/%02d %d:%02d:%02d\n",days,month,year,
 | 
				
			||||||
 | 
						    root.coMins/60,root.coMins%60,root.coTicks/50);	
 | 
				
			||||||
 | 
						adfDays2Date(root.days, &year, &month, &days);
 | 
				
			||||||
 | 
					    printf ("last access %d/%02d/%02d %d:%02d:%02d,   ",days,month,year,
 | 
				
			||||||
 | 
						    root.mins/60,root.mins%60,root.ticks/50);	
 | 
				
			||||||
 | 
						adfDays2Date(root.cDays, &year, &month, &days);
 | 
				
			||||||
 | 
					    printf ("%d/%02d/%02d %d:%02d:%02d\n",days,month,year,
 | 
				
			||||||
 | 
						    root.cMins/60,root.cMins%60,root.cTicks/50);	
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * adfMount
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					struct Volume* adfMount( struct Device *dev, int nPart, BOOL readOnly )
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int32_t nBlock;
 | 
				
			||||||
 | 
					    struct bRootBlock root;
 | 
				
			||||||
 | 
						struct bBootBlock boot;
 | 
				
			||||||
 | 
						struct Volume* vol;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (dev==NULL || nPart >= dev->nVol) {
 | 
				
			||||||
 | 
					        (*adfEnv.eFct)("adfMount : invalid parameter(s)");
 | 
				
			||||||
 | 
					        return NULL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    vol = dev->volList[nPart];
 | 
				
			||||||
 | 
						vol->dev = dev;
 | 
				
			||||||
 | 
					    vol->mounted = TRUE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*printf("first=%ld last=%ld root=%ld\n",vol->firstBlock,
 | 
				
			||||||
 | 
					 vol->lastBlock, vol->rootBlock);
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					    if (adfReadBootBlock(vol, &boot)!=RC_OK) {
 | 
				
			||||||
 | 
					        (*adfEnv.wFct)("adfMount : BootBlock invalid");
 | 
				
			||||||
 | 
					        return NULL;
 | 
				
			||||||
 | 
					    }       
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
						vol->dosType = boot.dosType[3];
 | 
				
			||||||
 | 
						if (isFFS(vol->dosType))
 | 
				
			||||||
 | 
							vol->datablockSize=512;
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							vol->datablockSize=488;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (dev->readOnly /*|| isDIRCACHE(vol->dosType)*/)
 | 
				
			||||||
 | 
					       vol->readOnly = TRUE;
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					       vol->readOnly = readOnly;
 | 
				
			||||||
 | 
						   	
 | 
				
			||||||
 | 
						if (adfReadRootBlock(vol, vol->rootBlock, &root)!=RC_OK) {
 | 
				
			||||||
 | 
					        (*adfEnv.wFct)("adfMount : RootBlock invalid");       
 | 
				
			||||||
 | 
					        return NULL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    nBlock = vol->lastBlock - vol->firstBlock +1 - 2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						adfReadBitmap( vol, nBlock, &root );
 | 
				
			||||||
 | 
					    vol->curDirPtr = vol->rootBlock;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*printf("blockSize=%d\n",vol->blockSize);*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return( vol );
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					*
 | 
				
			||||||
 | 
					* adfUnMount
 | 
				
			||||||
 | 
					*
 | 
				
			||||||
 | 
					* free bitmap structures
 | 
				
			||||||
 | 
					* free current dir
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					void adfUnMount(struct Volume *vol)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (!vol) {
 | 
				
			||||||
 | 
							(*adfEnv.eFct)("adfUnMount : vol is null");
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    adfFreeBitmap(vol);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    vol->mounted = FALSE;
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * adfCreateVol
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					struct Volume* adfCreateVol( struct Device* dev, int32_t start, int32_t len, 
 | 
				
			||||||
 | 
					    char* volName, int volType )
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    struct bBootBlock boot;
 | 
				
			||||||
 | 
					    struct bRootBlock root;
 | 
				
			||||||
 | 
					/*    struct bDirCacheBlock dirc;*/
 | 
				
			||||||
 | 
					    SECTNUM blkList[2];
 | 
				
			||||||
 | 
					    struct Volume* vol;
 | 
				
			||||||
 | 
					    int nlen;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (adfEnv.useProgressBar)
 | 
				
			||||||
 | 
					        (*adfEnv.progressBar)(0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    vol=(struct Volume*)malloc(sizeof(struct Volume));
 | 
				
			||||||
 | 
					    if (!vol) { 
 | 
				
			||||||
 | 
							(*adfEnv.eFct)("adfCreateVol : malloc vol");
 | 
				
			||||||
 | 
					        return NULL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
					    vol->dev = dev;
 | 
				
			||||||
 | 
					    vol->firstBlock = (dev->heads * dev->sectors)*start;
 | 
				
			||||||
 | 
					    vol->lastBlock = (vol->firstBlock + (dev->heads * dev->sectors)*len)-1;
 | 
				
			||||||
 | 
					    vol->rootBlock = (vol->lastBlock - vol->firstBlock+1)/2;
 | 
				
			||||||
 | 
					/*printf("first=%ld last=%ld root=%ld\n",vol->firstBlock,
 | 
				
			||||||
 | 
					 vol->lastBlock, vol->rootBlock);
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					    vol->curDirPtr = vol->rootBlock;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    vol->readOnly = dev->readOnly;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    vol->mounted = TRUE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    nlen = min( MAXNAMELEN, strlen(volName) );
 | 
				
			||||||
 | 
					    vol->volName = (char*)malloc(nlen+1);
 | 
				
			||||||
 | 
					    if (!vol->volName) { 
 | 
				
			||||||
 | 
							(*adfEnv.eFct)("adfCreateVol : malloc");
 | 
				
			||||||
 | 
							free(vol); return NULL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    memcpy(vol->volName, volName, nlen);
 | 
				
			||||||
 | 
					    vol->volName[nlen]='\0';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (adfEnv.useProgressBar)
 | 
				
			||||||
 | 
					        (*adfEnv.progressBar)(25);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    memset(&boot, 0, 1024);
 | 
				
			||||||
 | 
					    boot.dosType[3] = volType;
 | 
				
			||||||
 | 
					/*printf("first=%d last=%d\n", vol->firstBlock, vol->lastBlock);
 | 
				
			||||||
 | 
					printf("name=%s root=%d\n", vol->volName, vol->rootBlock);
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					    if (adfWriteBootBlock(vol, &boot)!=RC_OK) {
 | 
				
			||||||
 | 
					        free(vol->volName); free(vol);
 | 
				
			||||||
 | 
					        return NULL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (adfEnv.useProgressBar)
 | 
				
			||||||
 | 
					        (*adfEnv.progressBar)(20);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (adfCreateBitmap( vol )!=RC_OK) {
 | 
				
			||||||
 | 
					        free(vol->volName); free(vol);
 | 
				
			||||||
 | 
					        return NULL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (adfEnv.useProgressBar)
 | 
				
			||||||
 | 
					        (*adfEnv.progressBar)(40);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*for(i=0; i<127; i++)
 | 
				
			||||||
 | 
					printf("%3d %x, ",i,vol->bitmapTable[0]->map[i]);
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					    if ( isDIRCACHE(volType) )
 | 
				
			||||||
 | 
					        adfGetFreeBlocks( vol, 2, blkList );
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					        adfGetFreeBlocks( vol, 1, blkList );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*printf("[0]=%d [1]=%d\n",blkList[0],blkList[1]);*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    memset(&root, 0, LOGICAL_BLOCK_SIZE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (strlen(volName)>MAXNAMELEN)
 | 
				
			||||||
 | 
					        volName[MAXNAMELEN]='\0';
 | 
				
			||||||
 | 
					    root.nameLen = strlen(volName);
 | 
				
			||||||
 | 
					    memcpy(root.diskName,volName,root.nameLen);
 | 
				
			||||||
 | 
					    adfTime2AmigaTime(adfGiveCurrentTime(),&(root.coDays),&(root.coMins),&(root.coTicks));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* dircache block */
 | 
				
			||||||
 | 
					    if ( isDIRCACHE(volType) ) {
 | 
				
			||||||
 | 
					        root.extension = 0L;
 | 
				
			||||||
 | 
					        root.secType = ST_ROOT; /* needed by adfCreateEmptyCache() */
 | 
				
			||||||
 | 
					        adfCreateEmptyCache(vol, (struct bEntryBlock*)&root, blkList[1]);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (adfEnv.useProgressBar)
 | 
				
			||||||
 | 
					        (*adfEnv.progressBar)(60);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (adfWriteRootBlock(vol, blkList[0], &root)!=RC_OK) {
 | 
				
			||||||
 | 
					        free(vol->volName); free(vol);
 | 
				
			||||||
 | 
					        return NULL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   /* fills root->bmPages[] and writes filled bitmapExtBlocks */
 | 
				
			||||||
 | 
					    if (adfWriteNewBitmap(vol)!=RC_OK)
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (adfEnv.useProgressBar)
 | 
				
			||||||
 | 
					        (*adfEnv.progressBar)(80);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (adfUpdateBitmap(vol)!=RC_OK)
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (adfEnv.useProgressBar)
 | 
				
			||||||
 | 
					        (*adfEnv.progressBar)(100);
 | 
				
			||||||
 | 
					/*printf("free blocks %ld\n",adfCountFreeBlocks(vol));*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* will be managed by adfMount() later */
 | 
				
			||||||
 | 
					    adfFreeBitmap(vol);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    vol->mounted = FALSE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return(vol);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*-----*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * adfReadBlock
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * read logical block
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					RETCODE
 | 
				
			||||||
 | 
					adfReadBlock(struct Volume* vol, int32_t nSect, uint8_t* buf)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  /*    char strBuf[80];*/
 | 
				
			||||||
 | 
					    int32_t pSect;
 | 
				
			||||||
 | 
					    struct nativeFunctions *nFct;
 | 
				
			||||||
 | 
					    RETCODE rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!vol->mounted) {
 | 
				
			||||||
 | 
					        (*adfEnv.eFct)("the volume isn't mounted, adfReadBlock not possible");
 | 
				
			||||||
 | 
					        return RC_ERROR;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* translate logical sect to physical sect */
 | 
				
			||||||
 | 
					    pSect = nSect+vol->firstBlock;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (adfEnv.useRWAccess)
 | 
				
			||||||
 | 
					        (*adfEnv.rwhAccess)(pSect,nSect,FALSE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*printf("psect=%ld nsect=%ld\n",pSect,nSect);*/
 | 
				
			||||||
 | 
					/*    sprintf(strBuf,"ReadBlock : accessing logical block #%ld", nSect);	
 | 
				
			||||||
 | 
					    (*adfEnv.vFct)(strBuf);
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					    if (pSect<vol->firstBlock || pSect>vol->lastBlock) {
 | 
				
			||||||
 | 
					        (*adfEnv.wFct)("adfReadBlock : nSect out of range");
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					/*printf("pSect R =%ld\n",pSect);*/
 | 
				
			||||||
 | 
					    nFct = adfEnv.nativeFct;
 | 
				
			||||||
 | 
					    if (vol->dev->isNativeDev)
 | 
				
			||||||
 | 
					        rc = (*nFct->adfNativeReadSector)(vol->dev, pSect, 512, buf);
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					        rc = adfReadDumpSector(vol->dev, pSect, 512, buf);
 | 
				
			||||||
 | 
					/*printf("rc=%ld\n",rc);*/
 | 
				
			||||||
 | 
					    if (rc!=RC_OK)
 | 
				
			||||||
 | 
					        return RC_ERROR;
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					        return RC_OK;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * adfWriteBlock
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					RETCODE adfWriteBlock(struct Volume* vol, int32_t nSect, uint8_t *buf)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int32_t pSect;
 | 
				
			||||||
 | 
					    struct nativeFunctions *nFct;
 | 
				
			||||||
 | 
					    RETCODE rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!vol->mounted) {
 | 
				
			||||||
 | 
					        (*adfEnv.eFct)("the volume isn't mounted, adfWriteBlock not possible");
 | 
				
			||||||
 | 
					        return RC_ERROR;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (vol->readOnly) {
 | 
				
			||||||
 | 
					        (*adfEnv.wFct)("adfWriteBlock : can't write block, read only volume");
 | 
				
			||||||
 | 
					        return RC_ERROR;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pSect = nSect+vol->firstBlock;
 | 
				
			||||||
 | 
					/*printf("write nsect=%ld psect=%ld\n",nSect,pSect);*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (adfEnv.useRWAccess)
 | 
				
			||||||
 | 
					        (*adfEnv.rwhAccess)(pSect,nSect,TRUE);
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					    if (pSect<vol->firstBlock || pSect>vol->lastBlock) {
 | 
				
			||||||
 | 
					        (*adfEnv.wFct)("adfWriteBlock : nSect out of range");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    nFct = adfEnv.nativeFct;
 | 
				
			||||||
 | 
					/*printf("nativ=%d\n",vol->dev->isNativeDev);*/
 | 
				
			||||||
 | 
					    if (vol->dev->isNativeDev)
 | 
				
			||||||
 | 
					        rc = (*nFct->adfNativeWriteSector)(vol->dev, pSect, 512, buf);
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					        rc = adfWriteDumpSector(vol->dev, pSect, 512, buf);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (rc!=RC_OK)
 | 
				
			||||||
 | 
					        return RC_ERROR;
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					        return RC_OK;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*#######################################################################################*/
 | 
				
			||||||
							
								
								
									
										52
									
								
								dep/adflib/src/adf_disk.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								dep/adflib/src/adf_disk.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,52 @@
 | 
				
			|||||||
 | 
					#ifndef _ADF_DISK_H
 | 
				
			||||||
 | 
					#define _ADF_DISK_H 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *  ADF Library. (C) 1997-2002 Laurent Clevy
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  adf_disk.h
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  $Id$
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  This file is part of ADFLib.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  ADFLib is free software; you can redistribute it and/or modify
 | 
				
			||||||
 | 
					 *  it under the terms of the GNU General Public License as published by
 | 
				
			||||||
 | 
					 *  the Free Software Foundation; either version 2 of the License, or
 | 
				
			||||||
 | 
					 *  (at your option) any later version.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  ADFLib is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
					 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
					 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
				
			||||||
 | 
					 *  GNU General Public License for more details.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  You should have received a copy of the GNU General Public License
 | 
				
			||||||
 | 
					 *  along with Foobar; if not, write to the Free Software
 | 
				
			||||||
 | 
					 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "prefix.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "adf_str.h"
 | 
				
			||||||
 | 
					#include "adf_defs.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					PREFIX RETCODE adfInstallBootBlock(struct Volume *vol,uint8_t*);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					PREFIX BOOL isSectNumValid(struct Volume *vol, SECTNUM nSect);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					PREFIX struct Volume* adfMount( struct Device *dev, int nPart, BOOL readOnly );
 | 
				
			||||||
 | 
					PREFIX void adfUnMount(struct Volume *vol);
 | 
				
			||||||
 | 
					PREFIX void adfVolumeInfo(struct Volume *vol);
 | 
				
			||||||
 | 
					struct Volume* adfCreateVol( struct Device* dev, int32_t start, int32_t len, 
 | 
				
			||||||
 | 
					    char* volName, int volType );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*void adfReadBitmap(struct Volume* , int32_t nBlock, struct bRootBlock* root);
 | 
				
			||||||
 | 
					void adfUpdateBitmap(struct Volume*);
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					PREFIX RETCODE adfReadBlock(struct Volume* , int32_t nSect, uint8_t* buf);
 | 
				
			||||||
 | 
					PREFIX RETCODE adfWriteBlock(struct Volume* , int32_t nSect, uint8_t* buf);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* _ADF_DISK_H */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*##########################################################################*/
 | 
				
			||||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user