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 Frank Vannieuwkerke

Makerbot Server for LPC1768 Copyright (c) 2013, jake (at) allaboutjake (dot) com All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

  • Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
  • Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
  • The name of the author and/or copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER, AUTHOR, OR ANY CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

Warnings:

This is not a commercial product or a hardened and secure network appliance. It is intended as a thought experiment or proof of concept and should not be relied upon in any way. Always operate your 3D printer in a safe and controlled manner.

Do not connect this directly to the exposed internet. It is intended to be behind a secure firewall (and NAT) such that it will only accept commands from the local network. Imagine how much fun a hacker could have instructing your 3D printer to continually print Standford bunnies. Well it could be much worse then that- a malicious user could send commands that could crash your machine (both in the software sense, as well as in the "smash your moving parts against the side of the machine repeatedly sense), overheat your extruders, cause your build plate to catch fire, and do severe damage to the machine, any surrounding building and propery. You have been warned.

Never print unattended and be ready to step in and stop the machine if something goes wrong. Keep in mind, a 3D printer has heaters that are operating at high temperatures, and if something starts to burn, it could cause damage to the machine, other property, and/or hurt yourself, pets, or others.

You should understand what you are doing. The source code here is not intended as a finished product or set of step by step instructions. You should engineer your own solution, which may wind up being better than mine.

Proceed at your own risk. You've been warned. (Several times) If you break your Makerbot, burn your house down, or injure yourself or others, I take no responsibility.

Introduction

I've been working on a side project to solve the "last mile" problem for people wanting to print from the network on their bots. I feel like the first half of the problem is solved with the FlashAir- getting the files to the card. The next step is a lightweight way of sending the "play back capture" command to the bot.

I looked around for a microcontroller platform that supports both networking and can function as a USB host. I happened to have an mbed (mbed) on hand that fit the bill. The mbed also has a working online toolchain (you need to own an mbed to gain access to the compiler). Some people don't like the online development environment, but I'm a fan of "working" and "Mac compatible." It was a good start, but cost wise, you would need an mbed LPC1768 module and some sort of carrier board that has both USB host and ethernet, or rig up your own connector solution. I happened to also have a Seedstudio mbed shield carrier board. This provides ethernet and USB connectors, but is another $25, putting the solution at around $75.

I also had an LPC1768 development board here called the "Mini-DK2". It has a USB host and a wired ethernet connector on board (search ebay if you're interested). It's a single-board solution that costs only $32 (and for $40 you can get one with a touchscreen) Its the cheapest development board I've seen with both USB host and an ethernet connector. I considered RasPi, but I'm not on that bandwagon. Since I had the Mini-DK2 on hand from another project that never went anywhere, I moved from the mbed module and carrier board to the DK2.

The mbed environment can compile binaries that work on the DK2 (again, you need to own at least one 1768 mbed already to get a license to use the compiler), and the mbed libraries provide some nice features. A USB Host library and and Ethernet library were readily available. The USBHost library didn't quite work out of the box. It took some time and more learning about the USB protocols than I would have liked, but I have the board communicating over the USB Host and the Makerbot.

Changes to stock mbed libraries

Many libraries are imported, but then converted to folders as to unlink them.

mbed provides a USHost library that includes a USBHostSerial object for connecting to CDC serial devices. Unfortunately, it did not work for me out of the box. I spent some time learning about USB protocols. One good reference is [Jan Axelson's Lakeview Research](http://www.lvr.com/usb_virtual_com_port.htm) discussion about CDC.

I found that the stock library was sending the control transfers to Interface 1. From what I understand, the control transfers needed to go to interface 0. I modified the USBHostSerial library to correct this, and the serial port interface came to life.

Next, I found that I wasn't able to get reliable communication. I traced it to what I think is an odd C++ inheritance and override problem. The USBHostSerial class implements the Stream interface, allowing printf/scanf operations. This is done by overriding the virtual _getc and _putc methods. Unfortunately, and for a reason I can't understand, these methods were not being called consistently. Sometimes they would work, but other times they would not. My solution was to implement transmit/receive methods with different names, and since the names were different, they seemed to get called consistently. I'd like to learn exactly what's going on here, but I don't feel like debugging it for academic purposes when it works just fine with the added methods.

Usage

Connect up your chosen dev board to power, ethernet and the USB host to the Makerbot's USB cable. The Mini-DK uses a USB-OTG adapter for the USB host. If you're using a Mini-DK board with an LCD, it will inform you of it's IP address on the display. This means it is now listening for a connection on port 7654.

If you are using an mbed dev board, or a Mini-DK without a display, the message will be directed to the serial console. Connect your computer to the appropriate port at a baud rate of 115200 to see the messages.

Use a telnet client to connect to the given IP address at port 7654. Telnet clients typically revert to "line mode" on ports other than 21. This means you get a local echo and the command isn't sent until you press enter.

Once connected, you can send the following commands:

A <username>:<password> : Set a username & password for the web interface and the telnet interface. Use the format shown with a colon separating the username from the password.

V : Print the version and Makerbot name, as well as the local firmware version (the Makerbot_Server firmware as discussed here).

B <filename.x3g> : Build from SD the given filename. According tot he protocol spec, this command is limited to 12 characters, so 8.3 filenames only.

P : Pause an active build

R : Resume active build

C : Cancel build- note that this immediately halts the build and does not clear the build area. You might want to pause the build first, and then cancel shortly after to make sure the nozzle isn't left hot and in contact with a printed part.

S : Print build status, tool and platform temps

Q : Quit and logout

The Mini-DK has two onboard buttons (besides the ISP and reset buttons). Currently one button will trigger a pause (if the Makerbot is printing) and the other will resume (if the Makerbot it paused)

Compiling

Edit "Target.h" to set whether you're building for an MBED module or the Mini-DK2

Installation

If you are using a mbed, then you can simply load the BIN file to the mbed using the mass storage bootloader. The mbed mounts as if it were a USB thumbdrive, and you copy the BIN file to the drive. After a reset, you're running the installed firmware.

The MiniDK has a serial bootloader. You connect to this bootloader from the "top" USB connector (not the USB host one). Hold down the ISP button and then tap the reset button and then release the ISP button to put it into programming mode. I use [lpc21isp](http://sourceforge.net/projects/lpc21isp/) to load the binary. The other option is FlashMagic, which uses HEX files, so you'll need to use some sort of bin2hex utility to convert the firmware file if you use this utility. I can't really say if/how this works, as I don't use this method. See this (http://mbed.org/users/frankvnk/notebook/lpc1768-mini-dk/) for more info.

Credits

Some credits, where credit is due.

EthernetInterface - modified to include PHY code for both the MiniDK2 and MBED based on selected #definitions

Mini-DK - Thanks for Frank and Erik for doing all the heavy lifting getting the MBED compiler and libraries and peripherals working on the Mini-DK2

NTP Client - Thanks to Donatien for this library to set the clock over the network

RTC - Thanks to Erik for the RTC library. I've got it in my project, but I don't think I'm using it for anything (yet).

SimpleSocket - Thanks to Yamaguchi-san. Modified slightly to take out references to EthernetInterface::init() and ::getIPAddress(). For some reason these don't like to be called in a thread.

JPEGCamera - Thanks again to Yamaguchi-san. Modified to output the JPEG binary over a socket rather than to a file descriptor.

USBHost - modified as noted above

IAP - Thanks to Okano-san. Pulled out of the Mini-DK folder so that I could link it back to the base repository at the root level.

Committer:
jakeb
Date:
Fri Aug 23 21:45:08 2013 +0000
Revision:
15:688b3e3958fd
Initial commit of software v0.2;

Who changed what in which revision?

UserRevisionLine numberNew contents of line
jakeb 15:688b3e3958fd 1 // Copyright (c) 2013, jake (at) allaboutjake (dot) com
jakeb 15:688b3e3958fd 2 // All rights reserved.
jakeb 15:688b3e3958fd 3 //
jakeb 15:688b3e3958fd 4 // Redistribution and use in source and binary forms, with or without
jakeb 15:688b3e3958fd 5 // modification, are permitted provided that the following conditions are met:
jakeb 15:688b3e3958fd 6 // * Redistributions of source code must retain the above copyright
jakeb 15:688b3e3958fd 7 // notice, this list of conditions and the following disclaimer.
jakeb 15:688b3e3958fd 8 // * Redistributions in binary form must reproduce the above copyright
jakeb 15:688b3e3958fd 9 // notice, this list of conditions and the following disclaimer in the
jakeb 15:688b3e3958fd 10 // documentation and/or other materials provided with the distribution.
jakeb 15:688b3e3958fd 11 // * The name of the author and/or copyright holder nor the
jakeb 15:688b3e3958fd 12 // names of its contributors may be used to endorse or promote products
jakeb 15:688b3e3958fd 13 // derived from this software without specific prior written permission.
jakeb 15:688b3e3958fd 14 //
jakeb 15:688b3e3958fd 15 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
jakeb 15:688b3e3958fd 16 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
jakeb 15:688b3e3958fd 17 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
jakeb 15:688b3e3958fd 18 // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER, AUTHOR, OR ANY CONTRIBUTORS
jakeb 15:688b3e3958fd 19 // BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
jakeb 15:688b3e3958fd 20 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
jakeb 15:688b3e3958fd 21 // GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
jakeb 15:688b3e3958fd 22 // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
jakeb 15:688b3e3958fd 23 // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
jakeb 15:688b3e3958fd 24 // OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
jakeb 15:688b3e3958fd 25
jakeb 15:688b3e3958fd 26 // DESCRIPTION OF FILE:
jakeb 15:688b3e3958fd 27 //
jakeb 15:688b3e3958fd 28 // This file contains a C++ object for communicating with a Makerbot over a USB
jakeb 15:688b3e3958fd 29 // host serial.
jakeb 15:688b3e3958fd 30 //
jakeb 15:688b3e3958fd 31
jakeb 15:688b3e3958fd 32 #include "makerbot.h"
jakeb 15:688b3e3958fd 33 #include "mbed.h"
jakeb 15:688b3e3958fd 34
jakeb 15:688b3e3958fd 35 // Constructor
jakeb 15:688b3e3958fd 36 Makerbot::Makerbot(USBHostSerial* hostSerial) {
jakeb 15:688b3e3958fd 37 // Save the serial object
jakeb 15:688b3e3958fd 38 serial = hostSerial;
jakeb 15:688b3e3958fd 39
jakeb 15:688b3e3958fd 40 // Initialize caced values to NULL/zero, etc.
jakeb 15:688b3e3958fd 41 machineName=NULL;
jakeb 15:688b3e3958fd 42 buildName=NULL;
jakeb 15:688b3e3958fd 43 machineVersion=0.0;
jakeb 15:688b3e3958fd 44 }
jakeb 15:688b3e3958fd 45
jakeb 15:688b3e3958fd 46 // Helper function to calculate the iButton CRC of a buffer
jakeb 15:688b3e3958fd 47 uint8_t Makerbot::CalculateCRC(uint8_t* data, int length) {
jakeb 15:688b3e3958fd 48 uint8_t val = 0;
jakeb 15:688b3e3958fd 49 for (int x=0; x<length; x++) {
jakeb 15:688b3e3958fd 50 val = crctab[val ^ data[x]];
jakeb 15:688b3e3958fd 51 }
jakeb 15:688b3e3958fd 52 return val;
jakeb 15:688b3e3958fd 53 }
jakeb 15:688b3e3958fd 54
jakeb 15:688b3e3958fd 55 // Send a packet with the given payload.
jakeb 15:688b3e3958fd 56 int Makerbot::send_packet(uint8_t* payload, int payload_length) {
jakeb 15:688b3e3958fd 57 // Verify payload length within bounds
jakeb 15:688b3e3958fd 58 if (payload_length > MAXIMUM_PAYLOAD_LENGTH)
jakeb 15:688b3e3958fd 59 return PACKET_TOO_BIG;
jakeb 15:688b3e3958fd 60
jakeb 15:688b3e3958fd 61 // Calculate teh checksum
jakeb 15:688b3e3958fd 62 uint8_t checksum = CalculateCRC(payload, payload_length);
jakeb 15:688b3e3958fd 63
jakeb 15:688b3e3958fd 64 // Send the data
jakeb 15:688b3e3958fd 65 serial->putch(HEADER);
jakeb 15:688b3e3958fd 66 serial->putch(payload_length);
jakeb 15:688b3e3958fd 67 serial->writeBuffer(payload, payload_length);
jakeb 15:688b3e3958fd 68 serial->putch(checksum);
jakeb 15:688b3e3958fd 69
jakeb 15:688b3e3958fd 70 // Return 0 for success;
jakeb 15:688b3e3958fd 71 return 0;
jakeb 15:688b3e3958fd 72 }
jakeb 15:688b3e3958fd 73
jakeb 15:688b3e3958fd 74
jakeb 15:688b3e3958fd 75 // Receive a packet and fill the payload buffer with the packet's payload.
jakeb 15:688b3e3958fd 76 int Makerbot::recv_packet(uint8_t* payload, int buffer_length) {
jakeb 15:688b3e3958fd 77 // Wait for a packet
jakeb 15:688b3e3958fd 78 while (!serial->available()) { Thread::wait(100); }
jakeb 15:688b3e3958fd 79
jakeb 15:688b3e3958fd 80 // Check for the header
jakeb 15:688b3e3958fd 81 if (serial->getch() != HEADER) {
jakeb 15:688b3e3958fd 82 DBG_INFO("recv_packet error: Header not found");
jakeb 15:688b3e3958fd 83 return -1;
jakeb 15:688b3e3958fd 84 }
jakeb 15:688b3e3958fd 85
jakeb 15:688b3e3958fd 86 // Get the payload length
jakeb 15:688b3e3958fd 87 int length = serial->getch();
jakeb 15:688b3e3958fd 88 if (length > buffer_length) {
jakeb 15:688b3e3958fd 89 DBG_INFO("recv_packet: Payload is larger then available buffer");
jakeb 15:688b3e3958fd 90 return -1;
jakeb 15:688b3e3958fd 91 }
jakeb 15:688b3e3958fd 92
jakeb 15:688b3e3958fd 93 // Get the data with the given length
jakeb 15:688b3e3958fd 94 for (int x=0; x<length; x++) {
jakeb 15:688b3e3958fd 95 payload[x] = serial->getch();
jakeb 15:688b3e3958fd 96 }
jakeb 15:688b3e3958fd 97
jakeb 15:688b3e3958fd 98 // Get the checksum and verify the data we got matches the checksum
jakeb 15:688b3e3958fd 99 int checksum = serial->getch();
jakeb 15:688b3e3958fd 100 if (checksum < 0 || checksum != CalculateCRC(payload, length)) {
jakeb 15:688b3e3958fd 101 DBG_INFO("recv_packet: Checksum error");
jakeb 15:688b3e3958fd 102 return -1;
jakeb 15:688b3e3958fd 103 }
jakeb 15:688b3e3958fd 104
jakeb 15:688b3e3958fd 105 // Return the length of the packet we received.
jakeb 15:688b3e3958fd 106 return length;
jakeb 15:688b3e3958fd 107 }
jakeb 15:688b3e3958fd 108
jakeb 15:688b3e3958fd 109 // Display a message to to the Makerbot's LCD
jakeb 15:688b3e3958fd 110 int Makerbot::displayMessageToLCD(uint8_t options, uint8_t xPos, uint8_t yPos, uint8_t timeout, char* message) {
jakeb 15:688b3e3958fd 111 // Get the length of the message
jakeb 15:688b3e3958fd 112 int msgLen = strlen(message);
jakeb 15:688b3e3958fd 113
jakeb 15:688b3e3958fd 114 // The packet uses 5 bytes for the command and the other parameters
jakeb 15:688b3e3958fd 115 // Make sure there is enough remaining space for the given message.
jakeb 15:688b3e3958fd 116 if (msgLen > MAXIMUM_PAYLOAD_LENGTH - 5) {
jakeb 15:688b3e3958fd 117 DBG_INFO("displayMessageToLCD: error: message too long.");
jakeb 15:688b3e3958fd 118 return -1;
jakeb 15:688b3e3958fd 119 }
jakeb 15:688b3e3958fd 120
jakeb 15:688b3e3958fd 121 // Build the packet
jakeb 15:688b3e3958fd 122 uint8_t packet[MAXIMUM_PAYLOAD_LENGTH+3];
jakeb 15:688b3e3958fd 123 packet[0] = 149; // LCD
jakeb 15:688b3e3958fd 124 packet[1] = options;
jakeb 15:688b3e3958fd 125 packet[2] = xPos;
jakeb 15:688b3e3958fd 126 packet[3] = yPos;
jakeb 15:688b3e3958fd 127 packet[4] = timeout;
jakeb 15:688b3e3958fd 128 for (int x=0; x<msgLen; x++) {
jakeb 15:688b3e3958fd 129 packet[5+x] = message[x];
jakeb 15:688b3e3958fd 130 }
jakeb 15:688b3e3958fd 131 packet[5+msgLen] = 0x00; //terminate
jakeb 15:688b3e3958fd 132
jakeb 15:688b3e3958fd 133 // Send the packet and receive the response
jakeb 15:688b3e3958fd 134 mutex.lock();
jakeb 15:688b3e3958fd 135 send_packet(packet, msgLen+6);
jakeb 15:688b3e3958fd 136 uint8_t response[MAXIMUM_PAYLOAD_LENGTH];
jakeb 15:688b3e3958fd 137 recv_packet(response, MAXIMUM_PAYLOAD_LENGTH);
jakeb 15:688b3e3958fd 138 mutex.unlock();
jakeb 15:688b3e3958fd 139
jakeb 15:688b3e3958fd 140 // Return 0 if success (easier for error handling since SUCCESS is not zero)
jakeb 15:688b3e3958fd 141 if (response[0]==SUCCESS) return 0;
jakeb 15:688b3e3958fd 142
jakeb 15:688b3e3958fd 143 // Otherwise return the actual response code.
jakeb 15:688b3e3958fd 144 return response[0];
jakeb 15:688b3e3958fd 145 }
jakeb 15:688b3e3958fd 146
jakeb 15:688b3e3958fd 147 // Get the version of the makerbot
jakeb 15:688b3e3958fd 148 float Makerbot::getMakerbotVersion() {
jakeb 15:688b3e3958fd 149 //If we have a cache of the version, just return it
jakeb 15:688b3e3958fd 150 if (machineVersion) return machineVersion;
jakeb 15:688b3e3958fd 151
jakeb 15:688b3e3958fd 152 //Build the packet
jakeb 15:688b3e3958fd 153 uint8_t packet[3];
jakeb 15:688b3e3958fd 154 packet[0]=0x00;
jakeb 15:688b3e3958fd 155 packet[1]=0x00;
jakeb 15:688b3e3958fd 156 packet[2]=0x64;
jakeb 15:688b3e3958fd 157
jakeb 15:688b3e3958fd 158 //Send the packet and get the response packet
jakeb 15:688b3e3958fd 159 mutex.lock();
jakeb 15:688b3e3958fd 160 send_packet(packet, 3);
jakeb 15:688b3e3958fd 161 uint8_t response[MAXIMUM_PAYLOAD_LENGTH];
jakeb 15:688b3e3958fd 162 int length = recv_packet(response, MAXIMUM_PAYLOAD_LENGTH);
jakeb 15:688b3e3958fd 163 mutex.unlock();
jakeb 15:688b3e3958fd 164
jakeb 15:688b3e3958fd 165 //Make sure we got back the right payload length
jakeb 15:688b3e3958fd 166 if (length != 3) {
jakeb 15:688b3e3958fd 167 DBG_INFO("getMakerbotVersion: Expected 2 byte response. got %d", length);
jakeb 15:688b3e3958fd 168 return 0; //Version=0 is an error in this case
jakeb 15:688b3e3958fd 169 }
jakeb 15:688b3e3958fd 170
jakeb 15:688b3e3958fd 171 //Convert the version to a float and return
jakeb 15:688b3e3958fd 172 uint16_t versionData = *((uint16_t*)&response[1]);
jakeb 15:688b3e3958fd 173 machineVersion = ((float)(versionData / 100)) + (((float)(versionData % 100)) / 10);
jakeb 15:688b3e3958fd 174 return machineVersion;
jakeb 15:688b3e3958fd 175 }
jakeb 15:688b3e3958fd 176
jakeb 15:688b3e3958fd 177 char* Makerbot::getBuildName() {
jakeb 15:688b3e3958fd 178 // One byte commend
jakeb 15:688b3e3958fd 179 uint8_t cmd = 0x14; // 20 = Pause/Resume command
jakeb 15:688b3e3958fd 180
jakeb 15:688b3e3958fd 181 // Send the Packet, get the response
jakeb 15:688b3e3958fd 182 mutex.lock();
jakeb 15:688b3e3958fd 183 send_packet(&cmd, 1);
jakeb 15:688b3e3958fd 184 uint8_t response[MAXIMUM_PAYLOAD_LENGTH];
jakeb 15:688b3e3958fd 185 int length = recv_packet(response, MAXIMUM_PAYLOAD_LENGTH);
jakeb 15:688b3e3958fd 186 mutex.unlock();
jakeb 15:688b3e3958fd 187
jakeb 15:688b3e3958fd 188 if (length > 1 && response[0]==SUCCESS) {
jakeb 15:688b3e3958fd 189 //if we have an old build name, trash it
jakeb 15:688b3e3958fd 190 if (buildName) {
jakeb 15:688b3e3958fd 191 free(buildName);
jakeb 15:688b3e3958fd 192 buildName = NULL;
jakeb 15:688b3e3958fd 193 }
jakeb 15:688b3e3958fd 194
jakeb 15:688b3e3958fd 195 buildName = (char*)malloc(length-1);
jakeb 15:688b3e3958fd 196 strncpy(buildName, (char*)response+1,length-1);
jakeb 15:688b3e3958fd 197 return buildName;
jakeb 15:688b3e3958fd 198 }
jakeb 15:688b3e3958fd 199
jakeb 15:688b3e3958fd 200 return NULL;
jakeb 15:688b3e3958fd 201 }
jakeb 15:688b3e3958fd 202
jakeb 15:688b3e3958fd 203 // Start a print job from the SD card with the given filename
jakeb 15:688b3e3958fd 204 int Makerbot::playbackCapture(char* filename) {
jakeb 15:688b3e3958fd 205 // Build the packet
jakeb 15:688b3e3958fd 206 uint8_t packet[14];
jakeb 15:688b3e3958fd 207 packet[0]=0x10; //Playback = 16
jakeb 15:688b3e3958fd 208
jakeb 15:688b3e3958fd 209 // Copy over the filename into the packet one byte at a time
jakeb 15:688b3e3958fd 210 // TODO: replace with memcpy?
jakeb 15:688b3e3958fd 211 int length = 1;
jakeb 15:688b3e3958fd 212 for (int x=0; x<12; x++) {
jakeb 15:688b3e3958fd 213 packet[x+1] = filename[x];
jakeb 15:688b3e3958fd 214 length++;
jakeb 15:688b3e3958fd 215 if (filename[x]==0) break;
jakeb 15:688b3e3958fd 216 }
jakeb 15:688b3e3958fd 217
jakeb 15:688b3e3958fd 218 // Send the packet, get the response
jakeb 15:688b3e3958fd 219 mutex.lock();
jakeb 15:688b3e3958fd 220 send_packet(packet, length);
jakeb 15:688b3e3958fd 221 uint8_t response[MAXIMUM_PAYLOAD_LENGTH];
jakeb 15:688b3e3958fd 222 int recvLength = recv_packet(response, MAXIMUM_PAYLOAD_LENGTH);
jakeb 15:688b3e3958fd 223 mutex.unlock();
jakeb 15:688b3e3958fd 224
jakeb 15:688b3e3958fd 225 // Check for response success
jakeb 15:688b3e3958fd 226 if (recvLength > 0 && response[0] == SUCCESS) {
jakeb 15:688b3e3958fd 227 return 0;
jakeb 15:688b3e3958fd 228 }
jakeb 15:688b3e3958fd 229
jakeb 15:688b3e3958fd 230 //If we got here, there was a problem somewhere
jakeb 15:688b3e3958fd 231 return -1;
jakeb 15:688b3e3958fd 232 }
jakeb 15:688b3e3958fd 233
jakeb 15:688b3e3958fd 234 // Get machine name from bot's EEPROM
jakeb 15:688b3e3958fd 235 char* Makerbot::getMachineName() {
jakeb 15:688b3e3958fd 236 // If we have a cached name, return it
jakeb 15:688b3e3958fd 237 if (machineName) return machineName;
jakeb 15:688b3e3958fd 238
jakeb 15:688b3e3958fd 239 // Build the request packet
jakeb 15:688b3e3958fd 240 uint8_t payload[4];
jakeb 15:688b3e3958fd 241 payload[0]= 0xC; //read eprom = 12
jakeb 15:688b3e3958fd 242 *((uint16_t*)&payload[1])= MACHINE_NAME_OFFSET;
jakeb 15:688b3e3958fd 243 payload[3]= 16; //length of machine name;
jakeb 15:688b3e3958fd 244
jakeb 15:688b3e3958fd 245 // Send the packet, wait for response.
jakeb 15:688b3e3958fd 246 mutex.lock();
jakeb 15:688b3e3958fd 247 send_packet(payload, 4);
jakeb 15:688b3e3958fd 248 uint8_t response[MAXIMUM_PAYLOAD_LENGTH];
jakeb 15:688b3e3958fd 249 int length = recv_packet(response, MAXIMUM_PAYLOAD_LENGTH);
jakeb 15:688b3e3958fd 250 mutex.unlock();
jakeb 15:688b3e3958fd 251
jakeb 15:688b3e3958fd 252 // Return
jakeb 15:688b3e3958fd 253 if (length > 0 && response[0] == SUCCESS) {
jakeb 15:688b3e3958fd 254 //create a buffer to hold the machine name;
jakeb 15:688b3e3958fd 255 machineName = (char*)malloc(length+1);
jakeb 15:688b3e3958fd 256
jakeb 15:688b3e3958fd 257 memcpy(machineName, response+1, length-1);
jakeb 15:688b3e3958fd 258 machineName[length-2] = '\0'; //terminate
jakeb 15:688b3e3958fd 259
jakeb 15:688b3e3958fd 260 return machineName;
jakeb 15:688b3e3958fd 261 }
jakeb 15:688b3e3958fd 262
jakeb 15:688b3e3958fd 263 // Get machine name failed for some reason
jakeb 15:688b3e3958fd 264 DBG_INFO("getMachineName: unsuccessful");
jakeb 15:688b3e3958fd 265 return NULL;
jakeb 15:688b3e3958fd 266 }
jakeb 15:688b3e3958fd 267
jakeb 15:688b3e3958fd 268 int Makerbot::getEEPROMByte(uint16_t offset) {
jakeb 15:688b3e3958fd 269 // Build the request packet
jakeb 15:688b3e3958fd 270 uint8_t payload[4];
jakeb 15:688b3e3958fd 271 payload[0]= 0xC; //read eprom = 12
jakeb 15:688b3e3958fd 272 *((uint16_t*)&payload[1])= offset;
jakeb 15:688b3e3958fd 273 payload[3]= 1; //length of tool count (byte)
jakeb 15:688b3e3958fd 274
jakeb 15:688b3e3958fd 275 // Send the packet, wait for response.
jakeb 15:688b3e3958fd 276 mutex.lock();
jakeb 15:688b3e3958fd 277 send_packet(payload, 4);
jakeb 15:688b3e3958fd 278 uint8_t response[MAXIMUM_PAYLOAD_LENGTH];
jakeb 15:688b3e3958fd 279 int length = recv_packet(response, MAXIMUM_PAYLOAD_LENGTH);
jakeb 15:688b3e3958fd 280 mutex.unlock();
jakeb 15:688b3e3958fd 281
jakeb 15:688b3e3958fd 282 // Return
jakeb 15:688b3e3958fd 283 if (length == 2 && response[0] == SUCCESS) {
jakeb 15:688b3e3958fd 284 return response[1];
jakeb 15:688b3e3958fd 285 }
jakeb 15:688b3e3958fd 286
jakeb 15:688b3e3958fd 287 // Get machine name failed for some reason
jakeb 15:688b3e3958fd 288 DBG_INFO("getEEPROMByte: unsuccessful");
jakeb 15:688b3e3958fd 289 return 0;
jakeb 15:688b3e3958fd 290 }
jakeb 15:688b3e3958fd 291
jakeb 15:688b3e3958fd 292 // Get tool count from bot's EEPROM
jakeb 15:688b3e3958fd 293 int Makerbot::getToolCount() {
jakeb 15:688b3e3958fd 294 return getEEPROMByte(TOOL_COUNT_OFFSET);
jakeb 15:688b3e3958fd 295 }
jakeb 15:688b3e3958fd 296
jakeb 15:688b3e3958fd 297 int Makerbot::hasPlatform() {
jakeb 15:688b3e3958fd 298 return getEEPROMByte(HBP_PRESENT_OFFSET);
jakeb 15:688b3e3958fd 299 }
jakeb 15:688b3e3958fd 300
jakeb 15:688b3e3958fd 301 // Flush the buffer. Used to synchronize the stream
jakeb 15:688b3e3958fd 302 void Makerbot::flushInputChannel() {
jakeb 15:688b3e3958fd 303 mutex.lock();
jakeb 15:688b3e3958fd 304 while (1) {
jakeb 15:688b3e3958fd 305 if (serial->available())
jakeb 15:688b3e3958fd 306 serial->getch();
jakeb 15:688b3e3958fd 307 else
jakeb 15:688b3e3958fd 308 break;
jakeb 15:688b3e3958fd 309 }
jakeb 15:688b3e3958fd 310 mutex.unlock();
jakeb 15:688b3e3958fd 311 }
jakeb 15:688b3e3958fd 312
jakeb 15:688b3e3958fd 313 // Send pause/resume command
jakeb 15:688b3e3958fd 314 int Makerbot::pauseResume() {
jakeb 15:688b3e3958fd 315 // One byte commend
jakeb 15:688b3e3958fd 316 uint8_t cmd = 0x08; // 8 = Pause/Resume command
jakeb 15:688b3e3958fd 317
jakeb 15:688b3e3958fd 318 // Send the Packet, get the response
jakeb 15:688b3e3958fd 319 mutex.lock();
jakeb 15:688b3e3958fd 320 send_packet(&cmd, 1);
jakeb 15:688b3e3958fd 321 uint8_t response[MAXIMUM_PAYLOAD_LENGTH];
jakeb 15:688b3e3958fd 322 int length = recv_packet(response, MAXIMUM_PAYLOAD_LENGTH);
jakeb 15:688b3e3958fd 323 mutex.unlock();
jakeb 15:688b3e3958fd 324
jakeb 15:688b3e3958fd 325 // Return success status
jakeb 15:688b3e3958fd 326 if (length == 1 && response[1] == SUCCESS) return 0;
jakeb 15:688b3e3958fd 327 return -1;
jakeb 15:688b3e3958fd 328 }
jakeb 15:688b3e3958fd 329
jakeb 15:688b3e3958fd 330 // Send command to cancel build command
jakeb 15:688b3e3958fd 331 int Makerbot::abortImmediately() {
jakeb 15:688b3e3958fd 332 // One byte commend
jakeb 15:688b3e3958fd 333 uint8_t cmd = 0x07; // 7 = Abort command
jakeb 15:688b3e3958fd 334
jakeb 15:688b3e3958fd 335 // Send the Packet, get the response
jakeb 15:688b3e3958fd 336 mutex.lock();
jakeb 15:688b3e3958fd 337 send_packet(&cmd, 1);
jakeb 15:688b3e3958fd 338 uint8_t response[MAXIMUM_PAYLOAD_LENGTH];
jakeb 15:688b3e3958fd 339 int length = recv_packet(response, MAXIMUM_PAYLOAD_LENGTH);
jakeb 15:688b3e3958fd 340 mutex.unlock();
jakeb 15:688b3e3958fd 341
jakeb 15:688b3e3958fd 342 // Return success status
jakeb 15:688b3e3958fd 343 if (length == 1 && response[1] == SUCCESS) return 0;
jakeb 15:688b3e3958fd 344 return -1;
jakeb 15:688b3e3958fd 345 }
jakeb 15:688b3e3958fd 346
jakeb 15:688b3e3958fd 347 // Retrieve the current temperature for the given tool
jakeb 15:688b3e3958fd 348 int Makerbot::getToolTemperature(uint8_t toolIndex) {
jakeb 15:688b3e3958fd 349 // One byte commend
jakeb 15:688b3e3958fd 350 uint8_t payload[3];
jakeb 15:688b3e3958fd 351 payload[0] = 0x0A; // 7 = Abort command
jakeb 15:688b3e3958fd 352 payload[1] = toolIndex;
jakeb 15:688b3e3958fd 353 payload[2] = 0x2; //get toolhead temperature
jakeb 15:688b3e3958fd 354
jakeb 15:688b3e3958fd 355 // Send the Packet, get the response
jakeb 15:688b3e3958fd 356 mutex.lock();
jakeb 15:688b3e3958fd 357 send_packet(payload, 3);
jakeb 15:688b3e3958fd 358 uint8_t response[MAXIMUM_PAYLOAD_LENGTH];
jakeb 15:688b3e3958fd 359 int length = recv_packet(response, MAXIMUM_PAYLOAD_LENGTH);
jakeb 15:688b3e3958fd 360 mutex.unlock();
jakeb 15:688b3e3958fd 361
jakeb 15:688b3e3958fd 362
jakeb 15:688b3e3958fd 363 // Return success status
jakeb 15:688b3e3958fd 364 if (length == 3 && response[0] == SUCCESS) {
jakeb 15:688b3e3958fd 365 return *((uint16_t*)&response[1]);
jakeb 15:688b3e3958fd 366 }
jakeb 15:688b3e3958fd 367 return -1;
jakeb 15:688b3e3958fd 368 }
jakeb 15:688b3e3958fd 369
jakeb 15:688b3e3958fd 370 // Return the setpoint for the given tool
jakeb 15:688b3e3958fd 371 int Makerbot::getToolSetPoint(uint8_t toolIndex) {
jakeb 15:688b3e3958fd 372 // One byte commend
jakeb 15:688b3e3958fd 373 uint8_t payload[3];
jakeb 15:688b3e3958fd 374 payload[0] = 0x0A; // 7 = Abort command
jakeb 15:688b3e3958fd 375 payload[1] = toolIndex;
jakeb 15:688b3e3958fd 376 payload[2] = 0x20; //get toolhead set point
jakeb 15:688b3e3958fd 377
jakeb 15:688b3e3958fd 378 // Send the Packet, get the response
jakeb 15:688b3e3958fd 379 mutex.lock();
jakeb 15:688b3e3958fd 380 send_packet(payload, 3);
jakeb 15:688b3e3958fd 381 uint8_t response[MAXIMUM_PAYLOAD_LENGTH];
jakeb 15:688b3e3958fd 382 int length = recv_packet(response, MAXIMUM_PAYLOAD_LENGTH);
jakeb 15:688b3e3958fd 383 mutex.unlock();
jakeb 15:688b3e3958fd 384
jakeb 15:688b3e3958fd 385
jakeb 15:688b3e3958fd 386 // Return success status
jakeb 15:688b3e3958fd 387 if (length == 3 && response[0] == SUCCESS) {
jakeb 15:688b3e3958fd 388 return *((uint16_t*)&response[1]);
jakeb 15:688b3e3958fd 389 }
jakeb 15:688b3e3958fd 390 return -1;
jakeb 15:688b3e3958fd 391 }
jakeb 15:688b3e3958fd 392
jakeb 15:688b3e3958fd 393
jakeb 15:688b3e3958fd 394 // Retrieve the Platform temperature for the given tool
jakeb 15:688b3e3958fd 395 int Makerbot::getPlatformTemperature(uint8_t toolIndex) {
jakeb 15:688b3e3958fd 396 // One byte commend
jakeb 15:688b3e3958fd 397 uint8_t payload[3];
jakeb 15:688b3e3958fd 398 payload[0] = 0x0A; // 7 = Abort command
jakeb 15:688b3e3958fd 399 payload[1] = toolIndex;
jakeb 15:688b3e3958fd 400 payload[2] = 0x1E; //get toolhead temperature
jakeb 15:688b3e3958fd 401
jakeb 15:688b3e3958fd 402 // Send the Packet, get the response
jakeb 15:688b3e3958fd 403 mutex.lock();
jakeb 15:688b3e3958fd 404 send_packet(payload, 3);
jakeb 15:688b3e3958fd 405 uint8_t response[MAXIMUM_PAYLOAD_LENGTH];
jakeb 15:688b3e3958fd 406 int length = recv_packet(response, MAXIMUM_PAYLOAD_LENGTH);
jakeb 15:688b3e3958fd 407 mutex.unlock();
jakeb 15:688b3e3958fd 408
jakeb 15:688b3e3958fd 409
jakeb 15:688b3e3958fd 410 // Return success status
jakeb 15:688b3e3958fd 411 if (length == 3 && response[0] == SUCCESS) {
jakeb 15:688b3e3958fd 412 return *((uint16_t*)&response[1]);
jakeb 15:688b3e3958fd 413 }
jakeb 15:688b3e3958fd 414 return -1;
jakeb 15:688b3e3958fd 415 }
jakeb 15:688b3e3958fd 416
jakeb 15:688b3e3958fd 417 // Return the platform setpoint for the given tool
jakeb 15:688b3e3958fd 418 int Makerbot::getPlatformSetPoint(uint8_t toolIndex) {
jakeb 15:688b3e3958fd 419 // One byte commend
jakeb 15:688b3e3958fd 420 uint8_t payload[3];
jakeb 15:688b3e3958fd 421 payload[0] = 0x0A; // 7 = Abort command
jakeb 15:688b3e3958fd 422 payload[1] = toolIndex;
jakeb 15:688b3e3958fd 423 payload[2] = 0x21; //get toolhead set point
jakeb 15:688b3e3958fd 424
jakeb 15:688b3e3958fd 425 // Send the Packet, get the response
jakeb 15:688b3e3958fd 426 mutex.lock();
jakeb 15:688b3e3958fd 427 send_packet(payload, 3);
jakeb 15:688b3e3958fd 428 uint8_t response[MAXIMUM_PAYLOAD_LENGTH];
jakeb 15:688b3e3958fd 429 int length = recv_packet(response, MAXIMUM_PAYLOAD_LENGTH);
jakeb 15:688b3e3958fd 430 mutex.unlock();
jakeb 15:688b3e3958fd 431
jakeb 15:688b3e3958fd 432
jakeb 15:688b3e3958fd 433 // Return success status
jakeb 15:688b3e3958fd 434 if (length == 3 && response[0] == SUCCESS) {
jakeb 15:688b3e3958fd 435 return *((uint16_t*)&response[1]);
jakeb 15:688b3e3958fd 436 }
jakeb 15:688b3e3958fd 437 return -1;
jakeb 15:688b3e3958fd 438 }
jakeb 15:688b3e3958fd 439
jakeb 15:688b3e3958fd 440 // Get the build state. Note that we added a "BUILD_STATE_ERROR" value to detect errors in the return value.
jakeb 15:688b3e3958fd 441 Makerbot::MakerbotBuildState Makerbot::getBuildState() {
jakeb 15:688b3e3958fd 442 MakerbotBuildState state;
jakeb 15:688b3e3958fd 443
jakeb 15:688b3e3958fd 444 // One byte command
jakeb 15:688b3e3958fd 445 uint8_t cmd = 0x18; //24=get build statistics
jakeb 15:688b3e3958fd 446
jakeb 15:688b3e3958fd 447 // Send the packet, get the response
jakeb 15:688b3e3958fd 448 mutex.lock();
jakeb 15:688b3e3958fd 449 send_packet(&cmd, 1);
jakeb 15:688b3e3958fd 450 uint8_t response[MAXIMUM_PAYLOAD_LENGTH];
jakeb 15:688b3e3958fd 451 int length = recv_packet(response, MAXIMUM_PAYLOAD_LENGTH);
jakeb 15:688b3e3958fd 452 mutex.unlock();
jakeb 15:688b3e3958fd 453
jakeb 15:688b3e3958fd 454
jakeb 15:688b3e3958fd 455 // Check for success
jakeb 15:688b3e3958fd 456 if (response[0] == SUCCESS) {
jakeb 15:688b3e3958fd 457 // Copy the data to the return struct & return
jakeb 15:688b3e3958fd 458 memcpy(&state, response+1, sizeof(MakerbotBuildState));
jakeb 15:688b3e3958fd 459 return state;
jakeb 15:688b3e3958fd 460 }
jakeb 15:688b3e3958fd 461
jakeb 15:688b3e3958fd 462 // Otherwise return error state
jakeb 15:688b3e3958fd 463 state.build_state = BUILD_STATE_ERROR; //error
jakeb 15:688b3e3958fd 464 return state;
jakeb 15:688b3e3958fd 465 }
jakeb 15:688b3e3958fd 466
jakeb 15:688b3e3958fd 467 char* Makerbot::humanReadableBuildState(Makerbot::MakerbotBuildState state) {
jakeb 15:688b3e3958fd 468 switch (state.build_state) {
jakeb 15:688b3e3958fd 469 case Makerbot::NO_BUILD:
jakeb 15:688b3e3958fd 470 return "No Build";
jakeb 15:688b3e3958fd 471
jakeb 15:688b3e3958fd 472 case Makerbot::BUILD_RUNNING:
jakeb 15:688b3e3958fd 473 return "Build Running";
jakeb 15:688b3e3958fd 474
jakeb 15:688b3e3958fd 475 case Makerbot::BUILD_FINISHED_NORMALLY:
jakeb 15:688b3e3958fd 476 return "Build Finished";
jakeb 15:688b3e3958fd 477
jakeb 15:688b3e3958fd 478 case Makerbot::BUILD_PAUSED:
jakeb 15:688b3e3958fd 479 return "Build Paused";
jakeb 15:688b3e3958fd 480
jakeb 15:688b3e3958fd 481 case Makerbot::BUILD_CANCELLED:
jakeb 15:688b3e3958fd 482 return "Build Cancelled";
jakeb 15:688b3e3958fd 483
jakeb 15:688b3e3958fd 484 case Makerbot::BUILD_SLEEPING:
jakeb 15:688b3e3958fd 485 return "Build Sleeping";
jakeb 15:688b3e3958fd 486
jakeb 15:688b3e3958fd 487 case Makerbot::BUILD_STATE_ERROR:
jakeb 15:688b3e3958fd 488 default:
jakeb 15:688b3e3958fd 489 return "Unknown build status or status error";
jakeb 15:688b3e3958fd 490 }
jakeb 15:688b3e3958fd 491 }
jakeb 15:688b3e3958fd 492
jakeb 15:688b3e3958fd 493 // Clean up any objects created, just for good measure.
jakeb 15:688b3e3958fd 494 Makerbot::~Makerbot() {
jakeb 15:688b3e3958fd 495 if (machineName) {
jakeb 15:688b3e3958fd 496 free(machineName);
jakeb 15:688b3e3958fd 497 }
jakeb 15:688b3e3958fd 498 if (buildName) {
jakeb 15:688b3e3958fd 499 free(buildName);
jakeb 15:688b3e3958fd 500 }
jakeb 15:688b3e3958fd 501 }