update to RevG

This commit is contained in:
Georg
2016-10-07 23:44:50 +02:00
parent 31c43c5bfa
commit f46f5b4fbf
779 changed files with 162361 additions and 0 deletions
+242
View File
@@ -0,0 +1,242 @@
#!/usr/bin/python
import serial
import serial.tools.list_ports
import sys
import datetime
import time
import Chameleon
class Device:
COMMAND_VERSION = "VERSION"
COMMAND_UPLOAD = "UPLOAD"
COMMAND_DOWNLOAD = "DOWNLOAD"
COMMAND_SETTING = "SETTING"
COMMAND_UID = "UID"
COMMAND_CONFIG = "CONFIG"
COMMAND_LOG_DOWNLOAD = "LOGDOWNLOAD"
COMMAND_LOG_CLEAR = "LOGCLEAR"
COMMAND_LOGMODE = "LOGMODE"
COMMAND_LBUTTON = "LBUTTON"
COMMAND_RBUTTON = "RBUTTON"
COMMAND_GREEN_LED = "LEDGREEN"
COMMAND_RED_LED = "LEDRED"
STATUS_CODE_OK = 100
STATUS_CODE_OK_WITH_TEXT = 101
STATUS_CODE_WAITING_FOR_XMODEM = 110
STATUS_CODE_FALSE = 120
STATUS_CODE_TRUE = 121
STATUS_CODE_UNKNOWN_COMMAND = 200
STATUS_CODE_UNKNOWN_COMMAND_USAGE = 201
STATUS_CODE_INVALID_PARAMETER = 202
STATUS_CODES_SUCCESS = [
STATUS_CODE_OK,
STATUS_CODE_OK_WITH_TEXT,
STATUS_CODE_WAITING_FOR_XMODEM,
STATUS_CODE_FALSE,
STATUS_CODE_TRUE
]
STATUS_CODES_FAILURE = [
STATUS_CODE_UNKNOWN_COMMAND,
STATUS_CODE_UNKNOWN_COMMAND_USAGE,
STATUS_CODE_INVALID_PARAMETER
]
LINE_ENDING = "\r"
SUGGEST_CHAR = "?"
SET_CHAR = "="
GET_CHAR = "?"
def __init__(self, verboseFunc = None):
self.verboseFunc = verboseFunc
self.serial = serial.Serial(None, 9600, timeout=5.0)
self.versionString = ""
self.supportedConfs = []
def verboseLog(self, text):
if (self.verboseFunc):
self.verboseFunc(text)
def listDevices():
devices = []
for port in serial.tools.list_ports.grep("({0:04x}:{1:04x})|({0:04X}:{1:04X})".format(Chameleon.USB_VID, Chameleon.USB_PID)):
devices.append(port[0])
return devices
def connect(self, comport):
self.serial.port = comport
try:
self.serial.open()
except:
pass
if (self.serial.isOpen()):
# Send escape key to force clearing the Chameleon's input buffer
self.serial.write(b"\x1B")
self.verboseLog("Opening serial port {} succeeded".format(comport))
else:
self.verboseLog("Opening serial port {} failed".format(comport))
return False
# Try to retrieve chameleons version information and supported confs
result = self.getSetCmd(self.COMMAND_VERSION)
if (result is not None):
if (result['statusCode'] == self.STATUS_CODE_OK_WITH_TEXT):
self.versionString = result['response']
else:
return False
result = self.getCmdSuggestions(self.COMMAND_CONFIG)
if (result['statusCode'] == self.STATUS_CODE_OK_WITH_TEXT):
self.supportedConfs = result['response'].split(",")
else:
return False
else:
return False
return True
def disconnect(self):
self.verboseLog("Closing serial port")
self.serial.close()
def isConnected(self):
return self.serial.isOpen()
def read(self, size=1024, timeout=0.01):
self.serial.timeout = timeout
data = self.serial.read(size)
self.serial.timeout = 5.0
return data
def writeCmd(self, cmd):
# Execute command
cmdLine = cmd + self.LINE_ENDING
self.serial.write(cmdLine.encode('ascii'))
# Get status response
status = self.serial.readline().decode('ascii').rstrip()
if (len(status) == 0):
self.verboseLog("Executing <{}>: Timeout".format(cmd))
return None
else:
self.verboseLog("Executing <{}>: {}".format(cmd, status))
statusCode, statusText = status.split(":")
statusCode = int(statusCode)
result = {'statusCode': statusCode, 'statusText': statusText, 'response': None}
if (statusCode == self.STATUS_CODE_OK_WITH_TEXT):
result['response'] = self.readResponse()
elif (statusCode == self.STATUS_CODE_TRUE):
result['response'] = True
elif (statusCode == self.STATUS_CODE_FALSE):
result['response'] = False
return result
def readResponse(self):
# Read response to command, if any
response = self.serial.readline().decode('ascii').rstrip()
self.verboseLog("Response: {}".format(response))
return response
def execCmd(self, cmd, args=None):
if (args is None):
return self.writeCmd("{}".format(cmd))
else:
return self.writeCmd("{} {}".format(cmd, args))
def getSetCmd(self, cmd, arg=None):
# Determine if set or get mode
if (arg is None):
return self.writeCmd("{}{}".format(cmd, self.GET_CHAR))
else:
return self.writeCmd("{}{}{}".format(cmd, self.SET_CHAR, arg))
def getCmdSuggestions(self, cmd):
result = self.getSetCmd(cmd, self.SUGGEST_CHAR)
if (result['response'] is not None):
result['suggestions'] = result['response'].split(",")
return result
def cmdUploadDump(self, dataStream):
if (self.execCmd(self.COMMAND_UPLOAD)['statusCode'] == self.STATUS_CODE_WAITING_FOR_XMODEM):
# XMODEM started
xmodem = Chameleon.XModem(self.serial, self.verboseFunc)
bytesSent = xmodem.sendData(dataStream)
return bytesSent
else:
return None
def cmdDownloadDump(self, dataStream):
if (self.execCmd(self.COMMAND_DOWNLOAD)['statusCode'] == self.STATUS_CODE_WAITING_FOR_XMODEM):
# XMODEM started
xmodem = Chameleon.XModem(self.serial, self.verboseFunc)
return xmodem.recvData(dataStream)
else:
return None
def cmdDownloadLog(self, dataStream):
if (self.execCmd(self.COMMAND_LOG_DOWNLOAD)['statusCode'] == self.STATUS_CODE_WAITING_FOR_XMODEM):
# XMODEM started
xmodem = Chameleon.XModem(self.serial, self.verboseFunc)
return xmodem.recvData(dataStream)
else:
return None
def cmdClearLog(self):
return self.execCmd(self.COMMAND_LOG_CLEAR)
def cmdLogMode(self, newLogMode):
return self.getSetCmd(self.COMMAND_LOGMODE, newLogMode)
def cmdVersion(self):
return self.getSetCmd(self.COMMAND_VERSION)
def cmdSetting(self, newSetting = None):
return self.getSetCmd(self.COMMAND_SETTING, newSetting)
def cmdUID(self, newUID = None):
return self.getSetCmd(self.COMMAND_UID, newUID)
def cmdConfig(self, newConfig = None):
if (newConfig == self.SUGGEST_CHAR):
return self.getCmdSuggestions(self.COMMAND_CONFIG)
else:
return self.getSetCmd(self.COMMAND_CONFIG, newConfig)
def cmdLButton(self, newAction = None):
if (newAction == self.SUGGEST_CHAR):
return self.getCmdSuggestions(self.COMMAND_LBUTTON)
else:
return self.getSetCmd(self.COMMAND_LBUTTON, newAction)
def cmdRButton(self, newAction = None):
if (newAction == self.SUGGEST_CHAR):
return self.getCmdSuggestions(self.COMMAND_RBUTTON)
else:
return self.getSetCmd(self.COMMAND_RBUTTON, newAction)
def cmdGreenLED(self, newFunction = None):
if (newFunction == self.SUGGEST_CHAR):
return self.getCmdSuggestions(self.COMMAND_GREEN_LED)
else:
return self.getSetCmd(self.COMMAND_GREEN_LED, newFunction)
def cmdRedLED(self, newFunction = None):
if (newFunction == self.SUGGEST_CHAR):
return self.getCmdSuggestions(self.COMMAND_RED_LED)
else:
return self.getSetCmd(self.COMMAND_RED_LED, newFunction)
+100
View File
@@ -0,0 +1,100 @@
#!/usr/bin/python
import struct
import binascii
def noDecoder(data):
return ""
def textDecoder(data):
return data.decode('ascii')
def binaryDecoder(data):
return binascii.hexlify(data).decode()
eventTypes = {
0x00: { 'name': 'EMPTY', 'decoder': noDecoder },
0x10: { 'name': 'GENERIC', 'decoder': textDecoder },
0x11: { 'name': 'CONFIG SET', 'decoder': textDecoder },
0x12: { 'name': 'SETTING SET', 'decoder': textDecoder },
0x13: { 'name': 'UID SET', 'decoder': textDecoder },
0x20: { 'name': 'RESET APP', 'decoder': noDecoder },
0x40: { 'name': 'CODEC RX', 'decoder': binaryDecoder },
0x41: { 'name': 'CODEC TX', 'decoder': binaryDecoder },
0x80: { 'name': 'APP READ', 'decoder': binaryDecoder },
0x81: { 'name': 'APP WRITE', 'decoder': binaryDecoder },
0x84: { 'name': 'APP INC', 'decoder': binaryDecoder },
0x85: { 'name': 'APP DEC', 'decoder': binaryDecoder },
0x86: { 'name': 'APP TRANSFER', 'decoder': binaryDecoder },
0x87: { 'name': 'APP RESTORE', 'decoder': binaryDecoder },
0x90: { 'name': 'APP AUTH', 'decoder': binaryDecoder },
0x91: { 'name': 'APP HALT', 'decoder': binaryDecoder },
0x92: { 'name': 'APP UNKNOWN', 'decoder': binaryDecoder },
0xA0: { 'name': 'APP AUTHING', 'decoder': binaryDecoder },
0xA1: { 'name': 'APP AUTHED', 'decoder': binaryDecoder },
0xC0: { 'name': 'APP AUTH FAILED', 'decoder': binaryDecoder },
0xC1: { 'name': 'APP CSUM FAILED', 'decoder': binaryDecoder },
0xC2: { 'name': 'APP NOT AUTHED', 'decoder': binaryDecoder },
}
TIMESTAMP_MAX = 65536
def parseBinary(binaryStream):
log = []
# Completely read file contents and process them byte by byte
# logFile = fileHandle.read()
# fileIdx = 0
lastTimestamp = 0
while True:
# Read log entry header from file
header = binaryStream.read(struct.calcsize('<BBH'))
if (header is None):
# No more data available
break
if (len(header) < struct.calcsize('<BBH')):
# No more data available
break
(event, dataLength, timestamp) = struct.unpack_from('>BBH', header)
# Break if there are no more events
if (eventTypes[event]['name'] == 'EMPTY'):
break
# Read data from file
logData = binaryStream.read(dataLength)
# Decode data
logData = eventTypes[event]['decoder'](logData)
# Calculate delta timestamp respecting 16 bit overflow
deltaTimestamp = timestamp - lastTimestamp;
lastTimestamp = timestamp
if (deltaTimestamp < 0):
deltaTimestamp += TIMESTAMP_MAX;
# Create log entry as dict and append it to event list
logEntry = {
'eventName': eventTypes[event]['name'],
'dataLength': dataLength,
'timestamp': timestamp,
'deltaTimestamp': deltaTimestamp,
'data': logData
}
log.append(logEntry)
return log
+108
View File
@@ -0,0 +1,108 @@
#!/usr/bin/python
#
# Very lightweight implementation of XModem for Chameleon purposes
# Because the Chameleon uses a CDC over USB, we don't expect any
# retransmissions at all and thus don't implement it
import io
import time
class XModem:
BYTE_SOH = b'\x01'
BYTE_NAK = b'\x15'
BYTE_ACK = b'\x06'
BYTE_EOT = b'\x04'
def __init__(self, ioStream, verboseFunc = None):
self.ioStream = ioStream
self.verboseFunc = verboseFunc
def verboseLog(self, text):
if (self.verboseFunc):
self.verboseFunc(text)
def recvData(self, dataStream):
packetCounter = 1
bytesReceived = 0
startTime = time.time()
self.verboseLog("Starting XMODEM Reception")
# Start transmission by issuing a NAK
self.ioStream.write(self.BYTE_NAK)
while True:
pktId = self.ioStream.read(1)
if (pktId == self.BYTE_SOH):
currentPacket = self.ioStream.read(2)
if (currentPacket[0] == (255 - currentPacket[1])):
#frame number intact
if (currentPacket[0] == packetCounter):
#In order packet
dataBlock = self.ioStream.read(128)
checksum = self.ioStream.read(1)
if (int(checksum[0]) == (sum(dataBlock) % 256)):
# checksum correct
dataStream.write(dataBlock)
dataStream.flush()
packetCounter = (packetCounter + 1) % 256
bytesReceived += 128
self.ioStream.write(self.BYTE_ACK)
else:
self.ioStream.write(self.BYTE_NAK)
elif (pktId == self.BYTE_EOT):
# Transmission done
self.ioStream.write(self.BYTE_ACK)
break
else:
# Unknown pktId
break
deltaTime = time.time() - startTime
self.verboseLog("{} Bytes received in {:.2f} sec. ({:.0f} B/s)".format(bytesReceived, deltaTime, bytesReceived/deltaTime))
return bytesReceived
def sendData(self, dataStream):
packetCounter = 1
bytesSent = 0
startTime = time.time()
self.verboseLog("Waiting for XMODEM Connection")
# Wait for NAK from receiver to start transmission
if (self.ioStream.read(1) != self.BYTE_NAK):
# Timeout or different char received
return None
while True:
dataBlock = dataStream.read(128)
if (len(dataBlock) == 128):
# Write SOH, pktId, data and checksum
self.ioStream.write(self.BYTE_SOH)
self.ioStream.write(bytes([packetCounter]))
self.ioStream.write(bytes([255 - packetCounter]))
self.ioStream.write(dataBlock)
self.ioStream.write(bytes([sum(dataBlock) % 256]))
if (self.ioStream.read(1) == self.BYTE_ACK):
#Proceed to next packet
packetCounter = (packetCounter + 1) % 256
bytesSent += 128
else:
# Write EOT and wait for ACK
self.ioStream.write(self.BYTE_EOT)
self.ioStream.read(1)
break
deltaTime = time.time() - startTime
self.verboseLog("{} Bytes sent in {:.2f} sec. ({:.0f} B/s)".format(bytesSent, deltaTime, bytesSent/deltaTime))
return bytesSent
+15
View File
@@ -0,0 +1,15 @@
# Import modules
import Chameleon.Log
# Import classes
from Chameleon.Device import Device
from Chameleon.XModem import XModem
#import Chameleon.Device
MIN_SETTING = 1
MAX_SETTING = 8
VALID_SETTINGS = range(MIN_SETTING, MAX_SETTING + 1)
USB_VID = 0x16D0
USB_PID = 0x04B2
+27
View File
@@ -0,0 +1,27 @@
Copyright (c) 2014, Chema García
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of pycham nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+3
View File
@@ -0,0 +1,3 @@
ChamTool
========
The ChamTool is based on the pycham tool, see also the LICENSE file.
+102
View File
@@ -0,0 +1,102 @@
#!/usr/bin/python
#
# Command line tool to analyze binary dump files from the Chameleon
# Authors: Simon K. (simon.kueppers@rub.de)
import argparse
import sys
import json
import Chameleon
import io
import datetime
def verboseLog(text):
formatString = "[{}] {}"
timeString = datetime.datetime.utcnow()
print(formatString.format(timeString, text), file=sys.stderr)
def formatText(log):
formatString = '{timestamp:0>5d} ms <{deltaTimestamp:>+6d} ms>:'
formatString += '{eventName:<16} ({dataLength:<3} bytes) [{data}]\n'
text = ''
for logEntry in log:
text += formatString.format(**logEntry)
return text
def formatJSON(log):
text = json.dumps(log, sort_keys=True, indent=4)
return text
def main():
outputTypes = {
'text': formatText,
'json': formatJSON
}
argParser = argparse.ArgumentParser(description="Analyzes binary Chameleon logfiles")
group = argParser.add_mutually_exclusive_group(required=True)
group.add_argument("-f", "--file", dest="logfile", metavar="LOGFILE")
group.add_argument("-p", "--port", dest="port", metavar="COMPORT")
argParser.add_argument("-t", "--type", choices=outputTypes.keys(), default='text',
help="specifies output type")
argParser.add_argument("-l", "--live", dest="live", action='store_true', help="Use live logging capabilities of Chameleon")
argParser.add_argument("-c", "--clear", dest="clear", action='store_true', help="Clear Chameleon's log memory when using -p")
argParser.add_argument("-m", "--mode", dest="mode", metavar="LOGMODE", help="Additionally set Chameleon's log mode after reading it's memory")
argParser.add_argument("-v", "--verbose", dest="verbose", action='store_true', default=0)
args = argParser.parse_args()
if (args.verbose):
verboseFunc = verboseLog
else:
verboseFunc = None
if (args.live):
# Live logging mode
if (args.port is not None):
chameleon = Chameleon.Device(verboseFunc)
if (chameleon.connect(args.port)):
chameleon.cmdLogMode("LIVE")
while True:
stream = io.BytesIO(chameleon.read())
log = Chameleon.Log.parseBinary(stream)
if (len(log) > 0):
print(outputTypes[args.type](log))
else:
if (args.logfile is not None):
handle = open(args.logfile, "rb")
elif (args.port is not None):
chameleon = Chameleon.Device(verboseFunc)
if (chameleon.connect(args.port)):
handle = io.BytesIO()
chameleon.cmdDownloadLog(handle)
handle.seek(0)
if (args.clear):
chameleon.cmdClearLog()
if (args.mode is not None):
chameleon.cmdLogMode(args.mode)
chameleon.disconnect()
else:
sys.exit(2)
# Parse actual logfile
log = Chameleon.Log.parseBinary(handle)
# Print to console using chosen output type
print(outputTypes[args.type](log))
if __name__ == "__main__":
main()
+205
View File
@@ -0,0 +1,205 @@
#!/usr/bin/python
#
# Command line tool to control the Chameleon through command line
# Authors: Simon K. (simon.kueppers@rub.de)
import argparse
import Chameleon
import sys
import datetime
def verboseLog(text):
formatString = "[{}] {}"
timeString = datetime.datetime.utcnow()
print(formatString.format(timeString, text), file=sys.stderr)
# Command funcs
def cmdInfo(chameleon, arg):
return "{}".format(chameleon.cmdVersion()['response'])
def cmdSetting(chameleon, arg):
result = chameleon.cmdSetting(arg)
if (arg is None):
return "Current Setting: {}".format(result['response'])
else:
if (result['statusCode'] in chameleon.STATUS_CODES_SUCCESS):
return "Setting has been changed to {}".format(chameleon.cmdSetting()['response'])
else:
return "Change setting to {} failed: {}".format(arg, result['statusText'])
return
def cmdUID(chameleon, arg):
result = chameleon.cmdUID(arg)
if (arg is None):
return "{}".format(result['response'])
else:
if (result['statusCode'] in chameleon.STATUS_CODES_SUCCESS):
return "UID has been changed to {}".format(chameleon.cmdUID()['response'])
else:
return "Setting UID to {} failed: {}".format(arg, result['statusText'])
def cmdConfig(chameleon, arg):
result = chameleon.cmdConfig(arg)
if (arg is None):
return "Current configuration: {}".format(result['response'])
else:
if (arg == chameleon.SUGGEST_CHAR):
return "Possible configurations: {}".format(", ".join(result['suggestions']))
elif (result['statusCode'] in chameleon.STATUS_CODES_SUCCESS):
return "Configuration has been changed to {}".format(chameleon.cmdConfig()['response'])
else:
return "Changing configuration to {} failed: {}".format(arg, result['statusText'])
def cmdUpload(chameleon, arg):
with open(arg, 'rb') as fileHandle:
bytesSent = chameleon.cmdUploadDump(fileHandle)
return "{} Bytes successfully read from {}".format(bytesSent, arg)
def cmdDownload(chameleon, arg):
with open(arg, 'wb') as fileHandle:
bytesReceived = chameleon.cmdDownloadDump(fileHandle)
return "{} Bytes successfully written to {}".format(bytesReceived, arg)
def cmdLog(chameleon, arg):
with open(arg, 'wb') as fileHandle:
bytesReceived = chameleon.cmdDownloadLog(fileHandle)
return "{} Bytes successfully written to {}".format(bytesReceived, arg)
def cmdLButton(chameleon, arg):
result = chameleon.cmdLButton(arg)
if (arg is None):
return "Current left button action: {}".format(result['response'])
else:
if (arg == chameleon.SUGGEST_CHAR):
return "Possible left button actions: {}".format(", ".join(result['suggestions']))
elif (result['statusCode'] in chameleon.STATUS_CODES_SUCCESS):
return "Left button action has been set to {}".format(chameleon.cmdLButton()['response'])
else:
return "Setting left button action to {} failed: {}".format(arg, result['statusText'])
def cmdRButton(chameleon, arg):
result = chameleon.cmdRButton(arg)
if (arg is None):
return "Current right button action: {}".format(result['response'])
else:
if (arg == chameleon.SUGGEST_CHAR):
return "Possible right button actions: {}".format(", ".join(result['suggestions']))
elif (result['statusCode'] in chameleon.STATUS_CODES_SUCCESS):
return "Right button action has been set to {}".format(chameleon.cmdRButton()['response'])
else:
return "Setting right button action to {} failed: {}".format(arg, result['statusText'])
def cmdGreenLED(chameleon, arg):
result = chameleon.cmdGreenLED(arg)
if (arg is None):
return "Current green LED function: {}".format(result['response'])
else:
if (arg == chameleon.SUGGEST_CHAR):
return "Possible green LED functions: {}".format(", ".join(result['suggestions']))
elif (result['statusCode'] in chameleon.STATUS_CODES_SUCCESS):
return "Green LED function has been set to {}".format(chameleon.cmdGreenLED()['response'])
else:
return "Setting green LED function to {} failed: {}".format(arg, result['statusText'])
def cmdRedLED(chameleon, arg):
result = chameleon.cmdRedLED(arg)
if (arg is None):
return "Current red LED function: {}".format(result['response'])
else:
if (arg == chameleon.SUGGEST_CHAR):
return "Possible red LED functions: {}".format(", ".join(result['suggestions']))
elif (result['statusCode'] in chameleon.STATUS_CODES_SUCCESS):
return "Red LED function has been set to {}".format(chameleon.cmdRedLED()['response'])
else:
return "Setting red LED function to {} failed: {}".format(arg, result['statusText'])
# Custom class for argparse
class CmdListAction(argparse.Action):
def __init__(self, option_strings, dest, default=False, required=False,
help=None, metavar=None, nargs=None, type=None, choices=None, const=None):
super(CmdListAction, self).__init__(
option_strings=option_strings, dest=dest, nargs=nargs, const=const, default=default,
required=required, help=help, metavar=metavar, type=type, choices=choices)
def __call__(self, parser, namespace, values, option_string=None):
# Create new attribute cmdList if not exist and append command to list
if not hasattr(namespace, "cmdList"):
setattr(namespace, "cmdList", [])
namespace.cmdList.append([self.dest, values])
def main():
argParser = argparse.ArgumentParser(description="Controls the Chameleon through the command line")
argParser.add_argument("-v", "--verbose", dest="verbose", action="store_true", default=0, help="output verbose")
argParser.add_argument("-p", "--port", dest="port", metavar="COMPORT", help="specify device's comport")
# Add the commands using custom action that populates a list in the order the arguments are given
cmdArgGroup = argParser.add_argument_group(title="Chameleon commands", description="These arguments can appear multiple times and are executed in the order they are given on the command line. "
"Some of these arguments can be used with '" + Chameleon.Device.SUGGEST_CHAR + "' as parameter to get a list of suggestions.")
cmdArgGroup.add_argument("-u", "--upload", dest="upload", action=CmdListAction, metavar="DUMPFILE", help="upload a card dump")
cmdArgGroup.add_argument("-d", "--download", dest="download", action=CmdListAction, metavar="DUMPFILE", help="download a card dump")
cmdArgGroup.add_argument("-l", "--log", dest="log", action=CmdListAction, metavar="LOGFILE", help="download the device log")
cmdArgGroup.add_argument("-i", "--info", dest="info", action=CmdListAction, nargs=0, help="retrieve the version information")
cmdArgGroup.add_argument("-s", "--setting", dest="setting", action=CmdListAction, nargs='?', type=int, choices=Chameleon.VALID_SETTINGS, help="retrieve or set the current setting")
cmdArgGroup.add_argument("-U", "--uid", dest="uid", action=CmdListAction, nargs='?', help="retrieve or set the current UID")
cmdArgGroup.add_argument("-c", "--config", dest="config", action=CmdListAction, metavar="CFGNAME", nargs='?', help="retrieve or set the current configuration")
cmdArgGroup.add_argument("-lb", "--lbutton", dest="lbutton", action=CmdListAction, metavar="ACTION", nargs='?', help="retrieve or set the current left button action")
cmdArgGroup.add_argument("-rb", "--rbutton", dest="rbutton", action=CmdListAction, metavar="ACTION", nargs='?', help="retrieve or set the current right button action")
cmdArgGroup.add_argument("-gl", "--gled", dest="gled", action=CmdListAction, metavar="FUNCTION", nargs='?', help="retrieve or set the current green led function")
cmdArgGroup.add_argument("-rl", "--rled", dest="rled", action=CmdListAction, metavar="FUNCTION", nargs='?', help="retrieve or set the current red led function")
args = argParser.parse_args()
if (args.verbose):
verboseFunc = verboseLog
else:
verboseFunc = None
# Instantiate device object and connect
chameleon = Chameleon.Device(verboseFunc)
if (args.port):
if (chameleon.connect(args.port)):
# Generate a jumptable and execute all commands in the order they are given on the command line
cmdFuncs = {
"setting" : cmdSetting,
"info" : cmdInfo,
"uid" : cmdUID,
"config" : cmdConfig,
"upload" : cmdUpload,
"download" : cmdDownload,
"log" : cmdLog,
"lbutton" : cmdLButton,
"rbutton" : cmdRButton,
"gled" : cmdGreenLED,
"rled" : cmdRedLED,
}
if hasattr(args, "cmdList"):
for (cmd, arg) in args.cmdList:
result = cmdFuncs[cmd](chameleon, arg)
print("[{}] {}".format(cmd, result))
# Goodbye
chameleon.disconnect()
else:
print("Unable to establish communication on {}".format(args.port))
sys.exit(2)
else:
#List possible Chameleon ports
print("Use -p COMPORT to specify the communication port (see help).")
print("List of potential Chameleons connected to the system:")
for port in Chameleon.Device.listDevices():
print(port)
sys.exit(0)
if __name__ == "__main__":
main()