`#!/usr/bin/env node

'use strict'`

# Require the "nixfilter" module
nixfilter = require('nixfilter')

# Import/Require the "nixfilter-logicsignal" module
nixfilter_logicsignal = require('nixfilter-logicsignal')

# Import/Require the "rpio" module
rpio = require('rpio')

# Define the filter and register it on the module
nixfilter.filter module,
	description: 'Send logic/binary signals via a GPIO pin of a Raspberry Pi. The logic/binary signals are read as lines from STDIN, as comma-separated integer values representing durations in nanoseconds. Negative values indicate "inactive"/"low" levels, positive values indicate "active"/"high" levels. For example, the input line "360000,-1080000,+1080000,360000" would output a binary signal of 360µs "high" level, followed by 1080µs "low" level, followed by 1080µs "high" level, followed by 360µs "low" level.'

	input_reader: nixfilter_logicsignal.reader.logic_signal()

	output_writer: null

	add_arguments: (argument_parser) ->
		argument_parser.addArgument ['--latency', '-l'],
			type: 'int'
			defaultValue: 65
			help: 'The latency overhead (in microseconds) for every signal. This depends on the Raspberry Pi being used; on the Raspberry Pi 3B+, this is about 65. (default: 65)'
		argument_parser.addArgument ['--inactive_state', '-i'],
			choices: ['low', 'high']
			defaultValue: 'low'
			help: 'The GPIO pin\'s inactive state, if no signal is being sent (default: low)'
		argument_parser.addArgument ['gpio_pin_id'],
			type: 'int'
			help: 'The numerical ID of the GPIO pin to use for outputting the signals'
		return

	setup: (args) ->
		if (@args.inactive_state is 'low')
			@inactive_state = rpio.LOW
			@active_state = rpio.HIGH
		else
			@inactive_state = rpio.HIGH
			@active_state = rpio.LOW
		# Set the GPIO pin to its "inactive" state and open it
		rpio.open(@args.gpio_pin_id, rpio.OUTPUT, @inactive_state)

	output_timings: (signal_timings) ->
		# Reduce timings by latency
		timings = [-200]
		for timing in signal_timings
			timings.push(Math.max((Math.abs(timing // 1000) - @args.latency), 1) * (if (timing > 0) then 1 else -1))
		# Setup local variables to ensure the "for" loop runs as fast as possible
		gpio_pin_id = @args.gpio_pin_id
		inactive_state = @inactive_state
		active_state = @active_state
		# Output the signal
		for timing in timings
			if (timing > 0)
				rpio.write(gpio_pin_id, active_state)
				rpio.usleep(timing)
			else
				rpio.write(gpio_pin_id, inactive_state)
				rpio.usleep(-timing)
		# Set the GPIO pin to it's "inactive" state again
		rpio.write(gpio_pin_id, inactive_state)
		return

	on_input: (logic_signal) ->
		@output_timings(logic_signal.get_timings())
		return

