2013-12-20 16:29:46 +01:00
--
-- This file is part of the Doodle3D project (http://doodle3d.com).
--
-- @copyright 2013, Doodle3D
-- @license This software is licensed under the terms of the GNU GPL v2 or later.
-- See file LICENSE.txt or visit http://www.gnu.org/licenses/gpl.html for full license details.
2014-05-19 21:37:17 +02:00
-- TODO: return errors like in print_POST (error message in a 'msg' key instead of directly in the response) if this does not break API compatibility
2013-12-20 16:29:46 +01:00
2013-08-07 17:50:30 +02:00
local lfs = require ( ' lfs ' )
2013-07-26 10:18:55 +02:00
local log = require ( ' util.logger ' )
local utils = require ( ' util.utils ' )
local settings = require ( ' util.settings ' )
2013-10-10 12:11:16 +02:00
local printerUtils = require ( ' util.printer ' )
local accessManager = require ( ' util.access ' )
2013-07-26 10:18:55 +02:00
2014-04-25 14:51:29 +02:00
local MOD_ABBR = " APRN "
2013-07-26 10:18:55 +02:00
local M = {
isApi = true
}
function M . _global ( request , response )
-- TODO: list all printers (based on /dev/ttyACM* and /dev/ttyUSB*)
response : setSuccess ( )
end
function M . temperature ( request , response )
2013-09-17 00:14:42 +02:00
local argId = request : get ( " id " )
2013-10-10 12:11:16 +02:00
local printer , msg = printerUtils.createPrinterOrFail ( argId , response )
2014-05-19 21:37:17 +02:00
if not printer or not printer : hasSocket ( ) then return end
2013-08-07 17:50:30 +02:00
2013-09-20 11:09:25 +02:00
local temperatures , msg = printer : getTemperatures ( )
2013-09-17 00:14:42 +02:00
2013-09-20 11:09:25 +02:00
response : addData ( ' id ' , argId )
if temperatures then
response : setSuccess ( )
response : addData ( ' hotend ' , temperatures.hotend )
response : addData ( ' hotend_target ' , temperatures.hotend_target )
response : addData ( ' bed ' , temperatures.bed )
response : addData ( ' bed_target ' , temperatures.bed_target )
2014-05-19 21:37:17 +02:00
elseif temperatures == false then
response : addData ( ' status ' , msg )
response : setFail ( )
2013-09-20 11:09:25 +02:00
else
response : setError ( msg )
end
2013-07-26 10:18:55 +02:00
end
2013-08-09 22:15:58 +02:00
function M . progress ( request , response )
2013-09-20 11:09:25 +02:00
local argId = request : get ( " id " )
2013-10-10 12:11:16 +02:00
local printer , msg = printerUtils.createPrinterOrFail ( argId , response )
2014-05-19 21:37:17 +02:00
if not printer or not printer : hasSocket ( ) then return end
2013-09-17 00:14:42 +02:00
2013-10-10 17:00:16 +02:00
-- NOTE: despite their names, `currentLine` is still the error indicator and `bufferedLines` the message in such case.
2016-02-12 15:40:07 +01:00
local currentLine , bufferedLines , totalLines , bufferSize , maxBufferSize = printer : getProgress ( )
2013-08-09 22:15:58 +02:00
2013-09-20 11:09:25 +02:00
response : addData ( ' id ' , argId )
if currentLine then
response : setSuccess ( )
2013-08-09 22:15:58 +02:00
response : addData ( ' current_line ' , currentLine )
2013-10-10 17:00:16 +02:00
response : addData ( ' buffered_lines ' , bufferedLines )
2013-10-10 17:51:14 +02:00
response : addData ( ' total_lines ' , totalLines )
2016-02-12 15:40:07 +01:00
response : addData ( ' buffer_size ' , bufferSize )
response : addData ( ' max_buffer_size ' , maxBufferSize )
2014-05-19 21:37:17 +02:00
elseif progress == false then
response : addData ( ' status ' , bufferedLines )
response : setFail ( )
2013-09-20 11:09:25 +02:00
else
2013-10-10 17:00:16 +02:00
response : setError ( bufferedLines )
2013-09-20 11:09:25 +02:00
end
end
2014-05-19 21:37:17 +02:00
-- Note: onlyReturnState is optional and prevents response from being modified, used when calling from within other api call
-- Note: unlike regular API-functions, this one returns either true+state or false
2013-10-23 16:12:19 +02:00
function M . state ( request , response , onlyReturnState )
2013-09-20 11:09:25 +02:00
local argId = request : get ( " id " )
2013-10-23 16:12:19 +02:00
if not onlyReturnState then response : addData ( ' id ' , argId ) end
2013-10-10 17:51:14 +02:00
local printer , msg = printerUtils.createPrinterOrFail ( argId , response )
2013-10-23 16:12:19 +02:00
if not printer then
2013-10-10 17:51:14 +02:00
local printerState = " disconnected "
2013-10-23 16:12:19 +02:00
if not onlyReturnState then
response : setSuccess ( )
response : addData ( ' state ' , printerState )
end
2013-10-10 17:51:14 +02:00
return true , printerState
2014-03-09 02:12:36 +01:00
elseif not printer : hasSocket ( ) then
-- while dev is present but no server is running yet, return 'fake' connecting state
local printerState = " connecting "
if not onlyReturnState then
response : setSuccess ( )
response : addData ( ' state ' , printerState )
end
return true , printerState
2013-10-23 16:12:19 +02:00
else
2013-10-10 17:51:14 +02:00
local rv , msg = printer : getState ( )
if rv then
2013-10-23 16:12:19 +02:00
if not onlyReturnState then
response : setSuccess ( )
response : addData ( ' state ' , rv )
end
2013-10-10 17:51:14 +02:00
return true , rv
2014-05-19 21:37:17 +02:00
else -- Note: do not differentiate between false and nil here, false should never be returned
2013-10-23 16:12:19 +02:00
if not onlyReturnState then response : setError ( msg ) end
2013-10-10 17:51:14 +02:00
return false
end
2013-09-20 11:09:25 +02:00
end
2014-05-19 21:37:17 +02:00
--this point cannot be reached, no return necessary
2013-07-26 10:18:55 +02:00
end
2013-12-05 17:31:32 +01:00
-- retrieve a list of 3D printers currently supported
function M . listall ( request , response )
response : setSuccess ( )
response : addData ( ' printers ' , printerUtils.supportedPrinters ( ) )
end
2013-07-26 10:18:55 +02:00
function M . heatup_POST ( request , response )
2013-10-10 12:11:16 +02:00
if not accessManager.hasControl ( request.remoteAddress ) then
response : setFail ( " No control access " )
return
end
2013-09-20 11:09:25 +02:00
local argId = request : get ( " id " )
2013-10-10 12:11:16 +02:00
local printer , msg = printerUtils.createPrinterOrFail ( argId , response )
2014-03-09 02:12:36 +01:00
if not printer or not printer : hasSocket ( ) then return false end
2013-09-17 00:14:42 +02:00
2013-09-27 18:25:16 +02:00
local temperature = settings.get ( ' printer.heatup.temperature ' )
2013-09-20 11:09:25 +02:00
local rv , msg = printer : heatup ( temperature )
2013-09-17 00:14:42 +02:00
2013-09-20 11:09:25 +02:00
response : addData ( ' id ' , argId )
2014-05-19 21:37:17 +02:00
if rv then
response : setSuccess ( )
elseif rv == false then
response : addData ( ' status ' , msg )
response : setFail ( )
else
response : setError ( msg )
2013-07-26 10:18:55 +02:00
end
end
2013-08-04 11:26:47 +02:00
function M . stop_POST ( request , response )
2014-04-25 14:51:29 +02:00
log : info ( MOD_ABBR , " API:printer/stop " )
2013-10-22 13:51:02 +02:00
2013-10-10 12:11:16 +02:00
if not accessManager.hasControl ( request.remoteAddress ) then
response : setFail ( " No control access " )
return
end
2013-09-20 11:09:25 +02:00
local argId = request : get ( " id " )
2013-10-28 17:13:26 +01:00
local argGcode = request : get ( " gcode " )
2013-10-10 12:11:16 +02:00
local printer , msg = printerUtils.createPrinterOrFail ( argId , response )
2014-05-19 21:37:17 +02:00
if not printer or not printer : hasSocket ( ) then return end
2014-03-09 02:12:36 +01:00
2013-10-28 17:13:26 +01:00
if ( argGcode == nil ) then
argGcode = " "
end
local rv , msg = printer : stopPrint ( argGcode )
2013-08-04 11:26:47 +02:00
2013-09-20 11:09:25 +02:00
response : addData ( ' id ' , argId )
2014-05-19 21:37:17 +02:00
if rv then
response : setSuccess ( )
elseif rv == false then
response : addData ( ' status ' , msg )
response : setFail ( )
else
response : setError ( msg )
2013-08-04 11:26:47 +02:00
end
end
2014-04-25 14:51:29 +02:00
--requires: gcode(string) (the gcode to be appended)
--accepts: id(string) (the printer ID to append to)
2013-07-26 10:18:55 +02:00
--accepts: first(bool) (chunks will be concatenated but output file will be cleared first if this argument is true)
2013-10-11 15:34:57 +02:00
--accepts: start(bool) (only when this argument is true will printing be started)
2014-05-19 21:37:17 +02:00
--accepts: seq_number(int) (sequence number of the chunk, must be given until clear() after given once, and incremented each time)
--accepts: seq_total(int) (total number of gcode chunks to be appended, must be given until clear() after given once, and stay the same)
2014-06-16 14:19:29 +02:00
--returns: when the gcode buffer cannot accept the gcode, or the IPC transaction fails, a fail with a (formal, i.e., parseable) status argument will be returned
2013-07-26 10:18:55 +02:00
function M . print_POST ( request , response )
2014-05-12 12:22:16 +02:00
log : info ( MOD_ABBR , " API:printer/print " )
2013-10-10 12:11:16 +02:00
local controllerIP = accessManager.getController ( )
local hasControl = false
if controllerIP == " " then
accessManager.setController ( request.remoteAddress )
hasControl = true
elseif controllerIP == request.remoteAddress then
hasControl = true
end
2013-10-10 17:00:16 +02:00
2014-04-25 14:51:29 +02:00
log : info ( MOD_ABBR , " hasControl: " .. utils.dump ( hasControl ) )
2013-10-10 12:11:16 +02:00
if not hasControl then
response : setFail ( " No control access " )
return
end
2013-09-20 11:09:25 +02:00
local argId = request : get ( " id " )
2013-07-26 10:18:55 +02:00
local argGcode = request : get ( " gcode " )
local argIsFirst = utils.toboolean ( request : get ( " first " ) )
2013-10-11 15:34:57 +02:00
local argStart = utils.toboolean ( request : get ( " start " ) )
2014-05-19 21:37:17 +02:00
local argSeqNumber = request : get ( " seq_number " ) or - 1
local argSeqTotal = request : get ( " seq_total " ) or - 1
local remoteHost = request : getRemoteHost ( )
2013-09-17 00:14:42 +02:00
2013-10-10 12:11:16 +02:00
local printer , msg = printerUtils.createPrinterOrFail ( argId , response )
2014-05-19 21:37:17 +02:00
if not printer or not printer : hasSocket ( ) then return end
2013-09-20 11:09:25 +02:00
response : addData ( ' id ' , argId )
2013-07-26 10:18:55 +02:00
if argGcode == nil or argGcode == ' ' then
response : setError ( " missing gcode argument " )
return
end
2013-09-17 00:14:42 +02:00
2013-07-26 10:18:55 +02:00
if argIsFirst == true then
2014-05-12 12:22:16 +02:00
log : verbose ( MOD_ABBR , " clearing all gcode for " .. printer : getId ( ) )
2013-07-26 10:18:55 +02:00
response : addData ( ' gcode_clear ' , true )
2013-09-20 11:09:25 +02:00
local rv , msg = printer : clearGcode ( )
2014-05-19 21:37:17 +02:00
if rv == false then
response : addData ( ' status ' , msg )
response : setFail ( " could not clear gcode " )
elseif rv == nil then
2013-09-20 11:09:25 +02:00
response : setError ( msg )
return
end
2013-07-26 10:18:55 +02:00
end
2013-09-17 00:14:42 +02:00
2013-07-26 10:18:55 +02:00
local rv , msg
2013-09-17 00:14:42 +02:00
2014-05-19 21:37:17 +02:00
rv , msg = printer : appendGcode ( argGcode , { seq_number = argSeqNumber , seq_total = argSeqTotal , source = remoteHost } )
2013-09-20 11:09:25 +02:00
if rv then
--NOTE: this does not report the number of lines, but only the block which has just been added
response : addData ( ' gcode_append ' , argGcode : len ( ) )
2014-05-19 21:37:17 +02:00
elseif rv == false then
response : addData ( ' status ' , msg )
response : setFail ( " could not add gcode " )
return
2013-09-20 11:09:25 +02:00
else
2013-07-26 10:18:55 +02:00
response : addData ( ' msg ' , msg )
2014-05-19 21:37:17 +02:00
response : setError ( " could not add gcode " )
2013-07-26 10:18:55 +02:00
return
end
2013-09-17 00:14:42 +02:00
2013-10-11 15:34:57 +02:00
if argStart == true then
2013-09-20 11:09:25 +02:00
rv , msg = printer : startPrint ( )
2013-09-17 00:14:42 +02:00
2013-07-26 10:18:55 +02:00
if rv then
response : setSuccess ( )
response : addData ( ' gcode_print ' , true )
2014-05-19 21:37:17 +02:00
elseif rv == false then
response : addData ( ' status ' , msg )
response : setFail ( " could not send gcode " )
return
2013-07-26 10:18:55 +02:00
else
response : addData ( ' msg ' , msg )
2014-05-19 21:37:17 +02:00
response : setError ( " could not send gcode " )
return
2013-07-26 10:18:55 +02:00
end
else
response : setSuccess ( )
end
end
return M