123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292 |
- /*
- LUFA Library
- Copyright (C) Dean Camera, 2021.
- dean [at] fourwalledcubicle [dot] com
- www.lufa-lib.org
- */
- /*
- Copyright 2021 Dean Camera (dean [at] fourwalledcubicle [dot] com)
- Permission to use, copy, modify, distribute, and sell this
- software and its documentation for any purpose is hereby granted
- without fee, provided that the above copyright notice appear in
- all copies and that both that the copyright notice and this
- permission notice and warranty disclaimer appear in supporting
- documentation, and that the name of the author not be used in
- advertising or publicity pertaining to distribution of the
- software without specific, written prior permission.
- The author disclaims all warranties with regard to this
- software, including all implied warranties of merchantability
- and fitness. In no event shall the author be liable for any
- special, indirect or consequential damages or any damages
- whatsoever resulting from loss of use, data or profits, whether
- in an action of contract, negligence or other tortious action,
- arising out of or in connection with the use or performance of
- 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.
- */
- #include "usbcas.h"
- /*
- * Probe for modem control status bits and send them if changed,
- * or if forced...
- */
- static void update_modem_status(USB_ClassInfo_CDC_Device_t* const CDCInterfaceInfo, bool forced)
- {
- uint16_t lines = CDC_CONTROL_LINE_IN_DSR;
- if (!(PINB & (1 << 4))) /* Cassette relay active */
- lines |= CDC_CONTROL_LINE_IN_DCD;
- #if 0
- if (lines & CDC_CONTROL_LINE_IN_DCD)
- PORTB &= ~(1U << 0);
- else
- PORTB |= (1U << 0);
- #endif
- if (forced || CDCInterfaceInfo->State.ControlLineStates.DeviceToHost != lines) {
- CDCInterfaceInfo->State.ControlLineStates.DeviceToHost = lines;
- CDC_Device_SendControlLineStateChange(CDCInterfaceInfo);
- }
- }
- /* This is called in the main loop, but also any time we are waiting on something... */
- void do_usb_task(void)
- {
- /* Update modem flags if needed */
- update_modem_status(&VirtualSerial_CDC_Interface, false);
- CDC_Device_USBTask(&VirtualSerial_CDC_Interface);
- USB_USBTask();
- }
- /** 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));
- 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 */
- }
- }
- 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)
- {
- break;
- }
- /* Dequeue the already sent byte from the buffer now we have confirmed that no transmission error occurred */
- RingBuffer_Remove(&CAStoUSB_Buffer);
- }
- }
- }
- do_usb_task();
- }
- }
- static uint32_t current_baudrate;
- /** Configures the board hardware and chip peripherals for the demo's functionality. */
- void SetupHardware(void)
- {
- #if (ARCH == ARCH_AVR8)
- /* Disable watchdog if enabled by bootloader/fuses */
- MCUSR &= ~(1 << WDRF);
- wdt_disable();
- /* Disable clock division */
- clock_prescale_set(clock_div_1);
- #endif
- /* Hardware Initialization */
- USB_Init();
- /* PORTB: PB0 - RXLED, PB4 - Relay (pullup), PB5 - relay out */
- PORTB |= (1 << 0) | (1 << 4);
- DDRB = (DDRB & ~((1 << 4))) | ((1 << 0) | (1 << 5));
- /* Initialize receiver and transmitter */
- fmrx_init();
- current_baudrate = fmtx_real_baudrate(0);
- fmrx_set_speed(current_baudrate);
- fmtx_init_speed(current_baudrate);
- }
- /** Event handler for the library USB Connection event. */
- void EVENT_USB_Device_Connect(void)
- {
- }
- /** Event handler for the library USB Disconnection event. */
- void EVENT_USB_Device_Disconnect(void)
- {
- }
- /** Event handler for the library USB Configuration Changed event. */
- void EVENT_USB_Device_ConfigurationChanged(void)
- {
- bool success = true;
- success &= CDC_Device_ConfigureEndpoints(&VirtualSerial_CDC_Interface);
- if (success)
- update_modem_status(&VirtualSerial_CDC_Interface, true);
- }
- /** Event handler for the library USB Control Request reception event. */
- void EVENT_USB_Device_ControlRequest(void)
- {
- CDC_Device_ProcessControlRequest(&VirtualSerial_CDC_Interface);
- }
- /*
- * Called from the demodulation ISR to push a new byte into the buffer
- */
- void fmrx_recv_byte(uint8_t byte)
- {
- if (USB_DeviceState == DEVICE_STATE_Configured &&
- !RingBuffer_IsFull(&CAStoUSB_Buffer))
- RingBuffer_Insert(&CAStoUSB_Buffer, byte);
- }
- /*
- * Called from the transmit register empty ISR to fetch a new byte;
- * returns -1 if the ring buffer is empty.
- */
- int fmtx_next_byte(void)
- {
- if (USB_DeviceState != DEVICE_STATE_Configured ||
- RingBuffer_IsEmpty(&USBtoCAS_Buffer))
- return -1;
- return RingBuffer_Remove(&USBtoCAS_Buffer);
- }
- /** Event handler for the CDC Class driver Line Encoding Changed event.
- *
- * \param[in] CDCInterfaceInfo Pointer to the CDC class interface configuration structure being referenced
- */
- void EVENT_CDC_Device_LineEncodingChanged(USB_ClassInfo_CDC_Device_t* const CDCInterfaceInfo)
- {
- uint32_t baudrate = CDCInterfaceInfo->State.LineEncoding.BaudRateBPS;
- if (baudrate == 9600)
- baudrate = CAS_BAUDRATE_ABC80;
- baudrate = fmtx_real_baudrate(baudrate);
- if (1 || baudrate != current_baudrate) {
- current_baudrate = baudrate;
- fmtx_drain();
- fmrx_set_speed(current_baudrate);
- fmtx_init_speed(current_baudrate);
- }
- }
- /*
- * Control lines changed
- */
- void EVENT_CDC_Device_ControLineStateChanged(USB_ClassInfo_CDC_Device_t* const CDCInterfaceInfo)
- {
- /* 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
- }
|