A web server for monitoring and controlling a MakerBot Replicator over the USB host and ethernet.
Dependencies: IAP NTPClient RTC mbed-rtos mbed Socket lwip-sys lwip BurstSPI
Fork of LPC1768_Mini-DK by
makerbot.cpp
00001 // Copyright (c) 2013, jake (at) allaboutjake (dot) com 00002 // All rights reserved. 00003 // 00004 // Redistribution and use in source and binary forms, with or without 00005 // modification, are permitted provided that the following conditions are met: 00006 // * Redistributions of source code must retain the above copyright 00007 // notice, this list of conditions and the following disclaimer. 00008 // * Redistributions in binary form must reproduce the above copyright 00009 // notice, this list of conditions and the following disclaimer in the 00010 // documentation and/or other materials provided with the distribution. 00011 // * The name of the author and/or copyright holder nor the 00012 // names of its contributors may be used to endorse or promote products 00013 // derived from this software without specific prior written permission. 00014 // 00015 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 00016 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 00017 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 00018 // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER, AUTHOR, OR ANY CONTRIBUTORS 00019 // BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 00020 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 00021 // GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 00022 // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 00023 // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 00024 // OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00025 00026 // DESCRIPTION OF FILE: 00027 // 00028 // This file contains a C++ object for communicating with a Makerbot over a USB 00029 // host serial. 00030 // 00031 00032 #include "makerbot.h" 00033 #include "mbed.h" 00034 00035 // Constructor 00036 Makerbot::Makerbot(USBHostSerial* hostSerial) { 00037 // Save the serial object 00038 serial = hostSerial; 00039 00040 // Initialize caced values to NULL/zero, etc. 00041 machineName=NULL; 00042 buildName=NULL; 00043 machineVersion=0.0; 00044 } 00045 00046 // Helper function to calculate the iButton CRC of a buffer 00047 uint8_t Makerbot::CalculateCRC(uint8_t* data, int length) { 00048 uint8_t val = 0; 00049 for (int x=0; x<length; x++) { 00050 val = crctab[val ^ data[x]]; 00051 } 00052 return val; 00053 } 00054 00055 // Send a packet with the given payload. 00056 int Makerbot::send_packet(uint8_t* payload, int payload_length) { 00057 // Verify payload length within bounds 00058 if (payload_length > MAXIMUM_PAYLOAD_LENGTH) 00059 return PACKET_TOO_BIG; 00060 00061 // Calculate teh checksum 00062 uint8_t checksum = CalculateCRC(payload, payload_length); 00063 00064 // Send the data 00065 serial->putch(HEADER); 00066 serial->putch(payload_length); 00067 serial->writeBuffer(payload, payload_length); 00068 serial->putch(checksum); 00069 00070 // Return 0 for success; 00071 return 0; 00072 } 00073 00074 00075 // Receive a packet and fill the payload buffer with the packet's payload. 00076 int Makerbot::recv_packet(uint8_t* payload, int buffer_length) { 00077 // Wait for a packet 00078 while (!serial->available()) { Thread::wait(100); } 00079 00080 // Check for the header 00081 if (serial->getch() != HEADER) { 00082 DBG_INFO("recv_packet error: Header not found"); 00083 return -1; 00084 } 00085 00086 // Get the payload length 00087 int length = serial->getch(); 00088 if (length > buffer_length) { 00089 DBG_INFO("recv_packet: Payload is larger then available buffer"); 00090 return -1; 00091 } 00092 00093 // Get the data with the given length 00094 for (int x=0; x<length; x++) { 00095 payload[x] = serial->getch(); 00096 } 00097 00098 // Get the checksum and verify the data we got matches the checksum 00099 int checksum = serial->getch(); 00100 if (checksum < 0 || checksum != CalculateCRC(payload, length)) { 00101 DBG_INFO("recv_packet: Checksum error"); 00102 return -1; 00103 } 00104 00105 // Return the length of the packet we received. 00106 return length; 00107 } 00108 00109 // Display a message to to the Makerbot's LCD 00110 int Makerbot::displayMessageToLCD(uint8_t options, uint8_t xPos, uint8_t yPos, uint8_t timeout, char* message) { 00111 // Get the length of the message 00112 int msgLen = strlen(message); 00113 00114 // The packet uses 5 bytes for the command and the other parameters 00115 // Make sure there is enough remaining space for the given message. 00116 if (msgLen > MAXIMUM_PAYLOAD_LENGTH - 5) { 00117 DBG_INFO("displayMessageToLCD: error: message too long."); 00118 return -1; 00119 } 00120 00121 // Build the packet 00122 uint8_t packet[MAXIMUM_PAYLOAD_LENGTH+3]; 00123 packet[0] = 149; // LCD 00124 packet[1] = options; 00125 packet[2] = xPos; 00126 packet[3] = yPos; 00127 packet[4] = timeout; 00128 for (int x=0; x<msgLen; x++) { 00129 packet[5+x] = message[x]; 00130 } 00131 packet[5+msgLen] = 0x00; //terminate 00132 00133 // Send the packet and receive the response 00134 mutex.lock(); 00135 send_packet(packet, msgLen+6); 00136 uint8_t response[MAXIMUM_PAYLOAD_LENGTH]; 00137 recv_packet(response, MAXIMUM_PAYLOAD_LENGTH); 00138 mutex.unlock(); 00139 00140 // Return 0 if success (easier for error handling since SUCCESS is not zero) 00141 if (response[0]==SUCCESS) return 0; 00142 00143 // Otherwise return the actual response code. 00144 return response[0]; 00145 } 00146 00147 // Get the version of the makerbot 00148 float Makerbot::getMakerbotVersion() { 00149 //If we have a cache of the version, just return it 00150 if (machineVersion) return machineVersion; 00151 00152 //Build the packet 00153 uint8_t packet[3]; 00154 packet[0]=0x00; 00155 packet[1]=0x00; 00156 packet[2]=0x64; 00157 00158 //Send the packet and get the response packet 00159 mutex.lock(); 00160 send_packet(packet, 3); 00161 uint8_t response[MAXIMUM_PAYLOAD_LENGTH]; 00162 int length = recv_packet(response, MAXIMUM_PAYLOAD_LENGTH); 00163 mutex.unlock(); 00164 00165 //Make sure we got back the right payload length 00166 if (length != 3) { 00167 DBG_INFO("getMakerbotVersion: Expected 2 byte response. got %d", length); 00168 return 0; //Version=0 is an error in this case 00169 } 00170 00171 //Convert the version to a float and return 00172 uint16_t versionData = *((uint16_t*)&response[1]); 00173 machineVersion = ((float)(versionData / 100)) + (((float)(versionData % 100)) / 10); 00174 return machineVersion; 00175 } 00176 00177 char* Makerbot::getBuildName() { 00178 // One byte commend 00179 uint8_t cmd = 0x14; // 20 = Pause/Resume command 00180 00181 // Send the Packet, get the response 00182 mutex.lock(); 00183 send_packet(&cmd, 1); 00184 uint8_t response[MAXIMUM_PAYLOAD_LENGTH]; 00185 int length = recv_packet(response, MAXIMUM_PAYLOAD_LENGTH); 00186 mutex.unlock(); 00187 00188 if (length > 1 && response[0]==SUCCESS) { 00189 //if we have an old build name, trash it 00190 if (buildName) { 00191 free(buildName); 00192 buildName = NULL; 00193 } 00194 00195 buildName = (char*)malloc(length-1); 00196 strncpy(buildName, (char*)response+1,length-1); 00197 return buildName; 00198 } 00199 00200 return NULL; 00201 } 00202 00203 // Start a print job from the SD card with the given filename 00204 int Makerbot::playbackCapture(char* filename) { 00205 // Build the packet 00206 uint8_t packet[14]; 00207 packet[0]=0x10; //Playback = 16 00208 00209 // Copy over the filename into the packet one byte at a time 00210 // TODO: replace with memcpy? 00211 int length = 1; 00212 for (int x=0; x<12; x++) { 00213 packet[x+1] = filename[x]; 00214 length++; 00215 if (filename[x]==0) break; 00216 } 00217 00218 // Send the packet, get the response 00219 mutex.lock(); 00220 send_packet(packet, length); 00221 uint8_t response[MAXIMUM_PAYLOAD_LENGTH]; 00222 int recvLength = recv_packet(response, MAXIMUM_PAYLOAD_LENGTH); 00223 mutex.unlock(); 00224 00225 // Check for response success 00226 if (recvLength > 0 && response[0] == SUCCESS) { 00227 return 0; 00228 } 00229 00230 //If we got here, there was a problem somewhere 00231 return -1; 00232 } 00233 00234 // Get machine name from bot's EEPROM 00235 char* Makerbot::getMachineName() { 00236 // If we have a cached name, return it 00237 if (machineName) return machineName; 00238 00239 // Build the request packet 00240 uint8_t payload[4]; 00241 payload[0]= 0xC; //read eprom = 12 00242 *((uint16_t*)&payload[1])= MACHINE_NAME_OFFSET; 00243 payload[3]= 16; //length of machine name; 00244 00245 // Send the packet, wait for response. 00246 mutex.lock(); 00247 send_packet(payload, 4); 00248 uint8_t response[MAXIMUM_PAYLOAD_LENGTH]; 00249 int length = recv_packet(response, MAXIMUM_PAYLOAD_LENGTH); 00250 mutex.unlock(); 00251 00252 // Return 00253 if (length > 0 && response[0] == SUCCESS) { 00254 //create a buffer to hold the machine name; 00255 machineName = (char*)malloc(length+1); 00256 00257 memcpy(machineName, response+1, length-1); 00258 machineName[length-2] = '\0'; //terminate 00259 00260 return machineName; 00261 } 00262 00263 // Get machine name failed for some reason 00264 DBG_INFO("getMachineName: unsuccessful"); 00265 return NULL; 00266 } 00267 00268 int Makerbot::getEEPROMByte(uint16_t offset) { 00269 // Build the request packet 00270 uint8_t payload[4]; 00271 payload[0]= 0xC; //read eprom = 12 00272 *((uint16_t*)&payload[1])= offset; 00273 payload[3]= 1; //length of tool count (byte) 00274 00275 // Send the packet, wait for response. 00276 mutex.lock(); 00277 send_packet(payload, 4); 00278 uint8_t response[MAXIMUM_PAYLOAD_LENGTH]; 00279 int length = recv_packet(response, MAXIMUM_PAYLOAD_LENGTH); 00280 mutex.unlock(); 00281 00282 // Return 00283 if (length == 2 && response[0] == SUCCESS) { 00284 return response[1]; 00285 } 00286 00287 // Get machine name failed for some reason 00288 DBG_INFO("getEEPROMByte: unsuccessful"); 00289 return 0; 00290 } 00291 00292 // Get tool count from bot's EEPROM 00293 int Makerbot::getToolCount() { 00294 return getEEPROMByte(TOOL_COUNT_OFFSET); 00295 } 00296 00297 int Makerbot::hasPlatform() { 00298 return getEEPROMByte(HBP_PRESENT_OFFSET); 00299 } 00300 00301 // Flush the buffer. Used to synchronize the stream 00302 void Makerbot::flushInputChannel() { 00303 mutex.lock(); 00304 while (1) { 00305 if (serial->available()) 00306 serial->getch(); 00307 else 00308 break; 00309 } 00310 mutex.unlock(); 00311 } 00312 00313 // Send pause/resume command 00314 int Makerbot::pauseResume() { 00315 // One byte commend 00316 uint8_t cmd = 0x08; // 8 = Pause/Resume command 00317 00318 // Send the Packet, get the response 00319 mutex.lock(); 00320 send_packet(&cmd, 1); 00321 uint8_t response[MAXIMUM_PAYLOAD_LENGTH]; 00322 int length = recv_packet(response, MAXIMUM_PAYLOAD_LENGTH); 00323 mutex.unlock(); 00324 00325 // Return success status 00326 if (length == 1 && response[1] == SUCCESS) return 0; 00327 return -1; 00328 } 00329 00330 // Send command to cancel build command 00331 int Makerbot::abortImmediately() { 00332 // One byte commend 00333 uint8_t cmd = 0x07; // 7 = Abort command 00334 00335 // Send the Packet, get the response 00336 mutex.lock(); 00337 send_packet(&cmd, 1); 00338 uint8_t response[MAXIMUM_PAYLOAD_LENGTH]; 00339 int length = recv_packet(response, MAXIMUM_PAYLOAD_LENGTH); 00340 mutex.unlock(); 00341 00342 // Return success status 00343 if (length == 1 && response[1] == SUCCESS) return 0; 00344 return -1; 00345 } 00346 00347 // Retrieve the current temperature for the given tool 00348 int Makerbot::getToolTemperature(uint8_t toolIndex) { 00349 // One byte commend 00350 uint8_t payload[3]; 00351 payload[0] = 0x0A; // 7 = Abort command 00352 payload[1] = toolIndex; 00353 payload[2] = 0x2; //get toolhead temperature 00354 00355 // Send the Packet, get the response 00356 mutex.lock(); 00357 send_packet(payload, 3); 00358 uint8_t response[MAXIMUM_PAYLOAD_LENGTH]; 00359 int length = recv_packet(response, MAXIMUM_PAYLOAD_LENGTH); 00360 mutex.unlock(); 00361 00362 00363 // Return success status 00364 if (length == 3 && response[0] == SUCCESS) { 00365 return *((uint16_t*)&response[1]); 00366 } 00367 return -1; 00368 } 00369 00370 // Return the setpoint for the given tool 00371 int Makerbot::getToolSetPoint(uint8_t toolIndex) { 00372 // One byte commend 00373 uint8_t payload[3]; 00374 payload[0] = 0x0A; // 7 = Abort command 00375 payload[1] = toolIndex; 00376 payload[2] = 0x20; //get toolhead set point 00377 00378 // Send the Packet, get the response 00379 mutex.lock(); 00380 send_packet(payload, 3); 00381 uint8_t response[MAXIMUM_PAYLOAD_LENGTH]; 00382 int length = recv_packet(response, MAXIMUM_PAYLOAD_LENGTH); 00383 mutex.unlock(); 00384 00385 00386 // Return success status 00387 if (length == 3 && response[0] == SUCCESS) { 00388 return *((uint16_t*)&response[1]); 00389 } 00390 return -1; 00391 } 00392 00393 00394 // Retrieve the Platform temperature for the given tool 00395 int Makerbot::getPlatformTemperature(uint8_t toolIndex) { 00396 // One byte commend 00397 uint8_t payload[3]; 00398 payload[0] = 0x0A; // 7 = Abort command 00399 payload[1] = toolIndex; 00400 payload[2] = 0x1E; //get toolhead temperature 00401 00402 // Send the Packet, get the response 00403 mutex.lock(); 00404 send_packet(payload, 3); 00405 uint8_t response[MAXIMUM_PAYLOAD_LENGTH]; 00406 int length = recv_packet(response, MAXIMUM_PAYLOAD_LENGTH); 00407 mutex.unlock(); 00408 00409 00410 // Return success status 00411 if (length == 3 && response[0] == SUCCESS) { 00412 return *((uint16_t*)&response[1]); 00413 } 00414 return -1; 00415 } 00416 00417 // Return the platform setpoint for the given tool 00418 int Makerbot::getPlatformSetPoint(uint8_t toolIndex) { 00419 // One byte commend 00420 uint8_t payload[3]; 00421 payload[0] = 0x0A; // 7 = Abort command 00422 payload[1] = toolIndex; 00423 payload[2] = 0x21; //get toolhead set point 00424 00425 // Send the Packet, get the response 00426 mutex.lock(); 00427 send_packet(payload, 3); 00428 uint8_t response[MAXIMUM_PAYLOAD_LENGTH]; 00429 int length = recv_packet(response, MAXIMUM_PAYLOAD_LENGTH); 00430 mutex.unlock(); 00431 00432 00433 // Return success status 00434 if (length == 3 && response[0] == SUCCESS) { 00435 return *((uint16_t*)&response[1]); 00436 } 00437 return -1; 00438 } 00439 00440 // Get the build state. Note that we added a "BUILD_STATE_ERROR" value to detect errors in the return value. 00441 Makerbot::MakerbotBuildState Makerbot::getBuildState() { 00442 MakerbotBuildState state; 00443 00444 // One byte command 00445 uint8_t cmd = 0x18; //24=get build statistics 00446 00447 // Send the packet, get the response 00448 mutex.lock(); 00449 send_packet(&cmd, 1); 00450 uint8_t response[MAXIMUM_PAYLOAD_LENGTH]; 00451 int length = recv_packet(response, MAXIMUM_PAYLOAD_LENGTH); 00452 mutex.unlock(); 00453 00454 00455 // Check for success 00456 if (response[0] == SUCCESS) { 00457 // Copy the data to the return struct & return 00458 memcpy(&state, response+1, sizeof(MakerbotBuildState)); 00459 return state; 00460 } 00461 00462 // Otherwise return error state 00463 state.build_state = BUILD_STATE_ERROR; //error 00464 return state; 00465 } 00466 00467 char* Makerbot::humanReadableBuildState(Makerbot::MakerbotBuildState state) { 00468 switch (state.build_state) { 00469 case Makerbot::NO_BUILD: 00470 return "No Build"; 00471 00472 case Makerbot::BUILD_RUNNING: 00473 return "Build Running"; 00474 00475 case Makerbot::BUILD_FINISHED_NORMALLY: 00476 return "Build Finished"; 00477 00478 case Makerbot::BUILD_PAUSED: 00479 return "Build Paused"; 00480 00481 case Makerbot::BUILD_CANCELLED: 00482 return "Build Cancelled"; 00483 00484 case Makerbot::BUILD_SLEEPING: 00485 return "Build Sleeping"; 00486 00487 case Makerbot::BUILD_STATE_ERROR: 00488 default: 00489 return "Unknown build status or status error"; 00490 } 00491 } 00492 00493 // Clean up any objects created, just for good measure. 00494 Makerbot::~Makerbot() { 00495 if (machineName) { 00496 free(machineName); 00497 } 00498 if (buildName) { 00499 free(buildName); 00500 } 00501 }
Generated on Tue Jul 12 2022 17:52:03 by 1.7.2