diff --git a/QtDMM.spec b/QtDMM.spec index e49bc25..b6061e8 100644 --- a/QtDMM.spec +++ b/QtDMM.spec @@ -1,5 +1,5 @@ Name: qtdmm -Version: 1.0.0-alpha.1+dc7490a +Version: 1.0.0-alpha.1-12-gd0ba312+d0ba312 Release: 1%{?dist} Summary: DMM Readout Software Including a Configurable Recorder. diff --git a/assets/icons/add.xpm b/assets/icons/add.xpm new file mode 100644 index 0000000..74c723a --- /dev/null +++ b/assets/icons/add.xpm @@ -0,0 +1,465 @@ +/* XPM */ +static char * add_xpm[] = { +"32 32 430 2", +" c None", +". c #81CB74", +"+ c #57BA43", +"@ c #39AD1E", +"# c #3CB020", +"$ c #52BA37", +"% c #8ED27A", +"& c #ABDAA3", +"* c #DEEFDA", +"= c #8FCE82", +"- c #34A91C", +"; c #38AB1E", +"> c #76C560", +", c #D2EBCB", +"' c #D3EDCC", +") c #3EA92D", +"! c #9AD091", +"~ c #E3EDE2", +"{ c #C2E4B8", +"] c #AADC9B", +"^ c #B3DEA6", +"/ c #F1F5F0", +"( c #B4DDA8", +"_ c #72C55A", +": c #279C17", +"< c #5DB451", +"[ c #BEE2B6", +"} c #B0EC8D", +"| c #ABEB86", +"1 c #AEDBA2", +"2 c #67BC50", +"3 c #46B128", +"4 c #1F9610", +"5 c #229712", +"6 c #91D083", +"7 c #A1E580", +"8 c #A1D893", +"9 c #3BA81F", +"0 c #40AB21", +"a c #1C910F", +"b c #1F9210", +"c c #8BCE7D", +"d c #98E07A", +"e c #9CD58F", +"f c #38A31E", +"g c #3DA720", +"h c #1A8D0D", +"i c #1D8E0F", +"j c #88CB7B", +"k c #8FDC74", +"l c #97D38A", +"m c #359F1B", +"n c #39A31E", +"o c #18890C", +"p c #1A8A0E", +"q c #85C979", +"r c #87D76E", +"s c #87D86E", +"t c #93D087", +"u c #329B1A", +"v c #369F1C", +"w c #15850B", +"x c #18860D", +"y c #81C776", +"z c #7ED268", +"A c #7FD268", +"B c #7FD368", +"C c #8ECE83", +"D c #2F9819", +"E c #339C1B", +"F c #12800A", +"G c #16830C", +"H c #7FC575", +"I c #78CE63", +"J c #78CF63", +"K c #8ACC7F", +"L c #2C9418", +"M c #309819", +"N c #58AE58", +"O c #188D18", +"P c #037E01", +"Q c #057C03", +"R c #077B03", +"S c #097B05", +"T c #0C7A06", +"U c #0E7C07", +"V c #117D09", +"W c #147E0B", +"X c #7DC473", +"Y c #72CB5E", +"Z c #72CC5E", +"` c #73CC5E", +" . c #86C97B", +".. c #2A9016", +"+. c #2D9417", +"@. c #32991A", +"#. c #369E1C", +"$. c #3BA11F", +"%. c #3FA622", +"&. c #44AA24", +"*. c #49B027", +"=. c #5EBA3D", +"-. c #8DD172", +";. c #70BA70", +">. c #74BA74", +",. c #2E942E", +"'. c #017B01", +"). c #037802", +"!. c #067802", +"~. c #077704", +"{. c #0A7705", +"]. c #0C7806", +"^. c #0E7908", +"/. c #127B09", +"(. c #79C070", +"_. c #6CC85A", +":. c #6DC95B", +"<. c #6EC95B", +"[. c #81C675", +"}. c #288E14", +"|. c #2B9116", +"1. c #2F9618", +"2. c #339A1B", +"3. c #389F1E", +"4. c #3DA320", +"5. c #41A923", +"6. c #46AD25", +"7. c #6ABE4C", +"8. c #9CD487", +"9. c #9FD888", +"0. c #1F931F", +"a. c #50A950", +"b. c #89C389", +"c. c #89C486", +"d. c #7ABE75", +"e. c #79BD74", +"f. c #78BE73", +"g. c #77BE72", +"h. c #77BF71", +"i. c #76BE70", +"j. c #75BE6D", +"k. c #76BF6D", +"l. c #80C976", +"m. c #68C656", +"n. c #6AC756", +"o. c #6AC757", +"p. c #6BC857", +"q. c #86CC79", +"r. c #7FC571", +"s. c #82C775", +"t. c #86C97A", +"u. c #8ACB7F", +"v. c #8ECD84", +"w. c #91D088", +"x. c #97D28C", +"y. c #9ED595", +"z. c #A3D499", +"A. c #A6D696", +"B. c #87CE6C", +"C. c #6EC848", +"D. c #028402", +"E. c #1F8E1F", +"F. c #85C283", +"G. c #5BB64F", +"H. c #57B74B", +"I. c #57B94B", +"J. c #57BB4B", +"K. c #57BD4B", +"L. c #59BE4C", +"M. c #5BBF4D", +"N. c #5EC14F", +"O. c #60C250", +"P. c #62C351", +"Q. c #64C452", +"R. c #65C553", +"S. c #66C653", +"T. c #67C653", +"U. c #65C552", +"V. c #63C451", +"W. c #5DC04E", +"X. c #64C257", +"Y. c #6FC368", +"Z. c #4AAD47", +"`. c #038303", +" + c #7FC274", +".+ c #65C044", +"++ c #57C02F", +"@+ c #008200", +"#+ c #007B00", +"$+ c #60AF5C", +"%+ c #50B046", +"&+ c #50B246", +"*+ c #50B546", +"=+ c #50B746", +"-+ c #51B846", +";+ c #54BA48", +">+ c #56BC49", +",+ c #5ABE4B", +"'+ c #5CBF4C", +")+ c #5FC14E", +"!+ c #61C24F", +"~+ c #63C350", +"{+ c #64C451", +"]+ c #64C350", +"^+ c #62C350", +"/+ c #66C454", +"(+ c #7BCB6E", +"_+ c #6CC263", +":+ c #46B040", +"<+ c #058F02", +"[+ c #008900", +"}+ c #008300", +"|+ c #59B04C", +"1+ c #4EB72A", +"2+ c #54BC2C", +"3+ c #008100", +"4+ c #007900", +"5+ c #58A955", +"6+ c #49AC41", +"7+ c #49AE41", +"8+ c #49B041", +"9+ c #49B341", +"0+ c #4BB542", +"a+ c #4EB744", +"b+ c #51B945", +"c+ c #55BB47", +"d+ c #58BD49", +"e+ c #5BBF4B", +"f+ c #5EC14C", +"g+ c #60C24D", +"h+ c #62C34E", +"i+ c #7BCD6B", +"j+ c #7BCD6C", +"k+ c #73C764", +"l+ c #5DBB4E", +"m+ c #27A218", +"n+ c #1A9B0D", +"o+ c #109508", +"p+ c #079004", +"q+ c #008B00", +"r+ c #008400", +"s+ c #55AF48", +"t+ c #4BB428", +"u+ c #52BB2B", +"v+ c #008000", +"w+ c #007700", +"x+ c #479C45", +"y+ c #20911D", +"z+ c #259821", +"A+ c #2A9F25", +"B+ c #31A52C", +"C+ c #3AAC33", +"D+ c #45B33D", +"E+ c #53B947", +"F+ c #57BA47", +"G+ c #5BBC4B", +"H+ c #5FC04E", +"I+ c #67C255", +"J+ c #65C151", +"K+ c #5ABD44", +"L+ c #40B124", +"M+ c #38AD1D", +"N+ c #34AB1B", +"O+ c #2EA818", +"P+ c #27A415", +"Q+ c #1E9E10", +"R+ c #14980A", +"S+ c #0A9205", +"T+ c #008C00", +"U+ c #008500", +"V+ c #5BB34C", +"W+ c #49B327", +"X+ c #4FB929", +"Y+ c #007500", +"Z+ c #0C740C", +"`+ c #378E37", +" @ c #328E32", +".@ c #328F32", +"+@ c #329132", +"@@ c #349234", +"#@ c #389535", +"$@ c #3C9638", +"%@ c #409A39", +"&@ c #449D3C", +"*@ c #4CAB3E", +"=@ c #33AB1B", +"-@ c #3AAF1E", +";@ c #3EB221", +">@ c #41B323", +",@ c #5DB647", +"'@ c #56AD44", +")@ c #55AD44", +"!@ c #53AD43", +"~@ c #50AD41", +"{@ c #4CAC40", +"]@ c #4AAB3E", +"^@ c #47AA3C", +"/@ c #53AE45", +"(@ c #48B02C", +"_@ c #46B226", +":@ c #4DB828", +"<@ c #006B00", +"[@ c #006500", +"}@ c #006000", +"|@ c #005E00", +"1@ c #005D00", +"2@ c #015F00", +"3@ c #036001", +"4@ c #056202", +"5@ c #066503", +"6@ c #449D39", +"7@ c #38AE1E", +"8@ c #40B222", +"9@ c #46B625", +"0@ c #4AB827", +"a@ c #55AB42", +"b@ c #197D0D", +"c@ c #1D810F", +"d@ c #218611", +"e@ c #248B13", +"f@ c #289015", +"g@ c #2C9517", +"h@ c #309A19", +"i@ c #359F1C", +"j@ c #3AA51F", +"k@ c #44B125", +"l@ c #006300", +"m@ c #005B00", +"n@ c #005A00", +"o@ c #005C00", +"p@ c #015D01", +"q@ c #036002", +"r@ c #056203", +"s@ c #409A34", +"t@ c #45B524", +"u@ c #4CBA28", +"v@ c #51BD2B", +"w@ c #54AB3F", +"x@ c #187C0D", +"y@ c #1B810E", +"z@ c #1E8510", +"A@ c #228A12", +"B@ c #268F14", +"C@ c #2A9416", +"D@ c #2E9918", +"E@ c #339E1A", +"F@ c #38A41E", +"G@ c #3DAA20", +"H@ c #035E01", +"I@ c #046102", +"J@ c #3C9730", +"K@ c #3EB121", +"L@ c #49B826", +"M@ c #52BD2B", +"N@ c #59C12F", +"O@ c #52AA3D", +"P@ c #167B0C", +"Q@ c #1A800E", +"R@ c #015B01", +"S@ c #035F01", +"T@ c #37952B", +"U@ c #3DB120", +"V@ c #49B827", +"W@ c #55BF2D", +"X@ c #5FC532", +"Y@ c #52AA39", +"Z@ c #147A0B", +"`@ c #187F0D", +" # c #005900", +".# c #025E01", +"+# c #309026", +"@# c #38AE1D", +"## c #53BE2C", +"$# c #60C633", +"%# c #52AB38", +"&# c #137A0A", +"*# c #177F0C", +"=# c #015C01", +"-# c #278C1F", +";# c #2FA819", +"># c #3BB01F", +",# c #47A531", +"'# c #127A0A", +")# c #157F0B", +"!# c #1D8617", +"~# c #21A011", +"{# c #2BA617", +"]# c #3CB01F", +"^# c #349B24", +"/# c #107B09", +"(# c #14800A", +"_# c #11810F", +":# c #0F9508", +"<# c #16990C", +"[# c #1D9D0F", +"}# c #1F9F10", +"|# c #209016", +"1# c #0F7D07", +"2# c #138209", +"3# c #046003", +"4# c #12690A", +"5# c #268416", +"6# c #028D01", +"7# c #068F03", +"8# c #258A23", +"9# c #1B7B15", +"0# c #13810B", +"a# c #0D6C08", +"b# c #3F821E", +"c# c #719728", +"d# c #2D8613", +"e# c #047A04", +"f# c #057D04", +"g# c #3A9239", +"h# c #4B8948", +"i# c #267B21", +"j# c #147F0D", +"k# c #609925", +"l# c #82A62B", +"m# c #42911E", +"n# c #027701", +"o# c #047B02", +"p# c #69A567", +"q# c #4D904B", +"r# c #278123", +"s# c #65AB2A", +"t# c #2E9218", +"u# c #038301", +"v# c #6CAE6A", +"w# c #549951", +" ", +" . + @ # $ % ", +" & * = - ; > , ' ", +" ) ! ~ { ] ] ^ / ( _ ", +" : < [ } | | | 1 2 3 ", +" 4 5 6 7 7 7 7 8 9 0 ", +" a b c d d d d e f g ", +" h i j k k k k l m n ", +" o p q r s s s t u v ", +" w x y z A B B C D E ", +" F G H I J J J K L M ", +" N O P Q R S T U V W X Y Z ` ` ...+.@.#.$.%.&.*.=.-. ", +" ;.>.,.'.).!.~.{.].^./.(._.:.<.<.[.}.|.1.2.3.4.5.6.7.8.9. ", +" 0.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.A.B.C. ", +" D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.T.S.U.V.O.W.X.Y.Z.`. +.+++ ", +" @+#+$+%+&+*+=+-+;+>+,+'+)+!+~+{+{+{+]+^+/+(+_+:+<+[+}+|+1+2+ ", +" 3+4+5+6+7+8+9+0+a+b+c+d+e+f+g+h+m.i+j+k+l+m+n+o+p+q+r+s+t+u+ ", +" v+w+x+y+z+A+B+C+D+=+E+F+G+H+I+J+K+L+M+N+O+P+Q+R+S+T+U+V+W+X+ ", +" v+Y+Z+`+ @.@+@@@#@$@%@&@*@=@-@;@>@,@'@)@)@!@~@{@]@^@/@(@_@:@ ", +" Y+<@[@}@|@1@|@2@3@4@5@6@7@8@9@0@a@b@c@d@e@f@g@h@i@j@0 k@ ", +" <@l@1@m@n@n@o@p@q@r@s@# t@u@v@w@x@y@z@A@B@C@D@E@F@G@ ", +" H@I@J@K@L@M@N@O@P@Q@ ", +" R@S@T@U@V@W@X@Y@Z@`@ ", +" #.#+#@#9@##$#%#&#*# ", +" #=#-#;#>#L@W@,#'#)# ", +" #1@!#~#{#N+]#^#/#(# ", +" n@|@_#:#<#[#}#|#1#2# ", +" 3#4#5#q+6#<+7#8#9#0# ", +" a#b#c#d#e#f#g#h#i#j# ", +" k#l#m#n#o#p#q#r# ", +" s#t#v+u#v#w# ", +" "}; diff --git a/assets/icons/instances.xpm b/assets/icons/instances.xpm new file mode 100644 index 0000000..cd49b14 --- /dev/null +++ b/assets/icons/instances.xpm @@ -0,0 +1,199 @@ +/* XPM */ +static char * instances_xpm[] = { +"32 32 164 2", +" c None", +". c #D68504", +"+ c #000000", +"@ c #563D06", +"# c #D38D06", +"$ c #915906", +"% c #7F5309", +"& c #F2BB0E", +"* c #875208", +"= c #DE9506", +"- c #7F7F7F", +"; c #86827D", +"> c #8B867C", +", c #8B887C", +"' c #CA954A", +") c #F5CB35", +"! c #B9774A", +"~ c #FFE840", +"{ c #C18046", +"] c #EABA24", +"^ c #E8AA18", +"/ c #595959", +"( c #84654F", +"_ c #CE922B", +": c #B77E3A", +"< c #AC6738", +"[ c #FFE655", +"} c #F6CE3B", +"| c #FFEA64", +"1 c #F4CD3B", +"2 c #FFEE60", +"3 c #AE6100", +"4 c #DC8C03", +"5 c #E3A115", +"6 c #1C1401", +"7 c #794A03", +"8 c #F7E05F", +"9 c #FADF5E", +"0 c #FAE062", +"a c #FFEA77", +"b c #FFEA76", +"c c #FDE568", +"d c #F7D757", +"e c #FFEC68", +"f c #DB8F0F", +"g c #C0D8C1", +"h c #C1D8C0", +"i c #C3D5BB", +"j c #C8A17C", +"k c #F9E165", +"l c #FFF18C", +"m c #FFF08B", +"n c #FFF08C", +"o c #FDE871", +"p c #CE7200", +"q c #B6CBB5", +"r c #804F00", +"s c #C59C00", +"t c #FDEB45", +"u c #FFFAA4", +"v c #FFF6A9", +"w c #FFF6A5", +"x c #FFF6A3", +"y c #FFF9A8", +"z c #FFF254", +"A c #F7CA00", +"B c #DC9402", +"C c #323232", +"D c #CDE0CE", +"E c #C1D8C1", +"F c #C6D6BD", +"G c #D09838", +"H c #F9CF00", +"I c #FFDF0E", +"J c #FFE329", +"K c #FFE531", +"L c #FFE32A", +"M c #FFDF11", +"N c #FDD600", +"O c #E5A83A", +"P c #A25E05", +"Q c #2D2D2D", +"R c #D0E1D1", +"S c #494949", +"T c #B5A287", +"U c #EEC212", +"V c #FFE700", +"W c #FFDF00", +"X c #FFDE00", +"Y c #FFDD00", +"Z c #FFE600", +"` c #F5CD0D", +" . c #A1620C", +".. c #303030", +"+. c #CEDFCF", +"@. c #A79986", +"#. c #DAB369", +"$. c #E6C25C", +"%. c #DC9D4C", +"&. c #FBD800", +"*. c #FEE100", +"=. c #FFE200", +"-. c #FFE201", +";. c #FFE400", +">. c #CC8A3A", +",. c #E9BA33", +"'. c #E3A700", +"). c #141414", +"!. c #C3D9C4", +"~. c #68645F", +"{. c #534D44", +"]. c #676560", +"^. c #E1C17A", +"/. c #E5CC00", +"(. c #D69A48", +"_. c #FFF000", +":. c #C78A2E", +"<. c #EDD011", +"[. c #DCB043", +"}. c #C1D8C2", +"|. c #C1D9C2", +"1. c #C3D9C3", +"2. c #D7C283", +"3. c #C3D7BD", +"4. c #D2D0B4", +"5. c #E9CA00", +"6. c #8C7C6B", +"7. c #74634B", +"8. c #C79704", +"9. c #C2D9C3", +"0. c #CCDDCA", +"a. c #E1D1A9", +"b. c #C0D4BF", +"c. c #BCC3B1", +"d. c #B68207", +"e. c #5F5F5D", +"f. c #4F504F", +"g. c #B4976F", +"h. c #BBCFBC", +"i. c #C1D6C3", +"j. c #D4DFD5", +"k. c #4C4337", +"l. c #5E5F60", +"m. c #828386", +"n. c #BED4BF", +"o. c #C2D8C3", +"p. c #C4DAC6", +"q. c #C9DBCB", +"r. c #121213", +"s. c #5B5B5B", +"t. c #424242", +"u. c #383939", +"v. c #121212", +"w. c #181919", +"x. c #181819", +"y. c #3A3A3A", +"z. c #0A0A0B", +"A. c #FF0000", +"B. c #FFFFFF", +"C. c #969696", +"D. c #FFEE00", +"E. c #0019FF", +"F. c #C4C4C4", +"G. c #0022FF", +" . ", +" + + + + + + + + + + + + + + + @ # $ % & * = ", +" + - - - - - - - - - - - - - ; > , ' ) ! ~ { ] ^ ", +" + - / / / / / / / / / / / / / ( _ : < [ } | 1 2 3 4 5 ", +" + - / + + + + + + + + + + + + 6 7 8 9 0 a b a c d e f ", +" + - / + g g g g g g g g g g h h i j k l m m m n o p ", +" + - / + g + + + g g g + g + q r s t u v w x w v y z A B ", +" + - / + g g g + g g g + g C D E F G H I J K L M N O P ", +" + - / + g + + + g g g + + Q R S T U V W X X X Y Z ` . ", +" + - / + g g g + g g g g g ..+.@.#.$.%.&.*.=.-.;.>.,.'. ", +" + - / + g + + + g + g g g ).!.~.{.].^./.(._.:.<.[. ", +" + - / + g g g g g g g g g g g }.|.1.2.3.4.5.6.7.8. ", +" + - / + g + g + g + g + g g g g 9.0.a.b.c.d.e.f.g. ", +" + - / + g + g + g + g + g g g g |.9.h.i.j.k./ l.m. ", +" + - / + g g g g g g g g g g g g g n.o.p.q.r.s.t.u. ", +" + - / + + + + + + + + + + + + + + v.w.x.r.r./ y.z. ", +" + - / / / / / / / / / / / / / / / / / / / / / y.+ ", +" + - / A.A./ / / / / / / / / / / / / / / / / / / + ", +" + - A.B.A.A./ / / / / / / + + + + + + + + + + y.+ ", +" + - A.B.B.A./ / / / + + + C.C.C.C.C.C.C.C.C.C.y.+ ", +" + - / A.A./ / + + + C.C.C.C.C.C.D.C.C.C.E.E.C.y.+ ", +" + / / / / + + C.C.C.C.C.C.C.C.D.D.D.C.E.E.E.E.y.+ ", +" + - + + + C.C.C.C.C.F.F.C.C.F.C.C.C.C.E.E.E.E.y.+ ", +" + - C.C.C.C.C.F.C.C.C.C.C.C.C.C.C.C.F.C.E.E.C.y.+ ", +" + - D.C.C.C.C.C.C.D.D.D.F.F.F.F.C.C.F.C.C.C.C.y.+ ", +" + - D.C.F.C.C.F.F.D.D.D.F.F.F.F.F.F.C.C.C.C.C.y.+ ", +" + - D.F.C.C.F.F.F.+ + + + + + + F.F.G.C.C.F.C.y.+ ", +" + - D.C.C.F.F.F.+ + + + + + + + + G.G.G.C.F.C.y.+ ", +" + - D.C.C.F.F.+ B.+ y.y.y.y.y.+ + + G.G.C.C.C.y.+ ", +" + - D.C.A.A.+ + y.B.).y.y.y.y.y.+ + + G.G.C.C.y.+ ", +" + - D.C.A.A.+ + y.).).).y.y.y.y.y.+ + G.G.C.C.y.+ ", +" y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y. "}; diff --git a/assets/icons/menu.xpm b/assets/icons/menu.xpm index 17e0bec..6f08e88 100644 --- a/assets/icons/menu.xpm +++ b/assets/icons/menu.xpm @@ -31,27 +31,27 @@ static char * menu_xpm[] = { " ", " .++++++++++++++++++++++. ", " @#########$%&*=-;>,''''@ ", +" @#########$%&*=-;>,''''@ ", " )#######!~{]^/;(_'''''') ", " :::::::::::::::::::::::: ", " ", " ", " ", +" ", +" ", " ++++++++++++++++++++++++ ", " @#########$%&*=-;>,''''@ ", +" @#########$%&*=-;>,''''@ ", " )#######!~{]^/;(_'''''') ", " :::::::::::::::::::::::: ", " ", " ", " ", -" .++++++++++++++++++++++. ", -" @#########$%&*=-;>,''''@ ", -" )#######!~{]^/;(_'''''') ", -" :::::::::::::::::::::::: ", -" ", " ", " ", " ++++++++++++++++++++++++ ", " @#########$%&*=-;>,''''@ ", +" @#########$%&*=-;>,''''@ ", " )#######!~{]^/;(_'''''') ", " :::::::::::::::::::::::: ", " ", diff --git a/assets/icons/remove.xpm b/assets/icons/remove.xpm new file mode 100644 index 0000000..8add7d5 --- /dev/null +++ b/assets/icons/remove.xpm @@ -0,0 +1,289 @@ +/* XPM */ +static char * remove_xpm[] = { +"32 32 254 2", +" c None", +". c #B85E5E", +"+ c #9B1D1D", +"@ c #8D0000", +"# c #8E0000", +"$ c #8F0000", +"% c #910000", +"& c #930000", +"* c #960000", +"= c #990000", +"- c #9C0000", +"; c #A00000", +"> c #A40000", +", c #A80000", +"' c #AC0000", +") c #B10000", +"! c #B50000", +"~ c #BB0000", +"{ c #C00000", +"] c #C50000", +"^ c #CB0000", +"/ c #D10000", +"( c #D70000", +"_ c #DF1C1C", +": c #EB5C5C", +"< c #BF6E6E", +"[ c #C07373", +"} c #9D2D2D", +"| c #830000", +"1 c #840000", +"2 c #850000", +"3 c #860000", +"4 c #880000", +"5 c #8A0000", +"6 c #900000", +"7 c #970000", +"8 c #9B0000", +"9 c #A50000", +"0 c #AA0000", +"a c #AF0000", +"b c #B40000", +"c c #BA0000", +"d c #C10000", +"e c #C70000", +"f c #CD0000", +"g c #D30000", +"h c #E02C2C", +"i c #EB7070", +"j c #F06C6C", +"k c #9E2323", +"l c #AE4D4D", +"m c #CA8F8F", +"n c #CC8484", +"o c #BF5E5E", +"p c #C26262", +"q c #C36262", +"r c #C46262", +"s c #C56161", +"t c #C76161", +"u c #C86161", +"v c #CA6161", +"w c #CC6161", +"x c #CD6161", +"y c #CF6161", +"z c #D16161", +"A c #D36161", +"B c #D46161", +"C c #D66161", +"D c #D76161", +"E c #D86161", +"F c #D96161", +"G c #DA6060", +"H c #DA5D5D", +"I c #DD5F5F", +"J c #E36D6D", +"K c #DF8383", +"L c #E98484", +"M c #EC4D4D", +"N c #ED2222", +"O c #8F0505", +"P c #931E1E", +"Q c #C97F7F", +"R c #D25B5B", +"S c #D04E4E", +"T c #D45151", +"U c #D75050", +"V c #DA5050", +"W c #DD5050", +"X c #E05050", +"Y c #E25050", +"Z c #E45050", +"` c #E65050", +" . c #E75050", +".. c #E85050", +"+. c #E95050", +"@. c #E95151", +"#. c #E85151", +"$. c #E54F4F", +"%. c #E24D4D", +"&. c #E04C4C", +"*. c #DE5353", +"=. c #DE6161", +"-. c #D46363", +";. c #B43E3E", +">. c #8C1414", +",. c #CD5F5F", +"'. c #E92222", +"). c #E80404", +"!. c #890000", +"~. c #7E0000", +"{. c #B65555", +"]. c #C84848", +"^. c #C74343", +"/. c #CB4444", +"(. c #CF4444", +"_. c #D24444", +":. c #D64444", +"<. c #D94444", +"[. c #DC4444", +"}. c #DE4444", +"|. c #E04444", +"1. c #E24444", +"2. c #E44343", +"3. c #E54242", +"4. c #E54141", +"5. c #E44A4A", +"6. c #E45555", +"7. c #E05D5D", +"8. c #D55454", +"9. c #BE3131", +"0. c #A30808", +"a. c #850101", +"b. c #C03838", +"c. c #E50101", +"d. c #E60000", +"e. c #870000", +"f. c #7C0000", +"g. c #B35353", +"h. c #C84949", +"i. c #C74444", +"j. c #CF4343", +"k. c #D24343", +"l. c #D64242", +"m. c #D94242", +"n. c #DC4242", +"o. c #DF4242", +"p. c #E24242", +"q. c #E44444", +"r. c #E64646", +"s. c #E84A4A", +"t. c #E85454", +"u. c #E55555", +"v. c #DF4B4B", +"w. c #D43434", +"x. c #C51515", +"y. c #AB0000", +"z. c #A30000", +"A. c #9B0101", +"B. c #880101", +"C. c #BE3636", +"D. c #E30202", +"E. c #E40000", +"F. c #790000", +"G. c #A14242", +"H. c #AC2D2D", +"I. c #B22626", +"J. c #BE2E2E", +"K. c #C63333", +"L. c #CE3737", +"M. c #D43939", +"N. c #D93B3B", +"O. c #DD3C3C", +"P. c #E13D3D", +"Q. c #E43E3E", +"R. c #E63D3D", +"S. c #E73939", +"T. c #E63333", +"U. c #E42727", +"V. c #E01818", +"W. c #DA0808", +"X. c #CC0000", +"Y. c #BC0101", +"Z. c #B10303", +"`. c #A40202", +" + c #880A0A", +".+ c #C33535", +"++ c #E00000", +"@+ c #E20000", +"#+ c #7B1111", +"$+ c #8F2F2F", +"%+ c #922B2B", +"&+ c #962D2D", +"*+ c #9B2E2E", +"=+ c #A03030", +"-+ c #A53131", +";+ c #A93232", +">+ c #AD3232", +",+ c #B13131", +"'+ c #B52F2F", +")+ c #B82C2C", +"!+ c #BC2929", +"~+ c #BF2828", +"{+ c #C22727", +"]+ c #C42929", +"^+ c #C62C2C", +"/+ c #C72F2F", +"(+ c #C73030", +"_+ c #C62F2F", +":+ c #C42E2E", +"<+ c #C22E2E", +"[+ c #C02D2D", +"}+ c #BC2D2D", +"|+ c #C13131", +"1+ c #D51212", +"2+ c #DB0000", +"3+ c #E10000", +"4+ c #6D0000", +"5+ c #680000", +"6+ c #660202", +"7+ c #650101", +"8+ c #670000", +"9+ c #6A0000", +"0+ c #710000", +"a+ c #750101", +"b+ c #7A0101", +"c+ c #7E0202", +"d+ c #840202", +"e+ c #890202", +"f+ c #8E0202", +"g+ c #940101", +"h+ c #A20101", +"i+ c #A90101", +"j+ c #B00101", +"k+ c #B70101", +"l+ c #BF0101", +"m+ c #C70101", +"n+ c #CE0000", +"o+ c #D20000", +"p+ c #DA0000", +"q+ c #660000", +"r+ c #630000", +"s+ c #620000", +"t+ c #650000", +"u+ c #6B0000", +"v+ c #6F0000", +"w+ c #730000", +"x+ c #770000", +"y+ c #810000", +"z+ c #8B0000", +"A+ c #9D0000", +"B+ c #A90000", +"C+ c #BC0000", +"D+ c #C30000", +"E+ c #CA0000", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" . + @ @ @ # $ % & * = - ; > , ' ) ! ~ { ] ^ / ( _ : ", +" < [ } | 1 1 2 3 4 5 @ 6 & 7 8 ; 9 0 a b c d e f g h i j ", +" k l m n o p q r s t u v w x y z A B C D E F G H I J K L M N ", +" O P Q R S T U V W X Y Z ` ...+.@.#. .$.%.&.*.=.-.;.>.,.'.). ", +" !.~.{.].^./.(._.:.<.[.}.|.1.2.2.3.4.2.5.6.7.8.9.0.& a.b.c.d. ", +" e.f.g.h.i./.j.k.l.m.n.o.p.q.r.s...t.u.v.w.x.! y.z.A.B.C.D.E. ", +" 2 F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.g X.] Y.Z.`.7 +.+++@+ ", +" | F.#+$+%+&+*+=+-+;+>+,+'+)+!+~+{+]+^+/+(+_+:+<+[+}+|+1+2+3+ ", +" F.4+5+6+7+7+7+8+9+4+0+a+b+c+d+e+f+g+A.h+i+j+k+l+m+n+o+p+ ", +" 4+q+r+s+r+t+5+u+v+w+x+f.y+3 z+% 7 A+z.B+a ! C+D+E+o+ ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" "}; diff --git a/assets/translations/qtdmm_de.ts b/assets/translations/qtdmm_de.ts index 7bd3554..682b318 100644 --- a/assets/translations/qtdmm_de.ts +++ b/assets/translations/qtdmm_de.ts @@ -4,24 +4,24 @@ ConfigDlg - - - + + + QtDMM: Welcome! QtDMM: Willkommen! - + <font size=+2><b>Welcome!</b></font><p>This seems to be your first invocation of QtDMM (Or you have deleted its configuration file).<p>QtDMM has created the file %1 in your home directory to save its settings. <font size+2><b>Willkommen!</b></font><p>Dies scheint der erste Aufruf von QtDMM zu sein, bzw. die Konfigurstion wurde gelöscht.<p>QtDMM hate eine neue Datei unter dem Pfad %1 angelegt. - + <font size=+2><b>Welcome!</b></font><p>You seem to have upgraded <b>QtDMM</b> from a version prior to 0.8.4. Please check your configuration. There are some new parameters to be configured.<p>Thank you for choosing <b>QtDMM</b>.<p><i>Matthias Toussaint</i> <font size=+2><b>Willkommen!</b><p>Wie es ausschaut, wurde <b>QtDMM</b> von einer Version vor 0.8.4 aktualisiert. Bitte überprüfen Sie die Konfiguration. Es gibt einige neue Parameter.<p>Danke das Sie <b>QtDMM</b> benutzen.<p><i>Matthias Toussaint</i> - + Your config file has been converted to the new format. Please check your color settings, because they couldn't be converted automatically. Your old config ~/.qtdmmrc was renamed to ~/.qtdmmrc.old. @@ -34,8 +34,8 @@ Die Datei ~/.qtdmmtc wurden zu ~/.qtdmmrc.old umbenannt. <font size+2><b>Willkommen!</b></font><p>Dies scheint der erste Aufruf von QtDMM zu sein, bzw. die Konfigurstion wurde gelöscht.<p>QtDMM hate eine neue Datei unter dem Pfad %1 angelegt. - - + + Continue Fortsetzen @@ -229,41 +229,57 @@ Ist das DMM angeschlossen und eingeschaltet? Daten importieren ... - + Export data Daten exportieren + + + File contains only header + + All files (*.*) Alle Dateien (*.*) - + QtDMM: Unsaved data QtDMM: Ungesicherte Daten - + <font size=+2><b>Unsaved data</b></font><p>Importing data will overwrite your measured data<p>Do you want to export your unsaved data first? <font size=+2><b>Ungesicherte Daten</b></font><p>Beim Importieren werden alle bisherigen Messwerte gelöscht.<p>Möchten Sie zu ersten die bisherigen Daten exportieren? - + Export data first Daten zu erst exportieren - + Import & overwrite data Importieren und Daten löschen - + Import data Daten importieren - + + CSV (*.csv);;All files (*) + + + + + Cannot open file. + + + + + Oops! Seems not to be a valid file Diese Datei scheint nicht gültig zu sein @@ -303,18 +319,18 @@ Ist das DMM angeschlossen und eingeschaltet? <b>Hier können Sie den Anschluss und das Protokoll für Ihr DMM einstellen. Es gibt schon eine Reihe vorkonfigurierter Modelle.</b> - + Manual settings Manuelle Einstellung - + Load DMM description DMM Beschreibung laden - - + + DMM description (*.cfg) DMM Beschreibung (*.cfg) @@ -323,7 +339,7 @@ Ist das DMM angeschlossen und eingeschaltet? DMM Beschreibung (*.ini) - + Save DMM description DMM Beschreibung speichern @@ -385,6 +401,24 @@ Ist das DMM angeschlossen und eingeschaltet? <b>Hier wird das Erscheinungsbild von QtDMM eingestellt.</b> + + InstancesDlg + + + QtDMM - new instance + + + + + Instance name: + + + + + Instance already exists. + + + IntegrationPrefs @@ -401,47 +435,47 @@ Ist das DMM angeschlossen und eingeschaltet? MainWid - + QtDMM: Unsaved data QtDMM: Ungesicherte Daten - + <font size=+2><b>Unsaved data</b></font><p>You still have unsaved measured data in memory. If you quit now it will be lost.<p>Do you want to export your unsaved data first? <font size=+2><b>Ungesicherte Daten</b></font><p>Es befinden sich ungesicherte Daten im Speicher. Wenn Sie das Programm beenden gehen diese verloren.<p>Sollen diese vorher exportiert werden? - + Export data first Daten erst exportieren - + Quit without saving Beenden ohne speichern - + Automatic start at %1 Automatisch starten bei %1 - + Raising threshold %1 Grenzwert steigent %1 - + Falling threshold %1 Grenzwert fallend %1 - + <font size=+2><b>Launch error</b></font><p>Application %1 is still running!<p>Do you want to kill it now? <font size=+2><b>Startfehler</b></font><p>Programm %s läuft noch!<p>Wollen sie es jetzt beenden? - + <font size=+2><b>Launch error</b></font><p>Couldn't launch %1 <font size=+2><b>Startfehler</b></font><p>Konnte %1 nicht starten @@ -450,18 +484,18 @@ Ist das DMM angeschlossen und eingeschaltet? <font size=+2><b>Startfehler</b></font><p>Programm %s is still running!<p>Do you want to kill it now - + Launched %1 %1 gestartet - + %1 terminated with exit code %2. %1 mit dem Rückgabecode %2 beendet. - - + + QtDMM: Launch error QtDMM: Startfehler @@ -470,17 +504,17 @@ Ist das DMM angeschlossen und eingeschaltet? <font size=+2><b>Startfehler</b></font><p>Programm %1 läuft noch.<p>Soll es getötet werden - + Yes, kill it! Ja, töten! - + No, keep running Nein, es laufen lassen - + Bummer! Reinfall! @@ -488,15 +522,41 @@ Ist das DMM angeschlossen und eingeschaltet? MainWin - + + Record DMM data + + + + + Multiple instances of QtDMM have been detected. +Please choose which instance should record. + + + + + This instance + + + + + All instances + + + + QtDMM: Welcome! QtDMM: Willkommen! - + <h1>QtDMM %1</h1><hr><div align=right><i>A simple recorder for DMM's</i></div><p><div align=justify>A simple display software for a variety of digital multimeter. Currently confirmed are:<table>%2</table>Other compatible models may work also.<p>QtDMM features min/max memory and a configurable recorder with import/export and printing function. Sampling may be started manually, at a given time or triggered by a measured threshold. Additionally an external program may be started when given thresholds are reached.</div><div align=justify><b>QtDMM</b> uses the platform independent toolkit <b>Qt</b> version %3 and is licensed under <b>GPL 3</b> (Versions prior to v0.9.0 where licensed under GPL 2)</div><br>&copy; 2001-2014 Matthias Toussaint &nbsp;-&nbsp;&nbsp;<font color=blue><u><a href='mailto:qtdmm@mtoussaint.de'>qtdmm@mtoussaint.de</a></u></font><p><br>The icons (except the DMM icon) have been taken from the KDE project.<p> <h1>QtDMM %1</h1><hr><div align=right><i>Ein einfacher Datenrekorder für DMM</i></div><p><div align=justify>Ein einfaches Anzeigeprogramm für eine Vielzahl von DMM's. Aktuell bestätigt sind:<table>%2</table>Andere kompatible Modelle sollten ebenfalls funktionieren.<p>QtDMM stellt die Funktionen Min/Max Werte halten, ein konfigurierbaren Datenrekorder mit Daten im/export Funktion sowie ein Druckfunktion zur Verfügung. Die Datenaufzeichnung kann manuell, durch einen Grenzwert oder durch eine Zeitfunktion ausgelöst werden. Desweiteren kann ein externes Programm beim erreichen eines Grenzwertes gestartet werden.</div><div align=justify><b>QtDMM</b> wurde mit der Platformunabhängigen <b>Qt</b> Bibliothek in der Version %3 welche unter der <b>GPLv3</b> lizensiert ist erstellt.(Versionen vor 0.9.0 wurden unter der GPLv2 Lizenz veröffentlicht)</div><br>&copy; 2001-2014 Matthias Toussaint &nbsp;-&nbsp;&nbsp;<font color=blue><u><a href='mailto:qtdmm@mtoussaint.de'>qtdmm@mtoussaint.de</a></u></font><p><br>Die Symbole (bis auf das DMM Symbol) stammen von dem KDE Projekt.<p> + + + Another instance is running. + + PortsPrefs @@ -652,47 +712,47 @@ Danach müssen Sie sich ab- und wieder anmelden. Hier kann das DMM Modell ausgewählt werden. Wenn Ihr DMM nicht in der Liste ist, können Sie versuchen die Einstellungen per Hand herauszufinden. Und freundlicher weise an <font color=blue><u>qtdmm@mtoussaint.de</u></font> schicken, so das diese in der nächsten Version eingepflegt werden. - + Load Settings Einstellungen laden - + Save Settings Einstellungen speichern - + Port settings Anschlusseinstellungen - + Parit&y &Parität - + Parity for serial communication. May be None, Odd or Even. Parität für die serielle Übertragung. Diese kann Keine, Gerade oder Ungerade sein. - + None Keine - + Even Gerade - + Odd Ungerade - + Number of display digits. <ul><li>3 1/2 - 2000 Counts</li> <li>3 3/4 - 4000 Counts</li> @@ -707,47 +767,47 @@ Danach müssen Sie sich ab- und wieder anmelden. </ul> - + variable bytes ASCII, Sigrok variable bytes ASCII, Sigrok - + <html><head/><body><p>These protocoll settings have not been confirmed by a user yet. If you own this model and can confirm that it works. Please give me a note. <a href="https://github.com/tuxmaster/QtDMM"><span style=" text-decoration: underline; color:#0000ff;">https://github.com/tuxmaster/QtDMM</span></a></p></body></html> <html><head/><body><p>Diese Protokolleinstellungen wurden bisher von keinem Benutzer bestätigt. Wenn Sie dieses Modell besitzen und bestätigen können, das es funkioniert, dann melden Sie es bitte an: <a href="mailto:qtdmm@mtoussaint.de"><span style=" text-decoration: underline; color:#0000ff;">qtdmm@mtoussaint.de</span></a></p></body></html> - + <html><head/><body><p>If you have a DMM not listed above and find manual settings that work, please report to <a href="https://github.com/tuxmaster/QtDMM"><span style=" text-decoration: underline; color:#0000ff;">https://github.com/tuxmaster/QtDMM</span></a>. This way future users of this DMM can benefit from your help.</p></body></html> <html><head/><body><p>Wenn Sie ein DMM verwenden, welches hier nicht aufgeführt ist, aber Sie aber passende Einstellungen gefunden haben, so teilen Sie es bitte <a href="mailto:qtdmm@mtoussaint.de"><span style=" text-decoration: underline; color:#0000ff;">qtdmm@mtoussaint.de</span></a> mit. So können zukümpftige Versionen von Ihrer Hilfe profitieren.</p></body></html> - + 11 bytes binary, continuous (CyrustekES51986) 11 bytes binär, kontinuierlich (CyrustekES51986) - + 23 bytes ASCII, continuous (VC870) 23 bytes ASCII, kontinuierlich (VC870) - + 22 bytes binary, continuous (DO3122) 22 bytes binary, kontinuierlich (DO3122) - + 14 bytes half-ASCII, UNI-T UT61E (CyrustekES51922) 14 bytes halb-ASCII, UNI-T UT61E (CyrustekES51922) - + DTM0660 DTM0660 - + 11 bytes binary, continuous (CyrustekES51962) 11 bytes binär, kontinuierlich(CyrustekES51962) @@ -760,7 +820,7 @@ Danach müssen Sie sich ab- und wieder anmelden. <html><head/><body><p>Wenn Sie ein DMM verwenden, welches hier nicht aufgeführt ist, aber Sie aber passende Einstellungen gefunden haben, so teilen Sie es bitte <a href="mailto:qtdmm@mtoussaint.de"><span style=" text-decoration: underline; color:#0000ff;">qtdmm@mtoussaint.de</span></a> mit. So können zukümpftige Versionen von Ihrer Hilfe profitieren.</p></body></html> - + Number of bits for serial communication. Anzahl der Bits für die Übertragung. @@ -781,12 +841,12 @@ Danach müssen Sie sich ab- und wieder anmelden. 8 Bits - + &Bits: - + Number of stop bits for serial communication. Anzahl der Stoppbits. @@ -799,17 +859,17 @@ Danach müssen Sie sich ab- und wieder anmelden. 2 Stoppbits - + &Port: &Anschluss: - + Choose the serial device here. <i>(Hint for DOS people: /dev/ttyS0 corresponds to COM1. /dev/ttyS1 to COM2 ...)</i> Hier bitte den seriellen Anschluß wählen.<i>(Für Unixumsteiger: /dev/ttyS0 entspricht COM1 und so weiter)</i> - + Select the baud rate for the DMM here. If you encounter problems connecting to your DMM try lowering the baud rate. I had some problems with my <b>Metex ME-32</b>. The Documentation said 1200 baud but it only worked at 600. Hier die Baudrate für das DMM auswählen. Wenn Probleme mit der Verbindung zum DMM auftreten, bitte die Baudrate verringern. Es sind Probleme mit dem <b>Metex ME-32</b> bekannt. Laut Dokumentation soll es mit 1200 Baud laufen, aber tatsächlich geht es nur mit 600 Baud. @@ -842,63 +902,63 @@ Danach müssen Sie sich ab- und wieder anmelden. 19200 Baud - + &Digits S&tellen - + &Stop bits: &Stoppbits: - + Baud &rate: Baud&rate: - + External device setup Externe Steuerung - + Protocol Protokoll - + Here you may select the Communication type. If you have a not "officially" supported multimeter, just try out the existing protocols. If you are lucky it may work. If you find working settings, send the to me. Hier wird das Kommunikationsprotokoll ausgewählt. Wenn Sie kein "offiziell" unterstützes DMM benutzte, versuchen Sie eines der bereits vorhanden Protokolle. Mit etwas etwas Glück passt eines. Wenn Sie eins finden, teilen Sie es bitte dem Autor mit. Here you may select the Communication type. If you have a not "officially" supported multimeter, just try out the existing protocols. If you are lucky it may work. If you find working settings, send the to me. - + 14 bytes ASCII, polling (Metex/Voltcraft) 14 Bytes ASCII, auf Abfrage (Metex/Voltcraft) - + 11 bytes ASCII, continuous (PeakTech 451) 11 Bytes ASCII, kontinuierlich (PeakTech 451) - + 14 bytes ASCII, continuous (Voltcraft) 14 Bytes ASCII, kontinuierlich (Voltcraft) - + 15 bytes ASCII, continuous (Voltcraft) 15 Bytes ASCII, kontinuierlich (Voltcraft) - + 11 bytes binary, continuous (M9803R) 11 Bytes binär, kontinuierlich (M9803R) - + 14 bytes binary, continuous (VC820) 14 Bytes binär, kontinuierlich (VC820) @@ -907,27 +967,27 @@ Danach müssen Sie sich ab- und wieder anmelden. 22 Bytes ASCII, kontinuierlich (IsoTech) - + 11 bytes binary, continuous (VC940) 11 Bytes binär, kontinuierlich (VC940) - + 14 bytes ASCII/binary, continuous (QM1537) 14 Bytes ASCII/Binär, kontinuierlich (QM1537) - + 9 bytes binary, continuous (RS 22-812) 9 Bytes binär, kontinuierlich (RS 22-812) - + &Number of values: &Anzahl der Werte: - + Some multimeter send several lines of data containing different measured values. As QtDMM only shows one variable here you can set the number of lines to be ignored for each measurement (That means that QtDMM only uses the first line). Einige Multimeter senden verschiedenen Zeile mit verschiedenen Messwerten. Hier kann die Anzahl der zu ignorieren Zeilen eingetragen werden.( Das bedeutet, QtDMM verarbeitet nur die erste Zeile). @@ -1300,6 +1360,39 @@ Der Wert kann auch mit einem Suffix wie m, u, n, p, k, M, G oder T angegeben wer Tipp des Tages anzeigen + + UIInstancesDlg + + + Instance Manager + + + + + Choose instance to open, or add/remove instances + + + + + add new instance + + + + + + + + + + + remove instances + + + + + - + + + UIIntegrationPrefs @@ -1506,39 +1599,99 @@ Die maximale Auflösung für die Datensammlung liegt bei 1/10 Sekunde, bei Bedar - + Recorder Rekorder - + File Datei - + + Export graph + + + + + Import graph + + + + + Print graph + + + + + Connect/Disconnect DMM + + + + + reset min/max + + + + + Start recording + + + + + Stop recording + + + + + Clear graph + Graphen löschen + + + Help Hilfe - + + Ctrl+M + + + + + Instances + + + + + Instance Manager + + + + + Ctrl+N + + + + Display Anzeige - - - + + + Menu Menü - + &Export &Export - + <html><head/><body><p><span style=" font-weight:600;">Export recorder graph</span></p><p>Here you can export the recorded data as tab separated list. Each line contains the following values (separated by a tab character): date (dd.mm.yyyy) time (hh:mm:ss) value (float) unit.</p></body></html> <html><head/><body><p><span style=" font-weight:600;">Rekorder Graphen exportieren</span></p><p>Hier können die aufgezeichneten Daten als eine Liste durch Tabulatoren getrennt exportiert werden. Jede Zeile enthält die folgenden Werte (getrennt durch einen Tabulator): Datum (tt.mm.jjjj) Zeit (ss:mm:SS) Wert (Fließkomma) Einheit.</p></body></html> @@ -1547,22 +1700,22 @@ Die maximale Auflösung für die Datensammlung liegt bei 1/10 Sekunde, bei Bedar Strg+E - + &Import - + <html><head/><body><p><span style=" font-weight:600;">Import data into recorder</span></p><p>Here you can import previously exported data files. QtDMM tries to do an educated guess if the file format is correct and rejects import of files which to not match.</p></body></html> <html><head/><body><p><span style=" font-weight:600;">Importiert Daten in den Rekorder</span></p><p>Hier können zuvor exportierte Daten importiert werden. QtDMM versucht das Format zu lesen und verweigert den Import von ungültigen Dateien.</p></body></html> - + &Print &Drucken - + <html><head/><body><p><span style=" font-weight:600;">Print recorder graph</span></p><p>A dialog will open where you can define a title and a comment for your printout. The printer itself can also be configured here. To be able to print you need at least one working postscript printer configured in your system. Printing into a file is also supported.</p></body></html> <html><head/><body><p><span style=" font-weight:600;">Rekorder Graphen drucken</span></p><p>Es öffnet sich ein Fenster,indem der Titel und ein Kommentar für den Ausdruck festgelegt werden kann. Der Drucker selbst kann hier auch ausgewält werden. Der Ausdruck in eine Datei(PDF) ist ebenfalls möglich.</p></body></html> @@ -1571,25 +1724,25 @@ Die maximale Auflösung für die Datensammlung liegt bei 1/10 Sekunde, bei Bedar Strg+D - - + + &Configure &Konfigurieren - - - + + + <html><head/><body><p><span style=" font-weight:600;">Configure QtDMM</span></p><p>This will open QtDMM's configuration dialog. Here you can configure it's visual appearance and all options regarding the multimeter hardware and the recorder.</p></body></html> <html><head/><body><p><span style=" font-weight:600;">QtDMM konfigurieren</span></p><p>Dies öffnen das Konfugurationsfenster für QtDMM. Hier kann die visuelle Erscheinung, alle Optionen die die Datenaufzeichnung betreffen sowie die Einstellungen für das DMM festgelegt werden.</p></body></html> - + &Quit &Beenden - + <html><head/><body><p><span style=" font-weight:600;">Quit QtDMM</span></p><p>If the recorder contains unsaved data QtDMM will give you the option to savve your data first.</p></body></html> <html><head/><body><p><span style=" font-weight:600;">QtDMM Beenden</span></p><p>Wenn der Datenrekorder ungespeicherte Daten enthällt, haben Sie die Möglichkeit diese vorher zu speichern.</p></body></html> @@ -1598,12 +1751,12 @@ Die maximale Auflösung für die Datensammlung liegt bei 1/10 Sekunde, bei Bedar Strg+B - + &Connect &Verbinden - + <html><head/><body><p><span style=" font-weight:600;">Connect to the Multimeter</span></p><p>This will establish the serial connection to the dmm. If not connected the serial port is free and can be used by other software.</p></body></html> <html><head/><body><p><span style=" font-weight:600;">Verbindung zum DMM herstellen</span></p><p>Die baut die serielle Verbindung zum DMM auf.</p></body></html> @@ -1612,12 +1765,12 @@ Die maximale Auflösung für die Datensammlung liegt bei 1/10 Sekunde, bei Bedar Strg+V - + &Reset &Zurücksetzen - + <html><head/><body><p><span style=" font-weight:600;">Reset min/max values</span></p><p>The min/max values in the display will be reset. You can activate this option at any time. </p></body></html> <html><head/><body><p><span style=" font-weight:600;">Min/Max Werte zurücksetzen</span></p><p>Die Min/Max Werte in der Anzeige werden zurückgesetzt. Diese Option kann jederzeit aktiviert werden. </p></body></html> @@ -1626,12 +1779,12 @@ Die maximale Auflösung für die Datensammlung liegt bei 1/10 Sekunde, bei Bedar Strg+Z - + &Start &Starten - + <html><head/><body><p><span style=" font-weight:600;">Start the recorder</span></p><p>If you are in manual mode this will start the recorder. Press F2 to set the recorder options.</p></body></html> <html><head/><body><p><span style=" font-weight:600;">Rekorder starten</span></p><p>Startet den Rekorder wenn sich dieser im manuellen Modus befindet. F2 drücken für die Rekordereinstellungen.</p></body></html> @@ -1640,12 +1793,12 @@ Die maximale Auflösung für die Datensammlung liegt bei 1/10 Sekunde, bei Bedar Strg+S - + S&top &Anhalten - + <html><head/><body><p><span style=" font-weight:600;">Stop the recorder</span></p><p>The recorder will be stopped. This is independent from the start mode of the recorder. </p></body></html> <html><head/><body><p><span style=" font-weight:600;">Hällt den Rekorder an</span></p><p>Der Rekoder wird angehalten. Dies ist unabhängig von dem gewählten Startmodus. </p></body></html> @@ -1654,12 +1807,12 @@ Die maximale Auflösung für die Datensammlung liegt bei 1/10 Sekunde, bei Bedar Strg+A - + &Clear &Löschen - + <html><head/><body><p><span style=" font-weight:600;">Clear the recorder graph</span></p><p>If the recorder is already started it will clear the graph and continue recording.</p></body></html> <html><head/><body><p><span style=" font-weight:600;">Lösche den Graphen</span></p><p>Wenn der Rekorder läuft, wird der Graph gelöscht und es wird weiter aufgezeichnet.</p></body></html> @@ -1668,7 +1821,7 @@ Die maximale Auflösung für die Datensammlung liegt bei 1/10 Sekunde, bei Bedar Enf - + C&onfigure &Konfigurieren @@ -1677,7 +1830,7 @@ Die maximale Auflösung für die Datensammlung liegt bei 1/10 Sekunde, bei Bedar Strg+F2 - + &About Ü&ber @@ -1686,12 +1839,12 @@ Die maximale Auflösung für die Datensammlung liegt bei 1/10 Sekunde, bei Bedar Ü&ber die Version - + <html><head/><body><p><span style=" font-weight:600;">Copyright information</span></p><p>Show copyright information and some blurb about QtDMM. </p></body></html> <html><head/><body><p><span style=" font-weight:600;">Urheber Information</span></p><p>Zeigt die Information zum Urheber sowie etwas Werbung zu QtDMM an. </p></body></html> - + &Tip of the day &Tipp des Tages @@ -1700,17 +1853,17 @@ Die maximale Auflösung für die Datensammlung liegt bei 1/10 Sekunde, bei Bedar &Tipp des Tages - + <html><head/><body><p>Show tip of the day.</p></body></html> <html><head/><body><p>Zeigt den Tipp des Tages an.</p></body></html> - + &Direct Help &Direkte Hilfe - + <html><head/><body><p><span style=" font-weight:600;">Direct Help</span></p><p>Enter the direct help mode. You have done this already when reading this text :)</p></body></html> <html><head/><body><p><span style=" font-weight:600;">Direkte Hilfe</span></p><p>Schalten in den direkten Hilfemodus um. Dies haben Sie bereits duch lesen des Textes getan :)</p></body></html> diff --git a/cmake/ctest.cmake b/cmake/ctest.cmake index 4e8c46c..351a075 100644 --- a/cmake/ctest.cmake +++ b/cmake/ctest.cmake @@ -6,7 +6,7 @@ if (BUILD_TESTING) add_executable(${TEST_DECODER} MACOSX_BUNDLE tests/test_decoder.cpp src/dmmdecoder.cpp ${DECODER_FILES}) target_link_libraries(${TEST_DECODER} PRIVATE Qt::Core Qt::Test) - file(GLOB TEST_FILES CONFIGURE_DEPENDS "${CMAKE_SOURCE_DIR}/tests/data/*.json") + file(GLOB TEST_FILES CONFIGURE_DEPENDS "${CMAKE_SOURCE_DIR}/tests/data/decoder/*.json") foreach(test_file ${TEST_FILES}) get_filename_component(name ${test_file} NAME_WE) add_test(NAME ${name} COMMAND ${TEST_DECODER} ${test_file}) diff --git a/compile.sh b/compile.sh index 7a912ab..eb7bd49 100755 --- a/compile.sh +++ b/compile.sh @@ -129,7 +129,7 @@ then ${RUN} && ${QTDMM_EXE} elif ${RUN} then - ./${QTDMM_EXE} --debug + ./${QTDMM_EXE} #--debug fi exit 0 diff --git a/src/configdlg.cpp b/src/configdlg.cpp index a671dc6..3f794a0 100644 --- a/src/configdlg.cpp +++ b/src/configdlg.cpp @@ -39,15 +39,14 @@ #include -ConfigDlg::ConfigDlg(QString session_id, QString config_path, QWidget *parent) : QDialog(parent) +ConfigDlg::ConfigDlg(Settings* settings, QWidget *parent) + : QDialog(parent) + , m_settings(settings) { m_buttonBox_OK = false; setupUi(this); - m_settings = new Settings(this, session_id, config_path); - // Check if configuration file exists. If not welcome user - if (!m_settings->fileExists()) { QMessageBox welcome; diff --git a/src/configdlg.h b/src/configdlg.h index e2baae4..6cd0e67 100644 --- a/src/configdlg.h +++ b/src/configdlg.h @@ -57,8 +57,7 @@ class ConfigDlg : public QDialog, private Ui::UIConfigDlg NumItems, }; - ConfigDlg(QString session_id, QString config_path, QWidget *parent = Q_NULLPTR); - Settings *getSettings() { return m_settings; } + ConfigDlg(Settings* settings, QWidget *parent = Q_NULLPTR); QString device() const; int speed() const; int windowSeconds() const; diff --git a/src/dmmgraph.cpp b/src/dmmgraph.cpp index 8b8e8a8..95e8552 100644 --- a/src/dmmgraph.cpp +++ b/src/dmmgraph.cpp @@ -1152,20 +1152,28 @@ void DMMGraph::fillInfoBox(const QPoint &pos) bool DMMGraph::exportDataSLOT() { QDir path; - QString fn = QFileDialog::getSaveFileName(this, tr("Export data"), m_cfg->getString("QtDMM/LastUsesPath", "")); - if (!fn.isNull()) + QFileInfo fileInfo(m_cfg->getString("QtDMM/LastUsesPath")); + QStringList validSuffixes = { "csv" }; + QString fnSuffix = validSuffixes.contains(fileInfo.suffix()) ? fileInfo.suffix() : "csv"; + QString fn = fileInfo.baseName().isEmpty() ? "untitled.csv" : fileInfo.absolutePath() + "/untitled." + fnSuffix; + fn = QFileDialog::getSaveFileName(this, tr("Export data"), fn, "CSV (*.csv)"); + + if (!fn.isNull() && m_pointer>0) { QFile file(fn); m_cfg->setString("QtDMM/LastUsesPath", path.absoluteFilePath(fn)); file.open(QIODevice::WriteOnly); QTextStream ts(&file); - printf("p %d %d\n", m_pointer, m_sampleTime); + QString line = QString("timestamp;time (s);value;unit\n"); + ts << line; + for (int i = 0; i < m_pointer; i++) { - //QDateTime dt = m_graphStartDateTime.addMSecs(i * static_cast(qRound(m_sampleTime / 10.))); QDateTime dt = m_graphStartDateTime.addMSecs(i * m_sampleTime * 100); - QString line = QString("%1\t%2\t%3\n").arg(dt.toString("dd.MM.yyyy\tHH:mm:ss:zzz")).arg((*m_array)[i], 0, 'f').arg(m_unit); + //timestamp: ISO8601 + double deltaTime = (dt.toMSecsSinceEpoch()-m_graphStartDateTime.toMSecsSinceEpoch())/1000.0f; + line = QString("%1;%2;%3;%4\n").arg(dt.toString("yyyy-MM-ddTHH:mm:ss,zzz")).arg(deltaTime).arg((*m_array)[i], 0, 'f').arg(m_unit); ts << line; } m_dirty = false; @@ -1178,6 +1186,188 @@ bool DMMGraph::exportDataSLOT() return false; } + +void DMMGraph::importDataSLOT() +{ + if (m_dirty && m_alertUnsaved) + { + QMessageBox question; + question.setWindowTitle(tr("QtDMM: Unsaved data")); + question.setText(tr("Unsaved data

" + "Importing data will overwrite your measured data" + "

Do you want to export your unsaved data first?")); + question.setIcon(QMessageBox::Question); + + // Standard-Buttons + question.setStandardButtons(QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel); + question.setDefaultButton(QMessageBox::Yes); + question.setEscapeButton(QMessageBox::Cancel); + + QAbstractButton *yesButton = question.button(QMessageBox::Yes); + if (yesButton) + yesButton->setText(tr("Export data first")); + + QAbstractButton *noButton = question.button(QMessageBox::No); + if (noButton) + noButton->setText(tr("Import & overwrite data")); + + switch (question.exec()) + { + case QMessageBox::Yes: + exportDataSLOT(); + return; + case QMessageBox::Cancel: + return; + } + } + QDir path; + QString fn = QFileDialog::getOpenFileName(this, tr("Import data"), m_cfg->getString("QtDMM/LastUsesPath", tr("CSV (*.csv);;All files (*)"))); + + int cnt = 0; + int sample = 0; + + QDateTime graphEnd; + + if (!fn.isNull()) + { + m_cfg->setString("QtDMM/LastUsesPath", path.absoluteFilePath(fn)); + // First pass -> figure out size and sample time + QFile file(fn); + if (!file.open(QIODevice::ReadOnly)) + { + Q_EMIT error(tr("Cannot open file.")); + return; + } + + QStringList token; + QStringList dateToken; + QStringList timeToken; + QStringList timeParts; + + QTextStream ts(&file); + + QString line = ts.readLine(); + if (line.isNull()) + { + Q_EMIT error(tr("Oops! Seems not to be a valid file")); + file.close(); + return; + } + + // skip CSV-Header + if (line.startsWith("timestamp")) + { + line = ts.readLine(); + if (line.isNull()) + { + Q_EMIT error(tr("File contains only header")); + file.close(); + return; + } + } + + QRegularExpression reLegacy( + R"(^(?\d{2})\.(?\d{2})\.(?\d{4})\t(?\d{2}):(?\d{2}):(?\d{2}):(?\d{1,3})\t(?-?\d+(?:\.\d+)?|nan)\t(?.*)$)", + QRegularExpression::CaseInsensitiveOption + ); + + QRegularExpression reCSV( + R"(^(?\d{4})-(?\d{2})-(?\d{2})T(?\d{2}):(?\d{2}):(?\d{2})[,\.](?\d{1,3});(?-?\d+(?:\.\d+)?|nan);(?-?\d+(?:\.\d+)?|nan);(?.*)$)", + QRegularExpression::CaseInsensitiveOption + ); + + // detect format + bool isLegacy = reLegacy.match(line).hasMatch(); + + //(*m_array).clear(); + QVector values; + QRegularExpressionMatch match; + do + { + if (!line.trimmed().isEmpty()) + { + match = isLegacy ? reLegacy.match(line) : reCSV.match(line); + + if (!match.hasMatch()) + { + qInfo() << line; + Q_EMIT error(tr("Oops! Seems not to be a valid file")); + file.close(); + return; + } + + QDate valueDate( + match.captured("year").toInt(), + match.captured("month").toInt(), + match.captured("day").toInt() + ); + + QTime valueTime( + match.captured("hour").toInt(), + match.captured("minute").toInt(), + match.captured("second").toInt(), + match.captured("ms").toInt() + ); + + if (values.isEmpty()) + { + setUnit(match.captured("unit")); + m_graphStartDateTime = QDateTime(valueDate, valueTime); + } + + graphEnd = QDateTime(valueDate, valueTime); + sample += m_graphStartDateTime.secsTo(graphEnd); + values << (match.captured("value") == "nan" ? 0.0f : match.captured("value").toDouble()); + } + + line = ts.readLine(); + } + while (!line.isNull()); + file.close(); + + int cnt = values.size(); + m_sampleTime = (sample / (cnt > 1 ? cnt - 1 : 1))/10; + if (m_sampleTime<1) m_sampleTime=1; + qInfo() << m_graphStartDateTime.secsTo( graphEnd ) << m_sampleTime; + //m_sampleTime = m_graphStartDateTime.secsTo( graphEnd ) / (cnt > 1 ? cnt - 1 : 1); + + int size = m_size * m_sampleTime; + + if (cnt > 1) + { + Q_EMIT sampleTime(m_sampleTime); + m_sampleTime = (sample / (cnt - 1))/10; + } + if (m_sampleTime<1) m_sampleTime=1; + qInfo() << sample << cnt << m_sampleTime << m_graphStartDateTime.secsTo( graphEnd ); + + m_scaleMin = 1e40; + m_scaleMax = -1e40; + + // TEST + setGraphSize(size, cnt * m_sampleTime); + + for(int i=0; isetText(tr("Export data first")); @@ -1240,8 +1429,13 @@ void DMMGraph::importDataSLOT() if (!line.isNull()) { - QRegularExpression re(R"(^\d+\.\d+\.\d+\t\d+:\d+:\d+(?:\.\d+)?\t-?\d*\.\d+\t.*$)"); - if (!re.match(line).hasMatch()) + QRegularExpression reLegacy( + R"(^(?\d{2})\.(?\d{2})\.(?\d{4})\t(?\d{2}):(?\d{2}):(?\d{2}):(?\d{1,3})\t(?-?\d+(?:\.\d+)?)\t.*$)" + ); + QRegularExpression reCSV( + R"(^(?\d{4})-(?\d{2})-(?\d{2})T(?\d{2}):(?\d{2}):(?\d{2}),(?\d{1,3});(?-?\d+(?:\.\d+)?);(?-?\d+(?:\.\d+)?);(?.+)$)" + ); + if (!reCSV.match(line).hasMatch()) { Q_EMIT error(tr("Oops! Seems not to be a valid file")); @@ -1321,12 +1515,12 @@ void DMMGraph::importDataSLOT() m_sampleTime = sample / (cnt - 1); } - /* if (cnt*m_sampleTime > length) - { - if (size > cnt*m_sampleTime) size = cnt*m_sampleTime; - emit graphSize( size, cnt*m_sampleTime ); - setGraphSize( size, cnt*m_sampleTime ); - }*/ + // if (cnt*m_sampleTime > length) + // { + // if (size > cnt*m_sampleTime) size = cnt*m_sampleTime; + // emit graphSize( size, cnt*m_sampleTime ); + // setGraphSize( size, cnt*m_sampleTime ); + // } m_scaleMin = 1e40; m_scaleMax = -1e40; @@ -1373,6 +1567,10 @@ void DMMGraph::importDataSLOT() } } +*/ + + + void DMMGraph::setThresholds(double falling, double raising) { m_fallingThreshold = falling; diff --git a/src/dmmgraph.h b/src/dmmgraph.h index ae1878c..426b1da 100644 --- a/src/dmmgraph.h +++ b/src/dmmgraph.h @@ -150,7 +150,7 @@ protected Q_SLOTS: double m_xstep; double m_hUnitFact; double m_maxUnit; - int m_sampleTime; + double m_sampleTime; int m_sampleLength; bool m_running; bool m_connected; diff --git a/src/dmmprefs.cpp b/src/dmmprefs.cpp index fd659fe..7b2e1b3 100644 --- a/src/dmmprefs.cpp +++ b/src/dmmprefs.cpp @@ -45,6 +45,21 @@ DmmPrefs::DmmPrefs(QWidget *parent) : PrefWidget(parent) " also a number of predefined models."); m_pixmap = new QPixmap(":/Symbols/dmm.xpm"); + setupComboBoxModel(); + + message2->hide(); + + m_path = QDir::currentPath(); +} + + +DmmPrefs::~DmmPrefs() +{ + delete m_pixmap; +} + +void DmmPrefs::setupComboBoxModel() +{ ui_model->clear(); ui_model->insertItem(-1, tr("Manual settings")); @@ -61,15 +76,27 @@ DmmPrefs::DmmPrefs(QWidget *parent) : PrefWidget(parent) ui_model->addItem(cfg.name); } - message2->hide(); - - m_path = QDir::currentPath(); -} + QCompleter *completer = new QCompleter(ui_model->model(), this); + completer->setCaseSensitivity(Qt::CaseInsensitive); + completer->setFilterMode(Qt::MatchContains); + completer->setCompletionMode(QCompleter::PopupCompletion); + ui_model->setCompleter(completer); -DmmPrefs::~DmmPrefs() -{ - delete m_pixmap; + connect(ui_model->lineEdit(), &QLineEdit::editingFinished, this, [this]() + { + bool found = false; + for (int i = 0; i < ui_model->count(); ++i) + { + if (ui_model->itemText(i).compare(ui_model->currentText(), Qt::CaseInsensitive) == 0) + { + found = true; + break; + } + } + if (!found) + ui_model->setCurrentIndex(-1); + }); } QString DmmPrefs::deviceListText() const diff --git a/src/dmmprefs.h b/src/dmmprefs.h index c75b93b..1d5d814 100644 --- a/src/dmmprefs.h +++ b/src/dmmprefs.h @@ -64,7 +64,7 @@ protected Q_SLOTS: protected: QString m_path; DmmDecoder::DMMInfo m_dmmInfo; - -private: QStringListModel *m_portlist; + + void setupComboBoxModel(); }; diff --git a/src/guiprefs.cpp b/src/guiprefs.cpp index afc8758..c99ea88 100644 --- a/src/guiprefs.cpp +++ b/src/guiprefs.cpp @@ -103,8 +103,8 @@ void GuiPrefs::setToolbarVisibility(bool disp, bool dmm, bool graph, bool file) void GuiPrefs::applySLOT() { - m_cfg->setInt("QtDMM/version", 0); - m_cfg->setInt("QtDMM/revision", 84); + m_cfg->setInt("QtDMM/version", 0); // TODO set version by cmake + m_cfg->setInt("QtDMM/revision", 84); // TODO set revision by cmake m_cfg->setBool("QtDMM/show-tip", showTip()); m_cfg->setBool("Save/window-pos", saveWindowPosition()); m_cfg->setBool("Save/window-size", saveWindowSize()); diff --git a/src/instancesdlg.cpp b/src/instancesdlg.cpp new file mode 100644 index 0000000..3bce2b6 --- /dev/null +++ b/src/instancesdlg.cpp @@ -0,0 +1,144 @@ +#include +#include + +#include "instancesdlg.h" + + +InstancesDlg::InstancesDlg(Settings *settings, QString instance_id, QString config_path, QWidget *parent) + : QDialog(parent) + , m_instanceId(instance_id.isEmpty() ? "default" : instance_id) + , m_configPath(config_path) + , m_settings(settings) +{ + setupUi(this); + ui_instancesList->setStyleSheet("background-color: palette(window);"); +} + +void InstancesDlg::setInstancesOnline(QStringList instances) +{ + m_instancesOnline = instances; + updateInstancesListBox(); +} + +void InstancesDlg::updateInstancesListBox() +{ + ui_instancesList->clear(); + m_instancesConfigured = m_settings->getConfigInstances(); + + QStringList instances = m_instancesConfigured; + for (auto &instanceId : m_instancesOnline) + if (!instances.contains(instanceId)) + instances << instanceId; + + for (auto &instanceId : m_instancesConfigured) + { + QListWidgetItem *wi_item = new QListWidgetItem(ui_instancesList); + wi_item->setSizeHint(QSize(150, 40)); + + QPushButton *btn = new QPushButton(instanceId, ui_instancesList); + btn->setProperty("instanceId", instanceId); + QFont font = btn->font(); + if (instanceId != m_instanceId) + font.setBold(true); + font.setPointSize(font.pointSize() + 2); + btn->setFont(font); + + if (instanceId == m_instanceId || (m_onDelete && m_instancesOnline.contains(instanceId))) + btn->setEnabled(false); + else if (m_onDelete) + { + btn->setCheckable(true); + } + else + { + btn->setCheckable(false); + } + + connect(btn, SIGNAL(clicked()), this, SLOT(onInstanceButtonClicked())); + + ui_instancesList->addItem(wi_item); + ui_instancesList->setItemWidget(wi_item, btn); + } +} + + +void InstancesDlg::onInstanceButtonClicked() +{ + if (m_onDelete) + return; + + QPushButton *btn = qobject_cast(sender()); + if (!btn) + return; + + QString configId = btn->property("instanceId").toString(); + QString exePath = QCoreApplication::applicationFilePath(); + + if (configId == m_instanceId) + return; + + if (m_instancesOnline.contains(configId)) + Q_EMIT writeState("RAISE_"+configId); + else + { + QStringList args; + if (configId != "default") + args << "--config-id" << configId; + if (!m_configPath.isEmpty()) + args << "--config-dir" << m_configPath; + + QProcess::startDetached(exePath, args); + } +} + +void InstancesDlg::on_ui_instance_add_clicked() +{ + bool ok{}; + QString configId = QInputDialog::getText(this, tr("QtDMM - new instance"), tr("Instance name:"), QLineEdit::Normal, "", &ok).trimmed(); + if (!ok || configId.isEmpty() || configId == "default") + return; + + if (m_instancesOnline.contains(configId) || m_instancesConfigured.contains(configId) ) + { + QMessageBox::warning(this, APP_NAME,tr("Instance already exists.")); + return; + } + + QString exePath = QCoreApplication::applicationFilePath(); + + QStringList args; + if (configId != "default") + args << "--config-id" << configId; + if (!m_configPath.isEmpty()) + args << "--config-dir" << m_configPath; + + QProcess::startDetached(exePath, args); + Q_EMIT writeState("UPDATE_INSTANCES_"+QString::number(QDateTime::currentMSecsSinceEpoch())); +} + + +void InstancesDlg::on_ui_instance_del_clicked() +{ + if (m_onDelete && !ui_instance_del->isChecked()) + { + for (int i = 0; i < ui_instancesList->count(); ++i) + { + QListWidgetItem *item = ui_instancesList->item(i); + if (!item) + continue; + + auto btn = qobject_cast(ui_instancesList->itemWidget(item)); + if (!btn || !btn->isChecked()) + continue; + + QString configId = btn->property("instanceId").toString(); + m_settings->deleteConfig(configId); + } + Q_EMIT writeState("UPDATE_INSTANCES_"+QString::number(QDateTime::currentMSecsSinceEpoch())); + } + + m_onDelete = ui_instance_del->isChecked(); + updateInstancesListBox(); +} + + diff --git a/src/instancesdlg.h b/src/instancesdlg.h new file mode 100644 index 0000000..77274ce --- /dev/null +++ b/src/instancesdlg.h @@ -0,0 +1,32 @@ +#pragma once + +#include +#include "ui_uiinstancesdlg.h" +#include "settings.h" + +class InstancesDlg : public QDialog, private Ui::UIInstancesDlg +{ + Q_OBJECT +public: + InstancesDlg(Settings *settings, QString instance_id, QString config_path, QWidget *parent = Q_NULLPTR); + + void setInstancesOnline(QStringList instances); + void updateInstancesListBox(); + +protected: + QStringList m_instancesOnline; + QStringList m_instancesConfigured; + QString m_configPath; + QString m_instanceId; + Settings *m_settings; + bool m_onDelete; + +protected Q_SLOTS: + void onInstanceButtonClicked(); + void on_ui_instance_add_clicked(); + void on_ui_instance_del_clicked(); + +Q_SIGNALS: + void raiseApplicationWindow(const QString &); + void writeState(const QString &); +}; diff --git a/src/mainwid.cpp b/src/mainwid.cpp index b68f8c0..d8d8736 100644 --- a/src/mainwid.cpp +++ b/src/mainwid.cpp @@ -31,8 +31,12 @@ #include "dmm.h" #include "displaywid.h" #include "tipdlg.h" +#include "settings.h" +#include "instancesdlg.h" -MainWid::MainWid(QString session_id, QString config_path, QWidget *parent) : QFrame(parent), + + +MainWid::MainWid(QString instance_id, QString config_path, QWidget *parent) : QFrame(parent), m_display(0), m_tipDlg(0) { @@ -42,14 +46,18 @@ MainWid::MainWid(QString session_id, QString config_path, QWidget *parent) : QF m_dmm = new DMM(this); m_external = new QProcess(this); - m_configDlg = new ConfigDlg(session_id, config_path, this); + m_settings = new Settings(instance_id, config_path, this); + m_configDlg = new ConfigDlg(m_settings, this); m_configDlg->hide(); - m_configDlg->readPrinter(&m_printer); m_printDlg = new qtdmm::PrintDlg(this); m_printDlg->hide(); + m_instancesDlg = new InstancesDlg(m_settings, instance_id, config_path,this); + + connect(m_instancesDlg, SIGNAL(writeState(const QString &)), parent, SLOT(sendStateSLOT(const QString &))); + connect(this, SIGNAL(sendState(const QString &)), parent, SLOT(sendStateSLOT(const QString &))); connect(m_dmm, SIGNAL(value(double, const QString &, const QString &, const QString &, const QString &, bool, bool, int)), this, SLOT(valueSLOT(double, const QString &, const QString &, const QString &, const QString &, bool, bool, int))); connect(m_dmm, SIGNAL(error(const QString &)), this, SIGNAL(error(const QString &))); @@ -74,10 +82,11 @@ MainWid::MainWid(QString session_id, QString config_path, QWidget *parent) : QF connect(ui_graph, SIGNAL(thresholdChanged(DMMGraph::CursorMode, double)), m_configDlg, SLOT(thresholdChangedSLOT(DMMGraph::CursorMode, double))); - ui_graph->setSettings(m_configDlg->getSettings()); + ui_graph->setSettings(m_settings); //resetSLOT(); - + m_settings->save(); + Q_EMIT sendState("UPDATE_INSTANCES_"+QString::number(QDateTime::currentMSecsSinceEpoch())); startTimer(100); if (m_configDlg->showTip()) @@ -539,3 +548,13 @@ void MainWid::setToolbarVisibility(bool disp, bool dmm, bool graph, bool file) { m_configDlg->setToolbarVisibility(disp, dmm, graph, file); } + +void MainWid::instancesSLOT() +{ + m_instancesDlg->show(); +} + +void MainWid::instancesChangedSlot(QStringList& instances) +{ + m_instancesDlg->setInstancesOnline(instances); +} diff --git a/src/mainwid.h b/src/mainwid.h index 0071018..d39986c 100644 --- a/src/mainwid.h +++ b/src/mainwid.h @@ -27,6 +27,7 @@ #include #include "ui_uimainwid.h" + #include "printdlg.h" class DMM; @@ -34,12 +35,14 @@ class QProcess; class ConfigDlg; class DisplayWid; class TipDlg; +class Settings; +class InstancesDlg; class MainWid : public QFrame, private Ui::UIMainWid { Q_OBJECT public: - MainWid(QString session_id, QString config_path, QWidget *parent = Q_NULLPTR); + MainWid(QString instance_id, QString config_path, QWidget *parent = Q_NULLPTR); bool closeWin(); QRect winRect() const; bool saveWindowPosition() const; @@ -59,6 +62,7 @@ class MainWid : public QFrame, private Ui::UIMainWid void setConnect(bool); void toolbarVisibility(bool, bool, bool, bool); void connectDMM(bool); + void sendState(const QString&); public Q_SLOTS: void valueSLOT(double, const QString &, const QString &, const QString &, const QString &, bool, bool, int); @@ -79,6 +83,8 @@ public Q_SLOTS: void applySLOT(); void rejectSLOT(); void showTipsSLOT(); + void instancesSLOT(); + void instancesChangedSlot(QStringList&); protected: DMM *m_dmm; @@ -92,6 +98,8 @@ public Q_SLOTS: DisplayWid *m_display; double m_dval; TipDlg *m_tipDlg; + InstancesDlg *m_instancesDlg; + Settings *m_settings; void readConfig(); QRect parentRect() const; diff --git a/src/mainwin.cpp b/src/mainwin.cpp index 9c0368c..87503e7 100644 --- a/src/mainwin.cpp +++ b/src/mainwin.cpp @@ -29,27 +29,29 @@ #include "mainwid.h" #include "displaywid.h" - MainWin::MainWin(QCommandLineParser &parser, QWidget *parent) : QMainWindow(parent) , m_running(false) , m_menu(Q_NULLPTR) + , m_localRecord(true) { setupUi(this); setupIcons(); + m_config_id = parser.value("config-id"); + + m_stateMgr = new SharedStateManager(m_config_id.isEmpty()?"default":m_config_id,this); QWidget* spacer = new QWidget(); spacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); this->toolBarMenu->addWidget(spacer); this->toolBarMenu->addAction(this->action_Menu); - QString config_id = parser.value("config-id"); QString version = APP_VERSION; int plusIndex = version.indexOf('+'); if (plusIndex != -1) version = version.left(plusIndex); - m_wid = new MainWid(config_id, parser.value("config-dir"), this); + m_wid = new MainWid(m_config_id, parser.value("config-dir"), this); setCentralWidget(m_wid); setConsoleLogging(parser.isSet("debug")); @@ -59,7 +61,10 @@ MainWin::MainWin(QCommandLineParser &parser, QWidget *parent) toolBarDisplay->addWidget(m_display); m_wid->setDisplay(m_display); - setWindowTitle(QString("%1 %2 %3").arg(APP_NAME).arg(version).arg(config_id)); + if (m_config_id.isEmpty()) + setWindowTitle(QString("%1 %2").arg(APP_NAME).arg(version)); + else + setWindowTitle(QString("%1 %2 [%3]").arg(APP_NAME).arg(version).arg(m_config_id)); connect(m_wid, SIGNAL(running(bool)), this, SLOT(runningSLOT(bool))); @@ -88,19 +93,51 @@ MainWin::MainWin(QCommandLineParser &parser, QWidget *parent) m_wid->applySLOT(); - if (!winRect.isEmpty()) { if (m_wid->saveWindowPosition()) + { move(winRect.x(), winRect.y()); + } if (m_wid->saveWindowSize()) resize(winRect.width(), winRect.height()); else resize(640, 480); } - QTimer::singleShot(1000, action_Connect, &QAction::trigger); + + connect(m_stateMgr, &SharedStateManager::stateChanged, this, [=](const QString& state){ + if (state == "RECORD") + { + QMetaObject::invokeMethod(m_wid, "startSLOT", Qt::DirectConnection); + m_localRecord = false; + } + else if (state == "STOP") + { + if (!m_localRecord) + action_Stop->trigger(); + } + else if (state == "RAISE_"+(m_config_id.isEmpty()?"default":m_config_id)) + { + bringMainWindowToFront(); + m_stateMgr->writeState("IDLE"); + } + }); + + connect(m_stateMgr, &SharedStateManager::instanceIdAlreadyInUse, this, [=](){ + QMessageBox::critical(this, APP_NAME,tr("Another instance is running.")); + qApp->quit(); + }); + + if ( m_stateMgr->registerInstance() ) + QTimer::singleShot(1000, action_Connect, &QAction::trigger); } +void MainWin::sendStateSLOT(const QString & state) +{ + m_stateMgr->writeState(state); +} + + void MainWin::setConsoleLogging(bool on) { m_wid->setConsoleLogging(on); @@ -122,8 +159,9 @@ void MainWin::createActions() connect(action_Connect, SIGNAL(triggered(bool)), m_wid, SLOT(connectSLOT(bool))); connect(action_Connect, SIGNAL(triggered(bool)), this, SLOT(connectSLOT(bool))); connect(action_Reset, SIGNAL(triggered()), m_wid, SLOT(resetSLOT())); - connect(action_Start, SIGNAL(triggered()), m_wid, SLOT(startSLOT())); + connect(action_Start, SIGNAL(triggered()), this, SLOT(startSLOT())); connect(action_Stop, SIGNAL(triggered()), m_wid, SLOT(stopSLOT())); + connect(action_Stop, SIGNAL(triggered()), this, SLOT(stopSLOT())); connect(action_Clear, SIGNAL(triggered()), m_wid, SLOT(clearSLOT())); connect(action_Print, SIGNAL(triggered()), m_wid, SLOT(printSLOT())); connect(action_Import, SIGNAL(triggered()), m_wid, SLOT(importSLOT())); @@ -135,6 +173,7 @@ void MainWin::createActions() connect(action_Quit, SIGNAL(triggered()), m_wid, SLOT(quitSLOT())); connect(action_Direct_help, SIGNAL(triggered()), m_wid, SLOT(helpSLOT())); connect(action_Tip_of_the_day, SIGNAL(triggered()), m_wid, SLOT(showTipsSLOT())); + connect(action_Instances, SIGNAL(triggered()), m_wid, SLOT(instancesSLOT())); connect(toolBarDisplay, SIGNAL(visibilityChanged(bool)), this, SLOT(setToolbarVisibilitySLOT())); connect(toolBarMenu, SIGNAL(visibilityChanged(bool)), this, SLOT(setToolbarVisibilitySLOT())); @@ -142,12 +181,56 @@ void MainWin::createActions() connect(toolBarRecorder, SIGNAL(visibilityChanged(bool)), this, SLOT(setToolbarVisibilitySLOT())); connect(toolBarDMM, SIGNAL(visibilityChanged(bool)), this, SLOT(setToolbarVisibilitySLOT())); + connect(m_stateMgr, SIGNAL(instancesChanged(QStringList&)), m_wid, SLOT(instancesChangedSlot(QStringList&))); + connect(new QShortcut(action_Configure->shortcut(), this), SIGNAL(activated()), action_Configure, SLOT(trigger())); connect(new QShortcut(action_Direct_help->shortcut(), this), SIGNAL(activated()), action_Direct_help, SLOT(trigger())); connect(new QShortcut(action_About->shortcut(), this), SIGNAL(activated()), action_About, SLOT(trigger())); connect(new QShortcut(action_Quit->shortcut(), this), SIGNAL(activated()), action_Quit, SLOT(trigger())); } +void MainWin::startSLOT() +{ + if (m_stateMgr->instances().count()<=1) + { + QMetaObject::invokeMethod(m_wid, "startSLOT", Qt::DirectConnection); + m_localRecord = true; + } + else + { + QMessageBox question( + QMessageBox::Question, + tr("Record DMM data"), + tr("Multiple instances of QtDMM have been detected.\n" + "Please choose which instance should record."), + QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel); + question.button(QMessageBox::Yes)->setText(tr("This instance")); + question.button(QMessageBox::No)->setText(tr("All instances")); + question.setEscapeButton(QMessageBox::Cancel); + + switch (question.exec()) + { + case QMessageBox::Yes: + QMetaObject::invokeMethod(m_wid, "startSLOT", Qt::DirectConnection); + m_localRecord = true; + return; + case QMessageBox::No: + m_stateMgr->writeState("RECORD"); + m_localRecord = false; + return; + } + } +} + +void MainWin::stopSLOT() +{ + qInfo() << "stop" << m_localRecord; + if (! m_localRecord) + m_stateMgr->writeState("STOP"); + m_localRecord = false; + +} + void MainWin::runningSLOT(bool on) { m_running = on; @@ -251,3 +334,25 @@ void MainWin::setupIcons() this->action_Connect->setIcon(checked ? iconConnectOn : iconConnectOff); }); } + +void MainWin::bringMainWindowToFront() +{ + QWidget *mainWin = nullptr; + const auto topWidgets = QApplication::topLevelWidgets(); + + for (QWidget *w : topWidgets) + { + if (w->inherits("MainWin")) + { + mainWin = w; + break; + } + } + + if (!mainWin) + return; + + mainWin->showNormal(); + mainWin->raise(); + mainWin->activateWindow(); +} diff --git a/src/mainwin.h b/src/mainwin.h index 8f8fd7e..f5197b0 100644 --- a/src/mainwin.h +++ b/src/mainwin.h @@ -28,6 +28,7 @@ #include #include "ui_uimainwin.h" +#include "sharedstatemanager.h" class MainWid; class DisplayWid; @@ -43,6 +44,9 @@ class MainWin : public QMainWindow, private Ui::UIMainWin protected Q_SLOTS: void runningSLOT(bool); void connectSLOT(bool); + void startSLOT(); + void stopSLOT(); + void sendStateSLOT(const QString &); void on_action_About_triggered(); void on_action_Menu_triggered(); void setConnectSLOT(bool); @@ -57,10 +61,14 @@ protected Q_SLOTS: QLabel *m_error; QLabel *m_info; QMenu *m_menu; + SharedStateManager* m_stateMgr; + QString m_config_id; + bool m_localRecord; void setupIcons(); void createToolBars(); void createActions(); void closeEvent(QCloseEvent *)Q_DECL_OVERRIDE; + void bringMainWindowToFront(); }; diff --git a/src/resources.qrc b/src/resources.qrc index a61b464..c7692e6 100644 --- a/src/resources.qrc +++ b/src/resources.qrc @@ -22,6 +22,7 @@ ../assets/icons/W.xpm ../assets/icons/W_small.xpm ../assets/icons/ac.xpm + ../assets/icons/add.xpm ../assets/icons/all_digits.xpm ../assets/icons/auto.xpm ../assets/icons/bar.xpm @@ -61,6 +62,7 @@ ../assets/icons/icon.xpm ../assets/icons/icon_gray.xpm ../assets/icons/import.xpm + ../assets/icons/instances.xpm ../assets/icons/integration.xpm ../assets/icons/integration_old.xpm ../assets/icons/k.xpm @@ -88,6 +90,7 @@ ../assets/icons/print.xpm ../assets/icons/quit.xpm ../assets/icons/recorder.xpm + ../assets/icons/remove.xpm ../assets/icons/reset.xpm ../assets/icons/scale.xpm ../assets/icons/sixty_bar.xpm diff --git a/src/settings.cpp b/src/settings.cpp index 0a8f283..c1723ac 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -34,25 +34,73 @@ Settings::~Settings() delete m_tmpConfig; } -Settings::Settings(QObject *parent, const QString &session_id, const QString &config_path) : Settings(parent) +Settings::Settings(const QString &instance_id, const QString &config_path, QObject *parent) + : Settings(parent) { - if (!session_id.isEmpty()) + QFileInfo fileInfo(m_qsettings->fileName()); + m_configPath = fileInfo.absolutePath(); + m_configBaseFileName = fileInfo.baseName(); + m_configFileNameSuffix = fileInfo.suffix(); + m_instanceId = instance_id.isEmpty() ? "default" : instance_id; + + if (!instance_id.isEmpty() || !config_path.isEmpty()) { - QSettings qsettings(this); - QFileInfo fileInfo(qsettings.fileName()); - QString fileDir = config_path.isEmpty() ? fileInfo.absolutePath() : config_path; + m_configPath = config_path.isEmpty() ? fileInfo.absolutePath() : config_path; + m_configBaseFileName = fileInfo.baseName(); + m_configFileNameSuffix = fileInfo.suffix(); + + QString instance_fileName = m_configBaseFileName+(instance_id.isEmpty() ? "" : "_"+instance_id)+"."+m_configFileNameSuffix; + instance_fileName.prepend(m_configPath+"/"); - QString session_fileName = fileDir+"/"+fileInfo.baseName()+"_"+session_id+"."+fileInfo.suffix(); delete m_qsettings; - m_qsettings = new QSettings(session_fileName, QSettings::IniFormat, this); + m_qsettings = new QSettings(instance_fileName, QSettings::IniFormat, this); QFile file(m_qsettings->fileName()); m_fileExists = file.exists(); m_filename = m_qsettings->fileName(); m_fileConverted = false; - qInfo() << "config file: " << m_qsettings->fileName(); + //qInfo() << "config file: " << m_qsettings->fileName(); } } +QStringList Settings::getConfigInstances() +{ + QDir dir(m_configPath); + if (!dir.exists()) + return {}; + //qInfo() << m_configPath << m_configBaseFileName << m_configFileNameSuffix; + QString pattern = QString("%1*%2") + .arg(m_configBaseFileName) + .arg(m_configFileNameSuffix.isEmpty() ? "" : "." + m_configFileNameSuffix); + + QStringList result; + result << m_instanceId; + for (const QString &file : dir.entryList({ pattern }, QDir::Files, QDir::Name)) + { + QString base = QFileInfo(file).completeBaseName(); + + if (base.startsWith(m_configBaseFileName)) + base = base.mid(m_configBaseFileName.length()); + + if (base.startsWith("_")) + base.remove(0, 1); + + result << (base.isEmpty() ? "default" : base); + } + + result.removeDuplicates(); + result.sort(Qt::CaseInsensitive); + if (result.contains("default")) + { + result.removeAll("default"); + result.prepend("default"); + } + + //for (auto item : result) + // qInfo() << item; + + return result; +} + int Settings::getInt(const QString &name, const int &def) const { return m_qsettings->value(name, def).toInt(); @@ -107,3 +155,14 @@ void Settings::clear() { m_tmpConfig->clear(); } + + +void Settings::deleteConfig(QString instance_id) +{ + if(instance_id.isEmpty()) + return; + + QFile configFile(m_configPath+"/"+m_configBaseFileName+"_"+instance_id+"."+m_configFileNameSuffix); + configFile.remove(); +} + diff --git a/src/settings.h b/src/settings.h index 9c5aea4..651f2cc 100644 --- a/src/settings.h +++ b/src/settings.h @@ -25,14 +25,16 @@ class Settings : public QObject Q_OBJECT public: explicit Settings(QObject *parent = Q_NULLPTR); - explicit Settings(QObject *parent, const QString &session_id, const QString &config_path); + explicit Settings(const QString &instance_id, const QString &config_path, QObject *parent = Q_NULLPTR); ~Settings(); const bool &fileExists() const { return m_fileExists; } const bool &fileConverted() const { return m_fileConverted; } + const QString &fileName() const { return m_filename; } - const QString &fileName()const { return m_filename; } + void deleteConfig(QString instance_id); + QStringList getConfigInstances(); void save(); void clear(); @@ -53,5 +55,9 @@ class Settings : public QObject bool m_fileConverted; QString m_filename; QSettings *m_qsettings; + QString m_configPath; + QString m_configBaseFileName; + QString m_configFileNameSuffix; + QString m_instanceId; QHash *m_tmpConfig; }; diff --git a/src/sharedstatemanager.cpp b/src/sharedstatemanager.cpp new file mode 100644 index 0000000..d768faa --- /dev/null +++ b/src/sharedstatemanager.cpp @@ -0,0 +1,175 @@ +#include "sharedstatemanager.h" +#include +#include +#include +#include +#include +#include +#include + +SharedStateManager::SharedStateManager(const QString &instanceId, QObject *parent) + : QObject(parent), + m_memory("qtdmm_ipc_memory"), + m_lastState(), + m_instanceId(instanceId), + m_registered(false), + m_emit_inUse(false) +{ + m_timer.setInterval(250); + connect(&m_timer, &QTimer::timeout, this, &SharedStateManager::checkForChanges); + m_timer.start(); +} + +SharedStateManager::~SharedStateManager() +{ + unregisterInstance(); +} + +QJsonObject SharedStateManager::initialJson() +{ + QJsonObject data; + data["instances"] = QJsonArray(); + data["state"] = ""; + return data; +} + + +QJsonObject SharedStateManager::readJsonData() +{ + if (!m_memory.isAttached() && !m_memory.attach()) + return initialJson(); + + m_memory.lock(); + + QByteArray rawData(static_cast(m_memory.constData()), m_memory.size()); + int end = rawData.indexOf('\0'); + if (end != -1) + rawData.truncate(end); + + m_memory.unlock(); + QJsonParseError parseError; + QJsonDocument doc = QJsonDocument::fromJson(rawData, &parseError); + //qInfo() << QJsonDocument(doc).toJson(QJsonDocument::Compact); + + if (parseError.error != QJsonParseError::NoError || !doc.isObject()) + { + qInfo("parse error"); + return initialJson(); + } + + return doc.object(); +} + +bool SharedStateManager::writeJsonData(const QJsonObject &obj) +{ + if (!m_memory.isAttached() && !m_memory.attach()) + { + if (!m_memory.create(8192)) + return false; + } + QJsonDocument doc(obj); + QByteArray jsonData = doc.toJson(QJsonDocument::Compact); + + if (jsonData.size() > m_memory.size()) + { + m_memory.detach(); + if (!m_memory.create(jsonData.size() + 1024)) + return false; + } + + m_memory.lock(); + char *to = static_cast(m_memory.data()); + const char* from = jsonData.constData(); + memset(to, 0, m_memory.size()); + memcpy(to, from, jsonData.size()); + + m_memory.unlock(); + + return true; +} + +bool SharedStateManager::registerInstance() +{ + if (!m_registered) + { + QJsonObject data = readJsonData(); + QJsonArray instances = data["instances"].toArray(); + + for (const QJsonValue &val : instances) + { + if (val.toString() == m_instanceId) + { + qWarning() << m_instanceId << "id exists"; + m_emit_inUse = true; + return false; + } + } + + instances.append(m_instanceId); + data["instances"] = instances; + + m_registered = writeJsonData(data); + if (!m_registered) + qInfo() << "reg failed"; + } + + return m_registered; +} + +void SharedStateManager::checkForChanges() +{ + if (m_registered) + { + QJsonObject data = readJsonData(); + + QString currentState = data["state"].toString(); + QStringList instances; + for (const QVariant &v : data["instances"].toArray().toVariantList()) + instances << v.toString(); + + if (instances.count() != m_instances.count()) + { + m_instances = instances; + Q_EMIT instancesChanged(m_instances); + } + + if (currentState != m_lastState) + { + //qInfo() << currentState << QJsonDocument(data).toJson(QJsonDocument::Compact); + m_lastState = currentState; + if (currentState.startsWith("UPDATE_INSTANCES")) + Q_EMIT instancesChanged(m_instances); + Q_EMIT stateChanged(currentState); + } + } + if (m_emit_inUse) + Q_EMIT instanceIdAlreadyInUse(); + +} + +bool SharedStateManager::writeState(const QString &newState) +{ + QJsonObject data = readJsonData(); + data["state"] = newState; + return writeJsonData(data); +} + +void SharedStateManager::unregisterInstance() +{ + if (m_registered) + { + QJsonObject data = readJsonData(); + QJsonArray instances = data["instances"].toArray(); + + QJsonArray updated; + for (const QJsonValue &val : instances) + { + if (val.toString() != m_instanceId) + updated.append(val); + } + + data["instances"] = updated; + writeJsonData(data); + } +} + diff --git a/src/sharedstatemanager.h b/src/sharedstatemanager.h new file mode 100644 index 0000000..326cbf1 --- /dev/null +++ b/src/sharedstatemanager.h @@ -0,0 +1,42 @@ +#pragma once + +#include +#include +#include +#include + +class SharedStateManager : public QObject +{ + Q_OBJECT + +public: + explicit SharedStateManager(const QString &instanceId, QObject *parent = nullptr); + ~SharedStateManager(); + + bool registerInstance(); + void unregisterInstance(); + + void checkForChanges(); + QStringList instances() { return m_instances; }; + +signals: + void stateChanged(const QString &newState); + void instanceIdAlreadyInUse(); + void instancesChanged(QStringList &instances); + +public Q_SLOTS: + bool writeState(const QString &newState); + +private: + QJsonObject readJsonData(); + bool writeJsonData(const QJsonObject &obj); + QJsonObject initialJson(); + + QSharedMemory m_memory; + QTimer m_timer; + QString m_lastState; + QString m_instanceId; + bool m_registered; + bool m_emit_inUse; + QStringList m_instances; +}; diff --git a/src/ui/uidmmprefs.ui b/src/ui/uidmmprefs.ui index cf617c7..8115210 100644 --- a/src/ui/uidmmprefs.ui +++ b/src/ui/uidmmprefs.ui @@ -40,9 +40,18 @@ Here you may select your DMM model. If your DMM is not in the list, try to find working settings and mail them to me (<font color=blue><u>qtdmm@mtoussaint.de</u></font>). So I can add them to the list in the next release. + + true + + + QComboBox::NoInsert + + + QComboBox::AdjustToContents + diff --git a/src/ui/uiinstancesdlg.ui b/src/ui/uiinstancesdlg.ui new file mode 100644 index 0000000..cb8c6a8 --- /dev/null +++ b/src/ui/uiinstancesdlg.ui @@ -0,0 +1,147 @@ + + + UIInstancesDlg + + + + 0 + 0 + 390 + 397 + + + + Instance Manager + + + + + + 12 + + + 12 + + + + + Choose instance to open, or add/remove instances + + + + + + + + + false + + + QFrame::NoFrame + + + QFrame::Plain + + + 0 + + + + + + + + + add new instance + + + + + + + + :/Symbols/add.xpm:/Symbols/add.xpm + + + + + + + remove instances + + + - + + + + :/Symbols/remove.xpm:/Symbols/remove.xpm + + + true + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Close + + + + + + + + + + + + + ui_instances_buttonBox + accepted() + UIInstancesDlg + accept() + + + 248 + 254 + + + 157 + 268 + + + + + ui_instances_buttonBox + rejected() + UIInstancesDlg + reject() + + + 389 + 254 + + + 286 + 268 + + + + + diff --git a/src/ui/uimainwin.ui b/src/ui/uimainwin.ui index 149f25d..6a9892f 100644 --- a/src/ui/uimainwin.ui +++ b/src/ui/uimainwin.ui @@ -26,6 +26,9 @@ DMM + + + false @@ -41,6 +44,8 @@ false + + @@ -48,6 +53,9 @@ Recorder + + + false @@ -148,6 +156,9 @@ &Export + + Export graph + <html><head/><body><p><span style=" font-weight:600;">Export recorder graph</span></p><p>Here you can export the recorded data as tab separated list. Each line contains the following values (separated by a tab character): date (dd.mm.yyyy) time (hh:mm:ss) value (float) unit.</p></body></html> @@ -166,6 +177,9 @@ &Import + + Import graph + <html><head/><body><p><span style=" font-weight:600;">Import data into recorder</span></p><p>Here you can import previously exported data files. QtDMM tries to do an educated guess if the file format is correct and rejects import of files which to not match.</p></body></html> @@ -184,6 +198,9 @@ &Print + + Print graph + <html><head/><body><p><span style=" font-weight:600;">Print recorder graph</span></p><p>A dialog will open where you can define a title and a comment for your printout. The printer itself can also be configured here. To be able to print you need at least one working postscript printer configured in your system. Printing into a file is also supported.</p></body></html> @@ -241,6 +258,9 @@ &Connect + + Connect/Disconnect DMM + <html><head/><body><p><span style=" font-weight:600;">Connect to the Multimeter</span></p><p>This will establish the serial connection to the dmm. If not connected the serial port is free and can be used by other software.</p></body></html> @@ -259,6 +279,9 @@ &Reset + + reset min/max + <html><head/><body><p><span style=" font-weight:600;">Reset min/max values</span></p><p>The min/max values in the display will be reset. You can activate this option at any time. </p></body></html> @@ -294,6 +317,9 @@ &Start + + Start recording + <html><head/><body><p><span style=" font-weight:600;">Start the recorder</span></p><p>If you are in manual mode this will start the recorder. Press F2 to set the recorder options.</p></body></html> @@ -315,6 +341,9 @@ S&top + + Stop recording + <html><head/><body><p><span style=" font-weight:600;">Stop the recorder</span></p><p>The recorder will be stopped. This is independent from the start mode of the recorder. </p></body></html> @@ -333,6 +362,9 @@ &Clear + + Clear graph + <html><head/><body><p><span style=" font-weight:600;">Clear the recorder graph</span></p><p>If the recorder is already started it will clear the graph and continue recording.</p></body></html> @@ -412,7 +444,7 @@ - + :/Symbols/menu.xpm:/Symbols/menu.xpm @@ -422,7 +454,22 @@ Menu - Ctrl+M + Ctrl+M + + + + + + :/Symbols/instances.xpm:/Symbols/instances.xpm + + + Instances + + + Instance Manager + + + Ctrl+N diff --git a/tests/data/do3122.json_todo b/tests/data/do3122.json_todo deleted file mode 100644 index 9cacdcb..0000000 --- a/tests/data/do3122.json_todo +++ /dev/null @@ -1,17 +0,0 @@ -{ - "decoder": "DO3122Continuous", - "tests": [ - { - "hex": "AA 55 52 24 00 xx ", - "expected": { - "dval": 0.0, - "val": "0.0000", - "unit": "V", - "range": "AUTO", - "special": "DC", - "hold": false, - "showBar": true - } - } - ] -} diff --git a/tests/data/dtm0660.json_todo b/tests/data/dtm0660.json_todo deleted file mode 100644 index 1d5ed5a..0000000 --- a/tests/data/dtm0660.json_todo +++ /dev/null @@ -1,17 +0,0 @@ -{ - "decoder": "DTM0660", - "tests": [ - { - "hex": "17 27 3D 4F 5D 67 7D 87 9D A0 B0 C0 D4 E0", - "expected": { - "dval": 0.0, - "val": "0.0000", - "unit": "V", - "range": "AUTO", - "special": "DC", - "hold": false, - "showBar": true - } - } - ] -} diff --git a/tests/data/es51922.json b/tests/data/es51922.json deleted file mode 100644 index e1eeccb..0000000 --- a/tests/data/es51922.json +++ /dev/null @@ -1,101 +0,0 @@ -{ - "decoder": "CyrustekES51922", - "tests": [ - { - "hex": "30 30 30 30 30 30 3B 30 30 30 3A 30 0D 0A", - "expected": { - "dval": 0.0, - "val": "0.0000", - "unit": "V", - "range": "AUTO", - "special": "DC", - "hold": false, - "showBar": true - } - }, - { - "hex": "30 30 30 30 30 30 3B 30 30 30 38 30 0D 0A", - "expected": { - "dval": 0.0, - "val": "0.0000", - "unit": "V", - "range": "MANU", - "special": "DC", - "hold": false, - "showBar": true - } - }, - { - "hex": "30 30 30 30 30 30 3B 32 30 30 3A 30 0D 0A", - "expected": { - "dval": 0.0, - "val": "0.0000", - "unit": "V", - "range": "AUTO", - "special": "DC", - "hold": false, - "showBar": true - } - }, - { - "hex": "30 30 30 30 30 30 3D 30 30 30 3A 30 0D 0A", - "expected": { - "dval": 0.0, - "val": "000.00", - "unit": "uA", - "range": "AUTO", - "special": "DC", - "hold": false, - "showBar": true - } - }, - { - "hex": "30 30 30 30 30 30 30 30 30 30 34 32 0D 0A", - "expected": { - "dval": 0.0, - "val": "00.000", - "unit": "A", - "range": "MANU", - "special": "AC", - "hold": true, - "showBar": true - } - }, - { - "hex": "30 30 30 30 30 30 3B 30 30 30 3B 30 0D 0A", - "expected": { - "dval": 0.0, - "val": "0.0000", - "unit": "Hz", - "range": "AUTO", - "special": "DC", - "hold": false, - "showBar": true - } - }, - { - "hex": "30 30 30 30 30 37 3F 30 30 30 36 30 0D 0A", - "expected": { - "dval": 0.000007, - "val": "00.007", - "unit": "mA", - "range": "AUTO", - "special": "AC", - "hold": false, - "showBar": true - } - }, - { - "hex": "34 30 31 33 34 34 3B 34 30 30 38 30 0D 0A", - "expected": { - "dval": -0.01344, - "val": "-013.44", - "unit": "mV", - "range": "MANU", - "special": "DC", - "hold": false, - "showBar": true - } - } - ] -} diff --git a/tests/data/es51962.json b/tests/data/es51962.json deleted file mode 100644 index f74eba5..0000000 --- a/tests/data/es51962.json +++ /dev/null @@ -1,41 +0,0 @@ -{ - "decoder": "CyrustekES51962", - "tests": [ - { - "hex": "30 30 30 35 38 3B 30 30 3A 0D 0A", - "expected": { - "dval": 0.0058, - "val": "005.8", - "unit": "mV", - "range": "AUTO", - "special": "DC", - "hold": false, - "showBar": true - } - }, - { - "hex": "30 30 30 32 31 3B 34 30 38 0D 0A", - "expected": { - "dval": -0.0021, - "val": "-002.1", - "unit": "mV", - "range": "MANU", - "special": "DC", - "hold": false, - "showBar": true - } - }, - { - "hex": "30 30 31 34 30 33 30 30 30 0D 0A", - "expected": { - "dval": 14.0, - "val": "014.0", - "unit": "Ohm", - "range": "MANU", - "special": "", - "hold": false, - "showBar": true - } - } - ] -} diff --git a/tests/data/es51986.json b/tests/data/es51986.json deleted file mode 100644 index 3c82703..0000000 --- a/tests/data/es51986.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "decoder": "CyrustekES51986", - "tests": [ - { - "hex": "30 30 30 30 30 3B 38 30 3A 0D 0A", - "expected": { - "dval": 0.0, - "val": "0.000", - "unit": "V", - "range": "AUTO", - "special": "DC", - "hold": false, - "showBar": true - } - }, - { - "hex": "30 30 30 30 30 3B 3C 30 38 0D 0A", - "expected": { - "dval": 0.0, - "val": "-0.000", - "unit": "V", - "range": "MANU", - "special": "DC", - "hold": false, - "showBar": true - } - } - ] -} diff --git a/tests/data/graph/legacy.txt b/tests/data/graph/legacy.txt new file mode 100644 index 0000000..350a0be --- /dev/null +++ b/tests/data/graph/legacy.txt @@ -0,0 +1,42 @@ +09.07.2025 13:16:38 0.001200 V +09.07.2025 13:16:39 -0.000080 V +09.07.2025 13:16:40 -0.003340 V +09.07.2025 13:16:41 -0.001470 V +09.07.2025 13:16:42 -0.002050 V +09.07.2025 13:16:43 -0.001940 V +09.07.2025 13:16:44 -0.005850 V +09.07.2025 13:16:45 -0.371410 V +09.07.2025 13:16:46 -1.049560 V +09.07.2025 13:16:47 -1.314830 V +09.07.2025 13:16:48 -1.314900 V +09.07.2025 13:16:49 -1.314900 V +09.07.2025 13:16:50 -1.314900 V +09.07.2025 13:16:51 -1.314930 V +09.07.2025 13:16:52 -1.062350 V +09.07.2025 13:16:53 -0.792770 V +09.07.2025 13:16:54 -1.079020 V +09.07.2025 13:16:55 -0.987650 V +09.07.2025 13:16:56 -0.044250 V +09.07.2025 13:16:57 0.002180 V +09.07.2025 13:16:58 -0.002060 V +09.07.2025 13:16:59 -0.000850 V +09.07.2025 13:17:00 -0.000080 V +09.07.2025 13:17:01 0.411220 V +09.07.2025 13:17:02 1.315010 V +09.07.2025 13:17:03 1.315130 V +09.07.2025 13:17:04 1.315170 V +09.07.2025 13:17:05 1.315130 V +09.07.2025 13:17:06 1.315170 V +09.07.2025 13:17:07 1.315100 V +09.07.2025 13:17:08 0.920540 V +09.07.2025 13:17:09 -0.000190 V +09.07.2025 13:17:10 -0.000640 V +09.07.2025 13:17:11 -0.000380 V +09.07.2025 13:17:12 -0.020760 V +09.07.2025 13:17:13 -1.055930 V +09.07.2025 13:17:14 -0.911510 V +09.07.2025 13:17:15 0.005540 V +09.07.2025 13:17:16 0.000000 V +09.07.2025 13:17:17 0.000000 V +09.07.2025 13:17:18 -0.000030 V +09.07.2025 13:17:19 -0.000160 V diff --git a/tests/data/graph/legacy_nan.txt b/tests/data/graph/legacy_nan.txt new file mode 100644 index 0000000..23995b6 --- /dev/null +++ b/tests/data/graph/legacy_nan.txt @@ -0,0 +1,47 @@ +15.07.2025 10:14:53:775 nan Ohm +15.07.2025 10:14:54:275 nan Ohm +15.07.2025 10:14:54:775 nan Ohm +15.07.2025 10:14:55:275 nan Ohm +15.07.2025 10:14:55:775 nan Ohm +15.07.2025 10:14:56:275 nan Ohm +15.07.2025 10:14:56:775 0.011452 Ohm +15.07.2025 10:14:57:275 0.037174 Ohm +15.07.2025 10:14:57:775 0.075652 Ohm +15.07.2025 10:14:58:275 0.032896 Ohm +15.07.2025 10:14:58:775 -0.004520 Ohm +15.07.2025 10:14:59:275 0.044218 Ohm +15.07.2025 10:14:59:775 -0.030110 Ohm +15.07.2025 10:15:00:275 -0.064386 Ohm +15.07.2025 10:15:00:775 -0.007114 Ohm +15.07.2025 10:15:01:275 -0.020008 Ohm +15.07.2025 10:15:01:775 -0.022212 Ohm +15.07.2025 10:15:02:275 -0.022284 Ohm +15.07.2025 10:15:02:775 -0.021094 Ohm +15.07.2025 10:15:03:275 -0.019696 Ohm +15.07.2025 10:15:03:775 -0.020166 Ohm +15.07.2025 10:15:04:275 -0.020674 Ohm +15.07.2025 10:15:04:775 nan Ohm +15.07.2025 10:15:05:275 nan Ohm +15.07.2025 10:15:05:775 nan Ohm +15.07.2025 10:15:06:275 nan Ohm +15.07.2025 10:15:06:775 nan Ohm +15.07.2025 10:15:07:275 nan Ohm +15.07.2025 10:15:07:775 nan Ohm +15.07.2025 10:15:08:275 nan Ohm +15.07.2025 10:15:08:775 nan Ohm +15.07.2025 10:15:09:275 nan Ohm +15.07.2025 10:15:09:775 nan Ohm +15.07.2025 10:15:10:275 2117800.000000 Ohm +15.07.2025 10:15:10:775 2543000.000000 Ohm +15.07.2025 10:15:11:275 2460800.000000 Ohm +15.07.2025 10:15:11:775 2610000.000000 Ohm +15.07.2025 10:15:12:275 2716800.000000 Ohm +15.07.2025 10:15:12:775 2777600.000000 Ohm +15.07.2025 10:15:13:275 2730800.000000 Ohm +15.07.2025 10:15:13:775 2675000.000000 Ohm +15.07.2025 10:15:14:275 2811200.000000 Ohm +15.07.2025 10:15:14:775 2890800.000000 Ohm +15.07.2025 10:15:15:275 2966800.000000 Ohm +15.07.2025 10:15:15:775 5567600.000000 Ohm +15.07.2025 10:15:16:275 31088200.000000 Ohm +15.07.2025 10:15:16:775 63226000.000000 Ohm diff --git a/tests/data/graph/new_dpoint.csv b/tests/data/graph/new_dpoint.csv new file mode 100644 index 0000000..84480a6 --- /dev/null +++ b/tests/data/graph/new_dpoint.csv @@ -0,0 +1,43 @@ +12.07.2025 23:38:02:997 0.007020 V +12.07.2025 23:38:03:497 0.002960 V +12.07.2025 23:38:03:997 0.003720 V +12.07.2025 23:38:04:497 0.015560 V +12.07.2025 23:38:04:997 -0.005920 V +12.07.2025 23:38:05:497 -0.008000 V +12.07.2025 23:38:05:997 0.003000 V +12.07.2025 23:38:06:497 0.008060 V +12.07.2025 23:38:06:997 0.003660 V +12.07.2025 23:38:07:497 0.004400 V +12.07.2025 23:38:07:997 -0.003740 V +12.07.2025 23:38:08:497 0.006900 V +12.07.2025 23:38:08:997 0.004340 V +12.07.2025 23:38:09:497 0.010820 V +12.07.2025 23:38:09:997 0.012800 V +12.07.2025 23:38:10:497 0.001280 V +12.07.2025 23:38:10:997 0.002960 V +12.07.2025 23:38:11:497 0.027380 V +12.07.2025 23:38:11:997 0.034560 V +12.07.2025 23:38:12:497 0.027940 V +12.07.2025 23:38:12:997 0.026200 V +12.07.2025 23:38:13:497 0.027480 V +12.07.2025 23:38:13:997 0.019960 V +12.07.2025 23:38:14:497 0.010080 V +12.07.2025 23:38:14:997 0.015940 V +12.07.2025 23:38:15:497 0.027260 V +12.07.2025 23:38:15:997 0.031040 V +12.07.2025 23:38:16:497 0.032680 V +12.07.2025 23:38:16:997 0.032040 V +12.07.2025 23:38:17:497 0.008040 V +12.07.2025 23:38:17:997 -0.016300 V +12.07.2025 23:38:18:497 0.048620 V +12.07.2025 23:38:18:997 0.016080 V +12.07.2025 23:38:19:497 -0.000800 V +12.07.2025 23:38:19:997 0.040260 V +12.07.2025 23:38:20:497 0.005200 V +12.07.2025 23:38:20:997 -0.002120 V +12.07.2025 23:38:21:497 0.009780 V +12.07.2025 23:38:21:997 0.001220 V +12.07.2025 23:38:22:497 -0.001840 V +12.07.2025 23:38:22:997 -0.002940 V +12.07.2025 23:38:23:497 0.002880 V +12.07.2025 23:38:23:997 0.000880 V diff --git a/tests/data/graph/new_komma_ms.csv b/tests/data/graph/new_komma_ms.csv new file mode 100644 index 0000000..f13176d --- /dev/null +++ b/tests/data/graph/new_komma_ms.csv @@ -0,0 +1,28 @@ +timestamp;time (ms);value;unit +2025-08-11T05:41:54,551;0;0.000000;V +2025-08-11T05:41:54,751;0.2;0.000000;V +2025-08-11T05:41:54,951;0.4;0.000000;V +2025-08-11T05:41:55,151;0.6;0.000000;V +2025-08-11T05:41:55,351;0.8;0.000000;V +2025-08-11T05:41:55,551;1;0.000000;V +2025-08-11T05:41:55,751;1.2;0.000000;V +2025-08-11T05:41:55,951;1.4;-0.003600;V +2025-08-11T05:41:56,151;1.6;-0.003600;V +2025-08-11T05:41:56,351;1.8;-0.001900;V +2025-08-11T05:41:56,551;2;-0.000200;V +2025-08-11T05:41:56,751;2.2;-0.000200;V +2025-08-11T05:41:56,951;2.4;-0.000400;V +2025-08-11T05:41:57,151;2.6;-0.000400;V +2025-08-11T05:41:57,351;2.8;-0.000400;V +2025-08-11T05:41:57,551;3;-0.000400;V +2025-08-11T05:41:57,751;3.2;-0.000400;V +2025-08-11T05:41:57,951;3.4;0.000000;V +2025-08-11T05:41:58,151;3.6;0.000000;V +2025-08-11T05:41:58,351;3.8;0.000000;V +2025-08-11T05:41:58,551;4;0.000000;V +2025-08-11T05:41:58,751;4.2;0.000000;V +2025-08-11T05:41:58,951;4.4;0.000000;V +2025-08-11T05:41:59,151;4.6;0.000000;V +2025-08-11T05:41:59,351;4.8;0.000000;V +2025-08-11T05:41:59,551;5;0.000000;V +2025-08-11T05:41:59,751;5.2;0.000000;V diff --git a/tests/data/graph/new_larger.csv b/tests/data/graph/new_larger.csv new file mode 100644 index 0000000..9907ae2 --- /dev/null +++ b/tests/data/graph/new_larger.csv @@ -0,0 +1,272 @@ +timestamp;time (s);value;unit +2025-08-11T10:25:22,289;0;0.032700;V +2025-08-11T10:25:22,489;0.2;0.036000;V +2025-08-11T10:25:22,689;0.4;0.036000;V +2025-08-11T10:25:22,889;0.6;0.032400;V +2025-08-11T10:25:23,089;0.8;0.028800;V +2025-08-11T10:25:23,289;1;0.028800;V +2025-08-11T10:25:23,489;1.2;0.024700;V +2025-08-11T10:25:23,689;1.4;0.024700;V +2025-08-11T10:25:23,889;1.6;0.027950;V +2025-08-11T10:25:24,089;1.8;0.031200;V +2025-08-11T10:25:24,289;2;0.031200;V +2025-08-11T10:25:24,489;2.2;0.032100;V +2025-08-11T10:25:24,689;2.4;0.032100;V +2025-08-11T10:25:24,889;2.6;0.034250;V +2025-08-11T10:25:25,089;2.8;0.036400;V +2025-08-11T10:25:25,289;3;0.036400;V +2025-08-11T10:25:25,489;3.2;0.033600;V +2025-08-11T10:25:25,689;3.4;0.033600;V +2025-08-11T10:25:25,889;3.6;0.045300;V +2025-08-11T10:25:26,089;3.8;0.057000;V +2025-08-11T10:25:26,289;4;0.057000;V +2025-08-11T10:25:26,489;4.2;0.053900;V +2025-08-11T10:25:26,689;4.4;0.053900;V +2025-08-11T10:25:26,889;4.6;0.049350;V +2025-08-11T10:25:27,089;4.8;0.044800;V +2025-08-11T10:25:27,289;5;0.044800;V +2025-08-11T10:25:27,489;5.2;0.043000;V +2025-08-11T10:25:27,689;5.4;0.043000;V +2025-08-11T10:25:27,889;5.6;0.038850;V +2025-08-11T10:25:28,089;5.8;0.034700;V +2025-08-11T10:25:28,289;6;0.034700;V +2025-08-11T10:25:28,489;6.2;0.029500;V +2025-08-11T10:25:28,689;6.4;0.029500;V +2025-08-11T10:25:28,889;6.6;0.026150;V +2025-08-11T10:25:29,089;6.8;0.022800;V +2025-08-11T10:25:29,289;7;0.022800;V +2025-08-11T10:25:29,489;7.2;0.025200;V +2025-08-11T10:25:29,689;7.4;0.025200;V +2025-08-11T10:25:29,889;7.6;0.024200;V +2025-08-11T10:25:30,089;7.8;0.023200;V +2025-08-11T10:25:30,289;8;0.023200;V +2025-08-11T10:25:30,489;8.2;0.035500;V +2025-08-11T10:25:30,689;8.4;0.035500;V +2025-08-11T10:25:30,889;8.6;0.036850;V +2025-08-11T10:25:31,089;8.8;0.038200;V +2025-08-11T10:25:31,289;9;0.038200;V +2025-08-11T10:25:31,489;9.2;0.036000;V +2025-08-11T10:25:31,689;9.4;0.036000;V +2025-08-11T10:25:31,889;9.6;0.036000;V +2025-08-11T10:25:32,089;9.8;0.036000;V +2025-08-11T10:25:32,289;10;0.036000;V +2025-08-11T10:25:32,489;10.2;0.032800;V +2025-08-11T10:25:32,689;10.4;0.032800;V +2025-08-11T10:25:32,889;10.6;0.034050;V +2025-08-11T10:25:33,089;10.8;0.035300;V +2025-08-11T10:25:33,289;11;0.035300;V +2025-08-11T10:25:33,489;11.2;0.033100;V +2025-08-11T10:25:33,689;11.4;0.033100;V +2025-08-11T10:25:33,889;11.6;0.030500;V +2025-08-11T10:25:34,089;11.8;0.027900;V +2025-08-11T10:25:34,289;12;0.027900;V +2025-08-11T10:25:34,489;12.2;0.053300;V +2025-08-11T10:25:34,689;12.4;0.053300;V +2025-08-11T10:25:34,889;12.6;0.041200;V +2025-08-11T10:25:35,089;12.8;0.029100;V +2025-08-11T10:25:35,289;13;0.029100;V +2025-08-11T10:25:35,489;13.2;0.023000;V +2025-08-11T10:25:35,689;13.4;0.023000;V +2025-08-11T10:25:35,889;13.6;0.020800;V +2025-08-11T10:25:36,089;13.8;0.018600;V +2025-08-11T10:25:36,289;14;0.018600;V +2025-08-11T10:25:36,489;14.2;0.007700;V +2025-08-11T10:25:36,689;14.4;0.007700;V +2025-08-11T10:25:36,889;14.6;0.006100;V +2025-08-11T10:25:37,089;14.8;0.004500;V +2025-08-11T10:25:37,289;15;0.004500;V +2025-08-11T10:25:37,489;15.2;0.080400;V +2025-08-11T10:25:37,689;15.4;0.080400;V +2025-08-11T10:25:37,889;15.6;0.118350;V +2025-08-11T10:25:38,089;15.8;0.156300;V +2025-08-11T10:25:38,289;16;0.156300;V +2025-08-11T10:25:38,489;16.2;-0.011100;V +2025-08-11T10:25:38,689;16.4;-0.011100;V +2025-08-11T10:25:38,889;16.6;0.001150;V +2025-08-11T10:25:39,089;16.8;0.013400;V +2025-08-11T10:25:39,289;17;0.013400;V +2025-08-11T10:25:39,489;17.2;-0.051650;V +2025-08-11T10:25:39,689;17.4;-0.116700;V +2025-08-11T10:25:39,889;17.6;-0.116700;V +2025-08-11T10:25:40,089;17.8;-0.004700;V +2025-08-11T10:25:40,289;18;-0.004700;V +2025-08-11T10:25:40,489;18.2;-0.022100;V +2025-08-11T10:25:40,689;18.4;-0.039500;V +2025-08-11T10:25:40,889;18.6;-0.039500;V +2025-08-11T10:25:41,089;18.8;0.017900;V +2025-08-11T10:25:41,289;19;0.017900;V +2025-08-11T10:25:41,489;19.2;0.008900;V +2025-08-11T10:25:41,689;19.4;-0.000100;V +2025-08-11T10:25:41,889;19.6;-0.000100;V +2025-08-11T10:25:42,089;19.8;-0.042000;V +2025-08-11T10:25:42,289;20;-0.042000;V +2025-08-11T10:25:42,489;20.2;-0.005550;V +2025-08-11T10:25:42,689;20.4;0.030900;V +2025-08-11T10:25:42,889;20.6;0.030900;V +2025-08-11T10:25:43,089;20.8;0.006100;V +2025-08-11T10:25:43,289;21;0.006100;V +2025-08-11T10:25:43,489;21.2;-0.006100;V +2025-08-11T10:25:43,689;21.4;-0.018300;V +2025-08-11T10:25:43,889;21.6;-0.018300;V +2025-08-11T10:25:44,089;21.8;0.000700;V +2025-08-11T10:25:44,289;22;0.000700;V +2025-08-11T10:25:44,489;22.2;0.009400;V +2025-08-11T10:25:44,689;22.4;0.018100;V +2025-08-11T10:25:44,889;22.6;0.018100;V +2025-08-11T10:25:45,089;22.8;0.032300;V +2025-08-11T10:25:45,289;23;0.032300;V +2025-08-11T10:25:45,489;23.2;0.032600;V +2025-08-11T10:25:45,689;23.4;0.032900;V +2025-08-11T10:25:45,889;23.6;0.032900;V +2025-08-11T10:25:46,089;23.8;0.029600;V +2025-08-11T10:25:46,289;24;0.029600;V +2025-08-11T10:25:46,489;24.2;0.006350;V +2025-08-11T10:25:46,689;24.4;-0.016900;V +2025-08-11T10:25:46,889;24.6;-0.016900;V +2025-08-11T10:25:47,089;24.8;-0.001000;V +2025-08-11T10:25:47,289;25;-0.001000;V +2025-08-11T10:25:47,489;25.2;0.004100;V +2025-08-11T10:25:47,689;25.4;0.009200;V +2025-08-11T10:25:47,889;25.6;0.009200;V +2025-08-11T10:25:48,089;25.8;0.008100;V +2025-08-11T10:25:48,289;26;0.008100;V +2025-08-11T10:25:48,489;26.2;0.002950;V +2025-08-11T10:25:48,689;26.4;-0.002200;V +2025-08-11T10:25:48,889;26.6;-0.002200;V +2025-08-11T10:25:49,089;26.8;0.015600;V +2025-08-11T10:25:49,289;27;0.015600;V +2025-08-11T10:25:49,489;27.2;0.007800;V +2025-08-11T10:25:49,689;27.4;0.000000;V +2025-08-11T10:25:49,889;27.6;0.000000;V +2025-08-11T10:25:50,089;27.8;0.014200;V +2025-08-11T10:25:50,289;28;0.014200;V +2025-08-11T10:25:50,489;28.2;0.040000;V +2025-08-11T10:25:50,689;28.4;0.065800;V +2025-08-11T10:25:50,889;28.6;0.065800;V +2025-08-11T10:25:51,089;28.8;0.015300;V +2025-08-11T10:25:51,289;29;0.015300;V +2025-08-11T10:25:51,489;29.2;0.018650;V +2025-08-11T10:25:51,689;29.4;0.022000;V +2025-08-11T10:25:51,889;29.6;0.022000;V +2025-08-11T10:25:52,089;29.8;0.007600;V +2025-08-11T10:25:52,289;30;0.007600;V +2025-08-11T10:25:52,489;30.2;0.000800;V +2025-08-11T10:25:52,689;30.4;-0.006000;V +2025-08-11T10:25:52,889;30.6;-0.006000;V +2025-08-11T10:25:53,089;30.8;0.002400;V +2025-08-11T10:25:53,289;31;0.002400;V +2025-08-11T10:25:53,489;31.2;0.002700;V +2025-08-11T10:25:53,689;31.4;0.003000;V +2025-08-11T10:25:53,889;31.6;0.003000;V +2025-08-11T10:25:54,089;31.8;0.549700;V +2025-08-11T10:25:54,289;32;0.549700;V +2025-08-11T10:25:54,489;32.2;0.292850;V +2025-08-11T10:25:54,689;32.4;0.036000;V +2025-08-11T10:25:54,889;32.6;0.036000;V +2025-08-11T10:25:55,089;32.8;0.000000;V +2025-08-11T10:25:55,289;33;0.000000;V +2025-08-11T10:25:55,489;33.2;-0.006500;V +2025-08-11T10:25:55,689;33.4;-0.013000;V +2025-08-11T10:25:55,889;33.6;-0.013000;V +2025-08-11T10:25:56,089;33.8;0.000000;V +2025-08-11T10:25:56,289;34;0.000000;V +2025-08-11T10:25:56,489;34.2;-0.003500;V +2025-08-11T10:25:56,689;34.4;-0.007000;V +2025-08-11T10:25:56,889;34.6;-0.007000;V +2025-08-11T10:25:57,089;34.8;-0.007000;V +2025-08-11T10:25:57,289;35;-0.007000;V +2025-08-11T10:25:57,489;35.2;-0.004000;V +2025-08-11T10:25:57,689;35.4;-0.001000;V +2025-08-11T10:25:57,889;35.6;-0.001000;V +2025-08-11T10:25:58,089;35.8;0.322000;V +2025-08-11T10:25:58,289;36;0.322000;V +2025-08-11T10:25:58,489;36.2;0.075000;V +2025-08-11T10:25:58,689;36.4;-0.172000;V +2025-08-11T10:25:58,889;36.6;-0.172000;V +2025-08-11T10:25:59,089;36.8;0.123000;V +2025-08-11T10:25:59,289;37;0.123000;V +2025-08-11T10:25:59,489;37.2;-0.551500;V +2025-08-11T10:25:59,689;37.4;-1.226000;V +2025-08-11T10:25:59,889;37.6;-1.226000;V +2025-08-11T10:26:00,089;37.8;-0.059000;V +2025-08-11T10:26:00,289;38;-0.059000;V +2025-08-11T10:26:00,489;38.2;0.345500;V +2025-08-11T10:26:00,689;38.4;0.750000;V +2025-08-11T10:26:00,889;38.6;0.750000;V +2025-08-11T10:26:01,089;38.8;1.205000;V +2025-08-11T10:26:01,289;39;1.205000;V +2025-08-11T10:26:01,489;39.2;1.241500;V +2025-08-11T10:26:01,689;39.4;1.278000;V +2025-08-11T10:26:01,889;39.6;1.278000;V +2025-08-11T10:26:02,089;39.8;0.704000;V +2025-08-11T10:26:02,289;40;0.704000;V +2025-08-11T10:26:02,489;40.2;0.718500;V +2025-08-11T10:26:02,689;40.4;0.733000;V +2025-08-11T10:26:02,889;40.6;0.733000;V +2025-08-11T10:26:03,089;40.8;0.153000;V +2025-08-11T10:26:03,289;41;0.153000;V +2025-08-11T10:26:03,489;41.2;0.198500;V +2025-08-11T10:26:03,689;41.4;0.244000;V +2025-08-11T10:26:03,889;41.6;0.244000;V +2025-08-11T10:26:04,089;41.8;-0.013000;V +2025-08-11T10:26:04,289;42;-0.013000;V +2025-08-11T10:26:04,489;42.2;-0.344500;V +2025-08-11T10:26:04,689;42.4;-0.676000;V +2025-08-11T10:26:04,889;42.6;-0.676000;V +2025-08-11T10:26:05,089;42.8;-0.820000;V +2025-08-11T10:26:05,289;43;-0.820000;V +2025-08-11T10:26:05,489;43.2;-0.059500;V +2025-08-11T10:26:05,689;43.4;0.701000;V +2025-08-11T10:26:05,889;43.6;0.701000;V +2025-08-11T10:26:06,089;43.8;1.168000;V +2025-08-11T10:26:06,289;44;1.168000;V +2025-08-11T10:26:06,489;44.2;0.625500;V +2025-08-11T10:26:06,689;44.4;0.083000;V +2025-08-11T10:26:06,889;44.6;0.083000;V +2025-08-11T10:26:07,089;44.8;-0.237000;V +2025-08-11T10:26:07,289;45;-0.237000;V +2025-08-11T10:26:07,489;45.2;-0.232000;V +2025-08-11T10:26:07,689;45.4;-0.227000;V +2025-08-11T10:26:07,889;45.6;-0.227000;V +2025-08-11T10:26:08,089;45.8;0.432000;V +2025-08-11T10:26:08,289;46;0.432000;V +2025-08-11T10:26:08,489;46.2;0.348500;V +2025-08-11T10:26:08,689;46.4;0.265000;V +2025-08-11T10:26:08,889;46.6;0.265000;V +2025-08-11T10:26:09,089;46.8;-0.043000;V +2025-08-11T10:26:09,289;47;-0.043000;V +2025-08-11T10:26:09,489;47.2;-0.021500;V +2025-08-11T10:26:09,689;47.4;0.000000;V +2025-08-11T10:26:09,889;47.6;0.000000;V +2025-08-11T10:26:10,089;47.8;1.144200;V +2025-08-11T10:26:10,289;48;1.144200;V +2025-08-11T10:26:10,489;48.2;0.712500;V +2025-08-11T10:26:10,689;48.4;0.280800;V +2025-08-11T10:26:10,889;48.6;0.280800;V +2025-08-11T10:26:11,089;48.8;0.835900;V +2025-08-11T10:26:11,289;49;0.835900;V +2025-08-11T10:26:11,489;49.2;0.046150;V +2025-08-11T10:26:11,689;49.4;-0.743600;V +2025-08-11T10:26:11,889;49.6;-0.743600;V +2025-08-11T10:26:12,089;49.8;0.002900;V +2025-08-11T10:26:12,289;50;0.002900;V +2025-08-11T10:26:12,489;50.2;0.003250;V +2025-08-11T10:26:12,689;50.4;0.003600;V +2025-08-11T10:26:12,889;50.6;0.003600;V +2025-08-11T10:26:13,089;50.8;-0.049300;V +2025-08-11T10:26:13,289;51;-0.049300;V +2025-08-11T10:26:13,489;51.2;-0.024250;V +2025-08-11T10:26:13,689;51.4;0.000800;V +2025-08-11T10:26:13,889;51.6;0.000800;V +2025-08-11T10:26:14,089;51.8;-0.009800;V +2025-08-11T10:26:14,289;52;-0.009800;V +2025-08-11T10:26:14,489;52.2;-0.016300;V +2025-08-11T10:26:14,689;52.4;-0.022800;V +2025-08-11T10:26:14,889;52.6;-0.022800;V +2025-08-11T10:26:15,089;52.8;-0.003100;V +2025-08-11T10:26:15,289;53;-0.003100;V +2025-08-11T10:26:15,489;53.2;-0.006600;V +2025-08-11T10:26:15,689;53.4;-0.010100;V +2025-08-11T10:26:15,889;53.6;-0.010100;V +2025-08-11T10:26:16,089;53.8;0.001600;V +2025-08-11T10:26:16,289;54;0.001600;V diff --git a/tests/data/m9803r.json b/tests/data/m9803r.json deleted file mode 100644 index cbec126..0000000 --- a/tests/data/m9803r.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "decoder": "M9803RContinuous", - "tests": [ - { - "hex": "00 04 03 02 01 00 00 00 04 00 0D 0A", - "expected": { - "dval": 123.4, - "val": "123.4", - "unit": "mV", - "range": "AUTO", - "special": "DC", - "hold": false, - "showBar": true - } - } - ] -} diff --git a/tests/data/qm1537.json b/tests/data/qm1537.json deleted file mode 100644 index a0cda73..0000000 --- a/tests/data/qm1537.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "decoder": "QM1537Continuous", - "tests": [ - { - "hex": "2B 33 34 38 32 20 34 31 00 40 80 22 0D 0A", - "expected": { - "dval": 348.2, - "val": "348.2", - "unit": "mV", - "range": "AUTO", - "special": "DC", - "hold": false, - "showBar": true - } - } - ] -} diff --git a/tests/data/rs22812.json b/tests/data/rs22812.json deleted file mode 100644 index 55701b0..0000000 --- a/tests/data/rs22812.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "decoder": "RS22812Continuous", - "tests": [ - { - "hex": "00 03 00 D7 D7 DF 50 0B 24", - "expected": { - "dval": -0.001, - "val": " -1.000", - "unit": "mV", - "range": "AUTO", - "special": "DC", - "hold": false, - "showBar": true - } - } - ] -} diff --git a/tests/data/vc820.json b/tests/data/vc820.json deleted file mode 100644 index 7d72a17..0000000 --- a/tests/data/vc820.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "decoder": "VC820Continuous", - "tests": [ - { - "hex": "17 2F 3D 47 5D 67 7D 8A 97 A0 B8 C0 D4 E8", - "expected": { - "dval": -0.4, - "val": " -000.4", - "unit": "mV", - "range": "AUTO", - "special": "DC", - "hold": false, - "showBar": true - } - }, - { - "hex": "15 25 3B 40 55 67 7D 8F 9E A0 B0 C0 D1 E1", - "expected": { - "dval": 210.6, - "val": " 210.6", - "unit": "C", - "range": "MANU", - "special": "TE", - "hold": false, - "showBar": true - } - } - ] -} diff --git a/tests/data/vc870.json b/tests/data/vc870.json deleted file mode 100644 index 6bb6fc9..0000000 --- a/tests/data/vc870.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "decoder": "VC870Continuous", - "tests": [ - { - "hex": "30 30 30 34 30 30 30 30 34 30 30 30 30 00 00 30 30 30 30 30 31 0D 0A", - "expected": { - "dval": 4.0, - "val": " 4.0000", - "unit": "V", - "special": "DC", - "dval2": 4.0, - "val2": " 4.0000", - "unit2": "V", - "hold": false, - "showBar": true - } - } - ] -} diff --git a/tests/data/vc940.json b/tests/data/vc940.json deleted file mode 100644 index e4c9372..0000000 --- a/tests/data/vc940.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "decoder": "VC940Continuous", - "tests": [ - { - "hex": "30 30 30 30 30 31 31 30 31 0D 0A", - "expected": { - "dval": 0.0, - "val": "0.0000", - "unit": "V", - "range": "AUTO", - "special": "DC", - "hold": false, - "showBar": true - } - } - ] -}