EasyCAT LAB - EtherCAT master legacy example

Dependencies:   SOEM SPI_STMPE610 SPI_TFT_ILI9341 TFT_fonts

The EasyCAT LAB is a complete educational and experimental EtherCAT® system, composed of one master and two slaves .

/media/uploads/EasyCAT/easycat_lab.jpg

/media/uploads/EasyCAT/components.jpg

Revision:
0:7077d8f28b3e
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/soem_start.cpp	Tue Jun 11 10:19:08 2019 +0000
@@ -0,0 +1,705 @@
+
+#include "soem_start.h"
+#include "ethercat.h"
+#include "string.h"
+#include "oshw.h"
+
+#include "mbed.h"
+
+#include <inttypes.h>
+
+#include "SPI_TFT_ILI9341.h"
+
+extern SPI_TFT_ILI9341 TFT;
+
+boolean printSDO = TRUE;			
+boolean printMAP = TRUE;			
+
+ec_ODlistt ODlist;
+ec_OElistt OElist;
+char usdo[128];
+char hstr[1024];
+
+char extern IOmap[];
+
+uint32_t error_counter = 0;
+
+
+char* dtype2string(uint16 dtype);
+char* SDO2string(uint16 slave, uint16 index, uint8 subidx, uint16 dtype);
+int si_PDOassign(uint16 slave, uint16 PDOassign, int mapoffset, int bitoffset);
+void si_sdo(int cnt);
+int si_map_sdo(int slave);
+int si_siiPDO(uint16 slave, uint8 t, int mapoffset, int bitoffset);
+bool network_scanning(void);
+
+
+
+//---- convert Ethercat types to string ----------------------------------------
+
+
+char* dtype2string(uint16 dtype)
+{
+    switch(dtype)
+    {
+        case ECT_BOOLEAN:
+            sprintf(hstr, "BOOLEAN");
+            break;
+        case ECT_INTEGER8:
+            sprintf(hstr, "INTEGER8");
+            break;
+        case ECT_INTEGER16:
+            sprintf(hstr, "INTEGER16");
+            break;
+        case ECT_INTEGER32:
+            sprintf(hstr, "INTEGER32");
+            break;
+        case ECT_INTEGER24:
+            sprintf(hstr, "INTEGER24");
+            break;
+        case ECT_INTEGER64:
+            sprintf(hstr, "INTEGER64");
+            break;
+        case ECT_UNSIGNED8:
+            sprintf(hstr, "UNSIGNED8");
+            break;
+        case ECT_UNSIGNED16:
+            sprintf(hstr, "UNSIGNED16");
+            break;
+        case ECT_UNSIGNED32:
+            sprintf(hstr, "UNSIGNED32");
+            break;
+        case ECT_UNSIGNED24:
+            sprintf(hstr, "UNSIGNED24");
+            break;
+        case ECT_UNSIGNED64:
+            sprintf(hstr, "UNSIGNED64");
+            break;
+        case ECT_REAL32:
+            sprintf(hstr, "REAL32");
+            break;
+        case ECT_REAL64:
+            sprintf(hstr, "REAL64");
+            break;
+        case ECT_BIT1:
+            sprintf(hstr, "BIT1");
+            break;
+        case ECT_BIT2:
+            sprintf(hstr, "BIT2");
+            break;
+        case ECT_BIT3:
+            sprintf(hstr, "BIT3");
+            break;
+        case ECT_BIT4:
+            sprintf(hstr, "BIT4");
+            break;
+        case ECT_BIT5:
+            sprintf(hstr, "BIT5");
+            break;
+        case ECT_BIT6:
+            sprintf(hstr, "BIT6");
+            break;
+        case ECT_BIT7:
+            sprintf(hstr, "BIT7");
+            break;
+        case ECT_BIT8:
+            sprintf(hstr, "BIT8");
+            break;
+        case ECT_VISIBLE_STRING:
+            sprintf(hstr, "VISIBLE_STRING");
+            break;
+        case ECT_OCTET_STRING:
+            sprintf(hstr, "OCTET_STRING");
+            break;
+        default:
+            sprintf(hstr, "Type 0x%4.4X", dtype);
+    }
+    return hstr;
+}
+
+
+//------------------------------------------------------------------------------
+
+char* SDO2string(uint16 slave, uint16 index, uint8 subidx, uint16 dtype)
+{
+   int l = sizeof(usdo) - 1, i;
+   uint8 *u8;
+   int8 *i8;
+   uint16 *u16;
+   int16 *i16;
+   uint32 *u32;
+   int32 *i32;
+   uint64 *u64;
+   int64 *i64;
+   float *sr;
+   double *dr;
+   char es[32];
+
+   memset(&usdo, 0, 128);
+   ec_SDOread(slave, index, subidx, FALSE, &l, &usdo, EC_TIMEOUTRXM);
+   if (EcatError)
+   {
+      return ec_elist2string();
+   }
+   else
+   {
+      switch(dtype)
+      {
+         case ECT_BOOLEAN:
+            u8 = (uint8*) &usdo[0];
+            if (*u8) sprintf(hstr, "TRUE");
+             else sprintf(hstr, "FALSE");
+            break;
+         case ECT_INTEGER8:
+            i8 = (int8*) &usdo[0];
+            sprintf(hstr, "0x%2.2x %d", *i8, *i8);
+            break;
+         case ECT_INTEGER16:
+            i16 = (int16*) &usdo[0];
+            sprintf(hstr, "0x%4.4x %d", *i16, *i16);
+            break;
+         case ECT_INTEGER32:
+         case ECT_INTEGER24:
+            i32 = (int32*) &usdo[0];
+            sprintf(hstr, "0x%8.8x %d", *i32, *i32);
+            break;
+         case ECT_INTEGER64:
+            i64 = (int64*) &usdo[0];
+            sprintf(hstr, "0x%16.16"PRIx64" %"PRId64, *i64, *i64);
+            break;
+         case ECT_UNSIGNED8:
+            u8 = (uint8*) &usdo[0];
+            sprintf(hstr, "0x%2.2x %u", *u8, *u8);
+            break;
+         case ECT_UNSIGNED16:
+            u16 = (uint16*) &usdo[0];
+            sprintf(hstr, "0x%4.4x %u", *u16, *u16);
+            break;
+         case ECT_UNSIGNED32:
+         case ECT_UNSIGNED24:
+            u32 = (uint32*) &usdo[0];
+            sprintf(hstr, "0x%8.8x %u", *u32, *u32);
+            break;
+         case ECT_UNSIGNED64:
+            u64 = (uint64*) &usdo[0];
+            sprintf(hstr, "0x%16.16"PRIx64" %"PRIu64, *u64, *u64);
+            break;
+         case ECT_REAL32:
+            sr = (float*) &usdo[0];
+            sprintf(hstr, "%f", *sr);
+            break;
+         case ECT_REAL64:
+            dr = (double*) &usdo[0];
+            sprintf(hstr, "%f", *dr);
+            break;
+         case ECT_BIT1:
+         case ECT_BIT2:
+         case ECT_BIT3:
+         case ECT_BIT4:
+         case ECT_BIT5:
+         case ECT_BIT6:
+         case ECT_BIT7:
+         case ECT_BIT8:
+            u8 = (uint8*) &usdo[0];
+            sprintf(hstr, "0x%x", *u8);
+            break;
+         case ECT_VISIBLE_STRING:
+            strcpy(hstr, usdo);
+            break;
+         case ECT_OCTET_STRING:
+            hstr[0] = 0x00;
+            for (i = 0 ; i < l ; i++)
+            {
+               sprintf(es, "0x%2.2x ", usdo[i]);
+               strcat( hstr, es);
+            }
+            break;
+         default:
+            sprintf(hstr, "Unknown type");
+      }
+      return hstr;
+   }
+}
+
+
+//----- read PDO assign structure ----------------------------------------------
+
+int si_PDOassign(uint16 slave, uint16 PDOassign, int mapoffset, int bitoffset)
+{
+    uint16 idxloop, nidx, subidxloop, rdat, idx, subidx;
+    uint8 subcnt;
+    int wkc, bsize = 0, rdl;
+    int32 rdat2;
+    uint8 bitlen, obj_subidx;
+    uint16 obj_idx;
+    int abs_offset, abs_bit;
+
+    rdl = sizeof(rdat); rdat = 0;
+    															// read PDO assign subindex 0 (= number of PDO's)
+    wkc = ec_SDOread(slave, PDOassign, 0x00, FALSE, &rdl, &rdat, EC_TIMEOUTRXM);
+    rdat = etohs(rdat);
+
+    if ((wkc > 0) && (rdat > 0))							    // positive result from slave?
+    {
+        nidx = rdat;											// number of available sub indexes 
+        bsize = 0;
+        
+        for (idxloop = 1; idxloop <= nidx; idxloop++)			// read all PDO's 
+        {
+            rdl = sizeof(rdat); rdat = 0;
+            													// read PDO assign 
+            wkc = ec_SDOread(slave, PDOassign, (uint8)idxloop, FALSE, &rdl, &rdat, EC_TIMEOUTRXM);
+            										
+            idx = etohl(rdat);									// result is index of PDO
+            if (idx > 0)
+            {
+                rdl = sizeof(subcnt); subcnt = 0;
+                												// read number of subindexes of PDO
+                wkc = ec_SDOread(slave,idx, 0x00, FALSE, &rdl, &subcnt, EC_TIMEOUTRXM);
+                subidx = subcnt;
+                												// for each subindex 
+                for (subidxloop = 1; subidxloop <= subidx; subidxloop++)
+                {
+                    rdl = sizeof(rdat2); rdat2 = 0;
+                    											// read SDO that is mapped in PDO
+                    wkc = ec_SDOread(slave, idx, (uint8)subidxloop, FALSE, &rdl, &rdat2, EC_TIMEOUTRXM);
+                    rdat2 = etohl(rdat2);
+                    
+                    bitlen = LO_BYTE(rdat2);					// extract bitlength of SDO
+                    bsize += bitlen;
+                    obj_idx = (uint16)(rdat2 >> 16);
+                    obj_subidx = (uint8)((rdat2 >> 8) & 0x000000ff);
+                    abs_offset = mapoffset + (bitoffset / 8);
+                    abs_bit = bitoffset % 8;
+                    ODlist.Slave = slave;
+                    ODlist.Index[0] = obj_idx;
+                    OElist.Entries = 0;
+                    wkc = 0;
+                    											
+                    if(obj_idx || obj_subidx)					// read object entry from dictionary if not a filler (0x0000:0x00)
+                        wkc = ec_readOEsingle(0, obj_subidx, &ODlist, &OElist);
+                    printf("  [0x%4.4X.%1d] 0x%4.4X:0x%2.2X 0x%2.2X", abs_offset, abs_bit, obj_idx, obj_subidx, bitlen);
+                    
+                    if((wkc > 0) && OElist.Entries)
+                    {
+                        printf(" %-12s %s\n", dtype2string(OElist.DataType[obj_subidx]), OElist.Name[obj_subidx]);
+                    }
+                    else
+                        printf("\n");
+                    bitoffset += bitlen;
+                };
+            };
+        };
+    };
+
+    return bsize;											    // return total found bitlength (PDO)
+}
+
+
+//---- PDO mapping according to CoE --------------------------------------------
+
+int si_map_sdo(int slave)
+{
+    int wkc, rdl;
+    int retVal = 0;
+    uint8 nSM, iSM, tSM;
+    int Tsize, outputs_bo, inputs_bo;
+    uint8 SMt_bug_add;
+
+    printf("PDO mapping according to CoE :\n\n");
+    SMt_bug_add = 0;
+    outputs_bo = 0;
+    inputs_bo = 0;
+    rdl = sizeof(nSM); nSM = 0;
+    														// read SyncManager Communication Type object count
+    wkc = ec_SDOread(slave, ECT_SDO_SMCOMMTYPE, 0x00, FALSE, &rdl, &nSM, EC_TIMEOUTRXM);
+    														
+    if ((wkc > 0) && (nSM > 2))								// positive result from slave ? 
+    {   
+        nSM--;               								// make nSM equal to number of defined SM 
+        
+        if (nSM > EC_MAXSM)									// limit to maximum number of SM defined,
+            nSM = EC_MAXSM;									// if true the slave can't be configured 
+        
+        for (iSM = 2 ; iSM <= nSM ; iSM++)					// iterate for every SM type defined 		
+        {
+            rdl = sizeof(tSM); tSM = 0;
+            												// read SyncManager Communication Type 
+            wkc = ec_SDOread(slave, ECT_SDO_SMCOMMTYPE, iSM + 1, FALSE, &rdl, &tSM, EC_TIMEOUTRXM);
+            if (wkc > 0)
+            {
+                if((iSM == 2) && (tSM == 2)) 				// SM2 has type 2 == mailbox out, this is a bug in the slave!
+                {
+                    SMt_bug_add = 1; 						// try to correct, this works if the types are 0 1 2 3 and should be 1 2 3 4
+                    printf("Activated SM type workaround, possible incorrect mapping.\n");
+                }
+                
+                if(tSM)										// only add if SMt > 0
+                    tSM += SMt_bug_add; 					
+
+                if (tSM == 3) 								// outputs
+                {											// read the assign RXPDO
+                 
+                    printf("  SM%1d outputs\n        addr b   index: sub bitl data_type    name\n", iSM);
+                    Tsize = si_PDOassign(slave, ECT_SDO_PDOASSIGN + iSM, (int)(ec_slave[slave].outputs - (uint8 *)&IOmap[0]), outputs_bo );
+                    outputs_bo += Tsize;
+                }
+                
+                if (tSM == 4) 								// inputs
+                {											// read the assign TXPDO 
+                    
+                    printf("  SM%1d inputs\n     addr b   index: sub bitl data_type    name\n", iSM);
+                    Tsize = si_PDOassign(slave, ECT_SDO_PDOASSIGN + iSM, (int)(ec_slave[slave].inputs - (uint8 *)&IOmap[0]), inputs_bo );
+                    inputs_bo += Tsize;
+                }
+            }
+        }
+    }
+
+    if ((outputs_bo > 0) || (inputs_bo > 0))				// found some I/O bits? 
+        retVal = 1;
+    return retVal;
+}
+
+
+//---- CoE objects description -------------------------------------------------
+
+void si_sdo(int cnt)
+{
+    int i, j;
+
+    ODlist.Entries = 0;
+    memset(&ODlist, 0, sizeof(ODlist));
+    if( ec_readODlist(cnt, &ODlist))
+    {
+        printf(" CoE Object Description found, %d entries.\n",ODlist.Entries);
+        for( i = 0 ; i < ODlist.Entries ; i++)
+        {
+            ec_readODdescription(i, &ODlist);
+            while(EcatError) printf("%s", ec_elist2string());
+            printf(" Index: %4.4x Datatype: %4.4x Objectcode: %2.2x Name: %s\n",
+                ODlist.Index[i], ODlist.DataType[i], ODlist.ObjectCode[i], ODlist.Name[i]);
+            memset(&OElist, 0, sizeof(OElist));
+            ec_readOE(i, &ODlist, &OElist);
+            while(EcatError) printf("%s", ec_elist2string());
+            for( j = 0 ; j < ODlist.MaxSub[i]+1 ; j++)
+            {
+                if ((OElist.DataType[j] > 0) && (OElist.BitLength[j] > 0))
+                {
+                    printf("  Sub: %2.2x Datatype: %4.4x Bitlength: %4.4x Obj.access: %4.4x Name: %s\n",
+                        j, OElist.DataType[j], OElist.BitLength[j], OElist.ObjAccess[j], OElist.Name[j]);
+                    if ((OElist.ObjAccess[j] & 0x0007))
+                    {
+                        printf("          Value :%s\n", SDO2string(cnt, ODlist.Index[i], j, OElist.DataType[j]));
+                    }
+                }
+            }
+        }
+    }
+    else
+    {
+        while(EcatError) printf("%s", ec_elist2string());
+    }
+}
+
+
+//---- PDO mapping according to SII --------------------------------------------
+
+int si_map_sii(int slave)
+{
+    int retVal = 0;
+    int Tsize, outputs_bo, inputs_bo;
+
+    printf("\nPDO mapping according to SII :\n\n");
+
+    outputs_bo = 0;
+    inputs_bo = 0;
+    														// read the assign RXPDOs 
+    Tsize = si_siiPDO(slave, 1, (int)(ec_slave[slave].outputs - (uint8*)&IOmap), outputs_bo );
+    outputs_bo += Tsize;
+    														// read the assign TXPDOs 
+    Tsize = si_siiPDO(slave, 0, (int)(ec_slave[slave].inputs - (uint8*)&IOmap), inputs_bo );
+    inputs_bo += Tsize;
+    
+    if ((outputs_bo > 0) || (inputs_bo > 0))				// found some I/O bits ? 
+        retVal = 1;
+    return retVal;
+}
+
+
+//------------------------------------------------------------------------------
+
+int si_siiPDO(uint16 slave, uint8 t, int mapoffset, int bitoffset)
+{
+    uint16 a , w, c, e, er, Size;
+    uint8 eectl;
+    uint16 obj_idx;
+    uint8 obj_subidx;
+    uint8 obj_name;
+    uint8 obj_datatype;
+    uint8 bitlen;
+    int totalsize;
+    ec_eepromPDOt eepPDO;
+    ec_eepromPDOt *PDO;
+    int abs_offset, abs_bit;
+    char str_name[EC_MAXNAME + 1];
+
+    eectl = ec_slave[slave].eep_pdi;
+    Size = 0;
+    totalsize = 0;
+    PDO = &eepPDO;
+    PDO->nPDO = 0;
+    PDO->Length = 0;
+    PDO->Index[1] = 0;
+  
+    for (c = 0 ; c < EC_MAXSM ; c++)
+    	PDO->SMbitsize[c] = 0;
+  
+    if (t > 1)
+        t = 1;
+  
+    PDO->Startpos = ec_siifind(slave, ECT_SII_PDO + t);
+  
+    if (PDO->Startpos > 0)
+    {
+        a = PDO->Startpos;
+        w = ec_siigetbyte(slave, a++);
+        w += (ec_siigetbyte(slave, a++) << 8);
+        PDO->Length = w;
+        c = 1;
+        
+        do													// traverse through all PDOs			
+        {
+            PDO->nPDO++;
+            PDO->Index[PDO->nPDO] = ec_siigetbyte(slave, a++);
+            PDO->Index[PDO->nPDO] += (ec_siigetbyte(slave, a++) << 8);
+            PDO->BitSize[PDO->nPDO] = 0;
+            c++;
+            
+            e = ec_siigetbyte(slave, a++);					// number of entries in PDO 
+            PDO->SyncM[PDO->nPDO] = ec_siigetbyte(slave, a++);
+            a++;
+            obj_name = ec_siigetbyte(slave, a++);
+            a += 2;
+            c += 2;
+            
+            if (PDO->SyncM[PDO->nPDO] < EC_MAXSM) 			// active and in range SM? 
+            {
+                str_name[0] = 0;
+                if(obj_name)
+                	ec_siistring(str_name, slave, obj_name);
+                	
+                if (t)
+                  	printf("  SM%1d RXPDO 0x%4.4X %s\n", PDO->SyncM[PDO->nPDO], PDO->Index[PDO->nPDO], str_name);
+                else
+                  	printf("  SM%1d TXPDO 0x%4.4X %s\n", PDO->SyncM[PDO->nPDO], PDO->Index[PDO->nPDO], str_name);
+                
+                printf("     addr b   index: sub  bitl data_type    name\n");
+                
+                for (er = 1; er <= e; er++)					// read all entries defined in PDO 
+                {
+                    c += 4;
+                    obj_idx = ec_siigetbyte(slave, a++);
+                    obj_idx += (ec_siigetbyte(slave, a++) << 8);
+                    obj_subidx = ec_siigetbyte(slave, a++);
+                    obj_name = ec_siigetbyte(slave, a++);
+                    obj_datatype = ec_siigetbyte(slave, a++);
+                    bitlen = ec_siigetbyte(slave, a++);
+                    abs_offset = mapoffset + (bitoffset / 8);
+                    abs_bit = bitoffset % 8;
+
+                    PDO->BitSize[PDO->nPDO] += bitlen;
+                    a += 2;
+
+                    if(obj_idx || obj_subidx)				// skip entry if filler (0x0000:0x00)
+                    {
+                       str_name[0] = 0;
+                       if(obj_name)
+                          ec_siistring(str_name, slave, obj_name);
+
+                       printf("  [0x%4.4X.%1d] 0x%4.4X:0x%2.2X 0x%2.2X", abs_offset, abs_bit, obj_idx, obj_subidx, bitlen);
+                       printf(" %-12s %s\n", dtype2string(obj_datatype), str_name);
+                    }
+                    bitoffset += bitlen;
+                    totalsize += bitlen;
+                }
+                PDO->SMbitsize[ PDO->SyncM[PDO->nPDO] ] += PDO->BitSize[PDO->nPDO];
+                Size += PDO->BitSize[PDO->nPDO];
+                c++;
+            }
+            
+            else 											// PDO deactivated because SM is 0xff or > EC_MAXSM 
+            {
+                c += 4 * e;
+                a += 8 * e;
+                c++;
+            }
+            												// limit number of PDO entries in buffer 
+            if (PDO->nPDO >= (EC_MAXEEPDO - 1)) c = PDO->Length; 
+        }
+        while (c < PDO->Length);
+    }
+                                        
+    if (eectl) 
+    	ec_eeprom2pdi(slave); 								// if eeprom control was previously pdi then restore 
+    
+    return totalsize;
+}
+
+
+//------------------------------------------------------------------------------
+
+bool network_scanning(void)
+
+{
+    int expectedWKC;
+	int cnt, i, j, nSM;
+   	uint16 ssigen;	     	
+
+    if ( ec_config(FALSE, &IOmap) > 0 )  					// find and configure the slaves	
+  	{
+     	ec_configdc();
+     	while(EcatError) printf("%s", ec_elist2string());
+     	
+     	printf("%d slaves found and configured.\n",ec_slavecount);
+ 	 	TFT.printf("%d slaves found and configured.\n\n",ec_slavecount);	     	
+     	
+     	expectedWKC = (ec_group[0].outputsWKC * 2) + ec_group[0].inputsWKC;
+     	printf("Calculated workcounter %d\n", expectedWKC);
+     														// wait for all slaves to reach SAFE_OP state 
+     	ec_statecheck(0, EC_STATE_SAFE_OP,  EC_TIMEOUTSTATE * 3);
+     	
+     	if (ec_slave[0].state != EC_STATE_SAFE_OP )
+     	{
+        	printf("Not all slaves reached safe operational state.\n");
+        	ec_readstate();
+        	for(i = 1; i<=ec_slavecount ; i++)
+        	{
+           		if(ec_slave[i].state != EC_STATE_SAFE_OP)
+           		{
+              		printf("Slave %d State=%2x StatusCode=%4x : %s\n",
+                	i, ec_slave[i].state, ec_slave[i].ALstatuscode, ec_ALstatuscode2string(ec_slave[i].ALstatuscode));
+           		}
+         	}  		
+        }
+
+		ec_readstate();			
+				        				        
+		for( cnt = 1 ; cnt <= ec_slavecount ; cnt++)
+		{  
+            printf("\nSlave:%d -------------------------------------------------\nName:%s\n Output size: %dbits\n Input size: %dbits\n State: %d\n Delay: %d[ns]\n Has DC: %d\n",
+                  	cnt, ec_slave[cnt].name, ec_slave[cnt].Obits, ec_slave[cnt].Ibits,
+                  	ec_slave[cnt].state, ec_slave[cnt].pdelay, ec_slave[cnt].hasdc);         
+
+			int Line = cnt-1; 
+
+			TFT.foreground(Green);							// print Name, Manufacturer, ID and Revision
+			TFT.locate(0, 12*(((Line % 6)*3)+3));			// of the slaves found on the TFT
+            TFT.printf("Slave %d ", cnt); 					//
+			TFT.foreground(Yellow);							//	
+															//
+			TFT.foreground(Magenta);						//
+			TFT.locate(60, 12*(((Line % 6)*3)+3));			//	
+            TFT.printf("Name"); 							//
+            TFT.foreground(Yellow);							//
+			TFT.locate(104, 12*(((Line % 6)*3)+3));         //  	 
+            TFT.printf("%.14s", ec_slave[cnt].name);  		//	             
+                											//
+			TFT.foreground(Magenta); 						//
+			TFT.locate(220, 12*(((Line % 6)*3)+3));			//  	                    
+            TFT.printf("Man");								//
+            TFT.foreground(Yellow);  						//
+			TFT.locate(250, 12*(((Line % 6)*3)+3));	        //      
+            TFT.printf("%8.8X", (int)ec_slave[cnt].eep_man);//
+               												//		
+			TFT.foreground(Magenta);   						//
+			TFT.locate(60, 12*(((Line % 6)*3)+4));			//                    
+            TFT.printf("ID");            					//
+            TFT.foreground(Yellow);							//
+			TFT.locate(104, 12*(((Line % 6)*3)+4));         //                 
+            TFT.printf("%8.8X", (int)ec_slave[cnt].eep_id); //       
+ 															//
+			TFT.foreground(Magenta);   						//
+			TFT.locate(220, 12*(((Line % 6)*3)+4));			//                    
+            TFT.printf("Rev ");            					//
+            TFT.foreground(Yellow);   						//
+			TFT.locate(250,  12*(((Line % 6)*3)+4));	    //                 
+            TFT.printf("%8.8X", (int)ec_slave[cnt].eep_rev);//    
+                                                             
+                          
+            if (ec_slave[cnt].hasdc) printf(" DCParentport:%d\n", ec_slave[cnt].parentport);
+            printf(" Activeports:%d.%d.%d.%d\n", (ec_slave[cnt].activeports & 0x01) > 0 ,
+                                         (ec_slave[cnt].activeports & 0x02) > 0 ,
+                                         (ec_slave[cnt].activeports & 0x04) > 0 ,
+                                         (ec_slave[cnt].activeports & 0x08) > 0 );
+                                         
+            printf(" Configured address: %4.4X\n", ec_slave[cnt].configadr);
+        	printf(" Outputs address: %X\n", ec_slave[cnt].outputs);
+    		printf(" Inputs address: %X\n", ec_slave[cnt].inputs);            
+            
+            printf(" Man: %8.8x ID: %8.8x Rev: %8.8x\n", (int)ec_slave[cnt].eep_man, (int)ec_slave[cnt].eep_id, (int)ec_slave[cnt].eep_rev);
+            for(nSM = 0 ; nSM < EC_MAXSM ; nSM++)
+            {
+               if(ec_slave[cnt].SM[nSM].StartAddr > 0)
+                  printf(" SM%1d A:%4.4x L:%4d F:%8.8x Type:%d\n",nSM, ec_slave[cnt].SM[nSM].StartAddr, ec_slave[cnt].SM[nSM].SMlength,
+                         (int)ec_slave[cnt].SM[nSM].SMflags, ec_slave[cnt].SMtype[nSM]);
+            }
+            for(j = 0 ; j < ec_slave[cnt].FMMUunused ; j++)
+            {
+               printf(" FMMU%1d Ls:%8.8x Ll:%4d Lsb:%d Leb:%d Ps:%4.4x Psb:%d Ty:%2.2x Act:%2.2x\n", j,
+                       (int)ec_slave[cnt].FMMU[j].LogStart, ec_slave[cnt].FMMU[j].LogLength, ec_slave[cnt].FMMU[j].LogStartbit,
+                       ec_slave[cnt].FMMU[j].LogEndbit, ec_slave[cnt].FMMU[j].PhysStart, ec_slave[cnt].FMMU[j].PhysStartBit,
+                       ec_slave[cnt].FMMU[j].FMMUtype, ec_slave[cnt].FMMU[j].FMMUactive);
+            }
+            printf(" FMMUfunc 0:%d 1:%d 2:%d 3:%d\n",
+                     ec_slave[cnt].FMMU0func, ec_slave[cnt].FMMU1func, ec_slave[cnt].FMMU2func, ec_slave[cnt].FMMU3func);
+            printf(" MBX length wr: %d rd: %d MBX protocols : %2.2x\n", ec_slave[cnt].mbx_l, ec_slave[cnt].mbx_rl, ec_slave[cnt].mbx_proto);
+            ssigen = ec_siifind(cnt, ECT_SII_GENERAL);
+            	
+            if (ssigen)										 // SII general section 
+            {
+               ec_slave[cnt].CoEdetails = ec_siigetbyte(cnt, ssigen + 0x07);
+               ec_slave[cnt].FoEdetails = ec_siigetbyte(cnt, ssigen + 0x08);
+               ec_slave[cnt].EoEdetails = ec_siigetbyte(cnt, ssigen + 0x09);
+               ec_slave[cnt].SoEdetails = ec_siigetbyte(cnt, ssigen + 0x0a);
+               if((ec_siigetbyte(cnt, ssigen + 0x0d) & 0x02) > 0)
+               {
+                  ec_slave[cnt].blockLRW = 1;
+                  ec_slave[0].blockLRW++;
+               }
+               ec_slave[cnt].Ebuscurrent = ec_siigetbyte(cnt, ssigen + 0x0e);
+               ec_slave[cnt].Ebuscurrent += ec_siigetbyte(cnt, ssigen + 0x0f) << 8;
+               ec_slave[0].Ebuscurrent += ec_slave[cnt].Ebuscurrent;
+    		}
+            printf(" CoE details: %2.2x FoE details: %2.2x EoE details: %2.2x SoE details: %2.2x\n",
+                    ec_slave[cnt].CoEdetails, ec_slave[cnt].FoEdetails, ec_slave[cnt].EoEdetails, ec_slave[cnt].SoEdetails);
+            printf(" Ebus current: %d[mA]\n only LRD/LWR:%d\n",
+                    ec_slave[cnt].Ebuscurrent, ec_slave[cnt].blockLRW);
+                    
+            if ((ec_slave[cnt].mbx_proto & ECT_MBXPROT_COE) && printSDO)
+            	si_sdo(cnt);
+                    
+            if(printMAP)
+            {
+        		if (ec_slave[cnt].mbx_proto & ECT_MBXPROT_COE)   
+                	si_map_sdo(cnt);
+                else
+                	si_map_sii(cnt);
+            }
+		}		
+		return 1;
+	}
+	
+	else
+	{	
+  	//	ec_close();		//******// 
+  		
+  		return 0;											// no slaves found
+	}	
+}
+
+
+
+
+
+