A lot of untested modifications.

This commit is contained in:
klaute 2016-08-30 16:48:55 +02:00
parent 45398caf80
commit d9546a3120
4 changed files with 652 additions and 385 deletions

View file

@ -1,13 +1,21 @@
/**
* description: Modified LUFA example to get two virtual serial USB devices.
* author: Kai Lauterbach
* date: 08/2016
* version: v0.1
* license: GPLv3
*/
/* /*
LUFA Library LUFA Library
Copyright (C) Dean Camera, 2015. Copyright (C) Dean Camera, 2016.
dean [at] fourwalledcubicle [dot] com dean [at] fourwalledcubicle [dot] com
www.lufa-lib.org www.lufa-lib.org
*/ */
/* /*
Copyright 2015 Dean Camera (dean [at] fourwalledcubicle [dot] com) Copyright 2016 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
@ -30,357 +38,467 @@
/** \file /** \file
* *
* Main source file for the iUSB2SerialMux demo. This file contains the main tasks of the demo and * Main source file for the project - based on the Mouse and VirtualSerial lufa demo.
* is responsible for the initial application hardware configuration. * This file contains the main tasks of the demo and is responsible for the initial
* application hardware configuration.
*/ */
#include "main.h" #include "main.h"
/**************************************************************************************/ //********************************************************************************//
uint32_t EEMEM eep_baudrate; FIFO_t agent_fifo;
FIFO_t seq_mod_fifo;
FIFO_t seq_val_fifo;
uint32_t baudrate = 115200; // replacement for the UART_BAUDRATE definition uint8_t seq_delay = 0;
/**************************************************************************************/ 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
* upon request or the host will assume the device is non-functional. /** Buffer to hold the previously generated Keyboard HID report, for comparison purposes inside the HID class driver. */
* 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.
*/ */
static CDC_LineEncoding_t LineEncoding1 = { .BaudRateBPS = 0, USB_ClassInfo_HID_Device_t Keyboard_HID_Interface =
.CharFormat = CDC_LINEENCODING_OneStopBit, {
.ParityType = CDC_PARITY_None, .Config =
.DataBits = 8 }; {
.InterfaceNumber = INTERFACE_ID_Keyboard,
.ReportINEndpoint =
{
.Address = KEYBOARD_IN_EPADDR,
.Size = KEYBOARD_EPSIZE,
.Banks = 1,
},
.PrevReportINBuffer = PrevKeyboardHIDReportBuffer,
.PrevReportINBufferSize = sizeof(PrevKeyboardHIDReportBuffer),
},
};
/** Contains the current baud rate and other settings of the second virtual serial port. While this demo does not use /** LUFA CDC Class driver interface configuration and state information. This structure is
* the physical USART and thus does not use these settings, they must still be retained and returned to the host * passed to all CDC Class driver functions, so that multiple instances of the same class
* upon request or the host will assume the device is non-functional. * within a device can be differentiated from one another.
*
* 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.
*/ */
static CDC_LineEncoding_t LineEncoding2 = { .BaudRateBPS = 0, USB_ClassInfo_CDC_Device_t VirtualSerial_CDC_Interface =
.CharFormat = CDC_LINEENCODING_OneStopBit, {
.ParityType = CDC_PARITY_None, .Config =
.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();
// initialize the command interpreter // init the timer for time measurements
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();
SET_ERR_MASK(ERRMASK_USB_NOTREADY); FIFO_init( agent_fifo);
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 (;;)
{ {
CDC1_Task(); SendVirtualSerialData();
CDC2_Task();
ProcessVirtualSerialData();
CDC_Device_USBTask(&VirtualSerial_CDC_Interface);
HID_Device_USBTask(&Keyboard_HID_Interface);
USB_USBTask(); USB_USBTask();
//uart_putc('1'); static uint8_t delay = 0;
if (delay > 50)
{
delay = 0;
lm_show();
}
delay++;
} }
} }
/** Configures the board hardware and chip peripherals for the demo's functionality. */ //********************************************************************************//
void SetupHardware(void)
void timer_init()
{
// 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 core to run from it */ // Start the PLL to multiply the 2MHz RC oscillator to 32MHz and switch the CPU
// 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 48MHz using the USB SOF as a reference */ // Start the 32MHz internal RC oscillator and start the DFLL to increase it to
// 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
// set the three MUX control lines to output // Hardware Initialization */
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);
}
uart_init( UART_BAUD_SELECT(baudrate, F_CPU) );
sei();
/* USB Hardware Initialization */
USB_Init(); USB_Init();
} }
/** 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 ProcessVirtualSerialData()
{
// 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,
uint8_t* const ReportID,
const uint8_t ReportType,
void* ReportData,
uint16_t* const ReportSize)
{
// Determine which interface must have its report generated */
if (HIDInterfaceInfo == &Keyboard_HID_Interface)
{
USB_KeyboardReport_Data_t* KeyboardReport = (USB_KeyboardReport_Data_t*)ReportData;
// update the key matrix values
km_updateKeyStates();
// prepare the new sequence related to the pressed key
for (uint8_t k = 0; k < LM_LED_CNT; k++)
{
if (km_getKeyState(k) == KEY_STATE_GO_DOWN)
{
FIFO_push(agent_fifo, k);
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
* 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
// use-case is to use the Data Terminal Ready (DTR) flag to enable and
// 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;
}
//********************************************************************************//
/** Event handler for the library USB Connection event. */
void EVENT_USB_Device_Connect(void) void EVENT_USB_Device_Connect(void)
{ {
/* Indicate USB enumerating */ SET_GLOB_USB_STATUS(STATUSMASK_USB_ENUMERATING);
SET_ERR_MASK(ERRMASK_USB_ENUMERATING);
} }
/** Event handler for the USB_Disconnect event. This indicates that the device is no longer connected to a host via /** Event handler for the library USB Disconnection event. */
* the status LEDs and stops the USB management and CDC management tasks.
*/
void EVENT_USB_Device_Disconnect(void) void EVENT_USB_Device_Disconnect(void)
{ {
/* Indicate USB not ready */ SET_GLOB_USB_STATUS(STATUSMASK_USB_NOTREADY);
SET_ERR_MASK(ERRMASK_USB_NOTREADY);
} }
/** Event handler for the USB_ConfigurationChanged event. This is fired when the host set the current configuration /** Event handler for the library USB Configuration Changed event. */
* 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;
/* Setup first CDC Interface's Endpoints */ ConfigSuccess &= HID_Device_ConfigureEndpoints(&Keyboard_HID_Interface);
ConfigSuccess &= Endpoint_ConfigureEndpoint(CDC1_TX_EPADDR, EP_TYPE_BULK, CDC_TXRX_EPSIZE, 1); ConfigSuccess &= CDC_Device_ConfigureEndpoints(&VirtualSerial_CDC_Interface);
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);
/* Setup second CDC Interface's Endpoints */ USB_Device_EnableSOFEvents();
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);
/* Reset line encoding baud rates so that the host knows to send new values */ SET_GLOB_USB_STATUS(ConfigSuccess ? STATUSMASK_USB_READY : STATUSMASK_USB_ERROR);
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 USB_ControlRequest event. This is used to catch and process control requests sent to /** Event handler for the library USB Control Request reception event. */
* 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)
{ {
/* Determine which interface's Line Coding data is being set from the wIndex parameter */ HID_Device_ProcessControlRequest(&Keyboard_HID_Interface);
void* LineEncodingData = (USB_ControlRequest.wIndex == 0) ? &LineEncoding1 : &LineEncoding2; CDC_Device_ProcessControlRequest(&VirtualSerial_CDC_Interface);
}
/* Process CDC specific control requests */ /** Event handler for the USB device Start Of Frame event. */
switch (USB_ControlRequest.bRequest) void EVENT_USB_Device_StartOfFrame(void)
{ {
case CDC_REQ_GetLineEncoding: HID_Device_MillisecondElapsed(&Keyboard_HID_Interface);
if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE)) }
//********************************************************************************//
void USB_serialStreamWriteC(char* msg, uint16_t len)
{ {
Endpoint_ClearSETUP(); for (uint8_t i = 0; i < len; i++)
/* 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(); fputc(msg[i], &USBSerialStream);
}
/* 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; void USB_serialStreamWrite(char* msg)
case CDC_REQ_SetControlLineState:
if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
{ {
Endpoint_ClearSETUP(); fputs(msg, &USBSerialStream);
Endpoint_ClearStatusStage();
} }
break; //********************************************************************************//
}
}
/** 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.
*/
void CDC1_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(CDC1_RX_EPADDR);
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();
for (uint16_t i = 0; i < DataLength; i++)
{
// process the received data and descide to do an action
LED0_ON;
cc_processData(Buffer[i]);
LED0_OFF;
}
}
}
void USB_serialStreamWriteC(char *data, uint16_t len)
{
//===========================================================================
/* Determine if data/answeres should be sent to the host
* the previous RX section should be clarify that behaviour.
*/
/* 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;
}
}
/** 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();
// TODO at this point send the data to the USART
// Send USART &Buffer
for (uint16_t i = 0; i < DataLength; i++)
{
uart_putc(Buffer[i]);
}
}
//return;
//===========================================================================
uint8_t outBuffer[OUTPUT_BUFFER_SIZE];
// TODO 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++;
}
/*
cnt = 1;
outBuffer[0] = '2';
*/
// 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();
}
}

36
tools/_serial.py Executable file
View file

@ -0,0 +1,36 @@
# a simple class to manage serial communication testing without to install the pySerial package
class Serial:
def __init__(self, device, baudrate, timeout):
self.device = device
self.baudrate = baudrate
self.timeout = timeout
self.msg_ok = [ 0x3c, 0x3e, 0x01, 0x0d, 0x0a ]
self.msg_nok = [ 0x3c, 0x3e, 0x02, 0x0d, 0x0a ]
self.msg_br = [ 0x3c, 0x3e, 0x03, 0x00, 0x01, 0xc2, 0x00, 0x0d, 0x0a ]
self.msg_ml = [ 0x3c, 0x3e, 0x04, 0x00, 0x0d, 0x0a ]
def read(self, num=0):
if num == 0:
return bytearray(['0'])
else:
ret = []
tmp = self.msg_ok
tmp += self.msg_nok
tmp += self.msg_br
tmp += self.msg_ml
for i in range(0, num):
if i < len(tmp):
ret.append(tmp[i])
return bytearray(ret)
def write(self, data):
for d in data:
print "0x%02x " % (d)
pass
def close(self):
print "Serial connection close"

23
tools/logClusterBootup.sh Executable file
View file

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

View file

@ -10,11 +10,11 @@ import copy
############################################################################### ###############################################################################
parser = argparse.ArgumentParser(description='USB2SerialMux control helper tool.') parser = argparse.ArgumentParser(description='USB2SerialMux control helper tool.')
parser.add_argument("-g", "--getbaudrate", default=False, help="", action='store_true') parser.add_argument("-g", "--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="", 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')
############################################################################### ###############################################################################
@ -28,23 +28,27 @@ MSG_TYPE_ANSWER_NOK = 0x02
MSG_TYPE_BAUDRATE = 0x03 MSG_TYPE_BAUDRATE = 0x03
MSG_TYPE_MUXLINE = 0x04 MSG_TYPE_MUXLINE = 0x04
MSG_TYPE_ANSWER_OK_DATA_TO_RECV = 0
MSG_TYPE_ANSWER_NOK_DATA_TO_RECV = 0
MSG_TYPE_BAUDRATE_DATA_TO_RECV = 4
MSG_TYPE_MUXLINE_DATA_TO_RECV = 1
CC_CMD_SET_BAUDRATE = 0x0A CC_CMD_SET_BAUDRATE = 0x0A
CC_CMD_GET_BAUDRATE = 0x14 CC_CMD_GET_BAUDRATE = 0x14
CC_CMD_SET_MUX_LINE = 0x1E CC_CMD_SET_MUX_LINE = 0x1E
CC_CMD_GET_MUX_LINE = 0x28 CC_CMD_GET_MUX_LINE = 0x28
CC_CMD_START_BTLDR = 0x32 CC_CMD_START_BTLDR = 0x32
CC_CMD_GET_BAUDRATE_DATA_TO_RECV 4 ###############################################################################
CC_CMD_SET_BAUDRATE_DATA_TO_RECV 0
CC_CMD_GET_MUX_LINE_DATA_TO_RECV 1 TIMEOUT_CNT_MAX = 50
CC_CMD_SET_MUX_LINE_DATA_TO_RECV 0 MAIN_LOOP_DELAY_S = 0.05
CC_CMD_START_BTLDR_DATA_TO_RECV 0 THREAD_LOOP_DELAY_S = 0.01
############################################################################### ###############################################################################
TIMEOUT_CNT_MAX = 1000 MUX_MIN_VAL = 0
MAIN_LOOP_DELAY_S = 0.05 MUX_MAX_VAL = 7
THREAD_LOOP_DELAY_S = 0.01
############################################################################### ###############################################################################
@ -62,30 +66,31 @@ CC_STATE_WAIT_SOD2 = 0x02
CC_STATE_READ_DATA = 0x03 CC_STATE_READ_DATA = 0x03
CC_STATE_WAIT_EOD1 = 0x04 CC_STATE_WAIT_EOD1 = 0x04
CC_STATE_WAIT_EOD2 = 0x05 CC_STATE_WAIT_EOD2 = 0x05
CC_STATE_GET_TYPE = 0x06
cc_state = CC_STATE_WAIT_SOD1 cc_state = CC_STATE_WAIT_SOD1
cc_cmd_list = [ CC_CMD_SET_BAUDRATE, cc_state_list = [ CC_STATE_WAIT_SOD1,
CC_CMD_GET_BAUDRATE, CC_STATE_WAIT_SOD2,
CC_CMD_SET_MUX_LINE, CC_STATE_READ_DATA,
CC_CMD_GET_MUX_LINE, CC_STATE_WAIT_EOD1,
CC_CMD_START_BTLDR, ] CC_STATE_WAIT_EOD2 ]
cc_state_fn = { CC_STATE_WAIT_SOD1 : cc_state_fn_wait_for_sod1, cc_state_fn = {}
CC_STATE_WAIT_SOD2 : cc_state_fn_wait_for_sod2,
CC_STATE_WAIT_EOD1 : cc_state_fn_wait_for_eod1,
CC_STATE_WAIT_EOD2 : cc_state_fn_wait_for_eod2,
CC_STATE_GET_TYPE : cc_state_fn_get_type,
CC_STATE_READ_DATA : cc_state_fn_read_data, }
cc_cmd_data_to_read = { CC_CMD_SET_BAUDRATE : CC_CMD_SET_BAUDRATE_DATA_TO_RECV, msg_type_list = [ MSG_TYPE_ANSWER_OK,
CC_CMD_GET_BAUDRATE : CC_CMD_GET_BAUDRATE_DATA_TO_RECV, MSG_TYPE_ANSWER_NOK,
CC_CMD_SET_MUX_LINE : CC_CMD_SET_MUX_LINE_DATA_TO_RECV, MSG_TYPE_BAUDRATE,
CC_CMD_GET_MUX_LINE : CC_CMD_GET_MUX_LINE_DATA_TO_RECV, MSG_TYPE_MUXLINE, ]
CC_CMD_START_BTLDR : CC_CMD_START_BTLDR_DATA_TO_RECV, }
msg_type_data_to_read = { MSG_TYPE_ANSWER_OK : MSG_TYPE_ANSWER_OK_DATA_TO_RECV,
MSG_TYPE_ANSWER_NOK : MSG_TYPE_ANSWER_NOK_DATA_TO_RECV,
MSG_TYPE_BAUDRATE : MSG_TYPE_BAUDRATE_DATA_TO_RECV,
MSG_TYPE_MUXLINE : MSG_TYPE_MUXLINE_DATA_TO_RECV, }
msg_type = 0
cc_data_read = 0 cc_data_read = 0
cc_type = 0
cc_data_buffer = [] cc_data_buffer = []
# yes a separate counter to manage the order of the received messages # yes a separate counter to manage the order of the received messages
@ -96,15 +101,37 @@ cc_received_messages = []
thread_obj = None thread_obj = None
thread_lock = None thread_lock = None
thread_started = False
thread_stop = False
############################################################################### ###############################################################################
def cc_init():
global cc_state_fn
global cc_state
cc_state = CC_STATE_WAIT_SOD1
cc_state_fn = { CC_STATE_WAIT_SOD1 : cc_state_fn_wait_for_sod1,
CC_STATE_WAIT_SOD2 : cc_state_fn_wait_for_sod2,
CC_STATE_WAIT_EOD1 : cc_state_fn_wait_for_eod1,
CC_STATE_WAIT_EOD2 : cc_state_fn_wait_for_eod2,
CC_STATE_GET_TYPE : cc_state_fn_get_type,
CC_STATE_READ_DATA : cc_state_fn_read_data, }
########## function to call by the thread ########## function to call by the thread
def processReceivedData(): def cc_dataReceiverThread():
global ser
global cc_state
global cc_state_fn
global thread_started
global thread_stop
thread_started = True thread_started = True
for thread_stop == False: while thread_stop == False:
# 1. read byte from serial port into incoming # 1. read byte from serial port into incoming
incoming = [] incoming = []
@ -112,77 +139,123 @@ def processReceivedData():
# 2. process the received data # 2. process the received data
for c in incoming: for c in incoming:
# 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:
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
########## ##########
def startReceiverThread(): def cc_startReceiverThread():
global thread_obj
global thread_lock
global thread_stop
if thread_started == False: if thread_started == False:
thread_lock = threading.Lock() thread_lock = threading.Lock()
thread_obj = threading.Thread(target=processReceivedData) thread_obj = threading.Thread(target=cc_dataReceiverThread)
thread_obj.start() thread_obj.start()
thread_stop = False thread_stop = False
########## ##########
def stopReceiverThread(): def cc_stopReceiverThread():
global thread_obj
global thread_started
global thread_stop
if thread_started == True:
thread_stop = True thread_stop = True
thread_obj.join() # wait for the thread to finish thread_obj.join() # wait for the thread to finish
##### CC_STATE_WAIT_SOD1 ##### CC_STATE_WAIT_SOD1
def cc_state_fn_wait_for_sod1(c): def cc_state_fn_wait_for_sod1(c):
global cc_data_read
global msg_type
global cc_data_buffer
global cc_state
cc_data_read = 0 cc_data_read = 0
cc_type = 0 msg_type = 0
cc_data_buffer = [] cc_data_buffer = []
if c == MSG_SOD1: if c == MSG_SOD1:
cc_state = CC_STATE_WAIT_SOD2 cc_state = CC_STATE_WAIT_SOD2
else else:
cc_state = CC_STATE_WAIT_SOD1 cc_state = CC_STATE_WAIT_SOD1
##### CC_STATE_WAIT_SOD2 ##### CC_STATE_WAIT_SOD2
def cc_state_fn_wait_for_sod2(c): def cc_state_fn_wait_for_sod2(c):
global cc_state
if c == MSG_SOD2: if c == MSG_SOD2:
cc_state = CC_STATE_GET_TYPE cc_state = CC_STATE_GET_TYPE
else else:
cc_state = CC_STATE_WAIT_SOD1 cc_state = CC_STATE_WAIT_SOD1
##### CC_STATE_GET_TYPE ##### CC_STATE_GET_TYPE
def cc_state_fn_get_type(c): def cc_state_fn_get_type(c):
if c in cc_cmd_list:
cc_type = c global msg_type
if cc_cmd_data_to_read[cc_type] > 0: global cc_state
if c in msg_type_list:
msg_type = c
if msg_type_data_to_read[msg_type] > 0:
cc_state = CC_STATE_READ_DATA cc_state = CC_STATE_READ_DATA
else: else:
cc_state = CC_STATE_WAIT_EOD1 cc_state = CC_STATE_WAIT_EOD1
else else:
cc_state = CC_STATE_WAIT_SOD1 cc_state = CC_STATE_WAIT_SOD1
##### CC_STATE_READ_DATA ##### CC_STATE_READ_DATA
def cc_state_fn_read_data(c): def cc_state_fn_read_data(c):
if cc_data_read <= cc_state_data_to_read[cc_state] - 1:
cc_data_buffer[cc_data_read] = c global cc_data_buffer
global cc_data_read
global cc_state
if cc_data_read <= msg_type_data_to_read[msg_type] - 1:
cc_data_buffer.append(c)
cc_data_read = cc_data_read + 1 cc_data_read = cc_data_read + 1
if cc_data_read == cc_state_data_to_read[cc_state]: if cc_data_read == msg_type_data_to_read[msg_type]:
cc_state = CC_STATE_WAIT_EOD1 cc_state = CC_STATE_WAIT_EOD1
##### CC_STATE_WAIT_EOD1 ##### CC_STATE_WAIT_EOD1
def cc_state_fn_wait_for_eod1(c): def cc_state_fn_wait_for_eod1(c):
global cc_state
if c == MSG_EOD1: if c == MSG_EOD1:
cc_state = CC_STATE_WAIT_EOD2 cc_state = CC_STATE_WAIT_EOD2
else else:
cc_state = CC_STATE_WAIT_SOD1 cc_state = CC_STATE_WAIT_SOD1
##### CC_STATE_WAIT_EOD2 ##### CC_STATE_WAIT_EOD2
def cc_state_fn_wait_for_eod2(c): def cc_state_fn_wait_for_eod2(c):
global thread_lock
global cc_message_cnt
global cc_state
if c == MSG_EOD2: if c == MSG_EOD2:
# TODO process or save the data # 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_type, is_message_read, copy.deepcopy(cc_data_buffer) ]) cc_received_messages.append([ cc_message_cnt,
msg_type,
is_message_read,
copy.deepcopy(cc_data_buffer) ])
thread_lock.release() thread_lock.release()
cc_message_cnt = cc_message_cnt + 1 cc_message_cnt = cc_message_cnt + 1
@ -190,60 +263,71 @@ def cc_state_fn_wait_for_eod2(c):
############################################################################### ###############################################################################
def getBaudrate(): def send_getBaudrate():
print "send: get baudrate " % CC_CMD_GET_BAUDRATE
print "send: get baudrate (0x%02x)" % (CC_CMD_GET_BAUDRATE)
sendSerialData([CC_CMD_GET_BAUDRATE]) sendSerialData([CC_CMD_GET_BAUDRATE])
def setBaudrate(b): def send_setBaudrate(b):
print "send: set baudrate " % CC_CMD_SET_BAUDRATE
print "send: set baudrate (0x%02x)" % (CC_CMD_SET_BAUDRATE)
sendSerialData([ CC_CMD_SET_BAUDRATE, sendSerialData([ CC_CMD_SET_BAUDRATE,
(baudrate & 0xff000000) >> 24, (b & 0xff000000) >> 24,
(baudrate & 0xff0000) >> 16, (b & 0xff0000) >> 16,
(baudrate & 0xff00) >> 8, (b & 0xff00) >> 8,
(baudrate & 0xff)]) (b & 0xff) ])
############################################################################### ###############################################################################
def getMuxLine(): def send_getMuxLine():
print "send: get mux line " % CC_CMD_GET_MUX_LINE
print "send: get mux line (0x%02x)" % (CC_CMD_GET_MUX_LINE)
sendSerialData([CC_CMD_GET_MUX_LINE]) sendSerialData([CC_CMD_GET_MUX_LINE])
def setMuxLine(l): def send_setMuxLine(l):
print "send: set mux line " % CC_CMD_SET_MUX_LINE
sendSerialData([CC_CMD_SET_MUX_LINE, muxLine]) print "send: set mux line (0x%02x)" % (CC_CMD_SET_MUX_LINE)
sendSerialData([CC_CMD_SET_MUX_LINE, l])
############################################################################### ###############################################################################
def getStatus(): def send_resetToBtldr():
getBaudrate() print "send: reset to bootloader message (0x%02x)" % (CC_CMD_START_BTLDR)
getMuxLine()
###############################################################################
def resetToBtldr():
print "send: reset to bootloader message " % CC_CMD_START_BTLDR
sendSerialData([CC_CMD_START_BTLDR]) sendSerialData([CC_CMD_START_BTLDR])
############################################################################### ###############################################################################
##### #####
def openSerialDevice(d): def openSerialDevice(d):
global ser
# Why 115200? Because the host defines the baudrate for the USB serial connection.
ser = serial.Serial(d, 115200, timeout=0) ser = serial.Serial(d, 115200, timeout=0)
##### #####
def closeSerialDevice(): def closeSerialDevice():
global ser
ser.close() ser.close()
##### #####
def sendSerialData(data): def sendSerialData(data):
for c in data:
ser.write(c) global ser
ser.write([ MSG_SOD1, MSG_SOD2 ])
ser.write(bytearray(data))
ser.write([ MSG_EOD1, MSG_EOD2 ])
############################################################################### ###############################################################################
if __name__ == "__main__": if __name__ == "__main__":
cc_init()
# parse the commandline arguments # parse the commandline arguments
args = parser.parse_args() args = parser.parse_args()
@ -253,67 +337,70 @@ if __name__ == "__main__":
# 1. open serial device or abort # 1. open serial device or abort
openSerialDevice("/dev/ttyACM0") openSerialDevice("/dev/ttyACM0")
# 2. start thread to poll processReceivedData() # 2. start thread to poll cc_dataReceiverThread()
startReceiverThread() cc_startReceiverThread()
# 3. get status # 3. get and process the commandline arguments/parameter
getStatus() if args.resetToBtldr == True:
send_resetToBtldr()
# 4. get and process the commandline arguments/parameter
if args.resettobtldr == True:
resetToBtldr()
else: else:
if args.getbaudrate == True: if args.setBaudrate != None:
getBaudrate() baudrate = args.setBaudrate
send_setBaudrate(baudrate)
dataSend = dataSend + 1 dataSend = dataSend + 1
if args.getmuxline == True: if args.setMuxLine != None:
getMuxLine() muxLine = args.setMuxLine
# keep the mux line in range
if muxLine < MUX_MIN_VAL:
muxLine = MUX_MIN_VAL
if muxLine > MUX_MAX_VAL:
muxLine = MUX_MAX_VAL
send_setMuxLine(muxLine)
dataSend = dataSend + 1 dataSend = dataSend + 1
if args.setbaudrate != None: if args.getBaudrate == True:
baudrate = map(int, args.setbaudrate) send_getBaudrate()
setBaudrate(baudrate)
dataSend = dataSend + 1 dataSend = dataSend + 1
if args.setmuxline != None: if args.getMuxLine == True:
muxLine = map(int, args.setmuxline) send_getMuxLine()
if muxLine < 0:
muxLine = 0
if muxLine > 7:
muxLine = 7
setMuxLine(muxLine)
dataSend = dataSend + 1 dataSend = dataSend + 1
# 5. start main loop # 4. start main loop
for dataSend > 0 and timeout < TIMEOUT_CNT_MAX: while dataSend > 0 and timeout < TIMEOUT_CNT_MAX:
thread_lock.acquire() thread_lock.acquire()
tmp_messages = copy.deepcopy(cc_received_messages) tmp_messages = copy.deepcopy(cc_received_messages)
thread_lock.release() thread_lock.release()
# 5.1 wait for the response(s) # 4.1 test for the response(s)
for e in tmp_messages: for e in tmp_messages:
if e[2] == False: # test for unread message if e[2] == False: # test for unread message
# process it and set the data to read # process it and set the data to read
if e[1] == MSG_TYPE_ANSWER_OK: if e[1] == MSG_TYPE_ANSWER_OK:
print "recv: OK" print "recv: OK"
elif e[1] == MSG_TYPE_ANSWER_NOK: elif e[1] == MSG_TYPE_ANSWER_NOK:
print "recv: NOT OK" print "recv: NOT OK"
elif e[1] == MSG_TYPE_BAUDRATE: elif e[1] == MSG_TYPE_BAUDRATE:
baudrate = e[3][0] << 24 baudrate = e[3][0] << 24
baudrate = baudrate + e[3][1] << 16 baudrate += e[3][1] << 16
baudrate = baudrate + e[3][2] << 8 baudrate += e[3][2] << 8
baudrate = baudrate + e[3][3] baudrate += e[3][3]
print "recv: baudrate = " % baudrate print "recv: baudrate = %d" % (baudrate)
elif e[1] == MSG_TYPE_MUXLINE: elif e[1] == MSG_TYPE_MUXLINE:
muxLine = e[3][0] muxLine = e[3][0]
print "recv: muxLine = " % muxLine print "recv: muxLine = %d" % (muxLine)
else: else:
print "err: unknown type " % e[1] print "err: unknown type 0x%02x" % (e[1])
break break
thread_lock.acquire() thread_lock.acquire()
@ -329,10 +416,13 @@ if __name__ == "__main__":
time.sleep(MAIN_LOOP_DELAY_S) time.sleep(MAIN_LOOP_DELAY_S)
timeout = timeout + 1 timeout = timeout + 1
# 6. stop data processing thread if timeout >= TIMEOUT_CNT_MAX:
stopReceiverThread() print "Timeout happened"
# 7. close serial device # 5. stop data processing thread
cc_stopReceiverThread()
# 6. close serial device
closeSerialDevice() closeSerialDevice()
exit(0) exit(0)