Browse Source

driver_cloud_grpc_civetweb. but not complete.

yuchuli 3 years ago
parent
commit
61054f8f94

+ 73 - 0
src/driver/driver_cloud_grpc_civetweb/.gitignore

@@ -0,0 +1,73 @@
+# This file is used to ignore files which are generated
+# ----------------------------------------------------------------------------
+
+*~
+*.autosave
+*.a
+*.core
+*.moc
+*.o
+*.obj
+*.orig
+*.rej
+*.so
+*.so.*
+*_pch.h.cpp
+*_resource.rc
+*.qm
+.#*
+*.*#
+core
+!core/
+tags
+.DS_Store
+.directory
+*.debug
+Makefile*
+*.prl
+*.app
+moc_*.cpp
+ui_*.h
+qrc_*.cpp
+Thumbs.db
+*.res
+*.rc
+/.qmake.cache
+/.qmake.stash
+
+# qtcreator generated files
+*.pro.user*
+
+# xemacs temporary files
+*.flc
+
+# Vim temporary files
+.*.swp
+
+# Visual Studio generated files
+*.ib_pdb_index
+*.idb
+*.ilk
+*.pdb
+*.sln
+*.suo
+*.vcproj
+*vcproj.*.*.user
+*.ncb
+*.sdf
+*.opensdf
+*.vcxproj
+*vcxproj.*
+
+# MinGW generated files
+*.Debug
+*.Release
+
+# Python byte code
+*.pyc
+
+# Binaries
+# --------
+*.dll
+*.exe
+

+ 63 - 0
src/driver/driver_cloud_grpc_civetweb/driver_cloud_grpc_civetweb.pro

@@ -0,0 +1,63 @@
+QT -= gui
+
+CONFIG += c++11 console
+CONFIG -= app_bundle
+
+# The following define makes your compiler emit warnings if you use
+# any feature of Qt which as been marked deprecated (the exact warnings
+# depend on your compiler). Please consult the documentation of the
+# deprecated API in order to know how to port your code away from it.
+DEFINES += QT_DEPRECATED_WARNINGS
+
+system(protoc -I=./../../include/proto3 --cpp_out=./../../include/msgtype   ./../../include/proto3/uploadthreadmsg.proto)
+
+# You can also make your code fail to compile if you use deprecated APIs.
+# In order to do so, uncomment the following line.
+# You can also select to disable deprecated APIs only up to a certain version of Qt.
+#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0
+
+SOURCES += main.cpp \
+    ../driver_cloud_grpc_thread/uploadthreadmsg.grpc.pb.cc \
+    ../../include/msgtype/uploadthreadmsg.pb.cc \
+    grpcpc.cpp \
+    ../../include/msgtype/cloud.pb.cc \
+    ../../include/msgtype/rawpic.pb.cc \
+    grpccivet.cpp \
+    ../../../thirdpartylib/civetweb/CivetServer.cpp \
+    ../../../thirdpartylib/civetweb/civetweb.c
+
+
+!include(../../../include/common.pri ) {
+    error( "Couldn't find the common.pri file!" )
+}
+
+
+INCLUDEPATH += $$PWD/../../driver/driver_cloud_grpc_thread
+
+INCLUDEPATH += $$PWD/../../../thirdpartylib/grpc/include
+
+LIBS += -L$$PWD/../../../thirdpartylib/grpc/lib
+
+LIBS += -lprotobuf -lyaml-cpp
+
+
+LIBS += -lgrpc++_unsecure -lgrpc++_reflection -labsl_raw_hash_set -labsl_hashtablez_sampler -labsl_exponential_biased -labsl_hash -labsl_bad_variant_access -labsl_city -labsl_status -labsl_cord -labsl_str_format_internal -labsl_synchronization -labsl_graphcycles_internal -labsl_symbolize -labsl_demangle_internal -labsl_stacktrace -labsl_debugging_internal -labsl_malloc_internal -labsl_time -labsl_time_zone -labsl_civil_time -labsl_strings -labsl_strings_internal -labsl_throw_delegate -labsl_int128 -labsl_base -labsl_spinlock_wait -labsl_bad_optional_access -labsl_raw_logging_internal -labsl_log_severity
+
+HEADERS += \
+    ../driver_cloud_grpc_thread/uploadthreadmsg.grpc.pb.h \
+    ../../include/msgtype/uploadthreadmsg.pb.h \
+    grpcpc.h \
+    ../../include/msgtype/cloud.pb.h \
+    ../../include/msgtype/rawpic.pb.h \
+    grpccivet.h \
+    ../../../thirdpartylib/civetweb/CivetServer.h \
+    ../../../thirdpartylib/civetweb/civetweb.h
+
+INCLUDEPATH += $$PWD/../../../thirdpartylib/civetweb
+DEFINES += NO_SSL
+#DEFINES += NO_SSL_DL
+DEFINES += USE_WEBSOCKET
+
+
+
+LIBS += -ldl -lrt

+ 417 - 0
src/driver/driver_cloud_grpc_civetweb/frontend/index.html

@@ -0,0 +1,417 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="UTF-8">
+<title>ADCIV WEB UI. Designed Base CivetWeb.</title>
+<script>
+
+//var i_width=window.document.body.clientWidth//网页可用宽度  
+//var i_height=window.document.body.clientHeight;
+//var pic = document.getElementById("myCanvas");
+//pic.style.height=i_height+"px";
+//pic.style.width=i_width+"px";
+var index=0
+var xc=0
+//var int=self.setInterval('clock()',100);
+var int2=self.setInterval('changeFrontImage()',29);
+var int1=self.setInterval('updatectrl()',100);
+//var int3=self.setInterval('changeRearImage()',29);
+//var int4=self.setInterval('changeLeftImage()',29);
+//var int5=self.setInterval('changeRightImage()',29);
+
+var oldvel= 0;
+var oldwheel = 0.5;
+var nchange = 50;
+
+	var n = 0;
+	var ic = 0;
+        var upcount = 0;
+	var image=new Image();//放入函数里面:浏览器运行一分钟左右系统内存用到高达90%,故做一个全局的反冲图片
+	var imagerear=new Image();
+	var imageleft=new Image();
+	var imageright=new Image();
+
+
+
+                document.onkeydown=function(event){
+			nchange = 50;
+                    //keyCode来获取按键的编码,来判断那个键是否按下
+                    //还有altKey shiftKry altKey等 来判断是否按下
+//                    console.log("按键按下");
+                    if(event.keyCode==87){
+			var valuex = 0.1;
+			valuex = parseFloat(document.getElementById("sildervel").value);
+			valuex = valuex + 0.1;
+			document.getElementById("sildervel").value = valuex;  
+                        console.log("w键按下了");
+			document.getElementById("demo").innerHTML=valuex;
+                    }
+                    if(event.keyCode==83){
+			document.getElementById("sildervel").value = parseFloat(document.getElementById("sildervel").value) - 0.1;  
+                        console.log("s键按下了");
+			document.getElementById("demo").innerHTML=Date();
+                    }
+                    if(event.keyCode==65){
+			document.getElementById("silderwheel").value = parseFloat(document.getElementById("silderwheel").value) - 0.01;
+                        console.log("a键按下了");
+			document.getElementById("demo").innerHTML=Date();
+                    }
+                    if(event.keyCode==68){
+			document.getElementById("silderwheel").value = parseFloat(document.getElementById("silderwheel").value) + 0.01;
+                        console.log("d键按下了");
+			document.getElementById("demo").innerHTML=Date();
+                    }
+                    if(event.keyCode==80){
+			document.getElementById("sildervel").value = 0;
+                    }
+                    if(event.keyCode==67){
+			document.getElementById("silderwheel").value = 0.5;
+                    }
+                    if(event.altKey && event.keyCode==89){
+                        console.log("alt+y键同时按下了");
+                    }
+                }
+//                document.onkeyup=function(){
+//                    console.log("按键松开");
+//                }
+                
+                //2.
+                var input=document.getElementsByTagName("input")[0];
+                input.onkeydown=function(){
+                    //console.log("input中按下");
+                    //可以来限制input中不能输入数字
+                    if(event.keyCode>=48 && event.keyCode<=57){//数字1-9对应48-57
+                        //取消input的默认行为,使输入东西不显示
+                        return false;
+                    }
+            }
+
+function onClickStop(){	
+	document.getElementById("sildervel").value = 0;  
+//	document.getElementById("demo").innerHTML=Date();
+}
+function onClickCenter(){	
+	document.getElementById("silderwheel").value = 0.5;  
+//	document.getElementById("demo").innerHTML=Date();
+}
+
+function updatectrl(){ 
+
+	var vel = parseFloat(document.getElementById("sildervel").value);
+	var wheel = parseFloat(document.getElementById("silderwheel").value);
+	if((vel == oldvel)&&(wheel == oldwheel))
+	{
+		if(nchange > 0)nchange = nchange-1;
+		if(nchange <= 0)
+		{
+			if(vel>=0)
+			{
+				vel = vel - 0.1;
+				document.getElementById("sildervel").value = vel;
+				oldvel = parseFloat(document.getElementById("sildervel").value);
+			}
+		}
+	}
+	else
+	{
+		nchange = 50;
+		oldvel = vel;
+		oldwheel = wheel;
+	}
+	document.getElementById("demo").innerHTML=nchange;
+}
+	function changeFrontImage()
+	{ 
+		if(ic == 1)
+		{
+			return;
+		}
+		ic = 1;
+		var canvas=document.getElementById("myCanvas2");  
+		var cxt=canvas.getContext("2d");
+
+		//ctx.restore();
+		image.src="./picfront?"+n;
+		imagerear.src="./picrear?"+n;
+		imageleft.src="./picleft?"+n;
+		imageright.src="./picright?"+n;
+		n++; 
+		var nerror = 0;
+				CanvasWidth = 960*(1920-40)/1920;
+				CanvasHeight = 540*(1920-40)/1920;
+		
+		image.onload = function () //确保图片已经加载完毕  
+		{  
+			if (image.complete)//如果图片加载完成,绘制
+			{
+				cxt.save();
+				imgScale = 1.0;
+
+				imgScale = CanvasWidth/image.width;
+				if(imgScale* image.height > CanvasHeight)imgScale = CanvasHeight/image.height;
+//				cxt.drawImage(image,0,0);  
+				cxt.drawImage(image,0,0,image.width,image.height,20+CanvasWidth/2.0,0,image.width*imgScale,image.height*imgScale);  
+//				cxt.drawImage(image,0,0,image.width,image.height,0,0,image.width*imgScale*0.5,image.height*imgScale*0.5); 
+//				cxt.drawImage(image,0,0,image.width,image.height,40+CanvasWidth*1.5,0,image.width*imgScale*0.5,image.height*imgScale*0.5); 
+//				cxt.drawImage(image,0,0,image.width,image.height,20+CanvasWidth/2.0,20+CanvasHeight,image.width*imgScale,image.height*imgScale); 
+				cxt.restore();
+				nerror = 0;
+				upcount++;
+			}
+			else
+			{
+				nerror++;
+				if(nerror>100)
+				{
+					alert(image.complete);
+					nerror = 0;
+				}
+			}
+			ic = 0;
+			
+		}  
+		image.onerror=function(){  
+			document.getElementById("F2").innerHTML="error N:"+n; 
+			ic = 0;
+		}; 
+		imagerear.onload = function () //确保图片已经加载完毕  
+		{  
+			if (imagerear.complete)//如果图片加载完成,绘制
+			{
+				cxt.save();
+				imgScale = 1.0;
+
+				imgScale = CanvasWidth/imagerear.width;
+				if(imgScale* image.height > CanvasHeight)imgScale = CanvasHeight/imagerear.height;
+//				cxt.drawImage(image,0,0);  
+//				cxt.drawImage(image,0,0,image.width,image.height,20+CanvasWidth/2.0,0,image.width*imgScale,image.height*imgScale);  
+//				cxt.drawImage(image,0,0,image.width,image.height,0,0,image.width*imgScale*0.5,image.height*imgScale*0.5); 
+//				cxt.drawImage(image,0,0,image.width,image.height,40+CanvasWidth*1.5,0,image.width*imgScale*0.5,image.height*imgScale*0.5); 
+				cxt.drawImage(imagerear,0,0,imagerear.width,imagerear.height,20+CanvasWidth/2.0,20+CanvasHeight,imagerear.width*imgScale,imagerear.height*imgScale); 
+				cxt.restore();
+				nerror = 0;
+				upcount++;
+			}
+			else
+			{
+				nerror++;
+				if(nerror>100)
+				{
+					alert(image.complete);
+					nerror = 0;
+				}
+			}
+			ic = 0;
+			
+		}  
+		imagerear.onerror=function(){  
+			document.getElementById("F2").innerHTML="error N:"+n; 
+			ic = 0;
+		};  
+		//ctx.save();
+  	}
+
+	function changeRearImage()
+	{ 
+		if(ic == 1)
+		{
+			return;
+		}
+		ic = 1;
+		var canvas=document.getElementById("myCanvas2");  
+		var cxt=canvas.getContext("2d");
+
+		//ctx.restore();
+		imagerear.src="./picrear?"+n;
+		n++; 
+		var nerror = 0;
+		
+		imagerear.onload = function () //确保图片已经加载完毕  
+		{  
+			if (imagerear.complete)//如果图片加载完成,绘制
+			{
+				cxt.save();
+				imgScale = 1.0;
+				CanvasWidth = 960*(1920-40)/1920;
+				CanvasHeight = 540*(1920-40)/1920;
+				imgScale = CanvasWidth/imagerear.width;
+				if(imgScale* imagerear.height > CanvasHeight)imgScale = CanvasHeight/imagerear.height;
+//				cxt.drawImage(image,0,0);  
+				cxt.drawImage(imagerear,0,0,imagerear.width,imagerear.height,20+CanvasWidth/2.0,20+CanvasHeight,imagerear.width*imgScale,imagerear.height*imgScale); 
+				cxt.restore();
+				nerror = 0;
+				upcount++;
+			}
+			else
+			{
+				nerror++;
+				if(nerror>100)
+				{
+					alert(image.complete);
+					nerror = 0;
+				}
+			}
+			ic = 0;
+			
+		}  
+		imagerear.onerror=function(){  
+			document.getElementById("F2").innerHTML="error N:"+n; 
+			ic = 0;
+		};  
+		//ctx.save();
+  	}
+
+	function changeLeftImage()
+	{ 
+		if(ic == 1)
+		{
+			return;
+		}
+		ic = 1;
+		var canvas=document.getElementById("myCanvas2");  
+		var cxt=canvas.getContext("2d");
+
+		//ctx.restore();
+		image.src="./picleft?"+n;
+		n++; 
+		var nerror = 0;
+		
+		image.onload = function () //确保图片已经加载完毕  
+		{  
+			if (image.complete)//如果图片加载完成,绘制
+			{
+				cxt.save();
+				imgScale = 1.0;
+				CanvasWidth = 960*(1920-40)/1920;
+				CanvasHeight = 540*(1920-40)/1920;
+				imgScale = CanvasWidth/image.width;
+				if(imgScale* image.height > CanvasHeight)imgScale = CanvasHeight/image.height;
+//				cxt.drawImage(image,0,0);   
+				cxt.drawImage(image,0,0,image.width,image.height,0,0,image.width*imgScale*0.5,image.height*imgScale*0.5); 
+				cxt.restore();
+				nerror = 0;
+				upcount++;
+			}
+			else
+			{
+				nerror++;
+				if(nerror>100)
+				{
+					alert(image.complete);
+					nerror = 0;
+				}
+			}
+			ic = 0;
+			
+		}  
+		image.onerror=function(){  
+			document.getElementById("F2").innerHTML="error N:"+n; 
+			ic = 0;
+		};  
+		//ctx.save();
+  	}
+
+	function changeRightImage()
+	{ 
+		if(ic == 1)
+		{
+			return;
+		}
+		ic = 1;
+		var canvas=document.getElementById("myCanvas2");  
+		var cxt=canvas.getContext("2d");
+
+		//ctx.restore();
+		image.src="./picright?"+n;
+		n++; 
+		var nerror = 0;
+		
+		image.onload = function () //确保图片已经加载完毕  
+		{  
+			if (image.complete)//如果图片加载完成,绘制
+			{
+				cxt.save();
+				imgScale = 1.0;
+				CanvasWidth = 960*(1920-40)/1920;
+				CanvasHeight = 540*(1920-40)/1920;
+				imgScale = CanvasWidth/image.width;
+				if(imgScale* image.height > CanvasHeight)imgScale = CanvasHeight/image.height;
+//				cxt.drawImage(image,0,0);  
+				cxt.drawImage(image,0,0,image.width,image.height,40+CanvasWidth*1.5,0,image.width*imgScale*0.5,image.height*imgScale*0.5); 
+				cxt.restore();
+				nerror = 0;
+				upcount++;
+			}
+			else
+			{
+				nerror++;
+				if(nerror>100)
+				{
+					alert(image.complete);
+					nerror = 0;
+				}
+			}
+			ic = 0;
+			
+		}  
+		image.onerror=function(){  
+			document.getElementById("F2").innerHTML="error N:"+n; 
+			ic = 0;
+		};  
+		//ctx.save();
+  	}
+
+function clock() 
+{ 
+	if(ic == 0)
+	{
+		ic = 1;
+		changeImage();
+	}
+} 
+function load() {
+	changeImage();
+}
+
+
+
+</script>
+</head>
+<body onload="changeImage()">
+<!-- <div id='websock_text_field'>No websocket connection yet</div>-->
+<!--  <iframe id='image' src="" width="800" height="600"></iframe>  -->
+
+<form>
+<br>
+<label for="title" style="width:300px;display:inline-block;">远程控制系统</label>
+<input type="radio" style="width:100px;display:inline-block;height:30px;" name="ctrl" value="auto" checked>
+<label style="width:100px;display:inline-block;">自动</label>
+<input type="radio" style="width:100px;display:inline-block;height:30px;" name="ctrl" value="man">
+<label style="width:100px;display:inline-block;">远程</label>
+<input type="radio" style="width:100px;display:inline-block;height:30px;" name="shift" value="D" checked>
+<label style="width:100px;display:inline-block;">前进</label>
+<input type="radio" style="width:100px;display:inline-block;height:30px;" name="shift" value="R">
+<label style="width:100px;display:inline-block;">后退</label>
+<br>
+<br>
+<br>
+<label style="width:150px;display:inline-block;" >车速</label>
+<input type="range" name="slidervel" id="sildervel" value="0.0" max="10" min="0" step="0.1" style="width:900px"/>
+<label style="width:50px;display:inline-block;" > </label>
+<button type="button" onclick="onClickStop()" style="width:100px;"  >停车</button>
+<br>
+<br>
+<label style="width:150px;display:inline-block;" >转向</label>
+<input type="range" name="sliderwheel" id="silderwheel" value="0.5" max="1" min="0" step="0.01" style="width:900px;"/>
+<label style="width:50px;display:inline-block;" > </label>
+<button type="button" onclick="onClickCenter()" style="width:100px;"  >居中</button>
+</form> 
+<p>  </p>
+<canvas id="myCanvas2" width="1920" height="1080" style="border:0px solid #c3c3c3;">  
+Your browser does not support the canvas element.  
+</canvas>
+
+<p id="demo">This is a paragraph.</p> 
+
+</body>
+</html>

BIN
src/driver/driver_cloud_grpc_civetweb/frontend/tvsnow.jpg


+ 7 - 0
src/driver/driver_cloud_grpc_civetweb/grpccivet.cpp

@@ -0,0 +1,7 @@
+#include "grpccivet.h"
+
+grpccivet::grpccivet()
+{
+//    mpgrpcpc = new grpcpc;
+//    mpgrpcpc->start();
+}

+ 16 - 0
src/driver/driver_cloud_grpc_civetweb/grpccivet.h

@@ -0,0 +1,16 @@
+#ifndef GRPCCIVET_H
+#define GRPCCIVET_H
+
+
+#include "grpcpc.h"
+
+class grpccivet
+{
+public:
+    grpccivet();
+
+private:
+    grpcpc * mpgrpcpc;
+};
+
+#endif // GRPCCIVET_H

+ 422 - 0
src/driver/driver_cloud_grpc_civetweb/grpcpc.cpp

@@ -0,0 +1,422 @@
+#include "grpcpc.h"
+
+#include <memory>
+static grpcpc * ggrpcpc;
+
+
+
+grpcpc::grpcpc(std::string stryamlpath)
+{
+
+
+    mstrpicmsgname[0] = "picfront";
+    mstrpicmsgname[1] = "picrear";
+    mstrpicmsgname[2] = "picleft";
+    mstrpicmsgname[3] = "picright";
+
+
+    ggrpcpc = this;
+
+
+    unsigned int i;
+
+    for(i=0;i<NUM_CAM;i++)
+    {
+        mnPicUpLatency[i] = 1000;
+        mnFrameRate[i] = 0;
+        mnPicDownLatency[i] = 1000;
+    }
+
+
+    for(i=0;i<NUM_CAM;i++)
+    {
+        unsigned int j;
+        for(j=0;j<NUM_THREAD_PERCAM;j++)
+        {
+            mpThread[i*NUM_THREAD_PERCAM + j] = new std::thread(&grpcpc::threadpicdownload,this,i);
+        }
+    }
+}
+
+
+void grpcpc::run()
+{
+    int nsize = mvectormsgunit.size();
+    int nctrlsize = mvectorctrlmsgunit.size();
+    int i;
+
+    qint64 nlasttime = 0;
+
+    int ninterval = atoi(gstruploadinterval.data());
+    if(ninterval<=0)ninterval = 100;
+
+    QTime xTime;
+    xTime.start();
+    int nlastsend = xTime.elapsed();
+
+    std::string target_str = gstrserverip+":";
+    target_str = target_str + gstrserverport ;//std::to_string()
+    auto cargs = grpc::ChannelArguments();
+    cargs.SetMaxReceiveMessageSize(1024 * 1024 * 1024); // 1 GB
+    cargs.SetMaxSendMessageSize(1024 * 1024 * 1024);
+
+    std::shared_ptr<Channel> channel = grpc::CreateCustomChannel(
+             target_str, grpc::InsecureChannelCredentials(),cargs);
+
+    std::unique_ptr<iv::UploadThread::Stub> stub_ = iv::UploadThread::NewStub(channel);
+
+
+    iv::queryReqThread request;
+    iv::queryReplyThread xreply;
+
+    int nid = 0;
+    int nctrlid = 0;
+
+    // Container for the data we expect from the server.
+//    iv::queryReply reply;
+
+    gpr_timespec timespec;
+      timespec.tv_sec = 30;//设置阻塞时间为2秒
+      timespec.tv_nsec = 0;
+      timespec.clock_type = GPR_TIMESPAN;
+
+      qint64 nLastCtrlTime = 0;
+
+
+    while(!QThread::isInterruptionRequested())
+    {
+        std::this_thread::sleep_for(std::chrono::milliseconds(1));
+        if(abs(xTime.elapsed()-nlastsend)<ninterval)
+        {
+            continue;
+        }
+
+        bool bImportant = false;
+        int nkeeptime = 0;
+
+            iv::cloud::cloudmsg xmsg;
+            xmsg.set_xtime(QDateTime::currentMSecsSinceEpoch());
+            nlastsend = xTime.elapsed();
+
+            {
+
+                ClientContext context ;
+                context.set_deadline(timespec);
+ //               qint64 time1 = QDateTime::currentMSecsSinceEpoch();
+
+                request.set_strquerymd5(gstrqueryMD5);
+                request.set_strvin(gstrVIN);
+
+                request.set_nlasttime(nlasttime);
+
+                request.set_id(nctrlid);nctrlid++;
+                request.set_strctrlmd5(gstrctrlMD5);
+                request.set_strvin(gstrVIN);
+                request.set_ntime(QDateTime::currentMSecsSinceEpoch());
+                request.set_bimportant(bImportant);
+                request.set_kepptime(nkeeptime);
+
+                if(nLastCtrlTime != mnmsgsendupdatetime)
+                {
+
+                    mMutexmsgsend.lock();
+                    nLastCtrlTime = mnmsgsendupdatetime;
+                    xmsg.CopyFrom(mmsgsend);
+                    mMutexmsgsend.unlock();
+                    if(xmsg.xclouddata_size()>0)
+                    {
+                        int nbytesize = xmsg.ByteSize();
+                        std::vector<char> pvectordata;
+                        pvectordata.resize(nbytesize);
+                        if(xmsg.SerializeToArray(pvectordata.data(),nbytesize))
+                        {
+
+                            request.set_xdata(pvectordata.data(),pvectordata.size());
+
+                        }
+                    }
+                }
+
+
+
+                QDateTime xTime;
+                xTime.fromMSecsSinceEpoch(1607905685318);  //1607914763641
+//                qDebug("time:%s",xTime.toString("yyyy-MM-dd:hh:mm:ss:zzz").toLatin1().data());
+//                qDebug("nlasttime is %ld",nlasttime);//1607905685318
+                nid++;
+                // The actual RPC.
+                Status status = stub_->queryctrl(&context, request, &xreply);
+                if (status.ok()) {
+ //                   std::cout<<nid<<" query successfully, res is "<<xreply.nres()<<std::endl;
+                    if(xreply.nres() == 1)
+                    {
+
+                        if(nlasttime != xmsg.xtime())
+                        {
+                            iv::cloud::cloudmsg xmsg;
+                            if(xmsg.ParseFromArray(xreply.xdata().data(),xreply.xdata().size()))
+                            {
+                                mMutexmsgrecv.lock();
+                                mmsgrecv.CopyFrom(xmsg);
+                                mnmsgrecvupdatetime = QDateTime::currentMSecsSinceEpoch();
+                                mMutexmsgrecv.unlock();
+                            }
+                        }
+
+                        nlasttime = xreply.ntime();
+                    }
+                    else
+                    {
+                        std::this_thread::sleep_for(std::chrono::milliseconds(30));
+                    }
+                } else {
+                  std::cout << status.error_code() << ": " << status.error_message()
+                            << std::endl;
+                  std::cout<<"RPC failed"<<std::endl;
+
+                  if(status.error_code() == 4)
+                  {
+                      std::cout<<" RPC Exceed Time, Create New stub_"<<std::endl;
+                      channel = grpc::CreateCustomChannel(
+                               target_str, grpc::InsecureChannelCredentials(),cargs);
+
+                      stub_ = iv::UploadThread::NewStub(channel);
+                  }
+                  std::this_thread::sleep_for(std::chrono::milliseconds(900));
+
+                }
+
+            }
+
+
+
+    }
+}
+
+
+
+std::string grpcpc::GetVIN()
+{
+    return gstrVIN;
+}
+
+
+//int gnPicNum[NUM_CAM];
+//QMutex gMutexPic[NUM_CAM];
+//qint64 gnTimeSecond[NUM_CAM];
+
+
+void grpcpc::threadpicdownload(int nCamPos)
+{
+    std::cout<<"thread cam "<<nCamPos<<"run"<<std::endl;
+    int nsize = mvectormsgunit.size();
+    int i;
+
+    std::string strcclientid = "civetweb";//ServiceRCIni.GetClientID();
+
+    int ninterval = atoi(gstruploadinterval.data());
+    if(ninterval<=0)ninterval = 100;
+
+    QTime xTime;
+    xTime.start();
+    int nlastsend = xTime.elapsed();
+
+    std::string target_str = gstrserverip+":";
+    target_str = target_str + gstrserverport ;//std::to_string()
+    auto cargs = grpc::ChannelArguments();
+    cargs.SetMaxReceiveMessageSize(1024 * 1024 * 1024); // 1 GB
+    cargs.SetMaxSendMessageSize(1024 * 1024 * 1024);
+
+    std::shared_ptr<Channel> channel = grpc::CreateCustomChannel(
+             target_str, grpc::InsecureChannelCredentials(),cargs);
+
+    std::unique_ptr<iv::UploadThread::Stub> stub_ = iv::UploadThread::NewStub(channel);
+
+
+    iv::PicDownReqThread request;
+
+    int nid = 0;
+
+    // Container for the data we expect from the server.
+    iv::PicDownReplyThread reply;
+
+    gpr_timespec timespec;
+      timespec.tv_sec = 30;//设置阻塞时间为2秒
+      timespec.tv_nsec = 0;
+      timespec.clock_type = GPR_TIMESPAN;
+
+ //   ClientContext context;
+
+
+
+    while(true)
+    {
+        std::shared_ptr<char> pstr_ptr;
+        if((nCamPos<0)||(nCamPos >= NUM_CAM))
+        {
+            std::cout<<"Cam Pos Error. "<<"Pos: "<<nCamPos<<" TOTAL:"<<NUM_CAM<<std::endl;
+            std::this_thread::sleep_for(std::chrono::milliseconds(100));
+            continue;
+        }
+
+
+
+        request.set_strclientid(strcclientid);
+        request.set_ncampos(nCamPos);
+        request.set_strquerymd5(gstrqueryMD5);
+        request.set_strvin(gstrVIN);
+
+
+        ClientContext context ;
+        context.set_deadline(timespec);
+        qint64 time1 = QDateTime::currentMSecsSinceEpoch();
+
+
+        //If extend 10 seconds not request picture, pause get picture from server.
+        if((time1 - mnLastGetPicTime)>10000)
+        {
+            std::cout<<"not need updata"<<std::endl;
+            std::this_thread::sleep_for(std::chrono::milliseconds(50));
+            continue;
+        }
+        nlastsend = xTime.elapsed();
+        // The actual RPC.
+        Status status = stub_->querypic(&context, request, &reply);
+        if (status.ok()) {
+
+            if(reply.nres() == 1)
+            {
+                std::cout<<nCamPos<<":pic time is "<<reply.npictime()<<std::endl;
+                mnPicUpLatency[nCamPos] = reply.npicuplatency();
+                mnFrameRate[nCamPos] = reply.npicframerate();
+                mnPicDownLatency[nCamPos] = QDateTime::currentMSecsSinceEpoch() - time1;
+                iv::vision::rawpic xrawpic;
+                if(xrawpic.ParseFromArray(reply.xdata().data(),reply.xdata().size()))
+                {
+                    mMutexPic[nCamPos].lock();
+                    mRawPic[nCamPos].CopyFrom(xrawpic);
+                    mnPicUpdateTime[nCamPos] = QDateTime::currentMSecsSinceEpoch();
+                    xrawpic.CopyFrom(mRawPic[nCamPos]);
+                    //               iv::modulecomm::ModuleSendMsg(mpaPic[nCamPos],reply.xdata().data(),reply.xdata().size());
+                    mMutexPic[nCamPos].unlock();
+                }
+//                iv::cloud::cloudmsg xmsg;
+//                if(xmsg.ParseFromArray(reply.xdata().data(),reply.xdata().size()))
+//                {
+//                    sharectrlmsg(&xmsg);
+//                }
+            }
+            else
+            {
+                std::this_thread::sleep_for(std::chrono::milliseconds(10*NUM_THREAD_PERCAM));
+            }
+        } else {
+          std::cout << status.error_code() << ": " << status.error_message()
+                    << std::endl;
+          std::cout<<"camera dowm"<<nCamPos<<" RPC failed"<<std::endl;
+          if(status.error_code() == 4)
+          {
+              std::cout<<nCamPos<<" RPC Exceed Time, Create New stub_"<<std::endl;
+              channel = grpc::CreateCustomChannel(
+                       target_str, grpc::InsecureChannelCredentials(),cargs);
+
+              stub_ = iv::UploadThread::NewStub(channel);
+          }
+          std::this_thread::sleep_for(std::chrono::milliseconds(900));
+
+        }
+
+
+    }
+}
+
+qint64 grpcpc::GetPicLatency(int nCamPos)
+{
+    if((nCamPos < 0)||(nCamPos >= NUM_CAM))return -1;
+    return mnPicUpLatency[nCamPos];
+}
+
+int grpcpc::GetFrameRate(int nCamPos)
+{
+    if((nCamPos < 0)||(nCamPos >= NUM_CAM))return -1;
+    return mnFrameRate[nCamPos];
+}
+
+qint64 grpcpc::GetPicDownLatency(int nCamPos)
+{
+    if((nCamPos < 0)||(nCamPos >= NUM_CAM))return -1;
+    return mnPicDownLatency[nCamPos];
+}
+
+void grpcpc::setserverip(std::string strip)
+{
+    gstrserverip = strip;
+}
+
+void grpcpc::setserverport(std::string strport)
+{
+    gstrserverport = strport;
+}
+
+void grpcpc::setqueryinterval(std::string strinterval)
+{
+    gstruploadinterval = strinterval;
+}
+
+void grpcpc::setVIN(std::string strVIN)
+{
+    gstrVIN = strVIN;
+}
+
+void grpcpc::setqueryMD5(std::string strmd5)
+{
+    gstrqueryMD5 = strmd5;
+}
+
+void grpcpc::setctrlMD5(std::string strmd5)
+{
+    gstrctrlMD5 = strmd5;
+}
+
+
+int grpcpc::GetRawPic(unsigned int camindex,iv::vision::rawpic & xrawpic)
+{
+    mnLastGetPicTime = QDateTime::currentMSecsSinceEpoch();
+    if((camindex >= NUM_CAM))return -1;
+    qint64 now = QDateTime::currentMSecsSinceEpoch();
+    if((now - mnPicUpdateTime[camindex])>1000)
+    {
+        return 0;
+    }
+    mMutexPic[camindex].lock();
+    xrawpic.CopyFrom(mRawPic[camindex]);
+
+    mMutexPic[camindex].unlock();
+    return 1;
+}
+
+int grpcpc::GetRecvMsg(iv::cloud::cloudmsg & xmsg)
+{
+    mnLastGetmsgTime = QDateTime::currentMSecsSinceEpoch();
+    qint64 now = QDateTime::currentMSecsSinceEpoch();
+    if((now - mnmsgrecvupdatetime) > 1000)
+    {
+        return 0;
+    }
+    mMutexmsgrecv.lock();
+    xmsg.CopyFrom(mmsgrecv);
+
+    mMutexmsgrecv.unlock();
+    return 1;
+}
+
+int grpcpc::SetSendMsg(iv::cloud::cloudmsg & xmsg)
+{
+    mMutexmsgsend.lock();
+    mmsgsend.CopyFrom(xmsg);
+    mnmsgsendupdatetime = QDateTime::currentMSecsSinceEpoch();
+    mMutexmsgsend.unlock();
+    return 0;
+}
+
+

+ 151 - 0
src/driver/driver_cloud_grpc_civetweb/grpcpc.h

@@ -0,0 +1,151 @@
+#ifndef GRPCPC_H
+#define GRPCPC_H
+
+#include <QThread>
+
+#include <yaml-cpp/yaml.h>
+
+#include <QDateTime>
+
+#include <iostream>
+
+#include <vector>
+
+#include <memory>
+
+#include <QMutex>
+
+#include <thread>
+
+#include "modulecomm.h"
+
+#include "rawpic.pb.h"
+#include "cloud.pb.h"
+
+#include <iostream>
+#include <memory>
+#include <string>
+
+#include <grpcpp/grpcpp.h>
+
+#include "uploadthreadmsg.grpc.pb.h"
+
+#ifndef NUM_CAM
+#define NUM_CAM 4
+#endif
+
+#ifndef NUM_THREAD_PERCAM
+#define NUM_THREAD_PERCAM 1
+//int NUM_THREAD_PERCAM = 1;
+#endif
+
+using grpc::Channel;
+using grpc::ClientContext;
+using grpc::Status;
+
+namespace iv {
+struct msgunit
+{
+    char mstrmsgname[256];
+    int mnBufferSize = 10000;
+    int mnBufferCount = 1;
+    void * mpa;
+    std::shared_ptr<char> mpstrmsgdata;
+    int mndatasize = 0;
+    bool mbRefresh = false;
+    bool mbImportant = false;
+    int mnkeeptime = 100;
+};
+}
+
+class grpcpc : public QThread
+{
+public:
+    grpcpc(std::string stryamlpath);
+
+private:
+    void run();
+
+private:
+    std::string gstrserverip = "127.0.0.1";//"111.33.136.149";//"127.0.0.1";// "140.143.237.38";
+    std::string gstrserverport = "50051";//"9000";
+    std::string gstruploadinterval = "100";
+    void * gpa;
+    QMutex gMutexMsg;
+    std::vector<iv::msgunit> mvectormsgunit;
+
+    std::vector<iv::msgunit> mvectorctrlmsgunit;
+
+
+    std::string gstrVIN = "AAAAAAAAAAAAAAAAA";
+    std::string gstrqueryMD5 = "5d41402abc4b2a76b9719d911017c592";
+    std::string gstrctrlMD5 = "5d41402abc4b2a76b9719d911017c592";
+
+
+
+
+    int gindex = 0;
+
+
+private:
+
+
+public:
+    void UpdateData(const char * strdata,const unsigned int nSize,const char * strmemname);
+    std::string GetVIN();
+
+private:
+    void threadpicdownload(int nCamPos);
+    void * mpaPic[NUM_CAM];
+    std::string mstrpicmsgname[NUM_CAM];
+
+    std::thread * mpThread[NUM_CAM * NUM_THREAD_PERCAM];
+
+    QMutex mMutexPic[NUM_CAM];
+
+    qint64 mnPicUpLatency[NUM_CAM];
+    int mnFrameRate[NUM_CAM];
+    int mnPicDownLatency[NUM_CAM];
+
+
+public:
+    qint64 GetPicLatency(int nCamPos);
+    int GetFrameRate(int nCamPos);
+    qint64 GetPicDownLatency(int nCamPos);
+
+
+public:
+    void setserverip(std::string strip);
+    void setserverport(std::string strport);
+    void setqueryinterval(std::string strinterval);
+    void setVIN(std::string strVIN);
+    void setqueryMD5(std::string strmd5);
+    void setctrlMD5(std::string strmd5);
+
+private:
+    iv::vision::rawpic mRawPic[NUM_CAM];
+    qint64 mnPicUpdateTime[NUM_CAM];
+//    QMutex mMuteRawPic[NUM_CAM];
+    qint64 mnLastGetPicTime = 0;
+
+    iv::cloud::cloudmsg mmsgrecv;
+    qint64 mnmsgrecvupdatetime = 0;
+    QMutex mMutexmsgrecv;
+    qint64 mnLastGetmsgTime = 0;
+
+    iv::cloud::cloudmsg mmsgsend;
+    qint64 mnmsgsendupdatetime = 0;
+    QMutex mMutexmsgsend;
+
+
+public:
+    int GetRawPic(unsigned int camindex,iv::vision::rawpic & xrawpic);
+    int GetRecvMsg(iv::cloud::cloudmsg & xmsg);
+    int SetSendMsg(iv::cloud::cloudmsg & xmsg);
+
+
+
+
+};
+
+#endif // GRPCPC_H

+ 401 - 0
src/driver/driver_cloud_grpc_civetweb/main.cpp

@@ -0,0 +1,401 @@
+#include <QCoreApplication>
+
+
+#include <QMutex>
+#include <iostream>
+#include <QFile>
+
+#include "xmlparam.h"
+
+#include "rawpic.pb.h"
+
+#include "CivetServer.h"
+#include <cstring>
+
+#ifdef _WIN32
+#include <windows.h>
+#else
+#include <unistd.h>
+#endif
+
+#include "grpccivet.h"
+
+#define DOCUMENT_ROOT "./frontend/dist"
+
+QByteArray gbasnow;
+
+
+grpcpc * ggrpc;
+
+class WsStartHandler : public CivetHandler
+{
+  public:
+    bool
+    handleGet(CivetServer *server, struct mg_connection *conn)
+    {
+
+    mg_printf(conn,
+              "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nConnection: "
+              "close\r\n\r\n");
+
+    mg_printf(conn, "<!DOCTYPE html>\n");
+    mg_printf(conn, "<html>\n<head>\n");
+    mg_printf(conn, "<meta charset=\"UTF-8\">\n");
+    mg_printf(conn, "<title>ADC IV RemoteCtrl UI</title>\n");
+
+    QFile xFile;
+    xFile.setFileName("./frontend/index.html");
+    if(xFile.open(QIODevice::ReadOnly))
+    {
+        QByteArray ba = xFile.readAll();
+        mg_printf(conn,ba.data());
+
+    }
+
+    return 1;
+
+
+
+    }
+};
+
+class PicFrontHandler : public CivetHandler
+{
+  public:
+    bool
+    handleGet(CivetServer *server, struct mg_connection *conn)
+    {
+
+        static int ncount;
+
+        mg_printf(conn,
+                  "HTTP/1.1 200 OK\r\n"
+                  "Connection: close\r\n"
+                  "Max-Age: 0\r\n"
+                  "Expires: 0\r\n"
+                  "Cache-Control: no-cache, no-store, must-revalidate, private\r\n"
+                  "Pragma: no-cache\r\n"
+                  "Content-Type: multipart/x-mixed-replace; "
+                  "boundary=--BoundaryString\r\n"
+                  "\r\n");
+
+        mg_printf(conn,"<meta http-equiv=\"refresh\" content=\"1\">");
+        mg_printf(conn,
+        "<script type=\"text/javascript\">\r\n"
+            "function myrefresh() {\r\n"
+                "window.location.reload();\r\n"
+            "}\r\n"
+            "setTimeout('myrefresh()', 1000);\r\n"
+        "</script>\r\n");
+
+        QByteArray ba;
+
+
+        iv::vision::rawpic xrawpic;
+        if(ggrpc->GetRawPic(0,xrawpic) == 1)
+        {
+            ba.append(xrawpic.picdata().data(),xrawpic.picdata().size());
+        }
+        else
+        {
+            ba = gbasnow;
+        }
+//        if(gLastUpdate > 0)
+//        {
+//        iv::vision::rawpic xrawpic;
+//        gMutex.lock();
+//        xrawpic.CopyFrom(mRawPic);
+//        gMutex.unlock();
+//        ba.append(xrawpic.picdata().data(),xrawpic.picdata().size());
+
+//        }
+        mg_printf(conn,
+                  "--BoundaryString\r\n"
+                  "Content-type: image/jpeg\r\n"
+                  "Content-Length: %zu\r\n"
+                  "\r\n",
+                  ba.size());
+
+
+        mg_write(conn, ba.data(), ba.size());
+
+
+        mg_printf(conn, "\r\n\r\n");
+
+
+        ncount++;
+        printf("send pic. %d\n",ncount);
+
+        return true;
+    }
+};
+
+
+class PicRearHandler : public CivetHandler
+{
+  public:
+    bool
+    handleGet(CivetServer *server, struct mg_connection *conn)
+    {
+
+        static int ncount;
+
+        mg_printf(conn,
+                  "HTTP/1.1 200 OK\r\n"
+                  "Connection: close\r\n"
+                  "Max-Age: 0\r\n"
+                  "Expires: 0\r\n"
+                  "Cache-Control: no-cache, no-store, must-revalidate, private\r\n"
+                  "Pragma: no-cache\r\n"
+                  "Content-Type: multipart/x-mixed-replace; "
+                  "boundary=--BoundaryString\r\n"
+                  "\r\n");
+
+        mg_printf(conn,"<meta http-equiv=\"refresh\" content=\"1\">");
+        mg_printf(conn,
+        "<script type=\"text/javascript\">\r\n"
+            "function myrefresh() {\r\n"
+                "window.location.reload();\r\n"
+            "}\r\n"
+            "setTimeout('myrefresh()', 1000);\r\n"
+        "</script>\r\n");
+
+        QByteArray ba;
+
+
+        iv::vision::rawpic xrawpic;
+        if(ggrpc->GetRawPic(1,xrawpic) == 1)
+        {
+            ba.append(xrawpic.picdata().data(),xrawpic.picdata().size());
+        }
+        else
+        {
+            ba = gbasnow;
+        }
+//        if(gLastUpdate > 0)
+//        {
+//        iv::vision::rawpic xrawpic;
+//        gMutex.lock();
+//        xrawpic.CopyFrom(mRawPic);
+//        gMutex.unlock();
+//        ba.append(xrawpic.picdata().data(),xrawpic.picdata().size());
+
+//        }
+        mg_printf(conn,
+                  "--BoundaryString\r\n"
+                  "Content-type: image/jpeg\r\n"
+                  "Content-Length: %zu\r\n"
+                  "\r\n",
+                  ba.size());
+
+
+        mg_write(conn, ba.data(), ba.size());
+
+
+        mg_printf(conn, "\r\n\r\n");
+
+
+        ncount++;
+        printf("send pic. %d\n",ncount);
+
+        return true;
+    }
+};
+
+
+
+class PicLeftHandler : public CivetHandler
+{
+  public:
+    bool
+    handleGet(CivetServer *server, struct mg_connection *conn)
+    {
+
+        static int ncount;
+
+        mg_printf(conn,
+                  "HTTP/1.1 200 OK\r\n"
+                  "Connection: close\r\n"
+                  "Max-Age: 0\r\n"
+                  "Expires: 0\r\n"
+                  "Cache-Control: no-cache, no-store, must-revalidate, private\r\n"
+                  "Pragma: no-cache\r\n"
+                  "Content-Type: multipart/x-mixed-replace; "
+                  "boundary=--BoundaryString\r\n"
+                  "\r\n");
+
+        mg_printf(conn,"<meta http-equiv=\"refresh\" content=\"1\">");
+        mg_printf(conn,
+        "<script type=\"text/javascript\">\r\n"
+            "function myrefresh() {\r\n"
+                "window.location.reload();\r\n"
+            "}\r\n"
+            "setTimeout('myrefresh()', 1000);\r\n"
+        "</script>\r\n");
+
+        QByteArray ba;
+
+
+        iv::vision::rawpic xrawpic;
+        if(ggrpc->GetRawPic(2,xrawpic) == 1)
+        {
+            ba.append(xrawpic.picdata().data(),xrawpic.picdata().size());
+        }
+        else
+        {
+            ba = gbasnow;
+        }
+//        if(gLastUpdate > 0)
+//        {
+//        iv::vision::rawpic xrawpic;
+//        gMutex.lock();
+//        xrawpic.CopyFrom(mRawPic);
+//        gMutex.unlock();
+//        ba.append(xrawpic.picdata().data(),xrawpic.picdata().size());
+
+//        }
+        mg_printf(conn,
+                  "--BoundaryString\r\n"
+                  "Content-type: image/jpeg\r\n"
+                  "Content-Length: %zu\r\n"
+                  "\r\n",
+                  ba.size());
+
+
+        mg_write(conn, ba.data(), ba.size());
+
+
+        mg_printf(conn, "\r\n\r\n");
+
+
+        ncount++;
+        printf("send pic. %d\n",ncount);
+
+        return true;
+    }
+};
+
+
+
+class PicRightHandler : public CivetHandler
+{
+  public:
+    bool
+    handleGet(CivetServer *server, struct mg_connection *conn)
+    {
+
+        static int ncount;
+
+        mg_printf(conn,
+                  "HTTP/1.1 200 OK\r\n"
+                  "Connection: close\r\n"
+                  "Max-Age: 0\r\n"
+                  "Expires: 0\r\n"
+                  "Cache-Control: no-cache, no-store, must-revalidate, private\r\n"
+                  "Pragma: no-cache\r\n"
+                  "Content-Type: multipart/x-mixed-replace; "
+                  "boundary=--BoundaryString\r\n"
+                  "\r\n");
+
+        mg_printf(conn,"<meta http-equiv=\"refresh\" content=\"1\">");
+        mg_printf(conn,
+        "<script type=\"text/javascript\">\r\n"
+            "function myrefresh() {\r\n"
+                "window.location.reload();\r\n"
+            "}\r\n"
+            "setTimeout('myrefresh()', 1000);\r\n"
+        "</script>\r\n");
+
+        QByteArray ba;
+
+
+        iv::vision::rawpic xrawpic;
+        if(ggrpc->GetRawPic(3,xrawpic) == 1)
+        {
+            ba.append(xrawpic.picdata().data(),xrawpic.picdata().size());
+        }
+        else
+        {
+            ba = gbasnow;
+        }
+//        if(gLastUpdate > 0)
+//        {
+//        iv::vision::rawpic xrawpic;
+//        gMutex.lock();
+//        xrawpic.CopyFrom(mRawPic);
+//        gMutex.unlock();
+//        ba.append(xrawpic.picdata().data(),xrawpic.picdata().size());
+
+//        }
+        mg_printf(conn,
+                  "--BoundaryString\r\n"
+                  "Content-type: image/jpeg\r\n"
+                  "Content-Length: %zu\r\n"
+                  "\r\n",
+                  ba.size());
+
+
+        mg_write(conn, ba.data(), ba.size());
+
+
+        mg_printf(conn, "\r\n\r\n");
+
+
+        ncount++;
+        printf("send pic. %d\n",ncount);
+
+        return true;
+    }
+};
+
+
+int main(int argc, char *argv[])
+{
+    QCoreApplication a(argc, argv);
+
+    iv::xmlparam::Xmlparam xp("./driver_cloud_grpc_civetweb.xml");
+//    std::string strmsgname =  xp.GetParam("imagemsgname","picfront");
+    std::string strport = xp.GetParam("Port","6101");
+//    gpa = iv::modulecomm::RegisterRecv(strmsgname.data(),Listenpic);
+
+    QFile xFile;
+    xFile.setFileName("./frontend/tvsnow.jpg");
+    if(xFile.open(QIODevice::ReadOnly))
+    {
+        gbasnow = xFile.readAll();
+
+    }
+    xFile.close();
+
+    mg_init_library(0);
+
+
+    const char *options[] = {
+        "document_root", DOCUMENT_ROOT, "listening_ports", strport.data(), 0};
+
+    std::vector<std::string> cpp_options;
+    for (int i=0; i<(sizeof(options)/sizeof(options[0])-1); i++) {
+        cpp_options.push_back(options[i]);
+    }
+
+    // CivetServer server(options); // <-- C style start
+    CivetServer server(cpp_options); // <-- C++ style start
+
+    WsStartHandler h_ws;
+    server.addHandler("/", h_ws);
+
+    PicFrontHandler h_picfront;
+    server.addHandler("/picfront", h_picfront);
+
+    PicRearHandler h_picrear;
+    server.addHandler("/picrear", h_picrear);
+    PicLeftHandler h_picleft;
+    server.addHandler("/picleft", h_picleft);
+    PicRightHandler h_picright;
+    server.addHandler("/picright", h_picright);
+
+    ggrpc = new grpcpc("test");
+    ggrpc->start();
+
+    return a.exec();
+}