Last active
March 24, 2017 22:18
-
-
Save probonopd/aef8eb21d5c56dc96b7a1910ae58a4aa to your computer and use it in GitHub Desktop.
I think this does not crash as long as lcd is commented out and it is NOT hooked up to printer...?!?
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
Works with Arduino Hourly and ESP git as of March 4, 2017 | |
when using a 2 GB card formatted with the SD Association's formatter | |
Send G-Code stored on SD card | |
This sketch reads G-Code from a file from the SD card using the | |
SD library and sends it over the serial port. | |
Basic G-Code sending: | |
http://fightpc.blogspot.de/2016/08/g-code-over-wifi.html | |
Advanced G-Code sending: | |
https://github.com/Ultimaker/Cura/blob/master/plugins/USBPrinting/USBPrinterOutputDevice.py | |
The circuit: | |
SD card attached to WeMos D1 mini as follows: | |
MOSI - pin D7 | |
MISO - pin D6 | |
CLK - pin D5 | |
CS - pin D8 | |
capacitor across power pins of SD card for getting the card recognized | |
*/ | |
/* | |
* Need to apply https://github.com/esp8266/Arduino/pull/3079/files | |
* in order for SDFile to work | |
*/ | |
#define FS_NO_GLOBALS | |
#include <ESP8266WiFi.h> | |
#include <ESP8266mDNS.h> | |
#include <WiFiUdp.h> | |
#include <ArduinoOTA.h> | |
#include <ESPAsyncWebServer.h> | |
#include <SPI.h> | |
#include <SD.h> | |
// !!! Make sure it says | |
// Multiple libraries were found for "SD.h" | |
// Used: (...)/hardware/esp8266/esp8266/libraries/SD <-- MUST use this one | |
// Not used: (...)/libraries/SD <-- Must NOT use this one | |
#include "private.h" | |
// const char* ssid = "____"; | |
// const char* password = "____"; | |
/* Access SDK functions for timer */ | |
extern "C" { | |
#include "user_interface.h" | |
} | |
os_timer_t myTimer; | |
// #define MTU_Size 2*1460 // https://github.com/esp8266/Arduino/issues/1853 | |
const char* sketch_version = "1.0"; | |
const char* host = "3d"; | |
const int chipSelect = SS; | |
const String uploadfilename = "cache.gco"; // 8+3 limitation of FAT, otherwise won't be written | |
bool okFound = true; // Set to true if last response from 3D printer was "ok", otherwise false | |
String response; // The last response from 3D printer | |
bool isPrinting = false; | |
bool shouldPrint = false; | |
long lineNumberLastPrinted = 0; | |
String lineLastSent = ""; | |
String lineLastReceived = ""; | |
String jobName = ""; | |
String priorityLine = ""; // A line that should be sent to the printer "in between"/before any other lines being sent. TODO: Extend to an array of lines | |
const int timerInterval = 2000; // Tick every 2 seconds | |
bool tickOccured = false; // Whether the timer has fired | |
void timerCallback(void *pArg) { | |
tickOccured = true; | |
} | |
bool SD_exists(String path) { | |
bool exists = false; | |
SDFile test = SD.open(path); | |
if (test) { | |
test.close(); | |
exists = true; | |
} | |
return exists; | |
} | |
String sendToPrinter(String line) { | |
/* Although this function does not return before okFound is true, | |
somewhere else in the sketch this function might also have been called | |
hence we make sure we have okFound before we start sending. */ | |
while (okFound == false) { | |
yield(); | |
} | |
/* If a priority line exists (e.g., a stop command), then send it before anything else. | |
TODO: Extend this to handle multiple priority lines. */ | |
if (priorityLine != "") { | |
String originalLine = line; | |
line = priorityLine; | |
priorityLine = ""; | |
sendToPrinter(line); | |
sendToPrinter(originalLine); | |
} | |
Serial.println(line); // Send to 3D Printer | |
lineLastSent = line; | |
okFound = false; | |
while (okFound == false) { | |
response = Serial.readStringUntil('\n'); | |
lineLastReceived = response; | |
if (response.startsWith("ok")) okFound = true; | |
} | |
return (response); | |
} | |
void lcd(String string) { | |
// sendToPrinter("M117 " + string); | |
} | |
/* Start webserver functions */ | |
AsyncWebServer server(80); | |
static bool hasSD = false; | |
SDFile uploadFile; | |
/* This function streams out the G-Code to the printer */ | |
void handlePrint() { | |
shouldPrint = false; | |
isPrinting = true; | |
os_timer_disarm(&myTimer); | |
int i = 0; | |
SDFile gcodeFile = SD.open(uploadfilename.c_str(), FILE_READ); | |
String line; | |
if (gcodeFile) { | |
while (gcodeFile.available()) { | |
lineNumberLastPrinted = lineNumberLastPrinted + 1; | |
line = gcodeFile.readStringUntil('\n'); // The G-Code line being worked on | |
int pos = line.indexOf(';'); | |
if (pos != -1) { | |
line = line.substring(0, pos); | |
} | |
if ((line.startsWith("(")) || (line.startsWith(";")) || (line.length() == 0)) { | |
continue; | |
} | |
sendToPrinter(line); | |
} | |
} else { | |
lcd("File is not on SD card"); | |
} | |
isPrinting = false; | |
jobName = ""; | |
os_timer_arm(&myTimer, timerInterval, true); | |
lcd("Complete"); | |
} | |
// https://forum.arduino.cc/index.php?topic=228884.msg2670971#msg2670971 | |
String IpAddress2String(const IPAddress& ipAddress) | |
{ | |
return String(ipAddress[0]) + String(".") + \ | |
String(ipAddress[1]) + String(".") + \ | |
String(ipAddress[2]) + String(".") + \ | |
String(ipAddress[3]) ; | |
} | |
void setup() { | |
delay(3000); // 3D printer needs this time | |
Serial.begin(115200); | |
Serial.setTimeout(240000); // How long we wait for "ok" in milliseconds | |
WiFi.begin(ssid, password); | |
String text = "Connecting to "; | |
text = text + ssid; | |
lcd(text); | |
// Wait for connection | |
uint8_t i = 0; | |
while (WiFi.status() != WL_CONNECTED && i++ < 20) {//wait 10 seconds | |
delay(500); | |
} | |
if (i == 21) { | |
text = "Could not connect"; | |
text = text + ssid; | |
lcd(text); | |
while (1) delay(500); | |
} | |
lcd(IpAddress2String(WiFi.localIP())); | |
if (MDNS.begin(host)) { | |
MDNS.addService("http", "tcp", 80); | |
MDNS.addService("wirelessprint", "tcp", 80); | |
MDNS.addServiceTxt("wirelessprint", "tcp", "version", sketch_version); | |
} | |
text = "http://"; | |
text = text + host; | |
text = text + ".local"; | |
// Hostname defaults to esp8266-[ChipID] | |
ArduinoOTA.setHostname(host); | |
ArduinoOTA.begin(); | |
server.on("/", HTTP_GET, [](AsyncWebServerRequest * request) { | |
// TODO: Offer stop when print is running | |
String message = "<h1>WirelessPrint</h1>"; | |
if (isPrinting == false) { | |
message += "<form enctype=\"multipart/form-data\" action=\"/print\" method=\"POST\">\n"; | |
message += "<p>You can also print from the command line using curl:</p>\n"; | |
message += "<pre>curl -F \"file=@/path/to/some.gcode\" 3d.local/print</pre>\n"; | |
message += "<input type=\"hidden\" name=\"MAX_FILE_SIZE\" value=\"100000\" />\n"; | |
message += "Choose a file to upload: <input name=\"file\" type=\"file\" /><br />\n"; | |
message += "<input type=\"submit\" value=\"Upload\" />\n"; | |
message += "</form>"; | |
message += ""; | |
message += "<p><a href=\"/download\">Download</a></p>"; | |
} | |
request->send(200, "text/html", message + "\r\n"); | |
}); | |
/* Cura asks the printer for status periodically. | |
We should make it easy on the ESP8266 and not do too much processing here | |
because a print may be in progress at the same time. | |
So avoid JSON processing, not expensive calculations, let Cura do them */ | |
server.on("/status", HTTP_GET, [](AsyncWebServerRequest * request) { | |
String message = "[Status]\n"; | |
message += "lineLastSent=" + lineLastSent + "\n"; | |
message += "lineLastReceived=" + lineLastReceived + "\n"; | |
message += "isPrinting=" + String(isPrinting) + "\n"; | |
message += "lineNumberLastPrinted=" + String(lineNumberLastPrinted) + "\n"; | |
message += "jobName=" + jobName + "\n"; | |
request->send(200, "text/plain", message + "\r\n"); | |
}); | |
server.onFileUpload([](AsyncWebServerRequest * request, String filename, size_t index, uint8_t *data, size_t len, bool final) { | |
lcd("Receiving..."); | |
if (!index) { | |
if (SD_exists(uploadfilename)) SD.remove(uploadfilename); | |
// jobName = request->getParam("path", true)->value(); //// CRASHES ////////////////////////////////777 | |
// delay(500); | |
uploadFile = SD.open(uploadfilename, FILE_WRITE | O_TRUNC); | |
} | |
if (len && uploadFile) | |
uploadFile.write(data, len); | |
if (final) { | |
if (uploadFile) uploadFile.close(); | |
delay(50); | |
lcd("Received"); | |
Serial.println(";Received"); | |
delay(1000); // So that we can read the message | |
shouldPrint = true; // This is seen by loop() and the printing is then started, but this function can exit, hence ending the HTTP transmission | |
} | |
}); | |
server.begin(); | |
if (SD.begin(SS, 50000000)) { // https://github.com/esp8266/Arduino/issues/1853 | |
hasSD = true; | |
lcd("SD Card OK"); | |
delay(1000); // So that we can read the last message on the LCD | |
lcd(text); // may be too large to fit on screen | |
} else { | |
lcd("SD Card ERROR"); | |
} | |
/* Set up the timer to fire every 2 seconds */ | |
os_timer_setfn(&myTimer, timerCallback, NULL); | |
os_timer_arm(&myTimer, timerInterval, true); | |
} | |
void loop() { | |
ArduinoOTA.handle(); | |
if (shouldPrint == true) handlePrint(); | |
/* When the timer has ticked and we are not printing, ask for temperature */ | |
if ((isPrinting == false) && (tickOccured == true)) { | |
sendToPrinter("M105"); | |
tickOccured = false; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment