ezo-driver 0.6.0__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.
- ezo_driver-0.6.0/LICENSE +22 -0
- ezo_driver-0.6.0/MANIFEST.in +7 -0
- ezo_driver-0.6.0/PKG-INFO +127 -0
- ezo_driver-0.6.0/README.md +257 -0
- ezo_driver-0.6.0/bindings/python/README.md +106 -0
- ezo_driver-0.6.0/bindings/python/build_ffi.py +54 -0
- ezo_driver-0.6.0/bindings/python/cdef/ezo_api.h +984 -0
- ezo_driver-0.6.0/bindings/python/cdef/ezo_fakes.h +46 -0
- ezo_driver-0.6.0/bindings/python/src/ezo_driver/__init__.py +47 -0
- ezo_driver-0.6.0/bindings/python/src/ezo_driver/_call.py +450 -0
- ezo_driver-0.6.0/bindings/python/src/ezo_driver/_ffi.py +5 -0
- ezo_driver-0.6.0/bindings/python/src/ezo_driver/_support.py +313 -0
- ezo_driver-0.6.0/bindings/python/src/ezo_driver/base.py +32 -0
- ezo_driver-0.6.0/bindings/python/src/ezo_driver/calibration_transfer.py +129 -0
- ezo_driver-0.6.0/bindings/python/src/ezo_driver/control.py +311 -0
- ezo_driver-0.6.0/bindings/python/src/ezo_driver/do.py +237 -0
- ezo_driver-0.6.0/bindings/python/src/ezo_driver/ec.py +237 -0
- ezo_driver-0.6.0/bindings/python/src/ezo_driver/enums.py +193 -0
- ezo_driver-0.6.0/bindings/python/src/ezo_driver/errors.py +37 -0
- ezo_driver-0.6.0/bindings/python/src/ezo_driver/hum.py +121 -0
- ezo_driver-0.6.0/bindings/python/src/ezo_driver/i2c.py +40 -0
- ezo_driver-0.6.0/bindings/python/src/ezo_driver/orp.py +121 -0
- ezo_driver-0.6.0/bindings/python/src/ezo_driver/parse.py +108 -0
- ezo_driver-0.6.0/bindings/python/src/ezo_driver/ph.py +193 -0
- ezo_driver-0.6.0/bindings/python/src/ezo_driver/product.py +54 -0
- ezo_driver-0.6.0/bindings/python/src/ezo_driver/rtd.py +244 -0
- ezo_driver-0.6.0/bindings/python/src/ezo_driver/schema.py +55 -0
- ezo_driver-0.6.0/bindings/python/src/ezo_driver/types.py +292 -0
- ezo_driver-0.6.0/bindings/python/src/ezo_driver/uart.py +52 -0
- ezo_driver-0.6.0/bindings/python/src/ezo_driver.egg-info/PKG-INFO +127 -0
- ezo_driver-0.6.0/bindings/python/src/ezo_driver.egg-info/SOURCES.txt +103 -0
- ezo_driver-0.6.0/bindings/python/src/ezo_driver.egg-info/dependency_links.txt +1 -0
- ezo_driver-0.6.0/bindings/python/src/ezo_driver.egg-info/requires.txt +5 -0
- ezo_driver-0.6.0/bindings/python/src/ezo_driver.egg-info/top_level.txt +1 -0
- ezo_driver-0.6.0/bindings/python/tests/__init__.py +2 -0
- ezo_driver-0.6.0/bindings/python/tests/_fakes.py +82 -0
- ezo_driver-0.6.0/bindings/python/tests/_support.py +253 -0
- ezo_driver-0.6.0/bindings/python/tests/test_control_and_calibration.py +103 -0
- ezo_driver-0.6.0/bindings/python/tests/test_products.py +180 -0
- ezo_driver-0.6.0/bindings/python/tests/test_public_api.py +36 -0
- ezo_driver-0.6.0/bindings/python/tests/test_shared_and_transport.py +143 -0
- ezo_driver-0.6.0/platform/linux/ezo_i2c_linux_i2c.c +81 -0
- ezo_driver-0.6.0/platform/linux/ezo_linux_device.c +216 -0
- ezo_driver-0.6.0/platform/linux/ezo_uart_posix_serial.c +267 -0
- ezo_driver-0.6.0/pyproject.toml +45 -0
- ezo_driver-0.6.0/setup.cfg +7 -0
- ezo_driver-0.6.0/setup.py +8 -0
- ezo_driver-0.6.0/src/ezo.c +52 -0
- ezo_driver-0.6.0/src/ezo.h +42 -0
- ezo_driver-0.6.0/src/ezo_calibration_transfer.c +321 -0
- ezo_driver-0.6.0/src/ezo_calibration_transfer.h +97 -0
- ezo_driver-0.6.0/src/ezo_common.c +243 -0
- ezo_driver-0.6.0/src/ezo_common.h +24 -0
- ezo_driver-0.6.0/src/ezo_control.c +862 -0
- ezo_driver-0.6.0/src/ezo_control.h +262 -0
- ezo_driver-0.6.0/src/ezo_do.c +947 -0
- ezo_driver-0.6.0/src/ezo_do.h +253 -0
- ezo_driver-0.6.0/src/ezo_ec.c +827 -0
- ezo_driver-0.6.0/src/ezo_ec.h +256 -0
- ezo_driver-0.6.0/src/ezo_hum.c +477 -0
- ezo_driver-0.6.0/src/ezo_hum.h +135 -0
- ezo_driver-0.6.0/src/ezo_i2c.c +344 -0
- ezo_driver-0.6.0/src/ezo_i2c.h +87 -0
- ezo_driver-0.6.0/src/ezo_i2c_arduino_wire.h +19 -0
- ezo_driver-0.6.0/src/ezo_i2c_linux_i2c.h +21 -0
- ezo_driver-0.6.0/src/ezo_linux_device.h +49 -0
- ezo_driver-0.6.0/src/ezo_orp.c +396 -0
- ezo_driver-0.6.0/src/ezo_orp.h +126 -0
- ezo_driver-0.6.0/src/ezo_parse.c +329 -0
- ezo_driver-0.6.0/src/ezo_parse.h +77 -0
- ezo_driver-0.6.0/src/ezo_ph.c +681 -0
- ezo_driver-0.6.0/src/ezo_ph.h +205 -0
- ezo_driver-0.6.0/src/ezo_product.c +526 -0
- ezo_driver-0.6.0/src/ezo_product.h +141 -0
- ezo_driver-0.6.0/src/ezo_rtd.c +803 -0
- ezo_driver-0.6.0/src/ezo_rtd.h +238 -0
- ezo_driver-0.6.0/src/ezo_schema.c +175 -0
- ezo_driver-0.6.0/src/ezo_schema.h +78 -0
- ezo_driver-0.6.0/src/ezo_uart.c +347 -0
- ezo_driver-0.6.0/src/ezo_uart.h +94 -0
- ezo_driver-0.6.0/src/ezo_uart_arduino_stream.h +22 -0
- ezo_driver-0.6.0/src/ezo_uart_posix_serial.h +45 -0
- ezo_driver-0.6.0/tests/fakes/ezo_fake_i2c_transport.c +105 -0
- ezo_driver-0.6.0/tests/fakes/ezo_fake_i2c_transport.h +38 -0
- ezo_driver-0.6.0/tests/fakes/ezo_fake_uart_transport.c +178 -0
- ezo_driver-0.6.0/tests/fakes/ezo_fake_uart_transport.h +44 -0
ezo_driver-0.6.0/LICENSE
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2019 Atlas Scientific
|
|
4
|
+
Copyright (c) 2026 Cameron K. Brooks
|
|
5
|
+
|
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
8
|
+
in the Software without restriction, including without limitation the rights
|
|
9
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
10
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
11
|
+
furnished to do so, subject to the following conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice shall be included in all
|
|
14
|
+
copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
18
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
19
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
20
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
21
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
22
|
+
SOFTWARE.
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
include bindings/python/README.md
|
|
2
|
+
include bindings/python/build_ffi.py
|
|
3
|
+
recursive-include bindings/python/cdef *.h
|
|
4
|
+
recursive-include bindings/python/tests *.py
|
|
5
|
+
recursive-include src *.c *.h
|
|
6
|
+
recursive-include platform/linux *.c *.h
|
|
7
|
+
recursive-include tests/fakes *.c *.h
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: ezo-driver
|
|
3
|
+
Version: 0.6.0
|
|
4
|
+
Summary: Linux Python bindings for ezo-driver
|
|
5
|
+
Author: ezo-driver maintainers
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/feastorg/ezo-driver
|
|
8
|
+
Project-URL: Issues, https://github.com/feastorg/ezo-driver/issues
|
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
|
10
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
11
|
+
Classifier: Programming Language :: C
|
|
12
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
13
|
+
Requires-Python: >=3.9
|
|
14
|
+
Description-Content-Type: text/markdown
|
|
15
|
+
License-File: LICENSE
|
|
16
|
+
Requires-Dist: cffi>=1.16
|
|
17
|
+
Provides-Extra: test
|
|
18
|
+
Requires-Dist: pytest>=7; extra == "test"
|
|
19
|
+
Requires-Dist: setuptools; extra == "test"
|
|
20
|
+
Dynamic: license-file
|
|
21
|
+
|
|
22
|
+
# `ezo-driver` Python bindings
|
|
23
|
+
|
|
24
|
+
Linux-only Python bindings for the canonical `ezo-driver` C library.
|
|
25
|
+
|
|
26
|
+
## Support statement
|
|
27
|
+
|
|
28
|
+
- Supported host platform: Linux
|
|
29
|
+
- Supported transports: Linux I2C and POSIX UART
|
|
30
|
+
- Supported Python install mode: `pip install ezo-driver` from PyPI, with wheels for x86_64 and aarch64 Linux on Python 3.9+; other platforms build from the sdist or the repo checkout
|
|
31
|
+
- Public package name: `ezo-driver`
|
|
32
|
+
- Public import package: `ezo_driver`
|
|
33
|
+
|
|
34
|
+
## Install
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
python -m pip install ezo-driver
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
PyPI carries `cp39-abi3` manylinux wheels for x86_64 and aarch64 Linux, so any CPython 3.9 or newer installs one without a compiler, a 64-bit Raspberry Pi included. On other platforms pip builds from the sdist, which needs a C compiler and the Python headers.
|
|
41
|
+
|
|
42
|
+
From the repo root:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
python -m pip install .
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
For development, install it editable with the test dependencies:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
python -m pip install -e ".[test]"
|
|
52
|
+
python -m pytest bindings/python/tests
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
The packaging lives at the repo root (`pyproject.toml`, `setup.py`, `setup.cfg`, `MANIFEST.in`) so the sdist carries the C sources from `src/` and `platform/linux/` and a wheel can be built from it. `setup.cfg` tags the wheel `cp39-abi3`: cffi builds `ezo_driver._native` against the limited C API, so one wheel per architecture covers every supported Python. The release workflow builds the wheels with cibuildwheel (`[tool.cibuildwheel]` in `pyproject.toml`) and publishes them to PyPI.
|
|
56
|
+
|
|
57
|
+
The shipped `ezo_driver._native` module holds the C core and the Linux transports only. The tests drive it through the fake transports from `tests/fakes/`, which `bindings/python/tests/_fakes.py` compiles into a separate test-only cffi module in a temporary directory each session; this needs a C compiler and the `test` extra. The C sources are found in the checkout that holds the tests; when the tests run from a copy elsewhere, point `EZO_DRIVER_SOURCE_DIR` at the checkout.
|
|
58
|
+
|
|
59
|
+
## Public modules
|
|
60
|
+
|
|
61
|
+
- `ezo_driver.errors`
|
|
62
|
+
- `ezo_driver.enums`
|
|
63
|
+
- `ezo_driver.types`
|
|
64
|
+
- `ezo_driver.base`
|
|
65
|
+
- `ezo_driver.i2c`
|
|
66
|
+
- `ezo_driver.uart`
|
|
67
|
+
- `ezo_driver.product`
|
|
68
|
+
- `ezo_driver.parse`
|
|
69
|
+
- `ezo_driver.schema`
|
|
70
|
+
- `ezo_driver.control`
|
|
71
|
+
- `ezo_driver.calibration_transfer`
|
|
72
|
+
- `ezo_driver.ph`
|
|
73
|
+
- `ezo_driver.orp`
|
|
74
|
+
- `ezo_driver.rtd`
|
|
75
|
+
- `ezo_driver.ec`
|
|
76
|
+
- `ezo_driver.do`
|
|
77
|
+
- `ezo_driver.hum`
|
|
78
|
+
|
|
79
|
+
Top-level `ezo_driver` exports only the stable transport constructors, exception hierarchy, and shared enums/types.
|
|
80
|
+
|
|
81
|
+
## I2C example
|
|
82
|
+
|
|
83
|
+
```python
|
|
84
|
+
from ezo_driver import LinuxI2CDevice, ProductId
|
|
85
|
+
from ezo_driver import control, ph
|
|
86
|
+
|
|
87
|
+
with LinuxI2CDevice(bus=1, address=0x63) as dev:
|
|
88
|
+
wait_ms = control.send_info_query_i2c(dev, ProductId.PH)
|
|
89
|
+
info = control.read_info_i2c(dev)
|
|
90
|
+
|
|
91
|
+
wait_ms = ph.send_read_i2c(dev)
|
|
92
|
+
reading = ph.read_response_i2c(dev)
|
|
93
|
+
|
|
94
|
+
print(info)
|
|
95
|
+
print(reading)
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## UART example
|
|
99
|
+
|
|
100
|
+
```python
|
|
101
|
+
from ezo_driver import LinuxUARTDevice, ProductId
|
|
102
|
+
from ezo_driver import control, ph
|
|
103
|
+
|
|
104
|
+
with LinuxUARTDevice("/dev/ttyUSB0", baud=9600, read_timeout_ms=1000) as dev:
|
|
105
|
+
wait_ms = control.send_info_query_uart(dev, ProductId.PH)
|
|
106
|
+
info = control.read_info_uart(dev)
|
|
107
|
+
|
|
108
|
+
wait_ms = ph.send_read_uart(dev)
|
|
109
|
+
reading = ph.read_response_uart(dev)
|
|
110
|
+
|
|
111
|
+
print(info)
|
|
112
|
+
print(reading)
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## Design constraints
|
|
116
|
+
|
|
117
|
+
- The Python layer stays transport-explicit. There is no unified device abstraction.
|
|
118
|
+
- The bindings mirror the C library concepts instead of exposing buffer management.
|
|
119
|
+
- Timing hints are returned as integer milliseconds.
|
|
120
|
+
- I2C device status codes and UART response kinds stay explicit values in the API.
|
|
121
|
+
|
|
122
|
+
## Non-goals
|
|
123
|
+
|
|
124
|
+
- No implicit sleeps
|
|
125
|
+
- No implicit retries
|
|
126
|
+
- No implicit reconnect/resynchronization
|
|
127
|
+
- No workflow wrapper above the canonical transport and product helpers
|
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
# EZO Driver
|
|
2
|
+
|
|
3
|
+
Cross-platform Atlas Scientific EZO driver with:
|
|
4
|
+
|
|
5
|
+
- a platform-agnostic C99 core
|
|
6
|
+
- explicit I2C and UART driver families
|
|
7
|
+
- a thin C++11 wrapper for the I2C surface
|
|
8
|
+
- Arduino `TwoWire` integration for I2C
|
|
9
|
+
- Arduino `Stream` integration for UART
|
|
10
|
+
- Linux I2C support
|
|
11
|
+
- Linux host POSIX UART support
|
|
12
|
+
- Linux Python bindings
|
|
13
|
+
- host-side tests and Arduino compile CI
|
|
14
|
+
|
|
15
|
+
## Status
|
|
16
|
+
|
|
17
|
+
Current implementation includes:
|
|
18
|
+
|
|
19
|
+
- shared `ezo.h` surface for results, timing hints, and numeric parsing
|
|
20
|
+
- product identity and metadata for the initial six documented EZO families
|
|
21
|
+
- shared query/CSV parsing, UART sequence-state helpers, and canonical output schemas
|
|
22
|
+
- shared control-plane helpers for identity, status, LED, UART response-code mode, sleep, factory reset, protocol lock, and mode switching
|
|
23
|
+
- shared calibration-transfer helpers for export/import workflows
|
|
24
|
+
- typed scalar product modules for pH, ORP, and RTD
|
|
25
|
+
- typed multi-output product modules for EC, DO, and HUM
|
|
26
|
+
- complete I2C core with text and raw response decoding
|
|
27
|
+
- complete UART core with line-based response handling
|
|
28
|
+
- Arduino integrations for both I2C and UART
|
|
29
|
+
- Linux I2C integration
|
|
30
|
+
- Linux host POSIX UART integration
|
|
31
|
+
- Linux Python bindings on PyPI as `ezo-driver`, with `cp39-abi3` wheels for x86_64 and aarch64
|
|
32
|
+
- focused Arduino and Linux examples
|
|
33
|
+
- host-side C and C++ tests plus fake transport coverage
|
|
34
|
+
- PlatformIO Arduino compile validation in CI
|
|
35
|
+
|
|
36
|
+
Current support matrix:
|
|
37
|
+
|
|
38
|
+
- I2C: C core, I2C C++ wrapper, Arduino `TwoWire`, Linux I2C adapter
|
|
39
|
+
- UART: C core, Arduino `Stream`, Linux host POSIX serial adapter
|
|
40
|
+
- Python: Linux-only bindings, `pip install ezo-driver` on Python 3.9+ with wheels for x86_64 and aarch64
|
|
41
|
+
- Product modules: full typed support for the initial six families, including shared control/admin coverage, calibration-transfer primitives, and advanced per-product helpers
|
|
42
|
+
- Product foundation: identity, metadata, timing fallback, and parse/schema utilities for the initial six documented families
|
|
43
|
+
- Shared: host-side tests and Arduino compile validation
|
|
44
|
+
|
|
45
|
+
## Start Here
|
|
46
|
+
|
|
47
|
+
- Raw transport bring-up: [`src/ezo_i2c.h`](./src/ezo_i2c.h) or [`src/ezo_uart.h`](./src/ezo_uart.h)
|
|
48
|
+
- Device identity and support metadata: [`src/ezo_control.h`](./src/ezo_control.h) plus [`src/ezo_product.h`](./src/ezo_product.h)
|
|
49
|
+
- Shared admin/protocol workflows: [`src/ezo_control.h`](./src/ezo_control.h)
|
|
50
|
+
- Calibration export/import primitives: [`src/ezo_calibration_transfer.h`](./src/ezo_calibration_transfer.h)
|
|
51
|
+
- Known-product application code: the matching typed product header in `src/`
|
|
52
|
+
|
|
53
|
+
Public guidance docs:
|
|
54
|
+
|
|
55
|
+
- [`docs/public-api-layers.md`](./docs/public-api-layers.md)
|
|
56
|
+
- [`docs/support-matrix.md`](./docs/support-matrix.md)
|
|
57
|
+
- [`docs/product-onboarding.md`](./docs/product-onboarding.md)
|
|
58
|
+
- [`docs/examples.md`](./docs/examples.md)
|
|
59
|
+
|
|
60
|
+
## Layout
|
|
61
|
+
|
|
62
|
+
- `src/`: canonical library root for public headers and Arduino-safe implementation
|
|
63
|
+
- `platform/`: host-only platform implementation code not intended for Arduino library builds
|
|
64
|
+
- `examples/linux/`: full Linux reference example tree with `raw`, `commissioning`, `typed`, and `advanced` flows for I2C and UART
|
|
65
|
+
- `examples/arduino/`: Arduino smoke, commissioning, full typed reads, broad I2C advanced workflows, and focused UART admin/routing sketches
|
|
66
|
+
- `bindings/python/`: Linux-only Python bindings package and tests; its packaging (`pyproject.toml`, `setup.py`, `setup.cfg`, `MANIFEST.in`) is at the repo root
|
|
67
|
+
- `tests/`: host-side tests and fakes
|
|
68
|
+
- `docs/`: tracked handoff docs and curated EZO product/protocol notes
|
|
69
|
+
|
|
70
|
+
## Build
|
|
71
|
+
|
|
72
|
+
Canonical host-side CMake usage is via presets:
|
|
73
|
+
|
|
74
|
+
```sh
|
|
75
|
+
cmake --preset host-linux-debug
|
|
76
|
+
cmake --build --preset host-linux-debug --parallel
|
|
77
|
+
ctest --preset host-linux-debug
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
That Linux preset is the main maintained path. It enables:
|
|
81
|
+
|
|
82
|
+
- host tests
|
|
83
|
+
- Linux I2C adapter
|
|
84
|
+
- Linux POSIX UART adapter
|
|
85
|
+
- Linux examples
|
|
86
|
+
|
|
87
|
+
For Windows development on the shared/core surface, use:
|
|
88
|
+
|
|
89
|
+
```sh
|
|
90
|
+
cmake --preset host-windows-debug
|
|
91
|
+
cmake --build --preset host-windows-debug --parallel
|
|
92
|
+
ctest --preset host-windows-debug
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
The Windows preset is intentionally limited to the shared/core host test surface. Linux-only adapters and examples are not part of the Windows development contract. The tracked Windows presets target the Visual Studio 2022 generator.
|
|
96
|
+
|
|
97
|
+
To install the public headers and static libraries for host-side consumption:
|
|
98
|
+
|
|
99
|
+
```sh
|
|
100
|
+
cmake --preset host-linux-release
|
|
101
|
+
cmake --build --preset host-linux-release --parallel
|
|
102
|
+
cmake --install build/host-linux-release --prefix <install-prefix>
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## Validation
|
|
106
|
+
|
|
107
|
+
- host CI builds and runs C and C++ tests for the shared, parse/schema, I2C, UART, and product-foundation paths
|
|
108
|
+
- host CI also runs typed product-module tests for pH, ORP, RTD, EC, DO, and HUM
|
|
109
|
+
- Linux I2C and Linux host POSIX UART adapter behavior are covered by host-side tests
|
|
110
|
+
- PlatformIO CI compile-checks the full Arduino sketch surface on `uno` and the UART/helper path on `esp32dev`
|
|
111
|
+
- Python CI builds the sdist, builds a wheel from it, checks both with `twine`, installs the wheel and runs the Linux bindings pytest suite against it from outside the source tree
|
|
112
|
+
- the release workflow builds the `cp39-abi3` wheels for x86_64 and aarch64 Linux with cibuildwheel, runs the bindings tests against each inside its manylinux container, and publishes them to PyPI through Trusted Publishing
|
|
113
|
+
- Arduino IDE validation is manual by design
|
|
114
|
+
|
|
115
|
+
## Packaging
|
|
116
|
+
|
|
117
|
+
- `library.properties`: Arduino tooling metadata for the combined library
|
|
118
|
+
- `library.json`: PlatformIO metadata for the combined library
|
|
119
|
+
|
|
120
|
+
## Examples
|
|
121
|
+
|
|
122
|
+
Start with the example chooser in [`docs/examples.md`](./docs/examples.md). That doc is the canonical matrix and first-use guide.
|
|
123
|
+
|
|
124
|
+
Short version:
|
|
125
|
+
|
|
126
|
+
- If transport is unknown, start with [`examples/linux/uart/commissioning/inspect_device.c`](./examples/linux/uart/commissioning/inspect_device.c). UART is the shipping default across the currently documented products.
|
|
127
|
+
- If transport is known but setup state is not, start with the matching readiness example:
|
|
128
|
+
[`examples/linux/i2c/commissioning/readiness_check.c`](./examples/linux/i2c/commissioning/readiness_check.c)
|
|
129
|
+
or [`examples/linux/uart/commissioning/readiness_check.c`](./examples/linux/uart/commissioning/readiness_check.c)
|
|
130
|
+
- If product and transport are already known, jump straight to the matching typed example under `examples/linux/<transport>/typed/`.
|
|
131
|
+
- If you need the bare transport contract first, start with:
|
|
132
|
+
[`examples/linux/i2c/raw/raw_command.c`](./examples/linux/i2c/raw/raw_command.c)
|
|
133
|
+
or [`examples/linux/uart/raw/raw_command.c`](./examples/linux/uart/raw/raw_command.c)
|
|
134
|
+
- If you need Arduino, use the maintained sketches under `examples/arduino/`:
|
|
135
|
+
raw smoke and commissioning inspect for both transports, full typed reads for all six products,
|
|
136
|
+
a broad I2C advanced bench layer, and focused UART admin/routing sketches.
|
|
137
|
+
|
|
138
|
+
Representative entry points:
|
|
139
|
+
|
|
140
|
+
- Linux I2C raw: [`examples/linux/i2c/raw/raw_command.c`](./examples/linux/i2c/raw/raw_command.c)
|
|
141
|
+
- Linux UART raw: [`examples/linux/uart/raw/raw_command.c`](./examples/linux/uart/raw/raw_command.c)
|
|
142
|
+
- Linux I2C commissioning: [`examples/linux/i2c/commissioning/inspect_device.c`](./examples/linux/i2c/commissioning/inspect_device.c)
|
|
143
|
+
- Linux UART commissioning: [`examples/linux/uart/commissioning/inspect_device.c`](./examples/linux/uart/commissioning/inspect_device.c)
|
|
144
|
+
- Linux I2C typed pH: [`examples/linux/i2c/typed/read_ph.c`](./examples/linux/i2c/typed/read_ph.c)
|
|
145
|
+
- Linux UART typed pH: [`examples/linux/uart/typed/read_ph.c`](./examples/linux/uart/typed/read_ph.c)
|
|
146
|
+
- Linux advanced staged pH calibration:
|
|
147
|
+
[`examples/linux/i2c/advanced/ph_calibration.c`](./examples/linux/i2c/advanced/ph_calibration.c)
|
|
148
|
+
and [`examples/linux/uart/advanced/ph_calibration.c`](./examples/linux/uart/advanced/ph_calibration.c)
|
|
149
|
+
- Linux advanced EC workflow:
|
|
150
|
+
[`examples/linux/i2c/advanced/ec_workflow.c`](./examples/linux/i2c/advanced/ec_workflow.c)
|
|
151
|
+
and [`examples/linux/uart/advanced/ec_workflow.c`](./examples/linux/uart/advanced/ec_workflow.c)
|
|
152
|
+
- Linux advanced calibration transfer:
|
|
153
|
+
[`examples/linux/i2c/advanced/calibration_transfer.c`](./examples/linux/i2c/advanced/calibration_transfer.c)
|
|
154
|
+
and [`examples/linux/uart/advanced/calibration_transfer.c`](./examples/linux/uart/advanced/calibration_transfer.c)
|
|
155
|
+
- Linux advanced shared control workflow:
|
|
156
|
+
[`examples/linux/i2c/advanced/control_workflow.c`](./examples/linux/i2c/advanced/control_workflow.c)
|
|
157
|
+
and [`examples/linux/uart/advanced/control_workflow.c`](./examples/linux/uart/advanced/control_workflow.c)
|
|
158
|
+
- Linux advanced transport switch:
|
|
159
|
+
[`examples/linux/i2c/advanced/transport_switch.c`](./examples/linux/i2c/advanced/transport_switch.c)
|
|
160
|
+
and [`examples/linux/uart/advanced/transport_switch.c`](./examples/linux/uart/advanced/transport_switch.c)
|
|
161
|
+
- Linux advanced RTD-driven EC temperature compensation:
|
|
162
|
+
[`examples/linux/i2c/advanced/ec_temp_comp_from_rtd.c`](./examples/linux/i2c/advanced/ec_temp_comp_from_rtd.c)
|
|
163
|
+
and [`examples/linux/uart/advanced/ec_temp_comp_from_rtd.c`](./examples/linux/uart/advanced/ec_temp_comp_from_rtd.c)
|
|
164
|
+
- Linux advanced EC-driven D.O. salinity compensation:
|
|
165
|
+
[`examples/linux/i2c/advanced/do_salinity_comp_from_ec.c`](./examples/linux/i2c/advanced/do_salinity_comp_from_ec.c)
|
|
166
|
+
and [`examples/linux/uart/advanced/do_salinity_comp_from_ec.c`](./examples/linux/uart/advanced/do_salinity_comp_from_ec.c)
|
|
167
|
+
- Linux advanced full D.O. compensation chain:
|
|
168
|
+
[`examples/linux/i2c/advanced/do_full_compensation_chain.c`](./examples/linux/i2c/advanced/do_full_compensation_chain.c)
|
|
169
|
+
and [`examples/linux/uart/advanced/do_full_compensation_chain.c`](./examples/linux/uart/advanced/do_full_compensation_chain.c)
|
|
170
|
+
- Arduino I2C inspect: [`examples/arduino/i2c/commissioning/inspect_device/inspect_device.ino`](./examples/arduino/i2c/commissioning/inspect_device/inspect_device.ino)
|
|
171
|
+
- Arduino UART inspect: [`examples/arduino/uart/commissioning/inspect_device/inspect_device.ino`](./examples/arduino/uart/commissioning/inspect_device/inspect_device.ino)
|
|
172
|
+
- Arduino I2C typed EC: [`examples/arduino/i2c/typed/read_ec/read_ec.ino`](./examples/arduino/i2c/typed/read_ec/read_ec.ino)
|
|
173
|
+
- Arduino UART typed RTD: [`examples/arduino/uart/typed/read_rtd/read_rtd.ino`](./examples/arduino/uart/typed/read_rtd/read_rtd.ino)
|
|
174
|
+
- Arduino I2C advanced staged pH calibration:
|
|
175
|
+
[`examples/arduino/i2c/advanced/ph_calibration/ph_calibration.ino`](./examples/arduino/i2c/advanced/ph_calibration/ph_calibration.ino)
|
|
176
|
+
- Arduino I2C advanced EC workflow:
|
|
177
|
+
[`examples/arduino/i2c/advanced/ec_workflow/ec_workflow.ino`](./examples/arduino/i2c/advanced/ec_workflow/ec_workflow.ino)
|
|
178
|
+
- Arduino I2C advanced shared control workflow:
|
|
179
|
+
[`examples/arduino/i2c/advanced/control_workflow/control_workflow.ino`](./examples/arduino/i2c/advanced/control_workflow/control_workflow.ino)
|
|
180
|
+
- Arduino UART advanced shared control workflow:
|
|
181
|
+
[`examples/arduino/uart/advanced/control_workflow/control_workflow.ino`](./examples/arduino/uart/advanced/control_workflow/control_workflow.ino)
|
|
182
|
+
- Arduino I2C advanced calibration transfer:
|
|
183
|
+
[`examples/arduino/i2c/advanced/calibration_transfer/calibration_transfer.ino`](./examples/arduino/i2c/advanced/calibration_transfer/calibration_transfer.ino)
|
|
184
|
+
- Arduino I2C advanced RTD-driven EC temperature compensation:
|
|
185
|
+
[`examples/arduino/i2c/advanced/ec_temp_comp_from_rtd/ec_temp_comp_from_rtd.ino`](./examples/arduino/i2c/advanced/ec_temp_comp_from_rtd/ec_temp_comp_from_rtd.ino)
|
|
186
|
+
- Arduino I2C advanced full D.O. compensation chain:
|
|
187
|
+
[`examples/arduino/i2c/advanced/do_full_compensation_chain/do_full_compensation_chain.ino`](./examples/arduino/i2c/advanced/do_full_compensation_chain/do_full_compensation_chain.ino)
|
|
188
|
+
- Arduino UART advanced multi-device routing:
|
|
189
|
+
[`examples/arduino/uart/advanced/multi_device_router/multi_device_router.ino`](./examples/arduino/uart/advanced/multi_device_router/multi_device_router.ino)
|
|
190
|
+
|
|
191
|
+
## Entry Points
|
|
192
|
+
|
|
193
|
+
Primary public headers:
|
|
194
|
+
|
|
195
|
+
- [`src/ezo.h`](./src/ezo.h)
|
|
196
|
+
- [`src/ezo_do.h`](./src/ezo_do.h)
|
|
197
|
+
- [`src/ezo_ec.h`](./src/ezo_ec.h)
|
|
198
|
+
- [`src/ezo_hum.h`](./src/ezo_hum.h)
|
|
199
|
+
- [`src/ezo_calibration_transfer.h`](./src/ezo_calibration_transfer.h)
|
|
200
|
+
- [`src/ezo_control.h`](./src/ezo_control.h)
|
|
201
|
+
- [`src/ezo_parse.h`](./src/ezo_parse.h)
|
|
202
|
+
- [`src/ezo_i2c.h`](./src/ezo_i2c.h)
|
|
203
|
+
- [`src/ezo_i2c.hpp`](./src/ezo_i2c.hpp)
|
|
204
|
+
- [`src/ezo_i2c_arduino_wire.h`](./src/ezo_i2c_arduino_wire.h)
|
|
205
|
+
- [`src/ezo_i2c_linux_i2c.h`](./src/ezo_i2c_linux_i2c.h)
|
|
206
|
+
- [`src/ezo_orp.h`](./src/ezo_orp.h)
|
|
207
|
+
- [`src/ezo_ph.h`](./src/ezo_ph.h)
|
|
208
|
+
- [`src/ezo_product.h`](./src/ezo_product.h)
|
|
209
|
+
- [`src/ezo_rtd.h`](./src/ezo_rtd.h)
|
|
210
|
+
- [`src/ezo_schema.h`](./src/ezo_schema.h)
|
|
211
|
+
- [`src/ezo_uart.h`](./src/ezo_uart.h)
|
|
212
|
+
- [`src/ezo_uart_posix_serial.h`](./src/ezo_uart_posix_serial.h)
|
|
213
|
+
- [`src/ezo_uart_arduino_stream.h`](./src/ezo_uart_arduino_stream.h)
|
|
214
|
+
|
|
215
|
+
Primary implementation files:
|
|
216
|
+
|
|
217
|
+
- [`src/ezo.c`](./src/ezo.c)
|
|
218
|
+
- [`src/ezo_calibration_transfer.c`](./src/ezo_calibration_transfer.c)
|
|
219
|
+
- [`src/ezo_common.c`](./src/ezo_common.c)
|
|
220
|
+
- [`src/ezo_control.c`](./src/ezo_control.c)
|
|
221
|
+
- [`src/ezo_do.c`](./src/ezo_do.c)
|
|
222
|
+
- [`src/ezo_ec.c`](./src/ezo_ec.c)
|
|
223
|
+
- [`src/ezo_hum.c`](./src/ezo_hum.c)
|
|
224
|
+
- [`src/ezo_i2c.c`](./src/ezo_i2c.c)
|
|
225
|
+
- [`src/ezo_i2c_arduino_wire.cpp`](./src/ezo_i2c_arduino_wire.cpp)
|
|
226
|
+
- [`platform/linux/ezo_i2c_linux_i2c.c`](./platform/linux/ezo_i2c_linux_i2c.c)
|
|
227
|
+
- [`src/ezo_orp.c`](./src/ezo_orp.c)
|
|
228
|
+
- [`src/ezo_ph.c`](./src/ezo_ph.c)
|
|
229
|
+
- [`src/ezo_parse.c`](./src/ezo_parse.c)
|
|
230
|
+
- [`src/ezo_product.c`](./src/ezo_product.c)
|
|
231
|
+
- [`src/ezo_rtd.c`](./src/ezo_rtd.c)
|
|
232
|
+
- [`src/ezo_schema.c`](./src/ezo_schema.c)
|
|
233
|
+
- [`src/ezo_uart.c`](./src/ezo_uart.c)
|
|
234
|
+
- [`platform/linux/ezo_uart_posix_serial.c`](./platform/linux/ezo_uart_posix_serial.c)
|
|
235
|
+
- [`src/ezo_uart_arduino_stream.cpp`](./src/ezo_uart_arduino_stream.cpp)
|
|
236
|
+
|
|
237
|
+
## Docs
|
|
238
|
+
|
|
239
|
+
- [`docs/ezo/README.md`](./docs/ezo/README.md): curated EZO product and protocol context for this repo
|
|
240
|
+
- [`docs/public-api-layers.md`](./docs/public-api-layers.md): where to start by API layer and use case
|
|
241
|
+
- [`docs/support-matrix.md`](./docs/support-matrix.md): tracked public support statement and tier policy
|
|
242
|
+
- [`docs/product-onboarding.md`](./docs/product-onboarding.md): maintainer checklist for onboarding another product family
|
|
243
|
+
- [`docs/examples.md`](./docs/examples.md): staged example chooser and full matrix
|
|
244
|
+
- [`bindings/python/README.md`](./bindings/python/README.md): canonical Linux Python bindings doc
|
|
245
|
+
- [`docs/architecture.md`](./docs/architecture.md): structure, boundaries, packaging, validation
|
|
246
|
+
- [`docs/api-contract.md`](./docs/api-contract.md): behavioral contract for the public API
|
|
247
|
+
- [`docs/canonical-library-direction.md`](./docs/canonical-library-direction.md): stable long-term direction for the canonical product-aware library
|
|
248
|
+
- [`CHANGELOG.md`](./CHANGELOG.md): tracked change history
|
|
249
|
+
|
|
250
|
+
## Scope Notes
|
|
251
|
+
|
|
252
|
+
Intentionally out of scope for the current baseline:
|
|
253
|
+
|
|
254
|
+
- async/state-machine behavior
|
|
255
|
+
- hidden reconnect or resynchronization workflows around rebooting, sleep, or mode changes
|
|
256
|
+
- hidden retries or hidden delays
|
|
257
|
+
- UART C++ wrapper
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
# `ezo-driver` Python bindings
|
|
2
|
+
|
|
3
|
+
Linux-only Python bindings for the canonical `ezo-driver` C library.
|
|
4
|
+
|
|
5
|
+
## Support statement
|
|
6
|
+
|
|
7
|
+
- Supported host platform: Linux
|
|
8
|
+
- Supported transports: Linux I2C and POSIX UART
|
|
9
|
+
- Supported Python install mode: `pip install ezo-driver` from PyPI, with wheels for x86_64 and aarch64 Linux on Python 3.9+; other platforms build from the sdist or the repo checkout
|
|
10
|
+
- Public package name: `ezo-driver`
|
|
11
|
+
- Public import package: `ezo_driver`
|
|
12
|
+
|
|
13
|
+
## Install
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
python -m pip install ezo-driver
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
PyPI carries `cp39-abi3` manylinux wheels for x86_64 and aarch64 Linux, so any CPython 3.9 or newer installs one without a compiler, a 64-bit Raspberry Pi included. On other platforms pip builds from the sdist, which needs a C compiler and the Python headers.
|
|
20
|
+
|
|
21
|
+
From the repo root:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
python -m pip install .
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
For development, install it editable with the test dependencies:
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
python -m pip install -e ".[test]"
|
|
31
|
+
python -m pytest bindings/python/tests
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
The packaging lives at the repo root (`pyproject.toml`, `setup.py`, `setup.cfg`, `MANIFEST.in`) so the sdist carries the C sources from `src/` and `platform/linux/` and a wheel can be built from it. `setup.cfg` tags the wheel `cp39-abi3`: cffi builds `ezo_driver._native` against the limited C API, so one wheel per architecture covers every supported Python. The release workflow builds the wheels with cibuildwheel (`[tool.cibuildwheel]` in `pyproject.toml`) and publishes them to PyPI.
|
|
35
|
+
|
|
36
|
+
The shipped `ezo_driver._native` module holds the C core and the Linux transports only. The tests drive it through the fake transports from `tests/fakes/`, which `bindings/python/tests/_fakes.py` compiles into a separate test-only cffi module in a temporary directory each session; this needs a C compiler and the `test` extra. The C sources are found in the checkout that holds the tests; when the tests run from a copy elsewhere, point `EZO_DRIVER_SOURCE_DIR` at the checkout.
|
|
37
|
+
|
|
38
|
+
## Public modules
|
|
39
|
+
|
|
40
|
+
- `ezo_driver.errors`
|
|
41
|
+
- `ezo_driver.enums`
|
|
42
|
+
- `ezo_driver.types`
|
|
43
|
+
- `ezo_driver.base`
|
|
44
|
+
- `ezo_driver.i2c`
|
|
45
|
+
- `ezo_driver.uart`
|
|
46
|
+
- `ezo_driver.product`
|
|
47
|
+
- `ezo_driver.parse`
|
|
48
|
+
- `ezo_driver.schema`
|
|
49
|
+
- `ezo_driver.control`
|
|
50
|
+
- `ezo_driver.calibration_transfer`
|
|
51
|
+
- `ezo_driver.ph`
|
|
52
|
+
- `ezo_driver.orp`
|
|
53
|
+
- `ezo_driver.rtd`
|
|
54
|
+
- `ezo_driver.ec`
|
|
55
|
+
- `ezo_driver.do`
|
|
56
|
+
- `ezo_driver.hum`
|
|
57
|
+
|
|
58
|
+
Top-level `ezo_driver` exports only the stable transport constructors, exception hierarchy, and shared enums/types.
|
|
59
|
+
|
|
60
|
+
## I2C example
|
|
61
|
+
|
|
62
|
+
```python
|
|
63
|
+
from ezo_driver import LinuxI2CDevice, ProductId
|
|
64
|
+
from ezo_driver import control, ph
|
|
65
|
+
|
|
66
|
+
with LinuxI2CDevice(bus=1, address=0x63) as dev:
|
|
67
|
+
wait_ms = control.send_info_query_i2c(dev, ProductId.PH)
|
|
68
|
+
info = control.read_info_i2c(dev)
|
|
69
|
+
|
|
70
|
+
wait_ms = ph.send_read_i2c(dev)
|
|
71
|
+
reading = ph.read_response_i2c(dev)
|
|
72
|
+
|
|
73
|
+
print(info)
|
|
74
|
+
print(reading)
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## UART example
|
|
78
|
+
|
|
79
|
+
```python
|
|
80
|
+
from ezo_driver import LinuxUARTDevice, ProductId
|
|
81
|
+
from ezo_driver import control, ph
|
|
82
|
+
|
|
83
|
+
with LinuxUARTDevice("/dev/ttyUSB0", baud=9600, read_timeout_ms=1000) as dev:
|
|
84
|
+
wait_ms = control.send_info_query_uart(dev, ProductId.PH)
|
|
85
|
+
info = control.read_info_uart(dev)
|
|
86
|
+
|
|
87
|
+
wait_ms = ph.send_read_uart(dev)
|
|
88
|
+
reading = ph.read_response_uart(dev)
|
|
89
|
+
|
|
90
|
+
print(info)
|
|
91
|
+
print(reading)
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## Design constraints
|
|
95
|
+
|
|
96
|
+
- The Python layer stays transport-explicit. There is no unified device abstraction.
|
|
97
|
+
- The bindings mirror the C library concepts instead of exposing buffer management.
|
|
98
|
+
- Timing hints are returned as integer milliseconds.
|
|
99
|
+
- I2C device status codes and UART response kinds stay explicit values in the API.
|
|
100
|
+
|
|
101
|
+
## Non-goals
|
|
102
|
+
|
|
103
|
+
- No implicit sleeps
|
|
104
|
+
- No implicit retries
|
|
105
|
+
- No implicit reconnect/resynchronization
|
|
106
|
+
- No workflow wrapper above the canonical transport and product helpers
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
from cffi import FFI
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
THIS_DIR = Path(__file__).resolve().parent
|
|
9
|
+
REPO_ROOT = THIS_DIR.parent.parent
|
|
10
|
+
SRC_DIR = REPO_ROOT / "src"
|
|
11
|
+
LINUX_DIR = REPO_ROOT / "platform" / "linux"
|
|
12
|
+
CDEF_DIR = THIS_DIR / "cdef"
|
|
13
|
+
|
|
14
|
+
# The headers behind the cdef. The test-only fakes module (bindings/python/
|
|
15
|
+
# tests/_fakes.py) includes this ffibuilder and compiles against the same list.
|
|
16
|
+
HEADERS = [
|
|
17
|
+
"ezo.h",
|
|
18
|
+
"ezo_common.h",
|
|
19
|
+
"ezo_i2c.h",
|
|
20
|
+
"ezo_uart.h",
|
|
21
|
+
"ezo_product.h",
|
|
22
|
+
"ezo_parse.h",
|
|
23
|
+
"ezo_schema.h",
|
|
24
|
+
"ezo_control.h",
|
|
25
|
+
"ezo_calibration_transfer.h",
|
|
26
|
+
"ezo_ph.h",
|
|
27
|
+
"ezo_orp.h",
|
|
28
|
+
"ezo_rtd.h",
|
|
29
|
+
"ezo_ec.h",
|
|
30
|
+
"ezo_do.h",
|
|
31
|
+
"ezo_hum.h",
|
|
32
|
+
"ezo_linux_device.h",
|
|
33
|
+
]
|
|
34
|
+
INCLUDE_DIRS = [str(REPO_ROOT), str(SRC_DIR), str(LINUX_DIR)]
|
|
35
|
+
|
|
36
|
+
ffibuilder = FFI()
|
|
37
|
+
ffibuilder.cdef((CDEF_DIR / "ezo_api.h").read_text(encoding="ascii"))
|
|
38
|
+
|
|
39
|
+
ffibuilder.set_source(
|
|
40
|
+
"ezo_driver._native",
|
|
41
|
+
'\n'.join(f'#include "{header}"' for header in HEADERS),
|
|
42
|
+
sources=[
|
|
43
|
+
*sorted(str(path) for path in SRC_DIR.glob("*.c")),
|
|
44
|
+
str(LINUX_DIR / "ezo_i2c_linux_i2c.c"),
|
|
45
|
+
str(LINUX_DIR / "ezo_uart_posix_serial.c"),
|
|
46
|
+
str(LINUX_DIR / "ezo_linux_device.c"),
|
|
47
|
+
],
|
|
48
|
+
include_dirs=INCLUDE_DIRS,
|
|
49
|
+
define_macros=[("_GNU_SOURCE", "1")],
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
if __name__ == "__main__":
|
|
54
|
+
ffibuilder.compile(verbose=True)
|