Skip to content

Instantly share code, notes, and snippets.

@yatharthb97
Last active September 29, 2022 22:49
Show Gist options
  • Save yatharthb97/0ebb5a6e618c2de3720aeefbf82a708a to your computer and use it in GitHub Desktop.
Save yatharthb97/0ebb5a6e618c2de3720aeefbf82a708a to your computer and use it in GitHub Desktop.
Describes a class `UDCounter` or "Up - Down Counter" which is a multi-modal bidirectional counter object.
"""
Up or Down (Bimodal) Counting Object
Author - Yatharth Bhasin (github → yatharthb97)
Describes a class `UDCounter` or "Up - Down Counter" which is a multi-modal bidirectional counter object.
The design of this class was inspired by Hardware counters/timers.
`isr` : interrupt service routine
"""
class UDCounter:
'''
Bi-directional Counter → {"up", "down_counter"} counting object.
Multi-modal → {"off", "trigger on overflow", "trigger on compare", "trigger on multiple compares"}
'''
def __init__(self, name):
'''
Constructor object → no arguemnets. Sets the mode to "off".
'''
self.name = name
self.value = 0
self.reset = 0
self.verbose = False
self.mode = "off"
self.turn_off()
def update(self):
'''
Updates the value of the counter using the updater function.
'''
self.value = self.updater(self.value)
def load_val(self, value):
'''
Loads the given Positive Integer value to the counter value.
'''
self.value = value
def set_up_counter(self, value: int):
'''
Begins up-counting after setting the counter value to the passed arguement `value`.
'''
self.updater = lambda x : x + 1
self.mode = "up"
self.load_val(value)
if self.verbose:
print(f" •[UDCntr {self.name}] Up Counter set: {self.value}")
def set_down_counter(self, value: int):
'''
Begins down-counting after setting the counter value to the passed arguement `value`.
'''
self.updater = lambda x : x - 1
self.mode = "down" #Bookeeping
self.load_val(value)
if self.verbose:
print(f" •[UDCntr {self.name}] Down Counter set: {self.value}")
def val(self):
'''
Reads back the counter value.
'''
return self.value
def turn_off(self):
'''
Turns off the counter and freezes the current count value.
'''
self.mode == "off"
self.updater = lambda x : x # Blank Lambda
if self.verbose:
print(f" •[UDCntr {self.name}] Counter turned off: {self.value}")
def trigger_on_overflow(self, overflow_val: int, isr, **kwargs):
'''
Sets up the counter to trigger a callback function `isr` or Interrupt Service Routine after each overflow.
The `isr` returns nothing and accepts no arguements.
The overflow value is set by the passed parameter `overlow_val`. The counter is reset after each overflow.
The reset value is determined from the kwargs - 'reset' or the set object attribute `reset`.
The counter must first be set to either 'up' or 'down' mode before setting this function.
'''
if(self.mode != "up" or self.mode != "down"):
raise Exception ("Please set direction of the counter - 'up' or 'down'. ")
if 'reset' in kwargs:
self.reset = kwargs['reset']
self.mode = "trigger on overflow"
self.overflow = overflow_val
self.isr = isr
old_updater = self.updater
def overflow_updater(x):
x = old_updater(x)
if x == self.overflow:
self.isr()
x = 0
return x
self.updater = overflow_updater
if self.verbose:
print(f" •[UDCntr {self.name}] Overflow trigger set on: {self.overfow}")
def trigger_on_compare(self, compare_val: int, isr, **kwargs):
'''
Sets up the counter to trigger a callback function `isr` or Interrupt Service Routine after a compare event.
The `isr` returns nothing and accepts no arguements.
The compare value is set by the passed parameter `comapre_val`. The counter is NOT reset after a compare.
The counter must first be set to either 'up' or 'down' mode before setting this function.
'''
if(self.mode != "up" or self.mode != "down"):
raise Exception ("Please set direction of the counter - 'up' or 'down'. ")
self.mode = "trigger on compare"
self.compare = value
self.isr = isr
old_updater = self.updater
def compare_updater(x):
x = old_updater(x)
if (x == self.compare):
self.isr()
return x
self.updater = compare_updater
if self.verbose:
print(f" •[UDCntr {self.name}] Compare trigger set on: {self.compare}")
def trigger_on_multi_compare(self, compare_vals: int, isr):
'''
Sets up the counter to trigger a callback function `isr` or Interrupt Service after a compare event.
The `isr` returns nothing and accepts no arguements.
The compare value is set by the passed parameter `comapre_val`. The counter is NOT reset after a compare.
After exhausting the list of compare values, the compare value is reset from the first value in the list.
The counter must first be set to either 'up' or 'down' mode before setting this function.
'''
if(self.mode != "up" or self.mode != "down"):
raise Exception("Please set direction of the counter - 'up' or 'down'. ")
self.mode = "trigger on multiple compares"
self.compare = list(compare_vals)
self.isr = isr
old_updater = self.updater
compare_index = 0
def multi_compare_updater(x):
x = old_updater(x)
if (x == self.compare[compare_index]):
self.isr()
compare_index = comapre_index + 1
if comapre_index >= len(self.compare):
compare_index = 0
return x
self.updater = multi_compare_updater
if self.verbose:
print(f" •[UDCntr {self.name}] Compare trigger set on: {self.compare}")
def force_up(self):
'''
Forces an increment on the current value, irrespective of the counting direction.
'''
self.value = self.value + 1
def force_down(self):
'''
Forces a decrement on the current value, irrespective of the counting direction.
'''
self.value = self.value - 1
def summary(self):
'''
Prints a description of the counter object.
'''
print(f"Counter Object -> mode : {self.mode} | value -> {self.val()}")
if self.mode == "trigger on compare" : print(f"Compare Value -> {self.compare}")
if self.mode == "trigger on overflow" : print(f"Overflow Value -> {self.overfow}")
def __repr__(self):
'''
Returns the string description of the counter object.
'''
return f" <UDCounter Object> mode -> {self.mode} : current value -> {self.val()}"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment