server-simulator.py 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330
  1. import numpy as np
  2. import scipy.interpolate as interp
  3. import msgpack
  4. import json
  5. import socket
  6. class ServerSimulator:
  7. def __init__(self):
  8. self.events = []
  9. self.rfwaves = []
  10. self.time = 0
  11. #Socket parameters
  12. self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  13. self.conn = 0
  14. self.magic = 0xAA
  15. self.cmd = 0x00
  16. self.data = {}
  17. self.simview = {}
  18. #Simulation parameters
  19. self.freq = 3e6
  20. self.level = 20000
  21. #32bit Codes
  22. self.errCode = 0x00000000
  23. self.statCode = 0x00000000
  24. # Command callbacks
  25. self.cmd_dict = {
  26. 0x10: self.addEvent,
  27. 0x20: self.getRfwaveTable,
  28. 0x30: self.runEventList,
  29. 0x40: self.sendSimViewData,
  30. 0x00: self.disconnect
  31. }
  32. def connect(self, host, port):
  33. self.sock.bind((host, port))
  34. self.sock.listen(1)
  35. self.conn, addr = self.sock.accept()
  36. print(f"New connection from {addr}")
  37. def disconnect(self):
  38. self.conn.close()
  39. def getErrorMsg(self, errCode, errString):
  40. error = {
  41. "magic": self.magic,
  42. "cmd": b'\xFF',
  43. "code": errCode,
  44. "message": errString
  45. }
  46. return msgpack.packb(error, use_bin_type=True)
  47. def getStatusMsg(self, statCode, statString):
  48. status = {
  49. "magic": self.magic,
  50. "cmd": b'\xFE',
  51. "code": statCode,
  52. "message": statString
  53. }
  54. return msgpack.packb(status, use_bin_type=True)
  55. def acceptCommand(self):
  56. rawdata = self.sock.recv(4096)
  57. # Check if data is received
  58. if not rawdata:
  59. return False
  60. # Unpack data using msgpack
  61. self.data = msgpack.unpackb(rawdata, raw=False)
  62. if self.data["magic"] != self.magic:
  63. print("Invalid magic byte")
  64. self.errCode = 0x00000051 # Invalid magic byte
  65. self.conn.sendall(self.getErrorMsg(self.errCode, "Invalid magic byte"))
  66. return False
  67. if self.data["cmd"] not in self.cmd_dict.keys():
  68. print("Invalid command")
  69. self.errCode = 0x00000052 # Invalid command
  70. self.conn.sendall(self.getErrorMsg(self.errCode, "Invalid command"))
  71. return False
  72. print(f"Received command: {self.data['cmd']}")
  73. # Process command
  74. self.cmd = self.data["cmd"]
  75. self.cmd_dict[self.cmd](self.data)
  76. return True
  77. def addEvent(self, data):
  78. if not all (k in data for k in ("time", "duration", "wave", "time_front_rf_trigger", "time_back_rf", "rf_start", "rf_end", "time_adc_trigger", "time_back_adc")):
  79. print("Missing event parameters")
  80. self.errCode = 0x00000001 # Missing parameters
  81. self.conn.sendall(self.getErrorMsg(self.errCode, "Missing event parameters"))
  82. return False
  83. event = {
  84. "start_time": data["time"],
  85. "duration": data["duration"],
  86. "wave": data["wave"],
  87. "time_front_rf_trigger": data["time_front_rf_trigger"],
  88. "time_back_rf_trigger": data["time_back_rf"],
  89. "rf_start": data["rf_start"],
  90. "rf_end": data["rf_end"],
  91. "time_front_adc_trigger": data["time_adc_trigger"],
  92. "time_back_adc_trigger": data["time_back_adc"],
  93. }
  94. if event["start_time"] < self.time:
  95. print("Event start time is in the past")
  96. self.errCode = 0x00000002 # Event in the past
  97. self.conn.sendall(self.getErrorMsg(self.errCode, "Event start time is in the past"))
  98. return False
  99. self.time = event["start_time"] + event["duration"]
  100. if event["time_front_rf_trigger"] < 0 or event["time_back_rf_trigger"] < 0 or event["rf_start"] < 0 or event["rf_end"] < 0:
  101. print("RF trigger times and delays must be non-negative")
  102. self.errCode = 0x00000003 # Negative times
  103. self.conn.sendall(self.getErrorMsg(self.errCode, "RF trigger times and delays must be non-negative"))
  104. return False
  105. if event["time_front_adc_trigger"] < 0 or event["time_back_adc_trigger"] < 0:
  106. print("ADC trigger times must be non-negative")
  107. self.errCode = 0x00000004 # Negative times
  108. self.conn.sendall(self.getErrorMsg(self.errCode, "ADC trigger times must be non-negative"))
  109. return False
  110. if event["time_front_rf_trigger"] > event["duration"] or event["time_back_rf_trigger"] > event["duration"]:
  111. print("RF trigger times must be within event duration")
  112. self.errCode = 0x00000005 # RF trigger times out of bounds
  113. self.conn.sendall(self.getErrorMsg(self.errCode, "RF trigger times must be within event duration"))
  114. return False
  115. if event["rf_start"] > event["duration"] or event["rf_end"] > event["duration"]:
  116. print("RF start and end times must be within event duration")
  117. self.errCode = 0x00000006 # RF start/end times out of bounds
  118. self.conn.sendall(self.getErrorMsg(self.errCode, "RF start and end times must be within event duration"))
  119. return False
  120. if event["time_front_adc_trigger"] > event["duration"] or event["time_back_adc_trigger"] > event["duration"]:
  121. print("ADC trigger times must be within event duration")
  122. self.errCode = 0x00000007 # ADC trigger times out of bounds
  123. self.conn.sendall(self.getErrorMsg(self.errCode, "ADC trigger times must be within event duration"))
  124. return False
  125. if event["time_front_rf_trigger"] < event["time_back_rf_trigger"]:
  126. print("RF triggers and delays overlap")
  127. self.errCode = 0x00000008 # RF triggers overlap
  128. self.conn.sendall(self.getErrorMsg(self.errCode, "RF triggers and delays overlap"))
  129. return False
  130. if event["time_front_adc_trigger"] < event["time_back_adc_trigger"]:
  131. print("ADC triggers overlap")
  132. self.errCode = 0x00000009 # ADC triggers overlap
  133. self.conn.sendall(self.getErrorMsg(self.errCode, "ADC triggers overlap"))
  134. return False
  135. if event["rf_start"] < event["rf_end"]:
  136. print("RF start and end times overlap")
  137. self.errCode = 0x0000000A # RF start/end times overlap
  138. self.conn.sendall(self.getErrorMsg(self.errCode, "RF start and end times overlap"))
  139. return False
  140. if event["rf_start"] < event["time_front_rf_trigger"] or event["rf_end"] > event["time_back_rf_trigger"]:
  141. print("RF start and end times must be within RF trigger times")
  142. self.errCode = 0x0000000B # RF start/end times outside triggers
  143. self.conn.sendall(self.getErrorMsg(self.errCode, "RF start and end times must be within RF trigger times"))
  144. return False
  145. if event["rf_end"] - event["rf_start"] < len(self.rfwaves[event["wave"]]):
  146. print("RF pulse duration must be at least as long as the wave length")
  147. self.errCode = 0x0000000C # Insufficient RF pulse duration
  148. self.conn.sendall(self.getErrorMsg(self.errCode, "RF pulse duration must be at least as long as the wave length"))
  149. return False
  150. self.events.append(event)
  151. print(f"Added event: {event}")
  152. return True
  153. def getRfwaveTable(self, data):
  154. if not all (k in data for k in ("wavetype", "total_length", "total_packets", "packet_index", "packet_length")):
  155. print("Missing RF wave parameters")
  156. self.errCode = 0x0000000F # Missing parameters
  157. self.conn.sendall(self.getErrorMsg(self.errCode, "Missing RF wave parameters"))
  158. return False
  159. wavetype = data["wavetype"]
  160. total_length = data["total_length"]
  161. total_packets = data["total_packets"]
  162. packet_index = data["packet_index"]
  163. packet_length = data["packet_length"]
  164. total_wave_q = np.array([], dtype=np.int16)
  165. total_wave_i = np.array([], dtype=np.int16)
  166. self.conn.sendall(self.getStatusMsg(0x00000001, f"Ready to receive RF wave data packet {packet_index+1}/{total_packets} with length {packet_length}"))
  167. for i in range(total_packets):
  168. rawdata = self.sock.recv(4096)
  169. if not rawdata:
  170. print("No data received for RF wave packet")
  171. return False
  172. packet_data = msgpack.unpackb(rawdata, raw=False)
  173. if packet_data["magic"] != self.magic:
  174. print("Invalid magic byte in RF wave packet")
  175. self.errCode = 0x00000014 # Invalid magic byte
  176. self.conn.sendall(self.getErrorMsg(self.errCode, "Invalid magic byte in RF wave packet"))
  177. return False
  178. if packet_data["cmd"] != 0x2C:
  179. print("Invalid command in RF wave packet")
  180. self.errCode = 0x00000013 # Invalid command
  181. self.conn.sendall(self.getErrorMsg(self.errCode, "Invalid command in RF wave packet"))
  182. return False
  183. if "wavedata_q" not in packet_data or "wavedata_i" not in packet_data:
  184. print("Missing wave data in RF wave packet")
  185. self.errCode = 0x00000010 # Missing wave data
  186. self.conn.sendall(self.getErrorMsg(self.errCode, "Missing wave data in RF wave packet"))
  187. return False
  188. wave_q = np.frombuffer(packet_data["wavedata_q"], dtype=np.int16)
  189. wave_i = np.frombuffer(packet_data["wavedata_i"], dtype=np.int16)
  190. if len(wave_q) != len(wave_i):
  191. print("In-phase and quadrature wave data must have the same length in RF wave packet")
  192. self.errCode = 0x00000012 # Mismatched wave data lengths
  193. self.conn.sendall(self.getErrorMsg(self.errCode, "In-phase and quadrature wave data must have the same length in RF wave packet"))
  194. return False
  195. total_wave_q = np.concatenate([total_wave_q, wave_q])
  196. total_wave_i = np.concatenate([total_wave_i, wave_i])
  197. print(f"Received RF wave packet {i+1}/{total_packets} with length {len(wave_q)}")
  198. if len(total_wave_q) != total_length or len(total_wave_i) != total_length:
  199. print("Total wave data length does not match expected length")
  200. self.errCode = 0x00000011 # Total length mismatch
  201. self.conn.sendall(self.getErrorMsg(self.errCode, "Total wave data length does not match expected length"))
  202. return False
  203. self.rfwaves.append({data["wavetype"]: (total_wave_q, total_wave_i)})
  204. return True
  205. def runEventList(self, data):
  206. time_linspace = np.linspace(0, self.time, self.time+1)
  207. channel_g = np.ones(self.time, dtype=np.int16) * np.floor(3.3 / 5 * 32767)
  208. channel_rf_ttl = np.zeros(self.time, dtype=np.int16)
  209. channel_adc_ttl = np.zeros(self.time, dtype=np.int16)
  210. channel_rf = np.zeros(self.time, dtype=np.int16)
  211. for event in self.events:
  212. print(f"Running event: {event}")
  213. # Simulate RF pulse
  214. rf_wave_q = self.rfwaves[event["wave"]][0]
  215. rf_wave_i = self.rfwaves[event["wave"]][1]
  216. rf_pulse_length = event["rf_end"] - event["rf_start"]
  217. rf_trigger_length = event["time_back_rf_trigger"] - event["time_front_rf_trigger"]
  218. adc_trigger_length = event["time_back_adc_trigger"] - event["time_front_adc_trigger"]
  219. rf_wave_length = len(rf_wave_q)
  220. event_length = event["duration"]
  221. rf_time = np.linspace(0, rf_pulse_length, rf_pulse_length+1)
  222. rf_trigger_time = np.linspace(0, rf_trigger_length, rf_trigger_length+1)
  223. adc_trigger_time = np.linspace(0, adc_trigger_length, adc_trigger_length+1)
  224. event_time = np.linspace(0, event_length, event_length+1)
  225. if rf_pulse_length < rf_wave_length:
  226. print("RF pulse length is shorter than RF wave length, cannot run event")
  227. self.errCode = 0x00000031 # Invalid RF pulse length
  228. self.conn.sendall(self.getErrorMsg(self.errCode, "RF pulse length is shorter than RF wave length, cannot run event"))
  229. continue
  230. print("Interpolating RF wave to fit pulse duration...")
  231. interp_wave_q = np.zeros(rf_pulse_length, dtype=np.int16)
  232. interp_wave_i = np.zeros(rf_pulse_length, dtype=np.int16)
  233. if data["interpolation_method"] == "linear":
  234. interp_func_q = interp.interp1d(np.linspace(0, rf_wave_length, rf_wave_length), rf_wave_q, kind='linear')
  235. interp_func_i = interp.interp1d(np.linspace(0, rf_wave_length, rf_wave_length), rf_wave_i, kind='linear')
  236. interp_wave_q = interp_func_q(rf_time).astype(np.int16)
  237. interp_wave_i = interp_func_i(rf_time).astype(np.int16)
  238. elif data["interpolation_method"] == "nearest":
  239. interp_func_q = interp.interp1d(np.linspace(0, rf_wave_length, rf_wave_length), rf_wave_q, kind='nearest')
  240. interp_func_i = interp.interp1d(np.linspace(0, rf_wave_length, rf_wave_length), rf_wave_i, kind='nearest')
  241. interp_wave_q = interp_func_q(rf_time).astype(np.int16)
  242. interp_wave_i = interp_func_i(rf_time).astype(np.int16)
  243. elif data["interpolation_method"] == "cubic":
  244. interp_func_q = interp.interp1d(np.linspace(0, rf_wave_length, rf_wave_length), rf_wave_q, kind='cubic')
  245. interp_func_i = interp.interp1d(np.linspace(0, rf_wave_length, rf_wave_length), rf_wave_i, kind='cubic')
  246. interp_wave_q = interp_func_q(rf_time).astype(np.int16)
  247. interp_wave_i = interp_func_i(rf_time).astype(np.int16)
  248. channel_rf[event["rf_start"]:event["rf_end"]+1] = np.floor((interp_wave_q * np.cos(2 * np.pi * self.freq * rf_time * 8e-9) - interp_wave_i * np.sin(2 * np.pi * self.freq * rf_time * 8e-9)) / np.sqrt(2)).astype(np.int16)
  249. channel_rf_ttl[event["time_front_rf_trigger"]:event["time_back_rf_trigger"]+1] = 1
  250. channel_adc_ttl[event["time_front_adc_trigger"]:event["time_back_adc_trigger"]+1] = 1
  251. channel_g[event["start_time"]:(event["start_time"]+event["duration"]+1)] = 0
  252. self.simview = {
  253. "time": time_linspace,
  254. "channel_g": channel_g,
  255. "channel_rf_ttl": channel_rf_ttl,
  256. "channel_adc_ttl": channel_adc_ttl,
  257. "channel_rf": channel_rf
  258. }
  259. self.conn.sendall(self.getStatusMsg(0x00000032, "Event list simulation complete"))
  260. return True
  261. def sendSimViewData(self, data):
  262. data_length = len(self.simview["time"])
  263. channels = ["channel_g", "channel_rf_ttl", "channel_adc_ttl", "channel_rf"]
  264. packet_size = 1024
  265. total_packets = (data_length * len(channels) * 2) // packet_size + 1
  266. packet_index = 0
  267. self.conn.sendall(self.getStatusMsg(0x00000043, f"Ready to send simulation data in {total_packets} packets with size {packet_size} bytes"))
  268. for channel in channels:
  269. channel_data = self.simview[channel].tobytes()
  270. for i in range(0, len(channel_data), packet_size):
  271. packet_num += 1
  272. packet_data = None
  273. if i + packet_size > len(channel_data):
  274. packet_data = channel_data[i:]
  275. else:
  276. packet_data = channel_data[i:i+packet_size]
  277. packet_msg = {
  278. "magic": self.magic,
  279. "cmd": 0x33,
  280. "channel": channel,
  281. "total_packets": total_packets,
  282. "packet_index": packet_index,
  283. "data": packet_data
  284. }
  285. self.conn.sendall(msgpack.packb(packet_msg, use_bin_type=True))
  286. rawdata = self.conn.recv(1024) # Wait for ACK
  287. ack_data = msgpack.unpackb(rawdata, raw=False)
  288. if ack_data["magic"] != self.magic or ack_data["cmd"] != 0x41 or ack_data["code"] != packet_index:
  289. print(f"Invalid ACK for packet {packet_index}")
  290. self.errCode = 0x00000045 # Invalid ACK
  291. self.conn.sendall(self.getErrorMsg(self.errCode, f"Invalid ACK for packet {packet_index}"))
  292. return False
  293. print("Simulation data sent successfully")
  294. self.conn.sendall(self.getStatusMsg(0x00000044, "All simulation data packets sent"))
  295. return True