void Webserver::GetJsonResponse(const char* request) { jsonPointer = 0; writing = true; if(StringStartsWith(request, "poll")) { strncpy(jsonResponse, "{\"poll\":[", STRING_LENGTH); if(reprap.GetGCodes()->PrintingAFile()) strncat(jsonResponse, "\"P\",", STRING_LENGTH); // Printing else strncat(jsonResponse, "\"I\",", STRING_LENGTH); // Idle float liveCoordinates[DRIVES+1]; reprap.GetMove()->LiveCoordinates(liveCoordinates); for(int8_t drive = 0; drive < AXES; drive++) { strncat(jsonResponse, "\"", STRING_LENGTH); strncat(jsonResponse, ftoa(0, liveCoordinates[drive], 2), STRING_LENGTH); strncat(jsonResponse, "\",", STRING_LENGTH); } // FIXME: should loop through all Es strncat(jsonResponse, "\"", STRING_LENGTH); strncat(jsonResponse, ftoa(0, liveCoordinates[AXES], 4), STRING_LENGTH); strncat(jsonResponse, "\",", STRING_LENGTH); for(int8_t heater = 0; heater < HEATERS; heater++) { strncat(jsonResponse, "\"", STRING_LENGTH); strncat(jsonResponse, ftoa(0, reprap.GetHeat()->GetTemperature(heater), 1), STRING_LENGTH); if(heater < HEATERS - 1) strncat(jsonResponse, "\",", STRING_LENGTH); else strncat(jsonResponse, "\"", STRING_LENGTH); } strncat(jsonResponse, "]", STRING_LENGTH); // Send the Z probe value char scratch[SHORT_STRING_LENGTH+1]; scratch[SHORT_STRING_LENGTH] = 0; if (platform->GetZProbeType() == 2) { snprintf(scratch, SHORT_STRING_LENGTH, ",\"probe\":\"%d (%d)\"", (int)platform->ZProbe(), platform->ZProbeOnVal()); } else { snprintf(scratch, SHORT_STRING_LENGTH, ",\"probe\":\"%d\"", (int)platform->ZProbe()); } strncat(jsonResponse, scratch, STRING_LENGTH); // Send the amount of buffer space available for gcodes snprintf(scratch, SHORT_STRING_LENGTH, ",\"buff\":%u", GetReportedGcodeBufferSpace()); strncat(jsonResponse, scratch, STRING_LENGTH); // Send the home state. To keep the messages short, we send 1 for homed and 0 for not homed, instead of true and false. strncat(jsonResponse, ",\"hx\":", STRING_LENGTH); strncat(jsonResponse, (reprap.GetGCodes()->GetAxisIsHomed(0)) ? "1" : "0", STRING_LENGTH); strncat(jsonResponse, ",\"hy\":", STRING_LENGTH); strncat(jsonResponse, (reprap.GetGCodes()->GetAxisIsHomed(1)) ? "1" : "0", STRING_LENGTH); strncat(jsonResponse, ",\"hz\":", STRING_LENGTH); strncat(jsonResponse, (reprap.GetGCodes()->GetAxisIsHomed(2)) ? "1" : "0", STRING_LENGTH); // Send the response sequence number strncat(jsonResponse, ",\"seq\":", STRING_LENGTH); snprintf(scratch, SHORT_STRING_LENGTH, "%u", (unsigned int)seq); strncat(jsonResponse, scratch, STRING_LENGTH); // Send the response to the last command. Do this last because it is long and may need to be truncated. strncat(jsonResponse, ",\"resp\":\"", STRING_LENGTH); size_t jp = strnlen(jsonResponse, STRING_LENGTH); const char *p = gcodeReply; while (*p != 0 && jp < STRING_LENGTH - 2) // leave room for the final '"}' { char c = *p++; char esc; switch(c) { case '\r': esc = 'r'; break; case '\n': esc = 'n'; break; case '\t': esc = 't'; break; case '"': esc = '"'; break; case '\\': esc = '\\'; break; default: esc = 0; break; } if (esc) { if (jp == STRING_LENGTH - 3) break; jsonResponse[jp++] = '\\'; jsonResponse[jp++] = esc; } else { jsonResponse[jp++] = c; } } strncat(jsonResponse, "\"}", STRING_LENGTH); jsonResponse[STRING_LENGTH] = 0; JsonReport(true, request); return; } if(StringStartsWith(request, "gcode")) { LoadGcodeBuffer(&clientQualifier[6], true); char scratch[SHORT_STRING_LENGTH+1]; scratch[SHORT_STRING_LENGTH] = 0; snprintf(scratch, SHORT_STRING_LENGTH, "{\"buff\":%u}", GetReportedGcodeBufferSpace()); strncat(jsonResponse, scratch, STRING_LENGTH); JsonReport(true, request); return; } if(StringStartsWith(request, "files")) { char* fileList = platform->GetMassStorage()->FileList(platform->GetGCodeDir(), false); strncpy(jsonResponse, "{\"files\":[", STRING_LENGTH); strncat(jsonResponse, fileList, STRING_LENGTH); strncat(jsonResponse, "]}", STRING_LENGTH); JsonReport(true, request); return; } if(StringStartsWith(request, "name")) { strncpy(jsonResponse, "{\"myName\":\"", STRING_LENGTH); strncat(jsonResponse, myName, STRING_LENGTH); strncat(jsonResponse, "\"}", STRING_LENGTH); JsonReport(true, request); return; } if(StringStartsWith(request, "password")) { CheckPassword(); strncpy(jsonResponse, "{\"password\":\"", STRING_LENGTH); if(gotPassword) strncat(jsonResponse, "right", STRING_LENGTH); else strncat(jsonResponse, "wrong", STRING_LENGTH); strncat(jsonResponse, "\"}", STRING_LENGTH); JsonReport(true, request); return; } if(StringStartsWith(request, "axes")) { strncpy(jsonResponse, "{\"axes\":[", STRING_LENGTH); for(int8_t drive = 0; drive < AXES; drive++) { strncat(jsonResponse, "\"", STRING_LENGTH); strncat(jsonResponse, ftoa(0, platform->AxisLength(drive), 1), STRING_LENGTH); if(drive < AXES-1) strncat(jsonResponse, "\",", STRING_LENGTH); else strncat(jsonResponse, "\"", STRING_LENGTH); } strncat(jsonResponse, "]}", STRING_LENGTH); JsonReport(true, request); return; } JsonReport(false, request); }
// 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; }