byte getflags(ODentry od)
        {
            byte flags = 0;

            //aways return 0 for REC objects as CO_OD_getDataPointer() uses this to pickup the details
            if (od.objecttype == ObjectType.REC)
            {
                return(0);
            }

            flags = (byte)od.location;

            //fixme rwr and rrw are not supported
            if (od.accesstype == EDSsharp.AccessType.ro ||
                od.accesstype == EDSsharp.AccessType.rw ||
                od.accesstype == EDSsharp.AccessType.@const)
            {
                flags |= 0x04;
            }

            if (od.accesstype == EDSsharp.AccessType.wo ||
                od.accesstype == EDSsharp.AccessType.rw)
            {
                flags |= 0x08;
            }

            if (od.PDOMapping)
            {
                flags |= 0x10;
            }

            if (od.PDOMapping)
            {
                flags |= 0x20;
            }

            if (od.PDOMapping)
            {
                flags |= 0x30; //fix me no control over rx and tx mapping, its both or none
            }
            if (od.TPDODetectCos)
            {
                flags |= 0x40;
            }

            int datasize = od.sizeofdatatype();

            if (datasize > 1)
            {
                flags |= 0x80;
            }

            return(flags);
        }
        private void export_c()
        {
            StreamWriter file = new StreamWriter(folderpath + Path.DirectorySeparatorChar + "CO_OD.c");

            addGPLheader(file);

            file.WriteLine(@"#include ""CO_driver.h""
#include ""CO_OD.h""
#include ""CO_SDO.h""


/*******************************************************************************
   DEFINITION AND INITIALIZATION OF OBJECT DICTIONARY VARIABLES
*******************************************************************************/

/***** Definition for RAM variables *******************************************/
struct sCO_OD_RAM CO_OD_RAM = {
           CO_OD_FIRST_LAST_WORD,
");

            export_OD_def_array(file, StorageLocation.RAM);

            file.WriteLine(@"
           CO_OD_FIRST_LAST_WORD,
};

/***** Definition for EEPROM variables ****************************************/
struct sCO_OD_EEPROM CO_OD_EEPROM = {
           CO_OD_FIRST_LAST_WORD,
");


            export_OD_def_array(file, StorageLocation.EEPROM);

            file.WriteLine(@"  CO_OD_FIRST_LAST_WORD,
};


/***** Definition for ROM variables *******************************************/
struct sCO_OD_ROM CO_OD_ROM = {    //constant variables, stored in flash
           CO_OD_FIRST_LAST_WORD,

");


            export_OD_def_array(file, StorageLocation.ROM);

            file.WriteLine(@"

           CO_OD_FIRST_LAST_WORD
};


/*******************************************************************************
   STRUCTURES FOR RECORD TYPE OBJECTS
*******************************************************************************/

");

            export_record_types(file);

            file.Write(@"/*******************************************************************************
   OBJECT DICTIONARY
*******************************************************************************/
const CO_OD_entry_t CO_OD[");


            file.Write(string.Format("{0}", enabledcount));

            file.WriteLine(@"] = {
");

            bool arrayspecialcase = false;
            int  count            = 0;

            foreach (KeyValuePair <UInt16, ODentry> kvp in eds.ods)
            {
                ODentry od = kvp.Value;

                if (od.Disabled == true)
                {
                    continue;
                }

                string loc = getlocation(od.location);

                byte flags = getflags(od);

                DataType t        = eds.getdatatype(od);
                int      datasize = od.sizeofdatatype();

                string odf;

                if (od.AccessFunctionName != null)
                {
                    odf = od.AccessFunctionName;
                }
                else
                {
                    odf = "CO_ODF";
                }

                string array = "";

                //only needed for array objects
                if (od.objecttype == ObjectType.ARRAY && od.nosubindexes > 0)
                {
                    array = string.Format("[0]");
                }


                if (arrayspecial(od.index, true))
                {
                    arrayspecialcase = true;
                    count            = 0;
                }

                if (arrayspecialcase)
                {
                    array = string.Format("[{0}]", count);
                    count++;
                }

                //Arrays and Recs have 1 less subindex than actually present in the od.subobjects
                int nosubindexs = od.nosubindexes;
                if (od.objecttype == ObjectType.ARRAY || od.objecttype == ObjectType.REC)
                {
                    if (nosubindexs > 0)
                    {
                        nosubindexs--;
                    }
                }

                //Arrays really should obey the max subindex paramater not the physical number of elements
                if (od.objecttype == ObjectType.ARRAY)
                {
                    if ((od.getmaxsubindex() != nosubindexs) && od.index != 0x1003) //ignore this warning on 0x1003 it is a special case
                    {
                        Warnings.warning_list.Add(String.Format("Subindex discrepancy on object 0x{0:x4} arraysize: {1} vs max-subindex: {2}", od.index, nosubindexs, od.getmaxsubindex()));
                    }
                    nosubindexs = od.getmaxsubindex();
                }

                string pdata; //CO_OD_entry_t pData generator

                if (od.objecttype == ObjectType.REC)
                {
                    pdata = string.Format("&OD_record{0:x4}", od.index);
                }
                else
                {
                    pdata = string.Format("&{0}.{1}{2}", loc, make_cname(od.parameter_name), array);
                }

                if ((od.objecttype == ObjectType.VAR || od.objecttype == ObjectType.ARRAY) && od.datatype == DataType.DOMAIN)
                {
                    //NB domain MUST have a data pointer of 0, can open node requires this and makes checks
                    //against null to determine this is a DOMAIN type.
                    pdata = "0";
                }

                file.WriteLine(string.Format("{{0x{0:x4}, 0x{1:x2}, 0x{2:x2}, {3}, (void*){4}}},", od.index, nosubindexs, flags, datasize, pdata));

                if (arrayspecial(od.index, false))
                {
                    arrayspecialcase = false;
                }
            }



            file.WriteLine("};");

            file.Close();
        }
        private void print_h_bylocation(StreamWriter file, StorageLocation location)
        {
            string lastname = "";
            //pre walk the list to find groups for arrays

            Dictionary <string, int> au = new Dictionary <string, int>();

            foreach (KeyValuePair <UInt16, ODentry> kvp in eds.ods)
            {
                ODentry od = kvp.Value;
                if (od.Disabled == true)
                {
                    continue;
                }

                string name = make_cname(od.parameter_name);
                if (au.ContainsKey(name))
                {
                    au[name]++;
                }
                else
                {
                    au[name] = 1;
                }
            }

            foreach (KeyValuePair <UInt16, ODentry> kvp in eds.ods)
            {
                ODentry od = kvp.Value;

                if (od.Disabled == true)
                {
                    continue;
                }

                if ((od.location != location))
                {
                    if (!(od.location == 0 && location == StorageLocation.RAM))
                    {
                        continue;
                    }
                }


                if (od.nosubindexes == 0)
                {
                    string specialarraylength = "";
                    if (od.datatype == DataType.VISIBLE_STRING || od.datatype == DataType.OCTET_STRING)
                    {
                        specialarraylength = string.Format("[{0}]", od.sizeofdatatype());
                    }

                    file.WriteLine(string.Format("/*{0:x4}      */ {1,-15} {2}{3};", od.index, od.datatype.ToString(), make_cname(od.parameter_name), specialarraylength));
                }
                else
                {
                    DataType t = eds.getdatatype(od);


                    //If it not a defined type, and it probably is not for a REC, we must generate a name, this is
                    //related to the previous code that generated the actual structures.

                    string objecttypewords = "";

                    switch (od.objecttype)
                    {
                    case ObjectType.REC:
                        objecttypewords = String.Format("OD_{0}_t", make_cname(od.parameter_name));
                        break;

                    case ObjectType.ARRAY:
                        objecttypewords = t.ToString();     //this case is handled by the logic in eds.getdatatype();
                        break;

                    default:
                        objecttypewords = t.ToString();
                        break;
                    }

                    string name = make_cname(od.parameter_name);
                    if (au[name] > 1)
                    {
                        if (lastname == name)
                        {
                            continue;
                        }
                        lastname = name;
                        file.WriteLine(string.Format("/*{0:x4}      */ {1,-15} {2}[{3}];", od.index, objecttypewords, make_cname(od.parameter_name), au[name]));
                    }
                    else
                    {
                        //Don't put sub indexes on record type in h file unless there are multiples of the same
                        //in which case its not handleded here, we need a special case for the predefined special
                        //values that arrayspecial() checks for, to generate 1 element arrays if needed
                        if (od.objecttype == ObjectType.REC)
                        {
                            if (arrayspecial(od.index, true))
                            {
                                file.WriteLine(string.Format("/*{0:x4}      */ {1,-15} {2}[1];", od.index, objecttypewords, make_cname(od.parameter_name)));
                            }
                            else
                            {
                                file.WriteLine(string.Format("/*{0:x4}      */ {1,-15} {2};", od.index, objecttypewords, make_cname(od.parameter_name)));
                            }
                        }
                        else
                        {
                            file.WriteLine(string.Format("/*{0:x4}      */ {1,-15} {2}[{3}];", od.index, objecttypewords, make_cname(od.parameter_name), od.nosubindexes - 1));
                        }
                    }
                }
            }
        }
        private void export_h()
        {
            StreamWriter file = new StreamWriter(folderpath + Path.DirectorySeparatorChar + "CO_OD.h");


            addGPLheader(file);

            file.WriteLine("#pragma once");
            file.WriteLine("");

            file.WriteLine(@"/*******************************************************************************
   CANopen DATA DYPES
*******************************************************************************/
   typedef uint8_t      UNSIGNED8;
   typedef uint16_t     UNSIGNED16;
   typedef uint32_t     UNSIGNED32;
   typedef uint64_t     UNSIGNED64;
   typedef int8_t       INTEGER8;
   typedef int16_t      INTEGER16;
   typedef int32_t      INTEGER32;
   typedef int64_t      INTEGER64;
   typedef float32_t    REAL32; 
   typedef float64_t    REAL64; 
   typedef char_t       VISIBLE_STRING;
   typedef oChar_t      OCTET_STRING;
   typedef domain_t     DOMAIN;

");

            file.WriteLine("/*******************************************************************************");
            file.WriteLine("   FILE INFO:");
            file.WriteLine(string.Format("      FileName:     {0}", eds.fi.FileName));
            file.WriteLine(string.Format("      FileVersion:  {0}", eds.fi.FileVersion));
            file.WriteLine(string.Format("      CreationTime: {0}", eds.fi.CreationTime));
            file.WriteLine(string.Format("      CreationDate: {0}", eds.fi.CreationDate));
            file.WriteLine(string.Format("      CreatedBy:    {0}", eds.fi.CreatedBy));
            file.WriteLine("******************************************************************************/");
            file.WriteLine("");
            file.WriteLine("");

            file.WriteLine("/*******************************************************************************");
            file.WriteLine("   DEVICE INFO:");
            file.WriteLine(string.Format("      VendorName:     {0}", eds.di.VendorName));
            file.WriteLine(string.Format("      VendorNumber    {0}", eds.di.VendorNumber));
            file.WriteLine(string.Format("      ProductName:    {0}", eds.di.ProductName));
            file.WriteLine(string.Format("      ProductNumber:  {0}", eds.di.ProductNumber));
            file.WriteLine("******************************************************************************/");
            file.WriteLine("");
            file.WriteLine("");


            file.WriteLine(@"/*******************************************************************************
   FEATURES
*******************************************************************************/");

            file.WriteLine(string.Format("  #define CO_NO_SYNC                     {0}   //Associated objects: 1005-1007", noSYNC));

            file.WriteLine(string.Format("  #define CO_NO_EMERGENCY                {0}   //Associated objects: 1014, 1015", noEMCY));

            file.WriteLine(string.Format("  #define CO_NO_SDO_SERVER               {0}   //Associated objects: 1200-127F", noSDOservers));
            file.WriteLine(string.Format("  #define CO_NO_SDO_CLIENT               {0}   //Associated objects: 1280-12FF", noSDOclients));

            file.WriteLine(string.Format("  #define CO_NO_RPDO                     {0}   //Associated objects: 14xx, 16xx", noRXpdos));
            file.WriteLine(string.Format("  #define CO_NO_TPDO                     {0}   //Associated objects: 18xx, 1Axx", noTXpdos));


            bool ismaster = false;

            if (eds.ods.ContainsKey(0x1f80))
            {
                ODentry master = eds.ods[0x1f80];

                // we could do with a cut down function that returns a value rather than a string
                string meh = formatvaluewithdatatype(master.defaultvalue, master.datatype);
                meh = meh.Replace("L", "");

                UInt32 NMTStartup = Convert.ToUInt32(meh, 16);
                if ((NMTStartup & 0x01) == 0x01)
                {
                    ismaster = true;
                }
            }

            file.WriteLine(string.Format("  #define CO_NO_NMT_MASTER               {0}", ismaster == true?1:0));
            file.WriteLine("");
            file.WriteLine("");
            file.WriteLine(@"/*******************************************************************************
   OBJECT DICTIONARY
*******************************************************************************/");

            file.WriteLine(string.Format("   #define CO_OD_NoOfElements             {0}", enabledcount));
            file.WriteLine("");
            file.WriteLine("");

            file.WriteLine(@"/*******************************************************************************
   TYPE DEFINITIONS FOR RECORDS
*******************************************************************************/");

            //We need to identify all the record types used and generate a struct for each one
            //FIXME the original CanOpenNode exporter said how many items used this struct in the comments

            List <string> structnamelist = new List <string>();

            foreach (KeyValuePair <UInt16, ODentry> kvp in eds.ods)
            {
                ODentry od = kvp.Value;

                if (od.objecttype != ObjectType.REC)
                {
                    continue;
                }

                string structname = String.Format("OD_{0}_t", make_cname(od.parameter_name));

                if (structnamelist.Contains(structname))
                {
                    continue;
                }

                structnamelist.Add(structname);

                file.WriteLine(string.Format("/*{0:x4}    */ typedef struct {{", kvp.Key));
                foreach (KeyValuePair <UInt16, ODentry> kvp2 in kvp.Value.subobjects)
                {
                    string paramaterarrlen = "";

                    ODentry subod = kvp2.Value;

                    if (subod.datatype == DataType.VISIBLE_STRING || subod.datatype == DataType.OCTET_STRING)
                    {
                        paramaterarrlen = String.Format("[{0}]", subod.sizeofdatatype());
                    }

                    file.WriteLine(string.Format("               {0,-15}{1}{2};", subod.datatype.ToString(), make_cname(subod.parameter_name), paramaterarrlen));
                }

                file.WriteLine(string.Format("               }}              {0};", structname));
            }



            file.WriteLine(@"/*******************************************************************************
   STRUCTURES FOR VARIABLES IN DIFFERENT MEMORY LOCATIONS
*******************************************************************************/
#define  CO_OD_FIRST_LAST_WORD     0x55 //Any value from 0x01 to 0xFE. If changed, EEPROM will be reinitialized.

/***** Structure for RAM variables ********************************************/
struct sCO_OD_RAM{
               UNSIGNED32     FirstWord;
");

            print_h_bylocation(file, StorageLocation.RAM);

            file.WriteLine(@"
               UNSIGNED32     LastWord;
};");

            file.WriteLine(@"/***** Structure for EEPROM variables *****************************************/
struct sCO_OD_EEPROM{
               UNSIGNED32     FirstWord;


");
            print_h_bylocation(file, StorageLocation.EEPROM);

            file.WriteLine(@"
               UNSIGNED32     LastWord;
};");

            file.WriteLine(@"/***** Structure for ROM variables ********************************************/
struct sCO_OD_ROM{
               UNSIGNED32     FirstWord;


");
            print_h_bylocation(file, StorageLocation.ROM);

            file.WriteLine(@"
               UNSIGNED32     LastWord;
};");


            file.WriteLine(@"/***** Declaration of Object Dictionary variables *****************************/
extern struct sCO_OD_RAM CO_OD_RAM;

extern struct sCO_OD_EEPROM CO_OD_EEPROM;

extern struct sCO_OD_ROM CO_OD_ROM;


/*******************************************************************************
   ALIASES FOR OBJECT DICTIONARY VARIABLES
*******************************************************************************/");

            List <string> constructed_rec_types = new List <string>();

            foreach (KeyValuePair <UInt16, ODentry> kvp in eds.ods)
            {
                ODentry od = kvp.Value;

                if (od.Disabled == true)
                {
                    continue;
                }

                string loc = getlocation(od.location);

                DataType t = eds.getdatatype(od);


                switch (od.objecttype)
                {
                default:
                {
                    file.WriteLine(string.Format("/*{0:x4}, Data Type: {1} */", od.index, t.ToString()));
                    file.WriteLine(string.Format("        #define {0,-51} {1}.{2}", string.Format("OD_{0}", make_cname(od.parameter_name)), loc, make_cname(od.parameter_name)));

                    DataType dt = od.datatype;

                    if (dt == DataType.OCTET_STRING || dt == DataType.VISIBLE_STRING)
                    {
                        file.WriteLine(string.Format("        #define {0,-51} {1}", string.Format("ODL_{0}_stringLength", make_cname(od.parameter_name)), od.sizeofdatatype()));
                    }
                    file.WriteLine("");
                }
                break;

                case ObjectType.ARRAY:
                {
                    DataType dt = od.datatype;

                    file.WriteLine(string.Format("/*{0:x4}, Data Type: {1}, Array[{2}] */", od.index, t.ToString(), od.nosubindexes - 1));
                    file.WriteLine(string.Format("        #define OD_{0,-48} {1}.{2}", make_cname(od.parameter_name), loc, make_cname(od.parameter_name)));
                    file.WriteLine(string.Format("        #define {0,-51} {1}", string.Format("ODL_{0}_arrayLength", make_cname(od.parameter_name)), od.nosubindexes - 1));


                    List <string> ODAs = new List <string>();

                    string ODAout = "";

                    foreach (KeyValuePair <UInt16, ODentry> kvp2 in od.subobjects)
                    {
                        ODentry sub = kvp2.Value;

                        if (sub.subindex == 0)
                        {
                            continue;
                        }

                        string ODA = string.Format("{0}", string.Format("ODA_{0}_{1}", make_cname(od.parameter_name), make_cname(sub.parameter_name)));

                        if (ODAs.Contains(ODA))
                        {
                            continue;
                        }

                        ODAs.Add(ODA);

                        //Arrays do not have a size in the raw CO objects, Records do
                        //so offset by one
                        if (od.objecttype == ObjectType.ARRAY)
                        {
                            ODAout += (string.Format("        #define {0,-51} {1}\r\n", string.Format("ODA_{0}_{1}", make_cname(od.parameter_name), make_cname(sub.parameter_name)), sub.subindex - 1));
                        }
                        else
                        {
                            ODAout += (string.Format("        #define {0,-51} {1}\r\n", string.Format("ODA_{0}_{1}", make_cname(od.parameter_name), make_cname(sub.parameter_name)), sub.subindex));
                        }
                    }

                    file.Write(ODAout);
                    file.WriteLine("");
                }
                break;

                case ObjectType.REC:
                {
                    string rectype = make_cname(od.parameter_name);

                    if (!constructed_rec_types.Contains(rectype))
                    {
                        file.WriteLine(string.Format("/*{0:x4}, Data Type: {1}_t */", od.index, rectype));
                        file.WriteLine(string.Format("        #define {0,-51} {1}.{2}", string.Format("OD_{0}", rectype), loc, rectype));
                        constructed_rec_types.Add(rectype);
                        file.WriteLine("");
                    }
                }
                break;
                }
            }

            file.Close();
        }
        void export_record_types(StreamWriter file)
        {
            bool arrayopen  = false;
            int  arrayindex = 0;

            foreach (KeyValuePair <UInt16, ODentry> kvp in eds.ods)
            {
                ODentry od = kvp.Value;

                if (od.objecttype != ObjectType.REC)
                {
                    continue;
                }

                if (od.Disabled == true)
                {
                    continue;
                }

                int count = od.subobjects.Count; //don't include index

                if (od.index >= 0x1400 && od.index < 0x1600)
                {
                    count = 3; //CanOpenNode Fudging. Its only 3 paramaters for RX PDOS in the c code despite being a PDO_COMMUNICATION_PARAMETER
                }

                string cname = make_cname(od.parameter_name);

                file.WriteLine(String.Format("/*0x{0:x4}*/ const CO_OD_entryRecord_t OD_record{0:x4}[{1}] = {{", od.index, count));

                string arrayaccess = "";

                if (arrayspecial(od.index, true) || arrayopen)
                {
                    arrayaccess = string.Format("[{0}]", arrayindex);
                    arrayindex++;
                    arrayopen = true;
                }


                foreach (KeyValuePair <UInt16, ODentry> kvpsub in od.subobjects)
                {
                    ODentry sub = kvpsub.Value;

                    string subcname = make_cname(sub.parameter_name);

                    if (sub.datatype != DataType.DOMAIN)
                    {
                        file.WriteLine(string.Format("           {{(void*)&{5}.{0}{4}.{1}, 0x{2:x2}, 0x{3} }},", cname, subcname, getflags(sub), sub.sizeofdatatype(), arrayaccess, getlocation(od.location)));
                    }
                    else
                    {
                        //Domain type MUST have its data pointer set to 0 for CanOpenNode
                        file.WriteLine(string.Format("           {{(void*)0, 0x{2:x2}, 0x{3} }},", cname, subcname, getflags(sub), sub.sizeofdatatype(), arrayaccess, getlocation(od.location)));
                    }
                }


                if (arrayspecial(od.index, false))
                {
                    arrayindex = 0;
                    arrayopen  = false;
                }

                file.Write("};\r\n\r\n");
            }
        }
        void listView_TXCOBmap_onComboBoxIndexChanged(int row, int col, string Text)
        {
            //row+0x1a00 will be the slot to adjust

            eds.dirty = true;

            UInt16  slot   = (UInt16)(0x200 + Convert.ToUInt16(listView_TXCOBmap.Items[row].SubItems[1].Text, 16));
            ODentry slotod = eds.ods[slot];

            //Now rebuild the entire slot working out data size as we go

            for (byte p = 1; p < slotod.subobjects.Count; p++)
            {
                slotod.subobjects[p].defaultvalue = "0x00000000";
            }

            byte subcount        = 1;
            int  totaldatalength = 0;

            ListViewItem item = listView_TXCOBmap.Items[row];

            foreach (ListViewItem.ListViewSubItem subitem in item.SubItems)
            {
                if (subitem.Text == "" || subitem.Text == " - " || subitem.Text == "   ")
                {
                    continue;
                }

                string[] bits = subitem.Text.Split('/');
                if (bits.Length != 3) //ignore the first column
                {
                    continue;
                }
                UInt16 index = Convert.ToUInt16(bits[0], 16);
                Byte   sub   = Convert.ToByte(bits[1], 16);


                int datalength = 0;

                if (index >= 0x002 && index <= 0x007)
                {
                    //the dummy objects
                    switch (index)
                    {
                    case 0x002:
                        datalength = 8;
                        break;

                    case 0x003:
                        datalength = 16;
                        break;

                    case 0x004:
                        datalength = 32;
                        break;

                    case 0x005:
                        datalength = 8;
                        break;

                    case 0x006:
                        datalength = 16;
                        break;

                    case 0x007:
                        datalength = 32;
                        break;
                    }
                }
                else
                {
                    ODentry od = eds.ods[index];
                    if (sub != 0)
                    {
                        od = od.subobjects[sub];
                    }

                    //fixme for non basic types will this work?? i think
                    //its not even allowed for PDO but need trap in code to
                    //prevent this and throw error here
                    datalength = 8 * od.sizeofdatatype();
                }

                totaldatalength += datalength;

                if (totaldatalength > 64)
                {
                    MessageBox.Show(String.Format("Too much data in TX PDO {0}", slotod.index));
                    break;
                }

                string value = string.Format("0x{0:x4}{1:x2}{2:x2}", index, sub, datalength);

                if (subcount >= slotod.subobjects.Count())
                {
                    MessageBox.Show("PDO Mapping array is too small, please add more elements in OD editor");
                    break;
                }

                slotod.subobjects[subcount].defaultvalue = value;

                subcount++;
            }

            //write out the number of objects used into the sub object count [0]
            slotod.subobjects[0].defaultvalue = string.Format("{0}", subcount - 1);

            updatePDOinfo();
            doUpdateOD();
        }
        void updatePDOTXslot(ODentry od, int row)
        {
            UInt16 idx = (UInt16)(od.index + 0x200);

            if (!eds.ods.ContainsKey(idx))
            {
                return;
            }

            ODentry oddef = eds.ods[idx];

            int byteoff = 0;

            foreach (KeyValuePair <UInt16, ODentry> kvp in oddef.subobjects)
            {
                if (byteoff >= 8)
                {
                    continue;
                }

                ODentry sub = kvp.Value;
                if (sub.subindex == 0)
                {
                    continue;
                }

                UInt32 data = 0;
                if (sub.defaultvalue != "")
                {
                    data = Convert.ToUInt32(sub.defaultvalue, EDSsharp.getbase(sub.defaultvalue));
                }

                if (data == 0)
                {
                    listView_TXCOBmap.AddComboBoxCell(row, byteoff + 2, TXchoices);
                    listView_TXCOBmap.Items[row].SubItems[byteoff + 2].Text = "empty";
                    byteoff++;
                    continue;
                }

                //format is 0x6000 01 08
                byte   datasize = (byte)(data & 0x000000FF);
                UInt16 pdoindex = (UInt16)((data >> 16) & 0x0000FFFF);
                byte   pdosub   = (byte)((data >> 8) & 0x000000FF);

                //sanity check the real OD against the mapping parameters section

                bool mappingfail = true;
                if (eds.ods.ContainsKey(pdoindex) && (pdosub == 0 || eds.ods[pdoindex].containssubindex(pdosub)))
                {
                    ODentry maptarget;
                    if (pdosub == 0)
                    {
                        maptarget = eds.ods[pdoindex];
                    }
                    else
                    {
                        maptarget = eds.ods[pdoindex].getsubobject(pdosub);
                    }

                    if (maptarget.Disabled == false && datasize == (8 * maptarget.sizeofdatatype()))
                    {
                        mappingfail = false;
                    }

                    if (mappingfail == true)
                    {
                        MessageBox.Show(String.Format("PDO mapping failed for object 0x{0:x4}/{1:x2}\nplease manaully check the PDO mapping in the TX and RX PDO tabs\n as it does not agree with the mapping paramater 0x{2:x4}/{3:x2}\nThis can occur if you edit objects that are already mapped", pdoindex, pdosub, idx, sub.subindex));
                    }
                }

                String target      = "";
                int    PDOdatasize = 0;

                //dummy objects
                if (pdoindex >= 0x0002 && pdoindex <= 0x007)
                {
                    //the dummy objects
                    switch (pdoindex)
                    {
                    case 0x002:
                        target      = "0x0002/00/Dummy Int8";
                        PDOdatasize = 1;
                        break;

                    case 0x003:
                        target      = "0x0003/00/Dummy Int16";
                        PDOdatasize = 2;
                        break;

                    case 0x004:
                        target      = "0x0004/00/Dummy Int32";
                        PDOdatasize = 4;
                        break;

                    case 0x005:
                        target      = "0x0005/00/Dummy UInt8";
                        PDOdatasize = 1;
                        break;

                    case 0x006:
                        target      = "0x0006/00/Dummy UInt16";
                        PDOdatasize = 2;
                        break;

                    case 0x007:
                        target      = "0x0007/00/Dummy UInt32";
                        PDOdatasize = 4;
                        break;
                    }

                    if (PDOdatasize == 0)
                    {
                        continue;
                    }
                }
                else
                {
                    //fixme sanity checking here please
                    if (!eds.ods.ContainsKey(pdoindex))
                    {
                        continue;
                    }

                    ODentry targetod = eds.ods[pdoindex];

                    if (pdosub != 0)
                    {
                        //FIXME direct sub array access, unprotected and will fault with holes in range
                        targetod = targetod.subobjects[pdosub];
                    }

                    target      = String.Format("0x{0:x4}/{1:x2}/", targetod.index, targetod.subindex) + targetod.parameter_name;
                    PDOdatasize = targetod.sizeofdatatype();
                }


                listView_TXCOBmap.AddComboBoxCell(row, byteoff + 2, TXchoices);
                listView_TXCOBmap.Items[row].SubItems[byteoff + 2].Text = target;

                int oldPDOdatasize = PDOdatasize;

                while (oldPDOdatasize != 1)
                {
                    listView_TXCOBmap.Items[row].SubItems[byteoff + oldPDOdatasize + 1].Text = " - ";
                    oldPDOdatasize--;
                }

                byteoff += PDOdatasize;
            }
        }
        byte getflags(ODentry od)
        {
            byte flags   = 0;
            byte mapping = 0; //mapping flags, if pdo is enabled

            //aways return 0 for REC objects as CO_OD_getDataPointer() uses this to pickup the details
            if (od.objecttype == ObjectType.REC)
            {
                return(0);
            }

            flags = (byte)od.location;

            /* some exceptions for rwr/rww. Those are entries that are always r/w via SDO transfer,
             * but can only be read -or- written via PDO */
            if (od.accesstype == EDSsharp.AccessType.ro ||
                od.accesstype == EDSsharp.AccessType.rw ||
                od.accesstype == EDSsharp.AccessType.rwr ||
                od.accesstype == EDSsharp.AccessType.rww ||
                od.accesstype == EDSsharp.AccessType.@const)
            {
                /* SDO server may read from the variable */
                flags |= 0x04;

                if (od.accesstype != EDSsharp.AccessType.rww)
                {
                    /* Variable is mappable for TPDO  */
                    mapping |= 0x20;
                }
            }
            if (od.accesstype == EDSsharp.AccessType.wo ||
                od.accesstype == EDSsharp.AccessType.rw ||
                od.accesstype == EDSsharp.AccessType.rwr ||
                od.accesstype == EDSsharp.AccessType.rww)
            {
                /* SDO server may write to the variable */
                flags |= 0x08;

                if (od.accesstype != EDSsharp.AccessType.rwr)
                {
                    /* Variable is mappable for RPDO */
                    mapping |= 0x10;
                }
            }

            if (od.PDOMapping)
            {
                flags |= mapping;
            }

            if (od.TPDODetectCos)
            {
                /* If variable is mapped to any PDO, then  is automatically send, if variable its value */
                flags |= 0x40;
            }

            int datasize = od.sizeofdatatype();

            if (datasize > 1)
            {
                /* variable is a multibyte value */
                flags |= 0x80;
            }

            return(flags);
        }