ttl-barcoder 0.4.1__tar.gz → 0.4.2__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 (32) hide show
  1. {ttl_barcoder-0.4.1 → ttl_barcoder-0.4.2}/.gitignore +2 -0
  2. ttl_barcoder-0.4.2/LICENSE +31 -0
  3. {ttl_barcoder-0.4.1 → ttl_barcoder-0.4.2}/PKG-INFO +37 -4
  4. {ttl_barcoder-0.4.1 → ttl_barcoder-0.4.2}/README.md +2 -0
  5. ttl_barcoder-0.4.2/VERSION +1 -0
  6. {ttl_barcoder-0.4.1 → ttl_barcoder-0.4.2}/pyproject.toml +5 -4
  7. {ttl_barcoder-0.4.1 → ttl_barcoder-0.4.2}/src/ttl_barcoder/core/barcode_ttl.py +12 -1
  8. {ttl_barcoder-0.4.1 → ttl_barcoder-0.4.2}/src/ttl_barcoder/core/decoder.py +7 -2
  9. {ttl_barcoder-0.4.1 → ttl_barcoder-0.4.2}/src/ttl_barcoder/core/encoder.py +8 -0
  10. {ttl_barcoder-0.4.1 → ttl_barcoder-0.4.2}/src/ttl_barcoder/core/generator.py +6 -2
  11. {ttl_barcoder-0.4.1 → ttl_barcoder-0.4.2}/src/ttl_barcoder/hardware/bpod/sender.py +1 -0
  12. {ttl_barcoder-0.4.1 → ttl_barcoder-0.4.2}/src/ttl_barcoder/hardware/pigpio/sender.py +2 -0
  13. {ttl_barcoder-0.4.1 → ttl_barcoder-0.4.2}/tests/test_barcode_ttl.py +1 -1
  14. {ttl_barcoder-0.4.1 → ttl_barcoder-0.4.2}/tests/test_bpod.py +1 -1
  15. {ttl_barcoder-0.4.1 → ttl_barcoder-0.4.2}/tests/test_decoder.py +1 -1
  16. {ttl_barcoder-0.4.1 → ttl_barcoder-0.4.2}/tests/test_encoder.py +1 -1
  17. ttl_barcoder-0.4.1/LICENSE +0 -29
  18. ttl_barcoder-0.4.1/VERSION +0 -1
  19. {ttl_barcoder-0.4.1 → ttl_barcoder-0.4.2}/CITATION.cff +0 -0
  20. {ttl_barcoder-0.4.1 → ttl_barcoder-0.4.2}/examples/bpod_loopback.py +0 -0
  21. {ttl_barcoder-0.4.1 → ttl_barcoder-0.4.2}/examples/dry_simulation.py +0 -0
  22. {ttl_barcoder-0.4.1 → ttl_barcoder-0.4.2}/examples/pigpio_send.py +0 -0
  23. {ttl_barcoder-0.4.1 → ttl_barcoder-0.4.2}/src/ttl_barcoder/__init__.py +0 -0
  24. {ttl_barcoder-0.4.1 → ttl_barcoder-0.4.2}/src/ttl_barcoder/core/__init__.py +0 -0
  25. {ttl_barcoder-0.4.1 → ttl_barcoder-0.4.2}/src/ttl_barcoder/core/config.py +0 -0
  26. {ttl_barcoder-0.4.1 → ttl_barcoder-0.4.2}/src/ttl_barcoder/hardware/__init__.py +0 -0
  27. {ttl_barcoder-0.4.1 → ttl_barcoder-0.4.2}/src/ttl_barcoder/hardware/bpod/__init__.py +0 -0
  28. {ttl_barcoder-0.4.1 → ttl_barcoder-0.4.2}/src/ttl_barcoder/hardware/pigpio/__init__.py +0 -0
  29. {ttl_barcoder-0.4.1 → ttl_barcoder-0.4.2}/src/ttl_barcoder/py.typed +0 -0
  30. {ttl_barcoder-0.4.1 → ttl_barcoder-0.4.2}/tests/test_config.py +0 -0
  31. {ttl_barcoder-0.4.1 → ttl_barcoder-0.4.2}/tests/test_generator.py +0 -0
  32. {ttl_barcoder-0.4.1 → ttl_barcoder-0.4.2}/tests/test_smoke.py +0 -0
@@ -29,3 +29,5 @@ env/
29
29
  .idea/
30
30
  .vscode/
31
31
  .DS_Store
32
+ site/
33
+ uv.lock
@@ -0,0 +1,31 @@
1
+ Copyright (c) 2024-present Lars B. Rollik. All rights reserved.
2
+
3
+ Permission is granted, free of charge, to use, copy, modify, and distribute
4
+ this software and associated documentation files (the "Software") for
5
+ non-commercial research or academic purposes only, subject to the following
6
+ conditions:
7
+
8
+ 1. This copyright notice and permission notice must be included in all copies
9
+ or substantial portions of the Software.
10
+
11
+ 2. Any publication, presentation, or product that uses or builds upon the
12
+ Software must give clear attribution to the original work and its authors.
13
+
14
+ 3. Commercial use is prohibited without a separate written commercial licence
15
+ agreement with the copyright holder. Commercial use means incorporation of
16
+ the Software into anything for which fees or other compensation are charged
17
+ or received, including commercial products and commercial services.
18
+
19
+ 4. No patent licence, express or implied, is granted under these terms. Any
20
+ use that would require a patent licence from the copyright holder requires
21
+ a separate written agreement.
22
+
23
+ 5. Redistribution, in source or binary form, is permitted only for
24
+ non-commercial purposes and must retain this notice unmodified.
25
+
26
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
27
+ IMPLIED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM,
28
+ DAMAGES, OR OTHER LIABILITY ARISING FROM, OUT OF, OR IN CONNECTION WITH THE
29
+ SOFTWARE OR THE USE OR DEALINGS IN THE SOFTWARE.
30
+
31
+ For commercial or patent licensing enquiries contact: lars@rollik.me
@@ -1,17 +1,47 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ttl-barcoder
3
- Version: 0.4.1
3
+ Version: 0.4.2
4
4
  Summary: Modular barcode generation for TTL synchronization with clean hardware separation
5
5
  Project-URL: Homepage, https://github.com/murineshiftwork/ttl-barcoder
6
6
  Project-URL: Documentation, https://murineshiftwork.github.io/ttl-barcoder/
7
7
  Project-URL: Issue Tracker, https://github.com/murineshiftwork/ttl-barcoder/issues
8
- Author-email: "Lars B. Rollik" <L.B.Rollik@protonmail.com>
9
- License: BSD-3-Clause
8
+ Author-email: "Lars B. Rollik" <lars@rollik.me>
9
+ License: Copyright (c) 2024-present Lars B. Rollik. All rights reserved.
10
+
11
+ Permission is granted, free of charge, to use, copy, modify, and distribute
12
+ this software and associated documentation files (the "Software") for
13
+ non-commercial research or academic purposes only, subject to the following
14
+ conditions:
15
+
16
+ 1. This copyright notice and permission notice must be included in all copies
17
+ or substantial portions of the Software.
18
+
19
+ 2. Any publication, presentation, or product that uses or builds upon the
20
+ Software must give clear attribution to the original work and its authors.
21
+
22
+ 3. Commercial use is prohibited without a separate written commercial licence
23
+ agreement with the copyright holder. Commercial use means incorporation of
24
+ the Software into anything for which fees or other compensation are charged
25
+ or received, including commercial products and commercial services.
26
+
27
+ 4. No patent licence, express or implied, is granted under these terms. Any
28
+ use that would require a patent licence from the copyright holder requires
29
+ a separate written agreement.
30
+
31
+ 5. Redistribution, in source or binary form, is permitted only for
32
+ non-commercial purposes and must retain this notice unmodified.
33
+
34
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
35
+ IMPLIED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM,
36
+ DAMAGES, OR OTHER LIABILITY ARISING FROM, OUT OF, OR IN CONNECTION WITH THE
37
+ SOFTWARE OR THE USE OR DEALINGS IN THE SOFTWARE.
38
+
39
+ For commercial or patent licensing enquiries contact: lars@rollik.me
10
40
  License-File: LICENSE
11
41
  Keywords: barcode,bpod,daq,gpio,neuroscience,pigpio,raspberry-pi,synchronization,ttl
12
42
  Classifier: Development Status :: 4 - Beta
13
43
  Classifier: Intended Audience :: Science/Research
14
- Classifier: License :: OSI Approved :: BSD License
44
+ Classifier: License :: Free for non-commercial use
15
45
  Classifier: Operating System :: OS Independent
16
46
  Classifier: Programming Language :: Python :: 3
17
47
  Classifier: Programming Language :: Python :: 3.10
@@ -34,6 +64,7 @@ Requires-Dist: pytest-cov; extra == 'dev'
34
64
  Requires-Dist: ruff; extra == 'dev'
35
65
  Provides-Extra: docs
36
66
  Requires-Dist: mkdocs-material; extra == 'docs'
67
+ Requires-Dist: mkdocstrings[python]; extra == 'docs'
37
68
  Provides-Extra: pigpio
38
69
  Requires-Dist: pigpio>=1.78; extra == 'pigpio'
39
70
  Description-Content-Type: text/markdown
@@ -43,6 +74,8 @@ Description-Content-Type: text/markdown
43
74
  [![PyPI](https://img.shields.io/pypi/v/ttl-barcoder.svg)](https://pypi.org/project/ttl-barcoder)
44
75
 
45
76
  Generate and decode binary barcodes over TTL signals to synchronize multiple data acquisition systems.
77
+
78
+ **[→ Full documentation](https://murineshiftwork.github.io/ttl-barcoder)**
46
79
  Barcodes encode a timestamp or random value as a sequence of timed HIGH/LOW pulses, transmittable over any digital output.
47
80
 
48
81
 
@@ -3,6 +3,8 @@
3
3
  [![PyPI](https://img.shields.io/pypi/v/ttl-barcoder.svg)](https://pypi.org/project/ttl-barcoder)
4
4
 
5
5
  Generate and decode binary barcodes over TTL signals to synchronize multiple data acquisition systems.
6
+
7
+ **[→ Full documentation](https://murineshiftwork.github.io/ttl-barcoder)**
6
8
  Barcodes encode a timestamp or random value as a sequence of timed HIGH/LOW pulses, transmittable over any digital output.
7
9
 
8
10
 
@@ -0,0 +1 @@
1
+ 0.4.2
@@ -6,11 +6,11 @@ build-backend = "hatchling.build"
6
6
  name = "ttl-barcoder"
7
7
  dynamic = ["version"]
8
8
  authors = [
9
- { name = "Lars B. Rollik", email = "L.B.Rollik@protonmail.com" }
9
+ { name = "Lars B. Rollik", email = "lars@rollik.me" }
10
10
  ]
11
11
  description = "Modular barcode generation for TTL synchronization with clean hardware separation"
12
12
  readme = "README.md"
13
- license = {text = "BSD-3-Clause"}
13
+ license = { file = "LICENSE" }
14
14
  requires-python = ">=3.10"
15
15
  keywords = [
16
16
  "ttl", "barcode", "synchronization", "daq",
@@ -19,7 +19,7 @@ keywords = [
19
19
  classifiers = [
20
20
  "Development Status :: 4 - Beta",
21
21
  "Intended Audience :: Science/Research",
22
- "License :: OSI Approved :: BSD License",
22
+ "License :: Free for non-commercial use",
23
23
  "Operating System :: OS Independent",
24
24
  "Programming Language :: Python :: 3",
25
25
  "Programming Language :: Python :: 3.10",
@@ -47,6 +47,7 @@ dev = [
47
47
  ]
48
48
  docs = [
49
49
  "mkdocs-material",
50
+ "mkdocstrings[python]",
50
51
  ]
51
52
 
52
53
  [project.urls]
@@ -78,7 +79,7 @@ include = ["/src/ttl_barcoder", "/tests", "/examples", "/README.md", "/LICENSE",
78
79
  [tool.commitizen]
79
80
  name = "cz_conventional_commits"
80
81
  version_provider = "commitizen"
81
- version = "0.4.1"
82
+ version = "0.4.2"
82
83
  tag_format = "v$version"
83
84
  update_changelog_on_bump = false
84
85
  version_files = ["VERSION"]
@@ -11,7 +11,11 @@ from ttl_barcoder.core.generator import (
11
11
 
12
12
 
13
13
  class BarcodeTTL:
14
- """Main interface for TTL barcode generation and decoding."""
14
+ """Main interface for TTL barcode generation and decoding.
15
+
16
+ Constructs and owns a generator, encoder, and decoder whose parameters
17
+ are all derived from a single BarcodeConfig so they stay in sync.
18
+ """
15
19
 
16
20
  def __init__(self, config: BarcodeConfig | None = None) -> None:
17
21
  self.config = config or BarcodeConfig.default()
@@ -60,6 +64,11 @@ class BarcodeTTL:
60
64
  interval_s: float = 5.0,
61
65
  start_timestamp: float | None = None,
62
66
  ) -> list[list[tuple[bool, float]]]:
67
+ """Return timing sequences for multiple barcodes spaced interval_s apart.
68
+
69
+ For timestamp TTL the barcodes encode evenly spaced future times;
70
+ for random TTL each barcode is independently random.
71
+ """
63
72
  if self.config.ttl_type == TTLType.timestamp:
64
73
  assert isinstance(self.generator, TimestampGenerator)
65
74
  barcodes = self.generator.generate_sequence(
@@ -90,10 +99,12 @@ class BarcodeTTL:
90
99
 
91
100
  @classmethod
92
101
  def default_config(cls) -> BarcodeConfig:
102
+ """Return the default BarcodeConfig instance."""
93
103
  return BarcodeConfig.default()
94
104
 
95
105
  @property
96
106
  def info(self) -> dict:
107
+ """Return a summary dict covering config, generator, and encoder parameters."""
97
108
  return {
98
109
  "config": self.config.info(),
99
110
  "generator": self.generator.info,
@@ -2,7 +2,11 @@ import numpy as np
2
2
 
3
3
 
4
4
  class BarcodeDecoder:
5
- """Decode edge timestamps back to barcode values."""
5
+ """Decode edge timestamps back to barcode values.
6
+
7
+ Must be constructed with parameters that match the encoder that produced
8
+ the signal. Use BarcodeConfig to keep encoder and decoder in sync.
9
+ """
6
10
 
7
11
  def __init__(
8
12
  self,
@@ -44,7 +48,7 @@ class BarcodeDecoder:
44
48
  return (start_time, barcode_value)
45
49
 
46
50
  def _validate_init_pattern(self, rel_times_ms: list[float]) -> bool:
47
- # Require 1 init-duration gap (not 2): BNC idle-LOW + old encoder starting LOW
51
+ # Require >=1 init-duration gap (not 2): BNC idle-LOW + old encoder starting LOW
48
52
  # leaves only 1 detectable gap. HIGH-LOW-HIGH encoder fix gives 2; requiring 1
49
53
  # handles both encoder versions without breaking the fixed path.
50
54
  if len(rel_times_ms) < 4:
@@ -58,6 +62,7 @@ class BarcodeDecoder:
58
62
  def _decode_bits(
59
63
  self, data_times: list[float], data_levels: list[bool]
60
64
  ) -> list[int]:
65
+ """Sample each bit by majority level at the mid-point of its time slot."""
61
66
  bits = []
62
67
  current_level = False
63
68
  edge_idx = 0
@@ -17,6 +17,11 @@ class TimingEncoder:
17
17
  self.init_sequence_ms = 3 * init_duration_ms
18
18
 
19
19
  def encode_timing_sequence(self, bits: list[bool]) -> list[TimingSegment]:
20
+ """Encode bits into a full timing sequence including preamble and trailer.
21
+
22
+ The preamble is HIGH-LOW-HIGH so the first rising edge is always
23
+ detectable even when the output line idles LOW between trials.
24
+ """
20
25
  sequence = []
21
26
 
22
27
  # Start initialization: HIGH-LOW-HIGH
@@ -40,14 +45,17 @@ class TimingEncoder:
40
45
  return sequence
41
46
 
42
47
  def encode_state_durations(self, bits: list[bool]) -> list[float]:
48
+ """Return only the duration_ms values from the timing sequence (no levels)."""
43
49
  return [seg.duration_ms for seg in self.encode_timing_sequence(bits)]
44
50
 
45
51
  def encode_level_durations(self, bits: list[bool]) -> list[tuple[bool, float]]:
52
+ """Return (level, duration_ms) pairs suitable for hardware drivers."""
46
53
  return [
47
54
  (seg.level, seg.duration_ms) for seg in self.encode_timing_sequence(bits)
48
55
  ]
49
56
 
50
57
  def get_total_duration(self, num_bits: int) -> float:
58
+ """Return total transmission duration in milliseconds for a given bit count."""
51
59
  return 2 * self.init_sequence_ms + num_bits * self.bit_duration_ms
52
60
 
53
61
  @property
@@ -59,7 +59,7 @@ class TimestampGenerator(TTLGenerator):
59
59
  interval_s: float = 5.0,
60
60
  start_timestamp: float | None = None,
61
61
  ) -> list[int]:
62
- """Generate a sequence of barcodes at fixed time intervals."""
62
+ """Generate count barcodes spaced interval_s seconds apart."""
63
63
  if start_timestamp is None:
64
64
  start_timestamp = time.time()
65
65
  return [self.generate(start_timestamp + i * interval_s) for i in range(count)]
@@ -67,7 +67,11 @@ class TimestampGenerator(TTLGenerator):
67
67
  def recover_timestamp(
68
68
  self, barcode_value: int, reference_time: float | None = None
69
69
  ) -> float:
70
- """Recover timestamp from barcode value, resolving wraparound."""
70
+ """Recover Unix timestamp from a barcode value, resolving modular wraparound.
71
+
72
+ Checks the previous, current, and next bit-width windows relative to
73
+ reference_time and returns the candidate closest to the reference.
74
+ """
71
75
  if reference_time is None:
72
76
  reference_time = time.time()
73
77
  ref_units = int(reference_time * self._units_per_second)
@@ -45,6 +45,7 @@ class BpodBarcodeSender:
45
45
  first_state_name: str = BARCODE_FIRST_STATE_NAME,
46
46
  last_state_name: str = "exit",
47
47
  ):
48
+ """Inject barcode states into sma; delegates to inject_barcode_states."""
48
49
  return inject_barcode_states(
49
50
  sma, timing_sequence, bnc_channel, first_state_name, last_state_name
50
51
  )
@@ -48,6 +48,7 @@ class PigpioConnection:
48
48
  self.sender = PigpioBarcodeSender(pin)
49
49
 
50
50
  def connect(self) -> bool:
51
+ """Connect to the pigpio daemon and configure the output pin."""
51
52
  try:
52
53
  self.pi = pigpio.pi(self.host, self.port)
53
54
  if not self.pi.connected:
@@ -86,6 +87,7 @@ class PigpioConnection:
86
87
  return False
87
88
 
88
89
  def disconnect(self):
90
+ """Stop any active wave and close the connection to the pigpio daemon."""
89
91
  if self.pi is not None:
90
92
  try:
91
93
  self.pi.wave_tx_stop()
@@ -1,4 +1,4 @@
1
- """Tests for BarcodeTTL the main public interface."""
1
+ """Tests for BarcodeTTL: the main public interface."""
2
2
 
3
3
  from __future__ import annotations
4
4
 
@@ -1,4 +1,4 @@
1
- """Tests for Bpod barcode injection no pybpod installation required."""
1
+ """Tests for Bpod barcode injection: no pybpod installation required."""
2
2
 
3
3
  from __future__ import annotations
4
4
 
@@ -1,4 +1,4 @@
1
- """Tests for BarcodeDecoder roundtrip and edge-case handling."""
1
+ """Tests for BarcodeDecoder: roundtrip and edge-case handling."""
2
2
 
3
3
  from __future__ import annotations
4
4
 
@@ -1,4 +1,4 @@
1
- """Tests for TimingEncoder sequence structure and timing."""
1
+ """Tests for TimingEncoder: sequence structure and timing."""
2
2
 
3
3
  from __future__ import annotations
4
4
 
@@ -1,29 +0,0 @@
1
- BSD 3-Clause License
2
-
3
- Copyright (c) 2024, Lars B. Rollik
4
- All rights reserved.
5
-
6
- Redistribution and use in source and binary forms, with or without
7
- modification, are permitted provided that the following conditions are met:
8
-
9
- 1. Redistributions of source code must retain the above copyright notice, this
10
- list of conditions and the following disclaimer.
11
-
12
- 2. Redistributions in binary form must reproduce the above copyright notice,
13
- this list of conditions and the following disclaimer in the documentation
14
- and/or other materials provided with the distribution.
15
-
16
- 3. Neither the name of the copyright holder nor the names of its contributors
17
- may be used to endorse or promote products derived from this software
18
- without specific prior written permission.
19
-
20
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21
- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23
- DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24
- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25
- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26
- SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27
- CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28
- OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -1 +0,0 @@
1
- 0.4.1
File without changes