1 /*
2     This file is a part of the RepSnapper project.
3     Copyright (C) 2011-12 martin.dieringer@gmx.de
4 
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU Lesser General Public License as published by
7     the Free Software Foundation; either version 2 of the License, or
8     (at your option) any later version.
9 
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU Lesser General Public License for more details.
14 
15     You should have received a copy of the GNU Lesser General Public License along
16     with this program; if not, write to the Free Software Foundation, Inc.,
17     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19 
20 #pragma once
21 
22 #include <limits.h>
23 
24 #include "thread.h"
25 #include "thread_buffer.h"
26 #include "printer_serial.h"
27 
28 using namespace std;
29 
30 class ThreadedPrinterSerial : protected PrinterSerial
31 {
32   static const unsigned long command_buffer_size = 8192;
33   static const unsigned long response_buffer_size = 4096;
34   static const unsigned long log_buffer_size = 8192;
35 
36   static const ntime_t command_buffer_sleep;
37   static const ntime_t response_buffer_sleep;
38   static const ntime_t log_buffer_sleep;
39   static const ntime_t helper_thread_sleep;
40 
41   // Rules:
42   // request_print, is_printing, and printer_commands are initialized to NULL
43   // To stop printing, thread must lock the mutex, set request_print to false
44   //   and wait for the helper to signal on pc_cond.  Finally, release the
45   //   mutex.
46   // To start printing, lock the mutex, if is_printing is true, stop printing
47   //   per the above steps.  Next, set printer commands to the desired commands
48   //   and clear ps_status.  Then, set request_print to true and wait for
49   //   the helper to signal on pc_cond.  Finally, release the mutex.
50   // For the purpose of status bars and status lights,
51   //   the values of is_printing and pc_status can be examined without needing
52   //   to lock the mutex.
53   //
54   // Helper:
55   //   if request_print is different than is_printing, aquire the mutex,
56   //     set is_printing to match request_print, signal on pc_cond, and relase
57   //     the mutex.
58   //   <<handle queued commands>
59   //   if is_printing, send the next command from printer_commands.  Do NOT
60   //     need to lock the mutex.
61 
62   mutex_t pc_mutex;
63   bool request_print; // set by main thread(s), pc_mutex required
64   bool is_printing; // set by helper, pc_cond_mutex required
65   bool printing_complete; // set by helper, no mutex required
66   cond_t pc_cond; // signaled by helper, pc_mutex and pc_cond_mutex required
67   mutex_t pc_cond_mutex;
68   const char *printer_commands; // set by main thread(s), pc_mutex required
69   unsigned long pc_lines_printed; // when is_printing is false, set by main thread(s), pc_mutex required.  When is_printing is true, set by helper, pc_mutex requried
70   unsigned long pc_bytes_printed; // when is_printing is false, set by main thread(s), pc_mutex required.  When is_printing is true, set by helper, pc_mutex required
71   unsigned long pc_stop_line; // set by main thread(s), pc_mutex required
72   int inhibit_count; // set by main thread(s), pc_cond_mutex required
73 
74   ThreadBufferReturnData command_buffer;
75   SignalingThreadBuffer response_buffer;
76   ThreadBuffer log_buffer;
77   ThreadBuffer error_buffer;
78 
79   bool helper_active;
80   thread_t helper_thread;
81   bool helper_cancel;
82 
83   ThreadBufferReturnData::ReturnData *return_data;
84 
85   void CheckPrintingState( void ); // Check if main thread is requesting printing and set helper thread switches accordingly
86 
87   void SendNextPrinterCommand( void );
88   void SendCommand( bool buffer_response );
89 
90   void RecvTimeout( void );
91   void LogLine( const char *line ); // Log the line.  The provided line should end in a newline character.
92   void LogError( const char *error_line ); // Log the error.  The provided line should end in a newline character.
93 
94   static void *HelperMainStatic( void *arg );
95   void *HelperMain( void );
96 
97  public:
98   ThreadedPrinterSerial();
99   virtual ~ThreadedPrinterSerial();
100 
101   // Connect to or disconnect from a printer
102   virtual bool Connect( string device, int baudrate );
103   virtual void Disconnect( void );
104   virtual bool IsConnected( void );
105   virtual bool Reset( void );
106 
107   // Start printing gcode
108   // Commands are sent one at a time in the background
109   // Send and SendAndWaitResponse can safely be sent
110   // while printing.
111   virtual bool StartPrinting( string commands, unsigned long start_line = 1, unsigned long stop_line = ULONG_MAX );
112   virtual bool IsPrinting( void );
113   virtual bool StopPrinting( bool wait = true );
114   virtual bool ContinuePrinting( bool wait = true );
115   virtual void Inhibit( bool value = true );
116   virtual bool IsInhibited( void );
117 
118   unsigned long GetPrintingProgress( unsigned long *bytes_printed = NULL );
119   // Returns last line number ok'd by the printer
120   // If printing is stopped, returns last line number of previous print
121   // If bytes_printed is non-null, sets that value as well.
122 
123   unsigned long GetTotalPrintingLines( void );
124   // Return the ending line of the current print
125 
126   using PrinterSerial::Send;
127   bool SendAsync( char const * command );
128   bool Send( string command );
129   // Command may be multiple commands separated by newlines (\n).
130   // Such commands are queued atomically.
131   // Commands may be sent when printing is active.
132   // Commands sent with this interface have higher priority than commands
133   // sent from StartPrinting.
134 
135   string ReadResponse( bool wait = false );
136   // returns "" if wait is false and no response is ready
137   // only returns responses from Send() and StartPeriodic() and NOT from
138   // SendAndWaitResponse() or StartingPrinting()
139 
140   string SendAndWaitResponse( string command );
141   // Send the string and wait for the response
142   // May take up to several seconds if the printer is already processing
143   // a long command
144 
145   string ReadLog( bool wait = false );
146   // returns "" if wait is false and no log entries are ready
147 
148   string ReadErrorLog( bool wait = false );
149   // returns "" if wait is false and no log entries are ready
150 };
151