X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=kll_lib%2Fcontainers.py;h=814cd5cc044de8c4ef4b66fe22c0229130471598;hb=refs%2Fheads%2Fdonlayout;hp=b96cc32d6577845e41eee80704ac7a61347a8480;hpb=59a4b27de52b82bf7991ea3cbeed786f38fce1ac;p=kiibohd-kll.git diff --git a/kll_lib/containers.py b/kll_lib/containers.py index b96cc32..814cd5c 100644 --- a/kll_lib/containers.py +++ b/kll_lib/containers.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 # KLL Compiler Containers # -# Copyright (C) 2014 by Jacob Alexander +# Copyright (C) 2014-2015 by Jacob Alexander # # This file is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -34,6 +34,67 @@ ERROR = '\033[5;1;31mERROR\033[0m:' ## Containers +class ScanCode: + # Container for ScanCodes + # + # scancode - Non-interconnect adjusted scan code + # interconnect_id - Unique id for the interconnect node + def __init__( self, scancode, interconnect_id ): + self.scancode = scancode + self.interconnect_id = interconnect_id + + def __eq__( self, other ): + return self.dict() == other.dict() + + def __repr__( self ): + return repr( self.dict() ) + + def dict( self ): + return { + 'ScanCode' : self.scancode, + 'Id' : self.interconnect_id, + } + + # Calculate the actual scancode using the offset list + def offset( self, offsetList ): + if self.interconnect_id > 0: + return self.scancode + offsetList[ self.interconnect_id - 1 ] + else: + return self.scancode + + +class ScanCodeStore: + # Unique lookup for ScanCodes + def __init__( self ): + self.scancodes = [] + + def __getitem__( self, name ): + # First check if this is a ScanCode object + if isinstance( name, ScanCode ): + # Do a reverse lookup + for idx, scancode in enumerate( self.scancodes ): + if scancode == name: + return idx + + # Could not find scancode + return None + + # Return scancode using unique id + return self.scancodes[ name ] + + # Attempt add ScanCode to list, return unique id + def append( self, new_scancode ): + # Iterate through list to make sure this is a unique ScanCode + for idx, scancode in enumerate( self.scancodes ): + if new_scancode == scancode: + return idx + + # Unique entry, add to the list + self.scancodes.append( new_scancode ) + + return len( self.scancodes ) - 1 + + class Capabilities: # Container for capabilities dictionary and convenience functions def __init__( self ): @@ -87,6 +148,9 @@ class Macros: # Default layer (0) self.layer = 0 + # Unique ScanCode Hash Id Lookup + self.scanCodeStore = ScanCodeStore() + # Macro Storage self.macros = [ dict() ] @@ -102,6 +166,7 @@ class Macros: self.triggerList = [] self.maxScanCode = [] self.firstScanCode = [] + self.interconnectOffset = [] # USBCode Assignment Cache self.assignmentCache = [] @@ -146,7 +211,8 @@ class Macros: self.macros[ self.layer ][ trigger ] = [ result ] # Mark layer scan code, so it won't be removed later - if not self.baseLayout is None: + # Also check to see if it hasn't already been removed before + if not self.baseLayout is None and trigger in self.layerLayoutMarkers[ self.layer ]: del self.layerLayoutMarkers[ self.layer ][ trigger ] # Return a list of ScanCode triggers with the given USB Code trigger @@ -158,8 +224,31 @@ class Macros: if usbCode in self.macros[ self.layer ][ macro ]: scanCodeList.append( macro ) + if len(scanCodeList) == 0: + if len(usbCode) > 1 or len(usbCode[0]) > 1: + for combo in usbCode: + comboCodes = list() + for key in combo: + scanCode = self.lookupUSBCodes(((key,),)) + comboCodes.append(scanCode[0][0][0]) + scanCodeList.append(tuple(code for code in comboCodes)) + scanCodeList = [tuple(scanCodeList)] + return scanCodeList + # Check whether we should do soft replacement + def softReplaceCheck( self, scanCode ): + # First check if not the default layer + if self.layer == 0: + return True + + # Check if current layer is set the same as the BaseMap + if not self.baseLayout is None and scanCode in self.layerLayoutMarkers[ self.layer ]: + return False + + # Otherwise, allow replacement + return True + # Cache USBCode Assignment def cacheAssignment( self, operator, scanCode, result ): self.assignmentCache.append( [ operator, scanCode, result ] ) @@ -178,7 +267,7 @@ class Macros: self.removeScanCode( item[1], item[2] ) # Replace Case - elif item[0] == ":": + elif item[0] == ":" or item[0] == "::": self.replaceScanCode( item[1], item[2] ) # Clear assignment cache @@ -188,6 +277,7 @@ class Macros: def generate( self ): self.generateIndices() self.sortIndexLists() + self.generateOffsetTable() self.generateTriggerLists() # Generates Index of Results and Triggers @@ -218,6 +308,34 @@ class Macros: for trigger in self.triggersIndex.keys(): self.triggersIndexSorted[ self.triggersIndex[ trigger ] ] = trigger + # Generates list of offsets for each of the interconnect ids + def generateOffsetTable( self ): + idMaxScanCode = [ 0 ] + + # Iterate over each layer to get list of max scancodes associated with each interconnect id + for layer in range( 0, len( self.macros ) ): + # Iterate through each trigger/sequence in the layer + for sequence in self.macros[ layer ].keys(): + # Iterate over the trigger to locate the ScanCodes + for combo in sequence: + # Iterate over each scancode id in the combo + for scancode_id in combo: + # Lookup ScanCode + scancode_obj = self.scanCodeStore[ scancode_id ] + + # Extend list if not large enough + if scancode_obj.interconnect_id >= len( idMaxScanCode ): + idMaxScanCode.extend( [ 0 ] * ( scancode_obj.interconnect_id - len( idMaxScanCode ) + 1 ) ) + + # Determine if the max seen id for this interconnect id + if scancode_obj.scancode > idMaxScanCode[ scancode_obj.interconnect_id ]: + idMaxScanCode[ scancode_obj.interconnect_id ] = scancode_obj.scancode + + # Generate interconnect offsets + self.interconnectOffset = [ idMaxScanCode[0] + 1 ] + for index in range( 1, len( idMaxScanCode ) ): + self.interconnectOffset.append( self.interconnectOffset[ index - 1 ] + idMaxScanCode[ index ] ) + # Generates Trigger Lists per layer using index lists def generateTriggerLists( self ): for layer in range( 0, len( self.macros ) ): @@ -237,7 +355,8 @@ class Macros: # Iterate over the trigger to locate the ScanCodes for sequence in trigger: - for combo in sequence: + for combo_id in sequence: + combo = self.scanCodeStore[ combo_id ].offset( self.interconnectOffset ) # Append triggerIndex for each found scanCode of the Trigger List # Do not re-add if triggerIndex is already in the Trigger List if not triggerIndex in self.triggerList[ layer ][ combo ]: @@ -276,19 +395,69 @@ class Variables: # Container for variables # Stores three sets of variables, the overall combined set, per layer, and per file def __init__( self ): - pass + # Dictionaries of variables + self.baseLayout = dict() + self.fileVariables = dict() + self.layerVariables = [ dict() ] + self.overallVariables = dict() + self.defines = dict() + + self.currentFile = "" + self.currentLayer = 0 + self.baseLayoutEnabled = True - def baseLayerFinished( self ): - pass + def baseLayoutFinished( self ): + self.baseLayoutEnabled = False def setCurrentFile( self, name ): # Store using filename and current layer - pass + self.currentFile = name + self.fileVariables[ name ] = dict() + + # If still processing BaseLayout + if self.baseLayoutEnabled: + if '*LayerFiles' in self.baseLayout.keys(): + self.baseLayout['*LayerFiles'] += [ name ] + else: + self.baseLayout['*LayerFiles'] = [ name ] + # Set for the current layer + else: + if '*LayerFiles' in self.layerVariables[ self.currentLayer ].keys(): + self.layerVariables[ self.currentLayer ]['*LayerFiles'] += [ name ] + else: + self.layerVariables[ self.currentLayer ]['*LayerFiles'] = [ name ] - def setCurrentLayer( self, layer ): + def incrementLayer( self ): # Store using layer index - pass + self.currentLayer += 1 + self.layerVariables.append( dict() ) def assignVariable( self, key, value ): - pass + # Overall set of variables + self.overallVariables[ key ] = value + + # The Name variable is a special accumulation case + if key == 'Name': + # BaseLayout still being processed + if self.baseLayoutEnabled: + if '*NameStack' in self.baseLayout.keys(): + self.baseLayout['*NameStack'] += [ value ] + else: + self.baseLayout['*NameStack'] = [ value ] + # Layers + else: + if '*NameStack' in self.layerVariables[ self.currentLayer ].keys(): + self.layerVariables[ self.currentLayer ]['*NameStack'] += [ value ] + else: + self.layerVariables[ self.currentLayer ]['*NameStack'] = [ value ] + + # If still processing BaseLayout + if self.baseLayoutEnabled: + self.baseLayout[ key ] = value + # Set for the current layer + else: + self.layerVariables[ self.currentLayer ][ key ] = value + + # File context variables + self.fileVariables[ self.currentFile ][ key ] = value