plmn id handling improved

Change-Id: I20f0d6c347756a1f567c97b084d38240bc3a53bc
Signed-off-by: Juha Hyttinen <juha.hyttinen@nokia.com>
diff --git a/e2ap/pkg/conv/bcd.go b/e2ap/pkg/conv/bcd.go
index bbd1c70..d651ec1 100644
--- a/e2ap/pkg/conv/bcd.go
+++ b/e2ap/pkg/conv/bcd.go
@@ -19,18 +19,18 @@
 
 package conv
 
-type Bcd struct {
-	ConvTbl string
+//
+//
+
+//-----------------------------------------------------------------------------
+//
+//-----------------------------------------------------------------------------
+type bcdbase struct {
+	convtbl string
 }
 
-func NewBcd(convTbl string) *Bcd {
-	b := &Bcd{}
-	b.ConvTbl = convTbl
-	return b
-}
-
-func (bcd *Bcd) index(c byte) int {
-	for cpos, cchar := range bcd.ConvTbl {
+func (bcd *bcdbase) index(c byte) int {
+	for cpos, cchar := range bcd.convtbl {
 		if cchar == rune(c) {
 			return cpos
 		}
@@ -38,11 +38,28 @@
 	return -1
 }
 
-func (bcd *Bcd) byte(i int) byte {
+func (bcd *bcdbase) byte(i int) byte {
 	if i < 0 && i > 15 {
 		return '?'
 	}
-	return bcd.ConvTbl[i]
+	return bcd.convtbl[i]
+}
+
+//-----------------------------------------------------------------------------
+//
+// 5 digit example
+// String format   : D1D2D3D4D5
+// BCD Coded format: 0xD1D2 0xD3D4 0xD50f
+// String format   : D1D2D3D4D5F
+//
+// 6 digit example
+// String format   : D1D2D3D4D5D6
+// BCD Coded format: 0xD1D2 0xD3D4 0xD5D6
+// String format   : D1D2D3D4D5D6
+//
+//-----------------------------------------------------------------------------
+type Bcd struct {
+	bcdbase
 }
 
 func (bcd *Bcd) Encode(str string) []byte {
@@ -53,6 +70,61 @@
 			return nil
 		}
 		if i%2 > 0 {
+			buf[i/2] &= 0xf0
+			buf[i/2] |= ((uint8)(schar) & 0x0f)
+		} else {
+			buf[i/2] = 0x0f | (uint8)(schar)<<4
+		}
+
+	}
+	return buf
+}
+
+func (bcd *Bcd) Decode(buf []byte) string {
+	var strbytes []byte
+	for i := 0; i < len(buf); i++ {
+		var b byte
+
+		b = bcd.byte(int(buf[i] >> 4))
+		//if b == '?' {
+		//	return ""
+		//}
+		strbytes = append(strbytes, b)
+
+		b = bcd.byte(int(buf[i] & 0x0f))
+		//if b == '?' {
+		//	return ""
+		//}
+		strbytes = append(strbytes, b)
+	}
+	return string(strbytes)
+}
+
+//-----------------------------------------------------------------------------
+//
+// 5 digit example
+// String format   : D1D2D3D4D5
+// TBCD Coded format: 0xD2D1 0xD4D3 0x0fD5
+// String format   : D1D2D3D4D5F
+//
+// 6 digit example
+// String format   : D1D2D3D4D5
+// TBCD Coded format: 0xD2D1 0xD4D3 0xD6D5
+// String format   : D1D2D3D4D5D6
+//
+//-----------------------------------------------------------------------------
+type Tbcd struct {
+	bcdbase
+}
+
+func (bcd *Tbcd) Encode(str string) []byte {
+	buf := make([]byte, len(str)/2+len(str)%2)
+	for i := 0; i < len(str); i++ {
+		var schar int = bcd.index(str[i])
+		if schar < 0 {
+			return nil
+		}
+		if i%2 > 0 {
 			buf[i/2] &= 0x0f
 			buf[i/2] |= (uint8)(schar) << 4
 		} else {
@@ -62,7 +134,7 @@
 	return buf
 }
 
-func (bcd *Bcd) Decode(buf []byte) string {
+func (bcd *Tbcd) Decode(buf []byte) string {
 	var strbytes []byte
 	for i := 0; i < len(buf); i++ {
 		var b byte
@@ -80,3 +152,43 @@
 	}
 	return string(strbytes)
 }
+
+//-----------------------------------------------------------------------------
+//
+//-----------------------------------------------------------------------------
+
+func NewBcd(convTbl string) *Bcd {
+	b := &Bcd{}
+	if len(convTbl) == 16 {
+		b.convtbl = convTbl
+	} else {
+		b.convtbl = "0123456789?????f"
+	}
+	return b
+}
+
+func NewTbcd(convTbl string) *Tbcd {
+	b := &Tbcd{}
+	if len(convTbl) == 16 {
+		b.convtbl = convTbl
+	} else {
+		b.convtbl = "0123456789*#abcf"
+	}
+	return b
+}
+
+//-----------------------------------------------------------------------------
+//
+//-----------------------------------------------------------------------------
+
+var BCD *Bcd
+var TBCD *Tbcd
+
+//-----------------------------------------------------------------------------
+//
+//-----------------------------------------------------------------------------
+
+func init() {
+	BCD = NewBcd("")
+	TBCD = NewTbcd("")
+}
diff --git a/e2ap/pkg/conv/bcd_test.go b/e2ap/pkg/conv/bcd_test.go
index 4560dc7..fa2c61b 100644
--- a/e2ap/pkg/conv/bcd_test.go
+++ b/e2ap/pkg/conv/bcd_test.go
@@ -20,16 +20,24 @@
 package conv
 
 import (
+	"encoding/hex"
+	"fmt"
 	"os"
 	"testing"
 )
 
-// Test cases
+//-----------------------------------------------------------------------------
+//
+//-----------------------------------------------------------------------------
 func TestMain(m *testing.M) {
 	code := m.Run()
 	os.Exit(code)
 }
 
+//-----------------------------------------------------------------------------
+//
+//-----------------------------------------------------------------------------
+
 func TestBcdEven(t *testing.T) {
 
 	bcd := NewBcd("0123456789??????")
@@ -38,6 +46,22 @@
 		t.Errorf("TestBcdEven: bcd Encode failed")
 	}
 
+	if bcdbuf[0] != 0x12 {
+		t.Errorf("TestBcdEven: bcdbuf[0] expected 0x12 got 0x%x", bcdbuf[0])
+	}
+
+	if bcdbuf[1] != 0x34 {
+		t.Errorf("TestBcdEven: bcdbuf[1] expected 0x34 got 0x%x", bcdbuf[1])
+	}
+
+	if bcdbuf[2] != 0x56 {
+		t.Errorf("TestBcdEven: bcdbuf[2] expected 0x56 got 0x%x", bcdbuf[2])
+	}
+
+	hexdata := make([]byte, hex.EncodedLen(len(bcdbuf)))
+	hex.Encode(hexdata, bcdbuf)
+	fmt.Printf("TestBcdEven: 123456 encoded data [%s]\n", string(hexdata))
+
 	bcdstr := bcd.Decode(bcdbuf)
 	if bcdstr != string("123456") {
 		t.Errorf("TestBcdEven: bcd Decode failed: got %s expect %s", bcdstr, string("123456"))
@@ -53,6 +77,22 @@
 		t.Errorf("TestBcdUnEven1: bcd Encode failed")
 	}
 
+	if bcdbuf[0] != 0x12 {
+		t.Errorf("TestBcdEven: bcdbuf[0] expected 0x12 got 0x%x", bcdbuf[0])
+	}
+
+	if bcdbuf[1] != 0x34 {
+		t.Errorf("TestBcdEven: bcdbuf[1] expected 0x34 got 0x%x", bcdbuf[1])
+	}
+
+	if bcdbuf[2] != 0x5f {
+		t.Errorf("TestBcdEven: bcdbuf[2] expected 0x5f got 0x%x", bcdbuf[2])
+	}
+
+	hexdata := make([]byte, hex.EncodedLen(len(bcdbuf)))
+	hex.Encode(hexdata, bcdbuf)
+	fmt.Printf("TestBcdUnEven1: 12345 encoded data [%s]\n", string(hexdata))
+
 	bcdstr := bcd.Decode(bcdbuf)
 	if bcdstr != string("12345?") {
 		t.Errorf("TestBcdUnEven1: bcd Decode failed: got %s expect %s", bcdstr, string("12345?"))
@@ -67,8 +107,118 @@
 		t.Errorf("TestBcdUnEven2: bcd Encode failed")
 	}
 
+	if bcdbuf[0] != 0x12 {
+		t.Errorf("TestBcdEven: bcdbuf[0] expected 0x12 got 0x%x", bcdbuf[0])
+	}
+
+	if bcdbuf[1] != 0x34 {
+		t.Errorf("TestBcdEven: bcdbuf[1] expected 0x34 got 0x%x", bcdbuf[1])
+	}
+
+	if bcdbuf[2] != 0x5f {
+		t.Errorf("TestBcdEven: bcdbuf[2] expected 0x5f got 0x%x", bcdbuf[2])
+	}
+
+	hexdata := make([]byte, hex.EncodedLen(len(bcdbuf)))
+	hex.Encode(hexdata, bcdbuf)
+	fmt.Printf("TestBcdUnEven2: 12345f encoded data [%s]\n", string(hexdata))
+
 	bcdstr := bcd.Decode(bcdbuf)
 	if bcdstr != string("12345f") {
 		t.Errorf("TestBcdUnEven2: bcd Decode failed: got %s expect %s", bcdstr, string("12345f"))
 	}
 }
+
+//-----------------------------------------------------------------------------
+//
+//-----------------------------------------------------------------------------
+func TestTbcdEven(t *testing.T) {
+
+	bcd := NewTbcd("0123456789??????")
+	bcdbuf := bcd.Encode("123456")
+	if len(bcdbuf) == 0 {
+		t.Errorf("TestTbcdEven: bcd Encode failed")
+	}
+
+	if bcdbuf[0] != 0x21 {
+		t.Errorf("TestBcdEven: bcdbuf[0] expected 0x21 got 0x%x", bcdbuf[0])
+	}
+
+	if bcdbuf[1] != 0x43 {
+		t.Errorf("TestBcdEven: bcdbuf[1] expected 0x34 got 0x%x", bcdbuf[1])
+	}
+
+	if bcdbuf[2] != 0x65 {
+		t.Errorf("TestBcdEven: bcdbuf[2] expected 0x65 got 0x%x", bcdbuf[2])
+	}
+
+	hexdata := make([]byte, hex.EncodedLen(len(bcdbuf)))
+	hex.Encode(hexdata, bcdbuf)
+	fmt.Printf("TestTbcdEven: 123456 encoded data [%s]\n", string(hexdata))
+
+	bcdstr := bcd.Decode(bcdbuf)
+	if bcdstr != string("123456") {
+		t.Errorf("TestTbcdEven: bcd Decode failed: got %s expect %s", bcdstr, string("123456"))
+	}
+
+}
+
+func TestTbcdUnEven1(t *testing.T) {
+
+	bcd := NewTbcd("0123456789??????")
+	bcdbuf := bcd.Encode("12345")
+	if len(bcdbuf) == 0 {
+		t.Errorf("TestTbcdUnEven1: bcd Encode failed")
+	}
+
+	if bcdbuf[0] != 0x21 {
+		t.Errorf("TestBcdEven: bcdbuf[0] expected 0x21 got 0x%x", bcdbuf[0])
+	}
+
+	if bcdbuf[1] != 0x43 {
+		t.Errorf("TestBcdEven: bcdbuf[1] expected 0x43 got 0x%x", bcdbuf[1])
+	}
+
+	if bcdbuf[2] != 0xf5 {
+		t.Errorf("TestBcdEven: bcdbuf[2] expected 0xf5 got 0x%x", bcdbuf[2])
+	}
+
+	hexdata := make([]byte, hex.EncodedLen(len(bcdbuf)))
+	hex.Encode(hexdata, bcdbuf)
+	fmt.Printf("TestTbcdUnEven1: 12345 encoded data [%s]\n", string(hexdata))
+
+	bcdstr := bcd.Decode(bcdbuf)
+	if bcdstr != string("12345?") {
+		t.Errorf("TestTbcdUnEven1: bcd Decode failed: got %s expect %s", bcdstr, string("12345?"))
+	}
+}
+
+func TestTbcdUnEven2(t *testing.T) {
+
+	bcd := NewTbcd("0123456789?????f")
+	bcdbuf := bcd.Encode("12345f")
+	if len(bcdbuf) == 0 {
+		t.Errorf("TestTbcdUnEven2: bcd Encode failed")
+	}
+
+	if bcdbuf[0] != 0x21 {
+		t.Errorf("TestBcdEven: bcdbuf[0] expected 0x21 got 0x%x", bcdbuf[0])
+	}
+
+	if bcdbuf[1] != 0x43 {
+		t.Errorf("TestBcdEven: bcdbuf[1] expected 0x43 got 0x%x", bcdbuf[1])
+	}
+
+	if bcdbuf[2] != 0xf5 {
+		t.Errorf("TestBcdEven: bcdbuf[2] expected 0xf5 got 0x%x", bcdbuf[2])
+	}
+
+	hexdata := make([]byte, hex.EncodedLen(len(bcdbuf)))
+	hex.Encode(hexdata, bcdbuf)
+	fmt.Printf("TestTbcdUnEven2: 12345f encoded data [%s]\n", string(hexdata))
+
+	bcdstr := bcd.Decode(bcdbuf)
+	if bcdstr != string("12345f") {
+		t.Errorf("TestTbcdUnEven2: bcd Decode failed: got %s expect %s", bcdstr, string("12345f"))
+	}
+}
diff --git a/e2ap/pkg/conv/plmn.go b/e2ap/pkg/conv/plmn.go
index 61f2c3e..2f56de4 100644
--- a/e2ap/pkg/conv/plmn.go
+++ b/e2ap/pkg/conv/plmn.go
@@ -19,77 +19,155 @@
 
 package conv
 
+import (
+	"io"
+)
+
 //-----------------------------------------------------------------------------
 //
-// MCC 3 digits MNC 2 digits
-// BCD Coded format: 0xC2C1 0xfC3 0xN2N1
-// String format   : C1C2C3N1N2
-//
-// MCC 3 digits MNC 3 digits
-// BCD Coded format: 0xC2C1 0xN3C3 0xN2N1
-// String format   : C1C2C3N1N2N3
+//-----------------------------------------------------------------------------
+type PlmnIdentityIf interface {
+	String() string
+	MccString() string
+	MncString() string
+	EncodeTo(writer io.Writer) (int, error)
+	DecodeFrom(reader io.Reader) (int, error)
+}
+
+//-----------------------------------------------------------------------------
 //
 //-----------------------------------------------------------------------------
 
 type PlmnIdentity struct {
-	Val [3]uint8
+	Mcc string
+	Mnc string
 }
 
 func (plmnid *PlmnIdentity) String() string {
-	bcd := NewBcd("0123456789?????f")
-
-	str := bcd.Decode(plmnid.Val[:])
-
-	if str[3] == 'f' {
-		return string(str[0:3]) + string(str[4:])
-	}
-	return string(str[0:3]) + string(str[4:]) + string(str[3])
+	return plmnid.MccString() + plmnid.MncString()
 }
 
 func (plmnid *PlmnIdentity) MccString() string {
-	fullstr := plmnid.String()
-	return string(fullstr[0:3])
+	return plmnid.Mcc
 }
 
 func (plmnid *PlmnIdentity) MncString() string {
-	fullstr := plmnid.String()
-	return string(fullstr[3:])
+	return plmnid.Mnc
 }
 
-func (plmnid *PlmnIdentity) StringPut(str string) bool {
+func (plmnid *PlmnIdentity) Set(str string) {
+	plmnid.Mcc = str[0:3]
+	plmnid.Mnc = str[3:]
+}
+
+//-----------------------------------------------------------------------------
+//
+// MCC 3 digits MNC 2 digits
+// String format      : C1C2C3N1N2
+// Pre encode format  : C1C2C3FN1N2
+// TBCD Coded format  : 0xC2C1 0xfC3 0xN2N1
+// Post decode format : C1C2C3FN1N2
+// String format      : C1C2C3N1N2
+//
+// MCC 3 digits MNC 3 digits
+// String format      : C1C2C3N1N2N3
+// Pre encode format  : C1C2C3N3N1N2
+// TBCD Coded format  : 0xC2C1 0xN3C3 0xN2N1
+// Post decode format : C1C2C3N3N1N2
+// String format      : C1C2C3N1N2N3
+//
+//-----------------------------------------------------------------------------
+
+type PlmnIdentityTbcd struct {
+	PlmnIdentity
+}
+
+func (plmnid *PlmnIdentityTbcd) EncodeTo(writer io.Writer) (int, error) {
 
 	var tmpStr string
 	switch {
-
-	case len(str) == 5:
-		//C1 C2 C3 N1 N2 -->
-		//C2C1 0fC3 N2N1
-		tmpStr = string(str[0:3]) + string("f") + string(str[3:])
-	case len(str) == 6:
-		//C1 C2 C3 N1 N2 N3 -->
-		//C2C1 N3C3 N2N1
-		tmpStr = string(str[0:3]) + string(str[5]) + string(str[3:5])
+	case len(plmnid.Mnc) == 2:
+		tmpStr = plmnid.Mcc + string("f") + plmnid.Mnc
+	case len(plmnid.Mnc) == 3:
+		tmpStr = plmnid.Mcc + string(plmnid.Mnc[2]) + string(plmnid.Mnc[0:2])
 	default:
-		return false
+		return 0, nil
 	}
 
-	bcd := NewBcd("0123456789?????f")
-	buf := bcd.Encode(tmpStr)
-
-	if buf == nil {
-		return false
-	}
-
-	return plmnid.BcdPut(buf)
+	buf := TBCD.Encode(tmpStr)
+	return writer.Write(buf)
 }
 
-func (plmnid *PlmnIdentity) BcdPut(val []uint8) bool {
+func (plmnid *PlmnIdentityTbcd) DecodeFrom(reader io.Reader) (int, error) {
+	tmpBytes := make([]byte, 3)
+	n, err := reader.Read(tmpBytes)
+	if err != nil {
+		return n, err
+	}
+	str := TBCD.Decode(tmpBytes)
 
-	if len(val) != 3 {
-		return false
+	if str[3] == 'f' {
+		plmnid.Mcc = string(str[0:3])
+		plmnid.Mnc = string(str[4:])
+	} else {
+		plmnid.Mcc = string(str[0:3])
+		plmnid.Mnc = string(str[4:]) + string(str[3])
 	}
-	for i := 0; i < 3; i++ {
-		plmnid.Val[i] = val[i]
+	return n, nil
+}
+
+//-----------------------------------------------------------------------------
+//
+// MCC 3 digits MNC 2 digits
+// String format      : C1C2C3N1N2
+// Pre encode format  : C1C2C3FN1N2
+// BCD Coded format   : 0xC2C1 0xC3f 0xN1N2
+// Post decode format : C1C2C3FN1N2
+// String format      : C1C2C3N1N2
+//
+// MCC 3 digits MNC 3 digits
+// String format      : C1C2C3N1N2N3
+// Pre encode format  : C1C2C3N1N2N3
+// BCD Coded format   : 0xC2C1 0xC3N1 0xN2N3
+// Post decode format : C1C2C3N1N2N3
+// String format      : C1C2C3N1N2N3
+//
+//-----------------------------------------------------------------------------
+
+type PlmnIdentityBcd struct {
+	PlmnIdentity
+}
+
+func (plmnid *PlmnIdentityBcd) EncodeTo(writer io.Writer) (int, error) {
+
+	var tmpStr string
+	switch {
+	case len(plmnid.Mnc) == 2:
+		tmpStr = plmnid.Mcc + string("f") + plmnid.Mnc
+	case len(plmnid.Mnc) == 3:
+		tmpStr = plmnid.Mcc + plmnid.Mnc
+	default:
+		return 0, nil
 	}
-	return true
+
+	buf := BCD.Encode(tmpStr)
+	return writer.Write(buf)
+}
+
+func (plmnid *PlmnIdentityBcd) DecodeFrom(reader io.Reader) (int, error) {
+	tmpBytes := make([]byte, 3)
+	n, err := reader.Read(tmpBytes)
+	if err != nil {
+		return n, err
+	}
+	str := BCD.Decode(tmpBytes)
+
+	if str[3] == 'f' {
+		plmnid.Mcc = string(str[0:3])
+		plmnid.Mnc = string(str[4:])
+	} else {
+		plmnid.Mcc = string(str[0:3])
+		plmnid.Mnc = string(str[3:])
+	}
+	return n, nil
 }
diff --git a/e2ap/pkg/conv/plmn_test.go b/e2ap/pkg/conv/plmn_test.go
index 20a6617..3740f53 100644
--- a/e2ap/pkg/conv/plmn_test.go
+++ b/e2ap/pkg/conv/plmn_test.go
@@ -20,69 +20,237 @@
 package conv
 
 import (
+	"bytes"
 	"testing"
 )
 
-func TestPlmnId1(t *testing.T) {
-
+//-----------------------------------------------------------------------------
+//
+//-----------------------------------------------------------------------------
+func TestPlmnId(t *testing.T) {
 	var ident PlmnIdentity
-	ident.StringPut("23350")
-
-	if ident.Val[0] != 0x32 {
-		t.Errorf("TestPlmnId1: ident.val[0] expected 0x32 got 0x%x", ident.Val[0])
+	ident.Set("12345")
+	if ident.Mcc != "123" {
+		t.Errorf("TestPlmnId: mcc expect 123 was %s", ident.Mcc)
+	}
+	if ident.Mnc != "45" {
+		t.Errorf("TestPlmnId: mnc expect 45 was %s", ident.Mnc)
 	}
 
-	if ident.Val[1] != 0xf3 {
-		t.Errorf("TestPlmnId1: ident.val[1] expected 0xf3 got 0x%x", ident.Val[1])
+	ident.Set("123456")
+	if ident.Mcc != "123" {
+		t.Errorf("TestPlmnId: mcc expect 123 was %s", ident.Mcc)
+	}
+	if ident.Mnc != "456" {
+		t.Errorf("TestPlmnId: mnc expect 456 was %s", ident.Mnc)
 	}
 
-	if ident.Val[2] != 0x05 {
-		t.Errorf("TestPlmnId1: ident.val[2] expected 0x05 got 0x%x", ident.Val[2])
+}
+
+//-----------------------------------------------------------------------------
+//
+//-----------------------------------------------------------------------------
+func TestPlmnIdBcd1(t *testing.T) {
+
+	var encident PlmnIdentityBcd
+	encident.Mcc = "233"
+	encident.Mnc = "50"
+	encbuf := new(bytes.Buffer)
+	retlen, err := encident.EncodeTo(encbuf)
+
+	if err != nil {
+		t.Errorf("TestPlmnIdBcd1: EncodeTo err %s", err.Error())
+	}
+	if retlen != 3 {
+		t.Errorf("TestPlmnIdBcd1: EncodeTo expected len 3 got %d", retlen)
 	}
 
-	fullstr := ident.String()
-	if fullstr != "23350" {
-		t.Errorf("TestPlmnId2: fullstr expected 23350 got %s", fullstr)
+	encdata := encbuf.Bytes()
+
+	if encdata[0] != 0x23 {
+		t.Errorf("TestPlmnIdBcd1: encident.val[0] expected 0x23 got 0x%x", encdata[0])
 	}
 
-	mccstr := ident.MccString()
-	if mccstr != "233" {
-		t.Errorf("TestPlmnId1: mcc expected 233 got %s", mccstr)
+	if encdata[1] != 0x3f {
+		t.Errorf("TestPlmnIdBcd1: encident.val[1] expected 0x3f got 0x%x", encdata[1])
 	}
-	mncstr := ident.MncString()
-	if mncstr != "50" {
-		t.Errorf("TestPlmnId1: mnc expected 50 got %s", mncstr)
+
+	if encdata[2] != 0x50 {
+		t.Errorf("TestPlmnIdBcd1: encident.val[2] expected 0x50 got 0x%x", encdata[2])
+	}
+
+	var decident PlmnIdentityBcd
+	decbuf := []byte{0x23, 0x3f, 0x50}
+
+	reader := bytes.NewReader(decbuf)
+	retlen, err = decident.DecodeFrom(reader)
+
+	if err != nil {
+		t.Errorf("TestPlmnIdBcd1: DecodeFrom err %s", err.Error())
+	}
+	if retlen != 3 {
+		t.Errorf("TestPlmnIdBcd1: DecodeFrom expected len 3 got %d", retlen)
+	}
+
+	if decident.Mcc != "233" {
+		t.Errorf("TestPlmnIdBcd1: mcc expected 233 got %s", decident.Mcc)
+	}
+	if decident.Mnc != "50" {
+		t.Errorf("TestPlmnIdBcd1: mnc expected 50 got %s", decident.Mnc)
 	}
 }
 
-func TestPlmnId2(t *testing.T) {
+func TestPlmnIdBcd2(t *testing.T) {
 
-	var ident PlmnIdentity
-	ident.StringPut("233550")
+	var encident PlmnIdentityBcd
 
-	if ident.Val[0] != 0x32 {
-		t.Errorf("TestPlmnId1: ident.val[0] expected 0x32 got 0x%x", ident.Val[0])
+	encident.Mcc = "233"
+	encident.Mnc = "550"
+	encbuf := new(bytes.Buffer)
+	retlen, err := encident.EncodeTo(encbuf)
+
+	if err != nil {
+		t.Errorf("TestPlmnIdBcd2: EncodeTo err %s", err.Error())
+	}
+	if retlen != 3 {
+		t.Errorf("TestPlmnIdBcd2: EncodeTo expected len 3 got %d", retlen)
 	}
 
-	if ident.Val[1] != 0x03 {
-		t.Errorf("TestPlmnId1: ident.val[1] expected 0x03 got 0x%x", ident.Val[1])
+	encdata := encbuf.Bytes()
+
+	if encdata[0] != 0x23 {
+		t.Errorf("TestPlmnIdBcd2: encident.val[0] expected 0x23 got 0x%x", encdata[0])
 	}
 
-	if ident.Val[2] != 0x55 {
-		t.Errorf("TestPlmnId1: ident.val[2] expected 0x55 got 0x%x", ident.Val[2])
+	if encdata[1] != 0x35 {
+		t.Errorf("TestPlmnIdBcd1: encident.val[1] expected 0x35 got 0x%x", encdata[1])
 	}
 
-	fullstr := ident.String()
-	if fullstr != "233550" {
-		t.Errorf("TestPlmnId2: fullstr expected 233550 got %s", fullstr)
+	if encdata[2] != 0x50 {
+		t.Errorf("TestPlmnIdBcd2: encident.val[2] expected 0x50 got 0x%x", encdata[2])
 	}
 
-	mccstr := ident.MccString()
-	if mccstr != "233" {
-		t.Errorf("TestPlmnId2: mcc expected 233 got %s", mccstr)
+	var decident PlmnIdentityBcd
+	decbuf := []byte{0x23, 0x35, 0x50}
+
+	reader := bytes.NewReader(decbuf)
+	retlen, err = decident.DecodeFrom(reader)
+
+	if err != nil {
+		t.Errorf("TestPlmnIdBcd2: DecodeFrom err %s", err.Error())
 	}
-	mncstr := ident.MncString()
-	if mncstr != "550" {
-		t.Errorf("TestPlmnId2: mnc expected 550 got %s", mncstr)
+	if retlen != 3 {
+		t.Errorf("TestPlmnIdBcd2: DecodeFrom expected len 3 got %d", retlen)
+	}
+
+	if decident.Mcc != "233" {
+		t.Errorf("TestPlmnIdBcd2: mcc expected 233 got %s", decident.Mcc)
+	}
+	if decident.Mnc != "550" {
+		t.Errorf("TestPlmnIdBcd2: mnc expected 550 got %s", decident.Mnc)
+	}
+}
+
+//-----------------------------------------------------------------------------
+//
+//-----------------------------------------------------------------------------
+func TestPlmnIdTbcd1(t *testing.T) {
+
+	var encident PlmnIdentityTbcd
+	encident.Mcc = "233"
+	encident.Mnc = "50"
+	encbuf := new(bytes.Buffer)
+	retlen, err := encident.EncodeTo(encbuf)
+
+	if err != nil {
+		t.Errorf("TestPlmnIdTbcd1: EncodeTo err %s", err.Error())
+	}
+	if retlen != 3 {
+		t.Errorf("TestPlmnIdTbcd1: EncodeTo expected len 3 got %d", retlen)
+	}
+
+	encdata := encbuf.Bytes()
+
+	if encdata[0] != 0x32 {
+		t.Errorf("TestPlmnIdTbcd1: encident.val[0] expected 0x32 got 0x%x", encdata[0])
+	}
+
+	if encdata[1] != 0xf3 {
+		t.Errorf("TestPlmnIdTbcd1: encident.val[1] expected 0xf3 got 0x%x", encdata[1])
+	}
+
+	if encdata[2] != 0x05 {
+		t.Errorf("TestPlmnIdTbcd1: encident.val[2] expected 0x05 got 0x%x", encdata[2])
+	}
+
+	var decident PlmnIdentityTbcd
+	decbuf := []byte{0x32, 0xf3, 0x05}
+
+	reader := bytes.NewReader(decbuf)
+	retlen, err = decident.DecodeFrom(reader)
+
+	if err != nil {
+		t.Errorf("TestPlmnIdTbcd1: DecodeFrom err %s", err.Error())
+	}
+	if retlen != 3 {
+		t.Errorf("TestPlmnIdTbcd1: DecodeFrom expected len 3 got %d", retlen)
+	}
+
+	if decident.Mcc != "233" {
+		t.Errorf("TestPlmnIdTbcd1: mcc expected 233 got %s", decident.Mcc)
+	}
+	if decident.Mnc != "50" {
+		t.Errorf("TestPlmnIdTbcd1: mnc expected 50 got %s", decident.Mnc)
+	}
+}
+
+func TestPlmnIdTbcd2(t *testing.T) {
+
+	var encident PlmnIdentityTbcd
+
+	encident.Mcc = "233"
+	encident.Mnc = "550"
+	encbuf := new(bytes.Buffer)
+	retlen, err := encident.EncodeTo(encbuf)
+
+	if err != nil {
+		t.Errorf("TestPlmnIdTbcd2: EncodeTo err %s", err.Error())
+	}
+	if retlen != 3 {
+		t.Errorf("TestPlmnIdTbcd2: EncodeTo expected len 3 got %d", retlen)
+	}
+
+	encdata := encbuf.Bytes()
+
+	if encdata[0] != 0x32 {
+		t.Errorf("TestPlmnIdTbcd2: encident.val[0] expected 0x32 got 0x%x", encdata[0])
+	}
+
+	if encdata[1] != 0x03 {
+		t.Errorf("TestPlmnIdTbcd1: encident.val[1] expected 0x03 got 0x%x", encdata[1])
+	}
+
+	if encdata[2] != 0x55 {
+		t.Errorf("TestPlmnIdTbcd2: encident.val[2] expected 0x55 got 0x%x", encdata[2])
+	}
+
+	var decident PlmnIdentityTbcd
+	decbuf := []byte{0x32, 0x03, 0x55}
+
+	reader := bytes.NewReader(decbuf)
+	retlen, err = decident.DecodeFrom(reader)
+
+	if err != nil {
+		t.Errorf("TestPlmnIdTbcd2: DecodeFrom err %s", err.Error())
+	}
+	if retlen != 3 {
+		t.Errorf("TestPlmnIdTbcd2: DecodeFrom expected len 3 got %d", retlen)
+	}
+
+	if decident.Mcc != "233" {
+		t.Errorf("TestPlmnIdTbcd2: mcc expected 233 got %s", decident.Mcc)
+	}
+	if decident.Mnc != "550" {
+		t.Errorf("TestPlmnIdTbcd2: mnc expected 550 got %s", decident.Mnc)
 	}
 }
diff --git a/e2ap/pkg/e2ap/e2ap_tests/msg_e2ap_subscription.go b/e2ap/pkg/e2ap/e2ap_tests/msg_e2ap_subscription.go
index d865703..50a4eab 100644
--- a/e2ap/pkg/e2ap/e2ap_tests/msg_e2ap_subscription.go
+++ b/e2ap/pkg/e2ap/e2ap_tests/msg_e2ap_subscription.go
@@ -77,28 +77,32 @@
 	}
 
 	areqenc.EventTriggerDefinition.InterfaceId.GlobalEnbId.Present = true
-	areqenc.EventTriggerDefinition.InterfaceId.GlobalEnbId.PlmnIdentity.StringPut("310150")
+	areqenc.EventTriggerDefinition.InterfaceId.GlobalEnbId.PlmnIdentity.Mcc = "310"
+	areqenc.EventTriggerDefinition.InterfaceId.GlobalEnbId.PlmnIdentity.Mnc = "150"
 	areqenc.EventTriggerDefinition.InterfaceId.GlobalEnbId.NodeId.Bits = e2ap.E2AP_ENBIDHomeBits28
 	areqenc.EventTriggerDefinition.InterfaceId.GlobalEnbId.NodeId.Id = 202251
 	testCtxt.SetDesc("SubsReq-28bit")
 	testCtxt.E2ApTestMsgSubscriptionRequestWithData(t, &areqenc)
 
 	//areqenc.EventTriggerDefinition.InterfaceId.GlobalEnbId.Present = true
-	//areqenc.EventTriggerDefinition.InterfaceId.GlobalEnbId.PlmnIdentity.StringPut("310150")
+	//areqenc.EventTriggerDefinition.InterfaceId.GlobalEnbId.PlmnIdentity.Mcc = "310"
+	//areqenc.EventTriggerDefinition.InterfaceId.GlobalEnbId.PlmnIdentity.Mnc = "150"
 	//areqenc.EventTriggerDefinition.InterfaceId.GlobalEnbId.NodeId.Bits = e2ap.E2AP_ENBIDShortMacroits18
 	//areqenc.EventTriggerDefinition.InterfaceId.GlobalEnbId.NodeId.Id = 55
 	//testCtxt.SetDesc("SubsReq-18bit")
 	//testCtxt.E2ApTestMsgSubscriptionRequestWithData(t,&areqenc)
 
 	//areqenc.EventTriggerDefinition.InterfaceId.GlobalEnbId.Present = true
-	//areqenc.EventTriggerDefinition.InterfaceId.GlobalEnbId.PlmnIdentity.StringPut("310150")
+	//areqenc.EventTriggerDefinition.InterfaceId.GlobalEnbId.PlmnIdentity.Mcc = "310"
+	//areqenc.EventTriggerDefinition.InterfaceId.GlobalEnbId.PlmnIdentity.Mnc = "150"
 	//areqenc.EventTriggerDefinition.InterfaceId.GlobalEnbId.NodeId.Bits = e2ap.E2AP_ENBIDMacroPBits20
 	//areqenc.EventTriggerDefinition.InterfaceId.GlobalEnbId.NodeId.Id = 55
 	//testCtxt.SetDesc("SubsReq-20bit")
 	//testCtxt.E2ApTestMsgSubscriptionRequestWithData(t,&areqenc)
 
 	//areqenc.EventTriggerDefinition.InterfaceId.GlobalEnbId.Present = true
-	//areqenc.EventTriggerDefinition.InterfaceId.GlobalEnbId.PlmnIdentity.StringPut("310150")
+	//areqenc.EventTriggerDefinition.InterfaceId.GlobalEnbId.PlmnIdentity.Mcc = "310"
+	//areqenc.EventTriggerDefinition.InterfaceId.GlobalEnbId.PlmnIdentity.Mnc = "150"
 	//areqenc.EventTriggerDefinition.InterfaceId.GlobalEnbId.NodeId.Bits = e2ap.E2AP_ENBIDlongMacroBits21
 	//areqenc.EventTriggerDefinition.InterfaceId.GlobalEnbId.NodeId.Id = 55
 	//testCtxt.SetDesc("SubsReq-21bit")
diff --git a/e2ap/pkg/e2ap/msg_e2ap.go b/e2ap/pkg/e2ap/msg_e2ap.go
index 153f07b..2784a2c 100644
--- a/e2ap/pkg/e2ap/msg_e2ap.go
+++ b/e2ap/pkg/e2ap/msg_e2ap.go
@@ -226,7 +226,7 @@
 //-----------------------------------------------------------------------------
 type GlobalNodeId struct {
 	Present      bool
-	PlmnIdentity conv.PlmnIdentity
+	PlmnIdentity conv.PlmnIdentityTbcd
 	NodeId       NodeId
 }
 
diff --git a/e2ap/pkg/e2ap_wrapper/packer_e2ap.go b/e2ap/pkg/e2ap_wrapper/packer_e2ap.go
index b01baeb..7069f86 100644
--- a/e2ap/pkg/e2ap_wrapper/packer_e2ap.go
+++ b/e2ap/pkg/e2ap_wrapper/packer_e2ap.go
@@ -175,22 +175,26 @@
 	entry *C.PLMNIdentity_t
 }
 
-func (plmnId *e2apEntryPlmnIdentity) set(id *conv.PlmnIdentity) error {
+func (plmnId *e2apEntryPlmnIdentity) set(id conv.PlmnIdentityIf) error {
 
-	plmnId.entry.contentLength = (C.uint8_t)(len(id.Val))
-	for i := 0; i < len(id.Val); i++ {
-		plmnId.entry.pLMNIdentityVal[i] = (C.uint8_t)(id.Val[i])
+	buf := new(bytes.Buffer)
+	id.EncodeTo(buf)
+	data := buf.Bytes()
+	plmnId.entry.contentLength = (C.uint8_t)(len(data))
+	for i := 0; i < len(data); i++ {
+		plmnId.entry.pLMNIdentityVal[i] = (C.uint8_t)(data[i])
 	}
 	return nil
 }
 
-func (plmnId *e2apEntryPlmnIdentity) get(id *conv.PlmnIdentity) error {
+func (plmnId *e2apEntryPlmnIdentity) get(id conv.PlmnIdentityIf) error {
 	conlen := (int)(plmnId.entry.contentLength)
 	bcdBuf := make([]uint8, conlen)
 	for i := 0; i < conlen; i++ {
 		bcdBuf[i] = (uint8)(plmnId.entry.pLMNIdentityVal[i])
 	}
-	id.BcdPut(bcdBuf)
+	reader := bytes.NewReader(bcdBuf)
+	id.DecodeFrom(reader)
 	return nil
 }
 
diff --git a/pkg/control/subscription.go b/pkg/control/subscription.go
index c2b5283..f66a1f1 100644
--- a/pkg/control/subscription.go
+++ b/pkg/control/subscription.go
@@ -121,17 +121,13 @@
 
 	if s.SubReqMsg.EventTriggerDefinition.InterfaceId.GlobalEnbId.Present != subReqMsg.EventTriggerDefinition.InterfaceId.GlobalEnbId.Present ||
 		s.SubReqMsg.EventTriggerDefinition.InterfaceId.GlobalEnbId.NodeId != subReqMsg.EventTriggerDefinition.InterfaceId.GlobalEnbId.NodeId ||
-		s.SubReqMsg.EventTriggerDefinition.InterfaceId.GlobalEnbId.PlmnIdentity.Val[0] != subReqMsg.EventTriggerDefinition.InterfaceId.GlobalEnbId.PlmnIdentity.Val[0] ||
-		s.SubReqMsg.EventTriggerDefinition.InterfaceId.GlobalEnbId.PlmnIdentity.Val[1] != subReqMsg.EventTriggerDefinition.InterfaceId.GlobalEnbId.PlmnIdentity.Val[1] ||
-		s.SubReqMsg.EventTriggerDefinition.InterfaceId.GlobalEnbId.PlmnIdentity.Val[2] != subReqMsg.EventTriggerDefinition.InterfaceId.GlobalEnbId.PlmnIdentity.Val[2] {
+		s.SubReqMsg.EventTriggerDefinition.InterfaceId.GlobalEnbId.PlmnIdentity.String() != subReqMsg.EventTriggerDefinition.InterfaceId.GlobalEnbId.PlmnIdentity.String() {
 		return false
 	}
 
 	if s.SubReqMsg.EventTriggerDefinition.InterfaceId.GlobalGnbId.Present != subReqMsg.EventTriggerDefinition.InterfaceId.GlobalGnbId.Present ||
 		s.SubReqMsg.EventTriggerDefinition.InterfaceId.GlobalGnbId.NodeId != subReqMsg.EventTriggerDefinition.InterfaceId.GlobalGnbId.NodeId ||
-		s.SubReqMsg.EventTriggerDefinition.InterfaceId.GlobalGnbId.PlmnIdentity.Val[0] != subReqMsg.EventTriggerDefinition.InterfaceId.GlobalGnbId.PlmnIdentity.Val[0] ||
-		s.SubReqMsg.EventTriggerDefinition.InterfaceId.GlobalGnbId.PlmnIdentity.Val[1] != subReqMsg.EventTriggerDefinition.InterfaceId.GlobalGnbId.PlmnIdentity.Val[1] ||
-		s.SubReqMsg.EventTriggerDefinition.InterfaceId.GlobalGnbId.PlmnIdentity.Val[2] != subReqMsg.EventTriggerDefinition.InterfaceId.GlobalGnbId.PlmnIdentity.Val[2] {
+		s.SubReqMsg.EventTriggerDefinition.InterfaceId.GlobalGnbId.PlmnIdentity.String() != subReqMsg.EventTriggerDefinition.InterfaceId.GlobalGnbId.PlmnIdentity.String() {
 		return false
 	}
 
diff --git a/pkg/teststube2ap/stubE2.go b/pkg/teststube2ap/stubE2.go
index 9323555..a5dfa54 100644
--- a/pkg/teststube2ap/stubE2.go
+++ b/pkg/teststube2ap/stubE2.go
@@ -104,7 +104,8 @@
 	p.Req.FunctionId = 1
 
 	p.Req.EventTriggerDefinition.InterfaceId.GlobalEnbId.Present = true
-	p.Req.EventTriggerDefinition.InterfaceId.GlobalEnbId.PlmnIdentity.StringPut("310150")
+	p.Req.EventTriggerDefinition.InterfaceId.GlobalEnbId.PlmnIdentity.Mcc = "310"
+	p.Req.EventTriggerDefinition.InterfaceId.GlobalEnbId.PlmnIdentity.Mnc = "150"
 	p.Req.EventTriggerDefinition.InterfaceId.GlobalEnbId.NodeId.Id = 123
 	p.Req.EventTriggerDefinition.InterfaceId.GlobalEnbId.NodeId.Bits = e2ap.E2AP_ENBIDHomeBits28