pyadi-jif 0.1.0__py2.py3-none-any.whl → 0.1.1__py2.py3-none-any.whl
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.
- adijif/__init__.py +2 -2
- adijif/clocks/ad9523_1_bf.py +3 -3
- adijif/clocks/ad9528_bf.py +1 -1
- adijif/clocks/hmc7044_bf.py +1 -1
- adijif/clocks/ltc6952.py +2 -2
- adijif/clocks/ltc6952_bf.py +1 -1
- adijif/clocks/ltc6953.py +2 -2
- adijif/converters/__init__.py +12 -1
- adijif/converters/ad9081.py +1 -1
- adijif/converters/ad9081_dp.py +2 -0
- adijif/converters/ad9084.py +29 -7
- adijif/converters/ad9084_draw.py +20 -14
- adijif/converters/ad9084_util.py +24 -5
- adijif/converters/ad9088_dp.py +111 -0
- adijif/converters/converter.py +153 -2
- adijif/draw.py +11 -2
- adijif/fpgas/xilinx/__init__.py +4 -2
- adijif/jesd.py +3 -1
- adijif/plls/adf4030.py +6 -1
- adijif/plls/adf4382.py +0 -1
- adijif/solvers.py +5 -4
- adijif/system.py +16 -1
- adijif/tools/explorer/cli.py +36 -0
- adijif/tools/explorer/main.py +41 -0
- adijif/tools/explorer/src/pages/__init__.py +16 -0
- adijif/tools/explorer/src/pages/clockconfigurator.py +193 -0
- adijif/tools/explorer/src/pages/helpers/datapath.py +85 -0
- adijif/tools/explorer/src/pages/helpers/drawers.py +87 -0
- adijif/tools/explorer/src/pages/helpers/jesd.py +140 -0
- adijif/tools/explorer/src/pages/jesdmodeselector.py +209 -0
- adijif/tools/explorer/src/pages/systemconfigurator.py +252 -0
- adijif/tools/explorer/src/state.py +141 -0
- adijif/tools/explorer/src/utils.py +37 -0
- adijif/types.py +23 -4
- {pyadi_jif-0.1.0.dist-info → pyadi_jif-0.1.1.dist-info}/METADATA +36 -12
- {pyadi_jif-0.1.0.dist-info → pyadi_jif-0.1.1.dist-info}/RECORD +41 -30
- pyadi_jif-0.1.1.dist-info/entry_points.txt +2 -0
- adijif/d2/__init__.py +0 -26
- adijif/d2/d2lib.h +0 -81
- {pyadi_jif-0.1.0.dist-info → pyadi_jif-0.1.1.dist-info}/WHEEL +0 -0
- {pyadi_jif-0.1.0.dist-info → pyadi_jif-0.1.1.dist-info}/licenses/AUTHORS.rst +0 -0
- {pyadi_jif-0.1.0.dist-info → pyadi_jif-0.1.1.dist-info}/licenses/LICENSE +0 -0
- {pyadi_jif-0.1.0.dist-info → pyadi_jif-0.1.1.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
"""System configurator page."""
|
|
2
|
+
|
|
3
|
+
from typing import Optional
|
|
4
|
+
|
|
5
|
+
import pandas as pd
|
|
6
|
+
import streamlit as st
|
|
7
|
+
|
|
8
|
+
import adijif
|
|
9
|
+
from adijif.clocks import supported_parts as csp
|
|
10
|
+
from adijif.converters import supported_parts as xsp
|
|
11
|
+
|
|
12
|
+
# from adijif.utils import get_jesd_mode_from_params
|
|
13
|
+
from ..utils import Page
|
|
14
|
+
from .helpers.datapath import gen_datapath
|
|
15
|
+
|
|
16
|
+
# Clocks
|
|
17
|
+
options_to_skip = ["list_references_available", "d_syspulse"]
|
|
18
|
+
parts_to_ignore = ["ad9545", "ad9523_1"]
|
|
19
|
+
sp = [p for p in csp if p not in parts_to_ignore]
|
|
20
|
+
# Put HMC7044 at the front
|
|
21
|
+
sp = [p for p in sp if p != "hmc7044"]
|
|
22
|
+
sp.insert(0, "hmc7044")
|
|
23
|
+
|
|
24
|
+
# Converters
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class SystemConfigurator(Page):
|
|
28
|
+
"""System configurator tool page."""
|
|
29
|
+
|
|
30
|
+
def __init__(self, state: Optional[object]) -> None:
|
|
31
|
+
"""Initialize system configurator page.
|
|
32
|
+
|
|
33
|
+
Args:
|
|
34
|
+
state: Application state object
|
|
35
|
+
"""
|
|
36
|
+
self.state = state
|
|
37
|
+
|
|
38
|
+
def write(self) -> None:
|
|
39
|
+
"""Render the system configurator page."""
|
|
40
|
+
st.title("System Configurator")
|
|
41
|
+
|
|
42
|
+
with st.expander("System Settings", expanded=True):
|
|
43
|
+
hsx = st.selectbox(
|
|
44
|
+
label="Select a converter part",
|
|
45
|
+
options=xsp,
|
|
46
|
+
format_func=lambda x: x.upper(),
|
|
47
|
+
key="converter_part_select",
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
clock = st.selectbox(
|
|
51
|
+
label="Select a clock part",
|
|
52
|
+
options=sp,
|
|
53
|
+
format_func=lambda x: x.upper(),
|
|
54
|
+
key="clock_part_select",
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
fpga_kit = st.selectbox(
|
|
58
|
+
label="Select an FPGA development kit",
|
|
59
|
+
options=adijif.xilinx._available_dev_kit_names,
|
|
60
|
+
format_func=lambda x: x.upper(),
|
|
61
|
+
key="fpga_dev_kit_select",
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
reference_rate = st.number_input(
|
|
65
|
+
f"Reference Rate (VCXO) for {clock.upper()} (Hz)",
|
|
66
|
+
value=125000000,
|
|
67
|
+
min_value=int(100e6),
|
|
68
|
+
max_value=int(400e6),
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
sys = adijif.system(hsx.lower(), clock.lower(), "xilinx", reference_rate)
|
|
72
|
+
|
|
73
|
+
# Get Converter clocking requirements
|
|
74
|
+
sys.Debug_Solver = False
|
|
75
|
+
|
|
76
|
+
# Get FPGA clocking requirements
|
|
77
|
+
sys.fpga.setup_by_dev_kit_name(fpga_kit.lower())
|
|
78
|
+
|
|
79
|
+
converter_c, fpga_c = st.columns(2)
|
|
80
|
+
|
|
81
|
+
with converter_c:
|
|
82
|
+
# st.header("Converter Configuration")
|
|
83
|
+
with st.expander("Converter Settings", expanded=True):
|
|
84
|
+
|
|
85
|
+
# Units GHz, MHz, kHz
|
|
86
|
+
units = st.selectbox(
|
|
87
|
+
label="Select units for Converter Clock",
|
|
88
|
+
options=["Hz", "kHz", "MHz", "GHz"],
|
|
89
|
+
index=2,
|
|
90
|
+
)
|
|
91
|
+
if units == "Hz":
|
|
92
|
+
multiplier = 1
|
|
93
|
+
elif units == "kHz":
|
|
94
|
+
multiplier = 1e3
|
|
95
|
+
elif units == "MHz":
|
|
96
|
+
multiplier = 1e6
|
|
97
|
+
elif units == "GHz":
|
|
98
|
+
multiplier = 1e9
|
|
99
|
+
|
|
100
|
+
# Converter Clock
|
|
101
|
+
converter_clock = st.number_input(
|
|
102
|
+
f"Converter Clock ({units})",
|
|
103
|
+
value=1e9 / multiplier,
|
|
104
|
+
format="%f",
|
|
105
|
+
min_value=1e6 / multiplier,
|
|
106
|
+
max_value=20e9 / multiplier,
|
|
107
|
+
)
|
|
108
|
+
# sys.converter.decimation = 1
|
|
109
|
+
|
|
110
|
+
decimation = gen_datapath(sys.converter)
|
|
111
|
+
sys.converter.sample_clock = converter_clock * multiplier / decimation
|
|
112
|
+
|
|
113
|
+
# JESD modes
|
|
114
|
+
qsm = sys.converter.quick_configuration_modes
|
|
115
|
+
|
|
116
|
+
# Flatten dict for display as a list
|
|
117
|
+
qsm_flat = {}
|
|
118
|
+
for jesdclasses in qsm:
|
|
119
|
+
for mode in qsm[jesdclasses]:
|
|
120
|
+
other_settings = (
|
|
121
|
+
f" (M={sys.converter.M}, "
|
|
122
|
+
+ f"F={sys.converter.F}, K={sys.converter.K}, "
|
|
123
|
+
+ f"Np={sys.converter.Np}, CS={sys.converter.CS}, "
|
|
124
|
+
+ f"L={sys.converter.L}, S={sys.converter.S})"
|
|
125
|
+
)
|
|
126
|
+
qsm_flat[
|
|
127
|
+
f"{jesdclasses.upper()} Mode: {mode} {other_settings}"
|
|
128
|
+
] = {
|
|
129
|
+
"mode": mode,
|
|
130
|
+
"jesdclass": jesdclasses,
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
mode = st.selectbox(
|
|
134
|
+
label="Select JESD Configuration Mode",
|
|
135
|
+
options=list(qsm_flat.keys()),
|
|
136
|
+
# options=list(qsm_flat.keys()),
|
|
137
|
+
# format_func=lambda x: f"{x} : {qsm_flat[x]}",
|
|
138
|
+
)
|
|
139
|
+
sys.converter.set_quick_configuration_mode(
|
|
140
|
+
qsm_flat[mode]["mode"], qsm_flat[mode]["jesdclass"]
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
# with clock_c:
|
|
144
|
+
# st.header("Clock Configuration")
|
|
145
|
+
|
|
146
|
+
# with st.container(border=True):
|
|
147
|
+
# st.markdown(cfg["clock"])
|
|
148
|
+
|
|
149
|
+
with fpga_c:
|
|
150
|
+
with st.expander("FPGA Settings", expanded=True):
|
|
151
|
+
|
|
152
|
+
# sys.fpga.ref_clock_constraint = "Unconstrained"
|
|
153
|
+
ref_clock_constraint = st.selectbox(
|
|
154
|
+
options=adijif.xilinx._ref_clock_constraint_options,
|
|
155
|
+
label="FPGA Reference Clock Constraint",
|
|
156
|
+
index=adijif.xilinx._ref_clock_constraint_options.index(
|
|
157
|
+
"Unconstrained"
|
|
158
|
+
),
|
|
159
|
+
)
|
|
160
|
+
sys.fpga.ref_clock_constraint = ref_clock_constraint
|
|
161
|
+
|
|
162
|
+
# sys.fpga.sys_clk_select = "XCVR_QPLL0" # Use faster QPLL
|
|
163
|
+
sys_clk_select = st.multiselect(
|
|
164
|
+
options=adijif.xilinx.sys_clk_selections,
|
|
165
|
+
label="XCVR System Clock Source Selection",
|
|
166
|
+
default=adijif.xilinx.sys_clk_selections,
|
|
167
|
+
)
|
|
168
|
+
sys.fpga.sys_clk_select = sys_clk_select
|
|
169
|
+
|
|
170
|
+
# Enable all adijif.xilinx._out_clk_selections for selection by default
|
|
171
|
+
out_clk_select = st.multiselect(
|
|
172
|
+
options=adijif.xilinx._out_clk_selections,
|
|
173
|
+
label="XCVR Output Clock Selection",
|
|
174
|
+
default=adijif.xilinx._out_clk_selections,
|
|
175
|
+
)
|
|
176
|
+
sys.fpga.out_clk_select = out_clk_select
|
|
177
|
+
|
|
178
|
+
# sys.fpga.force_qpll = 1
|
|
179
|
+
force_qpll_options = ["Auto", "Force QPLL", "Force QPLL1", "Force CPLL"]
|
|
180
|
+
force_qpll_selection = st.selectbox(
|
|
181
|
+
options=force_qpll_options,
|
|
182
|
+
label="Transceiver PLL Selection",
|
|
183
|
+
index=0,
|
|
184
|
+
)
|
|
185
|
+
if force_qpll_selection == "Force QPLL":
|
|
186
|
+
sys.fpga.force_qpll = True
|
|
187
|
+
elif force_qpll_selection == "Force QPLL1":
|
|
188
|
+
sys.fpga.force_qpll1 = True
|
|
189
|
+
elif force_qpll_selection == "Force CPLL":
|
|
190
|
+
sys.fpga.force_cpll = True
|
|
191
|
+
|
|
192
|
+
with st.expander("Derived Settings", expanded=True):
|
|
193
|
+
|
|
194
|
+
# Table with lane rate and core clock
|
|
195
|
+
lane_rate = sys.converter.bit_clock
|
|
196
|
+
core_clock = (
|
|
197
|
+
sys.converter.bit_clock / 66
|
|
198
|
+
if sys.converter.jesd_class == "jesd204c"
|
|
199
|
+
else sys.converter.bit_clock / 40
|
|
200
|
+
)
|
|
201
|
+
sample_clock = sys.converter.sample_clock
|
|
202
|
+
converter_clock = sys.converter.converter_clock
|
|
203
|
+
|
|
204
|
+
# Build pandas DataFrame
|
|
205
|
+
df = pd.DataFrame(
|
|
206
|
+
{
|
|
207
|
+
"Setting": [
|
|
208
|
+
"Lane Rate (Gbps)",
|
|
209
|
+
"Needed Core Clock (MHz)",
|
|
210
|
+
"Sample Clock (MHz)",
|
|
211
|
+
"Converter Clock (MHz)",
|
|
212
|
+
],
|
|
213
|
+
"Value": [
|
|
214
|
+
f"{lane_rate/1e9:.4f}",
|
|
215
|
+
f"{core_clock/1e6:.4f}",
|
|
216
|
+
f"{sample_clock/1e6:.4f}",
|
|
217
|
+
f"{converter_clock/1e6:.4f}",
|
|
218
|
+
],
|
|
219
|
+
}
|
|
220
|
+
)
|
|
221
|
+
# Remove index
|
|
222
|
+
df.index = df["Setting"]
|
|
223
|
+
df = df.drop(columns=["Setting"])
|
|
224
|
+
st.table(df)
|
|
225
|
+
|
|
226
|
+
with st.expander("System Configuration", expanded=False):
|
|
227
|
+
try:
|
|
228
|
+
cfg = sys.solve()
|
|
229
|
+
|
|
230
|
+
st.subheader("Clock Configuration")
|
|
231
|
+
st.write(cfg["clock"])
|
|
232
|
+
|
|
233
|
+
st.subheader("Converter Configuration")
|
|
234
|
+
st.write(cfg["converter"])
|
|
235
|
+
|
|
236
|
+
st.subheader("FPGA Configuration")
|
|
237
|
+
st.write(cfg["fpga_" + sys.converter.name.upper()])
|
|
238
|
+
|
|
239
|
+
st.subheader("Converter JESD Configuration")
|
|
240
|
+
st.write(cfg["jesd_" + sys.converter.name.upper()])
|
|
241
|
+
|
|
242
|
+
diagram = sys.draw(cfg)
|
|
243
|
+
|
|
244
|
+
except Exception as e:
|
|
245
|
+
diagram = None
|
|
246
|
+
st.error(f"Error solving system configuration: {e}")
|
|
247
|
+
|
|
248
|
+
with st.expander("Diagram", expanded=False):
|
|
249
|
+
if diagram:
|
|
250
|
+
st.image(diagram, width="stretch")
|
|
251
|
+
else:
|
|
252
|
+
st.write("No diagram available.")
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
"""Session state management for Streamlit application."""
|
|
2
|
+
|
|
3
|
+
from copy import deepcopy
|
|
4
|
+
from typing import TYPE_CHECKING, Any, Callable, Dict, Optional
|
|
5
|
+
|
|
6
|
+
from streamlit.runtime import get_instance
|
|
7
|
+
from streamlit.runtime.legacy_caching.hashing import _CodeHasher
|
|
8
|
+
from streamlit.runtime.scriptrunner import get_script_run_ctx
|
|
9
|
+
|
|
10
|
+
if TYPE_CHECKING:
|
|
11
|
+
from streamlit.runtime.state.session_state import SessionState as Session
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class _SessionState:
|
|
15
|
+
"""Internal session state management class."""
|
|
16
|
+
|
|
17
|
+
def __init__(
|
|
18
|
+
self, session: "Session", hash_funcs: Optional[Dict[type, Callable[[Any], str]]]
|
|
19
|
+
) -> None:
|
|
20
|
+
"""Initialize SessionState instance."""
|
|
21
|
+
self.__dict__["_state"] = {
|
|
22
|
+
"data": {},
|
|
23
|
+
"hash": None,
|
|
24
|
+
"hasher": _CodeHasher(hash_funcs),
|
|
25
|
+
"is_rerun": False,
|
|
26
|
+
"session": session,
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
def __call__(self, **kwargs: Dict[str, Any]) -> None: # type: ignore[misc]
|
|
30
|
+
"""Initialize state data once."""
|
|
31
|
+
for item, value in kwargs.items():
|
|
32
|
+
if item not in self._state["data"]:
|
|
33
|
+
self._state["data"][item] = value
|
|
34
|
+
|
|
35
|
+
def __getitem__(self, item: str) -> Any: # noqa: ANN401
|
|
36
|
+
"""Return a saved state value, None if item is undefined."""
|
|
37
|
+
return self._state["data"].get(item, None)
|
|
38
|
+
|
|
39
|
+
def __getattr__(self, item: str) -> Any: # noqa: ANN401
|
|
40
|
+
"""Return a saved state value, None if item is undefined."""
|
|
41
|
+
return self._state["data"].get(item, None)
|
|
42
|
+
|
|
43
|
+
def __setitem__(self, item: str, value: Any) -> None: # noqa: ANN401
|
|
44
|
+
"""Set state value."""
|
|
45
|
+
self._state["data"][item] = value
|
|
46
|
+
|
|
47
|
+
def __setattr__(self, item: str, value: Any) -> None: # noqa: ANN401
|
|
48
|
+
"""Set state value."""
|
|
49
|
+
self._state["data"][item] = value
|
|
50
|
+
|
|
51
|
+
def clear(self) -> None:
|
|
52
|
+
"""Clear session state and request a rerun."""
|
|
53
|
+
self._state["data"].clear()
|
|
54
|
+
self._state["session"].request_rerun()
|
|
55
|
+
|
|
56
|
+
def sync(self) -> None:
|
|
57
|
+
"""Rerun the app with all state values up to date.
|
|
58
|
+
|
|
59
|
+
This fixes rollbacks from the beginning.
|
|
60
|
+
"""
|
|
61
|
+
# Ensure to rerun only once to avoid infinite loops
|
|
62
|
+
# caused by a constantly changing state value at each run.
|
|
63
|
+
#
|
|
64
|
+
# Example: state.value += 1
|
|
65
|
+
if self._state["is_rerun"]:
|
|
66
|
+
self._state["is_rerun"] = False
|
|
67
|
+
|
|
68
|
+
elif self._state["hash"] is not None:
|
|
69
|
+
if self._state["hash"] != self._state["hasher"].to_bytes(
|
|
70
|
+
self._state["data"], None
|
|
71
|
+
):
|
|
72
|
+
self._state["is_rerun"] = True
|
|
73
|
+
self._state["session"].request_rerun(None)
|
|
74
|
+
|
|
75
|
+
self._state["hash"] = self._state["hasher"].to_bytes(self._state["data"], None)
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def _get_session() -> Any: # noqa: ANN401
|
|
79
|
+
"""Get the current Streamlit session."""
|
|
80
|
+
runtime = get_instance()
|
|
81
|
+
session_id = get_script_run_ctx().session_id
|
|
82
|
+
session_info = runtime._session_mgr.get_session_info(session_id)
|
|
83
|
+
|
|
84
|
+
if session_info is None:
|
|
85
|
+
raise RuntimeError("Couldn't get your Streamlit Session object.")
|
|
86
|
+
|
|
87
|
+
return session_info.session
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def get_state(
|
|
91
|
+
hash_funcs: Optional[Dict[type, Callable[[Any], str]]] = None,
|
|
92
|
+
) -> _SessionState:
|
|
93
|
+
"""Get or create session state.
|
|
94
|
+
|
|
95
|
+
Args:
|
|
96
|
+
hash_funcs: Optional hash functions for state comparison
|
|
97
|
+
|
|
98
|
+
Returns:
|
|
99
|
+
Session state object
|
|
100
|
+
"""
|
|
101
|
+
session = _get_session()
|
|
102
|
+
|
|
103
|
+
if not hasattr(session, "_custom_session_state"):
|
|
104
|
+
session._custom_session_state = _SessionState(session, hash_funcs)
|
|
105
|
+
|
|
106
|
+
return session._custom_session_state
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
# Only used for separating namespace
|
|
110
|
+
# Everything can be saved at state variable as well.
|
|
111
|
+
CONFIG_DEFAULTS: Dict[str, Any] = {"slider_value": 0}
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def provide_state(
|
|
115
|
+
hash_funcs: Optional[Dict[type, Callable[[Any], str]]] = None,
|
|
116
|
+
) -> Callable[[Callable[..., Any]], Callable[..., Any]]:
|
|
117
|
+
"""Decorator to provide state to a function.
|
|
118
|
+
|
|
119
|
+
Args:
|
|
120
|
+
hash_funcs: Optional hash functions for state comparison
|
|
121
|
+
|
|
122
|
+
Returns:
|
|
123
|
+
Decorator function
|
|
124
|
+
"""
|
|
125
|
+
|
|
126
|
+
def inner(func: Callable[..., Any]) -> Callable[..., Any]: # noqa: ANN401
|
|
127
|
+
"""Inner decorator function."""
|
|
128
|
+
|
|
129
|
+
def wrapper(*args: Any, **kwargs: Any) -> Any: # noqa: ANN401
|
|
130
|
+
"""Wrapper function that injects state."""
|
|
131
|
+
state = get_state(hash_funcs=hash_funcs)
|
|
132
|
+
if state.client_config is None:
|
|
133
|
+
state.client_config = deepcopy(CONFIG_DEFAULTS)
|
|
134
|
+
|
|
135
|
+
return_value = func(*args, state=state, **kwargs) # noqa: B026
|
|
136
|
+
state.sync()
|
|
137
|
+
return return_value
|
|
138
|
+
|
|
139
|
+
return wrapper
|
|
140
|
+
|
|
141
|
+
return inner
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"""Utility functions and base classes for the explorer."""
|
|
2
|
+
|
|
3
|
+
from abc import ABC, abstractmethod
|
|
4
|
+
|
|
5
|
+
import streamlit as st
|
|
6
|
+
|
|
7
|
+
# st.set_page_config(layout="wide")
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class Page(ABC):
|
|
11
|
+
"""Base class for all page types."""
|
|
12
|
+
|
|
13
|
+
@abstractmethod
|
|
14
|
+
def write(self) -> None:
|
|
15
|
+
"""Render the page content."""
|
|
16
|
+
pass
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def add_custom_css() -> None:
|
|
20
|
+
"""Add custom CSS styling to the Streamlit app."""
|
|
21
|
+
st.html(
|
|
22
|
+
"""
|
|
23
|
+
<style>
|
|
24
|
+
.stMainBlockContainer {
|
|
25
|
+
max-width:1200px;
|
|
26
|
+
}
|
|
27
|
+
</style>
|
|
28
|
+
""",
|
|
29
|
+
)
|
|
30
|
+
# st .markdown(
|
|
31
|
+
# """
|
|
32
|
+
# <style>
|
|
33
|
+
# section.main > div {max-width:1000px;}
|
|
34
|
+
# </style>
|
|
35
|
+
# """,
|
|
36
|
+
# unsafe_allow_html=True,
|
|
37
|
+
# )
|
adijif/types.py
CHANGED
|
@@ -95,16 +95,35 @@ class arb_source:
|
|
|
95
95
|
|
|
96
96
|
_max_scalar = int(1e11)
|
|
97
97
|
|
|
98
|
-
def __init__(
|
|
98
|
+
def __init__(
|
|
99
|
+
self,
|
|
100
|
+
name: str,
|
|
101
|
+
a_min: Union[None, int] = None,
|
|
102
|
+
b_min: Union[None, int] = None,
|
|
103
|
+
a_max: Union[None, int] = None,
|
|
104
|
+
b_max: Union[None, int] = None,
|
|
105
|
+
) -> None:
|
|
99
106
|
"""Arbitrary source for solver.
|
|
100
107
|
|
|
101
108
|
Args:
|
|
102
109
|
name (str): Name of source
|
|
110
|
+
a_min (int, optional): Minimum value for numerator. Defaults to None.
|
|
111
|
+
b_min (int, optional): Minimum value for denominator. Defaults to None.
|
|
112
|
+
a_max (int, optional): Maximum value for numerator. Defaults to None.
|
|
113
|
+
b_max (int, optional): Maximum value for denominator. Defaults to None.
|
|
103
114
|
"""
|
|
104
115
|
self.name = name
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
116
|
+
if a_min is None:
|
|
117
|
+
a_min = 0
|
|
118
|
+
if a_max is None:
|
|
119
|
+
a_max = self._max_scalar
|
|
120
|
+
if b_min is None:
|
|
121
|
+
b_min = 0
|
|
122
|
+
if b_max is None:
|
|
123
|
+
b_max = self._max_scalar
|
|
124
|
+
|
|
125
|
+
self._a = integer_var(a_min, a_max, name=name + "_a")
|
|
126
|
+
self._b = integer_var(b_min, b_max, name=name + "_b")
|
|
108
127
|
|
|
109
128
|
def __call__(self, model: Union[GEKKO, CpoModel]) -> Dict:
|
|
110
129
|
"""Generate arbitrary source for solver.
|
|
@@ -1,29 +1,39 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pyadi-jif
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.1
|
|
4
4
|
Summary: Python interface and configurator for ADI JESD Interface Framework
|
|
5
5
|
Author-email: "Travis F. Collins" <travis.collins@analog.com>
|
|
6
6
|
Maintainer: Analog Devices, Inc.
|
|
7
7
|
Maintainer-email: Travis Collins <travis.collins@analog.com>
|
|
8
8
|
License: EPL-2.0
|
|
9
|
+
Classifier: Programming Language :: Python
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
9
13
|
Requires-Python: >=3.9
|
|
10
14
|
Description-Content-Type: text/markdown
|
|
11
15
|
License-File: LICENSE
|
|
12
16
|
License-File: AUTHORS.rst
|
|
13
|
-
Requires-Dist: numpy
|
|
17
|
+
Requires-Dist: numpy
|
|
14
18
|
Requires-Dist: openpyxl>=3.1.3
|
|
15
|
-
Requires-Dist: pandas
|
|
19
|
+
Requires-Dist: pandas>=1.1.5
|
|
16
20
|
Provides-Extra: cplex
|
|
17
21
|
Requires-Dist: cplex; extra == "cplex"
|
|
18
|
-
Requires-Dist: docplex
|
|
22
|
+
Requires-Dist: docplex; extra == "cplex"
|
|
19
23
|
Provides-Extra: gekko
|
|
20
24
|
Requires-Dist: gekko; extra == "gekko"
|
|
25
|
+
Provides-Extra: draw
|
|
26
|
+
Requires-Dist: pyd2lang-native==0.0.3; extra == "draw"
|
|
27
|
+
Provides-Extra: tools
|
|
28
|
+
Requires-Dist: streamlit; extra == "tools"
|
|
21
29
|
Dynamic: license-file
|
|
22
30
|
|
|
23
31
|
# pyadi-jif: Python Configurator for ADI JESD204 Interface Framework (JIF)
|
|
24
32
|
|
|
25
33
|
A framework to simplify the use of JESD204 with Analog Devices, Inc. data converters and clock chips.
|
|
26
34
|
|
|
35
|
+
**New:** Try the interactive web-based [JIF Tools Explorer](#jif-tools-explorer) for a graphical interface!
|
|
36
|
+
|
|
27
37
|
<p align="center">
|
|
28
38
|
<img src="doc/source/imgs/PyADI-JIF_logo.png" width="500" alt="PyADI-JIF Logo"> </br>
|
|
29
39
|
</p>
|
|
@@ -33,7 +43,7 @@ A framework to simplify the use of JESD204 with Analog Devices, Inc. data conver
|
|
|
33
43
|
<a href="https://opensource.org/licenses/">
|
|
34
44
|
<img src="https://img.shields.io/badge/License-EPL%20v2-blue.svg" alt="EPL v2.0>
|
|
35
45
|
</a>
|
|
36
|
-
|
|
46
|
+
|
|
37
47
|
<a href="https://github.com/analogdevicesinc/pyadi-jif/actions/workflows/tests.yml">
|
|
38
48
|
<img src="https://github.com/analogdevicesinc/pyadi-jif/actions/workflows/tests.yml/badge.svg" alt="Test Status">
|
|
39
49
|
</a>
|
|
@@ -41,22 +51,36 @@ A framework to simplify the use of JESD204 with Analog Devices, Inc. data conver
|
|
|
41
51
|
<a href="https://codecov.io/gh/analogdevicesinc/pyadi-jif">
|
|
42
52
|
<img src="https://codecov.io/gh/analogdevicesinc/pyadi-jif/branch/main/graph/badge.svg?token=WVSRCSXFWL" alt="Coverage Status">
|
|
43
53
|
</a>
|
|
44
|
-
</p>
|
|
45
|
-
|
|
46
|
-
## Installation
|
|
54
|
+
</p>
|
|
55
|
+
|
|
56
|
+
## Installation
|
|
47
57
|
|
|
48
58
|
Install JIF with pip
|
|
49
59
|
|
|
50
|
-
```bash
|
|
51
|
-
|
|
60
|
+
```bash
|
|
61
|
+
pip install 'pyadi-jif[cplex]'
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## JIF Tools Explorer
|
|
65
|
+
|
|
66
|
+
Launch the interactive web-based tools for JESD204 configuration:
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
jiftools
|
|
52
70
|
```
|
|
53
71
|
|
|
72
|
+
The JIF Tools Explorer provides:
|
|
73
|
+
- **JESD204 Mode Selector** - Find and filter valid JESD204 modes for ADI converters
|
|
74
|
+
- **Clock Configurator** - Configure ADI clock chips (HMC7044, AD9545, etc.)
|
|
75
|
+
- **System Configurator** - Complete end-to-end system design (FPGA + Converter + Clock)
|
|
76
|
+
|
|
77
|
+
See the [Tools Documentation](https://analogdevicesinc.github.io/pyadi-jif/main/tools.html) for detailed usage guide.
|
|
54
78
|
|
|
55
79
|
## Documentation
|
|
56
80
|
|
|
57
|
-
[Documentation](https://analogdevicesinc.github.io/pyadi-jif
|
|
81
|
+
[Documentation](https://analogdevicesinc.github.io/pyadi-jif)
|
|
82
|
+
|
|
58
83
|
|
|
59
|
-
|
|
60
84
|
## License
|
|
61
85
|
|
|
62
86
|
[EPL-2.0](https://www.eclipse.org/legal/epl-2.0/)
|