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.
Files changed (59) hide show
  1. thzdaqapi/Agilent/__init__.py +0 -0
  2. thzdaqapi/Agilent/signal_generator.py +157 -0
  3. thzdaqapi/Arduino/__init__.py +1 -0
  4. thzdaqapi/Arduino/grid.py +159 -0
  5. thzdaqapi/Arduino/step_motor/grid_1/grid_1.ino +164 -0
  6. thzdaqapi/Arduino/step_motor/grid_2/grid_2.ino +170 -0
  7. thzdaqapi/Chopper/__init__.py +60 -0
  8. thzdaqapi/Chopper/chopper_async.py +222 -0
  9. thzdaqapi/Chopper/chopper_ethernet.py +141 -0
  10. thzdaqapi/Chopper/chopper_sync.py +280 -0
  11. thzdaqapi/Keithley/__init__.py +1 -0
  12. thzdaqapi/Keithley/multimeter.py +75 -0
  13. thzdaqapi/Keithley/power_supply.py +86 -0
  14. thzdaqapi/LakeShore/__init__.py +1 -0
  15. thzdaqapi/LakeShore/temperature_controller.py +155 -0
  16. thzdaqapi/NationalInstruments/__init__.py +0 -0
  17. thzdaqapi/NationalInstruments/yig_filter.py +92 -0
  18. thzdaqapi/Pfeiffer/__init__.py +0 -0
  19. thzdaqapi/Pfeiffer/data_types.py +240 -0
  20. thzdaqapi/Pfeiffer/hicube80.py +171 -0
  21. thzdaqapi/Pfeiffer/parameters.py +794 -0
  22. thzdaqapi/Pfeiffer/protocol.py +285 -0
  23. thzdaqapi/Pfeiffer/tc110.py +300 -0
  24. thzdaqapi/Rigol/DP832A.py +88 -0
  25. thzdaqapi/Rigol/__init__.py +0 -0
  26. thzdaqapi/RohdeSchwarz/__init__.py +3 -0
  27. thzdaqapi/RohdeSchwarz/power_meter_nrx.py +112 -0
  28. thzdaqapi/RohdeSchwarz/power_supply.py +124 -0
  29. thzdaqapi/RohdeSchwarz/spectrum_fsek30.py +216 -0
  30. thzdaqapi/RohdeSchwarz/vna.py +177 -0
  31. thzdaqapi/SRS/LockIn_SR830.py +33 -0
  32. thzdaqapi/SRS/__init__.py +0 -0
  33. thzdaqapi/Scontel/__init__.py +1 -0
  34. thzdaqapi/Scontel/sis_block.py +259 -0
  35. thzdaqapi/Scontel/sis_block_stream.py +33 -0
  36. thzdaqapi/Sumitomo/Compressor.py +208 -0
  37. thzdaqapi/Sumitomo/__init__.py +1 -0
  38. thzdaqapi/Sumitomo/f70_rest.py +97 -0
  39. thzdaqapi/Sumitomo/tests.py +3 -0
  40. thzdaqapi/__init__.py +8 -0
  41. thzdaqapi/adapters/__init__.py +6 -0
  42. thzdaqapi/adapters/http_adapter.py +70 -0
  43. thzdaqapi/adapters/prologix.py +63 -0
  44. thzdaqapi/adapters/prologix_usb.py +62 -0
  45. thzdaqapi/adapters/serial_adapter.py +48 -0
  46. thzdaqapi/adapters/socket_adapter.py +117 -0
  47. thzdaqapi/adapters/socket_single_adapter.py +6 -0
  48. thzdaqapi/device_types.py +17 -0
  49. thzdaqapi/settings.py +42 -0
  50. thzdaqapi/utils/__init__.py +5 -0
  51. thzdaqapi/utils/classes.py +139 -0
  52. thzdaqapi/utils/constants.py +2 -0
  53. thzdaqapi/utils/decorators.py +15 -0
  54. thzdaqapi/utils/exceptions.py +1 -0
  55. thzdaqapi/utils/functions.py +221 -0
  56. thzdaqapi-0.1.0.dist-info/METADATA +249 -0
  57. thzdaqapi-0.1.0.dist-info/RECORD +59 -0
  58. thzdaqapi-0.1.0.dist-info/WHEEL +4 -0
  59. 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
+ }