| 1 | /* |
| 2 | This file is part of Smoothie (http://smoothieware.org/). The motion control part is heavily based on Grbl (https://github.com/simen/grbl). |
| 3 | Smoothie is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. |
| 4 | Smoothie is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. |
| 5 | You should have received a copy of the GNU General Public License along with Smoothie. If not, see <http://www.gnu.org/licenses/>. |
| 6 | */ |
| 7 | |
| 8 | #include "libs/Module.h" |
| 9 | #include "libs/Kernel.h" |
| 10 | #include "ToolManager.h" |
| 11 | #include "Tool.h" |
| 12 | #include "PublicDataRequest.h" |
| 13 | #include "ToolManagerPublicAccess.h" |
| 14 | #include "Config.h" |
| 15 | #include "Robot.h" |
| 16 | #include "ConfigValue.h" |
| 17 | #include "Conveyor.h" |
| 18 | #include "checksumm.h" |
| 19 | #include "PublicData.h" |
| 20 | #include "Gcode.h" |
| 21 | |
| 22 | #include "libs/SerialMessage.h" |
| 23 | #include "libs/StreamOutput.h" |
| 24 | #include "FileStream.h" |
| 25 | |
| 26 | #include <math.h> |
| 27 | |
| 28 | ToolManager::ToolManager() |
| 29 | { |
| 30 | active_tool = 0; |
| 31 | current_tool_name = CHECKSUM("hotend"); |
| 32 | } |
| 33 | |
| 34 | void ToolManager::on_module_loaded() |
| 35 | { |
| 36 | |
| 37 | this->register_for_event(ON_GCODE_RECEIVED); |
| 38 | this->register_for_event(ON_GET_PUBLIC_DATA); |
| 39 | this->register_for_event(ON_SET_PUBLIC_DATA); |
| 40 | } |
| 41 | |
| 42 | void ToolManager::on_gcode_received(void *argument) |
| 43 | { |
| 44 | Gcode *gcode = static_cast<Gcode*>(argument); |
| 45 | |
| 46 | if( gcode->has_letter('T') && !gcode->has_m) { |
| 47 | int new_tool = gcode->get_value('T'); |
| 48 | char buff[32]; // should be big enough for any status |
| 49 | int n = snprintf(buff, sizeof(buff), "T%d,T%d switching ", this->active_tool, new_tool); |
| 50 | gcode->txt_after_ok.append(buff, n); |
| 51 | if(new_tool >= (int)this->tools.size() || new_tool < 0) { |
| 52 | // invalid tool |
| 53 | char buf[32]; // should be big enough for any status |
| 54 | int n = snprintf(buf, sizeof(buf), "T%d invalid tool ", new_tool); |
| 55 | gcode->txt_after_ok.append(buf, n); |
| 56 | |
| 57 | } else { |
| 58 | if(new_tool != this->active_tool) { |
| 59 | // We must wait for an empty queue before we can disable the current extruder |
| 60 | THEKERNEL->conveyor->wait_for_idle(); |
| 61 | this->tools[active_tool]->deselect(); |
| 62 | this->active_tool = new_tool; |
| 63 | this->current_tool_name = this->tools[active_tool]->get_name(); |
| 64 | this->tools[active_tool]->select(); |
| 65 | |
| 66 | //send new_tool_offsets to robot |
| 67 | const float *new_tool_offset = tools[new_tool]->get_offset(); |
| 68 | THEROBOT->setToolOffset(new_tool_offset); |
| 69 | } |
| 70 | } |
| 71 | } |
| 72 | } |
| 73 | |
| 74 | void ToolManager::on_get_public_data(void* argument) |
| 75 | { |
| 76 | PublicDataRequest* pdr = static_cast<PublicDataRequest*>(argument); |
| 77 | |
| 78 | if(!pdr->starts_with(tool_manager_checksum)) return; |
| 79 | |
| 80 | if(pdr->second_element_is(is_active_tool_checksum)) { |
| 81 | |
| 82 | // check that we control the given tool |
| 83 | bool managed = false; |
| 84 | for(auto t : tools) { |
| 85 | uint16_t n = t->get_name(); |
| 86 | if(pdr->third_element_is(n)) { |
| 87 | managed = true; |
| 88 | break; |
| 89 | } |
| 90 | } |
| 91 | |
| 92 | // we are not managing this tool so do not answer |
| 93 | if(!managed) return; |
| 94 | |
| 95 | pdr->set_data_ptr(&this->current_tool_name); |
| 96 | pdr->set_taken(); |
| 97 | |
| 98 | }else if(pdr->second_element_is(get_active_tool_checksum)) { |
| 99 | pdr->set_data_ptr(&this->active_tool); |
| 100 | pdr->set_taken(); |
| 101 | } |
| 102 | } |
| 103 | |
| 104 | void ToolManager::on_set_public_data(void* argument) |
| 105 | { |
| 106 | PublicDataRequest* pdr = static_cast<PublicDataRequest*>(argument); |
| 107 | |
| 108 | if(!pdr->starts_with(tool_manager_checksum)) return; |
| 109 | |
| 110 | // ok this is targeted at us, so change tools |
| 111 | //uint16_t tool_name= *static_cast<float*>(pdr->get_data_ptr()); |
| 112 | // TODO: fire a tool change gcode |
| 113 | //pdr->set_taken(); |
| 114 | } |
| 115 | |
| 116 | // Add a tool to the tool list |
| 117 | void ToolManager::add_tool(Tool* tool_to_add) |
| 118 | { |
| 119 | if(this->tools.size() == 0) { |
| 120 | tool_to_add->select(); |
| 121 | this->current_tool_name = tool_to_add->get_name(); |
| 122 | //send new_tool_offsets to robot |
| 123 | const float *new_tool_offset = tool_to_add->get_offset(); |
| 124 | THEROBOT->setToolOffset(new_tool_offset); |
| 125 | } else { |
| 126 | tool_to_add->deselect(); |
| 127 | } |
| 128 | this->tools.push_back( tool_to_add ); |
| 129 | } |
| 130 | |
| 131 | |
| 132 | |