diff --git a/src/MjpegServerImpl.cpp b/src/MjpegServerImpl.cpp index 164411f813..628ce87f80 100644 --- a/src/MjpegServerImpl.cpp +++ b/src/MjpegServerImpl.cpp @@ -31,12 +31,35 @@ using namespace cs; #define BOUNDARY "boundarydonotcross" // A bare-bones HTML webpage for user friendliness. -static const char* rootPage = - "CameraServer" +static const char* emptyRootPage = + "CameraServer" "

" "Settings JSON" ""; +// An HTML page to be sent when a source exists +static const char* startRootPage = "\n" + "\n" + "CameraServer\n" + "

\n" + "Settings JSON\n"; +static const char* endRootPage =""; + class MjpegServerImpl::ConnThread : public wpi::SafeThread { public: ConnThread(llvm::StringRef name) : m_name(name) {} @@ -46,6 +69,7 @@ class MjpegServerImpl::ConnThread : public wpi::SafeThread { bool ProcessCommand(llvm::raw_ostream& os, SourceImpl& source, llvm::StringRef parameters, bool respond); void SendJSON(llvm::raw_ostream& os, SourceImpl& source, bool header); + void SendHTML(llvm::raw_ostream& os, SourceImpl& source, bool header); void SendStream(wpi::raw_socket_ostream& os); void ProcessRequest(); @@ -289,6 +313,83 @@ bool MjpegServerImpl::ConnThread::ProcessCommand(llvm::raw_ostream& os, return true; } +// Send the root html file with controls for all the settable properties. +void MjpegServerImpl::ConnThread::SendHTML(llvm::raw_ostream& os, + SourceImpl& source, bool header) { + if (header) SendHeader(os, 200, "OK", "application/x-javascript"); + + os << startRootPage; + llvm::SmallVector properties_vec; + CS_Status status = 0; + for (auto prop : source.EnumerateProperties(properties_vec, &status)) { + llvm::SmallString<128> name_buf; + auto name = source.GetPropertyName(prop, name_buf, &status); + if (name.startswith("raw_")) continue; + auto kind = source.GetPropertyKind(prop); + os << "

" + << "\n"; + switch (kind) { + case CS_PROP_BOOLEAN: + os << "\n"; + else + os << " />\n"; + break; + case CS_PROP_INTEGER: { + auto valI = source.GetProperty(prop, &status); + auto min = source.GetPropertyMin(prop, &status); + auto max = source.GetPropertyMax(prop, &status); + auto step = source.GetPropertyStep(prop, &status); + os << "\n"; + os << "" << valI + << "\n"; + break; + } + case CS_PROP_ENUM: { + auto valE = source.GetProperty(prop, &status); + auto choices = source.GetEnumPropertyChoices(prop, &status); + int j = 0; + for (auto choice = choices.begin(), end = choices.end(); choice != end; + ++j, ++choice) { + if (choice->empty()) continue; // skip empty choices + // replace any non-printable characters in name with spaces + llvm::SmallString<128> ch_name; + for (char ch : *choice) ch_name.push_back(isprint(ch) ? ch : ' '); + os << "\n"; + } + break; + } + case CS_PROP_STRING: { + llvm::SmallString<128> strval_buf; + os << "\n"; + os << "\n"; + break; + } + default: + break; + } + } + + os << endRootPage << "\r\n"; + os.flush(); +} + // Send a JSON file which is contains information about the source parameters. void MjpegServerImpl::ConnThread::SendJSON(llvm::raw_ostream& os, SourceImpl& source, bool header) { @@ -587,7 +688,11 @@ void MjpegServerImpl::ConnThread::ProcessRequest() { case kRootPage: SDEBUG("request for root page"); SendHeader(os, 200, "OK", "text/html"); - os << rootPage << "\r\n"; + if (auto source = GetSource()) { + SendHTML(os, *source, false); + } else { + os << emptyRootPage << "\r\n"; + } break; }