spikesafe-python 1.13.5__tar.gz → 1.15.8__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. {spikesafe_python-1.13.5/spikesafe_python.egg-info → spikesafe_python-1.15.8}/PKG-INFO +1 -1
  2. {spikesafe_python-1.13.5 → spikesafe_python-1.15.8}/pyproject.toml +1 -1
  3. {spikesafe_python-1.13.5 → spikesafe_python-1.15.8}/spikesafe_python/Compensation.py +21 -4
  4. {spikesafe_python-1.13.5 → spikesafe_python-1.15.8}/spikesafe_python/DigitizerDataFetch.py +54 -18
  5. {spikesafe_python-1.13.5 → spikesafe_python-1.15.8}/spikesafe_python/Discharge.py +8 -2
  6. {spikesafe_python-1.13.5 → spikesafe_python-1.15.8}/spikesafe_python/MemoryTableReadData.py +6 -1
  7. {spikesafe_python-1.13.5 → spikesafe_python-1.15.8}/spikesafe_python/Precision.py +51 -11
  8. {spikesafe_python-1.13.5 → spikesafe_python-1.15.8}/spikesafe_python/PulseWidthCorrection.py +8 -2
  9. {spikesafe_python-1.13.5 → spikesafe_python-1.15.8}/spikesafe_python/ReadAllEvents.py +26 -5
  10. {spikesafe_python-1.13.5 → spikesafe_python-1.15.8}/spikesafe_python/ScpiFormatter.py +14 -4
  11. {spikesafe_python-1.13.5 → spikesafe_python-1.15.8}/spikesafe_python/SpikeSafeEvents.py +3 -0
  12. {spikesafe_python-1.13.5 → spikesafe_python-1.15.8}/spikesafe_python/SpikeSafeInfoParser.py +10 -6
  13. {spikesafe_python-1.13.5 → spikesafe_python-1.15.8}/spikesafe_python/TcpSocket.py +4 -1
  14. {spikesafe_python-1.13.5 → spikesafe_python-1.15.8}/spikesafe_python/Threading.py +17 -9
  15. spikesafe_python-1.15.8/spikesafe_python/_deprecation.py +21 -0
  16. {spikesafe_python-1.13.5 → spikesafe_python-1.15.8/spikesafe_python.egg-info}/PKG-INFO +1 -1
  17. {spikesafe_python-1.13.5 → spikesafe_python-1.15.8}/spikesafe_python.egg-info/SOURCES.txt +3 -1
  18. spikesafe_python-1.15.8/tests/test_get_new_voltage_data_estimated_complete_time.py +59 -0
  19. spikesafe_python-1.15.8/tests/test_spikesafe_info_parser.py +54 -0
  20. spikesafe_python-1.13.5/tests/test_get_new_voltage_data_estimated_complete_time.py +0 -26
  21. {spikesafe_python-1.13.5 → spikesafe_python-1.15.8}/LICENSE +0 -0
  22. {spikesafe_python-1.13.5 → spikesafe_python-1.15.8}/README.md +0 -0
  23. {spikesafe_python-1.13.5 → spikesafe_python-1.15.8}/setup.cfg +0 -0
  24. {spikesafe_python-1.13.5 → spikesafe_python-1.15.8}/setup.py +0 -0
  25. {spikesafe_python-1.13.5 → spikesafe_python-1.15.8}/spikesafe_python/ChannelData.py +0 -0
  26. {spikesafe_python-1.13.5 → spikesafe_python-1.15.8}/spikesafe_python/DigitizerData.py +0 -0
  27. {spikesafe_python-1.13.5 → spikesafe_python-1.15.8}/spikesafe_python/DigitizerEnums.py +0 -0
  28. {spikesafe_python-1.13.5 → spikesafe_python-1.15.8}/spikesafe_python/DigitizerInfo.py +0 -0
  29. {spikesafe_python-1.13.5 → spikesafe_python-1.15.8}/spikesafe_python/DigitizerVfCustomSequence.py +0 -0
  30. {spikesafe_python-1.13.5 → spikesafe_python-1.15.8}/spikesafe_python/DigitizerVfCustomSequenceStep.py +0 -0
  31. {spikesafe_python-1.13.5 → spikesafe_python-1.15.8}/spikesafe_python/EventData.py +0 -0
  32. {spikesafe_python-1.13.5 → spikesafe_python-1.15.8}/spikesafe_python/SerialPortConnection.py +0 -0
  33. {spikesafe_python-1.13.5 → spikesafe_python-1.15.8}/spikesafe_python/SpikeSafeEnums.py +0 -0
  34. {spikesafe_python-1.13.5 → spikesafe_python-1.15.8}/spikesafe_python/SpikeSafeError.py +0 -0
  35. {spikesafe_python-1.13.5 → spikesafe_python-1.15.8}/spikesafe_python/SpikeSafeInfo.py +0 -0
  36. {spikesafe_python-1.13.5 → spikesafe_python-1.15.8}/spikesafe_python/TemperatureData.py +0 -0
  37. {spikesafe_python-1.13.5 → spikesafe_python-1.15.8}/spikesafe_python/__init__.py +0 -0
  38. {spikesafe_python-1.13.5 → spikesafe_python-1.15.8}/spikesafe_python.egg-info/dependency_links.txt +0 -0
  39. {spikesafe_python-1.13.5 → spikesafe_python-1.15.8}/spikesafe_python.egg-info/requires.txt +0 -0
  40. {spikesafe_python-1.13.5 → spikesafe_python-1.15.8}/spikesafe_python.egg-info/top_level.txt +0 -0
  41. {spikesafe_python-1.13.5 → spikesafe_python-1.15.8}/tests/test_custom_compensation.py +0 -0
  42. {spikesafe_python-1.13.5 → spikesafe_python-1.15.8}/tests/test_custom_compensation_old.py +0 -0
  43. {spikesafe_python-1.13.5 → spikesafe_python-1.15.8}/tests/test_digitizer_fetch_time_of_sampling.py +0 -0
  44. {spikesafe_python-1.13.5 → spikesafe_python-1.15.8}/tests/test_digitizer_fetch_time_of_sampling_old.py +0 -0
  45. {spikesafe_python-1.13.5 → spikesafe_python-1.15.8}/tests/test_event_data.py +0 -0
  46. {spikesafe_python-1.13.5 → spikesafe_python-1.15.8}/tests/test_event_data_old.py +0 -0
  47. {spikesafe_python-1.13.5 → spikesafe_python-1.15.8}/tests/test_optimum_compensation.py +0 -0
  48. {spikesafe_python-1.13.5 → spikesafe_python-1.15.8}/tests/test_optimum_compensation_old.py +0 -0
  49. {spikesafe_python-1.13.5 → spikesafe_python-1.15.8}/tests/test_optimum_pulse_width_correction.py +0 -0
  50. {spikesafe_python-1.13.5 → spikesafe_python-1.15.8}/tests/test_optimum_pulse_width_correction_old.py +0 -0
  51. {spikesafe_python-1.13.5 → spikesafe_python-1.15.8}/tests/test_spikesafe_info_compare_rev_version.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: spikesafe-python
3
- Version: 1.13.5
3
+ Version: 1.15.8
4
4
  Summary: SpikeSafe Python Library
5
5
  Author-email: Vektrex <support@vektrex.com>
6
6
  Classifier: Programming Language :: Python :: 3
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "spikesafe-python"
7
- version = "1.13.5"
7
+ version = "1.15.8"
8
8
  authors = [
9
9
  { name="Vektrex", email="support@vektrex.com" },
10
10
  ]
@@ -3,6 +3,7 @@ import jsonschema
3
3
  from jsonschema import validate
4
4
  import logging
5
5
  import os
6
+ from ._deprecation import deprecated
6
7
  from .SpikeSafeEnums import LoadImpedance, RiseTime
7
8
 
8
9
  log = logging.getLogger(__name__)
@@ -551,6 +552,10 @@ class Compensation:
551
552
  # f"for device_type: {device_type}, max current: {max_current}")
552
553
 
553
554
 
555
+ @deprecated(
556
+ "get_optimum_compensation is deprecated; "
557
+ "use Compensation.get_optimum_compensation() instead."
558
+ )
554
559
  def get_optimum_compensation(
555
560
  spikesafe_model_max_current_amps: float,
556
561
  set_current_amps: float,
@@ -558,10 +563,14 @@ def get_optimum_compensation(
558
563
  enable_logging: bool = False
559
564
  ) -> tuple[LoadImpedance, RiseTime]:
560
565
  """
561
- Obsolete: Use Compensation.get_optimum_compensation() instead.
566
+ Deprecated: Use Compensation.get_optimum_compensation() instead.
562
567
  """
563
568
  return Compensation.get_optimum_compensation(spikesafe_model_max_current_amps, set_current_amps, pulse_on_time_seconds, enable_logging)
564
569
 
570
+ @deprecated(
571
+ "get_custom_compensation is deprecated; "
572
+ "use Compensation.get_custom_compensation() instead."
573
+ )
565
574
  def get_custom_compensation(
566
575
  spikesafe_model_max_current_amps: float,
567
576
  set_current_amps: float,
@@ -571,18 +580,26 @@ def get_custom_compensation(
571
580
  enable_logging: bool = False
572
581
  ) -> tuple[LoadImpedance, RiseTime]:
573
582
  """
574
- Obsolete: Use Compensation.get_custom_compensation() instead.
583
+ Deprecated: Use Compensation.get_custom_compensation() instead.
575
584
  """
576
585
  return Compensation.get_custom_compensation(spikesafe_model_max_current_amps, set_current_amps, device_type, custom_compensation_table, pulse_on_time_seconds, enable_logging)
577
586
 
587
+ @deprecated(
588
+ "load_custom_compensation_table is deprecated; "
589
+ "use Compensation.load_custom_compensation_table() instead."
590
+ )
578
591
  def load_custom_compensation_table(file_path: str) -> list[dict]:
579
592
  """
580
- Obsolete: Use Compensation.load_custom_compensation_table() instead.
593
+ Deprecated: Use Compensation.load_custom_compensation_table() instead.
581
594
  """
582
595
  return Compensation.load_custom_compensation_table(file_path)
583
596
 
597
+ @deprecated(
598
+ "load_custom_compensation_unique_device_types is deprecated; "
599
+ "use Compensation.load_custom_compensation_unique_device_types() instead."
600
+ )
584
601
  def load_custom_compensation_unique_device_types(custom_compensation_table: list[dict]) -> list[str]:
585
602
  """
586
- Obsolete: Use Compensation.load_custom_compensation_unique_device_types() instead.
603
+ Deprecated: Use Compensation.load_custom_compensation_unique_device_types() instead.
587
604
  """
588
605
  return Compensation.load_custom_compensation_unique_device_types(custom_compensation_table)
@@ -7,6 +7,7 @@ from __future__ import annotations
7
7
  import sys
8
8
  import logging
9
9
  import time
10
+ from ._deprecation import deprecated
10
11
  from .DigitizerData import DigitizerData
11
12
  from .DigitizerEnums import TimeSamplingMode, SamplingMode
12
13
  from .DigitizerVfCustomSequence import DigitizerVfCustomSequence
@@ -31,8 +32,8 @@ class DigitizerDataFetch:
31
32
  Returns an array of voltage readings using custom sampling mode from the digitizer obtained through a fetch query.
32
33
  wait_for_new_voltage_data(spike_safe_socket: TcpSocket, wait_time: float = 0.0, enable_logging: bool | None = None, timeout: float | None = None, digitizer_number: int | None = None) -> None
33
34
  Queries the SpikeSafe PSMU digitizer until it responds that it has acquired new data.
34
- get_new_voltage_data_estimated_complete_time(aperture_microseconds: int, reading_count: int, hardware_trigger_count: int | None = None, hardware_trigger_delay_microseconds: int | None = None) -> float
35
- Returns the estimated minimum possible time in seconds it will take for the SpikeSafe PSMU digitizer to acquire new voltage readings. If hardware triggering is used, this does not take into account the pulse period, so the actual time may be longer.
35
+ get_new_voltage_data_estimated_complete_time(aperture_microseconds: int, reading_count: int, hardware_trigger_count: int | None = None, hardware_trigger_delay_microseconds: int | None = None, pulse_period_seconds: float | None = None) -> float
36
+ Returns the estimated minimum possible time in seconds it will take for the SpikeSafe PSMU digitizer to acquire new voltage readings.
36
37
  """
37
38
  @staticmethod
38
39
  def fetch_voltage_data(
@@ -355,10 +356,11 @@ class DigitizerDataFetch:
355
356
  aperture_microseconds: int,
356
357
  reading_count: int,
357
358
  hardware_trigger_count: int | None = None,
358
- hardware_trigger_delay_microseconds: int | None = None
359
+ hardware_trigger_delay_microseconds: int | None = None,
360
+ pulse_period_seconds: float | None = None
359
361
  ) -> float:
360
362
  """
361
- Returns the estimated minimum possible time it will take for the SpikeSafe PSMU digitizer to acquire new voltage readings. If hardware triggering is used, this does not take into account the pulse period, so the actual time may be longer.
363
+ Returns the estimated minimum possible time it will take for the SpikeSafe PSMU digitizer to acquire new voltage readings.
362
364
 
363
365
  Parameters
364
366
  ----------
@@ -374,6 +376,9 @@ class DigitizerDataFetch:
374
376
  hardware_trigger_delay_microseconds : int, optional
375
377
  Delay in microseconds between each hardware trigger
376
378
 
379
+ pulse_period_seconds : float, optional
380
+ Pulse period in seconds. If not provided, the Digitizer minimum retrigger time of 600us is used for multiple hardware triggers.
381
+
377
382
  Returns
378
383
  -------
379
384
  float
@@ -390,13 +395,20 @@ class DigitizerDataFetch:
390
395
  if hardware_trigger_delay_microseconds is None:
391
396
  hardware_trigger_delay_microseconds = 0 # Default value if not provided
392
397
 
398
+ trigger_delay_seconds = hardware_trigger_delay_microseconds / 1_000_000.0
399
+ acquisition_time_seconds = (aperture_microseconds * reading_count) / 1_000_000.0
400
+
393
401
  if hardware_trigger_count == 1:
394
- # 𝑀𝑖𝑛𝑖𝑚𝑢𝑚 𝑇𝑜𝑡𝑎𝑙 𝐴𝑐𝑞𝑢𝑖𝑠𝑖𝑡𝑖𝑜𝑛 𝑇𝑖𝑚𝑒 = 𝑇𝑟𝑖𝑔𝑔𝑒𝑟 𝐶𝑜𝑢𝑛𝑡 (𝑇𝑟𝑖𝑔𝑔𝑒𝑟 𝐷𝑒𝑙𝑎𝑦+𝐴𝑝𝑒𝑟𝑡𝑢𝑟𝑒 𝑇𝑖𝑚𝑒×𝑅𝑒𝑎𝑑𝑖𝑛𝑔 𝐶𝑜𝑢𝑛𝑡)
395
- estimated_complete_time_seconds = (hardware_trigger_count * (hardware_trigger_delay_microseconds + aperture_microseconds * reading_count)) / 1_000_000.0
402
+ estimated_complete_time_seconds = trigger_delay_seconds + acquisition_time_seconds
396
403
  else:
397
- retrigger_time_microseconds = 600
398
- # 𝑀𝑖𝑛𝑖𝑚𝑢𝑚 𝑇𝑜𝑡𝑎𝑙 𝐴𝑐𝑞𝑢𝑖𝑠𝑖𝑡𝑖𝑜𝑛 𝑇𝑖𝑚𝑒 = 𝑇𝑟𝑖𝑔𝑔𝑒𝑟 𝐶𝑜𝑢𝑛𝑡 (𝑇𝑟𝑖𝑔𝑔𝑒𝑟 𝐷𝑒𝑙𝑎𝑦 + Retrigger Time + 𝐴𝑝𝑒𝑟𝑡𝑢𝑟𝑒 𝑇𝑖𝑚𝑒 × 𝑅𝑒𝑎𝑑𝑖𝑛𝑔 𝐶𝑜𝑢𝑛𝑡) - Retrigger Time (ignore time last trigger)
399
- estimated_complete_time_seconds = (hardware_trigger_count * (hardware_trigger_delay_microseconds + retrigger_time_microseconds + aperture_microseconds * reading_count) - retrigger_time_microseconds) / 1_000_000.0
404
+ digitizer_minimum_retrigger_time_seconds = 0.000600
405
+ effective_trigger_spacing_seconds = digitizer_minimum_retrigger_time_seconds
406
+ if pulse_period_seconds is not None and pulse_period_seconds > digitizer_minimum_retrigger_time_seconds:
407
+ effective_trigger_spacing_seconds = pulse_period_seconds
408
+
409
+ # Do not add trigger spacing after the final trigger.
410
+ estimated_complete_time_seconds = hardware_trigger_count * (trigger_delay_seconds + effective_trigger_spacing_seconds + acquisition_time_seconds) - effective_trigger_spacing_seconds
411
+
400
412
  # wait time cannot be less than 0s
401
413
  estimated_complete_time_seconds = max(estimated_complete_time_seconds, 0)
402
414
 
@@ -550,17 +562,24 @@ class DigitizerDataFetch:
550
562
  # Regular sample
551
563
  return accumulated_time_since_start + aperture
552
564
 
553
-
565
+ @deprecated(
566
+ "fetch_voltage_data is deprecated; "
567
+ "use DigitizerDataFetch.fetch_voltage_data() instead."
568
+ )
554
569
  def fetch_voltage_data(
555
570
  spike_safe_socket: TcpSocket,
556
571
  enable_logging: bool | None = None,
557
572
  digitizer_number: int | None = None
558
573
  ) -> list[DigitizerData]:
559
574
  """
560
- Obsolete: Use DigitizerDataFetch.fetch_voltage_data() instead.
575
+ Deprecated: Use DigitizerDataFetch.fetch_voltage_data() instead.
561
576
  """
562
577
  return DigitizerDataFetch.fetch_voltage_data(spike_safe_socket, enable_logging, digitizer_number=digitizer_number)
563
578
 
579
+ @deprecated(
580
+ "fetch_voltage_data_sampling_mode_linear is deprecated; "
581
+ "use DigitizerDataFetch.fetch_voltage_data_sampling_mode_linear() instead."
582
+ )
564
583
  def fetch_voltage_data_sampling_mode_linear(
565
584
  spike_safe_socket: TcpSocket,
566
585
  time_sampling_mode: TimeSamplingMode,
@@ -572,10 +591,14 @@ def fetch_voltage_data_sampling_mode_linear(
572
591
  digitizer_number: int | None = None
573
592
  ) -> list[DigitizerData]:
574
593
  """
575
- Obsolete: Use DigitizerDataFetch.fetch_voltage_data_sampling_mode_linear() instead.
594
+ Deprecated: Use DigitizerDataFetch.fetch_voltage_data_sampling_mode_linear() instead.
576
595
  """
577
596
  return DigitizerDataFetch.fetch_voltage_data_sampling_mode_linear(spike_safe_socket, time_sampling_mode, aperture_microseconds, reading_count, hardware_trigger_delay_microseconds, pulse_period_seconds, enable_logging, digitizer_number=digitizer_number)
578
597
 
598
+ @deprecated(
599
+ "fetch_voltage_data_sampling_mode_logarithmic is deprecated; "
600
+ "use DigitizerDataFetch.fetch_voltage_data_sampling_mode_logarithmic() instead."
601
+ )
579
602
  def fetch_voltage_data_sampling_mode_logarithmic(
580
603
  spike_safe_socket: TcpSocket,
581
604
  time_sampling_mode: TimeSamplingMode,
@@ -585,10 +608,14 @@ def fetch_voltage_data_sampling_mode_logarithmic(
585
608
  digitizer_number: int | None = None
586
609
  ) -> list[DigitizerData]:
587
610
  """
588
- Obsolete: Use DigitizerDataFetch.fetch_voltage_data_sampling_mode_logarithmic() instead.
611
+ Deprecated: Use DigitizerDataFetch.fetch_voltage_data_sampling_mode_logarithmic() instead.
589
612
  """
590
613
  return DigitizerDataFetch.fetch_voltage_data_sampling_mode_logarithmic(spike_safe_socket, time_sampling_mode, sampling_mode, hardware_trigger_delay_microseconds, enable_logging, digitizer_number=digitizer_number)
591
614
 
615
+ @deprecated(
616
+ "fetch_voltage_data_sampling_mode_custom is deprecated; "
617
+ "use DigitizerDataFetch.fetch_voltage_data_sampling_mode_custom() instead."
618
+ )
592
619
  def fetch_voltage_data_sampling_mode_custom(
593
620
  spike_safe_socket: TcpSocket,
594
621
  time_sampling_mode: TimeSamplingMode,
@@ -598,21 +625,30 @@ def fetch_voltage_data_sampling_mode_custom(
598
625
  digitizer_number: int | None = None
599
626
  ) -> list[DigitizerData]:
600
627
  """
601
- Obsolete: Use DigitizerDataFetch.fetch_voltage_data_sampling_mode_custom() instead.
628
+ Deprecated: Use DigitizerDataFetch.fetch_voltage_data_sampling_mode_custom() instead.
602
629
  """
603
630
  return DigitizerDataFetch.fetch_voltage_data_sampling_mode_custom(spike_safe_socket, time_sampling_mode, custom_sequence, hardware_trigger_delay_microseconds, enable_logging, digitizer_number=digitizer_number)
604
631
 
632
+ @deprecated(
633
+ "get_new_voltage_data_estimated_complete_time is deprecated; "
634
+ "use DigitizerDataFetch.get_new_voltage_data_estimated_complete_time() instead."
635
+ )
605
636
  def get_new_voltage_data_estimated_complete_time(
606
637
  aperture_microseconds: int,
607
638
  reading_count: int,
608
639
  hardware_trigger_count: int | None = None,
609
- hardware_trigger_delay_microseconds: int | None = None
640
+ hardware_trigger_delay_microseconds: int | None = None,
641
+ pulse_period_seconds: float | None = None
610
642
  ) -> float:
611
643
  """
612
- Obsolete: Use DigitizerDataFetch.get_new_voltage_data_estimated_complete_time() instead.
644
+ Deprecated: Use DigitizerDataFetch.get_new_voltage_data_estimated_complete_time() instead.
613
645
  """
614
- return DigitizerDataFetch.get_new_voltage_data_estimated_complete_time(aperture_microseconds, reading_count, hardware_trigger_count, hardware_trigger_delay_microseconds)
646
+ return DigitizerDataFetch.get_new_voltage_data_estimated_complete_time(aperture_microseconds, reading_count, hardware_trigger_count, hardware_trigger_delay_microseconds, pulse_period_seconds)
615
647
 
648
+ @deprecated(
649
+ "wait_for_new_voltage_data is deprecated; "
650
+ "use DigitizerDataFetch.wait_for_new_voltage_data() instead."
651
+ )
616
652
  def wait_for_new_voltage_data(
617
653
  spike_safe_socket: TcpSocket,
618
654
  wait_time: float = 0.010,
@@ -621,6 +657,6 @@ def wait_for_new_voltage_data(
621
657
  digitizer_number: int | None = None
622
658
  ) -> None:
623
659
  """
624
- Obsolete: Use DigitizerDataFetch.wait_for_new_voltage_data() instead.
660
+ Deprecated: Use DigitizerDataFetch.wait_for_new_voltage_data() instead.
625
661
  """
626
662
  return DigitizerDataFetch.wait_for_new_voltage_data(spike_safe_socket, wait_time, enable_logging, timeout, digitizer_number=digitizer_number)
@@ -1,4 +1,6 @@
1
1
  import time
2
+
3
+ from ._deprecation import deprecated
2
4
  from .SpikeSafeInfo import SpikeSafeInfo
3
5
  from .TcpSocket import TcpSocket
4
6
  from .Threading import wait
@@ -97,9 +99,13 @@ class Discharge:
97
99
  # when Discharge Complete query is not supported, use a calculated wait time
98
100
  wait_time = Discharge.get_spikesafe_channel_discharge_time(compliance_voltage + 35) # 35V gives extra time, some windows pcs return early from wait function
99
101
  wait(wait_time)
100
-
102
+
103
+ @deprecated(
104
+ "get_spikesafe_channel_discharge_time is deprecated; "
105
+ "use Discharge.get_spikesafe_channel_discharge_time() instead."
106
+ )
101
107
  def get_spikesafe_channel_discharge_time(compliance_voltage: float) -> float:
102
108
  """
103
- Obsolete: use Discharge.get_spikesafe_channel_discharge_time instead
109
+ Deprecated: use Discharge.get_spikesafe_channel_discharge_time instead
104
110
  """
105
111
  return Discharge.get_spikesafe_channel_discharge_time(compliance_voltage)
@@ -5,6 +5,7 @@
5
5
  from __future__ import annotations
6
6
  import logging
7
7
  import math
8
+ from ._deprecation import deprecated
8
9
  from .ChannelData import ChannelData
9
10
  from .TcpSocket import TcpSocket
10
11
  from .TemperatureData import TemperatureData
@@ -203,8 +204,12 @@ class MemoryTableReadData:
203
204
  data = spike_safe_socket.read_data() # read SpikeSafe memory table
204
205
  log.info(data)
205
206
 
207
+ @deprecated(
208
+ "log_memory_table_read is deprecated; "
209
+ "use MemoryTableReadData.log_memory_table_read() instead."
210
+ )
206
211
  def log_memory_table_read(spike_safe_socket: TcpSocket) -> None:
207
212
  """
208
- Obsolete: Use MemoryTableReadData.log_memory_table_read(spike_safe_socket) instead.
213
+ Deprecated: Use MemoryTableReadData.log_memory_table_read(spike_safe_socket) instead.
209
214
  """
210
215
  return MemoryTableReadData.log_memory_table_read(spike_safe_socket)
@@ -1,5 +1,6 @@
1
1
 
2
2
  from __future__ import annotations
3
+ from ._deprecation import deprecated
3
4
 
4
5
  class Precision:
5
6
  """
@@ -203,63 +204,102 @@ class Precision:
203
204
  else:
204
205
  return f'{current_amps:.4f}'
205
206
 
206
-
207
+ @deprecated(
208
+ "get_precise_compliance_voltage_command_argument is deprecated; "
209
+ "use Precision.get_precise_compliance_voltage_command_argument() instead."
210
+ )
207
211
  def get_precise_compliance_voltage_command_argument(compliance_voltage: float) -> str:
208
212
  """
209
- Obsolete: use Precision.get_precise_compliance_voltage_command_argument instead.
213
+ Deprecated: use Precision.get_precise_compliance_voltage_command_argument instead.
210
214
  """
211
215
  return Precision.get_precise_compliance_voltage_command_argument(compliance_voltage)
212
216
 
217
+ @deprecated(
218
+ "get_precise_voltage_protection_ramp_dv_command_argument is deprecated; "
219
+ "use Precision.get_precise_voltage_protection_ramp_dv_command_argument() instead."
220
+ )
213
221
  def get_precise_voltage_protection_ramp_dv_command_argument(voltage_protection_ramp_dv: float) -> str:
214
222
  """
215
- Obsolete: use Precision.get_precise_voltage_protection_ramp_dv_command_argument instead.
223
+ Deprecated: use Precision.get_precise_voltage_protection_ramp_dv_command_argument instead.
216
224
  """
217
225
  return Precision.get_precise_voltage_protection_ramp_dv_command_argument(voltage_protection_ramp_dv)
218
226
 
227
+ @deprecated(
228
+ "get_precise_voltage_protection_ramp_dt_command_argument is deprecated; "
229
+ "use Precision.get_precise_voltage_protection_ramp_dt_command_argument() instead."
230
+ )
219
231
  def get_precise_voltage_protection_ramp_dt_command_argument(voltage_protection_ramp_dt: float) -> str:
220
232
  """
221
- Obsolete: use Precision.get_precise_voltage_protection_ramp_dt_command_argument instead.
233
+ Deprecated: use Precision.get_precise_voltage_protection_ramp_dt_command_argument instead.
222
234
  """
223
235
  return Precision.get_precise_voltage_protection_ramp_dt_command_argument(voltage_protection_ramp_dt)
224
236
 
237
+ @deprecated(
238
+ "get_precise_pulse_width_offset_command_argument is deprecated; "
239
+ "use Precision.get_precise_pulse_width_offset_command_argument() instead."
240
+ )
225
241
  def get_precise_pulse_width_offset_command_argument(pulse_width_offset: float) -> str:
226
242
  """
227
- Obsolete: use Precision.get_precise_pulse_width_offset_command_argument instead.
243
+ Deprecated: use Precision.get_precise_pulse_width_offset_command_argument instead.
228
244
  """
229
245
  return Precision.get_precise_pulse_width_offset_command_argument(pulse_width_offset)
230
246
 
247
+ @deprecated(
248
+ "get_precise_pulse_width_correction_command_argument is deprecated; "
249
+ "use Precision.get_precise_pulse_width_correction_command_argument() instead."
250
+ )
231
251
  def get_precise_pulse_width_correction_command_argument(pulse_width_correction: float) -> str:
232
252
  """
233
- Obsolete: use Precision.get_precise_pulse_width_correction_command_argument instead.
253
+ Deprecated: use Precision.get_precise_pulse_width_correction_command_argument instead.
234
254
  """
235
255
  return Precision.get_precise_pulse_width_correction_command_argument(pulse_width_correction)
236
256
 
257
+ @deprecated(
258
+ "get_precise_duty_cycle_command_argument is deprecated; "
259
+ "use Precision.get_precise_duty_cycle_command_argument() instead."
260
+ )
237
261
  def get_precise_duty_cycle_command_argument(duty_cycle: float) -> str:
238
262
  """
239
- Obsolete: use Precision.get_precise_duty_cycle_command_argument instead.
263
+ Deprecated: use Precision.get_precise_duty_cycle_command_argument instead.
240
264
  """
241
265
  return Precision.get_precise_duty_cycle_command_argument(duty_cycle)
242
266
 
267
+ @deprecated(
268
+ "get_precise_time_command_argument is deprecated; "
269
+ "use Precision.get_precise_time_command_argument() instead."
270
+ )
243
271
  def get_precise_time_command_argument(time_seconds: float) -> str:
244
272
  """
245
- Obsolete: use Precision.get_precise_time_command_argument instead.
273
+ Deprecated: use Precision.get_precise_time_command_argument instead.
246
274
  """
247
275
  return Precision.get_precise_time_command_argument(time_seconds)
248
276
 
277
+ @deprecated(
278
+ "get_precise_time_milliseconds_command_argument is deprecated; "
279
+ "use Precision.get_precise_time_milliseconds_command_argument() instead."
280
+ )
249
281
  def get_precise_time_milliseconds_command_argument(time_milliseconds: float) -> str:
250
282
  """
251
- Obsolete: use Precision.get_precise_time_milliseconds_command_argument instead.
283
+ Deprecated: use Precision.get_precise_time_milliseconds_command_argument instead.
252
284
  """
253
285
  return Precision.get_precise_time_milliseconds_command_argument(time_milliseconds)
254
286
 
287
+ @deprecated(
288
+ "get_precise_time_microseconds_command_argument is deprecated; "
289
+ "use Precision.get_precise_time_microseconds_command_argument() instead."
290
+ )
255
291
  def get_precise_time_microseconds_command_argument(time_microseconds: float) -> str:
256
292
  """
257
- Obsolete: use Precision.get_precise_time_microseconds_command_argument instead.
293
+ Deprecated: use Precision.get_precise_time_microseconds_command_argument instead.
258
294
  """
259
295
  return Precision.get_precise_time_microseconds_command_argument(time_microseconds)
260
296
 
297
+ @deprecated(
298
+ "get_precise_current_command_argument is deprecated; "
299
+ "use Precision.get_precise_current_command_argument() instead."
300
+ )
261
301
  def get_precise_current_command_argument(current_amps: float) -> str:
262
302
  """
263
- Obsolete: use Precision.get_precise_current_command_argument instead.
303
+ Deprecated: use Precision.get_precise_current_command_argument instead.
264
304
  """
265
305
  return Precision.get_precise_current_command_argument(current_amps)
@@ -1,3 +1,5 @@
1
+ from ._deprecation import deprecated
2
+
1
3
  from .SpikeSafeEnums import LoadImpedance, RiseTime
2
4
  from .SpikeSafeInfo import SpikeSafeInfo
3
5
 
@@ -2617,7 +2619,11 @@ class PulseWidthCorrection:
2617
2619
  }
2618
2620
 
2619
2621
  return table
2620
-
2622
+
2623
+ @deprecated(
2624
+ "get_optimum_pulse_width_correction is deprecated; "
2625
+ "use PulseWidthCorrection.get_optimum_pulse_width_correction() instead."
2626
+ )
2621
2627
  def get_optimum_pulse_width_correction(
2622
2628
  spikesafe_model_max_current_amps: float,
2623
2629
  set_current_amps: float,
@@ -2625,7 +2631,7 @@ def get_optimum_pulse_width_correction(
2625
2631
  rise_time: RiseTime
2626
2632
  ) -> str:
2627
2633
  """
2628
- Obsolete: use PulseWidthCorrection.get_optimum_pulse_width_correction() instead
2634
+ Deprecated: use PulseWidthCorrection.get_optimum_pulse_width_correction() instead.
2629
2635
  """
2630
2636
  spikesafe_info = SpikeSafeInfo()
2631
2637
  spikesafe_info.maximum_pulse_width_correction_override = 9
@@ -8,6 +8,8 @@
8
8
  from __future__ import annotations
9
9
  import logging
10
10
  import time
11
+
12
+ from ._deprecation import deprecated
11
13
  from .EventData import EventData
12
14
  from .SpikeSafeError import SpikeSafeError
13
15
  from .TcpSocket import TcpSocket
@@ -179,8 +181,15 @@ class ReadAllEvents:
179
181
  raise
180
182
 
181
183
  @staticmethod
184
+ @deprecated(
185
+ "ReadAllEvents.log_all_events is deprecated; "
186
+ "use ReadAllEvents.read_all_events(spike_safe_socket, enable_logging=True) instead."
187
+ )
182
188
  def log_all_events(spike_safe_socket: TcpSocket) -> None:
183
- """Reads all SpikeSafe events from event queue and prints them to the log file
189
+ """
190
+ Deprecated: Use ReadAllEvents.read_all_events(spike_safe_socket, enable_logging=True) instead.
191
+
192
+ Reads all SpikeSafe events from event queue and prints them to the log file
184
193
 
185
194
  Parameters
186
195
  ----------
@@ -193,29 +202,41 @@ class ReadAllEvents:
193
202
  """
194
203
  event_data = ReadAllEvents.read_all_events(spike_safe_socket) # read all events in SpikeSafe event queue and store in list
195
204
  for event in event_data: # print all SpikeSafe events to the log file
196
- log.info(event.event)
205
+ log.info(event.event)
197
206
 
207
+ @deprecated(
208
+ "ReadAllEvents.read_all_events is deprecated; "
209
+ "use ReadAllEvents.read_all_events(spike_safe_socket, enable_logging) instead."
210
+ )
198
211
  def read_all_events(
199
212
  spike_safe_socket: TcpSocket,
200
213
  enable_logging: bool | None = None
201
214
  ) -> list[EventData]:
202
215
  """
203
- Obsolete: Use ReadAllEvents.read_all_events instead.
216
+ Deprecated: Use ReadAllEvents.read_all_events(spike_safe_socket, enable_logging) instead.
204
217
  """
205
218
  return ReadAllEvents.read_all_events(spike_safe_socket, enable_logging)
206
219
 
220
+ @deprecated(
221
+ "ReadAllEvents.read_until_event is deprecated; "
222
+ "use ReadAllEvents.read_until_event(spike_safe_socket, code, enable_logging, timeout) instead."
223
+ )
207
224
  def read_until_event(
208
225
  spike_safe_socket: TcpSocket,
209
226
  code: int,
210
227
  enable_logging: bool | None = None
211
228
  ) -> list[EventData]:
212
229
  """
213
- Obsolete: Use ReadAllEvents.read_until_event instead.
230
+ Deprecated: Use ReadAllEvents.read_until_event(spike_safe_socket, code, enable_logging, timeout) instead.
214
231
  """
215
232
  return ReadAllEvents.read_until_event(spike_safe_socket, code, enable_logging)
216
233
 
234
+ @deprecated(
235
+ "ReadAllEvents.log_all_events is deprecated; "
236
+ "use ReadAllEvents.read_all_events(spike_safe_socket, enable_logging=True) instead."
237
+ )
217
238
  def log_all_events(spike_safe_socket: TcpSocket) -> None:
218
239
  """
219
- Obsolete: Use ReadAllEvents.log_all_events instead.
240
+ Deprecated: Use ReadAllEvents.read_all_events(spike_safe_socket, enable_logging=True) instead.
220
241
  """
221
242
  ReadAllEvents.log_all_events(spike_safe_socket)
@@ -1,3 +1,5 @@
1
+ from ._deprecation import deprecated
2
+
1
3
  class ScpiFormatter:
2
4
  """
3
5
  Class for formatting SCPI command arguments.
@@ -49,15 +51,23 @@ class ScpiFormatter:
49
51
  return 'ON'
50
52
  else:
51
53
  return 'OFF'
52
-
54
+
55
+ @deprecated(
56
+ "get_scpi_format_integer_for_bool is deprecated; "
57
+ "use ScpiFormatter.get_scpi_format_integer_for_bool() instead."
58
+ )
53
59
  def get_scpi_format_integer_for_bool(bool_value: bool) -> int:
54
60
  """
55
- Obsolete: Use ScpiFormatter.get_scpi_format_integer_for_bool() instead.
61
+ Deprecated: Use ScpiFormatter.get_scpi_format_integer_for_bool() instead.
56
62
  """
57
63
  return ScpiFormatter.get_scpi_format_integer_for_bool(bool_value)
58
-
64
+
65
+ @deprecated(
66
+ "get_scpi_format_on_state_for_bool is deprecated; "
67
+ "use ScpiFormatter.get_scpi_format_on_state_for_bool() instead."
68
+ )
59
69
  def get_scpi_format_on_state_for_bool(bool_value: bool) -> str:
60
70
  """
61
- Obsolete: Use ScpiFormatter.get_scpi_format_on_state_for_bool() instead.
71
+ Deprecated: Use ScpiFormatter.get_scpi_format_on_state_for_bool() instead.
62
72
  """
63
73
  return ScpiFormatter.get_scpi_format_on_state_for_bool(bool_value)
@@ -185,3 +185,6 @@ class SpikeSafeEvents(IntEnum):
185
185
  INVALID_VOLTAGE_PROTECTION_MODE = 600
186
186
  INVALID_STAIRCASE_SWEEP_ON_TIME = 602
187
187
  INVALID_STAIRCASE_SWEEP_STEP_COUNT = 603
188
+ INVALID_CURRENT_RAMP_RATE_SETTINGS = 604
189
+ BIAS_CURRENT_SETTING_IS_ONLY_ALLOWED_IN_BIAS_MODE_ON_CHANNEL_1 = 605
190
+ INVALID_PULSE_TIME_WITH_PULSE_CORRECTION_VALUE = 606
@@ -1,3 +1,4 @@
1
+ from ._deprecation import deprecated
1
2
  from .DigitizerInfo import DigitizerInfo
2
3
  from .SpikeSafeInfo import SpikeSafeInfo
3
4
  from .TcpSocket import TcpSocket
@@ -58,12 +59,11 @@ class SpikeSafeInfoParser:
58
59
  # Requires Release 3.12.9 (or Ethernet Processor must be 3.0.11.10 or later) to support Multiple digitizers, else:
59
60
  supports_multiple_digitizers = SpikeSafeInfoParser.compare_rev_version(spikesafe_info.version, "3.0.11.10")
60
61
  if supports_multiple_digitizers:
61
- spike_safe_socket.send_scpi_command('DIGI:FUNC:CARD:NUMB?')
62
- digitizer_functioning_card_number_list = spike_safe_socket.read_data(enable_logging)
63
- digitizer_functioning_card_number_list = digitizer_functioning_card_number_list.split(",")
62
+ digitizer_functioning_card_number_list = SpikeSafeInfoParser._query_int_list(spike_safe_socket, 'DIGI:FUNC:CARD:NUMB?', enable_logging)
63
+ digitizer_functioning_card_number_list = [card_number for card_number in digitizer_functioning_card_number_list if card_number > 0]
64
64
 
65
65
  for digitizer_functioning_card_number in digitizer_functioning_card_number_list:
66
- SpikeSafeInfoParser._fetch_digitizer_info(spike_safe_socket, spikesafe_info, digitizer_functioning_card_number, enable_logging)
66
+ SpikeSafeInfoParser._fetch_digitizer_info(spike_safe_socket, spikesafe_info, str(digitizer_functioning_card_number), enable_logging)
67
67
 
68
68
  spikesafe_info.has_digitizer = len(spikesafe_info.digitizer_infos) > 0
69
69
  else:
@@ -361,8 +361,12 @@ class SpikeSafeInfoParser:
361
361
  ref_parts = list(map(int, ref_version.split('.')))
362
362
  return rev_parts >= ref_parts
363
363
 
364
+ @deprecated(
365
+ "parse_spikesafe_info is deprecated; "
366
+ "use SpikeSafeInfoParser.parse_spikesafe_info() instead."
367
+ )
364
368
  def parse_spikesafe_info(spike_safe_socket: TcpSocket, enable_logging: bool | None = None) -> SpikeSafeInfo:
365
369
  """
366
- Obsolete: use SpikeSafeInfoParser.parse_spikesafe_info() instead
370
+ Deprecated: use SpikeSafeInfoParser.parse_spikesafe_info() instead
367
371
  """
368
- return SpikeSafeInfoParser.parse_spikesafe_info(spike_safe_socket, enable_logging)
372
+ return SpikeSafeInfoParser.parse_spikesafe_info(spike_safe_socket, enable_logging)
@@ -67,11 +67,14 @@ class TcpSocket:
67
67
  self.tcp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
68
68
  self.tcp_socket.settimeout(2)
69
69
  self.tcp_socket.setsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF, 512)
70
+
71
+ # disable nagel to reduce ACK calls and improve overall script timing
72
+ self.tcp_socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
70
73
 
71
74
  if (self.enable_logging):
72
75
  log.log(self.default_log_level, self.__get_formatted_log_message__('Connecting...'))
73
76
 
74
- self.tcp_socket.connect((ip_address, port_number))
77
+ self.tcp_socket.connect((ip_address, port_number))
75
78
  except Exception as err:
76
79
  # print any error to the log file and raise error to function caller
77
80
  log.error('Error connecting to socket at {}: {}'.format(ip_address, err))
@@ -1,4 +1,5 @@
1
1
  import time
2
+ from ._deprecation import deprecated
2
3
 
3
4
  class Threading:
4
5
  """
@@ -14,7 +15,7 @@ class Threading:
14
15
  def wait(
15
16
  wait_time: float,
16
17
  os_timer_resolution_offset_time: float = 0,
17
- current_time: float = time.perf_counter()
18
+ current_time: float | None = None
18
19
  ) -> None:
19
20
  """
20
21
  Suspends the current thread for a specified amount of time.
@@ -25,20 +26,27 @@ class Threading:
25
26
  Wait time in seconds to suspend the current thread.
26
27
  os_timer_resolution_offset_time: float, optional
27
28
  The offset time in seconds to add to wait_time due to the operating system timer resolution limit. Default is 0.
28
- current_time: float, optional
29
- The current time in seconds. Default is time.perf_counter(), which is the result from a high resolution clock
29
+ current_time: float | None, optional
30
+ The current time in seconds. If None, time.perf_counter() is used, which is the result from a high resolution clock.
30
31
  """
31
- now = current_time
32
- end = now + wait_time + os_timer_resolution_offset_time
33
- while now < end:
34
- now = time.perf_counter()
32
+ if current_time is None:
33
+ current_time = time.perf_counter()
35
34
 
35
+ end = current_time + wait_time + os_timer_resolution_offset_time
36
+
37
+ while time.perf_counter() < end:
38
+ pass
39
+
40
+ @deprecated(
41
+ "wait is deprecated; "
42
+ "use Threading.wait() instead."
43
+ )
36
44
  def wait(
37
45
  wait_time: float,
38
46
  os_timer_resolution_offset_time: float = 0,
39
- current_time: float = time.perf_counter()
47
+ current_time: float | None = None
40
48
  ) -> None:
41
49
  """
42
- Obsolete: use Threading.wait() instead
50
+ Deprecated: use Threading.wait() instead
43
51
  """
44
52
  return Threading.wait(wait_time, os_timer_resolution_offset_time, current_time)
@@ -0,0 +1,21 @@
1
+ from __future__ import annotations
2
+
3
+ from collections.abc import Callable
4
+ from functools import wraps
5
+ from typing import ParamSpec, TypeVar
6
+ import warnings
7
+
8
+ P = ParamSpec("P")
9
+ T = TypeVar("T")
10
+
11
+
12
+ def deprecated(message: str) -> Callable[[Callable[P, T]], Callable[P, T]]:
13
+ def decorator(func: Callable[P, T]) -> Callable[P, T]:
14
+ @wraps(func)
15
+ def wrapper(*args: P.args, **kwargs: P.kwargs) -> T:
16
+ warnings.warn(message, DeprecationWarning, stacklevel=2)
17
+ return func(*args, **kwargs)
18
+
19
+ return wrapper
20
+
21
+ return decorator
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: spikesafe-python
3
- Version: 1.13.5
3
+ Version: 1.15.8
4
4
  Summary: SpikeSafe Python Library
5
5
  Author-email: Vektrex <support@vektrex.com>
6
6
  Classifier: Programming Language :: Python :: 3
@@ -27,6 +27,7 @@ spikesafe_python/TcpSocket.py
27
27
  spikesafe_python/TemperatureData.py
28
28
  spikesafe_python/Threading.py
29
29
  spikesafe_python/__init__.py
30
+ spikesafe_python/_deprecation.py
30
31
  spikesafe_python.egg-info/PKG-INFO
31
32
  spikesafe_python.egg-info/SOURCES.txt
32
33
  spikesafe_python.egg-info/dependency_links.txt
@@ -43,4 +44,5 @@ tests/test_optimum_compensation.py
43
44
  tests/test_optimum_compensation_old.py
44
45
  tests/test_optimum_pulse_width_correction.py
45
46
  tests/test_optimum_pulse_width_correction_old.py
46
- tests/test_spikesafe_info_compare_rev_version.py
47
+ tests/test_spikesafe_info_compare_rev_version.py
48
+ tests/test_spikesafe_info_parser.py
@@ -0,0 +1,59 @@
1
+ import pytest
2
+ from spikesafe_python.DigitizerDataFetch import DigitizerDataFetch
3
+
4
+ @pytest.mark.parametrize(
5
+ "aperture_microseconds, reading_count, hardware_trigger_count, hardware_trigger_delay_microseconds, expected",
6
+ [
7
+ # 488us aperture, 1 reading, 1 hardware trigger, 200us delay
8
+ (488, 1, 1, 200, 0.000688),
9
+ # 500us aperture, 1 reading, 1 hardware trigger, 150us delay
10
+ (500, 1, 1, 150, 0.00065),
11
+ # 694us aperture, 1 reading, 1 hardware trigger, 0us delay
12
+ (694, 1, 1, 0, 0.000694),
13
+ # 25ms aperture, 1 reading, 1 hardware trigger, 3ms delay
14
+ (25000, 1, 1, 3000, 0.028),
15
+ ]
16
+ )
17
+ def test_get_new_voltage_data_estimated_complete_time(
18
+ aperture_microseconds, reading_count, hardware_trigger_count, hardware_trigger_delay_microseconds, expected
19
+ ):
20
+ result = DigitizerDataFetch.get_new_voltage_data_estimated_complete_time(
21
+ aperture_microseconds,
22
+ reading_count,
23
+ hardware_trigger_count,
24
+ hardware_trigger_delay_microseconds
25
+ )
26
+ assert pytest.approx(result, rel=1e-6) == expected
27
+
28
+ @pytest.mark.parametrize(
29
+ "pulse_period_seconds, expected",
30
+ [
31
+ # No pulse period uses the Digitizer minimum retrigger time of 600us
32
+ (None, 0.003),
33
+ # Pulse periods below 600us are clamped to the Digitizer minimum retrigger time
34
+ (0.0005, 0.003),
35
+ # Pulse periods above 600us are used as the effective trigger spacing time
36
+ (0.001, 0.0038),
37
+ ]
38
+ )
39
+ def test_get_new_voltage_data_estimated_complete_time_with_multiple_triggers_and_pulse_period(
40
+ pulse_period_seconds, expected
41
+ ):
42
+ result = DigitizerDataFetch.get_new_voltage_data_estimated_complete_time(
43
+ aperture_microseconds=400,
44
+ reading_count=1,
45
+ hardware_trigger_count=3,
46
+ hardware_trigger_delay_microseconds=200,
47
+ pulse_period_seconds=pulse_period_seconds
48
+ )
49
+ assert pytest.approx(result, rel=1e-6) == expected
50
+
51
+ def test_get_new_voltage_data_estimated_complete_time_ignores_pulse_period_for_single_trigger():
52
+ result = DigitizerDataFetch.get_new_voltage_data_estimated_complete_time(
53
+ aperture_microseconds=400,
54
+ reading_count=1,
55
+ hardware_trigger_count=1,
56
+ hardware_trigger_delay_microseconds=200,
57
+ pulse_period_seconds=0.001
58
+ )
59
+ assert pytest.approx(result, rel=1e-6) == 0.0006
@@ -0,0 +1,54 @@
1
+ from unittest.mock import patch
2
+
3
+ from spikesafe_python.SpikeSafeInfoParser import SpikeSafeInfoParser
4
+
5
+
6
+ class FakeSpikeSafeSocket:
7
+ def __init__(self, digitizer_card_numbers: str) -> None:
8
+ self.socket_ip_address = "127.0.0.1"
9
+ self.digitizer_card_numbers = digitizer_card_numbers
10
+ self.last_command = None
11
+ self.sent_commands = []
12
+
13
+ def send_scpi_command(self, command, enable_logging=None):
14
+ self.last_command = command
15
+ self.sent_commands.append(command)
16
+
17
+ def read_data(self, enable_logging=None):
18
+ responses = {
19
+ "*IDN?": "Vektrex, SpikeSafe 400, Rev 3.0.11.10; SN:1234, HwRev:1, CPLD 1; DSP 1, Last Cal Date:2024-01-01, ModelNum:ZIN644",
20
+ "SOUR0:CURR? MAX": "10",
21
+ "SOUR0:CURR? MIN": "0",
22
+ "SOUR0:VOLT? MAX": "100",
23
+ "SOUR0:VOLT? MIN": "0",
24
+ "SOUR0:PULS:TON? MIN": "1",
25
+ "SOUR0:PULS:TON? MAX": "100",
26
+ "SOUR0:PULS:OFFS? MIN": "0",
27
+ "SOUR0:PULS:OFFS? MAX": "10",
28
+ "MEM:DATA ZINNUM?": "ZIN644",
29
+ "DIGI:FUNC:CARD:NUMB?": self.digitizer_card_numbers,
30
+ "MEM:DATA CONNAVAIL?": "FALSE",
31
+ "SOUR0:FUNC:SHAP? LIST": "PULSED",
32
+ }
33
+ return responses[self.last_command]
34
+
35
+
36
+ def test_parse_spikesafe_info_does_not_fetch_digitizer_info_when_card_number_is_zero():
37
+ socket = FakeSpikeSafeSocket("0")
38
+
39
+ with patch.object(SpikeSafeInfoParser, "_fetch_digitizer_info") as fetch_digitizer_info:
40
+ spikesafe_info = SpikeSafeInfoParser.parse_spikesafe_info(socket)
41
+
42
+ fetch_digitizer_info.assert_not_called()
43
+ assert spikesafe_info.has_digitizer is False
44
+ assert spikesafe_info.digitizer_infos == []
45
+
46
+
47
+ def test_parse_spikesafe_info_only_fetches_positive_digitizer_card_numbers():
48
+ socket = FakeSpikeSafeSocket("1,2")
49
+
50
+ with patch.object(SpikeSafeInfoParser, "_fetch_digitizer_info") as fetch_digitizer_info:
51
+ spikesafe_info = SpikeSafeInfoParser.parse_spikesafe_info(socket)
52
+
53
+ assert [call.args[2] for call in fetch_digitizer_info.call_args_list] == ["1", "2"]
54
+ assert spikesafe_info.has_digitizer is False
@@ -1,26 +0,0 @@
1
- import pytest
2
- from spikesafe_python.DigitizerDataFetch import DigitizerDataFetch
3
-
4
- @pytest.mark.parametrize(
5
- "aperture_microseconds, reading_count, hardware_trigger_count, hardware_trigger_delay_microseconds, expected",
6
- [
7
- # 488us aperture, 1 reading, 1 hardware trigger, 200us delay
8
- (488, 1, 1, 200, 0.000688),
9
- # 500us aperture, 1 reading, 1 hardware trigger, 150us delay
10
- (500, 1, 1, 150, 0.00065),
11
- # 694us aperture, 1 reading, 1 hardware trigger, 0us delay
12
- (694, 1, 1, 0, 0.000694),
13
- # 25ms aperture, 1 reading, 1 hardware trigger, 3ms delay
14
- (25000, 1, 1, 3000, 0.028),
15
- ]
16
- )
17
- def test_get_new_voltage_data_estimated_complete_time(
18
- aperture_microseconds, reading_count, hardware_trigger_count, hardware_trigger_delay_microseconds, expected
19
- ):
20
- result = DigitizerDataFetch.get_new_voltage_data_estimated_complete_time(
21
- aperture_microseconds,
22
- reading_count,
23
- hardware_trigger_count,
24
- hardware_trigger_delay_microseconds
25
- )
26
- assert pytest.approx(result, rel=1e-6) == expected