thzdaqapi 0.1.0__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.
- thzdaqapi/Agilent/__init__.py +0 -0
- thzdaqapi/Agilent/signal_generator.py +157 -0
- thzdaqapi/Arduino/__init__.py +1 -0
- thzdaqapi/Arduino/grid.py +159 -0
- thzdaqapi/Arduino/step_motor/grid_1/grid_1.ino +164 -0
- thzdaqapi/Arduino/step_motor/grid_2/grid_2.ino +170 -0
- thzdaqapi/Chopper/__init__.py +60 -0
- thzdaqapi/Chopper/chopper_async.py +222 -0
- thzdaqapi/Chopper/chopper_ethernet.py +141 -0
- thzdaqapi/Chopper/chopper_sync.py +280 -0
- thzdaqapi/Keithley/__init__.py +1 -0
- thzdaqapi/Keithley/multimeter.py +75 -0
- thzdaqapi/Keithley/power_supply.py +86 -0
- thzdaqapi/LakeShore/__init__.py +1 -0
- thzdaqapi/LakeShore/temperature_controller.py +155 -0
- thzdaqapi/NationalInstruments/__init__.py +0 -0
- thzdaqapi/NationalInstruments/yig_filter.py +92 -0
- thzdaqapi/Pfeiffer/__init__.py +0 -0
- thzdaqapi/Pfeiffer/data_types.py +240 -0
- thzdaqapi/Pfeiffer/hicube80.py +171 -0
- thzdaqapi/Pfeiffer/parameters.py +794 -0
- thzdaqapi/Pfeiffer/protocol.py +285 -0
- thzdaqapi/Pfeiffer/tc110.py +300 -0
- thzdaqapi/Rigol/DP832A.py +88 -0
- thzdaqapi/Rigol/__init__.py +0 -0
- thzdaqapi/RohdeSchwarz/__init__.py +3 -0
- thzdaqapi/RohdeSchwarz/power_meter_nrx.py +112 -0
- thzdaqapi/RohdeSchwarz/power_supply.py +124 -0
- thzdaqapi/RohdeSchwarz/spectrum_fsek30.py +216 -0
- thzdaqapi/RohdeSchwarz/vna.py +177 -0
- thzdaqapi/SRS/LockIn_SR830.py +33 -0
- thzdaqapi/SRS/__init__.py +0 -0
- thzdaqapi/Scontel/__init__.py +1 -0
- thzdaqapi/Scontel/sis_block.py +259 -0
- thzdaqapi/Scontel/sis_block_stream.py +33 -0
- thzdaqapi/Sumitomo/Compressor.py +208 -0
- thzdaqapi/Sumitomo/__init__.py +1 -0
- thzdaqapi/Sumitomo/f70_rest.py +97 -0
- thzdaqapi/Sumitomo/tests.py +3 -0
- thzdaqapi/__init__.py +8 -0
- thzdaqapi/adapters/__init__.py +6 -0
- thzdaqapi/adapters/http_adapter.py +70 -0
- thzdaqapi/adapters/prologix.py +63 -0
- thzdaqapi/adapters/prologix_usb.py +62 -0
- thzdaqapi/adapters/serial_adapter.py +48 -0
- thzdaqapi/adapters/socket_adapter.py +117 -0
- thzdaqapi/adapters/socket_single_adapter.py +6 -0
- thzdaqapi/device_types.py +17 -0
- thzdaqapi/settings.py +42 -0
- thzdaqapi/utils/__init__.py +5 -0
- thzdaqapi/utils/classes.py +139 -0
- thzdaqapi/utils/constants.py +2 -0
- thzdaqapi/utils/decorators.py +15 -0
- thzdaqapi/utils/exceptions.py +1 -0
- thzdaqapi/utils/functions.py +221 -0
- thzdaqapi-0.1.0.dist-info/METADATA +249 -0
- thzdaqapi-0.1.0.dist-info/RECORD +59 -0
- thzdaqapi-0.1.0.dist-info/WHEEL +4 -0
- thzdaqapi-0.1.0.dist-info/licenses/LICENSE +21 -0
|
File without changes
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from typing import Any
|
|
3
|
+
|
|
4
|
+
from thzdaqapi import settings
|
|
5
|
+
from thzdaqapi.utils.classes import BaseInstrument
|
|
6
|
+
|
|
7
|
+
logger = logging.getLogger(__name__)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class SignalGenerator(BaseInstrument):
|
|
11
|
+
model = "E8247C"
|
|
12
|
+
ALC_RANGE = [-7.9, 2]
|
|
13
|
+
ATTENUATOR_RANGE = [0, 10, 20, 30, 40, 50, 60, 70, 80, 90]
|
|
14
|
+
|
|
15
|
+
def __init__(
|
|
16
|
+
self,
|
|
17
|
+
host: str = "169.254.156.103",
|
|
18
|
+
gpib: int = 19,
|
|
19
|
+
adapter: str = settings.PROLOGIX_ETHERNET,
|
|
20
|
+
port: int = 1234,
|
|
21
|
+
*args: Any,
|
|
22
|
+
**kwargs: Any,
|
|
23
|
+
) -> None:
|
|
24
|
+
"""Initialize device instance and configure connection parameters."""
|
|
25
|
+
super().__init__(host=host, gpib=gpib, adapter=adapter, port=port, *args, **kwargs)
|
|
26
|
+
|
|
27
|
+
def idn(self) -> str:
|
|
28
|
+
"""Return instrument identification string."""
|
|
29
|
+
assert self.adapter is not None, "Adapter couldn't be None"
|
|
30
|
+
return self.adapter.query("*IDN?", eq_addr=self.gpib)
|
|
31
|
+
|
|
32
|
+
def test(self) -> bool:
|
|
33
|
+
# return self.adapter.query("*TST?", eq_addr=self.gpib)
|
|
34
|
+
"""Run a lightweight communication check and return status."""
|
|
35
|
+
result = self.idn()
|
|
36
|
+
return "Agilent" in result
|
|
37
|
+
|
|
38
|
+
def reset(self) -> str:
|
|
39
|
+
"""Reset the device to a known default state."""
|
|
40
|
+
assert self.adapter is not None, "Adapter couldn't be None"
|
|
41
|
+
return self.adapter.write("*RST", eq_addr=self.gpib)
|
|
42
|
+
|
|
43
|
+
def get_rf_output_state(self) -> bool:
|
|
44
|
+
"""Read current rf output state from the device."""
|
|
45
|
+
assert self.adapter is not None, "Adapter couldn't be None"
|
|
46
|
+
return bool(int(self.adapter.query("OUTPut?", eq_addr=self.gpib)))
|
|
47
|
+
|
|
48
|
+
def set_rf_output_state(self, value: bool) -> None:
|
|
49
|
+
"""Set rf output state on the device."""
|
|
50
|
+
output = 1 if value else 0
|
|
51
|
+
assert self.adapter is not None, "Adapter couldn't be None"
|
|
52
|
+
self.adapter.write(f"OUTPut {output}", eq_addr=self.gpib)
|
|
53
|
+
|
|
54
|
+
def get_frequency(self) -> float:
|
|
55
|
+
"""Read current frequency from the device."""
|
|
56
|
+
assert self.adapter is not None, "Adapter couldn't be None"
|
|
57
|
+
return float(self.adapter.query(":FREQuency:FIXed? ", eq_addr=self.gpib))
|
|
58
|
+
|
|
59
|
+
def set_frequency(self, value: float) -> None:
|
|
60
|
+
"""Set frequency on the device."""
|
|
61
|
+
assert self.adapter is not None, "Adapter couldn't be None"
|
|
62
|
+
self.adapter.write(f":FREQuency:FIXed {value} ", eq_addr=self.gpib)
|
|
63
|
+
|
|
64
|
+
def get_attenuation_level(self) -> float:
|
|
65
|
+
"""Read current attenuation level from the device."""
|
|
66
|
+
assert self.adapter is not None, "Adapter couldn't be None"
|
|
67
|
+
return float(self.adapter.query(":POWer:ATTenuation?", eq_addr=self.gpib))
|
|
68
|
+
|
|
69
|
+
def set_attenuation_level(self, value: float) -> None:
|
|
70
|
+
"""Set attenuation level on the device."""
|
|
71
|
+
assert self.adapter is not None, "Adapter couldn't be None"
|
|
72
|
+
return self.adapter.write(f":POWer:ATTenuation {value}", eq_addr=self.gpib)
|
|
73
|
+
|
|
74
|
+
def get_alc_level(self) -> float:
|
|
75
|
+
"""Read current alc level from the device."""
|
|
76
|
+
assert self.adapter is not None, "Adapter couldn't be None"
|
|
77
|
+
return float(self.adapter.query(":POWer:ALC:LEVel?", eq_addr=self.gpib))
|
|
78
|
+
|
|
79
|
+
def set_alc_level(self, value: float) -> None:
|
|
80
|
+
"""Set alc level on the device."""
|
|
81
|
+
assert self.adapter is not None, "Adapter couldn't be None"
|
|
82
|
+
return self.adapter.write(f":POWer:ALC:LEVel {value}", eq_addr=self.gpib)
|
|
83
|
+
|
|
84
|
+
def get_amplitude(self) -> float:
|
|
85
|
+
"""Read current amplitude from the device."""
|
|
86
|
+
attenuation = self.get_attenuation_level()
|
|
87
|
+
asc = self.get_alc_level()
|
|
88
|
+
return asc - attenuation
|
|
89
|
+
|
|
90
|
+
def set_amplitude(self, value: float) -> None:
|
|
91
|
+
"""Set amplitude on the device."""
|
|
92
|
+
if value > 25:
|
|
93
|
+
raise Exception("Value greater then 25 dBm unsupported!")
|
|
94
|
+
k = int(round((abs(value) - 10) / 10))
|
|
95
|
+
if k < 0 or value > 0:
|
|
96
|
+
k = 0
|
|
97
|
+
attenuation = self.ATTENUATOR_RANGE[k]
|
|
98
|
+
alc = value + attenuation
|
|
99
|
+
self.set_alc_level(0)
|
|
100
|
+
self.set_attenuation_level(attenuation)
|
|
101
|
+
self.set_alc_level(alc)
|
|
102
|
+
|
|
103
|
+
def set_power(self, value: float) -> None:
|
|
104
|
+
"""Set power on the device."""
|
|
105
|
+
assert self.adapter is not None, "Adapter couldn't be None"
|
|
106
|
+
self.adapter.write(f"POW {value}dBm", eq_addr=self.gpib)
|
|
107
|
+
|
|
108
|
+
def get_power(self) -> float:
|
|
109
|
+
"""Read current power from the device."""
|
|
110
|
+
assert self.adapter is not None, "Adapter couldn't be None"
|
|
111
|
+
return float(self.adapter.query("POW?", eq_addr=self.gpib))
|
|
112
|
+
|
|
113
|
+
def get_oem_status(self) -> str:
|
|
114
|
+
"""ON|OFF|NONE|REAR|FRONT"""
|
|
115
|
+
assert self.adapter is not None, "Adapter couldn't be None"
|
|
116
|
+
return self.adapter.query(":SYSTem:OEMHead:SELect?", eq_addr=self.gpib)
|
|
117
|
+
|
|
118
|
+
def set_oem_status(self, value: str) -> None:
|
|
119
|
+
"""ON|OFF|NONE|REAR|FRONT"""
|
|
120
|
+
assert self.adapter is not None, "Adapter couldn't be None"
|
|
121
|
+
self.adapter.write(f":SYSTem:OEMHead:SELect {value}", eq_addr=self.gpib)
|
|
122
|
+
|
|
123
|
+
def get_oem_frequency_start(self) -> float:
|
|
124
|
+
"""Read current oem frequency start from the device."""
|
|
125
|
+
assert self.adapter is not None, "Adapter couldn't be None"
|
|
126
|
+
return float(self.adapter.query(":SYSTem:OEMHead:FREQuency:STARt?", eq_addr=self.gpib))
|
|
127
|
+
|
|
128
|
+
def set_oem_frequency_start(self, value: float) -> None:
|
|
129
|
+
"""Set oem frequency start on the device."""
|
|
130
|
+
assert self.adapter is not None, "Adapter couldn't be None"
|
|
131
|
+
self.adapter.write(f":SYSTem:OEMHead:FREQuency:STARt {value}", eq_addr=self.gpib)
|
|
132
|
+
|
|
133
|
+
def get_oem_frequency_stop(self) -> float:
|
|
134
|
+
"""Read current oem frequency stop from the device."""
|
|
135
|
+
assert self.adapter is not None, "Adapter couldn't be None"
|
|
136
|
+
return float(self.adapter.query(":SYSTem:OEMHead:FREQuency:STOP?", eq_addr=self.gpib))
|
|
137
|
+
|
|
138
|
+
def set_oem_frequency_stop(self, value: float) -> None:
|
|
139
|
+
"""Set oem frequency stop on the device."""
|
|
140
|
+
assert self.adapter is not None, "Adapter couldn't be None"
|
|
141
|
+
self.adapter.write(f":SYSTem:OEMHead:FREQuency:STOP {value}", eq_addr=self.gpib)
|
|
142
|
+
|
|
143
|
+
def get_oem_multiplier(self) -> float:
|
|
144
|
+
"""Read current oem multiplier from the device."""
|
|
145
|
+
assert self.adapter is not None, "Adapter couldn't be None"
|
|
146
|
+
return float(self.adapter.query(":SYST:OEMH:FREQ:MULT?", eq_addr=self.gpib))
|
|
147
|
+
|
|
148
|
+
def set_oem_multiplier(self, value: float) -> None:
|
|
149
|
+
"""Set oem multiplier on the device."""
|
|
150
|
+
assert self.adapter is not None, "Adapter couldn't be None"
|
|
151
|
+
self.adapter.write(f":SYST:OEMH:FREQ:MULT {value}", eq_addr=self.gpib)
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
if __name__ == "__main__":
|
|
155
|
+
dev = SignalGenerator(host="169.254.156.103", gpib=18)
|
|
156
|
+
print(dev.idn())
|
|
157
|
+
print(float(dev.adapter.query("POW?", eq_addr=dev.gpib)))
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .grid import GridDevice
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
import sys
|
|
5
|
+
from typing import Any, Protocol, TypeAlias, runtime_checkable
|
|
6
|
+
|
|
7
|
+
from serial.tools.list_ports import main as list_ports
|
|
8
|
+
|
|
9
|
+
from thzdaqapi.settings import ADAPTERS, HTTP, SERIAL
|
|
10
|
+
from thzdaqapi.utils.exceptions import DeviceConnectionError
|
|
11
|
+
from thzdaqapi.utils.functions import import_class
|
|
12
|
+
|
|
13
|
+
logger = logging.getLogger(__name__)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@runtime_checkable
|
|
17
|
+
class _GridHttpAdapter(Protocol):
|
|
18
|
+
def post(self, url: str, data: dict[str, Any] | None = None) -> tuple[int, dict[str, Any]]: ...
|
|
19
|
+
|
|
20
|
+
def close(self) -> None: ...
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@runtime_checkable
|
|
24
|
+
class _GridSerialAdapter(Protocol):
|
|
25
|
+
def write(self, cmd: str, **kwargs: Any) -> None: ...
|
|
26
|
+
|
|
27
|
+
def query(self, cmd: str, **kwargs: Any) -> str: ...
|
|
28
|
+
|
|
29
|
+
def close(self) -> None: ...
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
GridAdapter: TypeAlias = _GridHttpAdapter | _GridSerialAdapter
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class GridDevice:
|
|
36
|
+
"""Control Arduino grid rotation over HTTP or serial transport."""
|
|
37
|
+
|
|
38
|
+
DEFAULT_HOST = "169.254.0.52"
|
|
39
|
+
|
|
40
|
+
def __init__(
|
|
41
|
+
self,
|
|
42
|
+
host: str = DEFAULT_HOST,
|
|
43
|
+
adapter: str = HTTP,
|
|
44
|
+
current_angle: float = 0.0,
|
|
45
|
+
*args: Any,
|
|
46
|
+
**kwargs: Any,
|
|
47
|
+
) -> None:
|
|
48
|
+
self.host = host
|
|
49
|
+
self.adapter_name = adapter
|
|
50
|
+
self.current_angle = float(current_angle)
|
|
51
|
+
self.finish = False
|
|
52
|
+
self.adapter: GridAdapter | None = None
|
|
53
|
+
self._set_adapter(adapter, *args, **kwargs)
|
|
54
|
+
|
|
55
|
+
def _set_adapter(self, adapter: str, *args: Any, **kwargs: Any) -> None:
|
|
56
|
+
adapter_path = ADAPTERS.get(adapter)
|
|
57
|
+
if adapter_path is None:
|
|
58
|
+
raise ValueError(f"Unsupported adapter for GridDevice: {adapter}")
|
|
59
|
+
|
|
60
|
+
adapter_class = import_class(adapter_path)
|
|
61
|
+
if adapter == SERIAL:
|
|
62
|
+
# For serial adapter `host` represents serial port path.
|
|
63
|
+
instance = adapter_class(port=self.host, *args, **kwargs)
|
|
64
|
+
else:
|
|
65
|
+
instance = adapter_class(host=self.host, *args, **kwargs)
|
|
66
|
+
|
|
67
|
+
if adapter == SERIAL and not isinstance(instance, _GridSerialAdapter):
|
|
68
|
+
raise TypeError(
|
|
69
|
+
f"Serial grid adapter `{instance.__class__.__name__}` has invalid interface"
|
|
70
|
+
)
|
|
71
|
+
if adapter == HTTP and not isinstance(instance, _GridHttpAdapter):
|
|
72
|
+
raise TypeError(
|
|
73
|
+
f"HTTP grid adapter `{instance.__class__.__name__}` has invalid interface"
|
|
74
|
+
)
|
|
75
|
+
self.adapter = instance
|
|
76
|
+
|
|
77
|
+
def rotate(
|
|
78
|
+
self, angle: float = 90, finish: bool = False, relative: bool = False
|
|
79
|
+
) -> float | None:
|
|
80
|
+
"""Rotate grid and update in-memory angle.
|
|
81
|
+
|
|
82
|
+
Args:
|
|
83
|
+
angle: Target angle (absolute by default).
|
|
84
|
+
finish: Stop flag for long-running scripts.
|
|
85
|
+
relative: Interpret `angle` as delta from current angle.
|
|
86
|
+
"""
|
|
87
|
+
if self.finish:
|
|
88
|
+
return None
|
|
89
|
+
|
|
90
|
+
target_angle = self.current_angle + angle if relative else angle
|
|
91
|
+
delta = target_angle - self.current_angle
|
|
92
|
+
if abs(delta) < 1e-12:
|
|
93
|
+
return self.current_angle
|
|
94
|
+
|
|
95
|
+
if self.adapter_name == SERIAL:
|
|
96
|
+
if self.adapter is None:
|
|
97
|
+
raise RuntimeError("Grid adapter is not initialized")
|
|
98
|
+
self.adapter.write(str(target_angle))
|
|
99
|
+
self.current_angle = float(target_angle)
|
|
100
|
+
return self.current_angle
|
|
101
|
+
|
|
102
|
+
if self.adapter_name == HTTP:
|
|
103
|
+
if self.adapter is None:
|
|
104
|
+
raise RuntimeError("Grid adapter is not initialized")
|
|
105
|
+
status, _ = self.adapter.post(url="/rotate", data={"angle": delta})
|
|
106
|
+
if status == 200:
|
|
107
|
+
self.current_angle = float(target_angle)
|
|
108
|
+
return self.current_angle
|
|
109
|
+
|
|
110
|
+
self.finish = finish
|
|
111
|
+
return None
|
|
112
|
+
|
|
113
|
+
def rotate_relative(self, delta_angle: float) -> float | None:
|
|
114
|
+
"""Rotate by a relative delta from current in-memory angle."""
|
|
115
|
+
return self.rotate(angle=delta_angle, relative=True)
|
|
116
|
+
|
|
117
|
+
def test(self) -> bool:
|
|
118
|
+
"""Check communication with the grid controller."""
|
|
119
|
+
if self.adapter_name == SERIAL:
|
|
120
|
+
try:
|
|
121
|
+
if self.adapter is None:
|
|
122
|
+
raise RuntimeError("Grid adapter is not initialized")
|
|
123
|
+
response = self.adapter.query("test", buffer_size=128).strip()
|
|
124
|
+
return response.upper() == "OK"
|
|
125
|
+
except Exception as exc:
|
|
126
|
+
logger.error("[%s.test] %s", self.__class__.__name__, exc)
|
|
127
|
+
raise DeviceConnectionError(str(exc)) from exc
|
|
128
|
+
|
|
129
|
+
if self.adapter_name == HTTP:
|
|
130
|
+
try:
|
|
131
|
+
if self.adapter is None:
|
|
132
|
+
raise RuntimeError("Grid adapter is not initialized")
|
|
133
|
+
status, _ = self.adapter.post(url="/test", data={})
|
|
134
|
+
return status == 200
|
|
135
|
+
except Exception as exc:
|
|
136
|
+
logger.error("[%s.test] %s", self.__class__.__name__, exc)
|
|
137
|
+
raise DeviceConnectionError(str(exc)) from exc
|
|
138
|
+
|
|
139
|
+
raise ValueError(f"Unsupported adapter: {self.adapter_name}")
|
|
140
|
+
|
|
141
|
+
@staticmethod
|
|
142
|
+
def scan_ports() -> None:
|
|
143
|
+
list_ports()
|
|
144
|
+
|
|
145
|
+
def close(self) -> None:
|
|
146
|
+
if self.adapter is not None and hasattr(self.adapter, "close"):
|
|
147
|
+
self.adapter.close()
|
|
148
|
+
|
|
149
|
+
def __del__(self) -> None: # pragma: no cover - best effort
|
|
150
|
+
try:
|
|
151
|
+
self.close()
|
|
152
|
+
except Exception:
|
|
153
|
+
pass
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
if __name__ == "__main__":
|
|
157
|
+
angle = float(sys.argv[1])
|
|
158
|
+
ard = GridDevice()
|
|
159
|
+
ard.rotate(angle, relative=True)
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
#include <SPI.h>
|
|
2
|
+
#include <Ethernet2.h>
|
|
3
|
+
#include <ArduinoJson.h>
|
|
4
|
+
|
|
5
|
+
const int dirPin = 1;
|
|
6
|
+
const int stepPin = 2;
|
|
7
|
+
const int resetPin = 3;
|
|
8
|
+
const int sleepPin = 4;
|
|
9
|
+
const int ms1Pin = 5;
|
|
10
|
+
const int ms2Pin = 6;
|
|
11
|
+
const int ms3Pin = 7;
|
|
12
|
+
|
|
13
|
+
const int stepsPerRevolution = 16000;
|
|
14
|
+
const int stepDelay = 350;
|
|
15
|
+
|
|
16
|
+
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
|
|
17
|
+
IPAddress ip(169, 254, 0, 52);
|
|
18
|
+
EthernetServer server(80);
|
|
19
|
+
|
|
20
|
+
// Helpers
|
|
21
|
+
void urlHandler(String request, EthernetClient client) {
|
|
22
|
+
Serial.print("Recieved request: " + String(request));
|
|
23
|
+
if (request.indexOf("POST /rotate") != -1) {
|
|
24
|
+
Serial.println("Calling stepperRotateView");
|
|
25
|
+
stepperRotateView(request, client);
|
|
26
|
+
}
|
|
27
|
+
if (request.indexOf("POST /test") != -1) {
|
|
28
|
+
Serial.println("Calling testStepperRotateView");
|
|
29
|
+
testStepperRotateView(request, client);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
int getContentLength(String bodyFull) {
|
|
34
|
+
int contentLength = 0;
|
|
35
|
+
int contentLengthIndex = bodyFull.indexOf("Content-Length:");
|
|
36
|
+
if (contentLengthIndex != -1) {
|
|
37
|
+
contentLengthIndex += 16;
|
|
38
|
+
String contentLengthStr = bodyFull.substring(contentLengthIndex);
|
|
39
|
+
contentLength = contentLengthStr.toInt();
|
|
40
|
+
}
|
|
41
|
+
Serial.println("Request Length: " + String(contentLength));
|
|
42
|
+
return contentLength;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
void sendResponse(EthernetClient client, String response) {
|
|
46
|
+
client.println("HTTP/1.1 200 OK");
|
|
47
|
+
client.println("Content-Type: application/json");
|
|
48
|
+
client.println("Connection: close");
|
|
49
|
+
client.print("Content-Length: ");
|
|
50
|
+
client.println(response.length());
|
|
51
|
+
client.println();
|
|
52
|
+
client.println(response);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Serialization
|
|
56
|
+
float serializeRequest(String request, EthernetClient client) {
|
|
57
|
+
String bodyFull = client.readString();
|
|
58
|
+
int contentLength = getContentLength(bodyFull);
|
|
59
|
+
int bodyFullLength = bodyFull.length();
|
|
60
|
+
String body = bodyFull.substring(bodyFullLength - contentLength, bodyFullLength);
|
|
61
|
+
body.replace("\n", "");
|
|
62
|
+
body.replace("\r", "");
|
|
63
|
+
body.replace(" ", "");
|
|
64
|
+
Serial.println("Body: " + body);
|
|
65
|
+
int ind1 = body.indexOf(":") + 1;
|
|
66
|
+
int ind2 = body.length() - 1;
|
|
67
|
+
float angle = body.substring(ind1, ind2).toFloat();
|
|
68
|
+
Serial.println("Angle: " + String(angle));
|
|
69
|
+
client.flush();
|
|
70
|
+
return angle;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
String serializeResponse() {
|
|
74
|
+
DynamicJsonDocument responseDoc(1024);
|
|
75
|
+
responseDoc["status"] = "OK";
|
|
76
|
+
String response;
|
|
77
|
+
serializeJson(responseDoc, response);
|
|
78
|
+
return response;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
void processResponse(EthernetClient client) {
|
|
82
|
+
String response = serializeResponse();
|
|
83
|
+
sendResponse(client, response);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Views
|
|
87
|
+
void stepperRotateView(String request, EthernetClient client) {
|
|
88
|
+
float angle = serializeRequest(request, client);
|
|
89
|
+
stepperRotate(angle);
|
|
90
|
+
processResponse(client);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
void testStepperRotateView(String request, EthernetClient client) {
|
|
94
|
+
stepperRotate(45);
|
|
95
|
+
stepperRotate(-45);
|
|
96
|
+
processResponse(client);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// UseCases
|
|
100
|
+
void stepperRotate(float angle) {
|
|
101
|
+
int stepsRev = abs(stepsPerRevolution * angle / 360);
|
|
102
|
+
Serial.println("Steps: " + String(stepsRev));
|
|
103
|
+
if (angle >= 0) {
|
|
104
|
+
digitalWrite(dirPin, HIGH);
|
|
105
|
+
} else {
|
|
106
|
+
digitalWrite(dirPin, LOW);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
for (int i = 0; i < stepsRev; i++) {
|
|
110
|
+
digitalWrite(stepPin, HIGH);
|
|
111
|
+
delayMicroseconds(stepDelay);
|
|
112
|
+
digitalWrite(stepPin, LOW);
|
|
113
|
+
delayMicroseconds(stepDelay);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// Set Up
|
|
118
|
+
void setup() {
|
|
119
|
+
// Init serial
|
|
120
|
+
Serial.begin(9600);
|
|
121
|
+
Serial.print("Serial init OK\r\n");
|
|
122
|
+
// Set pins outs
|
|
123
|
+
pinMode(dirPin, OUTPUT);
|
|
124
|
+
pinMode(stepPin, OUTPUT);
|
|
125
|
+
pinMode(sleepPin, OUTPUT);
|
|
126
|
+
pinMode(resetPin, OUTPUT);
|
|
127
|
+
pinMode(ms1Pin, OUTPUT);
|
|
128
|
+
pinMode(ms2Pin, OUTPUT);
|
|
129
|
+
pinMode(ms3Pin, OUTPUT);
|
|
130
|
+
// Init ethernet
|
|
131
|
+
Ethernet.begin(mac, ip);
|
|
132
|
+
server.begin();
|
|
133
|
+
Serial.print("Server is at ");
|
|
134
|
+
Serial.println(Ethernet.localIP());
|
|
135
|
+
// Enable driver motor
|
|
136
|
+
digitalWrite(resetPin, HIGH);
|
|
137
|
+
digitalWrite(sleepPin, HIGH);
|
|
138
|
+
digitalWrite(ms1Pin, HIGH);
|
|
139
|
+
digitalWrite(ms2Pin, HIGH);
|
|
140
|
+
digitalWrite(ms3Pin, HIGH);
|
|
141
|
+
Serial.println("Motor enabled");
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// Main Loop
|
|
145
|
+
void loop() {
|
|
146
|
+
EthernetClient client = server.available();
|
|
147
|
+
if (client) {
|
|
148
|
+
Serial.println("New client");
|
|
149
|
+
String request = "";
|
|
150
|
+
while (client.connected()) {
|
|
151
|
+
if (client.available()) {
|
|
152
|
+
char c = client.read();
|
|
153
|
+
request += c;
|
|
154
|
+
if (c == '\n') {
|
|
155
|
+
break;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
urlHandler(request, client);
|
|
160
|
+
delay(0.1);
|
|
161
|
+
client.stop();
|
|
162
|
+
Serial.println("Client disconnected");
|
|
163
|
+
}
|
|
164
|
+
}
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
#include <SPI.h>
|
|
2
|
+
#include <Ethernet2.h>
|
|
3
|
+
#include <ArduinoJson.h>
|
|
4
|
+
|
|
5
|
+
const int dirPin = 2;
|
|
6
|
+
const int stepPin = 3;
|
|
7
|
+
const int sleepPin = 4;
|
|
8
|
+
const int resetPin = 5;
|
|
9
|
+
const int ms3Pin = 6;
|
|
10
|
+
const int ms2Pin = 7;
|
|
11
|
+
const int ms1Pin = 8;
|
|
12
|
+
const int enablePin = 9;
|
|
13
|
+
|
|
14
|
+
const int stepsPerRevolution = 16000;
|
|
15
|
+
const int stepDelay = 350;
|
|
16
|
+
|
|
17
|
+
byte mac[] = { 0x00, 0xAA, 0xBB, 0xCC, 0xDE, 0x02 };
|
|
18
|
+
IPAddress ip(169, 254, 0, 53);
|
|
19
|
+
EthernetServer server(80);
|
|
20
|
+
|
|
21
|
+
// Helpers
|
|
22
|
+
void urlHandler(String request, EthernetClient client) {
|
|
23
|
+
Serial.print("Recieved request: " + String(request));
|
|
24
|
+
if (request.indexOf("POST /rotate") != -1) {
|
|
25
|
+
Serial.println("Calling stepperRotateView");
|
|
26
|
+
stepperRotateView(request, client);
|
|
27
|
+
}
|
|
28
|
+
if (request.indexOf("POST /test") != -1) {
|
|
29
|
+
Serial.println("Calling testStepperRotateView");
|
|
30
|
+
testStepperRotateView(request, client);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
int getContentLength(String bodyFull) {
|
|
35
|
+
int contentLength = 0;
|
|
36
|
+
int contentLengthIndex = bodyFull.indexOf("Content-Length:");
|
|
37
|
+
if (contentLengthIndex != -1) {
|
|
38
|
+
contentLengthIndex += 16;
|
|
39
|
+
String contentLengthStr = bodyFull.substring(contentLengthIndex);
|
|
40
|
+
contentLength = contentLengthStr.toInt();
|
|
41
|
+
}
|
|
42
|
+
Serial.println("Request Length: " + String(contentLength));
|
|
43
|
+
return contentLength;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
void sendResponse(EthernetClient client, String response) {
|
|
47
|
+
client.println("HTTP/1.1 200 OK");
|
|
48
|
+
client.println("Content-Type: application/json");
|
|
49
|
+
client.println("Connection: close");
|
|
50
|
+
client.print("Content-Length: ");
|
|
51
|
+
client.println(response.length());
|
|
52
|
+
client.println();
|
|
53
|
+
client.println(response);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Serialization
|
|
57
|
+
float serializeRequest(String request, EthernetClient client) {
|
|
58
|
+
String bodyFull = client.readString();
|
|
59
|
+
int contentLength = getContentLength(bodyFull);
|
|
60
|
+
int bodyFullLength = bodyFull.length();
|
|
61
|
+
String body = bodyFull.substring(bodyFullLength - contentLength, bodyFullLength);
|
|
62
|
+
body.replace("\n", "");
|
|
63
|
+
body.replace("\r", "");
|
|
64
|
+
body.replace(" ", "");
|
|
65
|
+
Serial.println("Body: " + body);
|
|
66
|
+
int ind1 = body.indexOf(":") + 1;
|
|
67
|
+
int ind2 = body.length() - 1;
|
|
68
|
+
float angle = body.substring(ind1, ind2).toFloat();
|
|
69
|
+
Serial.println("Angle: " + String(angle));
|
|
70
|
+
client.flush();
|
|
71
|
+
return angle;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
String serializeResponse() {
|
|
75
|
+
DynamicJsonDocument responseDoc(1024);
|
|
76
|
+
responseDoc["status"] = "OK";
|
|
77
|
+
String response;
|
|
78
|
+
serializeJson(responseDoc, response);
|
|
79
|
+
return response;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
void processResponse(EthernetClient client) {
|
|
83
|
+
String response = serializeResponse();
|
|
84
|
+
sendResponse(client, response);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Views
|
|
88
|
+
void stepperRotateView(String request, EthernetClient client) {
|
|
89
|
+
float angle = serializeRequest(request, client);
|
|
90
|
+
stepperRotate(angle);
|
|
91
|
+
processResponse(client);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
void testStepperRotateView(String request, EthernetClient client) {
|
|
95
|
+
stepperRotate(45);
|
|
96
|
+
stepperRotate(-45);
|
|
97
|
+
processResponse(client);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// UseCases
|
|
101
|
+
void stepperRotate(float angle) {
|
|
102
|
+
int stepsRev = abs(stepsPerRevolution * angle / 360);
|
|
103
|
+
Serial.println("Steps: " + String(stepsRev));
|
|
104
|
+
if (angle >= 0) {
|
|
105
|
+
digitalWrite(dirPin, HIGH);
|
|
106
|
+
} else {
|
|
107
|
+
digitalWrite(dirPin, LOW);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
for (int i = 0; i < stepsRev; i++) {
|
|
111
|
+
digitalWrite(stepPin, HIGH);
|
|
112
|
+
delayMicroseconds(stepDelay);
|
|
113
|
+
digitalWrite(stepPin, LOW);
|
|
114
|
+
delayMicroseconds(stepDelay);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Set Up
|
|
119
|
+
void setup() {
|
|
120
|
+
// Init serial
|
|
121
|
+
Serial.begin(9600);
|
|
122
|
+
Serial.print("Serial init OK\r\n");
|
|
123
|
+
// Set pins outs
|
|
124
|
+
pinMode(dirPin, OUTPUT);
|
|
125
|
+
pinMode(stepPin, OUTPUT);
|
|
126
|
+
pinMode(sleepPin, OUTPUT);
|
|
127
|
+
pinMode(resetPin, OUTPUT);
|
|
128
|
+
pinMode(ms1Pin, OUTPUT);
|
|
129
|
+
pinMode(ms2Pin, OUTPUT);
|
|
130
|
+
pinMode(ms3Pin, OUTPUT);
|
|
131
|
+
pinMode(enablePin, OUTPUT);
|
|
132
|
+
// pinMode(resetPin, OUTPUT);
|
|
133
|
+
// pinMode(sleepPin, OUTPUT);
|
|
134
|
+
// Init default pins values
|
|
135
|
+
// Init ethernet
|
|
136
|
+
Ethernet.begin(mac, ip);
|
|
137
|
+
server.begin();
|
|
138
|
+
Serial.print("Server is at ");
|
|
139
|
+
Serial.println(Ethernet.localIP());
|
|
140
|
+
// Enable driver motor
|
|
141
|
+
digitalWrite(enablePin, LOW);
|
|
142
|
+
digitalWrite(resetPin, HIGH);
|
|
143
|
+
digitalWrite(sleepPin, HIGH);
|
|
144
|
+
digitalWrite(ms1Pin, HIGH);
|
|
145
|
+
digitalWrite(ms2Pin, HIGH);
|
|
146
|
+
digitalWrite(ms3Pin, HIGH);
|
|
147
|
+
Serial.println("Motor enabled");
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// Main Loop
|
|
151
|
+
void loop() {
|
|
152
|
+
EthernetClient client = server.available();
|
|
153
|
+
if (client) {
|
|
154
|
+
Serial.println("New client");
|
|
155
|
+
String request = "";
|
|
156
|
+
while (client.connected()) {
|
|
157
|
+
if (client.available()) {
|
|
158
|
+
char c = client.read();
|
|
159
|
+
request += c;
|
|
160
|
+
if (c == '\n') {
|
|
161
|
+
break;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
urlHandler(request, client);
|
|
166
|
+
delay(0.1);
|
|
167
|
+
client.stop();
|
|
168
|
+
Serial.println("Client disconnected");
|
|
169
|
+
}
|
|
170
|
+
}
|