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