Skip to content

Commit eeedb4e

Browse files
committed
Working on laser emulation
1 parent a3bcb98 commit eeedb4e

File tree

4 files changed

+183
-15
lines changed

4 files changed

+183
-15
lines changed

arduino-spoof/live_testbench.py

+36-5
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ def test_default_rep_rate(self):
1212
self.assertEqual(laser.get_repetition_rate(), 5.0)
1313

1414
def test_set_rep_rate(self):
15-
global laser, serial_conn
15+
global laser
1616
laser.set_rep_rate(1.2)
1717
self.assertEqual(laser.get_repetition_rate(), 1.2)
1818
laser.set_rep_rate(5.0)
@@ -24,15 +24,15 @@ def test_set_rep_rate(self):
2424
self.assertEqual(laser.get_repetition_rate(), 5.0)
2525

2626
def test_get_rep_rate_range(self):
27-
global laser, serial_conn
28-
pass
27+
global laser
28+
self.assertEqual(laser.get_repetition_rate_range(), (0.100, 50.000))
2929

3030
def test_default_burst_count(self):
31-
global laser, serial_conn
31+
global laser
3232
self.assertEqual(laser.get_burst_count(), 31)
3333

3434
def test_set_burst_count(self):
35-
global laser, serial_conn
35+
global laser
3636
laser.set_burst_count(2)
3737
self.assertEqual(laser.get_burst_count(), 2)
3838
self.assertEqual(laser._send_command("BC -5"), b"?5\r\n")
@@ -128,6 +128,37 @@ def test_pulse_mode(self):
128128
self.assertEqual(laser._send_command("PM 0.8"), b"?5\r\n")
129129
self.assertEqual(laser.get_pulse_mode(), 0)
130130

131+
def test_default_pulse_period(self):
132+
global laser
133+
self.assertEqual(laser.get_pulse_period(), 0.20000000)
134+
135+
def test_pulse_period_range(self):
136+
global laser
137+
self.assertEqual(laser.get_pulse_period_range(), (0.02, 10.0))
138+
139+
def test_pulse_period(self):
140+
global laser
141+
laser.set_pulse_period(0.25) # Using a nice round floating point #
142+
self.assertEqual(laser.get_pulse_period(), 0.25)
143+
laser.set_pulse_period(0.2)
144+
self.assertEqual(laser.get_pulse_period(), 0.20)
145+
self.assertEqual(laser._send_command("PE"), b"?5\r\n")
146+
self.assertEqual(laser._send_command("PE -1"), b"?5\r\n")
147+
self.assertEqual(laser._send_command("PE 11.0"), b"?5\r\n")
148+
self.assertEqual(laser._send_command("PE 0.01"), b"?5\r\n")
149+
self.assertEqual(laser.get_pulse_period(), 0.2)
150+
151+
def test_resonator_temp(self):
152+
global laser
153+
t = laser.get_resonator_temp()
154+
print("Resonator temperature: " + str(t))
155+
assert t > -1
156+
assert t < 51
157+
158+
def test_resonator_temp_range(self):
159+
global laser
160+
pass # TODO: Implement this, it's not that important of a function, but still needed for 100% emulation
161+
131162
if __name__ == "__main__":
132163
serial_port = "COM2"
133164
if len(sys.argv) > 1:

arduino-spoof/ujlaser_emulator/ujlaser_emulator.ino

+116-7
Original file line numberDiff line numberDiff line change
@@ -11,17 +11,26 @@ bool ready_to_fire = false;
1111
bool low_power_mode = false;
1212
bool high_power_mode = false;
1313

14+
#define DEFAULT_BURST_COUNT 31
15+
#define DEFAULT_PULSE_MODE 0
16+
#define DEFAULT_DIODE_TRIGGER 0
17+
#define DEFAULT_PULSE_WIDTH 0.00014000
18+
#define DEFAULT_PULSE_PERIOD 0.20000000
19+
#define DEFAULT_REP_RATE 5.0;
20+
1421
unsigned int shot_count = 0;
15-
unsigned int burst_count = 31;
16-
unsigned short pulse_mode = 0;
17-
unsigned short diode_trigger = 0;
22+
unsigned int burst_count = DEFAULT_BURST_COUNT;
23+
unsigned short pulse_mode = DEFAULT_PULSE_MODE;
24+
unsigned short diode_trigger = DEFAULT_DIODE_TRIGGER;
1825

1926
const float diode_current = 110.00; // Latest models of QC ujlasers have this fixed
20-
float pulse_width = 0.00014000;
21-
float pulse_period = 0.20000000;
22-
float rep_rate = 5.00;
27+
float pulse_width = DEFAULT_PULSE_WIDTH;
28+
float pulse_period = DEFAULT_PULSE_PERIOD;
29+
float rep_rate = DEFAULT_REP_RATE;
2330
float resonator_temp = -0.401; // NOTE: This value was taken while the diode was not connected.
2431
float fet_temp = 34.082;
32+
float bank_voltage = 0;
33+
2534

2635
#define ID_STRING "QC,MicroJewel,08130,1.0.9"
2736

@@ -127,6 +136,13 @@ void loop() {
127136
laser_enabled = false;
128137
}
129138

139+
if(bank_voltage > 0) {
140+
bank_voltage -= bank_voltage / 3; // This is a VERY rough approximation of the bank voltage discharging
141+
if(bank_voltage < 0) {
142+
bank_voltage = 0;
143+
}
144+
}
145+
130146
c = 0;
131147
while(Serial.available() > 0) {
132148
c = Serial.read();
@@ -201,6 +217,55 @@ void loop() {
201217
Serial.print("?6\r\n");
202218
}
203219
}
220+
else if (strcmp(cmd, "PE") == 0) {
221+
Serial.readBytes(k, 1);
222+
if(*k == '?') {
223+
Serial.print(pulse_period, 3);
224+
Serial.print("\r\n");
225+
}
226+
else if (*k == ' ') {
227+
float f = -1000;
228+
f = Serial.parseFloat();
229+
if (f == -1000) {
230+
Serial.print("?4\r\n");
231+
continue;
232+
}
233+
if(f < MIN_PE || f > MAX_PE) {
234+
Serial.print("?5\r\n");
235+
continue;
236+
}
237+
pulse_period = f;
238+
rep_rate = 1.0/f;
239+
ok();
240+
}
241+
else if (*k == ':') {
242+
char keyword[4];
243+
memset(keyword, 0, 4);
244+
if(Serial.readBytesUntil('?', keyword, 3) != 3){
245+
Serial.print("?5\r\n");
246+
Serial.flush();
247+
delay(200); // Idk why this must be here, but it makes it pass the test bench....... And yes, it must be 200ms, i tested it... idc
248+
continue;
249+
}
250+
if(strcmp(keyword, "MIN")==0) {
251+
Serial.print(MIN_PE);
252+
Serial.print("\r\n");
253+
continue;
254+
}
255+
else if(strcmp(keyword, "MAX")==0) {
256+
Serial.print(MAX_PE);
257+
Serial.print("\r\n");
258+
continue;
259+
}
260+
else {
261+
Serial.print("?3\r\n");
262+
continue;
263+
}
264+
}
265+
else {
266+
Serial.print("?5\r\n");
267+
}
268+
}
204269
else if (strcmp(cmd, "RR") == 0) {
205270
Serial.readBytes(k, 1);
206271
if(*k == '?') {
@@ -219,8 +284,32 @@ void loop() {
219284
continue;
220285
}
221286
rep_rate = f;
287+
pulse_period = 1/f;
222288
ok();
223289
}
290+
else if (*k == ':') {
291+
char keyword[4];
292+
memset(keyword, 0, 4);
293+
if(Serial.readBytesUntil('?', keyword, 3) != 3){
294+
Serial.print("?5\r\n");
295+
Serial.flush();
296+
continue;
297+
}
298+
if(strcmp(keyword, "MIN")==0) {
299+
Serial.print(MIN_RR);
300+
Serial.print("\r\n");
301+
continue;
302+
}
303+
else if(strcmp(keyword, "MAX")==0) {
304+
Serial.print(MAX_RR);
305+
Serial.print("\r\n");
306+
continue;
307+
}
308+
else {
309+
Serial.print("?3\r\n");
310+
continue;
311+
}
312+
}
224313
else {
225314
Serial.print("?5\r\n");
226315
}
@@ -381,7 +470,27 @@ void loop() {
381470
else if (strcmp(cmd, "BV") == 0) {
382471
Serial.readBytes(k,1);
383472
if (*k == '?') {
384-
Serial.print(0.000, 5);
473+
Serial.print(bank_voltage, 3);
474+
Serial.print("\r\n");
475+
}
476+
else {
477+
Serial.print("?6\r\n");
478+
}
479+
}
480+
else if (strcmp(cmd, "RS") == 0) {
481+
Serial.end();
482+
pulse_mode = DEFAULT_PULSE_MODE;
483+
diode_trigger = DEFAULT_DIODE_TRIGGER;
484+
pulse_width = DEFAULT_PULSE_WIDTH;
485+
pulse_period = DEFAULT_PULSE_PERIOD;
486+
rep_rate = DEFAULT_REP_RATE;
487+
burst_count = DEFAULT_BURST_COUNT;
488+
Serial.begin(115200);
489+
}
490+
else if (strcmp(cmd, "TR") == 0) {
491+
Serial.readBytes(k,1);
492+
if (*k == '?') {
493+
Serial.print(resonator_temp, 3);
385494
Serial.print("\r\n");
386495
}
387496
else {

tools/laser_terminal.py

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import sys
2+
from time import sleep
3+
from serial import Serial
4+
from ujlaser.lasercontrol import Laser, LaserCommandError
5+
6+
serial_port = "COM3"
7+
8+
if len(sys.argv) > 1:
9+
serial_port = sys.argv[1]
10+
11+
print("Connecting to serial port " + serial_port)
12+
s = Serial(serial_port, 115200)
13+
running = True
14+
while running:
15+
cmd = input(";LA:")
16+
if cmd == "exit" or cmd == "EXIT" or cmd == "quit" or cmd == "CMD":
17+
break
18+
r = s.write((";LA:" + cmd + "\r\n").encode("ascii"))
19+
sleep(0.3)
20+
if s.in_waiting:
21+
print(s.read_until())
22+
s.close()

ujlaser/lasercontrol.py

+9-3
Original file line numberDiff line numberDiff line change
@@ -471,7 +471,7 @@ def get_resonator_temp(self):
471471
Returns the float value of the resonator temperature in Celsius.
472472
"""
473473
response = self._send_command('TR?')
474-
if response[0] == b"?":
474+
if not response or response[0] == b"?":
475475
raise LaserCommandError(Laser.get_error_code_description(response))
476476
return float(response.decode('ascii'))
477477

@@ -658,6 +658,12 @@ def set_pulse_period(self, period):
658658
self.pulsePeriod = float(period)
659659
return True
660660
raise LaserCommandError(Laser.get_error_code_description(response))
661+
662+
def get_pulse_period(self):
663+
response = self._send_command("PE?")
664+
if not response or response[0] == b'?':
665+
raise LaserCommandError(Laser.get_error_code_description(response))
666+
return float(response)
661667

662668
def get_pulse_period_range(self):
663669
"""Returns the min and max periods for firing.
@@ -809,12 +815,12 @@ def get_repetition_rate_range(self):
809815
Item at index 0 is the minimum repitition rate, and item at index 1 is the maximum repitition rate.
810816
"""
811817
min_response = self._send_command("RR:MIN?")
812-
if min_response[0] == b"?":
818+
if not min_response or min_response[0] == b"?":
813819
raise LaserCommandError(Laser.get_error_code_description(min_response))
814820
minimum = float(min_response)
815821

816822
max_response = self._send_command("RR:MAX?")
817-
if max_response[0] == b"?":
823+
if not max_response or max_response[0] == b"?":
818824
raise LaserCommandError(Laser.get_error_code_description(max_response))
819825
maximum = float(max_response)
820826

0 commit comments

Comments
 (0)