Compare commits
	
		
			354 Commits
		
	
	
		
			61c847102d
			...
			v1.3.15-js
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 990d257b09 | |||
| dfbad69ab1 | |||
| 5f0c86ba19 | |||
| 3588b25e65 | |||
| 1f8b88b2b6 | |||
| 0050ea35d0 | |||
| 7e4c138d1b | |||
| 685568d4f6 | |||
| 14b4c035da | |||
| 90de2f415e | |||
| 3cc71cb69b | |||
| fef7533d00 | |||
| e93058cc6b | |||
| e65387aa60 | |||
| 904fa0374b | |||
| 4bf1bbe81f | |||
| 3ccdcbae51 | |||
| 8c50e6cf59 | |||
| 7e69846169 | |||
| 34c55c576c | |||
| 7c2c4d4b80 | |||
| f9f698fd15 | |||
| b4457d8815 | |||
| 3621777827 | |||
| 003bd0bf77 | |||
| 721c5dd7a5 | |||
| a24eb9fd8c | |||
| 24351b8342 | |||
| 4b3a39b0e6 | |||
| a44b780d93 | |||
| 19dfae9b56 | |||
| bef0d4fe12 | |||
| 72a2fc781c | |||
| fc264689b1 | |||
| fc587456d5 | |||
| a2b933ab71 | |||
| 7d0fdf4d6d | |||
| c2ce44c79b | |||
| 16a9556863 | |||
| 48896f97ec | |||
| 4486317cb2 | |||
| 6b9b88ea19 | |||
| 99a99d95a1 | |||
| d4ddbbee21 | |||
| 34e5189945 | |||
| c44c805238 | |||
| 196f1a730e | |||
| 7dc04c4422 | |||
| 5efac2619b | |||
| 9b0f741b9b | |||
| 81c5f8ee7e | |||
| 29e6a25e72 | |||
| 5abc057bda | |||
| 8aeb7ecfea | |||
| 4bb8e241b6 | |||
| 4469a23f9c | |||
| d1f795e2db | |||
| 6865056f4b | |||
| 37bd5c90d3 | |||
| fcba120dfa | |||
| 1d4f50fb9f | |||
| a78040a037 | |||
| 9b175d7789 | |||
| 2d7f145a25 | |||
| 4589c4ca76 | |||
| a32258a59e | |||
| 22f25e5251 | |||
| 258d883a51 | |||
| 504e242d42 | |||
| 731cdcbe09 | |||
| b4e2d4c54a | |||
| 42961dea40 | |||
| fd2f601f67 | |||
| b45af505cd | |||
| 2dfe80b654 | |||
| 4b9dcc5e99 | |||
| 53639b55c9 | |||
| 3a83efbd3f | |||
| c9d6a8d245 | |||
| 91db59b9f3 | |||
| 1d81e6b650 | |||
| 6d57b45d1a | |||
| 4e7ce2cd70 | |||
| 47fac31223 | |||
| 0d353cfbcf | |||
| bdcb073bf8 | |||
| 226553a8ab | |||
| d4ee56559b | |||
| 355b28ba40 | |||
| edeff35d7e | |||
| 09d5de1b0b | |||
| 145fdab26e | |||
| 89d1ec5b21 | |||
| f38c975dc6 | |||
| fba007aa35 | |||
| 8b6adb3ea7 | |||
| 30603317c6 | |||
| 7083f3b4f8 | |||
| 7ff866525e | |||
| 2164037123 | |||
| 2e7d33c4c8 | |||
| 2a2751f6f3 | |||
| 2764ef4371 | |||
| 9783f343e1 | |||
| 8c6f0dfcc7 | |||
| d688ad3d5c | |||
| 7b3f652b0e | |||
| 4cc42b2a65 | |||
| d783fd7fb6 | |||
| e0a0ff54e1 | |||
| 863d052a21 | |||
| 61b3d29e31 | |||
| cac4f7249e | |||
| 3223c430be | |||
| c09682ea33 | |||
| fef1d43d5f | |||
| 705424727b | |||
| b96f0896e3 | |||
| a3967c76ac | |||
| 1197598a3d | |||
| ec13e97226 | |||
| a8dd9d7e24 | |||
| 82751eb1d4 | |||
| 17a4a69df2 | |||
| a03261d04a | |||
| 7832ef5d8c | |||
| 9c213d0a97 | |||
| 18378afdc5 | |||
| 6dd8a8c6b3 | |||
| adfb358e12 | |||
| ff418b11a1 | |||
| 38e79f0354 | |||
| 103b3f3f9c | |||
| ff6a6e0e45 | |||
| afbce3b4ea | |||
| 823e59a582 | |||
| 01cfbddfb1 | |||
| 838efd3945 | |||
| 9a65cb4456 | |||
| df0951d671 | |||
| 60cc752819 | |||
| 57b4716e2a | |||
| 15f28e9ffd | |||
| a07893ddab | |||
| d0eb1d12d8 | |||
| cd59a39569 | |||
| 67c8b2f472 | |||
| 5158878ce2 | |||
| b6971c1db5 | |||
| 9df46a1c49 | |||
| 6765b12f0c | |||
| 3e925756cf | |||
| b2798b349e | |||
| 64dce44fe1 | |||
| 7e96b65c1b | |||
| 276d65a9d8 | |||
| ba71728979 | |||
| e82742a609 | |||
| 6773a7243a | |||
| 22c8997f1e | |||
| 9531a08b4a | |||
| c065b57f0c | |||
| cef05b7511 | |||
| bb35e985ad | |||
| 981a2ea13a | |||
| b14b296011 | |||
| 1ef9853876 | |||
| 01d8312aa8 | |||
| 507586f9dc | |||
| 12ffa71455 | |||
| a84f495d43 | |||
| 7e4b5006eb | |||
| 0a28f0d82c | |||
| 5427844977 | |||
| a45e552d90 | |||
| be28570d23 | |||
| 1509e8619c | |||
| a8df026a80 | |||
| a803907449 | |||
| afd31f1b27 | |||
| f8fef38009 | |||
| cbe1fd387d | |||
| 1620b73d01 | |||
| 4ebdcf56a0 | |||
| 99b9419150 | |||
| 4307fb96a6 | |||
| c35390b6d6 | |||
| fff6bd2b49 | |||
| 631ade1954 | |||
| 337bdd1bb0 | |||
| 978cc16304 | |||
| bea8242d6f | |||
| 56daa84a14 | |||
| 17ddfd0ddd | |||
| 2ac8c4cfc6 | |||
| 0559ff64e2 | |||
| 385a7b7b00 | |||
| 503b7c64f9 | |||
| beec9c2f9d | |||
| 5263b7de0f | |||
| 9b4d0494c8 | |||
| 0f2ee0349f | |||
| e700a40875 | |||
| 1eba5338e4 | |||
| f20be9ddcf | |||
| 7631c05e22 | |||
| ad93e536f0 | |||
| 259da8200e | |||
| 8d528f0f55 | |||
| 66d0214720 | |||
| 86064979b4 | |||
| 86c996d7ac | |||
| effe41bac9 | |||
| 4968942cc2 | |||
| 769626581f | |||
| 0e97ce7dc2 | |||
| 34334676fc | |||
| 853787cd4b | |||
| a932ed5471 | |||
| c338884fc7 | |||
| ed6df98653 | |||
| 9eb458c4c5 | |||
| 202e83268b | |||
| 8f26bfee0f | |||
| 1af136e39d | |||
| a550d55004 | |||
| a37a22d3f9 | |||
| a8941f4ef4 | |||
| 746565dbe0 | |||
| 79906df12e | |||
| edf1d105e7 | |||
| 6c4b02cb56 | |||
| 04d5061d79 | |||
| 042e6dfa38 | |||
| e523d3cc2c | |||
| 927197d0d1 | |||
| 72cb738af5 | |||
| 0fb38013f7 | |||
| 5f1376cf1e | |||
| 5db7b4224e | |||
| 7c7adc94e6 | |||
| 89c2d3a8ae | |||
| c2b52aa91d | |||
| 329c770aa0 | |||
| cdb045b72b | |||
| 6d43cf4c9f | |||
| 4caa0c0d83 | |||
| 4d2d38e45c | |||
| 9a55ce18e4 | |||
| 223c7a8f8d | |||
| ce72d3d14d | |||
| 8b66c47e49 | |||
| 4ff3b0efdf | |||
| 1fd2269753 | |||
| a8994423f4 | |||
| 4594c913e0 | |||
| cf9033e898 | |||
| b09ccfd4f5 | |||
| 6b4c486549 | |||
| 9c44656104 | |||
| d57914957d | |||
| c4f12ce75a | |||
| 4ad370ea46 | |||
| 44ad3caf2b | |||
| 427a272f8f | |||
| 96fb50e68d | |||
| 19274546c9 | |||
| d2d730589b | |||
| f88b0edb2a | |||
| c62299aa72 | |||
| c054668eac | |||
| 82352713f1 | |||
| 48073ab1f0 | |||
| c6e98f50c2 | |||
| ef88fdc9a4 | |||
| 8889aaca2a | |||
| 9b08420ac1 | |||
| 0ee92f0181 | |||
| a995cae000 | |||
| 0b7d504a7a | |||
| 6a4a852fd6 | |||
| 81a9304438 | |||
| 332d689b8c | |||
| b508c0517d | |||
| d2c0fdf820 | |||
| 7293afd203 | |||
| 2fd1053bf9 | |||
| e0a68a35f4 | |||
| 4e277b4ca6 | |||
| b3f4a4086b | |||
| eb7d77692b | |||
| ce1b1859df | |||
| 371cc1a187 | |||
| a94606ca89 | |||
| 5c9c9dc917 | |||
| ab8acfc7d1 | |||
| 1ddd0074b3 | |||
| 2b934f6baf | |||
| 1bdae56342 | |||
| 6caaae6d50 | |||
| 4dc0c71d3f | |||
| a54f4f94c9 | |||
| b8d6c909eb | |||
| e35fb9dc19 | |||
| 0e0363f131 | |||
| 088d7c8aa0 | |||
| 60084450e6 | |||
| 9775792916 | |||
| 93d6277386 | |||
| 37c5c7c4f6 | |||
| 5eb33f3e31 | |||
| 43f5f3ecae | |||
| c503750e90 | |||
| 7054c18113 | |||
| 077eb803a1 | |||
| f963b61ebc | |||
| 9ed51d60e4 | |||
| f5198efab3 | |||
| d6446f90fe | |||
| 58bceb5d27 | |||
| 92084bed99 | |||
| cd1c92a7db | |||
| 9ca758ecd3 | |||
| 3c54d8de6d | |||
| d91d4261d9 | |||
| 00f5216a9f | |||
| aeae9002fe | |||
| 9df425f5f8 | |||
| 5149a67d4b | |||
| 1309c27f7c | |||
| 26db620465 | |||
| bd213b8f8c | |||
| 31b7bd1314 | |||
| 0bdbd39632 | |||
| b979fb5b2a | |||
| cbefccd2d3 | |||
| 0ebe274e9a | |||
| c4d09eb2ea | |||
| 3039fcc553 | |||
| a67e587769 | |||
| d89520d58e | |||
| 06a9eba177 | |||
| a41dc5403f | |||
| 85b2c1f08e | |||
| ba8dd7d083 | |||
| fa04e32266 | |||
| 7d6b433373 | |||
| faae8b8d9a | |||
| a0d0de19c5 | |||
| 17eaa7858f | |||
| f2556412d8 | |||
| 26557542f1 | |||
| 6bb46e165c | |||
| 027529161d | 
| @@ -1,46 +1,125 @@ | |||||||
| # QT -= gui | QT += core gui | ||||||
| QT += core | QT += widgets serialport network | ||||||
| QT += widgets serialport |  | ||||||
| # QT += network | greaterThan(QT_MAJOR_VERSION, 4): QT += widgets | ||||||
|  |  | ||||||
| TARGET = ATBUpdateTool | TARGET = ATBUpdateTool | ||||||
|  |  | ||||||
|  | # The following define makes your compiler emit warnings if you use | ||||||
|  | # any Qt feature that has been marked deprecated (the exact warnings | ||||||
|  | # depend on your compiler). Please consult the documentation of the | ||||||
|  | # deprecated API in order to know how to port your code away from it. | ||||||
|  | DEFINES += QT_DEPRECATED_WARNINGS | ||||||
|  |  | ||||||
|  | # You can also make your code fail to compile if it uses deprecated APIs. | ||||||
|  | # In order to do so, uncomment the following line. | ||||||
|  | # You can also select to disable deprecated APIs only up to a certain version of Qt. | ||||||
|  | #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0 | ||||||
|  |  | ||||||
|  | # 1.3.6 :   Do not update device-controller/json files, but have the library | ||||||
|  | #           (in a later step) do that. | ||||||
|  | #           Fixed sending messages to ISMAS. | ||||||
|  | #           Always execute contents of opkg_commands-file (even if there are no | ||||||
|  | #           changes). | ||||||
|  | # 1.3.7 :   Wait forever for git-commands to finish in QProcess executing such | ||||||
|  | #           a command. | ||||||
|  | # 1.3.8 :   Remove accessing opkg_commands under file-system-path /etc/psa_update. | ||||||
|  | #           Activate download of json-configuration files. | ||||||
|  | # 1.3.9 :   Fix sendLastVersion: use configured branch and not master branch in | ||||||
|  | #               git show origin/master -s --format="c=%h m=%s d=%cI"    ==> | ||||||
|  | #               git show origin/zg1/zone1 -s --format="c=%h m=%s d=%cI" | ||||||
|  | #           Use dynamic values for os-release and apism-version when sending | ||||||
|  | #           last version info. | ||||||
|  | # 1.3.10:   Fix premature killing opkg-commands: detected timeout of 100s was | ||||||
|  | #           too small when updating apism. | ||||||
|  | #           Fix display of UPDATE_SUCCESS when opkg_command fails. Detected when | ||||||
|  | #           updating apsim failed. | ||||||
|  | # 1.3.11:   Integrate version of ATBUpdateTool in SendLastVersion-ISMAS-message. | ||||||
|  | # 1.3.12:   Add command parameters for output of yocto-infos about ATBUpdateTool. | ||||||
|  | #           Use 'git pull' instead of 'git fetch'. | ||||||
|  | #           Use 'git clone --filter=blob:none' instead of 'git clone' to speed | ||||||
|  | #           up cloning of customer repository. | ||||||
|  | # 1.3.13:   Fix: if the customer repository is corrupted, remove it and re-clone | ||||||
|  | #           the repository (without checking the ISMAS-trigger (WAIT-)button. | ||||||
|  | # 1.3.14:   Add additional check for sanity of customer repository using | ||||||
|  | #           "git fsck". | ||||||
|  | #           Stream-lined code of update process: massive refactoring. | ||||||
|  | #           Added functionality: If WAIT button is not active, then an existing | ||||||
|  | #           customer repository will be repaired, or a not existing repository | ||||||
|  | #           will be cloned. The process stops then. | ||||||
|  | #           However, if the WAIT button is active, the at least the commands in | ||||||
|  | #           opkg_commands will be executed. Changed files in the customer | ||||||
|  | #           repository will be worked on: tariff-files will be synced with the | ||||||
|  | #           local filesystem, json-files will be downloaded to firmware. | ||||||
|  | #           The device-controller firmware will be handled in a later version. | ||||||
|  | VERSION="1.3.15" | ||||||
|  | #           Bug fixes found during testing. | ||||||
|  | #           Don't disable Exit-button during update-process. | ||||||
|  | #           Removed worker-thread with an own event-loop: only the GUI thread | ||||||
|  | #           has an event loop. Tested JSON-downloads several times successfully | ||||||
|  | #           (using the slave lib where the CA helper tool was active as master). | ||||||
|  | #           Turned previous worker-object into its own thread, but without any | ||||||
|  | #           own event-loop (so it cannot block anything inside the CA-plugin). | ||||||
|  |  | ||||||
|  | # PLANNED TODOS: | ||||||
|  | #   1:  Das Repository wird repariert bwz. neu geklont. Unabhaengig vom WAIT. | ||||||
|  | #   2:  Wenn der WAIT-Button aktiv ist, dann wird ein Repository repariert (neu | ||||||
|  | #       geklont), aber zusaetzlich werden alle verfuegbaren Dateien als neu | ||||||
|  | #       angesehen und die entsprechenden Aktionen durchgefuehrt: tariff-files | ||||||
|  | #       spiegeln, json-files laden und dc laden. Also VORSICHT: das repository | ||||||
|  | #       muss in diesem fall wirklich in ordnung sein. | ||||||
|  | #   3:  Wurde keine Datei geaendert, kein initiales Clone und der WAIT-button | ||||||
|  | #       nicht aktiv, so (passiert natuerlich nichts) kann man davon ausgehen, | ||||||
|  | #       dass es sich um ein automatisches Update handelt. Dann koennte man im | ||||||
|  | #       ISMAS eine entsprechende Meldung anzeigen als Teil von SEND-LAST-VERSION. | ||||||
|  | #       Wenn der WAIT-button aktiv ist, dann werden zumindest die opkg-commands | ||||||
|  | #       ausgefuehrt. | ||||||
|  | #   4:  rsync: immer alle Dateien soiegeln (bis auf opkg-commands) | ||||||
|  | #   5:  Falls das Tool mal abstuerzt, dann einen Signal-Handler (fuer TERM) | ||||||
|  | #       installieren, sodass zumnidest SEND-LAST-VERSION mit rausgeht. | ||||||
|  | #   6:  rsync: explizites Binary, nicht das in busybox enthaltene. | ||||||
|  | #   7:  Ein ini-File oder sowas. | ||||||
|  |  | ||||||
|  | win32 { | ||||||
|  |     BUILD_DATE=$$system("date /t") | ||||||
|  |     BUILD_TIME=$$system("time /t") | ||||||
|  | } else { | ||||||
|  |     BUILD_DATE=$$system("date +%d-%m-%y") | ||||||
|  |     BUILD_TIME=$$system("date +%H:%M:%S") | ||||||
|  | } | ||||||
|  |  | ||||||
|  | GIT_COMMIT=$$system("git log -1 --format=oneline | cut -d' ' -f1") | ||||||
|  |  | ||||||
|  | EXTENDED_VERSION="$${VERSION}-$${GIT_COMMIT}" | ||||||
|  |  | ||||||
| INCLUDEPATH += plugins | INCLUDEPATH += plugins | ||||||
|  |  | ||||||
| CONFIG += c++17 console | CONFIG += c++17 | ||||||
| # CONFIG -= app_bundle | # CONFIG -= app_bundle | ||||||
|  |  | ||||||
| # DEFINES+=LinuxDesktop | DEFINES+=APP_VERSION=\\\"$$VERSION\\\" | ||||||
|  | DEFINES+=APP_BUILD_DATE=\\\"$$BUILD_DATE\\\" | ||||||
|  | DEFINES+=APP_BUILD_TIME=\\\"$$BUILD_TIME\\\" | ||||||
|  | DEFINES+=APP_EXTENDED_VERSION=\\\"$$EXTENDED_VERSION\\\" | ||||||
|  |  | ||||||
|  | # keep comments, as /* fall through */ | ||||||
|  | QMAKE_CXXFLAGS += -C | ||||||
|  | QMAKE_CXXFLAGS += -g | ||||||
| QMAKE_CXXFLAGS += -Wno-deprecated-copy | QMAKE_CXXFLAGS += -Wno-deprecated-copy | ||||||
|  |  | ||||||
| # custom target for 'git subtree' |  | ||||||
| # subtree.target = subtree |  | ||||||
| # subtree.commands = git subtree add --prefix DCPlugin https://git.mimbach49.de/GerhardHoffmann/DCPlugin.git master --squash |  | ||||||
| # subtree.depends = |  | ||||||
| # QMAKE_EXTRA_UNIX_TARGETS += subtree |  | ||||||
|  |  | ||||||
| # ! exists(DCPlugin) { |  | ||||||
| #     $$system("git subtree add --prefix DCPlugin https://git.mimbach49.de/GerhardHoffmann/DCPlugin.git master --squash") |  | ||||||
| # } else { |  | ||||||
|     # $$system("git subtree pull --prefix DCPlugin https://git.mimbach49.de/GerhardHoffmann/DCPlugin.git master --squash") |  | ||||||
| # } |  | ||||||
|  |  | ||||||
| # You can make your code fail to compile if it uses deprecated APIs. |  | ||||||
| # In order to do so, uncomment the following line. |  | ||||||
| #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0 |  | ||||||
|  |  | ||||||
| contains( CONFIG, PTU5 ) { | contains( CONFIG, PTU5 ) { | ||||||
|     greaterThan(QT_MAJOR_VERSION, 4): QT += serialport |     greaterThan(QT_MAJOR_VERSION, 4): QT += serialport | ||||||
|     CONFIG += link_pkgconfig |     CONFIG += link_pkgconfig | ||||||
|     lessThan(QT_MAJOR_VERSION, 5):   PKGCONFIG += qextserialport |     lessThan(QT_MAJOR_VERSION, 5):   PKGCONFIG += qextserialport | ||||||
|     QMAKE_CXXFLAGS += -std=c++11   # for GCC >= 4.7 |     QMAKE_CXXFLAGS += -O2 -std=c++17   # for GCC >= 4.7 | ||||||
|     QMAKE_CXXFLAGS += -Wno-deprecated-copy |     # QMAKE_CXXFLAGS += -Wno-deprecated-copy | ||||||
|     ARCH = PTU5 |     ARCH = PTU5 | ||||||
|     DEFINES+=PTU5 |     DEFINES+=PTU5 | ||||||
| } | } | ||||||
| contains( CONFIG, PTU5_YOCTO ) { | contains( CONFIG, PTU5_YOCTO ) { | ||||||
|     greaterThan(QT_MAJOR_VERSION, 4): QT += serialport |     greaterThan(QT_MAJOR_VERSION, 4): QT += serialport | ||||||
|  |     QMAKE_CXXFLAGS += -std=c++17   # for GCC >= 4.7 | ||||||
|  |     # QMAKE_CXXFLAGS += -Wno-deprecated-copy | ||||||
|     PTU5BASEPATH = /opt/devel/ptu5 |     PTU5BASEPATH = /opt/devel/ptu5 | ||||||
|     ARCH = PTU5 |     ARCH = PTU5 | ||||||
|     DEFINES+=PTU5 |     DEFINES+=PTU5 | ||||||
| @@ -53,8 +132,8 @@ contains( CONFIG, DesktopLinux ) { | |||||||
|     lessThan(QT_MAJOR_VERSION, 5):    CONFIG += extserialport |     lessThan(QT_MAJOR_VERSION, 5):    CONFIG += extserialport | ||||||
|     # QMAKE_CC = ccache $$QMAKE_CC |     # QMAKE_CC = ccache $$QMAKE_CC | ||||||
|     # QMAKE_CXX = ccache $$QMAKE_CXX |     # QMAKE_CXX = ccache $$QMAKE_CXX | ||||||
|     QMAKE_CXXFLAGS += -std=c++11 |     QMAKE_CXXFLAGS += -std=c++17 | ||||||
|     QMAKE_CXXFLAGS += -Wno-deprecated-copy |     # QMAKE_CXXFLAGS += -Wno-deprecated-copy | ||||||
|     linux-clang {  QMAKE_CXXFLAGS += -Qunused-arguments   } |     linux-clang {  QMAKE_CXXFLAGS += -Qunused-arguments   } | ||||||
|     ARCH = DesktopLinux |     ARCH = DesktopLinux | ||||||
|     DEFINES+=DesktopLinux |     DEFINES+=DesktopLinux | ||||||
| @@ -62,25 +141,39 @@ contains( CONFIG, DesktopLinux ) { | |||||||
|  |  | ||||||
| SOURCES += \ | SOURCES += \ | ||||||
|         main.cpp \ |         main.cpp \ | ||||||
|  |         progress_event.cpp \ | ||||||
|  |         update_dc_event.cpp \ | ||||||
|  |         mainwindow.cpp \ | ||||||
|  |         utils.cpp \ | ||||||
|         update.cpp \ |         update.cpp \ | ||||||
|  |         git/git_client.cpp \ | ||||||
|  |         ismas/ismas_client.cpp \ | ||||||
|  |         process/command.cpp \ | ||||||
|         message_handler.cpp \ |         message_handler.cpp \ | ||||||
|         worker.cpp \ |         worker.cpp | ||||||
|         worker_thread.cpp |  | ||||||
|  |  | ||||||
| HEADERS += \ | HEADERS += \ | ||||||
|         update.h \ |         update.h \ | ||||||
|  |         progress_event.h \ | ||||||
|  |         update_dc_event.h \ | ||||||
|  |         utils.h \ | ||||||
|  |         mainwindow.h \ | ||||||
|  |         git/git_client.h \ | ||||||
|  |         apism/ismas_data.h \ | ||||||
|  |         ismas/ismas_client.h \ | ||||||
|  |         process/command.h \ | ||||||
|         message_handler.h \ |         message_handler.h \ | ||||||
|         worker.h \ |         worker.h \ | ||||||
|         worker_thread.h \ |  | ||||||
|         plugins/interfaces.h |         plugins/interfaces.h | ||||||
|  |  | ||||||
| OTHER_FILES += \ | FORMS += \ | ||||||
|     /opt/app/tools/atbupdate/update_log.csv \ |     mainwindow.ui | ||||||
|     main.cpp.bck \ |  | ||||||
|     main.cpp.bck2 \ |  | ||||||
|     main.cpp.bck3 |  | ||||||
|  |  | ||||||
| # https://blog.developer.atlassian.com/the-power-of-git-subtree/?_ga=2-71978451-1385799339-1568044055-1068396449-1567112770 |  | ||||||
| # git subtree add --prefix DCPlugin https://git.mimbach49.de/GerhardHoffmann/DCPlugin.git master --squash | ########################################################################################## | ||||||
| # git subtree pull --prefix DCPlugin https://git.mimbach49.de/GerhardHoffmann/DCPlugin.git master --squash | # for running program on target through QtCreator | ||||||
| # include(./DCPlugin/DCPlugin.pri) | contains( CONFIG, PTU5 ) { | ||||||
|  |    qnx: target.path = /tmp/$${TARGET}/bin | ||||||
|  |    else: unix:!android: target.path = /opt/app/tools/atbupdate/ | ||||||
|  |    !isEmpty(target.path): INSTALLS += target | ||||||
|  | } | ||||||
|   | |||||||
							
								
								
									
										126
									
								
								allgemein.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										126
									
								
								allgemein.txt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,126 @@ | |||||||
|  | 0: | ||||||
|  |     Zunaechst wir immer nachgesehen, ob das Repository bereits geklont wurde. | ||||||
|  |     Wenn nein, dann wird geklont. Im Master-Branch befinden sich Dateinen, die | ||||||
|  |     in allen anderen Branches gemeinsam genutzt werden. Das sollte wohl auf | ||||||
|  |     jeden Fall fuer den DeviceController gelten. | ||||||
|  | 1: | ||||||
|  |     Anfrage bei ISMAS ob neue Daten da sind. Hier faengt die ganze Sache an. | ||||||
|  |     Da man nicht weiss, on ISMAS ueberhaupt antworten wird braucht es einen | ||||||
|  |     Timer. Man kann die Sache dann auch gleich mehrfach versuchen. | ||||||
|  |  | ||||||
|  |     Die Anfrage geht also per Signal an den Apism-Client. Im Signal wird der | ||||||
|  |     Zustand mitgegeben: | ||||||
|  |  | ||||||
|  |         ISMAS_UPDATE_REQUEST_PENDING | ||||||
|  |  | ||||||
|  |     und im Slot dann entsprechend uebernommen. Der Timer sollte nicht im Worker | ||||||
|  |     stehen, sondern im Apism-Client. Der Worker sollte damit nicht belastet | ||||||
|  |     sein. Der wird dann vom Apism-Client entsprechend benachrichtigt. | ||||||
|  |  | ||||||
|  |         ISMAS_UPDATE_REQUEST_FAILURE | ||||||
|  |             ISMAS_UPDATE_REQUEST_TIMEOUT | ||||||
|  |         ISMAS_UPDATE_REQUEST_SUCCESS | ||||||
|  |  | ||||||
|  |     Im 1./2.Fall wird dann ein Fehlerhandling durchgefuehrt. Insbesondere | ||||||
|  |     wird Apism ueber den DB-Kanal darueber informiert (U0003). Am Ende wie | ||||||
|  |     dann wie immer SendCmdVersion und beenden der Applikation. | ||||||
|  |  | ||||||
|  |     Im Erfolgsfall muss in der Antwort der Branch enthalten sein, fuer den das | ||||||
|  |     Update durchgefuhrt werden soll. Das ist auch bereits so (Location). | ||||||
|  |  | ||||||
|  |     Ein Sonderfall waere der -m-Modus, da hier niemand auf der ISMAS-Seite | ||||||
|  |     aktiv eingreift. Hier braucht es dann einen Ubergabeparameter an  | ||||||
|  |     ATBUpdateTool: --branch-name | ||||||
|  |  | ||||||
|  |     Normalfall ist aber die Aktivierung via ISMAS. Dann muss der in der Antwort | ||||||
|  |     enthaltene Branch zunaechst ausgecheckt werden. | ||||||
|  | 2:  | ||||||
|  |     Dazu wird ein entsprechendes Signal an den GitClient gesandet. | ||||||
|  |          | ||||||
|  |         GIT_CHECKOUT_BRANCH_REQUEST | ||||||
|  |  | ||||||
|  |     Der GitClient sieht jetzt erstmal nach, ob es diesen Branch ueberhaupt | ||||||
|  |     gibt. | ||||||
|  |  | ||||||
|  |         Falls nein:     | ||||||
|  |  | ||||||
|  |         GIT_CHECKOUT_BRANCH_REQUEST_FAILURE | ||||||
|  |             BRANCH_NOT_EXIST | ||||||
|  |   | ||||||
|  |         Falls ja: | ||||||
|  |             der GitClient versucht nun den Branch auszuchecken.  | ||||||
|  |             Geht das gut? | ||||||
|  |             Falls nein: | ||||||
|  |  | ||||||
|  |                 GIT_CHECKOUT_BRANCH_REQUEST_FAILURE | ||||||
|  |                     BRANCH_CHECKOUT_ERROR | ||||||
|  |  | ||||||
|  |             Falls ja: | ||||||
|  |                 GIT_CHECKOUT_BRANCH_REQUEST_SUCCESS | ||||||
|  |                     -> eventl. koennte man den Namen des Branches mitgeben | ||||||
|  |  | ||||||
|  |  | ||||||
|  |         Signal an den Worker. Im entsprechenden Slot wird jetzt der eigentliche | ||||||
|  |         UpdateProzess angeworfen. | ||||||
|  |  3: | ||||||
|  |     Mittels git fetch werden jetzt die Aenderungen ermittelt. | ||||||
|  |  | ||||||
|  |         GIT_FETCH_UPDATES_REQUEST | ||||||
|  |          | ||||||
|  |         GIT_FETCH_UPDATES_REQUEST_FAILURE | ||||||
|  |             -> Worker informieren damit Fehlerbehandlung aktiviert wird | ||||||
|  |         GIT_FETCH_UPDATES_REQUEST_SUCCESS | ||||||
|  |  | ||||||
|  |         GIT_DIFF_UPDATES | ||||||
|  |  | ||||||
|  |         Die Liste der geaenderten Dateien geht an den Worker. Der kann jetzt | ||||||
|  |         noch Test machen, ob das Sinn macht. Evtl. eine Statusmeldung ausgeben | ||||||
|  |         drueber was gleich passieren wird. | ||||||
|  | 4: | ||||||
|  |     Mittels git merge/pull werden nun die Dateien tatsaechlich im Branch  | ||||||
|  |     aktualisiert. | ||||||
|  |  | ||||||
|  |         GIT_PULL_UPDATES_REQUEST | ||||||
|  |         GIT_PULL_UPDATES_REQUEST_FAILURE | ||||||
|  |             -> Worker informieren damit Fehlerbehandlung aktiviert wird | ||||||
|  |         GIT_PULL_UPDATES_REQUEST_SUCCESS | ||||||
|  |             -> Worker informieren | ||||||
|  |  | ||||||
|  |     Sind die Daten vorhanden, dann werden sie mittels rsync ins Dateisystem | ||||||
|  |     kopiert. | ||||||
|  |  | ||||||
|  |         RSYNC_UPDATES  | ||||||
|  |         RSYNC_UPDATES_FAILURE | ||||||
|  |         RSYNC_UPDATES_SUCCESS | ||||||
|  |  | ||||||
|  |     Fuer jede kopierte Datei geht eine Nachricht raus ans ISMAS. | ||||||
|  | 5: | ||||||
|  |     Sind die Daten dann kopiert, so werden sie auf den DC kopiert (falls | ||||||
|  |     notwendig): hier gehen dann wieder Nachrichten an ISMAS raus: | ||||||
|  |  | ||||||
|  |         DC_UPDATE  | ||||||
|  |         DC_UPDATE_FAILURE | ||||||
|  |         DC_UPDATE_SUCCESS | ||||||
|  |  | ||||||
|  |         JSON_UPDATE | ||||||
|  |         JSON_UPDATE_FAILURE | ||||||
|  |         JSON_UPDATE_SUCCESS | ||||||
|  |          | ||||||
|  |         Hier fuer jedes Json-File. | ||||||
|  |  | ||||||
|  |     Schliesslich noch eine Zusammenfasung an ISMAS: | ||||||
|  |  | ||||||
|  |         ISMAS_UPDATE_INFO_CONFIRM | ||||||
|  |         ISMAS_UPDATE_INFO_CONFIRM_FAILURE | ||||||
|  |             -> Worker informieren damit Fehlerbehandlung aktiviert wird | ||||||
|  |         ISMAS_UPDATE_INFO_CONFIRM_SUCCESS | ||||||
|  |  | ||||||
|  |     und schliesslich der abschliessende Status an ISMAS zurueckgemeldet: | ||||||
|  |  | ||||||
|  |         ISMAS_CURRENT_PSA_STATUS_CONFIRM | ||||||
|  |         ISMAS_CURRENT_PSA_STATUS_CONFIRM_FAILURE | ||||||
|  |         ISMAS_CURRENT_PSA_STATUS_CONFIRM_SUCCESS | ||||||
|  |  | ||||||
|  |      | ||||||
|  |  | ||||||
|  |  | ||||||
							
								
								
									
										137
									
								
								apism/ismas_data.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										137
									
								
								apism/ismas_data.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,137 @@ | |||||||
|  | #ifndef ISMASDATA_H | ||||||
|  | #define ISMASDATA_H | ||||||
|  |  | ||||||
|  | #include <QJsonObject> | ||||||
|  | #include <QJsonArray> | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | namespace ISMAS { | ||||||
|  |  | ||||||
|  |     struct TransferData : public QJsonObject { | ||||||
|  |         struct : public QJsonObject { | ||||||
|  |             QJsonValue tariffId; | ||||||
|  |             QJsonValue group; | ||||||
|  |             QJsonValue zone; | ||||||
|  |         } device; | ||||||
|  |  | ||||||
|  |         struct : public QJsonObject { | ||||||
|  |             QJsonValue state; | ||||||
|  |             QJsonValue uid; | ||||||
|  |             QJsonValue seq_tick_number; | ||||||
|  |             QJsonValue timestamp; | ||||||
|  |             QJsonValue userText; | ||||||
|  |             QJsonValue userTextType; | ||||||
|  |         } transaction; | ||||||
|  |  | ||||||
|  |         struct : public QJsonObject { | ||||||
|  |             // TODO: check what is really used at the moment | ||||||
|  |             QJsonValue id;          // unique article id | ||||||
|  |             QJsonValue name;        // name | ||||||
|  |             QJsonValue price;       // price in cent | ||||||
|  |             QJsonValue currency;    // | ||||||
|  |             QJsonValue startTime;   // start time | ||||||
|  |             QJsonValue endTime;     // end time | ||||||
|  |             QJsonValue userText;    // additional info | ||||||
|  |             QJsonValue parkingTime; | ||||||
|  |             QJsonValue printText; | ||||||
|  |             // QJsonValue discount; | ||||||
|  |         } item; | ||||||
|  |  | ||||||
|  |         struct : public QJsonObject { | ||||||
|  |             struct : public QJsonObject { | ||||||
|  |                 QJsonValue coins;     // total amount of coins value | ||||||
|  |                 // QJsonValue notes;     // total amount of notes value | ||||||
|  |                 QJsonValue overpaid;  // in cent | ||||||
|  |                 QJsonValue currency; | ||||||
|  |                 QJsonValue change; | ||||||
|  |             } cash; | ||||||
|  |  | ||||||
|  |             struct : public QJsonObject { | ||||||
|  |                 QJsonValue cardNumber; | ||||||
|  |                 QJsonValue value;           // buchungsbetrag | ||||||
|  |                 QJsonValue cardType; | ||||||
|  |                 QJsonValue currency; | ||||||
|  |                 QJsonValue tid; | ||||||
|  |                 QJsonValue tresult; | ||||||
|  |             } card; | ||||||
|  |  | ||||||
|  |             struct : public QJsonObject { | ||||||
|  |                 QJsonValue cardNumber; | ||||||
|  |                 QJsonValue cardType; | ||||||
|  |                 QJsonValue value; | ||||||
|  |                 QJsonValue valueOld; | ||||||
|  |                 QJsonValue valueNew; | ||||||
|  |                 QJsonValue time; | ||||||
|  |                 QJsonValue timeOld; | ||||||
|  |                 QJsonValue timeNew; | ||||||
|  |             } prePaidCard; | ||||||
|  |         } payment; | ||||||
|  |  | ||||||
|  |         struct : public QJsonObject { | ||||||
|  |             QJsonValue delivery;    // PRINT, OnlineTicket | ||||||
|  |             QJsonValue result;      // SUCCESS, ERROR | ||||||
|  |             QJsonValue errorCode;   // 0=OK, 1=... | ||||||
|  |             QJsonValue errorMsg; | ||||||
|  |         } result; | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     struct AccountData : public QJsonObject { | ||||||
|  |         struct : public QJsonObject { | ||||||
|  |             QJsonValue UID; | ||||||
|  |             QJsonValue ChangeNumber; | ||||||
|  |             QJsonValue Process;         // Vorgang | ||||||
|  |             QJsonValue startDateTime; | ||||||
|  |             QJsonValue endDateTime; | ||||||
|  |             QJsonValue startHash; | ||||||
|  |             QJsonValue endHash; | ||||||
|  |  | ||||||
|  |             struct : public QJsonObject { | ||||||
|  |                 QJsonValue value;          // coin value | ||||||
|  |                 QJsonValue numberOfCoins;  // number of coins | ||||||
|  |                 QJsonValue currency; | ||||||
|  |             } coin; | ||||||
|  |  | ||||||
|  |         } coinBox;                  // Münzkasse | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     struct EventData : public QJsonObject { | ||||||
|  |         struct : public QJsonObject { | ||||||
|  |             QJsonValue eventID; | ||||||
|  |             QJsonValue deviceName; | ||||||
|  |             QJsonValue reason; | ||||||
|  |             QJsonValue event; | ||||||
|  |             QJsonValue eventState; | ||||||
|  |             QJsonValue timeStamp; | ||||||
|  |             QJsonValue parameter; | ||||||
|  |             QJsonValue secondLevelInfo; | ||||||
|  |         } machineEvent;                  // | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     struct StateData : public QJsonObject { | ||||||
|  |         QJsonValue Timestamp; | ||||||
|  |         QJsonArray HW_States; | ||||||
|  |         struct : public QJsonObject { | ||||||
|  |             QJsonValue name; | ||||||
|  |             QJsonValue value; | ||||||
|  |             QJsonValue unit; | ||||||
|  |         } machineState;                  // | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     enum class REQUEST : quint8 { | ||||||
|  |         NO_REQUEST, | ||||||
|  |         START, | ||||||
|  |         STOP, | ||||||
|  |         PING, | ||||||
|  |         SELF, | ||||||
|  |         ISMAS_PARAMETER | ||||||
|  |     }; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | #endif // ISMASDATA_H | ||||||
							
								
								
									
										434
									
								
								git/git_client.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										434
									
								
								git/git_client.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,434 @@ | |||||||
|  | #include "git_client.h" | ||||||
|  | #include "update.h" | ||||||
|  | #include "worker.h" | ||||||
|  | #include "utils.h" | ||||||
|  |  | ||||||
|  | #include <QRegularExpression> | ||||||
|  | #include <QDebug> | ||||||
|  | #include <QDir> | ||||||
|  |  | ||||||
|  |  | ||||||
|  | GitClient::GitClient(QString const &customerNrStr, | ||||||
|  |                      QString const &customerRepository, | ||||||
|  |                      QString const &workingDirectory, | ||||||
|  |                      QString const &branchName, | ||||||
|  |                      QObject *parent) | ||||||
|  |   : QObject(parent) | ||||||
|  |   , m_worker(qobject_cast<Worker *>(parent)) | ||||||
|  |   , m_repositoryPath(QString("https://git.mimbach49.de/GerhardHoffmann/%1.git").arg(customerNrStr)) | ||||||
|  |   , m_customerNr(customerNrStr) | ||||||
|  |   , m_workingDirectory(workingDirectory) | ||||||
|  |   , m_branchName(branchName) | ||||||
|  |   , m_customerRepository(customerRepository) { | ||||||
|  |     if (!m_worker) { | ||||||
|  |         qCritical() << "ERROR CASTING PARENT TO WORKER FAILED"; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool GitClient::gitCloneCustomerRepository() { | ||||||
|  |     /*  Blobless clone | ||||||
|  |         ============== | ||||||
|  |  | ||||||
|  |         When using the --filter=blob:none option, the initial git clone will | ||||||
|  |         download all reachable commits and trees, and only download the blobs | ||||||
|  |         for commits when you do a git checkout. This includes the first checkout | ||||||
|  |         inside the git clone operation. | ||||||
|  |  | ||||||
|  |         The important thing to notice is that we have a copy of every blob at | ||||||
|  |         HEAD but the blobs in the history are not present. If your repository | ||||||
|  |         has a deep history full of large blobs, then this option can | ||||||
|  |         significantly reduce your git clone times. The commit and tree data is | ||||||
|  |         still present, so any subsequent git checkout only needs to download | ||||||
|  |         the missing blobs. The Git client knows how to batch these requests to | ||||||
|  |         ask the server only for the missing blobs. | ||||||
|  |  | ||||||
|  |         Further, when running git fetch in a blobless clone, the server only | ||||||
|  |         sends the new commits and trees. The new blobs are downloaded only | ||||||
|  |         after a git checkout. Note that git pull runs git fetch and then git | ||||||
|  |         merge, so it will download the necessary blobs during the git merge | ||||||
|  |         command. | ||||||
|  |  | ||||||
|  |         When using a blobless clone, you will trigger a blob download whenever | ||||||
|  |         you need the contents of a file, but you will not need one if you only | ||||||
|  |         need the OID (object-id) of a file. This means that git log can detect | ||||||
|  |         which commits changed a given path without needing to download extra | ||||||
|  |         data. | ||||||
|  |  | ||||||
|  |         This means that blobless clones can perform commands like git | ||||||
|  |         merge-base, git log, or even git log -- <path> with the same performance | ||||||
|  |         as a full clone. | ||||||
|  |  | ||||||
|  |         Commands like git diff or git blame <path> require the contents of the | ||||||
|  |         paths to compute diffs, so these will trigger blob downloads the first | ||||||
|  |         time they are run. However, the good news is that after that you will | ||||||
|  |         have those blobs in your repository and do not need to download them a | ||||||
|  |         second time. Most developers only need to run git blame on a small | ||||||
|  |         number of files, so this tradeoff of a slightly slower git blame command | ||||||
|  |         is worth the faster clone and fetch times. | ||||||
|  |  | ||||||
|  |         Note: git v2.18 does not support treeless clones: --filter=tree:0. | ||||||
|  |      */ | ||||||
|  |  | ||||||
|  |     // Note: for some reason it is necessary to pass "--progress ---v", | ||||||
|  |     // otherwise QProcess returns an error of 128 = 0x80 for the command. | ||||||
|  |  | ||||||
|  |     QString gitCommand("git clone --progress -vvv --filter=blob:none "); | ||||||
|  |     gitCommand += m_repositoryPath; | ||||||
|  |     Command c(gitCommand); | ||||||
|  |  | ||||||
|  |     qInfo() << "IN CURRENT WD" << m_workingDirectory | ||||||
|  |             << "CLONE VIA COMMAND" << gitCommand; | ||||||
|  |  | ||||||
|  |     if (c.execute(m_workingDirectory)) { // execute the command in wd | ||||||
|  |         QString const result = c.getCommandResult(); | ||||||
|  |         if (!result.isEmpty()) { | ||||||
|  |             // Cloning into 'customer_281'...\n | ||||||
|  |             int customer = -1; | ||||||
|  |             int cloning = result.indexOf("Cloning", 0, Qt::CaseInsensitive); | ||||||
|  |             if (cloning != -1) { | ||||||
|  |                 customer = result.indexOf("customer_", cloning, Qt::CaseInsensitive); | ||||||
|  |                 if (customer != -1) { | ||||||
|  |                     QString customerNr = result.mid(customer); | ||||||
|  |                     static constexpr char const ch = '\''; | ||||||
|  |                     int i = customerNr.indexOf(QChar(ch)); | ||||||
|  |                     if (i != -1) { | ||||||
|  |                         if ((customerNr = customerNr.mid(0, i)) == m_customerNr) { | ||||||
|  |                             qInfo() << "CLONING" << m_repositoryPath << "OK"; | ||||||
|  |                             return true; | ||||||
|  |                         } | ||||||
|  |                         Utils::printCriticalErrorMsg( | ||||||
|  |                             QString("ERROR CLONE RESULT HAS WRONG CUSTOMER-NR. (%1 != %2) CLONE_RESULT=%3") | ||||||
|  |                                 .arg(customerNr) | ||||||
|  |                                 .arg(m_customerNr) | ||||||
|  |                                 .arg(result)); | ||||||
|  |                         return false; | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             Utils::printCriticalErrorMsg( | ||||||
|  |                 QString("ERROR CLONE RESULT HAS WRONG FORMAT. CLONING=%1 CUSTOMER=%2 CLONE_RESULT=%3") | ||||||
|  |                     .arg(cloning) | ||||||
|  |                     .arg(customer) | ||||||
|  |                     .arg(result)); | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |         Utils::printCriticalErrorMsg("ERROR CLONE RESULT IS EMPTY"); | ||||||
|  |     } | ||||||
|  |     return false; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool GitClient::copyGitConfigFromMaster() { // only allowed when called in | ||||||
|  |                                             // master branch (???) | ||||||
|  |     if (QDir(m_customerRepository).exists()) { | ||||||
|  |         QString const cp = QString("cp .gitconfig .git/config"); | ||||||
|  |         Command c("bash"); | ||||||
|  |         if (c.execute(m_customerRepository, QStringList() << "-c" << cp)) { | ||||||
|  |             qInfo() << "cp .gitconfig .git/config OK"; | ||||||
|  |             return true; | ||||||
|  |         } | ||||||
|  |         qCritical() << "ERROR cp .gitconfig .git/config"; | ||||||
|  |     } | ||||||
|  |     return false; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | QStringList GitClient::gitBranchNames() { | ||||||
|  |     // git config --global pager.branch false | ||||||
|  |     QStringList bNames; | ||||||
|  |     if (QDir(m_customerRepository).exists()) { | ||||||
|  |         QString gitCommand("git branch -a"); | ||||||
|  |         Command c(gitCommand); | ||||||
|  |         if (c.execute(m_customerRepository)) { | ||||||
|  |             QString const result = c.getCommandResult(); | ||||||
|  |             return result.split('\n'); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     return bNames; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool GitClient::gitCheckoutBranch() { | ||||||
|  |     // TODO: nachsehen, ob der Branch ueberhaupt existiert | ||||||
|  |  | ||||||
|  |     if (QDir(m_customerRepository).exists()) { | ||||||
|  |         int zoneNr = Utils::read1stLineOfFile("/mnt/system_data/zone_nr"); | ||||||
|  |         m_branchName = (zoneNr != 0) | ||||||
|  |             ? QString("zg1/zone%1").arg(zoneNr) : "master"; | ||||||
|  |  | ||||||
|  |         QString gitCommand("git checkout "); | ||||||
|  |         gitCommand += m_branchName; | ||||||
|  |  | ||||||
|  |         Command c(gitCommand); | ||||||
|  |         return c.execute(m_customerRepository); // execute command in customerRepo | ||||||
|  |     } | ||||||
|  |     Utils::printCriticalErrorMsg(QString("ERROR ") + m_customerRepository + " DOES NOT EXIST"); | ||||||
|  |     return false; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool GitClient::gitCloneAndCheckoutBranch() { | ||||||
|  |     qInfo() << "CLONE" << m_repositoryPath << "AND CHECKOUT" << m_branchName; | ||||||
|  |     if (gitCloneCustomerRepository()) { | ||||||
|  |         //if (copyGitConfigFromMaster()) { | ||||||
|  |             if (gitCheckoutBranch()) { | ||||||
|  |                 return true; | ||||||
|  |             } else { | ||||||
|  |                 // TODO | ||||||
|  |             } | ||||||
|  |         //} | ||||||
|  |     } | ||||||
|  |     Utils::printCriticalErrorMsg(QString("CLONE ") + m_repositoryPath + " AND CHECKOUT FAILED"); | ||||||
|  |     return false; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | QStringList GitClient::gitShowReason(QString branchName) { | ||||||
|  |     QStringList lst; | ||||||
|  |     if (QDir(m_customerRepository).exists()) { | ||||||
|  |         // %h: commit (short form) | ||||||
|  |         // %s: commit message | ||||||
|  |         // %cI: commit date, strict ISO 8601 format | ||||||
|  |         // Note: branch with branchName has to exist: format zg1/zone1 | ||||||
|  |         Command c(QString("git show origin/%1 -s --format=\"c=%h m=%s d=%cI\"").arg(branchName)); | ||||||
|  |         if (c.execute(m_customerRepository)) { | ||||||
|  |             QString const s = c.getCommandResult().trimmed(); | ||||||
|  |             int const c = s.indexOf("c="); | ||||||
|  |             int const m = s.indexOf("m="); | ||||||
|  |             int const d = s.indexOf("d="); | ||||||
|  |  | ||||||
|  |             QString msg = IsmasClient::getReasonForLastSendVersion(); | ||||||
|  |             QString commit{""}, date{""}; | ||||||
|  |  | ||||||
|  |             if (c != -1) { | ||||||
|  |                 int start = c + 2; | ||||||
|  |                 if (m >= start) { | ||||||
|  |                     int length = m - start; | ||||||
|  |                     commit = s.mid(start, length).trimmed(); | ||||||
|  |  | ||||||
|  |                     start = m + 2; | ||||||
|  |                     if (d >= start) { | ||||||
|  |                         length = d - start; | ||||||
|  |                         msg += " ("; | ||||||
|  |                         msg = s.mid(start, length).trimmed(); | ||||||
|  |                         msg += ")"; | ||||||
|  |  | ||||||
|  |                         start = d + 2; | ||||||
|  |                         date = s.mid(start); | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 if (!commit.isEmpty() && !msg.isEmpty() && !date.isEmpty()) { | ||||||
|  |                     lst << commit << msg << date; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } else { | ||||||
|  |         qCritical() << "CUSTOMER_REPOSITORY" << m_customerRepository | ||||||
|  |                     << "DOES NOT EXIST"; | ||||||
|  |     } | ||||||
|  |     return lst; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  Zu beachten: wird eine datei neu hinzugefuegt (git add/commit) dann aber gleich | ||||||
|  |  wieder geloscht, so wird sie im diff nicht angezeigt. | ||||||
|  |  */ | ||||||
|  | std::optional<QStringList> GitClient::gitDiff(QString const &commits) { | ||||||
|  |     if (QDir(m_customerRepository).exists()) { | ||||||
|  |         // 409f198..6c22726 | ||||||
|  |         QString gitCommand("git diff --compact-summary "); | ||||||
|  |         gitCommand += commits; | ||||||
|  |  | ||||||
|  |         Command c(gitCommand); | ||||||
|  |         if (c.execute(m_customerRepository)) { // execute command in local customerRepo | ||||||
|  |             QString s = c.getCommandResult().trimmed(); | ||||||
|  |             Utils::printInfoMsg("GIT DIFF RESULT " + s); | ||||||
|  |  | ||||||
|  |             QStringList lines = Update::split(s, '\n'); | ||||||
|  |             QStringList fileNames; | ||||||
|  |             // each line has the format "etc/psa_config/DC2C_print01.json | 1 + | ||||||
|  |             // or the format            "etc/psa_config/DC2C_print01.json (new) | 1 + | ||||||
|  |             // the filenames are relativ to the repository | ||||||
|  |             for (int i = 0; i < lines.size(); ++i) { | ||||||
|  |                 QString const &line = lines.at(i); | ||||||
|  |                 int newIndex = line.indexOf("(new");    // for new files | ||||||
|  |                 int goneIndex = line.indexOf("(gone");  // for removed files | ||||||
|  |                 int modeIndex = line.indexOf("(mode"); | ||||||
|  |                 int pipeIndex = line.indexOf('|'); | ||||||
|  |                 if (newIndex != -1) { | ||||||
|  |                     QString file = line.left(newIndex).trimmed(); | ||||||
|  |                     qInfo() << "FILE (NEW)" << file; | ||||||
|  |                     fileNames << file; | ||||||
|  |                 } else | ||||||
|  |                 if (modeIndex != -1) { | ||||||
|  |                     QString const file = line.left(modeIndex).trimmed(); | ||||||
|  |                     qInfo() << "FILE (MODE)" << file; | ||||||
|  |                     fileNames << file; | ||||||
|  |                 } else | ||||||
|  |                 if (goneIndex != -1) { | ||||||
|  |                     QString const file = line.left(goneIndex).trimmed(); | ||||||
|  |                     qCritical() << "FILE (GONE)" << file; | ||||||
|  |                 } else | ||||||
|  |                 if (pipeIndex != -1) { | ||||||
|  |                     QString const file = line.left(pipeIndex).trimmed(); | ||||||
|  |                     qInfo() << "FILE (PIPE)" << file; | ||||||
|  |                     fileNames << file; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             if (!fileNames.isEmpty()) { | ||||||
|  |                 return fileNames; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     return std::nullopt; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool GitClient::gitFsck() { | ||||||
|  |     bool r = false; | ||||||
|  |     if (QDir(m_customerRepository).exists()) { | ||||||
|  |         Command c("git fsck"); | ||||||
|  |         if ((r = c.execute(m_customerRepository)) == false) { | ||||||
|  |             QString const &s = c.getCommandResult().trimmed(); | ||||||
|  |             Utils::printCriticalErrorMsg(QString("GIT FSCK FAILED: %1").arg(s)); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     return r; | ||||||
|  | } | ||||||
|  | /* | ||||||
|  |  Hat sich nichts geaendert, so werden auch keine Commits <>..<> angezeigt | ||||||
|  |  */ | ||||||
|  | std::optional<QString> GitClient::gitPull() { | ||||||
|  |     if (QDir(m_customerRepository).exists()) { | ||||||
|  |         qInfo() << "BRANCH NAME" << m_branchName; | ||||||
|  |  | ||||||
|  |         Command c("git pull"); | ||||||
|  |         if (c.execute(m_customerRepository)) { | ||||||
|  |             QString const s = c.getCommandResult().trimmed(); | ||||||
|  |             if (!s.isEmpty()) { | ||||||
|  |                 QStringList lines = Update::split(s, '\n'); | ||||||
|  |                 worker()->CONSOLE(lines) << Worker::UPDATE_STEP::UPDATE_REPOSITORY; | ||||||
|  |                 if (!lines.empty()) { | ||||||
|  |                     static const QRegularExpression alreadyUpToDate("^\\s*Already\\s+up\\s+to\\s+date.*$"); | ||||||
|  |                     if (std::none_of(lines.cbegin(), lines.cend(), | ||||||
|  |                         [](QString const &s) { return s.contains(alreadyUpToDate); })) { | ||||||
|  |                         int zoneNr = Utils::read1stLineOfFile("/mnt/system_data/zone_nr"); | ||||||
|  |                         m_branchName = (zoneNr != 0) ? QString("zg1/zone%1").arg(zoneNr) : "master"; | ||||||
|  |                         // lines can look like this: | ||||||
|  |                         // From https://git.mimbach49.de/GerhardHoffmann/customer_281 | ||||||
|  |                         //   41ec581..5d25ac3  master     -> origin/master | ||||||
|  |                         //   ff10f57..43530a1  zg1/zone1  -> origin/zg1/zone1 | ||||||
|  |                         //   6ed893f..5d9882c  zg1/zone2  -> origin/zg1/zone2 | ||||||
|  |                         //   4384d17..77045d8  zg1/zone3  -> origin/zg1/zone3 | ||||||
|  |                         //   89d2812..36a0d74  zg1/zone5  -> origin/zg1/zone5 | ||||||
|  |                         bool found = false; | ||||||
|  |                         for (int i=0; i < lines.size(); ++i) { | ||||||
|  |                             if (lines.at(i).contains(m_branchName)) { | ||||||
|  |                                 found = true; | ||||||
|  |                                 // 409f198..6c22726  zg1/zone1  -> origin/zg1/zone1 | ||||||
|  |                                 static QRegularExpression re("(^\\s*)([0-9A-Fa-f]+..[0-9A-Fa-f]+)(.*$)"); | ||||||
|  |                                 QRegularExpressionMatch match = re.match(lines.at(i)); | ||||||
|  |                                 if (match.hasMatch()) { | ||||||
|  |                                     if (re.captureCount() == 3) { // start with full match (0), then the other 3 matches | ||||||
|  |                                         QString const matchCaptured = match.captured(2); | ||||||
|  |                                         worker()->CONSOLE(QStringList(matchCaptured)) << Worker::UPDATE_STEP::UPDATE_REPOSITORY; | ||||||
|  |                                         return matchCaptured; | ||||||
|  |                                     } else { | ||||||
|  |                                         QStringList lst(QString("(wrong capture count (%1)").arg(re.captureCount())); | ||||||
|  |                                         worker()->GUI(lst) << (worker()->CONSOLE(lst) << Worker::UPDATE_STEP::UPDATE_REPOSITORY_FAILURE); | ||||||
|  |                                     } | ||||||
|  |                                 } else { | ||||||
|  |                                     QStringList lst("no regex-match for commits"); | ||||||
|  |                                     worker()->GUI(lst) << (worker()->CONSOLE(lst) << Worker::UPDATE_STEP::UPDATE_REPOSITORY_FAILURE); | ||||||
|  |                                 } | ||||||
|  |                             } | ||||||
|  |                         } | ||||||
|  |                         if (!found) { | ||||||
|  |                             QStringList lst(QString("unknown branch name ") + m_branchName); | ||||||
|  |                             worker()->GUI(lst) << (worker()->CONSOLE(lst) << Worker::UPDATE_STEP::UPDATE_REPOSITORY_FAILURE); | ||||||
|  |                         } | ||||||
|  |                     } else { | ||||||
|  |                         return "Already up to date"; | ||||||
|  |                     } | ||||||
|  |                 } else { | ||||||
|  |                     QStringList lst(QString("WRONG FORMAT FOR RESULT OF 'GIT PULL' ") + s); | ||||||
|  |                     worker()->GUI(lst) << (worker()->CONSOLE(lst) << Worker::UPDATE_STEP::UPDATE_REPOSITORY_FAILURE); | ||||||
|  |                 } | ||||||
|  |             } else { | ||||||
|  |                 QStringList lst("EMPTY RESULT FOR 'GIT PULL'"); | ||||||
|  |                 worker()->GUI(lst) << (worker()->CONSOLE(lst) << Worker::UPDATE_STEP::UPDATE_REPOSITORY_FAILURE); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } else { | ||||||
|  |         QStringList lst(QString("REPOSITORY ") + m_customerRepository + " DOES NOT EXIST"); | ||||||
|  |         worker()->GUI(lst) << (worker()->CONSOLE(lst) << Worker::UPDATE_STEP::UPDATE_REPOSITORY_FAILURE); | ||||||
|  |     } | ||||||
|  |     return std::nullopt; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | std::optional<QStringList> GitClient::gitMerge() { | ||||||
|  |     Command c("git merge"); | ||||||
|  |     if (c.execute(m_workingDirectory)) { | ||||||
|  |         QString s = c.getCommandResult(); | ||||||
|  |         QStringList lst = Update::split(s, '\n'); | ||||||
|  |         return lst; | ||||||
|  |     } | ||||||
|  |     return std::nullopt; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | QString GitClient::gitLastCommit(QString fileName) { | ||||||
|  |     if (QDir(m_customerRepository).exists()) { | ||||||
|  |         QString const filePath | ||||||
|  |             = QDir::cleanPath(m_customerRepository + QDir::separator() + fileName); | ||||||
|  |         if (QFile(filePath).exists()) { | ||||||
|  |             QString const gitCommand = QString("git log %1 | head -n 1").arg(fileName); | ||||||
|  |             Command c("bash"); | ||||||
|  |             if (c.execute(m_customerRepository, QStringList() << "-c" << gitCommand)) { | ||||||
|  |                 QString const r = c.getCommandResult(); | ||||||
|  |                 int const idx = r.indexOf("commit "); | ||||||
|  |                 if (idx != -1) { | ||||||
|  |                     return r.mid(idx + 8).trimmed(); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     return ""; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // fileName has to an absolute path | ||||||
|  | QString GitClient::gitBlob(QString fileName) { | ||||||
|  |     QFileInfo fi(fileName); | ||||||
|  |     if (fi.exists()) { | ||||||
|  |         QString const gitCommand = QString("git hash-object %1").arg(fileName); | ||||||
|  |         Command c(gitCommand); | ||||||
|  |         if (c.execute("/tmp")) { | ||||||
|  |             return c.getCommandResult().trimmed(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     return "N/A"; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | QString GitClient::gitCommitForBlob(QString blob) { | ||||||
|  |     if (QDir(m_customerRepository).exists()) { | ||||||
|  |         QString const gitCommand | ||||||
|  |             = QString("git whatchanged --all --find-object=%1 | head -n 1").arg(blob); | ||||||
|  |         Command c(gitCommand); | ||||||
|  |         if (c.execute(m_customerRepository)) { | ||||||
|  |             return c.getCommandResult(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     return ""; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool GitClient::gitIsFileTracked(QString fName) { | ||||||
|  |     if (QDir(m_customerRepository).exists()) { | ||||||
|  |         QString const gitCommand | ||||||
|  |             = QString("git ls-files --error-unmatch %1").arg(fName); | ||||||
|  |         Command c(gitCommand); | ||||||
|  |         return c.execute(m_customerRepository); | ||||||
|  |     } | ||||||
|  |     return false; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | //get_commit_for_blob () { | ||||||
|  | //    # search for the blob in all commits for the file(name) $1 | ||||||
|  | //    echo $(git log --all --pretty=format:%H -- $2   | | ||||||
|  | //           xargs -I{} bash -c "git ls-tree {} -- $2 | | ||||||
|  | //           grep -q $1 && echo -n {} && head -n 1") | ||||||
|  | //} | ||||||
							
								
								
									
										62
									
								
								git/git_client.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								git/git_client.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,62 @@ | |||||||
|  | #ifndef GIT_CLIENT_H_INCLUDED | ||||||
|  | #define GIT_CLIENT_H_INCLUDED | ||||||
|  |  | ||||||
|  | #include <QObject> | ||||||
|  | #include <QStringList> | ||||||
|  | #include <optional> | ||||||
|  |  | ||||||
|  | #include "process/command.h" | ||||||
|  | #include "ismas/ismas_client.h" | ||||||
|  |  | ||||||
|  | class Worker; | ||||||
|  | class GitClient : public QObject { | ||||||
|  |     Q_OBJECT | ||||||
|  |  | ||||||
|  |     Worker *m_worker; | ||||||
|  |     QString const m_repositoryPath; | ||||||
|  |     QString const m_customerNr; | ||||||
|  |     QString const m_workingDirectory; | ||||||
|  |     QString m_branchName; | ||||||
|  |     QString const m_customerRepository; | ||||||
|  |  | ||||||
|  |     bool copyGitConfigFromMaster(); | ||||||
|  |  | ||||||
|  |   public: | ||||||
|  |     explicit GitClient(QString const &customerNrStr, | ||||||
|  |                        QString const &repositoryPath, | ||||||
|  |                        QString const &workingDirectory = QCoreApplication::applicationDirPath(), | ||||||
|  |                        QString const &branchName = "master", | ||||||
|  |                        QObject *parent = 0); | ||||||
|  |  | ||||||
|  |     bool gitCloneCustomerRepository(); | ||||||
|  |     bool gitCheckoutBranch(); | ||||||
|  |     QStringList gitBranchNames(); | ||||||
|  |  | ||||||
|  |     QString const workingDirectory() const { return m_workingDirectory; } | ||||||
|  |     QString workingDirectory() { return m_workingDirectory; } | ||||||
|  |  | ||||||
|  |     QString const branchName() const { return m_branchName; } | ||||||
|  |     QString branchName() { return m_branchName; } | ||||||
|  |  | ||||||
|  |     QString repositoryPath() { return m_repositoryPath; } | ||||||
|  |     QString const repositoryPath() const { return m_repositoryPath; } | ||||||
|  |  | ||||||
|  |     bool gitCloneAndCheckoutBranch(); | ||||||
|  |  | ||||||
|  |     Worker *worker() { return m_worker; } | ||||||
|  |     Worker const *worker() const { return m_worker; } | ||||||
|  |  | ||||||
|  |     std::optional<QString> gitPull(); | ||||||
|  |     std::optional<QStringList> gitDiff(QString const &commit); | ||||||
|  |     std::optional<QStringList> gitMerge(); | ||||||
|  |  | ||||||
|  |     bool gitFsck(); | ||||||
|  |  | ||||||
|  |     QString gitLastCommit(QString fileName); | ||||||
|  |     QStringList gitShowReason(QString branchName); | ||||||
|  |     static QString gitBlob(QString fileName); | ||||||
|  |     QString gitCommitForBlob(QString blob); | ||||||
|  |     bool gitIsFileTracked(QString file2name); | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | #endif // GIT_CLIENT_H_INCLUDED | ||||||
							
								
								
									
										942
									
								
								ismas/ismas_client.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										942
									
								
								ismas/ismas_client.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,942 @@ | |||||||
|  | #include "ismas/ismas_client.h" | ||||||
|  | #include "utils.h" | ||||||
|  |  | ||||||
|  | #include <cstring> | ||||||
|  | #include <cstdio> | ||||||
|  |  | ||||||
|  | #include <errno.h> | ||||||
|  | #include <arpa/inet.h> // inet_addr() | ||||||
|  | #include <netdb.h> | ||||||
|  | #include <stdio.h> | ||||||
|  | #include <stdlib.h> | ||||||
|  | #include <netinet/in.h> | ||||||
|  | #include <netinet/tcp.h> | ||||||
|  | #include <string.h> | ||||||
|  | #include <strings.h> // bzero() | ||||||
|  | #include <sys/socket.h> | ||||||
|  | #include <unistd.h> // read(), write(), close() | ||||||
|  | #include <fcntl.h> | ||||||
|  |  | ||||||
|  |  | ||||||
|  | #include <QThread> | ||||||
|  | #include <QJsonDocument> | ||||||
|  | #include <QJsonObject> | ||||||
|  |  | ||||||
|  | #if 0 | ||||||
|  | ######################## | ||||||
|  | # Spec vom 27.10.2023: | ||||||
|  | # U0010 -> %-Werte | ||||||
|  | # U0001 -> 100% | ||||||
|  | # U0003 -> "FAIL" | ||||||
|  | # U0002 -> "" (OK -> WAIT state reset) | ||||||
|  | # ISMAS -> "WAIT" | ||||||
|  | ######################## | ||||||
|  | # | ||||||
|  | # $1: EVENT: U0001 update finished: 100% | ||||||
|  | #            U0002 reset TRG | ||||||
|  | #            U0003 error | ||||||
|  | #            U0010 for update process | ||||||
|  | # $2: PERCENT : "only for ISMAS: 0-100%", | ||||||
|  | # $3: RESULTCODE : "only for ISMAS", | ||||||
|  | #   0: Success | ||||||
|  | #   1: no Update nessesary | ||||||
|  | #   2: Backup failed | ||||||
|  | #   3: Package error/ Wrong package | ||||||
|  | #   4: Install Error | ||||||
|  | # $4: STEP : "running step (only for us): update_psa...", | ||||||
|  | # $5: STEP_RESULT : "error and result text", | ||||||
|  | # $6: VERSION : "opkg and conf info; what will be updated" | ||||||
|  | # | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #include <QDateTime> | ||||||
|  | #include <QDebug> | ||||||
|  |  | ||||||
|  | void IsmasClient::printDebugMessage(int port, | ||||||
|  |                                     QString const &clientIP, | ||||||
|  |                                     int clientPort, | ||||||
|  |                                     QString const &message) { | ||||||
|  | #if 0 | ||||||
|  |     Q_UNUSED(port); | ||||||
|  |     Q_UNUSED(clientIP); | ||||||
|  |     Q_UNUSED(clientPort); | ||||||
|  |     Q_UNUSED(message); | ||||||
|  | #else | ||||||
|  |     qDebug().noquote() | ||||||
|  |         << "\n" | ||||||
|  |         << "SEND-REQUEST-RECEIVE-RESPONSE ..." << "\n" | ||||||
|  |         << "hostname ........" << "127.0.0.1"  << "\n" | ||||||
|  |         << "port ............" << port << "\n" | ||||||
|  |         << "local address ..." << clientIP << "\n" | ||||||
|  |         << "local port ......" << clientPort << "\n" | ||||||
|  |         << message; | ||||||
|  | #endif | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void IsmasClient::printInfoMessage(int port, | ||||||
|  |                                    QString const &clientIP, | ||||||
|  |                                    int clientPort, | ||||||
|  |                                    QString const &message) { | ||||||
|  | #if 0 | ||||||
|  |     Q_UNUSED(port); | ||||||
|  |     Q_UNUSED(clientIP); | ||||||
|  |     Q_UNUSED(clientPort); | ||||||
|  |     Q_UNUSED(message); | ||||||
|  | #else | ||||||
|  |     qInfo().noquote() | ||||||
|  |         << "\n" | ||||||
|  |         << "SEND-REQUEST-RECEIVE-RESPONSE ..." << "\n" | ||||||
|  |         << "hostname ........" << "127.0.0.1"  << "\n" | ||||||
|  |         << "port ............" << port << "\n" | ||||||
|  |         << "local address ..." << clientIP << "\n" | ||||||
|  |         << "local port ......" << clientPort << "\n" | ||||||
|  |         << message; | ||||||
|  | #endif | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void IsmasClient::printErrorMessage(int port, | ||||||
|  |                                     QString const &clientIP, | ||||||
|  |                                     int clientPort, | ||||||
|  |                                     QString const &message) { | ||||||
|  |     qCritical().noquote() | ||||||
|  |         << "\n" | ||||||
|  |         << "SEND-REQUEST-RECEIVE-RESPONSE ..." << "\n" | ||||||
|  |         << "hostname ........" << "127.0.0.1"  << "\n" | ||||||
|  |         << "port ............" << port << "\n" | ||||||
|  |         << "local address ..." << clientIP << "\n" | ||||||
|  |         << "local port ......" << clientPort << "\n" | ||||||
|  |         << message; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | std::optional<QString> | ||||||
|  | IsmasClient::sendRequestReceiveResponse(int port, QString const &request) { | ||||||
|  |  | ||||||
|  |     qInfo() << "REQUEST" << request; | ||||||
|  |  | ||||||
|  |     int sockfd; | ||||||
|  |     int r; | ||||||
|  |     errno = 0; | ||||||
|  |     // socket create and verification | ||||||
|  |     if ((sockfd = ::socket(AF_INET, SOCK_STREAM, 0)) == -1) { | ||||||
|  |         qCritical().noquote() | ||||||
|  |             << "\n" | ||||||
|  |             << "SEND-REQUEST-RECEIVE-RESPONSE ..." << "\n" | ||||||
|  |             << "SOCKET CREATION FAILED (" << strerror(errno) << ")"; | ||||||
|  |         return std::nullopt; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     struct sockaddr_in servAddr; | ||||||
|  |     bzero(&servAddr, sizeof(servAddr)); | ||||||
|  |     // assign IP, PORT | ||||||
|  |     servAddr.sin_family = AF_INET; | ||||||
|  |     servAddr.sin_addr.s_addr = inet_addr("127.0.0.1"); | ||||||
|  |  | ||||||
|  |     servAddr.sin_port = htons(port); | ||||||
|  |     // connect the client socket to server socket | ||||||
|  |     if ((r = ::connect(sockfd, (struct sockaddr *)(&servAddr), sizeof(servAddr))) != 0) { | ||||||
|  |         qCritical().noquote() | ||||||
|  |             << "\n" | ||||||
|  |             << "SEND-REQUEST-RECEIVE-RESPONSE ..." << "\n" | ||||||
|  |             << "CONNECTION WITH SERVER FAILED (" << strerror(r) << ")"; | ||||||
|  |         ::close(sockfd); | ||||||
|  |         return std::nullopt; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     struct sockaddr_in clientAddr; | ||||||
|  |     bzero(&clientAddr, sizeof(clientAddr)); | ||||||
|  |     socklen_t sockLen = sizeof(clientAddr); | ||||||
|  |  | ||||||
|  |     char clientIP[16]; | ||||||
|  |     bzero(&clientIP, sizeof(clientIP)); | ||||||
|  |     getsockname(sockfd, (struct sockaddr *)(&clientAddr), &sockLen); | ||||||
|  |     inet_ntop(AF_INET, &clientAddr.sin_addr, clientIP, sizeof(clientIP)); | ||||||
|  |     unsigned int clientPort = ntohs(clientAddr.sin_port); | ||||||
|  |  | ||||||
|  |     printDebugMessage(port, clientIP, clientPort, QString("CONNECTED TO SERVER")); | ||||||
|  |  | ||||||
|  |     struct timeval tv; | ||||||
|  |     tv.tv_sec = 10;  /* 10 secs timeout for read and write */ | ||||||
|  |  | ||||||
|  |     struct linger so_linger; | ||||||
|  |     so_linger.l_onoff = 1; | ||||||
|  |     so_linger.l_linger = 0; | ||||||
|  |  | ||||||
|  |     int maxfdp1; | ||||||
|  |     fd_set rset; | ||||||
|  |     fd_set wset; | ||||||
|  |  | ||||||
|  |     setsockopt(sockfd, SOL_SOCKET, SO_LINGER, &so_linger, sizeof(so_linger)); | ||||||
|  |     // no reliable, but does not harm, as we use select() as well | ||||||
|  |     setsockopt(sockfd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)); | ||||||
|  |     setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)); | ||||||
|  |     int flag = 1; | ||||||
|  |     setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(int)); | ||||||
|  |  | ||||||
|  |     static char buf[1024*8]; | ||||||
|  |     bzero(buf, sizeof(buf)); | ||||||
|  |     int const bytesToWrite = strlen(request.toStdString().c_str()); | ||||||
|  |     strncpy(buf, request.toStdString().c_str(), sizeof(buf)-1); | ||||||
|  |  | ||||||
|  |     int loop = 0; | ||||||
|  |     int bytesWritten = 0; | ||||||
|  |     while (bytesWritten < bytesToWrite) { | ||||||
|  |         errno = 0; | ||||||
|  |         FD_ZERO(&wset); | ||||||
|  |         FD_SET(sockfd, &wset); | ||||||
|  |         maxfdp1 = sockfd + 1; | ||||||
|  |         tv.tv_sec = 60;  /* 60 secs timeout for read and write -> APISM cuts the connection after 30s */ | ||||||
|  |         tv.tv_usec = 0; | ||||||
|  |  | ||||||
|  |         int const w = select(maxfdp1, NULL, &wset, NULL, &tv); | ||||||
|  |         if (w < 0) { // error | ||||||
|  |             if (errno == EINTR) { | ||||||
|  |                 printErrorMessage(port, clientIP, clientPort, | ||||||
|  |                     QString("INTERRUPTED BY SIGNAL (1) (") + strerror(errno) + ")"); | ||||||
|  |                 continue; | ||||||
|  |             } else { | ||||||
|  |                 printErrorMessage(port, clientIP, clientPort, | ||||||
|  |                         QString("SELECT-ERROR (WRITE) %1(").arg(loop) + strerror(errno) + ")"); | ||||||
|  |                 ::close(sockfd); | ||||||
|  |                 return std::nullopt; | ||||||
|  |             } | ||||||
|  |         } else | ||||||
|  |         if (w == 0) { // timeout | ||||||
|  |             printErrorMessage(port, clientIP, clientPort, | ||||||
|  |                     QString("SELECT-TIMEOUT (WRITE) %1(").arg(loop) + strerror(errno) + ")"); | ||||||
|  |             if (++loop < 10) { | ||||||
|  |                 QThread::msleep(500); | ||||||
|  |                 continue; | ||||||
|  |             } | ||||||
|  |             ::close(sockfd); | ||||||
|  |             return std::nullopt; | ||||||
|  |         } else | ||||||
|  |         if (w > 0) { | ||||||
|  |             int n = ::sendto(sockfd, buf+bytesWritten, bytesToWrite-bytesWritten, 0, NULL, 0); | ||||||
|  |             if (n >= 0) { | ||||||
|  |                 bytesWritten += n; | ||||||
|  |             } else { | ||||||
|  |                 if (errno == EWOULDBLOCK) { | ||||||
|  |                     if (++loop < 10) { | ||||||
|  |                         QThread::msleep(500); | ||||||
|  |                         continue; | ||||||
|  |                     } | ||||||
|  |                     printErrorMessage(port, clientIP, clientPort, | ||||||
|  |                         QString("WRITE TIMEOUT %1(").arg(loop) + strerror(errno) + ")"); | ||||||
|  |                     ::close(sockfd); | ||||||
|  |                     return std::nullopt; | ||||||
|  |                 } else | ||||||
|  |                 if (errno == EINTR) { | ||||||
|  |                     printErrorMessage(port, clientIP, clientPort, | ||||||
|  |                         QString("WRITE INTERRUPTED BY SIGNAL (1) (") + strerror(errno) + ")"); | ||||||
|  |                     continue; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // DO NOT USE SHUTDOWN! APISM CAN NOT COPE WITH IT | ||||||
|  |     // errno = 0; | ||||||
|  |     // if (shutdown(sockfd, SHUT_WR) < 0) { | ||||||
|  |     //     printErrorMessage(port, clientIP, clientPort, | ||||||
|  |     //        QString("CANNOT CLOSE WRITING END (") + strerror(errno) + ")"); | ||||||
|  |     // } | ||||||
|  |  | ||||||
|  |     printInfoMessage(port, clientIP, clientPort, QString("MESSAGE SENT <<<") + buf + ">>>"); | ||||||
|  |  | ||||||
|  |     loop = 0; | ||||||
|  |     bzero(buf, sizeof(buf)); | ||||||
|  |     int bytesToRead = sizeof(buf)-1; | ||||||
|  |     int bytesRead = 0; | ||||||
|  |     while (bytesRead < bytesToRead) { | ||||||
|  |         errno = 0; | ||||||
|  |         FD_ZERO(&rset); | ||||||
|  |         FD_SET(sockfd, &rset); | ||||||
|  |         maxfdp1 = sockfd + 1; | ||||||
|  |         tv.tv_sec = 60;  /* 60 secs timeout for read and write */ | ||||||
|  |         tv.tv_usec = 0; | ||||||
|  |  | ||||||
|  |         QString const selectStart = QDateTime::currentDateTime().toString(Qt::ISODateWithMs); | ||||||
|  |  | ||||||
|  |         int const r = select(maxfdp1, &rset, NULL, NULL, &tv); | ||||||
|  |         if (r < 0) { // error | ||||||
|  |             if (errno == EINTR) { | ||||||
|  |                 printErrorMessage(port, clientIP, clientPort, | ||||||
|  |                     QString("INTERRUPTED BY SIGNAL (2) (") + strerror(errno) + ")"); | ||||||
|  |                 continue; | ||||||
|  |             } else { | ||||||
|  |                 printErrorMessage(port, clientIP, clientPort, | ||||||
|  |                         QString("SELECT-ERROR (READ) %1(").arg(loop) + strerror(errno) + ")"); | ||||||
|  |                 ::close(sockfd); | ||||||
|  |                 return std::nullopt; | ||||||
|  |             } | ||||||
|  |         } else | ||||||
|  |         if (r == 0) { // timeout | ||||||
|  |             printErrorMessage(port, clientIP, clientPort, | ||||||
|  |                     QString("SELECT-TIMEOUT (READ) %1(").arg(loop) + strerror(errno) + ")"); | ||||||
|  |             if (++loop < 10) { | ||||||
|  |                 QThread::msleep(500); | ||||||
|  |                 continue; | ||||||
|  |             } | ||||||
|  |             ::close(sockfd); | ||||||
|  |             return std::nullopt; | ||||||
|  |         } else | ||||||
|  |         if (r > 0) { | ||||||
|  |             if (FD_ISSET(sockfd, &rset)) { | ||||||
|  |                 int n = ::recvfrom(sockfd, buf+bytesRead, bytesToRead-bytesRead, | ||||||
|  |                                    0, NULL, NULL); | ||||||
|  |                 if (n > 0) { // | ||||||
|  |                     bytesRead += n; | ||||||
|  |                 } else | ||||||
|  |                 if (n == 0) { | ||||||
|  |                     // The return value will be 0 when the peer has performed an orderly shutdown. | ||||||
|  |                     printErrorMessage(port, clientIP, clientPort, | ||||||
|  |                         QString("PEER CLOSED CONNECTION (") + strerror(errno) + ") START AT" + | ||||||
|  |                                 selectStart + " NOW " + QDateTime::currentDateTime().toString(Qt::ISODateWithMs)); | ||||||
|  |                     ::close(sockfd); | ||||||
|  |                     return std::nullopt; | ||||||
|  |                 } else | ||||||
|  |                 if (n < 0) { | ||||||
|  |                     if (errno == EWOULDBLOCK) { // check just in case | ||||||
|  |                         if (++loop < 10) { | ||||||
|  |                             QThread::msleep(500); | ||||||
|  |                             continue; | ||||||
|  |                         } | ||||||
|  |                         printErrorMessage(port, clientIP, clientPort, | ||||||
|  |                                 QString("READ TIMEOUT %1(").arg(loop) + strerror(errno) + ")"); | ||||||
|  |                         ::close(sockfd); | ||||||
|  |                         return std::nullopt; | ||||||
|  |                     } | ||||||
|  |                     if (errno == EINTR) { | ||||||
|  |                         printErrorMessage(port, clientIP, clientPort, | ||||||
|  |                             QString("INTERRUPTED BY SIGNAL (2) (") + strerror(errno) + ")"); | ||||||
|  |                         continue; | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // printInfoMessage(port, clientIP, clientPort, QString("MESSAGE RECEIVED ") + buf); | ||||||
|  |         QString response(buf); | ||||||
|  |  | ||||||
|  |         if (int idx = response.indexOf("{\"error\":\"ISMAS is offline\"}")) { | ||||||
|  |             response = response.mid(0, idx); | ||||||
|  |         } else | ||||||
|  |         if (response.contains("RECORD")) { // RECORD SAVED or RECORD WRITE ABORTED | ||||||
|  |             printInfoMessage(port, clientIP, clientPort, QString("IGNORED '") + response + "' RESPONSE"); | ||||||
|  |             ::close(sockfd); | ||||||
|  |             return std::nullopt; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         QJsonParseError parseError; | ||||||
|  |         QJsonDocument document(QJsonDocument::fromJson(response.toUtf8(), &parseError)); | ||||||
|  |         if (parseError.error == QJsonParseError::NoError) { | ||||||
|  |             if (document.isObject()) { // done: received valid APISM response | ||||||
|  |                 printInfoMessage(port, clientIP, clientPort, | ||||||
|  |                    QString("VALID APISM RESPONSE .. \n") + response); | ||||||
|  |                 ::close(sockfd); | ||||||
|  |                 return response; | ||||||
|  |             } else { | ||||||
|  |                 printInfoMessage(port, clientIP, clientPort, | ||||||
|  |                    QString("CORRUPTED RESPONSE ") + response); | ||||||
|  |                 ::close(sockfd); | ||||||
|  |                 return std::nullopt; | ||||||
|  |             } | ||||||
|  |         } else { | ||||||
|  |             printDebugMessage(port, clientIP, clientPort, | ||||||
|  |                 QString("PARSE ERROR ") + response + " " + parseError.errorString()); | ||||||
|  |             ::close(sockfd); | ||||||
|  |             return std::nullopt; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     return std::nullopt; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | QString IsmasClient::updateNewsToIsmas(char const *event, | ||||||
|  |                                        int percent, | ||||||
|  |                                        int resultCode, | ||||||
|  |                                        char const *step, | ||||||
|  |                                        char const *step_result, | ||||||
|  |                                        char const *version) { | ||||||
|  |     char buf[1024]; | ||||||
|  |     memset(buf, 0, sizeof(buf)); | ||||||
|  |  | ||||||
|  |     QString const ts = QDateTime::currentDateTime().toString(Qt::ISODateWithMs); | ||||||
|  |     snprintf(buf, sizeof(buf)-1, | ||||||
|  |         "{" | ||||||
|  |             "\"REASON\":\"SW_UP\"," | ||||||
|  |             "\"TIMESTAMP\":\"%s\"," | ||||||
|  |             "\"EVENT_ID\":\"0\"," | ||||||
|  |             "\"EVENT\":\"%s\"," | ||||||
|  |             "\"EVENTSTATE\":1," | ||||||
|  |             "\"PARAMETER\": {" | ||||||
|  |                 "\"PERCENT\" : %d," | ||||||
|  |                 "\"RESULTCODE\" : %d," | ||||||
|  |                 "\"STEP\" : \"%s\"," | ||||||
|  |                 "\"STEP_RESULT\" : \"%s\"," | ||||||
|  |                 "\"VERSION\" : \"%s\"" | ||||||
|  |             "}" | ||||||
|  |         "}", ts.toStdString().c_str(), event, percent, resultCode, | ||||||
|  |              step, step_result, version); | ||||||
|  |     return buf; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | QString IsmasClient::errorBackendNotConnected(QString const &info, | ||||||
|  |                                               QString const &version) { | ||||||
|  |     return updateNewsToIsmas("U0003", | ||||||
|  |                              m_progressInPercent, | ||||||
|  |                              RESULT_CODE::INSTALL_ERROR, | ||||||
|  |                              "CHECK BACKEND CONNECTIVITY", | ||||||
|  |                              info.toStdString().c_str(), | ||||||
|  |                              version.toStdString().c_str()); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | QString IsmasClient::errorGitClone(QString const &info, | ||||||
|  |                                    QString const &version) { | ||||||
|  |     return updateNewsToIsmas("U0003", | ||||||
|  |                              m_progressInPercent, | ||||||
|  |                              RESULT_CODE::INSTALL_ERROR, | ||||||
|  |                              "CLONE CUSTOMER REPOSITORY FAILED", | ||||||
|  |                              info.toStdString().c_str(), | ||||||
|  |                              version.toStdString().c_str()); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | QString IsmasClient::backendConnected(QString const &info, | ||||||
|  |                                       QString const &version) { | ||||||
|  |     return updateNewsToIsmas("U0010", | ||||||
|  |                              m_progressInPercent, | ||||||
|  |                              RESULT_CODE::SUCCESS, | ||||||
|  |                              "CHECK BACKEND CONNECTIVITY", | ||||||
|  |                              info.toStdString().c_str(), | ||||||
|  |                              version.toStdString().c_str()); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | QString IsmasClient::execOpkgCommand(QString const &info, | ||||||
|  |                                      QString const &version) { | ||||||
|  |     return updateNewsToIsmas("U0010", | ||||||
|  |                              m_progressInPercent, | ||||||
|  |                              RESULT_CODE::SUCCESS, | ||||||
|  |                              "EXECUTE OPKG COMMAND", | ||||||
|  |                              info.toStdString().c_str(), | ||||||
|  |                              version.toStdString().c_str()); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | QString IsmasClient::rsyncFile(QString const &info, QString const &version) { | ||||||
|  |     return updateNewsToIsmas("U0010", | ||||||
|  |                              m_progressInPercent, | ||||||
|  |                              RESULT_CODE::SUCCESS, | ||||||
|  |                              "RSYNC FILE", | ||||||
|  |                              info.toStdString().c_str(), | ||||||
|  |                              version.toStdString().c_str()); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | QString IsmasClient::updateTriggerSet(QString const &info, QString const &version) { | ||||||
|  |     return updateNewsToIsmas("U0010", | ||||||
|  |                              m_progressInPercent, | ||||||
|  |                              RESULT_CODE::SUCCESS, | ||||||
|  |                              "CHECK UPDATE TRIGGER", | ||||||
|  |                              info.toStdString().c_str(), | ||||||
|  |                              version.toStdString().c_str()); | ||||||
|  |  | ||||||
|  | } | ||||||
|  |  | ||||||
|  | QString IsmasClient::errorUpdateTrigger(QString const &info, QString const &version) { | ||||||
|  |     return updateNewsToIsmas("U0003", | ||||||
|  |                              m_progressInPercent, | ||||||
|  |                              RESULT_CODE::INSTALL_ERROR, | ||||||
|  |                              "CHECK UPDATE TRIGGER", | ||||||
|  |                              info.toStdString().c_str(), | ||||||
|  |                              version.toStdString().c_str()); | ||||||
|  |  | ||||||
|  | } | ||||||
|  |  | ||||||
|  | QString IsmasClient::updateOfPSASendVersion(PSAInstalled const &psa) { | ||||||
|  |     //static int const constexpr SIZE = 4096*8; | ||||||
|  |     static char buf[4096*2]; | ||||||
|  |     memset(buf, 0, sizeof(buf)); | ||||||
|  |  | ||||||
|  |     // local data="#M=APISM#C=CMD_SENDVERSION#J= | ||||||
|  |     snprintf(buf, sizeof(buf)-1, | ||||||
|  |         "{" | ||||||
|  |             "\"VERSION_INFO\" : {" | ||||||
|  |                 "\"REASON\":\"%s\"," | ||||||
|  |                 "\"CREATED\":\"%s\"," | ||||||
|  |                 "\"HASH\":\"%s\"" | ||||||
|  |             "}," | ||||||
|  |             "\"TARIFF\" : {" | ||||||
|  |                 "\"VERSION\" : \"%s\"," | ||||||
|  |                 "\"PROJECT\" : \"%s\"," | ||||||
|  |                 "\"ZONE\" : %d," | ||||||
|  |                 "\"INFO\" : \"%s\"," | ||||||
|  |                 "\"BLOB\" : \"%s\"," | ||||||
|  |                 "\"LAST-COMMIT\" : \"%s\"," | ||||||
|  |                 "\"SIZE\" : %d," | ||||||
|  |                 "\"LOADED\" : \"%s\"" | ||||||
|  |             "}," | ||||||
|  |             "\"OPKG_COMMANDS\" : {" | ||||||
|  |                 "\"BLOB\" : \"%s\"," | ||||||
|  |                 "\"LAST-COMMIT\" : \"%s\"," | ||||||
|  |                 "\"SIZE\" : %d," | ||||||
|  |                 "\"LOADED\" : \"%s\"" | ||||||
|  |             "}," | ||||||
|  |             "\"JSON\" : {" | ||||||
|  |                 "\"DC2C_CASH\" : {" | ||||||
|  |                     "\"BLOB\" : \"%s\"," | ||||||
|  |                     "\"SIZE\" : %d" | ||||||
|  |                 "}," | ||||||
|  |                 "\"DC2C_CONF\" : {" | ||||||
|  |                     "\"BLOB\" : \"%s\"," | ||||||
|  |                     "\"SIZE\" : %d" | ||||||
|  |                 "}," | ||||||
|  |                 "\"DC2C_DEVICE\" : {" | ||||||
|  |                     "\"BLOB\" : \"%s\"," | ||||||
|  |                     "\"SIZE\" : %d" | ||||||
|  |                 "}," | ||||||
|  |                 "\"DC2C_PRINT_01\" : {" | ||||||
|  |                     "\"BLOB\" : \"%s\"," | ||||||
|  |                     "\"SIZE\" : %d" | ||||||
|  |                 "}," | ||||||
|  |                 "\"DC2C_PRINT_02\" : {" | ||||||
|  |                     "\"BLOB\" : \"%s\"," | ||||||
|  |                     "\"SIZE\" : %d" | ||||||
|  |                 "}," | ||||||
|  |                 "\"DC2C_PRINT_03\" : {" | ||||||
|  |                     "\"BLOB\" : \"%s\"," | ||||||
|  |                     "\"SIZE\" : %d" | ||||||
|  |                 "}," | ||||||
|  |                 "\"DC2C_PRINT_04\" : {" | ||||||
|  |                     "\"BLOB\" : \"%s\"," | ||||||
|  |                     "\"SIZE\" : %d" | ||||||
|  |                 "}," | ||||||
|  |                 "\"DC2C_PRINT_05\" : {" | ||||||
|  |                     "\"BLOB\" : \"%s\"," | ||||||
|  |                     "\"SIZE\" : %d" | ||||||
|  |                 "}," | ||||||
|  |                 "\"DC2C_PRINT_06\" : {" | ||||||
|  |                     "\"BLOB\" : \"%s\"," | ||||||
|  |                     "\"SIZE\" : %d" | ||||||
|  |                 "}," | ||||||
|  |                 "\"DC2C_PRINT_07\" : {" | ||||||
|  |                     "\"BLOB\" : \"%s\"," | ||||||
|  |                     "\"SIZE\" : %d" | ||||||
|  |                 "}," | ||||||
|  |                 "\"DC2C_PRINT_08\" : {" | ||||||
|  |                     "\"BLOB\" : \"%s\"," | ||||||
|  |                     "\"SIZE\" : %d" | ||||||
|  |                 "}," | ||||||
|  |                 "\"DC2C_PRINT_09\" : {" | ||||||
|  |                     "\"BLOB\" : \"%s\"," | ||||||
|  |                     "\"SIZE\" : %d" | ||||||
|  |                 "}," | ||||||
|  |                 "\"DC2C_PRINT_10\" : {" | ||||||
|  |                     "\"BLOB\" : \"%s\"," | ||||||
|  |                     "\"SIZE\" : %d" | ||||||
|  |                 "}," | ||||||
|  |                 "\"DC2C_PRINT_11\" : {" | ||||||
|  |                     "\"BLOB\" : \"%s\"," | ||||||
|  |                     "\"SIZE\" : %d" | ||||||
|  |                 "}," | ||||||
|  |                 "\"DC2C_PRINT_12\" : {" | ||||||
|  |                     "\"BLOB\" : \"%s\"," | ||||||
|  |                     "\"SIZE\" : %d" | ||||||
|  |                 "}," | ||||||
|  |                 "\"DC2C_PRINT_13\" : {" | ||||||
|  |                     "\"BLOB\" : \"%s\"," | ||||||
|  |                     "\"SIZE\" : %d" | ||||||
|  |                 "}," | ||||||
|  |                 "\"DC2C_PRINT_14\" : {" | ||||||
|  |                     "\"BLOB\" : \"%s\"," | ||||||
|  |                     "\"SIZE\" : %d" | ||||||
|  |                 "}," | ||||||
|  |                 "\"DC2C_PRINT_15\" : {" | ||||||
|  |                     "\"BLOB\" : \"%s\"," | ||||||
|  |                     "\"SIZE\" : %d" | ||||||
|  |                 "}," | ||||||
|  |                 "\"DC2C_PRINT_16\" : {" | ||||||
|  |                     "\"BLOB\" : \"%s\"," | ||||||
|  |                     "\"SIZE\" : %d" | ||||||
|  |                 "}," | ||||||
|  |                 "\"DC2C_PRINT_17\" : {" | ||||||
|  |                     "\"BLOB\" : \"%s\"," | ||||||
|  |                     "\"SIZE\" : %d" | ||||||
|  |                 "}," | ||||||
|  |                 "\"DC2C_PRINT_18\" : {" | ||||||
|  |                     "\"BLOB\" : \"%s\"," | ||||||
|  |                     "\"SIZE\" : %d" | ||||||
|  |                 "}," | ||||||
|  |                 "\"DC2C_PRINT_19\" : {" | ||||||
|  |                     "\"BLOB\" : \"%s\"," | ||||||
|  |                     "\"SIZE\" : %d" | ||||||
|  |                 "}," | ||||||
|  |                 "\"DC2C_PRINT_20\" : {" | ||||||
|  |                     "\"BLOB\" : \"%s\"," | ||||||
|  |                     "\"SIZE\" : %d" | ||||||
|  |                 "}," | ||||||
|  |                 "\"DC2C_PRINT_21\" : {" | ||||||
|  |                     "\"BLOB\" : \"%s\"," | ||||||
|  |                     "\"SIZE\" : %d" | ||||||
|  |                 "}," | ||||||
|  |                 "\"DC2C_PRINT_22\" : {" | ||||||
|  |                     "\"BLOB\" : \"%s\"," | ||||||
|  |                     "\"SIZE\" : %d" | ||||||
|  |                 "}," | ||||||
|  |                 "\"DC2C_PRINT_23\" : {" | ||||||
|  |                     "\"BLOB\" : \"%s\"," | ||||||
|  |                     "\"SIZE\" : %d" | ||||||
|  |                 "}," | ||||||
|  |                 "\"DC2C_PRINT_24\" : {" | ||||||
|  |                     "\"BLOB\" : \"%s\"," | ||||||
|  |                     "\"SIZE\" : %d" | ||||||
|  |                 "}," | ||||||
|  |                 "\"DC2C_PRINT_25\" : {" | ||||||
|  |                     "\"BLOB\" : \"%s\"," | ||||||
|  |                     "\"SIZE\" : %d" | ||||||
|  |                 "}," | ||||||
|  |                 "\"DC2C_PRINT_26\" : {" | ||||||
|  |                     "\"BLOB\" : \"%s\"," | ||||||
|  |                     "\"SIZE\" : %d" | ||||||
|  |                 "}," | ||||||
|  |                 "\"DC2C_PRINT_27\" : {" | ||||||
|  |                     "\"BLOB\" : \"%s\"," | ||||||
|  |                     "\"SIZE\" : %d" | ||||||
|  |                 "}," | ||||||
|  |                 "\"DC2C_PRINT_28\" : {" | ||||||
|  |                     "\"BLOB\" : \"%s\"," | ||||||
|  |                     "\"SIZE\" : %d" | ||||||
|  |                 "}," | ||||||
|  |                 "\"DC2C_PRINT_29\" : {" | ||||||
|  |                     "\"BLOB\" : \"%s\"," | ||||||
|  |                     "\"SIZE\" : %d" | ||||||
|  |                 "}," | ||||||
|  |                 "\"DC2C_PRINT_30\" : {" | ||||||
|  |                     "\"BLOB\" : \"%s\"," | ||||||
|  |                     "\"SIZE\" : %d" | ||||||
|  |                 "}," | ||||||
|  |                 "\"DC2C_PRINT_31\" : {" | ||||||
|  |                     "\"BLOB\" : \"%s\"," | ||||||
|  |                     "\"SIZE\" : %d" | ||||||
|  |                 "}," | ||||||
|  |                 "\"DC2C_PRINT_32\" : {" | ||||||
|  |                     "\"BLOB\" : \"%s\"," | ||||||
|  |                     "\"SIZE\" : %d" | ||||||
|  |                 "}" | ||||||
|  |             "}," | ||||||
|  |             "\"HARDWARE\" : {" | ||||||
|  |                 "\"DEVICES\" : [\"PTU5\", \"DC\", \"PRINTER\", \"BNA\"]" | ||||||
|  |             "}," | ||||||
|  |             "\"OS\" : {" | ||||||
|  |                 "\"Linux\": \"%s\"" | ||||||
|  |             "}," | ||||||
|  |             "\"CONFIG\" : {" | ||||||
|  |                 "\"PTU5\" : {" | ||||||
|  |                     "\"CPU_SERIAL\" : \"%s\"" | ||||||
|  |                 "}," | ||||||
|  |                 "\"DC\" : {" | ||||||
|  |                     "\"HW-VERSION\" : \"%s\"," | ||||||
|  |                     "\"SW-VERSION\" : \"%s\"," | ||||||
|  |                     "\"SIZE\" : %d," | ||||||
|  |                     "\"GITBLOB\" : \"%s\"," | ||||||
|  |                     "\"GITLASTCOMMIT\" : \"%s\"" | ||||||
|  |                 "}," | ||||||
|  |                 "\"PRINTER\" : {" | ||||||
|  |                 "}," | ||||||
|  |                 "\"BNA\" : {" | ||||||
|  |                 "}" | ||||||
|  |             "}," | ||||||
|  |             "\"SOFTWARE\": {" | ||||||
|  |                 "\"APISM\" : {" | ||||||
|  |                     "\"VERSION\" : \"%s\"" | ||||||
|  |                 "}," | ||||||
|  |                 "\"ATBQT\" : {" | ||||||
|  |                     "\"VERSION\" : \"%s\"" | ||||||
|  |                 "}," | ||||||
|  |                 "\"ATB-UPDATE-TOOL\" : {" | ||||||
|  |                     "\"VERSION\" : \"%s\"" | ||||||
|  |                 "}" | ||||||
|  |             "}," | ||||||
|  |             "\"PLUGINS\" : {" | ||||||
|  |                 "\"libATBDeviceControllerPlugin.so\" : {" | ||||||
|  |                     "\"VERSION\" : \"%s\"" | ||||||
|  |                 "}," | ||||||
|  |                 "\"libIngenicoISelf_CCPlugin.so\" : {" | ||||||
|  |                     "\"VERSION\" : \"%s\"" | ||||||
|  |                 "}," | ||||||
|  |                 "\"libMOBILISIS_CalculatePricePlugin.so\" : {" | ||||||
|  |                     "\"VERSION\" : \"%s\"" | ||||||
|  |                 "}," | ||||||
|  |                 "\"libMOBILISIS_CalculatePricePlugin_ConfigUi.so\" : {" | ||||||
|  |                     "\"VERSION\" : \"%s\"" | ||||||
|  |                 "}," | ||||||
|  |                 "\"libPRM_CalculatePricePlugin.so\" : {" | ||||||
|  |                     "\"VERSION\" : \"%s\"" | ||||||
|  |                 "}," | ||||||
|  |                 "\"libPRM_CalculatePricePlugin_ConfigUi.so\" : {" | ||||||
|  |                     "\"VERSION\" : \"%s\"" | ||||||
|  |                 "}," | ||||||
|  |                 "\"libTCP_ZVT_CCPlugin.so\" : {" | ||||||
|  |                     "\"VERSION\" : \"%s\"" | ||||||
|  |                 "}" | ||||||
|  |             "}" | ||||||
|  |         "}", | ||||||
|  |         psa.versionInfo.reason.toStdString().c_str(), | ||||||
|  |         psa.versionInfo.created.toStdString().c_str(), | ||||||
|  |         psa.versionInfo.lastCommit.toStdString().c_str(), | ||||||
|  |  | ||||||
|  |         psa.tariff.version.toStdString().c_str(), | ||||||
|  |         psa.tariff.project.toStdString().c_str(), | ||||||
|  |         psa.tariff.zone, | ||||||
|  |         psa.tariff.info.toStdString().c_str(), | ||||||
|  |         psa.tariff.blob.toStdString().c_str(), | ||||||
|  |         psa.tariff.lastCommit.toStdString().c_str(), | ||||||
|  |         psa.tariff.size, | ||||||
|  |         psa.tariff.loadTime.toStdString().c_str(), | ||||||
|  |  | ||||||
|  |         psa.opkg.blob.toStdString().c_str(), | ||||||
|  |         psa.opkg.lastCommit.toStdString().c_str(), | ||||||
|  |         psa.opkg.size, | ||||||
|  |         psa.opkg.loadTime.toStdString().c_str(), | ||||||
|  |  | ||||||
|  |         psa.cash.blob.toStdString().c_str(), | ||||||
|  |         psa.cash.size, | ||||||
|  |         psa.conf.blob.toStdString().c_str(), | ||||||
|  |         psa.conf.size, | ||||||
|  |         psa.device.blob.toStdString().c_str(), | ||||||
|  |         psa.device.size, | ||||||
|  |  | ||||||
|  |         psa.print[0].blob.toStdString().c_str(), | ||||||
|  |         psa.print[0].size, | ||||||
|  |         psa.print[1].blob.toStdString().c_str(), | ||||||
|  |         psa.print[1].size, | ||||||
|  |         psa.print[2].blob.toStdString().c_str(), | ||||||
|  |         psa.print[2].size, | ||||||
|  |         psa.print[3].blob.toStdString().c_str(), | ||||||
|  |         psa.print[3].size, | ||||||
|  |         psa.print[4].blob.toStdString().c_str(), | ||||||
|  |         psa.print[4].size, | ||||||
|  |         psa.print[5].blob.toStdString().c_str(), | ||||||
|  |         psa.print[5].size, | ||||||
|  |         psa.print[6].blob.toStdString().c_str(), | ||||||
|  |         psa.print[6].size, | ||||||
|  |         psa.print[7].blob.toStdString().c_str(), | ||||||
|  |         psa.print[7].size, | ||||||
|  |         psa.print[8].blob.toStdString().c_str(), | ||||||
|  |         psa.print[8].size, | ||||||
|  |         psa.print[9].blob.toStdString().c_str(), | ||||||
|  |         psa.print[9].size, | ||||||
|  |         psa.print[10].blob.toStdString().c_str(), | ||||||
|  |         psa.print[10].size, | ||||||
|  |         psa.print[11].blob.toStdString().c_str(), | ||||||
|  |         psa.print[11].size, | ||||||
|  |         psa.print[12].blob.toStdString().c_str(), | ||||||
|  |         psa.print[12].size, | ||||||
|  |         psa.print[13].blob.toStdString().c_str(), | ||||||
|  |         psa.print[13].size, | ||||||
|  |         psa.print[14].blob.toStdString().c_str(), | ||||||
|  |         psa.print[14].size, | ||||||
|  |         psa.print[15].blob.toStdString().c_str(), | ||||||
|  |         psa.print[15].size, | ||||||
|  |         psa.print[16].blob.toStdString().c_str(), | ||||||
|  |         psa.print[16].size, | ||||||
|  |         psa.print[17].blob.toStdString().c_str(), | ||||||
|  |         psa.print[17].size, | ||||||
|  |         psa.print[18].blob.toStdString().c_str(), | ||||||
|  |         psa.print[18].size, | ||||||
|  |         psa.print[19].blob.toStdString().c_str(), | ||||||
|  |         psa.print[19].size, | ||||||
|  |         psa.print[20].blob.toStdString().c_str(), | ||||||
|  |         psa.print[20].size, | ||||||
|  |         psa.print[21].blob.toStdString().c_str(), | ||||||
|  |         psa.print[21].size, | ||||||
|  |         psa.print[22].blob.toStdString().c_str(), | ||||||
|  |         psa.print[22].size, | ||||||
|  |         psa.print[23].blob.toStdString().c_str(), | ||||||
|  |         psa.print[23].size, | ||||||
|  |         psa.print[24].blob.toStdString().c_str(), | ||||||
|  |         psa.print[24].size, | ||||||
|  |         psa.print[25].blob.toStdString().c_str(), | ||||||
|  |         psa.print[25].size, | ||||||
|  |         psa.print[26].blob.toStdString().c_str(), | ||||||
|  |         psa.print[26].size, | ||||||
|  |         psa.print[27].blob.toStdString().c_str(), | ||||||
|  |         psa.print[27].size, | ||||||
|  |         psa.print[28].blob.toStdString().c_str(), | ||||||
|  |         psa.print[28].size, | ||||||
|  |         psa.print[29].blob.toStdString().c_str(), | ||||||
|  |         psa.print[29].size, | ||||||
|  |         psa.print[30].blob.toStdString().c_str(), | ||||||
|  |         psa.print[30].size, | ||||||
|  |         psa.print[31].blob.toStdString().c_str(), | ||||||
|  |         psa.print[31].size, | ||||||
|  |  | ||||||
|  |         psa.hw.linuxVersion.toStdString().c_str(), | ||||||
|  |         psa.hw.cpuSerial.toStdString().c_str(), | ||||||
|  |  | ||||||
|  |         psa.dc.versionHW.toStdString().c_str(), | ||||||
|  |         psa.dc.versionSW.toStdString().c_str(), | ||||||
|  |         psa.dc.size, | ||||||
|  |         psa.dc.gitBlob.toStdString().c_str(), | ||||||
|  |         psa.dc.gitLastCommit.toStdString().c_str(), | ||||||
|  |  | ||||||
|  |         psa.sw.apismVersion.toStdString().c_str(), | ||||||
|  |         psa.sw.atbQTVersion.toStdString().c_str(), | ||||||
|  |         psa.sw.atbUpdateToolVersion.toStdString().c_str(), | ||||||
|  |  | ||||||
|  |         psa.pluginVersion.deviceController.toStdString().c_str(), | ||||||
|  |         psa.pluginVersion.ingenicoISelfCC.toStdString().c_str(), | ||||||
|  |         psa.pluginVersion.mobilisisCalculatePrice.toStdString().c_str(), | ||||||
|  |         psa.pluginVersion.mobilisisCalculatePriceConfigUi.toStdString().c_str(), | ||||||
|  |         psa.pluginVersion.prmCalculatePrice.toStdString().c_str(), | ||||||
|  |         psa.pluginVersion.prmCalculatePriceConfigUi.toStdString().c_str(), | ||||||
|  |         psa.pluginVersion.tcpZVT.toStdString().c_str()); | ||||||
|  |  | ||||||
|  |     qInfo() << buf; | ||||||
|  |  | ||||||
|  |     return buf; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | QString IsmasClient::updateOfPSAContinues(QString currentStage, | ||||||
|  |                                           QString currentStageInfo, | ||||||
|  |                                           QString const &version) { | ||||||
|  |     return updateNewsToIsmas("U0010", | ||||||
|  |                              m_progressInPercent, | ||||||
|  |                              RESULT_CODE::SUCCESS, | ||||||
|  |                              currentStage.toStdString().c_str(), | ||||||
|  |                              currentStageInfo.toStdString().c_str(), | ||||||
|  |                              version.toStdString().c_str()); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | QString IsmasClient::updateOfPSAStarted(QString const &version) { | ||||||
|  |     return updateNewsToIsmas("U0010", | ||||||
|  |                              m_progressInPercent, | ||||||
|  |                              RESULT_CODE::SUCCESS, | ||||||
|  |                              "START", | ||||||
|  |                              "detected WAIT state: start update process", | ||||||
|  |                              version.toStdString().c_str()); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | QString IsmasClient::checkoutBranch(QString const &info, QString const &version) { | ||||||
|  |     return updateNewsToIsmas("U0010", | ||||||
|  |                              m_progressInPercent, | ||||||
|  |                              RESULT_CODE::SUCCESS, | ||||||
|  |                              "BRANCH-CHECKOUT", | ||||||
|  |                              info.toStdString().c_str(), | ||||||
|  |                              version.toStdString().c_str()); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | QString IsmasClient::cloneAndCheckoutCustomerRepository(QString const &info, QString const &version) { // clone and checkout customer repository | ||||||
|  |     return updateNewsToIsmas("U0010", | ||||||
|  |                              m_progressInPercent, | ||||||
|  |                              RESULT_CODE::SUCCESS, | ||||||
|  |                              "CLONE-CHECKOUT", | ||||||
|  |                              info.toStdString().c_str(), | ||||||
|  |                              version.toStdString().c_str()); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | QString IsmasClient::gitFetch(QString const &info, QString const &version) { | ||||||
|  |     return updateNewsToIsmas("U0010", | ||||||
|  |                              m_progressInPercent, | ||||||
|  |                              RESULT_CODE::SUCCESS, | ||||||
|  |                              "GIT-FETCH", | ||||||
|  |                              info.toStdString().c_str(), | ||||||
|  |                              version.toStdString().c_str()); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | QString IsmasClient::errorGitFetch(int resultCode, QString const &info, QString const &version) { | ||||||
|  |     return updateNewsToIsmas("U0003", | ||||||
|  |                              m_progressInPercent, | ||||||
|  |                              resultCode, | ||||||
|  |                              "GIT-FETCH-FAILED", | ||||||
|  |                              info.toStdString().c_str(), | ||||||
|  |                              version.toStdString().c_str()); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | QString IsmasClient::updateOfPSAActivated(QString const &version) {   // sent even after success | ||||||
|  |     m_progressInPercent = 0; | ||||||
|  |     return updateNewsToIsmas("U0002", | ||||||
|  |                              m_progressInPercent, | ||||||
|  |                              RESULT_CODE::SUCCESS, | ||||||
|  |                              "UPDATE ACTIVATED", | ||||||
|  |                              "reset WAIT state", | ||||||
|  |                              version.toStdString().c_str()); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | QString IsmasClient::updateOfPSASucceeded(QString const &version) { | ||||||
|  |     m_progressInPercent = 100; | ||||||
|  |     return updateNewsToIsmas("U0001", | ||||||
|  |                              m_progressInPercent, | ||||||
|  |                              RESULT_CODE::SUCCESS, | ||||||
|  |                              "UPDATE SUCCESS", | ||||||
|  |                              "update process succeeded", | ||||||
|  |                              version.toStdString().c_str()); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | QString IsmasClient::sanityCheckFailed(int resultCode, QString reason, QString const &version) { | ||||||
|  |     return updateNewsToIsmas("U0003", | ||||||
|  |                              m_progressInPercent, | ||||||
|  |                              resultCode, | ||||||
|  |                              "SANITY-CHECK-FAILED", | ||||||
|  |                              reason.toStdString().c_str(), | ||||||
|  |                              version.toStdString().c_str()); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | QString IsmasClient::jsonParseFailed(int resultCode, QString reason, QString const &version) { | ||||||
|  |     return updateNewsToIsmas("U0003", | ||||||
|  |                              m_progressInPercent, | ||||||
|  |                              resultCode, | ||||||
|  |                              "JSON-PARSE-ERROR", | ||||||
|  |                              reason.toStdString().c_str(), | ||||||
|  |                              version.toStdString().c_str()); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | std::optional<QString> IsmasClient::finalResult(int resultCode, | ||||||
|  |                                                 QString reason, | ||||||
|  |                                                 QString const &version) { | ||||||
|  |     Q_UNUSED(resultCode); | ||||||
|  |     Q_UNUSED(reason); | ||||||
|  |     Q_UNUSED(version); | ||||||
|  |  | ||||||
|  |     /* | ||||||
|  |     m_progressInPercent = 100; | ||||||
|  |     if (resultCode == RESULT_CODE::SUCCESS) { | ||||||
|  |         return updateNewsToIsmas("U0002", | ||||||
|  |                                  m_progressInPercent, | ||||||
|  |                                  resultCode, | ||||||
|  |                                  "FINAL-UPDATE-RESULT", | ||||||
|  |                                  reason.toStdString().c_str(), | ||||||
|  |                                  version.toStdString().c_str()); | ||||||
|  |     } | ||||||
|  |     if (resultCode == RESULT_CODE::INSTALL_ERROR) { | ||||||
|  |         return updateNewsToIsmas("U0003", | ||||||
|  |                                  m_progressInPercent, | ||||||
|  |                                  resultCode, | ||||||
|  |                                  "FINAL-UPDATE-RESULT", | ||||||
|  |                                  reason.toStdString().c_str(), | ||||||
|  |                                  version.toStdString().c_str()); | ||||||
|  |     } | ||||||
|  |     */ | ||||||
|  |     return std::nullopt; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | QString IsmasClient::updateOfPSAFailed(int resultCode, QString step, | ||||||
|  |                                        QString reason, QString const &version) { | ||||||
|  |     return updateNewsToIsmas("U0003", | ||||||
|  |                              m_progressInPercent, | ||||||
|  |                              resultCode, | ||||||
|  |                              step.toStdString().c_str(), | ||||||
|  |                              reason.toStdString().c_str(), | ||||||
|  |                              version.toStdString().c_str()); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | char const *IsmasClient::reason[REASON::ENTRIES] = { | ||||||
|  |     "TIME-TRIGGERED", "SERVICE", "DEV-TEST" | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | QString IsmasClient::getReasonForLastSendVersion() { | ||||||
|  |     QString const &parentName = Utils::getParentName(); | ||||||
|  |     if (parentName == "ATBQT") { | ||||||
|  |         return reason[REASON::SERVICE]; | ||||||
|  |     } | ||||||
|  |     if (parentName == "systemd") { | ||||||
|  |         return reason[REASON::TIME_TRIGGERED]; | ||||||
|  |     } | ||||||
|  |     return reason[REASON::DEV_TEST]; | ||||||
|  | } | ||||||
							
								
								
									
										208
									
								
								ismas/ismas_client.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										208
									
								
								ismas/ismas_client.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,208 @@ | |||||||
|  | #ifndef ISMAS_CLIENT_H_INCLUDED | ||||||
|  | #define ISMAS_CLIENT_H_INCLUDED | ||||||
|  |  | ||||||
|  | #include <QObject> | ||||||
|  | #include <QString> | ||||||
|  |  | ||||||
|  | #include <optional> | ||||||
|  |  | ||||||
|  | struct PSAInstalled { | ||||||
|  |     struct VersionInfo { | ||||||
|  |         QString created; | ||||||
|  |         QString reason; | ||||||
|  |         QString lastCommit; | ||||||
|  |     } versionInfo; | ||||||
|  |  | ||||||
|  |     struct Tariff { | ||||||
|  |         QString name; | ||||||
|  |         QString version; | ||||||
|  |         QString project; | ||||||
|  |         int zone; | ||||||
|  |         int size; | ||||||
|  |         QString blob; | ||||||
|  |         QString lastCommit; | ||||||
|  |         QString info; | ||||||
|  |         QString loadTime; | ||||||
|  |     } tariff; | ||||||
|  |  | ||||||
|  |     struct HardWare { | ||||||
|  |         QString linuxVersion; | ||||||
|  |         QString cpuSerial; | ||||||
|  |     } hw; | ||||||
|  |  | ||||||
|  |     struct Opkg { | ||||||
|  |         int size; | ||||||
|  |         QString blob; | ||||||
|  |         QString lastCommit; | ||||||
|  |         QString loadTime; | ||||||
|  |     } opkg; | ||||||
|  |  | ||||||
|  |     struct DC { | ||||||
|  |         QString versionHW; | ||||||
|  |         QString versionSW; | ||||||
|  |         QString gitBlob; | ||||||
|  |         QString gitLastCommit; | ||||||
|  |         int size; | ||||||
|  |     } dc; | ||||||
|  |  | ||||||
|  |     struct SoftWare { | ||||||
|  |         QString apismVersion; | ||||||
|  |         QString atbQTVersion; | ||||||
|  |         QString atbUpdateToolVersion; | ||||||
|  |     } sw; | ||||||
|  |  | ||||||
|  |     struct PluginVersion { | ||||||
|  |         QString deviceController; | ||||||
|  |         QString ingenicoISelfCC; | ||||||
|  |         QString mobilisisCalculatePrice; | ||||||
|  |         QString mobilisisCalculatePriceConfigUi; | ||||||
|  |         QString prmCalculatePrice; | ||||||
|  |         QString prmCalculatePriceConfigUi; | ||||||
|  |         QString tcpZVT; | ||||||
|  |     } pluginVersion; | ||||||
|  |  | ||||||
|  |     struct DC2C { | ||||||
|  |         QString name; | ||||||
|  |         QString blob; | ||||||
|  |         int size; | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     DC2C cash; | ||||||
|  |     DC2C conf; | ||||||
|  |     DC2C device; | ||||||
|  |  | ||||||
|  |     DC2C print[32]; | ||||||
|  |  | ||||||
|  |     explicit PSAInstalled() { | ||||||
|  |         tariff.name = "N/A"; | ||||||
|  |         tariff.version = "N/A"; | ||||||
|  |         tariff.project = "N/A"; | ||||||
|  |         tariff.zone = -1; | ||||||
|  |         tariff.size = -1; | ||||||
|  |         tariff.blob = "N/A"; | ||||||
|  |         tariff.info = "N/A"; | ||||||
|  |         tariff.loadTime = "N/A"; | ||||||
|  |  | ||||||
|  |         hw.linuxVersion = "N/A"; | ||||||
|  |         hw.cpuSerial = "N/A"; | ||||||
|  |  | ||||||
|  |         opkg.size = -1; | ||||||
|  |         opkg.blob = "N/A"; | ||||||
|  |         opkg.lastCommit = "N/A"; | ||||||
|  |         opkg.loadTime = "N/A"; | ||||||
|  |  | ||||||
|  |         dc.versionHW = "N/A"; | ||||||
|  |         dc.versionSW = "N/A"; | ||||||
|  |         dc.gitBlob = "N/A"; | ||||||
|  |         dc.gitLastCommit = "N/A"; | ||||||
|  |         dc.size = -1; | ||||||
|  |  | ||||||
|  |         sw.apismVersion = "N/A"; | ||||||
|  |         sw.atbQTVersion = "N/A"; | ||||||
|  |         sw.atbUpdateToolVersion = "N/A"; | ||||||
|  |  | ||||||
|  |         pluginVersion.deviceController = "N/A"; | ||||||
|  |         pluginVersion.ingenicoISelfCC = "N/A"; | ||||||
|  |         pluginVersion.mobilisisCalculatePrice = "N/A"; | ||||||
|  |         pluginVersion.mobilisisCalculatePriceConfigUi = "N/A"; | ||||||
|  |         pluginVersion.prmCalculatePrice = "N/A"; | ||||||
|  |         pluginVersion.prmCalculatePriceConfigUi = "N/A"; | ||||||
|  |         pluginVersion.tcpZVT = "N/A"; | ||||||
|  |  | ||||||
|  |         cash.name = "N/A"; | ||||||
|  |         cash.blob = "N/A"; | ||||||
|  |         cash.size = -1; | ||||||
|  |  | ||||||
|  |         conf.name = "N/A"; | ||||||
|  |         conf.blob = "N/A"; | ||||||
|  |         conf.size = -1; | ||||||
|  |  | ||||||
|  |         device.size = -1; | ||||||
|  |         device.blob = "N/A"; | ||||||
|  |         device.size = -1; | ||||||
|  |  | ||||||
|  |         for (int i=0; i < 32; ++i) { | ||||||
|  |             print[i].size = -1; | ||||||
|  |             print[i].blob = "N/A"; | ||||||
|  |             print[i].size = -1; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | class IsmasClient : public QObject { | ||||||
|  |     Q_OBJECT | ||||||
|  |  | ||||||
|  |     int m_progressInPercent; | ||||||
|  | public: | ||||||
|  |     explicit IsmasClient() : m_progressInPercent(1) {} | ||||||
|  |  | ||||||
|  |     enum APISM { | ||||||
|  |         DB_PORT = 7777, | ||||||
|  |         DIRECT_PORT = 7778 | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     enum RESULT_CODE { | ||||||
|  |         SUCCESS=0, | ||||||
|  |         NO_UPDATE_NECESSARY=1, | ||||||
|  |         BACKUP_FAILED=2, | ||||||
|  |         WRONG_PACKAGE=3, | ||||||
|  |         INSTALL_ERROR=4}; | ||||||
|  |  | ||||||
|  |     enum REASON { | ||||||
|  |         TIME_TRIGGERED = 0, | ||||||
|  |         SERVICE, | ||||||
|  |         DEV_TEST, | ||||||
|  |         ENTRIES | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     static char const *reason[REASON::ENTRIES]; | ||||||
|  |  | ||||||
|  |     static std::optional<QString> | ||||||
|  |         sendRequestReceiveResponse(int port, QString const &request); | ||||||
|  |  | ||||||
|  |     static QString getReasonForLastSendVersion(); | ||||||
|  |  | ||||||
|  |     int getProgressInPercent() const {return m_progressInPercent; } | ||||||
|  |     void setProgressInPercent(int procent) { m_progressInPercent = procent; } | ||||||
|  |  | ||||||
|  |     QString updateNewsToIsmas(char const *event, | ||||||
|  |                               int percent, | ||||||
|  |                               int resultCode, | ||||||
|  |                               char const *step, | ||||||
|  |                               char const *step_result, | ||||||
|  |                               char const *version); | ||||||
|  |  | ||||||
|  |     QString updateOfPSAStarted(QString const &version = QString());   // start of update process | ||||||
|  |     QString cloneAndCheckoutCustomerRepository(QString const &info, QString const &version = QString());   // clone and checkout customer repository | ||||||
|  |     QString checkoutBranch(QString const &info, QString const &version = QString());   // checkout branch | ||||||
|  |     QString errorBackendNotConnected(QString const &info, QString const &version = QString());   // checkout branch | ||||||
|  |     QString errorGitClone(QString const &info, QString const &version = QString()); | ||||||
|  |     QString backendConnected(QString const &info, QString const &version = QString()); | ||||||
|  |     QString updateTriggerSet(QString const &info, QString const &version = QString()); | ||||||
|  |     QString errorUpdateTrigger(QString const &info, QString const &version = QString()); | ||||||
|  |     QString gitFetch(QString const &info, QString const &version = QString()); | ||||||
|  |     QString execOpkgCommand(QString const &info, QString const &version = QString()); | ||||||
|  |     QString rsyncFile(QString const &info, QString const &version = QString()); | ||||||
|  |     QString errorGitFetch(int resultCode, QString const &info, QString const &version = QString()); | ||||||
|  |     QString updateOfPSAActivated(QString const &version = QString()); | ||||||
|  |                                     // and update accepted | ||||||
|  |     QString updateOfPSASucceeded(QString const &version = QString()); // update process succeeded | ||||||
|  |     QString updateOfPSAContinues(QString currentStage, QString currentStageInfo, QString const &version = QString()); | ||||||
|  |     QString updateOfPSAFailed(int resultCode, QString step, QString reason, QString const &version = QString()); | ||||||
|  |     QString sanityCheckFailed(int resultCode, QString reason, QString const &version = QString()); | ||||||
|  |     QString jsonParseFailed(int resultCode, QString reason, QString const &version = QString()); | ||||||
|  |     std::optional<QString> finalResult(int resultCode, QString reason, QString const &version = QString()); | ||||||
|  |  | ||||||
|  |     QString updateOfPSASendVersion(PSAInstalled const &psa); | ||||||
|  |  | ||||||
|  |   private: | ||||||
|  |     static void printDebugMessage(int port, QString const &clientIP, int clientPort, | ||||||
|  |                                   QString const &message); | ||||||
|  |     static void printInfoMessage(int port, QString const &clientIP, int clientPort, | ||||||
|  |                                  QString const &message); | ||||||
|  |     static void printErrorMessage(int port, QString const &clientIP, int clientPort, | ||||||
|  |                                   QString const &message); | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | #endif // ISMAS_CLIENT_H_INCLUDED | ||||||
							
								
								
									
										141
									
								
								main.cpp
									
									
									
									
									
								
							
							
						
						
									
										141
									
								
								main.cpp
									
									
									
									
									
								
							| @@ -12,7 +12,6 @@ | |||||||
| #include "plugins/interfaces.h" | #include "plugins/interfaces.h" | ||||||
|  |  | ||||||
| #include <unistd.h> | #include <unistd.h> | ||||||
| #include <thread> |  | ||||||
| #include <memory> | #include <memory> | ||||||
| #include <QSharedMemory> | #include <QSharedMemory> | ||||||
| #include <QRunnable> | #include <QRunnable> | ||||||
| @@ -21,12 +20,24 @@ | |||||||
| #include <QProcess> | #include <QProcess> | ||||||
| #include <QCommandLineParser> | #include <QCommandLineParser> | ||||||
| #include <QStandardPaths> | #include <QStandardPaths> | ||||||
|  | #include <QMainWindow> | ||||||
|  |  | ||||||
| #include "update.h" | #include "update.h" | ||||||
|  | #include "git/git_client.h" | ||||||
|  | #include "ismas/ismas_client.h" | ||||||
| #include "worker_thread.h" | #include "worker_thread.h" | ||||||
| #include "worker.h" | #include "worker.h" | ||||||
|  | #include "mainwindow.h" | ||||||
|  | #include "utils.h" | ||||||
|  |  | ||||||
| #include <thread> | #include <QThread> | ||||||
|  | #include <QtWidgets> | ||||||
|  | #include <QScopedPointer> | ||||||
|  |  | ||||||
|  | #if defined (Q_OS_UNIX) || defined (Q_OS_LINUX) | ||||||
|  | #include <unistd.h> | ||||||
|  | #include <errno.h> | ||||||
|  | #endif | ||||||
|  |  | ||||||
| #ifdef PTU5 | #ifdef PTU5 | ||||||
| #define SERIAL_PORT "ttymxc2" | #define SERIAL_PORT "ttymxc2" | ||||||
| @@ -34,32 +45,23 @@ | |||||||
| #define SERIAL_PORT "ttyUSB0" | #define SERIAL_PORT "ttyUSB0" | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| class hwinf; |  | ||||||
| static void doWork(hwinf *hw, QString update_ctrl_file, |  | ||||||
|                    QString workingDir, bool maintenanceMode) { |  | ||||||
|     std::this_thread::sleep_for(std::chrono::milliseconds(2000)); |  | ||||||
|     Update update(hw, update_ctrl_file, workingDir, maintenanceMode); |  | ||||||
|     update.doUpdate(); |  | ||||||
|     std::this_thread::sleep_for(std::chrono::milliseconds(2000)); |  | ||||||
|     QCoreApplication::quit(); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // argv[1]: file to send to dc | // argv[1]: file to send to dc | ||||||
| int main(int argc, char *argv[]) { | int main(int argc, char *argv[]) { | ||||||
|  |     QByteArray const value = qgetenv("LC_ALL"); | ||||||
|     QByteArray const value = qgetenv("XDG_RUNTIME_DIR"); |     if (value != "C") { | ||||||
|     if (value.size() == 0) { |         qputenv("LC_ALL", "C"); | ||||||
|         qputenv("XDG_RUNTIME_DIR", "/run/user/0"); |  | ||||||
|     } |     } | ||||||
|  |     // qputenv("XDG_RUNTIME_DIR", "/run/user/0"); | ||||||
|  |  | ||||||
|  |     openlog("ATB-UPDATE", LOG_PERROR | LOG_PID | LOG_CONS, LOG_USER); | ||||||
|  |  | ||||||
|     QApplication a(argc, argv); |     QApplication a(argc, argv); | ||||||
|     QApplication::setApplicationName("ATBUpdateTool"); |     QApplication::setApplicationName("ATBUpdateTool"); | ||||||
|     QApplication::setApplicationVersion("1.0"); |     QApplication::setApplicationVersion(APP_VERSION); | ||||||
|  |  | ||||||
|     if (!messageHandlerInstalled()) { // change internal qt-QDebug-handling |     if (!messageHandlerInstalled()) { // change internal qt-QDebug-handling | ||||||
|         atbInstallMessageHandler(atbDebugOutput); |         atbInstallMessageHandler(atbDebugOutput); | ||||||
|         setDebugLevel(QtMsgType::QtDebugMsg); |         setDebugLevel(LOG_NOTICE); | ||||||
|         //setDebugLevel(QtMsgType::QtDebugMsg); |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     QCommandLineParser parser; |     QCommandLineParser parser; | ||||||
| @@ -70,57 +72,95 @@ int main(int argc, char *argv[]) { | |||||||
|     QCommandLineOption pluginDirectoryOption(QStringList() << "plugin-directory" << "plugin-directory", |     QCommandLineOption pluginDirectoryOption(QStringList() << "plugin-directory" << "plugin-directory", | ||||||
|         QCoreApplication::translate("main", "Where to find dc-plugin."), |         QCoreApplication::translate("main", "Where to find dc-plugin."), | ||||||
|         QCoreApplication::translate("main", "directory")); |         QCoreApplication::translate("main", "directory")); | ||||||
|     QString const pluginDefault = "./plugins"; |     QString const pluginDefault = "/usr/lib"; | ||||||
|     pluginDirectoryOption.setDefaultValue(pluginDefault); |     pluginDirectoryOption.setDefaultValue(pluginDefault); | ||||||
|     parser.addOption(pluginDirectoryOption); |     parser.addOption(pluginDirectoryOption); | ||||||
|  |  | ||||||
|     QCommandLineOption pluginNameOption(QStringList() << "plugin-name" << "plugin-name", |     QCommandLineOption pluginNameOption(QStringList() << "plugin-name" << "plugin-name", | ||||||
|         QCoreApplication::translate("main", "Name of dc-plugin."), |         QCoreApplication::translate("main", "Name of dc-plugin."), | ||||||
|         QCoreApplication::translate("main", "directory")); |         QCoreApplication::translate("main", "directory")); | ||||||
|     QString const pluginNameDefault = "libCAmaster.so"; |     QString const pluginNameDefault = "libCAslave.so"; | ||||||
|     pluginNameOption.setDefaultValue(pluginNameDefault); |     pluginNameOption.setDefaultValue(pluginNameDefault); | ||||||
|     parser.addOption(pluginNameOption); |     parser.addOption(pluginNameOption); | ||||||
|  |  | ||||||
|  |     QCommandLineOption noDownloadOption("no-psa-hardware-update", | ||||||
|  |         QCoreApplication::translate("main", "Do not update the PSA firmware (json, device-controller).")); | ||||||
|  |     parser.addOption(noDownloadOption); | ||||||
|  |  | ||||||
|     QCommandLineOption workingDirectoryOption(QStringList() << "working-directory" << "working-directory", |     QCommandLineOption workingDirectoryOption(QStringList() << "working-directory" << "working-directory", | ||||||
|         QCoreApplication::translate("main", "working directory of update-script."), |         QCoreApplication::translate("main", "working directory of update-script."), | ||||||
|         QCoreApplication::translate("main", "directory")); |         QCoreApplication::translate("main", "directory")); | ||||||
|     QString const workingDirectoryDefault = "."; |     QString const workingDirectoryDefault = "/opt/app/tools/atbupdate"; | ||||||
|     workingDirectoryOption.setDefaultValue(workingDirectoryDefault); |     workingDirectoryOption.setDefaultValue(workingDirectoryDefault); | ||||||
|     parser.addOption(workingDirectoryOption); |     parser.addOption(workingDirectoryOption); | ||||||
|  |  | ||||||
|     QCommandLineOption maintenanceOption("m", |     QCommandLineOption dryRunOption(QStringList() << "d" << "dry-run", | ||||||
|         QCoreApplication::translate("main", "Maintenance mode for underlying script")); |         QCoreApplication::translate("main", "Start ATBUpdateTool in dry-run-mode. No actual actions.")); | ||||||
|     parser.addOption(maintenanceOption); |     parser.addOption(dryRunOption); | ||||||
|  |  | ||||||
|     // TODO: |     QCommandLineOption extendedVersionOption(QStringList() << "V" << "extended-version", | ||||||
|     // add some additional parameters |         QCoreApplication::translate("main", "Show extended version (including last git commit).")); | ||||||
|     // --dry-run |     parser.addOption(extendedVersionOption); | ||||||
|     // -d: only update device-controller firmware |  | ||||||
|     // -j: only update json-files |     QCommandLineOption yoctoVersionOption(QStringList() << "y" << "yocto-version", | ||||||
|     // -o: only execute opkg-commnds |         QCoreApplication::translate("main", "Show yocto version of ATBUpdateTool.")); | ||||||
|     // -f: force. update_psa shall always perform a 'git pull' |     parser.addOption(yoctoVersionOption); | ||||||
|  |  | ||||||
|  |     QCommandLineOption yoctoInstallStatusOption(QStringList() << "Y" << "yocto-install", | ||||||
|  |         QCoreApplication::translate("main", "Show yocto install status of ATBUpdateTool.")); | ||||||
|  |     parser.addOption(yoctoInstallStatusOption); | ||||||
|  |  | ||||||
|     // Process the actual command line arguments given by the user |     // Process the actual command line arguments given by the user | ||||||
|     parser.process(a); |     parser.process(a); | ||||||
|     QString plugInDir = parser.value(pluginDirectoryOption); |     QString plugInDir = parser.value(pluginDirectoryOption); | ||||||
|     QString plugInName = parser.value(pluginNameOption); |     QString plugInName = parser.value(pluginNameOption); | ||||||
|     QString workingDir = parser.value(workingDirectoryOption); |     QString workingDir = parser.value(workingDirectoryOption); | ||||||
|     bool maintenanceMode = parser.isSet(maintenanceOption); |     bool const dryRun = parser.isSet(dryRunOption); | ||||||
|  |     bool const noUpdatePsaHardware = parser.isSet(noDownloadOption); | ||||||
|  |     bool const showYoctoVersion = parser.isSet(yoctoVersionOption); | ||||||
|  |     bool const showYoctoInstallStatus = parser.isSet(yoctoInstallStatusOption); | ||||||
|  |     bool const showExtendedVersion = parser.isSet(extendedVersionOption); | ||||||
|     QString const rtPath = QCoreApplication::applicationDirPath(); |     QString const rtPath = QCoreApplication::applicationDirPath(); | ||||||
|  |  | ||||||
|     if (plugInDir == pluginDefault) { |     int machineNr = Utils::read1stLineOfFile("/etc/machine_nr"); | ||||||
|         plugInDir = (rtPath + "/" + pluginDefault); |     int customerNr = Utils::read1stLineOfFile("/etc/cust_nr"); | ||||||
|  |     int zoneNr = Utils::read1stLineOfFile("/etc/zone_nr"); | ||||||
|  |     QString const branchName = (zoneNr != 0) | ||||||
|  |             ? QString("zg1/zone%1").arg(zoneNr) : "master"; | ||||||
|  |  | ||||||
|  |     QThread::currentThread()->setObjectName("main thread"); | ||||||
|  |     qInfo() << "Main thread" << QThread::currentThreadId(); | ||||||
|  |  | ||||||
|  |     if (showExtendedVersion) { | ||||||
|  |         printf(APP_EXTENDED_VERSION"\n"); | ||||||
|  |         return 0; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     if (showYoctoVersion) { | ||||||
|  |         printf("%s\n", Worker::getATBUpdateToolYoctoVersion().toStdString().c_str()); | ||||||
|  |         return 0; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (showYoctoInstallStatus) { | ||||||
|  |         printf("%s\n", Worker::getATBUpdateToolYoctoInstallationStatus().toStdString().c_str()); | ||||||
|  |         return 0; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     if (!QDir(plugInDir).exists()) { |     if (!QDir(plugInDir).exists()) { | ||||||
|         qCritical() << plugInDir |         qCritical() << plugInDir | ||||||
|                     << "does not exists, but has to contain dc-library"; |                     << "does not exists, but has to contain dc-library"; | ||||||
|         exit(-1); |         exit(-1); | ||||||
|     } |     } | ||||||
|     qInfo() << "pwd" << "=" << rtPath; |  | ||||||
|     qInfo() << "plugInDir" << "=" << plugInDir; |     qInfo() << "pwd ......................" << rtPath; | ||||||
|     qInfo() << "plugInName" << "=" << plugInName; |     qInfo() << "plugInDir ................" << plugInDir; | ||||||
|     qInfo() << "workingDir" << "=" << workingDir; |     qInfo() << "plugInName ..............." << plugInName; | ||||||
|     qInfo() << "maintenanceMode" << "=" << maintenanceMode; |     qInfo() << "workingDir ..............." << workingDir; | ||||||
|  |     qInfo() << "dryRun ..................." << dryRun; | ||||||
|  |     qInfo() << "noUpdatePsaHardware ......" << noUpdatePsaHardware; | ||||||
|  |     qInfo() << "extended-version ........." << APP_EXTENDED_VERSION; | ||||||
|  |     //qInfo() << "yocto-version ............" << Worker::getATBUpdateToolYoctoVersion(); | ||||||
|  |     //qInfo() << "yocto-install-status ....." << Worker::getATBUpdateToolYoctoInstallationStatus(); | ||||||
|  |  | ||||||
|     // before loading the library, delete all possible shared memory segments |     // before loading the library, delete all possible shared memory segments | ||||||
| #if defined Q_OS_LINUX || defined Q_OS_UNIX | #if defined Q_OS_LINUX || defined Q_OS_UNIX | ||||||
| @@ -129,14 +169,21 @@ int main(int argc, char *argv[]) { | |||||||
| #error "Only tested under UNIX/LINUX" | #error "Only tested under UNIX/LINUX" | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|     hwinf *hw = Update::loadDCPlugin(QDir(plugInDir), plugInName); |     Worker worker(customerNr, | ||||||
|     hw->dc_autoRequest(false); |                   machineNr, | ||||||
|  |                   zoneNr, | ||||||
|  |                   branchName, | ||||||
|  |                   plugInDir, | ||||||
|  |                   plugInName, | ||||||
|  |                   workingDir, | ||||||
|  |                   noUpdatePsaHardware, | ||||||
|  |                   dryRun); | ||||||
|  |  | ||||||
|     QString const update_ctrl_file = "/opt/app/tools/atbupdate/update_log.csv"; |     MainWindow mw(&worker); | ||||||
|     std::thread t(doWork, hw, update_ctrl_file, workingDir, maintenanceMode); |     worker.setMainWindow(&mw); | ||||||
|  |  | ||||||
|     int ret = a.exec(); |     mw.setWindowFlags(Qt::Window | Qt::FramelessWindowHint); | ||||||
|     t.join(); |     mw.showFullScreen(); | ||||||
|  |  | ||||||
|     return ret; |     return a.exec(); | ||||||
| } | } | ||||||
|   | |||||||
							
								
								
									
										305
									
								
								mainwindow.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										305
									
								
								mainwindow.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,305 @@ | |||||||
|  | #include "mainwindow.h" | ||||||
|  | #include "ui_mainwindow.h" | ||||||
|  | #include "worker.h" | ||||||
|  | #include "utils.h" | ||||||
|  | #include "progress_event.h" | ||||||
|  | #include "update_dc_event.h" | ||||||
|  | #include "plugins/interfaces.h" | ||||||
|  |  | ||||||
|  | #include <QDateTime> | ||||||
|  | #include <QMessageBox> | ||||||
|  | #include <QDebug> | ||||||
|  | #include <QScrollBar> | ||||||
|  | #include <QEvent> | ||||||
|  |  | ||||||
|  |  | ||||||
|  | MainWindow::MainWindow(Worker *worker, QWidget *parent) | ||||||
|  |     : QMainWindow(parent) | ||||||
|  |     , ui(new Ui::MainWindow) | ||||||
|  |     , m_worker(worker) | ||||||
|  |     , m_width(70) | ||||||
|  |     , m_progressRunning(false) | ||||||
|  |     , m_updateStep(UpdateDcEvent::UpdateStep::NONE) { | ||||||
|  |  | ||||||
|  |     this->setStatusBar(new QStatusBar(this)); | ||||||
|  |     QFont f; | ||||||
|  |     f.setStyleHint(QFont::Monospace); | ||||||
|  |     f.setWeight(QFont::Bold); | ||||||
|  |     f.setFamily("Misc Fixed"); | ||||||
|  |     f.setPixelSize(12); | ||||||
|  |     this->statusBar()->setFont(f); | ||||||
|  |  | ||||||
|  |     ui->setupUi(this); | ||||||
|  |  | ||||||
|  |     ui->updateProgress->setRange(0, 100); | ||||||
|  |     ui->updateProgress->reset(); | ||||||
|  |  | ||||||
|  |     QStringList lst; | ||||||
|  |     QString start = QDateTime::currentDateTime().toString(Qt::ISODate); | ||||||
|  |     lst << QString("Start: ") + start.leftJustified(m_width-10); | ||||||
|  |     lst << QString("").leftJustified(m_width-3, '='); | ||||||
|  |     lst << QString("Update tool version: %1 - %2 %3").arg(APP_VERSION).arg(APP_BUILD_DATE).arg(APP_BUILD_TIME).leftJustified(m_width-3); | ||||||
|  |     lst << QString("Machine number     : %1 ").arg(m_worker->machineNr()).leftJustified(m_width-3); | ||||||
|  |     lst << QString("Customer number    : %1 ").arg(m_worker->customerNr()).leftJustified(m_width-3); | ||||||
|  |     lst << QString("Zone number        : %1 (%2)").arg(m_worker->zoneNr()).arg(Utils::zoneName(m_worker->zoneNr())).leftJustified(m_width-3); | ||||||
|  |     lst << QString("APISM version      : %1").arg(m_worker->apismVersion()).leftJustified(m_width-3); | ||||||
|  |     lst << QString("").leftJustified(m_width-3, '='); | ||||||
|  |  | ||||||
|  |     ui->updateStatus->setText(lst.join('\n')); | ||||||
|  |     ui->updateStatus->setEnabled(true); | ||||||
|  |     // ui->updateStatus->installEventFilter(this); | ||||||
|  |  | ||||||
|  |     m_startTimer = new QTimer(this); | ||||||
|  |     connect(m_startTimer, SIGNAL(timeout()), m_worker, SLOT(start())); | ||||||
|  |     m_startTimer->setSingleShot(true); | ||||||
|  |     m_startTimer->start(1000); | ||||||
|  |  | ||||||
|  |     m_exitTimer = new QTimer(this); | ||||||
|  |     connect(m_exitTimer, SIGNAL(timeout()), ui->exit, SLOT(click())); | ||||||
|  |     m_exitTimer->setSingleShot(true); | ||||||
|  |     m_exitTimer->start(1800 * 1000); | ||||||
|  |  | ||||||
|  |     connect(ui->exit, SIGNAL(clicked()),this,SLOT(onQuit())); | ||||||
|  |     connect(m_worker, SIGNAL(disableExit()),this,SLOT(onDisableExit())); | ||||||
|  |     connect(m_worker, SIGNAL(enableExit()),this,SLOT(onEnableExit())); | ||||||
|  |     connect(m_worker, SIGNAL(stopStartTimer()),this,SLOT(onStopStartTimer())); | ||||||
|  |     connect(m_worker, SIGNAL(restartExitTimer()),this,SLOT(onRestartExitTimer())); | ||||||
|  |     connect(m_worker, SIGNAL(appendText(QString,QString)),this,SLOT(onAppendText(QString,QString))); | ||||||
|  |     connect(m_worker, SIGNAL(showErrorMessage(QString,QString)),this, SLOT(onShowErrorMessage(QString,QString))); | ||||||
|  |     connect(m_worker, SIGNAL(showStatusMessage(QString,QString)),this, SLOT(onShowStatusMessage(QString,QString))); | ||||||
|  |     connect(m_worker, SIGNAL(showErrorMessage(QStringList)),this, SLOT(onShowErrorMessage(QStringList))); | ||||||
|  |     connect(m_worker, SIGNAL(showStatusMessage(QString,QString)),this, SLOT(onShowStatusMessage(QString,QString))); | ||||||
|  |     connect(m_worker, SIGNAL(replaceLast(QString,QString)),this,SLOT(onReplaceLast(QString,QString))); | ||||||
|  |     connect(m_worker, SIGNAL(replaceLast(QStringList,QString)),this, SLOT(onReplaceLast(QStringList,QString))); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | MainWindow::~MainWindow() { | ||||||
|  |     delete m_startTimer; | ||||||
|  |     delete m_exitTimer; | ||||||
|  |     delete ui; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void MainWindow::customEvent(QEvent *event) { | ||||||
|  |     if (event->type() == ProgressEvent::type()) { | ||||||
|  |         ProgressEvent *pevent = (ProgressEvent *)event; | ||||||
|  |         int const progress = pevent->progressPercent(); | ||||||
|  |         QObject const *sender = pevent->sender(); | ||||||
|  |         if (sender == this) { | ||||||
|  |             switch(progress) { | ||||||
|  |             case 0: { | ||||||
|  |                 ui->updateProgress->reset(); | ||||||
|  |             } break; | ||||||
|  |             case START_PROGRESS_LOOP: { | ||||||
|  |                 m_progressRunning = true; | ||||||
|  |                 ui->updateProgress->reset(); | ||||||
|  |                 // m_progressValue = 10; | ||||||
|  |                 QApplication::postEvent(this, new ProgressEvent(this, 1)); | ||||||
|  |             } break; | ||||||
|  |             case STOP_PROGRESS_LOOP: { | ||||||
|  |                 m_progressRunning = false; | ||||||
|  |                 // m_progressValue -= 10; | ||||||
|  |                 // m_worker->setProgress(m_progressValue/10); | ||||||
|  |             } break; | ||||||
|  |             default: { | ||||||
|  |                 if (m_progressRunning) { | ||||||
|  |                     // m_progressValue = progress; | ||||||
|  |                     ui->updateProgress->setValue(progress); | ||||||
|  |                     // ueberpruefen: hauptfenster schickt sich selber ein event | ||||||
|  |                     // QApplication::postEvent(this, new ProgressEvent(this, progress)); | ||||||
|  |                     // QThread::msleep(500); | ||||||
|  |                 }} | ||||||
|  |             } | ||||||
|  |         } else | ||||||
|  |         if (sender == m_worker) { | ||||||
|  |             switch(progress) { | ||||||
|  |             case 0: { | ||||||
|  |                 ui->updateProgress->reset(); | ||||||
|  |             } break; | ||||||
|  |             case START_PROGRESS_LOOP: { | ||||||
|  |                 QApplication::postEvent(this, new ProgressEvent(this, START_PROGRESS_LOOP)); | ||||||
|  |             } break; | ||||||
|  |             case STOP_PROGRESS_LOOP: { | ||||||
|  |                 QApplication::postEvent(this, new ProgressEvent(this, STOP_PROGRESS_LOOP)); | ||||||
|  |             } break; | ||||||
|  |             default:{ | ||||||
|  |                 ui->updateProgress->setValue(progress); | ||||||
|  |             }} | ||||||
|  |         } else { | ||||||
|  |             qCritical() << "!!! UNKNOWN SENDER !!!"; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     QThread::yieldCurrentThread(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void MainWindow::onStopStartTimer() { | ||||||
|  |     m_startTimer->stop(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void MainWindow::onDisableExit() { | ||||||
|  |    ui->exit->setEnabled(false); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void MainWindow::onEnableExit() { | ||||||
|  |    ui->exit->setEnabled(true); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void MainWindow::onRestartExitTimer() { | ||||||
|  |     m_exitTimer->stop(); | ||||||
|  |     m_exitTimer->start(60 * 1000); | ||||||
|  |  | ||||||
|  |     scrollDownTextEdit(); | ||||||
|  |     ui->updateStatus->setEnabled(false); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void MainWindow::onQuit() { | ||||||
|  |     m_exitTimer->stop(); | ||||||
|  |     int errorCode = 0; | ||||||
|  |  | ||||||
|  |     qCritical() | ||||||
|  |         << QString("ON QUIT: CURRENT STEP %1") | ||||||
|  |             .arg(m_worker->getSmap()[m_worker->currentStep()]); | ||||||
|  |  | ||||||
|  |     // TODO: replace SEND_LAST_VERSION with UPDATE_SUCCEEDED | ||||||
|  |     if (m_worker->currentStep() != Worker::UPDATE_STEP::SEND_LAST_VERSION) { | ||||||
|  |         errorCode = -1; | ||||||
|  |     } | ||||||
|  |     qCritical() << QString("ON QUIT: EXIT CODE %1").arg(errorCode); | ||||||
|  |     qApp->exit(errorCode); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void MainWindow::scrollDownTextEdit() { | ||||||
|  |     // Utils::printInfoMsg(QString("SCROLL-DOWN-TEXT_EDIT CALLED AT ") | ||||||
|  |     //    + QDateTime::currentDateTime().toString(Qt::ISODateWithMs)); | ||||||
|  |  | ||||||
|  |     ui->updateStatus->setEnabled(true); | ||||||
|  |  | ||||||
|  |     QTextCursor tmpCursor = ui->updateStatus->textCursor(); | ||||||
|  |     tmpCursor.movePosition(QTextCursor::End); | ||||||
|  |     ui->updateStatus->setTextCursor(tmpCursor); | ||||||
|  |     ui->updateStatus->ensureCursorVisible(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void MainWindow::onAppendText(QString text, QString suffix) { | ||||||
|  |     // Utils::printInfoMsg(QString("ON APPEND CALLED AT ") | ||||||
|  |     //    + QDateTime::currentDateTime().toString(Qt::ISODateWithMs)); | ||||||
|  |  | ||||||
|  |     QString editText = ui->updateStatus->toPlainText(); | ||||||
|  |     scrollDownTextEdit(); | ||||||
|  |  | ||||||
|  |     if (!suffix.isNull() && suffix.size() > 0) { | ||||||
|  |         //qInfo() << "TEXT" << text << "SUFFIX" << suffix; | ||||||
|  |         if (suffix == Worker::UPDATE_STEP_SUCCESS || suffix == Worker::UPDATE_STEP_FAIL) { | ||||||
|  |             ui->updateStatus->insertPlainText(QString("\n").leftJustified(m_width-3, '=') + " "); | ||||||
|  |             // editText += QString("\n").leftJustified(m_width-3, '='); | ||||||
|  |             // editText += " "; | ||||||
|  |         } | ||||||
|  |         QString const &add = (QString("\n") + text).leftJustified(m_width - (2 + suffix.size())) + suffix; | ||||||
|  |         ui->updateStatus->insertPlainText(add); | ||||||
|  |         // editText += add; | ||||||
|  |     } else { | ||||||
|  |         QString const &add = text.leftJustified(m_width-9); | ||||||
|  |         ui->updateStatus->insertPlainText(add); | ||||||
|  |         //editText += add; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // debug | ||||||
|  |     // QString editText = ui->updateStatus->toPlainText(); | ||||||
|  |     // Utils::printLineEditInfo(editText.split('\n', QString::SplitBehavior::SkipEmptyParts)); | ||||||
|  |     // ui->updateStatus->setText(editText.trimmed()); | ||||||
|  |  | ||||||
|  |     // scrollDownTextEdit(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void MainWindow::onReplaceLast(QStringList newTextLines, QString suffix) { | ||||||
|  |     // Utils::printInfoMsg(QString("ON REPLACE LAST (LIST) CALLED AT ") | ||||||
|  |     //    + QDateTime::currentDateTime().toString(Qt::ISODateWithMs)); | ||||||
|  |  | ||||||
|  |     int const s = newTextLines.size(); | ||||||
|  |     if (s > 0) { | ||||||
|  |         QString editText = ui->updateStatus->toPlainText(); | ||||||
|  |         QStringList lines = editText.split('\n', QString::SplitBehavior::SkipEmptyParts); | ||||||
|  |         QString newText; | ||||||
|  |         if (lines.size() >= s) { | ||||||
|  |             for (int i = 0; i < s; ++i) { | ||||||
|  |                 lines.removeLast(); | ||||||
|  |             } | ||||||
|  |             if (lines.size() > 0) { | ||||||
|  |                 newText = lines.join('\n'); | ||||||
|  |                 newText += '\n'; | ||||||
|  |             } | ||||||
|  |             QStringList newLines; | ||||||
|  |             for (int i = 0; i < s; ++i) { | ||||||
|  |                 if (i == 0 && !suffix.isNull() && suffix.size() > 0 && suffix != "\n") { | ||||||
|  |                     newLines += Utils::rstrip(newTextLines.at(i).leftJustified(m_width-10) + suffix); | ||||||
|  |                 } else { | ||||||
|  |                     newLines += Utils::rstrip(newTextLines.at(i).leftJustified(m_width-10)); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             lines += newLines; | ||||||
|  |             newText += newLines.join(' '); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         ui->updateStatus->setText(newText); | ||||||
|  |         Utils::printLineEditInfo(lines); | ||||||
|  |         scrollDownTextEdit(); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void MainWindow::onReplaceLast(QString text, QString suffix) { | ||||||
|  |     // Utils::printInfoMsg(QString("ON REPLACE LAST (TEXT) CALLED AT ") | ||||||
|  |     //    + QDateTime::currentDateTime().toString(Qt::ISODateWithMs)); | ||||||
|  |  | ||||||
|  |     QString editText = ui->updateStatus->toPlainText(); | ||||||
|  |     QStringList lines = editText.split('\n', QString::SplitBehavior::SkipEmptyParts); | ||||||
|  |     if (lines.size() > 0) { | ||||||
|  |         lines.removeLast(); | ||||||
|  |         if (!suffix.isNull() && suffix.size() > 0 && suffix != "\n") { | ||||||
|  |             QString const add = text.leftJustified(m_width-10) + suffix; | ||||||
|  |             if (!add.isEmpty()) { | ||||||
|  |                 lines += text.leftJustified(m_width-10) + suffix; | ||||||
|  |             } | ||||||
|  |         } else { | ||||||
|  |             QString const add = text.leftJustified(m_width-10); | ||||||
|  |             if (!add.isEmpty()) { | ||||||
|  |                 lines += text.leftJustified(m_width-10); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     Utils::printLineEditInfo(lines); | ||||||
|  |     ui->updateStatus->setText(lines.join('\n').trimmed()); | ||||||
|  |     scrollDownTextEdit(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void MainWindow::onShowMessage(QString title, QString text) { | ||||||
|  |     this->statusBar()->clearMessage(); | ||||||
|  |     this->statusBar()->showMessage( // timeout: 10000 | ||||||
|  |         QString(title + " " + text).leftJustified(80, ' '), 10000); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void MainWindow::onShowErrorMessage(QString title, QString text) { | ||||||
|  |     onShowMessage(title, text); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void MainWindow::onShowStatusMessage(QString title, QString text) { | ||||||
|  |     onShowMessage(title, text); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void MainWindow::onShowErrorMessage(QStringList lst) { | ||||||
|  |     if (lst.size() >= 2) { | ||||||
|  |         onShowMessage(lst.at(0), lst.at(1)); | ||||||
|  |     } | ||||||
|  |     if (lst.size() == 1) { | ||||||
|  |         onShowMessage(lst.at(0), ""); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void MainWindow::onShowStatusMessage(QStringList lst) { | ||||||
|  |     if (lst.size() >= 2) { | ||||||
|  |         onShowMessage(lst.at(0), lst.at(1)); | ||||||
|  |     } | ||||||
|  |     if (lst.size() == 1) { | ||||||
|  |         onShowMessage(lst.at(0), ""); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										77
									
								
								mainwindow.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										77
									
								
								mainwindow.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,77 @@ | |||||||
|  | #ifndef MAINWINDOW_H | ||||||
|  | #define MAINWINDOW_H | ||||||
|  |  | ||||||
|  | #include <QMainWindow> | ||||||
|  | #include <QTimer> | ||||||
|  | #include <QStatusBar> | ||||||
|  |  | ||||||
|  | QT_BEGIN_NAMESPACE | ||||||
|  | namespace Ui { class MainWindow; } | ||||||
|  | QT_END_NAMESPACE | ||||||
|  |  | ||||||
|  | #include "worker.h" | ||||||
|  | #include "update.h" | ||||||
|  | #include "update_dc_event.h" | ||||||
|  |  | ||||||
|  | #define EMERGENCY_LEAVE_BL 0 | ||||||
|  |  | ||||||
|  | class hwinf; | ||||||
|  | class MainWindow : public QMainWindow { | ||||||
|  |     Q_OBJECT | ||||||
|  |  | ||||||
|  | protected: | ||||||
|  |     void customEvent(QEvent *event) override; | ||||||
|  |  | ||||||
|  | public: | ||||||
|  |     MainWindow(Worker *worker, QWidget *parent = nullptr); | ||||||
|  |     ~MainWindow(); | ||||||
|  |  | ||||||
|  |     static const int START_PROGRESS_LOOP = -1; | ||||||
|  |     static const int STOP_PROGRESS_LOOP = -2; | ||||||
|  |     static const int BL_START_COUNT = 5; | ||||||
|  |     static const int BL_CHECK_COUNT = 5; | ||||||
|  |     static const int BL_IS_UP_COUNT = 5; | ||||||
|  |     static const int BL_STOP_COUNT = 5; | ||||||
|  |  | ||||||
|  |     UpdateDcEvent::UpdateStep updateStep() const { return m_updateStep; } | ||||||
|  |     void setUpdateStep(UpdateDcEvent::UpdateStep updateStep) { m_updateStep = updateStep; } | ||||||
|  |  | ||||||
|  | public slots: | ||||||
|  |     void onAppendText(QString, QString suffix = ""); | ||||||
|  |     void onReplaceLast(QStringList, QString suffix = ""); | ||||||
|  |     void onReplaceLast(QString, QString suffix = ""); | ||||||
|  |     void onShowErrorMessage(QString, QString); | ||||||
|  |     void onShowStatusMessage(QString, QString); | ||||||
|  |     void onShowErrorMessage(QStringList); | ||||||
|  |     void onShowStatusMessage(QStringList); | ||||||
|  |     void onStopStartTimer(); | ||||||
|  |     void onRestartExitTimer(); | ||||||
|  |     void onEnableExit(); | ||||||
|  |     void onDisableExit(); | ||||||
|  | #if EMERGENCY_LEAVE_BL==1 | ||||||
|  |     void emergencyLeaveBL(); | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | signals: | ||||||
|  |  | ||||||
|  | #if EMERGENCY_LEAVE_BL==1 | ||||||
|  |     void leaveBL(); | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | private slots: | ||||||
|  |     void onQuit(); | ||||||
|  |  | ||||||
|  | private: | ||||||
|  |     void scrollDownTextEdit(); | ||||||
|  |     void onShowMessage(QString, QString); | ||||||
|  |  | ||||||
|  |     Ui::MainWindow *ui; | ||||||
|  |     Worker *m_worker; | ||||||
|  |     int const m_width; | ||||||
|  |     QTimer *m_startTimer; | ||||||
|  |     QTimer *m_exitTimer; | ||||||
|  |     bool m_progressRunning; | ||||||
|  |     //int m_progressValue; | ||||||
|  |     UpdateDcEvent::UpdateStep m_updateStep; | ||||||
|  | }; | ||||||
|  | #endif // MAINWINDOW_H | ||||||
							
								
								
									
										75
									
								
								mainwindow.ui
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										75
									
								
								mainwindow.ui
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,75 @@ | |||||||
|  | <?xml version="1.0" encoding="UTF-8"?> | ||||||
|  | <ui version="4.0"> | ||||||
|  |  <class>MainWindow</class> | ||||||
|  |  <widget class="QMainWindow" name="MainWindow"> | ||||||
|  |   <property name="geometry"> | ||||||
|  |    <rect> | ||||||
|  |     <x>0</x> | ||||||
|  |     <y>0</y> | ||||||
|  |     <width>800</width> | ||||||
|  |     <height>480</height> | ||||||
|  |    </rect> | ||||||
|  |   </property> | ||||||
|  |   <property name="font"> | ||||||
|  |    <font> | ||||||
|  |     <family>Source Code Pro</family> | ||||||
|  |    </font> | ||||||
|  |   </property> | ||||||
|  |   <property name="windowTitle"> | ||||||
|  |    <string>MainWindow</string> | ||||||
|  |   </property> | ||||||
|  |   <widget class="QWidget" name="centralwidget"> | ||||||
|  |    <widget class="QWidget" name="layoutWidget"> | ||||||
|  |     <property name="geometry"> | ||||||
|  |      <rect> | ||||||
|  |       <x>10</x> | ||||||
|  |       <y>10</y> | ||||||
|  |       <width>781</width> | ||||||
|  |       <height>441</height> | ||||||
|  |      </rect> | ||||||
|  |     </property> | ||||||
|  |     <layout class="QGridLayout" name="gridLayout"> | ||||||
|  |      <item row="3" column="2"> | ||||||
|  |       <widget class="QPushButton" name="exit"> | ||||||
|  |        <property name="text"> | ||||||
|  |         <string>Exit</string> | ||||||
|  |        </property> | ||||||
|  |       </widget> | ||||||
|  |      </item> | ||||||
|  |      <item row="3" column="1"> | ||||||
|  |       <widget class="QProgressBar" name="updateProgress"> | ||||||
|  |        <property name="value"> | ||||||
|  |         <number>1</number> | ||||||
|  |        </property> | ||||||
|  |       </widget> | ||||||
|  |      </item> | ||||||
|  |      <item row="0" column="0" rowspan="3" colspan="3"> | ||||||
|  |       <widget class="QTextEdit" name="updateStatus"> | ||||||
|  |        <property name="enabled"> | ||||||
|  |         <bool>true</bool> | ||||||
|  |        </property> | ||||||
|  |        <property name="font"> | ||||||
|  |         <font> | ||||||
|  |          <family>Misc Fixed</family> | ||||||
|  |          <pointsize>11</pointsize> | ||||||
|  |          <bold>true</bold> | ||||||
|  |         </font> | ||||||
|  |        </property> | ||||||
|  |        <property name="verticalScrollBarPolicy"> | ||||||
|  |         <enum>Qt::ScrollBarAsNeeded</enum> | ||||||
|  |        </property> | ||||||
|  |        <property name="horizontalScrollBarPolicy"> | ||||||
|  |         <enum>Qt::ScrollBarAsNeeded</enum> | ||||||
|  |        </property> | ||||||
|  |        <property name="sizeAdjustPolicy"> | ||||||
|  |         <enum>QAbstractScrollArea::AdjustToContents</enum> | ||||||
|  |        </property> | ||||||
|  |       </widget> | ||||||
|  |      </item> | ||||||
|  |     </layout> | ||||||
|  |    </widget> | ||||||
|  |   </widget> | ||||||
|  |  </widget> | ||||||
|  |  <resources/> | ||||||
|  |  <connections/> | ||||||
|  | </ui> | ||||||
| @@ -2,14 +2,17 @@ | |||||||
|  |  | ||||||
| #include <QDateTime> | #include <QDateTime> | ||||||
| #include <cstring> | #include <cstring> | ||||||
|  | #include <QString> | ||||||
|  | #include <QFileInfo> | ||||||
|  | #include <QMessageLogContext> | ||||||
|  |  | ||||||
| #define OUTPUT_LEN (512) |  | ||||||
|  |  | ||||||
|  | static char const *DBG_NAME[] = { "DBG  ", "WARN ", "CRIT ", "FATAL", "INFO " }; | ||||||
| static bool installedMsgHandler = false; | static bool installedMsgHandler = false; | ||||||
| static QtMsgType debugLevel = QtInfoMsg; | static int debugLevel = LOG_NOTICE; | ||||||
|  |  | ||||||
| QtMsgType getDebugLevel() { return debugLevel; } | int getDebugLevel() { return debugLevel; } | ||||||
| void setDebugLevel(QtMsgType newDebugLevel) { | void setDebugLevel(int newDebugLevel) { | ||||||
|     debugLevel = newDebugLevel; |     debugLevel = newDebugLevel; | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -42,82 +45,51 @@ QtMessageHandler atbInstallMessageHandler(QtMessageHandler handler) { | |||||||
| /// | /// | ||||||
| #if (QT_VERSION > QT_VERSION_CHECK(5, 0, 0) && QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) | #if (QT_VERSION > QT_VERSION_CHECK(5, 0, 0) && QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) | ||||||
| void atbDebugOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg) { | void atbDebugOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg) { | ||||||
|     static constexpr const char *format = "hh:mm:ss"; |     Q_UNUSED(context); | ||||||
|     // static constexpr const char *format = "dd.MM.yyyy hh:mm:ss"; |     QString const localMsg = QString(DBG_NAME[type]) + msg.toLocal8Bit(); | ||||||
|     QByteArray localMsg = msg.toLocal8Bit(); |  | ||||||
|     const char *file = context.file ? context.file : ""; |     switch (debugLevel) { | ||||||
|     const char *function = context.function ? context.function : ""; |         case LOG_DEBUG: { // debug-level message | ||||||
|     const char *p = std::strstr(function, "::"); |             syslog(LOG_DEBUG, "%s", localMsg.toStdString().c_str()); | ||||||
|     if (p) { |         } break; | ||||||
|         function = p + 2; |         case LOG_INFO: { // informational message | ||||||
|     } |             if (type != QtDebugMsg) { | ||||||
|     char const* output = std::strrchr(file, '/'); |                 syslog(LOG_DEBUG, "%s", localMsg.toStdString().c_str()); | ||||||
|     if (output) { |  | ||||||
|         file = output + 1; |  | ||||||
|     } |  | ||||||
|     qint64 const currentMSecsSinceEpoch = QDateTime::currentMSecsSinceEpoch(); |  | ||||||
|     int const fractional_part = currentMSecsSinceEpoch % 1000; |  | ||||||
|     char buf[OUTPUT_LEN]{}; |  | ||||||
|     memset(buf, 0x00, sizeof(buf)); |  | ||||||
|     QDateTime const datetime = QDateTime::fromMSecsSinceEpoch(currentMSecsSinceEpoch); |  | ||||||
|     switch (type) { |  | ||||||
|         case QtDebugMsg: { |  | ||||||
|             if (debugLevel == QtDebugMsg) { |  | ||||||
|                 snprintf(buf, sizeof(buf)-1, "%30.30s (%20.20s:%04u) %s.%03d DEBG %s\n", |  | ||||||
|                          function, file, context.line, |  | ||||||
|                          datetime.time().toString(format).toStdString().c_str(), |  | ||||||
|                          fractional_part, |  | ||||||
|                          localMsg.constData()); |  | ||||||
|                 fprintf(stderr, "%s\n", buf); |  | ||||||
|             } |             } | ||||||
|         } break; |         } break; | ||||||
|         case QtInfoMsg: { |         case LOG_NOTICE: { // normal, but significant, condition | ||||||
|             if (debugLevel == QtInfoMsg || debugLevel == QtDebugMsg) { |             if (type != QtDebugMsg) { | ||||||
|                 snprintf(buf, sizeof(buf)-1, "%30.30s (%20.20s:%04u) %s.%03d INFO %s\n", |                 syslog(LOG_DEBUG, "%s", localMsg.toStdString().c_str()); | ||||||
|                          function, file, context.line, |  | ||||||
|                          datetime.time().toString(format).toStdString().c_str(), |  | ||||||
|                          fractional_part, |  | ||||||
|                          localMsg.constData()); |  | ||||||
|                 fprintf(stderr, "%s\n", buf); |  | ||||||
|             } |             } | ||||||
|         } break; |         } break; | ||||||
|         case QtWarningMsg: { |         case LOG_WARNING: { // warning conditions | ||||||
|             if (debugLevel == QtInfoMsg || debugLevel == QtDebugMsg || debugLevel == QtWarningMsg) { |             if (type != QtInfoMsg && type != QtDebugMsg) { | ||||||
|                 snprintf(buf, sizeof(buf)-1, "%30.30s (%20.20s:%04u) %s.%03d WARN %s\n", |                 syslog(LOG_DEBUG, "%s", localMsg.toStdString().c_str()); | ||||||
|                          function, file, context.line, |  | ||||||
|                          datetime.time().toString(format).toStdString().c_str(), |  | ||||||
|                          fractional_part, |  | ||||||
|                          localMsg.constData()); |  | ||||||
|                 fprintf(stderr, "%s\n", buf); |  | ||||||
|             } |             } | ||||||
|         } break; |         } break; | ||||||
|         case QtCriticalMsg: { |         case LOG_ERR: { // error conditions | ||||||
|             if (debugLevel == QtInfoMsg || debugLevel == QtDebugMsg |             if (type != QtInfoMsg && type != QtDebugMsg && type != QtWarningMsg) { | ||||||
|              || debugLevel == QtWarningMsg || debugLevel == QtCriticalMsg) { |                 syslog(LOG_DEBUG, "%s", localMsg.toStdString().c_str()); | ||||||
|                 snprintf(buf, sizeof(buf)-1, "%30.30s (%20.20s:%04u) %s.%03d CRIT %s\n", |  | ||||||
|                          function, file, context.line, |  | ||||||
|                          datetime.time().toString(format).toStdString().c_str(), |  | ||||||
|                          fractional_part, |  | ||||||
|                          localMsg.constData()); |  | ||||||
|                 fprintf(stderr, "%s\n", buf); |  | ||||||
|             } |             } | ||||||
|         } break; |         } break; | ||||||
|         case QtFatalMsg: { |         case LOG_CRIT: { // critical conditions | ||||||
|             if (debugLevel == QtInfoMsg || debugLevel == QtDebugMsg |             if (type != QtInfoMsg && type != QtDebugMsg && type != QtWarningMsg) { | ||||||
|              || debugLevel == QtWarningMsg || debugLevel == QtCriticalMsg |                 syslog(LOG_DEBUG, "%s", localMsg.toStdString().c_str()); | ||||||
|              || debugLevel == QtFatalMsg) { |             } | ||||||
|                 snprintf(buf, sizeof(buf)-1, "%30.30s (%20.20s:%04u) %s.%03d FATAL %s\n", |         } break; | ||||||
|                          function, file, context.line, |         case LOG_ALERT: { // action must be taken immediately | ||||||
|                          datetime.time().toString(format).toStdString().c_str(), |             if (type != QtInfoMsg && type != QtDebugMsg && type != QtWarningMsg) { | ||||||
|                          fractional_part, |                 syslog(LOG_DEBUG, "%s", localMsg.toStdString().c_str()); | ||||||
|                          localMsg.constData()); |             } | ||||||
|                 fprintf(stderr, "%s\n", buf); |         } break; | ||||||
|  |         case LOG_EMERG: { // system is unusable | ||||||
|  |             if (type != QtInfoMsg && type != QtDebugMsg && type != QtWarningMsg) { | ||||||
|  |                 syslog(LOG_DEBUG, "%s", localMsg.toStdString().c_str()); | ||||||
|             } |             } | ||||||
|         } break; |         } break; | ||||||
|         default: { |         default: { | ||||||
|             fprintf(stderr, "%*.*s.%03d No ErrorLevel defined! %s\n", OUTPUT_LEN, OUTPUT_LEN, |             //fprintf(stderr, "%s No ErrorLevel defined! %s\n", | ||||||
|                 datetime.time().toString(format).toStdString().c_str(), fractional_part, |             //    datetime.toStdString().c_str(), msg.toStdString().c_str()); | ||||||
|                 msg.toStdString().c_str()); |  | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -2,9 +2,12 @@ | |||||||
| #define MESSAGE_HANDLER_H_INCLUDED | #define MESSAGE_HANDLER_H_INCLUDED | ||||||
|  |  | ||||||
| #include <QtGlobal> | #include <QtGlobal> | ||||||
|  | #ifdef __linux__ | ||||||
|  | #include <syslog.h> | ||||||
|  | #endif | ||||||
|  |  | ||||||
| QtMsgType getDebugLevel(); | int getDebugLevel(); | ||||||
| void setDebugLevel(QtMsgType newDebugLevel); | void setDebugLevel(int newDebugLevel); | ||||||
|  |  | ||||||
| bool messageHandlerInstalled(); | bool messageHandlerInstalled(); | ||||||
| QtMessageHandler atbInstallMessageHandler(QtMessageHandler handler); | QtMessageHandler atbInstallMessageHandler(QtMessageHandler handler); | ||||||
|   | |||||||
							
								
								
									
										410
									
								
								plugins/interfaces.h
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							
							
						
						
									
										410
									
								
								plugins/interfaces.h
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							| @@ -3,7 +3,7 @@ | |||||||
|  |  | ||||||
| #include <QtPlugin> | #include <QtPlugin> | ||||||
|  |  | ||||||
| #define THIS_IS_CA_MASTER |  | ||||||
|  |  | ||||||
| struct T_emp | struct T_emp | ||||||
| { | { | ||||||
| @@ -128,28 +128,24 @@ struct T_vaultRecord | |||||||
|         uint32_t AbsReserve; |         uint32_t AbsReserve; | ||||||
|         uint32_t AbsNrOfCuts; |         uint32_t AbsNrOfCuts; | ||||||
|  |  | ||||||
| //16 |  | ||||||
|         char label3buffer[4];	// mw > |         char label3buffer[4];	// mw > | ||||||
|  |  | ||||||
|         // Verkauf, T<EFBFBD>r zu: |         // Verkauf, Tuer zu: | ||||||
|         uint32_t VKcoinsInserted[16];		// nur f<EFBFBD>r Wechsler, soviel wurde eingeworfen |         uint32_t VKcoinsInserted[16];		// nur fuer Wechsler, soviel wurde eingeworfen | ||||||
|         uint32_t VKcoinsReturned[6];		// nur f<EFBFBD>r Wechsler, Anzahl M<EFBFBD>nzen pro Typ, soviel wurde zur<EFBFBD>ckgegeben |         uint32_t VKcoinsReturned[6];		// nur fuer Wechsler, Anzahl Muenzen pro Typ, soviel wurde zurueckgegeben | ||||||
| //88 |  | ||||||
|  |  | ||||||
|         // Service, T<EFBFBD>r offen: |         // Service, Tuer offen: | ||||||
|         uint16_t ServCoinsInserted[16];		// nur f<EFBFBD>r Wechsler, soviel wurde eingeworfen |         uint16_t ServCoinsInserted[16];		// nur fuer Wechsler, soviel wurde eingeworfen | ||||||
|         uint16_t ServCoinsReturned[6];		// nur f<EFBFBD>r Wechsler, Anzahl M<EFBFBD>nzen pro Typ, soviel wurde zur<EFBFBD>ckgegeben |         uint16_t ServCoinsReturned[6];		// nur fuer Wechsler, Anzahl Muenzen pro Typ, soviel wurde zurueckgegeben | ||||||
|         uint16_t resint3; |         uint16_t resint3; | ||||||
|         uint16_t resint4; |         uint16_t resint4; | ||||||
|         uint16_t currentTubeContent[6];		//  nur f<EFBFBD>r Wechsler, aktueller F<EFBFBD>llstand |         uint16_t currentTubeContent[6];		//  nur fuer Wechsler, aktueller Fuellstand | ||||||
|         uint16_t resint5; |         uint16_t resint5; | ||||||
|         uint16_t resint6; |         uint16_t resint6; | ||||||
| // 56 |  | ||||||
|  |  | ||||||
|         char label4buffer[4];	// box> |         char label4buffer[4];	// box> | ||||||
|         uint16_t coinsInVault[16]; |         uint16_t coinsInVault[16]; | ||||||
|         uint16_t billsInStacker[8]; |         uint16_t billsInStacker[8]; | ||||||
| // 48 |  | ||||||
|  |  | ||||||
|         char label5buffer[4];	// val> |         char label5buffer[4];	// val> | ||||||
|         // actually constant unless exchange rate is changed |         // actually constant unless exchange rate is changed | ||||||
| @@ -159,11 +155,17 @@ struct T_vaultRecord | |||||||
|         uint16_t exchangeRate; |         uint16_t exchangeRate; | ||||||
|         uint16_t resint9; |         uint16_t resint9; | ||||||
|  |  | ||||||
| // 64 |         // new from 1.8.23 | ||||||
|  |         uint32_t cutsSinceCBchange; | ||||||
|  |         uint32_t CBcontent_cent; | ||||||
|  |         uint32_t CBnrofCoins; | ||||||
|  |  | ||||||
|         char endofblock[4];	// end> |         char endofblock[4];	// end | ||||||
|  | // 332 bytes | ||||||
|  |  | ||||||
| // 316 byte Block im Speicher |         uint16_t CRC16;     // Xmodem16 from startbuffer[0] to endofblock[3] | ||||||
|  |         uint16_t resint11; | ||||||
|  |         char  endofRecord[4];	// ---- | ||||||
|  |  | ||||||
| }; | }; | ||||||
|  |  | ||||||
| @@ -191,7 +193,7 @@ struct T_moduleCondition | |||||||
|         uint8_t	coinChecker;		// EMP, OMP or mei-cashflow |         uint8_t	coinChecker;		// EMP, OMP or mei-cashflow | ||||||
|  |  | ||||||
|         uint8_t	coinEscrow; |         uint8_t	coinEscrow; | ||||||
|         uint8_t	mifareReader; |         uint8_t	mifareReader;       // 0: unknown  1=OK  200=no response  201=wrong response   202: Reader reports HW-error | ||||||
|         uint8_t	creditTerm; |         uint8_t	creditTerm; | ||||||
|         uint8_t	coinReject; |         uint8_t	coinReject; | ||||||
|  |  | ||||||
| @@ -201,7 +203,7 @@ struct T_moduleCondition | |||||||
|         uint8_t   temper; |         uint8_t   temper; | ||||||
|  |  | ||||||
|         uint8_t	poweronTest; |         uint8_t	poweronTest; | ||||||
|         uint8_t   doorState;			// 1: alles zu  200: t?r offen + bit1(S) +bit2(CB) + bit3(CB) |         uint8_t   doorState;			// 1: alles zu  200: tuer offen + bit1(S) +bit2(CB) + bit3(CB) | ||||||
|         uint8_t	doorWasOpened;		// 1: all doors are closed   200: any door was just opened |         uint8_t	doorWasOpened;		// 1: all doors are closed   200: any door was just opened | ||||||
|         uint8_t	changer;			// can only be tested by usage |         uint8_t	changer;			// can only be tested by usage | ||||||
|  |  | ||||||
| @@ -315,9 +317,10 @@ struct T_devices | |||||||
|     // set by master, used(1) or notused (0) or type 2....20 |     // set by master, used(1) or notused (0) or type 2....20 | ||||||
|  |  | ||||||
|     UCHAR   kindOfPrinter;			// 0:off   1:Gebe |     UCHAR   kindOfPrinter;			// 0:off   1:Gebe | ||||||
|     UCHAR	kindOfCoinChecker;		// 0: without  1=EMP820   2=EMP900    3=currenza c<EFBFBD>	(MW) |     UCHAR	kindOfCoinChecker;		// 0: without  1=EMP820   2=EMP900    3=currenza Csquare  (MW) | ||||||
|     UCHAR	kindOfMifareReader;		// by now only stronglink SL025 =1 |     UCHAR	kindOfMifareReader;		// by now only stronglink SL025 =1 | ||||||
|     UCHAR   suppressSleepMode;		// 0:sleep allowed   1: no sleep |     UCHAR   solarPower;             // 1:sleep allowed   0: no sleep | ||||||
|  |     //UCHAR   suppressSleepMode;	// 0:sleep allowed   1: no sleep | ||||||
|  |  | ||||||
|     UCHAR	kindOfModem;			// 0:off    1:Sunlink |     UCHAR	kindOfModem;			// 0:off    1:Sunlink | ||||||
|     UCHAR	kindOfCreditcard;		// 0:off    1:Feig NFC |     UCHAR	kindOfCreditcard;		// 0:off    1:Feig NFC | ||||||
| @@ -336,10 +339,46 @@ struct T_devices | |||||||
|  |  | ||||||
|     UINT	VaultFullWarnLevel; |     UINT	VaultFullWarnLevel; | ||||||
|     UINT	VaultFullErrorLevel; |     UINT	VaultFullErrorLevel; | ||||||
|  |     UINT    BattEmptyWarnLevel; | ||||||
|  |     UINT    BattEmptyErrorLevel; | ||||||
|  |  | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | struct T_chg_Tub | ||||||
|  | { | ||||||
|  |  | ||||||
|  |     uint8_t  tubeLevel[8];      // [0]=nr coins of lowest value | ||||||
|  |     uint8_t  tubeFull[8];       // 1=full  0 else | ||||||
|  |     uint16_t tubeValues[8];     // in cent [0]=lowest value 5c or 10cent | ||||||
|  |     uint16_t tubeFilled[8];     // nr of every coin inserted | ||||||
|  |     uint16_t tubeDispens[8];     // nr of every coin dispensed | ||||||
|  |     // 64 byte | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | struct T_changer | ||||||
|  | { | ||||||
|  |     // Fixdata from Coin Changer | ||||||
|  |     uint8_t setup;  	// always 1 | ||||||
|  |     uint8_t state;  	// step of state machine | ||||||
|  |         // 0..12 like EMP, 13...30 for coin dispense | ||||||
|  |  | ||||||
|  |     uint8_t level;      // mdb-level, always 3 | ||||||
|  |     uint16_t countryCode; | ||||||
|  |     uint8_t scale; | ||||||
|  |     uint8_t decimals; | ||||||
|  |     uint8_t coinSetup[16];  // [0]=lowest coin, multiply with scale | ||||||
|  |     uint16_t intendedAcceptance;    //bitwise 0,1 1=accept coin, came from master | ||||||
|  |     uint8_t tokenChannel; | ||||||
|  |     uint8_t pollingRunning;		// 1: emp is polled  0:not | ||||||
|  |     uint8_t paymentRunning;	// 1: coins are accepted | ||||||
|  |     uint16_t denomination[16]; | ||||||
|  |     uint16_t availableTubes; //bitwise 0,1 1=av. bit0 = lowest coin value | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | struct T_bna | ||||||
|  | { | ||||||
|  |  | ||||||
|  | }; | ||||||
|  |  | ||||||
| class hwinf | class hwinf | ||||||
| { | { | ||||||
| @@ -357,7 +396,7 @@ public: | |||||||
|     //      Furthermore the Cashagent-Library answers with status strings about sending and reading result |     //      Furthermore the Cashagent-Library answers with status strings about sending and reading result | ||||||
|     // $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ |     // $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ | ||||||
|  |  | ||||||
| #ifdef THIS_IS_CA_MASTER |  | ||||||
|     virtual bool dc_openSerial(int BaudNr, QString BaudStr, QString ComName, uint8_t connect)  const =0; |     virtual bool dc_openSerial(int BaudNr, QString BaudStr, QString ComName, uint8_t connect)  const =0; | ||||||
|         // Command: open serial interface |         // Command: open serial interface | ||||||
|         // BaudNr:  0:1200   1:9600   2:19200   3:38400   4:57600   5:115200 |         // BaudNr:  0:1200   1:9600   2:19200   3:38400   4:57600   5:115200 | ||||||
| @@ -368,7 +407,7 @@ public: | |||||||
|     virtual void dc_closeSerial(void)  const =0; |     virtual void dc_closeSerial(void)  const =0; | ||||||
|         // Command: close serial interface in order to save power while power down |         // Command: close serial interface in order to save power while power down | ||||||
|         // or if another port must be used |         // or if another port must be used | ||||||
| #endif |  | ||||||
|  |  | ||||||
|     virtual bool dc_isPortOpen(void)  const =0; |     virtual bool dc_isPortOpen(void)  const =0; | ||||||
|         // returns true if port open (don't send unless open. Sending to closed port will crash program)                          |         // returns true if port open (don't send unless open. Sending to closed port will crash program)                          | ||||||
| @@ -394,7 +433,7 @@ public: | |||||||
|         // get data back in "payLoad", max 64 byte, can be used for diagnosis |         // get data back in "payLoad", max 64 byte, can be used for diagnosis | ||||||
|         // retval = nr of bytes received. If host buffer too small then |         // retval = nr of bytes received. If host buffer too small then | ||||||
|         // only plBufSiz bytes are copied to "payLoad" |         // only plBufSiz bytes are copied to "payLoad" | ||||||
|         // plBufSiz<EFBFBD>z=size of host buffer |         // plBufSiz = size of host buffer | ||||||
|  |  | ||||||
|     virtual void dc_setWakeFrequency(uint8_t period)  const =0; |     virtual void dc_setWakeFrequency(uint8_t period)  const =0; | ||||||
|         // RTC wakes DC2 (and PTU) by hardware signal every 32seconds |         // RTC wakes DC2 (and PTU) by hardware signal every 32seconds | ||||||
| @@ -403,7 +442,7 @@ public: | |||||||
|     virtual void dc_OrderToReset(void)  const =0; |     virtual void dc_OrderToReset(void)  const =0; | ||||||
|         // want DC2 to reset (in order to start Bootloader) |         // want DC2 to reset (in order to start Bootloader) | ||||||
|  |  | ||||||
| #ifdef THIS_IS_CA_MASTER |  | ||||||
|     virtual QString dc_getSerialState(void)  const =0; |     virtual QString dc_getSerialState(void)  const =0; | ||||||
|         // get result of opening-command like "ttyS0 opened with 115200 8N1! |         // get result of opening-command like "ttyS0 opened with 115200 8N1! | ||||||
|         // or error messages like "comport not available..." |         // or error messages like "comport not available..." | ||||||
| @@ -411,7 +450,7 @@ public: | |||||||
|  |  | ||||||
|     virtual void dc_clrSerialStateText(void)  const =0; |     virtual void dc_clrSerialStateText(void)  const =0; | ||||||
|         // clear above text to avoid multiple repetive displaying |         // clear above text to avoid multiple repetive displaying | ||||||
| #endif |  | ||||||
|  |  | ||||||
|     virtual void bl_sendDataDirectly(uint8_t length, uint8_t *buf)  const =0; |     virtual void bl_sendDataDirectly(uint8_t length, uint8_t *buf)  const =0; | ||||||
|         // send without protocol frame, needed for the DC bootloader |         // send without protocol frame, needed for the DC bootloader | ||||||
| @@ -496,10 +535,10 @@ public: | |||||||
|  |  | ||||||
|     // Analog values: |     // Analog values: | ||||||
|     virtual uint32_t dc_getTemperature(void)  const =0; |     virtual uint32_t dc_getTemperature(void)  const =0; | ||||||
|         // in Sax-Format 0...400 (0=-50,0<EFBFBD>C    100=0,0<EFBFBD>C    141=20,5<EFBFBD>C    400=150,0<EFBFBD>C) |         // in Sax-Format 0...400 (0=-50,0degC    100=0,0degC    141=20,5degC    400=150,0degC) | ||||||
|  |  | ||||||
|     virtual QString  dc_getTemperaturStr(void)  const =0; |     virtual QString  dc_getTemperaturStr(void)  const =0; | ||||||
|         // as string like "-12,5<EFBFBD>C" |         // as string like "-12,5degC" | ||||||
|  |  | ||||||
|     virtual uint32_t dc_getVoltage(void)  const =0; |     virtual uint32_t dc_getVoltage(void)  const =0; | ||||||
|         // as value in mV,  0...65,535V |         // as value in mV,  0...65,535V | ||||||
| @@ -760,7 +799,7 @@ public: | |||||||
|                             uint8_t kindOfModem,        uint8_t kindOfCredit        ) const =0; |                             uint8_t kindOfModem,        uint8_t kindOfCredit        ) const =0; | ||||||
|     // enable hardware in device controller: |     // enable hardware in device controller: | ||||||
|     // kindOfPrinter:       0:off 1: GPT4672 (only this one implemented) |     // kindOfPrinter:       0:off 1: GPT4672 (only this one implemented) | ||||||
|     // kindOfCoinChecker:   0:off 1:EMP820 2:EMP900 3: C<EFBFBD>_changer |     // kindOfCoinChecker:   0:off 1:EMP820 2:EMP900 3: Csquare_changer | ||||||
|     // kindOfMifareReader:  0:off 1: SL025   (only this one implemented) |     // kindOfMifareReader:  0:off 1: SL025   (only this one implemented) | ||||||
|     // suppressSleep:       0:sleep allowed 1: sleep surpressed for special reason |     // suppressSleep:       0:sleep allowed 1: sleep surpressed for special reason | ||||||
|     // kindOfModem:         0:off 1: ATB_Sunlink_LTE        (not yet implemented) |     // kindOfModem:         0:off 1: ATB_Sunlink_LTE        (not yet implemented) | ||||||
| @@ -813,7 +852,7 @@ public: | |||||||
| // --------------------------------------------- MIFARE ----------------------------------------------------- | // --------------------------------------------- MIFARE ----------------------------------------------------- | ||||||
| // ---------------------------------------------------------------------------------------------------------- | // ---------------------------------------------------------------------------------------------------------- | ||||||
|  |  | ||||||
|  | // obsolete | ||||||
|     virtual uint8_t mif_returnReaderStateAndCardType(uint8_t *buf, uint8_t maxBufferSize) const =0; |     virtual uint8_t mif_returnReaderStateAndCardType(uint8_t *buf, uint8_t maxBufferSize) const =0; | ||||||
|         // retval 0=OK 1=error host buffer too small |         // retval 0=OK 1=error host buffer too small | ||||||
|     /* data description, new fast version: |     /* data description, new fast version: | ||||||
| @@ -835,13 +874,16 @@ public: | |||||||
|     virtual bool mif_readerIsOK(void) const =0; |     virtual bool mif_readerIsOK(void) const =0; | ||||||
|  |  | ||||||
|     virtual bool mif_cardAttached(void) const =0; |     virtual bool mif_cardAttached(void) const =0; | ||||||
|  |         // not working! use mif_cardIsAttached() instead | ||||||
|  |  | ||||||
|     virtual uint8_t mif_readResult(void) const =0; |     virtual uint8_t mif_readResult(void) const =0; | ||||||
|         // result: 0: unknown or still in progress |         // result: 0: unknown or still in progress | ||||||
|         //         1: card read successful |         //         1: card read successful | ||||||
|         //         2: reading error |         //         2: reading error | ||||||
|  |         // not working! | ||||||
|  |  | ||||||
|     virtual QString mif_cardUID(void) const =0; |     virtual QString mif_cardUID(void) const =0; | ||||||
|  |         // not working | ||||||
|  |  | ||||||
|     virtual uint8_t mif_getCardDataDec(uint8_t blkNr, uint8_t *buf, uint8_t maxBufferSize) const =0; |     virtual uint8_t mif_getCardDataDec(uint8_t blkNr, uint8_t *buf, uint8_t maxBufferSize) const =0; | ||||||
|  |  | ||||||
| @@ -886,7 +928,7 @@ public: | |||||||
|         // send 5 byte: byte 0,1: speed  5...250 mm/s |         // send 5 byte: byte 0,1: speed  5...250 mm/s | ||||||
|         //              byte2: density   0....(25)....50 |         //              byte2: density   0....(25)....50 | ||||||
|         //              byte3: alignment    'l', 'c', 'r' = left, center, right |         //              byte3: alignment    'l', 'c', 'r' = left, center, right | ||||||
|         //              byte4: orientation  0, 90, 180    = 0<EFBFBD>, 90<EFBFBD>, 180<EFBFBD> rotation (by now not supported!) |         //              byte4: orientation  0, 90, 180    = 0deg, 90deg, 180deg rotation (by now not supported!) | ||||||
|         // not batched! don't use twice within 100ms |         // not batched! don't use twice within 100ms | ||||||
|  |  | ||||||
|     virtual void prn_movePaper(uint8_t wayInMm, uint8_t direction) const =0; |     virtual void prn_movePaper(uint8_t wayInMm, uint8_t direction) const =0; | ||||||
| @@ -1018,7 +1060,7 @@ public: | |||||||
|         // use for changer |         // use for changer | ||||||
|  |  | ||||||
|  |  | ||||||
| #ifdef THIS_IS_CA_MASTER |  | ||||||
|     virtual QString dc_getTxt4RsDiagWin(void) const =0; |     virtual QString dc_getTxt4RsDiagWin(void) const =0; | ||||||
|     virtual void dc_clrTxt4RsDiagWin(void) const =0; |     virtual void dc_clrTxt4RsDiagWin(void) const =0; | ||||||
|     virtual QString dc_get2ndTxt4RsDiagWin(void) const =0; |     virtual QString dc_get2ndTxt4RsDiagWin(void) const =0; | ||||||
| @@ -1033,7 +1075,6 @@ public: | |||||||
|     virtual void dc_clrTxt4dataStateLine(void) const =0; |     virtual void dc_clrTxt4dataStateLine(void) const =0; | ||||||
|     virtual QString dc_getdatifLine(void) const =0; |     virtual QString dc_getdatifLine(void) const =0; | ||||||
|     virtual void dc_clrTxt4datifLine(void) const =0; |     virtual void dc_clrTxt4datifLine(void) const =0; | ||||||
| #endif |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -1152,14 +1193,13 @@ public: | |||||||
|         // to be forwarded to Ismas |         // to be forwarded to Ismas | ||||||
|  |  | ||||||
|     virtual bool prn_printAccountReceipt(void) const =0; |     virtual bool prn_printAccountReceipt(void) const =0; | ||||||
|  |         // print all 8 backuped accounting receipts | ||||||
|         // return true if sending to DC OK, false if cmd-stack is full |         // return true if sending to DC OK, false if cmd-stack is full | ||||||
|  |  | ||||||
|     virtual bool prn_printTestTicket(void) const =0; |     virtual bool prn_printTestTicket(void) const =0; | ||||||
|         // return true if sending to DC OK, false if cmd-stack is full |         // return true if sending to DC OK, false if cmd-stack is full | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|     virtual bool cash_startPayment(uint32_t amount) const =0; |     virtual bool cash_startPayment(uint32_t amount) const =0; | ||||||
|         // 17.4.23TS: extended to 32bit |         // 17.4.23TS: extended to 32bit | ||||||
|  |  | ||||||
| @@ -1178,7 +1218,7 @@ public: | |||||||
|     virtual uint16_t getLastInsertedCoin(void) const =0; |     virtual uint16_t getLastInsertedCoin(void) const =0; | ||||||
|  |  | ||||||
|     virtual bool getAllInsertedCoins(uint16_t *types, uint16_t *values) const =0; |     virtual bool getAllInsertedCoins(uint16_t *types, uint16_t *values) const =0; | ||||||
|         // alle bei diesem Verkauf eingeworfenen M<EFBFBD>nzen sind gespeichert, max 64 |         // alle bei diesem Verkauf eingeworfenen Muenzen sind gespeichert, max 64 | ||||||
|  |  | ||||||
|  |  | ||||||
|     virtual bool cash_cancelPayment(void) const =0; |     virtual bool cash_cancelPayment(void) const =0; | ||||||
| @@ -1232,6 +1272,8 @@ public: | |||||||
|  |  | ||||||
|     virtual uint8_t prn_getPrintResult() const =0; |     virtual uint8_t prn_getPrintResult() const =0; | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|     virtual uint8_t prn_getCurrentPrinterState() const =0; |     virtual uint8_t prn_getCurrentPrinterState() const =0; | ||||||
|         //        0: printer OK |         //        0: printer OK | ||||||
|         //          bit0: near paper end          bit1: no paper |         //          bit0: near paper end          bit1: no paper | ||||||
| @@ -1244,6 +1286,8 @@ public: | |||||||
|     virtual void sys_sendDeviceParameter(struct T_devices *deviceSettings) const =0; |     virtual void sys_sendDeviceParameter(struct T_devices *deviceSettings) const =0; | ||||||
|  |  | ||||||
|     virtual void sys_restoreDeviceParameter(struct T_devices *deviceSettings) const =0; |     virtual void sys_restoreDeviceParameter(struct T_devices *deviceSettings) const =0; | ||||||
|  |         // attention: only applies if function "sys_sendDeviceParameter()" was used to send this settings before | ||||||
|  |         //          cannot be used to see settings programmed by JsonFile | ||||||
|  |  | ||||||
|     virtual bool sys_areDCdataValid(void) const =0; |     virtual bool sys_areDCdataValid(void) const =0; | ||||||
|  |  | ||||||
| @@ -1268,6 +1312,279 @@ public: | |||||||
|  |  | ||||||
|     virtual bool dc_isAutoRequestOn(void) const =0; |     virtual bool dc_isAutoRequestOn(void) const =0; | ||||||
|  |  | ||||||
|  |     virtual uint16_t log_getLatestAccountNumber(void) const=0; | ||||||
|  |     // new function 27.6.2023 | ||||||
|  |     // latest = highest of the backup's | ||||||
|  |  | ||||||
|  |     virtual uint8_t log_getAvailableVaultBlocks(void) const=0; | ||||||
|  |         // return 0x0011 1111 if all 6 blocks are loaded (one bit per block) | ||||||
|  |  | ||||||
|  |     virtual uint8_t log_getAnswerToLastSlaveRequest(void) const =0; | ||||||
|  |         // use only for ONE request/command | ||||||
|  |         // return: 0xFF: result unknown by now as sending is ongoing | ||||||
|  |         // 0=OK | ||||||
|  |         // 1= wrong length    2=wrong start sign           5= wrong crc | ||||||
|  |         // 6= slave: master cmd was wrong       7: slave: could not write/read data | ||||||
|  |         // 8=timeout, got no response from slave | ||||||
|  |         // 0,8 work, 1..6 not yet tested. 8 comes immed. and stays 8 until reconnect | ||||||
|  |  | ||||||
|  |     // use for important and extended commands (print several templates, print ticket...) | ||||||
|  |     virtual void log_startSupervision(void) const =0; | ||||||
|  |  | ||||||
|  |     virtual uint8_t log_getAnswerToLastCmdBatch(void) const =0; | ||||||
|  |         // 0xFF: no command sent by now | ||||||
|  |         // 0: started, in progress | ||||||
|  |         // 1: done and OK | ||||||
|  |         // 2: done and error | ||||||
|  |         // not working properly, always 0 | ||||||
|  |  | ||||||
|  |     virtual bool log_getVaultData(uint8_t *data) const =0; | ||||||
|  |         // get vault record in linear 8bit buffer with 384 byte | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     // new from 1.8.23 | ||||||
|  |     virtual bool prn_printOneAccountReceipt(uint16_t accountNr) const =0; | ||||||
|  |         // print one out of eight stored last accounting receipts | ||||||
|  |         // function log_getHoldAccountNumbers() gives a list of acc-Nr. of the stored receipts | ||||||
|  |  | ||||||
|  |     virtual bool prn_printAllAvailAccountReceipts(void) const =0; | ||||||
|  |         // same as: prn_printAccountReceipt() from line 1153 | ||||||
|  |         // return true if sending to DC OK, false if cmd-stack is full | ||||||
|  |  | ||||||
|  |     virtual bool log_verifyVaultRecordByCrc(void) const =0; | ||||||
|  |         // return true if CRC16 is correct, data are 100% OK. Security level 1:65536 | ||||||
|  |         // verification is strongly recommended before further processing | ||||||
|  |         // in case of "false"-result please reload from DC | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     virtual uint16_t log_DC_getNextAccountNumber(void) const=0; | ||||||
|  |         // the current cash box content will be backuped with this number on next cashbox-change | ||||||
|  |  | ||||||
|  |     virtual void log_DC_setNextAccountNumber(uint16_t newAccountingNumber) const=0; | ||||||
|  |         // the current cash box content will be backuped with this number on next cashbox-change | ||||||
|  |         // use only in case of hardware replacements or errors which derailed the number | ||||||
|  |  | ||||||
|  |     virtual void log_DC_deleteAllVaultrecordsInDc(void) const=0; | ||||||
|  |         // use only in case of hardware replacements or errors which derailed the number | ||||||
|  |  | ||||||
|  |     virtual void log_DC_deleteAllTotalCounters(void) const=0; | ||||||
|  |         // use only in case of hardware replacements or errors which derailed the number | ||||||
|  |  | ||||||
|  |     virtual void dc_setNewCustomerNumber(uint16_t newCustNr) const =0; | ||||||
|  |  | ||||||
|  |     virtual void dc_setNewMachineNumber(uint16_t newMachNr) const =0; | ||||||
|  |  | ||||||
|  |     virtual void dc_setNewBorough(uint16_t newBorough) const =0; | ||||||
|  |  | ||||||
|  |     virtual void dc_setNewZone(uint16_t newZone) const =0; | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     // new functions from 8.9.23 | ||||||
|  |     virtual QString mif_getReaderType(void) const =0; | ||||||
|  |         // return "SL025" if correct reader is connected | ||||||
|  |  | ||||||
|  |     virtual void mif_getCardSize(uint8_t *cardSize, uint8_t *idLeng) const =0; | ||||||
|  |         // cardSize=1k or 4kByte | ||||||
|  |         // idLeng =4Byte or 7 byte | ||||||
|  |  | ||||||
|  |     virtual char mif_getAtbCardData(uint8_t *buf, uint8_t maxBuffSiz) const =0; | ||||||
|  |         // return complete buffer binary, just for test purpose | ||||||
|  |  | ||||||
|  |     virtual bool mif_isValidAtbCard(void) const =0; | ||||||
|  |  | ||||||
|  |     virtual uint32_t mif_getAtbCardCuNu(void) const =0; | ||||||
|  |  | ||||||
|  |     virtual uint8_t mif_getAtbCardTyp(void) const =0; | ||||||
|  |         // return 1=upper door card     1=lower door    3=printer-test   4=coin-test | ||||||
|  |         //          0: not a valid atb2020 card | ||||||
|  |  | ||||||
|  |     virtual QString mif_getAtbCardPerso(void) const =0; | ||||||
|  |         // e.g. "PNsax001" used for personal number, name shortcode, card number | ||||||
|  |         // free to use, can be set in AtbMcw23.exe tool | ||||||
|  |  | ||||||
|  |     virtual void mif_getAtbCardExpire(uint8_t *year, uint8_t *month, uint8_t *day, uint8_t *hour, uint8_t *minute) const =0; | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     // ------------------------------------------------------------------------------------ | ||||||
|  |     //    Device-Controller-Bootloader convenient version 21.09.2023 | ||||||
|  |     // ------------------------------------------------------------------------------------ | ||||||
|  |  | ||||||
|  |     // use this to jump to BL: | ||||||
|  |     //void hwapi::bl_rebootDC(void) const | ||||||
|  |  | ||||||
|  |     // use this to start BL: | ||||||
|  |     // void hwapi::bl_startBL(void) const | ||||||
|  |  | ||||||
|  |     // call this in order to get response from BL: | ||||||
|  |     //void hwapi::bl_checkBL(void) const | ||||||
|  |  | ||||||
|  |     // evaluate BL response: | ||||||
|  |     //bool hwapi::bl_isUp(void) const | ||||||
|  |  | ||||||
|  |     // 29.9.23: new: "completeStart" function, replaces bl_rebootDC(), bl_startBL() and bl_checkBL() | ||||||
|  |     // result can be verified with bl_isUp() as before | ||||||
|  |     virtual bool bl_completeStart(void) const =0; | ||||||
|  |         // must be used in DC's normal operation | ||||||
|  |  | ||||||
|  |     // select binfile-name in GUI | ||||||
|  |  | ||||||
|  |     // send binfile-name to BL-processor: | ||||||
|  |     virtual bool bl_storeFirmware(QString fileName) const =0; | ||||||
|  |         // load binary file 3x and compare | ||||||
|  |         // return true if loaded correctly | ||||||
|  |         // return false:  error, could not load correctly | ||||||
|  |  | ||||||
|  |     // request the number of blocks for this file | ||||||
|  |     virtual uint16_t bl_getNrOfFirmwareBlocks(void) const =0; | ||||||
|  |         // size of the loaded bin file in 64byte blocks | ||||||
|  |         // call after bl_storeFirmware() | ||||||
|  |  | ||||||
|  |     // call the next two function's repetitive with "blockNumber"=0,1,2,3....."bl_getNrOfFirmwareBlocks()" | ||||||
|  |  | ||||||
|  |     virtual bool bl_blockAutoLoad(uint16_t blockNumber) const =0; | ||||||
|  |         // call in loop from block number 0 up to <= "dcBL_getNrOfBlocks()" | ||||||
|  |         //the last block "bl_getNrOfFirmwareBlocks()" is sent as conclusion command (important!) | ||||||
|  |         // but after every call WAIT (!) for response "bl_blockAutoResponse()" !!!! | ||||||
|  |         // data will be sent to DC, if neccesary addr will be sent additionally | ||||||
|  |         // if neccesary sending will automatically repeat up to 3times | ||||||
|  |         // retval: false if blockNumber>4095, true else | ||||||
|  |  | ||||||
|  |     // check out this response after every block-sending, wait until >0!!! | ||||||
|  |     virtual int8_t bl_blockAutoResponse(void) const =0; | ||||||
|  |         // after every "bl_blockAutoLoad()" call this until response | ||||||
|  |         // retval  0: wait   1: OK, blk was sent    2: OK, transfer complete | ||||||
|  |         //         3: error despite repeating, cancel. probably bin file corrupted | ||||||
|  |         //      Max duration: 3x no response from BL = 900ms | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     // finally call: | ||||||
|  |     // void hwapi::bl_stopBL(void) const | ||||||
|  |     // -------------- end of bootloader --------------------------------------------------- | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     // new from 28.9.23 and earliest from DC version 4.45 | ||||||
|  |     // get all versions of the DC-Jsons | ||||||
|  |     virtual void sys_requestJsonVersions(uint8_t  jsonNr) const =0; | ||||||
|  |         // send one request for every single version | ||||||
|  |         // jsonNr=1...36, 1=config file (cust.Nr) 2=devices  3=cash  4=res. | ||||||
|  |         //      5=printer template 1 ..... 36= template 32 | ||||||
|  |  | ||||||
|  |     virtual void sys_getJsonVersions(uint8_t  jsonNr, char *versionString) const =0; | ||||||
|  |         // jsonNr=1...36, 1=config file (cust.Nr) 2=devices  3=cash  4=res. | ||||||
|  |         //      5=printer template 1 ..... 36= template 32 | ||||||
|  |         // length of buffer is always 16 byte | ||||||
|  |  | ||||||
|  |     // ------------------------------------------------------------------------------------ | ||||||
|  |     //   Coin Changer | ||||||
|  |     // ------------------------------------------------------------------------------------ | ||||||
|  |  | ||||||
|  |     // find above (same as for coin checker (EMP)): | ||||||
|  |  | ||||||
|  |     // mdb_switchPower(true);       // power on/off | ||||||
|  |     // cash_startPayment(amount_cent); // start polling, enable coins, changer turns to green | ||||||
|  |  | ||||||
|  |     // getInsertedAmount() | ||||||
|  |     // getLastInsertedCoin() | ||||||
|  |     // getAllInsertedCoins(uint16_t *types, uint16_t *values) | ||||||
|  |         // all inserted coins of this past transaction are stored, max 64 | ||||||
|  |  | ||||||
|  |     // cash_stopPayment();      // and wait for further command (changer blinks yellow) | ||||||
|  |     // cash_cancelPayment();    // and return complete paid amount | ||||||
|  |  | ||||||
|  |     // after ticket/goods issue: | ||||||
|  |     // vend_success() | ||||||
|  |         // conclude payment process, keep all coins. Printing was successful | ||||||
|  |         // return change (payment above start-amount), so it works only if | ||||||
|  |         //  Payment was started with real vending price (pre selection). | ||||||
|  |         // if payment was started with maximum price (for direct coin insertion) | ||||||
|  |         // then use "changer_returnCoins()", not vend_success() | ||||||
|  |  | ||||||
|  |     // vend_failed() | ||||||
|  |         // conclude payment process and return complete paid amount | ||||||
|  |  | ||||||
|  |     // also valid for changer: | ||||||
|  |     // emp_sendSettings(uint16_t coinAcceptance, uint8_t tokenChannel, uint16_t *coinDenomination ) const =0; | ||||||
|  |         // coinAcceptance: bit0=coin1 (lowest donomination)  bit15=coin16  bitH=accept  bit L = deny coin (no validation) | ||||||
|  |         // tokenChannel 0...31: if this signal comes from emp then a token was inserted | ||||||
|  |         // coinDenomination = array of 16 coin values (e.g. 5, 10, 20...) | ||||||
|  |  | ||||||
|  |     virtual void changer_returnCoins(uint32_t amountInCent) const =0; | ||||||
|  |  | ||||||
|  |     virtual void changer_requestChangeResult(void) const =0; | ||||||
|  |  | ||||||
|  |     virtual uint8_t changer_getChangeResult(uint32_t *returnedAmount) const =0; | ||||||
|  |         // get result of coin dispensing | ||||||
|  |         // receivedData[0]: 0: not yet started      1:amount returned | ||||||
|  |         //                  2:only partial return   3: no return possible | ||||||
|  |         // receivedData[2,3,4,5]: returned amount | ||||||
|  |  | ||||||
|  |     virtual void changer_getAllParameters(struct T_changer *mw) const =0; | ||||||
|  |         // requested automatically with 23, same like EMP | ||||||
|  |  | ||||||
|  |     virtual void changer_requestTubelevel(void) const =0; | ||||||
|  |  | ||||||
|  |     virtual void changer_getTubelevel(struct T_chg_Tub *tubLevel) const =0; | ||||||
|  |         // don't use tubeDispens[], it's not yet correct! | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     // ------------------------------------------------------------------------------------ | ||||||
|  |     //   bank note acceptor | ||||||
|  |     // ------------------------------------------------------------------------------------ | ||||||
|  |  | ||||||
|  |     // already defiened functions applying for BNA as well: | ||||||
|  |     // mdb_switchPower(true);       // power on/off | ||||||
|  |  | ||||||
|  |     // bank notes are integrated in the normal transaction process, so use the usual functions to run a vending cycle: | ||||||
|  |     // cash_startPayment(amount_cent); // start polling, enable bills, reader shows green | ||||||
|  |     // getInsertedAmount() | ||||||
|  |     // cash_stopPayment(); | ||||||
|  |     // cash_cancelPayment(); | ||||||
|  |     // vend_success() | ||||||
|  |     // vend_failed() | ||||||
|  |  | ||||||
|  |     virtual void bna_sendSettings(uint16_t notesToAccept, uint16_t parameters, | ||||||
|  |                                   uint16_t *billDenomination, | ||||||
|  |                                   uint32_t acceptanceLimit) const =0; | ||||||
|  |         // notesToAccept: bit0=bill1 (lowest donomination)  bitH=accept  bit L = deny | ||||||
|  |         // parameters: e.g. use escrow function for some notes | ||||||
|  |         // billDenomination = array of 16 bill values (e.g. 5, 10, 20...) | ||||||
|  |         // these can be set alternatively by Json-File DC2C_cash.json | ||||||
|  |         // acceptanceLimit: device will stop acceptance once this amount is reached and | ||||||
|  |         //          optionally keep last bill in escrow until vend_success() | ||||||
|  |         //          is called (put bill to stacker) or vend_failed() is called (return bill) | ||||||
|  |  | ||||||
|  |     virtual void bna_setCurrentAcceptance(uint16_t notesToAccept) const =0; | ||||||
|  |         // can be used to block notes dynamically, example: from now only 5€ bills are allowed (if only 3€ are to be paid) | ||||||
|  |         // only valid till next start-payment. Cannot add notes which are not activated in Json | ||||||
|  |  | ||||||
|  |     virtual void bna_requestParameters(void) const =0; | ||||||
|  |         // send command to DC in order to get static invariable device parameters like currency | ||||||
|  |         // device must be powered and polled to get these | ||||||
|  |  | ||||||
|  |     virtual bool bna_getAllParameters(struct T_bna *bna) const =0; | ||||||
|  |         // get all constant data from reader (e.g. currency) | ||||||
|  |         // and actual Host-Settings (sent with bna_sendSettings() or json) | ||||||
|  |         // retval = true if data are valid | ||||||
|  |  | ||||||
|  |     virtual void bna_requestCurrentNotes(void) const =0; | ||||||
|  |         // send command to DC in order to get transaction data | ||||||
|  |  | ||||||
|  |     virtual uint8_t bna_getCurrentNotes(uint16_t latestBill, uint16_t *currentNotes) const =0; | ||||||
|  |         // returns number of collected bank notes since start-command (current transaction) | ||||||
|  |         //  latestBill: last accepted bank note, value in cent | ||||||
|  |         //  currentNotes an array with up to 16 (further) notes collected | ||||||
|  |  | ||||||
|  |     virtual void bna_requestStackerLevel(void) const =0; | ||||||
|  |  | ||||||
|  |     virtual uint16_t bna_getStackerLevel(uint32_t *amountInStacker, uint16_t *countOfBills) const =0; | ||||||
|  |         // return val: nr of bills in stacker | ||||||
|  |         // countOfBills: array of up to 16 sums,    countOfBills[0]=nr of 5€-bills in stacker | ||||||
|  |         //                                          countOfBills[1] for 10€   and so on | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -1288,8 +1605,6 @@ signals: | |||||||
|     virtual void hwapi_payCancelled(void) const=0; |     virtual void hwapi_payCancelled(void) const=0; | ||||||
|     virtual void hwapi_coinProcessJustStopped(void) const=0; |     virtual void hwapi_coinProcessJustStopped(void) const=0; | ||||||
|  |  | ||||||
|  |  | ||||||
|     // new from 2023.06.12 |  | ||||||
|     virtual void hwapi_doorServiceDoorOpened(void) const=0; |     virtual void hwapi_doorServiceDoorOpened(void) const=0; | ||||||
|     virtual void hwapi_doorVaultDoorOpened(void) const=0; |     virtual void hwapi_doorVaultDoorOpened(void) const=0; | ||||||
|     virtual void hwapi_doorCoinBoxRemoved(void) const=0; |     virtual void hwapi_doorCoinBoxRemoved(void) const=0; | ||||||
| @@ -1326,6 +1641,10 @@ signals: | |||||||
| // 15.06.2023 V4.2  bring into same order as hwapi in order to set the THIS_IS_CA_MASTER correct | // 15.06.2023 V4.2  bring into same order as hwapi in order to set the THIS_IS_CA_MASTER correct | ||||||
| // 19.06.2023 V4.3  added some qCriticals to see emits | // 19.06.2023 V4.3  added some qCriticals to see emits | ||||||
|  |  | ||||||
|  | // 01.08.2023 V4.4  some new values at the end of struct T_vaultRecord | ||||||
|  | //                  two more values in struct T_devices | ||||||
|  | //                  7 new functions at the end of the file | ||||||
|  |  | ||||||
|  |  | ||||||
| //#define HWINF_iid "Atb.Psa2020.software.HWapi/3.1" | //#define HWINF_iid "Atb.Psa2020.software.HWapi/3.1" | ||||||
| //#define HWINF_iid "Atb.Psa1256ptu5.software.HWapi/3.1" | //#define HWINF_iid "Atb.Psa1256ptu5.software.HWapi/3.1" | ||||||
| @@ -1336,9 +1655,24 @@ signals: | |||||||
| //#define HWINF_iid "Atb.Psa1256ptu5.software.HWapi/4.0" | //#define HWINF_iid "Atb.Psa1256ptu5.software.HWapi/4.0" | ||||||
| //#define HWINF_iid "Atb.Psa1256ptu5.software.HWapi/4.1" | //#define HWINF_iid "Atb.Psa1256ptu5.software.HWapi/4.1" | ||||||
| //#define HWINF_iid "Atb.Psa1256ptu5.software.HWapi/4.2" | //#define HWINF_iid "Atb.Psa1256ptu5.software.HWapi/4.2" | ||||||
| #define HWINF_iid "Atb.Psa1256ptu5.software.HWapi/4.3" | //#define HWINF_iid "Atb.Psa1256ptu5.software.HWapi/4.3" | ||||||
|  | //#define HWINF_iid "Atb.Psa1256ptu5.software.HWapi/4.4" | ||||||
|  |     // 8.9.2023 two new functions (end of file) for mifare test | ||||||
|  | //#define HWINF_iid "Atb.Psa1256ptu5.software.HWapi/4.5" | ||||||
|  |     // 18.9.2023 major improvements for DC data exchange | ||||||
|  |     // verification of door and cash box signals | ||||||
|  |     // intensive verification of Json-Programming Master-Slave (PTU to DC), 100% ok | ||||||
|  | //#define HWINF_iid "Atb.Psa1256ptu5.software.HWapi/4.6" | ||||||
|  |     // 20.9.2023: speeding up door and cash box signals | ||||||
|  | //#define HWINF_iid "Atb.Psa1256ptu5.software.HWapi/4.7" | ||||||
|  |     // 26.09.2023: added improved DC-bootloader files | ||||||
|  | //#define HWINF_iid "Atb.Psa1256ptu5.software.HWapi/4.8" | ||||||
|  | // 28.09.2023: added version request of DC-Json-Files | ||||||
|  | //#define HWINF_iid "Atb.Psa1256ptu5.software.HWapi/5.0" | ||||||
|  |     // 10.10.2023: added coin changer | ||||||
|  |  | ||||||
|  | #define HWINF_iid "Atb.Psa1256ptu5.software.HWapi/5.1" | ||||||
|  | // 20.10.2023: added bill validator | ||||||
|  |  | ||||||
|  |  | ||||||
| Q_DECLARE_INTERFACE(hwinf, HWINF_iid) | Q_DECLARE_INTERFACE(hwinf, HWINF_iid) | ||||||
|   | |||||||
							
								
								
									
										
											BIN
										
									
								
								plugins/libCAmaster.so
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								plugins/libCAmaster.so
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										124
									
								
								process/command.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										124
									
								
								process/command.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,124 @@ | |||||||
|  | #include "command.h" | ||||||
|  |  | ||||||
|  | #include <QProcess> | ||||||
|  | #include <QDebug> | ||||||
|  | #include <QDir> | ||||||
|  | #include <QRegularExpression> | ||||||
|  | #include <QDateTime> | ||||||
|  |  | ||||||
|  | Command::Command(QString const &command, int start_timeout, int finish_timeout) | ||||||
|  |     : m_command(command.trimmed()) | ||||||
|  |     , m_commandResult("") | ||||||
|  |     , m_waitForStartTimeout(start_timeout) | ||||||
|  |     , m_waitForFinishTimeout(finish_timeout) | ||||||
|  |     , m_exitCode(-1) { | ||||||
|  | } | ||||||
|  |  | ||||||
|  | QString Command::getCommandResult() const { | ||||||
|  |     return m_commandResult; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void Command::readyReadStandardOutput() { | ||||||
|  |     QProcess *p = (QProcess *)sender(); | ||||||
|  |     m_commandResult += p->readAllStandardOutput(); | ||||||
|  |     // qCritical() << m_commandResult; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void Command::readyReadStandardError() { | ||||||
|  |     QProcess *p = (QProcess *)sender(); | ||||||
|  |     QByteArray buf = p->readAllStandardError(); | ||||||
|  |     qCritical() << buf; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void Command::finished(int /*exitCode*/, QProcess::ExitStatus /*exitStatus*/) { | ||||||
|  |     QProcess *p = (QProcess *)sender(); | ||||||
|  |     // read all remaining data sent to the process, just in case | ||||||
|  |     QString d = p->readAllStandardOutput(); | ||||||
|  |     if (!d.isEmpty()) { | ||||||
|  |         m_commandResult += d; | ||||||
|  |     } | ||||||
|  |     disconnect(p, SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(readyReadStandardOutput())); | ||||||
|  |     disconnect(p, SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(readyReadStandardError())); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool Command::execute(QString workingDirectory, QStringList args) { | ||||||
|  |  | ||||||
|  |     if (!QDir::setCurrent(workingDirectory)) { | ||||||
|  |         qCritical() << "SET WORKING_DIRECTORY" << workingDirectory | ||||||
|  |                     << "FAILED FOR" << m_command; | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     QScopedPointer<QProcess> p(new QProcess(this)); | ||||||
|  |     p->setWorkingDirectory(workingDirectory); | ||||||
|  |     p->setProcessChannelMode(QProcess::MergedChannels); | ||||||
|  |  | ||||||
|  |     connect(&(*p), SIGNAL(readyReadStandardOutput()), this, SLOT(readyReadStandardOutput())); | ||||||
|  |     connect(&(*p), SIGNAL(readyReadStandardError()), this, SLOT(readyReadStandardError())); | ||||||
|  |  | ||||||
|  |     if (!args.isEmpty()) { | ||||||
|  |         qDebug() << "START COMMAND" << m_command << "WITH ARGS" << args | ||||||
|  |                  << "IN" << p->workingDirectory(); | ||||||
|  |         p->start(m_command, args); | ||||||
|  |     } else { | ||||||
|  |         qDebug() << "START COMMAND" << m_command | ||||||
|  |                  << "IN" << p->workingDirectory(); | ||||||
|  |         p->start(m_command); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     qint64 const start = QDateTime::currentDateTime().toMSecsSinceEpoch(); | ||||||
|  |  | ||||||
|  |     if (p->waitForStarted(m_waitForStartTimeout)) { | ||||||
|  |         qDebug() << "PROCESS" << m_command << "STARTED IN" << p->workingDirectory(); | ||||||
|  |         if (p->state() == QProcess::ProcessState::Running) { | ||||||
|  |             qDebug() << "PROCESS" << m_command << "RUNNING IN" << p->workingDirectory(); | ||||||
|  |             // wait forever for git/opkg-commands to finish | ||||||
|  |             int wait = m_waitForFinishTimeout; | ||||||
|  |             if (m_command.trimmed().startsWith("git", Qt::CaseInsensitive) || | ||||||
|  |                 m_command.trimmed().startsWith("opkg", Qt::CaseInsensitive)) { | ||||||
|  |                 wait = -1; | ||||||
|  |             } | ||||||
|  |             bool const no_timeout = p->waitForFinished(wait); | ||||||
|  |             if (no_timeout) { | ||||||
|  |                 qDebug() << "PROCESS" << m_command << "FINISHED IN" << p->workingDirectory(); | ||||||
|  |                 if (p->exitStatus() == QProcess::NormalExit) { | ||||||
|  |                     if ((m_exitCode = p->exitCode()) == 0) { | ||||||
|  |                         qint64 const end = QDateTime::currentDateTime().toMSecsSinceEpoch(); | ||||||
|  |                         qDebug() << "EXECUTED" << m_command | ||||||
|  |                                  << QString("(runtime %1ms)").arg(end-start) | ||||||
|  |                                  << "with code" << m_exitCode | ||||||
|  |                                  << "IN" << p->workingDirectory(); | ||||||
|  |                         return true; | ||||||
|  |                     } else { | ||||||
|  |                         qint64 const end = QDateTime::currentDateTime().toMSecsSinceEpoch(); | ||||||
|  |                         qCritical() << "EXECUTED" << m_command | ||||||
|  |                                     << QString("(runtime %1ms)").arg(end-start) | ||||||
|  |                                     << "with code" << m_exitCode | ||||||
|  |                                     << "IN" << p->workingDirectory(); | ||||||
|  |                     } | ||||||
|  |                 } else { | ||||||
|  |                     qint64 const end = QDateTime::currentDateTime().toMSecsSinceEpoch(); | ||||||
|  |                     qCritical() << "PROCESS" << m_command << "CRASHED with code" | ||||||
|  |                                 << p->exitCode() | ||||||
|  |                                 << QString("(after %1ms)").arg(end-start) | ||||||
|  |                                 << "IN" << p->workingDirectory(); | ||||||
|  |                 } | ||||||
|  |             } else { | ||||||
|  |                 qint64 const end = QDateTime::currentDateTime().toMSecsSinceEpoch(); | ||||||
|  |                 qCritical() << "PROCESS" << m_command | ||||||
|  |                             << "DID NOT FINISH WITH" << wait | ||||||
|  |                             << "MS IN" << p->workingDirectory() | ||||||
|  |                             << QString("(runtime %1ms)").arg(end-start); | ||||||
|  |             } | ||||||
|  |         } else { | ||||||
|  |             qCritical() << "WRONG PROCESS STATE" << p->state() | ||||||
|  |                         << "IN" << p->workingDirectory(); | ||||||
|  |         } | ||||||
|  |     } else { | ||||||
|  |         qint64 const end = QDateTime::currentDateTime().toMSecsSinceEpoch(); | ||||||
|  |         qCritical() << "PROCESS" << m_command << "TIMEOUT AT START" | ||||||
|  |                     << QString("(runtime %1ms)").arg(end-start) | ||||||
|  |                     << "IN" << p->workingDirectory(); | ||||||
|  |     } | ||||||
|  |     return false; | ||||||
|  | } | ||||||
							
								
								
									
										35
									
								
								process/command.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								process/command.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,35 @@ | |||||||
|  | #ifndef COMMAND_H_INCLUDED | ||||||
|  | #define COMMAND_H_INCLUDED | ||||||
|  | #endif // COMMAND_H_INCLUDED | ||||||
|  |  | ||||||
|  | #include <QObject> | ||||||
|  | #include <QCoreApplication> | ||||||
|  | #include <QString> | ||||||
|  | #include <QStringList> | ||||||
|  | #include <QProcess> | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class Command : public QObject { | ||||||
|  |     Q_OBJECT | ||||||
|  |  | ||||||
|  |     QString m_command; | ||||||
|  |     QString m_commandResult; | ||||||
|  |     int m_waitForStartTimeout; | ||||||
|  |     int m_waitForFinishTimeout; | ||||||
|  |     int m_exitCode; | ||||||
|  | public: | ||||||
|  |     explicit Command(QString const &command, | ||||||
|  |                      int start_timeout = 100000, | ||||||
|  |                      int finish_timeout = 100000); | ||||||
|  |  | ||||||
|  |     QString getCommandResult() const; | ||||||
|  |     QString command() const { return m_command; } | ||||||
|  |  | ||||||
|  |     bool execute(QString workingDirectory, QStringList args = QStringList()); | ||||||
|  |     int exitCode() const { return m_exitCode; } | ||||||
|  |  | ||||||
|  | private slots: | ||||||
|  |     void readyReadStandardOutput(); | ||||||
|  |     void readyReadStandardError(); | ||||||
|  |     void finished(int exitCode, QProcess::ExitStatus exitStatus); | ||||||
|  | }; | ||||||
							
								
								
									
										20
									
								
								progress_event.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								progress_event.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,20 @@ | |||||||
|  | #include "progress_event.h" | ||||||
|  |  | ||||||
|  | QEvent::Type ProgressEvent::customEventType = QEvent::None; | ||||||
|  |  | ||||||
|  | ProgressEvent::ProgressEvent(QObject const *sender, int progressPercent) | ||||||
|  |     : QEvent(ProgressEvent::type()) | ||||||
|  |     , m_sender(sender) | ||||||
|  |     , m_progressPercent(progressPercent) { | ||||||
|  | } | ||||||
|  |  | ||||||
|  | ProgressEvent::~ProgressEvent() { | ||||||
|  | } | ||||||
|  |  | ||||||
|  | QEvent::Type ProgressEvent::type() { | ||||||
|  |     if (customEventType == QEvent::None) { | ||||||
|  |         int generatedType = QEvent::registerEventType(); | ||||||
|  |         customEventType = static_cast<QEvent::Type>(generatedType); | ||||||
|  |     } | ||||||
|  |     return customEventType; | ||||||
|  | } | ||||||
							
								
								
									
										26
									
								
								progress_event.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								progress_event.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,26 @@ | |||||||
|  | #ifndef PROGRESS_EVENT_H_INCLUDED | ||||||
|  | #define PROGRESS_EVENT_H_INCLUDED | ||||||
|  |  | ||||||
|  | #include <QEvent> | ||||||
|  |  | ||||||
|  | class ProgressEvent : public QEvent { | ||||||
|  |  | ||||||
|  |     QObject const *m_sender; | ||||||
|  |     int m_progressPercent; | ||||||
|  | public: | ||||||
|  |     explicit ProgressEvent(QObject const *sender, int progressPercent); | ||||||
|  |     virtual ~ProgressEvent(); | ||||||
|  |     static QEvent::Type type(); | ||||||
|  |  | ||||||
|  |     QObject const *sender() { return m_sender; } | ||||||
|  |     QObject const *sender() const { return m_sender; } | ||||||
|  |  | ||||||
|  |     void setProgress(int progressPercent) { m_progressPercent = progressPercent; } | ||||||
|  |     int progressPercent() { return m_progressPercent; } | ||||||
|  |     int progressPercent() const { return m_progressPercent; } | ||||||
|  | private: | ||||||
|  |     static QEvent::Type customEventType; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | #endif // PROGRESS_EVENT_H_INCLUDED | ||||||
							
								
								
									
										868
									
								
								update.cpp
									
									
									
									
									
								
							
							
						
						
									
										868
									
								
								update.cpp
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										55
									
								
								update.h
									
									
									
									
									
								
							
							
						
						
									
										55
									
								
								update.h
									
									
									
									
									
								
							| @@ -7,6 +7,7 @@ | |||||||
| #include <QDir> | #include <QDir> | ||||||
| #include <QByteArray> | #include <QByteArray> | ||||||
| #include <QProcess> | #include <QProcess> | ||||||
|  | #include <QPluginLoader> | ||||||
|  |  | ||||||
| #include "plugins/interfaces.h" | #include "plugins/interfaces.h" | ||||||
|  |  | ||||||
| @@ -16,46 +17,58 @@ | |||||||
| #define SERIAL_PORT "ttyUSB0" | #define SERIAL_PORT "ttyUSB0" | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| class Update; | class Worker; | ||||||
|  |  | ||||||
| // TODO: check hardware compatibility |  | ||||||
| // TODO: opkg commandos |  | ||||||
|  |  | ||||||
| class Update : public QObject { | class Update : public QObject { | ||||||
|     Q_OBJECT |     Q_OBJECT | ||||||
|  |  | ||||||
|     hwinf *m_hw; |     hwinf *m_hw = nullptr; | ||||||
|  |     Worker *m_worker = nullptr; | ||||||
|     char const *m_serialInterface; |     char const *m_serialInterface; | ||||||
|     char const *m_baudrate; |     char const *m_baudrate; | ||||||
|     QFile m_update_ctrl_file; |     QString m_customerRepository; | ||||||
|     QFile m_update_ctrl_file_copy; |     QString m_customerNrStr; | ||||||
|  |     QString m_branchName; | ||||||
|  |     QString m_pluginName; | ||||||
|     QString m_workingDir; |     QString m_workingDir; | ||||||
|     bool m_maintenanceMode; |     bool m_maintenanceMode; | ||||||
|  |     bool m_dryRun; | ||||||
|  |  | ||||||
|     bool m_init; |     static QPluginLoader pluginLoader; | ||||||
|  |  | ||||||
|     bool finishUpdate(bool finish); |  | ||||||
|     QStringList getLinesToWorkOn(); |  | ||||||
|     QStringList split(QString line, QChar sep = ','); |  | ||||||
|  |  | ||||||
|     bool execUpdateScript(); |  | ||||||
|  |  | ||||||
| public: | public: | ||||||
|     enum class DownloadResult {OK, ERROR, TIMEOUT, NOP}; |     enum class DownloadResult {OK, ERROR, TIMEOUT, NOP}; | ||||||
|     enum class FileTypeJson {CONFIG=1, DEVICE=2, CASH=3, SERIAL=4, TIME=5, PRINTER=6}; |     enum class FileTypeJson {CONFIG=1, DEVICE=2, CASH=3, SERIAL=4, TIME=5, PRINTER=6}; | ||||||
|  |  | ||||||
|     static hwinf *loadDCPlugin(QDir const &plugInDir, QString const &fn); |     static hwinf *loadDCPlugin(QDir const &plugInDir, QString const &fn); | ||||||
|  |     static bool unloadDCPlugin(); | ||||||
|  |     static QStringList split(QString line, QChar sep = ','); | ||||||
|  |  | ||||||
|  |  | ||||||
|     explicit Update(hwinf *hw, |     explicit Update(Worker *worker, | ||||||
|                     QString update_ctrl_file, |                     QString customerRepository, | ||||||
|                     QString workingDir = ".", |                     QString customerNrStr, | ||||||
|                     bool maintenanceMode = false, |                     QString branchName, | ||||||
|  |                     QString plugInDir, | ||||||
|  |                     QString pluginName, | ||||||
|  |                     QString workingDir, | ||||||
|  |                     bool dryRun = false, | ||||||
|                     QObject *parent = nullptr, |                     QObject *parent = nullptr, | ||||||
|                     char const *serialInterface = SERIAL_PORT, |                     char const *serialInterface = SERIAL_PORT, | ||||||
|                     char const *baudrate = "115200"); |                     char const *baudrate = "115200"); | ||||||
|     virtual ~Update() override; |     virtual ~Update() override; | ||||||
|     bool doUpdate(); |     bool doUpdate(int &displayIndex, QStringList const &linesToWorkOn); | ||||||
|  |  | ||||||
|  |     hwinf *hw() { return m_hw; } | ||||||
|  |     hwinf const *hw() const { return m_hw; } | ||||||
|  |  | ||||||
|  |     //QString customerId() { return m_customerId; } | ||||||
|  |     //QString const customerId() const { return m_customerId; } | ||||||
|  |  | ||||||
|  |     QString branchName() { return m_branchName; } | ||||||
|  |     QString const branchName() const { return m_branchName; } | ||||||
|  |  | ||||||
|  |     //QString repositoryPath() { return m_repositoryPath; } | ||||||
|  |     //QString const repositoryPath() const { return m_repositoryPath; } | ||||||
|  |  | ||||||
| private: | private: | ||||||
|     static QString jsonType(enum FileTypeJson type); |     static QString jsonType(enum FileTypeJson type); | ||||||
| @@ -69,6 +82,7 @@ private: | |||||||
|     bool stopBootloader() const; |     bool stopBootloader() const; | ||||||
|     bool openSerial(int br, QString baudrate, QString comPort) const; |     bool openSerial(int br, QString baudrate, QString comPort) const; | ||||||
|     void closeSerial() const; |     void closeSerial() const; | ||||||
|  |     bool isSerialOpen() const; | ||||||
|     bool resetDeviceController() const; |     bool resetDeviceController() const; | ||||||
|     QByteArray loadBinaryDCFile(QString filename) const; |     QByteArray loadBinaryDCFile(QString filename) const; | ||||||
|     bool downloadBinaryToDC(QString const &bFile) const; |     bool downloadBinaryToDC(QString const &bFile) const; | ||||||
| @@ -80,6 +94,7 @@ private: | |||||||
|     bool updateDeviceConf(QString jsFileToSendToDC); |     bool updateDeviceConf(QString jsFileToSendToDC); | ||||||
|     bool downloadJson(enum FileTypeJson type, int templateIdx, |     bool downloadJson(enum FileTypeJson type, int templateIdx, | ||||||
|                       QString jsFileToSendToDC) const; |                       QString jsFileToSendToDC) const; | ||||||
|  |     QStringList getDcSoftAndHardWareVersion(); | ||||||
|  |  | ||||||
| private slots: | private slots: | ||||||
|     void readyReadStandardOutput(); |     void readyReadStandardOutput(); | ||||||
|   | |||||||
							
								
								
									
										25
									
								
								update_dc_event.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								update_dc_event.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,25 @@ | |||||||
|  | #include "update_dc_event.h" | ||||||
|  |  | ||||||
|  | QEvent::Type UpdateDcEvent::customEventType = QEvent::None; | ||||||
|  |  | ||||||
|  | UpdateDcEvent::UpdateDcEvent(QObject const *sender, | ||||||
|  |                              UpdateStep updateStep, | ||||||
|  |                              int count, | ||||||
|  |                              QDateTime const &sendDateTime) | ||||||
|  |     : QEvent(UpdateDcEvent::type()) | ||||||
|  |     , m_sender(sender) | ||||||
|  |     , m_updateStep(updateStep) | ||||||
|  |     , m_count(count) | ||||||
|  |     , m_sendDateTime(sendDateTime) { | ||||||
|  | } | ||||||
|  |  | ||||||
|  | UpdateDcEvent::~UpdateDcEvent() { | ||||||
|  | } | ||||||
|  |  | ||||||
|  | QEvent::Type UpdateDcEvent::type() { | ||||||
|  |     if (customEventType == QEvent::None) { | ||||||
|  |         int generatedType = QEvent::registerEventType(); | ||||||
|  |         customEventType = static_cast<QEvent::Type>(generatedType); | ||||||
|  |     } | ||||||
|  |     return customEventType; | ||||||
|  | } | ||||||
							
								
								
									
										40
									
								
								update_dc_event.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								update_dc_event.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,40 @@ | |||||||
|  | #ifndef UPDATE_DC_EVENT_H_INCLUDED | ||||||
|  | #define UPDATE_DC_EVENT_H_INCLUDED | ||||||
|  |  | ||||||
|  | #include <QEvent> | ||||||
|  | #include <QDateTime> | ||||||
|  |  | ||||||
|  | class UpdateDcEvent : public QEvent { | ||||||
|  | public: | ||||||
|  |     enum UpdateStep { NONE, DC_REBOOT, BL_START, BL_CHECK, BL_CHECK_AFTER_STOP, BL_IS_UP, BL_IS_DOWN, BL_STOP}; | ||||||
|  |  | ||||||
|  | private: | ||||||
|  |     QObject const *m_sender; | ||||||
|  |     UpdateStep m_updateStep; | ||||||
|  |     int m_count; | ||||||
|  |     QDateTime m_sendDateTime; | ||||||
|  |  | ||||||
|  | public: | ||||||
|  |     explicit UpdateDcEvent(QObject const *sender, UpdateStep updateStep, | ||||||
|  |                            int count, | ||||||
|  |                            QDateTime const &sendDateTime = QDateTime::currentDateTime()); | ||||||
|  |     virtual ~UpdateDcEvent(); | ||||||
|  |     static QEvent::Type type(); | ||||||
|  |  | ||||||
|  |     QObject const *sender() { return m_sender; } | ||||||
|  |     QObject const *sender() const { return m_sender; } | ||||||
|  |  | ||||||
|  |     void setUpdateStep(UpdateStep updateStep) { m_updateStep = updateStep; } | ||||||
|  |     UpdateStep updateStep() { return m_updateStep; } | ||||||
|  |     UpdateStep updateStep() const { return m_updateStep; } | ||||||
|  |     int count() const { return m_count; } | ||||||
|  |     void setCount(int count) { m_count = count; } | ||||||
|  |     QDateTime &sendDateTime() { return m_sendDateTime; } | ||||||
|  |     QDateTime const &sendDateTime() const { return m_sendDateTime; } | ||||||
|  |  | ||||||
|  | private: | ||||||
|  |     static QEvent::Type customEventType; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | #endif // PROGRESS_EVENT_H_INCLUDED | ||||||
							
								
								
									
										457
									
								
								utils.cpp
									
									
									
									
									
								
							
							
						
						
									
										457
									
								
								utils.cpp
									
									
									
									
									
								
							| @@ -1,201 +1,304 @@ | |||||||
| #include "utils.h" | #include "utils.h" | ||||||
|  | #include "message_handler.h" | ||||||
|  | #include "git/git_client.h" | ||||||
|  |  | ||||||
|  |  | ||||||
|  | #if defined (Q_OS_UNIX) || defined (Q_OS_LINUX) | ||||||
|  | #include "unistd.h" | ||||||
|  | #endif | ||||||
|  |  | ||||||
| #include <QCoreApplication> |  | ||||||
| #include <QApplication> |  | ||||||
| #include <QFile> | #include <QFile> | ||||||
| #include <QTemporaryFile> |  | ||||||
| #include <QDebug> |  | ||||||
| #include <QTextStream> | #include <QTextStream> | ||||||
|  | #include <QDebug> | ||||||
|  | #include <QDir> | ||||||
|  | #include <QDirIterator> | ||||||
|  | #include <QRegularExpression> | ||||||
|  |  | ||||||
| #include "interfaces.h" | #include <fstream> | ||||||
| #include "DCPlugin/include/hwapi.h" |  | ||||||
|  |  | ||||||
| //#include <unistd.h> | int Utils::read1stLineOfFile(QString fileName) { | ||||||
| #include <thread> |     QFile f(fileName); | ||||||
| #include <memory> |     if (f.exists()) { | ||||||
| #include <QSharedMemory> |         if (f.open(QIODevice::ReadOnly | QIODevice::Text)) { | ||||||
| #include <QScopedPointer> |             QTextStream in(&f); | ||||||
| #include <QProcess> |             in.setCodec("UTF-8"); | ||||||
|  |             while(!in.atEnd()) { | ||||||
| #define COLUMN_STATUS       (0) |                 return in.readLine().toInt(); | ||||||
| #define COLUMN_NAME         (1) |             } | ||||||
| #define COLUMN_DATE_TIME    (2) |  | ||||||
| #define COLUMN_RESULT       (3) |  | ||||||
|  |  | ||||||
| Utils::Utils(QString update_ctrl_file, |  | ||||||
|              QObject *parent, |  | ||||||
|              char const *serialInterface, |  | ||||||
|              char const *baudrate) |  | ||||||
|     : QObject(parent) |  | ||||||
|     , m_hw(new hwapi()) |  | ||||||
|     , m_serialInterface(serialInterface) |  | ||||||
|     , m_baudrate(baudrate) |  | ||||||
|     , m_update_ctrl_file(update_ctrl_file) |  | ||||||
|     , m_update_ctrl_file_copy(update_ctrl_file + ".copy") |  | ||||||
|     , m_in(&m_update_ctrl_file) |  | ||||||
|     , m_out(&m_update_ctrl_file_copy) |  | ||||||
|     , m_init(true) { |  | ||||||
|  |  | ||||||
|     if (!m_update_ctrl_file.exists()) { |  | ||||||
|         qCritical() << "Update-file" << m_update_ctrl_file.fileName() |  | ||||||
|                     << "does not exist"; |  | ||||||
|         m_init = false; |  | ||||||
|     } |  | ||||||
|     if (!m_update_ctrl_file.open(QIODevice::ReadOnly | QIODevice::Text)) { |  | ||||||
|         qCritical() << "can not open " << m_update_ctrl_file.fileName() |  | ||||||
|                     << "for reading"; |  | ||||||
|         m_init = false; |  | ||||||
|     } |  | ||||||
|     if (!m_update_ctrl_file_copy.open(QIODevice::WriteOnly | QIODevice::Text)) { |  | ||||||
|         qCritical() << "can not open " << m_update_ctrl_file_copy.fileName() |  | ||||||
|                     << "for writing"; |  | ||||||
|         m_init = false; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| Utils::~Utils() { |  | ||||||
|  |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void Utils::updateBinary(char const *fileToSendToDC) { |  | ||||||
|     qDebug() << "file to send to DC ..." << fileToSendToDC; |  | ||||||
|     qDebug() << "baudrate ............." << m_baudrate; |  | ||||||
|     qDebug() << "serial interface ....." << m_serialInterface; |  | ||||||
|     m_hw->dc_updateDC(fileToSendToDC, m_baudrate, m_serialInterface); |  | ||||||
|     std::this_thread::sleep_for(std::chrono::milliseconds(3000)); |  | ||||||
|     QCoreApplication::quit(); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void Utils::updatePrinterConf(int nrOfTemplate, char const *fileToSendToDC) { |  | ||||||
|     QVector<int> printTemplates{ nrOfTemplate }; |  | ||||||
|     QVector<QString> filesToSend{ fileToSendToDC }; |  | ||||||
|  |  | ||||||
|     m_hw->dc_updatePrinterTemplate(hwapi::FileTypeJson::PRINTER, |  | ||||||
|                                    printTemplates, filesToSend, |  | ||||||
|                                    QString(m_baudrate), |  | ||||||
|                                    QString(m_serialInterface)); |  | ||||||
|     std::this_thread::sleep_for(std::chrono::milliseconds(3000)); |  | ||||||
|     QCoreApplication::quit(); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| QStringList Utils::getOpenLines() { |  | ||||||
|     QStringList openLines; |  | ||||||
|  |  | ||||||
|     while (!m_in.atEnd()) { |  | ||||||
|         QString line = m_in.readLine().trimmed(); |  | ||||||
|         // QString.split() is defined >= 5.14 |  | ||||||
|         if (!line.startsWith("OPEN")) { |  | ||||||
|             m_out << line; |  | ||||||
|         } else { |  | ||||||
|             openLines << line; |  | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     return openLines; |     return -1; | ||||||
| } | } | ||||||
|  |  | ||||||
| bool Utils::doUpdate() { | QString Utils::zoneName(quint8 i) { | ||||||
|     /* |     static constexpr char const *zName[] = { | ||||||
|         The file referred to by 'update_data' has the following structure for |         "", | ||||||
|         each line: |         "purple", | ||||||
|  |         "blue", | ||||||
|  |         "yellow", | ||||||
|  |         "green", | ||||||
|  |         "yellow (mars)", | ||||||
|  |         "green (mars)" | ||||||
|  |     }; | ||||||
|  |     if (i < (sizeof(zName)/sizeof(char const *))) { | ||||||
|  |         return zName[i]; | ||||||
|  |     } | ||||||
|  |     return "N/A"; | ||||||
|  | } | ||||||
|  |  | ||||||
|         # ====================================================================== | void Utils::printCriticalErrorMsg(QString const &errorMsg, bool upper, bool lower) { | ||||||
|         # STATUS    |  NAME  |   DATE  |  RESULT |     if (upper) qCritical() << QString(80, 'E'); | ||||||
|         # ====================================================================== |  | ||||||
|         # where |     qCritical() << errorMsg; | ||||||
|         # |  | ||||||
|         # STATUS: OPEN or CLOSED |     if (lower) qCritical() << QString(80, 'E'); | ||||||
|         # NAME  : If starting with 'opkg' it is an opkg-command to be executed. | } | ||||||
|         #         Otherwise its the name of a file which has to be updated. |  | ||||||
|         # DATE  : 0000-00-00T00:00:00 | void Utils::printCriticalErrorMsg(QStringList const &errorMsg) { | ||||||
|         # RESULT: SUCCESS or ERROR (possibly with description) |     qCritical() << QString(80, 'E'); | ||||||
|         # |     for (int i = 0; i < errorMsg.size(); ++i) { | ||||||
|      */ |         qCritical() << errorMsg.at(i); | ||||||
|     if (!m_init) { |     } | ||||||
|  |     qCritical() << QString(80, 'E'); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void Utils::printUpdateStatusMsg(QDebug debug, QStringList const &updateMsg) { | ||||||
|  |     //if (updateMsg.size() > 1) { | ||||||
|  |     //    qCritical() << QString(80, 'U'); | ||||||
|  |     //} | ||||||
|  |  | ||||||
|  |     Q_UNUSED(debug); | ||||||
|  |  | ||||||
|  |     for (int i = 0; i < updateMsg.size(); ++i) { | ||||||
|  |         qInfo() << updateMsg.at(i); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     //if (updateMsg.size() > 1) { | ||||||
|  |     //    qCritical() << QString(80, 'U'); | ||||||
|  |     //} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void Utils::printUpdateStatusMsg(QStringList const &updateMsg) { | ||||||
|  |     //if (updateMsg.size() > 1) { | ||||||
|  |     //    qCritical() << QString(80, 'U'); | ||||||
|  |     //} | ||||||
|  |  | ||||||
|  |     for (int i = 0; i < updateMsg.size(); ++i) { | ||||||
|  |         qCritical() << updateMsg.at(i); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     //if (updateMsg.size() > 1) { | ||||||
|  |     //    qCritical() << QString(80, 'U'); | ||||||
|  |     //} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void Utils::printUpdateStatusMsg(QString const &updateMsg, bool upper, bool lower) { | ||||||
|  |     if (upper) qCritical() << QString(80, 'U'); | ||||||
|  |  | ||||||
|  |     qCritical() << updateMsg; | ||||||
|  |  | ||||||
|  |     if (lower) qCritical() << QString(80, 'U'); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void Utils::printUpdateStatusMsg(QDebug debug, QString const &updateMsg, | ||||||
|  |                                  bool upper, bool lower) { | ||||||
|  |     if (upper) debug << QString(80, 'U'); | ||||||
|  |  | ||||||
|  |     qInfo() << updateMsg; | ||||||
|  |  | ||||||
|  |     if (lower) debug << QString(80, 'U'); | ||||||
|  |  | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void Utils::printInfoMsg(QString const &infoMsg, bool upper, bool lower) { | ||||||
|  |     if (upper) qCritical() << QString(80, 'I'); | ||||||
|  |  | ||||||
|  |     qCritical() << infoMsg; | ||||||
|  |  | ||||||
|  |     if (lower) qCritical() << QString(80, 'I'); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void Utils::printInfoMsg(QStringList const &infoMsg) { | ||||||
|  |     //if (infoMsg.size() > 1) { | ||||||
|  |     //    qCritical() << QString(80, 'I'); | ||||||
|  |     //} | ||||||
|  |  | ||||||
|  |     for (int i = 0; i < infoMsg.size(); ++i) { | ||||||
|  |         qCritical() << infoMsg.at(i); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     //if (infoMsg.size() > 1) { | ||||||
|  |     //    qCritical() << QString(80, 'I'); | ||||||
|  |     //} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void Utils::printLineEditInfo(QStringList const &lines) { | ||||||
|  |     if (getDebugLevel() == LOG_DEBUG) { | ||||||
|  |         for (int i=0; i<lines.size(); ++i) { | ||||||
|  |             qInfo() << lines.at(i); | ||||||
|  |         } qInfo() << ""; qInfo() << ""; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | QString Utils::getTariffLoadTime(QString fileName) { | ||||||
|  |     QFileInfo fInfo(fileName); | ||||||
|  |     if (fInfo.exists()) { | ||||||
|  |         QDateTime lastModifiedTime = fInfo.lastModified(); | ||||||
|  |         if (lastModifiedTime.isValid()) { | ||||||
|  |             return lastModifiedTime.toString(Qt::ISODateWithMs); | ||||||
|  |         } else { | ||||||
|  |             printCriticalErrorMsg(fileName + " HAS INVALID MODIFIED-TIME"); | ||||||
|  |             QDateTime birthTime = fInfo.birthTime(); | ||||||
|  |             if (birthTime.isValid()) { | ||||||
|  |                 return birthTime.toString(Qt::ISODateWithMs); | ||||||
|  |             } else { | ||||||
|  |                 printCriticalErrorMsg(fileName + " HAS INVALID BIRTH-TIME"); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } else { | ||||||
|  |         printCriticalErrorMsg(fileName + " DOES NOT EXIST"); | ||||||
|  |     } | ||||||
|  |     return "N/A"; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | QString Utils::rstrip(QString const &str) { | ||||||
|  |     int n = str.size() - 1; | ||||||
|  |     for (; n >= 0; --n) { | ||||||
|  |         if (!str.at(n).isSpace()) { | ||||||
|  |             return str.left(n + 1); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     return ""; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool Utils::sameFilesInDirs(QDir const &dir1, QDir const &dir2, | ||||||
|  |                             QStringList const &nameFilters) { | ||||||
|  |     if (!dir1.exists()) { | ||||||
|  |         printCriticalErrorMsg(dir1.dirName() + " DOES NOT EXIST"); | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |     if (!dir2.exists()) { | ||||||
|  |         printCriticalErrorMsg(dir2.dirName() + " DOES NOT EXIST"); | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |     if (dir1.absolutePath() == dir2.absolutePath()) { | ||||||
|  |         printCriticalErrorMsg(dir1.dirName() + " AND "+ dir2.dirName() + " HAVE SAME PATH"); | ||||||
|         return false; |         return false; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     QStringList openLines = getOpenLines(); |     // files, sorted by name | ||||||
|  |     QFileInfoList const &lst1 = dir1.entryInfoList(nameFilters, QDir::Files, QDir::Name); | ||||||
|  |     QFileInfoList const &lst2 = dir2.entryInfoList(nameFilters, QDir::Files, QDir::Name); | ||||||
|  |  | ||||||
|     bool res = false; |     QStringList fileNameLst1{}; | ||||||
|     QList<QString>::const_iterator it; |     QStringList fileNameLst2{}; | ||||||
|     for (it = openLines.cbegin(); it != openLines.cend(); ++it) { |     QListIterator<QFileInfo> i1(lst1); | ||||||
|         int start = 0, end; |     while (i1.hasNext()) { | ||||||
|         int column = 0; |         fileNameLst1 << i1.next().fileName(); | ||||||
|         QString status, name, datetime, result; |     } | ||||||
|         QString line = *it; |     QListIterator<QFileInfo> i2(lst2); | ||||||
|         while ((end = line.indexOf(QChar(','), start)) != -1) { |     while (i2.hasNext()) { | ||||||
|             QString next = line.mid(start, end).trimmed(); |         fileNameLst2 << i2.next().fileName(); | ||||||
|             switch (column) { |     } | ||||||
|             case COLUMN_STATUS: |  | ||||||
|                 status = next; |     if (fileNameLst1.isEmpty()) { | ||||||
|                 break; |         qCritical() << "DIR1" << dir1.dirName() << " DOES NOT CONTAIN EXPECTED FILES"; | ||||||
|             case COLUMN_NAME: |         return false; | ||||||
|                 name = next; |     } | ||||||
|                 break; |     if (fileNameLst2.isEmpty())  { | ||||||
|             case COLUMN_DATE_TIME: |         qCritical() << "DIR1" << dir2.dirName() << " DOES NOT CONTAIN EXPECTED FILES"; | ||||||
|                 datetime = next; |         return false; | ||||||
|                 break; |     } | ||||||
|             case COLUMN_RESULT: |     if (fileNameLst1 != fileNameLst2) { | ||||||
|                 result = next; |         printCriticalErrorMsg(dir1.dirName() + " AND " + dir2.dirName() | ||||||
|                 break; |                             + " DIFFER: [" + fileNameLst1.join(',') + "],[" | ||||||
|  |                             + fileNameLst2.join(',') + "]"); | ||||||
|  |         return false; | ||||||
|  |     } else { | ||||||
|  |         printInfoMsg(dir1.dirName() + " AND " + dir2.dirName() | ||||||
|  |                     + " ARE EQUAL: [" + fileNameLst1.join(',') + "]"); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     QStringList gitBlobLst1{}; | ||||||
|  |     QStringList gitBlobLst2{}; | ||||||
|  |     QListIterator<QFileInfo> i3(lst1); | ||||||
|  |     while (i3.hasNext()) { | ||||||
|  |         gitBlobLst1 << GitClient::gitBlob(i3.next().fileName()); | ||||||
|  |     } | ||||||
|  |     QListIterator<QFileInfo> i4(lst2); | ||||||
|  |     while (i4.hasNext()) { | ||||||
|  |         gitBlobLst2 << GitClient::gitBlob(i4.next().fileName()); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (gitBlobLst1.isEmpty()) { | ||||||
|  |         qCritical() << "DIR1" << dir1.dirName() << " DOES NOT CONTAIN EXPECTED FILES"; | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |     if (gitBlobLst2.isEmpty())  { | ||||||
|  |         qCritical() << "DIR1" << dir2.dirName() << " DOES NOT CONTAIN EXPECTED FILES"; | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (gitBlobLst1 != gitBlobLst2) { | ||||||
|  |         printCriticalErrorMsg(dir1.dirName() + " AND " + dir2.dirName() | ||||||
|  |                             + " DIFFER: [" + gitBlobLst1.join(',') + "],[" | ||||||
|  |                             + gitBlobLst2.join(',') + "]"); | ||||||
|  |         return false; | ||||||
|  |     } else { | ||||||
|  |         printInfoMsg(dir1.dirName() + " AND " + dir2.dirName() | ||||||
|  |                     + " CONTAIN SAME GIT-BLOBS FOR FILES: [" + fileNameLst1.join(',') + "]"); | ||||||
|  |  | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return true; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | QString Utils::getParentName() { // get name of parent process | ||||||
|  |     QString ppid = QString("/proc/%1/status").arg(getppid()); | ||||||
|  |     std::ifstream f(ppid.toStdString().c_str()); | ||||||
|  |     if (f.is_open()) { | ||||||
|  |         std::string next; | ||||||
|  |         while (std::getline(f, next)) { | ||||||
|  |             QString line = QString(next.c_str()).simplified(); | ||||||
|  |             if (line.startsWith("Name")) { | ||||||
|  |                 int const idx = line.indexOf(QChar(':')); | ||||||
|  |                 if (idx != -1) { | ||||||
|  |                     return line.mid(idx+1).trimmed(); | ||||||
|  |                 } | ||||||
|             } |             } | ||||||
|             ++column; |  | ||||||
|             start = end + 1; |  | ||||||
|         } |         } | ||||||
|  |     } | ||||||
|  |     return ""; | ||||||
|  | } | ||||||
|  |  | ||||||
|         if (!status.contains("OPEN")) { | bool Utils::isATBQTRunning() { | ||||||
|             qCritical() << "Parsing error for" << m_update_ctrl_file.fileName(); |     QDirIterator it("/proc", | ||||||
|             return false; |                     QStringList() << "status", | ||||||
|         } |                     QDir::Files, | ||||||
|         if (name.contains("dc2c") && name.endsWith(".bin")) { |                     QDirIterator::Subdirectories); | ||||||
|             updateBinary(name.toStdString().c_str()); |     while (it.hasNext()) { | ||||||
|             res = true; |         QString const &nextStatusFile = it.next(); | ||||||
|         } else |         static const QRegularExpression re("^/proc/[0-9]{1,}/status"); | ||||||
|         if (name.contains("DC2C_print") && name.endsWith(".json")) { |         QRegularExpressionMatch match = re.match(nextStatusFile); | ||||||
|             int i = name.indexOf("DC2C_print"); |         if (match.hasMatch()) { | ||||||
|             int templateIdx = name.mid(i).midRef(10, 2).toInt(); |             std::ifstream f(nextStatusFile.toStdString().c_str()); | ||||||
|             updatePrinterConf(templateIdx, name.toStdString().c_str()); |             if (f.is_open()) { | ||||||
|             res = true; |                 std::string next; | ||||||
|         } else |                 while (std::getline(f, next)) { | ||||||
|         if (name.contains("opkg")) { |                     QString line = QString(next.c_str()).simplified(); | ||||||
|             int i = name.indexOf("opkg "); |                     if (line.startsWith("Name")) { | ||||||
|             QString rest = name.mid(i).trimmed(); |                         int const idx = line.indexOf(QChar(':')); | ||||||
|             QScopedPointer<QProcess> p(new QProcess(this)); |                         if (idx != -1) { | ||||||
|             p->setProcessChannelMode(QProcess::MergedChannels); |                             QString const binary = line.mid(idx+1).trimmed(); | ||||||
|             p->start("opkg", QStringList() << rest); |                             if (binary == "ATBQT") { | ||||||
|             if (p->waitForStarted(1000)) { |                                 return true; | ||||||
|                 if (p->state() == QProcess::ProcessState::Running) { |                             } | ||||||
|                     if (p->waitForFinished(10000)) { |                         } | ||||||
|                         QByteArray output = p->readAllStandardOutput(); |  | ||||||
|                         qCritical() << output; |  | ||||||
|                         res = true; |  | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|         } else { |  | ||||||
|             // TODO |  | ||||||
|         } |  | ||||||
|         QString resultLine = "CLOSED"; |  | ||||||
|         resultLine += ", " + name; |  | ||||||
|         resultLine += ", " + QDateTime::currentDateTime().toString(Qt::ISODate); |  | ||||||
|         resultLine += ", " + (res == true) ? "SUCCESS" : "ERROR"; |  | ||||||
|         m_out << resultLine; |  | ||||||
|     } // for (it = openLines.cbegin(); it != openLines.end(); ++it) { |  | ||||||
|  |  | ||||||
|     return finishUpdate(openLines.size() > 0); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| bool Utils::finishUpdate(bool replaceCtrlFile) { |  | ||||||
|     if (replaceCtrlFile) { |  | ||||||
|         if (!m_update_ctrl_file_copy.exists()) { |  | ||||||
|             return false; |  | ||||||
|         } |  | ||||||
|         if (!m_update_ctrl_file.remove()) { |  | ||||||
|             return false; |  | ||||||
|         } |  | ||||||
|         if (!m_update_ctrl_file_copy.rename(m_update_ctrl_file.fileName())) { |  | ||||||
|             return false; |  | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     return true; |     return false; | ||||||
| } | } | ||||||
|   | |||||||
							
								
								
									
										59
									
								
								utils.h
									
									
									
									
									
								
							
							
						
						
									
										59
									
								
								utils.h
									
									
									
									
									
								
							| @@ -3,44 +3,33 @@ | |||||||
|  |  | ||||||
| #include <QObject> | #include <QObject> | ||||||
| #include <QString> | #include <QString> | ||||||
|  | #include <QStringList> | ||||||
| #include <QFile> | #include <QFile> | ||||||
|  | #include <QFileInfo> | ||||||
|  | #include <QDateTime> | ||||||
|  | #include <QDir> | ||||||
|  | #include <QDebug> | ||||||
|  |  | ||||||
| #include <memory> | namespace Utils { | ||||||
|  |     int read1stLineOfFile(QString fileName); | ||||||
|  |     QString zoneName(quint8 i); | ||||||
|  |     void printCriticalErrorMsg(QString const &errorMsg, bool upper=false, bool lower=false); | ||||||
|  |     void printCriticalErrorMsg(QStringList const &errorMsg); | ||||||
|  |     void printInfoMsg(QString const &infoMsg, bool upper=false, bool lower=false); | ||||||
|  |     void printInfoMsg(QStringList const &infoMsg); | ||||||
|  |     void printUpdateStatusMsg(QDebug debug, QStringList const &updateMsg); | ||||||
|  |     void printUpdateStatusMsg(QStringList const &updateMsg); | ||||||
|  |     void printUpdateStatusMsg(QString const &updateMsg, bool upper=false, bool lower=false); | ||||||
|  |     void printUpdateStatusMsg(QDebug debug, QString const &updateMsg, bool upper=false, bool lower=false); | ||||||
|  |     void printLineEditInfo(QStringList const &lines); | ||||||
|  |     QString getTariffLoadTime(QString fileName); | ||||||
|  |     QString rstrip(QString const &str); | ||||||
|  |     bool sameFilesInDirs(QDir const &dir1, QDir const &dir2, | ||||||
|  |                          QStringList const &nameFilters = {"*.json"}); | ||||||
|  |  | ||||||
| #include "interfaces.h" |  | ||||||
| #include "DCPlugin/include/hwapi.h" |  | ||||||
|  |  | ||||||
| #ifdef PTU5 |     QString getParentName(); | ||||||
| #define SERIAL_PORT "ttymxc2" |     bool isATBQTRunning(); | ||||||
| #else | } | ||||||
| #define SERIAL_PORT "ttyUSB0" |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| class Utils : public QObject { |  | ||||||
|     Q_OBJECT |  | ||||||
|  |  | ||||||
|     std::unique_ptr<hwinf> m_hw; |  | ||||||
|     char const *m_serialInterface; |  | ||||||
|     char const *m_baudrate; |  | ||||||
|     QFile m_update_ctrl_file; |  | ||||||
|     QFile m_update_ctrl_file_copy; |  | ||||||
|     QTextStream m_in; |  | ||||||
|     QTextStream m_out; |  | ||||||
|  |  | ||||||
|     bool m_init; |  | ||||||
|  |  | ||||||
|     void updateBinary(char const *fileToSendToDC); |  | ||||||
|     void updatePrinterConf(int nrOfTemplate, char const *fileToSendToDC); |  | ||||||
|     bool finishUpdate(bool finish); |  | ||||||
|     QStringList getOpenLines(); |  | ||||||
|     static constexpr QChar SEPARATOR = QChar(','); |  | ||||||
|  |  | ||||||
| public: |  | ||||||
|     explicit Utils(QString update_ctrl_file, |  | ||||||
|                    QObject *parent = nullptr, |  | ||||||
|                    char const *serialInterface = SERIAL_PORT, |  | ||||||
|                    char const *baudrate = "115200"); |  | ||||||
|     virtual ~Utils() override; |  | ||||||
|     bool doUpdate(); |  | ||||||
| }; |  | ||||||
| #endif // UTILS_H_INCLUDED | #endif // UTILS_H_INCLUDED | ||||||
|   | |||||||
							
								
								
									
										1113
									
								
								worker.cpp
									
									
									
									
									
								
							
							
						
						
									
										1113
									
								
								worker.cpp
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
		Reference in New Issue
	
	Block a user