Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • anders_blomdell/labcomm
  • klaren/labcomm
  • tommyo/labcomm
  • erikj/labcomm
  • sven/labcomm
5 results
Show changes
Showing
with 1497 additions and 150 deletions
package se.lth.control.labcomm;
package se.lth.control.labcomm2014;
import java.io.OutputStream;
import java.io.IOException;
class WriterWrapper implements LabCommWriter{
class WriterWrapper implements Writer{
private OutputStream os;
......
.PHONY: all
all:
.PHONY: test
test:
.PHONY: clean
clean:
find . -name '*.pyc' -exec rm {} \;
.PHONY: distclean
distclean: clean
import labcomm.LabComm
Decoder = labcomm.LabComm.Decoder
Encoder = labcomm.LabComm.Encoder
sample = labcomm.LabComm.sample
typedef = labcomm.LabComm.typedef
array = labcomm.LabComm.array
struct = labcomm.LabComm.struct
primitive = labcomm.LabComm.primitive
BOOLEAN = labcomm.LabComm.BOOLEAN
BYTE = labcomm.LabComm.BYTE
SHORT = labcomm.LabComm.SHORT
INTEGER = labcomm.LabComm.INTEGER
LONG = labcomm.LabComm.LONG
FLOAT = labcomm.LabComm.FLOAT
DOUBLE = labcomm.LabComm.DOUBLE
STRING = labcomm.LabComm.STRING
decl_from_signature = labcomm.LabComm.decl_from_signature
try:
import labcomm.TreeModel
TreeModel = labcomm.TreeModel.TreeModel
except:
pass
#!/usr/bin/python
#
# All packets follows the following layout
# LabComm2014 packet has the following layout
#
# +----+----+----+----+
# | id |
# | id (packed32)
# +----+----+----+----+
# | length (packed32)
# +----+----+----+----+
# | data
# | ...
# +----+--
#
# Data layouts for packets
# LabComm2014 SAMPLE_DEF:
#
# +----+----+----+----+
# | id = 0x02 (packed32)
# +----+----+----+----+
# | length (packed32)
# +----+----+----+----+
# | type number (packed32)
# +----+----+----+----+
# | type name (UTF8)
# | ...
# +----+----+----+----+
# | signature length (packed32)
# +----+----+----+----+
# | type signature
# | ...
# +----+--
#
# TYPEDEF:
# LabComm2014 SAMPLE_REF:
#
# +----+----+----+----+
# | id = 0x00000001 |
# | id = 0x03 (packed32)
# +----+----+----+----+
# | type number |
# | length (packed32)
# +----+----+----+----+
# | type number (packed32)
# +----+----+----+----+
# | type name (UTF8)
# | ...
# +----+----+----+----+
# | signature length (packed32)
# +----+----+----+----+
# | type signature
# | ...
# +----+--
#
# LabComm2014 TYPE_DEF: (as SAMPLE_DEF, but signatures are hierarchical,
# i.e., may contain references to other types
#
# +----+----+----+----+
# | id = 0x04 (packed32)
# +----+----+----+----+
# | length (packed32)
# +----+----+----+----+
# | type number (packed32)
# +----+----+----+----+
# | type name (UTF8)
# | ...
# +----+----+----+----+
# | type
# | signature length (packed32)
# +----+----+----+----+
# | type signature
# | ...
# +----+--
#
# LabComm2014 TYPE_BINDING
#
# +----+----+----+----+
# | id = 0x05 (packed32)
# +----+----+----+----+
# | length (packed32)
# +----+----+----+----+
# | sample number (packed32)
# +----+----+----+----+
# | type number (packed32)
# +----+----+----+----+
#
# LabComm2014 User data:
#
# +----+----+----+----+
# | id >= 0x00000040 (packed32)
# +----+----+----+----+
# | length (packed32)
# +----+----+----+----+
# | user data
# | ...
# +----+--
#
#
# SAMPLE:
# LabComm2006 packets has the following layout
#
# +----+----+----+----+
# | id |
# +----+----+----+----+
# | data
# | ...
# +----+--
#
# LabComm2006 SAMPLE:
#
# +----+----+----+----+
# | id = 0x00000002 |
......@@ -36,20 +109,20 @@
# | type name (UTF8)
# | ...
# +----+----+----+----+
# | type
# | type signature
# | ...
# +----+--
#
#
# User data:
# LabComm2006 User data:
#
# +----+----+----+----+
# | id >= 0x00000060 |
# | id >= 0x00000040 |
# +----+----+----+----+
# | user data
# | ...
# +----+--
#
#
#?? | field1 name
#?? | (length + UTF8)...
......@@ -87,24 +160,31 @@
#?? | fieldN data |
#?? | ... |
#?? +----+----+----+----+
#
#
# type numbers and lengths do not have a fixed lenght, but are packed into sequences
# of 7 bit chunks, represented in bytes with the high bit meaning that more data
# is to come.
#
# The chunks are sent "little endian": each 7 bit chunk is more significant than
# the previous. See encode_packed32 and decode_packed32 in in Codec classes below.
#
# type numbers and lengths do not have a fixed lenght, but are packed into
# sequences of 7 bit chunks, represented in bytes with the high bit meaning
# that more data is to come.
import types
import struct as packer
i_TYPEDEF = 0x01
i_SAMPLE = 0x02
DEFAULT_VERSION = "LabComm2014"
# Allowed packet tags
i_VERSION = 0x01
i_SAMPLE_DEF = 0x02
i_SAMPLE_REF = 0x03
i_TYPE_DEF = 0x04
i_TYPE_BINDING= 0x05
i_PRAGMA = 0x3f
i_USER = 0x40 # ..0xffffffff
# Predefined types
i_ARRAY = 0x10
i_STRUCT = 0x11
i_BOOLEAN = 0x20
i_BOOLEAN = 0x20
i_BYTE = 0x21
i_SHORT = 0x22
i_INTEGER = 0x23
......@@ -112,26 +192,62 @@ i_LONG = 0x24
i_FLOAT = 0x25
i_DOUBLE = 0x26
i_STRING = 0x27
i_SAMPLE = 0x28
# Version testing
def usePacketLength(version):
return version in [ None, "LabComm2014" ]
class length_encoder:
def __init__(self, encoder):
self.encoder = encoder
self.version = encoder.version
self.data = ""
i_USER = 0x40
def write(self, data):
self.data += data
def __enter__(self):
return Encoder(writer=self, version=None, codec=self.encoder)
def __exit__(self, type, value, traceback):
if usePacketLength(self.version):
self.encoder.encode_packed32(len(self.data))
self.encoder.pack("%ds" % len(self.data), self.data)
def indent(i, s):
return ("\n%s" % (" " * i)).join(s.split("\n"))
#
# Base type for all decl's
#
class type_decl(object):
pass
#
# Primitive types
#
class primitive(object):
class primitive(type_decl):
def decode_decl(self, decoder):
return self
def __eq__(self, other):
return self.__class__ == other.__class__
def __ne__(self, other):
return not self.__eq__(other)
def __hash__(self):
return hash(self.__class__)
class BOOLEAN(primitive):
def encode_decl(self, encoder):
return encoder.encode_type(i_BOOLEAN)
def encode(self, encoder, value):
return encoder.encode_boolean(value)
def decode(self, decoder, obj=None):
return decoder.decode_boolean()
......@@ -147,10 +263,10 @@ class BYTE(primitive):
def encode(self, encoder, value):
return encoder.encode_byte(value)
def decode(self, decoder, obj=None):
return decoder.decode_byte()
def new_instance(self):
return 0
......@@ -163,10 +279,10 @@ class SHORT(primitive):
def encode(self, encoder, value):
return encoder.encode_short(value)
def decode(self, decoder, obj=None):
return decoder.decode_short()
def new_instance(self):
return 0
......@@ -179,10 +295,10 @@ class INTEGER(primitive):
def encode(self, encoder, value):
return encoder.encode_int(value)
def decode(self, decoder, obj=None):
return decoder.decode_int()
def new_instance(self):
return 0
......@@ -195,10 +311,10 @@ class LONG(primitive):
def encode(self, encoder, value):
return encoder.encode_long(value)
def decode(self, decoder, obj=None):
return decoder.decode_long()
def new_instance(self):
return long(0)
......@@ -211,10 +327,10 @@ class FLOAT(primitive):
def encode(self, encoder, value):
return encoder.encode_float(value)
def decode(self, decoder, obj=None):
return decoder.decode_float()
def new_instance(self):
return 0.0
......@@ -227,10 +343,10 @@ class DOUBLE(primitive):
def encode(self, encoder, value):
return encoder.encode_double(value)
def decode(self, decoder, obj=None):
return decoder.decode_double()
def new_instance(self):
return 0.0
......@@ -243,39 +359,76 @@ class STRING(primitive):
def encode(self, encoder, value):
return encoder.encode_string(value)
def decode(self, decoder, obj=None):
return decoder.decode_string()
def new_instance(self):
return ""
def __repr__(self):
return "labcomm.STRING()"
class SAMPLE(primitive):
def encode_decl(self, encoder):
return encoder.encode_type(i_SAMPLE)
def encode(self, encoder, value):
if not isinstance(value, type_decl):
# Probably trying to encode a sample class, grab signature
value = value.signature
return encoder.encode_int(encoder.ref_to_index.get(value, 0))
def decode(self, decoder, obj=None):
return decoder.decode_ref()
def new_instance(self):
return ""
def __repr__(self):
return "labcomm.SAMPLE()"
# helper function
def dict_to_sorted_tuple(d):
tmpL = zip(d.keys(), d.values())
tmpL.sort()
return tuple(tmpL)
#
# Aggregate types
#
class sample_or_typedef(object):
def __init__(self, name, decl):
self.name = name
class sampledef_or_sampleref_or_typedef(type_decl):
def __init__(self, intentions={}, decl=None):
self.intentionDict = dict(intentions)
self.name = self.intentionDict.get('', None)
self.intentions = tuple(sorted(self.intentionDict.iteritems()))
self.decl = decl
def encode_decl_tail(self, encoder):
encoder.encode_type_number(self)
encoder.encode_string(self.name)
encoder.encode_type_number(self.decl)
def encode_decl(self, encoder):
encoder.encode_type(self.type_index)
with length_encoder(encoder) as e1:
e1.encode_type(self.get_index(encoder))
# XXX: temporary hack for intentions
e1.encode_intentions(self.intentions)
with length_encoder(e1) as e2:
self.decl.encode_decl(e2)
def encode(self, encoder, object):
self.decl.encode(encoder, object)
def encode(self, encoder, value):
self.decl.encode(encoder, value)
def decode_decl(self, decoder):
index = decoder.decode_type_number()
name = decoder.decode_string()
# XXX: temporary hack for intentions
# assume the name is the only intention
ints = decoder.decode_intentions()
if usePacketLength(decoder.version):
length = decoder.decode_packed32()
decl = decoder.decode_decl()
result = self.__class__.__new__(self.__class__)
result.__init__(name, decl)
decoder.add_decl(result, index)
result.__init__(intentions=ints, decl=decl)
self.add_index(decoder, index, result)
return result
def decode(self, decoder, obj=None):
......@@ -286,30 +439,81 @@ class sample_or_typedef(object):
def new_instance(self):
return self.decl.new_instance()
def __repr__(self):
return "'%s', %s" % (self.name, self.decl)
def __eq__(self, other):
return (self.__class__ == other.__class__ and
self.name == other.name and
self.decl == other.decl)
class sample(sample_or_typedef):
def encode_decl(self, encoder):
encoder.encode_type(i_SAMPLE)
self.encode_decl_tail(encoder)
def __ne__(self, other):
return not self.__eq__(other)
def __hash__(self):
return hash(self.__class__) ^ hash(self.name) ^ hash(self.decl)
def __repr__(self):
return "labcomm.sample(%s)" % super(sample, self).__repr__()
class typedef(sample_or_typedef):
return "%s('%s', %s)" % (self.type_name, self.name, self.decl)
class sample_def(sampledef_or_sampleref_or_typedef):
type_index = i_SAMPLE_DEF
type_name = 'sample'
def get_index(self, encoder):
return encoder.decl_to_index[self]
def add_index(self, decoder, index, decl):
decoder.add_decl(decl, index)
def rename(self, name):
newIntentions = dict(self.intentionDict)
newIntentions['']=name
return sample_def(newIntentions, decl=self.decl)
class sample_ref(sampledef_or_sampleref_or_typedef):
type_index = i_SAMPLE_REF
type_name = 'sample_ref'
def __init__(self, intentions={}, decl=None, sample=None):
self.intentionDict = dict(intentions)
self.name = self.intentionDict.get('', None) # XXX should we allow nameless?
self.decl = decl
self.intentions=tuple(sorted(self.intentionDict.iteritems()))
if sample == None and self.name != None and decl != None:
self.sample = sample_def(intentions, decl)
else:
self.sample = sample
def get_index(self, encoder):
return encoder.ref_to_index[self.sample]
def add_index(self, decoder, index, decl):
decoder.add_ref(decl, index)
class typedef(sampledef_or_sampleref_or_typedef):
type_index = i_TYPE_DEF
type_name = 'typedef'
def encode_decl(self, encoder):
encoder.encode_type(i_TYPEDEF)
self.encode_decl_tail(encoder)
self.decl.encode_decl(encoder)
def __repr__(self):
return "labcomm.typedef(%s)" % super(typedef, self).__repr__()
class array(object):
def encode(self, encoder, value):
self.decl.encode(encoder, value)
class array(type_decl):
def __init__(self, indices, decl):
self.indices = indices
self.indices = tuple(indices)
self.decl = decl
def __eq__(self, other):
return (self.__class__ == other.__class__ and
self.indices == other.indices and
self.decl == other.decl)
def __ne__(self, other):
return not self.__eq__(other)
def __hash__(self):
return hash(self.__class__) ^ hash(self.indices) ^ hash(self.decl)
def encode_decl(self, encoder):
encoder.encode_type(i_ARRAY)
encoder.encode_packed32(len(self.indices))
......@@ -317,19 +521,27 @@ class array(object):
encoder.encode_packed32(i)
encoder.encode_type_number(self.decl)
def min_max_shape(self, l, depth=0, shape=[]):
if isinstance(l, list):
def min_max_shape(self, l, depth, shape):
if isinstance(l, types.StringTypes):
return shape
try:
length = len(l)
if len(shape) <= depth:
shape.append((length, length))
pass
else:
(low, high) = shape[depth]
low = min(low, length)
high = max(high, length)
shape[depth] = (low, high)
pass
for e in l:
shape = self.min_max_shape(e, depth + 1, shape)
return shape
pass
pass
except TypeError:
pass
return shape
def shape(self, l):
shape = self.min_max_shape(l, 0, [])
......@@ -340,11 +552,10 @@ class array(object):
result.append(low)
return result
def encode_indices(self, encoder, value):
depth = len(self.indices)
shape = self.shape(value)
#if len(shape) != len(self.indices):
if len(shape) < len(self.indices):
raise Exception("Actual dimension %s differs from declared %s" %
(shape, self.indices))
......@@ -357,12 +568,12 @@ class array(object):
return depth
def encode_value(self, encoder, value, depth):
if depth and isinstance(value, list):
if depth:
for e in value:
self.encode_value(encoder, e, depth - 1)
else:
self.decl.encode(encoder, value)
def encode(self, encoder, value):
depth = self.encode_indices(encoder, value)
self.encode_value(encoder, value, depth)
......@@ -401,7 +612,7 @@ class array(object):
for i in range(indices[0]):
result.append(self.new_instance_value(indices[1:]))
return result
def new_instance(self):
indices = []
for i in self.indices:
......@@ -409,109 +620,124 @@ class array(object):
i = decoder.decode_packed32()
indices.append(i)
return self.new_instance_value(indices)
def __repr__(self):
return "labcomm.array(%s,\n %s)" % (
self.indices, indent(4, self.decl.__repr__()))
class struct:
class struct(type_decl):
def __init__(self, field):
self.field = field
self.field = tuple(field)
def __eq__(self, other):
return (self.__class__ == other.__class__ and
self.field == other.field)
def __ne__(self, other):
return not self.__eq__(other)
def __hash__(self):
return hash(self.__class__) ^ hash(self.field)
def encode_decl(self, encoder):
encoder.encode_type(i_STRUCT)
encoder.encode_packed32(len(self.field))
for (name, decl) in self.field:
encoder.encode_string(name)
encoder.encode_type_number(decl)
#type.encode_decl(encoder)
for (intentions, decl) in self.field:
encoder.encode_intentions(intentions)
encoder.encode_type_number(decl)
def encode(self, encoder, obj):
if isinstance(obj, dict):
for (name, decl) in self.field:
decl.encode(encoder, obj[name])
else:
for (name, decl) in self.field:
decl.encode(encoder, obj.__getattribute__(name))
try:
# hack to get names as keys in the obj:
tmp_foo = zip (map(lambda x:dict(x)[''],obj.keys()), obj.values())
tmp_obj = dict(tmp_foo)
for (intentions, decl) in self.field:
tmp = dict(intentions)
name = tmp['']
decl.encode(encoder, tmp_obj[name])
except AttributeError:
print "HERE BE DRAGONS! hack to get duck-typing example to work"
for (intentions, decl) in self.field:
tmp = dict(intentions)
name = tmp['']
print "trying to encode [%s] " % (name)
decl.encode(encoder, getattr(obj, name))
def decode_decl(self, decoder):
n_field = decoder.decode_packed32()
field = []
for i in range(n_field):
name = decoder.decode_string()
ints = decoder.decode_intentions()
decl = decoder.decode_decl()
field.append((name, decl))
field.append((ints, decl))
return struct(field)
def decode(self, decoder, obj=None):
if obj == None:
obj = decoder.create_object()
for (name, decl) in self.field:
obj.__setattr__(name, decl.decode(decoder))
for (intentions, decl) in self.field:
#name = dict(intentions)['']
obj.__setattr__(intentions, decl.decode(decoder))
return obj
def new_instance(self):
result = anonymous_object()
for (name, decl) in self.field:
for (intentions, decl) in self.field:
name = dict(intentions)['']
result.__setattr__(name, decl.new_instance())
return result
def __repr__(self):
delim = ""
result = "labcomm.struct(["
for (name, decl) in self.field:
for (intentions, decl) in self.field:
try:
name = dict(intentions)['']
except:
name = '(no name)'
result += "%s\n ('%s', %s)" % (delim, name, decl)
delim = ","
result += "\n])"
return result
SAMPLE = sample(None, None)
TYPEDEF = typedef(None, None)
SAMPLE_DEF = sample_def()
SAMPLE_REF = sample_ref()
ARRAY = array(None, None)
STRUCT = struct({})
class anonymous_object(object):
def __init__(self):
self._attr = {}
ARRAY = array([], None)
STRUCT = struct([])
class anonymous_object(dict):
def __setattr__(self, name, value):
if name.startswith("_"):
# XXX HERE BE DRAGONS! Is this OK:
if (str(name)).startswith("_"):
super(anonymous_object, self).__setattr__(name, value)
else:
self._attr[name] = value
self[name] = value
def __getattr__(self, name):
if name.startswith("_"):
return super(anonymous_object, self).__getattr__(name)
else:
return self._attr[name]
def __getattribute__(self, name):
if name.startswith("_"):
return super(anonymous_object, self).__getattribute__(name)
else:
return self._attr[name]
def __iter__(self):
return self._attr.iteritems()
return self[name]
def __repr__(self):
return self._attr.__repr__()
class Codec(object):
def __init__(self):
self.type_to_name = {}
self.name_to_type = {}
self.index_to_decl = {}
self.decl_to_index = {}
self.name_to_decl = {}
self.decl_index = i_USER
self.predefined_types()
def __init__(self, codec=None):
self.type_to_name = codec and codec.type_to_name or {}
self.name_to_type = codec and codec.name_to_type or {}
self.index_to_decl = codec and codec.index_to_decl or {}
self.decl_to_index = codec and codec.decl_to_index or {}
self.name_to_decl = codec and codec.name_to_decl or {}
self.index_to_ref = codec and codec.index_to_ref or {}
self.ref_to_index = codec and codec.ref_to_index or {}
self.name_to_ref = codec and codec.name_to_ref or {}
self.decl_index = codec and codec.decl_index or i_USER
self.ref_index = codec and codec.ref_index or i_USER
if not codec:
self.predefined_types()
def predefined_types(self):
self.add_decl(TYPEDEF, i_TYPEDEF)
self.add_decl(SAMPLE, i_SAMPLE)
self.add_decl(SAMPLE_DEF, i_SAMPLE_DEF)
self.add_decl(SAMPLE_REF, i_SAMPLE_REF)
self.add_decl(ARRAY, i_ARRAY)
self.add_decl(STRUCT, i_STRUCT)
......@@ -524,9 +750,12 @@ class Codec(object):
self.add_decl(FLOAT(), i_FLOAT)
self.add_decl(DOUBLE(), i_DOUBLE)
self.add_decl(STRING(), i_STRING)
self.add_decl(SAMPLE(), i_SAMPLE)
def add_decl(self, decl, index=0):
if index == 0:
if decl in self.decl_to_index:
return False
index = self.decl_index
self.decl_index += 1
self.index_to_decl[index] = decl
......@@ -535,7 +764,25 @@ class Codec(object):
self.name_to_decl[decl.name] = decl
except:
pass
return True
def add_ref(self, ref, index=0):
if not isinstance(ref, type_decl):
# Probably trying to register a sample class, grab signature
ref = ref.signature
if index == 0:
if ref.sample in self.ref_to_index:
return False
index = self.ref_index
self.ref_index += 1
self.index_to_ref[index] = ref.sample
self.ref_to_index[ref.sample] = index
try:
self.name_to_ref[ref.sample.name] = ref.sample
except:
pass
return True
def add_binding(self, name, decl):
self.type_to_name[decl] = name
self.name_to_type[name] = decl
......@@ -549,48 +796,82 @@ class Codec(object):
if i >= i_USER and isinstance(e, sample):
result.append(e)
return result
class Encoder(Codec):
def __init__(self, writer):
super(Encoder, self).__init__()
def __init__(self, writer, version=DEFAULT_VERSION, codec=None):
super(Encoder, self).__init__(codec)
self.writer = writer
self.version = version
if self.version in [ "LabComm2014" ]:
self.encode_type(i_VERSION)
with length_encoder(self) as e:
e.encode_string(version)
elif self.version in [ None, "LabComm2006" ]:
pass
else:
raise Exception("Unsupported labcomm version %s" % self.version)
def pack(self, format, *args):
self.writer.write(packer.pack(format, *args))
def add_decl(self, decl, index=0):
super(Encoder, self).add_decl(decl, index)
if not isinstance(decl, type_decl):
decl = decl.signature
if index == 0:
decl.encode_decl(self)
self.writer.mark()
self.writer.mark_begin(decl, None)
if super(Encoder, self).add_decl(decl, index):
decl.encode_decl(self)
self.writer.mark_end(decl, None)
def add_ref(self, ref, index=0):
if not isinstance(ref, type_decl):
# Trying to register a sample class
ref = ref.signature
decl = sample_ref(intentions=ref.intentions, decl=ref.decl, sample=ref)
if index == 0:
self.writer.mark_begin(ref, None)
if super(Encoder, self).add_ref(decl, index):
decl.encode_decl(self)
self.writer.mark_end(ref, None)
def encode(self, object, decl=None):
if decl == None:
name = self.type_to_name[object.__class__]
decl = self.name_to_decl[name]
if not isinstance(decl, type_decl):
decl = decl.signature
self.writer.mark_begin(decl, object)
self.encode_type_number(decl)
decl.encode(self, object)
self.writer.mark()
with length_encoder(self) as e:
decl.encode(e, object)
self.writer.mark_end(decl, object)
def encode_type_number(self, decl):
try:
self.encode_type(self.decl_to_index[decl])
except KeyError:
decl.encode_decl(self)
def encode_packed32(self, v):
tmp = v & 0xffffffff;
while(tmp >= 0x80 ):
self.encode_byte( (tmp & 0x7f) | 0x80 )
tmp >>= 7
self.encode_byte(tmp & 0x7f)
if self.version in [ None, "LabComm2014" ]:
v = v & 0xffffffff
tmp = [ v & 0x7f ]
v = v >> 7
while v:
tmp.append(v & 0x7f | 0x80)
v = v >> 7
for c in reversed(tmp):
self.encode_byte(c)
elif self.version == "LabComm2006" :
v = v & 0xffffffff
self.encode_int(v)
else :
raise Exception("Unsupported labcomm version %s" % self.version)
def encode_type(self, index):
self.encode_packed32(index)
# self.pack("!i", index)
def encode_boolean(self, v):
if v:
self.pack("!b", 1)
......@@ -598,7 +879,7 @@ class Encoder(Codec):
self.pack("!b", 0)
def encode_byte(self, v):
self.pack("!b", v)
self.pack("!B", v)
def encode_short(self, v):
self.pack("!h", v)
......@@ -619,13 +900,26 @@ class Encoder(Codec):
s = v.encode("utf8")
self.encode_packed32(len(s));
self.pack("%ds" % len(s),s)
# self.pack("!i%ds" % len(s), len(s), s)
def encode_intentions(self, intentions):
self.encode_packed32(len(intentions))
try:
for (k,v) in intentions:
self.encode_string(k)
self.encode_string(v)
except:
print "WARNING! encode_intentions: don't know what to do with %s" % intentions
class Decoder(Codec):
def __init__(self, reader):
def __init__(self, reader, version=DEFAULT_VERSION):
super(Decoder, self).__init__()
self.reader = reader
self.version = version
self.handlers = {}
def register_handler(self, decl, handler):
self.handlers[decl] = handler
def unpack(self, format):
size = packer.calcsize(format)
data = ""
......@@ -639,15 +933,73 @@ class Decoder(Codec):
result = self.index_to_decl[index]
if index < i_USER:
result = result.decode_decl(self)
else:
raise Exception('Should not be used')
return result
def skip(self, length):
for _ in xrange(length):
self.decode_byte()
# kludge, should really check if the index exists in self.version
def skip_or_raise(self, length, index):
if usePacketLength(self.version):
self.skip(length)
else:
raise Exception("Invalid type index %d" % index)
def runOne(self):
data,decl = self.decode()
# decode any signatures until next sample
while data == None:
data,decl = self.decode()
if decl:
if data != None:
if decl in self.handlers:
handler = self.handlers[decl]
handler(data)
else:
print ("No handler for %s" % decl.name )
for key, value in self.handlers.iteritems():
if key == decl:
print "but value %s == decl %s" % (key,decl)
print "hashes %d : %d" % (hash(key),hash(decl))
raise Exception()
def decode(self):
value = None
index = self.decode_type_number()
decl = self.index_to_decl[index]
if index == i_TYPEDEF or index == i_SAMPLE:
decl = decl.decode_decl(self)
while True:
index = self.decode_type_number()
if usePacketLength(self.version):
length = self.decode_packed32()
if index != i_VERSION:
break
else:
other_version = self.decode_string()
if self.version != other_version:
raise Exception("LabComm version mismatch %s != %s" %
(version, other_version))
if index == i_SAMPLE_DEF:
decl = self.index_to_decl[index].decode_decl(self)
value = None
elif index == i_SAMPLE_REF:
decl = self.index_to_decl[index].decode_decl(self)
value = None
elif index == i_TYPE_DEF:
self.skip_or_raise(length, index)
decl = None
value = None
elif index == i_TYPE_BINDING:
self.skip_or_raise(length, index)
decl = None
value = None
elif index == i_PRAGMA:
self.skip_or_raise(length, index)
decl = None
value = None
elif index < i_USER:
raise Exception("Invalid type index %d" % index)
else:
decl = self.index_to_decl[index]
value = decl.decode(self)
self.reader.mark(value, decl)
return (value, decl)
......@@ -664,45 +1016,62 @@ class Decoder(Codec):
result = anonymous_object()
return result
def decode_packed32(self):
res = 0
i = 0
cont = True
while (cont):
c = self.decode_byte()
res |= (c & 0x7f) << 7*i
cont = (c & 0x80) != 0;
return res
if self.version in [ "LabComm2013", "LabComm2014" ] :
result = 0
while True:
tmp = self.decode_byte()
result = (result << 7) | (tmp & 0x7f)
if (tmp & 0x80) == 0:
break
return result
elif self.version == "LabComm2006" :
return self.decode_int()
else :
raise Exception("Unsupported labcomm version %s" % self.version)
def decode_type_number(self):
return self.decode_packed32()
def decode_boolean(self):
return self.unpack("!b") != 0
def decode_byte(self):
return self.unpack("!b")
return self.unpack("!B")
def decode_short(self):
return self.unpack("!h")
def decode_int(self):
return self.unpack("!i")
def decode_long(self):
return self.unpack("!q")
def decode_float(self):
return self.unpack("!f")
def decode_double(self):
return self.unpack("!d")
def decode_string(self):
length = self.decode_packed32()
length = self.decode_packed32()
return self.unpack("!%ds" % length).decode("utf8")
def decode_ref(self):
index = self.decode_int()
return self.index_to_ref.get(index, None)
def decode_intentions(self):
numIntentions = self.decode_packed32()
res = {}
for i in range(numIntentions):
key = self.decode_string()
val = self.decode_string()
res[key] = val
result = dict_to_sorted_tuple(res)
return result
class signature_reader:
def __init__(self, signature):
......@@ -712,7 +1081,7 @@ class signature_reader:
result = self.signature[0:count]
self.signature = self.signature[count:]
return result
def decl_from_signature(signature):
decoder = Decoder(signature_reader(signature))
t = decoder.decode_decl()
......
class StreamReader:
def __init__(self, stream):
self.stream = stream
pass
def read(self, count):
result = self.stream.read(count)
if len(result) == 0:
raise EOFError()
return result
def mark(self, value, decl):
pass
pass
class StreamWriter:
def __init__(self, stream):
self.stream = stream
pass
def write(self, data):
self.stream.write(data)
pass
def mark_begin(self, decl, value):
pass
def mark_end(self, decl, value):
self.stream.flush()
pass
pass
__all__ = [ 'LabComm' ]
import LabComm
from StreamReader import StreamReader
from StreamWriter import StreamWriter
Decoder = LabComm.Decoder
Encoder = LabComm.Encoder
sample = LabComm.sample_def
sample_def = LabComm.sample_def
sample_ref = LabComm.sample_ref
typedef = LabComm.typedef
array = LabComm.array
struct = LabComm.struct
primitive = LabComm.primitive
BOOLEAN = LabComm.BOOLEAN
BYTE = LabComm.BYTE
SHORT = LabComm.SHORT
INTEGER = LabComm.INTEGER
LONG = LabComm.LONG
FLOAT = LabComm.FLOAT
DOUBLE = LabComm.DOUBLE
STRING = LabComm.STRING
SAMPLE = LabComm.SAMPLE
decl_from_signature = LabComm.decl_from_signature
labcomm2014-*.src.rpm
rpmbuild
.PHONY: all
all:
.PHONY: test
test:
.PHONY: clean
clean:
rm -rf rpmbuild
rm -f *~
.PHONY: distclean
distclean: clean
rm -f labcomm-*.src.rpm
.PHONY: srpm
srpm:
./make_srpm
#!/bin/sh
spec() {
cat << 'EOF'
Name: labcomm__SUFFIX__
Version: __VERSION__
Release: 1
Summary: LabComm communication protocol
License: GPLv3
# https://gitlab.control.lth.se/anders_blomdell/labcomm/repository/archive.tar.gz?__COMMIT__
Source0: labcomm.__DESCRIBE__.tar.gz
BuildRequires: gcc
BuildRequires: ant
BuildRequires: java
BuildRequires: mono-core
%description
LabComm communication protocol
%package devel
Summary: LabComm communication protocol
Requires: %{name} = %{version}-%{release}
%description devel
LabComm communication protocol
%
%prep
%setup -q -c -a 0
%build
pwd
make
%install
#
# C
#
install -d ${RPM_BUILD_ROOT}/%{_libdir}
install lib/c/liblabcomm2014.a ${RPM_BUILD_ROOT}/%{_libdir}/
install lib/c/liblabcomm2014.so.1 ${RPM_BUILD_ROOT}/%{_libdir}/liblabcomm2014.so.__VERSION__
ln -s liblabcomm2014.so.__VERSION__ ${RPM_BUILD_ROOT}/%{_libdir}/liblabcomm2014.so
install -d ${RPM_BUILD_ROOT}/%{_includedir}/labcomm
install lib/c/2014/*h ${RPM_BUILD_ROOT}/%{_includedir}/labcomm
#
# java
#
install -d ${RPM_BUILD_ROOT}/usr/lib
install -m u=r,g=r,o=r compiler/labcomm2014_compiler.jar ${RPM_BUILD_ROOT}/usr/lib
install -m u=r,g=r,o=r lib/java/labcomm2014.jar ${RPM_BUILD_ROOT}/usr/lib
install -d ${RPM_BUILD_ROOT}/%{_bindir}
install -m u=rx,g=rx,o=rx \
compiler/labcomm2014 ${RPM_BUILD_ROOT}/%{_bindir}/labcomm2014
ls -l ${RPM_BUILD_ROOT}/%{_bindir}
#
# C#
#
install -d ${RPM_BUILD_ROOT}/usr/lib
install -m u=r,g=r,o=r lib/csharp/labcomm2014.dll ${RPM_BUILD_ROOT}/usr/lib
#
# Python
#
install -d ${RPM_BUILD_ROOT}/%{python_sitelib}/labcomm2014
install lib/python/labcomm2014/* ${RPM_BUILD_ROOT}/%{python_sitelib}/labcomm2014
%files
%defattr (-, root, root)
%exclude /usr/lib/debug
%exclude /usr/lib/labcomm2014_compiler.jar
/usr/lib/*
%{_libdir}/*
%files devel
%defattr (-, root, root)
/usr/lib/labcomm2014_compiler.jar
%{_includedir}/labcomm/*
%{_bindir}/*
EOF
}
# Create a suitable directory for rpmbuild
rm -rf rpmbuild
mkdir -p rpmbuild/BUILD
mkdir -p rpmbuild/SPECS
mkdir -p rpmbuild/RPMS
mkdir -p rpmbuild/SRPMS
mkdir -p rpmbuild/SOURCES
rm -rf rpmbuild/SOURCES/*
# Create spec and .tar.gz
DESCRIBE=$(git describe | sed -e 's/^v\(.*\)/\1/')
SUFFIX=$(echo ${DESCRIBE} | sed -e 's/^\([^.]*\)[.].*$/\1/g')
VERSION=$(echo ${DESCRIBE} | sed -e 's/^[^.]*[.]\(.*\)/\1/g;s/-/./g')
COMMIT=$(git rev-parse HEAD)
(
spec | \
sed -e "s/__SUFFIX__/${SUFFIX}/g" | \
sed -e "s/__VERSION__/${VERSION}/g" | \
sed -e "s/__DESCRIBE__/${DESCRIBE}/g" | \
sed -e "s/__COMMIT__/${COMMIT}/g" \
) > rpmbuild/SPECS/labcomm.spec
(
cd $(git rev-parse --show-toplevel)
git archive --format tar HEAD
) > rpmbuild/SOURCES/labcomm.${DESCRIBE}.tar.gz
rpmbuild --define "_topdir $(pwd)/rpmbuild" \
-bs rpmbuild/SPECS/labcomm.spec 2>&1 | sed -e 's|rpmbuild/SRPMS/||g'
mv rpmbuild/SRPMS/* .
gen
TESTS=basic simple nested ref
LABCOMM_JAR=../compiler/labcomm2014_compiler.jar
LABCOMM=java -jar $(LABCOMM_JAR)
MONO_PATH=$(shell pwd)/../lib/csharp
PYTHONPATH=$(shell pwd)/../lib/python
include ../lib/c/os_compat.mk
all:
test: $(TESTS:%=test_%) $(TESTS:%=test_renaming_%) compiler_errors
# PYTHONPATH=../lib/python \
# ./test_encoder_decoder.py --labcomm="$(LABCOMM)" basic.lc
.PHONY: clean distclean
clean distclean:
rm -rf gen
.PHONY: test_%
test_%: gen/%/signatures.py \
gen/%/c_relay \
gen/%/cs_relay.exe \
gen/%/java_relay.class \
gen/%/java_code
PYTHONPATH=$(PYTHONPATH) MONO_PATH=$(MONO_PATH) \
./test_encoder_decoder.py \
--signatures=gen/$*/signatures.py \
--test tee gen/$*/testdata \
--test $(shell echo $(VALGRIND) | sed -e 's/[-][-]/\\\\--/g') \
gen/$*/c_relay /dev/stdin /dev/stdout \
--test mono gen/$*/cs_relay.exe /dev/stdin /dev/stdout \
--test java \\-cp gen/$*:../lib/java/labcomm2014.jar \
java_relay /dev/stdin /dev/stdout
.PHONY: test_renaming_%
test_renaming_%: gen/%/signatures.py \
gen/%/c_renaming_relay \
gen/%/cs_renaming_relay.exe \
gen/%/java_relay.class \
gen/%/java_code
PYTHONPATH=$(PYTHONPATH) MONO_PATH=$(MONO_PATH) \
./test_renaming_encoder_decoder.py \
--signatures=gen/$*/signatures.py \
--test tee gen/$*/testdata.renamed \
--test $(shell echo $(VALGRIND) | sed -e 's/[-][-]/\\\\--/g') \
gen/$*/c_renaming_relay /dev/stdin /dev/stdout \
--test mono gen/$*/cs_renaming_relay.exe \
/dev/stdin /dev/stdout
echo \
--test java \\-cp gen/$*:../lib/java/labcomm2014.jar \
java_relay /dev/stdin /dev/stdout
# test cases for compiler error checking
.PHONY: compiler_errors testErrorsOK testErrorsNOK
compiler_errors: testErrorsOK testErrorsNOK
# tests that should succeed
testErrorsOK: $(wildcard errors/correct/*.lc)
./test_errors.py --labcomm="$(LABCOMM)" --testOK $^
# tests that should fail
testErrorsNOK: $(wildcard errors/incorrect/*.lc)
./test_errors.py --labcomm="$(LABCOMM)" --testNOK $^
.PRECIOUS: gen/%/.dir
gen/%/.dir:
mkdir -p gen/$*
touch $@
.PRECIOUS: gen/%/typeinfo
gen/%/typeinfo: %.lc Makefile | gen/%/.dir
$(LABCOMM) --typeinfo=$@ $<
.PRECIOUS: gen/%/signatures.py
gen/%/signatures.py: %.lc Makefile | gen/%/.dir
$(LABCOMM) --python=$@ $<
# C relay test rules
.PRECIOUS: gen/%/c_code.h gen/%/c_code.c
gen/%/c_code.h gen/%/c_code.c: %.lc Makefile | gen/%/.dir
$(LABCOMM) --c=gen/$*/c_code.c --h=gen/$*/c_code.h $<
.PRECIOUS: gen/%/c_relay.c
gen/%/c_relay.c: gen/%/typeinfo relay_gen_c.py Makefile
./relay_gen_c.py $< > $@
.PRECIOUS: gen/%/c_relay
gen/%/c_relay: gen/%/c_relay.c gen/%/c_code.c Makefile
$(CC) $(CFLAGS) -o $@ $< -I../lib/c/2014 -I. -L../lib/c \
gen/$*/c_code.c -llabcomm2014
.PRECIOUS: gen/%/c_renaming_relay.c
gen/%/c_renaming_relay.c: gen/%/typeinfo relay_gen_c.py Makefile
./relay_gen_c.py --renaming $< > $@
.PRECIOUS: gen/%/c_renaming_relay
gen/%/c_renaming_relay: gen/%/c_renaming_relay.c gen/%/c_code.c Makefile
$(CC) $(CFLAGS) -o $@ $< -I../lib/c/2014 -I. -L../lib/c \
gen/$*/c_code.c -llabcomm2014
# C# relay test rules
.PRECIOUS: gen/%/cs_code.cs
gen/%/cs_code.cs: %.lc Makefile | gen/%/.dir
$(LABCOMM) --cs=$@ $<
.PRECIOUS: gen/%/cs_relay.cs
gen/%/cs_relay.cs: gen/%/typeinfo relay_gen_cs.py Makefile
./relay_gen_cs.py $< > $@
.PRECIOUS: gen/%/cs_relay.exe
gen/%/cs_relay.exe: gen/%/cs_relay.cs gen/%/cs_code.cs Makefile
mcs -out:$@ $(filter %.cs, $^) -lib:../lib/csharp/ -r:labcomm2014
.PRECIOUS: gen/%/cs_renaming_relay.cs
gen/%/cs_renaming_relay.cs: gen/%/typeinfo relay_gen_cs.py Makefile
./relay_gen_cs.py --renaming $< > $@
.PRECIOUS: gen/%/cs_renaming_relay.exe
gen/%/cs_renaming_relay.exe: gen/%/cs_renaming_relay.cs \
gen/%/cs_code.cs Makefile
mcs -out:$@ $(filter %.cs, $^) -lib:../lib/csharp/ -r:labcomm2014
# Java relay test rules
.PRECIOUS: gen/%/java_code
gen/%/java_code: %.lc | gen/%/.dir
mkdir -p $@
$(LABCOMM) --java=$@ $<
.PRECIOUS: gen/%/java_relay.java
gen/%/java_relay.java: gen/%/typeinfo relay_gen_java.py Makefile
./relay_gen_java.py $< > $@
.PRECIOUS: gen/%/java_relay.class
gen/%/java_relay.class: gen/%/java_relay.java gen/%/java_code Makefile
javac -d gen/$* -cp ../lib/java/labcomm2014.jar:gen/$*/java_code $<
sample void s_void;
sample byte s_byte;
sample short s_short;
sample int s_int;
sample long s_long;
sample float s_float;
sample double s_double;
sample boolean s_boolean;
sample string s_string;
def gen(f, signatures):
print """
#include <labcomm.h>
#include <labcomm_fd_reader_writer.h>
#include "%(f)s.h"
""" % { 'f': f }
for s in [s.name for s in signatures]:
t = "%s_%s" % (f, s)
print """
void handle_%(t)s(%(t)s *v, void *context)
{
struct labcomm_encoder *e = context;
labcomm_encode_%(t)s(e, v);
}
""" % {'t':t}
print """
int main(int argc, char *argv[]) {
struct labcomm_decoder *d;
struct labcomm_encoder *e;
"""
#!/usr/bin/python
import os
import re
import subprocess
import sys
def gen(classname, namespace, signatures):
yield 'using System;'
yield 'using System.IO;'
yield 'using se.lth.control.labcomm;'
yield ''
yield 'class %s :' % classname
for s in signatures[0:-1]:
yield '%s%s.Handler,' % (namespace, s.name)
yield '%s%s.Handler' % (namespace, signatures[-1].name)
yield '{'
yield ''
yield ' LabCommEncoderChannel encoder;'
for s in signatures:
yield ''
if s.type == 'void':
yield ' void %s%s.Handler.handle() {' % ( namespace, s.name)
else:
yield ' void %s%s.Handler.handle(%s data) {' % (
namespace, s.name, s.type)
yield ' Console.Error.WriteLine("%s%s");' % (namespace, s.name)
if s.type == 'void':
yield ' %s%s.encode(encoder);' % (namespace, s.name)
else:
yield ' %s%s.encode(encoder, data);' % (namespace, s.name)
yield ' }'
yield ''
yield ' public %s(String InName, String OutName) {' % (classname)
yield ' FileStream InFile = new FileStream(InName,'
yield ' FileMode.Open, '
yield ' FileAccess.Read);'
yield ' LabCommDecoderChannel d = new LabCommDecoderChannel(InFile);'
yield ' FileStream OutFile = new FileStream(OutName, '
yield ' FileMode.OpenOrCreate, '
yield ' FileAccess.Write);'
yield ' encoder = new LabCommEncoderChannel(OutFile);'
yield ''
for s in signatures:
yield ' %s%s.register(d, this);' % (namespace, s.name)
yield ''
for s in signatures:
yield ' %s%s.register(encoder);' % (namespace, s.name)
yield ''
yield ' try {'
yield ' d.run();'
yield ' } catch (EndOfStreamException) {'
yield ' }'
yield ''
yield ' }'
yield ''
yield ' static void Main(String[] arg) {'
yield ' new %s(arg[0], arg[1]);' % (classname)
yield ' }'
yield ''
yield '}'
class Signature:
def __init__(self, name, type):
self.name = name
self.type = type
def test_program(target, typeinfo):
f = open(typeinfo)
signature = []
for l in f:
m = re.match('C#,sample,([^,]+),(.*)', l)
if m:
signature.append(Signature(m.group(1), m.group(2)))
f.close()
f = open(target, "w")
for l in gen("x", "", signature):
f.write(l + "\n")
f.close()
if __name__ == "__main__":
#os.system("labcomm --typeinfo=/dev/stdout %s" % sys.argv[1])
typeinfo = subprocess.Popen(["labcomm",
"--typeinfo=/dev/stdout %s" % sys.argv[1]],
stdout=subprocess.PIPE)
signature = []
for l in typeinfo.stdout:
m = re.match('C#,sample,([^,]+),(.*)', l)
if m:
signature.append(Signature(m.group(1), m.group(2)))
for l in gen("x", "", signature):
print l
typedef struct {
string topic;
} pubsub;
sample pubsub subscribe;
sample pubsub unsubscribe;
sample pubsub publish;
sample pubsub unpublish;
typedef void avoid;
sample avoid doavoid;
// examples of errors: void may not be used
// in structs or arrays
//
// sample struct {
// int a;
// avoid error;
//} foo;
//
//sample void error2[2] ;
//sample avoid error3[_];
typedef void avoid;
// examples of errors: void may not be used
// in structs or arrays
//
sample struct {
int a;
avoid error_1;
} foo;
sample void error_2[2] ;
sample avoid error_3[_];
typedef int int_array_ss[1][_, 3, _][5];
sample struct { int aa; boolean bb; int_array_ss ias; } struct_array_ss[1][_][_];
sample int s_array_array_array[1][1, 1][1, 1, 1];
sample struct {
int b[1][1, 1];
int c[1][_, 1, _][_,_];
} struct_array_ss[1];
typedef int int_t;
typedef int int_array_t[1][2][3,4];
typedef struct { int a; } struct_t;
......@@ -18,3 +20,6 @@ sample int_array_t int_array_t_s;
sample struct_t struct_t_s;
sample struct_array_t struct_array_t_s;
sample struct_struct_t struct_struct_t_s;
sample string string_array[_];
sample struct { string s[_]; } string_struct_array;
sample sample s1;
sample sample s2;
sample sample s3;
sample sample sample_list[4];