lib/rint_core/driver/operations.rb
require 'rint_core/g_code'
require 'serialport'
module RintCore
module Driver
# Provides the raw functionality of the printer.
module Operations
# Connects to the printer.
# @return [Undefined] returns the value of the connect callback.
def connect!
return false if connected?
unless config.port.nil? && config.baud.nil?
disable_hup(config.port)
@connection = SerialPort.new(config.port, config.baud)
@connection.read_timeout = config.read_timeout
@stop_listening = false
sleep(config.long_sleep)
@listening_thread = Thread.new{listen()}
config.callbacks[:connect].call unless config.callbacks[:connect].nil?
end
end
# Disconnects to the printer.
# @return [Undefined] returns the value of the disconnect callback.
def disconnect!
if connected?
if @listening_thread
@stop_listening = true
send!(RintCore::GCode::Codes::GET_EXT_TEMP)
@listening_thread.join
@listening_thread = nil
end
@connection.close
end
@connection = nil
offline!
not_printing!
config.callbacks[:disconnect].call unless config.callbacks[:disconnect].nil?
end
# Resets the printer.
# @return [false] if not connected.
# @return [1] if printer was reset.
def reset!
return false unless connected?
@connection.dtr = 0
sleep(config.long_sleep)
@connection.dtr = 1
end
# Pauses printing.
# @return [Undefined] returns the value of the pause callback.
def pause!
return false unless printing?
@paused = true
until @print_thread.alive?
sleep(config.sleep_time)
end
@print_thread = nil
not_printing!
config.callbacks[:pause].call unless config.callbacks[:pause].nil?
end
# Resumes printing.
# @return [Undefined] returns the value of the resume callback.
def resume!
return false unless paused?
@paused = false
printing!
@print_thread = Thread.new{print()}
config.callbacks[:resume].call unless config.callbacks[:resume].nil?
end
# Sends the given command to the printer.
# @param command [String] the command to send to the printer.
# @param priority [Boolean] defines if command is a priority.
# @todo finalize return value.
def send!(command, priority = false)
return nil unless command.is_a?(String) || command.is_a?(Array)
if online?
if printing?
if priority
command.is_a?(String) ? @priority_queue.push(command) : @priority_queue + command
return true
else
return false
end
else
if command.is_a?(Array)
command.each do |line|
wait_then_send(line)
end
else
wait_then_send(command)
end
end
else
config.callbacks[:send_error].call unless config.callbacks[:send_error].nil?
end
end
# Sends command to the printer immediately by placing it in the priority queue.
# @see send
def send_now!(command)
send!(command, true)
end
# Starts a print.
# @param gcode [RintCore::GCode::Object] prints the given object.
# @param start_index [Fixnum] starts printing from the given index (used by {#pause!} and {#resume!}).
# @return [false] if printer isn't ready to print or already printing.
# @return [true] if print has been started.
def print!(gcode, start_index = 0)
p "Starting print!"
return false unless gcode.is_a?(RintCore::GCode::Object)
prep_to_print(start_index)
return false unless gcode.present?
if low_power?
@gcode_object = []
gcode.lines.each_with_index do |line,line_number|
@gcode_object << format_command(line.to_s(line_number))
end
gcode = nil
GC.start
p "Low power ENABLEDZ"
else
@gcode_object = gcode
@queue_length = gcode.length
end
@start_time = Time.now
@print_thread = Thread.new{print()}
return true
end
# Starts printing the given file.
# @param file [String] file name of a GCode file on the system.
# @see print!
def print_file!(file)
p "Print file!"
return false unless can_print?
p "Print file! 1"
return false unless File.exist?(file) && File.file?(file)
p "Print file! 2"
if config.low_power
@queue_length = %x{wc -l < "#{file}"}.to_i
@file_handle = File.open(file)
@start_time = Time.now
@print_thread = Thread.new{print()}
end
gcode = RintCore::GCode::Object.new(file, 2400, auto_process = false)
return false unless gcode
p "GCode OK"
print!(gcode)
end
private
def initialize_operations
@connection = nil
@listening_thread = nil
@print_thread = nil
@start_time = nil
@file_handle = nil
end
def readline!
begin
line = @connection.readline.strip
rescue EOFError, Errno::ENODEV => e
config.callbacks[:critcal_error].call(e) unless config.callbacks[:critcal_error].nil?
end
end
def prep_to_print(start_index)
p "Prrep 1"
return false unless can_print?
p "Prep 2"
return false if printing?
p "Prep 3"
printing!
@line_number = 0
@queue_index = start_index
@resend_from = -1
wait_until_clear
not_clear_to_send!
send_to_printer(RintCore::GCode::Codes::SET_LINE_NUM, -1)
p "Done"
end
def print
p "privatge print"
@machine_history = []
config.callbacks[:start].call unless config.callbacks[:start].nil?
p "enter ing loop"
while online? && printing? do
p "queueueue"
advance_queue
return true if paused?
end
p "finished?"
config.callbacks[:finish].call unless config.callbacks[:finish].nil?
@start_time = nil
initialize_queueing
@print_thread.join
@print_thread = nil
p "TRUE!zor"
return true
end
def listen
clear_to_send!
listen_until_online
while listen_can_continue? do
line = readline!
@last_line_received = line unless line == "wait"
case get_response_type(line)
when :valid
config.callbacks[:receive].call(line) unless config.callbacks[:receive].nil?
clear_to_send!
when :temperature
config.callbacks[:temperature].call(line) unless config.callbacks[:temperature].nil?
when :temperature_response
config.callbacks[:temperature].call(line) unless config.callbacks[:temperature].nil?
clear_to_send!
when :error
config.callbacks[:printer_error] unless config.callbacks[:printer_error].nil?
# TODO: Figure out if an error should be raised here or if it should be left to the callback
when :resend
@resend_from = get_resend_number(line)
config.callbacks[:resend].call(line) unless config.callbacks[:resend].nil?
clear_to_send!
when :debug
config.callbacks[:debug] unless config.callbacks[:debug].nil?
when :invalid
config.callbacks[:invalid_response] unless config.callbacks[:invalid_response].nil?
end
end
end
def listen_until_online
begin
empty_lines = 0
accepted_reponses = [:online,:temperature,:valid]
while listen_can_continue? do
line = readline!
unless line.empty?
empty_lines = 0
else
empty_lines += 1
not_clear_to_send!
send!(RintCore::GCode::Codes::GET_EXT_TEMP)
end
break if empty_lines == 5
if accepted_reponses.include?(get_response_type(line))
config.callbacks[:online].call unless config.callbacks[:online].nil?
online!
return true
end
sleep(config.long_sleep)
end
raise "Printer could not be brought online."
rescue RuntimeError => e
config.callbacks[:critcal_error].call(e) unless config.callbacks[:critcal_error].nil?
end
end
def send_to_printer(line, line_number = nil)
p "Sent to PRINTER"
line = RintCore::GCode::Line.new(line) if line.include?(RintCore::GCode::Codes::SET_LINE_NUM)
p "Sent to PRINTER 1.5"
return false if line.empty?
p "Sent to PRINTER 2"
line = format_command(line.to_s(line_number)) if line.is_a?(RintCore::GCode::Line)
p "Sent to PRINTER 2.5"
line = format_command(line, line_number) if line_number.nil? || !line.is_a?(RintCore::GCode::Line)
p "Sent to PRINTER 333"
if connected?
p "Sent to PRINTER CONNECTED 4"
@machine_history[line_number] = line if printing? && !line_number.nil? && !line.include?(RintCore::GCode::Codes::SET_LINE_NUM)
p "Sent to PRINTER CONNECTED 5"
config.callbacks[:send].call(line) unless config.callbacks[:send].nil?
p "Sent to PRINTER CONNECTED 6"
@connection.write(line)
p "Sent to PRINTER CONNECTED 7"
trim_machine_history
p "Sent to PRINTER CONNECTED 8"
return true
end
p "Sent to PRINTER CONNECTED 9"
false
end
def trim_machine_history
@machine_history[@line_number-300] = nil if @line_number >= 300 && @machine_history.length >= 300
end
def wait_then_send(line)
wait_until_clear
not_clear_to_send!
send_to_printer(line)
end
def wait_until_clear
until clear_to_send? do
sleep(config.sleep_time)
end
end
end
end
end