diff options
49 files changed, 5174 insertions, 0 deletions
diff --git a/.gitreview b/.gitreview new file mode 100644 index 0000000..2285229 --- /dev/null +++ b/.gitreview @@ -0,0 +1,5 @@ +[gerrit] +host=gerrit.automotivelinux.org +port=29418 +project=apps/settings-log-utils +defaultbranch=master @@ -0,0 +1,204 @@ + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don`t include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. + 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(); +} diff --git a/autobuild/agl/autobuild b/autobuild/agl/autobuild new file mode 100755 index 0000000..e87a1c3 --- /dev/null +++ b/autobuild/agl/autobuild @@ -0,0 +1,58 @@ +#!/usr/bin/make -f +# Copyright (C) 2015 - 2018 "IoT.bzh" +# Author "Romain Forlot" <romain.forlot@iot.bzh> +# +# 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. + +THISFILE := $(lastword $(MAKEFILE_LIST)) +BUILD_DIR := $(abspath $(dir $(THISFILE))/../../build) +DEST := ${BUILD_DIR} + +.PHONY: all clean distclean configure build package help + +all: help + +help: + @echo "List of targets available:" + @echo "" + @echo "- all" + @echo "- clean" + @echo "- distclean" + @echo "- configure" + @echo "- build: compilation, link and prepare files for package into a widget" + @echo "- package: output a widget file '*.wgt'" + @echo "- install: install in your INSTALL_ROOT directory" + @echo "" + @echo "Usage: ./autobuild/agl/autobuild package DEST=${HOME}/opt" + @echo "Don't use your build dir as DEST as wgt file is generated at this location" + +clean: + @([ -d ${BUILD_DIR} ] && make -C ${BUILD_DIR} ${CLEAN_ARGS} clean) || echo Nothing to clean + +distclean: + @([ -d ${BUILD_DIR} ] && make -C ${BUILD_DIR} distclean) || echo Nothing to distclean + +configure: + @[ -d ${BUILD_DIR} ] || mkdir -p ${BUILD_DIR} + @[ -f ${BUILD_DIR}/Makefile ] || (cd ${BUILD_DIR} && qmake ${CONFIGURE_ARGS} ..) + +build: configure + @make -C ${BUILD_DIR} ${BUILD_ARGS} all + +package: build + @if [ "${DEST}" != "${BUILD_DIR}/$@" ]; then \ + mkdir -p ${DEST} && cp ${BUILD_DIR}/$@/*.wgt ${DEST}; \ + fi + +install: build + @make -C ${BUILD_DIR} ${INSTALL_ARGS} install diff --git a/autobuild/linux/autobuild b/autobuild/linux/autobuild new file mode 100644 index 0000000..569d692 --- /dev/null +++ b/autobuild/linux/autobuild @@ -0,0 +1,62 @@ +#!/usr/bin/make -f +# Copyright (C) 2015 - 2018 "IoT.bzh" +# Author "Romain Forlot" <romain.forlot@iot.bzh> +# +# 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. + +THISFILE := $(lastword $(MAKEFILE_LIST)) +BUILD_DIR := $(abspath $(dir $(THISFILE))/../../build) +DEST := ${BUILD_DIR} + +.PHONY: all clean distclean configure build package help update + +all: help + +help: + @echo "List of targets available:" + @echo "" + @echo "- all + @echo "- clean" + @echo "- distclean" + @echo "- configure" + @echo "- build: compilation, link and prepare files for package into a widget" + @echo "- package: output a widget file '*.wgt'" + @echo "- install: install in your defined DEST directory" + @echo "" + @echo "Usage: ./autobuild/agl/autobuild package DEST=${HOME}/opt" + @echo "Don't use your build dir as DEST as wgt file is generated at this location" + + clean: + @([ -d ${BUILD_DIR} ] && make -C ${BUILD_DIR} ${CLEAN_ARGS} clean) || echo Nothing to clean + +distclean: + @[ -d ${DEST} ] && find ${DEST} -name "*.wgt" -delete + @([ -d ${BUILD_DIR} ] && make -C ${BUILD_DIR} distclean) || echo Nothing to distclean + +configure: + @[ -d ${BUILD_DIR} ] || mkdir -p ${BUILD_DIR} + @[ -f ${BUILD_DIR}/Makefile ] || (cd ${BUILD_DIR} && qmake ${CONFIGURE_ARGS} ..) + +build: configure + @make -C ${BUILD_DIR} ${BUILD_ARGS} all + +package: build + @if [ "${DEST}" != "${BUILD_DIR}/$@" ]; then \ + mkdir -p ${DEST} && cp ${BUILD_DIR}/$@/*.wgt ${DEST}; \ + fi + +install: build + @if [ "${DEST}" != "${BUILD_DIR}" ]; then \ + mkdir -p ${DEST} && cp -rf ${BUILD_DIR}/package/root/* ${DEST}; \ + fi + diff --git a/log-utils.pro b/log-utils.pro new file mode 100644 index 0000000..74fe35b --- /dev/null +++ b/log-utils.pro @@ -0,0 +1,3 @@ +TEMPLATE = subdirs +SUBDIRS = app videoutils tsutils package +package.depends += app diff --git a/package/config.xml b/package/config.xml new file mode 100644 index 0000000..1d61507 --- /dev/null +++ b/package/config.xml @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="UTF-8"?> +<widget xmlns="http://www.w3.org/ns/widgets" id="log-utils" version="0.1"> + <name>Log-Utils</name> + <icon src="icon.svg"/> + <content src="bin/log-utils" type="application/vnd.agl.native"/> + <description>This is the log application</description> + <author>Toyota</author> + <license>APL 2.0</license> + <feature name="urn:AGL:widget:required-api"> + <param name="windowmanager" value="ws" /> + <param name="homescreen" value="ws" /> + </feature> + <feature name="urn:AGL:widget:required-permission"> + <param name="urn:AGL:permission::public:no-htdocs" value="required" /> + </feature> +</widget> + + diff --git a/package/icon.svg b/package/icon.svg new file mode 100644 index 0000000..6628784 --- /dev/null +++ b/package/icon.svg @@ -0,0 +1,283 @@ +<?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" + x="0px" + y="0px" + viewBox="0 0 320 320" + style="enable-background:new 0 0 320 320;" + xml:space="preserve" + id="svg2" + inkscape:version="0.91 r13725" + sodipodi:docname="icon.svg"><metadata + id="metadata1292"><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="defs1290" /><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="namedview1288" + showgrid="false" + inkscape:zoom="0.7375" + inkscape:cx="-697.62712" + inkscape:cy="160" + inkscape:window-x="0" + inkscape:window-y="0" + inkscape:window-maximized="1" + inkscape:current-layer="svg2" /><style + type="text/css" + id="style4"> + .st0{display:none;} + .st1{display:inline;} + .st2{opacity:0.4;fill:url(#SVGID_1_);} + .st3{fill:url(#SVGID_2_);} + .st4{fill:#FFFFFF;} + .st5{font-family:'Roboto-Regular';} + .st6{font-size:25px;} + .st7{letter-spacing:6;} + .st8{fill:url(#SVGID_3_);} + .st9{fill:url(#SVGID_4_);} + .st10{fill:url(#SVGID_5_);} + .st11{fill:url(#SVGID_6_);} + .st12{fill:url(#SVGID_7_);} + .st13{fill:url(#SVGID_8_);} + .st14{fill:url(#SVGID_9_);} + .st15{fill:url(#SVGID_10_);} + .st16{fill:url(#SVGID_11_);} + .st17{fill:url(#SVGID_12_);} + .st18{fill:url(#SVGID_13_);} + .st19{fill:url(#SVGID_14_);} + .st20{fill:url(#SVGID_15_);} + .st21{fill:url(#SVGID_16_);} + .st22{fill:url(#SVGID_17_);} + .st23{fill:url(#SVGID_18_);} + .st24{opacity:0.29;} + .st25{fill:url(#SVGID_19_);} + .st26{fill:url(#SVGID_20_);} + .st27{fill:url(#SVGID_21_);} + .st28{fill:url(#SVGID_22_);} + .st29{fill:url(#SVGID_23_);} + .st30{fill:url(#SVGID_24_);} + .st31{fill:url(#SVGID_25_);} + .st32{fill:url(#SVGID_26_);} + .st33{fill:url(#SVGID_27_);} + .st34{fill:url(#SVGID_28_);} + .st35{fill:url(#SVGID_29_);} + .st36{fill:url(#SVGID_30_);} + .st37{fill:url(#SVGID_31_);} + .st38{fill:url(#SVGID_32_);} + .st39{fill:url(#SVGID_33_);} + .st40{fill:url(#SVGID_34_);} + .st41{fill:url(#SVGID_35_);} + .st42{fill:url(#SVGID_36_);} + .st43{opacity:0.4;fill:url(#SVGID_37_);} + .st44{fill:url(#SVGID_38_);} + .st45{fill:url(#SVGID_39_);} + .st46{fill:url(#SVGID_40_);} + .st47{fill:url(#SVGID_41_);} + .st48{fill:url(#SVGID_42_);} + .st49{fill:url(#SVGID_43_);} + .st50{fill:url(#SVGID_44_);} + .st51{display:inline;opacity:0.29;} + .st52{display:inline;fill:url(#SVGID_45_);} + .st53{display:inline;fill:url(#SVGID_46_);} + .st54{display:inline;fill:#FFFFFF;} + .st55{display:inline;fill:url(#SVGID_47_);} + .st56{display:inline;fill:url(#SVGID_48_);} + .st57{display:inline;fill:url(#SVGID_49_);} + .st58{display:inline;fill:url(#SVGID_50_);} + .st59{display:inline;fill:url(#SVGID_51_);} + .st60{display:inline;fill:url(#SVGID_52_);} + .st61{opacity:0.4;fill:url(#SVGID_53_);} + .st62{fill:url(#SVGID_54_);} + .st63{fill:url(#SVGID_55_);} + .st64{fill:url(#SVGID_56_);} + .st65{fill:url(#SVGID_57_);} + .st66{fill:url(#SVGID_58_);} + .st67{opacity:0.4;fill:url(#SVGID_59_);} + .st68{fill:url(#SVGID_60_);} + .st69{fill:url(#SVGID_61_);} + .st70{fill:url(#SVGID_62_);} + .st71{fill:url(#SVGID_63_);} + .st72{fill:url(#SVGID_64_);} + .st73{fill:url(#SVGID_65_);} + .st74{fill:url(#SVGID_66_);} + .st75{fill:url(#SVGID_67_);} + .st76{fill:url(#SVGID_68_);} + .st77{fill:url(#SVGID_69_);} + .st78{fill:url(#SVGID_70_);} + .st79{fill:url(#SVGID_71_);} + .st80{fill:url(#SVGID_72_);} + .st81{fill:url(#SVGID_73_);} + .st82{fill:url(#SVGID_74_);} + .st83{fill:url(#SVGID_75_);} + .st84{fill:url(#SVGID_76_);} + .st85{fill:url(#SVGID_77_);} + .st86{fill:url(#SVGID_78_);} + .st87{fill:url(#SVGID_79_);} + .st88{fill:url(#SVGID_80_);} + .st89{fill:url(#SVGID_81_);} + .st90{fill:url(#SVGID_82_);} + .st91{fill:url(#SVGID_83_);} + .st92{fill:url(#SVGID_84_);} + .st93{fill:url(#SVGID_85_);} + .st94{fill:url(#SVGID_86_);} + .st95{opacity:0.4;fill:url(#SVGID_87_);} + .st96{fill:url(#SVGID_88_);} + .st97{fill:url(#SVGID_89_);} + .st98{fill:url(#SVGID_90_);} + .st99{display:inline;fill:url(#SVGID_91_);} + .st100{display:inline;fill:url(#SVGID_92_);} + .st101{fill:url(#SVGID_93_);} + .st102{fill:url(#SVGID_94_);} + .st103{opacity:0.4;fill:url(#SVGID_95_);} + .st104{fill:url(#SVGID_96_);} + .st105{fill:url(#SVGID_97_);} + .st106{fill:url(#SVGID_98_);} + .st107{fill:url(#SVGID_99_);} + .st108{fill:url(#SVGID_100_);} + .st109{fill:url(#SVGID_101_);} + .st110{display:inline;fill:url(#SVGID_102_);} + .st111{display:inline;fill:url(#SVGID_103_);} + .st112{fill:url(#SVGID_104_);} + .st113{fill:url(#SVGID_105_);} + .st114{fill:url(#SVGID_106_);} + .st115{fill:url(#SVGID_107_);} + .st116{fill:url(#SVGID_108_);} + .st117{opacity:0.4;fill:url(#SVGID_109_);} + .st118{fill:url(#SVGID_110_);} + .st119{fill:url(#SVGID_111_);} + .st120{fill:url(#SVGID_112_);} + .st121{fill:url(#SVGID_113_);} + .st122{fill:url(#SVGID_114_);} + .st123{opacity:0.4;fill:url(#SVGID_115_);} + .st124{fill:url(#SVGID_116_);} + .st125{fill:url(#SVGID_117_);} + .st126{fill:url(#SVGID_118_);} + .st127{fill:url(#SVGID_119_);} + .st128{fill:url(#SVGID_120_);} + .st129{fill:url(#SVGID_121_);} + .st130{fill:url(#SVGID_122_);} +</style><switch + id="switch6"><g + i:extraneous="self" + id="g8"><g + id="Settings_Active"><circle + class="st24" + cx="159.7" + cy="133.4" + r="101.9" + id="circle1230" /><linearGradient + id="SVGID_119_" + gradientUnits="userSpaceOnUse" + x1="115.9317" + y1="254.1836" + x2="256.3852" + y2="-133.5267"><stop + offset="0" + style="stop-color:#8BC53F" + id="stop1233" /><stop + offset="2.015080e-02" + style="stop-color:#7CCB56;stop-opacity:0.9678" + id="stop1235" /><stop + offset="6.089833e-02" + style="stop-color:#62D67D;stop-opacity:0.9028" + id="stop1237" /><stop + offset="0.1057" + style="stop-color:#4BDFA0;stop-opacity:0.8312" + id="stop1239" /><stop + offset="0.1543" + style="stop-color:#38E7BE;stop-opacity:0.7537" + id="stop1241" /><stop + offset="0.2077" + style="stop-color:#28EED6;stop-opacity:0.6684" + id="stop1243" /><stop + offset="0.2681" + style="stop-color:#1CF3E8;stop-opacity:0.572" + id="stop1245" /><stop + offset="0.3394" + style="stop-color:#13F6F5;stop-opacity:0.4581" + id="stop1247" /><stop + offset="0.4323" + style="stop-color:#0EF8FD;stop-opacity:0.3098" + id="stop1249" /><stop + offset="0.6264" + style="stop-color:#0DF9FF;stop-opacity:0" + id="stop1251" /></linearGradient><circle + class="st127" + cx="159.7" + cy="133.4" + r="101.9" + id="circle1253" /><linearGradient + id="SVGID_120_" + gradientUnits="userSpaceOnUse" + x1="4.0481" + y1="287.9492" + x2="320.4859" + y2="-15.4029" + gradientTransform="matrix(1 5.464556e-03 -5.464556e-03 1 -2.0192 -3.0212)"><stop + offset="0" + style="stop-color:#59FF7F" + id="stop1256" /><stop + offset="1" + style="stop-color:#6BFBFF" + id="stop1258" /></linearGradient><path + class="st128" + d="M160,238.8c-0.2,0-0.4,0-0.6,0c-58-0.3-104.9-47.7-104.6-105.7C55.2,75.3,102.3,28.5,160,28.5 c0.2,0,0.4,0,0.6,0c58,0.3,104.9,47.7,104.6,105.7l0,0C264.8,192,217.7,238.8,160,238.8z M160,32.2 c-55.7,0-101.2,45.2-101.5,100.9c-0.3,55.9,45,101.7,100.9,102c0.2,0,0.4,0,0.6,0c55.7,0,101.2-45.2,101.5-100.9 c0.3-55.9-45-101.7-100.9-102C160.4,32.2,160.2,32.2,160,32.2z" + id="path1260" /><g + id="g1262"><text + transform="matrix(1 0 0 1 75.4379 284.7129)" + class="st4 st5 st6 st7" + id="text1264">SETTINGS</text> +<g + id="g1266"><g + id="g1268"><g + id="g1270"><linearGradient + id="SVGID_121_" + gradientUnits="userSpaceOnUse" + x1="79.1804" + y1="226.0817" + x2="282.752" + y2="-4.8609"><stop + offset="0" + style="stop-color:#59FF7F" + id="stop1273" /><stop + offset="1" + style="stop-color:#6BFBFF" + id="stop1275" /></linearGradient><path + class="st129" + d="M159.9,163.9c-16.3,0-29.5-13.2-29.5-29.4s13.2-29.4,29.5-29.4v3.9c-14.1,0-25.5,11.4-25.5,25.5 c0,14,11.5,25.5,25.5,25.5c14.1,0,25.6-11.4,25.6-25.5h3.9C189.4,150.7,176.2,163.9,159.9,163.9z" + id="path1277" /></g><g + id="g1279"><linearGradient + id="SVGID_122_" + gradientUnits="userSpaceOnUse" + x1="79.2457" + y1="226.1393" + x2="282.8174" + y2="-4.8033"><stop + offset="0" + style="stop-color:#59FF7F" + id="stop1282" /><stop + offset="1" + style="stop-color:#6BFBFF" + id="stop1284" /></linearGradient><path + class="st130" + d="M171.7,197.4h-23.4c-2.2,0-4-1.8-4-3.9V181c-2-0.7-4-1.5-6-2.5l-8.8,8.8c-1.5,1.5-4,1.5-5.6-0.1 l-16.6-16.6c-1.6-1.6-1.6-4.1-0.1-5.6l8.7-8.7c-1-2-1.8-4-2.5-6.1h-12.3c-2.2,0-3.9-1.8-3.9-4v-23.4c0-2.2,1.8-4,3.9-4h12.3 c0.9-2.6,1.9-5.1,3.2-7.4l3.5,1.8c-1.4,2.6-2.5,5.3-3.4,8.1l-0.4,1.4h-15.2l0,23.5l15.2,0.1l0.4,1.4c0.9,2.8,2,5.5,3.4,8 l0.7,1.3L110,167.8l16.6,16.6l10.9-10.8l1.3,0.7c2.6,1.4,5.2,2.5,8,3.3l1.4,0.4v15.4l23.5,0l0.1-15.4l1.4-0.4 c2.7-0.8,5.4-1.9,7.9-3.3l1.3-0.7l10.9,10.9l16.6-16.6l-10.8-11l0.7-1.3c1.4-2.6,2.5-5.2,3.3-7.9l0.4-1.4h15.4l0-23.5 l-15.3-0.1l-0.4-1.4c-0.8-2.8-1.9-5.5-3.3-8l-0.7-1.3l10.8-10.8l-16.6-16.6l-10.8,10.7l-1.3-0.7c-2.6-1.4-5.3-2.5-8.1-3.4 l-1.4-0.4V75.6l-23.5,0l-0.1,15.1l-1.4,0.4c-2.8,0.9-5.6,2-8.1,3.4l-1.3,0.7l-10.7-10.7L107.2,104c-1.5-1.5-1.5-4,0.1-5.6 l16.5-16.5c0.8-0.8,1.8-1.3,2.9-1.2c1,0,2,0.4,2.7,1.1l8.7,8.6c2-1,4-1.8,6.2-2.5V75.6c0-2.2,1.8-3.9,4-3.9h23.4 c2.2,0,4,1.8,4,3.9v12.3c2.1,0.7,4.1,1.6,6.1,2.5l8.7-8.7c0.7-0.7,1.7-1.1,2.7-1.1h0c1.1,0,2.1,0.4,2.9,1.2l16.6,16.6 c0.8,0.8,1.2,1.8,1.2,2.9c0,1-0.4,2-1.1,2.7l-8.8,8.8c1,2,1.8,4,2.5,6h12.4c2.2,0,3.9,1.8,3.9,4v23.4c0,2.2-1.8,4-3.9,4 h-12.5c-0.7,2-1.5,4-2.5,6l8.9,8.9c1.5,1.5,1.5,4-0.1,5.6l-16.6,16.6c-0.8,0.8-1.8,1.2-2.9,1.2h0c-1,0-2-0.4-2.7-1.1 l-8.9-8.9c-1.9,1-3.9,1.8-5.9,2.5v12.5C175.7,195.6,173.9,197.4,171.7,197.4z" + id="path1286" /></g></g></g></g></g></g></switch></svg>
\ No newline at end of file diff --git a/package/package.pro b/package/package.pro new file mode 100644 index 0000000..255e2d4 --- /dev/null +++ b/package/package.pro @@ -0,0 +1,21 @@ + +DISTFILES = icon.svg config.xml + +!equals($$_PRO_FILE_PWD_, $$OUT_PWD) { + copy_icon.target = $$OUT_PWD/root/icon.svg + copy_icon.depends = $$_PRO_FILE_PWD_/icon.svg + copy_icon.commands = $(COPY_FILE) \"$$replace(copy_icon.depends, /, $$QMAKE_DIR_SEP)\" \"$$replace(copy_icon.target, /, $$QMAKE_DIR_SEP)\" + QMAKE_EXTRA_TARGETS += copy_icon + PRE_TARGETDEPS += $$copy_icon.target + + copy_config.target = $$OUT_PWD/root/config.xml + copy_config.depends = $$_PRO_FILE_PWD_/config.xml + copy_config.commands = $(COPY_FILE) \"$$replace(copy_config.depends, /, $$QMAKE_DIR_SEP)\" \"$$replace(copy_config.target, /, $$QMAKE_DIR_SEP)\" + QMAKE_EXTRA_TARGETS += copy_config + PRE_TARGETDEPS += $$copy_config.target +} + +wgt.target = package +wgt.commands = wgtpkg-pack -f -o log-utils.wgt root + +QMAKE_EXTRA_TARGETS += wgt diff --git a/tsutils/tsplayer/tsplayer.c b/tsutils/tsplayer/tsplayer.c new file mode 100644 index 0000000..f0ab6f7 --- /dev/null +++ b/tsutils/tsplayer/tsplayer.c @@ -0,0 +1,332 @@ +/*
+ * 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 <fcntl.h>
+#include <linux/input.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <stdbool.h>
+
+typedef struct List
+{
+ int operIndex;
+ int seconds;
+ int microseconds;
+ uint16_t event_Type;
+ uint16_t event_Code;
+ float event_Value;
+ struct List *nextGp;
+}List;
+
+List *eventListHeader;
+List *eventListLast1;
+List *eventListLast2;
+List *eventListLast3;
+
+int touchScreenFd;
+
+extern char* getTouchScreenInfo();
+
+void deleteEventList() {
+ List *prevItem = eventListHeader;
+ List *nextItem = prevItem->nextGp;
+ while(prevItem && nextItem) {
+ free(prevItem);
+ prevItem = nextItem;
+ nextItem = nextItem->nextGp;
+ }
+
+ if (prevItem) {
+ free(prevItem);
+ }
+}
+
+void initEventList()
+{
+ eventListHeader = (struct List*)malloc(sizeof(struct List));
+
+ if (!eventListHeader)
+ {
+ printf("init event list failed. Exit\n");
+ exit(0);
+ }
+ else
+ {
+ memset(eventListHeader,0,sizeof(struct List));
+ eventListHeader->nextGp = NULL;
+ }
+
+ eventListLast1 = NULL;
+ eventListLast2 = NULL;
+ eventListLast3 = NULL;
+}
+
+void checkTouchUp(List *temp)
+{
+ if((temp->event_Type == 3) && (temp->event_Code == 57) && (temp->event_Value == -1))
+ {
+ if(eventListLast1 == NULL)
+ {
+ eventListLast1 = temp;
+ }
+ else if(eventListLast2 == NULL)
+ {
+ eventListLast2 = eventListLast1;
+ eventListLast1 = temp;
+ }
+ else
+ {
+ eventListLast3 = eventListLast2;
+ eventListLast2 = eventListLast1;
+ eventListLast1 = temp;
+ }
+ }
+}
+
+void deleteRedundantData()
+{
+ List *prevItem = eventListLast3->nextGp->nextGp->nextGp;
+ List *nextItem = prevItem->nextGp;
+ while(prevItem && nextItem) {
+ free(prevItem);
+ prevItem = nextItem;
+ nextItem = nextItem->nextGp;
+ }
+
+ if (prevItem) {
+ free(prevItem);
+ }
+}
+
+bool tailCreatList(char *fname)
+{
+ List *tmpData;
+ List *tail;
+
+ char buffer[512];
+
+ FILE *inFile;
+ inFile = fopen(fname,"r");
+
+ if (inFile == NULL)
+ {
+ printf("\nFailed to open the file : %s . Exit\n",fname);
+ exit(0);
+ }
+
+ initEventList();
+ tail = eventListHeader;
+
+ memset(buffer,0,sizeof(buffer));
+
+ while(fgets(buffer,sizeof(buffer),inFile))
+ {
+ tmpData = (struct List*)malloc(sizeof(struct List));
+ if (!tmpData)
+ {
+ printf("Faild to create event list. Exit\n");
+ fclose(inFile);
+ exit(0);
+ }
+
+ memset(tmpData,0,sizeof(struct List));
+
+ tmpData->nextGp = NULL;
+ sscanf(buffer,"%d %d %d %hu %hu %f",&(tmpData->operIndex),&(tmpData->seconds),&(tmpData->microseconds),&(tmpData->event_Type),&(tmpData->event_Code),&(tmpData->event_Value));
+
+ checkTouchUp(tmpData);
+ tail->nextGp = tmpData;
+ tail = tmpData;
+
+ memset(buffer,0,sizeof(buffer));
+ }
+
+ if(eventListLast3 != NULL)
+ {
+ tail = eventListLast3->nextGp->nextGp;
+ deleteRedundantData();
+ }
+ else
+ {
+ deleteEventList();
+ return false;
+ }
+
+ tail->nextGp = NULL;
+
+ fclose(inFile);
+
+ return true;
+}
+
+int reportKey(int fd, uint16_t type, uint16_t code, int32_t value)
+{
+ struct input_event event;
+ event.type = type;
+ event.code = code;
+ event.value = value;
+
+ gettimeofday(&event.time, 0);
+
+ if (write(fd, &event, sizeof(struct input_event)) < 0) {
+ printf("report key error!\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+void touchEventTest(List *listHeader, int screenWidth, int screenHeight,
+ int delayTime)
+{
+ List *p = listHeader->nextGp;
+ printf("--------Touch Event Test Start!!!--------\n");
+
+ while(p != NULL)
+ {
+ if ((p->event_Type == 3) && ((p->event_Code == 53) || (p->event_Code == 0)))
+ {
+ reportKey(touchScreenFd,p->event_Type,p->event_Code,p->event_Value * screenWidth);
+ }
+ else if ((p->event_Type == 3) && ((p->event_Code == 54) || (p->event_Code == 1)))
+ {
+ reportKey(touchScreenFd,p->event_Type,p->event_Code,p->event_Value * screenHeight);
+ }
+ else
+ {
+ reportKey(touchScreenFd,p->event_Type,p->event_Code,p->event_Value);
+ }
+
+ if (p->nextGp != NULL)
+ {
+ usleep((p->nextGp->seconds - p->seconds) * 1000000 + (p->nextGp->microseconds - p->microseconds));
+ }
+
+ p = p->nextGp;
+
+ }
+ printf("--------Touch Event Test End!!!--------\n");
+}
+
+int appNeedEventTestStart(int tsWidth, int tsHeight, char* eventNode,
+ char* eventFile, int delayTime)
+{
+ touchScreenFd = open(eventNode, O_RDWR);
+
+ if (touchScreenFd < 0)
+ {
+ printf("Open %s failed.\n", eventNode);
+ return -1;
+ }
+
+ if(tailCreatList(eventFile))
+ {
+ touchEventTest(eventListHeader, tsWidth, tsHeight, delayTime);
+ deleteEventList();
+ }
+
+ close(touchScreenFd);
+
+ return 1;
+}
+
+void printUsage(char* myName)
+{
+ printf("usage:\n \
+ %s -a <string> -d <number> -c <string> -e <number> -f <string>\n \
+ -a : application name(must)\n \
+ -d : the time interval(> 0) for capturing logs(unit:ms)(must).\n \
+ -c : child process name(s).If more than one, sperated by ','. \n\t\tEg. -c process1,prcocess2,process3.\n \
+ -f : file name for recorded event. If -e is 1, then -f must be specified.\n \
+ -e : 1 for apps that need events, 0 for apps that does not need events.Default is 0. \n", myName);
+}
+
+int main(int argc,char *argv[])
+{
+ int index = 0;
+ int screenWidth, screenHeight;
+ char eventFileName[100];
+ char eventNode[50];
+ const char* tsInfo;
+ int needEvents = 0;
+ int delayTime = 0;
+
+ if (argc < 5)
+ {
+ printUsage(argv[0]);
+ return -1;
+ }
+
+ memset(eventFileName, 0, sizeof(eventFileName));
+ memset(eventNode, 0, sizeof(eventNode));
+
+ for (index = 1; index < argc; index ++)
+ {
+ if (strcmp(argv[index], "-f") == 0)
+ {
+ memcpy(eventFileName, argv[++index], strlen(argv[index]));
+ }
+ else if (strcmp(argv[index], "-d") == 0)
+ {
+ delayTime = atoi(argv[++index]);
+ }
+ else if (strcmp(argv[index], "-e") == 0)
+ {
+ needEvents = atoi(argv[++index]);
+ }
+ else
+ {
+ printUsage(argv[0]);
+ return -1;
+ }
+ }
+
+ if (0 == delayTime) {
+ printf("Please specify an interval time(> 0)\n");
+ printUsage(argv[0]);
+ return -1;
+ }
+
+ printf("step %d. \n", __LINE__);
+ if ((1 == needEvents) && (0 == strlen(eventFileName))) {
+ printf("You should specify a file for recorded event.\n");
+ printUsage(argv[0]);
+ return -1;
+ }
+ printf("step %d. \n", __LINE__);
+
+ if (1 == needEvents)
+ {
+ printf("step %d. \n", __LINE__);
+ tsInfo = getTouchScreenInfo();
+ printf("step %d. \n", __LINE__);
+ if (NULL == tsInfo) {
+ printf("Failed to get touch screen info.\n");
+ return -1;
+ }
+ printf("step %d. tsInfo = %s. \n", __LINE__, tsInfo);
+
+ sscanf(tsInfo, "%s %d %d", eventNode, &screenWidth, &screenHeight);
+ appNeedEventTestStart(screenWidth, screenHeight, eventNode, eventFileName,
+ delayTime);
+ printf("step %d. \n", __LINE__);
+
+ }
+ return 0;
+}
diff --git a/tsutils/tsplayer/tsplayer.pro b/tsutils/tsplayer/tsplayer.pro new file mode 100644 index 0000000..8ff7cce --- /dev/null +++ b/tsutils/tsplayer/tsplayer.pro @@ -0,0 +1,7 @@ +TARGET = tsplayer + +DESTDIR = $${OUT_PWD}/../../package/root/bin + +SOURCES += \ + tsplayer.c \ + ../tsutils.c diff --git a/tsutils/tsrecorder/tsrecorder.c b/tsutils/tsrecorder/tsrecorder.c new file mode 100644 index 0000000..9c2e466 --- /dev/null +++ b/tsutils/tsrecorder/tsrecorder.c @@ -0,0 +1,150 @@ +/* + * 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 <fcntl.h> +#include <linux/input.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <stdint.h> +#include <unistd.h> + +static int eventFd = -1; +static FILE* pfile; +struct input_event ev0[64]; +static int screenWidth = 0; +static int screenHeight = 0; + +extern char* getTouchScreenInfo(); + +static int handle_event() +{ + int i, rd; + char str[256]; + float x = 0, y = 0; + + rd = read(eventFd, ev0, sizeof(struct input_event)* 64); + + if(rd < sizeof(struct input_event)) + return 0; + + for(i=0;i<rd/sizeof(struct input_event); i++) + { + memset(str, 0, sizeof(str)); + + if(ev0[i].type == 3) + { + if(ev0[i].code == 53 || ev0[i].code == 0) + {//screen widthに対して変換 + x = (float)ev0[i].value / screenWidth; + sprintf(str, "%2d\t%ld\t%ld\t%3hu\t%3hu\t%f\r\n", + i, ev0[i].time.tv_sec, ev0[i].time.tv_usec, ev0[i].type, ev0[i].code, x); + } + else if(ev0[i].code == 54 || ev0[i].code == 1) + {//screen heightに対して変換 + y = (float)ev0[i].value / screenHeight; + sprintf(str, "%2d\t%ld\t%ld\t%3hu\t%3hu\t%f\r\n", + i, ev0[i].time.tv_sec, ev0[i].time.tv_usec, ev0[i].type, ev0[i].code, y); + } + else + { + sprintf(str, "%2d\t%ld\t%ld\t%3hu\t%3hu\t%d\r\n", i, ev0[i].time.tv_sec, ev0[i].time.tv_usec, ev0[i].type, ev0[i].code, ev0[i].value); + } + } + else + { + sprintf(str, "%2d\t%ld\t%ld\t%3hu\t%3hu\t%d\r\n", i, ev0[i].time.tv_sec, ev0[i].time.tv_usec, ev0[i].type, ev0[i].code, ev0[i].value); + } + + fputs(str, pfile); + } + fflush(pfile); + return 1; +} + +void printUsage(char* myName) +{ + printf("usage:\n \ + %s -f <string>\n \ + -f : file name for recording event\n", myName); +} + +int main(int argc,char *argv[]) +{ + int done = 1; + int index = 0; + char* fName = NULL; + char eventNode[50]; + const char* tsInfo; + + if (argc < 3) + { + printUsage(argv[0]); + return -1; + } + + for (index = 1; index < argc; index++) + { + if (strcmp(argv[index], "-f") == 0) + { + fName = argv[++index]; + } + else + { + printUsage(argv[0]); + return -1; + } + } + + tsInfo = getTouchScreenInfo(); + if (NULL == tsInfo) { + printf("Failed to get touch screen info.\n"); + return -1; + } + + memset(eventNode, 0, sizeof(eventNode)); + sscanf(tsInfo, "%s %d %d", eventNode, &screenWidth, &screenHeight); + + eventFd = open(eventNode, O_RDWR); + if(eventFd <0) { + printf("open input device error\n"); + return -1; + } + + pfile = fopen(fName, "wb+"); + if(pfile == NULL) + { + printf("Failed to create file!\n"); + return -1; + } + + while (done) + { + printf("begin %s...\n", eventNode); + done = handle_event(); + printf("end %s...\n", eventNode); + } + + fclose(pfile); + + if(eventFd > 0) + { + close(eventFd); + eventFd = -1; + } + + return 0; +} diff --git a/tsutils/tsrecorder/tsrecorder.pro b/tsutils/tsrecorder/tsrecorder.pro new file mode 100644 index 0000000..3c3988b --- /dev/null +++ b/tsutils/tsrecorder/tsrecorder.pro @@ -0,0 +1,7 @@ +TARGET = tsrecorder + +DESTDIR = $${OUT_PWD}/../../package/root/bin + +SOURCES += \ + tsrecorder.c \ + ../tsutils.c diff --git a/tsutils/tsutils.c b/tsutils/tsutils.c new file mode 100644 index 0000000..79385d1 --- /dev/null +++ b/tsutils/tsutils.c @@ -0,0 +1,95 @@ +/* + * 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 <dirent.h> +#include <linux/input.h> +#include <unistd.h> +#include <fcntl.h> +#include <stdio.h> +#include <string.h> + +#define LONG_BITS (sizeof(long) << 3) +#define NUM_LONGS(bits) (((bits) + LONG_BITS - 1) / LONG_BITS) +#define DEV_INPUT "/dev/input" + +char tsInfo[200]; + +static inline int testBit(long bit, const long *array) { + return (array[bit / LONG_BITS] >> bit % LONG_BITS) & 1; +} + +char* getTouchScreenInfo() { + DIR* dir; + struct dirent* itemPtr; + int fd; + int isSingleTouch = 0, hasTouchScreen = 0; + long absbits[NUM_LONGS(ABS_CNT)]; + char tsDevNode[100]; + struct input_absinfo absInfo; + + int maxX, maxY; + + memset(tsDevNode, 0, sizeof(tsDevNode)); + memset(tsInfo, 0, sizeof(tsInfo)); + + if ((dir = opendir(DEV_INPUT)) == NULL) { + printf("open %s failed.\n", DEV_INPUT); + return NULL; + } + + while ((itemPtr = readdir(dir)) != NULL) { + //printf("name : %s---type : %d\n", itemPtr->d_name, itemPtr->d_type); + if ((strstr(itemPtr->d_name, "event") != NULL) && (2 == itemPtr->d_type)) { + sprintf(tsDevNode, "%s/%s", DEV_INPUT, itemPtr->d_name); + fd = open(tsDevNode, O_RDONLY); + if (fd < 0) { + printf("open %s failed.\n", tsDevNode); + return NULL; + } + + if (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(absbits)), absbits) >= 0) { + isSingleTouch = !testBit(ABS_MT_POSITION_X, absbits); + } else { + close(fd); + continue; + } + + if (ioctl(fd, EVIOCGABS((isSingleTouch ? ABS_X : ABS_MT_POSITION_X)), &absInfo) >= 0) { + maxX = absInfo.maximum; + } else { + close(fd); + continue; + } + + if (ioctl(fd, EVIOCGABS((isSingleTouch ? ABS_Y : ABS_MT_POSITION_Y)), &absInfo) >= 0) { + maxY = absInfo.maximum; + } else { + close(fd); + continue; + } + + hasTouchScreen = 1; + break; + } + } + + if (!hasTouchScreen) return NULL; + + sprintf(tsInfo, "%s %d %d", tsDevNode, maxX, maxY); + + close(fd); + closedir(dir); + return tsInfo; +} diff --git a/tsutils/tsutils.pro b/tsutils/tsutils.pro new file mode 100644 index 0000000..ed02c62 --- /dev/null +++ b/tsutils/tsutils.pro @@ -0,0 +1,2 @@ +TEMPLATE = subdirs +SUBDIRS = tsplayer tsrecorder
\ No newline at end of file diff --git a/videoutils/videoutils.cpp b/videoutils/videoutils.cpp new file mode 100644 index 0000000..343469c --- /dev/null +++ b/videoutils/videoutils.cpp @@ -0,0 +1,255 @@ +/* + * 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 "videoutils.h" +#include <opencv2/core.hpp> +#include <opencv2/imgproc/imgproc.hpp> + +#include <iostream> +#include <unistd.h> +#include <stdlib.h> +#include <boost/algorithm/string.hpp> +#include <glib.h> +#include <sys/time.h> + +using namespace VIDEO_UTILS; + +GMainLoop * mainloop = NULL; +static int grabImage(void *data); +static void printhelp(const char *argv0); +static void mainLoopQuit(int sig); + +VideoUtils::VideoUtils(int device, int framerate, int wid, int hght, std::string file, std::string co) + : fps(framerate), width(wid), height(hght), deviceno(device), codec(co), filename(file) +{ + cvCapture = std::unique_ptr < cv::VideoCapture > (new cv::VideoCapture()); + cvWriter = std::unique_ptr < cv::VideoWriter > (new cv::VideoWriter()); + + isReady = false; + framecount = 0; + + if (cvCapture && !cvCapture->isOpened()) + { + if (cvCapture->open(deviceno)) + { + cvCapture->set(cv::CAP_PROP_FRAME_WIDTH, width); + cvCapture->set(cv::CAP_PROP_FRAME_HEIGHT, height); + + if (cvWriter && !cvWriter->isOpened()) + { + isReady = openVideoWriter(); + } + } + } +} + +void VideoUtils::releaseSource() +{ + if (cvCapture && cvCapture->isOpened()) + { + cvCapture->release(); + } + + if (cvWriter && cvWriter->isOpened()) + { + cvWriter->release(); + } +} + +bool VideoUtils::openVideoWriter() +{ + if (!cvCapture || !cvCapture->isOpened() || !cvWriter) + { + return false; + } + + /* Get the size of a frame from the device. */ + cv::Size framesize = cv::Size((int) cvCapture->get(cv::CAP_PROP_FRAME_WIDTH), (int) cvCapture->get(cv::CAP_PROP_FRAME_HEIGHT)); + + /* Get the CODEC. */ + if (codec.empty() || codec.size() != 4) + { + codec = "MJPG"; + } + boost::algorithm::to_upper(codec); + + return cvWriter->open(filename, cv::VideoWriter::fourcc(codec.at(0), codec.at(1), codec.at(2), codec.at(3)), fps, framesize); +} + +void VideoUtils::writeVideoFrame(const cv::UMat& f) +{ + if (!cvWriter || !cvWriter->isOpened()) + { + return; + } + + if (framecount < fps) + { + framecount++; + return; + } + + cv::Mat frame; + f.copyTo(frame); + + /* Put the current time into the frame. */ + int fontFace = cv::FONT_HERSHEY_SIMPLEX; + double fontScale = 0.6; + int baseline = 0; + int thickness = 2; + std::stringstream datestr; + + datestr << getCurrentTime(); + + cv::Size dateTextSize = cv::getTextSize(datestr.str(), fontFace, fontScale, thickness, &baseline); + + for (; fontScale > 0.1 && dateTextSize.width > frame.cols; ) + { + fontScale -= 0.2; + dateTextSize = cv::getTextSize(datestr.str(), fontFace, fontScale, thickness, &baseline); + } + + cv::Point dateOrg(frame.cols - dateTextSize.width, dateTextSize.height); + + cv::putText(frame, datestr.str(), dateOrg, fontFace, fontScale, cv::Scalar(255, 255, 255), thickness); + + /* Write the frame into the log file. */ + *(cvWriter.get()) << frame; +} + +std::string VideoUtils::getCurrentTime() +{ + time_t seconds; + struct tm currenttime; + if (time(&seconds) == (time_t) - 1) + { + return ""; + } + localtime_r(&seconds, ¤ttime); + + char timestr[] = "1900/01/01/00/00/00"; + + sprintf(timestr, "%04d/%02d/%02d %02d:%02d:%02d", currenttime.tm_year + 1900, currenttime.tm_mon + 1, currenttime.tm_mday, currenttime.tm_hour, currenttime.tm_min, currenttime.tm_sec); + + return timestr; +} + +static int grabImage(void *data) +{ + VideoUtils* utils = reinterpret_cast<VideoUtils*>(data); + + if (!utils->cvCapture || !utils->cvCapture->isOpened()) + { + return false; + } + + cv::UMat frame; + *(utils->cvCapture.get()) >> frame; + + if (!frame.empty()) + { + /* Write the frame into the log file. */ + utils->writeVideoFrame(frame); + return true; + } + else + { + return false; + } +} + +static void printhelp(const char *argv0) +{ + printf("Usage: %s [args]\n" + " [-d|--device <0-5> ] set the device\n" + " [-w|--width] specify the width\n" + " [-h|--height] specify the height\n" + " [-r]--frame rate] specify the frame rate\n" + " [-c]--codec] specify the codec\n" + " [-f]--folder name] specify a folder to save the video file\n", argv0); +} + +static void mainLoopQuit(int sig) +{ + if ((sig == SIGUSR1) && (mainloop != NULL)) + { + g_main_loop_quit(mainloop); + } +} + +int main(int argc, char **argv) +{ + static int opt; + int device = 0; + int framerate = 30; + int width = 640; + int height = 480; + std::string filename = "/tmp/temp.avi"; + std::string codec = "MP42"; + + while ((opt = getopt(argc, argv, "d:w:h:r:f:c:")) != -1) + { + switch (opt) + { + case 'd': + device = atoi(optarg); + break; + case 'w': + width = atoi(optarg); + break; + case 'h': + height = atoi(optarg); + break; + case 'r': + framerate = atoi(optarg); + break; + case 'f': + filename.assign(optarg); + break; + case 'c': + codec.assign(optarg); + break; + default: + printhelp(basename(argv[0])); + return (0); + } + } + + VideoUtils utils(device, framerate, width, height, filename, codec); + + if (utils.isReady && framerate > 0) + { + void (*oldSigUsr1Handler)(int); + + oldSigUsr1Handler = signal(SIGUSR1, mainLoopQuit); + + mainloop = g_main_loop_new(NULL, FALSE); + + g_timeout_add(1000 / framerate, grabImage, &utils); + + g_main_loop_run(mainloop); + g_main_loop_unref(mainloop); + + if (oldSigUsr1Handler != SIG_ERR) + { + signal(SIGUSR1, oldSigUsr1Handler); + } + } + + utils.releaseSource(); + + return 0; +} diff --git a/videoutils/videoutils.h b/videoutils/videoutils.h new file mode 100644 index 0000000..78a0372 --- /dev/null +++ b/videoutils/videoutils.h @@ -0,0 +1,56 @@ +/* + * 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 VIDEOUTILS_H +#define VIDEOUTILS_H + +#include <memory> +#include <string> +#include <opencv2/videoio.hpp> + +namespace VIDEO_UTILS +{ +class VideoUtils +{ +public: + VideoUtils(int device, int framerate, int wid, int hght, std::string file, std::string co); + ~VideoUtils() + { + } + void writeVideoFrame(const cv::UMat& f); + void releaseSource(); + +private: + std::string getCurrentTime(); + bool openVideoWriter(); + +public: + bool isReady; + std::unique_ptr<cv::VideoCapture> cvCapture; + +private: + int fps; + int width; + int height; + int deviceno; + int framecount; + std::string codec; + std::string filename; + std::unique_ptr<cv::VideoWriter> cvWriter; +}; +} + +#endif // VIDEOUTILS_H diff --git a/videoutils/videoutils.pro b/videoutils/videoutils.pro new file mode 100644 index 0000000..9630cc5 --- /dev/null +++ b/videoutils/videoutils.pro @@ -0,0 +1,16 @@ +TARGET = videoutils + +LIBS += -lopencv_core -lopencv_videoio -lglib-2.0 -lopencv_imgproc + +DESTDIR = $${OUT_PWD}/../package/root/bin + +HEADERS += \ + videoutils.h + +SOURCES += \ + videoutils.cpp + +INCLUDEPATH += \ + $$[QT_SYSROOT]/usr/include/glib-2.0/ \ + $$[QT_SYSROOT]/usr/lib/glib-2.0/include + |