Compare commits
	
		
			381 Commits
		
	
	
		
			f52dec9124
			...
			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 | |||
| 61c847102d | |||
| 3034f49c96 | |||
| 528b74549a | |||
| c7acc2a99b | |||
| 61afdfc325 | |||
| c34944af8b | |||
| 58684cf3c4 | |||
| 08122cf703 | |||
| fdd32cea92 | |||
| 7c17090a2b | |||
| 3de46ea099 | |||
| f46ac4075a | |||
| 0668ab65be | |||
| f66ae498ce | |||
| e420f95eb0 | |||
| 809440ba95 | |||
| c6ea94e249 | |||
| 4cee0e37da | |||
| 9c343f3eeb | |||
| e79d6c6fef | |||
| 88013e82f0 | |||
| 079a6910dd | |||
| bbf97dc58d | |||
| 810b603d70 | |||
| 8281303a55 | |||
| a4afeeb396 | |||
| bc3a801b8d | 
@@ -1,51 +1,139 @@
 | 
			
		||||
# QT -= gui
 | 
			
		||||
QT += core
 | 
			
		||||
QT += widgets serialport
 | 
			
		||||
QT += network
 | 
			
		||||
QT += core gui
 | 
			
		||||
QT += widgets serialport network
 | 
			
		||||
 | 
			
		||||
TARGET = ATBUpdateDC
 | 
			
		||||
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
 | 
			
		||||
 | 
			
		||||
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
 | 
			
		||||
 | 
			
		||||
CONFIG += c++17
 | 
			
		||||
# 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
 | 
			
		||||
 | 
			
		||||
# 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 ) {
 | 
			
		||||
    greaterThan(QT_MAJOR_VERSION, 4): QT += serialport
 | 
			
		||||
    CONFIG += link_pkgconfig
 | 
			
		||||
    lessThan(QT_MAJOR_VERSION, 5):   PKGCONFIG += qextserialport
 | 
			
		||||
    QMAKE_CXXFLAGS += -std=c++11   # for GCC >= 4.7
 | 
			
		||||
    QMAKE_CXXFLAGS += -Wno-deprecated-copy
 | 
			
		||||
    QMAKE_CXXFLAGS += -O2 -std=c++17   # for GCC >= 4.7
 | 
			
		||||
    # QMAKE_CXXFLAGS += -Wno-deprecated-copy
 | 
			
		||||
    ARCH = PTU5
 | 
			
		||||
    DEFINES+=PTU5
 | 
			
		||||
}
 | 
			
		||||
contains( CONFIG, PTU5_YOCTO ) {
 | 
			
		||||
    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
 | 
			
		||||
    ARCH = PTU5
 | 
			
		||||
    DEFINES+=PTU5
 | 
			
		||||
 | 
			
		||||
    # add qmqtt lib
 | 
			
		||||
    #LIBS += -lQt5Qmqtt
 | 
			
		||||
}
 | 
			
		||||
contains( CONFIG, DesktopLinux ) {
 | 
			
		||||
    greaterThan(QT_MAJOR_VERSION, 4): QT += serialport
 | 
			
		||||
    lessThan(QT_MAJOR_VERSION, 5):    CONFIG += extserialport
 | 
			
		||||
    # QMAKE_CC = ccache $$QMAKE_CC
 | 
			
		||||
    # QMAKE_CXX = ccache $$QMAKE_CXX
 | 
			
		||||
    QMAKE_CXXFLAGS += -std=c++11
 | 
			
		||||
    QMAKE_CXXFLAGS += -Wno-deprecated-copy
 | 
			
		||||
    QMAKE_CXXFLAGS += -std=c++17
 | 
			
		||||
    # QMAKE_CXXFLAGS += -Wno-deprecated-copy
 | 
			
		||||
    linux-clang {  QMAKE_CXXFLAGS += -Qunused-arguments   }
 | 
			
		||||
    ARCH = DesktopLinux
 | 
			
		||||
    DEFINES+=DesktopLinux
 | 
			
		||||
@@ -53,30 +141,39 @@ contains( CONFIG, DesktopLinux ) {
 | 
			
		||||
 | 
			
		||||
SOURCES += \
 | 
			
		||||
        main.cpp \
 | 
			
		||||
        progress_event.cpp \
 | 
			
		||||
        update_dc_event.cpp \
 | 
			
		||||
        mainwindow.cpp \
 | 
			
		||||
        utils.cpp \
 | 
			
		||||
        update.cpp \
 | 
			
		||||
        git/git_client.cpp \
 | 
			
		||||
        ismas/ismas_client.cpp \
 | 
			
		||||
        process/command.cpp \
 | 
			
		||||
        message_handler.cpp \
 | 
			
		||||
        worker.cpp \
 | 
			
		||||
        worker_thread.cpp
 | 
			
		||||
        worker.cpp
 | 
			
		||||
 | 
			
		||||
HEADERS += \
 | 
			
		||||
        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 \
 | 
			
		||||
        worker.h \
 | 
			
		||||
        worker_thread.h \
 | 
			
		||||
        plugins/interfaces.h
 | 
			
		||||
 | 
			
		||||
OTHER_FILES += \
 | 
			
		||||
    /opt/app/tools/atbupdate/update_log.csv \
 | 
			
		||||
    main.cpp.bck \
 | 
			
		||||
    main.cpp.bck2 \
 | 
			
		||||
    main.cpp.bck3
 | 
			
		||||
FORMS += \
 | 
			
		||||
    mainwindow.ui
 | 
			
		||||
 | 
			
		||||
# 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
 | 
			
		||||
# include(./DCPlugin/DCPlugin.pri)
 | 
			
		||||
 | 
			
		||||
# Default rules for deployment.
 | 
			
		||||
qnx: target.path = /tmp/$${TARGET}/bin
 | 
			
		||||
else: unix:!android: target.path = /opt/$${TARGET}/bin
 | 
			
		||||
!isEmpty(target.path): INSTALLS += target
 | 
			
		||||
##########################################################################################
 | 
			
		||||
# for running program on target through QtCreator
 | 
			
		||||
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
 | 
			
		||||
							
								
								
									
										169
									
								
								main.cpp
									
									
									
									
									
								
							
							
						
						
									
										169
									
								
								main.cpp
									
									
									
									
									
								
							@@ -4,22 +4,40 @@
 | 
			
		||||
#include <QTimer>
 | 
			
		||||
#include <QFileInfo>
 | 
			
		||||
 | 
			
		||||
#ifdef __linux__
 | 
			
		||||
#include <stdlib.h> // system()
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include "message_handler.h"
 | 
			
		||||
#include "plugins/interfaces.h"
 | 
			
		||||
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#include <thread>
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include <QSharedMemory>
 | 
			
		||||
#include <QRunnable>
 | 
			
		||||
#include <QThreadPool>
 | 
			
		||||
#include <QDir>
 | 
			
		||||
#include <QProcess>
 | 
			
		||||
#include <QCommandLineParser>
 | 
			
		||||
#include <QStandardPaths>
 | 
			
		||||
#include <QMainWindow>
 | 
			
		||||
 | 
			
		||||
#include "update.h"
 | 
			
		||||
#include "git/git_client.h"
 | 
			
		||||
#include "ismas/ismas_client.h"
 | 
			
		||||
#include "worker_thread.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
 | 
			
		||||
#define SERIAL_PORT "ttymxc2"
 | 
			
		||||
@@ -27,52 +45,145 @@
 | 
			
		||||
#define SERIAL_PORT "ttyUSB0"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static void doWork(QString update_ctrl_file, QString workingDir) {
 | 
			
		||||
    std::this_thread::sleep_for(std::chrono::milliseconds(2000));
 | 
			
		||||
    //Update update(update_ctrl_file, workingDir);
 | 
			
		||||
    //update.doUpdate();
 | 
			
		||||
    std::this_thread::sleep_for(std::chrono::milliseconds(2000));
 | 
			
		||||
    QCoreApplication::quit();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// argv[1]: file to send to dc
 | 
			
		||||
int main(int argc, char *argv[]) {
 | 
			
		||||
    QByteArray const value = qgetenv("LC_ALL");
 | 
			
		||||
    if (value != "C") {
 | 
			
		||||
        qputenv("LC_ALL", "C");
 | 
			
		||||
    }
 | 
			
		||||
    // qputenv("XDG_RUNTIME_DIR", "/run/user/0");
 | 
			
		||||
 | 
			
		||||
    openlog("ATB-UPDATE", LOG_PERROR | LOG_PID | LOG_CONS, LOG_USER);
 | 
			
		||||
 | 
			
		||||
    QApplication a(argc, argv);
 | 
			
		||||
    QApplication::setApplicationName("ATBUpdateTool");
 | 
			
		||||
    QApplication::setApplicationVersion(APP_VERSION);
 | 
			
		||||
 | 
			
		||||
    if (!messageHandlerInstalled()) { // change internal qt-QDebug-handling
 | 
			
		||||
        atbInstallMessageHandler(atbDebugOutput);
 | 
			
		||||
        setDebugLevel(QtMsgType::QtDebugMsg);
 | 
			
		||||
        //setDebugLevel(QtMsgType::QtDebugMsg);
 | 
			
		||||
        setDebugLevel(LOG_NOTICE);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    QByteArray const value = qgetenv("XDG_RUNTIME_DIR");
 | 
			
		||||
    if (value.size() == 0) {
 | 
			
		||||
        qputenv("XDG_RUNTIME_DIR", "/run/user/0");
 | 
			
		||||
    QCommandLineParser parser;
 | 
			
		||||
    parser.setApplicationDescription("Download tool for downloading device controller firmware, printer json-files and executing opkg-commands.");
 | 
			
		||||
    parser.addHelpOption();
 | 
			
		||||
    parser.addVersionOption();
 | 
			
		||||
 | 
			
		||||
    QCommandLineOption pluginDirectoryOption(QStringList() << "plugin-directory" << "plugin-directory",
 | 
			
		||||
        QCoreApplication::translate("main", "Where to find dc-plugin."),
 | 
			
		||||
        QCoreApplication::translate("main", "directory"));
 | 
			
		||||
    QString const pluginDefault = "/usr/lib";
 | 
			
		||||
    pluginDirectoryOption.setDefaultValue(pluginDefault);
 | 
			
		||||
    parser.addOption(pluginDirectoryOption);
 | 
			
		||||
 | 
			
		||||
    QCommandLineOption pluginNameOption(QStringList() << "plugin-name" << "plugin-name",
 | 
			
		||||
        QCoreApplication::translate("main", "Name of dc-plugin."),
 | 
			
		||||
        QCoreApplication::translate("main", "directory"));
 | 
			
		||||
    QString const pluginNameDefault = "libCAslave.so";
 | 
			
		||||
    pluginNameOption.setDefaultValue(pluginNameDefault);
 | 
			
		||||
    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",
 | 
			
		||||
        QCoreApplication::translate("main", "working directory of update-script."),
 | 
			
		||||
        QCoreApplication::translate("main", "directory"));
 | 
			
		||||
    QString const workingDirectoryDefault = "/opt/app/tools/atbupdate";
 | 
			
		||||
    workingDirectoryOption.setDefaultValue(workingDirectoryDefault);
 | 
			
		||||
    parser.addOption(workingDirectoryOption);
 | 
			
		||||
 | 
			
		||||
    QCommandLineOption dryRunOption(QStringList() << "d" << "dry-run",
 | 
			
		||||
        QCoreApplication::translate("main", "Start ATBUpdateTool in dry-run-mode. No actual actions."));
 | 
			
		||||
    parser.addOption(dryRunOption);
 | 
			
		||||
 | 
			
		||||
    QCommandLineOption extendedVersionOption(QStringList() << "V" << "extended-version",
 | 
			
		||||
        QCoreApplication::translate("main", "Show extended version (including last git commit)."));
 | 
			
		||||
    parser.addOption(extendedVersionOption);
 | 
			
		||||
 | 
			
		||||
    QCommandLineOption yoctoVersionOption(QStringList() << "y" << "yocto-version",
 | 
			
		||||
        QCoreApplication::translate("main", "Show yocto version of ATBUpdateTool."));
 | 
			
		||||
    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
 | 
			
		||||
    parser.process(a);
 | 
			
		||||
    QString plugInDir = parser.value(pluginDirectoryOption);
 | 
			
		||||
    QString plugInName = parser.value(pluginNameOption);
 | 
			
		||||
    QString workingDir = parser.value(workingDirectoryOption);
 | 
			
		||||
    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();
 | 
			
		||||
 | 
			
		||||
    int machineNr = Utils::read1stLineOfFile("/etc/machine_nr");
 | 
			
		||||
    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;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    QString rtPath = QCoreApplication::applicationDirPath();
 | 
			
		||||
    QString plugInDir(rtPath +(rtPath.endsWith("/") ? "" : "/") + "plugins");
 | 
			
		||||
    if (!QDir(plugInDir).exists()) {
 | 
			
		||||
        qCritical() << plugInDir
 | 
			
		||||
                    << "does not exists, but has to contain dc-library";
 | 
			
		||||
        exit(-1);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    qInfo() << "pwd" << "=" << rtPath;
 | 
			
		||||
    qInfo() << "plugInDir" << "=" << plugInDir;
 | 
			
		||||
    qInfo() << "pwd ......................" << rtPath;
 | 
			
		||||
    qInfo() << "plugInDir ................" << plugInDir;
 | 
			
		||||
    qInfo() << "plugInName ..............." << plugInName;
 | 
			
		||||
    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();
 | 
			
		||||
 | 
			
		||||
    hwinf *hw = Update::loadDCPlugin(QDir(plugInDir), "libCAmaster.so");
 | 
			
		||||
    // before loading the library, delete all possible shared memory segments
 | 
			
		||||
#if defined Q_OS_LINUX || defined Q_OS_UNIX
 | 
			
		||||
    // system("rm -rf /tmp/qipc*");
 | 
			
		||||
#else
 | 
			
		||||
#error "Only tested under UNIX/LINUX"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    QString const update_ctrl_file = "/opt/app/tools/atbupdate/update_log.csv";
 | 
			
		||||
    QString const workingDir = (argc == 2) ? argv[1] : ".";
 | 
			
		||||
    Update update(hw, update_ctrl_file, workingDir);
 | 
			
		||||
    Worker worker(customerNr,
 | 
			
		||||
                  machineNr,
 | 
			
		||||
                  zoneNr,
 | 
			
		||||
                  branchName,
 | 
			
		||||
                  plugInDir,
 | 
			
		||||
                  plugInName,
 | 
			
		||||
                  workingDir,
 | 
			
		||||
                  noUpdatePsaHardware,
 | 
			
		||||
                  dryRun);
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
    MainWindow mw(&worker);
 | 
			
		||||
    worker.setMainWindow(&mw);
 | 
			
		||||
 | 
			
		||||
    std::thread t(doWork, update_ctrl_file, workingDir);
 | 
			
		||||
    mw.setWindowFlags(Qt::Window | Qt::FramelessWindowHint);
 | 
			
		||||
    mw.showFullScreen();
 | 
			
		||||
 | 
			
		||||
    int ret = a.exec();
 | 
			
		||||
    t.join();
 | 
			
		||||
 | 
			
		||||
    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 <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 QtMsgType debugLevel = QtInfoMsg;
 | 
			
		||||
static int debugLevel = LOG_NOTICE;
 | 
			
		||||
 | 
			
		||||
QtMsgType getDebugLevel() { return debugLevel; }
 | 
			
		||||
void setDebugLevel(QtMsgType newDebugLevel) {
 | 
			
		||||
int getDebugLevel() { return debugLevel; }
 | 
			
		||||
void setDebugLevel(int newDebugLevel) {
 | 
			
		||||
    debugLevel = newDebugLevel;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -42,80 +45,53 @@ QtMessageHandler atbInstallMessageHandler(QtMessageHandler handler) {
 | 
			
		||||
///
 | 
			
		||||
#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) {
 | 
			
		||||
    static constexpr const char *format = "hh:mm:ss";
 | 
			
		||||
    // static constexpr const char *format = "dd.MM.yyyy hh:mm:ss";
 | 
			
		||||
    QByteArray localMsg = msg.toLocal8Bit();
 | 
			
		||||
    const char *file = context.file ? context.file : "";
 | 
			
		||||
    const char *function = context.function ? context.function : "";
 | 
			
		||||
    const char *p = std::strstr(function, "::");
 | 
			
		||||
    if (p) {
 | 
			
		||||
        function = p + 2;
 | 
			
		||||
    }
 | 
			
		||||
    char const* output = std::strrchr(file, '/');
 | 
			
		||||
    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());
 | 
			
		||||
    Q_UNUSED(context);
 | 
			
		||||
    QString const localMsg = QString(DBG_NAME[type]) + msg.toLocal8Bit();
 | 
			
		||||
 | 
			
		||||
    switch (debugLevel) {
 | 
			
		||||
        case LOG_DEBUG: { // debug-level message
 | 
			
		||||
            syslog(LOG_DEBUG, "%s", localMsg.toStdString().c_str());
 | 
			
		||||
        } break;
 | 
			
		||||
        case LOG_INFO: { // informational message
 | 
			
		||||
            if (type != QtDebugMsg) {
 | 
			
		||||
                syslog(LOG_DEBUG, "%s", localMsg.toStdString().c_str());
 | 
			
		||||
            }
 | 
			
		||||
        } break;
 | 
			
		||||
        case QtInfoMsg: {
 | 
			
		||||
            if (debugLevel == QtInfoMsg || debugLevel == QtDebugMsg) {
 | 
			
		||||
                snprintf(buf, sizeof(buf)-1, "%30.30s (%20.20s:%04u) %s.%03d INFO %s\n",
 | 
			
		||||
                         function, file, context.line,
 | 
			
		||||
                         datetime.time().toString(format).toStdString().c_str(),
 | 
			
		||||
                         fractional_part,
 | 
			
		||||
                         localMsg.constData());
 | 
			
		||||
        case LOG_NOTICE: { // normal, but significant, condition
 | 
			
		||||
            if (type != QtDebugMsg) {
 | 
			
		||||
                syslog(LOG_DEBUG, "%s", localMsg.toStdString().c_str());
 | 
			
		||||
            }
 | 
			
		||||
        } break;
 | 
			
		||||
        case QtWarningMsg: {
 | 
			
		||||
            if (debugLevel == QtInfoMsg || debugLevel == QtDebugMsg || debugLevel == QtWarningMsg) {
 | 
			
		||||
                snprintf(buf, sizeof(buf)-1, "%30.30s (%20.20s:%04u) %s.%03d WARN %s\n",
 | 
			
		||||
                         function, file, context.line,
 | 
			
		||||
                         datetime.time().toString(format).toStdString().c_str(),
 | 
			
		||||
                         fractional_part,
 | 
			
		||||
                         localMsg.constData());
 | 
			
		||||
        case LOG_WARNING: { // warning conditions
 | 
			
		||||
            if (type != QtInfoMsg && type != QtDebugMsg) {
 | 
			
		||||
                syslog(LOG_DEBUG, "%s", localMsg.toStdString().c_str());
 | 
			
		||||
            }
 | 
			
		||||
        } break;
 | 
			
		||||
        case QtCriticalMsg: {
 | 
			
		||||
            if (debugLevel == QtInfoMsg || debugLevel == QtDebugMsg
 | 
			
		||||
             || debugLevel == QtWarningMsg || debugLevel == QtCriticalMsg) {
 | 
			
		||||
                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());
 | 
			
		||||
        case LOG_ERR: { // error conditions
 | 
			
		||||
            if (type != QtInfoMsg && type != QtDebugMsg && type != QtWarningMsg) {
 | 
			
		||||
                syslog(LOG_DEBUG, "%s", localMsg.toStdString().c_str());
 | 
			
		||||
            }
 | 
			
		||||
        } break;
 | 
			
		||||
        case QtFatalMsg: {
 | 
			
		||||
            if (debugLevel == QtInfoMsg || debugLevel == QtDebugMsg
 | 
			
		||||
             || debugLevel == QtWarningMsg || debugLevel == QtCriticalMsg
 | 
			
		||||
             || debugLevel == QtFatalMsg) {
 | 
			
		||||
                snprintf(buf, sizeof(buf)-1, "%30.30s (%20.20s:%04u) %s.%03d FATAL %s\n",
 | 
			
		||||
                         function, file, context.line,
 | 
			
		||||
                         datetime.time().toString(format).toStdString().c_str(),
 | 
			
		||||
                         fractional_part,
 | 
			
		||||
                         localMsg.constData());
 | 
			
		||||
        case LOG_CRIT: { // critical conditions
 | 
			
		||||
            if (type != QtInfoMsg && type != QtDebugMsg && type != QtWarningMsg) {
 | 
			
		||||
                syslog(LOG_DEBUG, "%s", localMsg.toStdString().c_str());
 | 
			
		||||
            }
 | 
			
		||||
        } break;
 | 
			
		||||
        case LOG_ALERT: { // action must be taken immediately
 | 
			
		||||
            if (type != QtInfoMsg && type != QtDebugMsg && type != QtWarningMsg) {
 | 
			
		||||
                syslog(LOG_DEBUG, "%s", localMsg.toStdString().c_str());
 | 
			
		||||
            }
 | 
			
		||||
        } break;
 | 
			
		||||
        case LOG_EMERG: { // system is unusable
 | 
			
		||||
            if (type != QtInfoMsg && type != QtDebugMsg && type != QtWarningMsg) {
 | 
			
		||||
                syslog(LOG_DEBUG, "%s", localMsg.toStdString().c_str());
 | 
			
		||||
            }
 | 
			
		||||
        } break;
 | 
			
		||||
        default: {
 | 
			
		||||
            fprintf(stderr, "%*.*s.%03d No ErrorLevel defined! %s\n", OUTPUT_LEN, OUTPUT_LEN,
 | 
			
		||||
                datetime.time().toString(format).toStdString().c_str(), fractional_part,
 | 
			
		||||
                msg.toStdString().c_str());
 | 
			
		||||
            //fprintf(stderr, "%s No ErrorLevel defined! %s\n",
 | 
			
		||||
            //    datetime.toStdString().c_str(), msg.toStdString().c_str());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    fprintf(stderr, "%s\n", buf);
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -2,9 +2,12 @@
 | 
			
		||||
#define MESSAGE_HANDLER_H_INCLUDED
 | 
			
		||||
 | 
			
		||||
#include <QtGlobal>
 | 
			
		||||
#ifdef __linux__
 | 
			
		||||
#include <syslog.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
QtMsgType getDebugLevel();
 | 
			
		||||
void setDebugLevel(QtMsgType newDebugLevel);
 | 
			
		||||
int getDebugLevel();
 | 
			
		||||
void setDebugLevel(int newDebugLevel);
 | 
			
		||||
 | 
			
		||||
bool messageHandlerInstalled();
 | 
			
		||||
QtMessageHandler atbInstallMessageHandler(QtMessageHandler handler);
 | 
			
		||||
 
 | 
			
		||||
@@ -4,9 +4,6 @@
 | 
			
		||||
#include <QtPlugin>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#define THIS_IS_CA_MASTER
 | 
			
		||||
// undef for slvae
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
struct T_emp
 | 
			
		||||
{
 | 
			
		||||
@@ -131,28 +128,24 @@ struct T_vaultRecord
 | 
			
		||||
        uint32_t AbsReserve;
 | 
			
		||||
        uint32_t AbsNrOfCuts;
 | 
			
		||||
 | 
			
		||||
//16
 | 
			
		||||
        char label3buffer[4];	// mw >
 | 
			
		||||
 | 
			
		||||
        // Verkauf, Tür zu:
 | 
			
		||||
        uint32_t VKcoinsInserted[16];		// nur für Wechsler, soviel wurde eingeworfen
 | 
			
		||||
        uint32_t VKcoinsReturned[6];		// nur für Wechsler, Anzahl Münzen pro Typ, soviel wurde zurückgegeben
 | 
			
		||||
//88
 | 
			
		||||
        // Verkauf, Tuer zu:
 | 
			
		||||
        uint32_t VKcoinsInserted[16];		// nur fuer Wechsler, soviel wurde eingeworfen
 | 
			
		||||
        uint32_t VKcoinsReturned[6];		// nur fuer Wechsler, Anzahl Muenzen pro Typ, soviel wurde zurueckgegeben
 | 
			
		||||
 | 
			
		||||
        // Service, Tür offen:
 | 
			
		||||
        uint16_t ServCoinsInserted[16];		// nur für Wechsler, soviel wurde eingeworfen
 | 
			
		||||
        uint16_t ServCoinsReturned[6];		// nur für Wechsler, Anzahl Münzen pro Typ, soviel wurde zurückgegeben
 | 
			
		||||
        // Service, Tuer offen:
 | 
			
		||||
        uint16_t ServCoinsInserted[16];		// nur fuer Wechsler, soviel wurde eingeworfen
 | 
			
		||||
        uint16_t ServCoinsReturned[6];		// nur fuer Wechsler, Anzahl Muenzen pro Typ, soviel wurde zurueckgegeben
 | 
			
		||||
        uint16_t resint3;
 | 
			
		||||
        uint16_t resint4;
 | 
			
		||||
        uint16_t currentTubeContent[6];		//  nur für Wechsler, aktueller Füllstand
 | 
			
		||||
        uint16_t currentTubeContent[6];		//  nur fuer Wechsler, aktueller Fuellstand
 | 
			
		||||
        uint16_t resint5;
 | 
			
		||||
        uint16_t resint6;
 | 
			
		||||
// 56
 | 
			
		||||
 | 
			
		||||
        char label4buffer[4];	// box>
 | 
			
		||||
        uint16_t coinsInVault[16];
 | 
			
		||||
        uint16_t billsInStacker[8];
 | 
			
		||||
// 48
 | 
			
		||||
 | 
			
		||||
        char label5buffer[4];	// val>
 | 
			
		||||
        // actually constant unless exchange rate is changed
 | 
			
		||||
@@ -162,11 +155,17 @@ struct T_vaultRecord
 | 
			
		||||
        uint16_t exchangeRate;
 | 
			
		||||
        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];	// ----
 | 
			
		||||
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@@ -194,7 +193,7 @@ struct T_moduleCondition
 | 
			
		||||
        uint8_t	coinChecker;		// EMP, OMP or mei-cashflow
 | 
			
		||||
 | 
			
		||||
        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	coinReject;
 | 
			
		||||
 | 
			
		||||
@@ -204,7 +203,7 @@ struct T_moduleCondition
 | 
			
		||||
        uint8_t   temper;
 | 
			
		||||
 | 
			
		||||
        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	changer;			// can only be tested by usage
 | 
			
		||||
 | 
			
		||||
@@ -318,9 +317,10 @@ struct T_devices
 | 
			
		||||
    // set by master, used(1) or notused (0) or type 2....20
 | 
			
		||||
 | 
			
		||||
    UCHAR   kindOfPrinter;			// 0:off   1:Gebe
 | 
			
		||||
    UCHAR	kindOfCoinChecker;		// 0: without  1=EMP820   2=EMP900    3=currenza c²	(MW)
 | 
			
		||||
    UCHAR	kindOfCoinChecker;		// 0: without  1=EMP820   2=EMP900    3=currenza Csquare  (MW)
 | 
			
		||||
    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	kindOfCreditcard;		// 0:off    1:Feig NFC
 | 
			
		||||
@@ -339,10 +339,46 @@ struct T_devices
 | 
			
		||||
 | 
			
		||||
    UINT	VaultFullWarnLevel;
 | 
			
		||||
    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
 | 
			
		||||
{
 | 
			
		||||
@@ -360,7 +396,7 @@ public:
 | 
			
		||||
    //      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;
 | 
			
		||||
        // Command: open serial interface
 | 
			
		||||
        // BaudNr:  0:1200   1:9600   2:19200   3:38400   4:57600   5:115200
 | 
			
		||||
@@ -371,7 +407,7 @@ public:
 | 
			
		||||
    virtual void dc_closeSerial(void)  const =0;
 | 
			
		||||
        // Command: close serial interface in order to save power while power down
 | 
			
		||||
        // or if another port must be used
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    virtual bool dc_isPortOpen(void)  const =0;
 | 
			
		||||
        // returns true if port open (don't send unless open. Sending to closed port will crash program)                         
 | 
			
		||||
@@ -397,7 +433,7 @@ public:
 | 
			
		||||
        // get data back in "payLoad", max 64 byte, can be used for diagnosis
 | 
			
		||||
        // retval = nr of bytes received. If host buffer too small then
 | 
			
		||||
        // only plBufSiz bytes are copied to "payLoad"
 | 
			
		||||
        // plBufSizz=size of host buffer
 | 
			
		||||
        // plBufSiz = size of host buffer
 | 
			
		||||
 | 
			
		||||
    virtual void dc_setWakeFrequency(uint8_t period)  const =0;
 | 
			
		||||
        // RTC wakes DC2 (and PTU) by hardware signal every 32seconds
 | 
			
		||||
@@ -406,7 +442,7 @@ public:
 | 
			
		||||
    virtual void dc_OrderToReset(void)  const =0;
 | 
			
		||||
        // want DC2 to reset (in order to start Bootloader)
 | 
			
		||||
 | 
			
		||||
#ifdef THIS_IS_CA_MASTER
 | 
			
		||||
 | 
			
		||||
    virtual QString dc_getSerialState(void)  const =0;
 | 
			
		||||
        // get result of opening-command like "ttyS0 opened with 115200 8N1!
 | 
			
		||||
        // or error messages like "comport not available..."
 | 
			
		||||
@@ -414,7 +450,7 @@ public:
 | 
			
		||||
 | 
			
		||||
    virtual void dc_clrSerialStateText(void)  const =0;
 | 
			
		||||
        // clear above text to avoid multiple repetive displaying
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    virtual void bl_sendDataDirectly(uint8_t length, uint8_t *buf)  const =0;
 | 
			
		||||
        // send without protocol frame, needed for the DC bootloader
 | 
			
		||||
@@ -499,10 +535,10 @@ public:
 | 
			
		||||
 | 
			
		||||
    // Analog values:
 | 
			
		||||
    virtual uint32_t dc_getTemperature(void)  const =0;
 | 
			
		||||
        // in Sax-Format 0...400 (0=-50,0°C    100=0,0°C    141=20,5°C    400=150,0°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;
 | 
			
		||||
        // as string like "-12,5°C"
 | 
			
		||||
        // as string like "-12,5degC"
 | 
			
		||||
 | 
			
		||||
    virtual uint32_t dc_getVoltage(void)  const =0;
 | 
			
		||||
        // as value in mV,  0...65,535V
 | 
			
		||||
@@ -763,7 +799,7 @@ public:
 | 
			
		||||
                            uint8_t kindOfModem,        uint8_t kindOfCredit        ) const =0;
 | 
			
		||||
    // enable hardware in device controller:
 | 
			
		||||
    // kindOfPrinter:       0:off 1: GPT4672 (only this one implemented)
 | 
			
		||||
    // kindOfCoinChecker:   0:off 1:EMP820 2:EMP900 3: C²_changer
 | 
			
		||||
    // kindOfCoinChecker:   0:off 1:EMP820 2:EMP900 3: Csquare_changer
 | 
			
		||||
    // kindOfMifareReader:  0:off 1: SL025   (only this one implemented)
 | 
			
		||||
    // suppressSleep:       0:sleep allowed 1: sleep surpressed for special reason
 | 
			
		||||
    // kindOfModem:         0:off 1: ATB_Sunlink_LTE        (not yet implemented)
 | 
			
		||||
@@ -816,7 +852,7 @@ public:
 | 
			
		||||
// --------------------------------------------- MIFARE -----------------------------------------------------
 | 
			
		||||
// ----------------------------------------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// obsolete
 | 
			
		||||
    virtual uint8_t mif_returnReaderStateAndCardType(uint8_t *buf, uint8_t maxBufferSize) const =0;
 | 
			
		||||
        // retval 0=OK 1=error host buffer too small
 | 
			
		||||
    /* data description, new fast version:
 | 
			
		||||
@@ -838,13 +874,16 @@ public:
 | 
			
		||||
    virtual bool mif_readerIsOK(void) const =0;
 | 
			
		||||
 | 
			
		||||
    virtual bool mif_cardAttached(void) const =0;
 | 
			
		||||
        // not working! use mif_cardIsAttached() instead
 | 
			
		||||
 | 
			
		||||
    virtual uint8_t mif_readResult(void) const =0;
 | 
			
		||||
        // result: 0: unknown or still in progress
 | 
			
		||||
        //         1: card read successful
 | 
			
		||||
        //         2: reading error
 | 
			
		||||
        // not working!
 | 
			
		||||
 | 
			
		||||
    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;
 | 
			
		||||
 | 
			
		||||
@@ -889,7 +928,7 @@ public:
 | 
			
		||||
        // send 5 byte: byte 0,1: speed  5...250 mm/s
 | 
			
		||||
        //              byte2: density   0....(25)....50
 | 
			
		||||
        //              byte3: alignment    'l', 'c', 'r' = left, center, right
 | 
			
		||||
        //              byte4: orientation  0, 90, 180    = 0°, 90°, 180° 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
 | 
			
		||||
 | 
			
		||||
    virtual void prn_movePaper(uint8_t wayInMm, uint8_t direction) const =0;
 | 
			
		||||
@@ -1021,7 +1060,7 @@ public:
 | 
			
		||||
        // use for changer
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#ifdef THIS_IS_CA_MASTER
 | 
			
		||||
 | 
			
		||||
    virtual QString dc_getTxt4RsDiagWin(void) const =0;
 | 
			
		||||
    virtual void dc_clrTxt4RsDiagWin(void) const =0;
 | 
			
		||||
    virtual QString dc_get2ndTxt4RsDiagWin(void) const =0;
 | 
			
		||||
@@ -1036,7 +1075,6 @@ public:
 | 
			
		||||
    virtual void dc_clrTxt4dataStateLine(void) const =0;
 | 
			
		||||
    virtual QString dc_getdatifLine(void) const =0;
 | 
			
		||||
    virtual void dc_clrTxt4datifLine(void) const =0;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -1155,14 +1193,13 @@ public:
 | 
			
		||||
        // to be forwarded to Ismas
 | 
			
		||||
 | 
			
		||||
    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
 | 
			
		||||
 | 
			
		||||
    virtual bool prn_printTestTicket(void) const =0;
 | 
			
		||||
        // return true if sending to DC OK, false if cmd-stack is full
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    virtual bool cash_startPayment(uint32_t amount) const =0;
 | 
			
		||||
        // 17.4.23TS: extended to 32bit
 | 
			
		||||
 | 
			
		||||
@@ -1181,7 +1218,7 @@ public:
 | 
			
		||||
    virtual uint16_t getLastInsertedCoin(void) const =0;
 | 
			
		||||
 | 
			
		||||
    virtual bool getAllInsertedCoins(uint16_t *types, uint16_t *values) const =0;
 | 
			
		||||
        // alle bei diesem Verkauf eingeworfenen Münzen sind gespeichert, max 64
 | 
			
		||||
        // alle bei diesem Verkauf eingeworfenen Muenzen sind gespeichert, max 64
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    virtual bool cash_cancelPayment(void) const =0;
 | 
			
		||||
@@ -1235,6 +1272,8 @@ public:
 | 
			
		||||
 | 
			
		||||
    virtual uint8_t prn_getPrintResult() const =0;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    virtual uint8_t prn_getCurrentPrinterState() const =0;
 | 
			
		||||
        //        0: printer OK
 | 
			
		||||
        //          bit0: near paper end          bit1: no paper
 | 
			
		||||
@@ -1247,6 +1286,8 @@ public:
 | 
			
		||||
    virtual void sys_sendDeviceParameter(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;
 | 
			
		||||
 | 
			
		||||
@@ -1271,6 +1312,279 @@ public:
 | 
			
		||||
 | 
			
		||||
    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
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -1291,8 +1605,6 @@ signals:
 | 
			
		||||
    virtual void hwapi_payCancelled(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_doorVaultDoorOpened(void) const=0;
 | 
			
		||||
    virtual void hwapi_doorCoinBoxRemoved(void) const=0;
 | 
			
		||||
@@ -1327,6 +1639,11 @@ signals:
 | 
			
		||||
//                  getAllInsertedCoins() fixed, also in datif and storeINdata
 | 
			
		||||
 | 
			
		||||
// 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
 | 
			
		||||
 | 
			
		||||
// 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"
 | 
			
		||||
@@ -1337,9 +1654,25 @@ signals:
 | 
			
		||||
//#define HWINF_iid "Atb.Psa1256ptu5.software.HWapi/3.6"
 | 
			
		||||
//#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.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.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)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										
											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
 | 
			
		||||
							
								
								
									
										862
									
								
								update.cpp
									
									
									
									
									
								
							
							
						
						
									
										862
									
								
								update.cpp
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										75
									
								
								update.h
									
									
									
									
									
								
							
							
						
						
									
										75
									
								
								update.h
									
									
									
									
									
								
							@@ -6,6 +6,8 @@
 | 
			
		||||
#include <QFile>
 | 
			
		||||
#include <QDir>
 | 
			
		||||
#include <QByteArray>
 | 
			
		||||
#include <QProcess>
 | 
			
		||||
#include <QPluginLoader>
 | 
			
		||||
 | 
			
		||||
#include "plugins/interfaces.h"
 | 
			
		||||
 | 
			
		||||
@@ -15,47 +17,62 @@
 | 
			
		||||
#define SERIAL_PORT "ttyUSB0"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
class Update;
 | 
			
		||||
 | 
			
		||||
// TODO: check hardware compatibility
 | 
			
		||||
// TODO: opkg commandos
 | 
			
		||||
 | 
			
		||||
class Worker;
 | 
			
		||||
class Update : public QObject {
 | 
			
		||||
    Q_OBJECT
 | 
			
		||||
 | 
			
		||||
    hwinf *m_hw;
 | 
			
		||||
    hwinf *m_hw = nullptr;
 | 
			
		||||
    Worker *m_worker = nullptr;
 | 
			
		||||
    char const *m_serialInterface;
 | 
			
		||||
    char const *m_baudrate;
 | 
			
		||||
    QFile m_update_ctrl_file;
 | 
			
		||||
    QFile m_update_ctrl_file_copy;
 | 
			
		||||
    QString m_customerRepository;
 | 
			
		||||
    QString m_customerNrStr;
 | 
			
		||||
    QString m_branchName;
 | 
			
		||||
    QString m_pluginName;
 | 
			
		||||
    QString m_workingDir;
 | 
			
		||||
    bool m_maintenanceMode;
 | 
			
		||||
    bool m_dryRun;
 | 
			
		||||
 | 
			
		||||
    bool m_init;
 | 
			
		||||
 | 
			
		||||
    bool updateBinary(char const *fileToSendToDC);
 | 
			
		||||
    bool updatePrinterConf(int nrOfTemplate, char const *fileToSendToDC);
 | 
			
		||||
    bool finishUpdate(bool finish);
 | 
			
		||||
    QStringList getOpenLines();
 | 
			
		||||
    QStringList split(QString line, QChar sep = ',');
 | 
			
		||||
 | 
			
		||||
    bool execUpdateScript();
 | 
			
		||||
    static QPluginLoader pluginLoader;
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
    enum class DownloadResult {OK, ERROR, TIMEOUT, NOP};
 | 
			
		||||
    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 bool unloadDCPlugin();
 | 
			
		||||
    static QStringList split(QString line, QChar sep = ',');
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    explicit Update(hwinf *hw,
 | 
			
		||||
                    QString update_ctrl_file,
 | 
			
		||||
                    QString workingDir = ".",
 | 
			
		||||
    explicit Update(Worker *worker,
 | 
			
		||||
                    QString customerRepository,
 | 
			
		||||
                    QString customerNrStr,
 | 
			
		||||
                    QString branchName,
 | 
			
		||||
                    QString plugInDir,
 | 
			
		||||
                    QString pluginName,
 | 
			
		||||
                    QString workingDir,
 | 
			
		||||
                    bool dryRun = false,
 | 
			
		||||
                    QObject *parent = nullptr,
 | 
			
		||||
                    char const *serialInterface = SERIAL_PORT,
 | 
			
		||||
                    char const *baudrate = "115200");
 | 
			
		||||
    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:
 | 
			
		||||
    static QString jsonType(enum FileTypeJson type);
 | 
			
		||||
 | 
			
		||||
    DownloadResult sendStatus(int ret) const;
 | 
			
		||||
    DownloadResult sendNextAddress(int bNum) const;
 | 
			
		||||
    DownloadResult sendNextDataBlock(QByteArray const &b, int bNum) const;
 | 
			
		||||
@@ -65,8 +82,24 @@ private:
 | 
			
		||||
    bool stopBootloader() const;
 | 
			
		||||
    bool openSerial(int br, QString baudrate, QString comPort) const;
 | 
			
		||||
    void closeSerial() const;
 | 
			
		||||
    bool isSerialOpen() const;
 | 
			
		||||
    bool resetDeviceController() const;
 | 
			
		||||
    QByteArray loadBinaryDCFile(QString filename) const;
 | 
			
		||||
    bool downloadBinaryToDC(QString const &bFile) const;
 | 
			
		||||
    bool updateDC(QString bFile) const;
 | 
			
		||||
    bool updatePrinterTemplate(int templateIdx, QString fname) const;
 | 
			
		||||
    bool updateBinary(char const *fileToSendToDC);
 | 
			
		||||
    bool updateConfig(QString jsFileToSendToDC);
 | 
			
		||||
    bool updateCashConf(QString jsFileToSendToDC);
 | 
			
		||||
    bool updateDeviceConf(QString jsFileToSendToDC);
 | 
			
		||||
    bool downloadJson(enum FileTypeJson type, int templateIdx,
 | 
			
		||||
                      QString jsFileToSendToDC) const;
 | 
			
		||||
    QStringList getDcSoftAndHardWareVersion();
 | 
			
		||||
 | 
			
		||||
private slots:
 | 
			
		||||
    void readyReadStandardOutput();
 | 
			
		||||
    void readyReadStandardError();
 | 
			
		||||
    void finished(int exitCode, QProcess::ExitStatus exitStatus);
 | 
			
		||||
 | 
			
		||||
};
 | 
			
		||||
#endif // UPDATE_H_INCLUDED
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										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 "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 <QTemporaryFile>
 | 
			
		||||
#include <QDebug>
 | 
			
		||||
#include <QTextStream>
 | 
			
		||||
#include <QDebug>
 | 
			
		||||
#include <QDir>
 | 
			
		||||
#include <QDirIterator>
 | 
			
		||||
#include <QRegularExpression>
 | 
			
		||||
 | 
			
		||||
#include "interfaces.h"
 | 
			
		||||
#include "DCPlugin/include/hwapi.h"
 | 
			
		||||
#include <fstream>
 | 
			
		||||
 | 
			
		||||
//#include <unistd.h>
 | 
			
		||||
#include <thread>
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include <QSharedMemory>
 | 
			
		||||
#include <QScopedPointer>
 | 
			
		||||
#include <QProcess>
 | 
			
		||||
 | 
			
		||||
#define COLUMN_STATUS       (0)
 | 
			
		||||
#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;
 | 
			
		||||
int Utils::read1stLineOfFile(QString fileName) {
 | 
			
		||||
    QFile f(fileName);
 | 
			
		||||
    if (f.exists()) {
 | 
			
		||||
        if (f.open(QIODevice::ReadOnly | QIODevice::Text)) {
 | 
			
		||||
            QTextStream in(&f);
 | 
			
		||||
            in.setCodec("UTF-8");
 | 
			
		||||
            while(!in.atEnd()) {
 | 
			
		||||
                return in.readLine().toInt();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return openLines;
 | 
			
		||||
    return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool Utils::doUpdate() {
 | 
			
		||||
    /*
 | 
			
		||||
        The file referred to by 'update_data' has the following structure for
 | 
			
		||||
        each line:
 | 
			
		||||
QString Utils::zoneName(quint8 i) {
 | 
			
		||||
    static constexpr char const *zName[] = {
 | 
			
		||||
        "",
 | 
			
		||||
        "purple",
 | 
			
		||||
        "blue",
 | 
			
		||||
        "yellow",
 | 
			
		||||
        "green",
 | 
			
		||||
        "yellow (mars)",
 | 
			
		||||
        "green (mars)"
 | 
			
		||||
    };
 | 
			
		||||
    if (i < (sizeof(zName)/sizeof(char const *))) {
 | 
			
		||||
        return zName[i];
 | 
			
		||||
    }
 | 
			
		||||
    return "N/A";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
        # ======================================================================
 | 
			
		||||
        # STATUS    |  NAME  |   DATE  |  RESULT
 | 
			
		||||
        # ======================================================================
 | 
			
		||||
        # where
 | 
			
		||||
        #
 | 
			
		||||
        # STATUS: OPEN or CLOSED
 | 
			
		||||
        # 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
 | 
			
		||||
        # RESULT: SUCCESS or ERROR (possibly with description)
 | 
			
		||||
        #
 | 
			
		||||
     */
 | 
			
		||||
    if (!m_init) {
 | 
			
		||||
void Utils::printCriticalErrorMsg(QString const &errorMsg, bool upper, bool lower) {
 | 
			
		||||
    if (upper) qCritical() << QString(80, 'E');
 | 
			
		||||
 | 
			
		||||
    qCritical() << errorMsg;
 | 
			
		||||
 | 
			
		||||
    if (lower) qCritical() << QString(80, 'E');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Utils::printCriticalErrorMsg(QStringList const &errorMsg) {
 | 
			
		||||
    qCritical() << QString(80, 'E');
 | 
			
		||||
    for (int i = 0; i < errorMsg.size(); ++i) {
 | 
			
		||||
        qCritical() << errorMsg.at(i);
 | 
			
		||||
    }
 | 
			
		||||
    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;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    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;
 | 
			
		||||
    QList<QString>::const_iterator it;
 | 
			
		||||
    for (it = openLines.cbegin(); it != openLines.cend(); ++it) {
 | 
			
		||||
        int start = 0, end;
 | 
			
		||||
        int column = 0;
 | 
			
		||||
        QString status, name, datetime, result;
 | 
			
		||||
        QString line = *it;
 | 
			
		||||
        while ((end = line.indexOf(QChar(','), start)) != -1) {
 | 
			
		||||
            QString next = line.mid(start, end).trimmed();
 | 
			
		||||
            switch (column) {
 | 
			
		||||
            case COLUMN_STATUS:
 | 
			
		||||
                status = next;
 | 
			
		||||
                break;
 | 
			
		||||
            case COLUMN_NAME:
 | 
			
		||||
                name = next;
 | 
			
		||||
                break;
 | 
			
		||||
            case COLUMN_DATE_TIME:
 | 
			
		||||
                datetime = next;
 | 
			
		||||
                break;
 | 
			
		||||
            case COLUMN_RESULT:
 | 
			
		||||
                result = next;
 | 
			
		||||
                break;
 | 
			
		||||
    QStringList fileNameLst1{};
 | 
			
		||||
    QStringList fileNameLst2{};
 | 
			
		||||
    QListIterator<QFileInfo> i1(lst1);
 | 
			
		||||
    while (i1.hasNext()) {
 | 
			
		||||
        fileNameLst1 << i1.next().fileName();
 | 
			
		||||
    }
 | 
			
		||||
    QListIterator<QFileInfo> i2(lst2);
 | 
			
		||||
    while (i2.hasNext()) {
 | 
			
		||||
        fileNameLst2 << i2.next().fileName();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (fileNameLst1.isEmpty()) {
 | 
			
		||||
        qCritical() << "DIR1" << dir1.dirName() << " DOES NOT CONTAIN EXPECTED FILES";
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
    if (fileNameLst2.isEmpty())  {
 | 
			
		||||
        qCritical() << "DIR1" << dir2.dirName() << " DOES NOT CONTAIN EXPECTED FILES";
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
    if (fileNameLst1 != fileNameLst2) {
 | 
			
		||||
        printCriticalErrorMsg(dir1.dirName() + " AND " + dir2.dirName()
 | 
			
		||||
                            + " 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")) {
 | 
			
		||||
            qCritical() << "Parsing error for" << m_update_ctrl_file.fileName();
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        if (name.contains("dc2c") && name.endsWith(".bin")) {
 | 
			
		||||
            updateBinary(name.toStdString().c_str());
 | 
			
		||||
            res = true;
 | 
			
		||||
        } else
 | 
			
		||||
        if (name.contains("DC2C_print") && name.endsWith(".json")) {
 | 
			
		||||
            int i = name.indexOf("DC2C_print");
 | 
			
		||||
            int templateIdx = name.mid(i).midRef(10, 2).toInt();
 | 
			
		||||
            updatePrinterConf(templateIdx, name.toStdString().c_str());
 | 
			
		||||
            res = true;
 | 
			
		||||
        } else
 | 
			
		||||
        if (name.contains("opkg")) {
 | 
			
		||||
            int i = name.indexOf("opkg ");
 | 
			
		||||
            QString rest = name.mid(i).trimmed();
 | 
			
		||||
            QScopedPointer<QProcess> p(new QProcess(this));
 | 
			
		||||
            p->setProcessChannelMode(QProcess::MergedChannels);
 | 
			
		||||
            p->start("opkg", QStringList() << rest);
 | 
			
		||||
            if (p->waitForStarted(1000)) {
 | 
			
		||||
                if (p->state() == QProcess::ProcessState::Running) {
 | 
			
		||||
                    if (p->waitForFinished(10000)) {
 | 
			
		||||
                        QByteArray output = p->readAllStandardOutput();
 | 
			
		||||
                        qCritical() << output;
 | 
			
		||||
                        res = true;
 | 
			
		||||
bool Utils::isATBQTRunning() {
 | 
			
		||||
    QDirIterator it("/proc",
 | 
			
		||||
                    QStringList() << "status",
 | 
			
		||||
                    QDir::Files,
 | 
			
		||||
                    QDirIterator::Subdirectories);
 | 
			
		||||
    while (it.hasNext()) {
 | 
			
		||||
        QString const &nextStatusFile = it.next();
 | 
			
		||||
        static const QRegularExpression re("^/proc/[0-9]{1,}/status");
 | 
			
		||||
        QRegularExpressionMatch match = re.match(nextStatusFile);
 | 
			
		||||
        if (match.hasMatch()) {
 | 
			
		||||
            std::ifstream f(nextStatusFile.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) {
 | 
			
		||||
                            QString const binary = line.mid(idx+1).trimmed();
 | 
			
		||||
                            if (binary == "ATBQT") {
 | 
			
		||||
                                return 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 <QString>
 | 
			
		||||
#include <QStringList>
 | 
			
		||||
#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
 | 
			
		||||
#define SERIAL_PORT "ttymxc2"
 | 
			
		||||
#else
 | 
			
		||||
#define SERIAL_PORT "ttyUSB0"
 | 
			
		||||
#endif
 | 
			
		||||
    QString getParentName();
 | 
			
		||||
    bool isATBQTRunning();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										1113
									
								
								worker.cpp
									
									
									
									
									
								
							
							
						
						
									
										1113
									
								
								worker.cpp
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
		Reference in New Issue
	
	Block a user