VOL-1395: Common shared libraries needed for Python based device adapters.

This is an initial check-in of code from the master branch.  Additional work
is expected on a few items to work with the new go-core and will be covered
by separate JIRAs and commits.

Change-Id: I0856ec6b79b8d3e49082c609eb9c7eedd75b1708
diff --git a/python/adapters/extensions/omci/omci_messages.py b/python/adapters/extensions/omci/omci_messages.py
new file mode 100644
index 0000000..04d3e83
--- /dev/null
+++ b/python/adapters/extensions/omci/omci_messages.py
@@ -0,0 +1,551 @@
+#
+# Copyright 2017 the original author or authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+import structlog
+from scapy.fields import ByteField, ThreeBytesField, StrFixedLenField, ConditionalField, IntField, Field
+from scapy.fields import ShortField, BitField
+from scapy.packet import Packet
+
+from voltha.extensions.omci.omci_defs import AttributeAccess, OmciSectionDataSize
+from voltha.extensions.omci.omci_fields import OmciTableField
+import voltha.extensions.omci.omci_entities as omci_entities
+
+
+log = structlog.get_logger()
+
+
+class OmciData(Field):
+
+    __slots__ = Field.__slots__ + ['_entity_class']
+
+    def __init__(self, name, entity_class="entity_class"):
+        Field.__init__(self, name=name, default=None, fmt='s')
+        self._entity_class = entity_class
+
+    def addfield(self, pkt, s, val):
+        class_id = getattr(pkt, self._entity_class)
+        entity_class = omci_entities.entity_id_to_class_map.get(class_id)
+        for attribute in entity_class.attributes:
+            if AttributeAccess.SetByCreate not in attribute.access:
+                continue
+            if attribute.field.name == 'managed_entity_id':
+                continue
+            fld = attribute.field
+            s = fld.addfield(pkt, s, val.get(fld.name, fld.default))
+        return s
+
+    def getfield(self, pkt, s):
+        """Extract an internal value from a string"""
+        class_id = getattr(pkt, self._entity_class)
+        entity_class = omci_entities.entity_id_to_class_map.get(class_id)
+        data = {}
+        for attribute in entity_class.attributes:
+            if AttributeAccess.SetByCreate not in attribute.access:
+                continue
+            if attribute.field.name == 'managed_entity_id':
+                continue
+            fld = attribute.field
+            s, value = fld.getfield(pkt, s)
+            data[fld.name] = value
+        return s, data
+
+
+class OmciMaskedData(Field):
+
+    __slots__ = Field.__slots__ + ['_entity_class', '_attributes_mask']
+
+    def __init__(self, name, entity_class="entity_class",
+                 attributes_mask="attributes_mask"):
+        Field.__init__(self, name=name, default=None, fmt='s')
+        self._entity_class = entity_class
+        self._attributes_mask = attributes_mask
+
+    def addfield(self, pkt, s, val):
+        class_id = getattr(pkt, self._entity_class)
+        attribute_mask = getattr(pkt, self._attributes_mask)
+        entity_class = omci_entities.entity_id_to_class_map.get(class_id)
+        indices = entity_class.attribute_indices_from_mask(attribute_mask)
+        for index in indices:
+            fld = entity_class.attributes[index].field
+            s = fld.addfield(pkt, s, val[fld.name])
+        return s
+
+    def getfield(self, pkt, s):
+        """Extract an internal value from a string"""
+        class_id = getattr(pkt, self._entity_class)
+        attribute_mask = getattr(pkt, self._attributes_mask)
+        entity_class = omci_entities.entity_id_to_class_map[class_id]
+        indices = entity_class.attribute_indices_from_mask(attribute_mask)
+        data = {}
+        table_attribute_mask = 0
+        for index in indices:
+            try:
+                fld = entity_class.attributes[index].field
+            except IndexError, e:
+                log.error("attribute-decode-failure", attribute_index=index,
+                          entity_class=entity_class, e=e)
+                continue
+            try:
+                s, value = fld.getfield(pkt, s)
+            except Exception, _e:
+                raise
+            if isinstance(pkt, OmciGetResponse) and isinstance(fld, OmciTableField):
+                data[fld.name + '_size'] = value
+                table_attribute_mask = table_attribute_mask | (1 << (15 - index))
+            else:
+                data[fld.name] = value
+        if table_attribute_mask:
+            data['table_attribute_mask'] = table_attribute_mask
+        return s, data
+
+
+class OmciMessage(Packet):
+    name = "OmciMessage"
+    message_id = None  # OMCI message_type value, filled by derived classes
+    fields_desc = []
+
+
+class OmciCreate(OmciMessage):
+    name = "OmciCreate"
+    message_id = 0x44
+    fields_desc = [
+        ShortField("entity_class", None),
+        ShortField("entity_id", 0),
+        OmciData("data")
+    ]
+
+
+class OmciCreateResponse(OmciMessage):
+    name = "OmciCreateResponse"
+    message_id = 0x24
+    fields_desc = [
+        ShortField("entity_class", None),
+        ShortField("entity_id", None),
+        ByteField("success_code", 0),
+        ShortField("parameter_error_attributes_mask", None),
+    ]
+
+
+class OmciDelete(OmciMessage):
+    name = "OmciDelete"
+    message_id = 0x46
+    fields_desc = [
+        ShortField("entity_class", None),
+        ShortField("entity_id", None),
+    ]
+
+
+class OmciDeleteResponse(OmciMessage):
+    name = "OmciDeleteResponse"
+    message_id = 0x26
+    fields_desc = [
+        ShortField("entity_class", None),
+        ShortField("entity_id", None),
+        ByteField("success_code", 0),
+    ]
+
+
+class OmciSet(OmciMessage):
+    name = "OmciSet"
+    message_id = 0x48
+    fields_desc = [
+        ShortField("entity_class", None),
+        ShortField("entity_id", 0),
+        ShortField("attributes_mask", None),
+        OmciMaskedData("data")
+    ]
+
+
+class OmciSetResponse(OmciMessage):
+    name = "OmciSetResponse"
+    message_id = 0x28
+    fields_desc = [
+        ShortField("entity_class", None),
+        ShortField("entity_id", None),
+        ByteField("success_code", 0),
+        ShortField("unsupported_attributes_mask", None),
+        ShortField("failed_attributes_mask", None),
+    ]
+
+
+class OmciGet(OmciMessage):
+    name = "OmciGet"
+    message_id = 0x49
+    fields_desc = [
+        ShortField("entity_class", None),
+        ShortField("entity_id", 0),
+        ShortField("attributes_mask", None)
+    ]
+
+
+class OmciGetResponse(OmciMessage):
+    name = "OmciGetResponse"
+    message_id = 0x29
+    fields_desc = [
+        ShortField("entity_class", None),
+        ShortField("entity_id", 0),
+        ByteField("success_code", 0),
+        ShortField("attributes_mask", None),
+        ConditionalField(
+            OmciMaskedData("data"), lambda pkt: pkt.success_code == 0)
+    ]
+
+
+class OmciGetAllAlarms(OmciMessage):
+    name = "OmciGetAllAlarms"
+    message_id = 0x4b
+    fields_desc = [
+        ShortField("entity_class", 2),  # Always 2 (ONT data)
+        ShortField("entity_id", 0),  # Always 0 (ONT instance)
+        ByteField("alarm_retrieval_mode", 0)  # 0 or 1
+    ]
+
+
+class OmciGetAllAlarmsResponse(OmciMessage):
+    name = "OmciGetAllAlarmsResponse"
+    message_id = 0x2b
+    fields_desc = [
+        ShortField("entity_class", 2),  # Always 2 (ONT data)
+        ShortField("entity_id", 0),
+        ShortField("number_of_commands", None)
+    ]
+
+
+class OmciGetAllAlarmsNext(OmciMessage):
+    name = "OmciGetAllAlarmsNext"
+    message_id = 0x4c
+    fields_desc = [
+        ShortField("entity_class", 2),  # Always 2 (ONT data)
+        ShortField("entity_id", 0),
+        ShortField("command_sequence_number", None)
+    ]
+
+
+class OmciGetAllAlarmsNextResponse(OmciMessage):
+    name = "OmciGetAllAlarmsNextResponse"
+    message_id = 0x2c
+    fields_desc = [
+        ShortField("entity_class", 2),  # Always 2 (ONT data)
+        ShortField("entity_id", 0),
+        ShortField("alarmed_entity_class", None),
+        ShortField("alarmed_entity_id", 0),
+        BitField("alarm_bit_map", None, 224)
+    ]
+
+
+class OmciMibUpload(OmciMessage):
+    name = "OmciMibUpload"
+    message_id = 0x4d
+    fields_desc = [
+        ShortField("entity_class", 2),  # Always 2 (ONT data)
+        ShortField("entity_id", 0),
+    ]
+
+
+class OmciMibUploadResponse(OmciMessage):
+    name = "OmciMibUploadResponse"
+    message_id = 0x2d
+    fields_desc = [
+        ShortField("entity_class", 2),  # Always 2 (ONT data)
+        ShortField("entity_id", 0),
+        ShortField("number_of_commands", None)
+    ]
+
+
+class OmciMibUploadNext(OmciMessage):
+    name = "OmciMibUploadNext"
+    message_id = 0x4e
+    fields_desc = [
+        ShortField("entity_class", 2),  # Always 2 (ONT data)
+        ShortField("entity_id", 0),
+        ShortField("command_sequence_number", None)
+    ]
+
+
+class OmciMibUploadNextResponse(OmciMessage):
+    name = "OmciMibUploadNextResponse"
+    message_id = 0x2e
+    fields_desc = [
+        ShortField("entity_class", 2),  # Always 2 (ONT data)
+        ShortField("entity_id", 0),
+        ShortField("object_entity_class", None),
+        ShortField("object_entity_id", 0),
+        ShortField("object_attributes_mask", None),
+        OmciMaskedData("object_data", entity_class='object_entity_class',
+                       attributes_mask='object_attributes_mask')
+    ]
+
+
+class OmciMibReset(OmciMessage):
+    name = "OmciMibReset"
+    message_id = 0x4f
+    fields_desc = [
+        ShortField("entity_class", None),
+        ShortField("entity_id", 0)
+    ]
+
+
+class OmciMibResetResponse(OmciMessage):
+    name = "OmciMibResetResponse"
+    message_id = 0x2f
+    fields_desc = [
+        ShortField("entity_class", None),
+        ShortField("entity_id", 0),
+        ByteField("success_code", 0)
+    ]
+
+
+class OmciAlarmNotification(OmciMessage):
+    name = "AlarmNotification"
+    message_id = 0x10
+    fields_desc = [
+        ShortField("entity_class", None),
+        ShortField("entity_id", 0),
+        BitField("alarm_bit_map", 0, 224),
+        ThreeBytesField("zero_padding", 0),
+        ByteField("alarm_sequence_number", None)
+    ]
+
+
+class OmciAttributeValueChange(OmciMessage):
+    name = "AttributeValueChange"
+    message_id = 0x11
+    fields_desc = [
+        ShortField("entity_class", None),
+        ShortField("entity_id", 0),
+        ShortField("attributes_mask", None),
+        OmciMaskedData("data")
+    ]
+
+
+class OmciTestResult(OmciMessage):
+    name = "TestResult"
+    message_id = 0x1B
+    fields_desc = [
+        ShortField("entity_class", None),
+        ShortField("entity_id", 0)
+        # ME Test specific message contents starts here
+        # TODO: Can this be coded easily with scapy?
+    ]
+
+
+class OmciReboot(OmciMessage):
+    name = "OmciOnuReboot"
+    message_id = 0x59
+    fields_desc = [
+        ShortField("entity_class", None),
+        ShortField("entity_id", 0),
+        ByteField("reboot_code", 0)
+    ]
+
+
+class OmciRebootResponse(OmciMessage):
+    name = "OmciOnuRebootResponse"
+    message_id = 0x39
+    fields_desc = [
+        ShortField("entity_class", None),
+        ShortField("entity_id", 0),
+        ByteField("success_code", 0)
+    ]
+
+
+class OmciGetNext(OmciMessage):
+    name = "OmciGetNext"
+    message_id = 0x5A
+    fields_desc = [
+        ShortField("entity_class", None),
+        ShortField("entity_id", 0),
+        ShortField("attributes_mask", None),
+        ShortField("command_sequence_number", None)
+    ]
+
+
+class OmciGetNextResponse(OmciMessage):
+    name = "OmciGetNextResponse"
+    message_id = 0x3A
+    fields_desc = [
+        ShortField("entity_class", None),
+        ShortField("entity_id", 0),
+        ByteField("success_code", 0),
+        ShortField("attributes_mask", None),
+        ConditionalField(OmciMaskedData("data"),
+                         lambda pkt: pkt.success_code == 0)
+    ]
+
+
+class OmciSynchronizeTime(OmciMessage):
+    name = "OmciSynchronizeTime"
+    message_id = 0x58
+    fields_desc = [
+        ShortField("entity_class", 256),  # OntG
+        ShortField("entity_id", 0),
+        ShortField("year", 0),       # eg) 2018
+        ByteField("month", 0),       # 1..12
+        ByteField("day", 0),         # 1..31
+        ByteField("hour", 0),        # 0..23
+        ByteField("minute", 0),      # 0..59
+        ByteField("second", 0)       # 0..59
+    ]
+
+
+class OmciSynchronizeTimeResponse(OmciMessage):
+    name = "OmciSynchronizeTimeResponse"
+    message_id = 0x38
+    fields_desc = [
+        ShortField("entity_class", 256),  # OntG
+        ShortField("entity_id", 0),
+        ByteField("success_code", 0),
+        ConditionalField(ShortField("success_info", None),
+                         lambda pkt: pkt.success_code == 0)
+    ]
+
+
+class OmciGetCurrentData(OmciMessage):
+    name = "OmciGetCurrentData"
+    message_id = 0x5C
+    fields_desc = [
+        ShortField("entity_class", None),
+        ShortField("entity_id", 0),
+        ShortField("attributes_mask", None),
+    ]
+
+
+class OmciGetCurrentDataResponse(OmciMessage):
+    name = "OmciGetCurrentDataResponse"
+    message_id = 0x3C
+    fields_desc = [
+        ShortField("entity_class", None),
+        ShortField("entity_id", 0),
+        ByteField("success_code", 0),
+        ShortField("attributes_mask", None),
+        ShortField("unsupported_attributes_mask", None),
+        ShortField("failed_attributes_mask", None),
+        ConditionalField(
+            OmciMaskedData("data"), lambda pkt: pkt.success_code == 0)
+    ]
+
+class OmciStartSoftwareDownload(OmciMessage):
+    name = "OmciStartSoftwareDownload"
+    message_id = 0x53
+    fields_desc = [
+        ShortField("entity_class", 7),  # Always 7 (Software image)
+        ShortField("entity_id", None),
+        ByteField("window_size", 0),
+        IntField("image_size", 0),
+        ByteField("image_number", 1),   # Always only 1 in parallel
+        ShortField("instance_id", None) # should be same as "entity_id"        
+    ]
+
+class OmciStartSoftwareDownloadResponse(OmciMessage):
+    name = "OmciStartSoftwareDownloadResponse"
+    message_id = 0x33
+    fields_desc = [
+        ShortField("entity_class", 7),  # Always 7 (Software image)
+        ShortField("entity_id", None),
+        ByteField("result", 0),
+        ByteField("window_size", 0),
+        ByteField("image_number", 1),   # Always only 1 in parallel
+        ShortField("instance_id", None) # should be same as "entity_id"        
+    ]
+
+class OmciEndSoftwareDownload(OmciMessage):
+    name = "OmciEndSoftwareDownload"
+    message_id = 0x55
+    fields_desc = [
+        ShortField("entity_class", 7),  # Always 7 (Software image)
+        ShortField("entity_id", None),
+        IntField("crc32", 0),
+        IntField("image_size", 0),
+        ByteField("image_number", 1),   # Always only 1 in parallel
+        ShortField("instance_id", None),# should be same as "entity_id"
+    ]
+
+class OmciEndSoftwareDownloadResponse(OmciMessage):
+    name = "OmciEndSoftwareDownload"
+    message_id = 0x35
+    fields_desc = [
+        ShortField("entity_class", 7),  # Always 7 (Software image)
+        ShortField("entity_id", None),
+        ByteField("result", 0),
+        ByteField("image_number", 1),   # Always only 1 in parallel
+        ShortField("instance_id", None),# should be same as "entity_id"
+        ByteField("result0", 0)         # same as result 
+    ]
+
+class OmciDownloadSection(OmciMessage):
+    name = "OmciDownloadSection"
+    message_id = 0x14
+    fields_desc = [
+        ShortField("entity_class", 7),   # Always 7 (Software image)
+        ShortField("entity_id", None),
+        ByteField("section_number", 0),  # Always only 1 in parallel
+        StrFixedLenField("data", 0, length=OmciSectionDataSize) # section data
+    ]
+
+class OmciDownloadSectionLast(OmciMessage):
+    name = "OmciDownloadSection"
+    message_id = 0x54
+    fields_desc = [
+        ShortField("entity_class", 7),   # Always 7 (Software image)
+        ShortField("entity_id", None),
+        ByteField("section_number", 0),  # Always only 1 in parallel
+        StrFixedLenField("data", 0, length=OmciSectionDataSize) # section data
+    ]
+
+class OmciDownloadSectionResponse(OmciMessage):
+    name = "OmciDownloadSectionResponse"
+    message_id = 0x34
+    fields_desc = [
+        ShortField("entity_class", 7),   # Always 7 (Software image)
+        ShortField("entity_id", None),
+        ByteField("result", 0),
+        ByteField("section_number", 0),  # Always only 1 in parallel
+    ]
+
+class OmciActivateImage(OmciMessage):
+    name = "OmciActivateImage"
+    message_id = 0x56
+    fields_desc = [
+        ShortField("entity_class", 7),   # Always 7 (Software image)
+        ShortField("entity_id", None),
+        ByteField("activate_flag", 0)    # Activate image unconditionally
+    ]
+
+class OmciActivateImageResponse(OmciMessage):
+    name = "OmciActivateImageResponse"
+    message_id = 0x36
+    fields_desc = [
+        ShortField("entity_class", 7),   # Always 7 (Software image)
+        ShortField("entity_id", None),
+        ByteField("result", 0)           # Activate image unconditionally
+    ]
+
+class OmciCommitImage(OmciMessage):
+    name = "OmciCommitImage"
+    message_id = 0x57
+    fields_desc = [
+        ShortField("entity_class", 7),   # Always 7 (Software image)
+        ShortField("entity_id", None),
+    ]
+
+class OmciCommitImageResponse(OmciMessage):
+    name = "OmciCommitImageResponse"
+    message_id = 0x37
+    fields_desc = [
+        ShortField("entity_class", 7),   # Always 7 (Software image)
+        ShortField("entity_id", None),
+        ByteField("result", 0)           # Activate image unconditionally
+    ]
+