From 39e4539925687d46c7bbe04681dcc09757dc9ae2 Mon Sep 17 00:00:00 2001 From: wanglu Date: Thu, 28 Mar 2019 09:31:38 +0800 Subject: Fix review problems: 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 --- app/app.pri | 12 + app/app.pro | 22 ++ app/images/HMI_Settings_DividingLine.svg | 58 ++++ app/images/HMI_Settings_X.svg | 72 +++++ app/images/images.qrc | 6 + app/logfile/AudioLog.qml | 79 +++++ app/logfile/Bar.qml | 70 +++++ app/logfile/CANLog.qml | 29 ++ app/logfile/LogFile.qml | 148 +++++++++ app/logfile/LogPlay.qml | 355 +++++++++++++++++++++ app/logfile/LogSave.qml | 238 ++++++++++++++ app/logfile/TouchLog.qml | 29 ++ app/logfile/TouchLogPlay.qml | 188 +++++++++++ app/logfile/VideoLog.qml | 213 +++++++++++++ app/logfile/images/HMI_Settings_Button_Cancel.svg | 93 ++++++ app/logfile/images/HMI_Settings_Button_Ok.svg | 93 ++++++ app/logfile/images/HMI_Settings_LogFile.svg | 87 ++++++ app/logfile/images/Keyboard_Arrow.svg | 65 ++++ app/logfile/images/Keyboard_Back.svg | 57 ++++ app/logfile/images/camerainfo_bg.svg | 93 ++++++ app/logfile/keyboard/AbstractKeyboard.qml | 27 ++ app/logfile/keyboard/Key.qml | 93 ++++++ app/logfile/keyboard/Keyboard.qml | 40 +++ app/logfile/keyboard/Numbers.qml | 130 ++++++++ app/logfile/logfile.qrc | 23 ++ app/logfile/logplay.cpp | 290 +++++++++++++++++ app/logfile/logplay.h | 67 ++++ app/logfile/logsave.cpp | 360 ++++++++++++++++++++++ app/logfile/logsave.h | 89 ++++++ app/logfile/touchlogplay.cpp | 271 ++++++++++++++++ app/logfile/touchlogplay.h | 72 +++++ app/main.cpp | 131 ++++++++ 32 files changed, 3600 insertions(+) create mode 100644 app/app.pri create mode 100644 app/app.pro create mode 100644 app/images/HMI_Settings_DividingLine.svg create mode 100644 app/images/HMI_Settings_X.svg create mode 100644 app/images/images.qrc create mode 100644 app/logfile/AudioLog.qml create mode 100644 app/logfile/Bar.qml create mode 100644 app/logfile/CANLog.qml create mode 100644 app/logfile/LogFile.qml create mode 100644 app/logfile/LogPlay.qml create mode 100644 app/logfile/LogSave.qml create mode 100644 app/logfile/TouchLog.qml create mode 100644 app/logfile/TouchLogPlay.qml create mode 100644 app/logfile/VideoLog.qml create mode 100644 app/logfile/images/HMI_Settings_Button_Cancel.svg create mode 100644 app/logfile/images/HMI_Settings_Button_Ok.svg create mode 100644 app/logfile/images/HMI_Settings_LogFile.svg create mode 100644 app/logfile/images/Keyboard_Arrow.svg create mode 100644 app/logfile/images/Keyboard_Back.svg create mode 100644 app/logfile/images/camerainfo_bg.svg create mode 100644 app/logfile/keyboard/AbstractKeyboard.qml create mode 100644 app/logfile/keyboard/Key.qml create mode 100644 app/logfile/keyboard/Keyboard.qml create mode 100644 app/logfile/keyboard/Numbers.qml create mode 100644 app/logfile/logfile.qrc create mode 100644 app/logfile/logplay.cpp create mode 100644 app/logfile/logplay.h create mode 100644 app/logfile/logsave.cpp create mode 100644 app/logfile/logsave.h create mode 100644 app/logfile/touchlogplay.cpp create mode 100644 app/logfile/touchlogplay.h create mode 100644 app/main.cpp (limited to 'app') 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 @@ + + + +image/svg+xml \ 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 @@ + + + +image/svg+xml \ 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 @@ + + + HMI_Settings_DividingLine.svg + HMI_Settings_X.svg + + 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 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 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 @@ + + + +image/svg+xml \ 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 @@ + + + +image/svg+xml \ 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 @@ + + + +image/svg+xml \ 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 @@ + + + +image/svg+xml \ 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 @@ + + + +image/svg+xml \ 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 @@ + + + +image/svg+xml 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 @@ + + + Bar.qml + LogFile.qml + LogSave.qml + CANLog.qml + LogPlay.qml + VideoLog.qml + AudioLog.qml + keyboard/Numbers.qml + keyboard/Keyboard.qml + keyboard/Key.qml + keyboard/AbstractKeyboard.qml + images/HMI_Settings_LogFile.svg + images/Keyboard_Arrow.svg + images/Keyboard_Back.svg + images/HMI_Settings_Button_Cancel.svg + images/HMI_Settings_Button_Ok.svg + TouchLog.qml + TouchLogPlay.qml + images/camerainfo_bg.svg + + 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 +#include +#include +#include +#include +#include + +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() data; + data[nameRole] = ""; + data[folderRole] = true; + data[childrenRole] = 0; + return data[role]; + } +} + +QModelIndex LogPlayImpl::parent(const QModelIndex &child) const +{ + (void)child; + return QModelIndex(); +} + +QHash 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 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 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 + +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 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 roles; + QList> datas; + std::map startTime; + std::map endTime; + QStringList portsList; + + static const std::string PlayUtilsExec; + + pid_t playUtils; + std::map 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 +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +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::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 +#include + +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 videoDevice; + std::map logFolders; + + pid_t dumpUtils; + pid_t audioMixer; + pid_t audioUtils; + pid_t videoUtils; + pid_t touchRecUtils; + + QVariantList cameras; + + std::map dumpUtilsArg; + std::map audioUtilsArg; + std::map videoUtilsArg; + std::map 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 +#include +#include +#include +#include +#include +#include + +#include +#include + +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() data; + data[nameRole] = ""; + data[folderRole] = true; + data[childrenRole] = 0; + return data[role]; + } +} + +QModelIndex TouchLogPlayImpl::parent(const QModelIndex &child) const +{ + (void)child; + return QModelIndex(); +} + +QHash 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 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 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 + +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 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 roles; + QList> datas; + + static const std::string touchPlayUtilsExec; + static void (*oldHandler)(int); + + pid_t touchPlayUtils; + std::map 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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", 1, 0, "LogSaveImpl"); + qmlRegisterType("LogPlayImpl", 1, 0, "LogPlayImpl"); + qmlRegisterType("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(root); + QObject::connect(window, SIGNAL(frameSwapped()), qwm, SLOT(slotActivateWindow())); + + return app.exec(); +} -- cgit 1.2.3-korg