diff options
author | wanglu <wang_lu@dl.cn.nexty-ele.com> | 2019-03-28 09:31:38 +0800 |
---|---|---|
committer | wanglu <wang_lu@dl.cn.nexty-ele.com> | 2019-04-12 09:25:29 +0800 |
commit | 39e4539925687d46c7bbe04681dcc09757dc9ae2 (patch) | |
tree | 05dea21f2f43b06b3ea260a4ddbb0b291392bcad /app | |
parent | 1e69db0b5eb9cfa6781e2c046d05dcca3a5bd909 (diff) |
Fix review problems:halibut_7.99.2halibut_7.99.1halibut/7.99.2halibut/7.99.17.99.27.99.1
1.Add autobuild
2.Replace literal with notation in tsutils/tsrecorder/tsrecorder.c
3.Update LICENSE and COPYRIGHT
This is a logging app with following functions included:
1.video recording
2.Audio recording
3.Can data recording & playing
4.Screen touch event recording & playing
Change-Id: Id7942e16f87e69d25240f4985d3c47bc262d25c2
Signed-off-by: wanglu <wang_lu@dl.cn.nexty-ele.com>
Diffstat (limited to 'app')
32 files changed, 3600 insertions, 0 deletions
diff --git a/app/app.pri b/app/app.pri new file mode 100644 index 0000000..014646f --- /dev/null +++ b/app/app.pri @@ -0,0 +1,12 @@ +TEMPLATE = app + +load(configure) +qtCompileTest(libhomescreen) + +config_libhomescreen { + CONFIG += link_pkgconfig + PKGCONFIG += homescreen + DEFINES += HAVE_LIBHOMESCREEN +} + +DESTDIR = $${OUT_PWD}/../package/root/bin diff --git a/app/app.pro b/app/app.pro new file mode 100644 index 0000000..6f945bf --- /dev/null +++ b/app/app.pro @@ -0,0 +1,22 @@ +TARGET = log-utils +QT = quickcontrols2 websockets + +HEADERS += \ + logfile/logsave.h \ + logfile/logplay.h \ + logfile/touchlogplay.h + +SOURCES = main.cpp \ + logfile/logsave.cpp \ + logfile/logplay.cpp \ + logfile/touchlogplay.cpp + +CONFIG += link_pkgconfig +PKGCONFIG += libhomescreen qlibwindowmanager qtappfw + +RESOURCES += \ + images/images.qrc \ + logfile/logfile.qrc + + +include(app.pri) diff --git a/app/images/HMI_Settings_DividingLine.svg b/app/images/HMI_Settings_DividingLine.svg new file mode 100644 index 0000000..d63589c --- /dev/null +++ b/app/images/HMI_Settings_DividingLine.svg @@ -0,0 +1,58 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Generator: Adobe Illustrator 21.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> + +<svg + xmlns:i="&ns_ai;" + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + version="1.1" + id="Layer_1" + x="0px" + y="0px" + viewBox="0 0 932.8 1" + style="enable-background:new 0 0 932.8 1;" + xml:space="preserve" + inkscape:version="0.91 r13725" + sodipodi:docname="HMI_Settings_DividingLine.svg"><metadata + id="metadata18"><rdf:RDF><cc:Work + rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs + id="defs16" /><sodipodi:namedview + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1" + objecttolerance="10" + gridtolerance="10" + guidetolerance="10" + inkscape:pageopacity="0" + inkscape:pageshadow="2" + inkscape:window-width="2560" + inkscape:window-height="1464" + id="namedview14" + showgrid="false" + inkscape:zoom="0.72041167" + inkscape:cx="-116.6" + inkscape:cy="0.5" + inkscape:window-x="0" + inkscape:window-y="0" + inkscape:window-maximized="1" + inkscape:current-layer="Layer_1" /><style + type="text/css" + id="style3"> + .st0{opacity:0.302;} + .st1{fill-rule:evenodd;clip-rule:evenodd;fill:#A8A8A8;} +</style><switch + id="switch5"><g + i:extraneous="self" + id="g7"><g + id="Divider_2_" + class="st0"><g + id="g10"><polygon + class="st1" + points="719.7,0 0,0 0,1 932.8,1 " + id="polygon12" /></g></g></g></switch></svg>
\ No newline at end of file diff --git a/app/images/HMI_Settings_X.svg b/app/images/HMI_Settings_X.svg new file mode 100644 index 0000000..5ad9479 --- /dev/null +++ b/app/images/HMI_Settings_X.svg @@ -0,0 +1,72 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Generator: Adobe Illustrator 21.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> + +<svg + xmlns:i="&#38;ns_ai;" + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + version="1.1" + x="0px" + y="0px" + viewBox="0 0 45 45" + style="enable-background:new 0 0 45 45;" + xml:space="preserve" + id="svg2" + inkscape:version="0.91 r13725" + sodipodi:docname="HMI_ContactScreen_X-01.svg"><metadata + id="metadata66"><rdf:RDF><cc:Work + rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs + id="defs64" /><sodipodi:namedview + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1" + objecttolerance="10" + gridtolerance="10" + guidetolerance="10" + inkscape:pageopacity="0" + inkscape:pageshadow="2" + inkscape:window-width="2560" + inkscape:window-height="1464" + id="namedview62" + showgrid="false" + inkscape:zoom="5.2444444" + inkscape:cx="-132.61653" + inkscape:cy="22.5" + inkscape:window-x="0" + inkscape:window-y="0" + inkscape:window-maximized="1" + inkscape:current-layer="svg2" /><style + type="text/css" + id="style4"> + .st0{fill:none;stroke:#FFFFFF;stroke-miterlimit:10;} + .st1{display:none;} + .st2{display:inline;opacity:0.15;fill:url(#SVGID_1_);} + .st3{display:inline;opacity:0.35;fill:url(#SVGID_2_);} + .st4{display:inline;} + .st5{opacity:0.15;fill:url(#SVGID_3_);} + .st6{opacity:0.15;fill:url(#SVGID_4_);stroke:url(#SVGID_5_);stroke-miterlimit:10;} + .st7{fill:url(#SVGID_6_);} +</style><switch + id="switch6"><g + i:extraneous="self" + id="g8"><g + id="Inactive"><g + id="g11"><line + class="st0" + x1="44.8" + y1="44.8" + x2="0.2" + y2="0.2" + id="line13" /><line + class="st0" + x1="45" + y1="0" + x2="0" + y2="45" + id="line15" /></g></g></g></switch></svg>
\ No newline at end of file diff --git a/app/images/images.qrc b/app/images/images.qrc new file mode 100644 index 0000000..0bb2c0d --- /dev/null +++ b/app/images/images.qrc @@ -0,0 +1,6 @@ +<RCC> + <qresource prefix="/images"> + <file>HMI_Settings_DividingLine.svg</file> + <file>HMI_Settings_X.svg</file> + </qresource> +</RCC> diff --git a/app/logfile/AudioLog.qml b/app/logfile/AudioLog.qml new file mode 100644 index 0000000..bb5d2b2 --- /dev/null +++ b/app/logfile/AudioLog.qml @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2019 TOYOTA MOTOR CORPORATION + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import QtQuick 2.6 +import QtQuick.Layouts 1.1 +import QtQuick.Controls 2.0 +import '..' + +RowLayout { + id: audiolog + + property int currentsps: 0 + property int part1fontsize: 30 + property int part2fontsize: 30 + property int partheight: 50 + property int part1width: 250 + property int part2width: 600 + + Item { + implicitWidth: part1width + implicitHeight: partheight + Label { + anchors.right: parent.right + anchors.bottom: parent.bottom + font.pixelSize: part1fontsize + text: 'SPS : ' + } + } + + TextField { + id: textfield + implicitWidth: part2width + implicitHeight: partheight + validator: IntValidator{bottom: 4000; top: 192000;} + color: 'white' + font.pixelSize: part2fontsize + verticalAlignment: TextInput.AlignBottom + Label { + x: parent.width - width + y: parent.height - height + text: '(4000~192000)' + color: 'gray' + font.pixelSize: 20 + } + onTextChanged: { + if(text == '0') { + text = '' + } + if(text.length > 0) { + currentsps = text + } + else { + currentsps = 0 + } + } + onFocusChanged: { + root.updateKeyBoard() + if(!focus && text < 4000) { + text = 4000 + } + } + Component.onCompleted: { + root.addTarget(textfield) + } + } +} diff --git a/app/logfile/Bar.qml b/app/logfile/Bar.qml new file mode 100644 index 0000000..3f0ac1f --- /dev/null +++ b/app/logfile/Bar.qml @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2019 TOYOTA MOTOR CORPORATION + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import QtQuick 2.6 +import QtQuick.Layouts 1.3 +import QtQuick.Controls 2.0 +import '..' + +TabBar { + id: root + property int tabbtnwidth: 460 + property int tabbtnheight: 51 + anchors.left: parent.left + anchors.right: parent.right + anchors.margins: 80 + background.opacity: 0 + Repeater { + id: tabs + model: ['Log Save', 'Log Play', 'Touch Log Play'] + delegate: TabButton { + implicitWidth: tabbtnwidth + implicitHeight: tabbtnheight + contentItem: Text { + text: model.modelData + font.family: 'Roboto' + font.pixelSize: 30 + opacity: enabled ? 1.0 : 0.3 + color: parent.down ? "#17a81a" : "white" + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + elide: Text.ElideRight + } + background: Image { + anchors.fill: parent + transform: parent.down ? opacity = 1.0 : opacity = 0.75 + } + } + } + Component.onCompleted: { + setBgImg() + } + + onCurrentIndexChanged: { + setBgImg() + } + + function setBgImg() { + for(var i = 0; i < tabs.count && i < root.count; i++) { + if(i == root.currentIndex) { + tabs.itemAt(i).background.source = './images/HMI_Settings_Button_Ok.svg'; + } + else { + tabs.itemAt(i).background.source = './images/HMI_Settings_Button_Cancel.svg'; + } + } + } +} diff --git a/app/logfile/CANLog.qml b/app/logfile/CANLog.qml new file mode 100644 index 0000000..61cb7c5 --- /dev/null +++ b/app/logfile/CANLog.qml @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2019 TOYOTA MOTOR CORPORATION + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import QtQuick 2.6 +import QtQuick.Layouts 1.1 +import QtQuick.Controls 2.0 +import '..' + +ColumnLayout { + anchors.left: parent.left + anchors.leftMargin: 100 + Label { + text: 'There is no property which needs to be set.' + font.pixelSize: 30 + } +} diff --git a/app/logfile/LogFile.qml b/app/logfile/LogFile.qml new file mode 100644 index 0000000..da1dc40 --- /dev/null +++ b/app/logfile/LogFile.qml @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2019 TOYOTA MOTOR CORPORATION + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import QtQuick 2.6 +import QtQuick.Layouts 1.3 +import QtQuick.Controls 2.0 +import '..' +import './keyboard' + +ApplicationWindow { + id: root + width: 1080 * screenInfo.scale_factor() + height: 1487 * screenInfo.scale_factor() +// icon: '/logfile/images/HMI_Settings_LogFile.svg' + title: 'LogFile' + property string trippath: '' + property string rootpath: '' + property var targets: new Array() + + Bar { + id: tabbar + anchors.top: parent.top + anchors.topMargin: 200 + onCurrentIndexChanged: { + keyboard.visible = false + } + } + + StackLayout { + id: pages + anchors.left: tabbar.left + anchors.right: tabbar.right + anchors.top: tabbar.bottom + currentIndex: tabbar.currentIndex + LogSave { id: logsave } + LogPlay { id: logplay } + TouchLogPlay { id: touchlogplay } + } + + Keyboard { + id: keyboard + anchors.bottom: parent.bottom + anchors.left: parent.left + anchors.right: parent.right + active: numbers + onVisibleChanged: { + var children = pages.children + for(var child in children) { + if(children[child].visible) { + children[child].resetPosition() + break; + } + } + } + Numbers { + id: numbers + anchors.left: parent.left + anchors.right: parent.right + anchors.leftMargin: parent.height / 2 + anchors.rightMargin: parent.height / 2 + target: parent.target + onHide: { + keyboard.visible = false + target.focus = false + } + onNext: { + var nexttarget + for(var i = 0; i < targets.length; i++) { + if(targets[i] === target) { + for(var j = i, k = 0; k < targets.length; k++) { + if(j === targets.length-1) { + j = 0; + } + else { + j++; + } + if(targets[j].visible) { + target.focus = false + nexttarget = targets[j] + nexttarget.focus = true + break; + } + } + break; + } + } + } + } + } + + onVisibleChanged: { + if(!visible) { + keyboard.visible = false + } + } + + function updateKeyBoard() { + var textfield = 0 + for(var i = 0; i < targets.length; i++) { + if(targets[i].focus) { + textfield = targets[i] + } + } + + if(textfield === 0) { + keyboard.visible = false + return + } + else { + keyboard.target = textfield + keyboard.visible = true + } + + var implicity = 0.0 + for(var itext = textfield; itext !== pages; itext = itext.parent) { + implicity += itext.y + } + implicity += itext.y + + var keyboardy = implicity + textfield.height + if(keyboard.y < keyboardy) { + var children = pages.children + for(var child in children) { + if(children[child].visible) { + children[child].adjustPosition(keyboardy - keyboard.y) + break; + } + } + } + } + + function addTarget(target) { + targets.push(target) + } +} diff --git a/app/logfile/LogPlay.qml b/app/logfile/LogPlay.qml new file mode 100644 index 0000000..c8e68fd --- /dev/null +++ b/app/logfile/LogPlay.qml @@ -0,0 +1,355 @@ +/* + * Copyright (c) 2019 TOYOTA MOTOR CORPORATION + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import QtQuick 2.6 +import QtQuick.Layouts 1.1 +import QtQuick.Controls 2.0 +import LogPlayImpl 1.0 +import '..' + +ColumnLayout { + property int blankheight : 50 + property bool playing: false + + property var timelist : '' + property var stime : ['1970', '01', '01', '00', '00', '00'] + property var etime : ['1970', '01', '01', '00', '00', '00'] + property var portslist : ['None'] + + anchors.left: parent.left + anchors.right: parent.right + + Item { height:blankheight } + + RowLayout{ + anchors.left: parent.left + anchors.right: parent.right + Label { text: 'CAN Log files: ' ; color: '#59FF7F'} + RowLayout{ + anchors.right: parent.right + Label { text: 'Port : ' } + ComboBox { + id: ports + implicitWidth: 220 + font.family: 'Roboto' + font.pixelSize: 30 + model: portslist + contentItem: Text { + text: ports.displayText + font: ports.font + color: ports.pressed ? "#17a81a" : "white" + horizontalAlignment: Text.AlignLeft + verticalAlignment: Text.AlignVCenter + elide: Text.ElideRight + } + indicator: Canvas { + id: canvas + x: ports.width - width - ports.rightPadding + y: ports.topPadding + (ports.availableHeight - height) / 2 + width: 20 + height: 12 + contextType: "2d" + + Connections { + target: ports + onPressedChanged: canvas.requestPaint() + } + + onPaint: { + context.reset(); + context.moveTo(0, 0); + context.lineTo(width, 0); + context.lineTo(width / 2, height); + context.closePath(); + context.fillStyle = ports.pressed ? "#17a81a" : "white"; + context.fill(); + } + } + popup: Popup { + id: portspopup + y: ports.height - 1 + implicitWidth: ports.width + implicitHeight: listview.contentHeight + padding: 0 + + contentItem: ListView { + id: listview + clip: true + model: portspopup.visible ? ports.delegateModel : null + currentIndex: ports.highlightedIndex + ScrollIndicator.vertical: ScrollIndicator { } + } + + background: Image { + source:'./images/HMI_Settings_Button_Cancel.svg' + } + } + delegate: ItemDelegate { + id: popupdelegate + width: ports.width + contentItem: Item { + implicitHeight: 30 + Text { + text: modelData + color: popupdelegate.pressed || highlighted ? "#21be2b" : "white" + font: ports.font + elide: Text.ElideRight + verticalAlignment: Text.AlignVCenter + } + } + + highlighted: ports.highlightedIndex == index + } + + background: Image { + source:'./images/HMI_Settings_Button_Cancel.svg' + } + onCurrentTextChanged: { + if(currentText != 'None') { + timelist = logplayimpl.getCanLogTime(currentText) + } + } + onModelChanged: { + if(currentText == '' || currentText == 'None') { + enabled = false + } + else { + enabled = true + } + } + } + } + } + Item { height:blankheight/3 } + Image { source: '../images/HMI_Settings_DividingLine.svg' } + Item { height:blankheight/3 } + ListView { + id: loglist + property int impheight: 0 + property int listitemheight : 50 + property int listmaxheight : 600 + + anchors.left: parent.left + anchors.right: parent.right + anchors.margins: 20 + implicitHeight: 0 + clip: true + model:logplayimpl + delegate: MouseArea { + height: loglist.listitemheight + width: ListView.view.width + Label { + anchors.right: parent.right + anchors.bottom: parent.bottom + visible: model.children > 0 ? true : false + text: '' + model.children + color: 'gray' + font.pixelSize: 30 + } + Image { + source: '../images/HMI_Settings_DividingLine.svg' + anchors.horizontalCenter: parent.horizontalCenter + anchors.top: parent.top + visible: model.index > 0 + } + Image { + visible: loglist.currentIndex === model.index ? true : false + anchors.fill: parent + source:'./images/HMI_Settings_Button_Cancel.svg' + } + Label { + anchors.left: parent.left + anchors.bottom: parent.bottom + anchors.margins: 5 + text: model.folder ? model.name : ' > ' + model.name + color: model.folder ? 'gray' : (loglist.currentIndex === model.index ? 'orange' : 'white') + font.pixelSize: 30 + } + onClicked: { + if(!model.folder) { + loglist.currentIndex = model.index + } + } + } + onCountChanged: { + impheight = (count * listitemheight) > listmaxheight ? listmaxheight : (count * listitemheight) + implicitHeight = impheight + } + + Component.onCompleted: { + currentIndex = -1 + } + onCurrentIndexChanged: { + model.setLogFileIndex(currentIndex) + portslist = model.getPortsList() + if(portslist.length == 0) { + portslist = ['None'] + } + timelist = model.getCanLogTime(ports.currentText) + } + } + Item { height:blankheight/3 } + Image { source: '../images/HMI_Settings_DividingLine.svg' } + Item { height:blankheight/3 } + Repeater { + id: logtime + model: ['Start Time : ', 'End Time : '] + delegate: RowLayout { + property var curidx: model.index + Item { + implicitHeight: 50 + implicitWidth: 250 + Label { + anchors.right: parent.right + anchors.bottom: parent.bottom + text: model.modelData + } + } + Repeater{ + id: datetime + property list<IntValidator> range: [ + IntValidator{bottom: 0; top: 23;}, + IntValidator{bottom: 0; top: 59;}, + IntValidator{bottom: 0; top: 59;} + ] + model: 6 + RowLayout { + implicitHeight: 50 + implicitWidth: 120 + Label { + anchors.bottom: parent.bottom + visible: model.index > 0 ? true : false + text: model.index === 3 ? ' ' : model.index > 3 ? ':' : '/' + color: model.index < 3 ? 'gray' : 'white' + font.pixelSize: 30 + } + TextField { + implicitWidth: model.index > 0 ? 60 : 90 + width: model.index > 0 ? 60 : 90 + text: (curidx*datetime.count + model.index) >= timelist.length ? '-' : timelist[(curidx*datetime.count + model.index)] + color: model.index > 2 ? 'white' : 'gray' + enabled: false + font.pixelSize: 30 + horizontalAlignment: TextInput.AlignHCenter + verticalAlignment: TextInput.AlignBottom + onTextChanged: { + if(model.index > 2 && text !== '/') { + enabled = true + if(text.length > 2) { + text = text.substring(text.length-2, text.length) + } + } + else { + enabled = false + } + if(curidx == 0 ) { + if(model.index < stime.length) { + stime[model.index] = text; + } + } + else { + if(model.index < stime.length) { + etime[model.index] = text; + } + } + } + onFocusChanged: { + root.updateKeyBoard() + if(!focus) { + if(text.length === 0) { + text = '00' + } + else if(text.length === 1 && text !== '/') { + text = '0' + text + } + } + } + } + } + Component.onCompleted: { + for(var i = 3, j = 0; i < count && j < range.length; i++, j++) { + itemAt(i).children[1].validator = range[j] + root.addTarget(itemAt(i).children[1]) + } + } + } + Label { + property int timeindex: 3+curidx*datetime.count + anchors.right: parent.right + anchors.bottom: parent.bottom + text: (timelist.length <= timeindex+2) ? '(-:-:-)' : + '('+timelist[timeindex]+':'+timelist[timeindex+1]+':'+timelist[timeindex+2]+')' + color: 'gray' + font.pixelSize: 20 + } + } + } + Item { height:blankheight/3 } + RowLayout { + anchors.left: parent.left + anchors.right: parent.right + Button { + anchors.left: parent.left + anchors.leftMargin: 100 + text: 'Refresh' + highlighted: true + onClicked: { + loglist.currentIndex = -1 + logplayimpl.refresh() + } + } + Button { + anchors.right: parent.right + anchors.rightMargin: 100 + text: playing ? 'Stop' : 'Play' + highlighted: true + onClicked: { + if(playing) { + playing = false + logplayimpl.CANPlay(false) + } + else { + if(logplayimpl.checkTime(ports.currentText, stime, etime)) + { + logplayimpl.setCANProperty(loglist.currentIndex, ports.currentText, stime, etime) + if(logplayimpl.CANPlay(true)) + playing = true + } + } + } + } + } + + LogPlayImpl { id: logplayimpl } + + onVisibleChanged: { + if(visible) { + logplayimpl.refresh() + } + else { + resetPosition() + } + } + + function adjustPosition(offset) { + loglist.implicitHeight -= offset + loglist.positionViewAtIndex(loglist.currentIndex, ListView.Beginning) + } + + function resetPosition() { + loglist.implicitHeight = loglist.impheight + } +} diff --git a/app/logfile/LogSave.qml b/app/logfile/LogSave.qml new file mode 100644 index 0000000..3b8a6ad --- /dev/null +++ b/app/logfile/LogSave.qml @@ -0,0 +1,238 @@ +/* + * Copyright (c) 2019 TOYOTA MOTOR CORPORATION + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import QtQuick 2.6 +import QtQuick.Layouts 1.3 +import QtQuick.Controls 2.0 +import LogSaveImpl 1.0 +import '..' + +ColumnLayout { + property int blankheight : 50 + property bool saving : false + + anchors.left: parent.left + anchors.right: parent.right + + Item { height:blankheight } + RowLayout { + anchors.left: parent.left + anchors.right: parent.right + Label { + text: 'CurPath : ' + color: 'white' + } + Label { + id: logpath + text: '' + color: 'white' + font.italic: true + font.pixelSize: 20 + } + } + + // Can log + Item { height:blankheight/3 } + Image { + width: tabbar.width + source: '../images/HMI_Settings_DividingLine.svg' + } + Item { height:blankheight/3 } + RowLayout { + anchors.left: parent.left + anchors.right: parent.right + Label { text: 'CAN'; color: '#59FF7F' } + Switch { id: canswitch;anchors.right: parent.right } + } +// Item { height:blankheight/3 } + CANLog {} + + // Touch log + Item { height:blankheight/3 } + Image { + width: tabbar.width + source: '../images/HMI_Settings_DividingLine.svg' + } + Item { height:blankheight/3 } + RowLayout { + anchors.left: parent.left + anchors.right: parent.right + Label { text: 'Touch'; color: '#59FF7F' } + Switch { id: touchswitch;anchors.right: parent.right } + } +// Item { height:blankheight/3 } + TouchLog {} + + // Video log + Item { height:blankheight/3 } + Image { + width: tabbar.width + source: '../images/HMI_Settings_DividingLine.svg' + } + Item { height:blankheight/3 } + RowLayout { + anchors.left: parent.left + anchors.right: parent.right + Label { text: 'Video'; color: '#59FF7F' } + Switch { id: videoswitch;anchors.right: parent.right } + } +// Item { height:blankheight/3 } + VideoLog { id: videolog } + + //Audio log + Item { height:blankheight/3 } + Image { + width: tabbar.width + source: '../images/HMI_Settings_DividingLine.svg' + } + Item { height:blankheight/3 } + RowLayout { + anchors.left: parent.left + anchors.right: parent.right + Label { text: 'Audio'; color: '#59FF7F' } + Switch { id: audioswitch;anchors.right: parent.right } + } +// Item { height:blankheight/3 } + AudioLog { id: audiolog } + + //Status bar + Item { height:blankheight/3 } + Image { + width: tabbar.width + source: '../images/HMI_Settings_DividingLine.svg' + } + Item { height:blankheight/3 } + RowLayout { + Label { + text: 'Status: ' + color: '#59FF7F' + } + Label { + id: recordstatus + property int hour: 0 + property int minute: 0 + property int second: 0 + property string duration: '' + text: saving ? ('Log Saving... '+ duration) : (hour > 0 || minute > 0 || second > 0) ? ('Duration: ' + duration) : 'Press SaveStart to save log file.' + font.pixelSize: 30 + Timer { + id: timer + property double seconds: 0 + interval: 1000 + running: false + repeat: true + onTriggered: { + if(saving) { + seconds++ + parent.hour = seconds/(60*60) + parent.minute = parent.hour > 0 ? seconds%(60*60)/60 : seconds/60 + parent.second = seconds - parent.hour*(60*60) - parent.minute*60 + parent.duration = (parent.hour > 0 ? (parent.hour + 'h ') : '')+(parent.minute > 0 ? (parent.minute + 'm ') : '')+(parent.second > 0 ? (parent.second + 's') : '') + } + } + } + } + } + + // Buttons + Item { height:blankheight/3 } + RowLayout { + anchors.left: parent.left + anchors.right: parent.right + Button { + id: savestart + anchors.horizontalCenter: parent.horizontalCenter + text: saving ? 'SaveStop' : 'SaveStart' + highlighted: true + onClicked: { + if(!saving && (canswitch.checked || touchswitch.checked || videoswitch.checked || audioswitch.checked)) { + if(logsaveimpl.createLogFolders()) { + logpath.text = logsaveimpl.getCurrentSeg() + + if(canswitch.checked) { + logsaveimpl.setCANProperty() + } + + if(touchswitch.checked) { + logsaveimpl.setTouchProperty() + } + + if(videoswitch.checked) { + logsaveimpl.setVideoProperty(videolog.properties) + } + + if(audioswitch.checked) { + logsaveimpl.setAudioProperty(audiolog.currentsps) + } + + console.log("touchswitch.checked: " + touchswitch.checked) + if(logsaveimpl.saveStart(canswitch.checked, touchswitch.checked, videoswitch.checked, audioswitch.checked)) { + recordstatus.hour = recordstatus.minute = recordstatus.second = 0 + recordstatus.duration = '' + timer.seconds = 0 + timer.start() + saving = true + } + } + }else if(saving) { + logsaveimpl.saveStop() + saving = false + timer.stop() + } + } + } + } + LogSaveImpl { + id: logsaveimpl + } + Component.onCompleted: { + if(logsaveimpl.createTripFolder()) { + logpath.text = trippath = logsaveimpl.getCurrentTrip() + } + else { + logpath.text = "" + } + } + + onVisibleChanged: { + if(!visible) { + resetPosition() + } + } + + function adjustPosition(offset) { + y -= offset + var heights = 0 + for(var child in children) { + heights += children[child].height + if(heights <= offset) { + children[child].opacity = 0 + } + else { + children[child].opacity = 0 + break + } + } + } + + function resetPosition() { + var children = logsave.children + for(var child in children) { + children[child].opacity = 1 + } + logsave.y = 0 + } +} diff --git a/app/logfile/TouchLog.qml b/app/logfile/TouchLog.qml new file mode 100644 index 0000000..61cb7c5 --- /dev/null +++ b/app/logfile/TouchLog.qml @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2019 TOYOTA MOTOR CORPORATION + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import QtQuick 2.6 +import QtQuick.Layouts 1.1 +import QtQuick.Controls 2.0 +import '..' + +ColumnLayout { + anchors.left: parent.left + anchors.leftMargin: 100 + Label { + text: 'There is no property which needs to be set.' + font.pixelSize: 30 + } +} diff --git a/app/logfile/TouchLogPlay.qml b/app/logfile/TouchLogPlay.qml new file mode 100644 index 0000000..3d78b95 --- /dev/null +++ b/app/logfile/TouchLogPlay.qml @@ -0,0 +1,188 @@ +/* + * Copyright (c) 2019 TOYOTA MOTOR CORPORATION + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import QtQuick 2.6 +import QtQuick.Layouts 1.1 +import QtQuick.Controls 2.0 +import TouchLogPlayImpl 1.0 +import '..' + +ColumnLayout { + property int blankheight : 50 +// property bool playing: false + + anchors.left: parent.left + anchors.right: parent.right + + Item { height:blankheight } + + // Title + RowLayout{ + anchors.left: parent.left + anchors.right: parent.right + Label { text: 'Touch Log files: ' ; color: '#59FF7F'} + } + + Item { height:blankheight/3 } + Image { source: '../images/HMI_Settings_DividingLine.svg' } + Item { height:blankheight/3 } + + // List view + ListView { + id: touchloglist + property int impheight: 0 + property int listitemheight : 50 + property int listmaxheight : 600 + + anchors.left: parent.left + anchors.right: parent.right + anchors.margins: 20 + implicitHeight: 0 + clip: true + model:touchlogplayimpl + delegate: MouseArea { + height: touchloglist.listitemheight + width: ListView.view.width + Label { + anchors.right: parent.right + anchors.bottom: parent.bottom + visible: model.children > 0 ? true : false + text: '' + model.children + color: 'gray' + font.pixelSize: 30 + } + Image { + source: '../images/HMI_Settings_DividingLine.svg' + anchors.horizontalCenter: parent.horizontalCenter + anchors.top: parent.top + visible: model.index > 0 + } + Image { + visible: touchloglist.currentIndex === model.index ? true : false + anchors.fill: parent + source:'./images/HMI_Settings_Button_Cancel.svg' + } + Label { + anchors.left: parent.left + anchors.bottom: parent.bottom + anchors.margins: 5 + text: model.folder ? model.name : ' > ' + model.name + color: model.folder ? 'gray' : (touchloglist.currentIndex === model.index ? 'orange' : 'white') + font.pixelSize: 30 + } + onClicked: { + if(!model.folder) { + touchloglist.currentIndex = model.index + } + } + } + onCountChanged: { + impheight = (count * listitemheight) > listmaxheight ? listmaxheight : (count * listitemheight) + implicitHeight = impheight + } + + Component.onCompleted: { + currentIndex = -1 + } + onCurrentIndexChanged: { + model.setLogFileIndex(currentIndex) + } + } + + Item { height:blankheight/3 } + Image { source: '../images/HMI_Settings_DividingLine.svg' } + Item { height:blankheight/3 } + + Item { height:blankheight/3 } + RowLayout { + anchors.left: parent.left + anchors.right: parent.right + Button { + anchors.left: parent.left + anchors.leftMargin: 100 + text: 'Refresh' + highlighted: true + onClicked: { + touchloglist.currentIndex = -1 + touchlogplayimpl.refresh() + } + } + Button { + id:playstopbutton + anchors.right: parent.right + anchors.rightMargin: 100 + text: touchlogplayimpl.propTouchPlayFlag ? 'Stop' : 'Play' + highlighted: true + + onClicked: { + console.log("status:", touchlogplayimpl.propTouchPlayFlag); + if(touchlogplayimpl.propTouchPlayFlag) { + touchlogplayimpl.touchPlay(false) + } + else { + touchlogplayimpl.setTouchProperty(touchloglist.currentIndex) + touchlogplayimpl.touchPlay(true) + } + } + } + } + + Timer { + id:countDown + repeat: false + triggeredOnStart: true + onTriggered: { + console.log("countDown onTriggered:"); + playstopbutton.text = 'Play' + countDown.stop(); + } + } + + TouchLogPlayImpl { + id: touchlogplayimpl + + onPropTouchPlayFlagChanged: { + console.log("onPropTouchPlayFlagChanged:", touchlogplayimpl.propTouchPlayFlag); + if(touchlogplayimpl.propTouchPlayFlag) { + playstopbutton.text = 'Stop' + console.log("Stop:"); + } else { + //playstopbutton.text = 'Play' + console.log("countDown.start():"); + countDown.start(); + console.log("countDown.started():"); + } + } + } + + onVisibleChanged: { + if(visible) { + touchlogplayimpl.refresh() + } + else { + resetPosition() + } + } + + function adjustPosition(offset) { + touchloglist.implicitHeight -= offset + touchloglist.positionViewAtIndex(touchloglist.currentIndex, ListView.Beginning) + } + + function resetPosition() { + touchloglist.implicitHeight = touchloglist.impheight + } +} diff --git a/app/logfile/VideoLog.qml b/app/logfile/VideoLog.qml new file mode 100644 index 0000000..325bea8 --- /dev/null +++ b/app/logfile/VideoLog.qml @@ -0,0 +1,213 @@ +/* + * Copyright (c) 2019 TOYOTA MOTOR CORPORATION + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import QtQuick 2.6 +import QtQuick.Layouts 1.1 +import QtQuick.Controls 2.0 +import '..' + +RowLayout { + id: videolog + + property var properties: ['', 0, 0,0] + + property int part1width: 250 + property int part2width: 600 + property int partheight: 50 + property int part1fontsize: 30 + property int part2fontsize: 30 + property var cameradevs: [] + + ColumnLayout{ + Repeater { + model: ['Zone : ', 'FPS : ', 'Width : ', 'Height : '] + delegate: Item { + implicitWidth: part1width + implicitHeight: partheight + Label { + anchors.right: parent.right + anchors.bottom: parent.bottom + font.pixelSize: part1fontsize + text: model.modelData + } + } + } + } + ColumnLayout{ +// RowLayout{ +// implicitWidth: part2width +// implicitHeight: partheight +// ButtonGroup { +// id: zonegroup +// } +// Repeater { +// id: zones +// model: ['None', 'Front', 'Rear', 'Left', 'Right'] +// delegate: CheckBox { +// text: model.modelData +// font.family: 'Roboto' +// font.pixelSize: part2fontsize +// ButtonGroup.group: zonegroup +// contentItem: Text { +// text: parent.text +// font: parent.font +// color:'white' +// horizontalAlignment: Text.AlignHCenter +// verticalAlignment: Text.AlignVCenter +// leftPadding: parent.indicator.width + parent.spacing +// } +// onCheckedChanged: { +// if(checked) { +// properties[0] = text +// } +// } +// } +// Component.onCompleted: { +// zones.itemAt(0).checked = true +// } +// } +// } + + ComboBox { + id: camerainfo + implicitWidth: part2width + font.pixelSize: 25 + model: cameradevs + contentItem: Text { + text: camerainfo.displayText + font: camerainfo.font + color: camerainfo.pressed ? "#17a81a" : "white" + horizontalAlignment: Text.AlignLeft + verticalAlignment: Text.AlignVCenter + elide: Text.ElideRight + } + indicator: Canvas { + id: canvas + x: camerainfo.width - width - camerainfo.rightPadding + y: camerainfo.topPadding + (camerainfo.availableHeight - height) / 2 + width: 20 + height: 12 + contextType: "2d" + + Connections { + target: camerainfo + onPressedChanged: { + canvas.requestPaint() + properties[0] = camerainfo.displayText + console.log("onPressedChanged", properties[0]) + } + } + + onPaint: { + context.reset(); + context.moveTo(0, 0); + context.lineTo(width, 0); + context.lineTo(width / 2, height); + context.closePath(); + context.fillStyle = camerainfo.pressed ? "#17a81a" : "white"; + context.fill(); + } + } + popup: Popup { + id: popup + y: camerainfo.height - 1 + implicitWidth: camerainfo.width + implicitHeight: listview.count > 6 ? (listview.contentHeight/3.3) : listview.contentHeight + padding: 0 + + contentItem: ListView { + id: listview + clip: true + model: camerainfo.visible ? camerainfo.delegateModel : null + currentIndex: camerainfo.highlightedIndex + ScrollIndicator.vertical: ScrollIndicator { } + } + + background: Image { source: "images/camerainfo_bg.svg" } + } + delegate: ItemDelegate { + id: popupdelegate + width: camerainfo.width + contentItem: Item { + implicitHeight: 30 + Text { + text: modelData + color: popupdelegate.pressed || highlighted ? "#21be2b" : "white" + font: camerainfo.font + elide: Text.ElideRight + verticalAlignment: Text.AlignVCenter + } + } + highlighted: camerainfo.highlightedIndex == index + } + + background: Image { source: "images/camerainfo_bg.svg" } + + onCurrentTextChanged: { + properties[0] = camerainfo.currentText + console.log("onCurrentTextChanged", properties[0]) + } + } + + Repeater { + id: textfields + property list<IntValidator> range: [ + IntValidator{bottom: 0; top: 100;}, + IntValidator{bottom: 0; top: 2000;}, + IntValidator{bottom: 0; top: 2000;} + ] + model: ['(0~100)', '(0~2000)', '(0~2000)'] + delegate: TextField { + implicitWidth: part2width + implicitHeight: partheight + color: 'white' + font.pixelSize: part2fontsize + verticalAlignment: TextInput.AlignBottom + Label { + anchors.right: parent.right + anchors.bottom: parent.bottom + text: model.modelData + color: 'gray' + font.pixelSize: 20 + } + onTextChanged: { + if(text == '0') { + text = '' + } + if(model.index + 1 < properties.length) { + properties[model.index + 1] = text + } + } + onFocusChanged: { + root.updateKeyBoard() + } + } + Component.onCompleted: { + for(var i = 0; i < textfields.count && i < range.length; i++) { + textfields.itemAt(i).validator = range[i] + root.addTarget(textfields.itemAt(i)) + } + } + } + } + + Component.onCompleted: { + logsaveimpl.enumerateCameras(); + cameradevs = logsaveimpl.cameradevs(); + properties[0] = cameradevs[0] + console.log(properties[0]); + } +} diff --git a/app/logfile/images/HMI_Settings_Button_Cancel.svg b/app/logfile/images/HMI_Settings_Button_Cancel.svg new file mode 100644 index 0000000..4251412 --- /dev/null +++ b/app/logfile/images/HMI_Settings_Button_Cancel.svg @@ -0,0 +1,93 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Generator: Adobe Illustrator 21.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> + +<svg + xmlns:i="&#38;ns_ai;" + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + version="1.1" + id="Layer_1" + x="0px" + y="0px" + viewBox="0 0 151 51" + style="enable-background:new 0 0 151 51;" + xml:space="preserve" + inkscape:version="0.91 r13725" + sodipodi:docname="HMI_Settings_TimeDate_Button_Cancel.svg"><metadata + id="metadata33"><rdf:RDF><cc:Work + rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs + id="defs31" /><sodipodi:namedview + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1" + objecttolerance="10" + gridtolerance="10" + guidetolerance="10" + inkscape:pageopacity="0" + inkscape:pageshadow="2" + inkscape:window-width="2560" + inkscape:window-height="1464" + id="namedview29" + showgrid="false" + inkscape:zoom="4.4503311" + inkscape:cx="-69.095982" + inkscape:cy="25.5" + inkscape:window-x="0" + inkscape:window-y="0" + inkscape:window-maximized="1" + inkscape:current-layer="Layer_1" /><style + type="text/css" + id="style3"> + .st0{fill:none;stroke:url(#SVGID_1_);stroke-miterlimit:10;} + .st1{opacity:0.3;fill:url(#SVGID_2_);} + .st2{fill:#FFFFFF;} + .st3{font-family:'Roboto-Regular';} + .st4{font-size:20px;} + .st5{letter-spacing:3;} +</style><switch + id="switch5"><g + i:extraneous="self" + id="g7"><g + id="g9"><linearGradient + id="SVGID_1_" + gradientUnits="userSpaceOnUse" + x1="24.7258" + y1="75.9063" + x2="126.2742" + y2="-24.9063"><stop + offset="0" + style="stop-color:#59FF7F" + id="stop12" /><stop + offset="1" + style="stop-color:#6BFBFF" + id="stop14" /></linearGradient><rect + x="0.5" + y="0.5" + class="st0" + width="150" + height="50" + id="rect16" /><linearGradient + id="SVGID_2_" + gradientUnits="userSpaceOnUse" + x1="-25.8746" + y1="126.14" + x2="190.2191" + y2="-88.3878"><stop + offset="0" + style="stop-color:#59FF7F" + id="stop19" /><stop + offset="1" + style="stop-color:#6BFBFF" + id="stop21" /></linearGradient><rect + x="0.5" + y="0.5" + class="st1" + width="150" + height="50" + id="rect23" /></g></g></switch></svg>
\ No newline at end of file diff --git a/app/logfile/images/HMI_Settings_Button_Ok.svg b/app/logfile/images/HMI_Settings_Button_Ok.svg new file mode 100644 index 0000000..dac68d8 --- /dev/null +++ b/app/logfile/images/HMI_Settings_Button_Ok.svg @@ -0,0 +1,93 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Generator: Adobe Illustrator 21.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> + +<svg + xmlns:i="&#38;ns_ai;" + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + version="1.1" + id="Layer_1" + x="0px" + y="0px" + viewBox="0 0 151 51" + style="enable-background:new 0 0 151 51;" + xml:space="preserve" + inkscape:version="0.91 r13725" + sodipodi:docname="HMI_Settings_TimeDate_Button_Set.svg"><metadata + id="metadata33"><rdf:RDF><cc:Work + rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs + id="defs31" /><sodipodi:namedview + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1" + objecttolerance="10" + gridtolerance="10" + guidetolerance="10" + inkscape:pageopacity="0" + inkscape:pageshadow="2" + inkscape:window-width="2560" + inkscape:window-height="1464" + id="namedview29" + showgrid="false" + inkscape:zoom="4.4503311" + inkscape:cx="-106.17187" + inkscape:cy="25.5" + inkscape:window-x="0" + inkscape:window-y="0" + inkscape:window-maximized="1" + inkscape:current-layer="Layer_1" /><style + type="text/css" + id="style3"> + .st0{fill:none;stroke:url(#SVGID_1_);stroke-miterlimit:10;} + .st1{opacity:0.84;fill:url(#SVGID_2_);} + .st2{fill:#27232B;} + .st3{font-family:'Roboto-Regular';} + .st4{font-size:20px;} + .st5{letter-spacing:3;} +</style><switch + id="switch5"><g + i:extraneous="self" + id="g7"><g + id="g9"><linearGradient + id="SVGID_1_" + gradientUnits="userSpaceOnUse" + x1="24.7258" + y1="75.9063" + x2="126.2742" + y2="-24.9063"><stop + offset="0" + style="stop-color:#59FF7F" + id="stop12" /><stop + offset="1" + style="stop-color:#6BFBFF" + id="stop14" /></linearGradient><rect + x="0.5" + y="0.5" + class="st0" + width="150" + height="50" + id="rect16" /><linearGradient + id="SVGID_2_" + gradientUnits="userSpaceOnUse" + x1="-25.8746" + y1="126.14" + x2="190.2191" + y2="-88.3878"><stop + offset="0" + style="stop-color:#59FF7F" + id="stop19" /><stop + offset="1" + style="stop-color:#6BFBFF" + id="stop21" /></linearGradient><rect + x="0.5" + y="0.5" + class="st1" + width="150" + height="50" + id="rect23" /></g></g></switch></svg>
\ No newline at end of file diff --git a/app/logfile/images/HMI_Settings_LogFile.svg b/app/logfile/images/HMI_Settings_LogFile.svg new file mode 100644 index 0000000..5c43c9d --- /dev/null +++ b/app/logfile/images/HMI_Settings_LogFile.svg @@ -0,0 +1,87 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Generator: Adobe Illustrator 21.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> + +<svg + xmlns:i="&#38;#38;#38;ns_ai;" + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + version="1.1" + id="Layer_1" + x="0px" + y="0px" + viewBox="0 0 100 100" + style="enable-background:new 0 0 100 100;" + xml:space="preserve" + inkscape:version="0.48.4 r9939" + sodipodi:docname="LOG2.svg" + width="100%" + height="100%"><metadata + id="metadata20"><rdf:RDF><cc:Work + rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs + id="defs18" /><sodipodi:namedview + pagecolor="#54544e" + bordercolor="#666666" + borderopacity="1" + objecttolerance="10" + gridtolerance="10" + guidetolerance="10" + inkscape:pageopacity="0.32941176" + inkscape:pageshadow="2" + inkscape:window-width="1615" + inkscape:window-height="917" + id="namedview16" + showgrid="false" + inkscape:zoom="3.337544" + inkscape:cx="29.813716" + inkscape:cy="60.135712" + inkscape:window-x="65" + inkscape:window-y="24" + inkscape:window-maximized="1" + inkscape:current-layer="g7" /><style + type="text/css" + id="style3"> + .st0{fill:#FFFFFF;} +</style><switch + id="switch5"><g + i:extraneous="self" + id="g7"><rect + style="fill:#ffffff;fill-opacity:0" + id="rect3825" + width="39.40678" + height="17.79661" + x="29.661016" + y="23.305084" + ry="7.2033896" /><path + style="fill:#ffffff;fill-opacity:1;stroke:none" + d="m 25.625,30.9375 c -2.112712,0 -3.84375,1.718453 -3.84375,3.84375 l 0,27.46875 c 0,2.125297 1.731038,3.84375 3.84375,3.84375 l 16.9375,0 c 1.879864,0 3.399091,-1.360464 3.71875,-3.15625 l -16.4375,0 c -2.112712,0 -3.8125,-1.718453 -3.8125,-3.84375 l 0,-27.5 c 0,-0.22376 0.05755,-0.443189 0.09375,-0.65625 l -0.5,0 z" + id="rect5439" + inkscape:connector-curvature="0" /><path + style="fill:#ffffff;fill-opacity:1;stroke:none" + d="m 49.157183,31.15625 c -6.669621,0 -12.094683,7.815468 -12.094683,17.46875 0,9.653282 5.425062,17.46875 12.094683,17.46875 6.66962,0 12.064745,-7.815468 12.064745,-17.46875 0,-9.653282 -5.395125,-17.46875 -12.064745,-17.46875 z m -0.239499,3.28125 c 4.764015,0 8.621952,6.38311 8.621952,14.28125 0,7.89814 -3.857937,14.3125 -8.621952,14.3125 -4.764015,0 -8.621952,-6.41436 -8.621952,-14.3125 0,-7.89814 3.857937,-14.28125 8.621952,-14.28125 z" + id="path5496" + inkscape:connector-curvature="0" /><path + style="fill:#ffffff;fill-opacity:1;stroke:none" + d="M 69.9375 30.84375 C 63.267879 30.84375 57.84375 38.659218 57.84375 48.3125 C 57.84375 57.965782 63.267879 65.78125 69.9375 65.78125 C 76.512166 65.78125 81.849391 58.181821 82 48.71875 L 78.3125 48.71875 C 78.211819 56.472129 74.388192 62.71875 69.6875 62.71875 C 64.923485 62.71875 61.0625 56.30439 61.0625 48.40625 C 61.0625 40.50811 64.923485 34.125 69.6875 34.125 C 73.815246 34.125 77.246493 38.926339 78.09375 45.34375 L 81.8125 45.34375 C 80.839908 37.107133 75.907462 30.84375 69.9375 30.84375 z " + id="path5496-9" /><rect + style="fill:#ffffff;fill-opacity:1;stroke:none" + id="rect5539" + width="9.7457628" + height="4.4491525" + x="70.886818" + y="48.691174" + rx="0.21186557" + ry="2.9228771" /><path + sodipodi:type="arc" + style="fill:#ffffff;fill-opacity:1;stroke:none" + id="path5541" + sodipodi:cx="50.186604" + sodipodi:cy="65.693336" + sodipodi:rx="38.501366" + sodipodi:ry="1.9475398" + d="m 88.687969,65.693336 a 38.501366,1.9475398 0 1 1 -77.002731,0 38.501366,1.9475398 0 1 1 77.002731,0 z" /></g></switch></svg>
\ No newline at end of file diff --git a/app/logfile/images/Keyboard_Arrow.svg b/app/logfile/images/Keyboard_Arrow.svg new file mode 100644 index 0000000..0b28afe --- /dev/null +++ b/app/logfile/images/Keyboard_Arrow.svg @@ -0,0 +1,65 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Generator: Adobe Illustrator 21.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> + +<svg + xmlns:i="&ns_ai;" + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + version="1.1" + id="Layer_1" + x="0px" + y="0px" + viewBox="0 0 89.6 119.8" + style="enable-background:new 0 0 89.6 119.8;" + xml:space="preserve" + inkscape:version="0.91 r13725" + sodipodi:docname="Keyboard_Arrow.svg"><metadata + id="metadata42"><rdf:RDF><cc:Work + rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs + id="defs40" /><sodipodi:namedview + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1" + objecttolerance="10" + gridtolerance="10" + guidetolerance="10" + inkscape:pageopacity="0" + inkscape:pageshadow="2" + inkscape:window-width="2560" + inkscape:window-height="1464" + id="namedview38" + showgrid="false" + inkscape:zoom="1.9699499" + inkscape:cx="-219.92755" + inkscape:cy="59.900002" + inkscape:window-x="0" + inkscape:window-y="0" + inkscape:window-maximized="1" + inkscape:current-layer="Layer_1" /><style + type="text/css" + id="style3"> + .st0{opacity:0.42;fill:#ACACA5;} + .st1{opacity:0.42;fill:url(#SVGID_1_);} + .st2{fill:none;stroke:#ACACA5;stroke-miterlimit:10;} + .st3{fill:none;stroke:#FFFFFF;stroke-width:2;stroke-miterlimit:10;} + .st4{fill:#FFFFFF;} +</style><switch + id="switch5"><g + i:extraneous="self" + id="g7"><g + id="g9"><g + id="g28"><g + id="g30"><polyline + class="st3" + points="53.7,44 53.7,71.2 22,71.2 " + id="polyline32" /><g + id="g34"><path + class="st4" + d="M35.7,61.6c0.3,0.5,0.2,1.1-0.3,1.4l-12.9,8.2l12.9,8.2c0.5,0.3,0.6,0.9,0.3,1.4 c-0.3,0.5-0.9,0.6-1.4,0.3l-14.2-9.1c-0.3-0.2-0.5-0.5-0.5-0.8c0-0.3,0.2-0.7,0.5-0.8l14.2-9.1c0.2-0.1,0.4-0.2,0.5-0.2 C35.2,61.2,35.5,61.3,35.7,61.6z" + id="path36" /></g></g></g></g></g></switch></svg>
\ No newline at end of file diff --git a/app/logfile/images/Keyboard_Back.svg b/app/logfile/images/Keyboard_Back.svg new file mode 100644 index 0000000..e28b58e --- /dev/null +++ b/app/logfile/images/Keyboard_Back.svg @@ -0,0 +1,57 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Generator: Adobe Illustrator 21.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> + +<svg + xmlns:i="&ns_ai;" + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + version="1.1" + id="Layer_1" + x="0px" + y="0px" + viewBox="0 0 78.3 119.8" + style="enable-background:new 0 0 78.3 119.8;" + xml:space="preserve" + inkscape:version="0.91 r13725" + sodipodi:docname="Keyboard_Inactive_Back.svg"><metadata + id="metadata21"><rdf:RDF><cc:Work + rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs + id="defs19" /><sodipodi:namedview + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1" + objecttolerance="10" + gridtolerance="10" + guidetolerance="10" + inkscape:pageopacity="0" + inkscape:pageshadow="2" + inkscape:window-width="2560" + inkscape:window-height="1464" + id="namedview17" + showgrid="false" + inkscape:zoom="1.9699499" + inkscape:cx="-229.89238" + inkscape:cy="59.900002" + inkscape:window-x="0" + inkscape:window-y="0" + inkscape:window-maximized="1" + inkscape:current-layer="Layer_1" /><style + type="text/css" + id="style3"> + .st0{opacity:0.42;fill:#ACACA5;} + .st1{fill:none;stroke:#ACACA5;stroke-miterlimit:10;} + .st2{fill:#FFFFFF;} +</style><switch + id="switch5"><g + i:extraneous="self" + id="g7"><g + id="g9"><path + class="st2" + d="M61.5,45.1H26.3c-0.5,0-1,0.2-1.3,0.5L10.6,59.9c-0.3,0.3-0.5,0.8-0.5,1.3s0.2,1,0.5,1.3L25,76.9 c0.3,0.3,0.8,0.5,1.3,0.5h35.3c1,0,1.8-0.8,1.8-1.8V46.9C63.4,45.9,62.5,45.1,61.5,45.1z M48.8,65.6c0.9,0.9,0.9,2.2,0,3.1 c-0.8,0.8-2.2,0.8-3.1,0l-4.3-4.3L37,68.7c-0.8,0.9-2.2,0.8-3.1,0c-0.8-0.8-0.9-2.2,0-3.1l4.3-4.3L34,56.9 c-0.8-0.8-0.8-2.2,0-3.1c0.9-0.9,2.2-0.8,3.1,0l4.3,4.3l4.4-4.4c0.8-0.8,2.2-0.8,3.1,0c0.8,0.8,0.8,2.2,0,3.1l-4.4,4.4L48.8,65.6 z" + id="path15" /></g></g></switch></svg>
\ No newline at end of file diff --git a/app/logfile/images/camerainfo_bg.svg b/app/logfile/images/camerainfo_bg.svg new file mode 100644 index 0000000..109ffe7 --- /dev/null +++ b/app/logfile/images/camerainfo_bg.svg @@ -0,0 +1,93 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Generator: Adobe Illustrator 21.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> + +<svg + xmlns:i="&#38;ns_ai;" + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + version="1.1" + id="Layer_1" + x="0px" + y="0px" + viewBox="0 0 600 51" + style="enable-background:new 0 0 600 51;" + xml:space="preserve" + inkscape:version="0.91 r13725" + sodipodi:docname="HMI_Settings_TimeDate_Button_Cancel.svg"><metadata + id="metadata33"><rdf:RDF><cc:Work + rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs + id="defs31" /><sodipodi:namedview + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1" + objecttolerance="10" + gridtolerance="10" + guidetolerance="10" + inkscape:pageopacity="0" + inkscape:pageshadow="2" + inkscape:window-width="2560" + inkscape:window-height="1464" + id="namedview29" + showgrid="false" + inkscape:zoom="4.4503311" + inkscape:cx="-69.095982" + inkscape:cy="25.5" + inkscape:window-x="0" + inkscape:window-y="0" + inkscape:window-maximized="1" + inkscape:current-layer="Layer_1" /><style + type="text/css" + id="style3"> + .st0{fill:none;stroke:url(#SVGID_1_);stroke-miterlimit:10;} + .st1{opacity:0.3;fill:url(#SVGID_2_);} + .st2{fill:#FFFFFF;} + .st3{font-family:'Roboto-Regular';} + .st4{font-size:20px;} + .st5{letter-spacing:3;} +</style><switch + id="switch5"><g + i:extraneous="self" + id="g7"><g + id="g9"><linearGradient + id="SVGID_1_" + gradientUnits="userSpaceOnUse" + x1="24.7258" + y1="75.9063" + x2="126.2742" + y2="-24.9063"><stop + offset="0" + style="stop-color:#59FF7F" + id="stop12" /><stop + offset="1" + style="stop-color:#6BFBFF" + id="stop14" /></linearGradient><rect + x="0.5" + y="0.5" + class="st0" + width="599" + height="50" + id="rect16" /><linearGradient + id="SVGID_2_" + gradientUnits="userSpaceOnUse" + x1="-25.8746" + y1="126.14" + x2="190.2191" + y2="-88.3878"><stop + offset="0" + style="stop-color:#59FF7F" + id="stop19" /><stop + offset="1" + style="stop-color:#6BFBFF" + id="stop21" /></linearGradient><rect + x="0.5" + y="0.5" + class="st1" + width="599" + height="50" + id="rect23" /></g></g></switch></svg> diff --git a/app/logfile/keyboard/AbstractKeyboard.qml b/app/logfile/keyboard/AbstractKeyboard.qml new file mode 100644 index 0000000..fc54aba --- /dev/null +++ b/app/logfile/keyboard/AbstractKeyboard.qml @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2019 TOYOTA MOTOR CORPORATION + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import QtQuick 2.6 +import QtQuick.Window 2.0 + +Item { + id: root + implicitWidth: Screen.width + implicitHeight: Screen.height / 3 + signal hide() + signal next() + property Item target +} diff --git a/app/logfile/keyboard/Key.qml b/app/logfile/keyboard/Key.qml new file mode 100644 index 0000000..390a066 --- /dev/null +++ b/app/logfile/keyboard/Key.qml @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2019 TOYOTA MOTOR CORPORATION + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import QtQuick 2.6 + +MouseArea { + id: root + implicitWidth: 50 + implicitHeight: 80 + property string text + property alias image: image.source + property bool touchable: true + property bool checkable: false + property bool checked: false + property bool capital: false + + onClicked: { + if (checkable) { + checked = !checked + } else { + if (label.text.length === 1) + insert(label.text) + } + } + + function clearSelctedText() { + if (target && target.selectedText.length > 0) { + target.remove(target.selectionStart, target.selectionEnd) + return true + } + return false + } + + function insert(text) { + clearSelctedText() + if(target) { + target.insert(target.cursorPosition, text) + } + } + + Rectangle { + id: buttonstyle + anchors.fill: parent + border.width: 2 + border.color: root.touchable ? 'white' : 'gray' + smooth: true + radius: root.height / 10 + color: 'gray' + Rectangle { + visible: root.touchable + anchors.fill: parent + radius: parent.radius + opacity: root.pressed || root.checked ? 0 : 0.5 + gradient: Gradient { + GradientStop { + position: 0.0 + color: 'transparent' + } + GradientStop { + position: 1.0 + color: '#66FF99' + } + } + } + } + + Text { + id: label + anchors.centerIn: parent + color: 'white' + font.pixelSize: root.height / 2 + text: root.text + } + + Image { + id: image + anchors.centerIn: parent + scale: 0.8 + } +} diff --git a/app/logfile/keyboard/Keyboard.qml b/app/logfile/keyboard/Keyboard.qml new file mode 100644 index 0000000..c5734d3 --- /dev/null +++ b/app/logfile/keyboard/Keyboard.qml @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2019 TOYOTA MOTOR CORPORATION + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import QtQuick 2.6 +import QtQuick.Window 2.0 +import QtQuick.Layouts 1.1 +import QtQuick.Controls 2.0 + +Item { + id: root + implicitWidth: Screen.width + implicitHeight: Screen.height / 3 + property Item target + property AbstractKeyboard active + + visible: false + + Rectangle { + anchors.fill: parent + color: 'black' + opacity: 0.5 + } + + MouseArea { + anchors.fill: parent + } +} diff --git a/app/logfile/keyboard/Numbers.qml b/app/logfile/keyboard/Numbers.qml new file mode 100644 index 0000000..664f206 --- /dev/null +++ b/app/logfile/keyboard/Numbers.qml @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2019 TOYOTA MOTOR CORPORATION + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import QtQuick 2.6 +import QtQuick.Window 2.0 +import QtQuick.Layouts 1.1 + +AbstractKeyboard { + id: root + + ColumnLayout { + anchors.fill: parent + anchors.margins: root.height / 10 + RowLayout { + Layout.fillWidth: true + Layout.fillHeight: true + Repeater { + model: ['1', '2', '3'] + delegate: Key { + text: model.modelData + Layout.preferredWidth: 2 + Layout.fillWidth: true + Layout.fillHeight: true + } + } + Key { + image: '../images/Keyboard_Back.svg' + Layout.preferredWidth: 2 + Layout.fillWidth: true + Layout.fillHeight: true + onClicked: { + if (!clearSelctedText()) { + if (target && target.cursorPosition > 0) + target.remove(target.cursorPosition - 1, target.cursorPosition) + } + } + } + } + RowLayout { + Layout.fillWidth: true + Layout.fillHeight: true + Repeater { + model: ['4', '5', '6'] + delegate: Key { + text: model.modelData + Layout.preferredWidth: 2 + Layout.fillWidth: true + Layout.fillHeight: true + } + } + Key { + image: '../images/Keyboard_Arrow.svg' + Layout.preferredWidth: 2 + Layout.fillWidth: true + Layout.fillHeight: true + onClicked: { + root.hide() + } + } + } + RowLayout { + Layout.fillWidth: true + Layout.fillHeight: true + Repeater { + model: ['7', '8', '9'] + delegate: Key { + text: model.modelData + Layout.preferredWidth: 2 + Layout.fillWidth: true + Layout.fillHeight: true + } + } + Key { + text: 'Next' + Layout.preferredWidth: 2 + Layout.fillWidth: true + Layout.fillHeight: true + onClicked: { + root.next() + } + } + } + RowLayout { + Layout.fillWidth: true + Layout.fillHeight: true + Key { + text: ' ' + Layout.preferredWidth: 2 + Layout.fillWidth: true + Layout.fillHeight: true + touchable: false + } + Key { + text: '0' + Layout.preferredWidth: 2 + Layout.fillWidth: true + Layout.fillHeight: true + } + Key { + text: ' ' + Layout.preferredWidth: 2 + Layout.fillWidth: true + Layout.fillHeight: true + touchable: false + } + Key { + text: 'Clear' + Layout.preferredWidth: 2 + Layout.fillWidth: true + Layout.fillHeight: true + onClicked: { + target.clear() + } + } + } + } +} diff --git a/app/logfile/logfile.qrc b/app/logfile/logfile.qrc new file mode 100644 index 0000000..b93cf0f --- /dev/null +++ b/app/logfile/logfile.qrc @@ -0,0 +1,23 @@ +<RCC> + <qresource prefix="/logfile"> + <file>Bar.qml</file> + <file>LogFile.qml</file> + <file>LogSave.qml</file> + <file>CANLog.qml</file> + <file>LogPlay.qml</file> + <file>VideoLog.qml</file> + <file>AudioLog.qml</file> + <file>keyboard/Numbers.qml</file> + <file>keyboard/Keyboard.qml</file> + <file>keyboard/Key.qml</file> + <file>keyboard/AbstractKeyboard.qml</file> + <file>images/HMI_Settings_LogFile.svg</file> + <file>images/Keyboard_Arrow.svg</file> + <file>images/Keyboard_Back.svg</file> + <file>images/HMI_Settings_Button_Cancel.svg</file> + <file>images/HMI_Settings_Button_Ok.svg</file> + <file>TouchLog.qml</file> + <file>TouchLogPlay.qml</file> + <file>images/camerainfo_bg.svg</file> + </qresource> +</RCC> diff --git a/app/logfile/logplay.cpp b/app/logfile/logplay.cpp new file mode 100644 index 0000000..e13c3fc --- /dev/null +++ b/app/logfile/logplay.cpp @@ -0,0 +1,290 @@ +/* + * Copyright (c) 2019 TOYOTA MOTOR CORPORATION + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "logplay.h" +#include <QDir> +#include <QDirIterator> +#include <QDateTime> +#include <QTextStream> +#include <sys/wait.h> +#include <unistd.h> + +const std::string LogPlayImpl::PlayUtilsExec = "/usr/bin/canplayer"; + +LogPlayImpl::LogPlayImpl(QObject *parent) : QAbstractItemModel(parent) +{ + roles[nameRole] = "name"; + roles[folderRole] = "folder"; + roles[childrenRole] = "children"; + roles[pathRole] = "path"; + + playUtils = -1; +} + +LogPlayImpl::~LogPlayImpl() +{ + CANPlay(false); +} + +int LogPlayImpl::rowCount(const QModelIndex &parent) const +{ + (void)parent; + return datas.size(); +} + +int LogPlayImpl::columnCount(const QModelIndex &parent) const +{ + (void)parent; + return 1; +} + +QModelIndex LogPlayImpl::index(int row, int column, const QModelIndex &parent) const +{ + (void)parent; + if((row >= 0) && (row < datas.size())) + { + return createIndex(row,column); + } + else + { + return QModelIndex(); + } +} + +QVariant LogPlayImpl::data(const QModelIndex &index, int role) const +{ + if(index.isValid() && index.row()<datas.size()) + { + return datas[index.row()][role]; + } + else + { + QHash<int,QVariant> data; + data[nameRole] = ""; + data[folderRole] = true; + data[childrenRole] = 0; + return data[role]; + } +} + +QModelIndex LogPlayImpl::parent(const QModelIndex &child) const +{ + (void)child; + return QModelIndex(); +} + +QHash<int,QByteArray> LogPlayImpl::roleNames() const +{ + return roles; +} + +void LogPlayImpl::refresh() +{ + QDir dir(QDir::homePath() + "/" + "LogDataFile"); + + if(dir.exists()) + { + beginResetModel(); + dir.setFilter(QDir::Dirs | QDir::NoDotAndDotDot); + dir.setSorting(QDir::Name); + + QFileInfoList list = dir.entryInfoList(); + datas.clear(); + + for(int i = 0; i < list.size(); i++) + { + QHash<int,QVariant> parent; + QStringList children; + + parent[nameRole] = list.at(i).fileName(); + parent[folderRole] = true; + parent[pathRole] = list.at(i).absoluteFilePath(); + + children.clear(); + + QDirIterator it(list.at(i).filePath(), QStringList() << "*.log", QDir::Files | QDir::NoSymLinks, QDirIterator::Subdirectories); + while(it.hasNext()) + { + children << it.next(); + } + + parent[childrenRole] = children.count(); + datas.append(parent); + + if(children.count() > 0) + { + children.sort(); + + for(int j = 0; j < children.count(); j++) + { + QHash<int,QVariant> child; + + child[nameRole] = children.at(j).section("/", -1); + child[folderRole] = false; + child[childrenRole] = 0; + child[pathRole] = children.at(j); + + datas.append(child); + } + } + } + endResetModel(); + } +} + +void LogPlayImpl::setLogFileIndex(int index) +{ + startTime.clear(); + endTime.clear(); + portsList.clear(); + + if(index > 0 && index < datas.size()) + { + QFile file(datas[index][pathRole].toString()); + + if(file.exists() && file.open(QIODevice::ReadOnly | QIODevice::Text)) + { + QTextStream filetxt(&file); + QString line = ""; + QString port = ""; + QDateTime datetime; + + while(!filetxt.atEnd()) + { + line = filetxt.readLine(); + if(!line.isEmpty()) + { + port = line.section(" ", 1, 1, QString::SectionSkipEmpty); + if(port.isEmpty()) + { + port = line.section("\t", 1, 1, QString::SectionSkipEmpty); + } + datetime = QDateTime::fromTime_t(line.mid(line.indexOf("(")+1, line.indexOf(".")-line.indexOf("(")-1).toUInt()); + if(!portsList.contains(port)) + { + portsList << port; + startTime[port] << datetime.toString("yyyy") << datetime.toString("MM") << datetime.toString("dd") + << datetime.toString("hh") << datetime.toString("mm") << datetime.toString("ss"); + } + if(endTime.find(port) != endTime.end()) + { + endTime[port].clear(); + } + endTime[port] << datetime.toString("yyyy") << datetime.toString("MM") << datetime.toString("dd") + << datetime.toString("hh") << datetime.toString("mm") << datetime.toString("ss"); + } + } + file.close(); + } + } +} + +QStringList LogPlayImpl::getCanLogTime(QString port) +{ + if(startTime.find(port) != startTime.end() && endTime.find(port) != endTime.end()) + { + return startTime[port] + endTime[port]; + } + else + { + return QStringList(); + } +} + +QStringList LogPlayImpl::getPortsList() +{ + return portsList; +} + +bool LogPlayImpl::CANPlay(bool play) +{ + if(play) + { + playUtils = fork(); + switch(playUtils) + { + case 0: + execl(PlayUtilsExec.c_str(), basename(PlayUtilsExec.c_str()), + playUtilsArg["-p"].toStdString().c_str(), + "-I", playUtilsArg["-I"].toStdString().c_str(), + "-l", "i", + (char*)NULL); + break; + default: + break; + } + } + else + { + if((playUtils > 0) && (kill(playUtils, SIGUSR1) == 0)) + { + waitpid(playUtils, NULL, 0); + } + } + + return true; +} + +void LogPlayImpl::setCANProperty(int index, QString port, QString stime, QString etime) +{ + if(index > 0 && index < datas.size()) + { + playUtilsArg["-p"] = "vcan0="+port; + playUtilsArg["-I"] = datas[index][pathRole].toString(); + } +} + +bool LogPlayImpl::checkTime(QString port, QString stime, QString etime) +{ + QString maxtime = ""; + QString mintime = ""; + + if(startTime.find(port) == startTime.end() || endTime.find(port) == endTime.end()) + { + return false; + } + + for(int idx = 0; idx < startTime[port].length() && idx < endTime[port].length(); idx++) + { + mintime += startTime[port].at(idx) + (idx == startTime[port].length() - 1 ? "" : ","); + maxtime += endTime[port].at(idx) + (idx == endTime[port].length() - 1 ? "" : ","); + } + + if((stime < mintime) || (stime > maxtime) || (etime < mintime) || (etime > maxtime) || (stime > etime)) + { + return false; + } + else + { + return true; + } +} + +QString LogPlayImpl::convertTimeFormat(QString time) +{ + QStringList sep; + QString convertstr = ""; + + sep << "-" << "-" << "." << ":" << ":"; + + //2016-02-08.09:41:59 + for(int idx = 0; idx <= time.count(","); idx++) + { + convertstr += time.section(',' , idx, idx) + (idx < sep.length() ? sep.at(idx) : ""); + } + + return convertstr; +} diff --git a/app/logfile/logplay.h b/app/logfile/logplay.h new file mode 100644 index 0000000..90a35c1 --- /dev/null +++ b/app/logfile/logplay.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2019 TOYOTA MOTOR CORPORATION + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LOGPLAYIMPPL_H +#define LOGPLAYIMPPL_H + +#include <QAbstractItemModel> + +class LogPlayImpl: public QAbstractItemModel +{ + Q_OBJECT +public: + explicit LogPlayImpl(QObject *parent = 0); + ~LogPlayImpl(); + + enum LogPlayImplRoles{ + nameRole=Qt::UserRole+1, + folderRole, + childrenRole, + pathRole + }; + + int rowCount(const QModelIndex &parent=QModelIndex()) const Q_DECL_OVERRIDE; + int columnCount(const QModelIndex &parent=QModelIndex()) const Q_DECL_OVERRIDE; + QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const Q_DECL_OVERRIDE; + QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const Q_DECL_OVERRIDE; + QModelIndex parent(const QModelIndex &child) const Q_DECL_OVERRIDE; + QHash<int,QByteArray> roleNames() const Q_DECL_OVERRIDE; + + Q_INVOKABLE void refresh(); + Q_INVOKABLE bool CANPlay(bool play); + Q_INVOKABLE void setCANProperty(int index, QString port, QString stime, QString etime); + Q_INVOKABLE void setLogFileIndex(int index); + Q_INVOKABLE QStringList getPortsList(); + Q_INVOKABLE QStringList getCanLogTime(QString port); + Q_INVOKABLE bool checkTime(QString port, QString stime, QString etime); + +private: + QString convertTimeFormat(QString time); + +private: + QHash<int,QByteArray> roles; + QList<QHash<int,QVariant>> datas; + std::map<QString, QStringList> startTime; + std::map<QString, QStringList> endTime; + QStringList portsList; + + static const std::string PlayUtilsExec; + + pid_t playUtils; + std::map<QString, QString> playUtilsArg; +}; + +#endif // LOGPLAYIMPPL_H diff --git a/app/logfile/logsave.cpp b/app/logfile/logsave.cpp new file mode 100644 index 0000000..0c21afe --- /dev/null +++ b/app/logfile/logsave.cpp @@ -0,0 +1,360 @@ +/* + * Copyright (c) 2019 TOYOTA MOTOR CORPORATION + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "logsave.h" + +#include <QDateTime> +#include <QDir> +#include <sys/wait.h> +#include <unistd.h> + +#include <fcntl.h> +#include <sys/ioctl.h> +#include <opencv2/imgproc.hpp> +#include <linux/videodev2.h> + +#include <QDebug> +#include <QCoreApplication> + +const QString LogSaveImpl::TripPre = "Trip_"; +const QString LogSaveImpl::SegPre = "Seg_"; + +const QString LogSaveImpl::FolderAudio = "AUDIO"; +const QString LogSaveImpl::FolderVideo = "VIDEO"; +const QString LogSaveImpl::FolderCAN = "CAN"; +const QString LogSaveImpl::FolderTouch = "TOUCH"; +const QString LogSaveImpl::FolderOther = "OTHER"; + +const QString LogSaveImpl::RootFolder = "LogDataFile"; + +const std::string LogSaveImpl::DumpUtilsExec = "/usr/bin/candump"; +const std::string LogSaveImpl::AudioMixerExec = "/usr/bin/amixer"; +const std::string LogSaveImpl::AudioUtilsExec = "/usr/bin/arecord"; +const std::string LogSaveImpl::VideoUtilsExec = std::string(getenv("AFM_APP_INSTALL_DIR")) + "/bin/videoutils"; +const std::string LogSaveImpl::TouchRecUtilsExec = std::string(getenv("AFM_APP_INSTALL_DIR")) + "/bin/tsrecorder"; + +LogSaveImpl::LogSaveImpl(QObject *parent):QObject(parent) +{ +// videoDevice["None"] = "10"; +// videoDevice["Front"] = "1"; +// videoDevice["Right"] = "2"; +// videoDevice["Left"] = "3"; +// videoDevice["Rear"] = "4"; + + logFolders[FolderAudio] = ""; + logFolders[FolderVideo] = ""; + logFolders[FolderCAN] = ""; + logFolders[FolderOther] = ""; + logFolders[FolderTouch] = ""; + + rootPath = QDir::homePath() + "/" + RootFolder; + QDir rootdir(rootPath); + if(!rootdir.exists()) + { + if(!rootdir.mkdir(rootPath)) + { + rootPath = "/tmp"; + } + } + + dumpUtils = -1; + audioMixer = -1; + audioUtils = -1; + videoUtils = -1; + touchRecUtils = -1; +} + +LogSaveImpl::~LogSaveImpl() +{ + saveStop(); +} + +void LogSaveImpl::setVideoProperty(QStringList properties) +{ + if(properties.length() < 4) + { + return; + } + +// videoUtilsArg["-d"] = videoDevice[properties[0]]; + videoUtilsArg["-d"] = properties[0].remove("/dev/video"); + videoUtilsArg["-r"] = (properties[1] != "0" ? properties[1] : "30"); + videoUtilsArg["-w"] = (properties[2] != "0" ? properties[2] : "640"); + videoUtilsArg["-h"] = (properties[3] != "0" ? properties[3] : "480"); + videoUtilsArg["-f"] = logFolders[FolderVideo] + QDateTime::currentDateTime().toString("yyyy_MM_dd_hh_mm_ss") + ".avi"; +} + +void LogSaveImpl::setCANProperty() +{ + dumpUtilsArg["-L"] = logFolders[FolderCAN] + QDateTime::currentDateTime().toString("yyyy_MM_dd_hh_mm_ss") + ".log"; +} + +void LogSaveImpl::setTouchProperty() +{ + touchRecUtilsArg["-f"] = logFolders[FolderTouch] + QDateTime::currentDateTime().toString("yyyy_MM_dd_hh_mm_ss") + ".touch"; +} + +void LogSaveImpl::setAudioProperty(QString sps) +{ + audioUtilsArg["-r"] = (sps != "0" ? sps : "44100"); + audioUtilsArg["-f"] = logFolders[FolderAudio] + QDateTime::currentDateTime().toString("yyyy_MM_dd_hh_mm_ss") + ".wav"; +} + +bool LogSaveImpl::saveStart(bool can, bool touch, bool video, bool audio) +{ + qDebug("touch:%d", touch); + if(video) + { + qDebug("-d:%s", videoUtilsArg["-d"].toStdString().c_str()); + videoUtils = fork(); + switch(videoUtils) + { + case 0: + execl(VideoUtilsExec.c_str(), basename(VideoUtilsExec.c_str()), + "-d", videoUtilsArg["-d"].toStdString().c_str(), + "-w", videoUtilsArg["-w"].toStdString().c_str(), + "-h", videoUtilsArg["-h"].toStdString().c_str(), + "-r", videoUtilsArg["-r"].toStdString().c_str(), + "-f", videoUtilsArg["-f"].toStdString().c_str(), + "-c", "MP42", + (char *)NULL); + break; + default: + break; + } + } + + if(can) + { + int fd; + dumpUtils = fork(); + switch(dumpUtils) + { + case 0: + fd = open(dumpUtilsArg["-L"].toStdString().c_str(), O_CREAT | O_WRONLY, 0666); + dup2(fd, 1); + close(fd); /* fd は以後不要なので close() */ + execl(DumpUtilsExec.c_str(), basename(DumpUtilsExec.c_str()), "vcan0", "-L", (char *)NULL); + break; + default: + break; + } + } + + if(touch) + { + qDebug() << "current file" << TouchRecUtilsExec.c_str(); + + touchRecUtils = fork(); + qDebug("touchRecUtils:%d", touchRecUtils); + switch(touchRecUtils) + { + case 0: + qDebug("TouchRecUtilsExec:%s", touchRecUtilsArg["-f"].toStdString().c_str()); + execl(TouchRecUtilsExec.c_str(), basename(TouchRecUtilsExec.c_str()), "-f", touchRecUtilsArg["-f"].toStdString().c_str(), (char *)NULL); + break; + default: + break; + } + } + + if(audio) + { + // Set volume + audioMixer = fork(); + switch(audioMixer) + { + case 0: + execl(AudioMixerExec.c_str(), basename(AudioMixerExec.c_str()), "-D", "hw:ak4613", "cset", "name='DVC In Capture Volume'", "100%", (char*)NULL); + break; + default: + break; + } + if(audioMixer > 0) + { + waitpid(audioMixer, NULL, 0); + } + + // Set mute off + audioMixer = fork(); + switch(audioMixer) + { + case 0: + execl(AudioMixerExec.c_str(), basename(AudioMixerExec.c_str()), "-D", "hw:ak4613", "cset", "name='DVC In Mute Switch'", "off", (char*)NULL); + break; + default: + break; + } + if(audioMixer > 0) + { + waitpid(audioMixer, NULL, 0); + } + + // Start record + audioUtils = fork(); + switch(audioUtils) + { + case 0: + execl(AudioUtilsExec.c_str(), basename(AudioUtilsExec.c_str()), "-c", "2", "-f", "S24_LE", "-r", audioUtilsArg["-r"].toStdString().c_str(), "-t", "wav", "-D", "hw:ak4613", audioUtilsArg["-f"].toStdString().c_str(), (char*)NULL); + break; + default: + break; + } + } + return true; +} + +void LogSaveImpl::saveStop() +{ + if((videoUtils > 0) && (kill(videoUtils, SIGUSR1) == 0)) + { + waitpid(videoUtils, NULL, 0); + } + + if((dumpUtils > 0) && (kill(dumpUtils, SIGUSR1) == 0)) + { + waitpid(dumpUtils, NULL, 0); + } + + if((audioUtils > 0) && (kill(audioUtils, SIGKILL) == 0)) + { + waitpid(audioUtils, NULL, 0); + } + + if((touchRecUtils > 0) && (kill(touchRecUtils, SIGKILL) == 0)) + { + waitpid(touchRecUtils, NULL, 0); + } +} + +bool LogSaveImpl::createLogFolders() +{ + bool result = false; + + if(createSegFolder()) + { + QString path; + QDir dir; + + result = true; + + for(std::map<QString,QString>::iterator it = logFolders.begin(); it != logFolders.end(); it++) + { + path = currentSeg + "/" + it->first; + if(!dir.exists(path) && !dir.mkdir(path)) + { + it->second = ""; + } + else + { + it->second = path + "/"; + } + } + } + return result; +} + +bool LogSaveImpl::createTripFolder() +{ + currentTrip = ""; + if(!rootPath.isEmpty()) + { + QDir tripdir; + + currentTrip = rootPath + "/" + TripPre + QDateTime::currentDateTime().toString("yyyyMMdd_hhmmss"); + + if(!tripdir.exists(currentTrip) && !tripdir.mkdir(currentTrip)) + { + currentTrip = ""; + } + } + + if(currentTrip.isEmpty()) + { + return false; + } + else + { + return true; + } +} + +bool LogSaveImpl::createSegFolder() +{ + currentSeg = ""; + + if(!currentTrip.isEmpty()) + { + QDir segdir; + + currentSeg = currentTrip + "/" + SegPre + QDateTime::currentDateTime().toString("yyyyMMdd_hhmmss"); + + if(!segdir.exists(currentSeg) && !segdir.mkdir(currentSeg)) + { + currentSeg = ""; + } + } + + if(currentSeg.isEmpty()) + { + return false; + } + else + { + return true; + } +} + +void LogSaveImpl::enumerateCameras() { + int maxID = 11; + for (int idx = 0; idx <maxID; idx++){ + std::stringstream no; + no << "/dev/video" << idx; + int fd = open(no.str().c_str(), O_RDWR); + if (fd != -1){ + struct v4l2_capability cap; + + if (ioctl(fd,VIDIOC_QUERYCAP,&cap) != -1){ + if ((cap.capabilities & (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING)) == (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING)){ + qDebug("cap.driver %s, cap.card %s, cap.bus_info %s", (char*)(cap.driver), (char*)(cap.card), (char*)(cap.bus_info)); + if(strcmp((char*)cap.driver, "uvcvideo") == 0) + { + cameras.push_back(no.str().c_str()); // vector of all available cameras + } + } + } + close(fd); + } + } +} + +QVariantList LogSaveImpl::cameradevs() const{ + return cameras; +} + +int LogSaveImpl::cameraCnt() { + return cameras.length(); +} + +QString LogSaveImpl::getCurrentTrip() +{ + return currentTrip; +} + +QString LogSaveImpl::getCurrentSeg() +{ + return currentSeg; +} diff --git a/app/logfile/logsave.h b/app/logfile/logsave.h new file mode 100644 index 0000000..45f5829 --- /dev/null +++ b/app/logfile/logsave.h @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2019 TOYOTA MOTOR CORPORATION + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LOGSAVE_H +#define LOGSAVE_H + +#include <QObject> +#include <QVariantList> + +class LogSaveImpl : public QObject +{ + Q_OBJECT +public: + explicit LogSaveImpl(QObject *parent = 0); + ~LogSaveImpl(); + +public: + Q_INVOKABLE bool saveStart(bool can, bool touch, bool video, bool audio); + Q_INVOKABLE void saveStop(); + Q_INVOKABLE void setCANProperty(); + Q_INVOKABLE void setTouchProperty(); + Q_INVOKABLE void setVideoProperty(QStringList properties); + Q_INVOKABLE void setAudioProperty(QString sps); + Q_INVOKABLE QString getCurrentTrip(); + Q_INVOKABLE QString getCurrentSeg(); + Q_INVOKABLE bool createTripFolder(); + Q_INVOKABLE bool createLogFolders(); + Q_INVOKABLE QVariantList cameradevs() const; + Q_INVOKABLE void enumerateCameras(); + Q_INVOKABLE int cameraCnt(); + +private: + bool createSegFolder(); + +signals: + void camraCntChanged(const QVariantList& camcnt); + +private: + static const QString TripPre; + static const QString SegPre; + + static const QString FolderAudio; + static const QString FolderVideo; + static const QString FolderCAN; + static const QString FolderTouch; + static const QString FolderOther; + + static const QString RootFolder; + + static const std::string DumpUtilsExec; + static const std::string AudioMixerExec; + static const std::string AudioUtilsExec; + static const std::string VideoUtilsExec; + static const std::string TouchRecUtilsExec; + + QString currentSeg; + QString currentTrip; + QString rootPath; +// std::map<QString, QString> videoDevice; + std::map<QString, QString> logFolders; + + pid_t dumpUtils; + pid_t audioMixer; + pid_t audioUtils; + pid_t videoUtils; + pid_t touchRecUtils; + + QVariantList cameras; + + std::map<QString, QString> dumpUtilsArg; + std::map<QString, QString> audioUtilsArg; + std::map<QString, QString> videoUtilsArg; + std::map<QString, QString> touchRecUtilsArg; +}; + +#endif // LOGSAVE_H diff --git a/app/logfile/touchlogplay.cpp b/app/logfile/touchlogplay.cpp new file mode 100644 index 0000000..02a53b4 --- /dev/null +++ b/app/logfile/touchlogplay.cpp @@ -0,0 +1,271 @@ +/* + * Copyright (c) 2019 TOYOTA MOTOR CORPORATION + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "touchlogplay.h" +#include <QDir> +#include <QDirIterator> +#include <QDateTime> +#include <QTextStream> +#include <sys/wait.h> +#include <unistd.h> +#include <signal.h> + +#include <QDebug> +#include <QCoreApplication> + +const std::string TouchLogPlayImpl::touchPlayUtilsExec = std::string(getenv("AFM_APP_INSTALL_DIR")) + "/bin/tsplayer"; +TouchLogPlayImpl *TouchLogPlayImpl::pointer = NULL; +bool TouchLogPlayImpl::touchPlayFlag = false; +void (*TouchLogPlayImpl::oldHandler)(int) = NULL; + +TouchLogPlayImpl::TouchLogPlayImpl(QObject *parent) : QAbstractItemModel(parent) +{ + roles[nameRole] = "name"; + roles[folderRole] = "folder"; + roles[childrenRole] = "children"; + roles[pathRole] = "path"; + + touchPlayUtils = -1; + pointer = this; +} + +TouchLogPlayImpl::~TouchLogPlayImpl() +{ + touchPlay(false); +} + +int TouchLogPlayImpl::rowCount(const QModelIndex &parent) const +{ + (void)parent; + return datas.size(); +} + +int TouchLogPlayImpl::columnCount(const QModelIndex &parent) const +{ + (void)parent; + return 1; +} + +QModelIndex TouchLogPlayImpl::index(int row, int column, const QModelIndex &parent) const +{ + (void)parent; + if((row >= 0) && (row < datas.size())) + { + return createIndex(row,column); + } + else + { + return QModelIndex(); + } +} + +QVariant TouchLogPlayImpl::data(const QModelIndex &index, int role) const +{ + if(index.isValid() && index.row()<datas.size()) + { + return datas[index.row()][role]; + } + else + { + QHash<int,QVariant> data; + data[nameRole] = ""; + data[folderRole] = true; + data[childrenRole] = 0; + return data[role]; + } +} + +QModelIndex TouchLogPlayImpl::parent(const QModelIndex &child) const +{ + (void)child; + return QModelIndex(); +} + +QHash<int,QByteArray> TouchLogPlayImpl::roleNames() const +{ + return roles; +} + +void TouchLogPlayImpl::refresh() +{ + QDir dir(QDir::homePath() + "/" + "LogDataFile"); + + if(dir.exists()) + { + beginResetModel(); + dir.setFilter(QDir::Dirs | QDir::NoDotAndDotDot); + dir.setSorting(QDir::Name); + + QFileInfoList list = dir.entryInfoList(); + datas.clear(); + + for(int i = 0; i < list.size(); i++) + { + QHash<int,QVariant> parent; + QStringList children; + + parent[nameRole] = list.at(i).fileName(); + parent[folderRole] = true; + parent[pathRole] = list.at(i).absoluteFilePath(); + + children.clear(); + + QDirIterator it(list.at(i).filePath(), QStringList() << "*.touch", QDir::Files | QDir::NoSymLinks, QDirIterator::Subdirectories); + while(it.hasNext()) + { + children << it.next(); + } + + parent[childrenRole] = children.count(); + datas.append(parent); + + if(children.count() > 0) + { + children.sort(); + + for(int j = 0; j < children.count(); j++) + { + QHash<int,QVariant> child; + + child[nameRole] = children.at(j).section("/", -1); + child[folderRole] = false; + child[childrenRole] = 0; + child[pathRole] = children.at(j); + + datas.append(child); + } + } + } + endResetModel(); + } +} + +void TouchLogPlayImpl::setLogFileIndex(int index) +{ + if(index > 0 && index < datas.size()) + { + QFile file(datas[index][pathRole].toString()); + + if(file.exists() && file.open(QIODevice::ReadOnly | QIODevice::Text)) + { + QTextStream filetxt(&file); + QString line = ""; + QString port = ""; + QDateTime datetime; + + while(!filetxt.atEnd()) + { + line = filetxt.readLine(); + if(!line.isEmpty()) + { + port = line.section(" ", 1, 1, QString::SectionSkipEmpty); + if(port.isEmpty()) + { + port = line.section("\t", 1, 1, QString::SectionSkipEmpty); + } + datetime = QDateTime::fromTime_t(line.mid(line.indexOf("(")+1, line.indexOf(".")-line.indexOf("(")-1).toUInt()); + } + } + file.close(); + } + } +} + +bool TouchLogPlayImpl::touchPlay(bool play) +{ + qDebug() << "touchPlayFlag:" << touchPlayFlag; + if(play) + { + oldHandler = signal(SIGCHLD, finalizeChild); + if(oldHandler == SIG_ERR) + { + qDebug("signal error."); + return false; + } + + qDebug() << "current file" << touchPlayUtilsExec.c_str(); + + touchPlayUtils = fork(); + switch(touchPlayUtils) + { + case 0: + execl(touchPlayUtilsExec.c_str(), basename(touchPlayUtilsExec.c_str()), + "-d", "1", + "-f", touchplayUtilsArg["-f"].toStdString().c_str(), + "-e", "1", + (char*)NULL); + break; + default: + touchPlayFlag = true; + emit propTouchPlayFlagChanged(); + qDebug() << "default:"; + break; + } + } + else + { + if(touchPlayFlag) + { + if((touchPlayUtils > 0) && (kill(touchPlayUtils, SIGUSR1) == 0)) + { + waitpid(touchPlayUtils, NULL, 0); + } + } + } + + return true; +} + +void TouchLogPlayImpl::setTouchProperty(int index) +{ + if(index > 0 && index < datas.size()) + { + touchplayUtilsArg["-f"] = datas[index][pathRole].toString(); + } +} + +bool TouchLogPlayImpl::propTouchPlayFlag() const +{ + return touchPlayFlag; +} + +void TouchLogPlayImpl::propTouchPlayFlagChangedDelegate() +{ + emit propTouchPlayFlagChanged(); +} + +void TouchLogPlayImpl::finalizeChild(int sig) +{ + if(sig == SIGCHLD) + { + qDebug("finalizeChild start."); + waitpid(-1, NULL, 0); + touchPlayFlag = false; + pointer->propTouchPlayFlagChangedDelegate(); + qDebug("finalizeChild end."); + } + + if(signal(SIGCHLD, oldHandler) == SIG_ERR) + { + qDebug("signal error."); + } +} + +void TouchLogPlayImpl::emitSignalAgent() +{ + qDebug("emitSignalAgent"); + pointer->propTouchPlayFlagChangedDelegate(); +} diff --git a/app/logfile/touchlogplay.h b/app/logfile/touchlogplay.h new file mode 100644 index 0000000..9114de5 --- /dev/null +++ b/app/logfile/touchlogplay.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2019 TOYOTA MOTOR CORPORATION + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef TOUCHLOGPLAY_H +#define TOUCHLOGPLAY_H + +#include <QAbstractItemModel> + +class TouchLogPlayImpl: public QAbstractItemModel +{ + Q_OBJECT + Q_PROPERTY(bool propTouchPlayFlag READ propTouchPlayFlag NOTIFY propTouchPlayFlagChanged) +public: + explicit TouchLogPlayImpl(QObject *parent = 0); + ~TouchLogPlayImpl(); + + enum TouchLogPlayImplRoles { + nameRole=Qt::UserRole+1, + folderRole, + childrenRole, + pathRole + }; + + int rowCount(const QModelIndex &parent=QModelIndex()) const Q_DECL_OVERRIDE; + int columnCount(const QModelIndex &parent=QModelIndex()) const Q_DECL_OVERRIDE; + QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const Q_DECL_OVERRIDE; + QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const Q_DECL_OVERRIDE; + QModelIndex parent(const QModelIndex &child) const Q_DECL_OVERRIDE; + QHash<int,QByteArray> roleNames() const Q_DECL_OVERRIDE; + + bool propTouchPlayFlag() const; + + Q_INVOKABLE void refresh(); + Q_INVOKABLE bool touchPlay(bool play); + Q_INVOKABLE void setTouchProperty(int index); + Q_INVOKABLE void setLogFileIndex(int index); + + void propTouchPlayFlagChangedDelegate(); + static void finalizeChild(int sig); + static void emitSignalAgent(); + +signals: + void propTouchPlayFlagChanged(); + +private: + QHash<int,QByteArray> roles; + QList<QHash<int,QVariant>> datas; + + static const std::string touchPlayUtilsExec; + static void (*oldHandler)(int); + + pid_t touchPlayUtils; + std::map<QString, QString> touchplayUtilsArg; + + static TouchLogPlayImpl *pointer; + static bool touchPlayFlag; +}; + +#endif // TOUCHLOGPLAY_H diff --git a/app/main.cpp b/app/main.cpp new file mode 100644 index 0000000..7473847 --- /dev/null +++ b/app/main.cpp @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2019 TOYOTA MOTOR CORPORATION + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <QtCore/QDebug> +#include <QtCore/QCommandLineParser> +#include <QtCore/QUrlQuery> +#include <QtCore/QFile> +#include <QtGui/QGuiApplication> +#include <QtQml/QQmlApplicationEngine> +#include <QtQml/QQmlContext> +#include <QtQuickControls2/QQuickStyle> +#include <QQuickWindow> +#include <libhomescreen.hpp> +#include <network.h> +#include <qlibwindowmanager.h> + +#include "logfile/logsave.h" +#include "logfile/logplay.h" +#include "logfile/touchlogplay.h" + +int main(int argc, char *argv[]) +{ + QString graphic_role = QString("log-utils"); // defined in layers.json in window manager + + QGuiApplication app(argc, argv); + app.setApplicationName(graphic_role); + app.setApplicationVersion(QStringLiteral("0.1.0")); + app.setOrganizationDomain(QStringLiteral("automotivelinux.org")); + app.setOrganizationName(QStringLiteral("AutomotiveGradeLinux")); + + QQuickStyle::setStyle("AGL"); + + QCommandLineParser parser; + parser.addPositionalArgument("port", app.translate("main", "port for binding")); + parser.addPositionalArgument("secret", app.translate("main", "secret for binding")); + parser.addHelpOption(); + parser.addVersionOption(); + parser.process(app); + QStringList positionalArguments = parser.positionalArguments(); + + qmlRegisterType<LogSaveImpl>("LogSaveImpl", 1, 0, "LogSaveImpl"); + qmlRegisterType<LogPlayImpl>("LogPlayImpl", 1, 0, "LogPlayImpl"); + qmlRegisterType<TouchLogPlayImpl>("TouchLogPlayImpl", 1, 0, "TouchLogPlayImpl"); + + QQmlApplicationEngine engine; + if (positionalArguments.length() != 2) { + exit(EXIT_FAILURE); + } + int port = positionalArguments.takeFirst().toInt(); + QString secret = positionalArguments.takeFirst(); + QUrlQuery query; + query.addQueryItem(QStringLiteral("token"), secret); + + QUrl bindingAddressWS; + bindingAddressWS.setScheme(QStringLiteral("ws")); + bindingAddressWS.setHost(QStringLiteral("localhost")); + bindingAddressWS.setPort(port); + bindingAddressWS.setPath(QStringLiteral("/api")); + bindingAddressWS.setQuery(query); + QQmlContext *context = engine.rootContext(); + context->setContextProperty(QStringLiteral("bindingAddressWS"), bindingAddressWS); + context->setContextProperty("network", new Network(bindingAddressWS, context)); + + std::string token = secret.toStdString(); + LibHomeScreen* hs = new LibHomeScreen(); + QLibWindowmanager* qwm = new QLibWindowmanager(); + + // WindowManager + if(qwm->init(port,secret) != 0) { + exit(EXIT_FAILURE); + } + AGLScreenInfo screenInfo(qwm->get_scale_factor()); + // Request a surface as described in layers.json windowmanager’s file + if(qwm->requestSurface(graphic_role) != 0) { + exit(EXIT_FAILURE); + } + // Create an event callback against an event type. Here a lambda is called when SyncDraw event occurs + qwm->set_event_handler(QLibWindowmanager::Event_SyncDraw, [qwm, &graphic_role](json_object *object) { + fprintf(stderr, "Surface got syncDraw!\n"); + qwm->endDraw(graphic_role); + }); + + // HomeScreen + hs->init(port, token.c_str()); + // Set the event handler for Event_ShowWindow which will activate the surface for windowmanager + hs->set_event_handler(LibHomeScreen::Event_ShowWindow, [qwm, &graphic_role](json_object *object){ + qDebug("Surface %s got showWindow\n", graphic_role.toStdString().c_str()); + qwm->activateWindow(graphic_role); + TouchLogPlayImpl::emitSignalAgent(); + }); + + QFile version("/proc/version"); + if (version.open(QFile::ReadOnly)) { + QStringList data = QString::fromLocal8Bit(version.readAll()).split(QLatin1Char(' ')); + engine.rootContext()->setContextProperty("kernel", data.at(2)); + version.close(); + } else { + qWarning() << version.errorString(); + } + + QFile aglversion("/etc/os-release"); + if (aglversion.open(QFile::ReadOnly)) { + QStringList data = QString::fromLocal8Bit(aglversion.readAll()).split(QLatin1Char('\n')); + QStringList data2 = data.at(2).split(QLatin1Char('"')); + engine.rootContext()->setContextProperty("ucb", data2.at(1)); + aglversion.close(); + } else { + qWarning() << aglversion.errorString(); + } + + engine.rootContext()->setContextProperty(QStringLiteral("screenInfo"), &screenInfo); + engine.load(QUrl(QStringLiteral("qrc:/logfile/LogFile.qml"))); + QObject *root = engine.rootObjects().first(); + QQuickWindow *window = qobject_cast<QQuickWindow *>(root); + QObject::connect(window, SIGNAL(frameSwapped()), qwm, SLOT(slotActivateWindow())); + + return app.exec(); +} |