/* * spreadspace avr utils * * * Copyright (C) 2012 Christian Pointner * * This file is part of spreadspace avr utils. * * spreadspace avr utils is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * spreadspace avr utils is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with spreadspace avr utils. If not, see . */ /* this is more or less the same as the LUFA example Project USBtoSerial and this is their LICENSE Header */ /* LUFA Library Copyright (C) Dean Camera, 2012. dean [at] fourwalledcubicle [dot] com www.lufa-lib.org */ /* Copyright 2012 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 disclaim 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 #include #include #include #include "lufa-descriptor-usbserial.h" #include "util.h" #include "led.h" #include #include #include /* Hardware Defines: */ #define SPI_DDR DDRB #define SPI_PORT PORTB #define SPI_PINB_REG PINB #define CS 0 #define SCK 1 #define MOSI 2 #define MISO 3 /* Function Prototypes: */ void SetupHardware(void); void SPI_TransferBuffer(void); void EVENT_USB_Device_Connect(void); void EVENT_USB_Device_Disconnect(void); void EVENT_USB_Device_ConfigurationChanged(void); void EVENT_USB_Device_ControlRequest(void); void EVENT_CDC_Device_LineEncodingChanged(USB_ClassInfo_CDC_Device_t* const CDCInterfaceInfo); /** Circular buffer to hold data from the host before it is sent to the device via the serial port. */ static RingBuffer_t USBtoSPI_Buffer; /** Underlying data buffer for \ref USBtoSPI_Buffer, where the stored bytes are located. */ static uint8_t USBtoSPI_Buffer_Data[128]; /** Circular buffer to hold data from the serial port before it is sent to the host. */ static RingBuffer_t SPItoUSB_Buffer; /** Underlying data buffer for \ref SPItoUSB_Buffer, where the stored bytes are located. */ static uint8_t SPItoUSB_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 = 0, .DataINEndpointNumber = CDC_TX_EPNUM, .DataINEndpointSize = CDC_TXRX_EPSIZE, .DataINEndpointDoubleBank = false, .DataOUTEndpointNumber = CDC_RX_EPNUM, .DataOUTEndpointSize = CDC_TXRX_EPSIZE, .DataOUTEndpointDoubleBank = false, .NotificationEndpointNumber = CDC_NOTIFICATION_EPNUM, .NotificationEndpointSize = CDC_NOTIFICATION_EPSIZE, .NotificationEndpointDoubleBank = 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(&USBtoSPI_Buffer, USBtoSPI_Buffer_Data, sizeof(USBtoSPI_Buffer_Data)); RingBuffer_InitBuffer(&SPItoUSB_Buffer, SPItoUSB_Buffer_Data, sizeof(SPItoUSB_Buffer_Data)); sei(); for (;;) { int16_t BytesReceived = CDC_Device_BytesReceived(&VirtualSerial_CDC_Interface); while(BytesReceived > 0) { if(!(RingBuffer_IsFull(&USBtoSPI_Buffer))) { int16_t ReceivedByte = CDC_Device_ReceiveByte(&VirtualSerial_CDC_Interface); /* Read bytes from the USB OUT endpoint into the SPI transmit buffer */ if (!(ReceivedByte < 0)) RingBuffer_Insert(&USBtoSPI_Buffer, ReceivedByte); BytesReceived--; } } /* Check if the SPI receive buffer flush timer has expired or the buffer is nearly full */ uint16_t BufferCount = RingBuffer_GetCount(&SPItoUSB_Buffer); if ((TIFR0 & (1 << TOV0)) || (BufferCount > (uint8_t)(sizeof(SPItoUSB_Buffer_Data) * .75))) { /* Clear flush timer expiry flag */ TIFR0 |= (1 << TOV0); /* Read bytes from the SPI receive buffer into the USB IN endpoint */ while (BufferCount--) { /* 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(&SPItoUSB_Buffer)) != ENDPOINT_READYWAIT_NoError) { break; } /* Dequeue the already sent byte from the buffer now we have confirmed that no transmission error occurred */ RingBuffer_Remove(&SPItoUSB_Buffer); } } /* Load the next byte from the SPI transmit buffer into the SPI Interface */ if (!(RingBuffer_IsEmpty(&USBtoSPI_Buffer))) SPI_TransferBuffer(); CDC_Device_USBTask(&VirtualSerial_CDC_Interface); USB_USBTask(); } } /** Configures the board hardware and chip peripherals for the demo's functionality. */ void SetupHardware(void) { /* Disable watchdog if enabled by bootloader/fuses */ MCUSR &= ~(1 << WDRF); wdt_disable(); cpu_init(); led_init(); USB_Init(); /* Start the flush timer so that overflows occur rapidly to push received bytes to the USB interface */ TCCR0B = (1 << CS02); /* Initialize SPI Interfaces configure Direction of SS / PB0 , MOSI and SCLK as Output */ SPI_DDR = (1<