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 bool_t       BOOLEAN;
   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.lengthofstring());
                    }

                    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(@"
/*******************************************************************************
   TYPE DEFINITIONS FOR OBJECT DICTIONARY INDEXES

   some of those are redundant with CO_SDO.h CO_ObjDicId_t <Common CiA301 object 
   dictionary entries>
*******************************************************************************/");

            //FIXME how can we get rid of that redundandency?

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

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

                DataType t = eds.getdatatype(od);


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

                    file.WriteLine("");
                }
                break;

                case ObjectType.ARRAY:
                case ObjectType.REC:
                {
                    file.WriteLine(string.Format("/*{0:x4} */", od.index));
                    file.WriteLine(string.Format("        #define {0,-51} 0x{1:x4}", string.Format("OD_{0:x4}_{1}", od.index, make_cname(od.parameter_name)), od.index, t.ToString()));

                    file.WriteLine("");

                    //sub indexes
                    file.WriteLine(string.Format("        #define {0,-51} 0", string.Format("OD_{0:x4}_0_{1}_maxSubIndex", od.index, make_cname(od.parameter_name))));

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

                    string ODSIout = "";

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

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

                        string ODSI = string.Format("{0}", string.Format("OD_{0:x4}_{1}_{2}_{3}", od.index, sub.subindex, make_cname(od.parameter_name), make_cname(sub.parameter_name)));

                        if (ODSIs.Contains(ODSI))
                        {
                            continue;
                        }

                        ODSIs.Add(ODSI);

                        ODSIout += (string.Format("        #define {0,-51} {1}\r\n", ODSI, sub.subindex));
                    }

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

            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.lengthofstring()));
                    }
                    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();
        }
        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;
                if (od.datatype == DataType.VISIBLE_STRING || od.datatype == DataType.OCTET_STRING || od.datatype == DataType.UNICODE_STRING)
                {
                    datasize = od.lengthofstring();
                }
                else
                {
                    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 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 = "";

            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 || od.datatype == DataType.UNICODE_STRING)
                    {
                        specialarraylength = string.Format("[{0}]", od.lengthofstring());
                    }

                    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));
                        }
                    }
                }
            }
        }