ttl-barcoder 0.4.1__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 (30) hide show
  1. ttl_barcoder-0.4.1/.gitignore +31 -0
  2. ttl_barcoder-0.4.1/CITATION.cff +11 -0
  3. ttl_barcoder-0.4.1/LICENSE +29 -0
  4. ttl_barcoder-0.4.1/PKG-INFO +167 -0
  5. ttl_barcoder-0.4.1/README.md +127 -0
  6. ttl_barcoder-0.4.1/VERSION +1 -0
  7. ttl_barcoder-0.4.1/examples/bpod_loopback.py +161 -0
  8. ttl_barcoder-0.4.1/examples/dry_simulation.py +88 -0
  9. ttl_barcoder-0.4.1/examples/pigpio_send.py +112 -0
  10. ttl_barcoder-0.4.1/pyproject.toml +124 -0
  11. ttl_barcoder-0.4.1/src/ttl_barcoder/__init__.py +34 -0
  12. ttl_barcoder-0.4.1/src/ttl_barcoder/core/__init__.py +29 -0
  13. ttl_barcoder-0.4.1/src/ttl_barcoder/core/barcode_ttl.py +104 -0
  14. ttl_barcoder-0.4.1/src/ttl_barcoder/core/config.py +138 -0
  15. ttl_barcoder-0.4.1/src/ttl_barcoder/core/decoder.py +76 -0
  16. ttl_barcoder-0.4.1/src/ttl_barcoder/core/encoder.py +59 -0
  17. ttl_barcoder-0.4.1/src/ttl_barcoder/core/generator.py +124 -0
  18. ttl_barcoder-0.4.1/src/ttl_barcoder/hardware/__init__.py +0 -0
  19. ttl_barcoder-0.4.1/src/ttl_barcoder/hardware/bpod/__init__.py +3 -0
  20. ttl_barcoder-0.4.1/src/ttl_barcoder/hardware/bpod/sender.py +50 -0
  21. ttl_barcoder-0.4.1/src/ttl_barcoder/hardware/pigpio/__init__.py +3 -0
  22. ttl_barcoder-0.4.1/src/ttl_barcoder/hardware/pigpio/sender.py +112 -0
  23. ttl_barcoder-0.4.1/src/ttl_barcoder/py.typed +0 -0
  24. ttl_barcoder-0.4.1/tests/test_barcode_ttl.py +129 -0
  25. ttl_barcoder-0.4.1/tests/test_bpod.py +99 -0
  26. ttl_barcoder-0.4.1/tests/test_config.py +132 -0
  27. ttl_barcoder-0.4.1/tests/test_decoder.py +90 -0
  28. ttl_barcoder-0.4.1/tests/test_encoder.py +82 -0
  29. ttl_barcoder-0.4.1/tests/test_generator.py +132 -0
  30. ttl_barcoder-0.4.1/tests/test_smoke.py +98 -0
@@ -0,0 +1,31 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *.so
5
+ *.egg
6
+ *.egg-info/
7
+ .eggs/
8
+ build/
9
+ dist/
10
+
11
+ # Testing
12
+ .coverage
13
+ .coverage.*
14
+ .pytest_cache/
15
+ htmlcov/
16
+ .tox/
17
+ .nox/
18
+
19
+ # Type checkers / linters
20
+ .mypy_cache/
21
+ .ruff_cache/
22
+
23
+ # Virtual environments
24
+ .venv/
25
+ venv/
26
+ env/
27
+
28
+ # IDE / OS
29
+ .idea/
30
+ .vscode/
31
+ .DS_Store
@@ -0,0 +1,11 @@
1
+ cff-version: 1.2.0
2
+ message: "If you use this software, please cite it as below."
3
+ type: software
4
+ title: "ttl-barcoder: TTL barcode generation for multi-system DAQ synchronization"
5
+ version: "0.4.0"
6
+ repository-code: https://github.com/murineshiftwork/ttl-barcoder
7
+ license: BSD-3-Clause
8
+ authors:
9
+ - family-names: Rollik
10
+ given-names: Lars B.
11
+ orcid: https://orcid.org/0000-0003-0160-6971
@@ -0,0 +1,29 @@
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.
@@ -0,0 +1,167 @@
1
+ Metadata-Version: 2.4
2
+ Name: ttl-barcoder
3
+ Version: 0.4.1
4
+ Summary: Modular barcode generation for TTL synchronization with clean hardware separation
5
+ Project-URL: Homepage, https://github.com/murineshiftwork/ttl-barcoder
6
+ Project-URL: Documentation, https://murineshiftwork.github.io/ttl-barcoder/
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
10
+ License-File: LICENSE
11
+ Keywords: barcode,bpod,daq,gpio,neuroscience,pigpio,raspberry-pi,synchronization,ttl
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Intended Audience :: Science/Research
14
+ Classifier: License :: OSI Approved :: BSD License
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Topic :: Scientific/Engineering
21
+ Classifier: Topic :: Scientific/Engineering :: Interface Engine/Protocol Translator
22
+ Classifier: Topic :: System :: Hardware :: Hardware Drivers
23
+ Requires-Python: >=3.10
24
+ Requires-Dist: numpy>=1.20
25
+ Requires-Dist: pydantic>=2.0
26
+ Provides-Extra: bpod
27
+ Requires-Dist: pybpod-api; extra == 'bpod'
28
+ Provides-Extra: dev
29
+ Requires-Dist: commitizen; extra == 'dev'
30
+ Requires-Dist: mypy; extra == 'dev'
31
+ Requires-Dist: pre-commit; extra == 'dev'
32
+ Requires-Dist: pytest; extra == 'dev'
33
+ Requires-Dist: pytest-cov; extra == 'dev'
34
+ Requires-Dist: ruff; extra == 'dev'
35
+ Provides-Extra: docs
36
+ Requires-Dist: mkdocs-material; extra == 'docs'
37
+ Provides-Extra: pigpio
38
+ Requires-Dist: pigpio>=1.78; extra == 'pigpio'
39
+ Description-Content-Type: text/markdown
40
+
41
+ # TTL Barcoder
42
+
43
+ [![PyPI](https://img.shields.io/pypi/v/ttl-barcoder.svg)](https://pypi.org/project/ttl-barcoder)
44
+
45
+ Generate and decode binary barcodes over TTL signals to synchronize multiple data acquisition systems.
46
+ Barcodes encode a timestamp or random value as a sequence of timed HIGH/LOW pulses, transmittable over any digital output.
47
+
48
+
49
+ ## Quick Start
50
+
51
+ ```python
52
+ from ttl_barcoder.core import BarcodeTTL, BarcodeConfig, TTLType, TimestampPrecision
53
+
54
+ # Timestamp barcode (default) — encodes current time at ms precision
55
+ barcoder = BarcodeTTL()
56
+ sequence = barcoder.get_sequence() # [(level: bool, duration_ms: float), ...]
57
+
58
+ # Random barcode
59
+ config = BarcodeConfig(ttl_type=TTLType.random, barcode_bits=32)
60
+ barcoder = BarcodeTTL(config)
61
+ sequence = barcoder.get_sequence()
62
+ ```
63
+
64
+ ### Bpod
65
+ ```python
66
+ from ttl_barcoder.core import BarcodeTTL
67
+ from ttl_barcoder.hardware.bpod import inject_barcode_states
68
+
69
+ barcoder = BarcodeTTL()
70
+ sequence = barcoder.get_sequence()
71
+ inject_barcode_states(sma, sequence, bnc_channel='BNC1', first_state_name='send_sync', last_state_name='next')
72
+ ```
73
+
74
+ ### Raspberry Pi GPIO
75
+ ```python
76
+ from ttl_barcoder.hardware.pigpio import send_barcode_sequence
77
+
78
+ send_barcode_sequence(barcoder.get_sequence(), pin=18)
79
+ ```
80
+
81
+
82
+ ## Installation
83
+
84
+ ```bash
85
+ pip install ttl-barcoder # core only
86
+ pip install ttl-barcoder[bpod] # + Bpod
87
+ pip install ttl-barcoder[pigpio] # + Raspberry Pi GPIO
88
+ ```
89
+
90
+
91
+ ## Configuration
92
+
93
+ `BarcodeConfig` is a Pydantic model — all fields are validated on construction.
94
+
95
+ ```python
96
+ from ttl_barcoder.core import BarcodeConfig, TTLType, TimestampPrecision
97
+
98
+ config = BarcodeConfig(
99
+ ttl_type=TTLType.timestamp, # or TTLType.random
100
+ barcode_bits=37, # 16–64 bits
101
+ timestamp_precision=TimestampPrecision.milliseconds, # s / ms / us
102
+ bit_duration_ms=35.0,
103
+ init_duration_ms=10.0,
104
+ tolerance=0.25,
105
+ )
106
+ ```
107
+
108
+ **Presets**: `default`, `high_speed`, `conservative`, `high_precision`, `random`
109
+
110
+ ```python
111
+ from ttl_barcoder.core import get_preset
112
+ config = get_preset("conservative")
113
+ ```
114
+
115
+ | Preset | Bits | Precision | Bit duration | TX duration | Coverage |
116
+ |------------------|------|-----------|--------------|-------------|----------|
117
+ | `default` | 37 | ms | 35 ms | 1355 ms | 4.4 yr |
118
+ | `high_speed` | 32 | ms | 25 ms | 848 ms | 49 days |
119
+ | `conservative` | 37 | ms | 50 ms | 1940 ms | 4.4 yr |
120
+ | `high_precision` | 42 | us | 50 ms | 2190 ms | 51 days |
121
+
122
+
123
+ ## Architecture
124
+
125
+ ```
126
+ ttl_barcoder/
127
+ ├── core/
128
+ │ ├── config.py # BarcodeConfig (Pydantic), TTLType, TimestampPrecision
129
+ │ ├── generator.py # TTLGenerator ABC → TimestampGenerator / RandomGenerator
130
+ │ ├── encoder.py # bits → (level, duration_ms) timing sequence
131
+ │ ├── decoder.py # edge timestamps → barcode value
132
+ │ └── barcode_ttl.py # BarcodeTTL — main interface combining the above
133
+ └── hardware/
134
+ ├── bpod/ # Bpod StateMachine integration
135
+ └── pigpio/ # Raspberry Pi GPIO via pigpio
136
+ ```
137
+
138
+ - The generator is selected via a factory (`create_generator(config)`) based on `TTLType`.
139
+ - `TimestampGenerator` quantizes Unix time at the configured precision
140
+ - `RandomGenerator` draws from a numpy RNG. Both share the same `encode_bits` / `max_value` interface on the `TTLGenerator` base class.
141
+
142
+
143
+ ## Examples
144
+
145
+ - `examples/dry_simulation.py` — full walkthrough, no hardware needed
146
+ - `examples/bpod_loopback.py` — Bpod StateMachine with loopback test
147
+ - `examples/pigpio_send.py` — Raspberry Pi GPIO transmission
148
+
149
+
150
+ ## Contributing
151
+
152
+ 1. Fork and create a feature branch
153
+ 2. Add tests for new functionality
154
+ 3. Run `pytest`
155
+ 4. Submit a pull request
156
+
157
+
158
+ ## Acknowledgments
159
+
160
+ - Based on barcode synchronization from University of Colorado ONE Core
161
+ - Inspired by Open Ephys protocols
162
+ - Built for the neuroscience and scientific DAQ community
163
+
164
+
165
+ ## License & sources
166
+
167
+ This software is released under the **[BSD 3-Clause License](LICENSE)**.
@@ -0,0 +1,127 @@
1
+ # TTL Barcoder
2
+
3
+ [![PyPI](https://img.shields.io/pypi/v/ttl-barcoder.svg)](https://pypi.org/project/ttl-barcoder)
4
+
5
+ Generate and decode binary barcodes over TTL signals to synchronize multiple data acquisition systems.
6
+ Barcodes encode a timestamp or random value as a sequence of timed HIGH/LOW pulses, transmittable over any digital output.
7
+
8
+
9
+ ## Quick Start
10
+
11
+ ```python
12
+ from ttl_barcoder.core import BarcodeTTL, BarcodeConfig, TTLType, TimestampPrecision
13
+
14
+ # Timestamp barcode (default) — encodes current time at ms precision
15
+ barcoder = BarcodeTTL()
16
+ sequence = barcoder.get_sequence() # [(level: bool, duration_ms: float), ...]
17
+
18
+ # Random barcode
19
+ config = BarcodeConfig(ttl_type=TTLType.random, barcode_bits=32)
20
+ barcoder = BarcodeTTL(config)
21
+ sequence = barcoder.get_sequence()
22
+ ```
23
+
24
+ ### Bpod
25
+ ```python
26
+ from ttl_barcoder.core import BarcodeTTL
27
+ from ttl_barcoder.hardware.bpod import inject_barcode_states
28
+
29
+ barcoder = BarcodeTTL()
30
+ sequence = barcoder.get_sequence()
31
+ inject_barcode_states(sma, sequence, bnc_channel='BNC1', first_state_name='send_sync', last_state_name='next')
32
+ ```
33
+
34
+ ### Raspberry Pi GPIO
35
+ ```python
36
+ from ttl_barcoder.hardware.pigpio import send_barcode_sequence
37
+
38
+ send_barcode_sequence(barcoder.get_sequence(), pin=18)
39
+ ```
40
+
41
+
42
+ ## Installation
43
+
44
+ ```bash
45
+ pip install ttl-barcoder # core only
46
+ pip install ttl-barcoder[bpod] # + Bpod
47
+ pip install ttl-barcoder[pigpio] # + Raspberry Pi GPIO
48
+ ```
49
+
50
+
51
+ ## Configuration
52
+
53
+ `BarcodeConfig` is a Pydantic model — all fields are validated on construction.
54
+
55
+ ```python
56
+ from ttl_barcoder.core import BarcodeConfig, TTLType, TimestampPrecision
57
+
58
+ config = BarcodeConfig(
59
+ ttl_type=TTLType.timestamp, # or TTLType.random
60
+ barcode_bits=37, # 16–64 bits
61
+ timestamp_precision=TimestampPrecision.milliseconds, # s / ms / us
62
+ bit_duration_ms=35.0,
63
+ init_duration_ms=10.0,
64
+ tolerance=0.25,
65
+ )
66
+ ```
67
+
68
+ **Presets**: `default`, `high_speed`, `conservative`, `high_precision`, `random`
69
+
70
+ ```python
71
+ from ttl_barcoder.core import get_preset
72
+ config = get_preset("conservative")
73
+ ```
74
+
75
+ | Preset | Bits | Precision | Bit duration | TX duration | Coverage |
76
+ |------------------|------|-----------|--------------|-------------|----------|
77
+ | `default` | 37 | ms | 35 ms | 1355 ms | 4.4 yr |
78
+ | `high_speed` | 32 | ms | 25 ms | 848 ms | 49 days |
79
+ | `conservative` | 37 | ms | 50 ms | 1940 ms | 4.4 yr |
80
+ | `high_precision` | 42 | us | 50 ms | 2190 ms | 51 days |
81
+
82
+
83
+ ## Architecture
84
+
85
+ ```
86
+ ttl_barcoder/
87
+ ├── core/
88
+ │ ├── config.py # BarcodeConfig (Pydantic), TTLType, TimestampPrecision
89
+ │ ├── generator.py # TTLGenerator ABC → TimestampGenerator / RandomGenerator
90
+ │ ├── encoder.py # bits → (level, duration_ms) timing sequence
91
+ │ ├── decoder.py # edge timestamps → barcode value
92
+ │ └── barcode_ttl.py # BarcodeTTL — main interface combining the above
93
+ └── hardware/
94
+ ├── bpod/ # Bpod StateMachine integration
95
+ └── pigpio/ # Raspberry Pi GPIO via pigpio
96
+ ```
97
+
98
+ - The generator is selected via a factory (`create_generator(config)`) based on `TTLType`.
99
+ - `TimestampGenerator` quantizes Unix time at the configured precision
100
+ - `RandomGenerator` draws from a numpy RNG. Both share the same `encode_bits` / `max_value` interface on the `TTLGenerator` base class.
101
+
102
+
103
+ ## Examples
104
+
105
+ - `examples/dry_simulation.py` — full walkthrough, no hardware needed
106
+ - `examples/bpod_loopback.py` — Bpod StateMachine with loopback test
107
+ - `examples/pigpio_send.py` — Raspberry Pi GPIO transmission
108
+
109
+
110
+ ## Contributing
111
+
112
+ 1. Fork and create a feature branch
113
+ 2. Add tests for new functionality
114
+ 3. Run `pytest`
115
+ 4. Submit a pull request
116
+
117
+
118
+ ## Acknowledgments
119
+
120
+ - Based on barcode synchronization from University of Colorado ONE Core
121
+ - Inspired by Open Ephys protocols
122
+ - Built for the neuroscience and scientific DAQ community
123
+
124
+
125
+ ## License & sources
126
+
127
+ This software is released under the **[BSD 3-Clause License](LICENSE)**.
@@ -0,0 +1 @@
1
+ 0.4.1
@@ -0,0 +1,161 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Example: Bpod loopback test
4
+
5
+ Demonstrates Bpod StateMachine integration with loopback testing
6
+ on the same device (BNC1 out -> BNC1 in).
7
+ """
8
+
9
+ from ttl_barcoder.core import BarcodeConfig, BarcodeTTL
10
+
11
+
12
+ def main():
13
+ print("TTL Barcoder - Bpod Loopback Example")
14
+ print("=" * 45)
15
+
16
+ try:
17
+ from pybpod import StateMachine
18
+
19
+ from ttl_barcoder.hardware.bpod import BpodBarcodeSender, inject_barcode_states
20
+ except ImportError as e:
21
+ print(f"Bpod not available: {e}")
22
+ print("Install with: pip install pybpod")
23
+ return
24
+
25
+ # Configuration for demo
26
+ config = BarcodeConfig(
27
+ barcode_bits=32, # Shorter for demo
28
+ bit_duration_ms=50.0, # Slower for visualization
29
+ init_duration_ms=15.0,
30
+ )
31
+
32
+ print(f"Using config: {config}")
33
+
34
+ # Create barcode system
35
+ barcoder = BarcodeTTL(config)
36
+
37
+ # Get barcode sequence
38
+ test_barcode = 12345
39
+ timing_sequence = barcoder.get_sequence(test_barcode)
40
+
41
+ print(f"\nGenerated sequence for barcode {test_barcode}:")
42
+ print(f" {len(timing_sequence)} segments")
43
+ print(f" Total duration: {config.total_duration_ms:.0f}ms")
44
+
45
+ # Create StateMachine
46
+ sma = StateMachine()
47
+
48
+ # Initial state
49
+ sma.add_state(
50
+ state_name="start",
51
+ state_timer=1.0,
52
+ state_change_conditions={"Tup": "send_barcode"},
53
+ output_actions=[],
54
+ )
55
+
56
+ # Method 1: Direct injection (recommended)
57
+ print("\nMethod 1: Direct injection")
58
+ sender = BpodBarcodeSender()
59
+ sender.inject_states(
60
+ sma=sma,
61
+ timing_sequence=timing_sequence,
62
+ bnc_channel="BNC1",
63
+ first_state_name="send_barcode",
64
+ last_state_name="listen_barcode",
65
+ )
66
+
67
+ # Listen for barcode return
68
+ sma.add_state(
69
+ state_name="listen_barcode",
70
+ state_timer=config.total_duration_ms / 1000.0 + 0.5, # Give extra time
71
+ state_change_conditions={"BNC1High": "detected", "Tup": "timeout"},
72
+ output_actions=[],
73
+ )
74
+
75
+ # Detection states
76
+ sma.add_state(
77
+ state_name="detected",
78
+ state_timer=0.1,
79
+ state_change_conditions={"Tup": "success"},
80
+ output_actions=[("LED", 255)], # Success indicator
81
+ )
82
+
83
+ sma.add_state(
84
+ state_name="timeout",
85
+ state_timer=0.1,
86
+ state_change_conditions={"Tup": "exit"},
87
+ output_actions=[],
88
+ )
89
+
90
+ sma.add_state(
91
+ state_name="success",
92
+ state_timer=2.0,
93
+ state_change_conditions={"Tup": "exit"},
94
+ output_actions={"LED": 255},
95
+ )
96
+
97
+ print(f"Created StateMachine with {len(sma.state_names)} states")
98
+ print("State sequence:", " -> ".join(sma.state_names))
99
+
100
+ # Method 2: Convenience function
101
+ print("\nMethod 2: Convenience function")
102
+ sma2 = StateMachine()
103
+ sma2.add_state(
104
+ state_name="start",
105
+ state_timer=1.0,
106
+ state_change_conditions={"Tup": "barcode"},
107
+ output_actions=[],
108
+ )
109
+
110
+ inject_barcode_states(
111
+ sma=sma2,
112
+ timing_sequence=timing_sequence,
113
+ bnc_channel="BNC1",
114
+ first_state_name="barcode",
115
+ last_state_name="end",
116
+ )
117
+
118
+ sma2.add_state(
119
+ state_name="end",
120
+ state_timer=0.1,
121
+ state_change_conditions={"Tup": "exit"},
122
+ output_actions=[],
123
+ )
124
+ print(f"Method 2 StateMachine: {len(sma2.state_names)} states")
125
+
126
+ # Connection and execution (commented for safety)
127
+ print("\nTo run on actual Bpod device:")
128
+ print("1. Connect Bpod at /dev/ttyACM0")
129
+ print("2. Wire BNC1 output to BNC1 input (loopback)")
130
+ print("3. Uncomment execution code below")
131
+
132
+ """
133
+ # Uncomment to run on actual device
134
+ class BpodConnection:
135
+ def __init__(self, device_path):
136
+ self.bpod = BpodBase(device_path)
137
+
138
+ def __enter__(self):
139
+ return self
140
+
141
+ def __exit__(self, *_):
142
+ self.bpod.close()
143
+
144
+ def run(self, sma):
145
+ self.bpod.send_state_machine(sma)
146
+ self.bpod.run_state_machine(sma)
147
+
148
+ try:
149
+ with BpodConnection("/dev/ttyACM0") as bpod:
150
+ print("Connected to Bpod, running state machine...")
151
+ bpod.run(sma)
152
+ print("StateMachine completed successfully!")
153
+ except Exception as e:
154
+ print(f"Bpod execution failed: {e}")
155
+ """
156
+
157
+ print("\nBpod loopback example completed!")
158
+
159
+
160
+ if __name__ == "__main__":
161
+ main()
@@ -0,0 +1,88 @@
1
+ from ttl_barcoder.core import BarcodeConfig, BarcodeTTL, get_preset
2
+
3
+
4
+ def main():
5
+ print("TTL Barcoder - Dry Simulation Example")
6
+ print("=" * 45)
7
+
8
+ # 1. Basic configuration
9
+ print("\n1. Basic Configuration:")
10
+ config = BarcodeConfig.default()
11
+ print(f"Default config: {config}")
12
+ print(f"Config info: {config.info()}")
13
+
14
+ # 2. Create BarcodeTTL instance
15
+ barcoder = BarcodeTTL(config)
16
+ print(f"\nBarcoder: {barcoder}")
17
+
18
+ # 3. One-liner sequence generation
19
+ print("\n2. One-liner Sequence Generation:")
20
+ sequence = barcoder.get_sequence() # Current timestamp
21
+ print(f"Generated sequence: {len(sequence)} segments")
22
+
23
+ # Show first few segments
24
+ print("First 5 segments:")
25
+ for i, (level, duration) in enumerate(sequence[:5]):
26
+ level_str = "HIGH" if level else "LOW"
27
+ print(f" {i}: {level_str} for {duration:.1f}ms")
28
+
29
+ # 4. Specific barcode
30
+ print("\n3. Specific Barcode:")
31
+ specific_sequence = barcoder.get_sequence(12345)
32
+ print(f"Barcode 12345 sequence: {len(specific_sequence)} segments")
33
+
34
+ # 5. Multiple sequences
35
+ print("\n4. Multiple Sequences:")
36
+ multi_sequences = barcoder.get_multiple_sequences(count=3, interval_s=1.0)
37
+ print(f"Generated {len(multi_sequences)} sequences")
38
+
39
+ # 6. Test different configurations
40
+ print("\n5. Configuration Presets:")
41
+ for preset_name in ["high_speed", "conservative", "high_precision"]:
42
+ preset_config = get_preset(preset_name)
43
+ preset_barcoder = BarcodeTTL(preset_config)
44
+ preset_sequence = preset_barcoder.get_sequence()
45
+
46
+ print(
47
+ f"{preset_name:15s}: {len(preset_sequence)} segments, "
48
+ f"{preset_config.total_duration_ms:.0f}ms total"
49
+ )
50
+
51
+ # 7. Simulate decode test
52
+ print("\n6. Decode Simulation:")
53
+ # Simulate perfect edge detection
54
+ test_sequence = barcoder.get_sequence(99999)
55
+ simulated_edges = simulate_perfect_edges(test_sequence)
56
+
57
+ decoded = barcoder.decode_edges(*simulated_edges)
58
+ if decoded:
59
+ timestamp, barcode_value = decoded
60
+ print(f"Simulated decode successful: barcode = {barcode_value}")
61
+ else:
62
+ print("Simulated decode failed")
63
+
64
+ print("\nDry simulation completed!")
65
+
66
+
67
+ def simulate_perfect_edges(timing_sequence):
68
+ """Convert timing sequence to perfect edge timestamps for testing."""
69
+ edge_times = []
70
+ edge_levels = []
71
+
72
+ current_time = 0.0
73
+ current_level = False # Start LOW
74
+
75
+ for target_level, duration_ms in timing_sequence:
76
+ if target_level != current_level:
77
+ # Level change - record edge
78
+ edge_times.append(current_time)
79
+ edge_levels.append(target_level)
80
+ current_level = target_level
81
+
82
+ current_time += duration_ms / 1000.0 # Convert to seconds
83
+
84
+ return edge_times, edge_levels
85
+
86
+
87
+ if __name__ == "__main__":
88
+ main()