VOL-4337: Code upgrade for 3/2020 G.988 support and remaining Extended Message Set support

Change-Id: I6c5e1a167216ad9b51e9da89460e9909465ae1bc
diff --git a/meframe/me_alarms.go b/meframe/me_alarms.go
new file mode 100644
index 0000000..ac0f242
--- /dev/null
+++ b/meframe/me_alarms.go
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2018 - present.  Boling Consulting Solutions (bcsw.net)
+ * Copyright 2020-present Open Networking Foundation
+
+ * 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.
+ */
+
+package meframe
+
+import (
+	"errors"
+	"fmt"
+	"github.com/google/gopacket"
+	. "github.com/opencord/omci-lib-go"
+	me "github.com/opencord/omci-lib-go/generated"
+)
+
+func GetAllAlarmsRequestFrame(m *me.ManagedEntity, opt options) (gopacket.SerializableLayer, error) {
+	if opt.frameFormat == ExtendedIdent {
+		return nil, errors.New("extended message set for this message type is not supported")
+	}
+	// Common for all MEs
+	meLayer := &GetAllAlarmsRequest{
+		MeBasePacket: MeBasePacket{
+			EntityClass:    m.GetClassID(),
+			EntityInstance: m.GetEntityID(),
+			Extended:       opt.frameFormat == ExtendedIdent,
+		},
+		AlarmRetrievalMode: opt.mode,
+	}
+	return meLayer, nil
+}
+
+func GetAllAlarmsResponseFrame(m *me.ManagedEntity, opt options) (gopacket.SerializableLayer, error) {
+	if opt.frameFormat == ExtendedIdent {
+		return nil, errors.New("extended message set for this message type is not supported")
+	}
+	// Common for all MEs
+	meLayer := &GetAllAlarmsResponse{
+		MeBasePacket: MeBasePacket{
+			EntityClass:    m.GetClassID(),
+			EntityInstance: m.GetEntityID(),
+			Extended:       opt.frameFormat == ExtendedIdent,
+		},
+		NumberOfCommands: opt.sequenceNumberCountOrSize,
+	}
+	return meLayer, nil
+}
+
+func GetAllAlarmsNextRequestFrame(m *me.ManagedEntity, opt options) (gopacket.SerializableLayer, error) {
+	if opt.frameFormat == ExtendedIdent {
+		return nil, errors.New("extended message set for this message type is not supported")
+	}
+	// Common for all MEs
+	meLayer := &GetAllAlarmsNextRequest{
+		MeBasePacket: MeBasePacket{
+			EntityClass:    m.GetClassID(),
+			EntityInstance: m.GetEntityID(),
+			Extended:       opt.frameFormat == ExtendedIdent,
+		},
+		CommandSequenceNumber: opt.sequenceNumberCountOrSize,
+	}
+	return meLayer, nil
+}
+
+func GetAllAlarmsNextResponseFrame(m *me.ManagedEntity, opt options) (gopacket.SerializableLayer, error) {
+	if opt.frameFormat == ExtendedIdent {
+		return nil, errors.New("extended message set for this message type is not supported")
+	}
+	// Common for all MEs
+	meLayer := &GetAllAlarmsNextResponse{
+		MeBasePacket: MeBasePacket{
+			EntityClass:    m.GetClassID(),
+			EntityInstance: m.GetEntityID(),
+			Extended:       opt.frameFormat == ExtendedIdent,
+		},
+		AlarmEntityClass:    opt.alarm.AlarmClassID,
+		AlarmEntityInstance: opt.alarm.AlarmInstance,
+	}
+	if len(opt.alarm.AlarmBitmap) > 28 {
+		return nil, errors.New("invalid Alarm Bitmap Size. Must be [0..27]")
+	}
+	for octet := 0; octet < len(opt.alarm.AlarmBitmap); octet++ {
+		meLayer.AlarmBitMap[octet] = opt.alarm.AlarmBitmap[octet]
+	}
+	for octet := len(opt.alarm.AlarmBitmap); octet < 28; octet++ {
+		meLayer.AlarmBitMap[octet] = 0
+	}
+	return meLayer, nil
+}
+
+func AlarmNotificationFrame(m *me.ManagedEntity, opt options) (gopacket.SerializableLayer, error) {
+	if opt.frameFormat == ExtendedIdent {
+		return nil, errors.New("extended message set for this message type is not supported")
+	}
+	mask, err := checkAttributeMask(m, opt.attributeMask)
+	if err != nil {
+		return nil, err
+	}
+	// Common for all MEs
+	meLayer := &AlarmNotificationMsg{
+		MeBasePacket: MeBasePacket{
+			EntityClass:    m.GetClassID(),
+			EntityInstance: m.GetEntityID(),
+			Extended:       opt.frameFormat == ExtendedIdent,
+		},
+	}
+	// Get payload space available
+	maxPayload := maxPacketAvailable(m, opt)
+	payloadAvailable := int(maxPayload) - 1 // Less alarm sequence number
+
+	// TODO: Lots of work to do
+	fmt.Println(mask, maxPayload, payloadAvailable)
+
+	return meLayer, errors.New("todo: Not implemented")
+}
diff --git a/meframe/me_alarms_test.go b/meframe/me_alarms_test.go
new file mode 100644
index 0000000..8f410cf
--- /dev/null
+++ b/meframe/me_alarms_test.go
@@ -0,0 +1,223 @@
+/*
+ * Copyright (c) 2018 - present.  Boling Consulting Solutions (bcsw.net)
+ * Copyright 2020-present Open Networking Foundation
+
+ * 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.
+ */
+package meframe_test
+
+import (
+	"github.com/google/gopacket"
+	. "github.com/opencord/omci-lib-go"
+	me "github.com/opencord/omci-lib-go/generated"
+	"github.com/opencord/omci-lib-go/meframe"
+	"github.com/stretchr/testify/assert"
+	"math/rand"
+	"testing"
+)
+
+func testGetAllAlarmsRequestTypeMeFrame(t *testing.T, managedEntity *me.ManagedEntity, messageSet DeviceIdent) {
+	params := me.ParamData{
+		EntityID: uint16(0),
+	}
+	// Create the managed instance
+	meInstance, err := me.NewManagedEntity(managedEntity.GetManagedEntityDefinition(), params)
+	assert.NotNil(t, err)
+	assert.Equal(t, err.StatusCode(), me.Success)
+
+	tid := uint16(rand.Int31n(0xFFFE) + 1) // [1, 0xFFFF]
+	mode := uint8(rand.Int31n(2))          // [0, 1]
+
+	frame, omciErr := meframe.GenFrame(meInstance, GetAllAlarmsRequestType, meframe.TransactionID(tid),
+		meframe.RetrievalMode(mode), meframe.FrameFormat(messageSet))
+	assert.NotNil(t, frame)
+	assert.NotZero(t, len(frame))
+	assert.Nil(t, omciErr)
+
+	///////////////////////////////////////////////////////////////////
+	// Now decode and compare
+	packet := gopacket.NewPacket(frame, LayerTypeOMCI, gopacket.NoCopy)
+	assert.NotNil(t, packet)
+
+	omciLayer := packet.Layer(LayerTypeOMCI)
+	assert.NotNil(t, omciLayer)
+
+	omciObj, omciOk := omciLayer.(*OMCI)
+	assert.NotNil(t, omciObj)
+	assert.True(t, omciOk)
+	assert.Equal(t, tid, omciObj.TransactionID)
+	assert.Equal(t, GetAllAlarmsRequestType, omciObj.MessageType)
+	assert.Equal(t, messageSet, omciObj.DeviceIdentifier)
+
+	msgLayer := packet.Layer(LayerTypeGetAllAlarmsRequest)
+	assert.NotNil(t, msgLayer)
+
+	msgObj, msgOk := msgLayer.(*GetAllAlarmsRequest)
+	assert.NotNil(t, msgObj)
+	assert.True(t, msgOk)
+
+	assert.Equal(t, meInstance.GetClassID(), msgObj.EntityClass)
+	assert.Equal(t, meInstance.GetEntityID(), msgObj.EntityInstance)
+	assert.Equal(t, mode, msgObj.AlarmRetrievalMode)
+}
+
+func testGetAllAlarmsResponseTypeMeFrame(t *testing.T, managedEntity *me.ManagedEntity, messageSet DeviceIdent) {
+	params := me.ParamData{
+		EntityID: uint16(0),
+	}
+	// Create the managed instance
+	meInstance, err := me.NewManagedEntity(managedEntity.GetManagedEntityDefinition(), params)
+	assert.NotNil(t, err)
+	assert.Equal(t, err.StatusCode(), me.Success)
+
+	tid := uint16(rand.Int31n(0xFFFE) + 1)  // [1, 0xFFFF]
+	numOfCommands := uint16(rand.Int31n(5)) // [0, 5)
+
+	frame, omciErr := meframe.GenFrame(meInstance, GetAllAlarmsResponseType, meframe.TransactionID(tid),
+		meframe.SequenceNumberCountOrSize(numOfCommands), meframe.FrameFormat(messageSet))
+	assert.NotNil(t, frame)
+	assert.NotZero(t, len(frame))
+	assert.Nil(t, omciErr)
+
+	///////////////////////////////////////////////////////////////////
+	// Now decode and compare
+	packet := gopacket.NewPacket(frame, LayerTypeOMCI, gopacket.NoCopy)
+	assert.NotNil(t, packet)
+
+	omciLayer := packet.Layer(LayerTypeOMCI)
+	assert.NotNil(t, omciLayer)
+
+	omciObj, omciOk := omciLayer.(*OMCI)
+	assert.NotNil(t, omciObj)
+	assert.True(t, omciOk)
+	assert.Equal(t, tid, omciObj.TransactionID)
+	assert.Equal(t, GetAllAlarmsResponseType, omciObj.MessageType)
+	assert.Equal(t, messageSet, omciObj.DeviceIdentifier)
+
+	msgLayer := packet.Layer(LayerTypeGetAllAlarmsResponse)
+	assert.NotNil(t, msgLayer)
+
+	msgObj, msgOk := msgLayer.(*GetAllAlarmsResponse)
+	assert.NotNil(t, msgObj)
+	assert.True(t, msgOk)
+
+	assert.Equal(t, meInstance.GetClassID(), msgObj.EntityClass)
+	assert.Equal(t, meInstance.GetEntityID(), msgObj.EntityInstance)
+	assert.Equal(t, numOfCommands, msgObj.NumberOfCommands)
+}
+
+func testGetAllAlarmsNextRequestTypeMeFrame(t *testing.T, managedEntity *me.ManagedEntity, messageSet DeviceIdent) {
+	params := me.ParamData{
+		EntityID: uint16(0),
+	}
+	// Create the managed instance
+	meInstance, err := me.NewManagedEntity(managedEntity.GetManagedEntityDefinition(), params)
+	assert.NotNil(t, err)
+	assert.Equal(t, err.StatusCode(), me.Success)
+
+	tid := uint16(rand.Int31n(0xFFFE) + 1)   // [1, 0xFFFF]
+	sequenceNumber := uint16(rand.Int31n(5)) // [0, 5)
+
+	frame, omciErr := meframe.GenFrame(meInstance, GetAllAlarmsNextRequestType, meframe.TransactionID(tid),
+		meframe.SequenceNumberCountOrSize(sequenceNumber), meframe.FrameFormat(messageSet))
+	assert.NotNil(t, frame)
+	assert.NotZero(t, len(frame))
+	assert.Nil(t, omciErr)
+
+	///////////////////////////////////////////////////////////////////
+	// Now decode and compare
+	packet := gopacket.NewPacket(frame, LayerTypeOMCI, gopacket.NoCopy)
+	assert.NotNil(t, packet)
+
+	omciLayer := packet.Layer(LayerTypeOMCI)
+	assert.NotNil(t, omciLayer)
+
+	omciObj, omciOk := omciLayer.(*OMCI)
+	assert.NotNil(t, omciObj)
+	assert.True(t, omciOk)
+	assert.Equal(t, tid, omciObj.TransactionID)
+	assert.Equal(t, GetAllAlarmsNextRequestType, omciObj.MessageType)
+	assert.Equal(t, messageSet, omciObj.DeviceIdentifier)
+
+	msgLayer := packet.Layer(LayerTypeGetAllAlarmsNextRequest)
+	assert.NotNil(t, msgLayer)
+
+	msgObj, msgOk := msgLayer.(*GetAllAlarmsNextRequest)
+	assert.NotNil(t, msgObj)
+	assert.True(t, msgOk)
+
+	assert.Equal(t, meInstance.GetClassID(), msgObj.EntityClass)
+	assert.Equal(t, meInstance.GetEntityID(), msgObj.EntityInstance)
+	assert.Equal(t, sequenceNumber, msgObj.CommandSequenceNumber)
+}
+
+func testGetAllAlarmsNextResponseTypeMeFrame(t *testing.T, managedEntity *me.ManagedEntity, messageSet DeviceIdent) {
+	params := me.ParamData{
+		EntityID: uint16(0),
+	}
+	// Create the managed instance
+	meInstance, err := me.NewManagedEntity(managedEntity.GetManagedEntityDefinition(), params)
+	assert.NotNil(t, err)
+	assert.Equal(t, err.StatusCode(), me.Success)
+
+	tid := uint16(rand.Int31n(0xFFFE) + 1) // [1, 0xFFFF]
+
+	alarmInfo := meframe.AlarmOptions{
+		AlarmClassID:  123, // TODO: Real class here?
+		AlarmInstance: 456,
+		AlarmBitmap:   make([]byte, 28),
+	}
+	// TODO: Allow a 1 to 28 octet array to be used and zero fill any remainder...
+	for octet := 0; octet < 28; octet++ {
+		alarmInfo.AlarmBitmap[octet] = uint8(rand.Intn(256))
+	}
+	frame, omciErr := meframe.GenFrame(meInstance, GetAllAlarmsNextResponseType, meframe.TransactionID(tid),
+		meframe.Alarm(alarmInfo), meframe.FrameFormat(messageSet))
+	assert.NotNil(t, frame)
+	assert.NotZero(t, len(frame))
+	assert.Nil(t, omciErr)
+
+	///////////////////////////////////////////////////////////////////
+	// Now decode and compare
+	packet := gopacket.NewPacket(frame, LayerTypeOMCI, gopacket.NoCopy)
+	assert.NotNil(t, packet)
+
+	omciLayer := packet.Layer(LayerTypeOMCI)
+	assert.NotNil(t, omciLayer)
+
+	omciObj, omciOk := omciLayer.(*OMCI)
+	assert.NotNil(t, omciObj)
+	assert.True(t, omciOk)
+	assert.Equal(t, tid, omciObj.TransactionID)
+	assert.Equal(t, GetAllAlarmsNextResponseType, omciObj.MessageType)
+	assert.Equal(t, messageSet, omciObj.DeviceIdentifier)
+
+	msgLayer := packet.Layer(LayerTypeGetAllAlarmsNextResponse)
+	assert.NotNil(t, msgLayer)
+
+	msgObj, msgOk := msgLayer.(*GetAllAlarmsNextResponse)
+	assert.NotNil(t, msgObj)
+	assert.True(t, msgOk)
+
+	assert.Equal(t, meInstance.GetClassID(), msgObj.EntityClass)
+	assert.Equal(t, meInstance.GetEntityID(), msgObj.EntityInstance)
+	assert.Equal(t, alarmInfo.AlarmClassID, msgObj.AlarmEntityClass)
+	assert.Equal(t, alarmInfo.AlarmInstance, msgObj.AlarmEntityInstance)
+	for octet := 0; octet < len(alarmInfo.AlarmBitmap); octet++ {
+		assert.Equal(t, alarmInfo.AlarmBitmap[octet], msgObj.AlarmBitMap[octet])
+	}
+}
+
+func testAlarmNotificationTypeMeFrame(t *testing.T, managedEntity *me.ManagedEntity, messageSet DeviceIdent) {
+	// TODO: Implement
+}
diff --git a/meframe/me_avc.go b/meframe/me_avc.go
new file mode 100644
index 0000000..e91339f
--- /dev/null
+++ b/meframe/me_avc.go
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2018 - present.  Boling Consulting Solutions (bcsw.net)
+ * Copyright 2020-present Open Networking Foundation
+
+ * 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.
+ */
+
+package meframe
+
+import (
+	"errors"
+	"fmt"
+	"github.com/google/gopacket"
+	. "github.com/opencord/omci-lib-go"
+	me "github.com/opencord/omci-lib-go/generated"
+)
+
+func AttributeValueChangeFrame(m *me.ManagedEntity, opt options) (gopacket.SerializableLayer, error) {
+	if opt.frameFormat == ExtendedIdent {
+		return nil, errors.New("extended message set for this message type is not supported")
+	}
+	mask, err := checkAttributeMask(m, opt.attributeMask)
+	if err != nil {
+		return nil, err
+	}
+	// Common for all MEs
+	meLayer := &AttributeValueChangeMsg{
+		MeBasePacket: MeBasePacket{
+			EntityClass:    m.GetClassID(),
+			EntityInstance: m.GetEntityID(),
+			Extended:       opt.frameFormat == ExtendedIdent,
+		},
+		AttributeMask: 0,
+		Attributes:    make(me.AttributeValueMap),
+	}
+	// Get payload space available
+	maxPayload := maxPacketAvailable(m, opt)
+	payloadAvailable := int(maxPayload) - 2 // Less attribute mask
+
+	// TODO: Lots of work to do
+
+	fmt.Println(mask, maxPayload, payloadAvailable)
+	return meLayer, errors.New("todo: Not implemented")
+}
diff --git a/meframe/me_avc_test.go b/meframe/me_avc_test.go
new file mode 100644
index 0000000..ddf360d
--- /dev/null
+++ b/meframe/me_avc_test.go
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2018 - present.  Boling Consulting Solutions (bcsw.net)
+ * Copyright 2020-present Open Networking Foundation
+
+ * 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.
+ */
+package meframe_test
+
+import (
+	. "github.com/opencord/omci-lib-go"
+	me "github.com/opencord/omci-lib-go/generated"
+	"testing"
+)
+
+func testAttributeValueChangeTypeMeFrame(t *testing.T, managedEntity *me.ManagedEntity, messageSet DeviceIdent) {
+	// TODO: Implement
+}
diff --git a/meframe/me_create.go b/meframe/me_create.go
new file mode 100644
index 0000000..1f363ed
--- /dev/null
+++ b/meframe/me_create.go
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2018 - present.  Boling Consulting Solutions (bcsw.net)
+ * Copyright 2020-present Open Networking Foundation
+
+ * 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.
+ */
+package meframe
+
+import (
+	"errors"
+	"github.com/google/gopacket"
+	. "github.com/opencord/omci-lib-go"
+	me "github.com/opencord/omci-lib-go/generated"
+)
+
+func CreateRequestFrame(m *me.ManagedEntity, opt options) (gopacket.SerializableLayer, error) {
+	if opt.frameFormat == ExtendedIdent {
+		return nil, errors.New("extended message set for this message type is not supported")
+	}
+	// NOTE: The OMCI parser does not extract the default values of set-by-create attributes
+	//       and are the zero 'default' (or nil) at this time.  For this reason, make sure
+	//       you specify all non-zero default values and pass them in appropriate
+	meLayer := &CreateRequest{
+		MeBasePacket: MeBasePacket{
+			EntityClass:    m.GetClassID(),
+			EntityInstance: m.GetEntityID(),
+			Extended:       opt.frameFormat == ExtendedIdent,
+		},
+		Attributes: m.GetAttributeValueMap(),
+	}
+	// Add any missing SetByCreate options if requested
+	if opt.addDefaults {
+		if attrDefs, err := me.GetAttributesDefinitions(m.GetClassID()); err.StatusCode() == me.Success {
+			for index, attr := range attrDefs {
+				if me.SupportsAttributeAccess(attr, me.SetByCreate) {
+					if index == 0 {
+						continue // Skip Entity ID, if it is SetByCreate, they should always specify it
+					}
+					if _, found := meLayer.Attributes[attr.GetName()]; !found {
+						meLayer.Attributes[attr.GetName()] = attr.DefValue
+					}
+				}
+			}
+		}
+	}
+	return meLayer, nil
+}
+
+func CreateResponseFrame(m *me.ManagedEntity, opt options) (gopacket.SerializableLayer, error) {
+	if opt.frameFormat == ExtendedIdent {
+		return nil, errors.New("extended message set for this message type is not supported")
+	}
+	meLayer := &CreateResponse{
+		MeBasePacket: MeBasePacket{
+			EntityClass:    m.GetClassID(),
+			EntityInstance: m.GetEntityID(),
+			Extended:       opt.frameFormat == ExtendedIdent,
+		},
+		Result: opt.result,
+	}
+	if meLayer.Result == me.ParameterError {
+		meLayer.AttributeExecutionMask = opt.attrExecutionMask
+	}
+	return meLayer, nil
+}
diff --git a/meframe/me_create_test.go b/meframe/me_create_test.go
new file mode 100644
index 0000000..5632af8
--- /dev/null
+++ b/meframe/me_create_test.go
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 2018 - present.  Boling Consulting Solutions (bcsw.net)
+ * Copyright 2020-present Open Networking Foundation
+
+ * 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.
+ */
+
+package meframe_test
+
+import (
+	"github.com/google/gopacket"
+	. "github.com/opencord/omci-lib-go"
+	me "github.com/opencord/omci-lib-go/generated"
+	"github.com/opencord/omci-lib-go/meframe"
+	"github.com/stretchr/testify/assert"
+	"math/rand"
+	"testing"
+)
+
+func testCreateRequestTypeMeFrame(t *testing.T, managedEntity *me.ManagedEntity, messageSet DeviceIdent) {
+	// Generate the frame. Use a default Entity ID of zero, but for the
+	// OMCI library, we need to specify all supported Set-By-Create
+	params := me.ParamData{
+		EntityID:   uint16(0),
+		Attributes: make(me.AttributeValueMap, 0),
+	}
+	for _, attrDef := range managedEntity.GetAttributeDefinitions() {
+		if attrDef.Index == 0 {
+			continue // Skip entity ID, already specified
+
+		} else if attrDef.GetAccess().Contains(me.SetByCreate) {
+			params.Attributes[attrDef.GetName()] = pickAValue(attrDef)
+		}
+	}
+	// Create the managed instance
+	meInstance, err := me.NewManagedEntity(managedEntity.GetManagedEntityDefinition(), params)
+	tid := uint16(rand.Int31n(0xFFFE) + 1) // [1, 0xFFFF]
+	assert.NotNil(t, err)
+	assert.Equal(t, err.StatusCode(), me.Success)
+
+	frame, omciErr := meframe.GenFrame(meInstance, CreateRequestType, meframe.TransactionID(tid), meframe.FrameFormat(messageSet))
+	assert.NotNil(t, frame)
+	assert.NotZero(t, len(frame))
+	assert.Nil(t, omciErr)
+
+	///////////////////////////////////////////////////////////////////
+	// Now decode and compare
+	packet := gopacket.NewPacket(frame, LayerTypeOMCI, gopacket.NoCopy)
+	assert.NotNil(t, packet)
+
+	omciLayer := packet.Layer(LayerTypeOMCI)
+	assert.NotNil(t, omciLayer)
+
+	omciObj, omciOk := omciLayer.(*OMCI)
+	assert.NotNil(t, omciObj)
+	assert.True(t, omciOk)
+	assert.Equal(t, tid, omciObj.TransactionID)
+	assert.Equal(t, CreateRequestType, omciObj.MessageType)
+	assert.Equal(t, messageSet, omciObj.DeviceIdentifier)
+
+	msgLayer := packet.Layer(LayerTypeCreateRequest)
+	assert.NotNil(t, msgLayer)
+
+	msgObj, msgOk := msgLayer.(*CreateRequest)
+	assert.NotNil(t, msgObj)
+	assert.True(t, msgOk)
+
+	assert.Equal(t, meInstance.GetClassID(), msgObj.EntityClass)
+	assert.Equal(t, meInstance.GetEntityID(), msgObj.EntityInstance)
+	assert.Equal(t, meInstance.GetAttributeValueMap(), msgObj.Attributes)
+}
+
+func testCreateResponseTypeMeFrame(t *testing.T, managedEntity *me.ManagedEntity, messageSet DeviceIdent) {
+	params := me.ParamData{
+		EntityID: uint16(0),
+	}
+	// Create the managed instance
+	meInstance, err := me.NewManagedEntity(managedEntity.GetManagedEntityDefinition(), params)
+	assert.NotNil(t, err)
+	assert.Equal(t, err.StatusCode(), me.Success)
+
+	tid := uint16(rand.Int31n(0xFFFE) + 1) // [1, 0xFFFF]
+	result := me.Results(rand.Int31n(7))   // [0, 6] Not all types will be tested
+
+	// Always pass a failure mask, but should only get encoded if result == ParameterError
+	var mask uint16
+	for _, attrDef := range managedEntity.GetAttributeDefinitions() {
+		if attrDef.Index == 0 {
+			continue // Skip entity ID, already specified
+
+		} else if attrDef.GetAccess().Contains(me.SetByCreate) {
+			// Random 20% chance this parameter was bad
+			if result == me.ParameterError && rand.Int31n(5) == 0 {
+				mask |= attrDef.Mask
+			}
+		}
+	}
+	frame, omciErr := meframe.GenFrame(meInstance, CreateResponseType,
+		meframe.TransactionID(tid), meframe.Result(result), meframe.AttributeExecutionMask(mask), meframe.FrameFormat(messageSet))
+	assert.NotNil(t, frame)
+	assert.NotZero(t, len(frame))
+	assert.Nil(t, omciErr)
+
+	///////////////////////////////////////////////////////////////////
+	// Now decode and compare
+	packet := gopacket.NewPacket(frame, LayerTypeOMCI, gopacket.NoCopy)
+	assert.NotNil(t, packet)
+
+	omciLayer := packet.Layer(LayerTypeOMCI)
+	assert.NotNil(t, omciLayer)
+
+	omciObj, omciOk := omciLayer.(*OMCI)
+	assert.NotNil(t, omciObj)
+	assert.True(t, omciOk)
+	assert.Equal(t, tid, omciObj.TransactionID)
+	assert.Equal(t, CreateResponseType, omciObj.MessageType)
+	assert.Equal(t, messageSet, omciObj.DeviceIdentifier)
+
+	msgLayer := packet.Layer(LayerTypeCreateResponse)
+	assert.NotNil(t, msgLayer)
+
+	msgObj, msgOk := msgLayer.(*CreateResponse)
+	assert.NotNil(t, msgObj)
+	assert.True(t, msgOk)
+
+	assert.Equal(t, meInstance.GetClassID(), msgObj.EntityClass)
+	assert.Equal(t, meInstance.GetEntityID(), msgObj.EntityInstance)
+	assert.Equal(t, result, msgObj.Result)
+
+	if result == me.ParameterError {
+		assert.Equal(t, mask, msgObj.AttributeExecutionMask)
+	} else {
+		assert.Zero(t, msgObj.AttributeExecutionMask)
+	}
+}
diff --git a/meframe/me_delete.go b/meframe/me_delete.go
new file mode 100644
index 0000000..0a5552f
--- /dev/null
+++ b/meframe/me_delete.go
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2018 - present.  Boling Consulting Solutions (bcsw.net)
+ * Copyright 2020-present Open Networking Foundation
+
+ * 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.
+ */
+
+package meframe
+
+import (
+	"errors"
+	"github.com/google/gopacket"
+	. "github.com/opencord/omci-lib-go"
+	me "github.com/opencord/omci-lib-go/generated"
+)
+
+func DeleteRequestFrame(m *me.ManagedEntity, opt options) (gopacket.SerializableLayer, error) {
+	if opt.frameFormat == ExtendedIdent {
+		return nil, errors.New("extended message set for this message type is not supported")
+	}
+	meLayer := &DeleteRequest{
+		MeBasePacket: MeBasePacket{
+			EntityClass:    m.GetClassID(),
+			EntityInstance: m.GetEntityID(),
+			Extended:       opt.frameFormat == ExtendedIdent,
+		},
+	}
+	return meLayer, nil
+}
+
+func DeleteResponseFrame(m *me.ManagedEntity, opt options) (gopacket.SerializableLayer, error) {
+	if opt.frameFormat == ExtendedIdent {
+		return nil, errors.New("extended message set for this message type is not supported")
+	}
+	meLayer := &DeleteResponse{
+		MeBasePacket: MeBasePacket{
+			EntityClass:    m.GetClassID(),
+			EntityInstance: m.GetEntityID(),
+			Extended:       opt.frameFormat == ExtendedIdent,
+		},
+		Result: opt.result,
+	}
+	return meLayer, nil
+}
diff --git a/meframe/me_delete_test.go b/meframe/me_delete_test.go
new file mode 100644
index 0000000..be0686e
--- /dev/null
+++ b/meframe/me_delete_test.go
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2018 - present.  Boling Consulting Solutions (bcsw.net)
+ * Copyright 2020-present Open Networking Foundation
+
+ * 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.
+ */
+package meframe_test
+
+import (
+	"github.com/google/gopacket"
+	. "github.com/opencord/omci-lib-go"
+	me "github.com/opencord/omci-lib-go/generated"
+	"github.com/opencord/omci-lib-go/meframe"
+	"github.com/stretchr/testify/assert"
+	"math/rand"
+	"testing"
+)
+
+func testDeleteRequestTypeMeFrame(t *testing.T, managedEntity *me.ManagedEntity, messageSet DeviceIdent) {
+	// Generate the frame. Use a default Entity ID of zero, but for the
+	// OMCI library, we need to specify all supported Set-By-Create
+	params := me.ParamData{
+		EntityID: uint16(0),
+	}
+	// Create the managed instance
+	meInstance, err := me.NewManagedEntity(managedEntity.GetManagedEntityDefinition(), params)
+	assert.NotNil(t, err)
+	assert.Equal(t, err.StatusCode(), me.Success)
+
+	tid := uint16(rand.Int31n(0xFFFE) + 1) // [1, 0xFFFF]
+
+	frame, omciErr := meframe.GenFrame(meInstance, DeleteRequestType, meframe.TransactionID(tid), meframe.FrameFormat(messageSet))
+	assert.NotNil(t, frame)
+	assert.NotZero(t, len(frame))
+	assert.Nil(t, omciErr)
+
+	///////////////////////////////////////////////////////////////////
+	// Now decode and compare
+	packet := gopacket.NewPacket(frame, LayerTypeOMCI, gopacket.NoCopy)
+	assert.NotNil(t, packet)
+
+	omciLayer := packet.Layer(LayerTypeOMCI)
+	assert.NotNil(t, omciLayer)
+
+	omciObj, omciOk := omciLayer.(*OMCI)
+	assert.NotNil(t, omciObj)
+	assert.True(t, omciOk)
+	assert.Equal(t, tid, omciObj.TransactionID)
+	assert.Equal(t, DeleteRequestType, omciObj.MessageType)
+	assert.Equal(t, messageSet, omciObj.DeviceIdentifier)
+
+	msgLayer := packet.Layer(LayerTypeDeleteRequest)
+	assert.NotNil(t, msgLayer)
+
+	msgObj, msgOk := msgLayer.(*DeleteRequest)
+	assert.NotNil(t, msgObj)
+	assert.True(t, msgOk)
+
+	assert.Equal(t, meInstance.GetClassID(), msgObj.EntityClass)
+	assert.Equal(t, meInstance.GetEntityID(), msgObj.EntityInstance)
+}
+
+func testDeleteResponseTypeMeFrame(t *testing.T, managedEntity *me.ManagedEntity, messageSet DeviceIdent) {
+	params := me.ParamData{
+		EntityID: uint16(0),
+	}
+	// Create the managed instance
+	meInstance, err := me.NewManagedEntity(managedEntity.GetManagedEntityDefinition(), params)
+	assert.NotNil(t, err)
+	assert.Equal(t, err.StatusCode(), me.Success)
+
+	tid := uint16(rand.Int31n(0xFFFE) + 1) // [1, 0xFFFF]
+	result := me.Results(rand.Int31n(7))   // [0, 6] Not all types will be tested
+
+	frame, omciErr := meframe.GenFrame(meInstance, DeleteResponseType, meframe.TransactionID(tid), meframe.Result(result),
+		meframe.FrameFormat(messageSet))
+	assert.NotNil(t, frame)
+	assert.NotZero(t, len(frame))
+	assert.Nil(t, omciErr)
+
+	///////////////////////////////////////////////////////////////////
+	// Now decode and compare
+	packet := gopacket.NewPacket(frame, LayerTypeOMCI, gopacket.NoCopy)
+	assert.NotNil(t, packet)
+
+	omciLayer := packet.Layer(LayerTypeOMCI)
+	assert.NotNil(t, omciLayer)
+
+	omciObj, omciOk := omciLayer.(*OMCI)
+	assert.NotNil(t, omciObj)
+	assert.True(t, omciOk)
+	assert.Equal(t, tid, omciObj.TransactionID)
+	assert.Equal(t, DeleteResponseType, omciObj.MessageType)
+	assert.Equal(t, messageSet, omciObj.DeviceIdentifier)
+
+	msgLayer := packet.Layer(LayerTypeDeleteResponse)
+	assert.NotNil(t, msgLayer)
+
+	msgObj, msgOk := msgLayer.(*DeleteResponse)
+	assert.NotNil(t, msgObj)
+	assert.True(t, msgOk)
+
+	assert.Equal(t, meInstance.GetClassID(), msgObj.EntityClass)
+	assert.Equal(t, meInstance.GetEntityID(), msgObj.EntityInstance)
+	assert.Equal(t, result, msgObj.Result)
+}
diff --git a/meframe/me_get.go b/meframe/me_get.go
new file mode 100644
index 0000000..f50e554
--- /dev/null
+++ b/meframe/me_get.go
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2018 - present.  Boling Consulting Solutions (bcsw.net)
+ * Copyright 2020-present Open Networking Foundation
+
+ * 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.
+ */
+
+package meframe
+
+import (
+	"errors"
+	"fmt"
+	"github.com/google/gopacket"
+	. "github.com/opencord/omci-lib-go"
+	me "github.com/opencord/omci-lib-go/generated"
+)
+
+func GetRequestFrame(m *me.ManagedEntity, opt options) (gopacket.SerializableLayer, error) {
+	// Given mask sent in (could be default of 0xFFFF) get what is allowable.
+	// This will be all allowed if 0xFFFF is passed in, or a subset if a fixed
+	// number of items.
+	maxMask, err := checkAttributeMask(m, opt.attributeMask)
+	if err != nil {
+		return nil, err
+	}
+	// Now scan attributes and reduce mask to only those requested
+	var mask uint16
+	mask, err = calculateAttributeMask(m, maxMask)
+	if err != nil {
+		return nil, err
+	}
+	if mask == 0 {
+		// TODO: Is a Get request with no attributes valid?
+		return nil, errors.New("no attributes requested for GetRequest")
+	}
+	meLayer := &GetRequest{
+		MeBasePacket: MeBasePacket{
+			EntityClass:    m.GetClassID(),
+			EntityInstance: m.GetEntityID(),
+			Extended:       opt.frameFormat == ExtendedIdent,
+		},
+		AttributeMask: mask,
+	}
+	return meLayer, nil
+}
+
+func GetResponseFrame(m *me.ManagedEntity, opt options) (gopacket.SerializableLayer, error) {
+	mask, err := checkAttributeMask(m, opt.attributeMask)
+	if err != nil {
+		return nil, err
+	}
+	mask, err = calculateAttributeMask(m, mask)
+	if err != nil {
+		return nil, err
+	}
+	meLayer := &GetResponse{
+		MeBasePacket: MeBasePacket{
+			EntityClass:    m.GetClassID(),
+			EntityInstance: m.GetEntityID(),
+			Extended:       opt.frameFormat == ExtendedIdent,
+		},
+		Result:        opt.result,
+		AttributeMask: 0,
+		Attributes:    make(me.AttributeValueMap),
+	}
+	if meLayer.Result == me.AttributeFailure {
+		meLayer.UnsupportedAttributeMask = opt.unsupportedMask
+		meLayer.FailedAttributeMask = opt.attrExecutionMask
+	}
+	// Encode whatever we can
+	if meLayer.Result == me.Success || meLayer.Result == me.AttributeFailure {
+		// Encode results
+		// Get payload space available
+		maxPayload := maxPacketAvailable(m, opt)
+		payloadAvailable := int(maxPayload) - 2 - 4 // Less attribute mask and attribute error encoding
+		meDefinition := m.GetManagedEntityDefinition()
+		attrDefs := meDefinition.GetAttributeDefinitions()
+		attrMap := m.GetAttributeValueMap()
+
+		if mask != 0 {
+			// Iterate down the attributes (Attribute 0 is the ManagedEntity ID)
+			var attrIndex uint
+			for attrIndex = 1; attrIndex <= 16; attrIndex++ {
+				// Is this attribute requested
+				if mask&(1<<(16-attrIndex)) != 0 {
+					// Get definitions since we need the name
+					attrDef, ok := attrDefs[attrIndex]
+					if !ok {
+						msg := fmt.Sprintf("Unexpected error, index %v not valued for ME %v",
+							attrIndex, meDefinition.GetName())
+						return nil, errors.New(msg)
+					}
+					var attrValue interface{}
+					attrValue, ok = attrMap[attrDef.Name]
+					if !ok {
+						msg := fmt.Sprintf("Unexpected error, attribute %v not provided in ME %v: %v",
+							attrDef.GetName(), meDefinition.GetName(), m)
+						return nil, errors.New(msg)
+					}
+					// Is space available?
+					if attrDef.Size <= payloadAvailable {
+						// Mark bit handled
+						mask &= ^attrDef.Mask
+						meLayer.AttributeMask |= attrDef.Mask
+						meLayer.Attributes[attrDef.Name] = attrValue
+						payloadAvailable -= attrDef.Size
+
+					} else if opt.failIfTruncated {
+						// TODO: Should we set truncate?
+						msg := fmt.Sprintf("out-of-space. Cannot fit attribute %v into GetResponse message",
+							attrDef.GetName())
+						return nil, me.NewMessageTruncatedError(msg)
+					} else {
+						// Add to existing 'failed' mask and update result
+						meLayer.FailedAttributeMask |= attrDef.Mask
+						meLayer.Result = me.AttributeFailure
+					}
+				}
+			}
+		}
+	}
+	return meLayer, nil
+}
diff --git a/meframe/me_get_test.go b/meframe/me_get_test.go
new file mode 100644
index 0000000..6e10431
--- /dev/null
+++ b/meframe/me_get_test.go
@@ -0,0 +1,230 @@
+/*
+ * Copyright (c) 2018 - present.  Boling Consulting Solutions (bcsw.net)
+ * Copyright 2020-present Open Networking Foundation
+
+ * 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.
+ */
+package meframe_test
+
+import (
+	"github.com/google/gopacket"
+	. "github.com/opencord/omci-lib-go"
+	me "github.com/opencord/omci-lib-go/generated"
+	"github.com/opencord/omci-lib-go/meframe"
+	"github.com/stretchr/testify/assert"
+	"math/rand"
+	"testing"
+)
+
+func testGetRequestTypeMeFrame(t *testing.T, managedEntity *me.ManagedEntity, messageSet DeviceIdent) {
+	params := me.ParamData{
+		EntityID:   uint16(0),
+		Attributes: make(me.AttributeValueMap, 0),
+	}
+	attrDefs := managedEntity.GetAttributeDefinitions()
+	for _, attrDef := range attrDefs {
+		if attrDef.Index == 0 {
+			continue // Skip entity ID, already specified
+		} else if attrDef.GetAccess().Contains(me.Read) {
+			// Allow 'nil' as parameter value for GetRequests since we only need names
+			params.Attributes[attrDef.GetName()] = nil
+		}
+	}
+	assert.NotEmpty(t, params.Attributes) // Need a parameter that is a table attribute
+	bitmask, attrErr := me.GetAttributesBitmap(attrDefs, getAttributeNameSet(params.Attributes))
+	assert.Nil(t, attrErr)
+
+	// Create the managed instance
+	meInstance, err := me.NewManagedEntity(managedEntity.GetManagedEntityDefinition(), params)
+	assert.NotNil(t, err)
+	assert.Equal(t, err.StatusCode(), me.Success)
+
+	tid := uint16(rand.Int31n(0xFFFE) + 1) // [1, 0xFFFF]
+
+	frame, omciErr := meframe.GenFrame(meInstance, GetRequestType, meframe.TransactionID(tid),
+		meframe.AttributeMask(bitmask), meframe.FrameFormat(messageSet))
+	assert.NotNil(t, frame)
+	assert.NotZero(t, len(frame))
+	assert.Nil(t, omciErr)
+
+	///////////////////////////////////////////////////////////////////
+	// Now decode and compare
+	packet := gopacket.NewPacket(frame, LayerTypeOMCI, gopacket.NoCopy)
+	assert.NotNil(t, packet)
+
+	omciLayer := packet.Layer(LayerTypeOMCI)
+	assert.NotNil(t, omciLayer)
+
+	omciObj, omciOk := omciLayer.(*OMCI)
+	assert.NotNil(t, omciObj)
+	assert.True(t, omciOk)
+	assert.Equal(t, tid, omciObj.TransactionID)
+	assert.Equal(t, GetRequestType, omciObj.MessageType)
+	assert.Equal(t, messageSet, omciObj.DeviceIdentifier)
+
+	msgLayer := packet.Layer(LayerTypeGetRequest)
+	assert.NotNil(t, msgLayer)
+
+	msgObj, msgOk := msgLayer.(*GetRequest)
+	assert.NotNil(t, msgObj)
+	assert.True(t, msgOk)
+
+	assert.Equal(t, meInstance.GetClassID(), msgObj.EntityClass)
+	assert.Equal(t, meInstance.GetEntityID(), msgObj.EntityInstance)
+	assert.Equal(t, meInstance.GetAttributeMask(), msgObj.AttributeMask)
+}
+
+func testGetResponseTypeMeFrame(t *testing.T, managedEntity *me.ManagedEntity, messageSet DeviceIdent) {
+	params := me.ParamData{
+		EntityID:   uint16(0),
+		Attributes: make(me.AttributeValueMap),
+	}
+	// Add loop to test all valid result codes for this message type
+	validResultCodes := []me.Results{
+		me.Success,
+		me.ProcessingError,
+		me.NotSupported,
+		me.ParameterError,
+		me.UnknownEntity,
+		me.UnknownInstance,
+		me.DeviceBusy,
+		me.AttributeFailure,
+	}
+	for _, result := range validResultCodes {
+		tid := uint16(rand.Int31n(0xFFFE) + 1) // [1, 0xFFFF]
+
+		// If success Results selected, set FailIfTruncated 50% of time to test
+		// overflow detection and failures periodically.  This is primarily for
+		// baseline message set for those MEs that may have lots of attribute space
+		// needed.  If extended message set, always fail if truncated since we should
+		// be able to stuff as much as we want (at least for now in these unit tests)
+		failIfTruncated := false
+		if result == me.Success && (rand.Int31n(2) == 1 || messageSet == ExtendedIdent) {
+			failIfTruncated = true
+		}
+		// Always pass a failure mask, but should only get encoded if result == ParameterError
+		var unsupportedMask uint16
+		var failedMask uint16
+		attrDefs := managedEntity.GetAttributeDefinitions()
+		for _, attrDef := range attrDefs {
+			if attrDef.Index == 0 {
+				continue // Skip entity ID, already specified
+
+			} else if attrDef.GetAccess().Contains(me.Read) {
+				// Random 5% chance this parameter unsupported and
+				// 5% it failed
+				switch rand.Int31n(20) {
+				default:
+					// TODO: Table attributes not yet supported.  For Table Attributes, figure out a
+					//       good way to unit test this and see if that can be extended to a more
+					//       general operation that provides the 'get-next' frames to the caller who
+					//		 wishes to serialize a table attribute.
+					if !attrDef.IsTableAttribute() {
+						params.Attributes[attrDef.GetName()] = pickAValue(attrDef)
+					}
+				case 0:
+					unsupportedMask |= attrDef.Mask
+				case 1:
+					failedMask |= attrDef.Mask
+				}
+			}
+		}
+		bitmask, attrErr := me.GetAttributesBitmap(attrDefs, getAttributeNameSet(params.Attributes))
+		assert.Nil(t, attrErr)
+
+		// Create the managed instance
+		meInstance, err := me.NewManagedEntity(managedEntity.GetManagedEntityDefinition(), params)
+
+		frame, omciErr := meframe.GenFrame(meInstance, GetResponseType,
+			meframe.TransactionID(tid), meframe.Result(result),
+			meframe.AttributeMask(bitmask), meframe.FrameFormat(messageSet),
+			meframe.AttributeExecutionMask(failedMask),
+			meframe.UnsupportedAttributeMask(unsupportedMask),
+			meframe.FailIfTruncated(failIfTruncated))
+
+		// TODO: Need to test if err is MessageTruncatedError. Sometimes reported as
+		//       a proessing error
+		if omciErr != nil {
+			if _, ok := omciErr.(*me.MessageTruncatedError); ok {
+				return
+			}
+		}
+		assert.NotNil(t, frame)
+		assert.NotZero(t, len(frame))
+		assert.NotNil(t, err)
+		assert.Equal(t, err.StatusCode(), me.Success)
+
+		///////////////////////////////////////////////////////////////////
+		// Now decode and compare
+		packet := gopacket.NewPacket(frame, LayerTypeOMCI, gopacket.NoCopy)
+		assert.NotNil(t, packet)
+
+		omciLayer := packet.Layer(LayerTypeOMCI)
+		assert.NotNil(t, omciLayer)
+
+		omciObj, omciOk := omciLayer.(*OMCI)
+		assert.NotNil(t, omciObj)
+		assert.True(t, omciOk)
+		assert.Equal(t, tid, omciObj.TransactionID)
+		assert.Equal(t, GetResponseType, omciObj.MessageType)
+		assert.Equal(t, messageSet, omciObj.DeviceIdentifier)
+
+		msgLayer := packet.Layer(LayerTypeGetResponse)
+		// If requested Result was Success and FailIfTruncated is true, then we may
+		// fail (get nil layer) if too many attributes to fit in a frame
+		if result == me.Success && msgLayer == nil {
+			return // was expected
+		}
+		assert.NotNil(t, msgLayer)
+
+		msgObj, msgOk := msgLayer.(*GetResponse)
+		assert.NotNil(t, msgObj)
+		assert.True(t, msgOk)
+
+		assert.Equal(t, meInstance.GetClassID(), msgObj.EntityClass)
+		assert.Equal(t, meInstance.GetEntityID(), msgObj.EntityInstance)
+
+		switch msgObj.Result {
+		default:
+			assert.Equal(t, result, msgObj.Result)
+			assert.Zero(t, msgObj.FailedAttributeMask)
+			assert.Zero(t, msgObj.UnsupportedAttributeMask)
+
+		case me.Success:
+			assert.Equal(t, result, msgObj.Result)
+			assert.Zero(t, msgObj.FailedAttributeMask)
+			assert.Zero(t, msgObj.UnsupportedAttributeMask)
+			assert.Equal(t, meInstance.GetAttributeValueMap(), msgObj.Attributes)
+
+		case me.AttributeFailure:
+			// Should have been Success or AttributeFailure to start with
+			assert.True(t, result == me.Success || result == me.AttributeFailure)
+			if result == me.AttributeFailure {
+				assert.Equal(t, unsupportedMask, msgObj.UnsupportedAttributeMask)
+			}
+			// Returned may have more bits set in failed mask and less attributes
+			// since failIfTruncated is false and we may add more fail attributes
+			// since they do not fit. May also set only lower value (lower bits)
+			// if it turns out that the upper bits are already pre-assigned to the
+			// failure bits.
+			//
+			// Make sure any successful attributes were requested
+			meMap := meInstance.GetAttributeValueMap()
+			for name := range msgObj.Attributes {
+				getValue, ok := meMap[name]
+				assert.True(t, ok)
+				assert.NotNil(t, getValue)
+			}
+		}
+	}
+}
diff --git a/meframe/me_getcurrent.go b/meframe/me_getcurrent.go
new file mode 100644
index 0000000..359a717
--- /dev/null
+++ b/meframe/me_getcurrent.go
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2018 - present.  Boling Consulting Solutions (bcsw.net)
+ * Copyright 2020-present Open Networking Foundation
+
+ * 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.
+ */
+
+package meframe
+
+import (
+	"errors"
+	"fmt"
+	"github.com/google/gopacket"
+	. "github.com/opencord/omci-lib-go"
+	me "github.com/opencord/omci-lib-go/generated"
+)
+
+func GetCurrentDataRequestFrame(m *me.ManagedEntity, opt options) (gopacket.SerializableLayer, error) {
+	if opt.frameFormat == ExtendedIdent {
+		return nil, errors.New("extended message set for this message type is not supported")
+	}
+	mask, err := checkAttributeMask(m, opt.attributeMask)
+	if err != nil {
+		return nil, err
+	}
+	// Common for all MEs
+	meLayer := &GetCurrentDataRequest{
+		MeBasePacket: MeBasePacket{
+			EntityClass:    m.GetClassID(),
+			EntityInstance: m.GetEntityID(),
+			Extended:       opt.frameFormat == ExtendedIdent,
+		},
+	}
+	// Get payload space available
+	maxPayload := maxPacketAvailable(m, opt)
+
+	// TODO: Lots of work to do
+
+	fmt.Println(mask, maxPayload)
+	return meLayer, errors.New("todo: Not implemented")
+}
+
+func GetCurrentDataResponseFrame(m *me.ManagedEntity, opt options) (gopacket.SerializableLayer, error) {
+	if opt.frameFormat == ExtendedIdent {
+		return nil, errors.New("extended message set for this message type is not supported")
+	}
+	mask, err := checkAttributeMask(m, opt.attributeMask)
+	if err != nil {
+		return nil, err
+	}
+	// Common for all MEs
+	meLayer := &GetCurrentDataResponse{
+		MeBasePacket: MeBasePacket{
+			EntityClass:    m.GetClassID(),
+			EntityInstance: m.GetEntityID(),
+			Extended:       opt.frameFormat == ExtendedIdent,
+		},
+	}
+	// Get payload space available
+	maxPayload := maxPacketAvailable(m, opt)
+
+	// TODO: Lots of work to do
+
+	fmt.Println(mask, maxPayload)
+	return meLayer, errors.New("todo: Not implemented")
+}
diff --git a/meframe/me_getcurrent_test.go b/meframe/me_getcurrent_test.go
new file mode 100644
index 0000000..9c9452b
--- /dev/null
+++ b/meframe/me_getcurrent_test.go
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2018 - present.  Boling Consulting Solutions (bcsw.net)
+ * Copyright 2020-present Open Networking Foundation
+
+ * 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.
+ */
+package meframe_test
+
+import (
+	. "github.com/opencord/omci-lib-go"
+	me "github.com/opencord/omci-lib-go/generated"
+	"testing"
+)
+
+func testGetCurrentDataRequestTypeMeFrame(t *testing.T, managedEntity *me.ManagedEntity, messageSet DeviceIdent) {
+	// TODO: Implement
+}
+
+func testGetCurrentDataResponseTypeMeFrame(t *testing.T, managedEntity *me.ManagedEntity, messageSet DeviceIdent) {
+	// TODO: Implement
+}
diff --git a/meframe/me_getnext.go b/meframe/me_getnext.go
new file mode 100644
index 0000000..090b333
--- /dev/null
+++ b/meframe/me_getnext.go
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2018 - present.  Boling Consulting Solutions (bcsw.net)
+ * Copyright 2020-present Open Networking Foundation
+
+ * 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.
+ */
+
+package meframe
+
+import (
+	"errors"
+	"fmt"
+	"github.com/google/gopacket"
+	. "github.com/opencord/omci-lib-go"
+	me "github.com/opencord/omci-lib-go/generated"
+)
+
+func GetNextRequestFrame(m *me.ManagedEntity, opt options) (gopacket.SerializableLayer, error) {
+	if opt.frameFormat == ExtendedIdent {
+		return nil, errors.New("extended message set for this message type is not supported")
+	}
+	// Validate attribute mask
+	mask, err := checkAttributeMask(m, opt.attributeMask)
+	if err != nil {
+		return nil, err
+	}
+	// Now scan attributes and reduce mask to only those requested
+	mask, err = calculateAttributeMask(m, mask)
+	if err != nil {
+		return nil, err
+	}
+	if mask == 0 {
+		return nil, errors.New("no attributes requested for GetNextRequest")
+	}
+	// TODO: If more than one attribute or the attribute requested is not a table attribute, return an error
+	// Common for all MEs
+	meLayer := &GetNextRequest{
+		MeBasePacket: MeBasePacket{
+			EntityClass:    m.GetClassID(),
+			EntityInstance: m.GetEntityID(),
+			Extended:       opt.frameFormat == ExtendedIdent,
+		},
+		AttributeMask:  mask,
+		SequenceNumber: opt.sequenceNumberCountOrSize,
+	}
+	return meLayer, nil
+}
+
+func GetNextResponseFrame(m *me.ManagedEntity, opt options) (gopacket.SerializableLayer, error) {
+	if opt.frameFormat == ExtendedIdent {
+		return nil, errors.New("extended message set for this message type is not supported")
+	}
+	// Validate attribute mask
+	mask, err := checkAttributeMask(m, opt.attributeMask)
+	if err != nil {
+		return nil, err
+	}
+	mask, err = calculateAttributeMask(m, mask)
+	if err != nil {
+		return nil, err
+	}
+	//
+	// Common for all MEs
+	meLayer := &GetNextResponse{
+		MeBasePacket: MeBasePacket{
+			EntityClass:    m.GetClassID(),
+			EntityInstance: m.GetEntityID(),
+			Extended:       opt.frameFormat == ExtendedIdent,
+		},
+		Result:        opt.result,
+		AttributeMask: 0,
+		Attributes:    make(me.AttributeValueMap),
+	}
+	if meLayer.Result == me.Success {
+		// Get payload space available
+		maxPayload := maxPacketAvailable(m, opt)
+		payloadAvailable := int(maxPayload) - 3 // Less results and attribute mask
+		meDefinition := m.GetManagedEntityDefinition()
+		attrDefs := meDefinition.GetAttributeDefinitions()
+		attrMap := m.GetAttributeValueMap()
+
+		if mask == 0 {
+			return nil, errors.New("no attributes requested for GetNextResponse")
+		}
+		// TODO: If more than one attribute or the attribute requested is not a table attribute, return an error
+		// Iterate down the attributes (Attribute 0 is the ManagedEntity ID)
+		var attrIndex uint
+		for attrIndex = 1; attrIndex <= 16; attrIndex++ {
+			// Is this attribute requested
+			if mask&(1<<(16-attrIndex)) != 0 {
+				// Get definitions since we need the name
+				attrDef, ok := attrDefs[attrIndex]
+				if !ok {
+					msg := fmt.Sprintf("Unexpected error, index %v not valued for ME %v",
+						attrIndex, meDefinition.GetName())
+					return nil, errors.New(msg)
+				}
+				var attrValue interface{}
+				attrValue, ok = attrMap[attrDef.Name]
+				if !ok || attrValue == nil {
+					msg := fmt.Sprintf("Unexpected error, attribute %v not provided in ME %v: %v",
+						attrDef.GetName(), meDefinition.GetName(), m)
+					return nil, errors.New(msg)
+				}
+				// Is space available?
+				if attrDef.Size <= payloadAvailable {
+					// Mark bit handled
+					mask &= ^attrDef.Mask
+					meLayer.AttributeMask |= attrDef.Mask
+					meLayer.Attributes[attrDef.Name] = attrValue
+					payloadAvailable -= attrDef.Size
+				} else {
+					// TODO: Should we set truncate?
+					msg := fmt.Sprintf("out-of-space. Cannot fit attribute %v into GetNextResponse message",
+						attrDef.GetName())
+					return nil, me.NewMessageTruncatedError(msg)
+				}
+			}
+		}
+	}
+	return meLayer, nil
+}
diff --git a/meframe/me_getnext_test.go b/meframe/me_getnext_test.go
new file mode 100644
index 0000000..6db557e
--- /dev/null
+++ b/meframe/me_getnext_test.go
@@ -0,0 +1,201 @@
+/*
+ * Copyright (c) 2018 - present.  Boling Consulting Solutions (bcsw.net)
+ * Copyright 2020-present Open Networking Foundation
+
+ * 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.
+ */
+package meframe_test
+
+import (
+	"github.com/google/gopacket"
+	. "github.com/opencord/omci-lib-go"
+	me "github.com/opencord/omci-lib-go/generated"
+	"github.com/opencord/omci-lib-go/meframe"
+	"github.com/stretchr/testify/assert"
+	"math/rand"
+	"testing"
+)
+
+func testGetNextRequestTypeMeFrame(t *testing.T, managedEntity *me.ManagedEntity, messageSet DeviceIdent) {
+	params := me.ParamData{
+		EntityID:   uint16(0),
+		Attributes: make(me.AttributeValueMap, 0),
+	}
+	// TODO: Loop over all table attributes for this class ID
+	// Find first attribute that is a table definition
+	// TODO: Test request of more than 1 attribute. G.988 specifies that a status
+	//       code of (3) should be returned.  Raise error during encode instead of
+	//       waiting for compliant ONU.  May want to have an 'ignore' to allow it.
+	attrDefs := managedEntity.GetAttributeDefinitions()
+	for _, attrDef := range attrDefs {
+		if attrDef.Index == 0 {
+			continue // Skip entity ID, already specified
+		} else if attrDef.IsTableAttribute() {
+			// TODO: Tables without a size are not supported. At least needs to be one octet
+			if attrDef.Size == 0 {
+				continue
+			}
+			// Allow 'nil' as parameter value for GetNextRequests since we only need names
+			params.Attributes[attrDef.GetName()] = nil
+			break
+		}
+	}
+	if len(params.Attributes) == 0 {
+		return
+	}
+	bitmask, attrErr := me.GetAttributesBitmap(attrDefs, getAttributeNameSet(params.Attributes))
+	assert.Nil(t, attrErr)
+
+	// Create the managed instance
+	meInstance, err := me.NewManagedEntity(managedEntity.GetManagedEntityDefinition(), params)
+	assert.NotNil(t, err)
+	assert.Equal(t, err.StatusCode(), me.Success)
+
+	seqNumber := uint16(rand.Int31n(0xFFFF)) // [0, 0xFFFE]
+	tid := uint16(rand.Int31n(0xFFFE) + 1)   // [1, 0xFFFF]
+
+	frame, omciErr := meframe.GenFrame(meInstance, GetNextRequestType, meframe.TransactionID(tid),
+		meframe.SequenceNumberCountOrSize(seqNumber), meframe.AttributeMask(bitmask), meframe.FrameFormat(messageSet))
+	assert.NotNil(t, frame)
+	assert.NotZero(t, len(frame))
+	assert.Nil(t, omciErr)
+
+	///////////////////////////////////////////////////////////////////
+	// Now decode and compare
+	packet := gopacket.NewPacket(frame, LayerTypeOMCI, gopacket.NoCopy)
+	assert.NotNil(t, packet)
+
+	omciLayer := packet.Layer(LayerTypeOMCI)
+	assert.NotNil(t, omciLayer)
+
+	omciObj, omciOk := omciLayer.(*OMCI)
+	assert.NotNil(t, omciObj)
+	assert.True(t, omciOk)
+	assert.Equal(t, tid, omciObj.TransactionID)
+	assert.Equal(t, GetNextRequestType, omciObj.MessageType)
+	assert.Equal(t, messageSet, omciObj.DeviceIdentifier)
+
+	msgLayer := packet.Layer(LayerTypeGetNextRequest)
+	assert.NotNil(t, msgLayer)
+
+	msgObj, msgOk := msgLayer.(*GetNextRequest)
+	assert.NotNil(t, msgObj)
+	assert.True(t, msgOk)
+
+	assert.Equal(t, meInstance.GetClassID(), msgObj.EntityClass)
+	assert.Equal(t, meInstance.GetEntityID(), msgObj.EntityInstance)
+	assert.Equal(t, meInstance.GetAttributeMask(), msgObj.AttributeMask)
+	assert.Equal(t, seqNumber, msgObj.SequenceNumber)
+}
+
+func testGetNextResponseTypeMeFrame(t *testing.T, managedEntity *me.ManagedEntity, messageSet DeviceIdent) {
+	params := me.ParamData{
+		EntityID:   uint16(0),
+		Attributes: make(me.AttributeValueMap, 0),
+	}
+	// TODO: Loop over result types (here and other responses with results)
+	result := me.Success // me.Results(rand.Int31n(7))  // [0, 6]
+	bitmask := uint16(0)
+	attrDefs := managedEntity.GetAttributeDefinitions()
+
+	// TODO: Loop over all table attributes for this class ID
+	if result == me.Success {
+		// Find first attribute that is a table definition
+		// TODO: Test request of more than 1 attribute. G.988 specifies that a status
+		//       code of (3) should be returned.  Raise error during encode instead of
+		//       waiting for compliant ONU.  May want to have an 'ignore' to allow it.
+		for _, attrDef := range attrDefs {
+			if attrDef.Index == 0 {
+				continue // Skip entity ID, already specified
+			} else if attrDef.IsTableAttribute() {
+				if len(params.Attributes) == 0 {
+					// Need a parameter that is a table attribute
+					return
+				}
+				params.Attributes[attrDef.GetName()] = pickAValue(attrDef)
+				break
+			}
+		}
+		if len(params.Attributes) == 0 {
+			return
+		}
+		assert.NotEmpty(t, params.Attributes) // Need a parameter that is a table attribute
+		var attrErr error
+		bitmask, attrErr = me.GetAttributesBitmap(attrDefs, getAttributeNameSet(params.Attributes))
+		assert.Nil(t, attrErr)
+	}
+	// Create the managed instance
+	meInstance, err := me.NewManagedEntity(managedEntity.GetManagedEntityDefinition(), params)
+	assert.NotNil(t, err)
+	assert.Equal(t, err.StatusCode(), me.Success)
+
+	tid := uint16(rand.Int31n(0xFFFE) + 1) // [1, 0xFFFF]
+
+	frame, omciErr := meframe.GenFrame(meInstance, GetNextResponseType, meframe.TransactionID(tid), meframe.Result(result),
+		meframe.AttributeMask(bitmask), meframe.FrameFormat(messageSet))
+	assert.NotNil(t, frame)
+	assert.NotZero(t, len(frame))
+	assert.Nil(t, omciErr)
+
+	///////////////////////////////////////////////////////////////////
+	// Now decode and compare
+	cid := meInstance.GetClassID()
+	assert.NotEqual(t, cid, 0)
+	packet := gopacket.NewPacket(frame, LayerTypeOMCI, gopacket.NoCopy)
+	assert.NotNil(t, packet)
+
+	omciLayer := packet.Layer(LayerTypeOMCI)
+	assert.NotNil(t, omciLayer)
+
+	omciObj, omciOk := omciLayer.(*OMCI)
+	assert.NotNil(t, omciObj)
+	assert.True(t, omciOk)
+	assert.Equal(t, tid, omciObj.TransactionID)
+	assert.Equal(t, GetNextResponseType, omciObj.MessageType)
+	assert.Equal(t, messageSet, omciObj.DeviceIdentifier)
+
+	msgLayer := packet.Layer(LayerTypeGetNextResponse)
+	assert.NotNil(t, msgLayer)
+
+	msgObj, msgOk := msgLayer.(*GetNextResponse)
+	assert.NotNil(t, msgObj)
+	assert.True(t, msgOk)
+
+	assert.Equal(t, meInstance.GetClassID(), msgObj.EntityClass)
+	assert.Equal(t, meInstance.GetEntityID(), msgObj.EntityInstance)
+	assert.Equal(t, meInstance.GetAttributeMask(), msgObj.AttributeMask)
+
+	switch msgObj.Result {
+	default:
+		assert.Equal(t, result, msgObj.Result)
+
+	case me.Success:
+		assert.Equal(t, result, msgObj.Result)
+		// The attributes should be equal but for variable length table attribute (size = 0 in structure)
+		// we will have the frame padding returned as well.
+		for attrName, value := range meInstance.GetAttributeValueMap() {
+			attr, err := me.GetAttributeDefinitionByName(attrDefs, attrName)
+			assert.Nil(t, err)
+			assert.NotNil(t, attr)
+			assert.Equal(t, attrName, attr.GetName())
+			if attr.IsTableAttribute() {
+				instValue := value.([]byte)
+				msgValue := msgObj.Attributes[attrName].([]byte)
+				assert.True(t, len(instValue) <= len(msgValue))
+				assert.Equal(t, msgValue[:len(instValue)], instValue)
+			} else {
+				assert.Equal(t, value, msgObj.Attributes[attrName])
+			}
+		}
+	}
+}
diff --git a/meframe/me_mibreset.go b/meframe/me_mibreset.go
new file mode 100644
index 0000000..78aab84
--- /dev/null
+++ b/meframe/me_mibreset.go
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2018 - present.  Boling Consulting Solutions (bcsw.net)
+ * Copyright 2020-present Open Networking Foundation
+
+ * 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.
+ */
+
+package meframe
+
+import (
+	"errors"
+	"github.com/google/gopacket"
+	. "github.com/opencord/omci-lib-go"
+	me "github.com/opencord/omci-lib-go/generated"
+)
+
+func MibResetRequestFrame(m *me.ManagedEntity, opt options) (gopacket.SerializableLayer, error) {
+	if opt.frameFormat == ExtendedIdent {
+		return nil, errors.New("extended message set for this message type is not supported")
+	}
+	// Common for all MEs
+	meLayer := &MibResetRequest{
+		MeBasePacket: MeBasePacket{
+			EntityClass:    m.GetClassID(),
+			EntityInstance: m.GetEntityID(),
+			Extended:       opt.frameFormat == ExtendedIdent,
+		},
+	}
+	return meLayer, nil
+}
+
+func MibResetResponseFrame(m *me.ManagedEntity, opt options) (gopacket.SerializableLayer, error) {
+	if opt.frameFormat == ExtendedIdent {
+		return nil, errors.New("extended message set for this message type is not supported")
+	}
+	// Common for all MEs
+	meLayer := &MibResetResponse{
+		MeBasePacket: MeBasePacket{
+			EntityClass:    m.GetClassID(),
+			EntityInstance: m.GetEntityID(),
+			Extended:       opt.frameFormat == ExtendedIdent,
+		},
+		Result: opt.result,
+	}
+	return meLayer, nil
+}
diff --git a/meframe/me_mibreset_test.go b/meframe/me_mibreset_test.go
new file mode 100644
index 0000000..3c58bcc
--- /dev/null
+++ b/meframe/me_mibreset_test.go
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2018 - present.  Boling Consulting Solutions (bcsw.net)
+ * Copyright 2020-present Open Networking Foundation
+
+ * 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.
+ */
+package meframe_test
+
+import (
+	"github.com/google/gopacket"
+	. "github.com/opencord/omci-lib-go"
+	me "github.com/opencord/omci-lib-go/generated"
+	"github.com/opencord/omci-lib-go/meframe"
+	"github.com/stretchr/testify/assert"
+	"math/rand"
+	"testing"
+)
+
+func testMibResetRequestTypeMeFrame(t *testing.T, managedEntity *me.ManagedEntity, messageSet DeviceIdent) {
+	params := me.ParamData{
+		EntityID: uint16(0),
+	}
+	// Create the managed instance
+	meInstance, err := me.NewManagedEntity(managedEntity.GetManagedEntityDefinition(), params)
+	assert.NotNil(t, err)
+	assert.Equal(t, err.StatusCode(), me.Success)
+
+	tid := uint16(rand.Int31n(0xFFFE) + 1) // [1, 0xFFFF]
+
+	frame, omciErr := meframe.GenFrame(meInstance, MibResetRequestType, meframe.TransactionID(tid), meframe.FrameFormat(messageSet))
+	assert.NotNil(t, frame)
+	assert.NotZero(t, len(frame))
+	assert.Nil(t, omciErr)
+
+	///////////////////////////////////////////////////////////////////
+	// Now decode and compare
+	packet := gopacket.NewPacket(frame, LayerTypeOMCI, gopacket.NoCopy)
+	assert.NotNil(t, packet)
+
+	omciLayer := packet.Layer(LayerTypeOMCI)
+	assert.NotNil(t, omciLayer)
+
+	omciObj, omciOk := omciLayer.(*OMCI)
+	assert.NotNil(t, omciObj)
+	assert.True(t, omciOk)
+	assert.Equal(t, tid, omciObj.TransactionID)
+	assert.Equal(t, MibResetRequestType, omciObj.MessageType)
+	assert.Equal(t, messageSet, omciObj.DeviceIdentifier)
+
+	msgLayer := packet.Layer(LayerTypeMibResetRequest)
+	assert.NotNil(t, msgLayer)
+
+	msgObj, msgOk := msgLayer.(*MibResetRequest)
+	assert.NotNil(t, msgObj)
+	assert.True(t, msgOk)
+
+	assert.Equal(t, meInstance.GetClassID(), msgObj.EntityClass)
+	assert.Equal(t, meInstance.GetEntityID(), msgObj.EntityInstance)
+}
+
+func testMibResetResponseTypeMeFrame(t *testing.T, managedEntity *me.ManagedEntity, messageSet DeviceIdent) {
+	params := me.ParamData{
+		EntityID: uint16(0),
+	}
+	// Create the managed instance
+	meInstance, err := me.NewManagedEntity(managedEntity.GetManagedEntityDefinition(), params)
+	assert.NotNil(t, err)
+	assert.Equal(t, err.StatusCode(), me.Success)
+
+	tid := uint16(rand.Int31n(0xFFFE) + 1) // [1, 0xFFFF]
+	result := me.Results(rand.Int31n(7))   // [0, 6] Not all types will be tested
+
+	frame, omciErr := meframe.GenFrame(meInstance, MibResetResponseType, meframe.TransactionID(tid),
+		meframe.Result(result), meframe.FrameFormat(messageSet))
+	assert.NotNil(t, frame)
+	assert.NotZero(t, len(frame))
+	assert.Nil(t, omciErr)
+
+	///////////////////////////////////////////////////////////////////
+	// Now decode and compare
+	packet := gopacket.NewPacket(frame, LayerTypeOMCI, gopacket.NoCopy)
+	assert.NotNil(t, packet)
+
+	omciLayer := packet.Layer(LayerTypeOMCI)
+	assert.NotNil(t, omciLayer)
+
+	omciObj, omciOk := omciLayer.(*OMCI)
+	assert.NotNil(t, omciObj)
+	assert.True(t, omciOk)
+	assert.Equal(t, tid, omciObj.TransactionID)
+	assert.Equal(t, MibResetResponseType, omciObj.MessageType)
+	assert.Equal(t, messageSet, omciObj.DeviceIdentifier)
+
+	msgLayer := packet.Layer(LayerTypeMibResetResponse)
+	assert.NotNil(t, msgLayer)
+
+	msgObj, msgOk := msgLayer.(*MibResetResponse)
+	assert.NotNil(t, msgObj)
+	assert.True(t, msgOk)
+
+	assert.Equal(t, meInstance.GetClassID(), msgObj.EntityClass)
+	assert.Equal(t, meInstance.GetEntityID(), msgObj.EntityInstance)
+	assert.Equal(t, result, msgObj.Result)
+}
diff --git a/meframe/me_mibupload.go b/meframe/me_mibupload.go
new file mode 100644
index 0000000..1b1dab9
--- /dev/null
+++ b/meframe/me_mibupload.go
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2018 - present.  Boling Consulting Solutions (bcsw.net)
+ * Copyright 2020-present Open Networking Foundation
+
+ * 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.
+ */
+
+package meframe
+
+import (
+	"errors"
+	"github.com/google/gopacket"
+	. "github.com/opencord/omci-lib-go"
+	me "github.com/opencord/omci-lib-go/generated"
+)
+
+func MibUploadRequestFrame(m *me.ManagedEntity, opt options) (gopacket.SerializableLayer, error) {
+	if opt.frameFormat == ExtendedIdent {
+		return nil, errors.New("extended message set for this message type is not supported")
+	}
+	// Common for all MEs
+	meLayer := &MibUploadRequest{
+		MeBasePacket: MeBasePacket{
+			EntityClass:    m.GetClassID(),
+			EntityInstance: 0,
+			Extended:       opt.frameFormat == ExtendedIdent,
+		},
+	}
+	return meLayer, nil
+}
+
+func MibUploadResponseFrame(m *me.ManagedEntity, opt options) (gopacket.SerializableLayer, error) {
+	if opt.frameFormat == ExtendedIdent {
+		return nil, errors.New("extended message set for this message type is not supported")
+	}
+	// Common for all MEs
+	meLayer := &MibUploadResponse{
+		MeBasePacket: MeBasePacket{
+			EntityClass:    m.GetClassID(),
+			EntityInstance: 0,
+			Extended:       opt.frameFormat == ExtendedIdent,
+		},
+		NumberOfCommands: opt.sequenceNumberCountOrSize,
+	}
+	return meLayer, nil
+}
+
+func MibUploadNextRequestFrame(m *me.ManagedEntity, opt options) (gopacket.SerializableLayer, error) {
+	if opt.frameFormat == ExtendedIdent {
+		return nil, errors.New("extended message set for this message type is not supported")
+	}
+	// Common for all MEs
+	meLayer := &MibUploadNextRequest{
+		MeBasePacket: MeBasePacket{
+			EntityClass:    m.GetClassID(),
+			EntityInstance: 0,
+			Extended:       opt.frameFormat == ExtendedIdent,
+		},
+		CommandSequenceNumber: opt.sequenceNumberCountOrSize,
+	}
+	return meLayer, nil
+}
+
+func MibUploadNextResponseFrame(m *me.ManagedEntity, opt options) (gopacket.SerializableLayer, error) {
+	if opt.frameFormat == ExtendedIdent {
+		return nil, errors.New("extended message set for this message type is not supported")
+	}
+	// Common for all MEs
+	meLayer := &MibUploadNextResponse{
+		MeBasePacket: MeBasePacket{
+			EntityClass:    m.GetClassID(),
+			EntityInstance: m.GetEntityID(),
+			Extended:       opt.frameFormat == ExtendedIdent,
+		},
+	}
+	if opt.payload == nil {
+		// Shortcut used to specify the request sequence number is out of range, encode
+		// a ME instance with class ID of zero to specify this per ITU G.988
+		meDef := me.ManagedEntityDefinition{
+			Name:                 "InvalidSequenceNumberManagedEntity",
+			ClassID:              me.ClassID(0),
+			MessageTypes:         nil,
+			AttributeDefinitions: make(me.AttributeDefinitionMap),
+		}
+		opt.payload, _ = me.NewManagedEntity(meDef)
+	}
+	if _, ok := opt.payload.(*[]me.ManagedEntity); ok {
+		if opt.frameFormat == BaselineIdent {
+			return nil, errors.New("invalid payload for Baseline message")
+		}
+		// TODO: List of MEs. valid for extended messages only
+	} else if managedEntity, ok := opt.payload.(*me.ManagedEntity); ok {
+		// Single ME
+		meLayer.ReportedME = *managedEntity
+	} else {
+		return nil, errors.New("invalid payload for MibUploadNextResponse frame")
+	}
+	return meLayer, nil
+}
diff --git a/meframe/me_mibupload_test.go b/meframe/me_mibupload_test.go
new file mode 100644
index 0000000..d278682
--- /dev/null
+++ b/meframe/me_mibupload_test.go
@@ -0,0 +1,208 @@
+/*
+ * Copyright (c) 2018 - present.  Boling Consulting Solutions (bcsw.net)
+ * Copyright 2020-present Open Networking Foundation
+
+ * 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.
+ */
+package meframe_test
+
+import (
+	"github.com/google/gopacket"
+	. "github.com/opencord/omci-lib-go"
+	me "github.com/opencord/omci-lib-go/generated"
+	"github.com/opencord/omci-lib-go/meframe"
+	"github.com/stretchr/testify/assert"
+	"math/rand"
+	"testing"
+)
+
+func testMibUploadRequestTypeMeFrame(t *testing.T, managedEntity *me.ManagedEntity, messageSet DeviceIdent) {
+	params := me.ParamData{
+		EntityID: uint16(0),
+	}
+	// Create the managed instance
+	meInstance, err := me.NewManagedEntity(managedEntity.GetManagedEntityDefinition(), params)
+	assert.NotNil(t, err)
+	assert.Equal(t, err.StatusCode(), me.Success)
+
+	tid := uint16(rand.Int31n(0xFFFE) + 1) // [1, 0xFFFF]
+
+	frame, omciErr := meframe.GenFrame(meInstance, MibUploadRequestType, meframe.TransactionID(tid), meframe.FrameFormat(messageSet))
+	assert.NotNil(t, frame)
+	assert.NotZero(t, len(frame))
+	assert.Nil(t, omciErr)
+
+	///////////////////////////////////////////////////////////////////
+	// Now decode and compare
+	packet := gopacket.NewPacket(frame, LayerTypeOMCI, gopacket.NoCopy)
+	assert.NotNil(t, packet)
+
+	omciLayer := packet.Layer(LayerTypeOMCI)
+	assert.NotNil(t, omciLayer)
+
+	omciObj, omciOk := omciLayer.(*OMCI)
+	assert.NotNil(t, omciObj)
+	assert.True(t, omciOk)
+	assert.Equal(t, tid, omciObj.TransactionID)
+	assert.Equal(t, MibUploadRequestType, omciObj.MessageType)
+	assert.Equal(t, messageSet, omciObj.DeviceIdentifier)
+
+	msgLayer := packet.Layer(LayerTypeMibUploadRequest)
+	assert.NotNil(t, msgLayer)
+
+	msgObj, msgOk := msgLayer.(*MibUploadRequest)
+	assert.NotNil(t, msgObj)
+	assert.True(t, msgOk)
+
+	assert.Equal(t, meInstance.GetClassID(), msgObj.EntityClass)
+	assert.Equal(t, meInstance.GetEntityID(), msgObj.EntityInstance)
+}
+
+func testMibUploadResponseTypeMeFrame(t *testing.T, managedEntity *me.ManagedEntity, messageSet DeviceIdent) {
+	params := me.ParamData{
+		EntityID: uint16(0),
+	}
+	// Create the managed instance
+	meInstance, err := me.NewManagedEntity(managedEntity.GetManagedEntityDefinition(), params)
+	assert.NotNil(t, err)
+	assert.Equal(t, err.StatusCode(), me.Success)
+
+	tid := uint16(rand.Int31n(0xFFFE) + 1)  // [1, 0xFFFF]
+	numOfCommands := uint16(rand.Int31n(5)) // [0, 5)
+
+	frame, omciErr := meframe.GenFrame(meInstance, MibUploadResponseType, meframe.TransactionID(tid),
+		meframe.SequenceNumberCountOrSize(numOfCommands), meframe.FrameFormat(messageSet))
+	assert.NotNil(t, frame)
+	assert.NotZero(t, len(frame))
+	assert.Nil(t, omciErr)
+
+	///////////////////////////////////////////////////////////////////
+	// Now decode and compare
+	packet := gopacket.NewPacket(frame, LayerTypeOMCI, gopacket.NoCopy)
+	assert.NotNil(t, packet)
+
+	omciLayer := packet.Layer(LayerTypeOMCI)
+	assert.NotNil(t, omciLayer)
+
+	omciObj, omciOk := omciLayer.(*OMCI)
+	assert.NotNil(t, omciObj)
+	assert.True(t, omciOk)
+	assert.Equal(t, tid, omciObj.TransactionID)
+	assert.Equal(t, MibUploadResponseType, omciObj.MessageType)
+	assert.Equal(t, messageSet, omciObj.DeviceIdentifier)
+
+	msgLayer := packet.Layer(LayerTypeMibUploadResponse)
+	assert.NotNil(t, msgLayer)
+
+	msgObj, msgOk := msgLayer.(*MibUploadResponse)
+	assert.NotNil(t, msgObj)
+	assert.True(t, msgOk)
+
+	assert.Equal(t, meInstance.GetClassID(), msgObj.EntityClass)
+	assert.Equal(t, meInstance.GetEntityID(), msgObj.EntityInstance)
+	assert.Equal(t, numOfCommands, msgObj.NumberOfCommands)
+}
+
+func testMibUploadNextRequestTypeMeFrame(t *testing.T, managedEntity *me.ManagedEntity, messageSet DeviceIdent) {
+	params := me.ParamData{
+		EntityID: uint16(0),
+	}
+	// Create the managed instance
+	meInstance, err := me.NewManagedEntity(managedEntity.GetManagedEntityDefinition(), params)
+	assert.NotNil(t, err)
+	assert.Equal(t, err.StatusCode(), me.Success)
+
+	seqNumber := uint16(rand.Int31n(0xFFFF)) // [0, 0xFFFE]
+	tid := uint16(rand.Int31n(0xFFFE) + 1)   // [1, 0xFFFF]
+
+	var frame []byte
+	frame, omciErr := meframe.GenFrame(meInstance, MibUploadNextRequestType, meframe.TransactionID(tid),
+		meframe.SequenceNumberCountOrSize(seqNumber), meframe.FrameFormat(messageSet))
+	assert.NotNil(t, frame)
+	assert.NotZero(t, len(frame))
+	assert.Nil(t, omciErr)
+
+	///////////////////////////////////////////////////////////////////
+	// Now decode and compare
+	packet := gopacket.NewPacket(frame, LayerTypeOMCI, gopacket.NoCopy)
+	assert.NotNil(t, packet)
+
+	omciLayer := packet.Layer(LayerTypeOMCI)
+	assert.NotNil(t, omciLayer)
+
+	omciObj, omciOk := omciLayer.(*OMCI)
+	assert.NotNil(t, omciObj)
+	assert.True(t, omciOk)
+	assert.Equal(t, tid, omciObj.TransactionID)
+	assert.Equal(t, MibUploadNextRequestType, omciObj.MessageType)
+	assert.Equal(t, messageSet, omciObj.DeviceIdentifier)
+
+	msgLayer := packet.Layer(LayerTypeMibUploadNextRequest)
+	assert.NotNil(t, msgLayer)
+
+	msgObj, msgOk := msgLayer.(*MibUploadNextRequest)
+	assert.NotNil(t, msgObj)
+	assert.True(t, msgOk)
+
+	assert.Equal(t, seqNumber, msgObj.CommandSequenceNumber)
+	assert.Equal(t, meInstance.GetClassID(), msgObj.EntityClass)
+	assert.Equal(t, meInstance.GetEntityID(), msgObj.EntityInstance)
+}
+
+func testMibUploadNextResponseTypeMeFrame(t *testing.T, managedEntity *me.ManagedEntity, messageSet DeviceIdent) {
+	params := me.ParamData{
+		EntityID: uint16(0),
+	}
+	// Create the managed instance
+	meInstance, err := me.NewManagedEntity(managedEntity.GetManagedEntityDefinition(), params)
+	assert.NotNil(t, err)
+	assert.Equal(t, err.StatusCode(), me.Success)
+
+	tid := uint16(rand.Int31n(0xFFFE) + 1) // [1, 0xFFFF]
+
+	// TODO: Since only baseline messages supported, send only one ME
+	uploadMe := meInstance
+
+	frame, omciErr := meframe.GenFrame(meInstance, MibUploadNextResponseType, meframe.TransactionID(tid),
+		meframe.Payload(uploadMe), meframe.FrameFormat(messageSet))
+	assert.NotNil(t, frame)
+	assert.NotZero(t, len(frame))
+	assert.Nil(t, omciErr)
+
+	///////////////////////////////////////////////////////////////////
+	// Now decode and compare
+	packet := gopacket.NewPacket(frame, LayerTypeOMCI, gopacket.NoCopy)
+	assert.NotNil(t, packet)
+
+	omciLayer := packet.Layer(LayerTypeOMCI)
+	assert.NotNil(t, omciLayer)
+
+	omciObj, omciOk := omciLayer.(*OMCI)
+	assert.NotNil(t, omciObj)
+	assert.True(t, omciOk)
+	assert.Equal(t, tid, omciObj.TransactionID)
+	assert.Equal(t, MibUploadNextResponseType, omciObj.MessageType)
+	assert.Equal(t, messageSet, omciObj.DeviceIdentifier)
+
+	msgLayer := packet.Layer(LayerTypeMibUploadNextResponse)
+	assert.NotNil(t, msgLayer)
+
+	msgObj, msgOk := msgLayer.(*MibUploadNextResponse)
+	assert.NotNil(t, msgObj)
+	assert.True(t, msgOk)
+
+	assert.Equal(t, meInstance.GetClassID(), msgObj.EntityClass)
+	assert.Equal(t, meInstance.GetEntityID(), msgObj.EntityInstance)
+	assert.Equal(t, uploadMe.GetClassID(), msgObj.ReportedME.GetClassID())
+	assert.Equal(t, uploadMe.GetEntityID(), msgObj.ReportedME.GetEntityID())
+}
diff --git a/meframe/me_reboot.go b/meframe/me_reboot.go
new file mode 100644
index 0000000..b4c23dc
--- /dev/null
+++ b/meframe/me_reboot.go
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2018 - present.  Boling Consulting Solutions (bcsw.net)
+ * Copyright 2020-present Open Networking Foundation
+
+ * 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.
+ */
+
+package meframe
+
+import (
+	"errors"
+	"github.com/google/gopacket"
+	. "github.com/opencord/omci-lib-go"
+	me "github.com/opencord/omci-lib-go/generated"
+)
+
+func RebootRequestFrame(m *me.ManagedEntity, opt options) (gopacket.SerializableLayer, error) {
+	if opt.frameFormat == ExtendedIdent {
+		return nil, errors.New("extended message set for this message type is not supported")
+	}
+	// Common for all MEs
+	meLayer := &RebootRequest{
+		MeBasePacket: MeBasePacket{
+			EntityClass:    m.GetClassID(),
+			EntityInstance: m.GetEntityID(),
+			Extended:       opt.frameFormat == ExtendedIdent,
+		},
+		RebootCondition: opt.mode,
+	}
+	return meLayer, nil
+}
+
+func RebootResponseFrame(m *me.ManagedEntity, opt options) (gopacket.SerializableLayer, error) {
+	if opt.frameFormat == ExtendedIdent {
+		return nil, errors.New("extended message set for this message type is not supported")
+	}
+	// Common for all MEs
+	meLayer := &RebootResponse{
+		MeBasePacket: MeBasePacket{
+			EntityClass:    m.GetClassID(),
+			EntityInstance: m.GetEntityID(),
+			Extended:       opt.frameFormat == ExtendedIdent,
+		},
+		Result: opt.result,
+	}
+	return meLayer, nil
+}
diff --git a/meframe/me_reboot_test.go b/meframe/me_reboot_test.go
new file mode 100644
index 0000000..8c16b7f
--- /dev/null
+++ b/meframe/me_reboot_test.go
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2018 - present.  Boling Consulting Solutions (bcsw.net)
+ * Copyright 2020-present Open Networking Foundation
+
+ * 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.
+ */
+package meframe_test
+
+import (
+	"github.com/google/gopacket"
+	. "github.com/opencord/omci-lib-go"
+	me "github.com/opencord/omci-lib-go/generated"
+	"github.com/opencord/omci-lib-go/meframe"
+	"github.com/stretchr/testify/assert"
+	"math/rand"
+	"testing"
+)
+
+func testRebootRequestTypeMeFrame(t *testing.T, managedEntity *me.ManagedEntity, messageSet DeviceIdent) {
+	params := me.ParamData{
+		EntityID: uint16(0),
+	}
+	// Create the managed instance
+	meInstance, err := me.NewManagedEntity(managedEntity.GetManagedEntityDefinition(), params)
+	assert.NotNil(t, err)
+	assert.Equal(t, err.StatusCode(), me.Success)
+
+	tid := uint16(rand.Int31n(0xFFFE) + 1) // [1, 0xFFFF]
+	condition := uint8(rand.Int31n(3))     // [0, 3]
+
+	frame, omciErr := meframe.GenFrame(meInstance, RebootRequestType, meframe.TransactionID(tid),
+		meframe.RebootCondition(condition), meframe.FrameFormat(messageSet))
+	assert.NotNil(t, frame)
+	assert.NotZero(t, len(frame))
+	assert.Nil(t, omciErr)
+
+	///////////////////////////////////////////////////////////////////
+	// Now decode and compare
+	packet := gopacket.NewPacket(frame, LayerTypeOMCI, gopacket.NoCopy)
+	assert.NotNil(t, packet)
+
+	omciLayer := packet.Layer(LayerTypeOMCI)
+	assert.NotNil(t, omciLayer)
+
+	omciObj, omciOk := omciLayer.(*OMCI)
+	assert.NotNil(t, omciObj)
+	assert.True(t, omciOk)
+	assert.Equal(t, tid, omciObj.TransactionID)
+	assert.Equal(t, RebootRequestType, omciObj.MessageType)
+	assert.Equal(t, messageSet, omciObj.DeviceIdentifier)
+
+	msgLayer := packet.Layer(LayerTypeRebootRequest)
+	assert.NotNil(t, msgLayer)
+
+	msgObj, msgOk := msgLayer.(*RebootRequest)
+	assert.NotNil(t, msgObj)
+	assert.True(t, msgOk)
+
+	assert.Equal(t, meInstance.GetClassID(), msgObj.EntityClass)
+	assert.Equal(t, meInstance.GetEntityID(), msgObj.EntityInstance)
+	assert.Equal(t, condition, msgObj.RebootCondition)
+}
+
+func testRebootResponseTypeMeFrame(t *testing.T, managedEntity *me.ManagedEntity, messageSet DeviceIdent) {
+	params := me.ParamData{
+		EntityID: uint16(0),
+	}
+	// Create the managed instance
+	meInstance, err := me.NewManagedEntity(managedEntity.GetManagedEntityDefinition(), params)
+	assert.NotNil(t, err)
+	assert.Equal(t, err.StatusCode(), me.Success)
+
+	tid := uint16(rand.Int31n(0xFFFE) + 1) // [1, 0xFFFF]
+	result := me.Results(rand.Int31n(7))   // [0, 6] Not all types will be tested
+
+	frame, omciErr := meframe.GenFrame(meInstance, RebootResponseType, meframe.TransactionID(tid),
+		meframe.Result(result), meframe.FrameFormat(messageSet))
+	assert.NotNil(t, frame)
+	assert.NotZero(t, len(frame))
+	assert.Nil(t, omciErr)
+
+	///////////////////////////////////////////////////////////////////
+	// Now decode and compare
+	packet := gopacket.NewPacket(frame, LayerTypeOMCI, gopacket.NoCopy)
+	assert.NotNil(t, packet)
+
+	omciLayer := packet.Layer(LayerTypeOMCI)
+	assert.NotNil(t, omciLayer)
+
+	omciObj, omciOk := omciLayer.(*OMCI)
+	assert.NotNil(t, omciObj)
+	assert.True(t, omciOk)
+	assert.Equal(t, tid, omciObj.TransactionID)
+	assert.Equal(t, RebootResponseType, omciObj.MessageType)
+	assert.Equal(t, messageSet, omciObj.DeviceIdentifier)
+
+	msgLayer := packet.Layer(LayerTypeRebootResponse)
+	assert.NotNil(t, msgLayer)
+
+	msgObj, msgOk := msgLayer.(*RebootResponse)
+	assert.NotNil(t, msgObj)
+	assert.True(t, msgOk)
+
+	assert.Equal(t, meInstance.GetClassID(), msgObj.EntityClass)
+	assert.Equal(t, meInstance.GetEntityID(), msgObj.EntityInstance)
+	assert.Equal(t, result, msgObj.Result)
+}
diff --git a/meframe/me_set.go b/meframe/me_set.go
new file mode 100644
index 0000000..af760a9
--- /dev/null
+++ b/meframe/me_set.go
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2018 - present.  Boling Consulting Solutions (bcsw.net)
+ * Copyright 2020-present Open Networking Foundation
+
+ * 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.
+ */
+
+package meframe
+
+import (
+	"errors"
+	"fmt"
+	"github.com/google/gopacket"
+	. "github.com/opencord/omci-lib-go"
+	me "github.com/opencord/omci-lib-go/generated"
+)
+
+func SetRequestFrame(m *me.ManagedEntity, opt options) (gopacket.SerializableLayer, error) {
+	mask, err := checkAttributeMask(m, opt.attributeMask)
+	if err != nil {
+		return nil, err
+	}
+	mask, err = calculateAttributeMask(m, mask)
+	if err != nil {
+		return nil, err
+	}
+	meDefinition := m.GetManagedEntityDefinition()
+	attrDefs := meDefinition.GetAttributeDefinitions()
+	attrMap := m.GetAttributeValueMap()
+
+	// Get payload space available
+	maxPayload := maxPacketAvailable(m, opt)
+	payloadAvailable := int(maxPayload) - 2 // Less attribute mask
+	if opt.frameFormat == ExtendedIdent {
+		return nil, errors.New("extended message set for this message type is not supported")
+		// payloadAvailable -= 2				// Less length
+	}
+	meLayer := &SetRequest{
+		MeBasePacket: MeBasePacket{
+			EntityClass:    m.GetClassID(),
+			EntityInstance: m.GetEntityID(),
+			Extended:       opt.frameFormat == ExtendedIdent,
+		},
+		AttributeMask: 0,
+		Attributes:    make(me.AttributeValueMap),
+	}
+	for mask != 0 {
+		// Iterate down the attributes (Attribute 0 is the ManagedEntity ID)
+		var attrIndex uint
+		for attrIndex = 1; attrIndex <= 16; attrIndex++ {
+			// Is this attribute requested
+			if mask&(1<<(16-attrIndex)) != 0 {
+				// Get definitions since we need the name
+				attrDef, ok := attrDefs[attrIndex]
+				if !ok {
+					msg := fmt.Sprintf("Unexpected error, index %v not valued for ME %v",
+						attrIndex, meDefinition.GetName())
+					return nil, errors.New(msg)
+				}
+				var attrValue interface{}
+				attrValue, ok = attrMap[attrDef.Name]
+				if !ok {
+					msg := fmt.Sprintf("Unexpected error, attribute %v not provided in ME %v: %v",
+						attrDef.GetName(), meDefinition.GetName(), m)
+					return nil, errors.New(msg)
+				}
+				// Is space available?
+				if attrDef.Size <= payloadAvailable {
+					// Mark bit handled
+					mask &= ^attrDef.Mask
+					meLayer.AttributeMask |= attrDef.Mask
+					meLayer.Attributes[attrDef.Name] = attrValue
+					payloadAvailable -= attrDef.Size
+				} else {
+					// TODO: Should we set truncate?
+					msg := fmt.Sprintf("out-of-space. Cannot fit attribute %v into SetRequest message",
+						attrDef.GetName())
+					return nil, me.NewMessageTruncatedError(msg)
+				}
+			}
+		}
+	}
+	if meLayer.AttributeMask == 0 {
+		// TODO: Is a set request with no attributes valid?
+		return nil, errors.New("no attributes encoded for SetRequest")
+	}
+	return meLayer, nil
+}
+
+func SetResponseFrame(m *me.ManagedEntity, opt options) (gopacket.SerializableLayer, error) {
+	if opt.frameFormat == ExtendedIdent {
+		return nil, errors.New("extended message set for this message type is not supported")
+	}
+	meLayer := &SetResponse{
+		MeBasePacket: MeBasePacket{
+			EntityClass:    m.GetClassID(),
+			EntityInstance: m.GetEntityID(),
+			Extended:       opt.frameFormat == ExtendedIdent,
+		},
+		Result: opt.result,
+	}
+	if meLayer.Result == me.AttributeFailure {
+		meLayer.UnsupportedAttributeMask = opt.unsupportedMask
+		meLayer.FailedAttributeMask = opt.attrExecutionMask
+	}
+	return meLayer, nil
+}
diff --git a/meframe/me_set_test.go b/meframe/me_set_test.go
new file mode 100644
index 0000000..33afb1a
--- /dev/null
+++ b/meframe/me_set_test.go
@@ -0,0 +1,175 @@
+/*
+ * Copyright (c) 2018 - present.  Boling Consulting Solutions (bcsw.net)
+ * Copyright 2020-present Open Networking Foundation
+
+ * 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.
+ */
+package meframe_test
+
+import (
+	"github.com/google/gopacket"
+	. "github.com/opencord/omci-lib-go"
+	me "github.com/opencord/omci-lib-go/generated"
+	"github.com/opencord/omci-lib-go/meframe"
+	"github.com/stretchr/testify/assert"
+	"math/rand"
+	"testing"
+)
+
+func testSetRequestTypeMeFrame(t *testing.T, managedEntity *me.ManagedEntity, messageSet DeviceIdent) {
+	params := me.ParamData{
+		EntityID:   uint16(0),
+		Attributes: make(me.AttributeValueMap, 0),
+	}
+	attrDefs := managedEntity.GetAttributeDefinitions()
+	tableAttrFound := false
+	for _, attrDef := range attrDefs {
+		if attrDef.Index == 0 {
+			continue // Skip entity ID, already specified
+		} else if attrDef.IsTableAttribute() {
+			tableAttrFound = true
+			continue // TODO: Skip table attributes for now
+		} else if attrDef.GetAccess().Contains(me.Write) {
+			params.Attributes[attrDef.GetName()] = pickAValue(attrDef)
+		}
+	}
+	if tableAttrFound && len(params.Attributes) == 0 {
+		// The only set attribute may have been a table and we do not have
+		// a test for that right now.
+		return
+	}
+	assert.NotEmpty(t, params.Attributes) // Need a parameter that is a table attribute
+	bitmask, attrErr := me.GetAttributesBitmap(attrDefs, getAttributeNameSet(params.Attributes))
+	assert.Nil(t, attrErr)
+
+	// Create the managed instance
+	meInstance, err := me.NewManagedEntity(managedEntity.GetManagedEntityDefinition(), params)
+	assert.NotNil(t, err)
+	assert.Equal(t, err.StatusCode(), me.Success)
+	tid := uint16(rand.Int31n(0xFFFE) + 1) // [1, 0xFFFF]
+
+	frame, omciErr := meframe.GenFrame(meInstance, SetRequestType, meframe.TransactionID(tid),
+		meframe.AttributeMask(bitmask), meframe.FrameFormat(messageSet))
+	// some frames cannot fit all the attributes
+	if omciErr != nil {
+		if _, ok := omciErr.(*me.MessageTruncatedError); ok {
+			return
+		}
+	}
+	assert.NotNil(t, frame)
+	assert.NotZero(t, len(frame))
+
+	///////////////////////////////////////////////////////////////////
+	// Now decode and compare
+	packet := gopacket.NewPacket(frame, LayerTypeOMCI, gopacket.NoCopy)
+	assert.NotNil(t, packet)
+
+	omciLayer := packet.Layer(LayerTypeOMCI)
+	assert.NotNil(t, omciLayer)
+
+	omciObj, omciOk := omciLayer.(*OMCI)
+	assert.NotNil(t, omciObj)
+	assert.True(t, omciOk)
+	assert.Equal(t, tid, omciObj.TransactionID)
+	assert.Equal(t, SetRequestType, omciObj.MessageType)
+	assert.Equal(t, messageSet, omciObj.DeviceIdentifier)
+
+	msgLayer := packet.Layer(LayerTypeSetRequest)
+	assert.NotNil(t, msgLayer)
+
+	msgObj, msgOk := msgLayer.(*SetRequest)
+	assert.NotNil(t, msgObj)
+	assert.True(t, msgOk)
+
+	assert.Equal(t, meInstance.GetClassID(), msgObj.EntityClass)
+	assert.Equal(t, meInstance.GetEntityID(), msgObj.EntityInstance)
+	assert.Equal(t, meInstance.GetAttributeValueMap(), msgObj.Attributes)
+}
+
+func testSetResponseTypeMeFrame(t *testing.T, managedEntity *me.ManagedEntity, messageSet DeviceIdent) {
+	params := me.ParamData{
+		EntityID: uint16(0),
+	}
+	// Create the managed instance
+	meInstance, err := me.NewManagedEntity(managedEntity.GetManagedEntityDefinition(), params)
+	assert.NotNil(t, err)
+	assert.Equal(t, err.StatusCode(), me.Success)
+
+	tid := uint16(rand.Int31n(0xFFFE) + 1) // [1, 0xFFFF]
+	result := me.Results(rand.Int31n(10))  // [0, 9] Not all types will be tested
+
+	// Always pass a failure mask, but should only get encoded if result == ParameterError
+	var unsupportedMask uint16
+	var failedMask uint16
+	attrDefs := managedEntity.GetAttributeDefinitions()
+	for _, attrDef := range attrDefs {
+		if attrDef.Index == 0 {
+			continue // Skip entity ID, already specified
+
+		} else if attrDef.GetAccess().Contains(me.Write) {
+			// Random 10% chance this parameter unsupported and
+			// 10% it failed
+			switch rand.Int31n(5) {
+			case 0:
+				unsupportedMask |= attrDef.Mask
+			case 1:
+				failedMask |= attrDef.Mask
+			}
+		}
+	}
+	bitmask, attrErr := me.GetAttributesBitmap(attrDefs, getAttributeNameSet(params.Attributes))
+	assert.Nil(t, attrErr)
+
+	frame, omciErr := meframe.GenFrame(meInstance, SetResponseType,
+		meframe.TransactionID(tid), meframe.Result(result),
+		meframe.AttributeMask(bitmask), meframe.FrameFormat(messageSet),
+		meframe.AttributeExecutionMask(failedMask),
+		meframe.UnsupportedAttributeMask(unsupportedMask))
+	assert.NotNil(t, frame)
+	assert.NotZero(t, len(frame))
+	assert.Nil(t, omciErr)
+
+	///////////////////////////////////////////////////////////////////
+	// Now decode and compare
+	packet := gopacket.NewPacket(frame, LayerTypeOMCI, gopacket.NoCopy)
+	assert.NotNil(t, packet)
+
+	omciLayer := packet.Layer(LayerTypeOMCI)
+	assert.NotNil(t, omciLayer)
+
+	omciObj, omciOk := omciLayer.(*OMCI)
+	assert.NotNil(t, omciObj)
+	assert.True(t, omciOk)
+	assert.Equal(t, tid, omciObj.TransactionID)
+	assert.Equal(t, SetResponseType, omciObj.MessageType)
+	assert.Equal(t, messageSet, omciObj.DeviceIdentifier)
+
+	msgLayer := packet.Layer(LayerTypeSetResponse)
+	assert.NotNil(t, msgLayer)
+
+	msgObj, msgOk := msgLayer.(*SetResponse)
+	assert.NotNil(t, msgObj)
+	assert.True(t, msgOk)
+
+	assert.Equal(t, meInstance.GetClassID(), msgObj.EntityClass)
+	assert.Equal(t, meInstance.GetEntityID(), msgObj.EntityInstance)
+	assert.Equal(t, result, msgObj.Result)
+
+	if result == me.AttributeFailure {
+		assert.Equal(t, failedMask, msgObj.FailedAttributeMask)
+		assert.Equal(t, unsupportedMask, msgObj.UnsupportedAttributeMask)
+	} else {
+		assert.Zero(t, msgObj.FailedAttributeMask)
+		assert.Zero(t, msgObj.UnsupportedAttributeMask)
+	}
+}
diff --git a/meframe/me_setable.go b/meframe/me_setable.go
new file mode 100644
index 0000000..07732c6
--- /dev/null
+++ b/meframe/me_setable.go
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2018 - present.  Boling Consulting Solutions (bcsw.net)
+ * Copyright 2020-present Open Networking Foundation
+
+ * 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.
+ */
+
+package meframe
+
+import (
+	"errors"
+	"fmt"
+	"github.com/google/gopacket"
+	. "github.com/opencord/omci-lib-go"
+	me "github.com/opencord/omci-lib-go/generated"
+)
+
+func SetTableRequestFrame(m *me.ManagedEntity, opt options) (gopacket.SerializableLayer, error) {
+	if opt.frameFormat != ExtendedIdent {
+		return nil, errors.New("set table message type only supported with Extended OMCI Messaging")
+	}
+	if opt.frameFormat == ExtendedIdent {
+		return nil, errors.New("extended message set for this message type is not supported")
+	}
+	mask, err := checkAttributeMask(m, opt.attributeMask)
+	if err != nil {
+		return nil, err
+	}
+	// Common for all MEs
+	meLayer := &SetTableRequest{
+		MeBasePacket: MeBasePacket{
+			EntityClass:    m.GetClassID(),
+			EntityInstance: m.GetEntityID(),
+			Extended:       opt.frameFormat == ExtendedIdent,
+		},
+	}
+	// Get payload space available
+	maxPayload := maxPacketAvailable(m, opt)
+
+	// TODO: Lots of work to do
+
+	fmt.Println(mask, maxPayload)
+	return meLayer, errors.New("todo: Not implemented")
+}
+
+func SetTableResponseFrame(m *me.ManagedEntity, opt options) (gopacket.SerializableLayer, error) {
+	if opt.frameFormat != ExtendedIdent {
+		return nil, errors.New("set table message type only supported with Extended OMCI Message Set")
+	}
+	if opt.frameFormat == ExtendedIdent {
+		return nil, errors.New("extended message set for this message type is not supported")
+	}
+	mask, err := checkAttributeMask(m, opt.attributeMask)
+	if err != nil {
+		return nil, err
+	}
+	// Common for all MEs
+	meLayer := &SetTableResponse{
+		MeBasePacket: MeBasePacket{
+			EntityClass:    m.GetClassID(),
+			EntityInstance: m.GetEntityID(),
+			Extended:       true,
+		},
+	}
+	// Get payload space available
+	maxPayload := maxPacketAvailable(m, opt)
+
+	// TODO: Lots of work to do
+
+	fmt.Println(mask, maxPayload)
+	return meLayer, errors.New("todo: Not implemented")
+}
diff --git a/meframe/me_setable_test.go b/meframe/me_setable_test.go
new file mode 100644
index 0000000..3afe70a
--- /dev/null
+++ b/meframe/me_setable_test.go
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2018 - present.  Boling Consulting Solutions (bcsw.net)
+ * Copyright 2020-present Open Networking Foundation
+
+ * 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.
+ */
+package meframe_test
+
+import (
+	. "github.com/opencord/omci-lib-go"
+	me "github.com/opencord/omci-lib-go/generated"
+	"testing"
+)
+
+func testSetTableRequestTypeMeFrame(t *testing.T, managedEntity *me.ManagedEntity, messageSet DeviceIdent) {
+	// TODO: Implement
+}
+
+func testSetTableResponseTypeMeFrame(t *testing.T, managedEntity *me.ManagedEntity, messageSet DeviceIdent) {
+	// TODO: Implement
+}
diff --git a/meframe/me_software.go b/meframe/me_software.go
new file mode 100644
index 0000000..6d6d3fb
--- /dev/null
+++ b/meframe/me_software.go
@@ -0,0 +1,262 @@
+/*
+ * Copyright (c) 2018 - present.  Boling Consulting Solutions (bcsw.net)
+ * Copyright 2020-present Open Networking Foundation
+
+ * 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.
+ */
+
+package meframe
+
+import (
+	"errors"
+	"fmt"
+	"github.com/google/gopacket"
+	. "github.com/opencord/omci-lib-go"
+	me "github.com/opencord/omci-lib-go/generated"
+)
+
+func StartSoftwareDownloadRequestFrame(m *me.ManagedEntity, opt options) (gopacket.SerializableLayer, error) {
+	if opt.frameFormat == ExtendedIdent {
+		return nil, errors.New("extended message set for this message type is not supported")
+	}
+	// Common for all MEs
+	meLayer := &StartSoftwareDownloadRequest{
+		MeBasePacket: MeBasePacket{
+			EntityClass:    m.GetClassID(),
+			EntityInstance: m.GetEntityID(),
+			Extended:       opt.frameFormat == ExtendedIdent,
+		},
+		WindowSize:           opt.software.WindowSize,
+		ImageSize:            opt.software.ImageSize,
+		NumberOfCircuitPacks: byte(len(opt.software.CircuitPacks)),
+		CircuitPacks:         opt.software.CircuitPacks,
+	}
+	// TODO: Add length check to insure we do not exceed maximum packet size
+	// payloadAvailable := int(maxPacketAvailable(m, opt))
+	payloadAvailable := 2
+	sizeNeeded := 1
+	if sizeNeeded > payloadAvailable {
+		// TODO: Should we set truncate?
+		msg := "out-of-space. Cannot fit Circuit Pack instances into Start Software Download Request message"
+		return nil, me.NewMessageTruncatedError(msg)
+	}
+	return meLayer, nil
+}
+
+func StartSoftwareDownloadResponseFrame(m *me.ManagedEntity, opt options) (gopacket.SerializableLayer, error) {
+	if opt.frameFormat == ExtendedIdent {
+		return nil, errors.New("extended message set for this message type is not supported")
+	}
+	// Common for all MEs
+	meLayer := &StartSoftwareDownloadResponse{
+		MeBasePacket: MeBasePacket{
+			EntityClass:    m.GetClassID(),
+			EntityInstance: m.GetEntityID(),
+			Extended:       opt.frameFormat == ExtendedIdent,
+		},
+		WindowSize:        opt.software.WindowSize,
+		NumberOfInstances: byte(len(opt.software.CircuitPacks)),
+		MeResults:         opt.software.Results,
+	}
+	// TODO: Add length check to insure we do not exceed maximum packet size
+	// payloadAvailable := int(maxPacketAvailable(m, opt))
+	payloadAvailable := 2
+	sizeNeeded := 1
+	if sizeNeeded > payloadAvailable {
+		// TODO: Should we set truncate?
+		msg := "out-of-space. Cannot fit Results  into Start Software Download Response message"
+		return nil, me.NewMessageTruncatedError(msg)
+	}
+	return meLayer, nil
+}
+
+func DownloadSectionRequestFrame(m *me.ManagedEntity, opt options) (gopacket.SerializableLayer, error) {
+	if opt.software.Data == nil {
+		return nil, me.NewNonStatusError("Software image data missing")
+	}
+	// Common for all MEs
+	meLayer := &DownloadSectionRequest{
+		MeBasePacket: MeBasePacket{
+			EntityClass:    m.GetClassID(),
+			EntityInstance: m.GetEntityID(),
+			Extended:       opt.frameFormat == ExtendedIdent,
+		},
+		SectionNumber: opt.software.SectionNumber,
+		SectionData:   opt.software.Data,
+	}
+	return meLayer, nil
+}
+
+func DownloadSectionResponseFrame(m *me.ManagedEntity, opt options) (gopacket.SerializableLayer, error) {
+	// Common for all MEs
+	meLayer := &DownloadSectionResponse{
+		MeBasePacket: MeBasePacket{
+			EntityClass:    m.GetClassID(),
+			EntityInstance: m.GetEntityID(),
+			Extended:       opt.frameFormat == ExtendedIdent,
+		},
+		Result:        opt.result,
+		SectionNumber: opt.software.SectionNumber,
+	}
+	return meLayer, nil
+}
+
+func EndSoftwareDownloadRequestFrame(m *me.ManagedEntity, opt options) (gopacket.SerializableLayer, error) {
+	if opt.frameFormat == ExtendedIdent {
+		return nil, errors.New("extended message set for this message type is not supported")
+	}
+	mask, err := checkAttributeMask(m, opt.attributeMask)
+	if err != nil {
+		return nil, err
+	}
+	// Common for all MEs
+	meLayer := &EndSoftwareDownloadRequest{
+		MeBasePacket: MeBasePacket{
+			EntityClass:    m.GetClassID(),
+			EntityInstance: m.GetEntityID(),
+			Extended:       opt.frameFormat == ExtendedIdent,
+		},
+	}
+	// Get payload space available
+	maxPayload := maxPacketAvailable(m, opt)
+
+	// TODO: Lots of work to do
+
+	fmt.Println(mask, maxPayload)
+	return meLayer, errors.New("todo: Not implemented")
+}
+
+func EndSoftwareDownloadResponseFrame(m *me.ManagedEntity, opt options) (gopacket.SerializableLayer, error) {
+	if opt.frameFormat == ExtendedIdent {
+		return nil, errors.New("extended message set for this message type is not supported")
+	}
+	mask, err := checkAttributeMask(m, opt.attributeMask)
+	if err != nil {
+		return nil, err
+	}
+	// Common for all MEs
+	meLayer := &EndSoftwareDownloadResponse{
+		MeBasePacket: MeBasePacket{
+			EntityClass:    m.GetClassID(),
+			EntityInstance: m.GetEntityID(),
+			Extended:       opt.frameFormat == ExtendedIdent,
+		},
+	}
+	// Get payload space available
+	maxPayload := maxPacketAvailable(m, opt)
+
+	// TODO: Lots of work to do
+
+	fmt.Println(mask, maxPayload)
+	return meLayer, errors.New("todo: Not implemented")
+}
+
+func ActivateSoftwareRequestFrame(m *me.ManagedEntity, opt options) (gopacket.SerializableLayer, error) {
+	if opt.frameFormat == ExtendedIdent {
+		return nil, errors.New("extended message set for this message type is not supported")
+	}
+	mask, err := checkAttributeMask(m, opt.attributeMask)
+	if err != nil {
+		return nil, err
+	}
+	// Common for all MEs
+	meLayer := &ActivateSoftwareRequest{
+		MeBasePacket: MeBasePacket{
+			EntityClass:    m.GetClassID(),
+			EntityInstance: m.GetEntityID(),
+			Extended:       opt.frameFormat == ExtendedIdent,
+		},
+	}
+	// Get payload space available
+	maxPayload := maxPacketAvailable(m, opt)
+
+	// TODO: Lots of work to do
+
+	fmt.Println(mask, maxPayload)
+	return meLayer, errors.New("todo: Not implemented")
+}
+
+func ActivateSoftwareResponseFrame(m *me.ManagedEntity, opt options) (gopacket.SerializableLayer, error) {
+	if opt.frameFormat == ExtendedIdent {
+		return nil, errors.New("extended message set for this message type is not supported")
+	}
+	mask, err := checkAttributeMask(m, opt.attributeMask)
+	if err != nil {
+		return nil, err
+	}
+	// Common for all MEs
+	meLayer := &ActivateSoftwareResponse{
+		MeBasePacket: MeBasePacket{
+			EntityClass:    m.GetClassID(),
+			EntityInstance: m.GetEntityID(),
+			Extended:       opt.frameFormat == ExtendedIdent,
+		},
+	}
+	// Get payload space available
+	maxPayload := maxPacketAvailable(m, opt)
+
+	// TODO: Lots of work to do
+
+	fmt.Println(mask, maxPayload)
+	return meLayer, errors.New("todo: Not implemented")
+}
+
+func CommitSoftwareRequestFrame(m *me.ManagedEntity, opt options) (gopacket.SerializableLayer, error) {
+	if opt.frameFormat == ExtendedIdent {
+		return nil, errors.New("extended message set for this message type is not supported")
+	}
+	mask, err := checkAttributeMask(m, opt.attributeMask)
+	if err != nil {
+		return nil, err
+	}
+	// Common for all MEs
+	meLayer := &CommitSoftwareRequest{
+		MeBasePacket: MeBasePacket{
+			EntityClass:    m.GetClassID(),
+			EntityInstance: m.GetEntityID(),
+			Extended:       opt.frameFormat == ExtendedIdent,
+		},
+	}
+	// Get payload space available
+	maxPayload := maxPacketAvailable(m, opt)
+
+	// TODO: Lots of work to do
+
+	fmt.Println(mask, maxPayload)
+	return meLayer, errors.New("todo: Not implemented")
+}
+
+func CommitSoftwareResponseFrame(m *me.ManagedEntity, opt options) (gopacket.SerializableLayer, error) {
+	if opt.frameFormat == ExtendedIdent {
+		return nil, errors.New("extended message set for this message type is not supported")
+	}
+	mask, err := checkAttributeMask(m, opt.attributeMask)
+	if err != nil {
+		return nil, err
+	}
+	// Common for all MEs
+	meLayer := &CommitSoftwareResponse{
+		MeBasePacket: MeBasePacket{
+			EntityClass:    m.GetClassID(),
+			EntityInstance: m.GetEntityID(),
+			Extended:       opt.frameFormat == ExtendedIdent,
+		},
+	}
+	// Get payload space available
+	maxPayload := maxPacketAvailable(m, opt)
+
+	// TODO: Lots of work to do
+
+	fmt.Println(mask, maxPayload)
+	return meLayer, errors.New("todo: Not implemented")
+}
diff --git a/meframe/me_software_test.go b/meframe/me_software_test.go
new file mode 100644
index 0000000..7f0ae6e
--- /dev/null
+++ b/meframe/me_software_test.go
@@ -0,0 +1,224 @@
+/*
+ * Copyright (c) 2018 - present.  Boling Consulting Solutions (bcsw.net)
+ * Copyright 2020-present Open Networking Foundation
+
+ * 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.
+ */
+package meframe_test
+
+import (
+	"github.com/google/gopacket"
+	. "github.com/opencord/omci-lib-go"
+	me "github.com/opencord/omci-lib-go/generated"
+	"github.com/opencord/omci-lib-go/meframe"
+	"github.com/stretchr/testify/assert"
+	"math/rand"
+	"testing"
+)
+
+func testStartSoftwareDownloadRequestTypeMeFrame(t *testing.T, managedEntity *me.ManagedEntity, messageSet DeviceIdent) {
+	instance := uint16(0) // ONU-G
+	image := uint16(1)
+	params := me.ParamData{
+		EntityID: uint16((instance << 8) + image),
+	}
+	// Create the managed instance
+	meInstance, err := me.NewManagedEntity(managedEntity.GetManagedEntityDefinition(), params)
+	assert.NotNil(t, err)
+	assert.Equal(t, err.StatusCode(), me.Success)
+
+	tid := uint16(rand.Int31n(0xFFFE) + 1) // [1, 0xFFFF]
+	options := meframe.SoftwareOptions{
+		WindowSize:   uint8(rand.Int31n(255)),                  // [0, 255]
+		ImageSize:    uint32(rand.Int31n(0x100000) + 0x100000), // [1 Meg, 2M-1]
+		CircuitPacks: []uint16{0},                              // [1 Meg, 2M-1]
+	}
+	frame, omciErr := meframe.GenFrame(meInstance, StartSoftwareDownloadRequestType,
+		meframe.TransactionID(tid), meframe.Software(options), meframe.FrameFormat(messageSet))
+	assert.NotNil(t, frame)
+	assert.NotZero(t, len(frame))
+	assert.Nil(t, omciErr)
+
+	///////////////////////////////////////////////////////////////////
+	// Now decode and compare
+	packet := gopacket.NewPacket(frame, LayerTypeOMCI, gopacket.NoCopy)
+	assert.NotNil(t, packet)
+
+	omciLayer := packet.Layer(LayerTypeOMCI)
+	assert.NotNil(t, omciLayer)
+
+	omciObj, omciOk := omciLayer.(*OMCI)
+	assert.NotNil(t, omciObj)
+	assert.True(t, omciOk)
+	assert.Equal(t, tid, omciObj.TransactionID)
+	assert.Equal(t, StartSoftwareDownloadRequestType, omciObj.MessageType)
+	assert.Equal(t, messageSet, omciObj.DeviceIdentifier)
+
+	msgLayer := packet.Layer(LayerTypeStartSoftwareDownloadRequest)
+	assert.NotNil(t, msgLayer)
+
+	msgObj, msgOk := msgLayer.(*StartSoftwareDownloadRequest)
+	assert.NotNil(t, msgObj)
+	assert.True(t, msgOk)
+
+	assert.Equal(t, meInstance.GetClassID(), msgObj.EntityClass)
+	assert.Equal(t, meInstance.GetEntityID(), msgObj.EntityInstance)
+	assert.Equal(t, options.ImageSize, msgObj.ImageSize)
+	assert.Equal(t, len(options.CircuitPacks), int(msgObj.NumberOfCircuitPacks))
+
+	for index, circuitPack := range options.CircuitPacks {
+		assert.Equal(t, circuitPack, msgObj.CircuitPacks[index])
+	}
+}
+
+func testStartSoftwareDownloadResponseTypeMeFrame(t *testing.T, managedEntity *me.ManagedEntity, messageSet DeviceIdent) {
+	// TODO: Implement
+}
+
+func testDownloadSectionRequestTypeMeFrame(t *testing.T, managedEntity *me.ManagedEntity, messageSet DeviceIdent) {
+	// TODO: In future, also support slot/multiple download formats
+	instance := uint16(0)
+	image := uint16(rand.Intn(1)) // Image 0 or 1 for this test
+	params := me.ParamData{
+		EntityID: (instance << 8) + image,
+	}
+	// Create the managed instance
+	meInstance, err := me.NewManagedEntity(managedEntity.GetManagedEntityDefinition(), params)
+	assert.NotNil(t, err)
+	assert.Equal(t, err.StatusCode(), me.Success)
+
+	tid := uint16(rand.Int31n(0xFFFE) + 1) // [1, 0xFFFF]
+	var data []byte
+
+	if messageSet == ExtendedIdent {
+		data = make([]byte, MaxDownloadSectionExtendedLength)
+	} else {
+		data = make([]byte, MaxDownloadSectionLength)
+	}
+	for index := range data {
+		data[index] = byte(index & 0xFF)
+	}
+	options := meframe.SoftwareOptions{
+		SectionNumber: uint8(rand.Int31n(255)), // [0, 255]
+		Data:          data,
+	}
+	frame, omciErr := meframe.GenFrame(meInstance, DownloadSectionRequestType,
+		meframe.TransactionID(tid), meframe.Software(options), meframe.FrameFormat(messageSet))
+	assert.NotNil(t, frame)
+	assert.NotZero(t, len(frame))
+	assert.Nil(t, omciErr)
+
+	///////////////////////////////////////////////////////////////////
+	// Now decode and compare
+	packet := gopacket.NewPacket(frame, LayerTypeOMCI, gopacket.NoCopy)
+	assert.NotNil(t, packet)
+
+	omciLayer := packet.Layer(LayerTypeOMCI)
+	assert.NotNil(t, omciLayer)
+
+	omciObj, omciOk := omciLayer.(*OMCI)
+	assert.NotNil(t, omciObj)
+	assert.True(t, omciOk)
+	assert.Equal(t, tid, omciObj.TransactionID)
+	assert.Equal(t, DownloadSectionRequestType, omciObj.MessageType)
+	assert.Equal(t, messageSet, omciObj.DeviceIdentifier)
+
+	msgLayer := packet.Layer(LayerTypeDownloadSectionRequest)
+	assert.NotNil(t, msgLayer)
+
+	msgObj, msgOk := msgLayer.(*DownloadSectionRequest)
+	assert.NotNil(t, msgObj)
+	assert.True(t, msgOk)
+
+	assert.Equal(t, meInstance.GetClassID(), msgObj.EntityClass)
+	assert.Equal(t, meInstance.GetEntityID(), msgObj.EntityInstance)
+	assert.Equal(t, options.SectionNumber, msgObj.SectionNumber)
+	assert.NotNil(t, msgObj.SectionData)
+	assert.Equal(t, options.Data, msgObj.SectionData)
+}
+
+func testDownloadSectionResponseTypeMeFrame(t *testing.T, managedEntity *me.ManagedEntity, messageSet DeviceIdent) {
+	instance := uint16(0)
+	image := uint16(rand.Intn(1)) // Image 0 or 1 for this test
+	params := me.ParamData{
+		EntityID: (instance << 8) + image,
+	}
+	// Create the managed instance
+	meInstance, err := me.NewManagedEntity(managedEntity.GetManagedEntityDefinition(), params)
+	assert.NotNil(t, err)
+	assert.Equal(t, err.StatusCode(), me.Success)
+
+	tid := uint16(rand.Int31n(0xFFFE) + 1) // [1, 0xFFFF]
+	result := me.Results(rand.Int31n(7))   // [0, 6] Not all types will be tested
+	swOptions := meframe.SoftwareOptions{
+		SectionNumber: uint8(rand.Int31n(255)), // [0, 255]
+	}
+	var frame []byte
+	frame, omciErr := meframe.GenFrame(meInstance, DownloadSectionResponseType, meframe.TransactionID(tid),
+		meframe.Result(result), meframe.FrameFormat(messageSet), meframe.Software(swOptions))
+
+	assert.NotNil(t, frame)
+	assert.NotZero(t, len(frame))
+	assert.Nil(t, omciErr)
+
+	///////////////////////////////////////////////////////////////////
+	// Now decode and compare
+	packet := gopacket.NewPacket(frame, LayerTypeOMCI, gopacket.NoCopy)
+	assert.NotNil(t, packet)
+
+	omciLayer := packet.Layer(LayerTypeOMCI)
+	assert.NotNil(t, omciLayer)
+
+	omciObj, omciOk := omciLayer.(*OMCI)
+	assert.NotNil(t, omciObj)
+	assert.True(t, omciOk)
+	assert.Equal(t, tid, omciObj.TransactionID)
+	assert.Equal(t, DownloadSectionResponseType, omciObj.MessageType)
+	assert.Equal(t, messageSet, omciObj.DeviceIdentifier)
+
+	msgLayer := packet.Layer(LayerTypeDownloadSectionResponse)
+	assert.NotNil(t, msgLayer)
+
+	msgObj, msgOk := msgLayer.(*DownloadSectionResponse)
+	assert.NotNil(t, msgObj)
+	assert.True(t, msgOk)
+
+	assert.Equal(t, meInstance.GetClassID(), msgObj.EntityClass)
+	assert.Equal(t, meInstance.GetEntityID(), msgObj.EntityInstance)
+	assert.Equal(t, result, msgObj.Result)
+	assert.Equal(t, swOptions.SectionNumber, msgObj.SectionNumber)
+}
+
+func testEndSoftwareDownloadRequestTypeMeFrame(t *testing.T, managedEntity *me.ManagedEntity, messageSet DeviceIdent) {
+	// TODO: Implement
+}
+
+func testEndSoftwareDownloadResponseTypeMeFrame(t *testing.T, managedEntity *me.ManagedEntity, messageSet DeviceIdent) {
+	// TODO: Implement
+}
+
+func testActivateSoftwareRequestTypeMeFrame(t *testing.T, managedEntity *me.ManagedEntity, messageSet DeviceIdent) {
+	// TODO: Implement
+}
+
+func testActivateSoftwareResponseTypeMeFrame(t *testing.T, managedEntity *me.ManagedEntity, messageSet DeviceIdent) {
+	// TODO: Implement
+}
+
+func testCommitSoftwareRequestTypeMeFrame(t *testing.T, managedEntity *me.ManagedEntity, messageSet DeviceIdent) {
+	// TODO: Implement
+}
+
+func testCommitSoftwareResponseTypeMeFrame(t *testing.T, managedEntity *me.ManagedEntity, messageSet DeviceIdent) {
+	// TODO: Implement
+}
diff --git a/meframe/me_synctime.go b/meframe/me_synctime.go
new file mode 100644
index 0000000..4773bc8
--- /dev/null
+++ b/meframe/me_synctime.go
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2018 - present.  Boling Consulting Solutions (bcsw.net)
+ * Copyright 2020-present Open Networking Foundation
+
+ * 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.
+ */
+
+package meframe
+
+import (
+	"errors"
+	"github.com/google/gopacket"
+	. "github.com/opencord/omci-lib-go"
+	me "github.com/opencord/omci-lib-go/generated"
+	"time"
+)
+
+func SynchronizeTimeRequestFrame(m *me.ManagedEntity, opt options) (gopacket.SerializableLayer, error) {
+	if opt.frameFormat == ExtendedIdent {
+		return nil, errors.New("extended message set for this message type is not supported")
+	}
+	// Common for all MEs
+	meLayer := &SynchronizeTimeRequest{
+		MeBasePacket: MeBasePacket{
+			EntityClass:    m.GetClassID(),
+			EntityInstance: m.GetEntityID(),
+			Extended:       opt.frameFormat == ExtendedIdent,
+		},
+	}
+	// Decode payload option. If nil, no timestamp provided
+	if timestamp, ok := opt.payload.(int64); ok {
+		tm := time.Unix(timestamp, 0)
+		meLayer.Year = uint16(tm.UTC().Year())
+		meLayer.Month = uint8(tm.UTC().Month())
+		meLayer.Day = uint8(tm.UTC().Day())
+		meLayer.Hour = uint8(tm.UTC().Hour())
+		meLayer.Minute = uint8(tm.UTC().Minute())
+		meLayer.Second = uint8(tm.UTC().Second())
+	}
+	return meLayer, nil
+}
+
+func SynchronizeTimeResponseFrame(m *me.ManagedEntity, opt options) (gopacket.SerializableLayer, error) {
+	if opt.frameFormat == ExtendedIdent {
+		return nil, errors.New("extended message set for this message type is not supported")
+	}
+	// Common for all MEs
+	meLayer := &SynchronizeTimeResponse{
+		MeBasePacket: MeBasePacket{
+			EntityClass:    m.GetClassID(),
+			EntityInstance: m.GetEntityID(),
+			Extended:       opt.frameFormat == ExtendedIdent,
+		},
+		Result:         opt.result,
+		SuccessResults: opt.mode,
+	}
+	return meLayer, nil
+}
diff --git a/meframe/me_synctime_test.go b/meframe/me_synctime_test.go
new file mode 100644
index 0000000..4ebe6d2
--- /dev/null
+++ b/meframe/me_synctime_test.go
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2018 - present.  Boling Consulting Solutions (bcsw.net)
+ * Copyright 2020-present Open Networking Foundation
+
+ * 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.
+ */
+package meframe_test
+
+import (
+	"github.com/google/gopacket"
+	. "github.com/opencord/omci-lib-go"
+	me "github.com/opencord/omci-lib-go/generated"
+	"github.com/opencord/omci-lib-go/meframe"
+	"github.com/stretchr/testify/assert"
+	"math/rand"
+	"testing"
+	"time"
+)
+
+func testSynchronizeTimeRequestTypeMeFrame(t *testing.T, managedEntity *me.ManagedEntity, messageSet DeviceIdent) {
+	params := me.ParamData{
+		EntityID: uint16(0),
+	}
+	// Create the managed instance
+	meInstance, err := me.NewManagedEntity(managedEntity.GetManagedEntityDefinition(), params)
+	assert.NotNil(t, err)
+	assert.Equal(t, err.StatusCode(), me.Success)
+
+	tid := uint16(rand.Int31n(0xFFFE) + 1) // [1, 0xFFFF]
+	tm := time.Now().UTC()
+	tmUnix := tm.Unix()
+
+	frame, omciErr := meframe.GenFrame(meInstance, SynchronizeTimeRequestType, meframe.TransactionID(tid),
+		meframe.Payload(tmUnix), meframe.FrameFormat(messageSet))
+	assert.NotNil(t, frame)
+	assert.NotZero(t, len(frame))
+	assert.Nil(t, omciErr)
+
+	///////////////////////////////////////////////////////////////////
+	// Now decode and compare
+	packet := gopacket.NewPacket(frame, LayerTypeOMCI, gopacket.NoCopy)
+	assert.NotNil(t, packet)
+
+	omciLayer := packet.Layer(LayerTypeOMCI)
+	assert.NotNil(t, omciLayer)
+
+	omciObj, omciOk := omciLayer.(*OMCI)
+	assert.NotNil(t, omciObj)
+	assert.True(t, omciOk)
+	assert.Equal(t, tid, omciObj.TransactionID)
+	assert.Equal(t, SynchronizeTimeRequestType, omciObj.MessageType)
+	assert.Equal(t, messageSet, omciObj.DeviceIdentifier)
+
+	msgLayer := packet.Layer(LayerTypeSynchronizeTimeRequest)
+	assert.NotNil(t, msgLayer)
+
+	msgObj, msgOk := msgLayer.(*SynchronizeTimeRequest)
+	assert.NotNil(t, msgObj)
+	assert.True(t, msgOk)
+
+	assert.Equal(t, meInstance.GetClassID(), msgObj.EntityClass)
+	assert.Equal(t, meInstance.GetEntityID(), msgObj.EntityInstance)
+
+	assert.Equal(t, uint16(tm.Year()), msgObj.Year)
+	assert.Equal(t, uint8(tm.Month()), msgObj.Month)
+	assert.Equal(t, uint8(tm.Day()), msgObj.Day)
+	assert.Equal(t, uint8(tm.Hour()), msgObj.Hour)
+	assert.Equal(t, uint8(tm.Minute()), msgObj.Minute)
+	assert.Equal(t, uint8(tm.Second()), msgObj.Second)
+}
+
+func testSynchronizeTimeResponseTypeMeFrame(t *testing.T, managedEntity *me.ManagedEntity, messageSet DeviceIdent) {
+	params := me.ParamData{
+		EntityID: uint16(0),
+	}
+	// Create the managed instance
+	meInstance, err := me.NewManagedEntity(managedEntity.GetManagedEntityDefinition(), params)
+	assert.NotNil(t, err)
+	assert.Equal(t, err.StatusCode(), me.Success)
+
+	tid := uint16(rand.Int31n(0xFFFE) + 1) // [1, 0xFFFF]
+	result := me.Results(rand.Int31n(7))   // [0, 6] Not all types will be tested
+	successResult := uint8(rand.Int31n(2)) // [0, 1]
+
+	var frame []byte
+	frame, omciErr := meframe.GenFrame(meInstance, SynchronizeTimeResponseType, meframe.TransactionID(tid),
+		meframe.Result(result), meframe.SuccessResult(successResult), meframe.FrameFormat(messageSet))
+	assert.NotNil(t, frame)
+	assert.NotZero(t, len(frame))
+	assert.Nil(t, omciErr)
+
+	///////////////////////////////////////////////////////////////////
+	// Now decode and compare
+	packet := gopacket.NewPacket(frame, LayerTypeOMCI, gopacket.NoCopy)
+	assert.NotNil(t, packet)
+
+	omciLayer := packet.Layer(LayerTypeOMCI)
+	assert.NotNil(t, omciLayer)
+
+	omciObj, omciOk := omciLayer.(*OMCI)
+	assert.NotNil(t, omciObj)
+	assert.True(t, omciOk)
+	assert.Equal(t, tid, omciObj.TransactionID)
+	assert.Equal(t, SynchronizeTimeResponseType, omciObj.MessageType)
+	assert.Equal(t, messageSet, omciObj.DeviceIdentifier)
+
+	msgLayer := packet.Layer(LayerTypeSynchronizeTimeResponse)
+	assert.NotNil(t, msgLayer)
+
+	msgObj, msgOk := msgLayer.(*SynchronizeTimeResponse)
+	assert.NotNil(t, msgObj)
+	assert.True(t, msgOk)
+
+	assert.Equal(t, meInstance.GetClassID(), msgObj.EntityClass)
+	assert.Equal(t, meInstance.GetEntityID(), msgObj.EntityInstance)
+	assert.Equal(t, result, msgObj.Result)
+	if result == me.Success {
+		assert.Equal(t, successResult, msgObj.SuccessResults)
+	} else {
+		assert.Zero(t, msgObj.SuccessResults)
+	}
+}
diff --git a/meframe/me_test.go b/meframe/me_test.go
new file mode 100644
index 0000000..45ddd15
--- /dev/null
+++ b/meframe/me_test.go
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2018 - present.  Boling Consulting Solutions (bcsw.net)
+ * Copyright 2020-present Open Networking Foundation
+
+ * 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.
+ */
+
+package meframe
+
+//func TestRequestFrame(m *me.ManagedEntity, opt options) (gopacket.SerializableLayer, error) {
+//	if opt.frameFormat == ExtendedIdent {
+//		return nil, errors.New("Extended message set for this message type is not supported")
+//	}
+//	mask, err := checkAttributeMask(m, opt.attributeMask)
+//	if err != nil {
+//		return nil, err
+//	}
+//	// Common for all MEs
+//	meLayer := &TestRequest{
+//		MeBasePacket: MeBasePacket{
+//			EntityClass:    m.GetClassID(),
+//			EntityInstance: m.GetEntityID(),
+//			Extended:       opt.frameFormat == ExtendedIdent,
+//		},
+//	}
+//	// Get payload space available
+//	maxPayload := maxPacketAvailable(m, opt)
+//
+//	// TODO: Lots of work to do
+//
+//	fmt.Println(mask, maxPayload)
+//	return meLayer, errors.New("todo: Not implemented")
+//}
+
+//func TestResponseFrame(m *me.ManagedEntity, opt options) (gopacket.SerializableLayer, error) {
+//	if opt.frameFormat == ExtendedIdent {
+//		return nil, errors.New("Extended message set for this message type is not supported")
+//	}
+//	mask, err := checkAttributeMask(m, opt.attributeMask)
+//	if err != nil {
+//		return nil, err
+//	}
+//	// Common for all MEs
+//	meLayer := &TestResponse{
+//		MeBasePacket: MeBasePacket{
+//			EntityClass:    m.GetClassID(),
+//			EntityInstance: m.GetEntityID(),
+//			Extended:       opt.frameFormat == ExtendedIdent,
+//		},
+//	}
+//	// Get payload space available
+//	maxPayload := maxPacketAvailable(m, opt)
+//
+//	// TODO: Lots of work to do
+//
+//	fmt.Println(mask, maxPayload)
+//	return meLayer, errors.New("todo: Not implemented")
+//}
+
+//func TestResultFrame(m *me.ManagedEntity, opt options) (gopacket.SerializableLayer, error) {
+//	if opt.frameFormat == ExtendedIdent {
+//		return nil, errors.New("Extended message set for this message type is not supported")
+//	}
+//	mask, err := checkAttributeMask(m, opt.attributeMask)
+//	if err != nil {
+//		return nil, err
+//	}
+//	// Common for all MEs
+//	meLayer := &TestResultNotification{
+//		MeBasePacket: MeBasePacket{
+//			EntityClass:    m.GetClassID(),
+//			EntityInstance: m.GetEntityID(),
+//			Extended:       opt.frameFormat == ExtendedIdent,
+//		},
+//	}
+//	// Get payload space available
+//	maxPayload := maxPacketAvailable(m, opt)
+//
+//	// TODO: Lots of work to do
+//
+//	fmt.Println(mask, maxPayload)
+//	return meLayer, errors.New("todo: Not implemented")
+//}
diff --git a/meframe/me_test_test.go b/meframe/me_test_test.go
new file mode 100644
index 0000000..a68c7f3
--- /dev/null
+++ b/meframe/me_test_test.go
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2018 - present.  Boling Consulting Solutions (bcsw.net)
+ * Copyright 2020-present Open Networking Foundation
+
+ * 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.
+ */
+package meframe_test
+
+import (
+	. "github.com/opencord/omci-lib-go"
+	me "github.com/opencord/omci-lib-go/generated"
+	"testing"
+)
+
+func testTestRequestTypeMeFrame(t *testing.T, managedEntity *me.ManagedEntity, messageSet DeviceIdent) {
+	// TODO: Implement
+}
+
+func testTestResponseTypeMeFrame(t *testing.T, managedEntity *me.ManagedEntity, messageSet DeviceIdent) {
+	// TODO: Implement
+}
+
+func testTestResultTypeMeFrame(t *testing.T, managedEntity *me.ManagedEntity, messageSet DeviceIdent) {
+	// TODO: Implement
+}
diff --git a/meframe/meframe.go b/meframe/meframe.go
new file mode 100644
index 0000000..a6b384b
--- /dev/null
+++ b/meframe/meframe.go
@@ -0,0 +1,415 @@
+/*
+ * Copyright (c) 2018 - present.  Boling Consulting Solutions (bcsw.net)
+ * Copyright 2020-present Open Networking Foundation
+
+ * 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.
+ */
+
+package meframe
+
+import (
+	"errors"
+	"fmt"
+	"github.com/deckarep/golang-set"
+	"github.com/google/gopacket"
+	. "github.com/opencord/omci-lib-go"
+	me "github.com/opencord/omci-lib-go/generated"
+)
+
+var encoderMap map[MessageType]func(*me.ManagedEntity, options) (gopacket.SerializableLayer, error)
+
+func init() {
+	encoderMap = make(map[MessageType]func(*me.ManagedEntity, options) (gopacket.SerializableLayer, error))
+
+	encoderMap[CreateRequestType] = CreateRequestFrame
+	encoderMap[DeleteRequestType] = DeleteRequestFrame
+	encoderMap[SetRequestType] = SetRequestFrame
+	encoderMap[GetRequestType] = GetRequestFrame
+	encoderMap[GetAllAlarmsRequestType] = GetAllAlarmsRequestFrame
+	encoderMap[GetAllAlarmsNextRequestType] = GetAllAlarmsNextRequestFrame
+	encoderMap[MibUploadRequestType] = MibUploadRequestFrame
+	encoderMap[MibUploadNextRequestType] = MibUploadNextRequestFrame
+	encoderMap[MibResetRequestType] = MibResetRequestFrame
+	//encoderMap[TestRequestType] = TestRequestFrame
+	encoderMap[StartSoftwareDownloadRequestType] = StartSoftwareDownloadRequestFrame
+	encoderMap[DownloadSectionRequestType] = DownloadSectionRequestFrame
+	encoderMap[EndSoftwareDownloadRequestType] = EndSoftwareDownloadRequestFrame
+	encoderMap[ActivateSoftwareRequestType] = ActivateSoftwareRequestFrame
+	encoderMap[CommitSoftwareRequestType] = CommitSoftwareRequestFrame
+	encoderMap[SynchronizeTimeRequestType] = SynchronizeTimeRequestFrame
+	encoderMap[RebootRequestType] = RebootRequestFrame
+	encoderMap[GetNextRequestType] = GetNextRequestFrame
+	encoderMap[GetCurrentDataRequestType] = GetCurrentDataRequestFrame
+	encoderMap[SetTableRequestType] = SetTableRequestFrame
+	encoderMap[CreateResponseType] = CreateResponseFrame
+	encoderMap[DeleteResponseType] = DeleteResponseFrame
+	encoderMap[SetResponseType] = SetResponseFrame
+	encoderMap[GetResponseType] = GetResponseFrame
+	encoderMap[GetAllAlarmsResponseType] = GetAllAlarmsResponseFrame
+	encoderMap[GetAllAlarmsNextResponseType] = GetAllAlarmsNextResponseFrame
+	encoderMap[MibUploadResponseType] = MibUploadResponseFrame
+	encoderMap[MibUploadNextResponseType] = MibUploadNextResponseFrame
+	encoderMap[MibResetResponseType] = MibResetResponseFrame
+	//encoderMap[TestResponseType] = TestResponseFrame
+	encoderMap[StartSoftwareDownloadResponseType] = StartSoftwareDownloadResponseFrame
+	encoderMap[DownloadSectionResponseType] = DownloadSectionResponseFrame
+	encoderMap[EndSoftwareDownloadResponseType] = EndSoftwareDownloadResponseFrame
+	encoderMap[ActivateSoftwareResponseType] = ActivateSoftwareResponseFrame
+	encoderMap[CommitSoftwareResponseType] = CommitSoftwareResponseFrame
+	encoderMap[SynchronizeTimeResponseType] = SynchronizeTimeResponseFrame
+	encoderMap[RebootResponseType] = RebootResponseFrame
+	encoderMap[GetNextResponseType] = GetNextResponseFrame
+	encoderMap[GetCurrentDataResponseType] = GetCurrentDataResponseFrame
+	encoderMap[SetTableResponseType] = SetTableResponseFrame
+	encoderMap[AlarmNotificationType] = AlarmNotificationFrame
+	encoderMap[AttributeValueChangeType] = AttributeValueChangeFrame
+	//encoderMap[TestResultType] = TestResultFrame
+}
+
+type options struct {
+	frameFormat               DeviceIdent
+	failIfTruncated           bool
+	attributeMask             uint16
+	result                    me.Results      // Common for many responses
+	attrExecutionMask         uint16          // Create Response Only if results == 3 or Set Response only if results == 0
+	unsupportedMask           uint16          // Set Response only if results == 9
+	sequenceNumberCountOrSize uint16          // For get-next request frames and for frames that return number of commands or length
+	transactionID             uint16          // OMCI TID
+	mode                      uint8           // Get All Alarms retrieval mode
+	alarm                     AlarmOptions    // Alarm related frames
+	software                  SoftwareOptions // Software image related frames
+	payload                   interface{}     // ME or list of MEs, alarm bitmap, timestamp, ...
+	addDefaults               bool            // Add missing SetByCreate attributes for Create Requests
+}
+
+var defaultFrameOptions = options{
+	frameFormat:               BaselineIdent,
+	failIfTruncated:           false,
+	attributeMask:             0xFFFF,
+	result:                    me.Success,
+	attrExecutionMask:         0,
+	unsupportedMask:           0,
+	sequenceNumberCountOrSize: 0,
+	transactionID:             0,
+	mode:                      0,
+	software:                  defaultSoftwareOptions,
+	alarm:                     defaultAlarmOptions,
+	payload:                   nil,
+	addDefaults:               false,
+}
+
+// FrameOption sets options such as frame format, etc.
+type FrameOption func(*options)
+
+// FrameFormat determines determines the OMCI message format used on the fiber.
+// The default value is BaselineIdent
+func FrameFormat(ff DeviceIdent) FrameOption {
+	return func(o *options) {
+		o.frameFormat = ff
+	}
+}
+
+// FailIfTruncated determines whether a request to encode a frame that does
+// not have enough room for all requested options should fail and return an
+// error.
+//
+// If set to 'false', the behaviour depends on the message type/operation
+// requested. The table below provides more information:
+//
+//   Request Type	Behavour
+//	 ------------------------------------------------------------------------
+//	 CreateRequest  A single CreateRequest struct is always returned as the
+//                  CreateRequest message does not have an attributes Mask
+//                  field and a Baseline OMCI message is large enough to
+//                  support all Set-By-Create attributes.
+//
+//   GetResponse	If multiple OMCI response frames are needed to return
+//					all requested attributes, only the attributes that can
+//					fit will be returned and the FailedAttributeMask field
+//					set to the attributes that could not be returned
+//
+//					If this is an ME with an attribute that is a table, the
+//					first GetResponse struct will return the size of the
+//					attribute and the following GetNextResponse structs will
+//					contain the attribute data. The ONU application is
+//					responsible for stashing these extra struct(s) away in
+//					anticipation of possible GetNext Requests occurring for
+//					the attribute.  See the discussion on Table attributes
+//					in the GetResponse section of ITU G.988 for more
+//					information.
+//
+// If set to 'true', no struct(s) are returned and an error is provided.
+//
+// The default value is 'false'
+func FailIfTruncated(f bool) FrameOption {
+	return func(o *options) {
+		o.failIfTruncated = f
+	}
+}
+
+// attributeMask determines the attributes to encode into the frame.
+// The default value is 0xFFFF which specifies all available attributes
+// in the frame
+func AttributeMask(m uint16) FrameOption {
+	return func(o *options) {
+		o.attributeMask = m
+	}
+}
+
+// AttributeExecutionMask is used by the Create and Set Response frames to indicate
+// attributes that failed to be created/set.
+func AttributeExecutionMask(m uint16) FrameOption {
+	return func(o *options) {
+		o.attrExecutionMask = m
+	}
+}
+
+// UnsupportedAttributeMask is used by the Set Response frames to indicate
+// attributes are not supported on this ONU
+func UnsupportedAttributeMask(m uint16) FrameOption {
+	return func(o *options) {
+		o.unsupportedMask = m
+	}
+}
+
+// Result is used to set returned results in responses
+// that have that field
+func Result(r me.Results) FrameOption {
+	return func(o *options) {
+		o.result = r
+	}
+}
+
+// SequenceNumberCountOrSize is used by the GetNext and MibUploadGetNext request frames and for
+// frames that return number of commands or length such as Get (table attribute) or
+// MibUpload/GetAllAlarms/...
+func SequenceNumberCountOrSize(m uint16) FrameOption {
+	return func(o *options) {
+		o.sequenceNumberCountOrSize = m
+	}
+}
+
+// TransactionID is to specify the TID in the OMCI header. The default is
+// zero which requires the caller to set it to the appropriate value if this
+// is not an autonomous ONU notification frame
+func TransactionID(tid uint16) FrameOption {
+	return func(o *options) {
+		o.transactionID = tid
+	}
+}
+
+// RetrievalMode is to specify the the Alarm Retrieval Mode in a GetAllAlarms Request
+func RetrievalMode(m uint8) FrameOption {
+	return func(o *options) {
+		o.mode = m
+	}
+}
+
+// SuccessResult is to specify the the SuccessResult for a SynchronizeTime Response
+func SuccessResult(m uint8) FrameOption {
+	return func(o *options) {
+		o.mode = m
+	}
+}
+
+// RebootCondition is to specify the the Reboot Condition for a ONU Reboot request
+func RebootCondition(m uint8) FrameOption {
+	return func(o *options) {
+		o.mode = m
+	}
+}
+
+// Alarm is used to specify a collection of options related to Alarm notifications
+func Alarm(ao AlarmOptions) FrameOption {
+	return func(o *options) {
+		o.alarm = ao
+	}
+}
+
+// Software is used to specify a collection of options related to Software image
+// manipulation
+func Software(so SoftwareOptions) FrameOption {
+	return func(o *options) {
+		o.software = so
+	}
+}
+
+// Payload is used to specify ME payload options that are not simple types. This
+// include the ME (list of MEs) to encode into a GetNextMibUpload response, the
+// alarm bitmap for alarm relates responses/notifications, alarm bitmaps, and
+// for specifying the download section data when performing Software Download.
+func Payload(p interface{}) FrameOption {
+	return func(o *options) {
+		o.payload = p
+	}
+}
+
+// AddDefaults is used to specify that if a SetByCreate attribute is not
+// specified in the list of attributes for a Create Request, use the attribute
+// defined default
+func AddDefaults(add bool) FrameOption {
+	return func(o *options) {
+		o.addDefaults = add
+	}
+}
+
+// Alarm related frames have a wide variety of settable values. Placing them
+// in a separate struct is mainly to keep the base options simple
+type AlarmOptions struct {
+	AlarmClassID  me.ClassID
+	AlarmInstance uint16
+	AlarmBitmap   []byte // Should be up to 58 octets
+}
+
+var defaultAlarmOptions = AlarmOptions{
+	AlarmClassID:  0,
+	AlarmInstance: 0,
+	AlarmBitmap:   nil,
+}
+
+// Software related frames have a wide variety of settable values. Placing them
+// in a separate struct is mainly to keep the base options simple
+type SoftwareOptions struct {
+	WindowSize    uint8 // Window size - 1
+	SectionNumber uint8 // [0..Window size - 1]
+	ImageSize     uint32
+	CircuitPacks  []uint16 // slot (upper 8 bits) and instance (lower 8 bits)
+	Results       []DownloadResults
+	Data          []byte
+}
+
+var defaultSoftwareOptions = SoftwareOptions{
+	WindowSize:    0,
+	SectionNumber: 0,
+	ImageSize:     0,
+	CircuitPacks:  nil,
+	Results:       nil,
+	Data:          nil,
+}
+
+// EncodeFrame will encode the Managed Entity specific protocol struct and an
+// OMCILayer struct. This struct can be provided to the gopacket.SerializeLayers()
+// function to be serialized into a buffer for transmission.
+func EncodeFrame(m *me.ManagedEntity, messageType MessageType, opt ...FrameOption) (*OMCI, gopacket.SerializableLayer, error) {
+	// Check for message type support
+	msgType := me.MsgType(messageType & me.MsgTypeMask)
+	meDefinition := m.GetManagedEntityDefinition()
+
+	if !me.SupportsMsgType(meDefinition, msgType) {
+		msg := fmt.Sprintf("managed entity %v does not support %v Message-Type",
+			meDefinition.GetName(), msgType)
+		return nil, nil, errors.New(msg)
+	}
+	// Decode options
+	opts := defaultFrameOptions
+	for _, o := range opt {
+		o(&opts)
+	}
+	// TODO: If AttributesMask option passed in, check for deprecated options. Allow encoding option
+	//       that will ignore deprecated option.   Add additional in the get and set meframe_test,go
+	//       test functions to test this. Also have it test attribute name(s) to see if the attribute
+	//       is deprecated.  The OMCI-Parser now supports detection of deprecated attributes and
+	//       provides that to the code-generator (and currently available in generated golang code).
+	// Note: Transaction ID should be set before frame serialization
+	omci := &OMCI{
+		TransactionID:    opts.transactionID,
+		MessageType:      messageType,
+		DeviceIdentifier: opts.frameFormat,
+	}
+	var meInfo gopacket.SerializableLayer
+	var err error
+
+	if encoder, ok := encoderMap[messageType]; ok {
+		meInfo, err = encoder(m, opts)
+	} else {
+		err = fmt.Errorf("message-type: %v/%#x is not supported", messageType, messageType)
+	}
+	if err != nil {
+		return nil, nil, err
+	}
+	return omci, meInfo, err
+}
+
+// For most all create methods below, error checking for valid masks, attribute
+// values, and other fields is left to when the frame is actually serialized.
+
+func checkAttributeMask(m *me.ManagedEntity, mask uint16) (uint16, error) {
+	if mask == defaultFrameOptions.attributeMask {
+		// Scale back to just what is allowed
+		return m.GetAllowedAttributeMask(), nil
+	}
+	if mask&m.GetManagedEntityDefinition().GetAllowedAttributeMask() != mask {
+		return 0, errors.New("invalid attribute mask")
+	}
+	return mask & m.GetManagedEntityDefinition().GetAllowedAttributeMask(), nil
+}
+
+// return the maximum space that can be used by attributes
+func maxPacketAvailable(m *me.ManagedEntity, opt options) uint {
+	if opt.frameFormat == BaselineIdent {
+		// OMCI Header          - 4 octets
+		// Class ID/Instance ID - 4 octets
+		// Length field			- 4 octets
+		// MIC                  - 4 octets
+		return MaxBaselineLength - 16
+	}
+	// OMCI Header          - 4 octets
+	// Class ID/Instance ID - 4 octets
+	// Length field			- 2 octets
+	// MIC                  - 4 octets
+	return MaxExtendedLength - 14
+}
+
+func calculateAttributeMask(m *me.ManagedEntity, requestedMask uint16) (uint16, error) {
+	attrDefs := m.GetAttributeDefinitions()
+	var entityIDName string
+	if entry, ok := attrDefs[0]; ok {
+		entityIDName = entry.GetName()
+	} else {
+		panic("unexpected error") // All attribute definition maps have an entity ID
+	}
+	attributeNames := make([]interface{}, 0)
+	for attrName := range m.GetAttributeValueMap() {
+		if attrName == entityIDName {
+			continue // No mask for EntityID
+		}
+		attributeNames = append(attributeNames, attrName)
+	}
+	calculatedMask, err := me.GetAttributesBitmap(attrDefs, mapset.NewSetWith(attributeNames...))
+
+	if err != nil {
+		return 0, err
+	}
+	return calculatedMask & requestedMask, nil
+}
+
+// GenFrame is a helper function to make tests a little easier to read.
+// For a real application, use the .../omci/generated/class.go 'New'
+// functions to create your Managed Entity and then use it to call the
+// EncodeFrame method.
+func GenFrame(meInstance *me.ManagedEntity, messageType MessageType, options ...FrameOption) ([]byte, error) {
+	omciLayer, msgLayer, err := EncodeFrame(meInstance, messageType, options...)
+	if err != nil {
+		return nil, err
+	}
+	// Serialize the frame and send it
+	var serializeOptions gopacket.SerializeOptions
+	serializeOptions.FixLengths = true
+
+	buffer := gopacket.NewSerializeBuffer()
+	err = gopacket.SerializeLayers(buffer, serializeOptions, omciLayer, msgLayer)
+	if err != nil {
+		return nil, err
+	}
+	return buffer.Bytes(), nil
+}
diff --git a/meframe/meframe_test.go b/meframe/meframe_test.go
new file mode 100644
index 0000000..9ebacb1
--- /dev/null
+++ b/meframe/meframe_test.go
@@ -0,0 +1,439 @@
+/*
+ * Copyright (c) 2018 - present.  Boling Consulting Solutions (bcsw.net)
+ * Copyright 2020-present Open Networking Foundation
+
+ * 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.
+ */
+package meframe_test
+
+import (
+	mapset "github.com/deckarep/golang-set"
+	"github.com/google/gopacket"
+	. "github.com/opencord/omci-lib-go"
+	me "github.com/opencord/omci-lib-go/generated"
+	"github.com/opencord/omci-lib-go/meframe"
+	"github.com/stretchr/testify/assert"
+	"math/rand"
+	"testing"
+)
+
+var messageTypeTestFuncs map[MessageType]func(*testing.T, *me.ManagedEntity, DeviceIdent)
+
+var allMessageTypes = [...]MessageType{
+	CreateRequestType,
+	CreateResponseType,
+	DeleteRequestType,
+	DeleteResponseType,
+	SetRequestType,
+	SetResponseType,
+	GetRequestType,
+	GetResponseType,
+	GetAllAlarmsRequestType,
+	GetAllAlarmsResponseType,
+	GetAllAlarmsNextRequestType,
+	GetAllAlarmsNextResponseType,
+	MibUploadRequestType,
+	MibUploadResponseType,
+	MibUploadNextRequestType,
+	MibUploadNextResponseType,
+	MibResetRequestType,
+	MibResetResponseType,
+	TestRequestType,
+	TestResponseType,
+	StartSoftwareDownloadRequestType,
+	StartSoftwareDownloadResponseType,
+	DownloadSectionRequestType,
+	DownloadSectionResponseType,
+	EndSoftwareDownloadRequestType,
+	EndSoftwareDownloadResponseType,
+	ActivateSoftwareRequestType,
+	ActivateSoftwareResponseType,
+	CommitSoftwareRequestType,
+	CommitSoftwareResponseType,
+	SynchronizeTimeRequestType,
+	SynchronizeTimeResponseType,
+	RebootRequestType,
+	RebootResponseType,
+	GetNextRequestType,
+	GetNextResponseType,
+	GetCurrentDataRequestType,
+	GetCurrentDataResponseType,
+	SetTableRequestType,
+	SetTableResponseType,
+	// Autonomous ONU messages
+	AlarmNotificationType,
+	AttributeValueChangeType,
+	TestResultType,
+}
+
+var allExtendedMessageTypes = [...]MessageType{
+	GetRequestType,
+	GetResponseType,
+}
+
+func init() {
+	messageTypeTestFuncs = make(map[MessageType]func(*testing.T, *me.ManagedEntity, DeviceIdent), 0)
+
+	messageTypeTestFuncs[CreateRequestType] = testCreateRequestTypeMeFrame
+	messageTypeTestFuncs[CreateResponseType] = testCreateResponseTypeMeFrame
+	messageTypeTestFuncs[DeleteRequestType] = testDeleteRequestTypeMeFrame
+	messageTypeTestFuncs[DeleteResponseType] = testDeleteResponseTypeMeFrame
+	messageTypeTestFuncs[SetRequestType] = testSetRequestTypeMeFrame
+	messageTypeTestFuncs[SetResponseType] = testSetResponseTypeMeFrame
+	messageTypeTestFuncs[GetRequestType] = testGetRequestTypeMeFrame
+	messageTypeTestFuncs[GetResponseType] = testGetResponseTypeMeFrame
+	messageTypeTestFuncs[GetAllAlarmsRequestType] = testGetAllAlarmsRequestTypeMeFrame
+	messageTypeTestFuncs[GetAllAlarmsResponseType] = testGetAllAlarmsResponseTypeMeFrame
+	messageTypeTestFuncs[GetAllAlarmsNextRequestType] = testGetAllAlarmsNextRequestTypeMeFrame
+	messageTypeTestFuncs[GetAllAlarmsNextResponseType] = testGetAllAlarmsNextResponseTypeMeFrame
+	messageTypeTestFuncs[MibUploadRequestType] = testMibUploadRequestTypeMeFrame
+	messageTypeTestFuncs[MibUploadResponseType] = testMibUploadResponseTypeMeFrame
+	messageTypeTestFuncs[MibUploadNextRequestType] = testMibUploadNextRequestTypeMeFrame
+	messageTypeTestFuncs[MibUploadNextResponseType] = testMibUploadNextResponseTypeMeFrame
+	messageTypeTestFuncs[MibResetRequestType] = testMibResetRequestTypeMeFrame
+	messageTypeTestFuncs[MibResetResponseType] = testMibResetResponseTypeMeFrame
+	messageTypeTestFuncs[TestRequestType] = testTestRequestTypeMeFrame
+	messageTypeTestFuncs[TestResponseType] = testTestResponseTypeMeFrame
+
+	// For Download section, AR=0 if not response expected, AR=1 if response expected (last section of a window)4
+	messageTypeTestFuncs[StartSoftwareDownloadRequestType] = testStartSoftwareDownloadRequestTypeMeFrame
+	messageTypeTestFuncs[StartSoftwareDownloadResponseType] = testStartSoftwareDownloadResponseTypeMeFrame
+	messageTypeTestFuncs[DownloadSectionRequestType] = testDownloadSectionRequestTypeMeFrame
+	messageTypeTestFuncs[DownloadSectionResponseType] = testDownloadSectionResponseTypeMeFrame
+	messageTypeTestFuncs[EndSoftwareDownloadRequestType] = testEndSoftwareDownloadRequestTypeMeFrame
+	messageTypeTestFuncs[EndSoftwareDownloadResponseType] = testEndSoftwareDownloadResponseTypeMeFrame
+	messageTypeTestFuncs[ActivateSoftwareRequestType] = testActivateSoftwareRequestTypeMeFrame
+	messageTypeTestFuncs[ActivateSoftwareResponseType] = testActivateSoftwareResponseTypeMeFrame
+	messageTypeTestFuncs[CommitSoftwareRequestType] = testCommitSoftwareRequestTypeMeFrame
+	messageTypeTestFuncs[CommitSoftwareResponseType] = testCommitSoftwareResponseTypeMeFrame
+	messageTypeTestFuncs[SynchronizeTimeRequestType] = testSynchronizeTimeRequestTypeMeFrame
+	messageTypeTestFuncs[SynchronizeTimeResponseType] = testSynchronizeTimeResponseTypeMeFrame
+	messageTypeTestFuncs[RebootRequestType] = testRebootRequestTypeMeFrame
+	messageTypeTestFuncs[RebootResponseType] = testRebootResponseTypeMeFrame
+	messageTypeTestFuncs[GetNextRequestType] = testGetNextRequestTypeMeFrame
+	messageTypeTestFuncs[GetNextResponseType] = testGetNextResponseTypeMeFrame
+	messageTypeTestFuncs[GetCurrentDataRequestType] = testGetCurrentDataRequestTypeMeFrame
+	messageTypeTestFuncs[GetCurrentDataResponseType] = testGetCurrentDataResponseTypeMeFrame
+	messageTypeTestFuncs[SetTableRequestType] = testSetTableRequestTypeMeFrame
+	messageTypeTestFuncs[SetTableResponseType] = testSetTableResponseTypeMeFrame
+	messageTypeTestFuncs[AlarmNotificationType] = testAlarmNotificationTypeMeFrame
+	messageTypeTestFuncs[AttributeValueChangeType] = testAttributeValueChangeTypeMeFrame
+	messageTypeTestFuncs[TestResultType] = testTestResultTypeMeFrame
+
+	// Supported Extended message set types here
+	messageTypeTestFuncs[GetRequestType+ExtendedTypeDecodeOffset] = testGetRequestTypeMeFrame
+	messageTypeTestFuncs[GetResponseType+ExtendedTypeDecodeOffset] = testGetResponseTypeMeFrame
+
+	// For Download section, AR=0 if not response expected, AR=1 if response expected (last section of a window)
+	messageTypeTestFuncs[DownloadSectionRequestType+ExtendedTypeDecodeOffset] = testDownloadSectionRequestTypeMeFrame
+	// TODO: messageTypeTestFuncs[DownloadSectionRequestWithResponseType+ExtendedTypeDecodeOffset] = testDownloadSectionLastRequestTypeMeFrame
+	messageTypeTestFuncs[DownloadSectionResponseType+ExtendedTypeDecodeOffset] = testDownloadSectionResponseTypeMeFrame
+
+	messageTypeTestFuncs[AlarmNotificationType+ExtendedTypeDecodeOffset] = testAlarmNotificationTypeMeFrame
+	messageTypeTestFuncs[AttributeValueChangeType+ExtendedTypeDecodeOffset] = testAttributeValueChangeTypeMeFrame
+	messageTypeTestFuncs[TestResultType+ExtendedTypeDecodeOffset] = testTestResultTypeMeFrame
+}
+
+func getMEsThatSupportAMessageType(messageType MessageType) []*me.ManagedEntity {
+	msgType := me.MsgType(byte(messageType) & me.MsgTypeMask)
+
+	entities := make([]*me.ManagedEntity, 0)
+	for _, classID := range me.GetSupportedClassIDs() {
+		if managedEntity, err := me.LoadManagedEntityDefinition(classID); err.StatusCode() == me.Success {
+			supportedTypes := managedEntity.GetManagedEntityDefinition().GetMessageTypes()
+			if supportedTypes.Contains(msgType) {
+				entities = append(entities, managedEntity)
+			}
+		}
+	}
+	return entities
+}
+
+func TestFrameFormatNotYetSupported(t *testing.T) {
+	// We do not yet support a few message types for the extended frame formats.
+	// As we do, add appropriate tests and change this to one that is not supported
+	// Until all are supported
+
+	params := me.ParamData{
+		Attributes: me.AttributeValueMap{"MibDataSync": 0},
+	}
+	managedEntity, omciErr := me.NewOnuData(params)
+	assert.NotNil(t, omciErr)
+	assert.Equal(t, omciErr.StatusCode(), me.Success)
+
+	buffer, err := meframe.GenFrame(managedEntity, SetRequestType, meframe.FrameFormat(ExtendedIdent), meframe.TransactionID(1))
+	assert.Nil(t, buffer)
+	assert.NotNil(t, err)
+}
+
+// TODO: Add more specific get next response tests as we have had issues
+
+func TestGetNextResponseOneFrameOnly(t *testing.T) {
+	// OMCI ME GetRequest for MsgTypes often needs only a single frame and
+	// it is a table of one octet values.  Make sure we decode it correctly
+
+	response1 := []uint8{
+		0, 250, 58, 10, 1, 31, 0, 0, 0, 64, 0,
+		4, 6, 8, 9, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 40,
+	}
+	// getNextSize is the size returned by the original Get request. Normally you would
+	// do many OMCI requests and append all the results (while decreasing size), but
+	// this is all in on packet.
+	//
+	// Do the buffer loop anyway
+	getNextSize := 23
+	remaining := getNextSize
+
+	dataBuffer := make([]byte, 0)
+	packets := []gopacket.Packet{
+		gopacket.NewPacket(response1, LayerTypeOMCI, gopacket.NoCopy),
+	}
+	for _, packet := range packets {
+		omciLayer := packet.Layer(LayerTypeOMCI)
+		assert.NotNil(t, omciLayer)
+
+		omciObj, omciOk := omciLayer.(*OMCI)
+		assert.True(t, omciOk)
+		assert.NotNil(t, omciObj)
+		assert.Equal(t, uint16(250), omciObj.TransactionID)
+		assert.Equal(t, GetNextResponseType, omciObj.MessageType)
+		assert.Equal(t, BaselineIdent, omciObj.DeviceIdentifier)
+		assert.Equal(t, uint32(0), omciObj.MIC)
+		assert.Equal(t, uint16(40), omciObj.Length)
+
+		msgLayer := packet.Layer(LayerTypeGetNextResponse)
+		msgObj, msgOk := msgLayer.(*GetNextResponse)
+		assert.True(t, msgOk)
+		assert.NotNil(t, msgObj)
+		assert.Equal(t, me.Success, msgObj.Result)
+		assert.Equal(t, uint16(0x4000), msgObj.AttributeMask)
+		assert.Equal(t, 2, len(msgObj.Attributes))
+
+		for attrName, value := range msgObj.Attributes {
+			// Skip Entity ID attribute always stored in attribute list
+			if attrName == "ManagedEntityId" {
+				assert.Equal(t, uint16(0), value.(uint16))
+				continue
+			}
+			assert.Equal(t, "MessageTypeTable", attrName)
+			tmpBuffer, ok := value.([]byte)
+			assert.True(t, ok)
+
+			validOctets := len(tmpBuffer)
+			assert.NotZero(t, validOctets)
+			if validOctets > remaining {
+				validOctets = remaining
+			}
+			remaining -= validOctets
+			dataBuffer = append(dataBuffer, tmpBuffer[:validOctets]...)
+
+			assert.True(t, remaining >= 0)
+			if remaining == 0 {
+				break
+			}
+		}
+	}
+	bufSize := len(dataBuffer)
+	assert.Equal(t, getNextSize, bufSize)
+}
+
+func aTestFailingGetNextResponseTypeMeFrame(t *testing.T) {
+	//params := me.ParamData{
+	//	EntityID:   0,
+	//	Attributes: me.AttributeValueMap{
+	//		"Rmep5DatabaseTable": []uint8{
+	//			0,1,2,3,4,5,6,7,8,9,
+	//			10,11,12,13,14,15,16,17,18,19,
+	//			20,21,22,23,24,25,26,27,28,29,
+	//			30,
+	//		},
+	//	},
+	//}
+	//meInstance, err := me.NewDot1AgMepCcmDatabase(params)
+	//bitmask := uint16(2048)
+	//assert.NotNil(t, meInstance)
+	//assert.Nil(t, err)
+	//
+	//tid := uint16(rand.Int31n(0xFFFE) + 1) // [1, 0xFFFF]
+	//
+	//frame, omciErr := meframe.GenFrame(meInstance, GetNextResponseType, meframe.TransactionID(tid), meframe.Result(me.Success),
+	//	AttributeMask(bitmask))
+	//assert.NotNil(t, frame)
+	//assert.NotZero(t, len(frame))
+	//assert.Nil(t, omciErr)
+	//
+	/////////////////////////////////////////////////////////////////////
+	//// Now decode and compare
+	//cid := meInstance.GetClassID()
+	//assert.NotEqual(t, cid, 0)
+	//packet := gopacket.NewPacket(frame,  LayerTypeOMCI, gopacket.NoCopy)
+	//assert.NotNil(t, packet)
+	//
+	//omciLayer := packet.Layer( LayerTypeOMCI)
+	//assert.NotNil(t, omciLayer)
+	//
+	//omciObj, omciOk := omciLayer.(* OMCI)
+	//assert.NotNil(t, omciObj)
+	//assert.True(t, omciOk)
+	//assert.Equal(t, tid, omciObj.TransactionID)
+	//assert.Equal(t, GetNextResponseType, omciObj.MessageType)
+	//assert.Equal(t, BaselineIdent, omciObj.DeviceIdentifier)
+	//
+	//msgLayer := packet.Layer(LayerTypeGetNextResponse)
+	//assert.NotNil(t, msgLayer)
+	//
+	//msgObj, msgOk := msgLayer.(*GetNextResponse)
+	//assert.NotNil(t, msgObj)
+	//assert.True(t, msgOk)
+	//
+	//assert.Equal(t, meInstance.GetClassID(), msgObj.EntityClass)
+	//assert.Equal(t, meInstance.GetEntityID(), msgObj.EntityInstance)
+	//assert.Equal(t, meInstance.GetAttributeMask(), msgObj.AttributeMask)
+
+}
+
+func TestAllMessageTypes(t *testing.T) {
+	// Loop over all message types
+	for _, messageType := range allMessageTypes {
+		//typeTested := false
+		if testRoutine, ok := messageTypeTestFuncs[messageType]; ok {
+			// Loop over all Managed Entities that support that type
+			for _, managedEntity := range getMEsThatSupportAMessageType(messageType) {
+				// Call the test routine
+				testRoutine(t, managedEntity, BaselineIdent)
+				//typeTested = true
+			}
+		}
+		// Verify at least one test ran for this message type
+		// TODO: Enable once all tests are working -> assert.True(t, typeTested)
+	}
+	// Now for the extended message set message types we support
+	for _, messageType := range allExtendedMessageTypes {
+		trueMessageType := messageType - ExtendedTypeDecodeOffset
+
+		if testRoutine, ok := messageTypeTestFuncs[messageType]; ok {
+			// Loop over all Managed Entities that support that type
+			for _, managedEntity := range getMEsThatSupportAMessageType(trueMessageType) {
+				// Call the test routine
+				testRoutine(t, managedEntity, ExtendedIdent)
+				//typeTested = true
+			}
+		}
+		// Verify at least one test ran for this message type
+		// TODO: Enable once all tests are working -> assert.True(t, typeTested)
+	}
+}
+
+//func TestAllThatSupportAlarms(t *testing.T) {  TODO: Future
+//	// Loop over all Managed Entities and test those with Attributes that support
+//
+//	for _, managedEntity := range getMEsThatSupportAMessageType(messageType) {
+//		// Call the test routine
+//		testRoutine(t, managedEntity)
+//		//typeTested = true
+//	}
+//}
+
+func getAttributeNameSet(attributes me.AttributeValueMap) mapset.Set {
+	// TODO: For Classes with attribute masks that can set/get/... more than just
+	//       a single attribute, test a set/get of just a single attribute to verify
+	//       all encoding/decoding methods are working as expected.
+	names := mapset.NewSet()
+	for name := range attributes {
+		names.Add(name)
+	}
+	return names
+}
+
+func pickAValue(attrDef me.AttributeDefinition) interface{} {
+	constraint := attrDef.Constraint
+	defaultVal := attrDef.DefValue
+	size := attrDef.GetSize()
+	_, isOctetString := defaultVal.([]byte)
+
+	if attrDef.IsTableAttribute() || isOctetString {
+		// Table attributes treated as a string of octets.  If size is zero, it is
+		// most likely an attribute with variable size. Pick a random size that will
+		// fit into a simple frame (1-33 octets)
+		if size == 0 {
+			size = rand.Intn(32) + 1
+		}
+		value := make([]byte, size)
+		for octet := 0; octet < size; octet++ {
+			value[octet] = byte(octet & 0xff)
+		}
+		return value
+	}
+	switch size {
+	case 1:
+		// Try the default + 1 as a value. Since some defaults are zero
+		// and we want example frames without zeros in them.
+		if value, ok := defaultVal.(uint8); ok {
+			if constraint == nil {
+				return value + 1
+			}
+			if err := constraint(value + 1); err == nil {
+				return value + 1
+			}
+		}
+		return defaultVal.(uint8)
+
+	case 2:
+		// Try the default + 1 as a value. Since some defaults are zero
+		// and we want example frames without zeros in them.
+		if value, ok := defaultVal.(uint16); ok {
+			if constraint == nil {
+				return value + 1
+			}
+			if err := constraint(value + 1); err == nil {
+				return value + 1
+			}
+		}
+		return defaultVal.(uint16)
+
+	case 4:
+		// Try the default + 1 as a value. Since some defaults are zero
+		// and we want example frames without zeros in them.
+		if value, ok := defaultVal.(uint32); ok {
+			if constraint == nil {
+				return value + 1
+			}
+			if err := constraint(value + 1); err == nil {
+				return value + 1
+			}
+		}
+		return defaultVal.(uint32)
+
+	case 8:
+		// Try the default + 1 as a value. Since some defaults are zero
+		// and we want example frames without zeros in them.
+		if value, ok := defaultVal.(uint64); ok {
+			if constraint == nil {
+				return value + 1
+			}
+			if err := constraint(value + 1); err == nil {
+				return value + 1
+			}
+		}
+		return defaultVal.(uint64)
+
+	default:
+		size := attrDef.GetSize()
+		value := make([]uint8, size)
+		for index := 0; index < size; index++ {
+			value[index] = uint8(index & 0xFF)
+		}
+		return value
+	}
+}