-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathconfig.py
More file actions
540 lines (482 loc) · 18.2 KB
/
config.py
File metadata and controls
540 lines (482 loc) · 18.2 KB
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
"""
Basic script for generating `labjack_channels.json`, which is used by the server
to fetch/stream data from the specified channels
"""
import json
import os
# mapping bases for X3/X4/X5 (CB37 AIN0..13 -> actual AIN)
BANK_BASE = {"X3": 48, "X4": 72, "X5": 96}
def load_channels():
if not os.path.exists("labjack_channels.json"):
return [], set()
with open("labjack_channels.json", "r") as f:
try:
data = json.load(f)
if isinstance(data, dict) and "Channels" in data:
channels = data["Channels"]
elif isinstance(data, list):
channels = data
else:
print("Unrecognized JSON structure. Starting fresh.")
return [], set()
used_pins = set()
for ch in channels:
# store used pins as strings "AIN#", "FIO#", "DAC#"
if "AIN" in ch:
used_pins.add(ch["AIN"])
if "NegativeAIN" in ch:
used_pins.add(ch["NegativeAIN"])
if "FIO" in ch:
used_pins.add(ch["FIO"])
if "DAC" in ch:
used_pins.add(ch["DAC"])
print("\nLoaded existing configuration from 'labjack_channels.json'")
print_configured_channels(channels)
return channels, used_pins
except json.JSONDecodeError, TypeError:
print(
"Warning: Could not parse JSON file. Starting with an empty configuration."
)
return [], set()
def print_configured_channels(channels):
if not channels:
print("\nNo channels currently configured.\n")
return
print("\n=== Configured Channels ===")
for ch in channels:
t = ch.get("Type", "AIN")
if t == "AIN":
ain = ch["AIN"]
neg = ch.get("NegativeAIN", "—")
print(
f" {ain} - {neg} | {ch['SensorType']} | Differential: {ch['Differential']}"
)
elif t == "FIO":
print(f" {ch['FIO']} | FIO | Direction: {ch.get('Direction', '—')}")
elif t == "DAC":
print(f" {ch['DAC']} | DAC | Voltage: {ch.get('Voltage', '—')}")
print("============================")
def remove_channel(channels, used_pins):
if not channels:
print("\nNo channels to remove.")
return
print_configured_channels(channels)
try:
label = input(
"\nEnter the channel label to remove (e.g. AIN94, FIO3, DAC0): "
).strip()
except ValueError:
print("Invalid input.")
return
for ch in channels:
# compare by label membership
if (
(ch.get("AIN") == label)
or (ch.get("FIO") == label)
or (ch.get("DAC") == label)
):
channels.remove(ch)
# remove used pins tracked
if "AIN" in ch:
used_pins.discard(ch["AIN"])
if "NegativeAIN" in ch:
used_pins.discard(ch["NegativeAIN"])
if "FIO" in ch:
used_pins.discard(ch["FIO"])
if "DAC" in ch:
used_pins.discard(ch["DAC"])
print(f"\nRemoved {label} successfully.")
return
print(f"\n{label} not found in configuration.")
def Sensortype():
print("\nAvailable sensor types:")
print(" - Voltage")
print(" - Thermocouple")
print(" - Pressure")
print(" - LoadCell")
while True:
s = (
input("Please choose from the available sensor types: ")
.strip()
.capitalize()
)
if s not in ("Voltage", "Thermocouple", "Pressure", "Loadcell"):
print("Please choose one of the available sensors")
else:
return "LoadCell" if s == "Loadcell" else s
def isDifferential():
while True:
choice = input("Is this a differential input? (yes/no): ").strip().lower()
if choice in ("y", "yes"):
return True
elif choice in ("n", "no"):
return False
else:
print("Please choose yes or no.")
def ask_bank():
while True:
b = input("Which Mux80 bank? (X2, X3, X4, X5): ").strip().upper()
if b in ("X2", "X3", "X4", "X5"):
return b
print("Please choose one of X2, X3, X4, X5.")
def ask_cb37_pin(bank):
"""
Ask user to select CB37 pin type and index.
Returns a tuple (type, index) where type in {"AIN","FIO","DAC"}.
"""
while True:
print("\nCB37 pin types:")
print(" 1) AIN0 - AIN13")
print(" 2) FIO0 - FIO7")
print(" 3) DAC0 or DAC1")
choice = input("Select pin type (1-3): ").strip()
if choice == "1":
try:
idx = int(input("Enter AIN index on CB37 (0-13): ").strip())
except ValueError:
print("Enter a valid integer 0-13.")
continue
if idx < 0 or idx > 13:
print("AIN index out of range (0-13).")
continue
if bank == "X2" and idx > 3:
print(
"On X2 we allow only AIN0-AIN3 for AIN configuration. "
"Please choose another pin or bank."
)
return None
return ("AIN", idx)
elif choice == "2":
try:
idx = int(input("Enter FIO index (0-7): ").strip())
except ValueError:
print("Enter a valid integer 0-7.")
continue
if idx < 0 or idx > 7:
print("FIO index out of range (0-7).")
continue
return ("FIO", idx)
elif choice == "3":
dac = input("Enter DAC channel (0 or 1): ").strip()
if dac not in ("0", "1"):
print("Only DAC0 or DAC1 are available.")
continue
return ("DAC", int(dac))
else:
print("Please choose 1-3.")
def map_cb37_to_actual_ain(bank, cb37_idx):
"""
Map CB37 AIN index (0..13) to actual T7 AIN number based on bank.
For X2 we only allow 0..3 and map directly to AIN0..AIN3.
For X3/X4/X5 use BANK_BASE.
"""
if bank == "X2":
# only AIN0..AIN3 are allowed on X2
if 0 <= cb37_idx <= 3:
return cb37_idx
return None
else:
base = BANK_BASE[bank]
return base + cb37_idx # CB37 AIN0 -> base + 0, AIN13 -> base + 13
def add_channel_flow(channels, used_pins):
# Ask whether this channel is on a mux80
on_mux = input("Is this channel on a Mux80? (yes/no): ").strip().lower()
on_mux_flag = on_mux in ("y", "yes")
bank = None
if on_mux_flag:
bank = ask_bank()
# ask CB37 pin if mux80 used, else allow direct AIN/FIO/DAC entry
if on_mux_flag:
res = ask_cb37_pin(bank)
if res is None:
# invalid selection (e.g., tried AIN4..13 on X2)
return # return to main menu
pin_type, idx = res
if pin_type == "AIN":
mapped_ain = map_cb37_to_actual_ain(bank, idx)
if mapped_ain is None:
print(f"CB37 AIN{idx} is not available on {bank}.")
return
# ask differential or single-ended
diff = isDifferential()
# validate differential rules
if bank == "X2":
# differential only allowed for AIN0 -> AIN1 and AIN2 -> AIN3
if diff and idx not in (0, 2):
print(f"AIN{idx} cannot be differential on bank {bank}.")
return # return to main menu (user requested this behavior)
if diff:
pos_label = f"AIN{mapped_ain}"
neg_label = f"AIN{mapped_ain + 1}" # 0->1, 2->3
if pos_label in used_pins or neg_label in used_pins:
print("One of the pins is already configured.")
return
used_pins.add(pos_label)
used_pins.add(neg_label)
sensor = Sensortype()
channel_info = {
"Type": "AIN",
"AIN": pos_label,
"NegativeAIN": neg_label,
"SensorType": sensor,
"Differential": True,
"Bank": bank,
"CB37_Index": idx,
}
else:
pos_label = f"AIN{mapped_ain}"
if pos_label in used_pins:
print("That AIN is already configured.")
return
used_pins.add(pos_label)
sensor = Sensortype()
channel_info = {
"Type": "AIN",
"AIN": pos_label,
"SensorType": sensor,
"Differential": False,
"Bank": bank,
"CB37_Index": idx,
}
else:
# X3/X4/X5
# differential allowed only for CB37 AIN0..AIN7 (idx 0..7)
if diff and idx > 7:
print(f"AIN{idx} cannot be differential on bank {bank}.")
return # return to main menu
if diff:
pos_label = f"AIN{mapped_ain}"
neg_label = f"AIN{mapped_ain + 8}" # positive + 8
if pos_label in used_pins or neg_label in used_pins:
print("One of the pins is already configured.")
return
used_pins.add(pos_label)
used_pins.add(neg_label)
sensor = Sensortype()
channel_info = {
"Type": "AIN",
"AIN": pos_label,
"NegativeAIN": neg_label,
"SensorType": sensor,
"Differential": True,
"Bank": bank,
"CB37_Index": idx,
}
else:
pos_label = f"AIN{mapped_ain}"
if pos_label in used_pins:
print("That AIN is already configured.")
return
used_pins.add(pos_label)
sensor = Sensortype()
channel_info = {
"Type": "AIN",
"AIN": pos_label,
"SensorType": sensor,
"Differential": False,
"Bank": bank,
"CB37_Index": idx,
}
elif pin_type == "FIO":
fio_label = f"FIO{idx}"
if fio_label in used_pins:
print("That FIO is already used.")
return
direction = input("Direction (input/output): ").strip().lower()
if direction not in ("input", "output"):
direction = "input"
used_pins.add(fio_label)
channel_info = {
"Type": "FIO",
"FIO": fio_label,
"Direction": direction,
"Bank": bank,
"CB37_Index": idx,
}
else: # DAC
dac_label = f"DAC{idx}"
if dac_label in used_pins:
print("That DAC is already used.")
return
try:
value = float(input("Enter output voltage (0–5 V): ").strip())
except ValueError:
print("Invalid voltage entered.")
return
if value < 0:
value = 0
if value > 5:
value = 5
used_pins.add(dac_label)
channel_info = {
"Type": "DAC",
"DAC": dac_label,
"Voltage": value,
"Bank": bank,
"CB37_Index": idx,
}
else:
# Not on Mux80: allow direct AIN(0-15), FIO0-7, DAC0/1
print("\nNot using Mux80 for this channel. Choose pin type:")
res = ask_cb37_pin_no_mux()
if res is None:
return
pin_type, idx = res
if pin_type == "AIN":
# direct AIN0..15
if idx < 0 or idx > 15:
print("AIN must be 0-15 for a non-Mux device.")
return
pos_label = f"AIN{idx}"
diff = isDifferential()
if diff:
# For non-mux, assume standard pairing even->odd only for 0/1 and 2/3?
# We'll restrict to the simplest: only allow differential if paired exists within 0..15 and not used.
# Require user to enter the negative by choosing an AIN that is its correct pair (we won't invent pair rules).
try:
neg_idx = int(
input("Enter negative AIN index (0-15): ").strip()
)
except ValueError:
print("Invalid negative AIN.")
return
neg_label = f"AIN{neg_idx}"
if pos_label in used_pins or neg_label in used_pins:
print("One of the pins is already configured.")
return
used_pins.add(pos_label)
used_pins.add(neg_label)
sensor = Sensortype()
channel_info = {
"Type": "AIN",
"AIN": pos_label,
"NegativeAIN": neg_label,
"SensorType": sensor,
"Differential": True,
"Bank": None,
"CB37_Index": None,
}
else:
if pos_label in used_pins:
print("That AIN is already configured.")
return
used_pins.add(pos_label)
sensor = Sensortype()
channel_info = {
"Type": "AIN",
"AIN": pos_label,
"SensorType": sensor,
"Differential": False,
"Bank": None,
"CB37_Index": None,
}
elif pin_type == "FIO":
fio_label = f"FIO{idx}"
if fio_label in used_pins:
print("That FIO is already used.")
return
direction = input("Direction (input/output): ").strip().lower()
if direction not in ("input", "output"):
direction = "input"
used_pins.add(fio_label)
channel_info = {
"Type": "FIO",
"FIO": fio_label,
"Direction": direction,
}
else: # DAC
dac_label = f"DAC{idx}"
if dac_label in used_pins:
print("That DAC is already used.")
return
try:
value = float(input("Enter output voltage (0–5 V): ").strip())
except ValueError:
print("Invalid voltage entered.")
return
if value < 0:
value = 0
if value > 5:
value = 5
used_pins.add(dac_label)
channel_info = {"Type": "DAC", "DAC": dac_label, "Voltage": value}
# if we get here, channel_info should be defined
channels.append(channel_info)
print("\nAdded new channel:")
print(json.dumps(channel_info, indent=2))
print_configured_channels(channels)
def ask_cb37_pin_no_mux():
# same as ask_cb37_pin but without bank-specific X2 restriction and mapping
while True:
print("\nPin types (no Mux80):")
print(" 1) AIN0 - AIN15")
print(" 2) FIO0 - FIO7")
print(" 3) DAC0 or DAC1")
choice = input("Select pin type (1-3): ").strip()
if choice == "1":
try:
idx = int(input("Enter AIN index (0-15): ").strip())
except ValueError:
print("Enter a valid integer 0-15.")
continue
if idx < 0 or idx > 15:
print("AIN index out of range (0-15).")
continue
return ("AIN", idx)
elif choice == "2":
try:
idx = int(input("Enter FIO index (0-7): ").strip())
except ValueError:
print("Enter a valid integer 0-7.")
continue
if idx < 0 or idx > 7:
print("FIO index out of range (0-7).")
continue
return ("FIO", idx)
elif choice == "3":
dac = input("Enter DAC channel (0 or 1): ").strip()
if dac not in ("0", "1"):
print("Only DAC0 or DAC1 are available.")
continue
return ("DAC", int(dac))
else:
print("Please choose 1-3.")
def main():
channels, used_pins = load_channels()
if channels:
overwrite = (
input(
"\nDo you want to completely overwrite the existing "
"configuration? (y/n): "
)
.strip()
.lower()
)
if overwrite in ("y", "yes"):
channels = []
used_pins = set()
print("\nConfiguration cleared.\n")
print("\n=== LabJack T7 Channel Configuration ===")
while True:
print("\nOptions:")
print(" 1. Add a channel")
print(" 2. Remove a channel")
print(" 3. View all configured channels")
print(" 4. Save and exit")
choice = input("Select an option (1-4): ").strip()
if choice == "1":
add_channel_flow(channels, used_pins)
elif choice == "2":
remove_channel(channels, used_pins)
elif choice == "3":
print_configured_channels(channels)
elif choice == "4":
break
else:
print("Invalid option. Please select 1-4.")
with open("labjack_channels.json", "w") as f:
json.dump(channels, f, indent=4)
print("\nConfiguration saved to 'labjack_channels.json'")
print_configured_channels(channels)
if __name__ == "__main__":
main()