Pārlūkot izejas kodu

usbcas: clean up insane formatting

H. Peter Anvin 3 gadi atpakaļ
vecāks
revīzija
4219e3b809
2 mainītis faili ar 140 papildinājumiem un 120 dzēšanām
  1. BIN
      USBCAS/usbcas-pin.ods
  2. 140 120
      USBCAS/usbcas.c

BIN
USBCAS/usbcas-pin.ods


+ 140 - 120
USBCAS/usbcas.c

@@ -1,3 +1,11 @@
+/*
+ * usbcas.c
+ *
+ * Emulator for the ABC80/800 cassette port
+ * Based in part on USBtoSerial.c from the LUFA library
+ *
+ * Copyright (C) 2021 H. Peter Anvin
+ */
 /*
              LUFA Library
      Copyright (C) Dean Camera, 2021.
@@ -28,69 +36,53 @@
   this software.
 */
 
-/** \file
- *
- *  Main source file for the USBtoSerial project. This file contains the main tasks of
- *  the project and is responsible for the initial application hardware configuration.
- */
-
 #include "usbcas.h"
 
-/** Circular buffer to hold data from the host before it is sent to the device via the serial port. */
-static RingBuffer_t USBtoCAS_Buffer;
-
-/** Underlying data buffer for \ref USBtoCAS_Buffer, where the stored bytes are located. */
-static uint8_t      USBtoCAS_Buffer_Data[128];
-
-/** Circular buffer to hold data from the serial port before it is sent to the host. */
-static RingBuffer_t CAStoUSB_Buffer;
-
-/** Underlying data buffer for \ref CAStoUSB_Buffer, where the stored bytes are located. */
-static uint8_t      CAStoUSB_Buffer_Data[128];
-
-/** LUFA CDC Class driver interface configuration and state information. This structure is
- *  passed to all CDC Class driver functions, so that multiple instances of the same class
- *  within a device can be differentiated from one another.
- */
-USB_ClassInfo_CDC_Device_t VirtualSerial_CDC_Interface =
-	{
-		.Config =
-			{
-				.ControlInterfaceNumber         = INTERFACE_ID_CDC_CCI,
-				.DataINEndpoint                 =
-					{
-						.Address                = CDC_TX_EPADDR,
-						.Size                   = CDC_TXRX_EPSIZE,
-						.Banks                  = 1,
-					},
-				.DataOUTEndpoint                =
-					{
-						.Address                = CDC_RX_EPADDR,
-						.Size                   = CDC_TXRX_EPSIZE,
-						.Banks                  = 1,
-					},
-				.NotificationEndpoint           =
-					{
-						.Address                = CDC_NOTIFICATION_EPADDR,
-						.Size                   = CDC_NOTIFICATION_EPSIZE,
-						.Banks                  = 1,
-					},
-			},
-	};
-
-
 /*
- * Transmit an FM-modulated signal using the USART in SPI master mode.
- * As per ABC standard, this signal is transmitted LSB first.
+ * Input and output ring buffers
  */
-
-#include "usbcas.h"
+static RingBuffer_t u2c_ringbuf;	/* USB -> CDC */
+static uint8_t      u2c_buffer[128];
+static RingBuffer_t c2u_ringbuf;	/* CDC -> USB */
+static uint8_t      c2u_buffer[128];
+
+/**
+ * LUFA CDC Class driver interface configuration and state
+ * information. This structure is passed to all CDC Class driver
+ *  functions, so that multiple instances of the same class within a
+ *  device can be differentiated from one another.
+ *
+ * "vcpif" stands for "Virtual COM Port Interface".
+ */
+USB_ClassInfo_CDC_Device_t vcpif = {
+	.Config = {
+		.ControlInterfaceNumber         = INTERFACE_ID_CDC_CCI,
+		.DataINEndpoint                 = {
+			.Address                = CDC_TX_EPADDR,
+			.Size                   = CDC_TXRX_EPSIZE,
+			.Banks                  = 1,
+		},
+		.DataOUTEndpoint                = {
+			.Address                = CDC_RX_EPADDR,
+			.Size                   = CDC_TXRX_EPSIZE,
+			.Banks                  = 1,
+		},
+		.NotificationEndpoint           =
+		{
+			.Address                = CDC_NOTIFICATION_EPADDR,
+			.Size                   = CDC_NOTIFICATION_EPSIZE,
+			.Banks                  = 1,
+		},
+	},
+};
 
 /*
  * Probe for modem control status bits and send them if changed,
- * or if forced...
+ * or if forced. DSR is always set, DCD indicates if the cassette
+ * motor relay is active.
  */
-static void update_modem_status(USB_ClassInfo_CDC_Device_t* const CDCInterfaceInfo, bool forced)
+static void update_modem_status(USB_ClassInfo_CDC_Device_t * const cii,
+				bool forced)
 {
 	uint16_t lines = CDC_CONTROL_LINE_IN_DSR;
 
@@ -104,74 +96,109 @@ static void update_modem_status(USB_ClassInfo_CDC_Device_t* const CDCInterfaceIn
 		PORTB |= (1U << 0);
 #endif
 
-	if (forced || CDCInterfaceInfo->State.ControlLineStates.DeviceToHost != lines) {
-		CDCInterfaceInfo->State.ControlLineStates.DeviceToHost = lines;
-		CDC_Device_SendControlLineStateChange(CDCInterfaceInfo);
+	if (forced || cii->State.ControlLineStates.DeviceToHost != lines) {
+		cii->State.ControlLineStates.DeviceToHost = lines;
+		CDC_Device_SendControlLineStateChange(cii);
 	}
 }
 
-/* This is called in the main loop, but also any time we are waiting on something... */
+/*
+ * This is called in the main loop, but also any time we are busy-waiting
+ * on something.
+ */
 void do_usb_task(void)
 {
 	/* Update modem flags if needed */
-	update_modem_status(&VirtualSerial_CDC_Interface, false);
+	update_modem_status(&vcpif, false);
 
-	CDC_Device_USBTask(&VirtualSerial_CDC_Interface);
+	CDC_Device_USBTask(&vcpif);
 	USB_USBTask();
 }
 
-/** Main program entry point. This routine contains the overall program flow, including initial
- *  setup of all components and the main program loop.
+/*
+ * Try to send the next byte of data to the host, abort without
+ * dequeuing if there is an error. Returns true on error.
+ */
+static bool usb_send_next_byte(void)
+{
+	uint8_t byte = RingBuffer_Peek(&c2u_ringbuf);
+
+	if (CDC_Device_SendByte(&vcpif, byte) != ENDPOINT_READYWAIT_NoError)
+		return true;
+
+	/*
+	 * Dequeue the already sent byte from the buffer now we have
+	 * confirmed that no transmission error occurred
+	 */
+	RingBuffer_Remove(&c2u_ringbuf);
+	return false;
+}
+
+/*
+ * Main program entry point. This routine contains the overall program
+ * flow, including initial setup of
+ * all components and the main program
+ * loop.
  */
 int main(void)
 {
 	SetupHardware();
 
-	RingBuffer_InitBuffer(&USBtoCAS_Buffer, USBtoCAS_Buffer_Data, sizeof(USBtoCAS_Buffer_Data));
-	RingBuffer_InitBuffer(&CAStoUSB_Buffer, CAStoUSB_Buffer_Data, sizeof(CAStoUSB_Buffer_Data));
+	RingBuffer_InitBuffer(&u2c_ringbuf, u2c_buffer, sizeof(u2c_buffer));
+	RingBuffer_InitBuffer(&c2u_ringbuf, c2u_buffer, sizeof(c2u_buffer));
 
 	GlobalInterruptEnable();
 
 	for (;;)
 	{
-		/* Only try to read in bytes from the CDC interface if the transmit buffer is not full */
-		if (!(RingBuffer_IsFull(&USBtoCAS_Buffer)))
-		{
-			int16_t ReceivedByte = CDC_Device_ReceiveByte(&VirtualSerial_CDC_Interface);
-
-			/* Store received byte into the USART transmit buffer */
-			if (!(ReceivedByte < 0)) {
-				RingBuffer_Insert(&USBtoCAS_Buffer, ReceivedByte);
-				fmtx_enable(); /* Enable TX interrupt routine if disabled */
+		/*
+		 * Only try to read in bytes from the CDC interface if
+		 * the transmit buffer is not full
+		*/
+		if (!(RingBuffer_IsFull(&u2c_ringbuf))) {
+			int byte;
+
+			byte = CDC_Device_ReceiveByte(&vcpif);
+
+			/*
+			 * Store received byte into the transmit buffer, then
+			 * enable the transmit ISR if disabled
+			 */
+			if (byte >= 0) {
+				RingBuffer_Insert(&u2c_ringbuf, byte);
+				fmtx_enable();
 			}
 		}
 
-		uint16_t BufferCount = RingBuffer_GetCount(&CAStoUSB_Buffer);
-		if (BufferCount)
-		{
-			Endpoint_SelectEndpoint(VirtualSerial_CDC_Interface.Config.DataINEndpoint.Address);
-
-			/* Check if a packet is already enqueued to the host - if so, we shouldn't try to send more data
-			 * until it completes as there is a chance nothing is listening and a lengthy timeout could occur */
-			if (Endpoint_IsINReady())
-			{
-				/* Never send more than one bank size less one byte to the host at a time, so that we don't block
-				 * while a Zero Length Packet (ZLP) to terminate the transfer is sent if the host isn't listening */
-				uint8_t BytesToSend = MIN(BufferCount, (CDC_TXRX_EPSIZE - 1));
-
-				/* Read bytes from the USART receive buffer into the USB IN endpoint */
-				while (BytesToSend--)
-				{
-					/* Try to send the next byte of data to the host, abort if there is an error without dequeuing */
-					if (CDC_Device_SendByte(&VirtualSerial_CDC_Interface,
-								RingBuffer_Peek(&CAStoUSB_Buffer)) != ENDPOINT_READYWAIT_NoError)
-					{
+		uint16_t outbytes = RingBuffer_GetCount(&c2u_ringbuf);
+		if (outbytes) {
+			Endpoint_SelectEndpoint(vcpif.Config.DataINEndpoint.Address);
+
+			/*
+			 * Check if a packet is already enqueued to
+			 * the host - if so, we shouldn't try to send
+			 * more data until it completes as there is a
+			 * chance nothing is listening and a lengthy
+			 * timeout could occur
+			 */
+			if (Endpoint_IsINReady()) {
+				/*
+				 * Never send more than one bank size
+				 * less one byte to the host at a
+				 * time, so that we don't block while
+				 * a Zero Length Packet (ZLP) to
+				 * terminate the transfer is sent if
+				 * the host isn't listening */
+				outbytes = MIN(outbytes, (CDC_TXRX_EPSIZE - 1));
+
+				/*
+				 * Transfer output bytes to the USB
+				 * endpoint. Abort without dequeuing if
+				 * there is an error.
+				 */
+				while (outbytes--)
+					if (usb_send_next_byte())
 						break;
-					}
-
-					/* Dequeue the already sent byte from the buffer now we have confirmed that no transmission error occurred */
-					RingBuffer_Remove(&CAStoUSB_Buffer);
-				}
 			}
 		}
 
@@ -222,15 +249,15 @@ void EVENT_USB_Device_ConfigurationChanged(void)
 {
 	bool success = true;
 
-	success &= CDC_Device_ConfigureEndpoints(&VirtualSerial_CDC_Interface);
+	success &= CDC_Device_ConfigureEndpoints(&vcpif);
 	if (success)
-		update_modem_status(&VirtualSerial_CDC_Interface, true);
+		update_modem_status(&vcpif, true);
 }
 
 /** Event handler for the library USB Control Request reception event. */
 void EVENT_USB_Device_ControlRequest(void)
 {
-	CDC_Device_ProcessControlRequest(&VirtualSerial_CDC_Interface);
+	CDC_Device_ProcessControlRequest(&vcpif);
 }
 
 /*
@@ -239,8 +266,8 @@ void EVENT_USB_Device_ControlRequest(void)
 void fmrx_recv_byte(uint8_t byte)
 {
 	if (USB_DeviceState == DEVICE_STATE_Configured &&
-	    !RingBuffer_IsFull(&CAStoUSB_Buffer))
-		RingBuffer_Insert(&CAStoUSB_Buffer, byte);
+	    !RingBuffer_IsFull(&c2u_ringbuf))
+		RingBuffer_Insert(&c2u_ringbuf, byte);
 }
 
 /*
@@ -250,20 +277,20 @@ void fmrx_recv_byte(uint8_t byte)
 int fmtx_next_byte(void)
 {
 	if (USB_DeviceState != DEVICE_STATE_Configured ||
-	    RingBuffer_IsEmpty(&USBtoCAS_Buffer))
+	    RingBuffer_IsEmpty(&u2c_ringbuf))
 		return -1;
 
-	return RingBuffer_Remove(&USBtoCAS_Buffer);
+	return RingBuffer_Remove(&u2c_ringbuf);
 }
 
-/** Event handler for the CDC Class driver Line Encoding Changed event.
- *
- *  \param[in] CDCInterfaceInfo  Pointer to the CDC class interface configuration structure being referenced
+/*
+ * Event handler for the CDC Class driver Line Encoding Changed event.
  */
-void EVENT_CDC_Device_LineEncodingChanged(USB_ClassInfo_CDC_Device_t* const CDCInterfaceInfo)
+void EVENT_CDC_Device_LineEncodingChanged(USB_ClassInfo_CDC_Device_t* const cii)
 {
-	uint32_t baudrate = CDCInterfaceInfo->State.LineEncoding.BaudRateBPS;
+	uint32_t baudrate = cii->State.LineEncoding.BaudRateBPS;
 
+	/* This is a hack to give a sensible default */
 	if (baudrate == 9600)
 		baudrate = CAS_BAUDRATE_ABC80;
 
@@ -278,15 +305,8 @@ void EVENT_CDC_Device_LineEncodingChanged(USB_ClassInfo_CDC_Device_t* const CDCI
 }
 
 /*
- * Control lines changed
+ * Event handler for control line changes
  */
-void EVENT_CDC_Device_ControLineStateChanged(USB_ClassInfo_CDC_Device_t* const CDCInterfaceInfo)
+void EVENT_CDC_Device_ControLineStateChanged(USB_ClassInfo_CDC_Device_t* const cii)
 {
-	/* Indicate the DTR line via RXLED for now */
-#if 0
-	if (CDCInterfaceInfo->State.ControlLineStates.HostToDevice & CDC_CONTROL_LINE_OUT_DTR)
-		PORTB &= ~(1U << 0);
-	else
-		PORTB |= (1U << 0);
-#endif
 }