commit 22bb178687a2c86b4fdc9c5ea9203c0e3b140003 Author: Valentin Ochs Date: Wed Aug 16 21:07:52 2023 +0200 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..30ade4e --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +BaitAndSwitch.bin +BaitAndSwitch.eep +BaitAndSwitch.elf +BaitAndSwitch.hex +BaitAndSwitch.lss +BaitAndSwitch.map +BaitAndSwitch.sym +obj diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..b6a8475 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "lufa"] + path = lufa + url = https://github.com/abcminiuser/lufa.git diff --git a/Config/LUFAConfig.h b/Config/LUFAConfig.h new file mode 100644 index 0000000..88bda00 --- /dev/null +++ b/Config/LUFAConfig.h @@ -0,0 +1,7 @@ +#pragma once +#define USE_STATIC_OPTIONS (USB_DEVICE_OPT_FULLSPEED | USB_OPT_REG_ENABLED | USB_OPT_AUTO_PLL) +#define USB_DEVICE_ONLY +#define USE_FLASH_DESCRIPTORS +#define FIXED_CONTROL_ENDPOINT_SIZE 8 +#define FIXED_NUM_CONFIGURATIONS 1 +#define INTERRUPT_CONTROL_ENDPOINT diff --git a/board.h b/board.h new file mode 100644 index 0000000..1dda11a --- /dev/null +++ b/board.h @@ -0,0 +1,34 @@ +#pragma once +#include +#include + +extern FILE USBSerialStream; + +#define SET_FUN_N(NAME, PORT, PIN) inline static void NAME(void) { PORT |= (1< + +extern FILE USBSerialStream; + +static void DB(char const *s) { + if (connected) { + fputs(s, &USBSerialStream); + fputs("\r\n", &USBSerialStream); + } +} + +void connectCTL(void) { + DB("CC"); + connectPowerCTL(); + disconnectPowerDUT(); + connectDataCTL(); +} + +void connectDUT(void) { + DB("CD"); + connectPowerDUT(); + disconnectPowerCTL(); + connectDataDUT(); +} + +void connectDataCTL(void) { + DB("CDC"); + PortBIndOff(); + CtrlDataOn(); + OutEnOn(); + PortAIndOn(); +} + +void connectDataDUT(void) { + DB("CDD"); + PortAIndOff(); + DutDataOn(); + OutEnOn(); + PortBIndOn(); +} + +void connectPowerCTL(void) { + DB("CPC"); + PortAPowOn(); +} + +void connectPowerDUT(void) { + DB("CPD"); + PortBPowOn(); +} + +void disconnect(void) { + DB("D"); + disconnectData(); + disconnectPower(); +} + +void disconnectData(void) { + DB("DD"); + OutEnOff(); + PortAIndOff(); + PortBIndOff(); +} + +void disconnectPower(void) { + DB("DP"); + disconnectPowerCTL(); + disconnectPowerDUT(); +} + +void disconnectPowerCTL(void) { + DB("DPC"); + PortAPowOff(); +} + +void disconnectPowerDUT(void) { + DB("DPD"); + PortBPowOff(); +} + +void clearID(void) { + DB("CI"); + SysLedOff(); +} + +void setID(void) { + DB("SI"); + SysLedOn(); +} + +void status(void) { + char buf[30]; + snprintf(buf, sizeof buf, + "PC:%d, PD:%d, " + "DT:%s\r\n" + , PortAPowPort(), PortBPowPort() + , OutEnPort() ? (CtrlDataPort() ? "Ctrl" : "DUT") : "off" + ); + CDC_Device_SendString(&VirtualSerial_CDC_Interface, buf); +} + +void debug(void) { + char buf[20]; + snprintf(buf, sizeof buf, + "(%02x %02x %02x)\r\n" + , (unsigned) (PINB & 0x87), (unsigned) (PINC & 0xF6), (unsigned) (PIND & 0xFF) + ); + CDC_Device_SendString(&VirtualSerial_CDC_Interface, buf); +} + diff --git a/commands.h b/commands.h new file mode 100644 index 0000000..ffa6306 --- /dev/null +++ b/commands.h @@ -0,0 +1,16 @@ +#pragma once +void connectCTL(void); +void connectDUT(void); +void connectDataCTL(void); +void connectDataDUT(void); +void connectPowerCTL(void); +void connectPowerDUT(void); +void disconnect(void); +void disconnectData(void); +void disconnectPower(void); +void disconnectPowerCTL(void); +void disconnectPowerDUT(void); +void clearID(void); +void setID(void); +void status(void); +void debug(void); diff --git a/descriptors.c b/descriptors.c new file mode 100644 index 0000000..ae25bff --- /dev/null +++ b/descriptors.c @@ -0,0 +1,180 @@ +#include "descriptors.h" + + +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; +} + diff --git a/descriptors.h b/descriptors.h new file mode 100644 index 0000000..545ef2d --- /dev/null +++ b/descriptors.h @@ -0,0 +1,110 @@ +/* + 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 + * + * Header file for Descriptors.c. + */ + +#ifndef _DESCRIPTORS_H_ +#define _DESCRIPTORS_H_ + + /* Includes: */ + #include + + #include + + /* Macros: */ + /** Endpoint address of the CDC device-to-host notification IN endpoint. */ + #define CDC_NOTIFICATION_EPADDR (ENDPOINT_DIR_IN | 2) + + /** Endpoint address of the CDC device-to-host data IN endpoint. */ + #define CDC_TX_EPADDR (ENDPOINT_DIR_IN | 3) + + /** Endpoint address of the CDC host-to-device data OUT endpoint. */ + #define CDC_RX_EPADDR (ENDPOINT_DIR_OUT | 4) + + /** Size in bytes of the CDC device-to-host notification IN endpoint. */ + #define CDC_NOTIFICATION_EPSIZE 8 + + /** Size in bytes of the CDC data IN and OUT endpoints. */ + #define CDC_TXRX_EPSIZE 16 + + /* Type Defines: */ + /** Type define for the device configuration descriptor structure. This must be defined in the + * application code, as the configuration descriptor contains several sub-descriptors which + * vary between devices, and which describe the device's usage to the host. + */ + 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 for the device interface descriptor IDs within the device. Each interface descriptor + * should have a unique ID index associated with it, which can be used to refer to the + * interface from other descriptors. + */ + enum InterfaceDescriptors_t + { + INTERFACE_ID_CDC_CCI = 0, /**< CDC CCI interface descriptor ID */ + INTERFACE_ID_CDC_DCI = 1, /**< CDC DCI interface descriptor ID */ + }; + + /** Enum for the device string descriptor IDs within the device. Each string descriptor should + * have a unique ID index associated with it, which can be used to refer to the string from + * other descriptors. + */ + enum StringDescriptors_t + { + STRING_ID_Language = 0, /**< Supported Languages string descriptor ID (must be zero) */ + STRING_ID_Manufacturer = 1, /**< Manufacturer string ID */ + STRING_ID_Product = 2, /**< Product string ID */ + }; + + /* Function Prototypes: */ + uint16_t CALLBACK_USB_GetDescriptor(const uint16_t wValue, + const uint16_t wIndex, + const void** const DescriptorAddress) + ATTR_WARN_UNUSED_RESULT ATTR_NON_NULL_PTR_ARG(3); + +#endif + diff --git a/lufa b/lufa new file mode 160000 index 0000000..15cf780 --- /dev/null +++ b/lufa @@ -0,0 +1 @@ +Subproject commit 15cf7809c7d9e7a6e42f256309dd965b6c8cc20b diff --git a/main.c b/main.c new file mode 100644 index 0000000..a8a2f92 --- /dev/null +++ b/main.c @@ -0,0 +1,141 @@ +#include "main.h" +#include "board.h" +#include "commands.h" +#include "usb.h" + +static void GPIO_Init(); +static void HandleSerialByte(uint8_t); + +int main(void) +{ + GlobalInterruptEnable(); + SetupHardware(); + + /* Create a regular character stream for the interface so that it can be used with the stdio.h functions */ + CDC_Device_CreateStream(&VirtualSerial_CDC_Interface, &USBSerialStream); + + for (;;) + { + CheckInputs(); + + CDC_Device_USBTask(&VirtualSerial_CDC_Interface); + USB_USBTask(); + + /* Must read data from the host, or it will lock up while waiting for the device */ + int16_t data = CDC_Device_ReceiveByte(&VirtualSerial_CDC_Interface); + if (data >= 0) { + HandleSerialByte((uint8_t)(data & 0xFF)); + } + + 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(); + + /* Disable clock division */ + clock_prescale_set(clock_div_1); + + /* Hardware Initialization */ + GPIO_Init(); + USB_Init(); +} + +void GPIO_Init() { + // Port B: + // 0, 1, 2: Inputs Disconnect, Sel B, Sel A -> Pullup + // 7: SYS_LED + DDRB = 1<<7; + PINB |= (1 << 0) | (1 << 1) | (1 << 2); + // Port C: + // 2, 4, 5, 6, 7: C_SENSE, VBUS_CTRL_DET, HS, ~USBON, VBUS_DUT_DET + // DDRC = 0; + // Port D: + // 0, 1: IND_PORTA, EN_POW_CTRL + // 2, 3: IND_PORTB, EN_POW_DUT + // 4: ~OE + // 5: ~CTRL/DUT + // 6: UNRST + // 7: 5VMCU + DDRD = ~((1<<7) | (1<<6)); +} + +static int gotCommand = 0; +void CheckInputs(void) +{ + uint8_t portValue = (~PINB) & 7; + static int lV = 0; + if ((portValue == 0 || portValue == lV) && !gotCommand) { + return; + } + + lV = portValue; + gotCommand = 0; + + if (portValue & (1<<0)) { + disconnect(); + } else if (portValue & (1<<1)) { + connectDUT(); + } else if (portValue & (1<<2)) { + connectCTL(); + } +} + +static const struct { + char const *name; + void (*fun)(void); +} commands[] = { + { "C", connectCTL }, + { "PC", connectPowerCTL }, + { "DC", connectDataCTL }, + { "D", connectDUT }, + { "PD", connectPowerDUT }, + { "DD", connectDataDUT }, + { "dPC", disconnectPowerCTL }, + { "dPD", disconnectPowerDUT }, + { "dP", disconnectPower }, + { "dD", disconnectData }, + { "d", disconnect }, + { "I", setID }, + { "i", clearID }, + { "s", status }, + { "x", debug } +}; + +static void HandleCommand(char *cmd, int cmdLen) { + for (int i = 0; i < (sizeof commands) / (sizeof commands[0]); i++) { + if (!strncmp(commands[i].name, cmd, cmdLen)) { + gotCommand = 1; + commands[i].fun(); + return; + } + } + + fputs("Unknown command\r\n", &USBSerialStream); +} + +static void HandleSerialByte(uint8_t b) { + static char cmd[64]; + static int cmdLen = 0; + + if (b != '\r' && b != '\n') { + if (cmdLen < sizeof cmd - 1) { + cmd[cmdLen++] = b; + fputc(b, &USBSerialStream); + } + } else { + if (cmdLen > 0) { + fputs("\r\n", &USBSerialStream); + CDC_Device_Flush(&VirtualSerial_CDC_Interface); + cmd[cmdLen] = '\0'; + HandleCommand(cmd, cmdLen); + cmdLen = 0; + } + } +} diff --git a/main.h b/main.h new file mode 100644 index 0000000..87e3413 --- /dev/null +++ b/main.h @@ -0,0 +1,22 @@ +#pragma once +#include +#include +#include +#include +#include +#include + +#include "descriptors.h" + +#include +#include + +void SetupHardware(void); +void CheckInputs(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); + +extern USB_ClassInfo_CDC_Device_t VirtualSerial_CDC_Interface; diff --git a/makefile b/makefile new file mode 100644 index 0000000..13938dc --- /dev/null +++ b/makefile @@ -0,0 +1,42 @@ +# +# LUFA Library +# Copyright (C) Dean Camera, 2021. +# +# dean [at] fourwalledcubicle [dot] com +# www.lufa-lib.org +# +# -------------------------------------- +# LUFA Project Makefile. +# -------------------------------------- + +# Run "make help" for target help. + +MCU = atmega16u2 +ARCH = AVR8 +F_CPU = 16000000 +F_USB = $(F_CPU) +OPTIMIZATION = s +TARGET = BaitAndSwitch +SRC = main.c descriptors.c $(LUFA_SRC_USB) $(LUFA_SRC_USBCLASS) usb.c commands.c +LUFA_PATH = lufa/LUFA +CC_FLAGS = -DUSE_LUFA_CONFIG_HEADER -IConfig/ +LD_FLAGS = + +# Default target +all: + +# Include LUFA-specific DMBS extension modules +DMBS_LUFA_PATH ?= $(LUFA_PATH)/Build/LUFA +include $(DMBS_LUFA_PATH)/lufa-sources.mk +include $(DMBS_LUFA_PATH)/lufa-gcc.mk + +# Include common DMBS build system modules +DMBS_PATH ?= $(LUFA_PATH)/Build/DMBS/DMBS +include $(DMBS_PATH)/core.mk +include $(DMBS_PATH)/cppcheck.mk +include $(DMBS_PATH)/doxygen.mk +include $(DMBS_PATH)/dfu.mk +include $(DMBS_PATH)/gcc.mk +include $(DMBS_PATH)/hid.mk +include $(DMBS_PATH)/avrdude.mk +include $(DMBS_PATH)/atprogram.mk diff --git a/usb.c b/usb.c new file mode 100644 index 0000000..4a1a2ae --- /dev/null +++ b/usb.c @@ -0,0 +1,70 @@ +#include "main.h" +#include "board.h" + +int connected = 0; + +FILE USBSerialStream; + +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) +{ + SysLedOff(); + connected = 0; +} + +void EVENT_USB_Device_ConfigurationChanged(void) +{ + bool ConfigSuccess = true; + + ConfigSuccess &= CDC_Device_ConfigureEndpoints(&VirtualSerial_CDC_Interface); + + if (ConfigSuccess) { + SysLedOn(); + } +} + +void EVENT_USB_Device_ControlRequest(void) +{ + CDC_Device_ProcessControlRequest(&VirtualSerial_CDC_Interface); +} + +void EVENT_CDC_Device_ControLineStateChanged(USB_ClassInfo_CDC_Device_t *const CDCInterfaceInfo) +{ + bool HostReady = (CDCInterfaceInfo->State.ControlLineStates.HostToDevice & CDC_CONTROL_LINE_OUT_DTR) != 0; + connected = HostReady; + if (connected) { + SysLedOn(); + } else { + SysLedOff(); + } +} + diff --git a/usb.h b/usb.h new file mode 100644 index 0000000..fa40a65 --- /dev/null +++ b/usb.h @@ -0,0 +1,3 @@ +#pragma once + +extern int connected;