// Set the DHCP hostname. Removes all whitespaces and converts the name to lower-case. void Network::SetHostname(const char *name) { size_t i = 0; while (*name && i < ARRAY_UPB(hostname)) { char c = *name++; if (c >= 'A' && c <= 'Z') { c += 'a' - 'A'; } if ((c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || (c == '-') || (c == '_')) { hostname[i++] = c; } } if (i) { hostname[i] = 0; } else { strcpy(hostname, HOSTNAME); } }
void Webserver::GetStatusResponse(uint8_t type) { GCodes *gc = reprap.GetGCodes(); if (type == 1) { // New-style status request // Send the printing/idle status char ch = (reprap.IsStopped()) ? 'S' : (gc->PrintingAFile()) ? 'P' : 'I'; snprintf(jsonResponse, ARRAY_UPB(jsonResponse), "{\"status\":\"%c\",\"heaters\":", ch); // Send the heater temperatures ch = '['; for (int8_t heater = 0; heater < HEATERS; heater++) { sncatf(jsonResponse, ARRAY_UPB(jsonResponse), "%c\%.1f", ch, reprap.GetHeat()->GetTemperature(heater)); ch = ','; } // Send XYZ and extruder positions float liveCoordinates[DRIVES + 1]; reprap.GetMove()->LiveCoordinates(liveCoordinates); strncat(jsonResponse, "],\"pos\":", ARRAY_UPB(jsonResponse)); // announce the XYZ position ch = '['; for (int8_t drive = 0; drive < AXES; drive++) { sncatf(jsonResponse, ARRAY_UPB(jsonResponse), "%c%.2f", ch, liveCoordinates[drive]); ch = ','; } sncatf(jsonResponse, ARRAY_UPB(jsonResponse), "],\"extr\":"); // announce the extruder positions ch = '['; for (int8_t drive = AXES; drive < DRIVES; drive++) // loop through extruders { sncatf(jsonResponse, ARRAY_UPB(jsonResponse), "%c%.3f", ch, gc->GetExtruderPosition(drive - AXES)); ch = ','; } strncat(jsonResponse, "]", ARRAY_UPB(jsonResponse)); // Send the speed and extruder override factors sncatf(jsonResponse, ARRAY_UPB(jsonResponse), ",\"sfactor\":%.2f,\"efactor:\":", gc->GetSpeedFactor() * 100.0); const float *extrusionFactors = gc->GetExtrusionFactors(); for (unsigned int i = 0; i < DRIVES - AXES; ++i) { sncatf(jsonResponse, ARRAY_UPB(jsonResponse), "%c%.2f", (i == 0) ? '[' : ',', extrusionFactors[i] * 100.0); } strncat(jsonResponse, "]", ARRAY_UPB(jsonResponse)); }
// Process a received string of gcodes void Webserver::LoadGcodeBuffer(const char* gc) { char gcodeTempBuf[GCODE_LENGTH]; uint16_t gtp = 0; bool inComment = false; for (;;) { char c = *gc++; if (c == 0) { gcodeTempBuf[gtp] = 0; ProcessGcode(gcodeTempBuf); return; } if (c == '\n') { gcodeTempBuf[gtp] = 0; ProcessGcode(gcodeTempBuf); gtp = 0; inComment = false; } else { if (c == ';') { inComment = true; } if (gtp == ARRAY_UPB(gcodeTempBuf)) { // gcode is too long, we haven't room for another character and a null if (c != ' ' && !inComment) { platform->Message(HOST_MESSAGE, "Webserver: GCode local buffer overflow.\n"); HandleReply("Webserver: GCode local buffer overflow", true); return; } // else we're either in a comment or the current character is a space. // If we're in a comment, we'll silently truncate it. // If the current character is a space, we'll wait until we see a non-comment character before reporting an error, // in case the next character is end-of-line or the start of a comment. } else { gcodeTempBuf[gtp++] = c; } } } }
void Webserver::ProcessGcode(const char* gc) { if (StringStartsWith(gc, "M30 ")) // delete SD card file { reprap.GetGCodes()->DeleteFile(&gc[4]); } else if (StringStartsWith(gc, "M23 ")) // select SD card file to print next { reprap.GetGCodes()->QueueFileToPrint(&gc[4]); } else if (StringStartsWith(gc, "M112") && !isdigit(gc[4])) // emergency stop { reprap.EmergencyStop(); gcodeReadIndex = gcodeWriteIndex; // clear the buffer reprap.GetGCodes()->Reset(); } else if (StringStartsWith(gc, "M503") && !isdigit(gc[4])) // echo config.g file { FileStore *configFile = platform->GetFileStore(platform->GetSysDir(), platform->GetConfigFile(), false); if (configFile == NULL) { HandleReply("Configuration file not found", true); } else { char c; size_t i = 0; while (i < ARRAY_UPB(gcodeReply) && configFile->Read(c)) { gcodeReply[i++] = c; } configFile->Close(); gcodeReply[i] = 0; ++seq; } } else if (StringStartsWith(gc, "M25") && !isDigit(gc[3])) // pause SD card print { reprap.GetGCodes()->PauseSDPrint(); } else { StoreGcodeData(gc, strlen(gc) + 1); } }
void Webserver::JsonReport(bool ok, const char* request) { if (ok) { jsonResponse[ARRAY_UPB(jsonResponse)] = 0; if (reprap.Debug()) { platform->Message(HOST_MESSAGE, "JSON response: "); platform->Message(HOST_MESSAGE, jsonResponse); platform->Message(HOST_MESSAGE, " queued\n"); } } else { jsonResponse[0] = 0; platform->Message(HOST_MESSAGE, "KnockOut request: "); platform->Message(HOST_MESSAGE, request); platform->Message(HOST_MESSAGE, " not recognised\n"); } }
void Webserver::GetJsonUploadResponse() { snprintf(jsonResponse, ARRAY_UPB(jsonResponse), "{\"ubuff\":%u,\"err\":%d}", GetReportedUploadBufferSpace(), (uploadState == uploadOK) ? 0 : 1); }
// Get the Json response for this command. // 'value' is null-terminated, but we also pass its length in case it contains embedded nulls, which matter when uploading files. bool Webserver::GetJsonResponse(const char* request, const char* key, const char* value, size_t valueLength) { bool found = true; // assume success bool keepOpen = false; // assume we don't want to persist the connection if (StringEquals(request, "status")) // new style status request { GetStatusResponse(1); } else if (StringEquals(request, "poll")) // old style status request { GetStatusResponse(0); } else if (StringEquals(request, "gcode") && StringEquals(key, "gcode")) { LoadGcodeBuffer(value); snprintf(jsonResponse, ARRAY_UPB(jsonResponse), "{\"buff\":%u}", GetReportedGcodeBufferSpace()); } else if (StringEquals(request, "upload_begin") && StringEquals(key, "name")) { CancelUpload(); FileStore *f = platform->GetFileStore("0:/", value, true); if (f != NULL) { fileBeingUploaded.Set(f); uploadState = uploadOK; } else { uploadState = uploadError; } GetJsonUploadResponse(); } else if (StringEquals(request, "upload_data") && StringEquals(key, "data")) { if (uploadState == uploadOK) { uploadPointer = value; uploadLength = valueLength; } GetJsonUploadResponse(); keepOpen = true; } else if (StringEquals(request, "upload_end") && StringEquals(key, "size")) { // Write the remaining data if (uploadLength != 0) { if (!fileBeingUploaded.Write(uploadPointer, uploadLength)) { uploadState = uploadError; } } uploadPointer = NULL; uploadLength = 0; if (uploadState == uploadOK && !fileBeingUploaded.Flush()) { uploadState = uploadError; } // Check the file length is as expected if (uploadState == uploadOK && fileBeingUploaded.Length() != strtoul(value, NULL, 10)) { uploadState = uploadError; } // Close the file if (!fileBeingUploaded.Close()) { uploadState = uploadError; } GetJsonUploadResponse(); if (uploadState != uploadOK && strlen(filenameBeingUploaded) != 0) { platform->GetMassStorage()->Delete("0:/", filenameBeingUploaded); } filenameBeingUploaded[0] = 0; } else if (StringEquals(request, "upload_cancel")) { CancelUpload(); snprintf(jsonResponse, ARRAY_UPB(jsonResponse), "{\"err\":%d}", 0); } else if (StringEquals(request, "delete") && StringEquals(key, "name")) { bool ok = platform->GetMassStorage()->Delete("0:/", value); snprintf(jsonResponse, ARRAY_UPB(jsonResponse), "{\"err\":%d}", (ok) ? 0 : 1); } else if (StringEquals(request, "files")) { const char* dir = (StringEquals(key, "dir")) ? value : platform->GetGCodeDir(); const char* fileList = platform->GetMassStorage()->FileList(dir, false); snprintf(jsonResponse, ARRAY_UPB(jsonResponse), "{\"files\":[%s]}", fileList); } else if (StringEquals(request, "fileinfo") && StringEquals(key, "name")) { unsigned long length; float height, filament, layerHeight; char generatedBy[50]; bool found = GetFileInfo(value, length, height, filament, layerHeight, generatedBy, ARRAY_SIZE(generatedBy)); if (found) { snprintf(jsonResponse, ARRAY_UPB(jsonResponse), "{\"err\":0,\"size\":%lu,\"height\":%.2f,\"filament\":%.1f,\"layerHeight\":%.2f,\"generatedBy\":\"%s\"}", length, height, filament, layerHeight, generatedBy); } else { snprintf(jsonResponse, ARRAY_UPB(jsonResponse), "{\"err\":1}"); } } else if (StringEquals(request, "name")) { snprintf(jsonResponse, ARRAY_UPB(jsonResponse), "{\"myName\":\""); size_t j = strlen(jsonResponse); for (size_t i = 0; i < ARRAY_SIZE(myName) - 1; ++i) { char c = myName[i]; if (c < ' ') // if null terminator or bad character break; if (c == '"' || c == '\\') { // Need to escape the quote-mark or backslash for JSON jsonResponse[j++] = '\\'; } jsonResponse[j++] = c; } jsonResponse[j++] = '"'; jsonResponse[j++] = '}'; jsonResponse[j] = 0; } else if (StringEquals(request, "password") && StringEquals(key, "password")) { CheckPassword(value); snprintf(jsonResponse, ARRAY_UPB(jsonResponse), "{\"password\":\"%s\"}", (gotPassword) ? "right" : "wrong"); } else if (StringEquals(request, "axes")) { strncpy(jsonResponse, "{\"axes\":", ARRAY_UPB(jsonResponse)); char ch = '['; for (int8_t drive = 0; drive < AXES; drive++) { sncatf(jsonResponse, ARRAY_UPB(jsonResponse), "%c%.1f", ch, platform->AxisTotalLength(drive)); ch = ','; } strncat(jsonResponse, "]}", ARRAY_UPB(jsonResponse)); } else if (StringEquals(request, "connect")) { CancelUpload(); GetStatusResponse(1); } else { found = false; } JsonReport(found, request); return keepOpen; }