-
Notifications
You must be signed in to change notification settings - Fork 1
/
gdev_gmc.py
4851 lines (3845 loc) · 215 KB
/
gdev_gmc.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
#! /usr/bin/env python3
# -*- coding: UTF-8 -*-
"""
gdev_gmc.py - GeigerLog commands to handle the Geiger counter
include in programs with:
import gdev_gmc
"""
###############################################################################
# This file is part of GeigerLog.
#
# GeigerLog is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# GeigerLog is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with GeigerLog. If not, see <http://www.gnu.org/licenses/>.
###############################################################################
__author__ = "ullix"
__copyright__ = "Copyright 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023, 2024"
__credits__ = ["Phil Gillaspy", "GQ"]
__license__ = "GPL3"
# credits:
# device command coding taken from:
# - Phil Gillaspy, https://sourceforge.net/projects/gqgmc/
# - and GQ documents
# 'GQ-RFC1201 GMC Communication Protocol. Re. 1.30'
# - 'GQ-RFC1201,GQ Ver 1.40 Jan-2015' http://www.gqelectronicsllc.com/downloads/download.asp?DownloadID=62
# - 'GQ-RFC1801 GMC Communication Protocol' http://www.gqelectronicsllc.com/downloads/download.asp?DownloadID=91
# - GQ's disclosure at: http://www.gqelectronicsllc.com/forum/topic.asp?TOPIC_ID=4948
# GMC memory configs:
# For listing of GMC memory configs see file: 'GMC_memory_config, 2018-2024-v4.ods'
# in folder: /home/ullix/geigerlog/evaluation/Geiger Counter - GMC-All Config memory
from gsup_utils import *
# Data only in the 1st 256 byte config (all counters)
cfgKeyLoDefault = {
#
# key Value, Index width
"Power" : [ None, [0, 1] ], # Power state (read only, not settable!)
"Alarm" : [ None, [1, 1] ], # Alarm state
"Speaker" : [ None, [2, 1] ], # Speaker state
"BackLightTOSec" : [ None, [4, 1] ], # see Light States (OFF ... 30, 6 states)
"AlarmCPMValue" : [ None, [6, 2] ], # AlarmlevelCPM (Hi, Lo Byte)
"CalibCPM_0" : [ None, [8, 2] ], # calibration_0 CPM Hi+Lo Byte
"CalibuSv_0" : [ None, [10, 4] ], # calibration_0 uSv 4 Byte
"CalibCPM_1" : [ None, [14, 2] ], # calibration_1 CPM Hi+Lo Byte
"CalibuSv_1" : [ None, [16, 4] ], # calibration_1 uSv 4 Byte
"CalibCPM_2" : [ None, [20, 2] ], # calibration_2 CPM Hi+Lo Byte
"CalibuSv_2" : [ None, [22, 4] ], # calibration_2 uSv 4 Byte
"AlarmValueuSv" : [ None, [27, 4] ], # Alarm Value in units of uSv/h, 4 bytes
"AlarmType" : [ None, [31, 1] ], # Alarmtype: CPM (=0) or µSv/h (=1)
"SaveDataType" : [ None, [32, 1] ], # History Save Data Type, see savedatatypes
"MaxCPM" : [ None, [49, 2] ], # MaxCPM Hi + Lo Byte
"LCDBackLightLevel" : [ None, [53, 1] ], # Backlightlevel; seems to go from 0 ... 20
"Battery" : [ None, [56, 1] ], # Battery Type: 1 is non rechargeable. 0 is chargeable.
"Baudrate" : [ None, [57, 1] ], # Baudrate, coded differently for 300 and 500/600 series
"ThresholdCPM" : [ None, [62, 2] ], # yes, at 62! Threshold in CPM (2 bytes)
"ThresholdMode" : [ None, [64, 1] ], # yes, at 64! Mode: 0:CPM, 1:µSv/h, 2:mR/h (1 byte)
"ThresholduSv" : [ None, [65, 4] ], # yes, at 65! Threshold in µSv (4 bytes)
}
cfgKeyLo = cfgKeyLoDefault.copy() # shallow copy
# Data all 512 bytes of config (even allowing counters having only 256 bytes)
# cfgKeyHiDefault = {
# # cfgHiIndex: 0 1 2 3 4 5 6 7
# # GLcfg counter GMC-300(E) GMC-320+V5 GMC-500 GMC500+ GMC-300S GMC-800
# # only only GMC-600 2.24 no WiFi no WiFi,
# # but FET FET,Cal6
# "SSID" : [ None, None, (253, 0), (69, 16), (69, 32), (69, 64), (253, 0), (508, 0) ], # user specific value
# "Password" : [ None, None, (253, 0), (85, 16), (101, 32), (133, 64), (253, 0), (508, 0) ], # user specific value
# "Website" : [ None, None, (253, 0), (101, 25), (133, 32), (197, 32), (253, 0), (508, 0) ], # default: www.gmcmap.com
# "URL" : [ None, None, (253, 0), (126, 12), (165, 32), (229, 32), (253, 0), (508, 0) ], # default: log2.asp
# "UserID" : [ None, None, (253, 0), (138, 12), (197, 32), (261, 32), (253, 0), (508, 0) ], # user specific value
# "CounterID" : [ None, None, (253, 0), (150, 12), (229, 32), (293, 32), (253, 0), (508, 0) ], # user specific value
# "Period" : [ None, 1, (253, 0), (162, 1), (261, 1), (325, 1), (251, 1), (508, 0) ], # value can be 1 ... 255
# "WiFi" : [ None, False, (253, 0), (163, 1), (262, 1), (326, 1), (253, 1), (508, 0) ], # WiFi On=1 Off=0
# "FET" : [ None, 60, (253, 0), (253, 0), (508, 1), (328, 1), ( 69, 1), ( 69, 1) ], # FET
# "RTC_OFFSET" : [ None, 0, (253, 0), (253, 0), (508, 1), (328, 1), (253, 0), (508, 0) ], # RTC_OFFSET -59 sec ... +59sec
# "DEADTIME_ENABLE" : [ None, False, (253, 0), (253, 0), (508, 1), (335, 1), (253, 1), (508, 0) ], # enable dead time setting (fw 2.41+)
# "DEADTIME_TUBE1" : [ None, 0, (253, 0), (253, 2), (508, 2), (336, 2), (253, 2), (508, 0) ], # DEADTIME_TUBE1_HIBYTE, LOBYTE
# "DEADTIME_TUBE2" : [ None, 0, (253, 0), (253, 2), (508, 2), (338, 2), (253, 2), (508, 0) ], # DEADTIME_TUBE2_HIBYTE, LOBYTE
# "TARGET_HV" : [ None, None, (253, 0), (253, 2), (508, 2), (346, 2), (253, 2), (508, 0) ], # Voltage read out
# "HV_CALIB" : [ None, None, (253, 0), (253, 0), (508, 1), (348, 1), (253, 1), (508, 0) ], # HV_CALIB (?)
# "DATETIME" : [ None, None, ( 62, 6), (253, 0), (379, 6), (379, 6), ( 70, 6), (508, 0) ], # DateTime (for what?) YY,MM,DD,hh,mm,ss
# "Cal6CPM_0" : [ None, None, (253, 0), (253, 0), (508, 0), (508, 0), (251, 4), (73, 4) ], # Calibration CPM for 6 point calib
# "Cal6CPM_1" : [ None, None, (253, 0), (253, 0), (508, 0), (508, 0), (251, 4), (77, 4) ], # Calibration CPM for 6 point calib
# "Cal6CPM_2" : [ None, None, (253, 0), (253, 0), (508, 0), (508, 0), (251, 4), (81, 4) ], # Calibration CPM for 6 point calib
# "Cal6CPM_3" : [ None, None, (253, 0), (253, 0), (508, 0), (508, 0), (251, 4), (85, 4) ], # Calibration CPM for 6 point calib
# "Cal6CPM_4" : [ None, None, (253, 0), (253, 0), (508, 0), (508, 0), (251, 4), (89, 4) ], # Calibration CPM for 6 point calib
# "Cal6CPM_5" : [ None, None, (253, 0), (253, 0), (508, 0), (508, 0), (251, 4), (93, 4) ], # Calibration CPM for 6 point calib
# "Cal6uSv_0" : [ None, None, (253, 0), (253, 0), (508, 0), (508, 0), (251, 4), (97, 4) ], # Calibration uSv for 6 point calib
# "Cal6uSv_1" : [ None, None, (253, 0), (253, 0), (508, 0), (508, 0), (251, 4), (101, 4) ], # Calibration uSv for 6 point calib
# "Cal6uSv_2" : [ None, None, (253, 0), (253, 0), (508, 0), (508, 0), (251, 4), (105, 4) ], # Calibration uSv for 6 point calib
# "Cal6uSv_3" : [ None, None, (253, 0), (253, 0), (508, 0), (508, 0), (251, 4), (109, 4) ], # Calibration uSv for 6 point calib
# "Cal6uSv_4" : [ None, None, (253, 0), (253, 0), (508, 0), (508, 0), (251, 4), (113, 4) ], # Calibration uSv for 6 point calib
# "Cal6uSv_5" : [ None, None, (253, 0), (253, 0), (508, 0), (508, 0), (251, 4), (117, 4) ], # Calibration uSv for 6 point calib
# }
cfgKeyHiDefault = {
# cfgHiIndex: 0 1 2 3 4 5 6 7 8
# GLcfg counter GMC-300(E) GMC-320+V5 GMC-500 GMC500+ GMC-300S GMC-800 GMC-500
# only only GMC-600 2.24 no WiFi no WiFi, GMC-600,
# but FET FET,Cal6
"SSID" : [ None, None, (253, 0), (69, 16), (69, 32), (69, 64), (253, 0), (508, 0), (69, 64) ], # user specific value
"Password" : [ None, None, (253, 0), (85, 16), (101, 32), (133, 64), (253, 0), (508, 0), (133, 64) ], # user specific value
"Website" : [ None, None, (253, 0), (101, 25), (133, 32), (197, 32), (253, 0), (508, 0), (197, 32) ], # default: www.gmcmap.com
"URL" : [ None, None, (253, 0), (126, 12), (165, 32), (229, 32), (253, 0), (508, 0), (229, 32) ], # default: log2.asp
"UserID" : [ None, None, (253, 0), (138, 12), (197, 32), (261, 32), (253, 0), (508, 0), (261, 32) ], # user specific value
"CounterID" : [ None, None, (253, 0), (150, 12), (229, 32), (293, 32), (253, 0), (508, 0), (293, 32) ], # user specific value
"Period" : [ None, 1, (253, 0), (162, 1), (261, 1), (325, 1), (251, 1), (508, 0), (325, 1) ], # value can be 1 ... 255
"WiFi" : [ None, False, (253, 0), (163, 1), (262, 1), (326, 1), (253, 1), (508, 0), (326, 1) ], # WiFi On=1 Off=0
"FET" : [ None, 60, (253, 0), (253, 0), (508, 1), (328, 1), ( 69, 1), ( 69, 1), (328, 1) ], # FET
"RTC_OFFSET" : [ None, 0, (253, 0), (253, 0), (508, 1), (328, 1), (253, 0), (508, 0), (508, 0) ], # RTC_OFFSET -59 sec ... +59sec
"DEADTIME_ENABLE" : [ None, False, (253, 0), (253, 0), (508, 1), (335, 1), (253, 1), (508, 0), (508, 0) ], # enable dead time setting (fw 2.41+)
"DEADTIME_TUBE1" : [ None, 0, (253, 0), (253, 2), (508, 2), (336, 2), (253, 2), (508, 0), (508, 0) ], # DEADTIME_TUBE1_HIBYTE, LOBYTE
"DEADTIME_TUBE2" : [ None, 0, (253, 0), (253, 2), (508, 2), (338, 2), (253, 2), (508, 0), (508, 0) ], # DEADTIME_TUBE2_HIBYTE, LOBYTE
"TARGET_HV" : [ None, None, (253, 0), (253, 2), (508, 2), (346, 2), (253, 2), (508, 0), (346, 2) ], # Voltage read out
"HV_CALIB" : [ None, None, (253, 0), (253, 0), (508, 1), (348, 1), (253, 1), (508, 0), (348, 1) ], # HV_CALIB (?)
"DATETIME" : [ None, None, ( 62, 6), (253, 0), (379, 6), (379, 6), ( 70, 6), (508, 0), (508, 0) ], # DateTime (for what?) YY,MM,DD,hh,mm,ss
"Cal6CPM_0" : [ None, None, (253, 0), (253, 0), (508, 0), (508, 0), (251, 4), (73, 4), (379, 4) ], # Calibration CPM for 6 point calib
"Cal6CPM_1" : [ None, None, (253, 0), (253, 0), (508, 0), (508, 0), (251, 4), (77, 4), (383, 4) ], # Calibration CPM for 6 point calib
"Cal6CPM_2" : [ None, None, (253, 0), (253, 0), (508, 0), (508, 0), (251, 4), (81, 4), (387, 4) ], # Calibration CPM for 6 point calib
"Cal6CPM_3" : [ None, None, (253, 0), (253, 0), (508, 0), (508, 0), (251, 4), (85, 4), (391, 4) ], # Calibration CPM for 6 point calib
"Cal6CPM_4" : [ None, None, (253, 0), (253, 0), (508, 0), (508, 0), (251, 4), (89, 4), (395, 4) ], # Calibration CPM for 6 point calib
"Cal6CPM_5" : [ None, None, (253, 0), (253, 0), (508, 0), (508, 0), (251, 4), (93, 4), (399, 4) ], # Calibration CPM for 6 point calib
"Cal6uSv_0" : [ None, None, (253, 0), (253, 0), (508, 0), (508, 0), (251, 4), (97, 4), (403, 4) ], # Calibration uSv for 6 point calib
"Cal6uSv_1" : [ None, None, (253, 0), (253, 0), (508, 0), (508, 0), (251, 4), (101, 4), (407, 4) ], # Calibration uSv for 6 point calib
"Cal6uSv_2" : [ None, None, (253, 0), (253, 0), (508, 0), (508, 0), (251, 4), (105, 4), (411, 4) ], # Calibration uSv for 6 point calib
"Cal6uSv_3" : [ None, None, (253, 0), (253, 0), (508, 0), (508, 0), (251, 4), (109, 4), (415, 4) ], # Calibration uSv for 6 point calib
"Cal6uSv_4" : [ None, None, (253, 0), (253, 0), (508, 0), (508, 0), (251, 4), (113, 4), (419, 4) ], # Calibration uSv for 6 point calib
"Cal6uSv_5" : [ None, None, (253, 0), (253, 0), (508, 0), (508, 0), (251, 4), (117, 4), (423, 4) ], # Calibration uSv for 6 point calib
}
cfgKeyHi = cfgKeyHiDefault.copy() # shallow copy
# the History mode of saving
savedatatypes = (
"OFF (no history saving)",
"CPS, save every second",
"CPM, save every minute",
"CPM, save hourly average",
"CPS, save every second if exceeding threshold",
"CPM, save every minute if exceeding threshold",
)
# Light states
LightState = (
"Light: OFF",
"Light: ON",
"Timeout: 1",
"Timeout: 3",
"Timeout: 10",
"Timeout: 30",
)
# to keep track of illegal entries in cal* fields
validMatrix = {
"cal0cpm" : True ,
"cal0usv" : True ,
"cal1cpm" : True ,
"cal1usv" : True ,
"cal2cpm" : True ,
"cal2usv" : True ,
}
def initGMC():
"""
Sets configuration, gets counter version, verifies communication
Return: on success: ""
on failure: <errmessage>
"""
## local ###################################################################################
def getGMC_SerialPorts(device):
"""
gets all USB-to-Serial port names which MATCH USB's vid + pid associated with device.
"""
# output by: lsusb
# NOTE: all have idVendor 0x1a86 and idProduct 0x7523 !
# GMC-300E+:
# bcdUSB 1.10
# idVendor 0x1a86 QinHeng Electronics
# idProduct 0x7523 HL-340 USB-Serial adapter
# iProduct 2 USB Serial
#
# GMC-300S: (and also GMC-320S ?)
# bcdUSB 1.10
# idVendor 0x1a86 QinHeng Electronics
# idProduct 0x7523 CH340 serial converter
# iProduct 2 USB Serial
#
# GMC-500+:
# bcdUSB 1.10
# idVendor 0x1a86 QinHeng Electronics
# idProduct 0x7523 HL-340 USB-Serial adapter
# iProduct 2 USB2.0-Serial
defname = "getGMC_SerialPorts: "
dprint(defname, "for device: '{}'".format(device))
setIndent(1)
PortsFound = []
ports = getPortList(symlinks=False)
for port in ports:
dprint(defname, "port: ", port)
if g.GMC_simul:
# simulation
PortsFound.append(port.device)
else:
# use real data from USB port
if port.vid == 0x1a86 and port.pid == 0x7523:
tmplt_match = "Found Chip ID match for device '{}' at: Port:'{}' - vid:0x{:04x}, pid:0x{:04x}"
gdprint(defname, tmplt_match.format(device, port, port.vid, port.pid))
PortsFound.append(port.device)
else:
dprint(defname, "Chip ID does not match")
setIndent(0)
return PortsFound
def getGMC_SerialBaudrate(usbport):
"""
Uses the provided usbport and tries to find a proper baudrate by testing for successful
serial communication at up to all possible baudrates, beginning with the highest.
return: returnBR = None : serial error
returnBR = 0 : No device found
returnBR = <number> : highest baudrate which worked
"""
# NOTE: the device port can be opened without error at any baudrate permitted by the Python code,
# even when no communication can be done, e.g. due to wrong baudrate. Therefore we test for
# successful communication by checking for the return string for getVersion beginning with 'GMC'.
defname = "getGMC_SerialBaudrate: "
dprint(defname, "Testing port: '{}'".format(usbport))
setIndent(1)
baudrates = g.GMCbaudrates[:] # limited to [57600, 115200]
baudrates.sort(reverse=True) # to start with highest baudrate
loop = 1
loopmax = 3
foundit = False
brec = None
while loop < loopmax: # try up to loopmax times to get a version from the device at this port
# cdprint(defname, "testing - loop #{} on port: '{}".format(loop, usbport))
for baudrate in baudrates:
dprint(defname, "testing - loop #{} on port: '{}' with baudrate: {}".format(loop, usbport, baudrate))
try:
with serial.Serial(usbport, baudrate=baudrate, timeout=0.3, write_timeout=0.5) as ABRser:
# calling getGMC_Version may fail after plugging in of device. Somehow, calling GETCPM first
# breaks up this failure. Strange.
bwrt = ABRser.write(b'<GETCPM>>') # returns bwrt: Number of bytes written, type: <class 'int'>
while True:
time.sleep(0.01)
brec = ABRser.read(1) # returns brec: data record of type: <class 'bytes'>
# rdprint("brec: ", brec)
if ABRser.in_waiting == 0: break
srec = getGMC_Version(ABRser) # get the GMC device version as string. Can be real or simulated
# rdprint(defname, "srec:", srec)
except OSError as e:
exceptPrint(e, "")
# edprint(defname + "OSError: ERRNO:{} ERRtext:'{}'".format(e.errno, e.strerror))
if e.errno == 13:
# no permission for port
msg = "You have no permission to access Serial Port '{}'.".format(usbport)
msg += "<br>Please review Appendix C of the GeigerLog manual.<br>"
else:
# ???
msg = "Serial Port {} not available".format(usbport)
edprint(msg)
efprint(msg)
return None
except Exception as e:
errmessage1 = defname + "FAILURE: Reading from device"
exceptPrint(e, "")
edprint(defname, errmessage1)
efprint(errmessage1)
setIndent(0)
return None # Python's None signals communication error
if srec.startswith("GMC"):
# it is a GMC device
foundit = True
loop = loopmax # got communication; no need for further calls in case model or serno don't match
dprint(defname + "Success - found GMC device '{}' using baudrate {}".format(g.GMC_DeviceDetected, baudrate))
# now check for a Model definition
# rdprint(defname, g.GMC_ID)
if g.GMC_ID[0] is None:
# a GMC device was found ok, and a specific Model was not requested. You're done
break # the for loop
else:
if srec.startswith(g.GMC_ID[0]):
# we found the specified Model
foundit = True
dprint(defname + "Success - matches configured Model '{}' ".format(g.GMC_ID[0]))
# now check for a SerialNumber definition if requested
if g.GMC_ID[1] is None:
break # not requested
else:
serno = getGMC_SerialNumber(usbport, baudrate)
if serno.startswith(g.GMC_ID[1]):
# it is the specified SerialNo
foundit = True
dprint(defname + "Success - matches SerialNumber '{}' ".format(g.GMC_ID[1]))
break # the for loop
else:
# not the specified SerialNo
foundit = False
else:
# not the specified Model
rdprint(defname + "FAILURE - does NOT match configured Model '{}' ".format(g.GMC_ID[0]))
foundit = False
break # the for loop
else:
# not a GMC device found; try next baudrate
foundit = False
# end for loop: for baudrate in baudrates:
if foundit:
returnBR = baudrate
break # the while loop
else:
returnBR = 0
dprint(defname + "FAILURE No matching device detected at port: {} baudrate: {}".format(usbport, baudrate))
rdprint("fail in loop #{} - repeating".format(loop))
loop += 1
# end while loop
setIndent(0)
return returnBR
def getGMC_SerialSetting():
"""test all USB-To-Serial ports and return first found port and baudrate with device
matching ID and/or Serial number if so requested"""
defname = "getGMC_SerialSetting: "
PortsFound = getGMC_SerialPorts("GMC")
portfound = None
baudfound = None
for port in PortsFound:
baudrate = getGMC_SerialBaudrate(port) # like: port: '/dev/ttyUSB0'
if baudrate is not None and baudrate > 0:
portfound = port
baudfound = baudrate
break
return (portfound, baudfound)
## end local defs ##################################################################################
defname = "initGMC: "
dprint(defname)
setIndent(1)
g.GMC_DeviceName = "GMC Device" # full model name is held in later set g.GMC_DeviceDetected
# this sets the values defined in the GeigerLog config file
if g.GMC_usbport == "auto": g.GMC_usbport = None
if g.GMC_baudrate == "auto": g.GMC_baudrate = None
if g.GMC_timeoutR == "auto": g.GMC_timeoutR = 3
if g.GMC_timeoutR_getData == "auto": g.GMC_timeoutR_getData = 0.5 # shorter Timeout-Read used for data collection
if g.GMC_timeoutW == "auto": g.GMC_timeoutW = 1
if g.GMC_ID == "auto": g.GMC_ID = (None, None)
if g.GMC_WiFiPeriod == "auto": g.GMC_WiFiPeriod = 1
if g.GMC_WiFiSwitch == "auto": g.GMC_WiFiSwitch = 1
if g.GMC_FastEstTime == "auto": g.GMC_FastEstTime = 60
if g.GMC_RTC_Offset == "auto": g.GMC_RTC_Offset = +1
if g.GMC_GL_ClockCorrection == "auto": g.GMC_GL_ClockCorrection = 30
# this sets the values defined in GeigerLog's own config to cfgHi
cfgKeyHi["SSID"] [0] = g.WiFiSSID
cfgKeyHi["Password"] [0] = g.WiFiPassword
cfgKeyHi["Website"] [0] = g.gmcmapWebsite
cfgKeyHi["URL"] [0] = g.gmcmapURL
cfgKeyHi["UserID"] [0] = g.gmcmapUserID
cfgKeyHi["CounterID"] [0] = g.gmcmapCounterID
cfgKeyHi["Period"] [0] = g.GMC_WiFiPeriod
cfgKeyHi["WiFi"] [0] = g.GMC_WiFiSwitch
cfgKeyHi["FET"] [0] = g.GMC_FastEstTime
cfgKeyHi["RTC_OFFSET"][0] = g.GMC_RTC_Offset
#
# get the usbport and find the baudrate
#
if g.GMC_usbport is None:
# user has NOT defined a port; now auto-find it and its baudrate
port, baud = getGMC_SerialSetting()
# rdprint(defname + "port, baud: ", port, baud)
if port is None or baud is None:
setIndent(0)
g.Devices["GMC"][g.CONN] = False
msg = "A {} was not detected.".format(g.GMC_DeviceName)
return msg
else:
g.GMC_usbport = port
g.GMC_baudrate = baud
g.Devices["GMC"][0] = g.GMC_DeviceDetected # detected at getGMC_Version()
# Example fprint: 'GMC Device 'GMC-300Re 4.54' was detected at port: /dev/ttyUSB0 and baudrate: 57600'
fprint("{} '{}' was detected at port: {} and baudrate: {}".format(
g.GMC_DeviceName,
g.GMC_DeviceDetected,
g.GMC_usbport,
g.GMC_baudrate),
)
else:
# user has defined a port; use it if it exists, return error if not; don't try anything else
if not os.path.exists(g.GMC_usbport):
# edprint("den shit gibbes nich")
return "The user defined port '{}' does not exist".format(g.GMC_usbport)
else:
# use the port configured by the user
# Example fprint: A GMC Device was user configured for port: '/dev/ttyUSB0'
fprint("A device {} was <b>user configured</b> for port: '{}'".format(
g.GMC_DeviceName,
g.GMC_usbport,))
baudrate = getGMC_SerialBaudrate(g.GMC_usbport)
if baudrate is not None and baudrate > 0:
g.GMC_baudrate = baudrate
fprint("{} '{}' was detected at port: {} and baudrate: {}".format(
g.GMC_DeviceName,
g.GMC_DeviceDetected,
g.GMC_usbport,
g.GMC_baudrate))
else:
return "A {} was not detected at user defined port '{}'.".format(
g.GMC_DeviceName,
g.GMC_usbport)
# if this point is reached, a serial connection does exist and the counter is connected and ID'd
g.Devices["GMC"][g.DNAME] = g.GMC_DeviceDetected
g.Devices["GMC"][g.CONN] = True
# PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP
# PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP
# get device details and GMC_variables
dprint(defname, "Found proper device '{}', now getting Device Properties:".format(g.GMC_DeviceDetected))
getGMC_DeviceProperties()
# PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP
# PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP
g.GMC_Variables = setLoggableVariables("GMC", g.GMC_Variables)
g.exgg.dbtnGMC.setToolTip("GMC Device<br><b>{}</b><br>Click Button for Device Info".format(g.GMC_DeviceDetected))
# turn Heartbeat --> OFF --- just in case it had been turned on!
turnGMC_HeartbeatOFF()
# ### turn Heartbeat --> ON --- use only for TESTING heartbeat !
# turnGMC_HeartbeatON()
# ### end
# set Threading
devvars = g.Devices["GMC"][g.VNAMES]
for vname in devvars: g.GMC_Value[vname] = g.NAN # define all vars
g.GMC_ThreadRun = True
g.GMC_Thread = threading.Thread(target=GMC_THREAD_Target, args=["Dummy"]) # auch tuple (args=("Dummy",)) möglich, aber NUR einzelnes Argument!
g.GMC_Thread.daemon = True
g.GMC_Thread.start()
# do a clock correction, but only if so configured
if g.GMC_GL_ClockCorrection > 0:
GMC_WriteDateTime()
g.GMC_NextCorrMin = (getMinute() + g.GMC_GL_ClockCorrection) % 60
# get the config and set it up for GL
rcfg, error, errmessage = getGMC_RawConfig()
vprintGMC_Config(defname, rcfg)
if error >= 0:
if g.devel:
# make list of cfg for copy/paste to simulator
ac = "["
for i, a in enumerate(rcfg):
if i % 20 == 0 and i > 0: ac += "\n "
ac += "{:3d}, ".format(a)
ac = ac[:-2] + "]"
cdprint(defname, " Python list for copy/paste of config for use in simulation\n", ac)
setGMC_Config4GL(rcfg) # no return val
setIndent(0)
return "" # empty message signals "Ok"; only other useful msg is "SIM" (for simulated, like from Raspi devices)
#end initgmc
# #
# # using AT code for 8266 chip in WiFi enabled counters
# #
# getResponseAT(b'<AT>>') # b'AT\r\r\n\r\nOK\r\n\n'
# getResponseAT(b'<AT+RST>>') # b'AT+RST\r\r\n\r\nOK\r\nWIFI DISCONNECT\r\n\r\n ets Jan 8 2013,rst cause:2, boot mode:(3,6)\r\n\r\nload 0x40100000, len 1856, room 16 \r\ntail 0\r\nchksum 0x63\r\nload 0x3ffe8000, len 776, room 8 \r\ntail 0\r\nchksum 0x02\r\nload 0x3ffe8310, len 552, room 8 \r\ntail 0\r\nchksum 0x7'
# # getResponseAT(b'<AT+GMR>>') # b'AT+GMR\r\r\nAT version:1.2.0.0(Jul 1 2016 20:04:45)\r\nSDK version:1.5.4.1(39cb9a32)\r\nAi-Thinker Technology Co. Ltd.\r\nDec 2 2016 14:21:16\r\nOK\r\nWIFI DISCONNECT\r\nWIFI CONNECTED\r\nWIFI GOT IP\r\n\n'
# # getResponseAT(b'<AT+CIFSR>>') # b'AT+CIFSR\r\r\n+CIFSR:APIP,"192.168.4.1"\r\n+CIFSR:APMAC,"a2:20:a6:36:ac:ba"\r\n+CIFSR:STAIP,"10.0.0.42"\r\n+CIFSR:STAMAC,"a0:20:a6:36:ac:ba"\r\n\r\nOK\r\n\n'
# # # FritzBox: GMC-500+: A0:20:A6:36:AC:BA == STAMAC!
# getResponseAT(b'<AT+CIPSTART="TCP","10.0.0.20",8000>>')
# getResponseAT(b'<AT+CIFSR>>')
# # getResponseAT(b'<AT+CIPMODE=0>>')
# # getResponseAT(b'<AT+CIPMODE=1>>') # 1 führt zur Blockade von CIPSTART
# # getResponseAT(b'<AT+CWLIF>>') # b'AT+CWLIF\r\r\n\r\nOK\r\n\n'
# # getResponseAT(b'<AT+CWSAP?>>') # b'AT+CWSAP?\r\r\n+CWSAP:"AI-THINKER_36ACBA","",1,0,4,0\r\n\r\nOK\r\nWIFI GOT IP\r\n\n'
# # getResponseAT(b'<AT+CWMODE?>>') # b'AT+CWMODE?\r\r\n+CWMODE:3\r\n\r\nOK\r\nWIFI DISCONNECT\r\nWIFI CONNECTED\r\nWIFI GOT IP\r\n\n'
# # getResponseAT(b'<AT+CWMODE=?>>') # b'AT+CWMODE=?\r\r\n+CWMODE:(1-3)\r\n\r\nOK\r\nWIFI GOT IP\r\n\n'
# # getResponseAT(b'<AT+CWLIF="mac">>') # --> error ??? not avialable?
# # getResponseAT(b'<AT+CMD>>') # b'AT+CMD?\r\r\n\r\nERROR\r\n\n' ??? not avialable?
# # getResponseAT(b'<AT+CMD?>>') # b'AT+CMD?\r\r\n\r\nERROR\r\n\n' ??? not avialable?
# return "" # empty message signals "Ok"
def terminateGMC():
"""close Serial connection if open, and reset some properties"""
defname = "terminateGMC: "
dprint(defname )
setIndent(1)
if g.GMCser is not None:
try: g.GMCser.close()
except: edprint(defname + "Failed trying to close Serial Connection; terminating anyway", debug=True)
g.GMCser = None
# shut down thread
dprint(defname, "stopping thread")
g.GMC_ThreadRun = False
g.GMC_Thread.join() # "This blocks the calling thread until the thread
# whose join() method is called is terminated."
# verify that thread has ended, but wait not longer than 5 sec (takes 0.006...0.016 ms)
start = time.time()
while g.GMC_Thread.is_alive() and (time.time() - start) < 5:
pass
msgalive = "Yes" if g.GMC_Thread.is_alive() else "No"
dprint(defname + "thread-status: alive: {}, waiting took:{:0.1f} ms".format(msgalive, 1000 * (time.time() - start)))
# set the GMC power icon to inactive state
g.exgg.dbtnGMCPower.setIcon(QIcon(QPixmap(os.path.join(g.resDir, 'icon_power-round_on.png'))))
g.exgg.dbtnGMCPower.setEnabled(False)
g.Devices["GMC"][g.CONN] = False
dprint(defname + "Terminated")
dprint(defname, "GMC_ThreadMessages: '{}'".format(g.GMC_ThreadMessages))
setIndent(0)
def getValuesGMC(varlist):
"""Read data from the locally held vars; set them to NAN after readout"""
###
### on 'g.GMC_testing' count values are reset to -20 to allow showing of missed data calls
###
start = time.time()
defname = "getValuesGMC: "
# mdprint(defname, "varlist: ", varlist)
ambientvars = ("Temp", "Press", "Humid", "Xtra")
alldata = {}
for vname in varlist:
if vname in g.GMC_Value.keys():
# g.GMC_Value has already the scaled data - do not scale again!!
alldata[vname] = g.GMC_Value[vname]
# reset g.GMC_Value
if vname in ambientvars: g.GMC_Value[vname] = g.NAN # do NOT set the ambient values to the -20 flag for missed calls
else: g.GMC_Value[vname] = -20 if g.GMC_testing else g.NAN
vprintLoggedValues(defname, varlist, alldata, (time.time() - start) * 1000)
return alldata
def GMC_THREAD_Target(args):
"""The thread to read the variables from the device"""
# funny args issue: threading.Thread(target=GMC_THREAD_Target, args=["Dummy"])
# auch tuple (args=("Dummy",)) möglich, aber stets NUR einzelnes Argument!
defname = "GMC_THREAD_Target: "
# rdprint(defname, "args: ", args)
oldnexttime = 0
varlist = g.Devices["GMC"][g.VNAMES]
while g.GMC_ThreadRun:
# go to sleep until (GMC_timeoutR_getData + 100 ms) before next cycle begins to be ready even when 1 timeout occurs
# Note: when GMC_timeoutR_getData is >= cycletime then NO sleeping occurs!
oldnexttime = g.nexttime
sleeptime = max(0, g.nexttime - time.time() - g.GMC_timeoutR_getData - 0.1) # sec
# rdprint(defname, "sleeptime: ", sleeptime)
time.sleep(sleeptime)
# actions when logging
actionstart = time.time()
if g.logging:
# fetch the values
g.GMC_Value = THREAD_GMC_fetchValues(varlist) # gives error if doing when not logging
# # alert on NAN
# if "CPM1st" in g.GMC_Value.keys():
# if np.isnan(g.GMC_Value["CPM1st"]): QueueSoundDVL("burp")
# clock correction
if g.GMC_GL_ClockCorrection > 0 and (getMinute() == g.GMC_NextCorrMin):
GMC_WriteDateTime()
g.GMC_NextCorrMin = (g.GMC_NextCorrMin + g.GMC_GL_ClockCorrection) % 60
# rdprint(defname, "g.GMC_NextCorrMin: ", g.GMC_NextCorrMin, " CurrentMinute: ", getMinute(), " GMC_GL_ClockCorrection: ", g.GMC_GL_ClockCorrection)
actiondur = time.time() - actionstart # sec
# wait until the next cycle has started
wstart = time.time()
loops = 0
while oldnexttime == g.nexttime: # wait until g.nexttime changes
if g.GMC_ThreadRun == False: break
time.sleep(0.020)
loops += 1
wdur = time.time() - wstart # sec
# save fSV
if g.GMC_testing and g.fSVStringSet:
msg = "TIMEOUT-FAIL: Device: '{}' Total calls:{:<6.0f} (CPM:{:0.2%} CPS:{:0.2%}) ".\
format(g.GMC_DeviceDetected, g.GMC_calls, g.GMC_callsTimeoutCPM / g.GMC_calls, g.GMC_callsTimeoutCPS / g.GMC_calls)
msg += "Varlist: {} Times[ms]: Sleeping:{:<6.0f} Action:{:<6.0f} Waiting:{:<6.0f} (loops: {})".\
format(varlist, sleeptime * 1000, actiondur * 1000, wdur * 1000, loops)
# writeSpecialLog(msg)
cdlogprint(msg)
def getClockDelta():
"""Delta of time_computer minus time_device - negative: device is faster"""
cstart = time.time()
defname = "getClockDelta: "
# mdprint(defname)
setIndent(1)
clock_delta = g.NAN
try:
with serial.Serial(g.GMC_usbport, baudrate=g.GMC_baudrate, timeout=1, write_timeout=0.5) as ABRser:
bwrt = ABRser.write(b'<GETDATETIME>>')
brec = ABRser.read(7)
except Exception as e:
exceptPrint(e, defname)
else: # successful try
# rdprint(defname, "brec: ", brec)
# broken clock in GMC-500: --> brec = b'\x00\x00\x00\x00\x00\x00\xaa'
if brec == b'\x00\x00\x00\x00\x00\x00\xaa':
rdprint(defname, "Broken clock - brec: {}".format(brec))
else:
if len(brec) >= 6:
try:
datetime_device = str(dt.datetime(brec[0] + 2000, brec[1], brec[2], brec[3], brec[4], brec[5]))
timestamp_device = mpld.datestr2num(datetime_device) # days
datetime_computer = longstime()
timestamp_computer = mpld.datestr2num(datetime_computer) # days
# rdprint(defname, "datetime_computer: ", datetime_computer, " timestamp_computer: ", timestamp_computer)
timestamp_delta = (timestamp_computer - timestamp_device) * 86400 # --> sec
# rdprint(defname, "datetime_device: ", datetime_device, " timestamp_device: ", timestamp_device, " Delta: {:0.6f} sec".format(timestamp_delta))
rounding = 3 # count of decimals
clock_delta = round(timestamp_delta, rounding) # delta time in sec
except Exception as e:
exceptPrint(e, "converting to time, and calc clock delta")
else:
rdprint(defname, "brec is too short - brec: ", brec, " len(brec): ", len(brec), " ", " ".join(str(x) for x in brec))
cdur = 1000 * (time.time() - cstart)
mdprint(defname, "Clock Delta is: {} s dur: {:0.1f} ms".format(clock_delta, cdur))
setIndent(0)
return (clock_delta, cdur)
def GMC_WriteDateTime():
"""Write DateTime to counter"""
# from GQ-RFC1201.txt:
# NOT CORRECT !!!!
# 22. Set year date and time
# command: <SETDATETIME[YYMMDDHHMMSS]>>
# Return: 0xAA
# Firmware supported: GMC-280, GMC-300 Re.3.00 or later
# from: GQ-GMC-ICD.odt
# CORRECT! 6 bytes, no square brackets
# <SETDATETIME[YY][MM][DD][hh][mm][ss]>>
defname = "GMC_WriteDateTime: "
# convert Computer DateTime to byte sequence format needed by counter
timelocal = list(time.localtime()) # timelocal: 2018-04-19 13:02:50 --> [2018, 4, 19, 13, 2, 50, 3, 109, 1]
timelocal[0] -= 2000
btimelocal = bytes(timelocal[:6])
# rdprint(defname, "Setting DateTime: now:", timelocal[:6], ", coded:", btimelocal)
# write DATETIME Byte-sequence to the counter
try:
with serial.Serial(g.GMC_usbport, baudrate=g.GMC_baudrate, timeout=3, write_timeout=0.5) as ABRser:
bwrt = ABRser.write(b'<SETDATETIME' + btimelocal + b'>>') # returns bwrt: Number of bytes written, type: <class 'int'>
brec = ABRser.read(1) # returns brec: b'\xaa' type: <class 'bytes'>
# rdprint(defname, "brec: ", brec)
except Exception as e:
msg = "DateTime could NOT be set!"
exceptPrint(e, defname + msg)
QueuePrint(msg)
QueueSoundDVL("burp")
else:
gdprint(defname, "DateTime was set!")
def THREAD_GMC_fetchValues(varlist):
"""get all data for vars in varlist for LOCAL storage"""
totalstart = time.time()
defname = "THREAD_GMC_fetchValues: "
# mdprint(defname, varlist)
# setIndent(1)
g.GMC_ThreadMessages = longstime() + " " + defname + str(varlist) + "\n"
durCPM = 0
durCPS = 0
THREAD_alldata = {}
g.fSVStringSet = False
# does the USB-Port exist?
if not os.path.exists(g.GMC_usbport):
# den shit gibbes nich - kann passieren, wenn nach Start der USB Stecker gezogen wird!
emsg = "FAILURE: GMC Serial Port '{}' does not exist; cannot access GMC device.".format(g.GMC_usbport)
QueuePrint(emsg)
QueueSound("burp")
mdprint(defname, emsg)
else:
# USB-Port does exist
# try to make a serial connection and get values on success
GMC_DataSerial = None
try:
GMC_DataSerial = serial.Serial(g.GMC_usbport, baudrate=g.GMC_baudrate, timeout=g.GMC_timeoutR_getData, write_timeout=g.GMC_timeoutW)
except serial.SerialException as e:
# no serial connection
exceptPrint(e, "Device can not be found or can not be configured; Port may already be open.")
except Exception as e:
# no serial connection
exceptPrint(e, "Unexpected Exception opening Serial Port")
else:
# serial connection had been made ok
for vname in varlist:
# THREAD_alldata[vname] = g.NAN
if vname in ["CPM3rd", "CPS3rd", "Temp", "Press", "Humid", "Xtra"]:
# ignore calls for these variables (possibly modified later, see end of function)
# pass
THREAD_alldata[vname] = g.NAN
else:
# vname in ["CPM", "CPS", CPM1st", "CPS1st", "CPM2nd", "CPS2nd"]
fSVstart = time.time()
fSV = fetchSingleValueGMC(GMC_DataSerial, vname)
fSVdur = 1000 * (time.time() - fSVstart)
# rdprint(defname, "fSVdur: {0:0.1f}".format(fSVdur))
g.GMC_calls += 1
if "CPM" in vname : durCPM += fSVdur
elif "CPS" in vname : durCPS += fSVdur
if type(fSV) is str:
# mdprint(defname, fSV, type(fSV), str(type(fSV)))
g.fSVStringSet = True
if "R_TIMEOUT" in fSV:
if "CPM" in vname: g.GMC_callsTimeoutCPM += 1
elif "CPS" in vname: g.GMC_callsTimeoutCPS += 1
emsg = "TIMEOUT-FAIL: {:6s} Dur:{:3.0f}ms (Fails: CPM:{:0.3%} CPS:{:0.3%})".format(vname, fSVdur, g.GMC_callsTimeoutCPM / g.GMC_calls, g.GMC_callsTimeoutCPS / g.GMC_calls)
QueuePrint("{} {}".format(longstime(), emsg))
dprint(defname, emsg)
g.SoundMsgQueue.append("doublebip")
fSV = -1000 * g.GMC_timeoutR_getData if g.GMC_testing else g.NAN
elif "EXTRABYTES" in fSV:
# wurde unter Windows einmal beobachtet. Nach einem timeout
g.GMC_callsExtrabyte += 1
emsg = "EXTRABYTES-FAIL: {:6s}".format(vname)
QueuePrint(emsg)
cdlogprint(defname + emsg)
fSV = -7000 if g.GMC_testing else g.NAN
elif "WRONG_BYTECOUNT" in fSV:
g.GMC_callsWrongbyteCount += 1
emsg = "BYTECOUNT-FAIL: {:6s} got {} bytes, expected {}!".format(vname, fSV.split(" ")[1], g.GMC_Bytes)
QueuePrint(emsg)
cdlogprint(defname + emsg)
fSV = -9000 if g.GMC_testing else g.NAN
elif "USBPORT_MISSING" in fSV:
emsg = "USBPORT_MISSING-FAIL: Serial port '{}' does not exist. Cannot read variable: '{}'".format(g.GMC_usbport, vname)
QueuePrint(emsg)
cdlogprint(defname + emsg)
fSV = -10000 if g.GMC_testing else g.NAN
elif "WRONG_VARNAME" in fSV:
emsg = "WRONG_VARNAME-FAIL: '{}' cannot be used".format(vname)
QueuePrint(emsg)
cdlogprint(defname + emsg)
fSV = -11000 if g.GMC_testing else g.NAN
elif "EXCEPTION" in fSV:
emsg = "EXCEPTION: getting value for '{}' on port: {}".format(vname, g.GMC_usbport)
QueuePrint(emsg)
cdlogprint(defname + emsg)
fSV = -12000 if g.GMC_testing else g.NAN
else:
cdlogprint(defname, "UNCAUGHT fSV string: ", fSV)
fSV = -20000 if g.GMC_testing else g.NAN
# end if (str message)
# fSV can be the original value or the negative error-string-modified-to-value
# valuescaling should only be done on original values, i.e. on non-negative values!
# fetchSingleValueGMC already retuns the scaled data !!!
THREAD_alldata[vname] = fSV if fSV < 0 else applyValueFormula(vname, fSV, g.ValueScale[vname], info=defname)
# Info on the Call performance
msg = "{:6s} Value: {:<5.0f} Calls: Total: {:<5d} Timeouts: CPM:{:<4d} ({:0.2%}) CPS:{:<4d} ({:0.2%}) Exceptions: {:<4d} ExtraBytes: {:<4d} WrongByteCount: {:<4d}"\
.format(vname, THREAD_alldata[vname], g.GMC_calls, g.GMC_callsTimeoutCPM, g.GMC_callsTimeoutCPM / g.GMC_calls, g.GMC_callsTimeoutCPS, g.GMC_callsTimeoutCPS / g.GMC_calls, g.GMC_callsException, g.GMC_callsExtrabyte, g.GMC_callsWrongbyteCount)
msg += " Call dur: {:0.1f} ms"\
.format(fSVdur)
g.GMC_ThreadMessages += longstime() + " " + defname + msg + "\n"
# end if-else: 'if vname in vars...'
# end loop: 'for vname in varlist'
GMC_DataSerial.close()
if g.devel:
pass
if "Temp" in varlist or "Press" in varlist:
T, P = getClockDelta()
if "Temp" in varlist: THREAD_alldata["Temp"] = T # counter's clocktime minus real time in sec (negative: --> counter runs faster)
if "Press" in varlist: THREAD_alldata["Press"] = P # duration of getting Clock Delta
if "Humid" in varlist: THREAD_alldata["Humid"] = round(durCPM, 3) # sum of durations of only all CPM calls
if "Xtra" in varlist: THREAD_alldata["Xtra"] = round(durCPS, 3) # sum of durations of only all CPS calls
# ### testing for response to RadPro commands on the formula interpreter
# if "Humid" in varlist: applyValueFormula("Humid", g.NAN, g.ValueScale["Humid"], info=defname)
# applyValueFormula("Humid", g.NAN, g.ValueScale["Humid"], info=defname)
# ####
totaldur = 1000 * (time.time() - totalstart) # sum of durations of all actions in this def
msg = "Total dur all calls: {:0.1f} ms".format(totaldur)
g.GMC_ThreadMessages += longstime() + " " + defname + msg + "\n"
vprintLoggedValues(defname, varlist, THREAD_alldata, totaldur)
# get GMCinfo during logging if requested
# as info requires multiple calls to counter, it can only be done when not
# interfering with calls for data. This place here is the ONLY one to assure this!
if g.GMC_getInfoFlag == 1: g.GMC_DatetimeMsg = getInfoGMC(extended=False, force=True)
elif g.GMC_getInfoFlag == 2: g.GMC_DatetimeMsg = getInfoGMC(extended=True, force=True)
g.GMC_getInfoFlag = 0
# setIndent(0)
return THREAD_alldata
def fetchSingleValueGMC(GMC_DataSerial, vname):
"""Get value for a single, specific var, and return single value after ValueFormula"""
# NOTE: Do not call with vname in ["CPM3rd", "CPS3rd", "Temp", "Press", "Humid", "Xtra"]
# These will result in return of NAN
# NOTE: Windows CANNOT open serial port when already opened elsewhere!
# for the 300 series counter:
# send <GETCPM>> and read 2 bytes
# In total 2 bytes data are returned from GQ GMC unit as a 16 bit unsigned integer.
# The first byte is MSB byte data and second byte is LSB byte data.
# e.g.: 00 1C -> the returned CPM is 28
# e.g.: 0B EA -> the returned CPM is 3050
#
# send <GETCPS>> and read 2 bytes
# In total 2 bytes data are returned from GQ GMC unit
# my observation: highest bit in MSB is always set -> mask out!
# e.g.: 80 1C -> the returned CPS is 28
# e.g.: FF FF -> the returned CPS is 3F FF -> thus maximum CPS is 16383
# -> thus maximum CPM is 16383 * 60 = 982980
#
# for the 500, 600 series counter:
# send <GETCPM>> and read 4 bytes -- all GETCPM* commands return 4 bytes! note cmd extension with L or H!
# send <GETCPS>> and read 4 bytes -- all GETCPS* commands return 4 bytes! note cmd extension with L or H!
### local function #######################################################
def getCommandCode(vname):
"""return tuple: (<GET_CallCode>>, maskHighBit)"""
CmdCode = (b'', False) # default when illegal vname used
# if vname == "CPM": CmdCode = (b'<GETCPMXYZabc>>' , False ) # this works also!!!
# elif vname == "CPS": CmdCode = (b'<GETCPSxyzabc>>' , True ) # this works also!!!
if vname == "CPM": CmdCode = (b'<GETCPM>>' , False ) # the normal CPM call; on GMC-500+ gets CPM as sum of both tubes
elif vname == "CPS": CmdCode = (b'<GETCPS>>' , True ) # the normal CPS call; on GMC-500+ gets CPM as sum of both tubes
elif vname == "CPM1st": CmdCode = (b'<GETCPML>>', False ) # get CPM from High Sensitivity tube; that should be the 'normal' tube
elif vname == "CPS1st": CmdCode = (b'<GETCPSL>>', True ) # get CPS from High Sensitivity tube; that should be the 'normal' tube
elif vname == "CPM2nd": CmdCode = (b'<GETCPMH>>', False ) # get CPM from Low Sensitivity tube; that should be the 2nd tube in the 500+
elif vname == "CPS2nd": CmdCode = (b'<GETCPSH>>', True ) # get CPS from Low Sensitivity tube; that should be the 2nd tube in the 500+
return CmdCode
def cleanExtrabytes():
"""getting extrabytes - faster routine"""
brec = b""
bsum = 0
while True:
bytesWaiting = GMC_DataSerial.in_waiting
if bytesWaiting > 0:
brec = GMC_DataSerial.read(bytesWaiting)