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 << "\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;
}