Compare commits

...

10 commits

15 changed files with 354 additions and 405 deletions

Binary file not shown.

BIN
doc/fuses.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 393 KiB

BIN
doc/lock.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 394 KiB

View file

@ -23,11 +23,17 @@ LUFA_PATH = ../LUFA/LUFA
CC_FLAGS = -DUSE_LUFA_CONFIG_HEADER -IConfig/ -Iuart/ CC_FLAGS = -DUSE_LUFA_CONFIG_HEADER -IConfig/ -Iuart/
LD_FLAGS = LD_FLAGS =
PROGRAMMER = dfu-programmer PROGRAMMER = dfu-programmer
MUX_TOOL =../tools/muxctrl.py
PYTHON = python
# Default target # Default target
all: all:
program: reset:
-$(PYTHON) $(MUX_TOOL) -d /dev/ttyACM0 -r
-sleep 2
program: reset
$(PROGRAMMER) $(MCU) erase $(PROGRAMMER) $(MCU) erase
$(PROGRAMMER) $(MCU) flash $(TARGET).hex $(PROGRAMMER) $(MCU) flash $(TARGET).hex
$(PROGRAMMER) $(MCU) reset $(PROGRAMMER) $(MCU) reset

View file

@ -21,7 +21,6 @@
/*****************************************************************************/ /*****************************************************************************/
void cc_setBaudrate(void); void cc_setBaudrate(void);
void cc_getBaudrate(void); void cc_getBaudrate(void);
void cc_setMuxLine(void); void cc_setMuxLine(void);

View file

@ -144,3 +144,16 @@ void cc_clearReadDataBuffer()
} }
/*****************************************************************************/ /*****************************************************************************/
uint32_t read32BitFromBuffer(uint8_t pos)
{
uint32_t tmp = (uint32_t)cc_read_data[pos ] << 24;
tmp += (uint32_t)cc_read_data[pos + 1] << 16;
tmp += (uint32_t)cc_read_data[pos + 2] << 8;
tmp += (uint32_t)cc_read_data[pos + 3];
return tmp;
}
/*****************************************************************************/

View file

@ -29,6 +29,8 @@
extern void USB_serialStreamWriteC(char*, uint16_t); extern void USB_serialStreamWriteC(char*, uint16_t);
uint32_t read32BitFromBuffer(uint8_t);
void cc_init(void); void cc_init(void);
void cc_abort(void); void cc_abort(void);
void cc_processData(uint8_t); void cc_processData(uint8_t);

View file

@ -15,10 +15,7 @@ extern uint32_t baudrate;
void cc_setBaudrate() void cc_setBaudrate()
{ {
baudrate = (uint32_t)cc_read_data[0] << 24; baudrate = read32BitFromBuffer(0);
baudrate += (uint32_t)cc_read_data[1] << 16;
baudrate += (uint32_t)cc_read_data[2] << 8;
baudrate += (uint32_t)cc_read_data[3];
eeprom_busy_wait(); eeprom_busy_wait();

View file

@ -8,14 +8,14 @@
/* /*
LUFA Library LUFA Library
Copyright (C) Dean Camera, 2016. Copyright (C) Dean Camera, 2015.
dean [at] fourwalledcubicle [dot] com dean [at] fourwalledcubicle [dot] com
www.lufa-lib.org www.lufa-lib.org
*/ */
/* /*
Copyright 2016 Dean Camera (dean [at] fourwalledcubicle [dot] com) Copyright 2015 Dean Camera (dean [at] fourwalledcubicle [dot] com)
Permission to use, copy, modify, distribute, and sell this Permission to use, copy, modify, distribute, and sell this
software and its documentation for any purpose is hereby granted software and its documentation for any purpose is hereby granted
@ -38,467 +38,359 @@
/** \file /** \file
* *
* Main source file for the project - based on the Mouse and VirtualSerial lufa demo. * Main source file for the USB2SerialMux. This file contains the main tasks of the application and
* This file contains the main tasks of the demo and is responsible for the initial * is responsible for the initial hardware configuration.
* application hardware configuration.
*/ */
#include "main.h" #include "main.h"
//********************************************************************************// /**************************************************************************************/
FIFO_t agent_fifo; uint32_t EEMEM eep_baudrate;
FIFO_t seq_mod_fifo;
FIFO_t seq_val_fifo;
uint8_t seq_delay = 0; uint32_t baudrate = 115200; // replacement for the UART_BAUDRATE definition
volatile uint16_t time_measure_cnt = 0; /**************************************************************************************/
volatile uint16_t keystroke_delay_time_measure_cnt_old = 0;
volatile uint16_t seq_delay_time_measure_cnt_old = 0;
//********************************************************************************// /** Contains the current baud rate and other settings of the first virtual serial port. While this demo does not use
* the physical USART and thus does not use these settings, they must still be retained and returned to the host
/** Buffer to hold the previously generated Keyboard HID report, for comparison purposes inside the HID class driver. */ * upon request or the host will assume the device is non-functional.
static uint8_t PrevKeyboardHIDReportBuffer[sizeof(USB_KeyboardReport_Data_t)]; *
* These values are set by the host via a class-specific request, however they are not required to be used accurately.
//********************************************************************************// * It is possible to completely ignore these value or use other settings as the host is completely unaware of the physical
* serial link characteristics and instead sends and receives data in endpoint streams.
/** LUFA HID Class driver interface configuration and state information. This structure is
* passed to all HID Class driver functions, so that multiple instances of the same class
* within a device can be differentiated from one another. This is for the keyboard HID
* interface within the device.
*/ */
USB_ClassInfo_HID_Device_t Keyboard_HID_Interface = static CDC_LineEncoding_t LineEncoding1 = { .BaudRateBPS = 0,
{ .CharFormat = CDC_LINEENCODING_OneStopBit,
.Config = .ParityType = CDC_PARITY_None,
{ .DataBits = 8 };
.InterfaceNumber = INTERFACE_ID_Keyboard,
.ReportINEndpoint =
{
.Address = KEYBOARD_IN_EPADDR,
.Size = KEYBOARD_EPSIZE,
.Banks = 1,
},
.PrevReportINBuffer = PrevKeyboardHIDReportBuffer,
.PrevReportINBufferSize = sizeof(PrevKeyboardHIDReportBuffer),
},
};
/** LUFA CDC Class driver interface configuration and state information. This structure is /** Contains the current baud rate and other settings of the second virtual serial port. While this demo does not use
* passed to all CDC Class driver functions, so that multiple instances of the same class * the physical USART and thus does not use these settings, they must still be retained and returned to the host
* within a device can be differentiated from one another. * upon request or the host will assume the device is non-functional.
*
* These values are set by the host via a class-specific request, however they are not required to be used accurately.
* It is possible to completely ignore these value or use other settings as the host is completely unaware of the physical
* serial link characteristics and instead sends and receives data in endpoint streams.
*/ */
USB_ClassInfo_CDC_Device_t VirtualSerial_CDC_Interface = static CDC_LineEncoding_t LineEncoding2 = { .BaudRateBPS = 0,
{ .CharFormat = CDC_LINEENCODING_OneStopBit,
.Config = .ParityType = CDC_PARITY_None,
{ .DataBits = 8 };
.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,
},
},
};
/** Standard file stream for the CDC interface when set up, so that the virtual /**************************************************************************************/
* CDC COM port can be used like any regular character stream in the C APIs.
*/
static FILE USBSerialStream;
//********************************************************************************// /** Main program entry point. This routine configures the hardware required by the application, then
* enters a loop to run the application tasks in sequence.
/** 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) int main(void)
{ {
// USB/LUFA init
SetupHardware(); SetupHardware();
// init the timer for time measurements // initialize the command interpreter
timer_init();
// LED matrix init
lm_init();
// KEY matrix init
km_init();
// read the key configuration table from EEPROM
ch_readConfig();
// init the serial communication command controller
cc_init(); cc_init();
FIFO_init( agent_fifo); SET_ERR_MASK(ERRMASK_USB_NOTREADY);
FIFO_init(seq_mod_fifo);
FIFO_init(seq_val_fifo);
// 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);
SET_GLOB_USB_STATUS(STATUSMASK_USB_NOTREADY);
GlobalInterruptEnable(); GlobalInterruptEnable();
for (;;) for (;;)
{ {
SendVirtualSerialData(); CDC1_Task();
CDC2_Task();
ProcessVirtualSerialData();
CDC_Device_USBTask(&VirtualSerial_CDC_Interface);
HID_Device_USBTask(&Keyboard_HID_Interface);
USB_USBTask(); USB_USBTask();
static uint8_t delay = 0; //uart_putc('1');
if (delay > 50)
{
delay = 0;
lm_show();
}
delay++;
} }
} }
//********************************************************************************// /**************************************************************************************/
void timer_init() /** Configures the board hardware and chip peripherals for the demo's functionality. */
{ void SetupHardware(void)
// configure TIMER0 to count using a specified frequency the TCNT0 variable to generate
// a overflow interrupt
TCCR0A = 0x02; // WGM1 = 1; WGM0 = 0 => CTC-mode
TCCR0B = 0x03; // prescaler = 64; WGM2 = 0 => 16MHz * 256 / 64 = ~ 1mz per Overflow Interrupt
TIMSK0 = 0x01; // Overflow Interrupt Enable
sei();
}
ISR(TCC0_OVF_vect)
{
if (time_measure_cnt >= 65534)
{
// reset all the counter values to prevent unpredictable behaviour
time_measure_cnt = 0;
seq_delay_time_measure_cnt_old = 0;
keystroke_delay_time_measure_cnt_old = 0;
}
time_measure_cnt++;
}
//********************************************************************************//
/** Configures the board hardware and chip peripherals for the demo's functionality.
*/
void SetupHardware()
{ {
#if (ARCH == ARCH_AVR8) #if (ARCH == ARCH_AVR8)
// Disable watchdog if enabled by bootloader/fuses /* Disable watchdog if enabled by bootloader/fuses */
MCUSR &= ~(1 << WDRF); MCUSR &= ~(1 << WDRF);
wdt_disable(); wdt_disable();
// Disable clock division */ /* Disable clock division */
clock_prescale_set(clock_div_1); clock_prescale_set(clock_div_1);
#elif (ARCH == ARCH_XMEGA) #elif (ARCH == ARCH_XMEGA)
// Start the PLL to multiply the 2MHz RC oscillator to 32MHz and switch the CPU /* Start the PLL to multiply the 2MHz RC oscillator to 32MHz and switch the CPU core to run from it */
// core to run from it
XMEGACLK_StartPLL(CLOCK_SRC_INT_RC2MHZ, 2000000, F_CPU); XMEGACLK_StartPLL(CLOCK_SRC_INT_RC2MHZ, 2000000, F_CPU);
XMEGACLK_SetCPUClockSource(CLOCK_SRC_PLL); XMEGACLK_SetCPUClockSource(CLOCK_SRC_PLL);
// Start the 32MHz internal RC oscillator and start the DFLL to increase it to /* Start the 32MHz internal RC oscillator and start the DFLL to increase it to 48MHz using the USB SOF as a reference */
// 48MHz using the USB SOF as a reference
XMEGACLK_StartInternalOscillator(CLOCK_SRC_INT_RC32MHZ); XMEGACLK_StartInternalOscillator(CLOCK_SRC_INT_RC32MHZ);
XMEGACLK_StartDFLL(CLOCK_SRC_INT_RC32MHZ, DFLL_REF_INT_USBSOF, F_USB); XMEGACLK_StartDFLL(CLOCK_SRC_INT_RC32MHZ, DFLL_REF_INT_USBSOF, F_USB);
PMIC.CTRL = PMIC_LOLVLEN_bm | PMIC_MEDLVLEN_bm | PMIC_HILVLEN_bm; PMIC.CTRL = PMIC_LOLVLEN_bm | PMIC_MEDLVLEN_bm | PMIC_HILVLEN_bm;
#endif #endif
// Hardware Initialization */ // set the three MUX control lines to output
DDRB |= (1 << PIN4) | (1 << PIN5) | (1 << PIN6);
// set every pin to low
EN_MUX_LINE0;
DDRB |= (1 << PIN0) | (1 << PIN1);
LED0_OFF;
LED1_OFF;
/* UART Hardware Initialization */
eeprom_busy_wait();
baudrate = eeprom_read_dword(&eep_baudrate);
if (baudrate == 0xffffffff)
{
eeprom_busy_wait();
baudrate = 115200;
eeprom_write_dword(&eep_baudrate, baudrate);
}
// initialize the uart to the default baudrate
uart_init( UART_BAUD_SELECT(baudrate, F_CPU) );
sei();
/* USB Hardware Initialization */
USB_Init(); USB_Init();
} }
//********************************************************************************// /**************************************************************************************/
void ProcessVirtualSerialData() /** Function to manage CDC data transmission and reception to and from the host for the first CDC interface,
{ * which sends answers or response data to the host.
// process the read data from Host here, if there is data to read
int16_t ReceivedBytes = CDC_Device_BytesReceived(&VirtualSerial_CDC_Interface);
if (ReceivedBytes > 0)
{
for (uint16_t i = 0; i < ReceivedBytes; i++)
{
int16_t ReceivedByte = CDC_Device_ReceiveByte(&VirtualSerial_CDC_Interface);
// call the command controller - command processor
cc_processData((uint8_t)ReceivedByte);
}
}
}
//********************************************************************************//
void SendVirtualSerialData()
{
char* ReportString = NULL;
// send the next id from the agent FIFO
if (FIFO_available(agent_fifo))
{
uint8_t id = FIFO_pop(agent_fifo);
ReportString = " ";
sprintf(ReportString, "%c%c%c%c%c%c", MSG_SOM1, MSG_SOM2,
MSG_TYPE_AGENTID, id,
MSG_EOM1, MSG_EOM2);
}
if ((ReportString != NULL))
{
// Write the string to the virtual COM port via the created character stream
USB_serialStreamWriteC(ReportString, 6);
}
}
//********************************************************************************//
/** HID class driver callback function for the creation of HID reports to the host.
*
* \param[in] HIDInterfaceInfo Pointer to the HID class interface configuration structure being referenced
* \param[in,out] ReportID Report ID requested by the host if non-zero, otherwise callback should set to the generated report ID
* \param[in] ReportType Type of the report to create, either HID_REPORT_ITEM_In or HID_REPORT_ITEM_Feature
* \param[out] ReportData Pointer to a buffer where the created report should be stored
* \param[out] ReportSize Number of bytes written in the report (or zero if no report is to be sent)
*
* \return Boolean \c true to force the sending of the report, \c false to let the library determine if it needs to be sent
*/ */
bool CALLBACK_HID_Device_CreateHIDReport(USB_ClassInfo_HID_Device_t* const HIDInterfaceInfo, void CDC1_Task(void)
uint8_t* const ReportID,
const uint8_t ReportType,
void* ReportData,
uint16_t* const ReportSize)
{ {
/* Device must be connected and configured for the task to run */
if (USB_DeviceState != DEVICE_STATE_Configured)
return;
// Determine which interface must have its report generated */ /* Select the Serial Rx Endpoint */
if (HIDInterfaceInfo == &Keyboard_HID_Interface) Endpoint_SelectEndpoint(CDC1_RX_EPADDR);
if (Endpoint_IsOUTReceived())
{ {
USB_KeyboardReport_Data_t* KeyboardReport = (USB_KeyboardReport_Data_t*)ReportData; /* Create a temp buffer big enough to hold the incoming endpoint packet */
uint8_t Buffer[Endpoint_BytesInEndpoint()];
// update the key matrix values /* Remember how large the incoming packet is */
km_updateKeyStates(); uint16_t DataLength = Endpoint_BytesInEndpoint();
// prepare the new sequence related to the pressed key /* Read in the incoming packet into the buffer */
for (uint8_t k = 0; k < LM_LED_CNT; k++) Endpoint_Read_Stream_LE(&Buffer, DataLength, NULL);
/* Finalize the stream transfer to send the last packet */
Endpoint_ClearOUT();
for (uint16_t i = 0; i < DataLength; i++)
{ {
if (km_getKeyState(k) == KEY_STATE_GO_DOWN) // process the received data and descide to do an action
{ LED0_ON;
FIFO_push(agent_fifo, k); cc_processData(Buffer[i]);
LED0_OFF;
for (uint8_t s = 0; s < EEP_KEY_CNT; s++)
{
// ignore a mod/value combination of 0xff 0xff
// just add the sequence to a "sequence execution FIFO" in case that it
// is not an agent call
// prevent multiple calls
// TODO manage multikey (simultanous pressed) shortcuts here
if (key_config[k][s][0] == 0xff && key_config[k][s][1] == 0xff)
{
s = EEP_KEY_CNT; // abort the loop, no more data found
} else {
FIFO_push(seq_mod_fifo, key_config[k][s][0]);
FIFO_push(seq_val_fifo, key_config[k][s][1]);
}
}
}
} }
// TODO maybe we shall do ab bit more precise time measurement
if (seq_delay > 0 && time_measure_cnt > seq_delay_time_measure_cnt_old)
{
seq_delay--;
seq_delay_time_measure_cnt_old = time_measure_cnt;
}
if (keystroke_delay_cnt > 0 && time_measure_cnt > keystroke_delay_time_measure_cnt_old)
{
// TODO test if NN seconds are gone
keystroke_delay_cnt--;
keystroke_delay_time_measure_cnt_old = time_measure_cnt;
}
// execute the sequence execution FIFO content
if (FIFO_available(seq_mod_fifo) && FIFO_available(seq_val_fifo) &&
seq_delay == 0 && keystroke_delay_cnt == 0)
{
uint8_t mod = FIFO_pop(seq_mod_fifo);
uint8_t val = FIFO_pop(seq_val_fifo);
// reset the keystroke delay
keystroke_delay_cnt = keystroke_delay;
// process the data
if ((mod & KEY_MOD_DELAY) != 0)
{
// start the delay
seq_delay = val;
} else {
// TODO be aware of the os_type variable
if ((mod & KEY_MOD_FN) != 0)
KeyboardReport->Modifier += HID_KEYBOARD_MODIFIER_RIGHTSHIFT; // TODO fix the modifier
if ((mod & KEY_MOD_SHIFT) != 0)
KeyboardReport->Modifier += HID_KEYBOARD_MODIFIER_LEFTSHIFT;
if ((mod & KEY_MOD_CTRL) != 0)
KeyboardReport->Modifier += HID_KEYBOARD_MODIFIER_LEFTCTRL;
if ((mod & KEY_MOD_ALT) != 0)
KeyboardReport->Modifier += HID_KEYBOARD_MODIFIER_LEFTALT;
if ((mod & KEY_MOD_ALTGR) != 0)
KeyboardReport->Modifier += HID_KEYBOARD_MODIFIER_RIGHTALT;
if ((mod & KEY_MOD_SUPER) != 0)
KeyboardReport->Modifier += HID_KEYBOARD_MODIFIER_LEFTGUI;
// possible values: http://www.fourwalledcubicle.com/files/LUFA/Doc/120219/html/group___group___u_s_b_class_h_i_d_common.html
KeyboardReport->KeyCode[0] = val; // TODO one key at a time, up to 6 is supported: http://www.fourwalledcubicle.com/files/LUFA/Doc/120219/html/struct_u_s_b___keyboard_report___data__t.html#a1c24d97011685d58ab05e2f65d7b2c1b
}
}
// Some debug and test code
for (uint8_t i = 0; i < LM_LED_CNT; i++)
{
if (km_getKeyState(i) == KEY_STATE_GO_DOWN)
lm_ledOn(i);
if (km_getKeyState(i) == KEY_STATE_GO_UP)
lm_ledOff(i);
}
*ReportSize = sizeof(USB_KeyboardReport_Data_t);
}
return false;
}
//********************************************************************************//
/** HID class driver callback function for the processing of HID reports from the host.
*
* \param[in] HIDInterfaceInfo Pointer to the HID class interface configuration structure being referenced
* \param[in] ReportID Report ID of the received report from the host
* \param[in] ReportType The type of report that the host has sent, either HID_REPORT_ITEM_Out or HID_REPORT_ITEM_Feature
* \param[in] ReportData Pointer to a buffer where the received report has been stored
* \param[in] ReportSize Size in bytes of the received HID report
*/
void CALLBACK_HID_Device_ProcessHIDReport(USB_ClassInfo_HID_Device_t* const HIDInterfaceInfo,
const uint8_t ReportID,
const uint8_t ReportType,
const void* ReportData,
const uint16_t ReportSize)
{
if (HIDInterfaceInfo == &Keyboard_HID_Interface)
{
uint8_t* LEDReport = (uint8_t*)ReportData;
/*
// TODO process the Keyboard LED status information
if (*LEDReport & HID_KEYBOARD_LED_NUMLOCK)
if (*LEDReport & HID_KEYBOARD_LED_CAPSLOCK)
if (*LEDReport & HID_KEYBOARD_LED_SCROLLLOCK)
*/
} }
} }
//********************************************************************************// /**************************************************************************************/
/** CDC class driver callback function the processing of changes to the virtual void USB_serialStreamWriteC(char *data, uint16_t len)
* control lines sent from the host..
*
* \param[in] CDCInterfaceInfo Pointer to the CDC class interface configuration structure being referenced
*/
void EVENT_CDC_Device_ControLineStateChanged(USB_ClassInfo_CDC_Device_t *const CDCInterfaceInfo)
{ {
// You can get changes to the virtual CDC lines in this callback; a common /* Determine if data/answeres should be sent to the host
// use-case is to use the Data Terminal Ready (DTR) flag to enable and * the previous RX section should be clarify that behaviour.
// disable CDC communications in your application when set to avoid the */
// application blocking while waiting for a host to become ready and read
// in the pending data from the USB endpoints.
bool HostReady = (CDCInterfaceInfo->State.ControlLineStates.HostToDevice & CDC_CONTROL_LINE_OUT_DTR) != 0; /* Flag management - Only allow one string to be sent per action */
if (data != NULL && len > 0 && LineEncoding1.BaudRateBPS)
{
LED1_ON;
/* Select the Serial Tx Endpoint */
Endpoint_SelectEndpoint(CDC1_TX_EPADDR);
/* Write the String to the Endpoint */
Endpoint_Write_Stream_LE(data, len, NULL);
/* Finalize the stream transfer to send the last packet */
Endpoint_ClearIN();
/* Wait until the endpoint is ready for another packet */
Endpoint_WaitUntilReady();
/* Send an empty packet to ensure that the host does not buffer data sent to it */
Endpoint_ClearIN();
LED1_OFF;
}
} }
//********************************************************************************// /**************************************************************************************/
/** Event handler for the library USB Connection event. */ /** Function to manage CDC data transmission and reception to and from the host for the second CDC interface,
* which sends all data received from a node (mux) during USART to the host.
*/
void CDC2_Task(void)
{
/* Device must be connected and configured for the task to run */
if (USB_DeviceState != DEVICE_STATE_Configured)
return;
//=====================================
/* Select the Serial Rx Endpoint */
Endpoint_SelectEndpoint(CDC2_RX_EPADDR);
/* Check to see if any data has been received */
if (Endpoint_IsOUTReceived())
{
/* Create a temp buffer big enough to hold the incoming endpoint packet */
uint8_t Buffer[Endpoint_BytesInEndpoint()];
/* Remember how large the incoming packet is */
uint16_t DataLength = Endpoint_BytesInEndpoint();
/* Read in the incoming packet into the buffer */
Endpoint_Read_Stream_LE(&Buffer, DataLength, NULL);
/* Finalize the stream transfer to send the last packet */
Endpoint_ClearOUT();
// at this point send the data to the USART
// Send USART &Buffer
for (uint16_t i = 0; i < DataLength; i++)
{
uart_putc(Buffer[i]);
}
}
//=====================================
uint8_t outBuffer[OUTPUT_BUFFER_SIZE];
// read the USART data and send them to the host
// Fill &Buffer with USART data or send the USART input buffer direct
uint16_t cnt = 0;
int c = uart_getc();
while (!(c & UART_NO_DATA) && cnt < OUTPUT_BUFFER_SIZE)
{
//LED0_ON;
outBuffer[cnt] = c;
c = uart_getc();
cnt++;
}
// send the data which was received from the uart connection
if (cnt > 0)
{
/* Select the Serial Tx Endpoint */
Endpoint_SelectEndpoint(CDC2_TX_EPADDR);
/* Write the received data to the endpoint */
Endpoint_Write_Stream_LE(&outBuffer, cnt, NULL);
/* Finalize the stream transfer to send the last packet */
Endpoint_ClearIN();
/* Wait until the endpoint is ready for the next packet */
Endpoint_WaitUntilReady();
/* Send an empty packet to prevent host buffering */
Endpoint_ClearIN();
}
}
/**************************************************************************************/
/** Event handler for the USB_Connect event. This indicates that the device is enumerating via the status LEDs and
* starts the library USB task to begin the enumeration and USB management process.
*/
void EVENT_USB_Device_Connect(void) void EVENT_USB_Device_Connect(void)
{ {
SET_GLOB_USB_STATUS(STATUSMASK_USB_ENUMERATING); /* Indicate USB enumerating */
SET_ERR_MASK(ERRMASK_USB_ENUMERATING);
} }
/** Event handler for the library USB Disconnection event. */ /** Event handler for the USB_Disconnect event. This indicates that the device is no longer connected to a host via
* the status LEDs and stops the USB management and CDC management tasks.
*/
void EVENT_USB_Device_Disconnect(void) void EVENT_USB_Device_Disconnect(void)
{ {
SET_GLOB_USB_STATUS(STATUSMASK_USB_NOTREADY); /* Indicate USB not ready */
SET_ERR_MASK(ERRMASK_USB_NOTREADY);
} }
/** Event handler for the library USB Configuration Changed event. */ /** Event handler for the USB_ConfigurationChanged event. This is fired when the host set the current configuration
* of the USB device after enumeration - the device endpoints are configured and the CDC management tasks are started.
*/
void EVENT_USB_Device_ConfigurationChanged(void) void EVENT_USB_Device_ConfigurationChanged(void)
{ {
bool ConfigSuccess = true; bool ConfigSuccess = true;
ConfigSuccess &= HID_Device_ConfigureEndpoints(&Keyboard_HID_Interface); /* Setup first CDC Interface's Endpoints */
ConfigSuccess &= CDC_Device_ConfigureEndpoints(&VirtualSerial_CDC_Interface); ConfigSuccess &= Endpoint_ConfigureEndpoint(CDC1_TX_EPADDR, EP_TYPE_BULK, CDC_TXRX_EPSIZE, 1);
ConfigSuccess &= Endpoint_ConfigureEndpoint(CDC1_RX_EPADDR, EP_TYPE_BULK, CDC_TXRX_EPSIZE, 1);
ConfigSuccess &= Endpoint_ConfigureEndpoint(CDC1_NOTIFICATION_EPADDR, EP_TYPE_INTERRUPT, CDC_NOTIFICATION_EPSIZE, 1);
USB_Device_EnableSOFEvents(); /* Setup second CDC Interface's Endpoints */
ConfigSuccess &= Endpoint_ConfigureEndpoint(CDC2_TX_EPADDR, EP_TYPE_BULK, CDC_TXRX_EPSIZE, 1);
ConfigSuccess &= Endpoint_ConfigureEndpoint(CDC2_RX_EPADDR, EP_TYPE_BULK, CDC_TXRX_EPSIZE, 1);
ConfigSuccess &= Endpoint_ConfigureEndpoint(CDC2_NOTIFICATION_EPADDR, EP_TYPE_INTERRUPT, CDC_NOTIFICATION_EPSIZE, 1);
SET_GLOB_USB_STATUS(ConfigSuccess ? STATUSMASK_USB_READY : STATUSMASK_USB_ERROR); /* Reset line encoding baud rates so that the host knows to send new values */
LineEncoding1.BaudRateBPS = 0;
LineEncoding2.BaudRateBPS = 0;
/* Indicate endpoint configuration success or failure */
SET_ERR_MASK(ConfigSuccess ? ERRMASK_USB_READY : ERRMASK_USB_ERROR);
} }
/** Event handler for the library USB Control Request reception event. */ /** Event handler for the USB_ControlRequest event. This is used to catch and process control requests sent to
* the device from the USB host before passing along unhandled control requests to the library for processing
* internally.
*/
void EVENT_USB_Device_ControlRequest(void) void EVENT_USB_Device_ControlRequest(void)
{ {
HID_Device_ProcessControlRequest(&Keyboard_HID_Interface); /* Determine which interface's Line Coding data is being set from the wIndex parameter */
CDC_Device_ProcessControlRequest(&VirtualSerial_CDC_Interface); void* LineEncodingData = (USB_ControlRequest.wIndex == 0) ? &LineEncoding1 : &LineEncoding2;
}
/** Event handler for the USB device Start Of Frame event. */ /* Process CDC specific control requests */
void EVENT_USB_Device_StartOfFrame(void) switch (USB_ControlRequest.bRequest)
{
HID_Device_MillisecondElapsed(&Keyboard_HID_Interface);
}
//********************************************************************************//
void USB_serialStreamWriteC(char* msg, uint16_t len)
{
for (uint8_t i = 0; i < len; i++)
{ {
fputc(msg[i], &USBSerialStream); case CDC_REQ_GetLineEncoding:
if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
{
Endpoint_ClearSETUP();
/* Write the line coding data to the control endpoint */
Endpoint_Write_Control_Stream_LE(LineEncodingData, sizeof(CDC_LineEncoding_t));
Endpoint_ClearOUT();
}
break;
case CDC_REQ_SetLineEncoding:
if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
{
Endpoint_ClearSETUP();
/* Read the line coding data in from the host into the global struct */
Endpoint_Read_Control_Stream_LE(LineEncodingData, sizeof(CDC_LineEncoding_t));
Endpoint_ClearIN();
}
break;
case CDC_REQ_SetControlLineState:
if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
{
Endpoint_ClearSETUP();
Endpoint_ClearStatusStage();
}
break;
} }
} }
void USB_serialStreamWrite(char* msg) /**************************************************************************************/
{
fputs(msg, &USBSerialStream);
}
//********************************************************************************//

View file

@ -58,7 +58,6 @@
/* UART definitions: */ /* UART definitions: */
//#define UART_BAUD_RATE 115200
#define OUTPUT_BUFFER_SIZE 100 #define OUTPUT_BUFFER_SIZE 100
#include "uart/uart.h" // include after the definition #include "uart/uart.h" // include after the definition

View file

@ -3,7 +3,7 @@
(general (general
(links 130) (links 130)
(no_connects 0) (no_connects 0)
(area 123.956999 89.993 192.560334 117.376333) (area 124.409999 91.389999 190.296001 116.890001)
(thickness 1.6) (thickness 1.6)
(drawings 8) (drawings 8)
(tracks 651) (tracks 651)
@ -281,11 +281,6 @@
(net 71 /RESET)) (net 71 /RESET))
(pad 6 smd rect (at 3.302 -5.08 270) (size 3 1) (layers B.Cu B.Paste B.Mask) (pad 6 smd rect (at 3.302 -5.08 270) (size 3 1) (layers B.Cu B.Paste B.Mask)
(net 1 GND)) (net 1 GND))
(model Pin_Headers.3dshapes/Pin_Header_Straight_2x03.wrl
(at (xyz 0.05 -0.1 0))
(scale (xyz 1 1 1))
(rotate (xyz 0 0 90))
)
) )
(module Housings_SSOP:TSSOP-16_4.4x5mm_Pitch0.65mm (layer B.Cu) (tedit 579A4441) (tstamp 5789E0C1) (module Housings_SSOP:TSSOP-16_4.4x5mm_Pitch0.65mm (layer B.Cu) (tedit 579A4441) (tstamp 5789E0C1)

View file

@ -1,4 +1,4 @@
update=25.08.2016 18:28:32 update=27.09.2016 11:23:30
version=1 version=1
last_client=kicad last_client=kicad
[cvpcb] [cvpcb]
@ -86,7 +86,7 @@ LibName34=crystal
[schematic_editor] [schematic_editor]
version=1 version=1
PageLayoutDescrFile= PageLayoutDescrFile=
PlotDirectoryName= PlotDirectoryName=usb2serialmux_sch.svg
SubpartIdSeparator=0 SubpartIdSeparator=0
SubpartFirstId=65 SubpartFirstId=65
NetFmtName= NetFmtName=

View file

@ -1,23 +1,28 @@
#!/bin/bash #!/bin/bash
# reset the mux device to default values # reset the mux device to default values
pypy ./muxctrl.py -g -m -l 0 -s 115200 python ./muxctrl.py -b -m -l 0 -s 115200
# TODO start logging of the received data # TODO start logging of the received data
./readTTYToFile.sh /dev/ttyACM1 &
sleep 2
# read from line 0 to 7 # read from line 0 to 7
for i in `seq 0 7`; for i in `seq 0 7`;
do do
echo "channel #"$i echo "channel #"$i
pypy ./muxctrl.py -l $i python ./muxctrl.py -l $i -m
echo sleep 30 seconds
sleep 30 sleep 30
done done
sleep 3 sleep 3
# TODO stop logging of the received data # TODO stop logging of the received data
killall -12 readTTYToFile.sh
pypy ./muxctrl.py -g -m -l 0 -s 115200 python ./muxctrl.py -b -m -l 0 -s 115200

View file

@ -6,15 +6,17 @@ import threading
import time import time
import serial import serial
import copy import copy
import binascii
############################################################################### ###############################################################################
parser = argparse.ArgumentParser(description='USB2SerialMux control helper tool.') parser = argparse.ArgumentParser(description='USB2SerialMux control helper tool.')
parser.add_argument("-g", "--getBaudrate", default=False, help="Get the baudrate for the USART connection.", action='store_true') parser.add_argument("-b", "--getBaudrate", default=False, help="Get the baudrate for the USART connection.", action='store_true')
parser.add_argument("-s", "--setBaudrate", type=int, help="Something like 9600 or 115200.") parser.add_argument("-s", "--setBaudrate", type=int, help="Something like 9600 or 115200.")
parser.add_argument("-m", "--getMuxLine", default=False, help="Get the current multiplexer control line state.", action='store_true') parser.add_argument("-m", "--getMuxLine", default=False, help="Get the current multiplexer control line state.", action='store_true')
parser.add_argument("-l", "--setMuxLine", type=int, help="Something like 0 to 7.") parser.add_argument("-l", "--setMuxLine", type=int, help="Something like 0 to 7.")
parser.add_argument("-r", "--resetToBtldr", default=False, help="Reset the device to the LUFA bootloader.", action='store_true') parser.add_argument("-r", "--resetToBtldr", default=False, help="Reset the device to the LUFA bootloader.", action='store_true')
parser.add_argument("-d", "--device", type=str, help="The control device like /dev/ttyACM0 or COM3.")
############################################################################### ###############################################################################
@ -52,7 +54,8 @@ MUX_MAX_VAL = 7
############################################################################### ###############################################################################
ser = None ser = None
device = "/dev/ttyACM0"
############################################################################### ###############################################################################
@ -135,19 +138,21 @@ def cc_dataReceiverThread():
# 1. read byte from serial port into incoming # 1. read byte from serial port into incoming
incoming = [] incoming = []
incoming = ser.read(64) bytesToRead = ser.inWaiting()
if bytesToRead > 0:
incoming = list(ser.read(64))
# 2. process the received data # 2. process the received data
for c in incoming: for c in incoming:
c = int(binascii.hexlify(c), 16)
# call the cc_state specific function to process the currently received byte # call the cc_state specific function to process the currently received byte
cc_state_fn[cc_state](c) cc_state_fn[cc_state](c)
if cc_state not in cc_state_list: if cc_state not in cc_state_list:
cc_state = CC_STATE_WAIT_SOD1 cc_state = CC_STATE_WAIT_SOD1
time.sleep(THREAD_LOOP_DELAY_S) time.sleep(THREAD_LOOP_DELAY_S)
thread_stop = True
thread_started = False thread_started = False
@ -210,6 +215,7 @@ def cc_state_fn_get_type(c):
if c in msg_type_list: if c in msg_type_list:
msg_type = c msg_type = c
if msg_type_data_to_read[msg_type] > 0: if msg_type_data_to_read[msg_type] > 0:
cc_state = CC_STATE_READ_DATA cc_state = CC_STATE_READ_DATA
else: else:
@ -249,7 +255,6 @@ def cc_state_fn_wait_for_eod2(c):
global cc_state global cc_state
if c == MSG_EOD2: if c == MSG_EOD2:
# TODO process or save the data
is_message_read = False is_message_read = False
thread_lock.acquire() thread_lock.acquire()
cc_received_messages.append([ cc_message_cnt, cc_received_messages.append([ cc_message_cnt,
@ -304,7 +309,14 @@ def openSerialDevice(d):
global ser global ser
# Why 115200? Because the host defines the baudrate for the USB serial connection. # Why 115200? Because the host defines the baudrate for the USB serial connection.
ser = serial.Serial(d, 115200, timeout=0) try:
if "com" in d.lower():
d = "\\\\.\\" + d
ser = serial.Serial(d, 115200, timeout=0)
except:
print "ERROR: Can't open the serial device " + d
exit(1)
##### #####
def closeSerialDevice(): def closeSerialDevice():
@ -318,9 +330,9 @@ def sendSerialData(data):
global ser global ser
ser.write([ MSG_SOD1, MSG_SOD2 ]) ser.write(bytearray([ MSG_SOD1, MSG_SOD2 ]))
ser.write(bytearray(data)) ser.write(bytearray(data))
ser.write([ MSG_EOD1, MSG_EOD2 ]) ser.write(bytearray([ MSG_EOD1, MSG_EOD2 ]))
############################################################################### ###############################################################################
@ -335,7 +347,10 @@ if __name__ == "__main__":
timeout = 0 timeout = 0
# 1. open serial device or abort # 1. open serial device or abort
openSerialDevice("/dev/ttyACM0") if args.device != None:
device = args.device
openSerialDevice(device)
# 2. start thread to poll cc_dataReceiverThread() # 2. start thread to poll cc_dataReceiverThread()
cc_startReceiverThread() cc_startReceiverThread()
@ -426,3 +441,4 @@ if __name__ == "__main__":
closeSerialDevice() closeSerialDevice()
exit(0) exit(0)

25
tools/readTTYToFile.sh Executable file
View file

@ -0,0 +1,25 @@
#!/bin/bash
TTY_DEV=$1 # or /dev/ttyACM1
OUT_FILE=$2
if [ -z "$TTY_DEV" ];
then
TTY_DEV=/dev/ttyACM1
fi
if [ -z "$OUT_FILE" ];
then
OUT_FILE="tty_bootup_seq.log"
fi
echo "Read from "$TTY_DEV" and write to "$OUT_FILE
while read line; do
if [ "$line" != "EOF" ]; then
echo "$line" >> $OUT_FILE
else
break
fi
done < $TTY_DEV