[VOL-4676]:
Initial Framework for reading SFP capabilities by reading the EEPROM data.
Use the detected SFP data to derive the MAC and PON system mode.
Make the SFP EEPROM read mode configurable per platform through the
DYNAMIC_PON_TRX_SUPPORT '#define' defined in the platform vendor.h file.

Change-Id: I07d7763371d2f804a1e93ca38646b1a30198f8ee
diff --git a/agent/device/asfvolt16/vendor.cc b/agent/device/asfvolt16/vendor.cc
index 86836ff..1c88cb0 100644
--- a/agent/device/asfvolt16/vendor.cc
+++ b/agent/device/asfvolt16/vendor.cc
@@ -19,3 +19,13 @@
 void vendor_init()
 {
 }
+
+// Returns the MAC System Mode based on the set of SFP IDs provided.
+// The derived class will most likely need to override this method to provide a
+// different implementation for that particular OLT platform.
+pair<bcmolt_system_mode, bool> PonTrx::get_mac_system_mode(int olt_mac_id, set<int> sfp_ids) {
+    bool ret = true;
+    bcmolt_system_mode sm = BCMOLT_SYSTEM_MODE_XGS__2_X;
+
+    return {sm, ret};
+}
\ No newline at end of file
diff --git a/agent/device/asfvolt16/vendor.h b/agent/device/asfvolt16/vendor.h
index f63142e..2e6c499 100644
--- a/agent/device/asfvolt16/vendor.h
+++ b/agent/device/asfvolt16/vendor.h
@@ -16,12 +16,15 @@
 
 #ifndef __VENDOR_H__
 #define __VENDOR_H__
+#include "device.h"
 #define VENDOR_ID "EdgeCore"
 #define ASFVOLT16
 #define MODEL_ID  "asfvolt16"
 #define MAX_SUPPORTED_PON 16
 #define ONU_BIT_TRANSMISSION_DELAY 0.1004823/1000 /* unit: ns to us */
 #define MINIMUM_ONU_RESPONSE_RANGING_TIME 1572135 /* hardcore: this is ranging time for the shortest distance, typically 35us */
+#define DEFAULT_MAC_SYSTEM_MODE BCMOLT_SYSTEM_MODE_XGS__2_X
+#define DEFAULT_PON_MODE BCMOLT_PON_TYPE_XGPON
 
 // DeviceInfo definitions
 
@@ -44,4 +47,59 @@
 
 #define MAC_DEVICE_ACTIVATION_DELAY 2000000 // in microseconds
 
+///////////////////////////////////////////////////////
+// Constants relevant for decoding PON Trx EEPROM Data
+
+// Uncomment below line when you need dynamic transceiver detection support
+// #define DYNAMIC_PON_TRX_SUPPORT
+
+
+#define TOTAL_PON_TRX_PORTS 16 // total PON transceiver ports
+#define TOTAL_PON_PORTS 16 // total PON ports (we could have up to 2 PON ports on the OLT MAC mapped to the external PON Trx)
+const int trx_port_to_pon_port_map[TOTAL_PON_TRX_PORTS][TOTAL_PON_PORTS/TOTAL_PON_TRX_PORTS]={{0},{1},{2},{3},{4},{5},{6},{7},{8},{9},{10},
+{11},{12},{13},{14},{15}};
+#define PONS_PER_TRX (TOTAL_PON_TRX_PORTS/TOTAL_PON_PORTS) // if there are more than one OLT MAC device,
+                                                           // they all have to be of the same type for this to work.
+
+const int bus_index[TOTAL_PON_TRX_PORTS] = {
+   47,  48,  37,  38,  35,  36,  33,  34,
+   39,  40,  41,  42,  43,  44,  45,  46
+};
+
+
+// FIXME: Check the correctness of the below constants for this platform
+
+#define PORT_ADDRESS 50
+
+#define NAME_EEPROM "sfp_eeprom"
+
+#define EEPROM_VENDOR_NAME_START_IDX 148
+#define EEPROM_VENDOR_NAME_LENGTH 16
+
+#define EEPROM_VENDOR_OUI_START_IDX 165
+#define EEPROM_VENDOR_OUI_LENGTH 3
+
+#define EEPROM_VENDOR_PART_NUMBER_START_IDX 168
+#define EEPROM_VENDOR_PART_NUMBER_LENGTH 16
+
+#define EEPROM_VENDOR_REVISION_START_IDX 184
+#define EEPROM_VENDOR_REVISION_LENGTH 2
+
+#define EEPROM_DOWNSTREAM_WAVELENGTH_START_IDX 186
+#define EEPROM_DOWNSTREAM_WAVELENGTH_LENGTH 2
+#define EEPROM_WAVELENGTH_RESOLUTION 0.05
+
+// Define valid values below in case of Combo PON Trx is supported
+// #define EEPROM_DOWNSTREAM_SECONDARY_WAVELENGTH_START_IDX 120
+// #define EEPROM_DOWNSTREAM_SECONDARY_WAVELENGTH_LENGTH 2
+
+
+class PonTrx: public PonTrxBase {
+   // override the base member functions if you need a different implementation
+   public:
+      // Get MAC System mode based on the olt mac id and the set of SFP IDs provided
+      pair<bcmolt_system_mode, bool> get_mac_system_mode(int, set<int>);
+
+};
+
 #endif
diff --git a/agent/device/asgvolt64/mkdebian/debian/files b/agent/device/asgvolt64/mkdebian/debian/files
index f622278..4a4e596 100644
--- a/agent/device/asgvolt64/mkdebian/debian/files
+++ b/agent/device/asgvolt64/mkdebian/debian/files
@@ -1 +1 @@
-asgvolt64_3.10.2.2+edgecore-V202111090101_amd64.deb misc optional
+asgvolt64_3.10.2.2+edgecore-V202111040101_amd64.deb misc optional
diff --git a/agent/device/asgvolt64/vendor.cc b/agent/device/asgvolt64/vendor.cc
index 86836ff..7e68606 100644
--- a/agent/device/asgvolt64/vendor.cc
+++ b/agent/device/asgvolt64/vendor.cc
@@ -18,4 +18,4 @@
 
 void vendor_init()
 {
-}
+}
\ No newline at end of file
diff --git a/agent/device/asgvolt64/vendor.h b/agent/device/asgvolt64/vendor.h
index 89a4bff..7f49bc5 100644
--- a/agent/device/asgvolt64/vendor.h
+++ b/agent/device/asgvolt64/vendor.h
@@ -16,12 +16,18 @@
 
 #ifndef __VENDOR_H__
 #define __VENDOR_H__
+#include "device.h"
+
 #define VENDOR_ID "EdgeCore"
 #define ASGVOLT64
 #define MODEL_ID  "asgvolt64"
 #define MAX_SUPPORTED_PON 64
 #define ONU_BIT_TRANSMISSION_DELAY 0.8038585/1000 /* unit: ns to us */
 #define MINIMUM_ONU_RESPONSE_RANGING_TIME 198075 /* hardcore: this is ranging time for the shortest distance, typically 35us */
+#define DEFAULT_MAC_SYSTEM_MODE BCMOLT_SYSTEM_MODE_GPON__16_X
+//#define DEFAULT_MAC_SYSTEM_MODE BCMOLT_SYSTEM_MODE_XGS__2_X
+#define DEFAULT_PON_MODE BCMOLT_PON_TYPE_GPON
+// #define DEFAULT_PON_MODE BCMOLT_PON_TYPE_XGPON
 
 // DeviceInfo definitions
 
@@ -44,4 +50,64 @@
 
 #define MAC_DEVICE_ACTIVATION_DELAY 2000000 // in microseconds
 
+///////////////////////////////////////////////////////
+// Constants relevant for decoding PON Trx EEPROM Data
+
+// Uncomment below line when you need dynamic transceiver detection support
+//#define DYNAMIC_PON_TRX_SUPPORT
+
+#define TOTAL_PON_TRX_PORTS 64 // total PON transceiver ports
+#define TOTAL_PON_PORTS 64 // total PON ports (we could have up to 2 PON ports on the OLT MAC mapped to the external PON Trx)
+const int trx_port_to_pon_port_map[TOTAL_PON_TRX_PORTS][TOTAL_PON_PORTS/TOTAL_PON_TRX_PORTS]={{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},{31},{32},{33},{34},{35},{36},{37},{38},
+{39},{40},{41},{42},{43},{44},{45},{46},{47},{48},{49},{50},{51},{52},{53},{54},{55},{56},{57},{58},{59},{60},{61},{62},{63}};
+#define PONS_PER_TRX (TOTAL_PON_TRX_PORTS/TOTAL_PON_PORTS) // if there are more than one OLT MAC device,
+                                                           // they all have to be of the same type for this to work.
+
+const int bus_index[TOTAL_PON_TRX_PORTS] = {
+   41,  42,  56,  55,  43,  44,  54,  53,
+   45,  46,  52,  51,  47,  48,  50,  49,
+   57,  58,  72,  71,  59,  60,  70,  69,
+   61,  62,  68,  67,  63,  64,  66,  65,
+   73,  74,  88,  87,  75,  76,  86,  85,
+   77,  78,  84,  83,  79,  80,  82,  81,
+   89,  90, 104, 103,  91,  92, 102, 101,
+   93,  94, 100,  99,  95,  96,  98,  97
+};
+
+// FIXME: Check the correctness of the below constants for this platform
+
+#define PORT_ADDRESS 50
+
+#define NAME_EEPROM "eeprom"
+
+#define EEPROM_VENDOR_NAME_START_IDX 20
+#define EEPROM_VENDOR_NAME_LENGTH 16
+
+#define EEPROM_VENDOR_OUI_START_IDX 37
+#define EEPROM_VENDOR_OUI_LENGTH 3
+
+#define EEPROM_VENDOR_PART_NUMBER_START_IDX 40
+#define EEPROM_VENDOR_PART_NUMBER_LENGTH 16
+
+#define EEPROM_VENDOR_REVISION_START_IDX 56
+#define EEPROM_VENDOR_REVISION_LENGTH 4
+
+#define EEPROM_DOWNSTREAM_WAVELENGTH_START_IDX 60
+#define EEPROM_DOWNSTREAM_WAVELENGTH_LENGTH 2
+#define EEPROM_WAVELENGTH_RESOLUTION 1
+
+// Define valid values below in case of Combo PON Trx is supported
+// #define EEPROM_DOWNSTREAM_SECONDARY_WAVELENGTH_START_IDX 120
+// #define EEPROM_DOWNSTREAM_SECONDARY_WAVELENGTH_LENGTH 2
+
+class PonTrx: public PonTrxBase {
+   public:
+      // override the base member functions if you need a different implementation
+      PonTrx(): PonTrxBase("eeprom", 50, "/sys/bus/i2c/devices/%d-00%d/%s") {
+
+      }
+
+};
+
 #endif
diff --git a/agent/device/device.cc b/agent/device/device.cc
new file mode 100644
index 0000000..c6f4cbf
--- /dev/null
+++ b/agent/device/device.cc
@@ -0,0 +1,369 @@
+/*
+ * Copyright 2018-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.
+ */
+
+#include "device.h"
+#include "vendor.h"
+#include "core_utils.h"
+
+using namespace std;
+
+// PonTrxBase class member function definitions
+// Note: 'cout' logger has been used in this file instead of OPENOLT_LOG
+// because the logger task may not be initialized in the openolt core module
+// before PonTrx module is initialized in the main handler. In that case,
+// any OPENOLT_LOG logger (which internally uses BCM_LOG) will not be logged.
+
+PonTrxBase::PonTrxBase(string eeprom_file_name,
+                       int port_addr,
+                       string eeprom_file_path_name,
+                       string sfp_presence_command) :
+        _eeprom_file_name{eeprom_file_name},
+        _port_addr{port_addr},
+        _eeprom_file_path_format{eeprom_file_path_name},
+        _sfp_presence_command{sfp_presence_command}
+{
+}
+
+PonTrxBase::~PonTrxBase() {
+    for (auto it : _t_data) {
+        delete it;
+    }
+}
+
+// returns the _sfp_presence_data
+const set<int> PonTrxBase::get_sfp_presence_data() {
+    return _sfp_presence_data;
+}
+
+// reads, updates and returns the _sfp_presence_data
+const set<int> PonTrxBase::read_sfp_presence_data() {
+    set<int> sp;
+    // command to read the sfp presence array
+    // The sample output of the command looks like below
+    // root@localhost:~# onlpdump -p
+    // Presence: 0 1 16
+    const string& command = _sfp_presence_command;
+    int status_code = system((command + " > temp.txt").c_str());
+    if (status_code != 0) {
+        perror("error getting sfp presence array from ONL\n");
+        // return the current _sfp_presence_data
+        return _sfp_presence_data;
+    }
+    ifstream ifs("temp.txt");
+    string res = {istreambuf_iterator<char>(ifs), istreambuf_iterator<char>()};
+    ifs.close(); // must close the inout stream so the file can be cleaned up
+    // If there is issue reading the sfp presence array, print error and return existing data
+    if (remove("temp.txt") != 0) {
+        perror("Error deleting temporary file");
+        // return the current sfp presence array
+        return _sfp_presence_data;
+    }
+
+    // parse the output of sfp presence command and read which PON Trx are connected/disconnected now
+    stringstream ss(res);
+    string s;
+    while (getline(ss, s, ' ')) {
+        try {
+            int i = stoi(s);
+            // Set the Trx port index corresponding the PON port to true if it appears on the sfp presence command output
+            if (i < TOTAL_PON_TRX_PORTS) {
+                sp.insert(i);
+            }
+
+        } catch(invalid_argument) {
+            // do nothing
+        } catch(out_of_range) {
+            // do nothing
+        }
+    }
+
+    // If the current _sfp_presence_data is not same the newly read data,
+    // update local copy and also raise an event.
+    if (sp != _sfp_presence_data) {
+        cout << "sfp presence data has been updated\n";
+
+        set<int> sfp_ports_up, sfp_ports_down;
+
+        set_difference(sp.begin(), sp.end(), _sfp_presence_data.begin(), _sfp_presence_data.end(), inserter(sfp_ports_up, sfp_ports_up.begin()));
+        // New SFPs are detected
+        if (sfp_ports_up.size() > 0) {
+            cout << "following pon sfp ports are up: ";
+            for (auto up_it : sfp_ports_up) {
+                cout << up_it << " ";
+            }
+            cout << "\n";
+        }
+        set_difference(_sfp_presence_data.begin(), _sfp_presence_data.end(), sp.begin(), sp.end(), inserter(sfp_ports_down, sfp_ports_down.begin()));
+        // Some SFPs are down
+        if (sfp_ports_down.size() > 0) {
+            cout << "following pon sfp ports are down: \n";
+            for (auto down_it : sfp_ports_down) {
+                cout << down_it << " ";
+            }
+            cout << "\n";
+        }
+
+        // FIXME: raise an event for all the PON Trx ports that have been updated
+        _sfp_presence_data = sp;
+    }
+
+    return _sfp_presence_data;
+}
+
+// reads the EEPROM data. The sfp_index is the bus index corresponding to the PON Trx
+// returns true if success
+bool PonTrxBase::read_eeprom_data_for_sfp(int sfp_index) {
+    ifstream is;
+    int len;
+    array<char, EEPROM_READ_PATH_SIZE> path{};
+    array<unsigned char, EEPROM_DATA_READ_SIZE> data{};
+
+    if (sfp_index >= TOTAL_PON_TRX_PORTS) {
+        perror("invalid pon trx index\n");
+        return false;
+    }
+
+    if (_eeprom_read_path.count(sfp_index) == 0) {
+        _eeprom_read_path[sfp_index] = path;
+        char file_name[PON_TRX_BUS_FORMAT_SIZE];
+        char *tmp_place_holder = new char[PON_TRX_BUS_FORMAT_SIZE];
+        // 4 is max length of _port_addr
+        if ((_eeprom_file_path_format.length() + _eeprom_file_name.length() + 4) > PON_TRX_BUS_FORMAT_SIZE) {
+            cerr << "resultant eeprom file length too long\n";
+            delete []tmp_place_holder;
+            return false;
+        }
+        strcpy(tmp_place_holder, _eeprom_file_path_format.c_str());
+        sprintf(file_name, tmp_place_holder, bus_index[sfp_index], _port_addr, _eeprom_file_name.c_str());
+        memcpy(&_eeprom_read_path[sfp_index][0], file_name, PON_TRX_BUS_FORMAT_SIZE);
+        delete []tmp_place_holder;
+    }
+    cout << "eeprom file to read is: " << _eeprom_read_path[sfp_index].data() << "for sfp " << sfp_index << endl;
+    FILE* fp = fopen(_eeprom_read_path[sfp_index].data(), "rb");
+    if (!fp) {
+        perror("failed to open file");
+        _eeprom_read_path.erase(sfp_index);
+        return false;
+    }
+    _eeprom_data[sfp_index] = data;
+    int val, cnt = 0;
+
+    // Populate EEPROM data
+    while ((val = fgetc(fp)) != EOF && cnt < EEPROM_DATA_READ_SIZE) {
+        _eeprom_data[sfp_index][cnt] = (unsigned char)val;
+        cnt++;
+    }
+    fclose(fp);
+    if (cnt != EEPROM_DATA_READ_SIZE) {
+        cerr << "invalid length of data read:" << cnt << endl;
+        _eeprom_read_path.erase(sfp_index);
+        _eeprom_data.erase(sfp_index);
+        return false;
+    }
+
+    return true;
+}
+
+// decodes the EEPROM data. The sfp_index is the bus index corresponding to the PON Trx
+// returns true if success
+bool PonTrxBase::decode_eeprom_data(int sfp_index) {
+    /*
+    try {
+    */
+
+    trx_data tmp, *store=NULL;
+    tmp.sfp_index = sfp_index;
+
+    // decode vendor name
+    array<unsigned char, EEPROM_VENDOR_NAME_LENGTH> vn{};
+    copy(&_eeprom_data[sfp_index][EEPROM_VENDOR_NAME_START_IDX],
+         &_eeprom_data[sfp_index][EEPROM_VENDOR_NAME_START_IDX] + EEPROM_VENDOR_NAME_LENGTH,
+         &vn[0]);
+    pair<string, bool> res_str = hex_to_ascii_string(vn.data(), vn.max_size());
+    if (!res_str.second) {
+        perror("error decoding vendor name\n");
+        return false;
+    }
+    tmp.vendor_name = res_str.first;
+    cout << "[" << sfp_index << "]" << " vendor name: " << tmp.vendor_name << endl;
+
+
+    // decode vendor oui
+    array<unsigned char, EEPROM_VENDOR_OUI_LENGTH> oui{};
+    copy(&_eeprom_data[sfp_index][EEPROM_VENDOR_OUI_START_IDX],
+         &_eeprom_data[sfp_index][EEPROM_VENDOR_OUI_START_IDX] + EEPROM_VENDOR_OUI_LENGTH,
+         &oui[0]);
+    res_str = hex_to_ascii_string(oui.data(), oui.max_size());
+    if (!res_str.second) {
+        perror("error decoding vendor oui\n");
+        return false;
+    }
+    if (res_str.first.length() == 3) { // vendor_oui length is 3
+        memcpy(tmp.vendor_oui, res_str.first.c_str(), 3);
+    }
+    cout << "[" << sfp_index << "]" << " vendor oui: " << res_str.first << endl;
+
+    // decode vendor part number
+    array<unsigned char, EEPROM_VENDOR_PART_NUMBER_LENGTH> pn{};
+    copy(&_eeprom_data[sfp_index][EEPROM_VENDOR_PART_NUMBER_START_IDX],
+         &_eeprom_data[sfp_index][EEPROM_VENDOR_PART_NUMBER_START_IDX] + EEPROM_VENDOR_PART_NUMBER_LENGTH,
+         &pn[0]);
+    res_str = hex_to_ascii_string(pn.data(), pn.max_size());
+    if (!res_str.second) {
+        perror("error decoding vendor part number\n");
+        return false;
+    }
+    tmp.vendor_part_no = res_str.first;
+    cout << "[" << sfp_index << "]" << " vendor pn: " << tmp.vendor_part_no << endl;
+
+    // decode vendor revision
+    array<unsigned char, EEPROM_VENDOR_REVISION_LENGTH> rev{};
+    copy(&_eeprom_data[sfp_index][EEPROM_VENDOR_REVISION_START_IDX],
+         &_eeprom_data[sfp_index][EEPROM_VENDOR_REVISION_START_IDX] + EEPROM_VENDOR_REVISION_LENGTH,
+         &rev[0]);
+    res_str = hex_to_ascii_string(rev.data(), rev.max_size());
+    if (!res_str.second) {
+        perror("error decoding vendor revision\n");
+        return false;
+    }
+    tmp.vendor_rev = res_str.first;
+    cout << "[" << sfp_index << "]" << " vendor rev: " << tmp.vendor_rev << endl;
+
+    // decode pon wavelength(s)
+    array<unsigned char, EEPROM_DOWNSTREAM_WAVELENGTH_LENGTH> wv{};
+    copy(&_eeprom_data[sfp_index][EEPROM_DOWNSTREAM_WAVELENGTH_START_IDX],
+         &_eeprom_data[sfp_index][EEPROM_DOWNSTREAM_WAVELENGTH_START_IDX] + EEPROM_DOWNSTREAM_WAVELENGTH_LENGTH,
+         &wv[0]);
+    pair<uint32_t, bool> res_uint = hex_to_uinteger(wv.data(), wv.max_size());
+    if (!res_uint.second) {
+        perror("error decoding primary downstream wavelength\n");
+        return false;
+    }
+    tmp.p_data[0].valid = true;
+    tmp.p_data[0].wavelength = res_uint.first * EEPROM_WAVELENGTH_RESOLUTION;
+    tmp.p_data[0].pon_type = get_pon_type_from_wavelength(tmp.p_data[0].wavelength);
+    cout << "[" << sfp_index << "]" << " pon wavelength: " << tmp.p_data[0].wavelength << endl;
+    // TODO: also fill the field pon_type
+
+    // TODO: Let's ignore secondary wavelength decode for now as we do not know how the secondary wavelength is represent on the Combo PON
+    tmp.p_data[1].valid = false;
+
+    store = new(nothrow) trx_data;
+    if (store == NULL) {
+        perror("could not allocate memory for trx_data");
+        return false;
+    }
+
+    // Copy data
+    store->sfp_index = sfp_index;
+    store->vendor_name = tmp.vendor_name;
+    memcpy(store->vendor_oui, tmp.vendor_oui, 3);
+    store->vendor_part_no = tmp.vendor_part_no;
+    store->vendor_rev = tmp.vendor_rev;
+    store->trx_type = tmp.trx_type;
+    for (int i = 0; i < MAX_PONS_PER_TRX; i++) {
+        store->p_data[i].valid = tmp.p_data[i].valid;
+        store->p_data[i].wavelength = tmp.p_data[i].wavelength;
+        store->p_data[i].pon_type = tmp.p_data[i].pon_type;
+    }
+
+    _t_data.insert(store);
+    /*
+    } catch(...) { // FIXME: Put specific exceptions here
+        perror("caught exception\n");
+        return false;
+    }
+    */
+    return true;
+}
+
+bcmolt_pon_type PonTrxBase::get_pon_type_from_wavelength(int wavelength) {
+    bcmolt_pon_type pon_type = BCMOLT_PON_TYPE_UNKNOWN;
+    switch (wavelength) {
+        case GPON_DOWNSTREAM_WAVELENGTH_NM:
+            pon_type = BCMOLT_PON_TYPE_GPON;
+        case XGSPON_DOWNSTREAM_WAVELENGTH_NM:
+            pon_type = BCMOLT_PON_TYPE_XGPON;
+        // Add more in the future as needed.
+    }
+    return pon_type;
+}
+
+bcmolt_pon_type PonTrxBase::get_sfp_mode(int sfp_index) {
+    bcmolt_pon_type pon0_type = BCMOLT_PON_TYPE_UNKNOWN;
+    bcmolt_pon_type pon1_type = BCMOLT_PON_TYPE_UNKNOWN;
+    trx_data *td = NULL;
+    set<trx_data*>::iterator it;
+    // Iterate the trx data set and break if we find a trx data with mathcing sfp index
+    for (it = _t_data.begin(); it != _t_data.end(); it++) {
+        if ((*it)->sfp_index == sfp_index) {
+            td = *it;
+            break;
+        }
+    }
+    if (it == _t_data.end()) {
+        perror("end of iterator, pon type not detected");
+        return pon0_type;
+    }
+    if (td == NULL) {
+        cerr << "trx data is null\n";
+        return pon0_type;
+    }
+
+    // Find the PON type/mode
+    if (td->p_data[0].valid) {
+        pon0_type = td->p_data[0].pon_type;
+        if (pon0_type == BCMOLT_PON_TYPE_UNKNOWN) {
+            return pon0_type;
+        }
+        if (td->p_data[1].valid) {
+            pon1_type = td->p_data[1].pon_type;
+            if (pon1_type == BCMOLT_PON_TYPE_UNKNOWN) {
+                return pon1_type;
+            }
+
+            if  (pon0_type == pon1_type) {
+                return pon0_type;
+            } else {
+                return BCMOLT_PON_TYPE_XGPON_GPON_WDMA; // Combo SFP!
+            }
+        }
+        return pon0_type;
+    }
+
+    return pon0_type;
+}
+
+// Returns the MAC System Mode based on the set of SFP IDs provided.
+// The derived class will most likely need to override this method to provide a
+// different implementation for that particular OLT platform.
+pair<bcmolt_system_mode, bool> PonTrxBase::get_mac_system_mode(int olt_mac_id, set<int> sfp_ids) {
+    bool ret = true;
+    bcmolt_system_mode sm = BCMOLT_SYSTEM_MODE_GPON__16_X;
+
+    return {sm, ret};
+}
+
+// Get trx data for sfp
+trx_data* PonTrxBase::get_trx_data(int sfp_index) {
+    for (auto it : _t_data) {
+        if (it->sfp_index == sfp_index) {
+            cout << "[" << sfp_index << "]" << " found trx data\n";
+            return (it);
+        }
+    }
+    return NULL;
+}
diff --git a/agent/device/device.h b/agent/device/device.h
index 71259ac..a0118a1 100644
--- a/agent/device/device.h
+++ b/agent/device/device.h
@@ -17,8 +17,120 @@
 #ifndef __DEVICE_H__
 #define __DEVICE_H__
 
-#include "vendor.h"
+#include <string>
+#include <fstream>
+#include <iostream>
+#include <algorithm>
+#include <cstdlib>
+#include <sstream>
+#include <new>
+#include <set>
+#include <map>
 
+extern "C"
+{
+#include <bcmolt_api.h>
+#include <bcmolt_api_model_supporting_enums.h>
+}
+
+using namespace std;
+
+/////////////////////////////////////////////////////
+
+// Constant definitions
+
+#define EEPROM_DATA_READ_SIZE 256 //bytes
+#define EEPROM_READ_PATH_SIZE 200
+#define PON_TRX_BUS_FORMAT_SIZE 64
+#define MAX_PONS_PER_TRX 2
+
+#define GPON_DOWNSTREAM_WAVELENGTH_NM 1490 // ITU-T G984.2 PMD specification
+#define XGSPON_DOWNSTREAM_WAVELENGTH_NM 1577 // ITU-T G9807.1 PMD specification
+
+
+/////////////////////////////////////////////////////
+
+// Structure definitions
+
+struct pon_data {
+    bool valid; // set to true if the below fields are set after reading eeprom data
+    uint32_t wavelength;
+    bcmolt_pon_type pon_type;
+    // add more fields as needed...
+};
+
+struct trx_data {
+    int sfp_index;
+    string vendor_name;
+    uint8_t vendor_oui[3];
+    string vendor_part_no;
+    string vendor_rev;
+    bcmolt_pon_type trx_type;
+    pon_data p_data[MAX_PONS_PER_TRX];
+};
+
+/////////////////////////////////////////////////////
+
+// Class Definitions
+
+// PonTrx: This class defines the member functions and attributes of the Pon Transceiver object
+class PonTrxBase {
+    public:
+
+        // Location of I2C file systems is pretty standard for Linux systems, and it is /sys/bus/i2c/devices
+        // Check here https://www.kernel.org/doc/html/latest/i2c/i2c-sysfs.html#location-of-i2c-sysfs for documentation on Linux I2C
+        // The OLTs we work with are based on Linux, however if it is something different this can be overridden.
+        PonTrxBase(string eeprom_file_name="sfp_eeprom",
+                   int port_addr=50,
+                   string eeprom_file_format_name="/sys/bus/i2c/devices/%d-00%d/%s",
+                   string sfp_presence_command="/lib/platform-config/current/onl/bin/onlpdump -p");
+
+        // Reads, updates and returns the _sfp_presence_array from the OLT device
+        const set<int> read_sfp_presence_data();
+
+        // Returns the _sfp_presence_array
+        const set<int> get_sfp_presence_data();
+
+        // Reads the EEPROM data. The sfp_index is the bus index corresponding to the PON Trx
+        // returns true if success
+        bool read_eeprom_data_for_sfp(int sfp_index);
+
+        // Decodes the EEPROM data. The sfp_index is the bus index corresponding to the PON Trx
+        // returns true if success
+        bool decode_eeprom_data(int sfp_index);
+
+        // Get Trx Type based on SFP ID provided
+        bcmolt_pon_type get_sfp_mode(int sfp_index);
+
+        // Get PON Type based on optical wavelength specified
+        bcmolt_pon_type get_pon_type_from_wavelength(int wavelength);
+
+        // Get MAC System mode based on the olt mac id and the set of SFP IDs provided
+        pair<bcmolt_system_mode, bool> get_mac_system_mode(int, set<int>);
+
+        // Get Trx data
+        trx_data* get_trx_data(int sfp_index);
+
+        ~PonTrxBase();
+
+    protected:
+        set<int> _sfp_presence_data;
+        set<trx_data*> _t_data;
+        map<int, array<char, EEPROM_READ_PATH_SIZE>> _eeprom_read_path;
+        map<int, array<unsigned char, EEPROM_DATA_READ_SIZE>> _eeprom_data;
+        // Location of I2C file systems is pretty standard for Linux systems, and it is /sys/bus/i2c/devices
+        // Check here https://www.kernel.org/doc/html/latest/i2c/i2c-sysfs.html#location-of-i2c-sysfs for documentation on Linux I2C
+        // The OLTs we work with are based on Linux, however if it is something different this can be overridden during objection creation.
+        string _eeprom_file_path_format = "/sys/bus/i2c/devices/%d-00%d/%s";
+        string _eeprom_file_name;
+        string _sfp_presence_command = "/lib/platform-config/current/onl/bin/onlpdump -p";
+        int _port_addr;
+
+};
+
+/////////////////////////////////////////////////////
+
+// Extern definitions
 extern void vendor_init();
 
 #endif
diff --git a/agent/device/generic/vendor.h b/agent/device/generic/vendor.h
index 8d2a5a0..987d927 100644
--- a/agent/device/generic/vendor.h
+++ b/agent/device/generic/vendor.h
@@ -16,6 +16,7 @@
 
 #ifndef __VENDOR_H__
 #define __VENDOR_H__
+#include "device.h"
 #define VENDOR_ID "generic"
 #define MODEL_ID  "generic"
 
@@ -38,4 +39,52 @@
 
 #define MAC_DEVICE_ACTIVATION_DELAY 200000 // in microseconds
 
+#define DEFAULT_MAC_SYSTEM_MODE BCMOLT_SYSTEM_MODE_GPON__16_X
+//#define DEFAULT_MAC_SYSTEM_MODE BCMOLT_SYSTEM_MODE_XGS__2_X
+#define DEFAULT_PON_MODE BCMOLT_PON_TYPE_GPON
+// #define DEFAULT_PON_MODE BCMOLT_PON_TYPE_XGPON
+
+
+#define TOTAL_PON_TRX_PORTS 16 // total PON transceiver ports
+#define TOTAL_PON_PORTS 16 // total PON ports (we could have up to 2 PON ports on the OLT MAC mapped to the external PON Trx)
+const int trx_port_to_pon_port_map[TOTAL_PON_TRX_PORTS][TOTAL_PON_PORTS/TOTAL_PON_TRX_PORTS]={{0},{1},{2},{3},{4},{5},{6},{7},{8},{9},{10},
+{11},{12},{13},{14},{15}};
+#define PONS_PER_TRX (TOTAL_PON_TRX_PORTS/TOTAL_PON_PORTS) // if there are more than one OLT MAC device,
+                                                           // they all have to be of the same type for this to work.
+
+const int bus_index[TOTAL_PON_TRX_PORTS] = {
+   41,  42,  56,  55,  43,  44,  54,  53,
+   45,  46,  52,  51,  47,  48,  50,  49
+};
+
+
+#define PORT_ADDRESS 50
+
+#define NAME_EEPROM "sfp_eeprom"
+
+#define EEPROM_VENDOR_NAME_START_IDX 148
+#define EEPROM_VENDOR_NAME_LENGTH 16
+
+#define EEPROM_VENDOR_OUI_START_IDX 165
+#define EEPROM_VENDOR_OUI_LENGTH 3
+
+#define EEPROM_VENDOR_PART_NUMBER_START_IDX 168
+#define EEPROM_VENDOR_PART_NUMBER_LENGTH 16
+
+#define EEPROM_VENDOR_REVISION_START_IDX 184
+#define EEPROM_VENDOR_REVISION_LENGTH 2
+
+#define EEPROM_DOWNSTREAM_WAVELENGTH_START_IDX 186
+#define EEPROM_DOWNSTREAM_WAVELENGTH_LENGTH 2
+#define EEPROM_WAVELENGTH_RESOLUTION 0.05
+
+// Define valid values below in case of Combo PON Trx is supported
+// #define EEPROM_DOWNSTREAM_SECONDARY_WAVELENGTH_START_IDX 120
+// #define EEPROM_DOWNSTREAM_SECONDARY_WAVELENGTH_LENGTH 2
+
+class PonTrx: public PonTrxBase {
+   // override the base member functions if you need a different implementation
+};
+
+
 #endif
diff --git a/agent/device/rlt-1600g-w/vendor.h b/agent/device/rlt-1600g-w/vendor.h
index 2a62bcb..2940b91 100644
--- a/agent/device/rlt-1600g-w/vendor.h
+++ b/agent/device/rlt-1600g-w/vendor.h
@@ -16,6 +16,8 @@
 
 #ifndef __VENDOR_H__
 #define __VENDOR_H__
+#include "device.h"
+
 #define VENDOR_ID "Radisys"
 #define RLT1600GW
 #define MODEL_ID  "rlt-1600g-w"
@@ -23,6 +25,12 @@
 #define ONU_BIT_TRANSMISSION_DELAY 0.8038585/1000 /* unit: ns to us */
 #define MINIMUM_ONU_RESPONSE_RANGING_TIME 198075 /* hardcore: this is ranging time for the shortest distance, typically 35us */
 
+#define DEFAULT_MAC_SYSTEM_MODE BCMOLT_SYSTEM_MODE_GPON__16_X
+//#define DEFAULT_MAC_SYSTEM_MODE BCMOLT_SYSTEM_MODE_XGS__2_X
+#define DEFAULT_PON_MODE BCMOLT_PON_TYPE_GPON
+// #define DEFAULT_PON_MODE BCMOLT_PON_TYPE_XGPON
+
+
 // DeviceInfo definitions
 
 #define ONU_ID_START 1
@@ -44,4 +52,48 @@
 
 #define MAC_DEVICE_ACTIVATION_DELAY 200000 // in microseconds
 
+#define TOTAL_PON_TRX_PORTS 16 // total PON transceiver ports
+#define TOTAL_PON_PORTS 16 // total PON ports (we could have up to 2 PON ports on the OLT MAC mapped to the external PON Trx)
+const int trx_port_to_pon_port_map[TOTAL_PON_TRX_PORTS][TOTAL_PON_PORTS/TOTAL_PON_TRX_PORTS]={{0},{1},{2},{3},{4},{5},{6},{7},{8},{9},{10},
+{11},{12},{13},{14},{15}};
+#define PONS_PER_TRX (TOTAL_PON_TRX_PORTS/TOTAL_PON_PORTS) // if there are more than one OLT MAC device,
+                                                           // they all have to be of the same type for this to work.
+
+// FIXME: These may not be correct for this platform
+const int bus_index[TOTAL_PON_TRX_PORTS] = {
+   41,  42,  56,  55,  43,  44,  54,  53,
+   45,  46,  52,  51,  47,  48,  50,  49
+};
+
+// FIXME: Check the correctness of the below constants for this platform
+
+#define PORT_ADDRESS 50
+
+#define NAME_EEPROM "eeprom"
+
+#define EEPROM_VENDOR_NAME_START_IDX 20
+#define EEPROM_VENDOR_NAME_LENGTH 16
+
+#define EEPROM_VENDOR_OUI_START_IDX 37
+#define EEPROM_VENDOR_OUI_LENGTH 3
+
+#define EEPROM_VENDOR_PART_NUMBER_START_IDX 40
+#define EEPROM_VENDOR_PART_NUMBER_LENGTH 16
+
+#define EEPROM_VENDOR_REVISION_START_IDX 56
+#define EEPROM_VENDOR_REVISION_LENGTH 4
+
+#define EEPROM_DOWNSTREAM_WAVELENGTH_START_IDX 60
+#define EEPROM_DOWNSTREAM_WAVELENGTH_LENGTH 2
+#define EEPROM_WAVELENGTH_RESOLUTION 1
+
+// Define valid values below in case of Combo PON Trx is supported
+// #define EEPROM_DOWNSTREAM_SECONDARY_WAVELENGTH_START_IDX 120
+// #define EEPROM_DOWNSTREAM_SECONDARY_WAVELENGTH_LENGTH 2
+
+class PonTrx: public PonTrxBase {
+   // override the base member functions if you need a different implementation
+
+};
+
 #endif
diff --git a/agent/device/rlt-1600x-w/vendor.h b/agent/device/rlt-1600x-w/vendor.h
index ec6b5c6..5c8425d 100644
--- a/agent/device/rlt-1600x-w/vendor.h
+++ b/agent/device/rlt-1600x-w/vendor.h
@@ -16,6 +16,8 @@
 
 #ifndef __VENDOR_H__
 #define __VENDOR_H__
+#include "device.h"
+
 #define VENDOR_ID "Radisys"
 #define RLT1600XW
 #define MODEL_ID  "rlt-1600x-w"
@@ -44,4 +46,54 @@
 
 #define MAC_DEVICE_ACTIVATION_DELAY 200000 // in microseconds
 
+#define DEFAULT_MAC_SYSTEM_MODE BCMOLT_SYSTEM_MODE_GPON__16_X
+//#define DEFAULT_MAC_SYSTEM_MODE BCMOLT_SYSTEM_MODE_XGS__2_X
+#define DEFAULT_PON_MODE BCMOLT_PON_TYPE_GPON
+// #define DEFAULT_PON_MODE BCMOLT_PON_TYPE_XGPON
+
+
+#define TOTAL_PON_TRX_PORTS 16 // total PON transceiver ports
+#define TOTAL_PON_PORTS 16 // total PON ports (we could have up to 2 PON ports on the OLT MAC mapped to the external PON Trx)
+const int trx_port_to_pon_port_map[TOTAL_PON_TRX_PORTS][TOTAL_PON_PORTS/TOTAL_PON_TRX_PORTS]={{0},{1},{2},{3},{4},{5},{6},{7},{8},{9},{10},
+{11},{12},{13},{14},{15}};
+#define PONS_PER_TRX (TOTAL_PON_TRX_PORTS/TOTAL_PON_PORTS) // if there are more than one OLT MAC device,
+                                                           // they all have to be of the same type for this to work.
+
+// FIXME: These may not be correct for this platform
+const int bus_index[TOTAL_PON_TRX_PORTS] = {
+   41,  42,  56,  55,  43,  44,  54,  53,
+   45,  46,  52,  51,  47,  48,  50,  49
+};
+
+// FIXME: Check the correctness of the below constants for this platform
+
+#define PORT_ADDRESS 50
+
+#define NAME_EEPROM "eeprom"
+
+#define EEPROM_VENDOR_NAME_START_IDX 20
+#define EEPROM_VENDOR_NAME_LENGTH 16
+
+#define EEPROM_VENDOR_OUI_START_IDX 37
+#define EEPROM_VENDOR_OUI_LENGTH 3
+
+#define EEPROM_VENDOR_PART_NUMBER_START_IDX 40
+#define EEPROM_VENDOR_PART_NUMBER_LENGTH 16
+
+#define EEPROM_VENDOR_REVISION_START_IDX 56
+#define EEPROM_VENDOR_REVISION_LENGTH 4
+
+#define EEPROM_DOWNSTREAM_WAVELENGTH_START_IDX 60
+#define EEPROM_DOWNSTREAM_WAVELENGTH_LENGTH 2
+#define EEPROM_WAVELENGTH_RESOLUTION 1
+
+// Define valid values below in case of Combo PON Trx is supported
+// #define EEPROM_DOWNSTREAM_SECONDARY_WAVELENGTH_START_IDX 120
+// #define EEPROM_DOWNSTREAM_SECONDARY_WAVELENGTH_LENGTH 2
+
+class PonTrx: public PonTrxBase {
+   // override the base member functions if you need a different implementation
+
+};
+
 #endif
diff --git a/agent/device/rlt-3200g-w/vendor.h b/agent/device/rlt-3200g-w/vendor.h
index b55cc02..df21c32 100644
--- a/agent/device/rlt-3200g-w/vendor.h
+++ b/agent/device/rlt-3200g-w/vendor.h
@@ -16,6 +16,8 @@
 
 #ifndef __VENDOR_H__
 #define __VENDOR_H__
+#include "device.h"
+
 #define VENDOR_ID "Radisys"
 #define RLT3200GW
 #define MODEL_ID  "rlt-3200g-w"
@@ -44,4 +46,56 @@
 
 #define MAC_DEVICE_ACTIVATION_DELAY 200000 // in microseconds
 
+#define DEFAULT_MAC_SYSTEM_MODE BCMOLT_SYSTEM_MODE_GPON__16_X
+//#define DEFAULT_MAC_SYSTEM_MODE BCMOLT_SYSTEM_MODE_XGS__2_X
+#define DEFAULT_PON_MODE BCMOLT_PON_TYPE_GPON
+// #define DEFAULT_PON_MODE BCMOLT_PON_TYPE_XGPON
+
+
+#define TOTAL_PON_TRX_PORTS 32 // total PON transceiver ports
+#define TOTAL_PON_PORTS 32 // total PON ports (we could have up to 2 PON ports on the OLT MAC mapped to the external PON Trx)
+const int trx_port_to_pon_port_map[TOTAL_PON_TRX_PORTS][TOTAL_PON_PORTS/TOTAL_PON_TRX_PORTS]={{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},{31}};
+#define PONS_PER_TRX (TOTAL_PON_TRX_PORTS/TOTAL_PON_PORTS) // if there are more than one OLT MAC device,
+                                                           // they all have to be of the same type for this to work.
+
+// FIXME: These may not be correct for this platform
+const int bus_index[TOTAL_PON_TRX_PORTS] = {
+   41,  42,  56,  55,  43,  44,  54,  53,
+   45,  46,  52,  51,  47,  48,  50,  49,
+   57,  58,  72,  71,  59,  60,  70,  69,
+   61,  62,  68,  67,  63,  64,  66,  65
+};
+
+// FIXME: Check the correctness of the below constants for this platform
+
+#define PORT_ADDRESS 50
+
+#define NAME_EEPROM "eeprom"
+
+#define EEPROM_VENDOR_NAME_START_IDX 20
+#define EEPROM_VENDOR_NAME_LENGTH 16
+
+#define EEPROM_VENDOR_OUI_START_IDX 37
+#define EEPROM_VENDOR_OUI_LENGTH 3
+
+#define EEPROM_VENDOR_PART_NUMBER_START_IDX 40
+#define EEPROM_VENDOR_PART_NUMBER_LENGTH 16
+
+#define EEPROM_VENDOR_REVISION_START_IDX 56
+#define EEPROM_VENDOR_REVISION_LENGTH 4
+
+#define EEPROM_DOWNSTREAM_WAVELENGTH_START_IDX 60
+#define EEPROM_DOWNSTREAM_WAVELENGTH_LENGTH 2
+#define EEPROM_WAVELENGTH_RESOLUTION 1
+
+// Define valid values below in case of Combo PON Trx is supported
+// #define EEPROM_DOWNSTREAM_SECONDARY_WAVELENGTH_START_IDX 120
+// #define EEPROM_DOWNSTREAM_SECONDARY_WAVELENGTH_LENGTH 2
+
+class PonTrx: public PonTrxBase {
+   // override the base member functions if you need a different implementation
+
+};
+
 #endif
diff --git a/agent/device/sda3016ss/vendor.cc b/agent/device/sda3016ss/vendor.cc
index 86836ff..75542bf 100755
--- a/agent/device/sda3016ss/vendor.cc
+++ b/agent/device/sda3016ss/vendor.cc
@@ -19,3 +19,13 @@
 void vendor_init()
 {
 }
+
+// Returns the MAC System Mode based on the set of SFP IDs provided.
+// The derived class will most likely need to override this method to provide a
+// different implementation for that particular OLT platform.
+pair<bcmolt_system_mode, bool> PonTrx::get_mac_system_mode(int olt_mac_id, set<int> sfp_ids) {
+    bool ret = true;
+    bcmolt_system_mode sm = BCMOLT_SYSTEM_MODE_XGS__8_X_GPON__8_X_WDMA;
+
+    return {sm, ret};
+}
diff --git a/agent/device/sda3016ss/vendor.h b/agent/device/sda3016ss/vendor.h
index d904e9b..b30960b 100755
--- a/agent/device/sda3016ss/vendor.h
+++ b/agent/device/sda3016ss/vendor.h
@@ -23,6 +23,8 @@
 #define MAX_SUPPORTED_SWITCH_PORT 16
 #define ONU_BIT_TRANSMISSION_DELAY 0.1004823/1000 /* unit: ns to us */
 #define MINIMUM_ONU_RESPONSE_RANGING_TIME 1572135 /* hardcore: this is ranging time for the shortest distance, typically 35us */
+#define DEFAULT_MAC_SYSTEM_MODE BCMOLT_SYSTEM_MODE_XGS__8_X_GPON__8_X_WDMA
+#define DEFAULT_PON_MODE BCMOLT_PON_TYPE_XGPON
 
 // DeviceInfo definitions
 
@@ -44,5 +46,60 @@
 #define INVALID_FLOW_ID 0
 
 #define MAC_DEVICE_ACTIVATION_DELAY 200000 // in microseconds
+///////////////////////////////////////////////////////
+// Constants relevant for decoding PON Trx EEPROM Data
+
+// Uncomment below line when you need dynamic transceiver detection support
+// #define DYNAMIC_PON_TRX_SUPPORT
+
+
+#define TOTAL_PON_TRX_PORTS 16 // total PON transceiver ports
+#define TOTAL_PON_PORTS 32 // total PON ports (we could have up to 2 PON ports on the OLT MAC mapped to the external PON Trx)
+const int trx_port_to_pon_port_map[TOTAL_PON_TRX_PORTS][TOTAL_PON_PORTS/TOTAL_PON_TRX_PORTS]={{0},{1},{2},{3},{4},{5},{6},{7},{8},{9},{10},
+{11},{12},{13},{14},{15}};
+#define PONS_PER_TRX (TOTAL_PON_TRX_PORTS/TOTAL_PON_PORTS) // if there are more than one OLT MAC device,
+                                                           // they all have to be of the same type for this to work.
+
+const int bus_index[TOTAL_PON_TRX_PORTS] = {
+   47,  48,  37,  38,  35,  36,  33,  34,
+   39,  40,  41,  42,  43,  44,  45,  46
+};
+
+
+// FIXME: Check the correctness of the below constants for this platform
+// This is Combo PON OLT - so not all the values below are accurate.
+
+#define PORT_ADDRESS 50
+
+#define NAME_EEPROM "sfp_eeprom"
+
+#define EEPROM_VENDOR_NAME_START_IDX 148
+#define EEPROM_VENDOR_NAME_LENGTH 16
+
+#define EEPROM_VENDOR_OUI_START_IDX 165
+#define EEPROM_VENDOR_OUI_LENGTH 3
+
+#define EEPROM_VENDOR_PART_NUMBER_START_IDX 168
+#define EEPROM_VENDOR_PART_NUMBER_LENGTH 16
+
+#define EEPROM_VENDOR_REVISION_START_IDX 184
+#define EEPROM_VENDOR_REVISION_LENGTH 2
+
+#define EEPROM_DOWNSTREAM_WAVELENGTH_START_IDX 186
+#define EEPROM_DOWNSTREAM_WAVELENGTH_LENGTH 2
+#define EEPROM_WAVELENGTH_RESOLUTION 0.05
+
+// Define valid values below in case of Combo PON Trx is supported
+// #define EEPROM_DOWNSTREAM_SECONDARY_WAVELENGTH_START_IDX 120
+// #define EEPROM_DOWNSTREAM_SECONDARY_WAVELENGTH_LENGTH 2
+
+
+class PonTrx: public PonTrxBase {
+   // override the base member functions if you need a different implementation
+   public:
+      // Get MAC System mode based on the olt mac id and the set of SFP IDs provided
+      pair<bcmolt_system_mode, bool> get_mac_system_mode(int, set<int>);
+
+};
 
 #endif
diff --git a/agent/device/sim/vendor.cc b/agent/device/sim/vendor.cc
index 86836ff..7e68606 100644
--- a/agent/device/sim/vendor.cc
+++ b/agent/device/sim/vendor.cc
@@ -18,4 +18,4 @@
 
 void vendor_init()
 {
-}
+}
\ No newline at end of file
diff --git a/agent/device/sim/vendor.h b/agent/device/sim/vendor.h
index 1dbc9cd..3fab2a6 100644
--- a/agent/device/sim/vendor.h
+++ b/agent/device/sim/vendor.h
@@ -16,6 +16,9 @@
 
 #ifndef __VENDOR_H__
 #define __VENDOR_H__
+
+#include "device.h"
+
 #define VENDOR_ID "ONF"
 #define SIM
 #define MODEL_ID  "sim"
@@ -44,4 +47,63 @@
 
 #define MAC_DEVICE_ACTIVATION_DELAY 200000 // in microseconds
 
+#define DEFAULT_MAC_SYSTEM_MODE BCMOLT_SYSTEM_MODE_GPON__16_X
+//#define DEFAULT_MAC_SYSTEM_MODE BCMOLT_SYSTEM_MODE_XGS__2_X
+#define DEFAULT_PON_MODE BCMOLT_PON_TYPE_GPON
+// #define DEFAULT_PON_MODE BCMOLT_PON_TYPE_XGPON
+
+
+///////////////////////////////////////////////////////
+// Constants relevant for decoding PON Trx EEPROM Data
+
+#define DYNAMIC_PON_TRX_SUPPORT
+
+#define TOTAL_PON_TRX_PORTS 16 // total PON transceiver ports
+#define TOTAL_PON_PORTS 16 // total PON ports (we could have up to 2 PON ports on the OLT MAC mapped to the external PON Trx)
+const int trx_port_to_pon_port_map[TOTAL_PON_TRX_PORTS][TOTAL_PON_PORTS/TOTAL_PON_TRX_PORTS]={{0},{1},{2},{3},{4},{5},{6},{7},{8},{9},{10},
+{11},{12},{13},{14},{15}};
+#define PONS_PER_TRX (TOTAL_PON_TRX_PORTS/TOTAL_PON_PORTS) // if there are more than one OLT MAC device,
+                                                           // they all have to be of the same type for this to work.
+
+const int bus_index[TOTAL_PON_TRX_PORTS] = {
+   47,  48,  37,  38,  35,  36,  33,  34,
+   39,  40,  41,  42,  43,  44,  45,  46
+};
+
+#define PORT_ADDRESS 50
+
+#define NAME_EEPROM "sfp_eeprom"
+
+#define EEPROM_VENDOR_NAME_START_IDX 148
+#define EEPROM_VENDOR_NAME_LENGTH 16
+
+#define EEPROM_VENDOR_OUI_START_IDX 165
+#define EEPROM_VENDOR_OUI_LENGTH 3
+
+#define EEPROM_VENDOR_PART_NUMBER_START_IDX 168
+#define EEPROM_VENDOR_PART_NUMBER_LENGTH 16
+
+#define EEPROM_VENDOR_REVISION_START_IDX 184
+#define EEPROM_VENDOR_REVISION_LENGTH 2
+
+#define EEPROM_DOWNSTREAM_WAVELENGTH_START_IDX 186
+#define EEPROM_DOWNSTREAM_WAVELENGTH_LENGTH 2
+#define EEPROM_WAVELENGTH_RESOLUTION 0.05
+
+// Define valid values below in case of Combo PON Trx is supported
+// #define EEPROM_DOWNSTREAM_SECONDARY_WAVELENGTH_START_IDX 120
+// #define EEPROM_DOWNSTREAM_SECONDARY_WAVELENGTH_LENGTH 2
+
+///////////////////////////////////////////////////////
+
+
+class PonTrx: public PonTrxBase {
+   public:
+      // override the base member functions if you need a different implementation
+      PonTrx(): PonTrxBase("sfp_eeprom", 50, "%d-00%d/%s") {
+
+      }
+
+};
+
 #endif