#!/usr/bin/env python # # Razer device commandline configuration tool # # Copyright (C) 2007-2011 Michael Buesch # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. import sys import os import getopt import time from ConfigParser import * from pyrazer import * razer = None def getRazer(): global razer if razer is None: razer = Razer() return razer class Operation: def parseProfileValueStr(self, parameter, idstr, nrValues=1): # Parse profile:value[:value]... string. Default to active # profile, if not given. May raise ValueError. split = parameter.split(":") if len(split) == nrValues: profile = None values = split elif len(split) == nrValues + 1: profile = int(split[0].strip()) values = split[1:] if profile == 0: profile = getRazer().getActiveProfile(idstr) + 1 if profile < 0: raise ValueError else: raise ValueError return (profile, values) class OpSleep(Operation): def __init__(self, seconds): self.seconds = seconds def run(self, idstr): time.sleep(self.seconds) class OpScan(Operation): def run(self, idstr): scanDevices() class OpReconfigure(Operation): def run(self, idstr): reconfigureDevices() class OpGetFwVer(Operation): def run(self, idstr): verTuple = getRazer().getFwVer(idstr) print "%s: Firmware version %d.%02d" %\ (idstr, verTuple[0], verTuple[1]) class OpGetProfile(Operation): def run(self, idstr): profileId = getRazer().getActiveProfile(idstr) print("Active profile: %u" % (profileId + 1)) class OpGetFreq(Operation): def run(self, idstr): freqs = getRazer().getSupportedFreqs(idstr) minfo = getRazer().getMouseInfo(idstr) if minfo & Razer.MOUSEINFOFLG_GLOBAL_FREQ: curFreq = getRazer().getCurrentFreq(idstr) self.printFreq(freqs, curFreq) if minfo & Razer.MOUSEINFOFLG_PROFILE_FREQ: profiles = getRazer().getProfiles(idstr) for profile in profiles: sys.stdout.write("Profile %2u: " % (profile + 1)) curFreq = getRazer().getCurrentFreq(idstr, profile) self.printFreq(freqs, curFreq) def printFreq(self, freqs, curFreq): output = [] for freq in freqs: pfx = "*" if freq == curFreq else " " output.append("%s%u Hz" % (pfx, freq)) print ", ".join(output) class OpGetRes(Operation): def run(self, idstr): mappings = getRazer().getSupportedDpiMappings(idstr) profiles = getRazer().getProfiles(idstr) for profile in profiles: sys.stdout.write("Profile %2u: " % (profile + 1)) curMapping = getRazer().getDpiMapping(idstr, profile) output = [] pm = filter(lambda m: m.profileMask == 0 or\ m.profileMask & (1 << profile), mappings) for mapping in pm: pfx = "*" if mapping.id == curMapping else " " r = [ "%u" % r for r in mapping.res if r is not None ] rStr = "/".join(r) output.append("%s%u (%s DPI)" % (pfx, mapping.id + 1, rStr)) print ", ".join(output) class OpPrintLeds(Operation): def run(self, idstr): minfo = getRazer().getMouseInfo(idstr) if minfo & Razer.MOUSEINFOFLG_GLOBAL_LEDS: sys.stdout.write("Global LEDs: ") leds = getRazer().getLeds(idstr) self.printLeds(leds) if minfo & Razer.MOUSEINFOFLG_PROFILE_LEDS: profiles = getRazer().getProfiles(idstr) for profile in profiles: sys.stdout.write("Profile %2u LEDs: " % (profile + 1)) leds = getRazer().getLeds(idstr, profile) self.printLeds(leds) def printLeds(self, leds): output = [] for led in leds: state = "on" if led.state else "off" color = "" if led.color is not None: color = "/color#%02X%02X%02X" %\ (led.color.r, led.color.g, led.color.b) output.append("%s => %s%s" % (led.name, state, color)) print ", ".join(output) class OpSetProfile(Operation): def __init__(self, param): self.param = param def run(self, idstr): try: profileId = int(self.param) - 1 error = getRazer().setActiveProfile(idstr, profileId) if error: raise RazerEx("Failed to set active profile (%s)" %\ Razer.strerror(error)) except (ValueError), e: raise RazerEx("Invalid parameter to --profile option") class OpSetLedState(Operation): def __init__(self, param): self.param = param def run(self, idstr): try: (profile, config) = self.parseProfileValueStr(self.param, idstr, 2) ledName = config[0].strip() newState = razer_str2bool(config[1]) if profile is None: profile = Razer.PROFILE_INVALID else: profile -= 1 leds = getRazer().getLeds(idstr, profile) led = filter(lambda l: l.name == ledName, leds)[0] led.state = newState error = getRazer().setLed(idstr, led) if error: raise RazerEx("Failed to set LED state (%s)" %\ Razer.strerror(error)) except (IndexError, ValueError): raise RazerEx("Invalid parameter to --setled option") class OpSetLedColor(Operation): def __init__(self, param): self.param = param def run(self, idstr): try: (profile, config) = self.parseProfileValueStr(self.param, idstr, 2) ledName = config[0].strip() newColor = RazerRGB.fromString(config[1]) if profile is None: profile = Razer.PROFILE_INVALID else: profile -= 1 leds = getRazer().getLeds(idstr, profile) led = filter(lambda l: l.name == ledName, leds)[0] led.color = newColor error = getRazer().setLed(idstr, led) if error: raise RazerEx("Failed to set LED color (%s)" %\ Razer.strerror(error)) except (IndexError, ValueError): raise RazerEx("Invalid parameter to --setledcolor option") class OpSetRes(Operation): def __init__(self, param): self.param = param def run(self, idstr): try: (profile, mapping) = self.parseProfileValueStr(self.param, idstr) mapping = int(mapping[0]) if profile is None: raise ValueError except ValueError: raise RazerEx("Invalid parameter to --res option") if mapping >= 100: # Mapping is in DPI. Get the mapping ID. mappings = getRazer().getSupportedDpiMappings(idstr) pm = filter(lambda m: m.profileMask == 0 or\ m.profileMask & (1 << profile), mappings) try: mapping = filter(lambda m: mapping in m.res, pm)[0].id except IndexError: raise RazerEx("Invalid resolution %d" % mapping) else: mapping = mapping - 1 error = getRazer().setDpiMapping(idstr, profile - 1, mapping) if error: raise RazerEx("Failed to set resolution to %u (%s)" %\ (mapping, Razer.strerror(error))) class OpSetFreq(Operation): def __init__(self, param): self.param = param def run(self, idstr): try: (profile, freq) = self.parseProfileValueStr(self.param, idstr) freq = int(freq[0]) except ValueError: raise RazerEx("Invalid parameter to --freq option") if profile is None: profile = Razer.PROFILE_INVALID else: profile -= 1 error = getRazer().setFrequency(idstr, profile, freq) if error: raise RazerEx("Failed to set frequency to %d Hz (%s)" %\ (freq, Razer.strerror(error))) class OpFlashFw(Operation): def __init__(self, filename): self.filename = filename def run(self, idstr): p = RazerFirmwareParser(self.filename) data = p.getImage() print "Flashing firmware on %s ..." % idstr print "!!! DO NOT DISCONNECT ANY DEVICE !!!" print "Sending %d bytes..." % len(data) error = getRazer().flashFirmware(idstr, data) if error: raise RazerEx("Failed to flash firmware (%s)" % Razer.strerror(error)) print "Firmware successfully flashed." # List of operations class DevOps: def __init__(self, idstr): self.idstr = idstr self.ops = [] def add(self, op): self.ops.append(op) def runAll(self): for op in self.ops: op.run(self.idstr) def scanDevices(): getRazer().rescanMice() mice = getRazer().getMice() for mouse in mice: print mouse def reconfigureDevices(): getRazer().rescanDevices() getRazer().reconfigureDevices() def exit(exitcode): sys.exit(exitcode) def prVersion(): print "Razer device configuration tool" print "Version", RAZER_VERSION def usage(): prVersion() print "" print "Usage: razercfg [OPTIONS] [-d DEV DEVOPS] [-d DEV DEVOPS]..." print "" print "-h|--help Print this help text" print "-v|--version Print the program version number" print "-B|--background Fork into the background" print "-s|--scan Scan for devices and print the bus IDs" print "-K|--reconfigure Force-reconfigure all detected devices" print "" print "-d|--device DEV Selects the device with the bus ID \"DEV\"" print " Use the special value \"mouse\" for DEV to select" print " the first razer mouse device found in the system." print " If this option is omitted, the first Razer device found is selected." print "" print "-S|--sleep SECS Sleep SECS seconds." print "" print "Device operations (DEVOPS):" print "These options apply to the device that is specified with -d" print "" print "Options for mice:" print "-V|--fwver Print the firmware version number" print "-p|--profile profile Changes the active profile" print "-P|--getprofile Prints the active profile" print "-r|--res profile:DPI Changes the scan resolution." print "-R|--getres Prints the resolutions" print "-f|--freq [profile:]FREQ Changes the scan frequency." print "-F|--getfreq Prints the frequencies" print "-L|--leds Print the identifiers of the LEDs on the device" print "-l|--setled [profile:]LED:off Toggle the LED with the identifier \"LED\" ON or OFF" print "-c|--setledcolor [profile:]LED:aabbcc Set LED color to RGB 'aabbcc'" print "-X|--flashfw FILE Flash a firmware image to the device" print "" print "The 'profile' number may be 0 for the current profile. If 'profile' is" print "omitted, the global settings are changed (not possible for every device)." def findDevice(deviceType=None): if deviceType is None or deviceType == "mouse": getRazer().rescanMice() mice = getRazer().getMice() if mice: return mice[0] # Return the first idstr if deviceType: raise RazerEx("No Razer mouse found in the system") raise RazerEx("No Razer device found in the system") def parse_args(): devOpsList = [] currentDevOps = None try: (opts, args) = getopt.getopt(sys.argv[1:], "hvBsKd:r:Rf:FLl:VS:X:c:p:P", [ "help", "version", "background", "scan", "reconfigure", "device=", "res=", "getres", "freq=", "getfreq", "leds", "setled=", "fwver", "config=", "sleep=", "flashfw=", "setledcolor=", "profile=", "getprofile", ]) except getopt.GetoptError: usage() exit(1) for (o, v) in opts: if o in ("-h", "--help"): usage() exit(0) if o in ("-v", "--version"): prVersion() exit(0) if o in ("-B", "--background"): if os.fork() != 0: exit(0) # Exit parent if o in ("-s", "--scan"): ops = currentDevOps if not currentDevOps: ops = DevOps(None) ops.add(OpScan()) if not currentDevOps: devOpsList.append(ops) continue if o in ("-K", "--reconfigure"): ops = currentDevOps if not currentDevOps: ops = DevOps(None) ops.add(OpReconfigure()) if not currentDevOps: devOpsList.append(ops) continue if o in ("-d", "--device"): if v == "mouse": # magic; select the first mouse v = findDevice("mouse") if currentDevOps and currentDevOps.ops: devOpsList.append(currentDevOps) currentDevOps = DevOps(v) continue if o in ("-p", "--profile"): if not currentDevOps: currentDevOps = DevOps(findDevice()) currentDevOps.add(OpSetProfile(v)) continue if o in ("-P", "--getprofile"): if not currentDevOps: currentDevOps = DevOps(findDevice()) currentDevOps.add(OpGetProfile()) continue if o in ("-r", "--res"): if not currentDevOps: currentDevOps = DevOps(findDevice()) currentDevOps.add(OpSetRes(v)) continue if o in ("-R", "--getres"): if not currentDevOps: currentDevOps = DevOps(findDevice()) currentDevOps.add(OpGetRes()) continue if o in ("-f", "--freq"): if not currentDevOps: currentDevOps = DevOps(findDevice()) currentDevOps.add(OpSetFreq(v)) continue if o in ("-F", "--getfreq"): if not currentDevOps: currentDevOps = DevOps(findDevice()) currentDevOps.add(OpGetFreq()) continue if o in ("-L", "--leds"): if not currentDevOps: currentDevOps = DevOps(findDevice()) currentDevOps.add(OpPrintLeds()) continue if o in ("-l", "--setled"): if not currentDevOps: currentDevOps = DevOps(findDevice()) currentDevOps.add(OpSetLedState(v)) continue if o in ("-c", "--setledcolor"): if not currentDevOps: currentDevOps = DevOps(findDevice()) currentDevOps.add(OpSetLedColor(v)) continue if o in ("-V", "--fwver"): if not currentDevOps: currentDevOps = DevOps(findDevice()) currentDevOps.add(OpGetFwVer()) continue if o in ("-S", "--sleep"): ops = currentDevOps if not currentDevOps: ops = DevOps(None) try: v = float(v) except ValueError: raise RazerEx("Value for -S|--sleep must be a floating point value") ops.add(OpSleep(v)) if not currentDevOps: devOpsList.append(ops) continue if o in ("-X", "--flashfw"): if not currentDevOps: raise RazerEx("Must specify a device (-d) before -X|--flashfw") currentDevOps.add(OpFlashFw(v)) continue if currentDevOps and currentDevOps.ops: devOpsList.append(currentDevOps) if not devOpsList: usage() exit(1) return devOpsList def main(): try: devOpsList = parse_args() for devOps in devOpsList: devOps.runAll() except (RazerEx), e: print e return 1 return 0 if __name__ == "__main__": exit(main())