# ebb_serial.py
# Serial connection utilities for EiBotBoard
# https://github.com/evil-mad/plotink
#
# Intended to provide some common interfaces that can be used by
# EggBot, WaterColorBot, AxiDraw, and similar machines.
#
# Version 0.3, Dated June 28, 2016.
#
# Thanks to Shel Michaels for bug fixes and helpful suggestions.
#
# The MIT License (MIT)
#
# Copyright (c) 2016 Evil Mad Scientist Laboratories
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
import serial
import inkex
import gettext
def version():
return "0.3" # Version number for this document
def findPort():
#Find a single EiBotBoard connected to a USB port.
try:
from serial.tools.list_ports import comports
except ImportError:
comports = None
return None
if comports:
comPortsList = list(comports())
EBBport = None
for port in comPortsList:
if port[1].startswith("USB-SERIAL CH340"):
EBBport = port[0] #Success; EBB found by name match.
break #stop searching-- we are done.
if EBBport is None:
for port in comPortsList:
if port[2].startswith("USB VID:PID=04D8:FD92"):
EBBport = port[0] #Success; EBB found by VID/PID match.
break #stop searching-- we are done.
return EBBport
def testPort( comPort ):
'''
Return a SerialPort object
for the first port with an EBB (EiBotBoard; EggBot controller board).
YOU are responsible for closing this serial port!
'''
if comPort is not None:
try:
serialPort = serial.Serial( comPort, timeout=3.0 ) # 1 second timeout!
serialPort.write( 'v\r' )
strVersion = serialPort.readline()
if strVersion and strVersion.startswith( 'EBB' ):
return serialPort
serialPort.write( 'v\r' )
strVersion = serialPort.readline()
if strVersion and strVersion.startswith( 'EBB' ):
return serialPort
serialPort.close()
except serial.SerialException:
pass
return None
else:
return None
def openPort():
foundPort = findPort()
serialPort = testPort( foundPort )
if serialPort:
return serialPort
return None
def closePort(comPort):
if comPort is not None:
try:
comPort.close()
except serial.SerialException:
pass
def query( comPort, cmd ):
if (comPort is not None) and (cmd is not None):
response = ''
try:
comPort.write( cmd )
response = comPort.readline()
nRetryCount = 0
while ( len(response) == 0 ) and ( nRetryCount < 100 ):
# get new response to replace null response if necessary
response = comPort.readline()
nRetryCount += 1
if cmd.strip().lower() not in ["v","i","a", "mr","pi","qm"]:
#Most queries return an "OK" after the data requested.
#We skip this for those few queries that do not return an extra line.
unused_response = comPort.readline() #read in extra blank/OK line
nRetryCount = 0
while ( len(unused_response) == 0 ) and ( nRetryCount < 100 ):
# get new response to replace null response if necessary
unused_response = comPort.readline()
nRetryCount += 1
except:
inkex.errormsg( gettext.gettext( "Error reading serial data." ) )
return response
else:
return None
def command( comPort, cmd ):
if (comPort is not None) and (cmd is not None):
try:
comPort.write( cmd )
response = comPort.readline()
nRetryCount = 0
while ( len(response) == 0 ) and ( nRetryCount < 100 ):
# get new response to replace null response if necessary
response = comPort.readline()
nRetryCount += 1
inkex.errormsg("Retry" + str(nRetryCount))
if response.strip().startswith("OK"):
pass # inkex.errormsg( 'OK after command: ' + cmd ) #Debug option: indicate which command.
else:
if ( response != '' ):
inkex.errormsg( 'Error: Unexpected response from EBB.')
inkex.errormsg( ' Command: ' + cmd.strip() )
inkex.errormsg( ' Response: ' + str( response.strip() ) )
else:
inkex.errormsg( 'EBB Serial Timeout after command: ' + cmd )
# except Exception,e:
# inkex.errormsg( str(e)) #For debugging: one may wish to display the error.
except:
inkex.errormsg( 'Failed after command: ' + cmd )
pass