Updated VirtualSerial for loopback and added throughput testing scripts.

This commit is contained in:
opendous
2011-11-23 05:22:48 +00:00
parent e34abd3593
commit d4838af0a2
7 changed files with 257 additions and 91 deletions

View File

@@ -203,9 +203,9 @@ const USB_Descriptor_String_t PROGMEM LanguageString =
*/ */
const USB_Descriptor_String_t PROGMEM ManufacturerString = const USB_Descriptor_String_t PROGMEM ManufacturerString =
{ {
.Header = {.Size = USB_STRING_LEN(11), .Type = DTYPE_String}, .Header = {.Size = USB_STRING_LEN(20), .Type = DTYPE_String},
.UnicodeString = L"Dean Camera" .UnicodeString = L"www.Micropendous.org"
}; };
/** Product descriptor string. This is a Unicode string containing the product's details in human readable form, /** Product descriptor string. This is a Unicode string containing the product's details in human readable form,
@@ -214,9 +214,9 @@ const USB_Descriptor_String_t PROGMEM ManufacturerString =
*/ */
const USB_Descriptor_String_t PROGMEM ProductString = const USB_Descriptor_String_t PROGMEM ProductString =
{ {
.Header = {.Size = USB_STRING_LEN(13), .Type = DTYPE_String}, .Header = {.Size = USB_STRING_LEN(35), .Type = DTYPE_String},
.UnicodeString = L"LUFA CDC Demo" .UnicodeString = L"LUFA-lib.org CDC VirtualSerial Demo"
}; };
/** This function is called by the library when in device mode, and must be overridden (see library "USB Descriptors" /** This function is called by the library when in device mode, and must be overridden (see library "USB Descriptors"

View File

@@ -55,6 +55,7 @@
#define CDC_NOTIFICATION_EPSIZE 8 #define CDC_NOTIFICATION_EPSIZE 8
/** Size in bytes of the CDC data IN and OUT endpoints. */ /** Size in bytes of the CDC data IN and OUT endpoints. */
// 32 is maximum size compatible with all USB AVRs
#define CDC_TXRX_EPSIZE 16 #define CDC_TXRX_EPSIZE 16
/* Type Defines: */ /* Type Defines: */

View File

@@ -0,0 +1,64 @@
# Purpose: Test the throughput of a Micropendous board loaded with Virtual Serial Port loopback firmware
# Visit www.Micropendous.org/Serial for more info.
# Created: 2008-09-30 by Opendous Inc.
# Last Edit: 2009-10-03 by Opendous Inc.
# Released under the MIT License
import serial # for accessing the serial port on multiple platforms
import time, sys
# test Serial Port throughput by sending and receiving transfersToComplete number
# of transferSize sized strings
# comport is a string - the Serial Port name to use
# transferSize is an integer - the string lenght
# transfersToComplete is an integer - the number of transfers to test with
def SerialThroughputTest(comport, transferSize, transfersToComplete):
ser = serial.Serial(comport) # open serial port for communication
print ser # dump all info regarding serial port being used
ScriptStartTime = time.time()
# create a transferSize length string
i = 0
s = ''
while (i < (transferSize - 1)):
s = s + 'A'
i = i + 1
# want last letter to be X
s = s + 'X'
# complete a series of transfers
i = 0
while (i < transfersToComplete):
# send one string to device then get back the string
ser.write(s)
receivedData = ser.read(transferSize)
#print receivedData
i = i + 1
ScriptEndTime = time.time()
print "\nIt took", (ScriptEndTime - ScriptStartTime), "seconds to transfer", \
(transfersToComplete * transferSize), "bytes for a throughput of", \
(((transfersToComplete * transferSize) / (ScriptEndTime - ScriptStartTime)) / 1000), "kbytes/second"
# be careful using readline as it will block until a newline character is received
ser.close() # release/close the serial port
# if this file is the program actually being run, print usage info or run SerialThroughputTest
if __name__ == '__main__':
if (len(sys.argv) != 4):
print "Serial Communication Throughput Testing"
print " Usage:"
print " python", sys.argv[0], "<port> <transferSize> <testSize>"
print " Where <port> = serial port; COM? on Windows, '/dev/ttyACM0 on Linux'"
print " Enumerated serial port can be found on Linux using dmesg"
print " look for something like cdc_acm 2-1:1.0: ttyACM0: USB ACM device"
print " Where <transferSize> = the size of each transfer, this value should match"
print " CDC_TXRX_EPSIZE in Descriptors.h for maximum throughput"
print " Where <testSize> = how many transfers to complete, 100 is usually enough"
print " "
print " python", sys.argv[0], "COM5 64 100"
exit()
SerialThroughputTest(sys.argv[1], int(sys.argv[2]), int(sys.argv[3]))

View File

@@ -9,6 +9,9 @@
/* /*
Copyright 2011 Dean Camera (dean [at] fourwalledcubicle [dot] com) Copyright 2011 Dean Camera (dean [at] fourwalledcubicle [dot] com)
Updated for Loopback by Opendous Inc. 2011-11-22
www.Micropendous.org/VirtualSerial
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
without fee, provided that the above copyright notice appear in without fee, provided that the above copyright notice appear in
@@ -36,6 +39,9 @@
#include "VirtualSerial.h" #include "VirtualSerial.h"
// Global buffer for use with STDIO functions
volatile char buffer[CDC_TXRX_EPSIZE];
/** LUFA CDC Class driver interface configuration and state information. This structure is /** LUFA CDC Class driver interface configuration and state information. This structure is
* passed to all CDC Class driver functions, so that multiple instances of the same class * passed to all CDC Class driver functions, so that multiple instances of the same class
* within a device can be differentiated from one another. * within a device can be differentiated from one another.
@@ -81,16 +87,18 @@ int main(void)
for (;;) for (;;)
{ {
CheckJoystickMovement(); MainTask();
/* Must throw away unused bytes from the host, or it will lock up while waiting for the device */ // Must throw away unused bytes from the host, or it will lock up while waiting for the device
CDC_Device_ReceiveByte(&VirtualSerial_CDC_Interface); // TODO: this causes loopback to fail
//CDC_Device_ReceiveByte(&VirtualSerial_CDC_Interface);
CDC_Device_USBTask(&VirtualSerial_CDC_Interface); CDC_Device_USBTask(&VirtualSerial_CDC_Interface);
USB_USBTask(); USB_USBTask();
} }
} }
/** Configures the board hardware and chip peripherals for the demo's functionality. */ /** Configures the board hardware and chip peripherals for the demo's functionality. */
void SetupHardware(void) void SetupHardware(void)
{ {
@@ -98,51 +106,20 @@ void SetupHardware(void)
MCUSR &= ~(1 << WDRF); MCUSR &= ~(1 << WDRF);
wdt_disable(); wdt_disable();
// TODO: disabling JTAG allows PF4, PF5, PF6, and PF7 to be used as GPIO pins
JTAG_DISABLE();
/* Disable clock division */ /* Disable clock division */
clock_prescale_set(clock_div_1); clock_prescale_set(clock_div_1);
/* Hardware Initialization */ /* Hardware Initialization */
Joystick_Init(); Board_Init();
LEDs_Init(); DISABLE_VOLTAGE_TXRX;
DISABLE_EXT_SRAM;
SELECT_USB_B;
USB_Init(); USB_Init();
} }
#define BUTTONS_BUTTON1 (1 << 2)
/** Checks for changes in the position of the board joystick, sending strings to the host upon each change. */
void CheckJoystickMovement(void)
{
uint8_t JoyStatus_LCL = Joystick_GetStatus();
char* ReportString = NULL;
static bool ActionSent = false;
if (JoyStatus_LCL & JOY_UP)
ReportString = "Joystick Up\r\n";
else if (JoyStatus_LCL & JOY_DOWN)
ReportString = "Joystick Down\r\n";
else if (JoyStatus_LCL & JOY_LEFT)
ReportString = "Joystick Left\r\n";
else if (JoyStatus_LCL & JOY_RIGHT)
ReportString = "Joystick Right\r\n";
else if (JoyStatus_LCL & JOY_PRESS)
ReportString = "Joystick Pressed\r\n";
else
ActionSent = false;
if (((PINE & BUTTONS_BUTTON1) ^ BUTTONS_BUTTON1))
{
DDRE &= ~BUTTONS_BUTTON1;
PORTE |= BUTTONS_BUTTON1;
ActionSent = true;
ReportString = "Joystick Pressed\r\n";
/* Write the string to the virtual COM port via the created character stream */
fputs(ReportString, &USBSerialStream);
/* Alternatively, without the stream: */
// CDC_Device_SendString(&VirtualSerial_CDC_Interface, ReportString);
}
}
/** Event handler for the library USB Connection event. */ /** Event handler for the library USB Connection event. */
void EVENT_USB_Device_Connect(void) void EVENT_USB_Device_Connect(void)
@@ -172,3 +149,24 @@ void EVENT_USB_Device_ControlRequest(void)
CDC_Device_ProcessControlRequest(&VirtualSerial_CDC_Interface); CDC_Device_ProcessControlRequest(&VirtualSerial_CDC_Interface);
} }
void MainTask(void)
{
int count = 0;
// If the host has sent data then echo it back
// Throughput is maximized if the full EP buffer is read and sent each time
// Throughput approaches CDC_TXRX_EPSIZE kbytes/second and depends on transfer size from host
if ((count = fread(&buffer, 1, CDC_TXRX_EPSIZE, &USBSerialStream)) > 0) {
fwrite(&buffer, 1, count, &USBSerialStream);
}
// If HWB Button is pressed then send formatted strings
if (Buttons_GetStatus()) {
fprintf_P(&USBSerialStream, PSTR("\r\nHWB has been pressed!\r\n")); // send a constant string stored in FLASH
fprintf(&USBSerialStream, "PORTD = %3x\r\n", PIND); // send a string that is dynamic and stored in SRAM
}
}

View File

@@ -48,7 +48,7 @@
#include <LUFA/Version.h> #include <LUFA/Version.h>
#include <LUFA/Drivers/Board/LEDs.h> #include <LUFA/Drivers/Board/LEDs.h>
#include <LUFA/Drivers/Board/Joystick.h> #include <LUFA/Drivers/Board/BoardSupport.h>
#include <LUFA/Drivers/USB/USB.h> #include <LUFA/Drivers/USB/USB.h>
/* Macros: */ /* Macros: */
@@ -66,7 +66,7 @@
/* Function Prototypes: */ /* Function Prototypes: */
void SetupHardware(void); void SetupHardware(void);
void CheckJoystickMovement(void); void MainTask(void);
void EVENT_USB_Device_Connect(void); void EVENT_USB_Device_Connect(void);
void EVENT_USB_Device_Disconnect(void); void EVENT_USB_Device_Disconnect(void);

View File

@@ -30,7 +30,11 @@
# make extcoff = Convert ELF to AVR Extended COFF. # make extcoff = Convert ELF to AVR Extended COFF.
# #
# make program = Download the hex file to the device, using avrdude. # make program = Download the hex file to the device, using avrdude.
# Please customize the avrdude settings below first! # Assumes the target is connected through an AVR ISP mkII programmer
#
# make cdc = Download the hex file to the device, using avrdude.
# Assumes the target device is running the LUFA CDC Bootloader
# Make sure to set the CDC_BOOTLOADER_PORT variable
# #
# make dfu = Download the hex file to the device, using dfu-programmer (must # make dfu = Download the hex file to the device, using dfu-programmer (must
# have dfu-programmer installed). # have dfu-programmer installed).
@@ -59,32 +63,63 @@
#---------------------------------------------------------------------------- #----------------------------------------------------------------------------
# MCU name # MCU name - uncomment _ONE_ of the following
MCU = atmega32u4 #MCU = at90usb82
#MCU = at90usb162
#MCU = atmega16u2
#MCU = atmega32u2
#MCU = atmega32u4
#MCU = at90usb646
#MCU = at90usb647
#MCU = at90usb1286
MCU = at90usb1287
# Target architecture (see library "Board Types" documentation). # Target architecture (see library "Board Types" documentation).
ARCH = AVR8 ARCH = AVR8
# Target board (see library "Board Types" documentation, NONE for projects not requiring # Target board:
# LUFA board drivers). If USER is selected, put custom board drivers in a directory called # - USER for custom board drivers in LUFA/LUFA/Drivers/Board/Board/*
# "Board" inside the application directory. # - NONE for projects not requiring LUFA board drivers such as boards
BOARD = USBKEY # with no LEDs and just an HWB button such as: Micropendous1, Micropendous2,
# Micropendous3 or Micropendous4 without external SRAM
# - MICROPENDOUS_32U2 for Micropendous-32U2 which has 1 user LED on PD6
# http://www.Micropendous.org/Micropendous-32U2
# - MICROPENDOUS_A for Micropendous-A, Micropendous3, or Micropendous3 boards with external SRAM
# where PE6 is the external SRAM Chip Enable Pin and PE7 is Address Bit 17/Bank Selector Pin
# http://www.Micropendous.org/Micropendous-A
# - MICROPENDOUS_REV1 for the Micropendous Arduino-like board with the
# CY7C1019D external SRAM IC or its DIP variant:
# http://www.Micropendous.org/Micropendous-REV1
# http://www.Micropendous.org/Micropendous-DIP
# - MICROPENDOUS_REV2 for the Micropendous Arduino-like board with the
# IS61C1024AL external SRAM IC:
# http://www.Micropendous.org/Micropendous
# Typical values are:
# BOARD = NONE
# BOARD = USER
# BOARD = MICROPENDOUS_A
# BOARD = MICROPENDOUS_32U2
# BOARD = MICROPENDOUS_REV1
# BOARD = MICROPENDOUS_REV2
BOARD = MICROPENDOUS_REV2
# Enable External SRAM: Defining to YES will enable external SRAM use
# via the linker. For more info visit www.Micropendous.org/SRAM
ENABLE_EXTERNAL_SRAM = NO
# Processor frequency. # Processor frequency.
# This will define a symbol, F_CPU, in all source code files equal to the # This will define a symbol, F_CPU, in all source code files equal to the
# processor frequency in Hz. You can then use this symbol in your source code to # crystal frequency. You can then use this symbol in your source code to
# calculate timings. Do NOT tack on a 'UL' at the end, this will be done # calculate timings. Do NOT tack on a 'UL' at the end, this will be done
# automatically to create a 32-bit value in your source code. # automatically to create a 32-bit value in your source code.
# # USB AVR possible values are:
# This will be an integer division of F_USB below, as it is sourced by # F_CPU = 8000000
# F_USB after it has run through any CPU prescalers. Note that this value # F_CPU = 16000000
# does not *change* the processor frequency - it should merely be updated to F_CPU = 16000000
# reflect the processor speed set externally so that the code can use accurate
# software delays.
F_CPU = 8000000
# Input clock frequency. # Input clock frequency.
@@ -101,6 +136,13 @@ F_CPU = 8000000
F_USB = $(F_CPU) F_USB = $(F_CPU)
# When using the LUFA CDC AVR109-compatible bootloader, you need to set this
# to the port under which your device enumerated. Under Windows it will be
# something like COM5 (Start->Control Panel->System->Hardware->Device Manager->Ports (COM and LPT))
# Under Linux it will be something like /dev/ttyACM0 which you can find with dmesg
CDC_BOOTLOADER_PORT = COM5
# Output format. (can be srec, ihex, binary) # Output format. (can be srec, ihex, binary)
FORMAT = ihex FORMAT = ihex
@@ -116,15 +158,24 @@ OBJDIR = .
# Path to the LUFA library # Path to the LUFA library
LUFA_PATH = ../../../.. LUFA_PATH = ../../libs/LUFA
AVRLIB_PATH = ../../libs/avrlib
ARDUINO_PATH = ../../libs/Arduino1
# LUFA library compile-time options and predefined tokens # LUFA library compile-time options and predefined tokens
LUFA_OPTS = -D USB_DEVICE_ONLY LUFA_OPTS = -D USB_DEVICE_ONLY
LUFA_OPTS += -D DEVICE_STATE_AS_GPIOR=0
LUFA_OPTS += -D ORDERED_EP_CONFIG
LUFA_OPTS += -D FIXED_CONTROL_ENDPOINT_SIZE=8 LUFA_OPTS += -D FIXED_CONTROL_ENDPOINT_SIZE=8
LUFA_OPTS += -D FIXED_NUM_CONFIGURATIONS=1 LUFA_OPTS += -D FIXED_NUM_CONFIGURATIONS=1
LUFA_OPTS += -D USE_FLASH_DESCRIPTORS LUFA_OPTS += -D USE_FLASH_DESCRIPTORS
LUFA_OPTS += -D USE_STATIC_OPTIONS="(USB_DEVICE_OPT_FULLSPEED | USB_OPT_REG_ENABLED | USB_OPT_AUTO_PLL)" LUFA_OPTS += -D USE_STATIC_OPTIONS="(USB_DEVICE_OPT_FULLSPEED | USB_OPT_REG_ENABLED | USB_OPT_AUTO_PLL)"
LUFA_OPTS += -D INTERRUPT_CONTROL_ENDPOINT
# All Micropendous boards except Rev.2 require manual VBUS management to select USB connector appropriately or have control of PE7
ifneq ($(BOARD),MICROPENDOUS_REV2)
LUFA_OPTS += -D NO_AUTO_VBUS_MANAGEMENT
endif
# Create the LUFA source path variables by including the LUFA root makefile # Create the LUFA source path variables by including the LUFA root makefile
@@ -152,6 +203,28 @@ CPPSRC =
ASRC = ASRC =
#---------------- External Memory Options ----------------
EXTMEMOPTS =
# for the AT90USB1287 with its 8KB of SRAM, external addresses start at 0x20FF
# 0xFFFF(65535) - 0x2100(8448) = 0xDEFF(57087) --> 58KB of available external SRAM
# SAFEST OPTION:
#EXTMEMOPTS +=-Wl,--defsym=__stack=0x802000,--section-start,.data=0x802100,--defsym=__heap_start=0x80DFFF,--defsym=__heap_end=0x80FFFF
ifeq ($(ENABLE_EXTERNAL_SRAM), YES)
# The following will leave the stack in internal memory, place .data+.bss in external memory, and
# leave the final (0x80FFFF-0x80DFFF)=0x2000= 8192 bytes for the heap (which malloc() will use)
# Alter __heap_start to leave more space for the heap
EXTMEMOPTS +=-Wl,--defsym=__stack=0x8020FC,--section-start,.data=0x802100,--defsym=__heap_start=0x80DFFF,--defsym=__heap_end=0x80FFFF
# the following would place .data+.bss and the stack in internal SRAM and only the heap in external SRAM using an AT90USB1287:
#EXTMEMOPTS +=-Wl,--defsym=__stack=0x8020FC,--section-start,.data=0x800100,--defsym=__heap_start=0x802100,--defsym=__heap_end=0x80FFFF
# the following would place .data+.bss such that it overlaps internal and external SRAM with the first 1024 bytes in internal SRAM:
#EXTMEMOPTS +=-Wl,--defsym=__stack=0x801C00,--section-start,.data=0x801D00,--defsym=__heap_start=0x80DFFF,--defsym=__heap_end=0x80FFFF
endif
# Optimization level, can be [0, 1, 2, 3, s]. # Optimization level, can be [0, 1, 2, 3, s].
# 0 = turn off optimization. s = optimize for size. # 0 = turn off optimization. s = optimize for size.
# (Note: 3 is not always the best optimization level. See avr-libc FAQ.) # (Note: 3 is not always the best optimization level. See avr-libc FAQ.)
@@ -169,7 +242,7 @@ DEBUG = dwarf-2
# Each directory must be seperated by a space. # Each directory must be seperated by a space.
# Use forward slashes for directory separators. # Use forward slashes for directory separators.
# For a directory that has spaces, enclose it in quotes. # For a directory that has spaces, enclose it in quotes.
EXTRAINCDIRS = $(LUFA_PATH)/ EXTRAINCDIRS = $(LUFA_PATH)/ $(AVRLIB_PATH)/ $(ARDUINO_PATH)/
# Compiler flag to set the C Standard level. # Compiler flag to set the C Standard level.
@@ -307,20 +380,6 @@ EXTRALIBDIRS =
#---------------- External Memory Options ----------------
# 64 KB of external RAM, starting after internal RAM (ATmega128!),
# used for variables (.data/.bss) and heap (malloc()).
#EXTMEMOPTS = -Wl,-Tdata=0x801100,--defsym=__heap_end=0x80ffff
# 64 KB of external RAM, starting after internal RAM (ATmega128!),
# only used for heap (malloc()).
#EXTMEMOPTS = -Wl,--section-start,.data=0x801100,--defsym=__heap_end=0x80ffff
EXTMEMOPTS =
#---------------- Linker Options ---------------- #---------------- Linker Options ----------------
# -Wl,...: tell GCC to pass this to linker. # -Wl,...: tell GCC to pass this to linker.
# -Map: create map file # -Map: create map file
@@ -341,7 +400,7 @@ LDFLAGS += $(PRINTF_LIB) $(SCANF_LIB) $(MATH_LIB)
# Type: avrdude -c ? # Type: avrdude -c ?
# to get a full listing. # to get a full listing.
# #
AVRDUDE_PROGRAMMER = jtagmkII AVRDUDE_PROGRAMMER = avrispmkII
# com1 = serial port. Use lpt1 to connect to parallel port. # com1 = serial port. Use lpt1 to connect to parallel port.
AVRDUDE_PORT = usb AVRDUDE_PORT = usb
@@ -362,7 +421,7 @@ AVRDUDE_WRITE_FLASH = -U flash:w:$(TARGET).hex
# Increase verbosity level. Please use this when submitting bug # Increase verbosity level. Please use this when submitting bug
# reports about avrdude. See <http://savannah.nongnu.org/projects/avrdude> # reports about avrdude. See <http://savannah.nongnu.org/projects/avrdude>
# to submit bug reports. # to submit bug reports.
#AVRDUDE_VERBOSE = -v -v AVRDUDE_VERBOSE = -v -v
AVRDUDE_FLAGS = -p $(MCU) -P $(AVRDUDE_PORT) -c $(AVRDUDE_PROGRAMMER) AVRDUDE_FLAGS = -p $(MCU) -P $(AVRDUDE_PORT) -c $(AVRDUDE_PROGRAMMER)
AVRDUDE_FLAGS += $(AVRDUDE_NO_VERIFY) AVRDUDE_FLAGS += $(AVRDUDE_NO_VERIFY)
@@ -518,6 +577,9 @@ gccversion :
program: $(TARGET).hex $(TARGET).eep program: $(TARGET).hex $(TARGET).eep
$(AVRDUDE) $(AVRDUDE_FLAGS) $(AVRDUDE_WRITE_FLASH) $(AVRDUDE_WRITE_EEPROM) $(AVRDUDE) $(AVRDUDE_FLAGS) $(AVRDUDE_WRITE_FLASH) $(AVRDUDE_WRITE_EEPROM)
cdc: $(TARGET).hex
$(AVRDUDE) $(AVRDUDE_VERBOSE) -c avr109 -P $(CDC_BOOTLOADER_PORT) -p $(MCU) $(AVRDUDE_WRITE_FLASH) $(AVRDUDE_WRITE_EEPROM)
flip: $(TARGET).hex flip: $(TARGET).hex
batchisp -hardware usb -device $(MCU) -operation erase f batchisp -hardware usb -device $(MCU) -operation erase f
batchisp -hardware usb -device $(MCU) -operation loadbuffer $(TARGET).hex program batchisp -hardware usb -device $(MCU) -operation loadbuffer $(TARGET).hex program

View File

@@ -0,0 +1,41 @@
# Purpose: Write then read characters from a serial port loopback device
# Visit www.Micropendous.org/Serial for more info.
# Created: 2009-09-31 by Opendous Inc.
# Last Edit: 2009-10-02 by Opendous Inc.
# Released to the Public Domain
import serial # PySerial for accessing the serial port on multiple platforms
import sys # command-line argument handling
# function which sends then reads data from the given serial port
# comport should be a string
def SerialSendReceive(comport):
# open the given serial port for communication
ser = serial.Serial(comport)
ser.setTimeout(2000)
ser.setWriteTimeout(2000)
print ser # dump all info regarding serial port being used
ser.write('www.Micropendous.org') # send these characters to the serial port
print ser.read(20) # read the above characters back, assuming loopback
ser.write('www.Micropendous.org\n') # send this line to the serial port
print ser.readline() # read the returned line
# be careful using readline() as it will block until a newline character is received
ser.close() # release/close the serial port
# if this file is the program actually being run, print usage info or run SerialSendReceive
if __name__ == '__main__':
if (len(sys.argv) != 2):
print "Serial Communication Example"
print " Usage:"
print " python", sys.argv[0], "<port>"
print " Where <port> = serial port; COM? on Windows, '/dev/ttyACM0 on Linux'"
print " Enumerated serial port can be found on Linux using dmesg"
print " look for something like cdc_acm 2-1:1.0: ttyACM0: USB ACM device"
print " python", sys.argv[0], "COM5"
exit()
SerialSendReceive(sys.argv[1])