Skip to content

Commit f736d25

Browse files
author
Axel Dahlberg
authored
Merge pull request #3 from SoftwareQuTech/Develop
Develop
2 parents 03ef04d + 288ee62 commit f736d25

File tree

8 files changed

+680
-4
lines changed

8 files changed

+680
-4
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,6 @@
55
/build/*
66
/dist/*
77
/cqc.egg-info/*
8+
/cqc/settings.ini
89

910
.idea/*

cqc/MessageHandler.py

Lines changed: 470 additions & 0 deletions
Large diffs are not rendered by default.

cqc/Protocol.py

Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
# Copyright (c) 2017, Stephanie Wehner and Axel Dahlberg
2+
# All rights reserved.
3+
#
4+
# Redistribution and use in source and binary forms, with or without
5+
# modification, are permitted provided that the following conditions are met:
6+
# 1. Redistributions of source code must retain the above copyright
7+
# notice, this list of conditions and the following disclaimer.
8+
# 2. Redistributions in binary form must reproduce the above copyright
9+
# notice, this list of conditions and the following disclaimer in the
10+
# documentation and/or other materials provided with the distribution.
11+
# 3. All advertising materials mentioning features or use of this software
12+
# must display the following acknowledgement:
13+
# This product includes software developed by Stephanie Wehner, QuTech.
14+
# 4. Neither the name of the QuTech organization nor the
15+
# names of its contributors may be used to endorse or promote products
16+
# derived from this software without specific prior written permission.
17+
#
18+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ''AS IS'' AND ANY
19+
# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20+
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21+
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
22+
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23+
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24+
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25+
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26+
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27+
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28+
29+
import logging
30+
31+
from twisted.internet.defer import inlineCallbacks
32+
from twisted.internet.protocol import Protocol, connectionDone
33+
34+
from cqc.cqcHeader import CQC_HDR_LENGTH, CQC_VERSION, CQCHeader
35+
36+
###############################################################################
37+
#
38+
# CQC Protocol
39+
#
40+
# Execute the CQC Protocol giving access to the SimulaQron backend via the
41+
# universal interface.
42+
#
43+
44+
45+
class CQCProtocol(Protocol):
46+
# Dictionary storing the next unique qubit id for each used app_id
47+
_next_q_id = {}
48+
49+
# Dictionary storing the next unique entanglement id for each used
50+
# (host_app_id,remote_node,remote_app_id)
51+
_next_ent_id = {}
52+
53+
def __init__(self, factory):
54+
55+
# CQC Factory, including our connection to the SimulaQron backend
56+
self.factory = factory
57+
58+
# Default application ID, typically one connection per application but
59+
# we will deliberately NOT check for that since this is the task of
60+
# higher layers or an OS
61+
self.app_id = 0
62+
63+
# Define the backend to use. Is a setting in settings.ini
64+
self.messageHandler = factory.backend
65+
66+
# Flag to determine whether we already received _all_ of the CQC header
67+
self.gotCQCHeader = False
68+
69+
# Header for which we are currently processing a packet
70+
self.currHeader = None
71+
72+
# Buffer received data (which may arrive in chunks)
73+
self.buf = None
74+
75+
# Convenience
76+
self.name = self.factory.name
77+
78+
logging.debug("CQC %s: Initialized Protocol", self.name)
79+
80+
def connectionMade(self):
81+
pass
82+
83+
def connectionLost(self, reason=connectionDone):
84+
pass
85+
86+
def dataReceived(self, data):
87+
"""
88+
Receive data. We will always wait to receive enough data for the
89+
header, and then the entire packet first before commencing processing.
90+
"""
91+
# Read whatever we received into a buffer
92+
if self.buf:
93+
self.buf = self.buf + data
94+
else:
95+
self.buf = data
96+
97+
# If we don't have the CQC header yet, try and read it in full.
98+
if not self.gotCQCHeader:
99+
if len(self.buf) < CQC_HDR_LENGTH:
100+
# Not enough data for CQC header, return and wait for the rest
101+
return
102+
103+
# Got enough data for the CQC Header so read it in
104+
self.gotCQCHeader = True
105+
raw_header = self.buf[0:CQC_HDR_LENGTH]
106+
self.currHeader = CQCHeader(raw_header)
107+
108+
# Remove the header from the buffer
109+
self.buf = self.buf[CQC_HDR_LENGTH: len(self.buf)]
110+
111+
logging.debug("CQC %s: Read CQC Header: %s", self.name, self.currHeader.printable())
112+
113+
# Check whether we already received all the data
114+
if len(self.buf) < self.currHeader.length:
115+
# Still waiting for data
116+
logging.debug(
117+
"CQC %s: Incomplete data. Waiting. Current length %s, " "required length %s",
118+
self.name,
119+
len(self.buf),
120+
self.currHeader.length,
121+
)
122+
return
123+
124+
# We got the header and all the data for this packet. Start processing.
125+
# Update our app ID
126+
self.app_id = self.currHeader.app_id
127+
# Invoke the relevant message handler, processing the possibly
128+
# remaining data
129+
try:
130+
self._parseData(self.currHeader, self.buf[0: self.currHeader.length])
131+
except Exception as e:
132+
print(e)
133+
import traceback
134+
135+
traceback.print_exc()
136+
137+
# if self.currHeader.tp in self.messageHandlers:
138+
# self.messageHandlers[self.currHeader.tp](self.currHeader, )
139+
# else:
140+
# self._send_back_cqc(self.currHeader, CQC_ERR_UNSUPP)
141+
142+
# Reset and await the next packet
143+
self.gotCQCHeader = False
144+
145+
# Check if we received data already for the next packet, if so save it
146+
if self.currHeader.length < len(self.buf):
147+
self.buf = self.buf[self.currHeader.length: len(self.buf)]
148+
self.dataReceived(b"")
149+
else:
150+
self.buf = None
151+
152+
@inlineCallbacks
153+
def _parseData(self, header, data):
154+
try:
155+
yield self.messageHandler.handle_cqc_message(header, data)
156+
messages = self.messageHandler.retrieve_return_messages()
157+
except Exception as e:
158+
raise e
159+
160+
if messages:
161+
# self.factory._lock.acquire()
162+
for msg in messages:
163+
self.transport.write(msg)
164+
# self.factory._lock.release()
165+
166+
def _send_back_cqc(self, header, msgType, length=0):
167+
"""
168+
Return a simple CQC header with the specified type.
169+
170+
header CQC header of the packet we respond to
171+
msgType Message type to return
172+
length Length of additional message
173+
"""
174+
hdr = CQCHeader()
175+
hdr.setVals(CQC_VERSION, msgType, header.app_id, length)
176+
177+
msg = hdr.pack()
178+
self.transport.write(msg)

cqc/entInfoHeader.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,32 @@ class EntInfoHeader(Header):
5151
HDR_LENGTH = ENT_INFO_LENGTH
5252
packaging_format = "!LHHLHHLQQHBB"
5353

54+
def __init__(self, headerBytes=None):
55+
"""
56+
Initialize using values received from a packet, if available.
57+
"""
58+
super().__init__(headerBytes)
59+
if headerBytes is None:
60+
self.node_A = 0
61+
self.port_A = 0
62+
self.app_id_A = 0
63+
64+
self.node_B = 0
65+
self.port_B = 0
66+
self.app_id_B = 0
67+
68+
self.id_AB = 0
69+
70+
self.timestamp = 0
71+
self.ToG = 0
72+
self.goodness = 0
73+
self.DF = 0
74+
self.is_set = False
75+
else:
76+
self.unpack(headerBytes)
77+
self.is_set = True
78+
79+
5480
def _setVals(self, node_A=0, port_A=0, app_id_A=0, node_B=0, port_B=0, app_id_B=0, id_AB=0, timestamp=0, ToG=0,
5581
goodness=0, DF=0):
5682
"""

cqc/pythonLib.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,6 @@
9393
from cqc.hostConfig import cqc_node_id_from_addrinfo, networkConfig
9494

9595

96-
9796
def shouldReturn(command):
9897
return command in {
9998
CQC_CMD_NEW,

cqc/settings.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ def set_config(config):
5454
with open(settings_file, 'w') as f:
5555
config.write(f)
5656

57+
5758
def get_cqc_file():
5859
"""
5960
Gets the path to the CQC file used

requirements.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
numpy>=1.14.0
22
bitstring>=3.1.5
3-
flake>=3.6.0
3+
flake8>=3.6.0
4+
twisted>=18.7.0

setup.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,13 @@
66

77
setuptools.setup(
88
name="cqc",
9-
version="2.0.1",
9+
version="2.2.0",
1010
author="Axel Dahlberg",
1111
author_email="[email protected]",
1212
description="The CQC interface",
1313
long_description=long_description,
1414
long_description_content_type="text/markdown",
15-
url="https://github.com/SoftwareQuTech/CQC",
15+
url="https://github.com/SoftwareQuTech/CQC-Python",
1616
include_package_data=True,
1717
package_data={
1818
'cqc': ['settings.ini']

0 commit comments

Comments
 (0)