mirror of
				https://github.com/davidgiven/fluxengine.git
				synced 2025-10-24 11:11:02 -07:00 
			
		
		
		
	Compare commits
	
		
			4 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | c8fd984c5c | ||
|  | 14ed696993 | ||
|  | 047521475f | ||
|  | d906d92016 | 
| @@ -1058,27 +1058,27 @@ | ||||
| <CyGuid_ebc4f06d-207f-49c2-a540-72acf4adabc0 type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtFolderSerialize" version="3"> | ||||
| <CyGuid_2f73275c-45bf-46ba-b3b1-00a2fe0c8dd8 type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtBaseContainerSerialize" version="1"> | ||||
| <CyGuid_31768f72-0253-412b-af77-e7dba74d1330 type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtItemSerialize" version="2" name="DSKCHG" persistent=""> | ||||
| <Hidden v="False" /> | ||||
| <Hidden v="True" /> | ||||
| </CyGuid_31768f72-0253-412b-af77-e7dba74d1330> | ||||
| <CyGuid_0820c2e7-528d-4137-9a08-97257b946089 type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtItemListSerialize" version="2"> | ||||
| <dependencies> | ||||
| <CyGuid_8b8ab257-35d3-4473-b57b-36315200b38b type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtFileSerialize" version="3" xml_contents_version="1"> | ||||
| <CyGuid_31768f72-0253-412b-af77-e7dba74d1330 type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtItemSerialize" version="2" name="DSKCHG_aliases.h" persistent="Generated_Source\PSoC5\DSKCHG_aliases.h"> | ||||
| <Hidden v="False" /> | ||||
| <Hidden v="True" /> | ||||
| </CyGuid_31768f72-0253-412b-af77-e7dba74d1330> | ||||
| <build_action v="HEADER;;;;" /> | ||||
| <PropertyDeltas /> | ||||
| </CyGuid_8b8ab257-35d3-4473-b57b-36315200b38b> | ||||
| <CyGuid_8b8ab257-35d3-4473-b57b-36315200b38b type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtFileSerialize" version="3" xml_contents_version="1"> | ||||
| <CyGuid_31768f72-0253-412b-af77-e7dba74d1330 type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtItemSerialize" version="2" name="DSKCHG.c" persistent="Generated_Source\PSoC5\DSKCHG.c"> | ||||
| <Hidden v="False" /> | ||||
| <Hidden v="True" /> | ||||
| </CyGuid_31768f72-0253-412b-af77-e7dba74d1330> | ||||
| <build_action v="SOURCE_C;CortexM3;;;" /> | ||||
| <PropertyDeltas /> | ||||
| </CyGuid_8b8ab257-35d3-4473-b57b-36315200b38b> | ||||
| <CyGuid_8b8ab257-35d3-4473-b57b-36315200b38b type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtFileSerialize" version="3" xml_contents_version="1"> | ||||
| <CyGuid_31768f72-0253-412b-af77-e7dba74d1330 type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtItemSerialize" version="2" name="DSKCHG.h" persistent="Generated_Source\PSoC5\DSKCHG.h"> | ||||
| <Hidden v="False" /> | ||||
| <Hidden v="True" /> | ||||
| </CyGuid_31768f72-0253-412b-af77-e7dba74d1330> | ||||
| <build_action v="HEADER;;;;" /> | ||||
| <PropertyDeltas /> | ||||
| @@ -3282,6 +3282,39 @@ | ||||
| </CyGuid_2f73275c-45bf-46ba-b3b1-00a2fe0c8dd8> | ||||
| <filters /> | ||||
| </CyGuid_ebc4f06d-207f-49c2-a540-72acf4adabc0> | ||||
| <CyGuid_ebc4f06d-207f-49c2-a540-72acf4adabc0 type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtFolderSerialize" version="3"> | ||||
| <CyGuid_2f73275c-45bf-46ba-b3b1-00a2fe0c8dd8 type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtBaseContainerSerialize" version="1"> | ||||
| <CyGuid_31768f72-0253-412b-af77-e7dba74d1330 type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtItemSerialize" version="2" name="READY" persistent=""> | ||||
| <Hidden v="False" /> | ||||
| </CyGuid_31768f72-0253-412b-af77-e7dba74d1330> | ||||
| <CyGuid_0820c2e7-528d-4137-9a08-97257b946089 type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtItemListSerialize" version="2"> | ||||
| <dependencies> | ||||
| <CyGuid_8b8ab257-35d3-4473-b57b-36315200b38b type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtFileSerialize" version="3" xml_contents_version="1"> | ||||
| <CyGuid_31768f72-0253-412b-af77-e7dba74d1330 type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtItemSerialize" version="2" name="READY_aliases.h" persistent="Generated_Source\PSoC5\READY_aliases.h"> | ||||
| <Hidden v="False" /> | ||||
| </CyGuid_31768f72-0253-412b-af77-e7dba74d1330> | ||||
| <build_action v="HEADER;;;;" /> | ||||
| <PropertyDeltas /> | ||||
| </CyGuid_8b8ab257-35d3-4473-b57b-36315200b38b> | ||||
| <CyGuid_8b8ab257-35d3-4473-b57b-36315200b38b type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtFileSerialize" version="3" xml_contents_version="1"> | ||||
| <CyGuid_31768f72-0253-412b-af77-e7dba74d1330 type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtItemSerialize" version="2" name="READY.c" persistent="Generated_Source\PSoC5\READY.c"> | ||||
| <Hidden v="False" /> | ||||
| </CyGuid_31768f72-0253-412b-af77-e7dba74d1330> | ||||
| <build_action v="SOURCE_C;CortexM3;;;" /> | ||||
| <PropertyDeltas /> | ||||
| </CyGuid_8b8ab257-35d3-4473-b57b-36315200b38b> | ||||
| <CyGuid_8b8ab257-35d3-4473-b57b-36315200b38b type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtFileSerialize" version="3" xml_contents_version="1"> | ||||
| <CyGuid_31768f72-0253-412b-af77-e7dba74d1330 type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtItemSerialize" version="2" name="READY.h" persistent="Generated_Source\PSoC5\READY.h"> | ||||
| <Hidden v="False" /> | ||||
| </CyGuid_31768f72-0253-412b-af77-e7dba74d1330> | ||||
| <build_action v="HEADER;;;;" /> | ||||
| <PropertyDeltas /> | ||||
| </CyGuid_8b8ab257-35d3-4473-b57b-36315200b38b> | ||||
| </dependencies> | ||||
| </CyGuid_0820c2e7-528d-4137-9a08-97257b946089> | ||||
| </CyGuid_2f73275c-45bf-46ba-b3b1-00a2fe0c8dd8> | ||||
| <filters /> | ||||
| </CyGuid_ebc4f06d-207f-49c2-a540-72acf4adabc0> | ||||
| </dependencies> | ||||
| </CyGuid_0820c2e7-528d-4137-9a08-97257b946089> | ||||
| </CyGuid_2f73275c-45bf-46ba-b3b1-00a2fe0c8dd8> | ||||
|   | ||||
										
											Binary file not shown.
										
									
								
							| @@ -12,7 +12,7 @@ | ||||
| #define STEP_SETTLING_TIME 50 /* ms */ | ||||
|  | ||||
| #define DISKSTATUS_WPT    1 | ||||
| #define DISKSTATUS_DSKCHG 2 | ||||
| #define DISKSTATUS_READY  2 /* Only used on QuickDisk drives */ | ||||
|  | ||||
| #define STEP_TOWARDS0 1 | ||||
| #define STEP_AWAYFROM0 0 | ||||
| @@ -37,6 +37,7 @@ static uint8_t dma_channel; | ||||
| static volatile int dma_writing_to_td = 0; | ||||
| static volatile int dma_reading_from_td = 0; | ||||
| static volatile bool dma_underrun = false; | ||||
| static crunch_state_t cs = {}; | ||||
|  | ||||
| #define DECLARE_REPLY_FRAME(STRUCT, TYPE) \ | ||||
|     STRUCT r = {.f = { .type = TYPE, .size = sizeof(STRUCT) }} | ||||
| @@ -269,13 +270,8 @@ static void init_capture_dma(void) | ||||
|     }     | ||||
| } | ||||
|  | ||||
| static void cmd_read(struct read_frame* f) | ||||
| static void init_capture(void) | ||||
| { | ||||
|     SIDE_REG_Write(f->side); | ||||
|     seek_to(current_track); | ||||
|      | ||||
|     /* Do slow setup *before* we go into the real-time bit. */ | ||||
|      | ||||
|     SAMPLER_CONTROL_Write(1); /* reset */ | ||||
|      | ||||
|     { | ||||
| @@ -288,38 +284,103 @@ static void cmd_read(struct read_frame* f) | ||||
|      | ||||
|     wait_until_writeable(FLUXENGINE_DATA_IN_EP_NUM); | ||||
|     init_capture_dma(); | ||||
| } | ||||
|  | ||||
|     /* Wait for the beginning of a rotation. */ | ||||
|          | ||||
|     print("wait"); | ||||
|     index_irq = false; | ||||
|     while (!index_irq) | ||||
|         ; | ||||
|     index_irq = false; | ||||
|      | ||||
|     crunch_state_t cs = {}; | ||||
| static void start_capture(void) | ||||
| { | ||||
|     memset(&cs, 0, sizeof(crunch_state_t)); | ||||
|     cs.outputptr = usb_buffer; | ||||
|     cs.outputlen = BUFFER_SIZE; | ||||
|      | ||||
|     dma_writing_to_td = 0; | ||||
|     dma_reading_from_td = -1; | ||||
|     dma_underrun = false; | ||||
|     int count = 0; | ||||
|     SAMPLER_CONTROL_Write(0); /* !reset */ | ||||
|     CAPTURE_CONTROL_Write(1); | ||||
|     CyDmaChSetInitialTd(dma_channel, td[dma_writing_to_td]); | ||||
|     CyDmaClearPendingDrq(dma_channel); | ||||
|     CyDmaChEnable(dma_channel, 1); | ||||
|  | ||||
|     /* Wait for the first DMA transfer to complete, after which we can start the | ||||
|      * USB transfer. */ | ||||
|     /* Wait for the first DMA transfer to complete, after which we can start | ||||
|      * the USB transfer. */ | ||||
|  | ||||
|     while ((dma_writing_to_td == 0) && !index_irq) | ||||
|     while (dma_writing_to_td == 0) | ||||
|         ; | ||||
|     dma_reading_from_td = 0; | ||||
| } | ||||
|  | ||||
| /* returns true if capture is aborted */ | ||||
| static bool do_capture_chunk(void) | ||||
| { | ||||
|     /* Wait for the next block to be read. */ | ||||
|     while (dma_reading_from_td == dma_writing_to_td) | ||||
|     { | ||||
|         /* On an underrun, give up immediately. */ | ||||
|         if (dma_underrun) | ||||
|             return true; | ||||
|     } | ||||
|  | ||||
|     uint8_t dma_buffer_usage = 0; | ||||
|     while (dma_buffer_usage < BUFFER_SIZE) | ||||
|     { | ||||
|         cs.inputptr = dma_buffer[dma_reading_from_td] + dma_buffer_usage; | ||||
|         cs.inputlen = BUFFER_SIZE - dma_buffer_usage; | ||||
|         crunch(&cs); | ||||
|         dma_buffer_usage += BUFFER_SIZE - cs.inputlen; | ||||
|         if (cs.outputlen == 0) | ||||
|         { | ||||
|             while (USBFS_GetEPState(FLUXENGINE_DATA_IN_EP_NUM) != USBFS_IN_BUFFER_EMPTY) | ||||
|             { | ||||
|                 if (dma_underrun) | ||||
|                     return true; | ||||
|             } | ||||
|  | ||||
|             USBFS_LoadInEP(FLUXENGINE_DATA_IN_EP_NUM, usb_buffer, BUFFER_SIZE); | ||||
|             cs.outputptr = usb_buffer; | ||||
|             cs.outputlen = BUFFER_SIZE; | ||||
|         } | ||||
|     } | ||||
|     dma_reading_from_td = NEXT_BUFFER(dma_reading_from_td); | ||||
|      | ||||
|     return false; | ||||
| } | ||||
|  | ||||
| static void stop_capture(void) | ||||
| { | ||||
|     CAPTURE_CONTROL_Write(0); | ||||
|     CyDmaChSetRequest(dma_channel, CY_DMA_CPU_TERM_CHAIN); | ||||
|     while (CyDmaChGetRequest(dma_channel)) | ||||
|         ; | ||||
|  | ||||
|     donecrunch(&cs); | ||||
|     wait_until_writeable(FLUXENGINE_DATA_IN_EP_NUM); | ||||
|     if (cs.outputlen != BUFFER_SIZE) | ||||
|         USBFS_LoadInEP(FLUXENGINE_DATA_IN_EP_NUM, usb_buffer, BUFFER_SIZE-cs.outputlen); | ||||
|     if ((cs.outputlen == BUFFER_SIZE) || (cs.outputlen == 0)) | ||||
|         USBFS_LoadInEP(FLUXENGINE_DATA_IN_EP_NUM, NULL, 0); | ||||
|     wait_until_writeable(FLUXENGINE_DATA_IN_EP_NUM); | ||||
|     deinit_dma(); | ||||
| } | ||||
|  | ||||
| static void cmd_read(struct read_frame* f) | ||||
| { | ||||
|     SIDE_REG_Write(f->side); | ||||
|     seek_to(current_track); | ||||
|      | ||||
|     /* Do slow setup *before* we go into the real-time bit. */ | ||||
|      | ||||
|     init_capture(); | ||||
|      | ||||
|     /* Wait for the beginning of a rotation. */ | ||||
|          | ||||
|     index_irq = false; | ||||
|     while (!index_irq) | ||||
|         ; | ||||
|     index_irq = false; | ||||
|      | ||||
|     /* Start transferring. */ | ||||
|  | ||||
|     start_capture(); | ||||
|     int revolutions = f->revolutions; | ||||
|     while (!dma_underrun) | ||||
|     { | ||||
| @@ -333,65 +394,77 @@ static void cmd_read(struct read_frame* f) | ||||
|             if (revolutions == 0) | ||||
|                 break; | ||||
|         } | ||||
|          | ||||
|         /* Wait for the next block to be read. */ | ||||
|         while (dma_reading_from_td == dma_writing_to_td) | ||||
|         { | ||||
|             /* On an underrun, give up immediately. */ | ||||
|             if (dma_underrun) | ||||
|                 goto abort; | ||||
|         } | ||||
|  | ||||
|         uint8_t dma_buffer_usage = 0; | ||||
|         while (dma_buffer_usage < BUFFER_SIZE) | ||||
|         { | ||||
|             cs.inputptr = dma_buffer[dma_reading_from_td] + dma_buffer_usage; | ||||
|             cs.inputlen = BUFFER_SIZE - dma_buffer_usage; | ||||
|             crunch(&cs); | ||||
|             dma_buffer_usage += BUFFER_SIZE - cs.inputlen; | ||||
|             count++; | ||||
|             if (cs.outputlen == 0) | ||||
|             { | ||||
|                 while (USBFS_GetEPState(FLUXENGINE_DATA_IN_EP_NUM) != USBFS_IN_BUFFER_EMPTY) | ||||
|                 { | ||||
|                     if (index_irq || dma_underrun) | ||||
|                         goto abort; | ||||
|                 } | ||||
|  | ||||
|                 USBFS_LoadInEP(FLUXENGINE_DATA_IN_EP_NUM, usb_buffer, BUFFER_SIZE); | ||||
|                 cs.outputptr = usb_buffer; | ||||
|                 cs.outputlen = BUFFER_SIZE; | ||||
|             } | ||||
|         } | ||||
|         dma_reading_from_td = NEXT_BUFFER(dma_reading_from_td); | ||||
|         if (do_capture_chunk()) | ||||
|             goto abort; | ||||
|     } | ||||
| abort:; | ||||
|     CAPTURE_CONTROL_Write(0); | ||||
|     CyDmaChSetRequest(dma_channel, CY_DMA_CPU_TERM_CHAIN); | ||||
|     while (CyDmaChGetRequest(dma_channel)) | ||||
|         ; | ||||
|  | ||||
|     donecrunch(&cs); | ||||
|     wait_until_writeable(FLUXENGINE_DATA_IN_EP_NUM); | ||||
|     unsigned zz = cs.outputlen; | ||||
|     if (cs.outputlen != BUFFER_SIZE) | ||||
|         USBFS_LoadInEP(FLUXENGINE_DATA_IN_EP_NUM, usb_buffer, BUFFER_SIZE-cs.outputlen); | ||||
|     if ((cs.outputlen == BUFFER_SIZE) || (cs.outputlen == 0)) | ||||
|         USBFS_LoadInEP(FLUXENGINE_DATA_IN_EP_NUM, NULL, 0); | ||||
|     wait_until_writeable(FLUXENGINE_DATA_IN_EP_NUM); | ||||
|     deinit_dma(); | ||||
|     stop_capture(); | ||||
|  | ||||
|     if (dma_underrun) | ||||
|     { | ||||
|         print("underrun after %d packets"); | ||||
|         send_error(F_ERROR_UNDERRUN); | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         DECLARE_REPLY_FRAME(struct any_frame, F_FRAME_READ_REPLY); | ||||
|         send_reply(&r); | ||||
|     } | ||||
|     print("count=%d i=%d d=%d zz=%d", count, index_irq, dma_underrun, zz); | ||||
| } | ||||
|  | ||||
| static void cmd_read_qd(struct read_frame* f) | ||||
| { | ||||
|     SIDE_REG_Write(f->side); | ||||
|      | ||||
|     /* Do slow setup *before* we go into the real-time bit. */ | ||||
|      | ||||
|     init_capture(); | ||||
|      | ||||
|     /* Reset the drive. */ | ||||
|      | ||||
|     STEP_REG_Write(2); | ||||
|     CyDelay(10); /* ms */ | ||||
|     STEP_REG_Write(0); | ||||
|      | ||||
|     /* Motor on, and wait for ready. */ | ||||
|      | ||||
|     MOTOR_REG_Write(1); | ||||
|     while (!(DISKSTATUS_REG_Read() & DISKSTATUS_READY)) | ||||
|         ; | ||||
|      | ||||
|     /* Turning the motor off has no effect until the head hits the stop, | ||||
|      * at which point it'll stop automatically. */ | ||||
|      | ||||
|     MOTOR_REG_Write(0); | ||||
|      | ||||
|     /* Start transferring. */ | ||||
|  | ||||
|     start_capture(); | ||||
|     while (!dma_underrun) | ||||
|     { | ||||
|         CyWdtClear(); | ||||
|  | ||||
|         /* Have we reached the end? */ | ||||
|         if (!(DISKSTATUS_REG_Read() & DISKSTATUS_READY)) | ||||
|             break; | ||||
|  | ||||
|         if (do_capture_chunk()) | ||||
|             goto abort; | ||||
|     } | ||||
| abort:; | ||||
|     stop_capture(); | ||||
|  | ||||
|     /* Reset the drive again to ensure the motor stops. */ | ||||
|      | ||||
|     STEP_REG_Write(2); | ||||
|     CyDelay(10); /* ms */ | ||||
|     STEP_REG_Write(0); | ||||
|  | ||||
|     if (dma_underrun) | ||||
|         send_error(F_ERROR_UNDERRUN); | ||||
|     else | ||||
|     { | ||||
|         DECLARE_REPLY_FRAME(struct any_frame, F_FRAME_READ_QD_REPLY); | ||||
|         send_reply(&r); | ||||
|     } | ||||
| } | ||||
|  | ||||
| static void init_replay_dma(void) | ||||
| @@ -647,6 +720,10 @@ static void handle_command(void) | ||||
|             cmd_read((struct read_frame*) f); | ||||
|             break; | ||||
|          | ||||
|         case F_FRAME_READ_QD_CMD: | ||||
|             cmd_read_qd((struct read_frame*) f); | ||||
|             break; | ||||
|          | ||||
|         case F_FRAME_WRITE_CMD: | ||||
|             cmd_write((struct write_frame*) f); | ||||
|             break; | ||||
|   | ||||
| @@ -112,6 +112,7 @@ FluxSpec::FluxSpec(const DataSpec& spec) | ||||
|  | ||||
|         locations.clear(); | ||||
|  | ||||
|         quickdisk = spec.has("qd") && spec.at("qd").only(); | ||||
|         const auto& drives = spec.at("d").data; | ||||
|         if (drives.size() != 1) | ||||
|             Error() << "you must specify exactly one drive"; | ||||
| @@ -128,7 +129,7 @@ FluxSpec::FluxSpec(const DataSpec& spec) | ||||
|         for (const auto& e : spec.modifiers) | ||||
|         { | ||||
|             const auto name = e.second.name; | ||||
|             if ((name != "t") && (name != "s") && (name != "d")) | ||||
|             if ((name != "t") && (name != "s") && (name != "d") && (name != "qd")) | ||||
|                 Error() << fmt::format("unknown fluxspec modifier '{}'", name); | ||||
|         } | ||||
|     } | ||||
|   | ||||
| @@ -73,6 +73,7 @@ public: | ||||
|     std::string filename; | ||||
|     std::vector<Location> locations; | ||||
|     unsigned drive; | ||||
|     bool quickdisk : 1; | ||||
| }; | ||||
|  | ||||
| class ImageSpec | ||||
|   | ||||
| @@ -15,7 +15,12 @@ std::unique_ptr<FluxSource> FluxSource::create(const FluxSpec& spec) | ||||
|     const auto& filename = spec.filename; | ||||
|  | ||||
|     if (filename.empty()) | ||||
|         return createHardwareFluxSource(spec.drive); | ||||
|     { | ||||
|         if (spec.quickdisk) | ||||
|             return createQuickdiskFluxSource(spec.drive); | ||||
|         else | ||||
|             return createHardwareFluxSource(spec.drive); | ||||
|     } | ||||
|     else if (ends_with(filename, ".flux")) | ||||
|         return createSqliteFluxSource(filename); | ||||
|     else if (ends_with(filename, "/")) | ||||
|   | ||||
| @@ -4,6 +4,7 @@ | ||||
| #include "flags.h" | ||||
|  | ||||
| extern FlagGroup hardwareFluxSourceFlags; | ||||
| extern FlagGroup quickdiskFluxSourceFlags; | ||||
|  | ||||
| class Fluxmap; | ||||
| class FluxSpec; | ||||
| @@ -16,6 +17,7 @@ public: | ||||
| private: | ||||
|     static std::unique_ptr<FluxSource> createSqliteFluxSource(const std::string& filename); | ||||
|     static std::unique_ptr<FluxSource> createHardwareFluxSource(unsigned drive); | ||||
|     static std::unique_ptr<FluxSource> createQuickdiskFluxSource(unsigned drive); | ||||
|     static std::unique_ptr<FluxSource> createStreamFluxSource(const std::string& path); | ||||
|  | ||||
| public: | ||||
|   | ||||
							
								
								
									
										50
									
								
								lib/fluxsource/quickdiskfluxsource.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								lib/fluxsource/quickdiskfluxsource.cc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,50 @@ | ||||
| #include "globals.h" | ||||
| #include "flags.h" | ||||
| #include "fluxmap.h" | ||||
| #include "usb.h" | ||||
| #include "fluxsource/fluxsource.h" | ||||
|  | ||||
| FlagGroup quickdiskFluxSourceFlags; | ||||
|  | ||||
| class QuickdiskFluxSource : public FluxSource | ||||
| { | ||||
| public: | ||||
|     QuickdiskFluxSource(unsigned drive): | ||||
|         _drive(drive) | ||||
|     { | ||||
|     } | ||||
|  | ||||
|     ~QuickdiskFluxSource() | ||||
|     { | ||||
|     } | ||||
|  | ||||
| public: | ||||
|     std::unique_ptr<Fluxmap> readFlux(int track, int side) | ||||
|     { | ||||
|         usbSetDrive(_drive, false); | ||||
|         Bytes crunched = usbReadQD(side); | ||||
|         auto fluxmap = std::make_unique<Fluxmap>(); | ||||
|         fluxmap->appendBytes(crunched.uncrunch()); | ||||
|         return fluxmap; | ||||
|     } | ||||
|  | ||||
|     void recalibrate() | ||||
|     { | ||||
|     } | ||||
|  | ||||
|     bool retryable() | ||||
|     { | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
| private: | ||||
|     unsigned _drive; | ||||
| }; | ||||
|  | ||||
| std::unique_ptr<FluxSource> FluxSource::createQuickdiskFluxSource(unsigned drive) | ||||
| { | ||||
|     return std::unique_ptr<FluxSource>(new QuickdiskFluxSource(drive)); | ||||
| } | ||||
|  | ||||
|  | ||||
|  | ||||
| @@ -16,7 +16,7 @@ | ||||
| #include "track.h" | ||||
| #include "fmt/format.h" | ||||
|  | ||||
| FlagGroup readerFlags { &hardwareFluxSourceFlags, &fluxmapReaderFlags }; | ||||
| FlagGroup readerFlags { &hardwareFluxSourceFlags, &quickdiskFluxSourceFlags, &fluxmapReaderFlags }; | ||||
|  | ||||
| static DataSpecFlag source( | ||||
|     { "--source", "-s" }, | ||||
| @@ -85,8 +85,6 @@ std::vector<std::unique_ptr<Track>> readTracks() | ||||
|  | ||||
|     std::cout << "Reading from: " << source << std::endl; | ||||
|  | ||||
| 	setHardwareFluxSourceDensity(highDensityFlag); | ||||
|  | ||||
| 	if (!destination.get().empty()) | ||||
| 	{ | ||||
| 		outdb = sqlOpen(destination, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE); | ||||
| @@ -102,8 +100,9 @@ std::vector<std::unique_ptr<Track>> readTracks() | ||||
| 		); | ||||
| 	} | ||||
|  | ||||
| 	std::shared_ptr<FluxSource> fluxSource = FluxSource::create(spec); | ||||
| 	setHardwareFluxSourceDensity(highDensityFlag); | ||||
|  | ||||
| 	std::shared_ptr<FluxSource> fluxSource = FluxSource::create(spec); | ||||
| 	std::vector<std::unique_ptr<Track>> tracks; | ||||
|     for (const auto& location : spec.locations) | ||||
| 	{ | ||||
|   | ||||
							
								
								
									
										21
									
								
								lib/usb.cc
									
									
									
									
									
								
							
							
						
						
									
										21
									
								
								lib/usb.cc
									
									
									
									
									
								
							| @@ -76,7 +76,7 @@ static void bad_reply(void) | ||||
| { | ||||
|     struct error_frame* f = (struct error_frame*) buffer; | ||||
|     if (f->f.type != F_FRAME_ERROR) | ||||
|         Error() << fmt::format("bad USB reply 0x{:2x}", f->f.type); | ||||
|         Error() << fmt::format("bad USB reply 0x{:02x}", f->f.type); | ||||
|     switch (f->error) | ||||
|     { | ||||
|         case F_ERROR_BAD_COMMAND: | ||||
| @@ -221,6 +221,25 @@ Bytes usbRead(int side, int revolutions) | ||||
|     return buffer; | ||||
| } | ||||
|  | ||||
| Bytes usbReadQD(int side) | ||||
| { | ||||
|     struct read_frame f = { | ||||
|         .f = { .type = F_FRAME_READ_QD_CMD, .size = sizeof(f) }, | ||||
|         .side = (uint8_t) side, | ||||
|         .revolutions = 1 | ||||
|     }; | ||||
|     usb_cmd_send(&f, f.f.size); | ||||
|  | ||||
|     auto fluxmap = std::unique_ptr<Fluxmap>(new Fluxmap); | ||||
|  | ||||
|     Bytes buffer(1024*1024); | ||||
|     int len = large_bulk_transfer(FLUXENGINE_DATA_IN_EP, buffer); | ||||
|     buffer.resize(len); | ||||
|  | ||||
|     await_reply<struct any_frame>(F_FRAME_READ_REPLY); | ||||
|     return buffer; | ||||
| } | ||||
|  | ||||
| void usbWrite(int side, const Bytes& bytes) | ||||
| { | ||||
|     unsigned safelen = bytes.size() & ~(FRAME_SIZE-1); | ||||
|   | ||||
| @@ -10,6 +10,7 @@ extern void usbSeek(int track); | ||||
| extern nanoseconds_t usbGetRotationalPeriod(); | ||||
| extern void usbTestBulkTransport(); | ||||
| extern Bytes usbRead(int side, int revolutions); | ||||
| extern Bytes usbReadQD(int side); | ||||
| extern void usbWrite(int side, const Bytes& bytes); | ||||
| extern void usbErase(int side); | ||||
| extern void usbSetDrive(int drive, bool high_density); | ||||
|   | ||||
| @@ -170,6 +170,7 @@ buildlibrary libbackend.a \ | ||||
|     lib/fluxsink/sqlitefluxsink.cc \ | ||||
|     lib/fluxsource/fluxsource.cc \ | ||||
|     lib/fluxsource/hardwarefluxsource.cc \ | ||||
|     lib/fluxsource/quickdiskfluxsource.cc \ | ||||
|     lib/fluxsource/kryoflux.cc \ | ||||
|     lib/fluxsource/sqlitefluxsource.cc \ | ||||
|     lib/fluxsource/streamfluxsource.cc \ | ||||
| @@ -203,6 +204,7 @@ buildlibrary libfrontend.a \ | ||||
|     src/fe-readibm.cc \ | ||||
|     src/fe-readmac.cc \ | ||||
|     src/fe-readmx.cc \ | ||||
|     src/fe-readqd.cc \ | ||||
|     src/fe-readvictor9k.cc \ | ||||
|     src/fe-readzilogmcz.cc \ | ||||
|     src/fe-rpm.cc \ | ||||
|   | ||||
| @@ -3,7 +3,7 @@ | ||||
|  | ||||
| enum  | ||||
| { | ||||
|     FLUXENGINE_VERSION = 8, | ||||
|     FLUXENGINE_VERSION = 9, | ||||
|  | ||||
|     FLUXENGINE_VID = 0x1209, | ||||
|     FLUXENGINE_PID = 0x6e00, | ||||
| @@ -54,6 +54,8 @@ enum | ||||
|     F_FRAME_BULK_TEST_REPLY,      /* any_frame */ | ||||
|     F_FRAME_READ_CMD,             /* read_frame */ | ||||
|     F_FRAME_READ_REPLY,           /* any_frame */ | ||||
|     F_FRAME_READ_QD_CMD,          /* read_frame */ | ||||
|     F_FRAME_READ_QD_REPLY,        /* any_frame */ | ||||
|     F_FRAME_WRITE_CMD,            /* write_frame */ | ||||
|     F_FRAME_WRITE_REPLY,          /* any_frame */ | ||||
|     F_FRAME_ERASE_CMD,            /* erase_frame */ | ||||
|   | ||||
							
								
								
									
										26
									
								
								src/fe-readqd.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								src/fe-readqd.cc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,26 @@ | ||||
| #include "globals.h" | ||||
| #include "flags.h" | ||||
| #include "reader.h" | ||||
| #include "fluxmap.h" | ||||
| #include "decoders/decoders.h" | ||||
| #include "image.h" | ||||
| #include "sector.h" | ||||
| #include "sectorset.h" | ||||
| #include "record.h" | ||||
| #include "ibm/ibm.h" | ||||
| #include "fmt/format.h" | ||||
|  | ||||
| static FlagGroup flags { &readerFlags }; | ||||
|  | ||||
| int mainReadQd(int argc, const char* argv[]) | ||||
| { | ||||
| 	setReaderDefaultSource(":qd=1"); | ||||
| 	setReaderDefaultOutput("qd.img"); | ||||
|     setReaderRevolutions(2); | ||||
|     flags.parseFlags(argc, argv); | ||||
|  | ||||
| 	IbmDecoder decoder(0); | ||||
| 	readDiskCommand(decoder); | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| @@ -20,6 +20,7 @@ extern command_cb mainReadFB100; | ||||
| extern command_cb mainReadIBM; | ||||
| extern command_cb mainReadMac; | ||||
| extern command_cb mainReadMx; | ||||
| extern command_cb mainReadQd; | ||||
| extern command_cb mainReadVictor9K; | ||||
| extern command_cb mainReadZilogMCZ; | ||||
| extern command_cb mainRpm; | ||||
| @@ -71,6 +72,7 @@ static std::vector<Command> readables = | ||||
|     { "ibm",           mainReadIBM,       "Reads the ubiquitous IBM format disks.", }, | ||||
|     { "mac",           mainReadMac,       "Reads Apple Macintosh disks.", }, | ||||
|     { "mx",            mainReadMx,        "Reads MX disks.", }, | ||||
|     { "qd",            mainReadQd,        "Reads QuickDisk disks.", }, | ||||
|     { "victor9k",      mainReadVictor9K,  "Reads Victor 9000 disks.", }, | ||||
|     { "zilogmcz",      mainReadZilogMCZ,  "Reads Zilog MCZ disks.", }, | ||||
| }; | ||||
|   | ||||
| @@ -85,6 +85,15 @@ static void test_fluxspec(void) | ||||
|             {{1, 9, 1}})); | ||||
|         assert((std::string)spec == ":d=1:s=1:t=9"); | ||||
|     } | ||||
|  | ||||
|     spec.set(""); | ||||
|     assert(FluxSpec(spec).quickdisk == false); | ||||
|  | ||||
|     spec.set(":qd=0"); | ||||
|     assert(FluxSpec(spec).quickdisk == false); | ||||
|  | ||||
|     spec.set(":qd=1"); | ||||
|     assert(FluxSpec(spec).quickdisk == true); | ||||
| } | ||||
|  | ||||
| static void test_imagespec(void) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user