57 #include <imgui_internal.h>
61 #ifndef V4L2_CTRL_CLASS_DETECT
62 #define V4L2_CTRL_CLASS_DETECT 0x00a30000
68 struct shortcontrol {
unsigned int id;
char const *
const shortname; };
73 static shortcontrol camcontrols[] = {
75 { V4L2_CID_BRIGHTNESS,
"brightness" },
76 { V4L2_CID_CONTRAST,
"contrast" },
77 { V4L2_CID_SATURATION,
"saturation" },
78 { V4L2_CID_HUE,
"hue" },
79 { V4L2_CID_AUDIO_VOLUME,
"audiovol" },
80 { V4L2_CID_AUDIO_BALANCE,
"audiobal" },
81 { V4L2_CID_AUDIO_BASS,
"audiobass" },
82 { V4L2_CID_AUDIO_TREBLE,
"audiotreble" },
83 { V4L2_CID_AUDIO_MUTE,
"audiomute" },
84 { V4L2_CID_AUDIO_LOUDNESS,
"audioloudness" },
85 { V4L2_CID_BLACK_LEVEL,
"blacklevel" },
86 { V4L2_CID_AUTO_WHITE_BALANCE,
"autowb" },
87 { V4L2_CID_DO_WHITE_BALANCE,
"dowb" },
88 { V4L2_CID_RED_BALANCE,
"redbal" },
89 { V4L2_CID_BLUE_BALANCE,
"bluebal" },
90 { V4L2_CID_GAMMA,
"gamma" },
91 { V4L2_CID_WHITENESS,
"whiteness" },
92 { V4L2_CID_EXPOSURE,
"exposure" },
93 { V4L2_CID_AUTOGAIN,
"autogain" },
94 { V4L2_CID_GAIN,
"gain" },
95 { V4L2_CID_HFLIP,
"hflip" },
96 { V4L2_CID_VFLIP,
"vflip" },
97 { V4L2_CID_POWER_LINE_FREQUENCY,
"powerfreq" },
98 { V4L2_CID_HUE_AUTO,
"autohue" },
99 { V4L2_CID_WHITE_BALANCE_TEMPERATURE,
"wbtemp" },
100 { V4L2_CID_SHARPNESS,
"sharpness" },
101 { V4L2_CID_BACKLIGHT_COMPENSATION,
"backlight" },
102 { V4L2_CID_CHROMA_AGC,
"chromaagc" },
103 { V4L2_CID_COLOR_KILLER,
"colorkiller" },
104 { V4L2_CID_COLORFX,
"colorfx" },
105 { V4L2_CID_AUTOBRIGHTNESS,
"autobrightness" },
106 { V4L2_CID_BAND_STOP_FILTER,
"bandfilter" },
107 { V4L2_CID_ROTATE,
"rotate" },
108 { V4L2_CID_BG_COLOR,
"bgcolor" },
109 { V4L2_CID_CHROMA_GAIN,
"chromagain" },
110 { V4L2_CID_ILLUMINATORS_1,
"illum1" },
111 { V4L2_CID_ILLUMINATORS_2,
"illum2" },
112 { V4L2_CID_MIN_BUFFERS_FOR_CAPTURE,
"mincapbuf" },
113 { V4L2_CID_MIN_BUFFERS_FOR_OUTPUT,
"minoutbuf" },
114 { V4L2_CID_ALPHA_COMPONENT,
"alphacompo" },
119 { V4L2_CID_EXPOSURE_AUTO,
"autoexp" },
120 { V4L2_CID_EXPOSURE_ABSOLUTE,
"absexp" },
121 { V4L2_CID_EXPOSURE_AUTO_PRIORITY,
"exppri" },
122 { V4L2_CID_PAN_RELATIVE,
"panrel" },
123 { V4L2_CID_TILT_RELATIVE,
"tiltrel" },
124 { V4L2_CID_PAN_RESET,
"panreset" },
125 { V4L2_CID_TILT_RESET,
"tiltreset" },
126 { V4L2_CID_PAN_ABSOLUTE,
"panabs" },
127 { V4L2_CID_TILT_ABSOLUTE,
"tiltabs" },
128 { V4L2_CID_FOCUS_ABSOLUTE,
"focusabs" },
129 { V4L2_CID_FOCUS_RELATIVE,
"focusrel" },
130 { V4L2_CID_FOCUS_AUTO,
"focusauto" },
131 { V4L2_CID_ZOOM_ABSOLUTE,
"zoomabs" },
132 { V4L2_CID_ZOOM_RELATIVE,
"zoomrel" },
133 { V4L2_CID_ZOOM_CONTINUOUS,
"zoomcontinuous" },
134 { V4L2_CID_PRIVACY,
"privacy" },
135 { V4L2_CID_IRIS_ABSOLUTE,
"irisabs" },
136 { V4L2_CID_IRIS_RELATIVE,
"irisrel" },
139 #ifndef V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE
140 #define V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE (V4L2_CID_CAMERA_CLASS_BASE+20)
161 { V4L2_CID_FLASH_LED_MODE,
"flashled" },
162 { V4L2_CID_FLASH_STROBE_SOURCE,
"flashstrobesrc" },
163 { V4L2_CID_FLASH_STROBE,
"flashstrobe" },
164 { V4L2_CID_FLASH_STROBE_STOP,
"flashstrobestop" },
165 { V4L2_CID_FLASH_STROBE_STATUS,
"flashstrovestat" },
166 { V4L2_CID_FLASH_TIMEOUT,
"flashtimeout" },
167 { V4L2_CID_FLASH_INTENSITY,
"flashintens" },
168 { V4L2_CID_FLASH_TORCH_INTENSITY,
"flashtorch" },
169 { V4L2_CID_FLASH_INDICATOR_INTENSITY,
"flashindintens" },
170 { V4L2_CID_FLASH_FAULT,
"flashfault" },
171 { V4L2_CID_FLASH_CHARGE,
"flashcharge" },
172 { V4L2_CID_FLASH_READY,
"flashready" },
175 { V4L2_CID_JPEG_CHROMA_SUBSAMPLING,
"jpegchroma" },
176 { V4L2_CID_JPEG_RESTART_INTERVAL,
"jpegrestartint" },
177 { V4L2_CID_JPEG_COMPRESSION_QUALITY,
"jpegcompression" },
178 { V4L2_CID_JPEG_ACTIVE_MARKER,
"jpegmarker" },
203 std::string abbreviate(std::string
const & longname)
205 std::string name(longname);
206 std::transform(name.begin(), name.end(), name.begin(), ::
tolower);
207 name.erase(std::remove_if(name.begin(), name.end(), [](
int c) { return !std::isalnum(c); }), name.end());
214 namespace jevois {
namespace engine {
static std::atomic<size_t> frameNumber(0); } }
216 size_t jevois::frameNum()
217 {
return jevois::engine::frameNumber.load(); }
221 jevois::
Manager(instance), itsMappings(), itsRunning(false), itsStreaming(false), itsStopMainLoop(false),
222 itsShellMode(false), itsTurbo(false), itsManualStreamon(false), itsVideoErrors(false),
223 itsNumSerialSent(0), itsRequestedFormat(-2)
227 #ifdef JEVOIS_PLATFORM_A33
229 itsCheckingMassStorage.store(
false); itsMassStorageMode.store(
false);
231 while (itsCheckingMassStorage.load() ==
false) std::this_thread::sleep_for(std::chrono::milliseconds(5));
234 jevois::engine::frameNumber.store(0);
239 jevois::
Manager(argc, argv, instance), itsMappings(), itsRunning(false), itsStreaming(false),
240 itsStopMainLoop(false), itsShellMode(false), itsTurbo(false), itsManualStreamon(false), itsVideoErrors(false),
241 itsNumSerialSent(0), itsRequestedFormat(-2)
245 #ifdef JEVOIS_PLATFORM_A33
247 itsCheckingMassStorage.store(
false); itsMassStorageMode.store(
false);
249 while (itsCheckingMassStorage.load() ==
false) std::this_thread::sleep_for(std::chrono::milliseconds(5));
252 jevois::engine::frameNumber.store(0);
257 std::string
const & newval)
262 for (std::list<std::shared_ptr<UserInterface> >::iterator itr = itsSerials.begin(); itr != itsSerials.end(); ++itr)
263 if ((*itr)->instanceName() ==
"serial") itr = itsSerials.erase(itr);
264 removeComponent(
"serial",
false);
267 if (newval.empty() ==
false)
270 std::shared_ptr<jevois::UserInterface> s;
271 if (newval ==
"stdio")
272 s = addComponent<jevois::StdioInterface>(
"serial");
279 itsSerials.push_back(s);
280 LINFO(
"Using [" << newval <<
"] hardware (4-pin connector) serial port");
283 else LINFO(
"No hardware (4-pin connector) serial port used");
288 std::string
const & newval)
293 for (std::list<std::shared_ptr<UserInterface> >::iterator itr = itsSerials.begin(); itr != itsSerials.end(); ++itr)
294 if ((*itr)->instanceName() ==
"usbserial") itr = itsSerials.erase(itr);
295 removeComponent(
"usbserial",
false);
298 if (newval.empty() ==
false)
301 std::shared_ptr<jevois::UserInterface> s =
304 itsSerials.push_back(s);
305 LINFO(
"Using [" << newval <<
"] USB serial port");
308 else LINFO(
"No USB serial port used");
313 jevois::engine::CPUmode
const & newval)
316 std::ofstream ofs(
"/sys/devices/system/cpu/cpu2/cpufreq/scaling_governor");
318 std::ofstream ofs(
"/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor");
320 if (ofs.is_open() ==
false)
322 #ifdef JEVOIS_PLATFORM
323 LERROR(
"Cannot set cpu frequency governor mode -- IGNORED");
330 case engine::CPUmode::PowerSave: ofs <<
"powersave" << std::endl;
break;
331 case engine::CPUmode::Conservative: ofs <<
"conservative" << std::endl;
break;
332 case engine::CPUmode::OnDemand: ofs <<
"ondemand" << std::endl;
break;
333 case engine::CPUmode::Interactive: ofs <<
"interactive" << std::endl;
break;
334 case engine::CPUmode::Performance: ofs <<
"performance" << std::endl;
break;
341 jevois::engine::CPUmode
const & newval)
343 std::ofstream ofs(
"/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor");
344 if (ofs.is_open() ==
false)
346 #ifdef JEVOIS_PLATFORM
347 LERROR(
"Cannot set cpu frequency governor mode -- IGNORED");
354 case engine::CPUmode::PowerSave: ofs <<
"powersave" << std::endl;
break;
355 case engine::CPUmode::Conservative: ofs <<
"conservative" << std::endl;
break;
356 case engine::CPUmode::OnDemand: ofs <<
"ondemand" << std::endl;
break;
357 case engine::CPUmode::Interactive: ofs <<
"interactive" << std::endl;
break;
358 case engine::CPUmode::Performance: ofs <<
"performance" << std::endl;
break;
365 unsigned int const & newval)
368 std::ofstream ofs(
"/sys/devices/system/cpu/cpu2/cpufreq/scaling_max_freq");
370 std::ofstream ofs(
"/sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq");
373 if (ofs.is_open() ==
false)
375 #ifdef JEVOIS_PLATFORM
376 LERROR(
"Cannot set cpu max frequency -- IGNORED");
381 ofs << newval * 1000U << std::endl;
388 itsVideoErrors.store(newval);
401 itsGUIhelper = addComponent<jevois::GUIhelper>(
"gui",
conslock::get());
402 auto s = addComponent<jevois::GUIconsole>(
"guiconsole");
403 itsSerials.push_back(s);
404 LINFO(
"GUI enabled.");
407 else if (itsGUIhelper)
409 for (
auto itr = itsSerials.begin(); itr != itsSerials.end(); ++itr)
410 if ((*itr)->instanceName() ==
"guiconsole") { itsSerials.erase(itr);
break; }
411 removeComponent(
"guiconsole",
false);
412 removeComponent(itsGUIhelper);
413 itsGUIhelper.reset();
414 LINFO(
"GUI disabled.");
420 unsigned int const & newval)
422 std::ofstream ofs(
"/sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq");
424 if (ofs.is_open() ==
false)
426 #ifdef JEVOIS_PLATFORM
427 LERROR(
"Cannot set cpu max frequency -- IGNORED");
432 ofs << newval * 1000U << std::endl;
437 float const & newval)
440 if (newval == 0.0
F) itsDemoReset =
true;
444 void jevois::Engine::runDemoStep()
446 if (! itsGUIhelper)
return;
448 int constexpr fade = 30;
449 int constexpr msg = 90;
450 int constexpr tmax = 15;
459 static size_t modidx = 0;
460 static int fade_out = 0, show_msg = 0, fade_in = 0;
461 static std::chrono::time_point<std::chrono::steady_clock> mod_load_time;
462 std::chrono::time_point<std::chrono::steady_clock>
const now = std::chrono::steady_clock::now();
468 cv::FileStorage fs(JEVOISPRO_DEMO_DATA_FILE, cv::FileStorage::READ);
469 if (fs.isOpened() ==
false)
470 {
LERROR(
"Could not open " << JEVOISPRO_DEMO_DATA_FILE <<
" -- DEMO MODE ABORTED"); demomode::set(0.0
F);
return; }
472 cv::FileNode fn = fs.root();
473 for (cv::FileNodeIterator gfit = fn.begin(); gfit != fn.end(); ++gfit)
475 cv::FileNode item = *gfit;
476 if (! item.isMap())
continue;
479 for(cv::FileNodeIterator fit = item.begin(); fit != item.end(); ++fit)
481 cv::FileNode param = *fit;
483 std::string k = param.name();
484 if (k ==
"demomapping")
486 std::string
const vmstr = (std::string)param;
487 jevois::VideoMapping vm; std::istringstream iss(vmstr); iss >> vm;
488 int idx = 0; dd.mapping_idx = -1;
489 foreachVideoMapping([&dd, &vm, &idx](jevois::VideoMapping
const & m)
490 {
if (vm.isSameAs(m)) dd.mapping_idx = idx;
else ++idx; });
491 if (dd.mapping_idx == -1) {
LERROR(
"Video mapping not found for [" << vmstr <<
"] -- SKIPPED");
break; }
493 else if (k ==
"demotitle")
494 dd.title = (std::string)param;
495 else if (k ==
"demomsg")
496 dd.msg = (std::string)param;
500 switch (param.type())
504 case cv::FileNode::STRING: v = (std::string)param;
break;
505 default:
LERROR(
"Invalid demo parameter for [" << item.name() <<
"]: " << k <<
" type " << param.type());
508 if (dd.mapping_idx != -1) dd.params.emplace_back(std::make_pair(k, v));
512 itsDemoData.emplace_back(std::move(dd));
515 if (itsDemoData.empty())
516 {
LERROR(
"No demos in " << JEVOISPRO_DEMO_DATA_FILE <<
" -- DEMO MODE ABORTED"); demomode::set(0.0
F);
return; }
517 else LINFO(
"Loaded demo information with " << itsDemoData.size() <<
" demo modules.");
520 fade_out = 0; show_msg = msg * 3; fade_in = 0; mod_load_time = now; modidx = 0;
521 itsGUIhelper->demoBanner(
"Welcome to JeVois-Pro!",
"This demo will cycle through a few machine vision algorithms.");
522 itsDemoReset =
false;
527 if (itsNextDemoRequested)
529 ++modidx;
if (modidx >= itsDemoData.size()) modidx = 0;
530 fade_out = 0; show_msg = msg; fade_in = 0; mod_load_time = now;
531 itsNextDemoRequested =
false;
535 if (show_msg == msg || itsGUIhelper->idle() ==
false)
536 itsGUIhelper->demoBanner(itsDemoData[modidx].title, itsDemoData[modidx].msg);
540 itsGUIhelper->twirl::set(tmax);
544 LINFO(
"Loading demo: " << itsDemoData[modidx].title);
545 requestSetFormat(itsDemoData[modidx].mapping_idx);
551 if (show_msg == 0) fade_in = fade;
557 for (
auto const & pp : itsDemoData[modidx].params)
558 try { setParamString(pp.first, pp.second); }
559 catch (...) {
LERROR(
"Failed to set param [" << pp.first <<
"] to [" << pp.second <<
"] -- IGNORED"); }
564 itsGUIhelper->twirl::set(
float(tmax * fade_in - tmax) /
float(fade));
565 if (--fade_in == 0 && itsGUIhelper->idle()) itsGUIhelper->demoBanner();
572 itsGUIhelper->twirl::set(tmax -
float(tmax * fade_out - tmax) /
float(fade));
573 if (--fade_out == 0) show_msg = msg;
578 std::chrono::duration<float>
const elapsed = now - mod_load_time;
582 ++modidx;
if (modidx >= itsDemoData.size()) modidx = 0;
588 { itsNextDemoRequested =
true; }
595 if (! itsGUIhelper)
return;
597 itsGUIhelper->twirl::set(0.0
F);
598 itsGUIhelper->demoBanner();
607 std::string
const paramcfg = std::string(JEVOIS_CONFIG_PATH) +
'/' + JEVOIS_MODULE_PARAMS_FILENAME;
608 std::ifstream ifs(paramcfg);
if (ifs.is_open()) setParamsFromStream(ifs, paramcfg);
623 itsMappings = jevois::loadVideoMappings(
camerasens::get(), itsDefaultMappingIdx,
true, usegui);
624 LINFO(
"Loaded " << itsMappings.size() <<
" vision processing modes.");
639 usbserialdev::freeze();
643 cameranbuf::freeze();
646 gadgetnbuf::freeze();
655 #ifdef JEVOIS_PLATFORM_PRO
656 if (camsens == jevois::CameraSensor::any)
659 size_t idx = 0;
while (idx < str.length() && std::isalnum(str[idx])) ++idx;
660 str = str.substr(0, idx);
661 camerasens::strset(str);
663 LINFO(
"Camera sensor selected from device tree: " << camsens);
666 camerasens::freeze();
667 LINFO(
"Using camera sensor: " << camsens);
682 reloadVideoMappings();
690 LINFO(
"Initalizing Python...");
698 LINFO(
"Starting camera device " << camdev);
700 #ifdef JEVOIS_PLATFORM_A33
702 std::ofstream ofs(
"/sys/module/vfe_v4l2/parameters/turbo");
705 if (itsTurbo) ofs <<
"1" << std::endl;
else ofs <<
"0" << std::endl;
708 else LERROR(
"Could not access VFE turbo parameter -- IGNORED");
714 #ifndef JEVOIS_PLATFORM
716 camreg::set(
false); camreg::freeze();
717 imureg::set(
false); imureg::freeze();
723 #ifdef JEVOIS_PLATFORM_A33
725 itsIMU.reset(
new jevois::IMUi2c(std::dynamic_pointer_cast<jevois::Camera>(itsCamera)));
729 #ifdef JEVOIS_PLATFORM_PRO
733 }
catch (...) {
LERROR(
"Sensor should have an IMU but we failed to initialize it."); }
737 LINFO(
"Using movie input " << camdev <<
" -- issue a 'streamon' to start processing.");
750 videomapping::freeze();
752 if (midx >=
int(itsMappings.size()))
753 {
LERROR(
"Mapping index " << midx <<
" out of range -- USING DEFAULT"); midx = -1; }
755 if (midx < 0) midx = itsDefaultMappingIdx;
761 LINFO(
"Using no USB video output.");
764 itsManualStreamon =
true;
768 LINFO(
"Loading USB video driver " << gd);
772 else if (gd.empty() ==
false)
774 LINFO(
"Saving output video to file " << gd);
777 itsManualStreamon =
true;
786 LINFO(
"Using OpenGL + ImGui display for video output");
791 LINFO(
"Using OpenGL display for video output");
796 LINFO(
"Using OpenCV display for video output");
800 itsManualStreamon =
true;
804 itsRunning.store(
true);
810 runScriptFromFile(JEVOIS_ENGINE_INIT_SCRIPT,
nullptr,
false);
822 itsRunning.store(
false);
824 #ifdef JEVOIS_PLATFORM_A33
826 itsCheckingMassStorage.store(
false);
832 if (itsModule) removeComponent(itsModule);
843 #ifdef JEVOIS_PLATFORM_A33
845 if (itsCheckMassStorageFut.valid())
854 #ifdef JEVOIS_PLATFORM_A33
855 void jevois::Engine::checkMassStorage()
857 itsCheckingMassStorage.store(
true);
859 while (itsCheckingMassStorage.load())
865 std::ifstream ifs(
"/sys/devices/platform/sunxi_usb_udc/gadget/lun0/mass_storage_in_use");
868 int inuse; ifs >> inuse;
869 if (itsMassStorageMode.load())
871 if (inuse == 0) stopMassStorageMode();
878 std::this_thread::sleep_for(std::chrono::milliseconds(500));
889 if (itsCamera) itsCamera->streamOn();
890 if (itsGadget) itsGadget->streamOn();
891 itsStreaming.store(
true);
900 if (itsGadget) itsGadget->abortStream();
901 if (itsCamera) itsCamera->abortStream();
904 LDEBUG(
"Stopping main loop...");
905 itsStopMainLoop.store(
true);
906 while (itsStopMainLoop.load() && itsRunning.load()) std::this_thread::sleep_for(std::chrono::milliseconds(10));
907 LDEBUG(
"Main loop stopped.");
911 if (itsGadget) itsGadget->streamOff();
912 if (itsCamera) itsCamera->streamOff();
919 itsRequestedFormat.store(idx);
927 LDEBUG(
"Set format number " << idx <<
" start...");
929 if (idx >= itsMappings.size())
930 LFATAL(
"Requested mapping index " << idx <<
" out of range [0 .. " << itsMappings.size()-1 <<
']');
933 setFormatInternal(idx);
934 LDEBUG(
"Set format number " << idx <<
" done");
938 void jevois::Engine::setFormatInternal(
size_t idx)
943 jevois::VideoMapping
const & m = itsMappings[idx];
944 setFormatInternal(m);
948 void jevois::Engine::setFormatInternal(jevois::VideoMapping
const & m,
bool reload)
954 itsModuleConstructionError =
"Unknown error while starting module " + m.modulename +
" ...";
956 #ifdef JEVOIS_PLATFORM_A33
957 if (itsMassStorageMode.load())
958 LFATAL(
"Cannot setup video streaming while in mass-storage mode. Eject the USB drive on your host computer first.");
966 LDEBUG(
"Removing current module " << itsModule->className() <<
": " << itsModule->descriptor());
967 try { removeComponent(itsModule); itsModule.reset();
LDEBUG(
"Current module removed."); }
974 LDEBUG(
"Setting camera format: " << m.cstrall());
975 try { itsCamera->setFormat(m); }
979 itsModuleConstructionError =
"Camera did not accept format:\n\n" + m.cstrall() +
980 "\n\nCheck videomappings.cfg and camera sensor specifications.";
984 LDEBUG(
"Setting gadget format: " << m.ostr());
985 try { itsGadget->setFormat(m); }
989 itsModuleConstructionError =
"Gadget did not accept format:\n\n" + m.ostr() +
990 "\n\nCheck videomappings.cfg for any unsupported output formats.";
996 itsCurrentMapping = m;
999 jevois::engine::frameNumber.store(0);
1007 std::string
const sopath = m.sopath(
true);
1010 if (
python::get() ==
false)
LFATAL(
"Python disabled, delete BOOT:nopython and restart to enable python");
1021 if (itsLoader.get() ==
nullptr || itsLoader->sopath() != sopath)
1023 LINFO(
"Instantiating dynamic loader for " << sopath);
1029 auto version_major = itsLoader->load<int()>(m.modulename +
"_version_major");
1030 auto version_minor = itsLoader->load<int()>(m.modulename +
"_version_minor");
1031 if (version_major() != JEVOIS_VERSION_MAJOR || version_minor() != JEVOIS_VERSION_MINOR)
1032 LERROR(
"Module " << m.modulename <<
" in file " << sopath <<
" was build for JeVois v" << version_major() <<
'.'
1033 << version_minor() <<
", but running framework is v" << JEVOIS_VERSION_STRING <<
" -- TRYING ANYWAY");
1036 auto create = itsLoader->load<std::shared_ptr<jevois::Module>(std::string
const &)>(m.modulename +
"_create");
1037 itsModule = create(m.modulename);
1043 boost::unique_lock<boost::shared_mutex> ulck(itsSubMtx);
1046 itsSubComponents.push_back(itsModule);
1047 itsModule->itsParent =
this;
1048 itsModule->setPath(sopath.substr(0, sopath.rfind(
'/')));
1052 if (itsInitialized) itsModule->runPreInit();
1054 std::string
const paramcfg = itsModule->absolutePath(JEVOIS_MODULE_PARAMS_FILENAME);
1055 std::ifstream ifs(paramcfg);
if (ifs.is_open()) itsModule->setParamsFromStream(ifs, paramcfg);
1057 if (itsInitialized) { itsModule->setInitialized(); itsModule->runPostInit(); }
1060 std::shared_ptr<jevois::UserInterface> ser;
1061 for (
auto & s : itsSerials)
1065 runScriptFromFile(itsModule->absolutePath(JEVOIS_MODULE_SCRIPT_FILENAME), ser,
false);
1067 LINFO(
"Module [" << m.modulename <<
"] loaded, initialized, and ready.");
1068 itsModuleConstructionError.clear();
1074 LERROR(
"Module [" << m.modulename <<
"] startup error and not operational.");
1093 for (
auto & s : itsSerials)
1095 try { s->
writeString(
"INF READY JEVOIS " JEVOIS_VERSION_STRING); }
1098 while (itsRunning.load())
1100 bool dosleep =
true;
1104 itsWatchdog->reset();
1109 int rf = itsRequestedFormat.load();
1113 itsRequestedFormat.store(-2);
1118 if (rf != -1 && itsStreaming.load())
1121 if (itsGadget) itsGadget->abortStream();
1122 if (itsCamera) itsCamera->abortStream();
1124 if (itsGadget) itsGadget->streamOff();
1125 if (itsCamera) itsCamera->streamOff();
1126 itsStreaming.store(
false);
1134 setFormatInternal(itsCurrentMapping,
true);
1140 if (itsGUIhelper) itsGUIhelper->reset( (rf != -1) );
1144 if (rf != -1 && itsCurrentMapping.ofmt != 0)
1148 if (itsCamera) itsCamera->streamOn();
1149 if (itsGadget) itsGadget->streamOn();
1150 itsStreaming.store(
true);
1156 if (itsGUIhelper && itsStreaming.load() ==
false)
1160 if (itsCamera) itsCamera->streamOn();
1161 if (itsGadget) itsGadget->streamOn();
1162 itsStreaming.store(
true);
1168 reportErrorInternal();
1173 if (itsGadget) itsGadget->abortStream();
1174 if (itsCamera) itsCamera->abortStream();
1176 if (itsGadget) itsGadget->streamOff();
1177 if (itsCamera) itsCamera->streamOff();
1178 itsStreaming.store(
false);
1190 if (itsStreaming.load())
1195 if (itsModuleConstructionError.empty() ==
false)
1198 reportErrorInternal(itsModuleConstructionError);
1213 switch (itsCurrentMapping.ofmt)
1222 if (itsGUIhelper) itsGUIhelper->headlessDisplay();
1246 catch (...) { reportErrorInternal(); }
1252 ++ jevois::engine::frameNumber;
1253 itsNumSerialSent.store(0);
1257 if (itsStopMainLoop.load())
1259 itsStreaming.store(
false);
1260 LDEBUG(
"-- Main loop stopped --");
1261 itsStopMainLoop.store(
false);
1266 LDEBUG(
"No processing module loaded or not streaming... Sleeping...");
1267 std::this_thread::sleep_for(std::chrono::milliseconds(25));
1272 for (
auto & s : itsSerials)
1276 std::string str;
bool parsed =
false;
bool success =
false;
1285 pfx = JEVOIS_JVINV_PREFIX;
1286 str = str.substr(pfx.length());
1293 try { parsed = parseCommand(str, s, pfx);
success = parsed; }
1294 catch (std::exception
const & e)
1295 { s->
writeString(pfx, std::string(
"ERR ") + e.what()); parsed =
true; }
1297 { s->
writeString(pfx,
"ERR Unknown error"); parsed =
true; }
1299 if (parsed ==
false)
1304 try { itsModule->parseSerial(str, s);
success =
true; }
1305 catch (std::exception
const & me) { s->
writeString(pfx, std::string(
"ERR ") + me.what()); }
1306 catch (...) { s->
writeString(pfx,
"ERR Command [" + str +
"] not recognized by Engine or Module"); }
1308 else s->
writeString(pfx,
"ERR Unsupported command [" + str +
"] and no module");
1326 if (islog ==
false && slim)
1328 if (itsNumSerialSent.load() >= slim)
return;
1336 case jevois::engine::SerPort::None:
1339 case jevois::engine::SerPort::All:
1340 for (
auto & s : itsSerials)
1344 case jevois::engine::SerPort::Hard:
1345 for (
auto & s : itsSerials)
1350 case jevois::engine::SerPort::USB:
1351 for (
auto & s : itsSerials)
1359 if (itsGUIhelper && ((islog && itsGUIhelper->serlogEnabled()) || (!islog && itsGUIhelper->seroutEnabled())))
1360 for (
auto & s : itsSerials)
1370 if (itsGUIhelper) itsGUIhelper->reportError(err);
1380 if (itsGUIhelper) itsGUIhelper->clearErrors();
1386 void jevois::Engine::reportErrorInternal(std::string
const & err)
1392 if (itsGUIhelper->frameStarted() ==
false) {
unsigned short w,
h; itsGUIhelper->startFrame(w,
h); }
1394 else itsGUIhelper->reportError(err);
1395 itsGUIhelper->endFrame();
1402 if (itsCurrentMapping.ofmt != 0 && itsCurrentMapping.ofmt !=
JEVOISPRO_FMT_GUI && itsVideoErrors.load())
1407 if (itsVideoErrorImage.valid() ==
false) itsGadget->get(itsVideoErrorImage);
1418 if (itsVideoErrorImage.valid()) itsGadget->send(itsVideoErrorImage);
1423 itsVideoErrorImage.invalidate();
1435 {
return itsModule; }
1443 {
return std::dynamic_pointer_cast<jevois::Camera>(itsCamera); }
1447 {
return itsCurrentMapping; }
1451 {
return itsMappings.size(); }
1456 if (idx >= itsMappings.size())
1457 LFATAL(
"Index " << idx <<
" out of range [0 .. " << itsMappings.size()-1 <<
']');
1459 return itsMappings[idx];
1466 if (iformat == 0 || iframe == 0)
return itsDefaultMappingIdx;
1472 float const fps = jevois::VideoMapping::uvcToFps(interval);
1475 for (jevois::VideoMapping
const & m : itsMappings)
1476 if (m.uvcformat == iformat && m.uvcframe == iframe && std::fabs(m.ofps - fps) < 0.1F)
return idx;
1479 LFATAL(
"No video mapping for iformat=" << iformat <<
", iframe=" << iframe <<
", interval=" << interval);
1485 for (jevois::VideoMapping
const & m : itsMappings)
1486 if (m.uvcformat == iformat && m.uvcframe == iframe)
return idx;
1489 LFATAL(
"No video mapping for iformat=" << iformat <<
", iframe=" << iframe <<
", interval=" << interval);
1495 {
return itsMappings[itsDefaultMappingIdx]; }
1499 {
return itsDefaultMappingIdx; }
1504 for (jevois::VideoMapping
const & m : itsMappings)
1509 jevois::VideoMapping
const &
1511 float oframespersec)
const
1513 for (jevois::VideoMapping
const & m : itsMappings)
1514 if (m.match(oformat, owidth, oheight, oframespersec))
return m;
1517 owidth <<
'x' << oheight <<
" @ " << oframespersec <<
" fps");
1521 void jevois::Engine::foreachCamCtrl(std::function<
void(
struct v4l2_queryctrl & qc, std::set<int> & doneids)> && func)
1523 struct v4l2_queryctrl qc = { }; std::set<int> doneids;
1529 qc.id = cls | 0x900;
unsigned int old_id;
1532 qc.id |= V4L2_CTRL_FLAG_NEXT_CTRL; old_id = qc.id;
bool failed =
false;
1533 try { func(qc, doneids); }
catch (...) { failed =
true; }
1537 qc.id |= V4L2_CTRL_FLAG_NEXT_CTRL;
1538 if (qc.id == old_id) { ++qc.id;
if (qc.id > 100 + (cls | 0x900 | V4L2_CTRL_FLAG_NEXT_CTRL))
break; }
1539 else if (failed)
break;
1545 std::string jevois::Engine::camctrlname(
unsigned int id,
char const * longname)
const
1547 for (
size_t i = 0; i <
sizeof camcontrols /
sizeof camcontrols[0]; ++i)
1548 if (camcontrols[i].
id ==
id)
return camcontrols[i].shortname;
1551 return abbreviate(longname);
1555 unsigned int jevois::Engine::camctrlid(std::string
const & shortname)
1557 for (
size_t i = 0; i <
sizeof camcontrols /
sizeof camcontrols[0]; ++i)
1558 if (shortname.compare(camcontrols[i].shortname) == 0)
return camcontrols[i].id;
1561 struct v4l2_queryctrl qc = { };
1567 qc.id = cls | 0x900;
1570 qc.id |= V4L2_CTRL_FLAG_NEXT_CTRL;
unsigned int old_id = qc.id;
bool failed =
false;
1573 itsCamera->queryControl(qc);
1574 if (abbreviate(
reinterpret_cast<char const *
>(qc.name)) == shortname)
return qc.id;
1576 catch (...) { failed =
true; }
1581 qc.id |= V4L2_CTRL_FLAG_NEXT_CTRL;
1582 if (qc.id == old_id) { ++qc.id;
if (qc.id > 100 + (cls | 0x900 | V4L2_CTRL_FLAG_NEXT_CTRL))
break; }
1583 else if (failed)
break;
1587 LFATAL(
"Could not find control [" << shortname <<
"] in the camera");
1591 std::string jevois::Engine::camCtrlHelp(
struct v4l2_queryctrl & qc, std::set<int> & doneids)
1594 itsCamera->queryControl(qc);
1595 qc.id &= ~V4L2_CTRL_FLAG_NEXT_CTRL;
1598 if (doneids.find(qc.id) != doneids.end())
return std::string();
else doneids.insert(qc.id);
1601 struct v4l2_control ctrl = { }; ctrl.id = qc.id;
1602 itsCamera->getControl(ctrl);
1605 std::ostringstream ss;
1606 ss <<
"- " << camctrlname(qc.id,
reinterpret_cast<char const *
>(qc.name));
1610 case V4L2_CTRL_TYPE_INTEGER:
1611 ss <<
" [int] min=" << qc.minimum <<
" max=" << qc.maximum <<
" step=" << qc.step
1612 <<
" def=" << qc.default_value <<
" curr=" << ctrl.value;
1624 case V4L2_CTRL_TYPE_BOOLEAN:
1625 ss <<
" [bool] default=" << qc.default_value <<
" curr=" << ctrl.value;
1634 case V4L2_CTRL_TYPE_BUTTON:
1638 case V4L2_CTRL_TYPE_BITMASK:
1639 ss <<
" [bitmask] max=" << qc.maximum <<
" def=" << qc.default_value <<
" curr=" << ctrl.value;
1642 case V4L2_CTRL_TYPE_MENU:
1644 struct v4l2_querymenu querymenu = { };
1645 querymenu.id = qc.id;
1646 ss <<
" [menu] values ";
1647 for (querymenu.index = qc.minimum; querymenu.index <= (
unsigned int)qc.maximum; ++querymenu.index)
1649 try { itsCamera->queryMenu(querymenu); }
catch (...) { strcpy((
char *)(querymenu.name),
"fixme"); }
1650 ss << querymenu.index <<
':' << querymenu.name <<
' ';
1652 ss <<
"curr=" << ctrl.value;
1657 ss <<
"[unknown type]";
1660 if (qc.flags & V4L2_CTRL_FLAG_DISABLED) ss <<
" [DISABLED]";
1666 std::string jevois::Engine::camCtrlInfo(
struct v4l2_queryctrl & qc, std::set<int> & doneids)
1669 itsCamera->queryControl(qc);
1670 qc.id &= ~V4L2_CTRL_FLAG_NEXT_CTRL;
1673 if (doneids.find(qc.id) != doneids.end())
return std::string();
else doneids.insert(qc.id);
1676 struct v4l2_control ctrl = { }; ctrl.id = qc.id;
1677 itsCamera->getControl(ctrl);
1680 std::ostringstream ss;
1681 ss << camctrlname(qc.id,
reinterpret_cast<char const *
>(qc.name));
1683 if (qc.flags & V4L2_CTRL_FLAG_DISABLED) ss <<
" D ";
1687 case V4L2_CTRL_TYPE_INTEGER:
1688 ss <<
" I " << qc.minimum <<
' ' << qc.maximum <<
' ' << qc.step
1689 <<
' ' << qc.default_value <<
' ' << ctrl.value;
1700 case V4L2_CTRL_TYPE_BOOLEAN:
1701 ss <<
" B " << qc.default_value <<
' ' << ctrl.value;
1709 case V4L2_CTRL_TYPE_BUTTON:
1713 case V4L2_CTRL_TYPE_BITMASK:
1714 ss <<
" K " << qc.maximum <<
' ' << qc.default_value <<
' ' << ctrl.value;
1717 case V4L2_CTRL_TYPE_MENU:
1719 struct v4l2_querymenu querymenu = { };
1720 querymenu.id = qc.id;
1721 ss <<
" M " << qc.default_value <<
' ' << ctrl.value;
1722 for (querymenu.index = qc.minimum; querymenu.index <= (
unsigned int)qc.maximum; ++querymenu.index)
1724 try { itsCamera->queryMenu(querymenu); }
catch (...) { strcpy((
char *)(querymenu.name),
"fixme"); }
1725 ss <<
' ' << querymenu.index <<
':' << querymenu.name <<
' ';
1737 #ifdef JEVOIS_PLATFORM_A33
1739 void jevois::Engine::startMassStorageMode()
1743 if (itsMassStorageMode.load()) {
LERROR(
"Already in mass-storage mode -- IGNORED");
return; }
1746 if (itsModule) { removeComponent(itsModule); itsModule.reset(); }
1747 if (itsLoader) itsLoader.reset();
1751 if (
std::system(
"mount -o remount,ro /jevois"))
LERROR(
"Failed to remount /jevois read-only -- IGNORED");
1754 std::ofstream ofs(JEVOIS_USBSD_SYS);
1755 if (ofs.is_open() ==
false)
LFATAL(
"Cannot setup mass-storage backing file to " << JEVOIS_USBSD_SYS);
1756 ofs << JEVOIS_USBSD_FILE << std::endl;
1758 LINFO(
"Exported JEVOIS partition of microSD to host computer as virtual flash drive.");
1759 itsMassStorageMode.store(
true);
1763 void jevois::Engine::stopMassStorageMode()
1766 LINFO(
"JeVois virtual USB drive ejected by host -- REBOOTING");
1776 #ifdef JEVOIS_PLATFORM_A33
1777 itsCheckingMassStorage.store(
false);
1779 itsRunning.store(
false);
1781 #ifdef JEVOIS_PLATFORM_A33
1783 if ( ! std::ofstream(
"/proc/sys/kernel/sysrq").put(
'1'))
LERROR(
"Cannot trigger hard reset -- please unplug me!");
1784 if ( ! std::ofstream(
"/proc/sysrq-trigger").put(
's'))
LERROR(
"Cannot trigger hard reset -- please unplug me!");
1785 if ( ! std::ofstream(
"/proc/sysrq-trigger").put(
'b'))
LERROR(
"Cannot trigger hard reset -- please unplug me!");
1796 itsGadget->abortStream();
1797 itsCamera->abortStream();
1798 itsStreaming.store(
false);
1799 itsGadget->streamOff();
1800 itsCamera->streamOff();
1801 itsRunning.store(
false);
1807 void jevois::Engine::cmdInfo(std::shared_ptr<UserInterface> s,
bool showAll, std::string
const & pfx)
1809 s->
writeString(pfx,
"help - print this help message");
1810 s->
writeString(pfx,
"help2 - print compact help message about current vision module only");
1811 s->
writeString(pfx,
"info - show system information including CPU speed, load and temperature");
1812 s->
writeString(pfx,
"setpar <name> <value> - set a parameter value");
1813 s->
writeString(pfx,
"getpar <name> - get a parameter value(s)");
1814 s->
writeString(pfx,
"runscript <filename> - run script commands in specified file");
1815 s->
writeString(pfx,
"setcam <ctrl> <val> - set camera control <ctrl> to value <val>");
1816 s->
writeString(pfx,
"getcam <ctrl> - get value of camera control <ctrl>");
1820 s->
writeString(pfx,
"setcamreg <reg> <val> - set raw camera register <reg> to value <val>");
1821 s->
writeString(pfx,
"getcamreg <reg> - get value of raw camera register <reg>");
1822 s->
writeString(pfx,
"setimureg <reg> <val> - set raw IMU register <reg> to value <val>");
1823 s->
writeString(pfx,
"getimureg <reg> - get value of raw IMU register <reg>");
1824 s->
writeString(pfx,
"setimuregs <reg> <num> <val1> ... <valn> - set array of raw IMU register values");
1825 s->
writeString(pfx,
"getimuregs <reg> <num> - get array of raw IMU register values");
1826 s->
writeString(pfx,
"setdmpreg <reg> <val> - set raw DMP register <reg> to value <val>");
1827 s->
writeString(pfx,
"getdmpreg <reg> - get value of raw DMP register <reg>");
1828 s->
writeString(pfx,
"setdmpregs <reg> <num> <val1> ... <valn> - set array of raw DMP register values");
1829 s->
writeString(pfx,
"getdmpregs <reg> <num> - get array of raw DMP register values");
1832 s->
writeString(pfx,
"listmappings - list all available video mappings");
1833 s->
writeString(pfx,
"setmapping <num> - select video mapping <num>, only possible while not streaming");
1834 s->
writeString(pfx,
"setmapping2 <CAMmode> <CAMwidth> <CAMheight> <CAMfps> <Vendor> <Module> - set no-USB-out "
1835 "video mapping defined on the fly, while not streaming");
1836 s->
writeString(pfx,
"reload - reload and reset the current module");
1838 if (showAll || itsCurrentMapping.ofmt == 0 || itsManualStreamon)
1840 s->
writeString(pfx,
"streamon - start camera video streaming");
1841 s->
writeString(pfx,
"streamoff - stop camera video streaming");
1845 s->
writeString(pfx,
"serlog <string> - forward string to the serial port(s) specified by the serlog parameter");
1846 s->
writeString(pfx,
"serout <string> - forward string to the serial port(s) specified by the serout parameter");
1851 s->
writeString(pfx,
"caminfo - returns machine-readable info about camera parameters");
1852 s->
writeString(pfx,
"cmdinfo [all] - returns machine-readable info about Engine commands");
1853 s->
writeString(pfx,
"modcmdinfo - returns machine-readable info about Module commands");
1854 s->
writeString(pfx,
"paraminfo [hot|mod|modhot] - returns machine-readable info about parameters");
1855 s->
writeString(pfx,
"serinfo - returns machine-readable info about serial settings (serout serlog serstyle serprec serstamp)");
1856 s->
writeString(pfx,
"fileget <filepath> - get a file from JeVois to the host. Use with caution!");
1857 s->
writeString(pfx,
"fileput <filepath> - put a file from the host to JeVois. Use with caution!");
1860 #ifdef JEVOIS_PLATFORM_A33
1861 s->
writeString(pfx,
"usbsd - export the JEVOIS partition of the microSD card as a virtual USB drive");
1863 s->
writeString(pfx,
"sync - commit any pending data write to microSD");
1864 s->
writeString(pfx,
"date [date and time] - get or set the system date and time");
1866 s->
writeString(pfx,
"!<string> - execute <string> as a Linux shell command. Use with caution!");
1867 s->
writeString(pfx,
"shell <string> - execute <string> as a Linux shell command. Use with caution!");
1868 s->
writeString(pfx,
"shellstart - execute all subsequent commands as Linux shell commands. Use with caution!");
1869 s->
writeString(pfx,
"shellstop - stop executing all subsequent commands as Linux shell commands.");
1872 s->
writeString(pfx,
"dnnget <key> - download and install a DNN from JeVois Model Converter");
1875 #ifdef JEVOIS_PLATFORM
1876 s->
writeString(pfx,
"restart - restart the JeVois smart camera");
1879 #ifndef JEVOIS_PLATFORM_A33
1885 void jevois::Engine::modCmdInfo(std::shared_ptr<UserInterface> s, std::string
const & pfx)
1889 std::stringstream css; itsModule->supportedCommands(css);
1890 for (std::string line; std::getline(css, line); ) s->
writeString(pfx, line);
1904 if (str ==
"shellstop") { itsShellMode =
false;
return true; }
1908 for (std::string
const & r : rvec) s->
writeString(pfx, r);
1924 switch (str.length())
1927 LDEBUG(
"Ignoring empty string");
return true;
1931 if (str[0] ==
'~') {
LDEBUG(
"Ignoring modem config command [~]");
return true; }
1935 if (str[0] ==
'#') { sendSerial(str,
true);
return true; }
1941 if (str[0] ==
'~') {
LDEBUG(
"Ignoring modem config command [" << str <<
']');
return true; }
1944 if (str[0] ==
'A' && str[1] ==
'T') {
LDEBUG(
"Ignoring AT command [" << str <<
']');
return true; }
1948 if (str[0] ==
'#') { sendSerial(str,
true);
return true; }
1951 std::string cmd, rem;
1954 cmd =
"shell"; rem = str.substr(1);
1959 size_t const idx = str.find(
' ');
1960 if (idx == str.npos) cmd = str;
1961 else { cmd = str.substr(0, idx);
if (idx < str.length()) rem = str.substr(idx+1); }
1970 cmdInfo(s,
false, pfx);
1983 std::stringstream pss; constructHelpMessage(pss);
1984 for (std::string line; std::getline(pss, line); ) s->
writeString(pfx, line);
1987 s->
writeString(pfx,
"AVAILABLE CAMERA CONTROLS:");
1990 foreachCamCtrl([
this,&pfx,&s](
struct v4l2_queryctrl & qc, std::set<int> & doneids)
1994 std::string hlp = camCtrlHelp(qc, doneids);
1995 if (hlp.empty() ==
false) s->
writeString(pfx, hlp);
2002 if (cmd ==
"caminfo")
2005 foreachCamCtrl([
this,&pfx,&s](
struct v4l2_queryctrl & qc, std::set<int> & doneids)
2009 std::string hlp = camCtrlInfo(qc, doneids);
2010 if (hlp.empty() ==
false) s->
writeString(pfx, hlp);
2017 if (cmd ==
"cmdinfo")
2019 bool showAll = (rem ==
"all") ?
true :
false;
2020 cmdInfo(s, showAll, pfx);
2025 if (cmd ==
"modcmdinfo")
2032 if (cmd ==
"paraminfo")
2034 std::map<std::string, std::string> categs;
2035 bool skipFrozen = (rem ==
"hot" || rem ==
"modhot") ?
true :
false;
2037 if (rem ==
"mod" || rem ==
"modhot")
2040 if (itsModule) itsModule->paramInfo(s, categs, skipFrozen, instanceName(), pfx);
2045 paramInfo(s, categs, skipFrozen,
"", pfx);
2052 if (cmd ==
"serinfo")
2054 std::string info = getParamStringUnique(
"serout") +
' ' + getParamStringUnique(
"serlog");
2056 info +=
' ' + mod->getParamStringUnique(
"serstyle") +
' ' + mod->getParamStringUnique(
"serprec") +
2057 ' ' + mod->getParamStringUnique(
"serstamp");
2058 else info +=
" - - -";
2071 std::stringstream css; itsModule->supportedCommands(css);
2074 for (std::string line; std::getline(css, line); ) s->
writeString(pfx, line);
2082 std::unordered_map<std::string,
2083 std::unordered_map<std::string,
2084 std::vector<std::pair<std::string,
2087 itsModule->populateHelpMessage(
"", helplist);
2089 if (helplist.empty())
2093 for (
auto const & c : helplist)
2099 for (
auto const & n : c.second)
2101 std::vector<std::string> tok =
jevois::split(n.first,
"[\\r\\n]+");
2103 for (
auto const & t : tok)
2108 auto const & v = n.second;
2111 if (v[0].second.empty())
2114 s->
writeString(pfx, t +
" current=[" + v[0].second +
']');
2116 else if (v.size() > 1)
2118 std::string sss = t +
" current=";
2119 for (
auto const & pp : v)
2120 if (pp.second.empty() ==
false) sss +=
'[' + pp.first +
':' + pp.second +
"] ";
2145 s->
writeString(pfx,
"INFO: JeVois " JEVOIS_VERSION_STRING);
2149 if (itsModule) s->
writeString(pfx,
"INFO: " + itsCurrentMapping.str());
2150 else s->
writeString(pfx,
"INFO: " + jevois::VideoMapping().str());
2155 if (cmd ==
"setpar")
2157 size_t const remidx = rem.find(
' ');
2158 if (remidx != rem.npos)
2160 std::string
const desc = rem.substr(0, remidx);
2161 if (remidx < rem.length())
2163 std::string
const val = rem.substr(remidx+1);
2164 setParamString(desc, val);
2168 errmsg =
"Need to provide a parameter name and a parameter value in setpar";
2172 if (cmd ==
"getpar")
2174 auto vec = getParamString(rem);
2175 for (
auto const & p : vec) s->
writeString(pfx, p.first +
' ' + p.second);
2180 if (cmd ==
"setcam")
2182 std::istringstream ss(rem); std::string ctrl;
int val; ss >> ctrl >> val;
2183 struct v4l2_control c = { }; c.id = camctrlid(ctrl); c.value = val;
2186 if (val == 0 && ctrl ==
"ispsensorpreset")
2188 c.value = 1; itsCamera->setControl(c);
2189 c.value = 0; itsCamera->setControl(c);
2191 else itsCamera->setControl(c);
2197 if (cmd ==
"getcam")
2199 struct v4l2_control c = { }; c.id = camctrlid(rem);
2200 itsCamera->getControl(c);
2206 if (cmd ==
"setcamreg")
2210 auto cam = std::dynamic_pointer_cast<jevois::Camera>(itsCamera);
2214 std::istringstream ss(rem); std::string reg, val; ss >> reg >> val;
2215 cam->writeRegister(std::stoi(reg,
nullptr, 0), std::stoi(val,
nullptr, 0));
2218 else errmsg =
"Not using a camera for video input";
2220 else errmsg =
"Access to camera registers is disabled, enable with: setpar camreg true";
2224 if (cmd ==
"getcamreg")
2228 auto cam = std::dynamic_pointer_cast<jevois::Camera>(itsCamera);
2231 unsigned int val = cam->readRegister(std::stoi(rem,
nullptr, 0));
2232 std::ostringstream os; os << std::hex << val;
2236 else errmsg =
"Not using a camera for video input";
2238 else errmsg =
"Access to camera registers is disabled, enable with: setpar camreg true";
2242 if (cmd ==
"setimureg")
2249 std::istringstream ss(rem); std::string reg, val; ss >> reg >> val;
2250 itsIMU->writeRegister(std::stoi(reg,
nullptr, 0), std::stoi(val,
nullptr, 0));
2253 else errmsg =
"No IMU driver loaded";
2255 else errmsg =
"Access to IMU registers is disabled, enable with: setpar imureg true";
2259 if (cmd ==
"getimureg")
2265 unsigned int val = itsIMU->readRegister(std::stoi(rem,
nullptr, 0));
2266 std::ostringstream os; os << std::hex << val;
2270 else errmsg =
"No IMU driver loaded";
2272 else errmsg =
"Access to IMU registers is disabled, enable with: setpar imureg true";
2276 if (cmd ==
"setimuregs")
2284 if (v.size() < 3) errmsg =
"Malformed arguments, need at least 3";
2287 unsigned short reg = std::stoi(v[0],
nullptr, 0);
2288 size_t num = std::stoi(v[1],
nullptr, 0);
2289 if (num > 32) errmsg =
"Maximum transfer size is 32 bytes";
2290 else if (num != v.size() - 2) errmsg =
"Incorrect number of data bytes, should pass " + v[1] +
" values.";
2293 unsigned char data[32];
2294 for (
size_t i = 2; i < v.size(); ++i) data[i-2] = std::stoi(v[i],
nullptr, 0) & 0xff;
2296 itsIMU->writeRegisterArray(reg, data, num);
2301 else errmsg =
"No IMU driver loaded";
2303 else errmsg =
"Access to IMU registers is disabled, enable with: setpar imureg true";
2307 if (cmd ==
"getimuregs")
2313 std::istringstream ss(rem); std::string reg, num; ss >> reg >> num;
2314 int n = std::stoi(num,
nullptr, 0);
2316 if (n > 32) errmsg =
"Maximum transfer size is 32 bytes";
2319 unsigned char data[32];
2320 itsIMU->readRegisterArray(std::stoi(reg,
nullptr, 0), data, n);
2322 std::ostringstream os; os << std::hex;
2323 for (
int i = 0; i < n; ++i) os << (
unsigned int)(data[i]) <<
' ';
2328 else errmsg =
"No IMU driver loaded";
2330 else errmsg =
"Access to IMU registers is disabled, enable with: setpar imureg true";
2334 if (cmd ==
"setdmpreg")
2341 std::istringstream ss(rem); std::string reg, val; ss >> reg >> val;
2342 itsIMU->writeDMPregister(std::stoi(reg,
nullptr, 0), std::stoi(val,
nullptr, 0));
2345 else errmsg =
"No IMU driver loaded";
2347 else errmsg =
"Access to IMU registers is disabled, enable with: setpar imureg true";
2351 if (cmd ==
"getdmpreg")
2357 unsigned int val = itsIMU->readDMPregister(std::stoi(rem,
nullptr, 0));
2358 std::ostringstream os; os << std::hex << val;
2362 else errmsg =
"No IMU driver loaded";
2364 else errmsg =
"Access to IMU registers is disabled, enable with: setpar imureg true";
2368 if (cmd ==
"setdmpregs")
2376 if (v.size() < 3) errmsg =
"Malformed arguments, need at least 3";
2379 unsigned short reg = std::stoi(v[0],
nullptr, 0);
2380 size_t num = std::stoi(v[1],
nullptr, 0);
2381 if (num > 32) errmsg =
"Maximum transfer size is 32 bytes";
2382 else if (num != v.size() - 2) errmsg =
"Incorrect number of data bytes, should pass " + v[1] +
" values.";
2385 unsigned char data[32];
2386 for (
size_t i = 2; i < v.size(); ++i) data[i-2] = std::stoi(v[i],
nullptr, 0) & 0xff;
2388 itsIMU->writeDMPregisterArray(reg, data, num);
2393 else errmsg =
"No IMU driver loaded";
2395 else errmsg =
"Access to IMU registers is disabled, enable with: setpar imureg true";
2399 if (cmd ==
"getdmpregs")
2405 std::istringstream ss(rem); std::string reg, num; ss >> reg >> num;
2406 int n = std::stoi(num,
nullptr, 0);
2408 if (n > 32) errmsg =
"Maximum transfer size is 32 bytes";
2411 unsigned char data[32];
2412 itsIMU->readDMPregisterArray(std::stoi(reg,
nullptr, 0), data, n);
2414 std::ostringstream os; os << std::hex;
2415 for (
int i = 0; i < n; ++i) os << (
unsigned int)(data[i]) <<
' ';
2420 else errmsg =
"No IMU driver loaded";
2422 else errmsg =
"Access to IMU registers is disabled, enable with: setpar imureg true";
2426 if (cmd ==
"listmappings")
2430 for (
size_t idx = 0; idx < itsMappings.size(); ++idx)
2433 if (idxstr.length() < 5) idxstr = std::string(5 - idxstr.length(),
' ') + idxstr;
2434 s->
writeString(pfx, idxstr +
" - " + itsMappings[idx].str());
2440 if (cmd ==
"setmapping")
2442 size_t const idx = std::stoi(rem);
2444 if (itsStreaming.load() && itsCurrentMapping.ofmt)
2445 errmsg =
"Cannot set mapping while streaming: Stop your webcam program on the host computer first.";
2446 else if (idx >= itsMappings.size())
2447 errmsg =
"Requested mapping index " +
std::to_string(idx) +
" out of range [0 .. " +
2453 setFormatInternal(idx);
2456 catch (std::exception
const & e) { errmsg =
"Error parsing or setting mapping [" + rem +
"]: " + e.what(); }
2457 catch (...) { errmsg =
"Error parsing or setting mapping [" + rem +
']'; }
2462 if (cmd ==
"setmapping2")
2464 if (itsStreaming.load() && itsCurrentMapping.ofmt)
2465 errmsg =
"Cannot set mapping while streaming: Stop your webcam program on the host computer first.";
2470 jevois::VideoMapping m; std::istringstream full(
"NONE 0 0 0.0 " + rem); full >> m;
2471 setFormatInternal(m);
2474 catch (std::exception
const & e) { errmsg =
"Error parsing or setting mapping [" + rem +
"]: " + e.what(); }
2475 catch (...) { errmsg =
"Error parsing or setting mapping [" + rem +
']'; }
2480 if (cmd ==
"reload")
2482 setFormatInternal(itsCurrentMapping,
true);
2487 if (itsCurrentMapping.ofmt == 0 || itsCurrentMapping.ofmt ==
JEVOISPRO_FMT_GUI || itsManualStreamon)
2489 if (cmd ==
"streamon")
2492 itsCamera->streamOn();
2493 itsGadget->streamOn();
2494 itsStreaming.store(
true);
2498 if (cmd ==
"streamoff")
2501 itsGadget->abortStream();
2502 itsCamera->abortStream();
2504 itsStreaming.store(
false);
2506 itsGadget->streamOff();
2507 itsCamera->streamOff();
2520 if (cmd ==
"serlog")
2522 sendSerial(rem,
true);
2527 if (cmd ==
"serout")
2529 sendSerial(rem,
false);
2534 #ifdef JEVOIS_PLATFORM_A33
2537 if (itsStreaming.load())
2539 errmsg =
"Cannot export microSD over USB while streaming: ";
2540 if (itsCurrentMapping.ofmt) errmsg +=
"Stop your webcam program on the host computer first.";
2541 else errmsg +=
"Issue a 'streamoff' command first.";
2545 startMassStorageMode();
2554 if (
std::system(
"sync")) errmsg =
"Disk sync failed";
2562 s->
writeString(pfx,
"date now " + dat.substr(0, dat.size()-1));
2567 if (cmd ==
"runscript")
2569 std::string
const fname = itsModule ? itsModule->absolutePath(rem).string() : rem;
2571 try { runScriptFromFile(fname, s,
true);
return true; }
2572 catch (...) { errmsg =
"Script " + fname +
" execution failed"; }
2580 for (std::string
const & r : rvec) s->
writeString(pfx, r);
2585 if (cmd ==
"shellstart")
2587 itsShellMode =
true;
2594 if (cmd ==
"dnnget")
2596 if (rem.length() != 4 || std::regex_match(rem, std::regex(
"^[a-zA-Z0-9]+$")) ==
false)
2597 errmsg =
"Key must be a 4-character alphanumeric string, as emailed to you by the model converter.";
2601 s->
writeString(pfx,
"Downloading custom DNN model " + rem +
" ...");
2602 std::string
const zip = rem +
".zip";
2603 std::string ret =
jevois::system(
"/usr/bin/curl " JEVOIS_CUSTOM_DNN_URL
"/" + zip +
" -o "
2604 JEVOIS_CUSTOM_DNN_PATH
"/" + zip,
true);
2606 for (std::string
const & r : rvec) s->
writeString(pfx, r);
2609 std::ifstream ifs(JEVOIS_CUSTOM_DNN_PATH
"/" + zip);
2610 if (ifs.is_open() ==
false)
2611 errmsg =
"Failed to download. Check network connectivity and available disk space.";
2615 s->
writeString(pfx,
"Unpacking custom DNN model " + rem +
" ...");
2616 ret =
jevois::system(
"/usr/bin/unzip -o " JEVOIS_CUSTOM_DNN_PATH
"/" + zip +
2617 " -d " JEVOIS_CUSTOM_DNN_PATH,
true);
2620 ret =
jevois::system(
"/bin/rm " JEVOIS_CUSTOM_DNN_PATH
"/" + zip,
true);
2623 s->
writeString(pfx,
"Reload your model zoo for changes to take effect.");
2632 if (cmd ==
"fileget")
2634 std::shared_ptr<jevois::Serial> ser = std::dynamic_pointer_cast<jevois::Serial>(s);
2636 errmsg =
"File transfer only supported over USB or Hard serial ports";
2639 std::string
const abspath = itsModule ? itsModule->absolutePath(rem).string() : rem;
2646 if (cmd ==
"fileput")
2648 std::shared_ptr<jevois::Serial> ser = std::dynamic_pointer_cast<jevois::Serial>(s);
2650 errmsg =
"File transfer only supported over USB or Hard serial ports";
2653 std::string
const abspath = itsModule ? itsModule->absolutePath(rem).string() : rem;
2660 #ifdef JEVOIS_PLATFORM
2662 if (cmd ==
"restart")
2664 s->
writeString(pfx,
"Restart command received - bye-bye!");
2666 if (itsStreaming.load())
2667 s->
writeString(pfx,
"ERR Video streaming is on - you should quit your video viewer before rebooting");
2671 #ifdef JEVOIS_PLATFORM_A33
2673 std::ofstream(JEVOIS_USBSD_SYS).put(
'\n');
2685 #ifndef JEVOIS_PLATFORM_A33
2689 s->
writeString(pfx,
"Quit command received - bye-bye!");
2700 if (errmsg.size())
throw std::runtime_error(
"Command error [" + str +
"]: " + errmsg);
2711 std::ifstream ifs(filename);
2712 if (!ifs) {
if (throw_no_file)
LFATAL(
"Could not open file " << filename);
else return; }
2718 if (itsSerials.empty())
LFATAL(
"Need at least one active serial to run script");
2722 case jevois::engine::SerPort::Hard:
2726 case jevois::engine::SerPort::USB:
2738 if (!ser) ser = itsSerials.front();
2743 for (std::string line; std::getline(ifs, line); )
2751 if (line.length() == 0 || line[0] ==
'#')
continue;
2756 bool parsed =
false;
2757 try { parsed = parseCommand(line, ser); }
2758 catch (std::exception
const & e)
2763 if (parsed ==
false)
2767 try { itsModule->parseSerial(line, ser); }
2768 catch (std::exception
const & me)
2773 else ser->
writeString(
"ERR Unsupported command [" + line +
"] and no module");
2785 ImGui::Columns(2,
"camctrl");
2787 foreachCamCtrl([
this](
struct v4l2_queryctrl & qc, std::set<int> & doneids)
2789 try { camCtrlGUI(qc, doneids); }
catch (...) { }
2796 void jevois::Engine::camCtrlGUI(
struct v4l2_queryctrl & qc, std::set<int> & doneids)
2799 itsCamera->queryControl(qc);
2800 qc.id &= ~V4L2_CTRL_FLAG_NEXT_CTRL;
2803 if (doneids.find(qc.id) != doneids.end())
return;
else doneids.insert(qc.id);
2806 struct v4l2_control ctrl = { }; ctrl.id = qc.id;
2807 itsCamera->getControl(ctrl);
2810 ImGui::AlignTextToFramePadding();
2811 ImGui::TextUnformatted(
reinterpret_cast<char const *
>(qc.name));
2812 ImGui::NextColumn();
2815 if (qc.flags & V4L2_CTRL_FLAG_DISABLED)
2817 ImGui::PushItemFlag(ImGuiItemFlags_Disabled,
true);
2818 ImGui::PushStyleVar(ImGuiStyleVar_Alpha, ImGui::GetStyle().Alpha * 0.5f);
2822 static char wname[16]; snprintf(wname, 16,
"##c%d", ctrl.id);
2827 case V4L2_CTRL_TYPE_INTEGER:
2828 case V4L2_CTRL_TYPE_INTEGER_MENU:
2831 long range = long(qc.maximum) - long(qc.minimum);
2832 if (range > 1 && range < 5000)
2834 if (ImGui::SliderInt(wname, &ctrl.value, qc.minimum, qc.maximum)) itsCamera->setControl(ctrl);
2839 if (ImGui::InputInt(wname, &ctrl.value, qc.step, qc.step * 2)) itsCamera->setControl(ctrl);
2856 case V4L2_CTRL_TYPE_BOOLEAN:
2858 bool checked = (ctrl.value != 0);
2859 if (ImGui::Checkbox(wname, &checked)) { ctrl.value = checked ? 1 : 0; itsCamera->setControl(ctrl); }
2864 case V4L2_CTRL_TYPE_BUTTON:
2865 static char bname[16]; snprintf(bname, 16,
"Go##%d", ctrl.id);
2866 if (ImGui::Button(bname)) { ctrl.value = 1; itsCamera->setControl(ctrl); }
2869 case V4L2_CTRL_TYPE_BITMASK:
2873 case V4L2_CTRL_TYPE_MENU:
2875 struct v4l2_querymenu querymenu = { };
2876 querymenu.id = qc.id;
2877 char * items[qc.maximum - qc.minimum + 1];
2879 for (querymenu.index = qc.minimum; querymenu.index <= (
unsigned int)qc.maximum; ++querymenu.index)
2881 try { itsCamera->queryMenu(querymenu); }
catch (...) { strncpy((
char *)querymenu.name,
"fixme", 32); }
2882 items[querymenu.index] =
new char[32];
2883 strncpy(items[querymenu.index], (
char const *)querymenu.name, 32);
2886 int idx = ctrl.value - qc.minimum;
2887 if (ImGui::Combo(wname, &idx, items, qc.maximum - qc.minimum + 1))
2888 { ctrl.value = qc.minimum + idx; itsCamera->setControl(ctrl); }
2890 for (
int i = qc.minimum; i <= qc.maximum; ++i)
delete [] items[i];
2900 static char rname[16]; snprintf(rname, 16,
"Reset##%d", ctrl.id);
2902 if (ImGui::Button(rname)) { ctrl.value = qc.default_value; itsCamera->setControl(ctrl); }
2906 if (qc.flags & V4L2_CTRL_FLAG_DISABLED)
2908 ImGui::PopItemFlag();
2909 ImGui::PopStyleVar();
2913 ImGui::NextColumn();
2917 #endif // JEVOIS_PRO
2923 std::lock_guard<std::mutex> _(itsPyRegMtx);
2924 auto itr = itsPythonRegistry.find(pyinst);
2925 if (itr != itsPythonRegistry.end())
LFATAL(
"Trying to register twice -- ABORT");
2926 itsPythonRegistry.insert(std::make_pair(pyinst, comp));
2933 std::lock_guard<std::mutex> _(itsPyRegMtx);
2934 auto itr = itsPythonRegistry.begin(), stop = itsPythonRegistry.end();
2935 while (itr != stop)
if (itr->second == comp) itr = itsPythonRegistry.erase(itr);
else ++itr;
2941 LDEBUG(std::hex << pyinst);
2942 std::lock_guard<std::mutex> _(itsPyRegMtx);
2943 auto itr = itsPythonRegistry.find(pyinst);
2944 if (itr == itsPythonRegistry.end())
LFATAL(
"Python instance not registered -- ABORT");