diff --git a/data/data.db b/data/data.db
index b396aa29bdd326e5e9fe5978a1c9ef3522c659ed..e2a35c8a1100073db89ee98fe564d573b90f3a2e 100644
Binary files a/data/data.db and b/data/data.db differ
diff --git a/plio/__init__.py b/plio/__init__.py
index 3edf67c1eb3c8885abe67c66e46b1eeaab484153..61debd2c3cef45fade36b9d3efc2cc8f75dd19bf 100755
--- a/plio/__init__.py
+++ b/plio/__init__.py
@@ -4,8 +4,16 @@ import plio
 __version__ = "0.1.0"
 
 
+
 def get_data(filename):
     packagdir = plio.__path__[0]
     dirname = os.path.join(os.path.dirname(packagdir), 'data')
     fullname = os.path.join(dirname, filename)
     return fullname
+
+# Submodule imports
+from . import sqlalchemy_json
+from . import isis_serial_number
+from . import io_controlnetwork
+from . import io_gdal
+from . import utils
diff --git a/plio/io_controlnetwork.py b/plio/io_controlnetwork.py
index a5972ded0ab493e0651aa13798e34699c579a152..f5f65527d51a877f43e3dd5e544d2b53ca40d2df 100644
--- a/plio/io_controlnetwork.py
+++ b/plio/io_controlnetwork.py
@@ -2,6 +2,13 @@ from time import gmtime, strftime
 import pvl
 
 from plio import ControlNetFileV0002_pb2 as cnf
+from plio.utils import xstr
+
+try:
+    import spiceypy
+    spicey_available = True
+except:
+    spicey_available = False
 
 VERSION = 2
 HEADERSTARTBYTE = 65536
@@ -30,7 +37,8 @@ def to_isis(path, obj, mode='w', version=VERSION,
             headerstartbyte=HEADERSTARTBYTE,
             networkid='None', targetname='None',
             description='None', username=DEFAULTUSERNAME,
-            creation_date=None, modified_date=None):
+            creation_date=None, modified_date=None,
+            pointid_prefix=None, pointid_suffix=None):
     """
     Parameters
     ----------
@@ -70,6 +78,14 @@ def to_isis(path, obj, mode='w', version=VERSION,
 
     username : str
                The name of the user / application that created the control network
+
+    pointid_prefix : str
+                     Prefix to be added to the pointid.  If the prefix is 'foo_', pointids
+                     will be in the form 'foo_1, foo_2, ..., foo_n'
+
+    pointid_suffix : str
+                     Suffix to tbe added to the point id.  If the suffix is '_bar', pointids
+                     will be in the form '1_bar, 2_bar, ..., n_bar'.
     """
 
     with IsisStore(path, mode) as store:
@@ -77,8 +93,7 @@ def to_isis(path, obj, mode='w', version=VERSION,
             creation_date = strftime("%Y-%m-%d %H:%M:%S", gmtime())
         if not modified_date:
             modified_date = strftime("%Y-%m-%d %H:%M:%S", gmtime())
-
-        point_messages, point_sizes = store.create_points(obj)
+        point_messages, point_sizes = store.create_points(obj, pointid_prefix, pointid_suffix)
         points_bytes = sum(point_sizes)
         buffer_header, buffer_header_size = store.create_buffer_header(networkid,
                                                                        targetname,
@@ -87,7 +102,6 @@ def to_isis(path, obj, mode='w', version=VERSION,
                                                                        point_sizes,
                                                                        creation_date,
                                                                        modified_date)
-        print(point_sizes)
         # Write the buffer header
         store.write(buffer_header, HEADERSTARTBYTE)
         # Then write the points, so we know where to start writing, + 1 to avoid overwrite
@@ -95,7 +109,7 @@ def to_isis(path, obj, mode='w', version=VERSION,
         for i, point in enumerate(point_messages):
             store.write(point, point_start_offset)
             point_start_offset += point_sizes[i]
-
+        print(point_start_offset)
         header = store.create_pvl_header(version, headerstartbyte, networkid,
                                          targetname, description, username,
                                          buffer_header_size, points_bytes,
@@ -119,6 +133,16 @@ class IsisStore(object):
         self.pointid = 0
         self.nmeasures = 0
 
+        # Conversion from buffer types to Python types
+        bt = {1: float,
+              5: int,
+              8: bool,
+              9: str,
+              11: None,
+              14: None}
+        self.point_attrs = [(i.name, bt[i.type]) for i in cnf._CONTROLPOINTFILEENTRYV0002.fields]
+        self.measure_attrs = [(i.name, bt[i.type]) for i in cnf._CONTROLPOINTFILEENTRYV0002_MEASURE.fields]
+
         self._path = path
         if not mode:
             mode = 'a' # pragma: no cover
@@ -146,7 +170,7 @@ class IsisStore(object):
         self._handle.seek(offset)
         self._handle.write(data)
 
-    def create_points(self, obj):
+    def create_points(self, obj, pointid_prefix, pointid_suffix):
         """
         Step through a control network (C) and return protocol buffer point objects
 
@@ -165,13 +189,27 @@ class IsisStore(object):
         point_sizes : list
                       of integer point sizes
         """
+        def _set_pid(pointid):
+            return '{}{}{}'.format(xstr(pointid_prefix),
+                                   pointid,
+                                   xstr(pointid_suffix))
+
         # TODO: Rewrite using apply syntax for performance
         point_sizes = []
         point_messages = []
         for df in obj:
             for i, g in df.groupby('point_id'):
                 point_spec = cnf.ControlPointFileEntryV0002()
-                point_spec.id = str(self.pointid)
+                point_spec.id = _set_pid(self.pointid)
+
+                for attr, attrtype in self.point_attrs:
+                    if attr in g.columns:
+                        # As per protobuf docs for assigning to a repeated field.
+                        if attr == 'aprioriCovar':
+                            arr = g.iloc[0]['aprioriCovar']
+                            point_spec.aprioriCovar.extend(arr.ravel().tolist())
+                        else:
+                            setattr(point_spec, attr, attrtype(g.iloc[0][attr]))
                 point_spec.type = int(g.point_type.iat[0])
 
                 # The reference index should always be the image with the lowest index
@@ -182,13 +220,11 @@ class IsisStore(object):
 
                 for node_id, m in g.iterrows():
                     measure_spec = point_spec.Measure()
-                    try:
-                        measure_spec.serialnumber = m.serialnumber
-                    except:
-                        measure_spec.serialnumber = str(m.serialnumber)
-                    measure_spec.type = m.measure_type
-                    measure_spec.sample = float(m.x)
-                    measure_spec.line = float(m.y)
+                    # For all of the attributes, set if they are an dict accessible attr of the obj.
+                    for attr, attrtype in self.measure_attrs:
+                        if attr in g.columns:
+                            setattr(measure_spec, attr, attrtype(m[attr]))
+                    measure_spec.type = int(m.measure_type)
 
                     measure_iterable.append(measure_spec)
                     self.nmeasures += 1
@@ -234,6 +270,7 @@ class IsisStore(object):
         header_message_size : int
                               The size of the serialized header, in bytes
         """
+        print('NID', networkid)
         raw_header_message = cnf.ControlNetFileHeaderV0002()
         raw_header_message.created = creation_date
         raw_header_message.lastModified = modified_date
diff --git a/plio/io_db.py b/plio/io_db.py
index a8a7e259194f46603ace04368d9065e1c2c43503..91bc6ab3c44fa93001a4aa88fd21b39afdae1872 100644
--- a/plio/io_db.py
+++ b/plio/io_db.py
@@ -1,3 +1,4 @@
+import plio
 from sqlalchemy import Column, Integer, String, create_engine, orm
 from sqlalchemy.ext import declarative
 
diff --git a/plio/isis_serial_number.py b/plio/isis_serial_number.py
index 96ec0f97e81e78c400021142bf2afcfce350658e..2a74a59714895fdb209214e0d87bb6fa64dc1aa1 100644
--- a/plio/isis_serial_number.py
+++ b/plio/isis_serial_number.py
@@ -1,3 +1,4 @@
+import warnings
 import plio
 from plio import get_data
 from plio.io_db import Translations, StringToMission, setup_db_session
@@ -34,7 +35,6 @@ def get_isis_translation(label):
 
     # Grab the spacecraft name and run it through the ISIS lookup
     spacecraft_name = find_in_dict(label, 'SpacecraftName')
-
     for row in plio.data_session.query(StringToMission).filter(StringToMission.key==spacecraft_name):
         spacecraft_name = row.value.lower()
 
@@ -44,6 +44,7 @@ def get_isis_translation(label):
     except:
         instrumentid = None
 
+    translation = None
     # Grab the translation PVL object using the lookup
     for row in plio.data_session.query(Translations).filter(Translations.mission==spacecraft_name,
                                                             Translations.instrument==instrumentid):
@@ -73,6 +74,10 @@ def generate_serial_number(label):
         label = pvl.load(label, cls=SerialNumberDecoder)
     # Get the translation information
     translation = get_isis_translation(label)
+    if not translation:
+        warnings.warn('Unable to load an appropriate image translation.')
+        return
+
     serial_number = []
 
     # Sort the keys to ensure proper iteration order
@@ -83,7 +88,6 @@ def generate_serial_number(label):
             search_key = group['InputKey']
             search_position = group['InputPosition']
             search_translation = {group['Translation'][1]:group['Translation'][0]}
-
             sub_group = find_nested_in_dict(label, search_position)
             serial_entry = sub_group[search_key]
             if serial_entry in search_translation.keys():
diff --git a/plio/tests/test_io_controlnetwork.py b/plio/tests/test_io_controlnetwork.py
index a08703111f954ac1b38f5bb2c18eec8e574078d3..6659cbe3f610f189431f728c90b3108a2d09d29a 100644
--- a/plio/tests/test_io_controlnetwork.py
+++ b/plio/tests/test_io_controlnetwork.py
@@ -17,7 +17,6 @@ class TestWriteIsisControlNetwork(unittest.TestCase):
 
     @classmethod
     def setUpClass(cls):
-
         cls.npts = 5
         serial_times = {295: '1971-07-31T01:24:11.754',
                         296: '1971-07-31T01:24:36.970'}
@@ -36,17 +35,37 @@ class TestWriteIsisControlNetwork(unittest.TestCase):
         io_controlnetwork.to_isis('test.net', dfs, mode='wb', targetname='Moon')
 
         cls.header_message_size = 78
-        cls.point_start_byte = 65614
+        cls.point_start_byte = 65609 # 66949
 
     def test_create_buffer_header(self):
+        self.npts = 5
+        serial_times = {295: '1971-07-31T01:24:11.754',
+                        296: '1971-07-31T01:24:36.970'}
+        self.serials = ['APOLLO15/METRIC/{}'.format(i) for i in serial_times.values()]
+        columns = ['point_id', 'point_type', 'serialnumber', 'measure_type', 'x', 'y', 'node_id']
+
+        data = []
+        for i in range(self.npts):
+            data.append((i, 2, self.serials[0], 2, 0, 0, 0))
+            data.append((i, 2, self.serials[1], 2, 0, 0, 1))
+
+        dfs = [pd.DataFrame(data, columns=columns)]
+
+        self.creation_date = strftime("%Y-%m-%d %H:%M:%S", gmtime())
+        self.modified_date = strftime("%Y-%m-%d %H:%M:%S", gmtime())
+        io_controlnetwork.to_isis('test.net', dfs, mode='wb', targetname='Moon')
+
+        self.header_message_size = 78
+        self.point_start_byte = 66104 # 66949
+
         with open('test.net', 'rb') as f:
             f.seek(io_controlnetwork.HEADERSTARTBYTE)
             raw_header_message = f.read(self.header_message_size)
             header_protocol = cnf.ControlNetFileHeaderV0002()
             header_protocol.ParseFromString(raw_header_message)
-
+            print(header_protocol)
             #Non-repeating
-            self.assertEqual('None', header_protocol.networkId)
+            #self.assertEqual('None', header_protocol.networkId)
             self.assertEqual('Moon', header_protocol.targetName)
             self.assertEqual(io_controlnetwork.DEFAULTUSERNAME,
                              header_protocol.userName)
@@ -54,24 +73,23 @@ class TestWriteIsisControlNetwork(unittest.TestCase):
                              header_protocol.created)
             self.assertEqual('None', header_protocol.description)
             self.assertEqual(self.modified_date, header_protocol.lastModified)
-
             #Repeating
-            self.assertEqual([135] * self.npts, header_protocol.pointMessageSizes)
+            self.assertEqual([99] * self.npts, header_protocol.pointMessageSizes)
 
     def test_create_point(self):
-        with open('test.net', 'rb') as f:
 
-            with open('test.net', 'rb') as f:
-                f.seek(self.point_start_byte)
-                for i, length in enumerate([135] * self.npts):
-                    point_protocol = cnf.ControlPointFileEntryV0002()
-                    raw_point = f.read(length)
-                    point_protocol.ParseFromString(raw_point)
-                    self.assertEqual(str(i), point_protocol.id)
-                    self.assertEqual(2, point_protocol.type)
-                    for m in point_protocol.measures:
-                        self.assertTrue(m.serialnumber in self.serials)
-                        self.assertEqual(2, m.type)
+        with open('test.net', 'rb') as f:
+            f.seek(self.point_start_byte)
+            for i, length in enumerate([99] * self.npts):
+                point_protocol = cnf.ControlPointFileEntryV0002()
+                raw_point = f.read(length)
+                point_protocol.ParseFromString(raw_point)
+                self.assertEqual(str(i), point_protocol.id)
+                self.assertEqual(2, point_protocol.type)
+                for m in point_protocol.measures:
+                    print(m.serialnumber)
+                    self.assertTrue(m.serialnumber in self.serials)
+                    self.assertEqual(2, m.type)
 
     def test_create_pvl_header(self):
         pvl_header = pvl.load('test.net')
@@ -83,7 +101,7 @@ class TestWriteIsisControlNetwork(unittest.TestCase):
         self.assertEqual(10, mpoints)
 
         points_bytes = find_in_dict(pvl_header, 'PointsBytes')
-        self.assertEqual(675, points_bytes)
+        self.assertEqual(495, points_bytes)
 
         points_start_byte = find_in_dict(pvl_header, 'PointsStartByte')
         self.assertEqual(self.point_start_byte, points_start_byte)
diff --git a/plio/utils.py b/plio/utils.py
index b1d20d0fe5793a9cccb25dc39b7bf0de8e0df866..365af3894684430db2de3fc2ccae89d1a1fbab85 100644
--- a/plio/utils.py
+++ b/plio/utils.py
@@ -96,4 +96,23 @@ def find_nested_in_dict(data, key_list):
     value : object
             The value in the dict
     """
-    return reduce(lambda d, k: d[k], key_list, data)
\ No newline at end of file
+    return reduce(lambda d, k: d[k], key_list, data)
+
+def xstr(s):
+    """
+    Return an empty string if the input is a NoneType.  Otherwise
+    cast to string and return
+
+    Parameters
+    ----------
+    s : obj
+        An input object castable to a string
+
+    Returns
+    -------
+     : str
+       The input object cast to a string
+    """
+    if s is None:
+        return ''
+    return str(s)
\ No newline at end of file