/*************************************************************************** * Copyright (C) 02/2021 by Olaf Rempel * * razzor@kopf-tisch.de * * * * This program 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; version 2 of the License, * * * * This program 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 this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include #include #include "event.h" #include "ledfade.h" #include "pwm.h" #include "usbcdc.h" /* *********************************************************************** */ #define CDC_NOTIFICATION_EPADDR (ENDPOINT_DIR_IN | 2) #define CDC_TX_EPADDR (ENDPOINT_DIR_IN | 3) #define CDC_RX_EPADDR (ENDPOINT_DIR_OUT | 4) #define CDC_NOTIFICATION_EPSIZE 8 #define CDC_TXRX_EPSIZE 16 typedef struct { USB_Descriptor_Configuration_Header_t Config; // CDC Control Interface USB_Descriptor_Interface_t CDC_CCI_Interface; USB_CDC_Descriptor_FunctionalHeader_t CDC_Functional_Header; USB_CDC_Descriptor_FunctionalACM_t CDC_Functional_ACM; USB_CDC_Descriptor_FunctionalUnion_t CDC_Functional_Union; USB_Descriptor_Endpoint_t CDC_NotificationEndpoint; // CDC Data Interface USB_Descriptor_Interface_t CDC_DCI_Interface; USB_Descriptor_Endpoint_t CDC_DataOutEndpoint; USB_Descriptor_Endpoint_t CDC_DataInEndpoint; } USB_Descriptor_Configuration_t; enum InterfaceDescriptors_t { INTERFACE_ID_CDC_CCI = 0, INTERFACE_ID_CDC_DCI = 1, }; enum StringDescriptors_t { STRING_ID_Language = 0, STRING_ID_Manufacturer = 1, STRING_ID_Product = 2, }; /* *********************************************************************** */ const USB_Descriptor_Device_t PROGMEM DeviceDescriptor = { .Header = {.Size = sizeof(USB_Descriptor_Device_t), .Type = DTYPE_Device}, .USBSpecification = VERSION_BCD(1,1,0), .Class = CDC_CSCP_CDCClass, .SubClass = CDC_CSCP_NoSpecificSubclass, .Protocol = CDC_CSCP_NoSpecificProtocol, .Endpoint0Size = FIXED_CONTROL_ENDPOINT_SIZE, .VendorID = 0x03EB, .ProductID = 0x2044, .ReleaseNumber = VERSION_BCD(0,0,1), .ManufacturerStrIndex = STRING_ID_Manufacturer, .ProductStrIndex = STRING_ID_Product, .SerialNumStrIndex = USE_INTERNAL_SERIAL, .NumberOfConfigurations = FIXED_NUM_CONFIGURATIONS }; const USB_Descriptor_Configuration_t PROGMEM ConfigurationDescriptor = { .Config = { .Header = {.Size = sizeof(USB_Descriptor_Configuration_Header_t), .Type = DTYPE_Configuration}, .TotalConfigurationSize = sizeof(USB_Descriptor_Configuration_t), .TotalInterfaces = 2, .ConfigurationNumber = 1, .ConfigurationStrIndex = NO_DESCRIPTOR, .ConfigAttributes = (USB_CONFIG_ATTR_RESERVED | USB_CONFIG_ATTR_SELFPOWERED), .MaxPowerConsumption = USB_CONFIG_POWER_MA(100) }, .CDC_CCI_Interface = { .Header = {.Size = sizeof(USB_Descriptor_Interface_t), .Type = DTYPE_Interface}, .InterfaceNumber = INTERFACE_ID_CDC_CCI, .AlternateSetting = 0, .TotalEndpoints = 1, .Class = CDC_CSCP_CDCClass, .SubClass = CDC_CSCP_ACMSubclass, .Protocol = CDC_CSCP_ATCommandProtocol, .InterfaceStrIndex = NO_DESCRIPTOR }, .CDC_Functional_Header = { .Header = {.Size = sizeof(USB_CDC_Descriptor_FunctionalHeader_t), .Type = CDC_DTYPE_CSInterface}, .Subtype = CDC_DSUBTYPE_CSInterface_Header, .CDCSpecification = VERSION_BCD(1,1,0), }, .CDC_Functional_ACM = { .Header = {.Size = sizeof(USB_CDC_Descriptor_FunctionalACM_t), .Type = CDC_DTYPE_CSInterface}, .Subtype = CDC_DSUBTYPE_CSInterface_ACM, .Capabilities = 0x06, }, .CDC_Functional_Union = { .Header = {.Size = sizeof(USB_CDC_Descriptor_FunctionalUnion_t), .Type = CDC_DTYPE_CSInterface}, .Subtype = CDC_DSUBTYPE_CSInterface_Union, .MasterInterfaceNumber = INTERFACE_ID_CDC_CCI, .SlaveInterfaceNumber = INTERFACE_ID_CDC_DCI, }, .CDC_NotificationEndpoint = { .Header = {.Size = sizeof(USB_Descriptor_Endpoint_t), .Type = DTYPE_Endpoint}, .EndpointAddress = CDC_NOTIFICATION_EPADDR, .Attributes = (EP_TYPE_INTERRUPT | ENDPOINT_ATTR_NO_SYNC | ENDPOINT_USAGE_DATA), .EndpointSize = CDC_NOTIFICATION_EPSIZE, .PollingIntervalMS = 0xFF }, .CDC_DCI_Interface = { .Header = {.Size = sizeof(USB_Descriptor_Interface_t), .Type = DTYPE_Interface}, .InterfaceNumber = INTERFACE_ID_CDC_DCI, .AlternateSetting = 0, .TotalEndpoints = 2, .Class = CDC_CSCP_CDCDataClass, .SubClass = CDC_CSCP_NoDataSubclass, .Protocol = CDC_CSCP_NoDataProtocol, .InterfaceStrIndex = NO_DESCRIPTOR }, .CDC_DataOutEndpoint = { .Header = {.Size = sizeof(USB_Descriptor_Endpoint_t), .Type = DTYPE_Endpoint}, .EndpointAddress = CDC_RX_EPADDR, .Attributes = (EP_TYPE_BULK | ENDPOINT_ATTR_NO_SYNC | ENDPOINT_USAGE_DATA), .EndpointSize = CDC_TXRX_EPSIZE, .PollingIntervalMS = 0x05 }, .CDC_DataInEndpoint = { .Header = {.Size = sizeof(USB_Descriptor_Endpoint_t), .Type = DTYPE_Endpoint}, .EndpointAddress = CDC_TX_EPADDR, .Attributes = (EP_TYPE_BULK | ENDPOINT_ATTR_NO_SYNC | ENDPOINT_USAGE_DATA), .EndpointSize = CDC_TXRX_EPSIZE, .PollingIntervalMS = 0x05 } }; const USB_Descriptor_String_t PROGMEM LanguageString = USB_STRING_DESCRIPTOR_ARRAY(LANGUAGE_ID_ENG); const USB_Descriptor_String_t PROGMEM ManufacturerString = USB_STRING_DESCRIPTOR(L"LUFA Library"); const USB_Descriptor_String_t PROGMEM ProductString = USB_STRING_DESCRIPTOR(L"LUFA CDC Demo"); uint16_t CALLBACK_USB_GetDescriptor(const uint16_t wValue, const uint16_t wIndex, const void** const DescriptorAddress) { const uint8_t DescriptorType = (wValue >> 8); const uint8_t DescriptorNumber = (wValue & 0xFF); const void* Address = NULL; uint16_t Size = NO_DESCRIPTOR; switch (DescriptorType) { case DTYPE_Device: Address = &DeviceDescriptor; Size = sizeof(USB_Descriptor_Device_t); break; case DTYPE_Configuration: Address = &ConfigurationDescriptor; Size = sizeof(USB_Descriptor_Configuration_t); break; case DTYPE_String: switch (DescriptorNumber) { case STRING_ID_Language: Address = &LanguageString; Size = pgm_read_byte(&LanguageString.Header.Size); break; case STRING_ID_Manufacturer: Address = &ManufacturerString; Size = pgm_read_byte(&ManufacturerString.Header.Size); break; case STRING_ID_Product: Address = &ProductString; Size = pgm_read_byte(&ProductString.Header.Size); break; } break; } *DescriptorAddress = Address; return Size; } 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, }, }, }; /* void EVENT_USB_Device_Connect(void) { } void EVENT_USB_Device_Disconnect(void) { } */ void EVENT_USB_Device_ConfigurationChanged(void) { CDC_Device_ConfigureEndpoints(&VirtualSerial_CDC_Interface); } void EVENT_USB_Device_ControlRequest(void) { CDC_Device_ProcessControlRequest(&VirtualSerial_CDC_Interface); } /* void EVENT_CDC_Device_LineEncodingChanged(USB_ClassInfo_CDC_Device_t* const CDCInterfaceInfo) { } void EVENT_CDC_Device_ControLineStateChanged(USB_ClassInfo_CDC_Device_t* const CDCInterfaceInfo) { } */ void usbcdc_event_handler(event_entry_t * p_event) { if ((p_event->type == EVENT_TYPE_LEDFADE_STATUS) && (p_event->num == EVENT_NUM_LED_CH0) ) { if (USB_DeviceState == DEVICE_STATE_Configured) { CDC_Device_SendByte(&VirtualSerial_CDC_Interface, '!'); } } } void usbcdc_task(void) { CDC_Device_USBTask(&VirtualSerial_CDC_Interface); USB_USBTask(); if (CDC_Device_BytesReceived(&VirtualSerial_CDC_Interface)) { uint8_t cmd = CDC_Device_ReceiveByte(&VirtualSerial_CDC_Interface); switch (cmd) { /* turn off fan */ case '0': event_queue(EVENT_TYPE_PWM_VALUE, EVENT_NUM_PWM_CH2, 0x00); break; /* turn on fan, ~50% (12V) */ case '1': event_queue(EVENT_TYPE_PWM_VALUE, EVENT_NUM_PWM_CH2, 0x58); break; /* turn on fan, ~75% (18V) */ case '2': event_queue(EVENT_TYPE_PWM_VALUE, EVENT_NUM_PWM_CH2, 0xC0); break; /* turn on fan, 100% (24V) */ case '3': event_queue(EVENT_TYPE_PWM_VALUE, EVENT_NUM_PWM_CH2, 0xFF); break; /* turn off LEDs */ case 'a': event_queue(EVENT_TYPE_LEDFADE_VALUE, EVENT_NUM_LED_CH0, 0); break; /* turn on LEDs */ case 'b': event_queue(EVENT_TYPE_LEDFADE_VALUE, EVENT_NUM_LED_CH0, 0x50); break; /* turn on LEDs */ case 'c': event_queue(EVENT_TYPE_LEDFADE_VALUE, EVENT_NUM_LED_CH0, 0x70); break; /* turn on LEDs, 100% */ case 'd': event_queue(EVENT_TYPE_LEDFADE_VALUE, EVENT_NUM_LED_CH0, 0x80); break; } } } void usbcdc_init(void) { USB_Init(); }