mirror of
https://github.com/davidgiven/fluxengine.git
synced 2025-10-31 11:17:01 -07:00
Merge from master.
This commit is contained in:
@@ -571,6 +571,7 @@
|
||||
<Data key="e51063a9-4fad-40c7-a06b-7cc4b137dc18" value="DSKCHG" />
|
||||
<Data key="ea7ee228-8b3f-426c-8bb8-cd7a81937769" value="DIR" />
|
||||
<Data key="ed092b9b-d398-4703-be89-cebf998501f6" value="UartTx" />
|
||||
<Data key="fbd1f839-40f9-498e-a48b-5f3048ea5c3d/52f31aa9-2f0a-497d-9a1f-1424095e13e6" value="SW_Tx_UART_1_tx" />
|
||||
<Data key="fede1767-f3fd-4021-b3d7-8f9d88f36f9b" value="DRVSA" />
|
||||
<Data key="fff78075-035e-43d7-8577-bc5be4d21926" value="WGATE" />
|
||||
</Group>
|
||||
@@ -3809,6 +3810,11 @@
|
||||
<Data key="Port Format" value="12,7" />
|
||||
</Group>
|
||||
</Group>
|
||||
<Group key="fbd1f839-40f9-498e-a48b-5f3048ea5c3d/52f31aa9-2f0a-497d-9a1f-1424095e13e6">
|
||||
<Group key="0">
|
||||
<Data key="Port Format" value="2,0" />
|
||||
</Group>
|
||||
</Group>
|
||||
<Group key="fede1767-f3fd-4021-b3d7-8f9d88f36f9b">
|
||||
<Group key="0">
|
||||
<Data key="Port Format" value="12,2" />
|
||||
|
||||
@@ -39,6 +39,20 @@
|
||||
<build_action v="HEADER;;;;" />
|
||||
<PropertyDeltas />
|
||||
</CyGuid_8b8ab257-35d3-4473-b57b-36315200b38b>
|
||||
<CyGuid_8b8ab257-35d3-4473-b57b-36315200b38b type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtFileSerialize" version="3" xml_contents_version="1">
|
||||
<CyGuid_31768f72-0253-412b-af77-e7dba74d1330 type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtItemSerialize" version="2" name="crunch.c" persistent="..\lib\common\crunch.c">
|
||||
<Hidden v="False" />
|
||||
</CyGuid_31768f72-0253-412b-af77-e7dba74d1330>
|
||||
<build_action v="SOURCE_C;;;;" />
|
||||
<PropertyDeltas />
|
||||
</CyGuid_8b8ab257-35d3-4473-b57b-36315200b38b>
|
||||
<CyGuid_8b8ab257-35d3-4473-b57b-36315200b38b type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtFileSerialize" version="3" xml_contents_version="1">
|
||||
<CyGuid_31768f72-0253-412b-af77-e7dba74d1330 type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtItemSerialize" version="2" name="crunch.h" persistent="..\lib\common\crunch.h">
|
||||
<Hidden v="False" />
|
||||
</CyGuid_31768f72-0253-412b-af77-e7dba74d1330>
|
||||
<build_action v="HEADER;;;;" />
|
||||
<PropertyDeltas />
|
||||
</CyGuid_8b8ab257-35d3-4473-b57b-36315200b38b>
|
||||
</dependencies>
|
||||
</CyGuid_0820c2e7-528d-4137-9a08-97257b946089>
|
||||
</CyGuid_2f73275c-45bf-46ba-b3b1-00a2fe0c8dd8>
|
||||
@@ -1692,20 +1706,20 @@
|
||||
<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="UART" persistent="">
|
||||
<Hidden v="True" />
|
||||
<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="UART.c" persistent="Generated_Source\PSoC5\UART.c">
|
||||
<Hidden v="True" />
|
||||
<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="UART.h" persistent="Generated_Source\PSoC5\UART.h">
|
||||
<Hidden v="True" />
|
||||
<Hidden v="False" />
|
||||
</CyGuid_31768f72-0253-412b-af77-e7dba74d1330>
|
||||
<build_action v="HEADER;;;;" />
|
||||
<PropertyDeltas />
|
||||
@@ -1731,6 +1745,34 @@
|
||||
<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="UART_AsmGnu.s" persistent="Generated_Source\PSoC5\UART_AsmGnu.s">
|
||||
<Hidden v="False" />
|
||||
</CyGuid_31768f72-0253-412b-af77-e7dba74d1330>
|
||||
<build_action v="SOURCE_ASM;CortexM0,CortexM0p,CortexM3,CortexM4,CortexM7;;b98f980c-3bd1-4fc7-a887-c56a20a46fdd;" />
|
||||
<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="UART_AsmRv.s" persistent="Generated_Source\PSoC5\UART_AsmRv.s">
|
||||
<Hidden v="False" />
|
||||
</CyGuid_31768f72-0253-412b-af77-e7dba74d1330>
|
||||
<build_action v="SOURCE_ASM;CortexM0,CortexM0p,CortexM3,CortexM4,CortexM7;;fdb8e1ae-f83a-46cf-9446-1d703716f38a;" />
|
||||
<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="UART_PVT.h" persistent="Generated_Source\PSoC5\UART_PVT.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="UART_AsmIar.s" persistent="Generated_Source\PSoC5\UART_AsmIar.s">
|
||||
<Hidden v="False" />
|
||||
</CyGuid_31768f72-0253-412b-af77-e7dba74d1330>
|
||||
<build_action v="SOURCE_ASM;CortexM0,CortexM0p,CortexM3,CortexM4,CortexM7;;e9305a93-d091-4da5-bdc7-2813049dcdbf;" />
|
||||
<PropertyDeltas />
|
||||
</CyGuid_8b8ab257-35d3-4473-b57b-36315200b38b>
|
||||
</dependencies>
|
||||
</CyGuid_0820c2e7-528d-4137-9a08-97257b946089>
|
||||
</CyGuid_2f73275c-45bf-46ba-b3b1-00a2fe0c8dd8>
|
||||
@@ -2164,20 +2206,20 @@
|
||||
<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="USBFS_ep4" 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="USBFS_ep4_dma.c" persistent="Generated_Source\PSoC5\USBFS_ep4_dma.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="USBFS_ep4_dma.h" persistent="Generated_Source\PSoC5\USBFS_ep4_dma.h">
|
||||
<Hidden v="False" />
|
||||
<Hidden v="True" />
|
||||
</CyGuid_31768f72-0253-412b-af77-e7dba74d1330>
|
||||
<build_action v="HEADER;;;;" />
|
||||
<PropertyDeltas />
|
||||
@@ -2190,20 +2232,20 @@
|
||||
<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="USBFS_ep3" 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="USBFS_ep3_dma.c" persistent="Generated_Source\PSoC5\USBFS_ep3_dma.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="USBFS_ep3_dma.h" persistent="Generated_Source\PSoC5\USBFS_ep3_dma.h">
|
||||
<Hidden v="False" />
|
||||
<Hidden v="True" />
|
||||
</CyGuid_31768f72-0253-412b-af77-e7dba74d1330>
|
||||
<build_action v="HEADER;;;;" />
|
||||
<PropertyDeltas />
|
||||
@@ -2216,20 +2258,20 @@
|
||||
<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="USBFS_ep2" 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="USBFS_ep2_dma.c" persistent="Generated_Source\PSoC5\USBFS_ep2_dma.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="USBFS_ep2_dma.h" persistent="Generated_Source\PSoC5\USBFS_ep2_dma.h">
|
||||
<Hidden v="False" />
|
||||
<Hidden v="True" />
|
||||
</CyGuid_31768f72-0253-412b-af77-e7dba74d1330>
|
||||
<build_action v="HEADER;;;;" />
|
||||
<PropertyDeltas />
|
||||
@@ -2242,20 +2284,20 @@
|
||||
<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="USBFS_ep1" 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="USBFS_ep1_dma.c" persistent="Generated_Source\PSoC5\USBFS_ep1_dma.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="USBFS_ep1_dma.h" persistent="Generated_Source\PSoC5\USBFS_ep1_dma.h">
|
||||
<Hidden v="False" />
|
||||
<Hidden v="True" />
|
||||
</CyGuid_31768f72-0253-412b-af77-e7dba74d1330>
|
||||
<build_action v="HEADER;;;;" />
|
||||
<PropertyDeltas />
|
||||
|
||||
Binary file not shown.
@@ -1,9 +1,11 @@
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <setjmp.h>
|
||||
#include "project.h"
|
||||
#include "../protocol.h"
|
||||
#include "../lib/common/crunch.h"
|
||||
|
||||
#define MOTOR_ON_TIME 5000 /* milliseconds */
|
||||
#define STEP_INTERVAL_TIME 6 /* ms */
|
||||
@@ -28,6 +30,7 @@ static uint8_t current_drive_flags = 0;
|
||||
#define BUFFER_SIZE 64
|
||||
static uint8_t td[BUFFER_COUNT];
|
||||
static uint8_t dma_buffer[BUFFER_COUNT][BUFFER_SIZE] __attribute__((aligned()));
|
||||
static uint8_t usb_buffer[BUFFER_SIZE] __attribute__((aligned()));
|
||||
static uint8_t dma_channel;
|
||||
#define NEXT_BUFFER(b) (((b)+1) % BUFFER_COUNT)
|
||||
|
||||
@@ -69,16 +72,17 @@ CY_ISR(replay_dma_finished_irq_cb)
|
||||
dma_underrun = true;
|
||||
}
|
||||
|
||||
static void print(const char* s)
|
||||
static void print(const char* msg, ...)
|
||||
{
|
||||
/* UART_PutString(s); */
|
||||
}
|
||||
|
||||
static void printi(int i)
|
||||
{
|
||||
char buffer[16];
|
||||
sprintf(buffer, "%d", i);
|
||||
print(buffer);
|
||||
char buffer[64];
|
||||
|
||||
va_list ap;
|
||||
va_start(ap, msg);
|
||||
vsnprintf(buffer, sizeof(buffer), msg, ap);
|
||||
va_end(ap);
|
||||
|
||||
UART_PutString(buffer);
|
||||
UART_PutCRLF();
|
||||
}
|
||||
|
||||
static void start_motor(void)
|
||||
@@ -106,6 +110,7 @@ static void wait_until_writeable(int ep)
|
||||
|
||||
static void send_reply(struct any_frame* f)
|
||||
{
|
||||
print("reply 0x%02x", f->f.type);
|
||||
wait_until_writeable(FLUXENGINE_CMD_IN_EP_NUM);
|
||||
USBFS_LoadInEP(FLUXENGINE_CMD_IN_EP_NUM, (uint8_t*) f, f->f.size);
|
||||
}
|
||||
@@ -276,11 +281,16 @@ static void cmd_read(struct read_frame* f)
|
||||
|
||||
/* Wait for the beginning of a rotation. */
|
||||
|
||||
print("wait");
|
||||
index_irq = false;
|
||||
while (!index_irq)
|
||||
;
|
||||
index_irq = false;
|
||||
|
||||
crunch_state_t cs = {};
|
||||
cs.outputptr = usb_buffer;
|
||||
cs.outputlen = BUFFER_SIZE;
|
||||
|
||||
dma_writing_to_td = 0;
|
||||
dma_reading_from_td = -1;
|
||||
dma_underrun = false;
|
||||
@@ -302,6 +312,8 @@ static void cmd_read(struct read_frame* f)
|
||||
int revolutions = f->revolutions;
|
||||
while (!dma_underrun)
|
||||
{
|
||||
CyWdtClear();
|
||||
|
||||
/* Have we reached the index pulse? */
|
||||
if (index_irq)
|
||||
{
|
||||
@@ -319,30 +331,47 @@ static void cmd_read(struct read_frame* f)
|
||||
goto abort;
|
||||
}
|
||||
|
||||
while (USBFS_GetEPState(FLUXENGINE_DATA_IN_EP_NUM) != USBFS_IN_BUFFER_EMPTY)
|
||||
uint8_t dma_buffer_usage = 0;
|
||||
while (dma_buffer_usage < BUFFER_SIZE)
|
||||
{
|
||||
if (index_irq || dma_underrun)
|
||||
goto abort;
|
||||
}
|
||||
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, dma_buffer[dma_reading_from_td], BUFFER_SIZE);
|
||||
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);
|
||||
count++;
|
||||
}
|
||||
abort:
|
||||
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);
|
||||
USBFS_LoadInEP(FLUXENGINE_DATA_IN_EP_NUM, NULL, 0);
|
||||
deinit_dma();
|
||||
|
||||
if (dma_underrun)
|
||||
{
|
||||
print("underrun after ");
|
||||
printi(count);
|
||||
print(" packets\r");
|
||||
print("underrun after %d packets");
|
||||
send_error(F_ERROR_UNDERRUN);
|
||||
}
|
||||
else
|
||||
@@ -350,6 +379,7 @@ abort:
|
||||
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 init_replay_dma(void)
|
||||
@@ -395,32 +425,80 @@ static void cmd_write(struct write_frame* f)
|
||||
|
||||
init_replay_dma();
|
||||
bool writing = false; /* to the disk */
|
||||
bool listening = false;
|
||||
bool finished = false;
|
||||
int packets = f->bytes_to_write / FRAME_SIZE;
|
||||
int count_read = 0;
|
||||
int count_written = 0;
|
||||
int count_read = 0;
|
||||
dma_writing_to_td = 0;
|
||||
dma_reading_from_td = -1;
|
||||
dma_underrun = false;
|
||||
|
||||
crunch_state_t cs = {};
|
||||
cs.outputlen = BUFFER_SIZE;
|
||||
USBFS_EnableOutEP(FLUXENGINE_DATA_OUT_EP_NUM);
|
||||
|
||||
int old_reading_from_td = -1;
|
||||
for (;;)
|
||||
{
|
||||
if (dma_reading_from_td != old_reading_from_td)
|
||||
{
|
||||
count_written++;
|
||||
old_reading_from_td = dma_reading_from_td;
|
||||
}
|
||||
/* Read data from USB into the buffers. */
|
||||
|
||||
if (dma_reading_from_td != -1)
|
||||
if (NEXT_BUFFER(dma_writing_to_td) != dma_reading_from_td)
|
||||
{
|
||||
/* We want to be writing to disk. */
|
||||
if (writing && (dma_underrun || index_irq))
|
||||
goto abort;
|
||||
|
||||
if (!writing)
|
||||
/* Read crunched data, if necessary. */
|
||||
|
||||
if (cs.inputlen == 0)
|
||||
{
|
||||
print("start writing\r");
|
||||
if (finished)
|
||||
{
|
||||
/* There's no more data to read, so fake some. */
|
||||
|
||||
for (int i=0; i<BUFFER_SIZE; i++)
|
||||
usb_buffer[i+0] = 0x7f;
|
||||
cs.inputptr = usb_buffer;
|
||||
cs.inputlen = BUFFER_SIZE;
|
||||
}
|
||||
else
|
||||
{
|
||||
while (USBFS_GetEPState(FLUXENGINE_DATA_OUT_EP_NUM) != USBFS_OUT_BUFFER_FULL)
|
||||
{
|
||||
if (writing && (dma_underrun || index_irq))
|
||||
goto abort;
|
||||
}
|
||||
|
||||
int length = usb_read(FLUXENGINE_DATA_OUT_EP_NUM, usb_buffer);
|
||||
cs.inputptr = usb_buffer;
|
||||
cs.inputlen = length;
|
||||
USBFS_EnableOutEP(FLUXENGINE_DATA_OUT_EP_NUM);
|
||||
|
||||
count_read++;
|
||||
if ((length < FRAME_SIZE) || (count_read == packets))
|
||||
finished = true;
|
||||
}
|
||||
}
|
||||
|
||||
/* If there *is* data waiting in the buffer, uncrunch it. */
|
||||
|
||||
if (cs.inputlen != 0)
|
||||
{
|
||||
cs.outputptr = dma_buffer[dma_writing_to_td] + BUFFER_SIZE - cs.outputlen;
|
||||
uncrunch(&cs);
|
||||
if (cs.outputlen == 0)
|
||||
{
|
||||
/* Completed a DMA buffer; queue it for writing. */
|
||||
|
||||
dma_writing_to_td = NEXT_BUFFER(dma_writing_to_td);
|
||||
cs.outputlen = BUFFER_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
/* If we have a full buffer, start writing. */
|
||||
if ((dma_reading_from_td == -1) && (dma_writing_to_td == BUFFER_COUNT-1))
|
||||
{
|
||||
dma_reading_from_td = old_reading_from_td = 0;
|
||||
|
||||
/* Start the DMA engine. */
|
||||
|
||||
SEQUENCER_DMA_FINISHED_IRQ_Enable();
|
||||
@@ -441,90 +519,38 @@ static void cmd_write(struct write_frame* f)
|
||||
ERASE_REG_Write(1); /* start erasing! */
|
||||
SEQUENCER_CONTROL_Write(0); /* start writing! */
|
||||
}
|
||||
|
||||
/* ...unless we reach the end of the track or suffer underrung, of course. */
|
||||
|
||||
if (index_irq || dma_underrun)
|
||||
break;
|
||||
}
|
||||
|
||||
if (NEXT_BUFFER(dma_writing_to_td) != dma_reading_from_td)
|
||||
if (writing && (dma_underrun || index_irq))
|
||||
goto abort;
|
||||
|
||||
if (dma_reading_from_td != old_reading_from_td)
|
||||
{
|
||||
/* We're ready for more data. */
|
||||
|
||||
if (finished)
|
||||
{
|
||||
/* The USB stream has stopped early, so just fake data to keep the writer happy. */
|
||||
|
||||
for (int i=0; i<BUFFER_SIZE; i++)
|
||||
dma_buffer[dma_writing_to_td][i] = 0x80;
|
||||
dma_writing_to_td = NEXT_BUFFER(dma_writing_to_td);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Make sure we're waiting for USB data. */
|
||||
|
||||
if (!listening)
|
||||
{
|
||||
USBFS_EnableOutEP(FLUXENGINE_DATA_OUT_EP_NUM);
|
||||
listening = true;
|
||||
}
|
||||
|
||||
/* Is more data actually ready? */
|
||||
|
||||
if (USBFS_GetEPState(FLUXENGINE_DATA_OUT_EP_NUM) == USBFS_OUT_BUFFER_FULL)
|
||||
{
|
||||
int length = usb_read(FLUXENGINE_DATA_OUT_EP_NUM, dma_buffer[dma_writing_to_td]);
|
||||
listening = false;
|
||||
dma_writing_to_td = NEXT_BUFFER(dma_writing_to_td);
|
||||
|
||||
count_read++;
|
||||
if ((length < FRAME_SIZE) || (count_read == packets))
|
||||
finished = true;
|
||||
}
|
||||
}
|
||||
|
||||
/* Only start writing once the buffer is full. */
|
||||
|
||||
if ((dma_reading_from_td == -1) && (dma_writing_to_td == BUFFER_COUNT-1))
|
||||
dma_reading_from_td = old_reading_from_td = 0;
|
||||
count_written++;
|
||||
old_reading_from_td = dma_reading_from_td;
|
||||
}
|
||||
}
|
||||
abort:
|
||||
SEQUENCER_DMA_FINISHED_IRQ_Disable();
|
||||
|
||||
SEQUENCER_CONTROL_Write(1); /* reset */
|
||||
if (writing)
|
||||
{
|
||||
ERASE_REG_Write(0);
|
||||
print("stop writing after ");
|
||||
printi(count_written);
|
||||
print("\r");
|
||||
CyDmaChSetRequest(dma_channel, CY_DMA_CPU_TERM_CHAIN);
|
||||
while (CyDmaChGetRequest(dma_channel))
|
||||
;
|
||||
CyDmaChDisable(dma_channel);
|
||||
}
|
||||
|
||||
if (dma_underrun)
|
||||
{
|
||||
print("underrun after ");
|
||||
printi(count_read);
|
||||
print(" out of ");
|
||||
printi(packets);
|
||||
print(" packets read\r");
|
||||
}
|
||||
|
||||
DECLARE_REPLY_FRAME(struct any_frame, F_FRAME_WRITE_REPLY);
|
||||
|
||||
//debug("p=%d cr=%d cw=%d f=%d l=%d w=%d index=%d underrun=%d", packets, count_read, count_written, finished, listening, writing, index_irq, dma_underrun);
|
||||
if (!finished)
|
||||
{
|
||||
if (!listening)
|
||||
USBFS_EnableOutEP(FLUXENGINE_DATA_OUT_EP_NUM);
|
||||
while (count_read < packets)
|
||||
{
|
||||
if (USBFS_GetEPState(FLUXENGINE_DATA_OUT_EP_NUM) == USBFS_OUT_BUFFER_FULL)
|
||||
{
|
||||
int length = usb_read(FLUXENGINE_DATA_OUT_EP_NUM, dma_buffer[0]);
|
||||
int length = usb_read(FLUXENGINE_DATA_OUT_EP_NUM, usb_buffer);
|
||||
if (length < FRAME_SIZE)
|
||||
break;
|
||||
USBFS_EnableOutEP(FLUXENGINE_DATA_OUT_EP_NUM);
|
||||
@@ -542,6 +568,7 @@ static void cmd_write(struct write_frame* f)
|
||||
return;
|
||||
}
|
||||
|
||||
DECLARE_REPLY_FRAME(struct any_frame, F_FRAME_WRITE_REPLY);
|
||||
send_reply((struct any_frame*) &r);
|
||||
}
|
||||
|
||||
@@ -551,7 +578,7 @@ static void cmd_erase(struct erase_frame* f)
|
||||
seek_to(current_track);
|
||||
/* Disk is now spinning. */
|
||||
|
||||
print("start erasing\r");
|
||||
print("start erasing");
|
||||
index_irq = false;
|
||||
while (!index_irq)
|
||||
;
|
||||
@@ -560,7 +587,7 @@ static void cmd_erase(struct erase_frame* f)
|
||||
while (!index_irq)
|
||||
;
|
||||
ERASE_REG_Write(0);
|
||||
print("stop erasing\r");
|
||||
print("stop erasing");
|
||||
|
||||
DECLARE_REPLY_FRAME(struct any_frame, F_FRAME_ERASE_REPLY);
|
||||
send_reply((struct any_frame*) &r);
|
||||
@@ -568,9 +595,9 @@ static void cmd_erase(struct erase_frame* f)
|
||||
|
||||
static void cmd_set_drive(struct set_drive_frame* f)
|
||||
{
|
||||
if (current_drive_flags != f->drive)
|
||||
if (current_drive_flags != f->drive_flags)
|
||||
{
|
||||
current_drive_flags = f->drive | (f->high_density<<1);
|
||||
current_drive_flags = f->drive_flags;
|
||||
DRIVE_REG_Write(current_drive_flags);
|
||||
homed = false;
|
||||
}
|
||||
@@ -585,6 +612,7 @@ static void handle_command(void)
|
||||
(void) usb_read(FLUXENGINE_CMD_OUT_EP_NUM, input_buffer);
|
||||
|
||||
struct any_frame* f = (struct any_frame*) input_buffer;
|
||||
print("command 0x%02x", f->f.type);
|
||||
switch (f->f.type)
|
||||
{
|
||||
case F_FRAME_GET_VERSION_CMD:
|
||||
@@ -637,7 +665,7 @@ int main(void)
|
||||
CAPTURE_DMA_FINISHED_IRQ_StartEx(&capture_dma_finished_irq_cb);
|
||||
SEQUENCER_DMA_FINISHED_IRQ_StartEx(&replay_dma_finished_irq_cb);
|
||||
DRIVE_REG_Write(0);
|
||||
/* UART_Start(); */
|
||||
UART_Start();
|
||||
USBFS_Start(0, USBFS_DWR_VDDD_OPERATION);
|
||||
|
||||
CyWdtStart(CYWDT_1024_TICKS, CYWDT_LPMODE_DISABLED);
|
||||
@@ -660,10 +688,10 @@ int main(void)
|
||||
|
||||
if (!USBFS_GetConfiguration() || USBFS_IsConfigurationChanged())
|
||||
{
|
||||
print("Waiting for USB...\r");
|
||||
print("Waiting for USB...");
|
||||
while (!USBFS_GetConfiguration())
|
||||
;
|
||||
print("USB ready\r");
|
||||
print("USB ready");
|
||||
USBFS_EnableOutEP(FLUXENGINE_CMD_OUT_EP_NUM);
|
||||
}
|
||||
|
||||
@@ -671,7 +699,7 @@ int main(void)
|
||||
{
|
||||
handle_command();
|
||||
USBFS_EnableOutEP(FLUXENGINE_CMD_OUT_EP_NUM);
|
||||
print("idle\r");
|
||||
print("idle");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
19
doc/using.md
19
doc/using.md
@@ -110,6 +110,25 @@ sensible for the command you're using.
|
||||
**Important note:** FluxEngine _always_ uses zero-based units (even if the
|
||||
*disk format says otherwise).
|
||||
|
||||
### High density disks
|
||||
|
||||
High density disks use a different magnetic medium to low and double density
|
||||
disks, and have different magnetic properties. 3.5" drives can usually
|
||||
autodetect what kind of medium is inserted into the drive based on the hole
|
||||
in the disk casing, but 5.25" drives can't. As a result, you need to
|
||||
explicitly tell FluxEngine on the command line whether you're using a high
|
||||
density disk or not with the `--hd` flag.
|
||||
**If you don't do this, your disks may not read correctly and will _certainly_
|
||||
fail to write correctly.**
|
||||
|
||||
You can distinguish high density 5.25" floppies from the presence of a
|
||||
traction ring around the hole in the middle of the disk; if the ring is not
|
||||
present, the disk is probably high density. However, this isn't always the
|
||||
case, and reading the disk label is much more reliable.
|
||||
|
||||
[Lots more information on high density vs double density disks can be found
|
||||
here.](http://www.retrotechnology.com/herbs_stuff/guzis.html)
|
||||
|
||||
### The commands
|
||||
|
||||
The FluxEngine client software is a largely undocumented set of small tools.
|
||||
|
||||
55
lib/bytes.cc
55
lib/bytes.cc
@@ -1,6 +1,7 @@
|
||||
#include "globals.h"
|
||||
#include "bytes.h"
|
||||
#include "fmt/format.h"
|
||||
#include "crunch.h"
|
||||
#include <zlib.h>
|
||||
|
||||
static std::shared_ptr<std::vector<uint8_t>> createVector(unsigned size)
|
||||
@@ -208,6 +209,60 @@ Bytes Bytes::decompress() const
|
||||
return output;
|
||||
}
|
||||
|
||||
Bytes Bytes::crunch() const
|
||||
{
|
||||
Bytes output;
|
||||
ByteWriter bw(output);
|
||||
Bytes outputBuffer(1024*1024);
|
||||
|
||||
crunch_state_t cs = {};
|
||||
cs.inputptr = begin();
|
||||
cs.inputlen = size();
|
||||
|
||||
do
|
||||
{
|
||||
cs.outputptr = outputBuffer.begin();
|
||||
cs.outputlen = outputBuffer.size();
|
||||
|
||||
::crunch(&cs);
|
||||
bw += outputBuffer.slice(0, outputBuffer.size() - cs.outputlen);
|
||||
}
|
||||
while (cs.inputlen != 0);
|
||||
cs.outputptr = outputBuffer.begin();
|
||||
cs.outputlen = outputBuffer.size();
|
||||
donecrunch(&cs);
|
||||
bw += outputBuffer.slice(0, outputBuffer.size() - cs.outputlen);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
Bytes Bytes::uncrunch() const
|
||||
{
|
||||
Bytes output;
|
||||
ByteWriter bw(output);
|
||||
Bytes outputBuffer(1024*1024);
|
||||
|
||||
crunch_state_t cs = {};
|
||||
cs.inputptr = begin();
|
||||
cs.inputlen = size();
|
||||
|
||||
do
|
||||
{
|
||||
cs.outputptr = outputBuffer.begin();
|
||||
cs.outputlen = outputBuffer.size();
|
||||
|
||||
::uncrunch(&cs);
|
||||
bw += outputBuffer.slice(0, outputBuffer.size() - cs.outputlen);
|
||||
}
|
||||
while (cs.inputlen != 0);
|
||||
cs.outputptr = outputBuffer.begin();
|
||||
cs.outputlen = outputBuffer.size();
|
||||
doneuncrunch(&cs);
|
||||
bw += outputBuffer.slice(0, outputBuffer.size() - cs.outputlen);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
ByteReader Bytes::reader() const
|
||||
{
|
||||
return ByteReader(*this);
|
||||
|
||||
@@ -46,6 +46,8 @@ public:
|
||||
Bytes slice(unsigned start, unsigned len) const;
|
||||
Bytes compress() const;
|
||||
Bytes decompress() const;
|
||||
Bytes crunch() const;
|
||||
Bytes uncrunch() const;
|
||||
|
||||
ByteReader reader() const;
|
||||
ByteWriter writer();
|
||||
|
||||
86
lib/common/crunch.c
Normal file
86
lib/common/crunch.c
Normal file
@@ -0,0 +1,86 @@
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "crunch.h"
|
||||
|
||||
void crunch(crunch_state_t* state)
|
||||
{
|
||||
while (state->inputlen && state->outputlen)
|
||||
{
|
||||
uint8_t data = *state->inputptr++;
|
||||
state->inputlen--;
|
||||
|
||||
if (data & 0x80)
|
||||
{
|
||||
state->fifo = (state->fifo << 2) | 2 | (data & 1);
|
||||
state->fifolen += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
state->fifo = (state->fifo << 8) | data;
|
||||
state->fifolen += 8;
|
||||
}
|
||||
|
||||
if (state->fifolen >= 8)
|
||||
{
|
||||
data = state->fifo >> (state->fifolen - 8);
|
||||
*state->outputptr++ = data;
|
||||
state->outputlen--;
|
||||
state->fifolen -= 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void donecrunch(crunch_state_t* state)
|
||||
{
|
||||
if (state->fifolen > 0)
|
||||
{
|
||||
uint8_t b = 0;
|
||||
state->inputptr = &b;
|
||||
state->inputlen = 1;
|
||||
crunch(state);
|
||||
}
|
||||
}
|
||||
|
||||
void uncrunch(crunch_state_t* state)
|
||||
{
|
||||
while (state->inputlen && state->outputlen)
|
||||
{
|
||||
if (state->fifolen < 8)
|
||||
{
|
||||
if (state->inputlen)
|
||||
{
|
||||
state->fifo = (state->fifo << 8) | *state->inputptr++;
|
||||
state->inputlen--;
|
||||
state->fifolen += 8;
|
||||
}
|
||||
else
|
||||
state->fifo <<= 8;
|
||||
}
|
||||
|
||||
uint8_t data = state->fifo >> (state->fifolen - 8);
|
||||
if (data & 0x80)
|
||||
{
|
||||
data = ((data >> 6) & 0x01) | 0x80;
|
||||
state->fifolen -= 2;
|
||||
}
|
||||
else
|
||||
state->fifolen -= 8;
|
||||
|
||||
if (data)
|
||||
{
|
||||
*state->outputptr++ = data;
|
||||
state->outputlen--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void doneuncrunch(crunch_state_t* state)
|
||||
{
|
||||
if (state->fifolen > 0)
|
||||
{
|
||||
uint8_t b = 0;
|
||||
state->inputptr = &b;
|
||||
state->inputlen = 1;
|
||||
uncrunch(state);
|
||||
}
|
||||
}
|
||||
45
lib/common/crunch.h
Normal file
45
lib/common/crunch.h
Normal file
@@ -0,0 +1,45 @@
|
||||
#ifndef CRUNCH_H
|
||||
#define CRUNCH_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/* To save bandwidth, we compress the byte stream from the sampler when
|
||||
* sending it over USB. The encoding used is:
|
||||
*
|
||||
* 0nnn.nnnn: value 0x00..0x7f
|
||||
* 1n : value 0x80|n
|
||||
*
|
||||
* The end of the buffer is terminated with zeroes, which are ignored
|
||||
* (not written to the output).
|
||||
*
|
||||
* This saves ~40%, which gets us in under the bandwidth cap.
|
||||
*/
|
||||
|
||||
typedef struct crunch_state_t
|
||||
{
|
||||
const uint8_t* inputptr;
|
||||
uint32_t inputlen;
|
||||
uint8_t* outputptr;
|
||||
uint32_t outputlen;
|
||||
uint16_t fifo;
|
||||
uint8_t fifolen;
|
||||
}
|
||||
crunch_state_t;
|
||||
|
||||
/* Crunches as much as possible and then stops. */
|
||||
extern void crunch(crunch_state_t* state);
|
||||
extern void donecrunch(crunch_state_t* state);
|
||||
|
||||
/* Uncrunches as much as possible and then stops. */
|
||||
extern void uncrunch(crunch_state_t* state);
|
||||
extern void doneuncrunch(crunch_state_t* state);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -33,7 +33,10 @@ public:
|
||||
{
|
||||
usbSetDrive(_drive, high_density);
|
||||
usbSeek(track);
|
||||
return usbRead(side, revolutions);
|
||||
Bytes crunched = usbRead(side, revolutions);
|
||||
auto fluxmap = std::make_unique<Fluxmap>();
|
||||
fluxmap->appendBytes(crunched.uncrunch());
|
||||
return fluxmap;
|
||||
}
|
||||
|
||||
void recalibrate()
|
||||
|
||||
@@ -28,7 +28,9 @@ public:
|
||||
{
|
||||
usbSetDrive(_drive, high_density);
|
||||
usbSeek(track);
|
||||
return usbWrite(side, fluxmap);
|
||||
|
||||
Bytes crunched = fluxmap.rawBytes().crunch();
|
||||
return usbWrite(side, crunched);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
@@ -59,10 +59,9 @@ std::unique_ptr<Fluxmap> Track::read()
|
||||
std::cout << fmt::format("{0:>3}.{1}: ", track, side) << std::flush;
|
||||
std::unique_ptr<Fluxmap> fluxmap = _fluxReader->readFlux(track, side);
|
||||
std::cout << fmt::format(
|
||||
"{0} ms in {1} bytes ({2} kB/s)\n",
|
||||
"{0} ms in {1} bytes\n",
|
||||
int(fluxmap->duration()/1e6),
|
||||
fluxmap->bytes(),
|
||||
(int)(1e6 * fluxmap->bytes() / fluxmap->duration()));
|
||||
fluxmap->bytes());
|
||||
if (outdb)
|
||||
sqlWriteFlux(outdb, track, side, *fluxmap);
|
||||
return fluxmap;
|
||||
|
||||
49
lib/usb.cc
49
lib/usb.cc
@@ -3,7 +3,9 @@
|
||||
#include "protocol.h"
|
||||
#include "fluxmap.h"
|
||||
#include "bytes.h"
|
||||
#include "crunch.h"
|
||||
#include <libusb.h>
|
||||
#include <fmt/format.h>
|
||||
|
||||
#define TIMEOUT 5000
|
||||
|
||||
@@ -51,6 +53,8 @@ static void usb_init()
|
||||
|
||||
static int usb_cmd_send(void* ptr, int len)
|
||||
{
|
||||
//std::cerr << "send:\n";
|
||||
//hexdump(std::cerr, Bytes((const uint8_t*)ptr, len));
|
||||
int i = libusb_interrupt_transfer(device, FLUXENGINE_CMD_OUT_EP,
|
||||
(uint8_t*) ptr, len, &len, TIMEOUT);
|
||||
if (i < 0)
|
||||
@@ -64,13 +68,15 @@ void usb_cmd_recv(void* ptr, int len)
|
||||
(uint8_t*) ptr, len, &len, TIMEOUT);
|
||||
if (i < 0)
|
||||
Error() << "failed to receive command reply: " << usberror(i);
|
||||
//std::cerr << "recv:\n";
|
||||
//hexdump(std::cerr, Bytes((const uint8_t*)ptr, len));
|
||||
}
|
||||
|
||||
static void bad_reply(void)
|
||||
{
|
||||
struct error_frame* f = (struct error_frame*) buffer;
|
||||
if (f->f.type != F_FRAME_ERROR)
|
||||
Error() << "bad USB reply " << f->f.type;
|
||||
Error() << fmt::format("bad USB reply 0x{:2x}", f->f.type);
|
||||
switch (f->error)
|
||||
{
|
||||
case F_ERROR_BAD_COMMAND:
|
||||
@@ -80,18 +86,26 @@ static void bad_reply(void)
|
||||
Error() << "USB underrun (not enough bandwidth)";
|
||||
|
||||
default:
|
||||
Error() << "unknown device error " << f->error;
|
||||
Error() << fmt::format("unknown device error {}", f->error);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static T* await_reply(int desired)
|
||||
{
|
||||
usb_cmd_recv(buffer, sizeof(buffer));
|
||||
struct any_frame* r = (struct any_frame*) buffer;
|
||||
if (r->f.type != desired)
|
||||
bad_reply();
|
||||
return (T*) r;
|
||||
for (;;)
|
||||
{
|
||||
usb_cmd_recv(buffer, sizeof(buffer));
|
||||
struct any_frame* r = (struct any_frame*) buffer;
|
||||
if (r->f.type == F_FRAME_DEBUG)
|
||||
{
|
||||
std::cout << "dev: " << ((struct debug_frame*)r)->payload << std::endl;
|
||||
continue;
|
||||
}
|
||||
if (r->f.type != desired)
|
||||
bad_reply();
|
||||
return (T*) r;
|
||||
}
|
||||
}
|
||||
|
||||
int usbGetVersion(void)
|
||||
@@ -188,7 +202,7 @@ void usbTestBulkTransport()
|
||||
await_reply<struct any_frame>(F_FRAME_BULK_TEST_REPLY);
|
||||
}
|
||||
|
||||
std::unique_ptr<Fluxmap> usbRead(int side, int revolutions)
|
||||
Bytes usbRead(int side, int revolutions)
|
||||
{
|
||||
struct read_frame f = {
|
||||
.f = { .type = F_FRAME_READ_CMD, .size = sizeof(f) },
|
||||
@@ -203,20 +217,14 @@ std::unique_ptr<Fluxmap> usbRead(int side, int revolutions)
|
||||
int len = large_bulk_transfer(FLUXENGINE_DATA_IN_EP, buffer);
|
||||
buffer.resize(len);
|
||||
|
||||
fluxmap->appendBytes(buffer);
|
||||
|
||||
await_reply<struct any_frame>(F_FRAME_READ_REPLY);
|
||||
return fluxmap;
|
||||
return buffer;
|
||||
}
|
||||
|
||||
void usbWrite(int side, const Fluxmap& fluxmap)
|
||||
void usbWrite(int side, const Bytes& bytes)
|
||||
{
|
||||
unsigned safelen = fluxmap.bytes() & ~(FRAME_SIZE-1);
|
||||
|
||||
/* Convert from intervals to absolute timestamps. */
|
||||
|
||||
Bytes buffer(fluxmap.rawBytes());
|
||||
buffer.resize(safelen);
|
||||
unsigned safelen = bytes.size() & ~(FRAME_SIZE-1);
|
||||
Bytes safeBytes = bytes.slice(0, safelen);
|
||||
|
||||
struct write_frame f = {
|
||||
.f = { .type = F_FRAME_WRITE_CMD, .size = sizeof(f) },
|
||||
@@ -229,7 +237,7 @@ void usbWrite(int side, const Fluxmap& fluxmap)
|
||||
|
||||
usb_cmd_send(&f, f.f.size);
|
||||
|
||||
large_bulk_transfer(FLUXENGINE_DATA_OUT_EP, buffer);
|
||||
large_bulk_transfer(FLUXENGINE_DATA_OUT_EP, safeBytes);
|
||||
|
||||
await_reply<struct any_frame>(F_FRAME_WRITE_REPLY);
|
||||
}
|
||||
@@ -251,8 +259,7 @@ void usbSetDrive(int drive, bool high_density)
|
||||
|
||||
struct set_drive_frame f = {
|
||||
{ .type = F_FRAME_SET_DRIVE_CMD, .size = sizeof(f) },
|
||||
.drive = (uint8_t) drive,
|
||||
.high_density = (uint8_t) high_density,
|
||||
.drive_flags = (uint8_t)((drive ? DRIVE_1 : DRIVE_0) | (high_density ? DRIVE_HD : DRIVE_DD)),
|
||||
};
|
||||
usb_cmd_send(&f, f.f.size);
|
||||
await_reply<struct any_frame>(F_FRAME_SET_DRIVE_REPLY);
|
||||
|
||||
@@ -2,14 +2,15 @@
|
||||
#define USB_H
|
||||
|
||||
class Fluxmap;
|
||||
class Bytes;
|
||||
|
||||
extern int usbGetVersion();
|
||||
extern void usbRecalibrate();
|
||||
extern void usbSeek(int track);
|
||||
extern nanoseconds_t usbGetRotationalPeriod();
|
||||
extern void usbTestBulkTransport();
|
||||
extern std::unique_ptr<Fluxmap> usbRead(int side, int revolutions);
|
||||
extern void usbWrite(int side, const Fluxmap& fluxmap);
|
||||
extern Bytes usbRead(int side, int revolutions);
|
||||
extern void usbWrite(int side, const Bytes& bytes);
|
||||
extern void usbErase(int side);
|
||||
extern void usbSetDrive(int drive, bool high_density);
|
||||
|
||||
|
||||
@@ -70,8 +70,9 @@ void writeTracks(
|
||||
sqlWriteFlux(outdb, location.track, location.side, *fluxmap);
|
||||
else
|
||||
{
|
||||
Bytes crunched = fluxmap->rawBytes().crunch();
|
||||
usbSeek(location.track);
|
||||
usbWrite(location.side, *fluxmap);
|
||||
usbWrite(location.side, crunched);
|
||||
}
|
||||
std::cout << fmt::format(
|
||||
"{0} ms in {1} bytes", int(fluxmap->duration()/1e6), fluxmap->bytes()) << std::endl;
|
||||
|
||||
14
meson.build
14
meson.build
@@ -1,4 +1,4 @@
|
||||
project('fluxclient', 'cpp')
|
||||
project('fluxclient', 'c', 'cpp')
|
||||
add_global_arguments('--std=c++14', language: 'cpp')
|
||||
|
||||
libusb = dependency('libusb-1.0')
|
||||
@@ -17,6 +17,15 @@ fmtlib = declare_dependency(
|
||||
include_directories('dep/fmt')
|
||||
)
|
||||
|
||||
crunchlib = declare_dependency(
|
||||
link_with:
|
||||
shared_library('crunch',
|
||||
['lib/common/crunch.c']
|
||||
),
|
||||
include_directories:
|
||||
include_directories('lib/common')
|
||||
)
|
||||
|
||||
felib = declare_dependency(
|
||||
link_with:
|
||||
shared_library('felib',
|
||||
@@ -33,7 +42,7 @@ felib = declare_dependency(
|
||||
'lib/usb.cc',
|
||||
'lib/bytes.cc',
|
||||
],
|
||||
dependencies: [fmtlib, libusb, zlib]
|
||||
dependencies: [fmtlib, crunchlib, libusb, zlib]
|
||||
),
|
||||
include_directories:
|
||||
include_directories('lib')
|
||||
@@ -245,3 +254,4 @@ test('BitAccumulator', executable('bitaccumulator-test', ['tests/bitaccumulator
|
||||
test('Kryoflux', executable('kryoflux-test', ['tests/kryoflux.cc'], dependencies: [felib, decoderlib, fluxreaderlib]))
|
||||
test('Compression', executable('compression-test', ['tests/compression.cc'], dependencies: [felib, decoderlib]))
|
||||
test('Bytes', executable('bytes-test', ['tests/bytes.cc'], dependencies: [felib]))
|
||||
test('Crunch', executable('crunch-test', ['tests/crunch.cc'], dependencies: [felib, crunchlib]))
|
||||
|
||||
18
protocol.h
18
protocol.h
@@ -3,7 +3,7 @@
|
||||
|
||||
enum
|
||||
{
|
||||
FLUXENGINE_VERSION = 5,
|
||||
FLUXENGINE_VERSION = 8,
|
||||
|
||||
FLUXENGINE_VID = 0x1209,
|
||||
FLUXENGINE_PID = 0x6e00,
|
||||
@@ -23,6 +23,11 @@ enum
|
||||
SIDE_SIDEA = 0<<0,
|
||||
SIDE_SIDEB = 1<<0,
|
||||
|
||||
DRIVE_0 = 0,
|
||||
DRIVE_1 = 1,
|
||||
DRIVE_DD = 0<<1,
|
||||
DRIVE_HD = 1<<1,
|
||||
|
||||
FRAME_SIZE = 64,
|
||||
TICK_FREQUENCY = 12000000,
|
||||
TICKS_PER_US = TICK_FREQUENCY / 1000000,
|
||||
@@ -38,6 +43,7 @@ enum
|
||||
enum
|
||||
{
|
||||
F_FRAME_ERROR = 0, /* any_frame */
|
||||
F_FRAME_DEBUG, /* debug_frame */
|
||||
F_FRAME_GET_VERSION_CMD, /* any_frame */
|
||||
F_FRAME_GET_VERSION_REPLY, /* version_frame */
|
||||
F_FRAME_SEEK_CMD, /* seek_frame */
|
||||
@@ -64,6 +70,7 @@ enum
|
||||
F_ERROR_BAD_COMMAND,
|
||||
F_ERROR_UNDERRUN,
|
||||
F_ERROR_INVALID_VALUE,
|
||||
F_ERROR_INTERNAL,
|
||||
};
|
||||
|
||||
struct frame_header
|
||||
@@ -83,6 +90,12 @@ struct error_frame
|
||||
uint8_t error;
|
||||
};
|
||||
|
||||
struct debug_frame
|
||||
{
|
||||
struct frame_header f;
|
||||
char payload[60];
|
||||
};
|
||||
|
||||
struct version_frame
|
||||
{
|
||||
struct frame_header f;
|
||||
@@ -124,8 +137,7 @@ struct erase_frame
|
||||
struct set_drive_frame
|
||||
{
|
||||
struct frame_header f;
|
||||
uint8_t drive;
|
||||
uint8_t high_density;
|
||||
uint8_t drive_flags;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -112,7 +112,8 @@ int main(int argc, const char* argv[])
|
||||
}
|
||||
|
||||
nanoseconds_t length = transition - lasttransition;
|
||||
std::cout << fmt::format("==== {: 10.3f} +{:.3f} = {:.1f} clocks",
|
||||
std::cout << fmt::format("==== {:06x} {: 10.3f} +{:.3f} = {:.1f} clocks",
|
||||
fr.tell(),
|
||||
(double)transition / 1000.0,
|
||||
(double)length / 1000.0,
|
||||
(double)length / clockPeriod);
|
||||
@@ -129,8 +130,16 @@ int main(int argc, const char* argv[])
|
||||
size_t cursor = seekFlag*1000000.0 / clockPeriod;
|
||||
while (cursor < bitmap.size())
|
||||
{
|
||||
std::cout << (bitmap[cursor] ? 'X' : '-');
|
||||
cursor++;
|
||||
std::cout << fmt::format("{: 10.3f} : ", (double)cursor / clockPeriod);
|
||||
for (unsigned i=0; i<60; i++)
|
||||
{
|
||||
if (cursor >= bitmap.size())
|
||||
break;
|
||||
std::cout << (bitmap[cursor] ? 'X' : '-');
|
||||
cursor++;
|
||||
}
|
||||
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
std::cout << std::endl;
|
||||
|
||||
43
tests/crunch.cc
Normal file
43
tests/crunch.cc
Normal file
@@ -0,0 +1,43 @@
|
||||
#include "globals.h"
|
||||
#include "bytes.h"
|
||||
#include "crunch.h"
|
||||
|
||||
static uint8_t outputbuffer[64];
|
||||
|
||||
static void test_crunch()
|
||||
{
|
||||
crunch_state_t cs = {};
|
||||
Bytes inputdata = { 0x01, 0x7f, 0x80, 0x81, 0x01 };
|
||||
cs.inputptr = inputdata.begin();
|
||||
cs.inputlen = inputdata.size();
|
||||
cs.outputptr = outputbuffer;
|
||||
cs.outputlen = 64;
|
||||
crunch(&cs);
|
||||
donecrunch(&cs);
|
||||
Bytes outputdata(outputbuffer, cs.outputptr - outputbuffer);
|
||||
|
||||
assert((outputdata == Bytes{ 0x01, 0x7f, 0xb0, 0x10 }));
|
||||
}
|
||||
|
||||
static void test_uncrunch()
|
||||
{
|
||||
crunch_state_t cs = {};
|
||||
Bytes inputdata = { 0x01, 0x7f, 0xb0, 0x10 };
|
||||
cs.inputptr = inputdata.begin();
|
||||
cs.inputlen = inputdata.size();
|
||||
cs.outputptr = outputbuffer;
|
||||
cs.outputlen = 64;
|
||||
uncrunch(&cs);
|
||||
doneuncrunch(&cs);
|
||||
Bytes outputdata(outputbuffer, cs.outputptr - outputbuffer);
|
||||
|
||||
assert((outputdata == Bytes { 0x01, 0x7f, 0x80, 0x81, 0x01 }));
|
||||
}
|
||||
|
||||
int main(int argc, const char* argv[])
|
||||
{
|
||||
test_crunch();
|
||||
test_uncrunch();
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user