UNPKG

nixfilter-logicsignal

Version:

Filters for handling (compressing/uncompressing etc.) logic signals

97 lines (82 loc) 3.68 kB
'use strict' # Returns true if the passed argument <value> is neither null nor undefined is_valid_value = (value) -> ((value isnt undefined) and (value isnt null)) # Returns the first value in <values...> that is neither null nor undefined first_valid_value = (values...) -> for value in values if is_valid_value(value) return value return # Assuming that array <array> can be constructed by repeating another array n times, returns the largest n get_number_of_repetitions_in_array = (array) -> for number_of_repetitions in [array.length..2] by -1 if ((array.length % number_of_repetitions) is 0) repeated_array_length = (array.length // number_of_repetitions) for index in [repeated_array_length...array.length] by 1 if (array[index] isnt array[index % repeated_array_length]) break if (index is array.length) return number_of_repetitions 1 # Returns the greatest common divisor (GCD) of <first_number> and <second_number> greatest_common_divisor = (first_number, second_number) -> return (if first_number then greatest_common_divisor(second_number % first_number, first_number) else second_number) # Returns the greatest_common_divisor (GCD) of all numbers in array <numbers_array> greatest_common_divisor_in_array = (numbers_array) -> numbers_array.reduce(greatest_common_divisor) # Returns true if <value> is an array is_array = (value) -> Array.isArray(value) # Returns a function with <value> argument that returns true if <value> is of type <type_string> is_of_type = (type_string) -> (value) -> (typeof(value) is type_string) # Returns true if <value> is of type "string" is_object_type = is_of_type('object') # Returns true if <value> is of type "string" is_string_type = is_of_type('string') # The regular expression pattern of a valid logic signal, as a string logic_signal_pattern = '^\\s*\\[?(\\s*[+-]?\\d+?(?:,\\s*[+-]?\\d+)*)\\]?(?:\\s*@\\s*(\\d+))?(?:\\s*\\*\\s*(\\d+))?\\s*$' # The regular expression pattern of a valid logic signal, as a RegExp logic_signal_regexp = (new RegExp(logic_signal_pattern)) # Repeat array <array> <number_of_repetitions> times repeat_array = (array, number_of_repetitions) -> (array[index % array.length] for index in [0...(array.length * number_of_repetitions)] by 1) # This class represents a logic/binary signal Logic_Signal = class constructor: (data, cycle_time, repetitions) -> if is_array(data) @cycles = data @cycle_time = cycle_time @repetitions = repetitions else if is_object_type(data) @cycles = data.cycles @cycle_time = data.cycle_time @repetitions = data.repetitions else if is_string_type(data) data = logic_signal_regexp.exec(data) @cycles = (parseInt(cycle_string) for cycle_string in data[1].split(',')) @cycle_time = data[2] @repetitions = data[3] else throw new Error('Logic signal constructor called with invalid arguments') @cycle_time = first_valid_value(@cycle_time, 1) @repetitions = first_valid_value(@repetitions, 1) get_unrepeated_timings: -> @cycles.map((cycle) => (cycle * @cycle_time)) get_timings: -> repeat_array(@get_unrepeated_timings(), @repetitions) compress: -> timings = @get_timings() repetitions = get_number_of_repetitions_in_array(timings) unrepeated_timings = timings.slice(0, (timings.length // repetitions)) cycle_time = greatest_common_divisor_in_array(unrepeated_timings) cycles = ((timing // cycle_time) for timing in unrepeated_timings) new Logic_Signal(cycles, cycle_time, repetitions) to_string: -> "#{@cycles.join(',')}@#{@cycle_time}*#{@repetitions}" to_timings_string: -> @get_timings().join(',') # What this module exports module.exports = Logic_Signal