Browse Source

feat: add eni & esi parse tool

Signed-off-by: sakumisu <1203593632@qq.com>
sakumisu 3 months ago
parent
commit
ee05a2b702
9 changed files with 4228 additions and 1 deletions
  1. 40 0
      README.md
  2. 40 0
      README_zh.md
  3. 2 0
      demo/hpmicro/main.c
  4. 1094 0
      scripts/ECAT_CIA402_ENI.xml
  5. 2141 0
      scripts/ECAT_CIA402_ESI.xml
  6. 381 0
      scripts/eni_parser.py
  7. 510 0
      scripts/esi_parser.py
  8. 19 0
      src/ec_cmd.c
  9. 1 1
      src/ec_sii.c

+ 40 - 0
README.md

@@ -56,6 +56,46 @@ CherryECAT is a tiny and beautiful, high real-time and low-jitter EtherCAT maste
 ![ethercat](docs/assets/ethercat6.png)
 ![ethercat](docs/assets/ethercat7.png)
 
+## Tool
+
+- esi_parser
+
+Use **esi_parser.py** to generate slave eeprom information and download eeprom to slave.
+
+```
+python ./esi_parser.py ECAT_CIA402_ESI.xml eeprom.bin eeprom.h
+
+Parsing XML file: ECAT_CIA402_ESI.xml
+Parsed XML: Vendor=0x0048504D, Product=0x00000003
+Device Name: ECAT_CIA402
+Mailbox RX: 0x1000(128)
+Mailbox TX: 0x1080(128)
+Generating EEPROM data...
+✓ Successfully converted 'ECAT_CIA402_ESI.xml' to 'eeprom.bin'
+✓ Generated 2048 bytes of EEPROM data
+✓ Vendor ID: 0x0048504D
+✓ Product Code: 0x00000003
+✓ Revision: 0x00000001
+✓ Device Name: ECAT_CIA402
+✓ Generated C header file: eeprom.h
+```
+
+- eni_parser
+
+Use **eni_parser.py** to generate CherryECAT slave sync config.
+
+```
+python ./eni_parser.py ECAT_CIA402_ENI.xml sync_config.h
+
+Parsing ENI file: ECAT_CIA402_ENI.xml
+Generating C code...
+✓ Successfully converted 'ECAT_CIA402_ENI.xml' to 'sync_config.h'
+✓ Generated C code for 1 slave(s)
+✓ Slave 1:
+  - RxPDO 0x1602: 3 entries
+  - TxPDO 0x1A02: 3 entries
+```
+
 ## Support Boards
 
 - HPM6750EVK2/HPM6800EVK/**HPM5E00EVK**(hybrid internal)

+ 40 - 0
README_zh.md

@@ -56,6 +56,46 @@ CherryECAT 是一个小而美的、高实时性、低抖动的 EtherCAT 主机
 ![ethercat](docs/assets/ethercat6.png)
 ![ethercat](docs/assets/ethercat7.png)
 
+## 工具
+
+- esi_parser
+
+使用 **esi_parser.py** 生成从站 eeprom 信息用于烧录从站
+
+```
+python ./esi_parser.py ECAT_CIA402_ESI.xml eeprom.bin eeprom.h
+
+Parsing XML file: ECAT_CIA402_ESI.xml
+Parsed XML: Vendor=0x0048504D, Product=0x00000003
+Device Name: ECAT_CIA402
+Mailbox RX: 0x1000(128)
+Mailbox TX: 0x1080(128)
+Generating EEPROM data...
+✓ Successfully converted 'ECAT_CIA402_ESI.xml' to 'eeprom.bin'
+✓ Generated 2048 bytes of EEPROM data
+✓ Vendor ID: 0x0048504D
+✓ Product Code: 0x00000003
+✓ Revision: 0x00000001
+✓ Device Name: ECAT_CIA402
+✓ Generated C header file: eeprom.h
+```
+
+- eni_parser
+
+使用 **eni_parser.py** 生成 CherryECAT slave sync 配置
+
+```
+python ./eni_parser.py ECAT_CIA402_ENI.xml sync_config.h
+
+Parsing ENI file: ECAT_CIA402_ENI.xml
+Generating C code...
+✓ Successfully converted 'ECAT_CIA402_ENI.xml' to 'sync_config.h'
+✓ Generated C code for 1 slave(s)
+✓ Slave 1:
+  - RxPDO 0x1602: 3 entries
+  - TxPDO 0x1A02: 3 entries
+```
+
 ## 支持的开发板
 
 - HPM6750EVK2/HPM6800EVK/**HPM5E00EVK**(hybrid internal)

+ 2 - 0
demo/hpmicro/main.c

@@ -100,6 +100,8 @@ static void task_start(void *param)
 
 CSH_CMD_EXPORT(ethercat, );
 
+unsigned char cherryecat_eepromdata[2048]; // EEPROM data buffer, please generate by esi_parse.py
+
 static ec_pdo_entry_info_t dio_1600[] = {
     { 0x6000, 0x00, 0x20 },
 };

+ 1094 - 0
scripts/ECAT_CIA402_ENI.xml

@@ -0,0 +1,1094 @@
+<?xml version="1.0"?>
+<EtherCATConfig xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="EtherCATConfig.xsd" Version="1.3">
+	<Config>
+		<Master>
+			<Info>
+				<Name><![CDATA[Device 2 (EtherCAT)]]></Name>
+				<Destination>010105010000</Destination>
+				<Source>2c58b9dca252</Source>
+				<EtherType>a488</EtherType>
+			</Info>
+			<MailboxStates>
+				<StartAddr>150994944</StartAddr>
+				<Count>1</Count>
+			</MailboxStates>
+			<InitCmds>
+				<InitCmd>
+					<Transition>IP</Transition>
+					<BeforeSlave>true</BeforeSlave>
+					<Comment><![CDATA[read slave count]]></Comment>
+					<Requires>cycle</Requires>
+					<Cmd>7</Cmd>
+					<Adp>0</Adp>
+					<Ado>304</Ado>
+					<Data>0000</Data>
+					<Retries>0</Retries>
+				</InitCmd>
+				<InitCmd>
+					<Transition>IP</Transition>
+					<BeforeSlave>true</BeforeSlave>
+					<Comment><![CDATA[read slave count]]></Comment>
+					<Requires>cycle</Requires>
+					<Cmd>7</Cmd>
+					<Adp>0</Adp>
+					<Ado>304</Ado>
+					<Data>0000</Data>
+					<Retries>0</Retries>
+				</InitCmd>
+				<InitCmd>
+					<Transition>IP</Transition>
+					<BeforeSlave>true</BeforeSlave>
+					<Comment><![CDATA[enable ECAT IRQ]]></Comment>
+					<Requires>cycle</Requires>
+					<Cmd>8</Cmd>
+					<Adp>0</Adp>
+					<Ado>512</Ado>
+					<Data>0400</Data>
+					<Retries>3</Retries>
+				</InitCmd>
+				<InitCmd>
+					<Transition>IP</Transition>
+					<BeforeSlave>true</BeforeSlave>
+					<Comment><![CDATA[clear configured addresses]]></Comment>
+					<Requires>cycle</Requires>
+					<Cmd>8</Cmd>
+					<Adp>0</Adp>
+					<Ado>16</Ado>
+					<Data>0000</Data>
+					<Retries>3</Retries>
+				</InitCmd>
+				<InitCmd>
+					<Transition>IP</Transition>
+					<BeforeSlave>true</BeforeSlave>
+					<Comment><![CDATA[clear crc register]]></Comment>
+					<Requires>cycle</Requires>
+					<Cmd>8</Cmd>
+					<Adp>0</Adp>
+					<Ado>768</Ado>
+					<Data>0000000000000000</Data>
+					<Retries>3</Retries>
+				</InitCmd>
+				<InitCmd>
+					<Transition>IP</Transition>
+					<Transition>PI</Transition>
+					<Transition>BI</Transition>
+					<Transition>SI</Transition>
+					<Transition>OI</Transition>
+					<BeforeSlave>true</BeforeSlave>
+					<Comment><![CDATA[clear fmmu]]></Comment>
+					<Requires>cycle</Requires>
+					<Cmd>8</Cmd>
+					<Adp>0</Adp>
+					<Ado>1536</Ado>
+					<DataLength>256</DataLength>
+					<Retries>3</Retries>
+				</InitCmd>
+				<InitCmd>
+					<Transition>IP</Transition>
+					<BeforeSlave>true</BeforeSlave>
+					<Comment><![CDATA[clear sm]]></Comment>
+					<Requires>cycle</Requires>
+					<Cmd>8</Cmd>
+					<Adp>0</Adp>
+					<Ado>2048</Ado>
+					<DataLength>256</DataLength>
+					<Retries>3</Retries>
+				</InitCmd>
+				<InitCmd>
+					<Transition>IP</Transition>
+					<BeforeSlave>true</BeforeSlave>
+					<Comment><![CDATA[clear dc system time]]></Comment>
+					<Requires>cycle</Requires>
+					<Cmd>8</Cmd>
+					<Adp>0</Adp>
+					<Ado>2320</Ado>
+					<DataLength>32</DataLength>
+					<Retries>3</Retries>
+				</InitCmd>
+				<InitCmd>
+					<Transition>IP</Transition>
+					<BeforeSlave>true</BeforeSlave>
+					<Comment><![CDATA[clear dc cycle cfg]]></Comment>
+					<Requires>cycle</Requires>
+					<Cmd>8</Cmd>
+					<Adp>0</Adp>
+					<Ado>2433</Ado>
+					<Data>00</Data>
+					<Retries>3</Retries>
+				</InitCmd>
+				<InitCmd>
+					<Transition>IP</Transition>
+					<BeforeSlave>true</BeforeSlave>
+					<Comment><![CDATA[reset dc speed]]></Comment>
+					<Requires>cycle</Requires>
+					<Cmd>8</Cmd>
+					<Adp>0</Adp>
+					<Ado>2352</Ado>
+					<Data>0010</Data>
+					<Retries>3</Retries>
+				</InitCmd>
+				<InitCmd>
+					<Transition>IP</Transition>
+					<BeforeSlave>true</BeforeSlave>
+					<Comment><![CDATA[configure dc filter]]></Comment>
+					<Requires>cycle</Requires>
+					<Cmd>8</Cmd>
+					<Adp>0</Adp>
+					<Ado>2356</Ado>
+					<Data>000c</Data>
+					<Retries>3</Retries>
+				</InitCmd>
+				<InitCmd>
+					<Transition>IP</Transition>
+					<BeforeSlave>true</BeforeSlave>
+					<Comment><![CDATA[en/disable second physical address]]></Comment>
+					<Requires>cycle</Requires>
+					<Cmd>8</Cmd>
+					<Adp>0</Adp>
+					<Ado>259</Ado>
+					<Data>00</Data>
+					<Retries>3</Retries>
+				</InitCmd>
+			</InitCmds>
+		</Master>
+		<Slave>
+			<Info>
+				<Name><![CDATA[Drive 1 (ECAT_CIA402)]]></Name>
+				<PhysAddr>1001</PhysAddr>
+				<AutoIncAddr>0</AutoIncAddr>
+				<Identification Value="0">
+					<Ado>#x0134</Ado>
+				</Identification>
+				<Physics>YYY</Physics>
+				<VendorId>4739149</VendorId>
+				<ProductCode>3</ProductCode>
+				<RevisionNo>1</RevisionNo>
+				<SerialNo>0</SerialNo>
+			</Info>
+			<ProcessData>
+				<Send>
+					<BitStart>312</BitStart>
+					<BitLength>64</BitLength>
+				</Send>
+				<Recv>
+					<BitStart>312</BitStart>
+					<BitLength>64</BitLength>
+				</Recv>
+				<Sm2>
+					<Type>Outputs</Type>
+					<StartAddress>4352</StartAddress>
+					<ControlByte>100</ControlByte>
+					<Enable>1</Enable>
+					<Pdo>5634</Pdo>
+				</Sm2>
+				<Sm3>
+					<Type>Inputs</Type>
+					<StartAddress>5120</StartAddress>
+					<ControlByte>32</ControlByte>
+					<Enable>1</Enable>
+					<Pdo>6658</Pdo>
+				</Sm3>
+				<TxPdo Fixed="true" Sm="3">
+					<Index DependOnSlot="true">#x1a02</Index>
+					<Name>Inputs</Name>
+					<Entry>
+						<Index DependOnSlot="true">#x6041</Index>
+						<SubIndex>0</SubIndex>
+						<BitLen>16</BitLen>
+						<Name>Status Word</Name>
+						<Comment>object 0x6041:0</Comment>
+						<DataType>UINT</DataType>
+					</Entry>
+					<Entry>
+						<Index DependOnSlot="true">#x6064</Index>
+						<SubIndex>0</SubIndex>
+						<BitLen>32</BitLen>
+						<Name>ActualPosition</Name>
+						<Comment>object 0x6064:0</Comment>
+						<DataType>DINT</DataType>
+					</Entry>
+					<Entry>
+						<Index>#x0</Index>
+						<BitLen>16</BitLen>
+					</Entry>
+				</TxPdo>
+				<RxPdo Fixed="true" Sm="2">
+					<Index DependOnSlot="true">#x1602</Index>
+					<Name>Outputs</Name>
+					<Entry>
+						<Index DependOnSlot="true">#x6040</Index>
+						<SubIndex>0</SubIndex>
+						<BitLen>16</BitLen>
+						<Name>Control Word</Name>
+						<Comment>object 0x6040:0</Comment>
+						<DataType>UINT</DataType>
+					</Entry>
+					<Entry>
+						<Index DependOnSlot="true">#x60ff</Index>
+						<SubIndex>0</SubIndex>
+						<BitLen>32</BitLen>
+						<Name>TargetVelocity</Name>
+						<Comment>object 0x60FF:0</Comment>
+						<DataType>DINT</DataType>
+					</Entry>
+					<Entry>
+						<Index>#x0</Index>
+						<BitLen>16</BitLen>
+					</Entry>
+				</RxPdo>
+			</ProcessData>
+			<Mailbox DataLinkLayer="true">
+				<Send>
+					<Start>4096</Start>
+					<Length>128</Length>
+				</Send>
+				<Recv>
+					<Start>4224</Start>
+					<Length>128</Length>
+					<StatusBitAddr>0</StatusBitAddr>
+				</Recv>
+				<Protocol>CoE</Protocol>
+				<CoE>
+					<InitCmds>
+						<InitCmd Fixed="true" CompleteAccess="true">
+							<Transition>PS</Transition>
+							<Comment><![CDATA[download pdo 0x1C12 index]]></Comment>
+							<Timeout>0</Timeout>
+							<Ccs>1</Ccs>
+							<Index>7186</Index>
+							<SubIndex>0</SubIndex>
+							<Data>01000216</Data>
+						</InitCmd>
+						<InitCmd Fixed="true" CompleteAccess="true">
+							<Transition>PS</Transition>
+							<Comment><![CDATA[download pdo 0x1C13 index]]></Comment>
+							<Timeout>0</Timeout>
+							<Ccs>1</Ccs>
+							<Index>7187</Index>
+							<SubIndex>0</SubIndex>
+							<Data>0100021a</Data>
+						</InitCmd>
+						<InitCmd ModuleHandle="0">
+							<Transition>SO</Transition>
+							<Timeout>0</Timeout>
+							<Ccs>1</Ccs>
+							<Index>24672</Index>
+							<SubIndex>0</SubIndex>
+							<Data>09</Data>
+						</InitCmd>
+					</InitCmds>
+					<Profile>
+						<ChannelInfo>
+							<ProfileNo>402</ProfileNo>
+							<AddInfo>2</AddInfo>
+						</ChannelInfo>
+						<ChannelInfo>
+							<ProfileNo>402</ProfileNo>
+							<AddInfo>0</AddInfo>
+						</ChannelInfo>
+					</Profile>
+				</CoE>
+			</Mailbox>
+			<InitCmds>
+				<InitCmd>
+					<Transition>PI</Transition>
+					<Transition>BI</Transition>
+					<Transition>SI</Transition>
+					<Transition>OI</Transition>
+					<Comment><![CDATA[set device state to INIT]]></Comment>
+					<Requires>cycle</Requires>
+					<Cmd>2</Cmd>
+					<Adp>0</Adp>
+					<Ado>288</Ado>
+					<Data>1100</Data>
+					<Retries>3</Retries>
+					<Timeout>5000</Timeout>
+				</InitCmd>
+				<InitCmd>
+					<Transition>PI</Transition>
+					<Transition>SI</Transition>
+					<Transition>OI</Transition>
+					<Comment><![CDATA[check device state for INIT]]></Comment>
+					<Requires>cycle</Requires>
+					<Cmd>1</Cmd>
+					<Adp>0</Adp>
+					<Ado>304</Ado>
+					<Data>0000</Data>
+					<Retries>3</Retries>
+					<Validate>
+						<Data>0100</Data>
+						<DataMask>0f00</DataMask>
+						<Timeout>5000</Timeout>
+					</Validate>
+				</InitCmd>
+				<InitCmd>
+					<Transition>BI</Transition>
+					<Comment><![CDATA[check device state for INIT]]></Comment>
+					<Requires>cycle</Requires>
+					<Cmd>1</Cmd>
+					<Adp>0</Adp>
+					<Ado>304</Ado>
+					<Data>0000</Data>
+					<Retries>3</Retries>
+					<Validate>
+						<Data>0100</Data>
+						<DataMask>0f00</DataMask>
+						<Timeout>10000</Timeout>
+					</Validate>
+				</InitCmd>
+				<InitCmd>
+					<Transition>IP</Transition>
+					<Transition>IB</Transition>
+					<Comment><![CDATA[set device state to INIT]]></Comment>
+					<Requires>cycle</Requires>
+					<Cmd>2</Cmd>
+					<Adp>0</Adp>
+					<Ado>288</Ado>
+					<Data>1100</Data>
+					<Cnt>1</Cnt>
+					<Retries>3</Retries>
+					<Timeout>2000</Timeout>
+				</InitCmd>
+				<InitCmd>
+					<Transition>IP</Transition>
+					<Transition>IB</Transition>
+					<Comment><![CDATA[check device state for INIT]]></Comment>
+					<Requires>cycle</Requires>
+					<Cmd>1</Cmd>
+					<Adp>0</Adp>
+					<Ado>304</Ado>
+					<Data>0000</Data>
+					<Cnt>1</Cnt>
+					<Retries>3</Retries>
+					<Validate>
+						<Data>0100</Data>
+						<DataMask>0f00</DataMask>
+						<Timeout>2000</Timeout>
+					</Validate>
+				</InitCmd>
+				<InitCmd>
+					<Transition>IP</Transition>
+					<Comment><![CDATA[assign EEPROM to ECAT]]></Comment>
+					<Requires>cycle</Requires>
+					<Cmd>2</Cmd>
+					<Adp>0</Adp>
+					<Ado>1280</Ado>
+					<Data>00</Data>
+					<Cnt>1</Cnt>
+					<Retries>3</Retries>
+				</InitCmd>
+				<InitCmd>
+					<Transition>IP</Transition>
+					<Comment><![CDATA[check vendor id]]></Comment>
+					<Cmd>2</Cmd>
+					<Adp>0</Adp>
+					<Ado>1282</Ado>
+					<Data>000108000000</Data>
+					<Cnt>1</Cnt>
+					<Retries>3</Retries>
+				</InitCmd>
+				<InitCmd>
+					<Transition>IP</Transition>
+					<Comment><![CDATA[check vendor id]]></Comment>
+					<Requires>cycle</Requires>
+					<Cmd>1</Cmd>
+					<Adp>0</Adp>
+					<Ado>1288</Ado>
+					<Data>00000000</Data>
+					<Cnt>1</Cnt>
+					<Retries>3</Retries>
+					<Validate>
+						<Data>4d504800</Data>
+						<Timeout>100</Timeout>
+					</Validate>
+				</InitCmd>
+				<InitCmd>
+					<Transition>IP</Transition>
+					<Comment><![CDATA[check product code]]></Comment>
+					<Cmd>2</Cmd>
+					<Adp>0</Adp>
+					<Ado>1282</Ado>
+					<Data>00010a000000</Data>
+					<Cnt>1</Cnt>
+					<Retries>3</Retries>
+				</InitCmd>
+				<InitCmd>
+					<Transition>IP</Transition>
+					<Comment><![CDATA[check product code]]></Comment>
+					<Requires>cycle</Requires>
+					<Cmd>1</Cmd>
+					<Adp>0</Adp>
+					<Ado>1288</Ado>
+					<Data>00000000</Data>
+					<Cnt>1</Cnt>
+					<Retries>3</Retries>
+					<Validate>
+						<Data>03000000</Data>
+						<Timeout>100</Timeout>
+					</Validate>
+				</InitCmd>
+				<InitCmd>
+					<Transition>IP</Transition>
+					<Transition>IB</Transition>
+					<Comment><![CDATA[set physical address]]></Comment>
+					<Requires>cycle</Requires>
+					<Cmd>2</Cmd>
+					<Adp>0</Adp>
+					<Ado>16</Ado>
+					<Data>e903</Data>
+					<Cnt>1</Cnt>
+					<Retries>3</Retries>
+				</InitCmd>
+				<InitCmd>
+					<Transition>IP</Transition>
+					<Transition>IB</Transition>
+					<Transition>PI</Transition>
+					<Transition>SI</Transition>
+					<Transition>OI</Transition>
+					<Comment><![CDATA[clear sm 0/1 (mailbox out/in)]]></Comment>
+					<Cmd>5</Cmd>
+					<Adp>1001</Adp>
+					<Ado>2048</Ado>
+					<Data>00000000000000000000000000000000</Data>
+					<Retries>3</Retries>
+				</InitCmd>
+				<InitCmd>
+					<Transition>BI</Transition>
+					<Comment><![CDATA[clear sm 0/1 (mailbox out/in)]]></Comment>
+					<Cmd>2</Cmd>
+					<Adp>0</Adp>
+					<Ado>2048</Ado>
+					<Data>00000000000000000000000000000000</Data>
+					<Retries>3</Retries>
+				</InitCmd>
+				<InitCmd>
+					<Transition>IP</Transition>
+					<Transition>IB</Transition>
+					<Comment><![CDATA[set sm 0 (mailbox out)]]></Comment>
+					<Cmd>5</Cmd>
+					<Adp>1001</Adp>
+					<Ado>2048</Ado>
+					<Data>0010800026000100</Data>
+					<Cnt>1</Cnt>
+					<Retries>3</Retries>
+				</InitCmd>
+				<InitCmd>
+					<Transition>IP</Transition>
+					<Transition>IB</Transition>
+					<Comment><![CDATA[set sm 1 (mailbox in)]]></Comment>
+					<Cmd>5</Cmd>
+					<Adp>1001</Adp>
+					<Ado>2056</Ado>
+					<Data>8010800022000100</Data>
+					<Cnt>1</Cnt>
+					<Retries>3</Retries>
+				</InitCmd>
+				<InitCmd>
+					<Transition>SP</Transition>
+					<Transition>OP</Transition>
+					<Comment><![CDATA[set device state to PREOP]]></Comment>
+					<Requires>cycle</Requires>
+					<Cmd>5</Cmd>
+					<Adp>1001</Adp>
+					<Ado>288</Ado>
+					<Data>1200</Data>
+					<Retries>300</Retries>
+					<Timeout>200</Timeout>
+				</InitCmd>
+				<InitCmd>
+					<Transition>IP</Transition>
+					<Transition>SP</Transition>
+					<Transition>SI</Transition>
+					<Transition>OP</Transition>
+					<Transition>OI</Transition>
+					<Comment><![CDATA[clear sms]]></Comment>
+					<Cmd>5</Cmd>
+					<Adp>1001</Adp>
+					<Ado>2064</Ado>
+					<Data>00000000000000000000000000000000</Data>
+					<Retries>3</Retries>
+				</InitCmd>
+				<InitCmd>
+					<Transition>PS</Transition>
+					<Comment><![CDATA[set sm 2 (outputs)]]></Comment>
+					<Cmd>5</Cmd>
+					<Adp>1001</Adp>
+					<Ado>2064</Ado>
+					<Data>0011080064000100</Data>
+					<Cnt>1</Cnt>
+					<Retries>3</Retries>
+				</InitCmd>
+				<InitCmd>
+					<Transition>PS</Transition>
+					<Comment><![CDATA[set sm 3 (inputs)]]></Comment>
+					<Cmd>5</Cmd>
+					<Adp>1001</Adp>
+					<Ado>2072</Ado>
+					<Data>0014080020000100</Data>
+					<Cnt>1</Cnt>
+					<Retries>3</Retries>
+				</InitCmd>
+				<InitCmd>
+					<Transition>PS</Transition>
+					<Comment><![CDATA[set fmmu 0 (outputs)]]></Comment>
+					<Cmd>5</Cmd>
+					<Adp>1001</Adp>
+					<Ado>1536</Ado>
+					<Data>00000001080000070011000201000000</Data>
+					<Cnt>1</Cnt>
+					<Retries>3</Retries>
+				</InitCmd>
+				<InitCmd>
+					<Transition>PS</Transition>
+					<Comment><![CDATA[set fmmu 1 (inputs)]]></Comment>
+					<Cmd>5</Cmd>
+					<Adp>1001</Adp>
+					<Ado>1552</Ado>
+					<Data>00000001080000070014000101000000</Data>
+					<Cnt>1</Cnt>
+					<Retries>3</Retries>
+				</InitCmd>
+				<InitCmd>
+					<Transition>IP</Transition>
+					<Transition>IB</Transition>
+					<Comment><![CDATA[set fmmu 2 (mailbox state)]]></Comment>
+					<Cmd>5</Cmd>
+					<Adp>1001</Adp>
+					<Ado>1568</Ado>
+					<Data>00000009010000000d08000101000000</Data>
+					<Cnt>1</Cnt>
+					<Retries>3</Retries>
+				</InitCmd>
+				<InitCmd>
+					<Transition>OS</Transition>
+					<Comment><![CDATA[set device state to SAFEOP]]></Comment>
+					<Requires>cycle</Requires>
+					<Cmd>5</Cmd>
+					<Adp>1001</Adp>
+					<Ado>288</Ado>
+					<Data>0400</Data>
+					<Retries>3</Retries>
+					<Timeout>200</Timeout>
+				</InitCmd>
+				<InitCmd>
+					<Transition>SP</Transition>
+					<Transition>SI</Transition>
+					<Transition>OP</Transition>
+					<Transition>OI</Transition>
+					<Comment><![CDATA[clear fmmu 0]]></Comment>
+					<Cmd>5</Cmd>
+					<Adp>1001</Adp>
+					<Ado>1536</Ado>
+					<Data>00000000000000000000000000000000</Data>
+					<Retries>3</Retries>
+				</InitCmd>
+				<InitCmd>
+					<Transition>SP</Transition>
+					<Transition>SI</Transition>
+					<Transition>OP</Transition>
+					<Transition>OI</Transition>
+					<Comment><![CDATA[clear fmmu 1]]></Comment>
+					<Cmd>5</Cmd>
+					<Adp>1001</Adp>
+					<Ado>1552</Ado>
+					<Data>00000000000000000000000000000000</Data>
+					<Retries>3</Retries>
+				</InitCmd>
+				<InitCmd>
+					<Transition>PI</Transition>
+					<Transition>BI</Transition>
+					<Transition>SI</Transition>
+					<Transition>OI</Transition>
+					<Comment><![CDATA[clear fmmu 2]]></Comment>
+					<Cmd>5</Cmd>
+					<Adp>1001</Adp>
+					<Ado>1568</Ado>
+					<Data>00000000000000000000000000000000</Data>
+					<Retries>3</Retries>
+				</InitCmd>
+				<InitCmd>
+					<Transition>SP</Transition>
+					<Transition>OP</Transition>
+					<Comment><![CDATA[check device state for PREOP]]></Comment>
+					<Requires>cycle</Requires>
+					<Cmd>4</Cmd>
+					<Adp>1001</Adp>
+					<Ado>304</Ado>
+					<Data>000000000000</Data>
+					<Retries>3</Retries>
+					<Validate>
+						<Data>020000000000</Data>
+						<DataMask>0f0000000000</DataMask>
+						<Timeout>5000</Timeout>
+					</Validate>
+				</InitCmd>
+				<InitCmd>
+					<Transition>IP</Transition>
+					<Transition>IB</Transition>
+					<Comment><![CDATA[assign EEPROM to PDI]]></Comment>
+					<Requires>cycle</Requires>
+					<Cmd>5</Cmd>
+					<Adp>1001</Adp>
+					<Ado>1280</Ado>
+					<Data>01</Data>
+					<Cnt>1</Cnt>
+					<Retries>3</Retries>
+				</InitCmd>
+				<InitCmd>
+					<Transition>II</Transition>
+					<Comment><![CDATA[assign EEPROM back to ECAT]]></Comment>
+					<Requires>cycle</Requires>
+					<Cmd>2</Cmd>
+					<Adp>0</Adp>
+					<Ado>1280</Ado>
+					<Data>00</Data>
+					<Retries>3</Retries>
+				</InitCmd>
+				<InitCmd>
+					<Transition>IP</Transition>
+					<Comment><![CDATA[set device state to PREOP]]></Comment>
+					<Requires>cycle</Requires>
+					<Cmd>5</Cmd>
+					<Adp>1001</Adp>
+					<Ado>288</Ado>
+					<Data>1200</Data>
+					<Cnt>1</Cnt>
+					<Retries>300</Retries>
+					<Timeout>2000</Timeout>
+				</InitCmd>
+				<InitCmd>
+					<Transition>IP</Transition>
+					<Comment><![CDATA[check device state for PREOP]]></Comment>
+					<Requires>cycle</Requires>
+					<Cmd>4</Cmd>
+					<Adp>1001</Adp>
+					<Ado>304</Ado>
+					<Data>000000000000</Data>
+					<Cnt>1</Cnt>
+					<Retries>3</Retries>
+					<Validate>
+						<Data>020000000000</Data>
+						<DataMask>1f0000000000</DataMask>
+						<Timeout>2000</Timeout>
+					</Validate>
+				</InitCmd>
+				<InitCmd>
+					<Transition>IP</Transition>
+					<Transition>BI</Transition>
+					<Comment><![CDATA[assign EEPROM back to ECAT]]></Comment>
+					<Requires>cycle</Requires>
+					<Cmd>2</Cmd>
+					<Adp>0</Adp>
+					<Ado>1280</Ado>
+					<Data>00</Data>
+					<Retries>3</Retries>
+				</InitCmd>
+				<InitCmd>
+					<Transition>IB</Transition>
+					<Comment><![CDATA[set device state to BOOT]]></Comment>
+					<Requires>cycle</Requires>
+					<Cmd>5</Cmd>
+					<Adp>1001</Adp>
+					<Ado>288</Ado>
+					<Data>1300</Data>
+					<Cnt>1</Cnt>
+					<Retries>3</Retries>
+					<Timeout>2000</Timeout>
+				</InitCmd>
+				<InitCmd>
+					<Transition>IB</Transition>
+					<Comment><![CDATA[check device state for BOOT]]></Comment>
+					<Requires>cycle</Requires>
+					<Cmd>4</Cmd>
+					<Adp>1001</Adp>
+					<Ado>304</Ado>
+					<Data>000000000000</Data>
+					<Cnt>1</Cnt>
+					<Retries>3</Retries>
+					<Validate>
+						<Data>030000000000</Data>
+						<DataMask>1f0000000000</DataMask>
+						<Timeout>2000</Timeout>
+					</Validate>
+				</InitCmd>
+				<InitCmd>
+					<Transition>PS</Transition>
+					<Comment><![CDATA[set device state to SAFEOP]]></Comment>
+					<Requires>cycle</Requires>
+					<Cmd>5</Cmd>
+					<Adp>1001</Adp>
+					<Ado>288</Ado>
+					<Data>0400</Data>
+					<Cnt>1</Cnt>
+					<Retries>3</Retries>
+					<Timeout>9000</Timeout>
+				</InitCmd>
+				<InitCmd>
+					<Transition>PS</Transition>
+					<Comment><![CDATA[check device state for SAFEOP]]></Comment>
+					<Requires>cycle</Requires>
+					<Cmd>4</Cmd>
+					<Adp>1001</Adp>
+					<Ado>304</Ado>
+					<Data>000000000000</Data>
+					<Cnt>1</Cnt>
+					<Retries>3</Retries>
+					<Validate>
+						<Data>040000000000</Data>
+						<DataMask>1f0000000000</DataMask>
+						<Timeout>9000</Timeout>
+					</Validate>
+				</InitCmd>
+				<InitCmd>
+					<Transition>OS</Transition>
+					<Comment><![CDATA[check device state for SAFEOP]]></Comment>
+					<Requires>cycle</Requires>
+					<Cmd>4</Cmd>
+					<Adp>1001</Adp>
+					<Ado>304</Ado>
+					<Data>000000000000</Data>
+					<Retries>3</Retries>
+					<Validate>
+						<Data>040000000000</Data>
+						<DataMask>0f0000000000</DataMask>
+						<Timeout>200</Timeout>
+					</Validate>
+				</InitCmd>
+				<InitCmd>
+					<Transition>SO</Transition>
+					<Comment><![CDATA[set device state to OP]]></Comment>
+					<Requires>cycle</Requires>
+					<Cmd>5</Cmd>
+					<Adp>1001</Adp>
+					<Ado>288</Ado>
+					<Data>0800</Data>
+					<Cnt>1</Cnt>
+					<Retries>3</Retries>
+					<Timeout>9000</Timeout>
+				</InitCmd>
+				<InitCmd>
+					<Transition>SO</Transition>
+					<Comment><![CDATA[check device state for OP]]></Comment>
+					<Requires>cycle</Requires>
+					<Cmd>4</Cmd>
+					<Adp>1001</Adp>
+					<Ado>304</Ado>
+					<Data>000000000000</Data>
+					<Cnt>1</Cnt>
+					<Retries>3</Retries>
+					<Validate>
+						<Data>080000000000</Data>
+						<DataMask>1f0000000000</DataMask>
+						<Timeout>9000</Timeout>
+					</Validate>
+				</InitCmd>
+			</InitCmds>
+		</Slave>
+		<Cyclic>
+			<Comment><![CDATA[synchronized with task 'NC-Task 1 SAF']]></Comment>
+			<CycleTime>2000</CycleTime>
+			<Priority>4</Priority>
+			<TaskId>1</TaskId>
+			<Frame>
+				<Cmd>
+					<State>PREOP</State>
+					<State>SAFEOP</State>
+					<State>OP</State>
+					<Comment><![CDATA[cyclic cmd]]></Comment>
+					<Cmd>10</Cmd>
+					<Addr>150994944</Addr>
+					<DataLength>1</DataLength>
+					<InputOffs>16</InputOffs>
+					<OutputOffs>16</OutputOffs>
+				</Cmd>
+				<Cmd>
+					<State>SAFEOP</State>
+					<State>OP</State>
+					<Comment><![CDATA[cyclic cmd]]></Comment>
+					<Cmd>12</Cmd>
+					<Addr>16777216</Addr>
+					<DataLength>8</DataLength>
+					<Cnt>3</Cnt>
+					<InputOffs>29</InputOffs>
+					<OutputOffs>29</OutputOffs>
+				</Cmd>
+				<Cmd>
+					<State>PREOP</State>
+					<State>SAFEOP</State>
+					<State>OP</State>
+					<Comment><![CDATA[cyclic cmd]]></Comment>
+					<Cmd>7</Cmd>
+					<Adp>0</Adp>
+					<Ado>304</Ado>
+					<DataLength>2</DataLength>
+					<Cnt>1</Cnt>
+					<InputOffs>49</InputOffs>
+					<OutputOffs>49</OutputOffs>
+				</Cmd>
+			</Frame>
+		</Cyclic>
+		<ProcessImage>
+			<Inputs>
+				<ByteSize>1536</ByteSize>
+				<Variable>
+					<Name>Drive 1 (ECAT_CIA402).Module 1 (csv -  axis).Inputs.Status Word</Name>
+					<Comment><![CDATA[object 0x6041:0]]></Comment>
+					<DataType>UINT</DataType>
+					<BitSize>16</BitSize>
+					<BitOffs>312</BitOffs>
+				</Variable>
+				<Variable>
+					<Name>Drive 1 (ECAT_CIA402).Module 1 (csv -  axis).Inputs.ActualPosition</Name>
+					<Comment><![CDATA[object 0x6064:0]]></Comment>
+					<DataType>DINT</DataType>
+					<BitSize>32</BitSize>
+					<BitOffs>328</BitOffs>
+				</Variable>
+				<Variable>
+					<Name>Inputs.Frm0State</Name>
+					<Comment><![CDATA[0x0001 = 1. EtherCAT command not sent (NOP requested)
+0x0002 = 2. EtherCAT command not sent (NOP requested)
+0x0004 = 3. EtherCAT command not sent (NOP requested)
+...
+0x4000 = 15. EtherCAT command not sent (NOP requested)
+0x8000 = complete frame not sent
+]]></Comment>
+					<DataType>UINT</DataType>
+					<BitSize>16</BitSize>
+					<BitOffs>12160</BitOffs>
+				</Variable>
+				<Variable>
+					<Name>Inputs.Frm0WcState</Name>
+					<Comment><![CDATA[0x0001 = wrong working counter of 1. EtherCAT command received
+0x0002 = wrong working counter of 2. EtherCAT command received
+0x0004 = wrong working counter of 3. EtherCAT command received
+...
+0x4000 = wrong working counter of 15. EtherCAT command received
+0x8000 = complete frame missing
+]]></Comment>
+					<DataType>UINT</DataType>
+					<BitSize>16</BitSize>
+					<BitOffs>12176</BitOffs>
+				</Variable>
+				<Variable>
+					<Name>Drive 1 (ECAT_CIA402).WcState.WcState</Name>
+					<Comment><![CDATA[0 = Data valid
+1 = Data invalid
+]]></Comment>
+					<DataType>BIT</DataType>
+					<BitSize>1</BitSize>
+					<BitOffs>12177</BitOffs>
+				</Variable>
+				<Variable>
+					<Name>Inputs.Frm0InputToggle</Name>
+					<Comment><![CDATA[0x0001 = Toggle Bit: 1. EtherCAT command received new inputs
+0x0002 = Toggle Bit: 2. EtherCAT command received new inputs
+0x0004 = Toggle Bit: 3. EtherCAT command received new inputs
+...
+0x4000 = Toggle Bit: 15. EtherCAT command received new inputs
+0x8000 = Old frame - not from the actual cycle - received
+]]></Comment>
+					<DataType>UINT</DataType>
+					<BitSize>16</BitSize>
+					<BitOffs>12192</BitOffs>
+				</Variable>
+				<Variable>
+					<Name>Drive 1 (ECAT_CIA402).WcState.InputToggle</Name>
+					<DataType>BIT</DataType>
+					<BitSize>1</BitSize>
+					<BitOffs>12193</BitOffs>
+				</Variable>
+				<Variable>
+					<Name>SyncUnits.&lt;default&gt;.NC-Task 1 SAF.WcState.WcState</Name>
+					<Comment><![CDATA[0 = Data valid
+1 = Data invalid
+]]></Comment>
+					<DataType>BIT</DataType>
+					<BitSize>1</BitSize>
+					<BitOffs>12208</BitOffs>
+				</Variable>
+				<Variable>
+					<Name>Inputs.SlaveCount</Name>
+					<Comment><![CDATA[Actual count of EtherCAT slaves received]]></Comment>
+					<DataType>UINT</DataType>
+					<BitSize>16</BitSize>
+					<BitOffs>12240</BitOffs>
+				</Variable>
+				<Variable>
+					<Name>Inputs.DevState</Name>
+					<Comment><![CDATA[0x0001 = Link error
+0x0002 = I/O locked after link error (I/O reset required)
+0x0004 = Link error (redundancy adapter)
+0x0008 = Missing one frame (redundancy mode)
+0x0010 = Out of send resources (I/O reset required)
+0x0020 = Watchdog triggered
+0x0040 = Ethernet driver (miniport) not found
+0x0080 = I/O reset active
+0x0100 = At least one device in 'INIT' state
+0x0200 = At least one device in 'PRE-OP' state
+0x0400 = At least one device in 'SAFE-OP' state
+0x0800 = At least one device indicates an error state
+0x1000 = DC not in sync
+]]></Comment>
+					<DataType>UINT</DataType>
+					<BitSize>16</BitSize>
+					<BitOffs>12272</BitOffs>
+				</Variable>
+				<Variable>
+					<Name>InfoData.ChangeCount</Name>
+					<Comment><![CDATA[Info data change counter]]></Comment>
+					<DataType>UINT</DataType>
+					<BitSize>16</BitSize>
+					<BitOffs>12288</BitOffs>
+				</Variable>
+				<Variable>
+					<Name>InfoData.DevId</Name>
+					<Comment><![CDATA[DeviceId of EtherCAT device]]></Comment>
+					<DataType>UINT</DataType>
+					<BitSize>16</BitSize>
+					<BitOffs>12304</BitOffs>
+				</Variable>
+				<Variable>
+					<Name>InfoData.AmsNetId</Name>
+					<Comment><![CDATA[AmsNetId of EtherCAT device]]></Comment>
+					<DataType>AMSNETID</DataType>
+					<BitSize>48</BitSize>
+					<BitOffs>12320</BitOffs>
+				</Variable>
+				<Variable>
+					<Name>InfoData.CfgSlaveCount</Name>
+					<Comment><![CDATA[Count of configured EtherCAT slaves]]></Comment>
+					<DataType>UINT</DataType>
+					<BitSize>16</BitSize>
+					<BitOffs>12368</BitOffs>
+				</Variable>
+				<Variable>
+					<Name>Drive 1 (ECAT_CIA402).InfoData.State</Name>
+					<Comment><![CDATA[0x___1 = Slave in 'INIT' state
+0x___2 = Slave in 'PREOP' state
+0x___3 = Slave in 'BOOT' state
+0x___4 = Slave in 'SAFEOP' state
+0x___8 = Slave in 'OP' state
+0x001_ = Slave signals error
+0x002_ = Invalid vendorId, productCode... read
+0x004_ = Initialization error occurred
+0x008_ = Slave disabled
+0x010_ = Slave not present
+0x020_ = Slave signals link error
+0x040_ = Slave signals missing link
+0x080_ = Slave signals unexpected link
+0x100_ = Communication port A
+0x200_ = Communication port B
+0x400_ = Communication port C
+0x800_ = Communication port D
+]]></Comment>
+					<DataType>UINT</DataType>
+					<BitSize>16</BitSize>
+					<BitOffs>12384</BitOffs>
+				</Variable>
+				<Variable>
+					<Name>Drive 1 (ECAT_CIA402).InfoData.AdsAddr</Name>
+					<Comment><![CDATA[Complete ADS address to access the slave (mailbox)]]></Comment>
+					<DataType>AMSADDR</DataType>
+					<BitSize>64</BitSize>
+					<BitOffs>12400</BitOffs>
+				</Variable>
+				<Variable>
+					<Name>Drive 1 (ECAT_CIA402).InfoData.Chn0</Name>
+					<Comment><![CDATA[Slave has a channel]]></Comment>
+					<DataType>USINT</DataType>
+					<BitSize>8</BitSize>
+					<BitOffs>12464</BitOffs>
+				</Variable>
+				<Variable>
+					<Name>Drive 1 (ECAT_CIA402).InfoData.Chn1</Name>
+					<Comment><![CDATA[Slave has a channel]]></Comment>
+					<DataType>USINT</DataType>
+					<BitSize>8</BitSize>
+					<BitOffs>12472</BitOffs>
+				</Variable>
+				<Variable>
+					<Name>SyncUnits.&lt;default&gt;.NC-Task 1 SAF.InfoData.ObjectId</Name>
+					<DataType>OTCID</DataType>
+					<BitSize>32</BitSize>
+					<BitOffs>12480</BitOffs>
+				</Variable>
+				<Variable>
+					<Name>SyncUnits.&lt;default&gt;.NC-Task 1 SAF.InfoData.State</Name>
+					<Comment><![CDATA[0x___1 = At least one slave in 'INIT' state
+0x___2 = At least one slave in 'PREOP' state
+0x___3 = At least one slave in 'BOOT' state
+0x___4 = At least one slave in 'SAFEOP' state
+0x___8 = At least one slave in 'OP' state
+0x001_ = At least one slave signals error
+0x002_ = Invalid vendorId, productCode... read
+0x004_ = Initialization error occurred
+0x008_ = At least one slave disabled
+0x010_ = At least one slave not present
+0x020_ = At least one slave signals link error
+0x040_ = At least one slave signals missing link
+0x080_ = At least one slave signals unexpected link
+]]></Comment>
+					<DataType>UINT</DataType>
+					<BitSize>16</BitSize>
+					<BitOffs>12512</BitOffs>
+				</Variable>
+				<Variable>
+					<Name>SyncUnits.&lt;default&gt;.NC-Task 1 SAF.InfoData.SlaveCount</Name>
+					<Comment><![CDATA[Info data slave counter]]></Comment>
+					<DataType>UINT</DataType>
+					<BitSize>16</BitSize>
+					<BitOffs>12528</BitOffs>
+				</Variable>
+			</Inputs>
+			<Outputs>
+				<ByteSize>1536</ByteSize>
+				<Variable>
+					<Name>Drive 1 (ECAT_CIA402).Module 1 (csv -  axis).Outputs.Control Word</Name>
+					<Comment><![CDATA[object 0x6040:0]]></Comment>
+					<DataType>UINT</DataType>
+					<BitSize>16</BitSize>
+					<BitOffs>312</BitOffs>
+				</Variable>
+				<Variable>
+					<Name>Drive 1 (ECAT_CIA402).Module 1 (csv -  axis).Outputs.TargetVelocity</Name>
+					<Comment><![CDATA[object 0x60FF:0]]></Comment>
+					<DataType>DINT</DataType>
+					<BitSize>32</BitSize>
+					<BitOffs>328</BitOffs>
+				</Variable>
+				<Variable>
+					<Name>Outputs.Frm0Ctrl</Name>
+					<Comment><![CDATA[0x0001 = prevent 1. EtherCAT command from sending (request NOP)
+0x0002 = prevent 2. EtherCAT command from sending (request NOP)
+0x0004 = prevent 3. EtherCAT command from sending (request NOP)
+...
+0x4000 = prevent 15. EtherCAT command from sending (request NOP)
+0x8000 = prevent complete frame from sending
+]]></Comment>
+					<DataType>UINT</DataType>
+					<BitSize>16</BitSize>
+					<BitOffs>12160</BitOffs>
+				</Variable>
+				<Variable>
+					<Name>Outputs.Frm0WcCtrl</Name>
+					<Comment><![CDATA[0x0001 = copy data with wrong working counter of 1. EtherCAT command
+0x0002 = copy data with wrong working counter of 2. EtherCAT command
+0x0004 = copy data with wrong working counter of 3. EtherCAT command
+...
+0x4000 = copy data with wrong working counter of 15. EtherCAT command
+]]></Comment>
+					<DataType>UINT</DataType>
+					<BitSize>16</BitSize>
+					<BitOffs>12176</BitOffs>
+				</Variable>
+				<Variable>
+					<Name>Outputs.DevCtrl</Name>
+					<DataType>UINT</DataType>
+					<BitSize>16</BitSize>
+					<BitOffs>12272</BitOffs>
+				</Variable>
+			</Outputs>
+		</ProcessImage>
+	</Config>
+</EtherCATConfig>

+ 2141 - 0
scripts/ECAT_CIA402_ESI.xml

@@ -0,0 +1,2141 @@
+<?xml version="1.0" encoding="utf-8"?>
+<EtherCATInfo xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="EtherCATInfo.xsd" Version="1.6">
+	<Vendor>
+		<Id>#x0048504D</Id>
+		<Name>HPMicro</Name>
+		<ImageData16x14>424DE6000000000000007600000028000000100000000E000000010004000000000070000000120B0000120B0000100000001000000000000000000080000080000000808000800000008000800080800000C0C0C000808080000000FF0000FF000000FFFF00FF000000FF00FF00FFFF0000FFFFFF009D9DD99DD9DDD9DD9D9D9DD9D9DDD9DD999D9DD9D999D9999D9D9DD9D9DDD9DD9D9DD99DD999D999DDDDDDDDDDDDDDDD88888888888888888888888888888888DDDDDDDDDDDDDDDD999D999DD99DD9D99D9D9DDD9DD9D9D999DD999D9DDDD99D9D9D9DDD9DD9D99D999D999DD99DD9D9</ImageData16x14>
+	</Vendor>
+	<Descriptions>
+		<Groups>
+			<Group>
+				<Type>ECAT_Device</Type>
+				<Name>ECAT_Device</Name>
+				<ImageData16x14>424DD8020000000000003600000028000000100000000E0000000100180000000000A2020000120B0000120B000000000000000000001306E31306E3190CE42B1FE62B1FE61306E31F13E5190CE42519E51306E31306E3190CE42F24E7190CE41306E31306E31306E31306E35F56EC645CED645CED4137E91F13E5473DE95F57EC3227E71306E3473DE95A51EC271BE61306E31306E31409CA524CC68E8AD74F48C1615CC82218D03E36BF716BCE746FCE453DC01307CE3931BA7D78D27671D1150CB21409CA1712801B1D1D1B1D1D1B1D1D1B1D1D120B891B1D1D1B1D1D1B1D1D1B1D1D120B891B1D1D1B1D1D1B1D1D1B1D1D1712801712807F8080D4D5D5D4D5D5383939120B89545656D4D5D5D4D5D5626464130C89292B2BD4D5D5D4D5D56264641915801712804647471B1D1DAAAAAAD4D5D5130E82383939292B2B717272D4D5D5151183D4D5D57F80801B1D1D7172721E1C81191580464747D4D5D5D4D5D51B1D1D19158A292B2BD4D5D5D4D5D5292B2B1B1B8AD4D5D56264641B1D1D1B1D1D2427821E1D81D4D5D54647476264643839391E208BD4D5D57F8080464747545656242A8BD4D5D59B9C9C292B2BAAAAAA2D3683252882464747D4D5D5D4D5D51B1D1D272D85292B2BD4D5D5D4D5D5292B2B2E37861B1D1DD4D5D5D4D5D5464747394484323BB52324812122822426822526824554C0323883292B822A2D83353C84424CBF3238843940842E32834853865D6EBB5262EB3E43E83334E74147E94349E9535FEB4D56EA5662EB484DEA545DEB636FED545AEA5A63EC6671ED8CA0F290A5F2748AEF6B7BEE5D68EC6874ED788AEF8397F17684EF7986EF8C9FF2818FF1818EF08E9DF18A97F18791F19BA9F3B0C0F691A4F291A2F28390F192A1F29CACF3A3B3F498A6F3A4B3F4AEBDF5B0BEF59EA8F3A3ADF4BBC7F7C4D1F8CAD7F8CED9F9B4C4F6B8C8F6ACB8F59AA3F3B6C1F6C5D2F8C2CDF8CCD7F9D2DDF9D5E0FAD2DAF9D5DCF9DFE7FBE2E9FBE5EBFBE8EEFB0000</ImageData16x14>
+			</Group>
+		</Groups>
+		<Devices>
+			<Device Physics="YYY">
+				<Type ProductCode="#x00000003" RevisionNo="#x00000001">ECAT_CIA402</Type>
+				<Name>ECAT_CIA402</Name>
+				<Info>
+					<StateMachine>
+						<Timeout>
+							<PreopTimeout>2000</PreopTimeout>
+							<SafeopOpTimeout>9000</SafeopOpTimeout>
+							<BackToInitTimeout>5000</BackToInitTimeout>
+							<BackToSafeopTimeout>200</BackToSafeopTimeout>
+						</Timeout>
+					</StateMachine>
+					<Mailbox>
+						<Timeout>
+							<RequestTimeout>100</RequestTimeout>
+							<ResponseTimeout>2000</ResponseTimeout>
+						</Timeout>
+					</Mailbox>
+					<EtherCATController>
+						<DpramSize>61440</DpramSize>
+						<SmCount>8</SmCount>
+						<FmmuCount>8</FmmuCount>
+					</EtherCATController>
+					<IdentificationReg134>true</IdentificationReg134>
+				</Info>
+				<GroupType>ECAT_Device</GroupType>
+				<Profile>
+					<ChannelInfo>
+						<ProfileNo>402</ProfileNo>
+						<AddInfo>2</AddInfo>
+					</ChannelInfo>
+					<ChannelInfo>
+						<ProfileNo>402</ProfileNo>
+						<AddInfo>0</AddInfo>
+					</ChannelInfo>
+					<Dictionary>
+						<DataTypes>
+							<DataType>
+								<Name>STRING(3)</Name>
+								<BitSize>24</BitSize>
+							</DataType>
+							<DataType>
+								<Name>STRING(11)</Name>
+								<BitSize>88</BitSize>
+							</DataType>
+							<DataType>
+								<Name>USINT</Name>
+								<BitSize>8</BitSize>
+							</DataType>
+							<DataType>
+								<Name>UDINT</Name>
+								<BitSize>32</BitSize>
+							</DataType>
+							<DataType>
+								<Name>UINT</Name>
+								<BitSize>16</BitSize>
+							</DataType>
+							<DataType>
+								<Name>ULINT</Name>
+								<BitSize>64</BitSize>
+							</DataType>
+							<DataType>
+								<Name>BOOL</Name>
+								<BitSize>1</BitSize>
+							</DataType>
+							<DataType>
+								<Name>DT1018</Name>
+								<BitSize>144</BitSize>
+								<SubItem>
+									<SubIdx>0</SubIdx>
+									<Name>SubIndex 000</Name>
+									<Type>USINT</Type>
+									<BitSize>8</BitSize>
+									<BitOffs>0</BitOffs>
+									<Flags>
+										<Access>ro</Access>
+									</Flags>
+								</SubItem>
+								<SubItem>
+									<SubIdx>1</SubIdx>
+									<Name>Vendor ID</Name>
+									<Type>UDINT</Type>
+									<BitSize>32</BitSize>
+									<BitOffs>16</BitOffs>
+									<Flags>
+										<Access>ro</Access>
+									</Flags>
+								</SubItem>
+								<SubItem>
+									<SubIdx>2</SubIdx>
+									<Name>Product Code</Name>
+									<Type>UDINT</Type>
+									<BitSize>32</BitSize>
+									<BitOffs>48</BitOffs>
+									<Flags>
+										<Access>ro</Access>
+									</Flags>
+								</SubItem>
+								<SubItem>
+									<SubIdx>3</SubIdx>
+									<Name>Revision Number</Name>
+									<Type>UDINT</Type>
+									<BitSize>32</BitSize>
+									<BitOffs>80</BitOffs>
+									<Flags>
+										<Access>ro</Access>
+									</Flags>
+								</SubItem>
+								<SubItem>
+									<SubIdx>4</SubIdx>
+									<Name>Serial number</Name>
+									<Type>UDINT</Type>
+									<BitSize>32</BitSize>
+									<BitOffs>112</BitOffs>
+									<Flags>
+										<Access>ro</Access>
+									</Flags>
+								</SubItem>
+							</DataType>
+							<DataType>
+								<Name>DT10F1</Name>
+								<BitSize>64</BitSize>
+								<SubItem>
+									<SubIdx>0</SubIdx>
+									<Name>SubIndex 000</Name>
+									<Type>USINT</Type>
+									<BitSize>8</BitSize>
+									<BitOffs>0</BitOffs>
+									<Flags>
+										<Access>ro</Access>
+									</Flags>
+								</SubItem>
+								<SubItem>
+									<SubIdx>1</SubIdx>
+									<Name>Local Error Reaction</Name>
+									<Type>UDINT</Type>
+									<BitSize>32</BitSize>
+									<BitOffs>16</BitOffs>
+									<Flags>
+										<Access>ro</Access>
+									</Flags>
+								</SubItem>
+								<SubItem>
+									<SubIdx>2</SubIdx>
+									<Name>Sync Error Counter Limit</Name>
+									<Type>UINT</Type>
+									<BitSize>16</BitSize>
+									<BitOffs>48</BitOffs>
+									<Flags>
+										<Access>rw</Access>
+									</Flags>
+								</SubItem>
+							</DataType>
+							<DataType>
+								<Name>DT1C00ARR</Name>
+								<BaseType>USINT</BaseType>
+								<BitSize>32</BitSize>
+								<ArrayInfo>
+									<LBound>1</LBound>
+									<Elements>4</Elements>
+								</ArrayInfo>
+							</DataType>
+							<DataType>
+								<Name>DT1C00</Name>
+								<BitSize>48</BitSize>
+								<SubItem>
+									<SubIdx>0</SubIdx>
+									<Name>SubIndex 000</Name>
+									<Type>USINT</Type>
+									<BitSize>8</BitSize>
+									<BitOffs>0</BitOffs>
+									<Flags>
+										<Access>ro</Access>
+									</Flags>
+								</SubItem>
+								<SubItem>
+									<Name>Elements</Name>
+									<Type>DT1C00ARR</Type>
+									<BitSize>32</BitSize>
+									<BitOffs>16</BitOffs>
+									<Flags>
+										<Access>ro</Access>
+									</Flags>
+								</SubItem>
+							</DataType>
+							<DataType>
+								<Name>DT1C12ARR</Name>
+								<BaseType>UINT</BaseType>
+								<BitSize>32</BitSize>
+								<ArrayInfo>
+									<LBound>1</LBound>
+									<Elements>2</Elements>
+								</ArrayInfo>
+							</DataType>
+							<DataType>
+								<Name>DT1C12</Name>
+								<BitSize>48</BitSize>
+								<SubItem>
+									<SubIdx>0</SubIdx>
+									<Name>SubIndex 000</Name>
+									<Type>USINT</Type>
+									<BitSize>8</BitSize>
+									<BitOffs>0</BitOffs>
+									<Flags>
+										<Access WriteRestrictions="PreOP">rw</Access>
+									</Flags>
+								</SubItem>
+								<SubItem>
+									<Name>Elements</Name>
+									<Type>DT1C12ARR</Type>
+									<BitSize>32</BitSize>
+									<BitOffs>16</BitOffs>
+									<Flags>
+										<Access WriteRestrictions="PreOP">rw</Access>
+									</Flags>
+								</SubItem>
+							</DataType>
+							<DataType>
+								<Name>DT1C13ARR</Name>
+								<BaseType>UINT</BaseType>
+								<BitSize>32</BitSize>
+								<ArrayInfo>
+									<LBound>1</LBound>
+									<Elements>2</Elements>
+								</ArrayInfo>
+							</DataType>
+							<DataType>
+								<Name>DT1C13</Name>
+								<BitSize>48</BitSize>
+								<SubItem>
+									<SubIdx>0</SubIdx>
+									<Name>SubIndex 000</Name>
+									<Type>USINT</Type>
+									<BitSize>8</BitSize>
+									<BitOffs>0</BitOffs>
+									<Flags>
+										<Access WriteRestrictions="PreOP">rw</Access>
+									</Flags>
+								</SubItem>
+								<SubItem>
+									<Name>Elements</Name>
+									<Type>DT1C13ARR</Type>
+									<BitSize>32</BitSize>
+									<BitOffs>16</BitOffs>
+									<Flags>
+										<Access WriteRestrictions="PreOP">rw</Access>
+									</Flags>
+								</SubItem>
+							</DataType>
+							<DataType>
+								<Name>DT1C32</Name>
+								<BitSize>488</BitSize>
+								<SubItem>
+									<SubIdx>0</SubIdx>
+									<Name>SubIndex 000</Name>
+									<Type>USINT</Type>
+									<BitSize>8</BitSize>
+									<BitOffs>0</BitOffs>
+									<Flags>
+										<Access>ro</Access>
+									</Flags>
+								</SubItem>
+								<SubItem>
+									<SubIdx>1</SubIdx>
+									<Name>Synchronization Type</Name>
+									<Type>UINT</Type>
+									<BitSize>16</BitSize>
+									<BitOffs>16</BitOffs>
+									<Flags>
+										<Access WriteRestrictions="PreOP">rw</Access>
+									</Flags>
+								</SubItem>
+								<SubItem>
+									<SubIdx>2</SubIdx>
+									<Name>Cycle Time</Name>
+									<Type>UDINT</Type>
+									<BitSize>32</BitSize>
+									<BitOffs>32</BitOffs>
+									<Flags>
+										<Access>ro</Access>
+									</Flags>
+								</SubItem>
+								<SubItem>
+									<SubIdx>4</SubIdx>
+									<Name>Synchronization Types supported</Name>
+									<Type>UINT</Type>
+									<BitSize>16</BitSize>
+									<BitOffs>96</BitOffs>
+									<Flags>
+										<Access>ro</Access>
+									</Flags>
+								</SubItem>
+								<SubItem>
+									<SubIdx>5</SubIdx>
+									<Name>Minimum Cycle Time</Name>
+									<Type>UDINT</Type>
+									<BitSize>32</BitSize>
+									<BitOffs>112</BitOffs>
+									<Flags>
+										<Access>ro</Access>
+									</Flags>
+								</SubItem>
+								<SubItem>
+									<SubIdx>6</SubIdx>
+									<Name>Calc and Copy Time</Name>
+									<Type>UDINT</Type>
+									<BitSize>32</BitSize>
+									<BitOffs>144</BitOffs>
+									<Flags>
+										<Access>ro</Access>
+									</Flags>
+								</SubItem>
+								<SubItem>
+									<SubIdx>8</SubIdx>
+									<Name>Get Cycle Time</Name>
+									<Type>UINT</Type>
+									<BitSize>16</BitSize>
+									<BitOffs>208</BitOffs>
+									<Flags>
+										<Access>rw</Access>
+									</Flags>
+								</SubItem>
+								<SubItem>
+									<SubIdx>9</SubIdx>
+									<Name>Delay Time</Name>
+									<Type>UDINT</Type>
+									<BitSize>32</BitSize>
+									<BitOffs>224</BitOffs>
+									<Flags>
+										<Access>ro</Access>
+									</Flags>
+								</SubItem>
+								<SubItem>
+									<SubIdx>10</SubIdx>
+									<Name>Sync0 Cycle Time</Name>
+									<Type>UDINT</Type>
+									<BitSize>32</BitSize>
+									<BitOffs>256</BitOffs>
+									<Flags>
+										<Access>rw</Access>
+									</Flags>
+								</SubItem>
+								<SubItem>
+									<SubIdx>11</SubIdx>
+									<Name>SM-Event Missed</Name>
+									<Type>UINT</Type>
+									<BitSize>16</BitSize>
+									<BitOffs>288</BitOffs>
+									<Flags>
+										<Access>ro</Access>
+									</Flags>
+								</SubItem>
+								<SubItem>
+									<SubIdx>12</SubIdx>
+									<Name>Cycle Time Too Small</Name>
+									<Type>UINT</Type>
+									<BitSize>16</BitSize>
+									<BitOffs>304</BitOffs>
+									<Flags>
+										<Access>ro</Access>
+									</Flags>
+								</SubItem>
+								<SubItem>
+									<SubIdx>13</SubIdx>
+									<Name>Shift Time Too Short Counter</Name>
+									<Type>UINT</Type>
+									<BitSize>16</BitSize>
+									<BitOffs>320</BitOffs>
+									<Flags>
+										<Access>ro</Access>
+									</Flags>
+								</SubItem>
+								<SubItem>
+									<SubIdx>32</SubIdx>
+									<Name>Sync Error</Name>
+									<Type>BOOL</Type>
+									<BitSize>1</BitSize>
+									<BitOffs>480</BitOffs>
+									<Flags>
+										<Access>ro</Access>
+									</Flags>
+								</SubItem>
+							</DataType>
+							<DataType>
+								<Name>DT1C33</Name>
+								<BitSize>488</BitSize>
+								<SubItem>
+									<SubIdx>0</SubIdx>
+									<Name>SubIndex 000</Name>
+									<Type>USINT</Type>
+									<BitSize>8</BitSize>
+									<BitOffs>0</BitOffs>
+									<Flags>
+										<Access>ro</Access>
+									</Flags>
+								</SubItem>
+								<SubItem>
+									<SubIdx>1</SubIdx>
+									<Name>Synchronization Type</Name>
+									<Type>UINT</Type>
+									<BitSize>16</BitSize>
+									<BitOffs>16</BitOffs>
+									<Flags>
+										<Access WriteRestrictions="PreOP">rw</Access>
+									</Flags>
+								</SubItem>
+								<SubItem>
+									<SubIdx>2</SubIdx>
+									<Name>Cycle Time</Name>
+									<Type>UDINT</Type>
+									<BitSize>32</BitSize>
+									<BitOffs>32</BitOffs>
+									<Flags>
+										<Access>ro</Access>
+									</Flags>
+								</SubItem>
+								<SubItem>
+									<SubIdx>4</SubIdx>
+									<Name>Synchronization Types supported</Name>
+									<Type>UINT</Type>
+									<BitSize>16</BitSize>
+									<BitOffs>96</BitOffs>
+									<Flags>
+										<Access>ro</Access>
+									</Flags>
+								</SubItem>
+								<SubItem>
+									<SubIdx>5</SubIdx>
+									<Name>Minimum Cycle Time</Name>
+									<Type>UDINT</Type>
+									<BitSize>32</BitSize>
+									<BitOffs>112</BitOffs>
+									<Flags>
+										<Access>ro</Access>
+									</Flags>
+								</SubItem>
+								<SubItem>
+									<SubIdx>6</SubIdx>
+									<Name>Calc and Copy Time</Name>
+									<Type>UDINT</Type>
+									<BitSize>32</BitSize>
+									<BitOffs>144</BitOffs>
+									<Flags>
+										<Access>ro</Access>
+									</Flags>
+								</SubItem>
+								<SubItem>
+									<SubIdx>8</SubIdx>
+									<Name>Get Cycle Time</Name>
+									<Type>UINT</Type>
+									<BitSize>16</BitSize>
+									<BitOffs>208</BitOffs>
+									<Flags>
+										<Access>rw</Access>
+									</Flags>
+								</SubItem>
+								<SubItem>
+									<SubIdx>9</SubIdx>
+									<Name>Delay Time</Name>
+									<Type>UDINT</Type>
+									<BitSize>32</BitSize>
+									<BitOffs>224</BitOffs>
+									<Flags>
+										<Access>ro</Access>
+									</Flags>
+								</SubItem>
+								<SubItem>
+									<SubIdx>10</SubIdx>
+									<Name>Sync0 Cycle Time</Name>
+									<Type>UDINT</Type>
+									<BitSize>32</BitSize>
+									<BitOffs>256</BitOffs>
+									<Flags>
+										<Access>rw</Access>
+									</Flags>
+								</SubItem>
+								<SubItem>
+									<SubIdx>11</SubIdx>
+									<Name>SM-Event Missed</Name>
+									<Type>UINT</Type>
+									<BitSize>16</BitSize>
+									<BitOffs>288</BitOffs>
+									<Flags>
+										<Access>ro</Access>
+									</Flags>
+								</SubItem>
+								<SubItem>
+									<SubIdx>12</SubIdx>
+									<Name>Cycle Time Too Small</Name>
+									<Type>UINT</Type>
+									<BitSize>16</BitSize>
+									<BitOffs>304</BitOffs>
+									<Flags>
+										<Access>ro</Access>
+									</Flags>
+								</SubItem>
+								<SubItem>
+									<SubIdx>13</SubIdx>
+									<Name>Shift Time Too Short Counter</Name>
+									<Type>UINT</Type>
+									<BitSize>16</BitSize>
+									<BitOffs>320</BitOffs>
+									<Flags>
+										<Access>ro</Access>
+									</Flags>
+								</SubItem>
+								<SubItem>
+									<SubIdx>32</SubIdx>
+									<Name>Sync Error</Name>
+									<Type>BOOL</Type>
+									<BitSize>1</BitSize>
+									<BitOffs>480</BitOffs>
+									<Flags>
+										<Access>ro</Access>
+									</Flags>
+								</SubItem>
+							</DataType>
+							<DataType>
+								<Name>DTF000</Name>
+								<BitSize>48</BitSize>
+								<SubItem>
+									<SubIdx>0</SubIdx>
+									<Name>SubIndex 000</Name>
+									<Type>USINT</Type>
+									<BitSize>8</BitSize>
+									<BitOffs>0</BitOffs>
+									<Flags>
+										<Access>ro</Access>
+									</Flags>
+								</SubItem>
+								<SubItem>
+									<SubIdx>1</SubIdx>
+									<Name>Index distance</Name>
+									<Type>UINT</Type>
+									<BitSize>16</BitSize>
+									<BitOffs>16</BitOffs>
+									<Flags>
+										<Access>ro</Access>
+									</Flags>
+								</SubItem>
+								<SubItem>
+									<SubIdx>2</SubIdx>
+									<Name>Maximum number of modules</Name>
+									<Type>UINT</Type>
+									<BitSize>16</BitSize>
+									<BitOffs>32</BitOffs>
+									<Flags>
+										<Access>ro</Access>
+									</Flags>
+								</SubItem>
+							</DataType>
+							<DataType>
+								<Name>DTF010ARR</Name>
+								<BaseType>UDINT</BaseType>
+								<BitSize>64</BitSize>
+								<ArrayInfo>
+									<LBound>1</LBound>
+									<Elements>2</Elements>
+								</ArrayInfo>
+							</DataType>
+							<DataType>
+								<Name>DTF010</Name>
+								<BitSize>80</BitSize>
+								<SubItem>
+									<SubIdx>0</SubIdx>
+									<Name>SubIndex 000</Name>
+									<Type>USINT</Type>
+									<BitSize>8</BitSize>
+									<BitOffs>0</BitOffs>
+									<Flags>
+										<Access>ro</Access>
+									</Flags>
+								</SubItem>
+								<SubItem>
+									<Name>Elements</Name>
+									<Type>DTF010ARR</Type>
+									<BitSize>64</BitSize>
+									<BitOffs>16</BitOffs>
+									<Flags>
+										<Access>ro</Access>
+									</Flags>
+								</SubItem>
+							</DataType>
+							<DataType>
+								<Name>DTF030ARR</Name>
+								<BaseType>UDINT</BaseType>
+								<BitSize>64</BitSize>
+								<ArrayInfo>
+									<LBound>1</LBound>
+									<Elements>2</Elements>
+								</ArrayInfo>
+							</DataType>
+							<DataType>
+								<Name>DTF030</Name>
+								<BitSize>80</BitSize>
+								<SubItem>
+									<SubIdx>0</SubIdx>
+									<Name>SubIndex 000</Name>
+									<Type>USINT</Type>
+									<BitSize>8</BitSize>
+									<BitOffs>0</BitOffs>
+									<Flags>
+										<Access WriteRestrictions="PreOP">rw</Access>
+									</Flags>
+								</SubItem>
+								<SubItem>
+									<Name>Elements</Name>
+									<Type>DTF030ARR</Type>
+									<BitSize>64</BitSize>
+									<BitOffs>16</BitOffs>
+									<Flags>
+										<Access WriteRestrictions="PreOP">rw</Access>
+									</Flags>
+								</SubItem>
+							</DataType>
+							<DataType>
+								<Name>DTF050ARR</Name>
+								<BaseType>UDINT</BaseType>
+								<BitSize>64</BitSize>
+								<ArrayInfo>
+									<LBound>1</LBound>
+									<Elements>2</Elements>
+								</ArrayInfo>
+							</DataType>
+							<DataType>
+								<Name>DTF050</Name>
+								<BitSize>80</BitSize>
+								<SubItem>
+									<SubIdx>0</SubIdx>
+									<Name>SubIndex 000</Name>
+									<Type>USINT</Type>
+									<BitSize>8</BitSize>
+									<BitOffs>0</BitOffs>
+									<Flags>
+										<Access>ro</Access>
+									</Flags>
+								</SubItem>
+								<SubItem>
+									<Name>Elements</Name>
+									<Type>DTF050ARR</Type>
+									<BitSize>64</BitSize>
+									<BitOffs>16</BitOffs>
+									<Flags>
+										<Access>ro</Access>
+									</Flags>
+								</SubItem>
+							</DataType>
+						</DataTypes>
+						<Objects>
+							<Object>
+								<Index>#x1000</Index>
+								<Name>Device type</Name>
+								<Type>UDINT</Type>
+								<BitSize>32</BitSize>
+								<Info>
+									<DefaultData>92010000</DefaultData>
+								</Info>
+								<Flags>
+									<Access>ro</Access>
+								</Flags>
+							</Object>
+							<Object>
+								<Index>#x1001</Index>
+								<Name>Error register</Name>
+								<Type>USINT</Type>
+								<BitSize>8</BitSize>
+								<Info>
+									<DefaultData>00</DefaultData>
+								</Info>
+								<Flags>
+									<Access>ro</Access>
+								</Flags>
+							</Object>
+							<Object>
+								<Index>#x1008</Index>
+								<Name>Device name</Name>
+								<Type>STRING(11)</Type>
+								<BitSize>88</BitSize>
+								<Info>
+									<DefaultData>454341545F434941343032</DefaultData>
+								</Info>
+								<Flags>
+									<Access>ro</Access>
+								</Flags>
+							</Object>
+							<Object>
+								<Index>#x1009</Index>
+								<Name>Manufacturer Hardware version</Name>
+								<Type>STRING(11)</Type>
+								<BitSize>88</BitSize>
+								<Info>
+									<DefaultData>454341545F446576696365</DefaultData>
+								</Info>
+								<Flags>
+									<Access>ro</Access>
+								</Flags>
+							</Object>
+							<Object>
+								<Index>#x100A</Index>
+								<Name>Manufacturer Software version</Name>
+								<Type>STRING(3)</Type>
+								<BitSize>24</BitSize>
+								<Info>
+									<DefaultData>312E30</DefaultData>
+								</Info>
+								<Flags>
+									<Access>ro</Access>
+								</Flags>
+							</Object>
+							<Object>
+								<Index>#x1018</Index>
+								<Name>Identity Object</Name>
+								<Type>DT1018</Type>
+								<BitSize>144</BitSize>
+								<Info>
+									<SubItem>
+										<Name>SubIndex 000</Name>
+										<Info>
+											<DefaultData>04</DefaultData>
+										</Info>
+									</SubItem>
+									<SubItem>
+										<Name>Vendor ID</Name>
+										<Info>
+											<DefaultData>4D504800</DefaultData>
+										</Info>
+									</SubItem>
+									<SubItem>
+										<Name>Product Code</Name>
+										<Info>
+											<DefaultData>03000000</DefaultData>
+										</Info>
+									</SubItem>
+									<SubItem>
+										<Name>Revision Number</Name>
+										<Info>
+											<DefaultData>01000000</DefaultData>
+										</Info>
+									</SubItem>
+									<SubItem>
+										<Name>Serial number</Name>
+										<Info>
+											<DefaultData>00000000</DefaultData>
+										</Info>
+									</SubItem>
+								</Info>
+							</Object>
+							<Object>
+								<Index>#x10F1</Index>
+								<Name>Error Settings</Name>
+								<Type>DT10F1</Type>
+								<BitSize>64</BitSize>
+								<Info>
+									<SubItem>
+										<Name>SubIndex 000</Name>
+										<Info>
+											<DefaultData>02</DefaultData>
+										</Info>
+									</SubItem>
+									<SubItem>
+										<Name>Local Error Reaction</Name>
+										<Info>
+											<DefaultData>01000000</DefaultData>
+										</Info>
+									</SubItem>
+									<SubItem>
+										<Name>Sync Error Counter Limit</Name>
+										<Info>
+											<DefaultData>0400</DefaultData>
+										</Info>
+									</SubItem>
+								</Info>
+							</Object>
+							<Object>
+								<Index>#x10F8</Index>
+								<Name>Timestamp Object</Name>
+								<Type>ULINT</Type>
+								<BitSize>64</BitSize>
+								<Flags>
+									<Access>rw</Access>
+									<PdoMapping>t</PdoMapping>
+								</Flags>
+							</Object>
+							<Object>
+								<Index>#x1C00</Index>
+								<Name>Sync manager type</Name>
+								<Type>DT1C00</Type>
+								<BitSize>48</BitSize>
+								<Info>
+									<SubItem>
+										<Name>SubIndex 000</Name>
+										<Info>
+											<DefaultData>04</DefaultData>
+										</Info>
+									</SubItem>
+									<SubItem>
+										<Name>SubIndex 001</Name>
+										<Info>
+											<DefaultData>01</DefaultData>
+										</Info>
+									</SubItem>
+									<SubItem>
+										<Name>SubIndex 002</Name>
+										<Info>
+											<DefaultData>02</DefaultData>
+										</Info>
+									</SubItem>
+									<SubItem>
+										<Name>SubIndex 003</Name>
+										<Info>
+											<DefaultData>03</DefaultData>
+										</Info>
+									</SubItem>
+									<SubItem>
+										<Name>SubIndex 004</Name>
+										<Info>
+											<DefaultData>04</DefaultData>
+										</Info>
+									</SubItem>
+								</Info>
+							</Object>
+							<Object>
+								<Index>#x1C12</Index>
+								<Name>RxPDO assign</Name>
+								<Type>DT1C12</Type>
+								<BitSize>48</BitSize>
+								<Info>
+									<SubItem>
+										<Name>SubIndex 000</Name>
+										<Info>
+											<DefaultData>00</DefaultData>
+										</Info>
+									</SubItem>
+									<SubItem>
+										<Name>SubIndex 001</Name>
+										<Info>
+											<DefaultData>0000</DefaultData>
+										</Info>
+									</SubItem>
+									<SubItem>
+										<Name>SubIndex 002</Name>
+										<Info>
+											<DefaultData>0000</DefaultData>
+										</Info>
+									</SubItem>
+								</Info>
+							</Object>
+							<Object>
+								<Index>#x1C13</Index>
+								<Name>TxPDO assign</Name>
+								<Type>DT1C13</Type>
+								<BitSize>48</BitSize>
+								<Info>
+									<SubItem>
+										<Name>SubIndex 000</Name>
+										<Info>
+											<DefaultData>00</DefaultData>
+										</Info>
+									</SubItem>
+									<SubItem>
+										<Name>SubIndex 001</Name>
+										<Info>
+											<DefaultData>0000</DefaultData>
+										</Info>
+									</SubItem>
+									<SubItem>
+										<Name>SubIndex 002</Name>
+										<Info>
+											<DefaultData>0000</DefaultData>
+										</Info>
+									</SubItem>
+								</Info>
+							</Object>
+							<Object>
+								<Index>#x1C32</Index>
+								<Name>SM output parameter</Name>
+								<Type>DT1C32</Type>
+								<BitSize>488</BitSize>
+								<Info>
+									<SubItem>
+										<Name>SubIndex 000</Name>
+										<Info>
+											<DefaultData>20</DefaultData>
+										</Info>
+									</SubItem>
+									<SubItem>
+										<Name>Synchronization Type</Name>
+										<Info>
+											<DefaultData>0100</DefaultData>
+										</Info>
+									</SubItem>
+									<SubItem>
+										<Name>Synchronization Types supported</Name>
+										<Info>
+											<DefaultData>0780</DefaultData>
+										</Info>
+									</SubItem>
+									<SubItem>
+										<Name>Minimum Cycle Time</Name>
+										<Info>
+											<DefaultData>E0790000</DefaultData>
+										</Info>
+									</SubItem>
+								</Info>
+							</Object>
+							<Object>
+								<Index>#x1C33</Index>
+								<Name>SM input parameter</Name>
+								<Type>DT1C33</Type>
+								<BitSize>488</BitSize>
+								<Info>
+									<SubItem>
+										<Name>SubIndex 000</Name>
+										<Info>
+											<DefaultData>20</DefaultData>
+										</Info>
+									</SubItem>
+									<SubItem>
+										<Name>Synchronization Type</Name>
+										<Info>
+											<DefaultData>2200</DefaultData>
+										</Info>
+									</SubItem>
+									<SubItem>
+										<Name>Synchronization Types supported</Name>
+										<Info>
+											<DefaultData>0780</DefaultData>
+										</Info>
+									</SubItem>
+									<SubItem>
+										<Name>Minimum Cycle Time</Name>
+										<Info>
+											<DefaultData>E0790000</DefaultData>
+										</Info>
+									</SubItem>
+								</Info>
+							</Object>
+							<Object>
+								<Index>#xF000</Index>
+								<Name>Modular Device Profile</Name>
+								<Type>DTF000</Type>
+								<BitSize>48</BitSize>
+								<Info>
+									<SubItem>
+										<Name>SubIndex 000</Name>
+										<Info>
+											<DefaultData>02</DefaultData>
+										</Info>
+									</SubItem>
+									<SubItem>
+										<Name>Index distance</Name>
+										<Info>
+											<DefaultData>0080</DefaultData>
+										</Info>
+									</SubItem>
+									<SubItem>
+										<Name>Maximum number of modules</Name>
+										<Info>
+											<DefaultData>0200</DefaultData>
+										</Info>
+									</SubItem>
+								</Info>
+							</Object>
+							<Object>
+								<Index>#xF010</Index>
+								<Name>Module Profile List</Name>
+								<Type>DTF010</Type>
+								<BitSize>80</BitSize>
+								<Info>
+									<SubItem>
+										<Name>SubIndex 000</Name>
+										<Info>
+											<DefaultData>02</DefaultData>
+										</Info>
+									</SubItem>
+									<SubItem>
+										<Name>SubIndex 001</Name>
+										<Info>
+											<DefaultData>02000000</DefaultData>
+										</Info>
+									</SubItem>
+									<SubItem>
+										<Name>SubIndex 002</Name>
+										<Info>
+											<DefaultData>00000000</DefaultData>
+										</Info>
+									</SubItem>
+								</Info>
+							</Object>
+							<Object>
+								<Index>#xF030</Index>
+								<Name>Configured Module Ident List</Name>
+								<Type>DTF030</Type>
+								<BitSize>80</BitSize>
+								<Info>
+									<SubItem>
+										<Name>SubIndex 000</Name>
+										<Info>
+											<DefaultData>02</DefaultData>
+										</Info>
+									</SubItem>
+									<SubItem>
+										<Name>SubIndex 001</Name>
+										<Info>
+											<DefaultData>00983100</DefaultData>
+										</Info>
+									</SubItem>
+									<SubItem>
+										<Name>SubIndex 002</Name>
+										<Info>
+											<MinData>00000000</MinData>
+											<DefaultData>00000000</DefaultData>
+										</Info>
+									</SubItem>
+								</Info>
+							</Object>
+							<Object>
+								<Index>#xF050</Index>
+								<Name>Module detected list</Name>
+								<Type>DTF050</Type>
+								<BitSize>80</BitSize>
+								<Info>
+									<SubItem>
+										<Name>SubIndex 000</Name>
+										<Info>
+											<DefaultData>02</DefaultData>
+										</Info>
+									</SubItem>
+									<SubItem>
+										<Name>SubIndex 001</Name>
+										<Info>
+											<DefaultData>00983100</DefaultData>
+										</Info>
+									</SubItem>
+									<SubItem>
+										<Name>SubIndex 002</Name>
+										<Info>
+											<DefaultData>00000000</DefaultData>
+										</Info>
+									</SubItem>
+								</Info>
+							</Object>
+						</Objects>
+					</Dictionary>
+				</Profile>
+				<Fmmu>Outputs</Fmmu>
+				<Fmmu>Inputs</Fmmu>
+				<Fmmu>MBoxState</Fmmu>
+				<Sm MinSize="#x24" MaxSize="#x10C" DefaultSize="#x80" StartAddress="#x1000" ControlByte="#x26" Enable="1">MBoxOut</Sm>
+				<Sm MinSize="#x24" MaxSize="#x10C" DefaultSize="#x80" StartAddress="#x1080" ControlByte="#x22" Enable="1">MBoxIn</Sm>
+				<Sm DefaultSize="0" StartAddress="#x1100" ControlByte="#x64" Enable="0">Outputs</Sm>
+				<Sm DefaultSize="0" StartAddress="#x1400" ControlByte="#x20" Enable="0">Inputs</Sm>
+				<Mailbox DataLinkLayer="true">
+					<CoE SdoInfo="true" PdoAssign="true" PdoConfig="false" CompleteAccess="true" SegmentedSdo="true" />
+				</Mailbox>
+				<Dc>
+					<OpMode>
+						<Name>Synchron</Name>
+						<Desc>SM-Synchron</Desc>
+						<AssignActivate>#x0</AssignActivate>
+					</OpMode>
+					<OpMode>
+						<Name>DC</Name>
+						<Desc>DC-Synchron</Desc>
+						<AssignActivate>#x300</AssignActivate>
+						<CycleTimeSync0 Factor="1">0</CycleTimeSync0>
+						<CycleTimeSync1 Factor="1">0</CycleTimeSync1>
+					</OpMode>
+				</Dc>
+				<Slots SlotPdoIncrement="16" SlotIndexIncrement="#x800">
+					<Slot MinInstances="1" MaxInstances="1">
+						<Name>Axis 0</Name>
+						<ModuleIdent Default="0">#x119800</ModuleIdent>
+						<ModuleIdent Default="0">#x219800</ModuleIdent>
+						<ModuleIdent Default="1">#x319800</ModuleIdent>
+					</Slot>
+					<Slot MinInstances="0" MaxInstances="1">
+						<Name>Axis 1</Name>
+						<ModuleIdent Default="0">#x119800</ModuleIdent>
+						<ModuleIdent Default="0">#x219800</ModuleIdent>
+						<ModuleIdent Default="0">#x319800</ModuleIdent>
+					</Slot>
+				</Slots>
+				<Eeprom>
+					<ByteSize>2048</ByteSize>
+					<ConfigData>800C8166000000001234</ConfigData>
+				</Eeprom>
+				<ImageData16x14>424DD8020000000000003600000028000000100000000E0000000100180000000000A2020000120B0000120B000000000000000000001306E31306E3190CE42B1FE62B1FE61306E31F13E5190CE42519E51306E31306E3190CE42F24E7190CE41306E31306E31306E31306E35F56EC645CED645CED4137E91F13E5473DE95F57EC3227E71306E3473DE95A51EC271BE61306E31306E31409CA524CC68E8AD74F48C1615CC82218D03E36BF716BCE746FCE453DC01307CE3931BA7D78D27671D1150CB21409CA1712801B1D1D1B1D1D1B1D1D1B1D1D120B891B1D1D1B1D1D1B1D1D1B1D1D120B891B1D1D1B1D1D1B1D1D1B1D1D1712801712807F8080D4D5D5D4D5D5383939120B89545656D4D5D5D4D5D5626464130C89292B2BD4D5D5D4D5D56264641915801712804647471B1D1DAAAAAAD4D5D5130E82383939292B2B717272D4D5D5151183D4D5D57F80801B1D1D7172721E1C81191580464747D4D5D5D4D5D51B1D1D19158A292B2BD4D5D5D4D5D5292B2B1B1B8AD4D5D56264641B1D1D1B1D1D2427821E1D81D4D5D54647476264643839391E208BD4D5D57F8080464747545656242A8BD4D5D59B9C9C292B2BAAAAAA2D3683252882464747D4D5D5D4D5D51B1D1D272D85292B2BD4D5D5D4D5D5292B2B2E37861B1D1DD4D5D5D4D5D5464747394484323BB52324812122822426822526824554C0323883292B822A2D83353C84424CBF3238843940842E32834853865D6EBB5262EB3E43E83334E74147E94349E9535FEB4D56EA5662EB484DEA545DEB636FED545AEA5A63EC6671ED8CA0F290A5F2748AEF6B7BEE5D68EC6874ED788AEF8397F17684EF7986EF8C9FF2818FF1818EF08E9DF18A97F18791F19BA9F3B0C0F691A4F291A2F28390F192A1F29CACF3A3B3F498A6F3A4B3F4AEBDF5B0BEF59EA8F3A3ADF4BBC7F7C4D1F8CAD7F8CED9F9B4C4F6B8C8F6ACB8F59AA3F3B6C1F6C5D2F8C2CDF8CCD7F9D2DDF9D5E0FAD2DAF9D5DCF9DFE7FBE2E9FBE5EBFBE8EEFB0000</ImageData16x14>
+			</Device>
+		</Devices>
+		<Modules>
+			<Module>
+				<Type ModuleIdent="#x119800">csv,csp - axis</Type>
+				<Name>dynamic switch bewteen csp/csv</Name>
+				<RxPdo Fixed="true" Sm="2">
+					<Index DependOnSlot="true">#x1600</Index>
+					<Name>Outputs</Name>
+					<Entry>
+						<Index DependOnSlot="true">#x6040</Index>
+						<SubIndex>0</SubIndex>
+						<BitLen>16</BitLen>
+						<Name>Control Word</Name>
+						<Comment>object 0x6040:0</Comment>
+						<DataType>UINT</DataType>
+					</Entry>
+					<Entry>
+						<Index DependOnSlot="true">#x607A</Index>
+						<SubIndex>0</SubIndex>
+						<BitLen>32</BitLen>
+						<Name>TargetPosition</Name>
+						<Comment>object 0x607A:0</Comment>
+						<DataType>DINT</DataType>
+					</Entry>
+					<Entry>
+						<Index DependOnSlot="true">#x60FF</Index>
+						<SubIndex>0</SubIndex>
+						<BitLen>32</BitLen>
+						<Name>TargetVelocity</Name>
+						<Comment>object 0x60FF:0</Comment>
+						<DataType>DINT</DataType>
+					</Entry>
+					<Entry>
+						<Index DependOnSlot="true">#x6060</Index>
+						<SubIndex>0</SubIndex>
+						<BitLen>8</BitLen>
+						<Name>ModeOfOperation</Name>
+						<Comment>object 0x6060:0</Comment>
+						<DataType>USINT</DataType>
+					</Entry>
+					<Entry>
+						<Index>0</Index>
+						<SubIndex>0</SubIndex>
+						<BitLen>8</BitLen>
+					</Entry>
+				</RxPdo>
+				<TxPdo Fixed="true" Sm="3">
+					<Index DependOnSlot="true">#x1a00</Index>
+					<Name>Inputs</Name>
+					<Entry>
+						<Index DependOnSlot="true">#x6041</Index>
+						<SubIndex>0</SubIndex>
+						<BitLen>16</BitLen>
+						<Name>Status Word</Name>
+						<Comment>object 0x6041:0</Comment>
+						<DataType>UINT</DataType>
+					</Entry>
+					<Entry>
+						<Index DependOnSlot="true">#x6064</Index>
+						<SubIndex>0</SubIndex>
+						<BitLen>32</BitLen>
+						<Name>ActualPosition</Name>
+						<Comment>object 0x6064:0</Comment>
+						<DataType>DINT</DataType>
+					</Entry>
+					<Entry>
+						<Index DependOnSlot="true">#x606C</Index>
+						<SubIndex>0</SubIndex>
+						<BitLen>32</BitLen>
+						<Name>ActualVelocity</Name>
+						<Comment>object 0x606C:0</Comment>
+						<DataType>DINT</DataType>
+					</Entry>
+					<Entry>
+						<Index DependOnSlot="true">#x6061</Index>
+						<SubIndex>0</SubIndex>
+						<BitLen>8</BitLen>
+						<Name>ModeOfOperationDisplay</Name>
+						<Comment>object 0x6061:0</Comment>
+						<DataType>USINT</DataType>
+					</Entry>
+					<Entry>
+						<Index>0</Index>
+						<SubIndex>0</SubIndex>
+						<BitLen>8</BitLen>
+					</Entry>
+				</TxPdo>
+				<Profile>
+					<ProfileNo>402</ProfileNo>
+					<AddInfo>2</AddInfo>
+					<Dictionary>
+						<DataTypes>
+							<DataType>
+								<Name>SINT</Name>
+								<BitSize>8</BitSize>
+							</DataType>
+							<DataType>
+								<Name>USINT</Name>
+								<BitSize>8</BitSize>
+							</DataType>
+							<DataType>
+								<Name>UDINT</Name>
+								<BitSize>32</BitSize>
+							</DataType>
+							<DataType>
+								<Name>DINT</Name>
+								<BitSize>32</BitSize>
+							</DataType>
+							<DataType>
+								<Name>INT</Name>
+								<BitSize>16</BitSize>
+							</DataType>
+							<DataType>
+								<Name>UINT</Name>
+								<BitSize>16</BitSize>
+							</DataType>
+							<DataType>
+								<Name>DT607DARR</Name>
+								<BaseType>DINT</BaseType>
+								<BitSize>64</BitSize>
+								<ArrayInfo>
+									<LBound>1</LBound>
+									<Elements>2</Elements>
+								</ArrayInfo>
+							</DataType>
+							<DataType>
+								<Name>DT607D</Name>
+								<BitSize>80</BitSize>
+								<SubItem>
+									<SubIdx>0</SubIdx>
+									<Name>SubIndex 000</Name>
+									<Type>USINT</Type>
+									<BitSize>8</BitSize>
+									<BitOffs>0</BitOffs>
+									<Flags>
+										<Access>ro</Access>
+									</Flags>
+								</SubItem>
+								<SubItem>
+									<Name>Elements</Name>
+									<Type>DT607DARR</Type>
+									<BitSize>64</BitSize>
+									<BitOffs>16</BitOffs>
+									<Flags>
+										<Access>rw</Access>
+										<PdoMapping>r</PdoMapping>
+									</Flags>
+								</SubItem>
+							</DataType>
+							<DataType>
+								<Name>DT60C2</Name>
+								<BitSize>32</BitSize>
+								<SubItem>
+									<SubIdx>0</SubIdx>
+									<Name>SubIndex 000</Name>
+									<Type>USINT</Type>
+									<BitSize>8</BitSize>
+									<BitOffs>0</BitOffs>
+									<Flags>
+										<Access>ro</Access>
+									</Flags>
+								</SubItem>
+								<SubItem>
+									<SubIdx>1</SubIdx>
+									<Name>Interpolation time period value</Name>
+									<Type>USINT</Type>
+									<BitSize>8</BitSize>
+									<BitOffs>16</BitOffs>
+									<Flags>
+										<Access>rw</Access>
+										<PdoMapping>r</PdoMapping>
+									</Flags>
+								</SubItem>
+								<SubItem>
+									<SubIdx>2</SubIdx>
+									<Name>Interpolation time index</Name>
+									<Type>SINT</Type>
+									<BitSize>8</BitSize>
+									<BitOffs>24</BitOffs>
+									<Flags>
+										<Access>rw</Access>
+										<PdoMapping>r</PdoMapping>
+									</Flags>
+								</SubItem>
+							</DataType>
+						</DataTypes>
+						<Objects>
+							<Object>
+								<Index DependOnSlot="true">#x603F</Index>
+								<Name>Error Code</Name>
+								<Type>UINT</Type>
+								<BitSize>16</BitSize>
+								<Flags>
+									<Access>ro</Access>
+									<PdoMapping>t</PdoMapping>
+								</Flags>
+							</Object>
+							<Object>
+								<Index DependOnSlot="true">#x6040</Index>
+								<Name>Control Word</Name>
+								<Type>UINT</Type>
+								<BitSize>16</BitSize>
+								<Flags>
+									<Access>rw</Access>
+									<PdoMapping>r</PdoMapping>
+								</Flags>
+							</Object>
+							<Object>
+								<Index DependOnSlot="true">#x6041</Index>
+								<Name>Status Word</Name>
+								<Type>UINT</Type>
+								<BitSize>16</BitSize>
+								<Flags>
+									<Access>ro</Access>
+									<PdoMapping>t</PdoMapping>
+								</Flags>
+							</Object>
+							<Object>
+								<Index DependOnSlot="true">#x605A</Index>
+								<Name>Quick stop option code</Name>
+								<Type>INT</Type>
+								<BitSize>16</BitSize>
+								<Flags>
+									<Access>rw</Access>
+								</Flags>
+							</Object>
+							<Object>
+								<Index DependOnSlot="true">#x605B</Index>
+								<Name>Shutdown option code</Name>
+								<Type>INT</Type>
+								<BitSize>16</BitSize>
+								<Flags>
+									<Access>rw</Access>
+								</Flags>
+							</Object>
+							<Object>
+								<Index DependOnSlot="true">#x605C</Index>
+								<Name>Disable operation option code</Name>
+								<Type>INT</Type>
+								<BitSize>16</BitSize>
+								<Flags>
+									<Access>rw</Access>
+								</Flags>
+							</Object>
+							<Object>
+								<Index DependOnSlot="true">#x605E</Index>
+								<Name>Fault reaction option code</Name>
+								<Type>INT</Type>
+								<BitSize>16</BitSize>
+								<Flags>
+									<Access>rw</Access>
+								</Flags>
+							</Object>
+							<Object>
+								<Index DependOnSlot="true">#x6060</Index>
+								<Name>Modes of operation</Name>
+								<Type>SINT</Type>
+								<BitSize>8</BitSize>
+								<Flags>
+									<Access>rw</Access>
+									<PdoMapping>r</PdoMapping>
+								</Flags>
+							</Object>
+							<Object>
+								<Index DependOnSlot="true">#x6061</Index>
+								<Name>Modes of operation display</Name>
+								<Type>SINT</Type>
+								<BitSize>8</BitSize>
+								<Flags>
+									<Access>ro</Access>
+									<PdoMapping>t</PdoMapping>
+								</Flags>
+							</Object>
+							<Object>
+								<Index DependOnSlot="true">#x6064</Index>
+								<Name>Position actual value</Name>
+								<Type>DINT</Type>
+								<BitSize>32</BitSize>
+								<Flags>
+									<Access>ro</Access>
+									<PdoMapping>t</PdoMapping>
+								</Flags>
+							</Object>
+							<Object>
+								<Index DependOnSlot="true">#x606C</Index>
+								<Name>Velocity actual value</Name>
+								<Type>DINT</Type>
+								<BitSize>32</BitSize>
+								<Flags>
+									<Access>ro</Access>
+									<PdoMapping>t</PdoMapping>
+								</Flags>
+							</Object>
+							<Object>
+								<Index DependOnSlot="true">#x6077</Index>
+								<Name>Torque actual value</Name>
+								<Type>INT</Type>
+								<BitSize>16</BitSize>
+								<Flags>
+									<Access>ro</Access>
+									<PdoMapping>t</PdoMapping>
+								</Flags>
+							</Object>
+							<Object>
+								<Index DependOnSlot="true">#x607D</Index>
+								<Name>Software position limit</Name>
+								<Type>DT607D</Type>
+								<BitSize>80</BitSize>
+							</Object>
+							<Object>
+								<Index DependOnSlot="true">#x607A</Index>
+								<Name>Target position</Name>
+								<Type>DINT</Type>
+								<BitSize>32</BitSize>
+								<Flags>
+									<Access>rw</Access>
+									<PdoMapping>r</PdoMapping>
+								</Flags>
+							</Object>
+							<Object>
+								<Index DependOnSlot="true">#x6085</Index>
+								<Name>Quick stop deceleration</Name>
+								<Type>UDINT</Type>
+								<BitSize>32</BitSize>
+								<Flags>
+									<Access>rw</Access>
+									<PdoMapping>r</PdoMapping>
+								</Flags>
+							</Object>
+							<Object>
+								<Index DependOnSlot="true">#x60C2</Index>
+								<Name>Interpolation time period</Name>
+								<Type>DT60C2</Type>
+								<BitSize>32</BitSize>
+							</Object>
+							<Object>
+								<Index DependOnSlot="true">#x60FF</Index>
+								<Name>Target velocity</Name>
+								<Type>DINT</Type>
+								<BitSize>32</BitSize>
+								<Flags>
+									<Access>rw</Access>
+									<PdoMapping>r</PdoMapping>
+								</Flags>
+							</Object>
+							<Object>
+								<Index DependOnSlot="true">#x6502</Index>
+								<Name>Supported drive modes</Name>
+								<Type>UDINT</Type>
+								<BitSize>32</BitSize>
+								<Flags>
+									<Access>ro</Access>
+									<PdoMapping>t</PdoMapping>
+								</Flags>
+							</Object>
+						</Objects>
+					</Dictionary>
+				</Profile>
+			</Module>
+			<Module>
+				<Type ModuleIdent="#x219800">csp - axis</Type>
+				<Name>csp</Name>
+				<RxPdo Fixed="true" Sm="2">
+					<Index DependOnSlot="true">#x1601</Index>
+					<Name>Outputs</Name>
+					<Entry>
+						<Index DependOnSlot="true">#x6040</Index>
+						<SubIndex>0</SubIndex>
+						<BitLen>16</BitLen>
+						<Name>Control Word</Name>
+						<Comment>object 0x6040:0</Comment>
+						<DataType>UINT</DataType>
+					</Entry>
+					<Entry>
+						<Index DependOnSlot="true">#x607A</Index>
+						<SubIndex>0</SubIndex>
+						<BitLen>32</BitLen>
+						<Name>TargetPosition</Name>
+						<Comment>object 0x607A:0</Comment>
+						<DataType>DINT</DataType>
+					</Entry>
+					<Entry>
+						<Index>#x0</Index>
+						<SubIndex>0</SubIndex>
+						<BitLen>16</BitLen>
+						<Comment>16bit padding</Comment>
+					</Entry>
+				</RxPdo>
+				<TxPdo Fixed="true" Sm="3">
+					<Index DependOnSlot="true">#x1a01</Index>
+					<Name>Inputs</Name>
+					<Entry>
+						<Index DependOnSlot="true">#x6041</Index>
+						<SubIndex>0</SubIndex>
+						<BitLen>16</BitLen>
+						<Name>Status Word</Name>
+						<Comment>object 0x6041:0</Comment>
+						<DataType>UINT</DataType>
+					</Entry>
+					<Entry>
+						<Index DependOnSlot="true">#x6064</Index>
+						<SubIndex>0</SubIndex>
+						<BitLen>32</BitLen>
+						<Name>ActualPosition</Name>
+						<Comment>object 0x6064:0</Comment>
+						<DataType>DINT</DataType>
+					</Entry>
+					<Entry>
+						<Index>#x0</Index>
+						<SubIndex>0</SubIndex>
+						<BitLen>16</BitLen>
+						<Comment>16bit padding</Comment>
+					</Entry>
+				</TxPdo>
+				<Mailbox>
+					<CoE>
+						<InitCmd>
+							<Transition>SO</Transition>
+							<Index DependOnSlot="true">#x6060</Index>
+							<SubIndex>0</SubIndex>
+							<Data>08</Data>
+						</InitCmd>
+					</CoE>
+				</Mailbox>
+				<Profile>
+					<ProfileNo>402</ProfileNo>
+					<AddInfo>2</AddInfo>
+					<Dictionary>
+						<DataTypes>
+							<DataType>
+								<Name>SINT</Name>
+								<BitSize>8</BitSize>
+							</DataType>
+							<DataType>
+								<Name>USINT</Name>
+								<BitSize>8</BitSize>
+							</DataType>
+							<DataType>
+								<Name>UDINT</Name>
+								<BitSize>32</BitSize>
+							</DataType>
+							<DataType>
+								<Name>DINT</Name>
+								<BitSize>32</BitSize>
+							</DataType>
+							<DataType>
+								<Name>INT</Name>
+								<BitSize>16</BitSize>
+							</DataType>
+							<DataType>
+								<Name>UINT</Name>
+								<BitSize>16</BitSize>
+							</DataType>
+							<DataType>
+								<Name>DT60C2</Name>
+								<BitSize>32</BitSize>
+								<SubItem>
+									<SubIdx>0</SubIdx>
+									<Name>SubIndex 000</Name>
+									<Type>USINT</Type>
+									<BitSize>8</BitSize>
+									<BitOffs>0</BitOffs>
+									<Flags>
+										<Access>ro</Access>
+									</Flags>
+								</SubItem>
+								<SubItem>
+									<SubIdx>1</SubIdx>
+									<Name>Interpolation time period value</Name>
+									<Type>USINT</Type>
+									<BitSize>8</BitSize>
+									<BitOffs>16</BitOffs>
+									<Flags>
+										<Access>rw</Access>
+										<PdoMapping>r</PdoMapping>
+									</Flags>
+								</SubItem>
+								<SubItem>
+									<SubIdx>2</SubIdx>
+									<Name>Interpolation time index</Name>
+									<Type>SINT</Type>
+									<BitSize>8</BitSize>
+									<BitOffs>24</BitOffs>
+									<Flags>
+										<Access>rw</Access>
+										<PdoMapping>r</PdoMapping>
+									</Flags>
+								</SubItem>
+							</DataType>
+							<DataType>
+								<Name>DT607DARR</Name>
+								<BaseType>DINT</BaseType>
+								<BitSize>64</BitSize>
+								<ArrayInfo>
+									<LBound>1</LBound>
+									<Elements>2</Elements>
+								</ArrayInfo>
+							</DataType>
+							<DataType>
+								<Name>DT607D</Name>
+								<BitSize>80</BitSize>
+								<SubItem>
+									<SubIdx>0</SubIdx>
+									<Name>SubIndex 000</Name>
+									<Type>USINT</Type>
+									<BitSize>8</BitSize>
+									<BitOffs>0</BitOffs>
+									<Flags>
+										<Access>ro</Access>
+									</Flags>
+								</SubItem>
+								<SubItem>
+									<Name>Elements</Name>
+									<Type>DT607DARR</Type>
+									<BitSize>64</BitSize>
+									<BitOffs>16</BitOffs>
+									<Flags>
+										<Access>rw</Access>
+										<PdoMapping>r</PdoMapping>
+									</Flags>
+								</SubItem>
+							</DataType>
+						</DataTypes>
+						<Objects>
+							<Object>
+								<Index DependOnSlot="true">#x603F</Index>
+								<Name>Error Code</Name>
+								<Type>UINT</Type>
+								<BitSize>16</BitSize>
+								<Flags>
+									<Access>ro</Access>
+									<PdoMapping>t</PdoMapping>
+								</Flags>
+							</Object>
+							<Object>
+								<Index DependOnSlot="true">#x6040</Index>
+								<Name>Control Word</Name>
+								<Type>UINT</Type>
+								<BitSize>16</BitSize>
+								<Flags>
+									<Access>rw</Access>
+									<PdoMapping>r</PdoMapping>
+								</Flags>
+							</Object>
+							<Object>
+								<Index DependOnSlot="true">#x6041</Index>
+								<Name>Status Word</Name>
+								<Type>UINT</Type>
+								<BitSize>16</BitSize>
+								<Flags>
+									<Access>ro</Access>
+									<PdoMapping>t</PdoMapping>
+								</Flags>
+							</Object>
+							<Object>
+								<Index DependOnSlot="true">#x605A</Index>
+								<Name>Quick stop option code</Name>
+								<Type>INT</Type>
+								<BitSize>16</BitSize>
+								<Flags>
+									<Access>rw</Access>
+								</Flags>
+							</Object>
+							<Object>
+								<Index DependOnSlot="true">#x605B</Index>
+								<Name>Shutdown option code</Name>
+								<Type>INT</Type>
+								<BitSize>16</BitSize>
+								<Flags>
+									<Access>rw</Access>
+								</Flags>
+							</Object>
+							<Object>
+								<Index DependOnSlot="true">#x605C</Index>
+								<Name>Disable operation option code</Name>
+								<Type>INT</Type>
+								<BitSize>16</BitSize>
+								<Flags>
+									<Access>rw</Access>
+								</Flags>
+							</Object>
+							<Object>
+								<Index DependOnSlot="true">#x605E</Index>
+								<Name>Fault reaction option code</Name>
+								<Type>INT</Type>
+								<BitSize>16</BitSize>
+								<Flags>
+									<Access>rw</Access>
+								</Flags>
+							</Object>
+							<Object>
+								<Index DependOnSlot="true">#x6060</Index>
+								<Name>Modes of operation</Name>
+								<Type>SINT</Type>
+								<BitSize>8</BitSize>
+								<Flags>
+									<Access>rw</Access>
+									<PdoMapping>r</PdoMapping>
+								</Flags>
+							</Object>
+							<Object>
+								<Index DependOnSlot="true">#x6061</Index>
+								<Name>Modes of operation display</Name>
+								<Type>SINT</Type>
+								<BitSize>8</BitSize>
+								<Flags>
+									<Access>ro</Access>
+									<PdoMapping>t</PdoMapping>
+								</Flags>
+							</Object>
+							<Object>
+								<Index DependOnSlot="true">#x6064</Index>
+								<Name>Position actual value</Name>
+								<Type>DINT</Type>
+								<BitSize>32</BitSize>
+								<Flags>
+									<Access>ro</Access>
+									<PdoMapping>t</PdoMapping>
+								</Flags>
+							</Object>
+							<Object>
+								<Index DependOnSlot="true">#x606C</Index>
+								<Name>Velocity actual value</Name>
+								<Type>DINT</Type>
+								<BitSize>32</BitSize>
+								<Flags>
+									<Access>ro</Access>
+									<PdoMapping>t</PdoMapping>
+								</Flags>
+							</Object>
+							<Object>
+								<Index DependOnSlot="true">#x6077</Index>
+								<Name>Torque actual value</Name>
+								<Type>INT</Type>
+								<BitSize>16</BitSize>
+								<Flags>
+									<Access>ro</Access>
+									<PdoMapping>t</PdoMapping>
+								</Flags>
+							</Object>
+							<Object>
+								<Index DependOnSlot="true">#x607D</Index>
+								<Name>Software position limit</Name>
+								<Type>DT607D</Type>
+								<BitSize>80</BitSize>
+							</Object>
+							<Object>
+								<Index DependOnSlot="true">#x607A</Index>
+								<Name>Target position</Name>
+								<Type>DINT</Type>
+								<BitSize>32</BitSize>
+								<Flags>
+									<Access>rw</Access>
+									<PdoMapping>r</PdoMapping>
+								</Flags>
+							</Object>
+							<Object>
+								<Index DependOnSlot="true">#x6085</Index>
+								<Name>Quick stop deceleration</Name>
+								<Type>UDINT</Type>
+								<BitSize>32</BitSize>
+								<Flags>
+									<Access>rw</Access>
+									<PdoMapping>r</PdoMapping>
+								</Flags>
+							</Object>
+							<Object>
+								<Index DependOnSlot="true">#x60C2</Index>
+								<Name>Interpolation time period</Name>
+								<Type>DT60C2</Type>
+								<BitSize>32</BitSize>
+							</Object>
+							<Object>
+								<Index DependOnSlot="true">#x60FF</Index>
+								<Name>Target velocity</Name>
+								<Type>DINT</Type>
+								<BitSize>32</BitSize>
+								<Flags>
+									<Access>rw</Access>
+									<PdoMapping>r</PdoMapping>
+								</Flags>
+							</Object>
+							<Object>
+								<Index DependOnSlot="true">#x6502</Index>
+								<Name>Supported drive modes</Name>
+								<Type>UDINT</Type>
+								<BitSize>32</BitSize>
+								<Flags>
+									<Access>ro</Access>
+									<PdoMapping>t</PdoMapping>
+								</Flags>
+							</Object>
+						</Objects>
+					</Dictionary>
+				</Profile>
+			</Module>
+			<Module>
+				<Type ModuleIdent="#x319800">csv -  axis</Type>
+				<Name>csv</Name>
+				<RxPdo Fixed="true" Sm="2">
+					<Index DependOnSlot="true">#x1602</Index>
+					<Name>Outputs</Name>
+					<Entry>
+						<Index DependOnSlot="true">#x6040</Index>
+						<SubIndex>0</SubIndex>
+						<BitLen>16</BitLen>
+						<Name>Control Word</Name>
+						<Comment>object 0x6040:0</Comment>
+						<DataType>UINT</DataType>
+					</Entry>
+					<Entry>
+						<Index DependOnSlot="true">#x60FF</Index>
+						<SubIndex>0</SubIndex>
+						<BitLen>32</BitLen>
+						<Name>TargetVelocity</Name>
+						<Comment>object 0x60FF:0</Comment>
+						<DataType>DINT</DataType>
+					</Entry>
+					<Entry>
+						<Index>#x0</Index>
+						<SubIndex>0</SubIndex>
+						<BitLen>16</BitLen>
+						<Comment>16bit padding</Comment>
+					</Entry>
+				</RxPdo>
+				<TxPdo Fixed="true" Sm="3">
+					<Index DependOnSlot="true">#x1a02</Index>
+					<Name>Inputs</Name>
+					<Entry>
+						<Index DependOnSlot="true">#x6041</Index>
+						<SubIndex>0</SubIndex>
+						<BitLen>16</BitLen>
+						<Name>Status Word</Name>
+						<Comment>object 0x6041:0</Comment>
+						<DataType>UINT</DataType>
+					</Entry>
+					<Entry>
+						<Index DependOnSlot="true">#x6064</Index>
+						<SubIndex>0</SubIndex>
+						<BitLen>32</BitLen>
+						<Name>ActualPosition</Name>
+						<Comment>object 0x6064:0</Comment>
+						<DataType>DINT</DataType>
+					</Entry>
+					<Entry>
+						<Index>#x0</Index>
+						<SubIndex>0</SubIndex>
+						<BitLen>16</BitLen>
+						<Comment>16bit padding</Comment>
+					</Entry>
+				</TxPdo>
+				<Mailbox>
+					<CoE>
+						<InitCmd>
+							<Transition>SO</Transition>
+							<Index DependOnSlot="true">#x6060</Index>
+							<SubIndex>0</SubIndex>
+							<Data>09</Data>
+						</InitCmd>
+					</CoE>
+				</Mailbox>
+				<Profile>
+					<ProfileNo>402</ProfileNo>
+					<AddInfo>2</AddInfo>
+					<Dictionary>
+						<DataTypes>
+							<DataType>
+								<Name>SINT</Name>
+								<BitSize>8</BitSize>
+							</DataType>
+							<DataType>
+								<Name>USINT</Name>
+								<BitSize>8</BitSize>
+							</DataType>
+							<DataType>
+								<Name>UDINT</Name>
+								<BitSize>32</BitSize>
+							</DataType>
+							<DataType>
+								<Name>DINT</Name>
+								<BitSize>32</BitSize>
+							</DataType>
+							<DataType>
+								<Name>INT</Name>
+								<BitSize>16</BitSize>
+							</DataType>
+							<DataType>
+								<Name>UINT</Name>
+								<BitSize>16</BitSize>
+							</DataType>
+							<DataType>
+								<Name>DT607DARR</Name>
+								<BaseType>DINT</BaseType>
+								<BitSize>64</BitSize>
+								<ArrayInfo>
+									<LBound>1</LBound>
+									<Elements>2</Elements>
+								</ArrayInfo>
+							</DataType>
+							<DataType>
+								<Name>DT607D</Name>
+								<BitSize>80</BitSize>
+								<SubItem>
+									<SubIdx>0</SubIdx>
+									<Name>SubIndex 000</Name>
+									<Type>USINT</Type>
+									<BitSize>8</BitSize>
+									<BitOffs>0</BitOffs>
+									<Flags>
+										<Access>ro</Access>
+									</Flags>
+								</SubItem>
+								<SubItem>
+									<Name>Elements</Name>
+									<Type>DT607DARR</Type>
+									<BitSize>64</BitSize>
+									<BitOffs>16</BitOffs>
+									<Flags>
+										<Access>rw</Access>
+										<PdoMapping>r</PdoMapping>
+									</Flags>
+								</SubItem>
+							</DataType>
+							<DataType>
+								<Name>DT60C2</Name>
+								<BitSize>32</BitSize>
+								<SubItem>
+									<SubIdx>0</SubIdx>
+									<Name>SubIndex 000</Name>
+									<Type>USINT</Type>
+									<BitSize>8</BitSize>
+									<BitOffs>0</BitOffs>
+									<Flags>
+										<Access>ro</Access>
+									</Flags>
+								</SubItem>
+								<SubItem>
+									<SubIdx>1</SubIdx>
+									<Name>Interpolation time period value</Name>
+									<Type>USINT</Type>
+									<BitSize>8</BitSize>
+									<BitOffs>16</BitOffs>
+									<Flags>
+										<Access>rw</Access>
+										<PdoMapping>r</PdoMapping>
+									</Flags>
+								</SubItem>
+								<SubItem>
+									<SubIdx>2</SubIdx>
+									<Name>Interpolation time index</Name>
+									<Type>SINT</Type>
+									<BitSize>8</BitSize>
+									<BitOffs>24</BitOffs>
+									<Flags>
+										<Access>rw</Access>
+										<PdoMapping>r</PdoMapping>
+									</Flags>
+								</SubItem>
+							</DataType>
+						</DataTypes>
+						<Objects>
+							<Object>
+								<Index DependOnSlot="true">#x603F</Index>
+								<Name>Error Code</Name>
+								<Type>UINT</Type>
+								<BitSize>16</BitSize>
+								<Flags>
+									<Access>ro</Access>
+									<PdoMapping>t</PdoMapping>
+								</Flags>
+							</Object>
+							<Object>
+								<Index DependOnSlot="true">#x6040</Index>
+								<Name>Control Word</Name>
+								<Type>UINT</Type>
+								<BitSize>16</BitSize>
+								<Flags>
+									<Access>rw</Access>
+									<PdoMapping>r</PdoMapping>
+								</Flags>
+							</Object>
+							<Object>
+								<Index DependOnSlot="true">#x6041</Index>
+								<Name>Status Word</Name>
+								<Type>UINT</Type>
+								<BitSize>16</BitSize>
+								<Flags>
+									<Access>ro</Access>
+									<PdoMapping>t</PdoMapping>
+								</Flags>
+							</Object>
+							<Object>
+								<Index DependOnSlot="true">#x605A</Index>
+								<Name>Quick stop option code</Name>
+								<Type>INT</Type>
+								<BitSize>16</BitSize>
+								<Flags>
+									<Access>rw</Access>
+								</Flags>
+							</Object>
+							<Object>
+								<Index DependOnSlot="true">#x605B</Index>
+								<Name>Shutdown option code</Name>
+								<Type>INT</Type>
+								<BitSize>16</BitSize>
+								<Flags>
+									<Access>rw</Access>
+								</Flags>
+							</Object>
+							<Object>
+								<Index DependOnSlot="true">#x605C</Index>
+								<Name>Disable operation option code</Name>
+								<Type>INT</Type>
+								<BitSize>16</BitSize>
+								<Flags>
+									<Access>rw</Access>
+								</Flags>
+							</Object>
+							<Object>
+								<Index DependOnSlot="true">#x605E</Index>
+								<Name>Fault reaction option code</Name>
+								<Type>INT</Type>
+								<BitSize>16</BitSize>
+								<Flags>
+									<Access>rw</Access>
+								</Flags>
+							</Object>
+							<Object>
+								<Index DependOnSlot="true">#x6060</Index>
+								<Name>Modes of operation</Name>
+								<Type>SINT</Type>
+								<BitSize>8</BitSize>
+								<Flags>
+									<Access>rw</Access>
+									<PdoMapping>r</PdoMapping>
+								</Flags>
+							</Object>
+							<Object>
+								<Index DependOnSlot="true">#x6061</Index>
+								<Name>Modes of operation display</Name>
+								<Type>SINT</Type>
+								<BitSize>8</BitSize>
+								<Flags>
+									<Access>ro</Access>
+									<PdoMapping>t</PdoMapping>
+								</Flags>
+							</Object>
+							<Object>
+								<Index DependOnSlot="true">#x6064</Index>
+								<Name>Position actual value</Name>
+								<Type>DINT</Type>
+								<BitSize>32</BitSize>
+								<Flags>
+									<Access>ro</Access>
+									<PdoMapping>t</PdoMapping>
+								</Flags>
+							</Object>
+							<Object>
+								<Index DependOnSlot="true">#x606C</Index>
+								<Name>Velocity actual value</Name>
+								<Type>DINT</Type>
+								<BitSize>32</BitSize>
+								<Flags>
+									<Access>ro</Access>
+									<PdoMapping>t</PdoMapping>
+								</Flags>
+							</Object>
+							<Object>
+								<Index DependOnSlot="true">#x6077</Index>
+								<Name>Torque actual value</Name>
+								<Type>INT</Type>
+								<BitSize>16</BitSize>
+								<Flags>
+									<Access>ro</Access>
+									<PdoMapping>t</PdoMapping>
+								</Flags>
+							</Object>
+							<Object>
+								<Index DependOnSlot="true">#x607D</Index>
+								<Name>Software position limit</Name>
+								<Type>DT607D</Type>
+								<BitSize>80</BitSize>
+							</Object>
+							<Object>
+								<Index DependOnSlot="true">#x607A</Index>
+								<Name>Target position</Name>
+								<Type>DINT</Type>
+								<BitSize>32</BitSize>
+								<Flags>
+									<Access>rw</Access>
+									<PdoMapping>r</PdoMapping>
+								</Flags>
+							</Object>
+							<Object>
+								<Index DependOnSlot="true">#x6085</Index>
+								<Name>Quick stop deceleration</Name>
+								<Type>UDINT</Type>
+								<BitSize>32</BitSize>
+								<Flags>
+									<Access>rw</Access>
+									<PdoMapping>r</PdoMapping>
+								</Flags>
+							</Object>
+							<Object>
+								<Index DependOnSlot="true">#x60C2</Index>
+								<Name>Interpolation time period</Name>
+								<Type>DT60C2</Type>
+								<BitSize>32</BitSize>
+							</Object>
+							<Object>
+								<Index DependOnSlot="true">#x60FF</Index>
+								<Name>Target velocity</Name>
+								<Type>DINT</Type>
+								<BitSize>32</BitSize>
+								<Flags>
+									<Access>rw</Access>
+									<PdoMapping>r</PdoMapping>
+								</Flags>
+							</Object>
+							<Object>
+								<Index DependOnSlot="true">#x6502</Index>
+								<Name>Supported drive modes</Name>
+								<Type>UDINT</Type>
+								<BitSize>32</BitSize>
+								<Flags>
+									<Access>ro</Access>
+									<PdoMapping>t</PdoMapping>
+								</Flags>
+							</Object>
+						</Objects>
+					</Dictionary>
+				</Profile>
+			</Module>
+		</Modules>
+	</Descriptions>
+</EtherCATInfo>

+ 381 - 0
scripts/eni_parser.py

@@ -0,0 +1,381 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+"""
+ENI (EtherCAT Network Information) Parser
+
+Copyright (c) 2025, sakumisu
+
+SPDX-License-Identifier: Apache-2.0
+
+"""
+
+import xml.etree.ElementTree as ET
+import sys
+import os
+from typing import Dict, List, Tuple, Optional
+
+class ENIParser:
+    def __init__(self):
+        self.slaves = []
+
+    def parse_hex_value(self, hex_str: str) -> int:
+        """解析十六进制字符串"""
+        if not hex_str:
+            return 0
+        hex_str = hex_str.strip()
+        if hex_str.startswith('#x'):
+            return int(hex_str[2:], 16)
+        elif hex_str.startswith('0x'):
+            return int(hex_str[2:], 16)
+        else:
+            try:
+                return int(hex_str, 16)
+            except:
+                try:
+                    return int(hex_str, 10)
+                except:
+                    return 0
+
+    def parse_slave_info(self, slave_elem):
+        """解析从站基本信息"""
+        slave_info = {}
+
+        info_elem = slave_elem.find('Info')
+        if info_elem is not None:
+            name_elem = info_elem.find('Name')
+            if name_elem is not None:
+                slave_info['name'] = name_elem.text.strip() if name_elem.text else ""
+
+            vendor_id_elem = info_elem.find('VendorId')
+            if vendor_id_elem is not None:
+                slave_info['vendor_id'] = int(vendor_id_elem.text)
+
+            product_code_elem = info_elem.find('ProductCode')
+            if product_code_elem is not None:
+                slave_info['product_code'] = int(product_code_elem.text)
+
+            revision_no_elem = info_elem.find('RevisionNo')
+            if revision_no_elem is not None:
+                slave_info['revision_no'] = int(revision_no_elem.text)
+
+        return slave_info
+
+    def parse_pdo_entry(self, entry_elem):
+        """解析单个PDO条目"""
+        entry_info = {}
+
+        # 解析Index
+        index_elem = entry_elem.find('Index')
+        if index_elem is not None and index_elem.text:
+            entry_info['index'] = self.parse_hex_value(index_elem.text)
+        else:
+            entry_info['index'] = 0x0000
+
+        # 解析SubIndex
+        subindex_elem = entry_elem.find('SubIndex')
+        if subindex_elem is not None and subindex_elem.text:
+            entry_info['subindex'] = int(subindex_elem.text)
+        else:
+            entry_info['subindex'] = 0x00
+
+        # 解析BitLen
+        bitlen_elem = entry_elem.find('BitLen')
+        if bitlen_elem is not None and bitlen_elem.text:
+            entry_info['bit_length'] = int(bitlen_elem.text)
+        else:
+            entry_info['bit_length'] = 16
+
+        # 解析Name (作为注释)
+        name_elem = entry_elem.find('Name')
+        if name_elem is not None and name_elem.text:
+            entry_info['name'] = name_elem.text.strip()
+        else:
+            # 如果Index是0或#x0,标记为Padding
+            if entry_info['index'] == 0:
+                entry_info['name'] = 'Padding'
+            else:
+                entry_info['name'] = f'Object_{entry_info["index"]:04X}'
+
+        # 解析DataType
+        datatype_elem = entry_elem.find('DataType')
+        if datatype_elem is not None and datatype_elem.text:
+            entry_info['data_type'] = datatype_elem.text.strip()
+        else:
+            entry_info['data_type'] = 'UINT'
+
+        # 解析Comment
+        comment_elem = entry_elem.find('Comment')
+        if comment_elem is not None and comment_elem.text:
+            entry_info['comment'] = comment_elem.text.strip()
+        else:
+            entry_info['comment'] = ''
+
+        return entry_info
+
+    def parse_process_data(self, slave_elem):
+        """解析过程数据配置"""
+        process_data = {
+            'rx_pdos': [],  # 输出PDO (主站->从站)
+            'tx_pdos': [],  # 输入PDO (从站->主站)
+            'syncs': []
+        }
+
+        process_elem = slave_elem.find('ProcessData')
+        if process_elem is None:
+            return process_data
+
+        # 解析RxPDO (输出)
+        for rxpdo_elem in process_elem.findall('RxPdo'):
+            pdo_info = {}
+
+            # 解析PDO Index
+            index_elem = rxpdo_elem.find('Index')
+            if index_elem is not None:
+                pdo_info['index'] = self.parse_hex_value(index_elem.text)
+
+            # 解析PDO Name
+            name_elem = rxpdo_elem.find('Name')
+            if name_elem is not None:
+                pdo_info['name'] = name_elem.text.strip() if name_elem.text else ""
+
+            # 解析所有Entry
+            entries = []
+            for entry_elem in rxpdo_elem.findall('Entry'):
+                entry_info = self.parse_pdo_entry(entry_elem)
+                entries.append(entry_info)
+
+            pdo_info['entries'] = entries
+            process_data['rx_pdos'].append(pdo_info)
+
+        # 解析TxPDO (输入)
+        for txpdo_elem in process_elem.findall('TxPdo'):
+            pdo_info = {}
+
+            # 解析PDO Index
+            index_elem = txpdo_elem.find('Index')
+            if index_elem is not None:
+                pdo_info['index'] = self.parse_hex_value(index_elem.text)
+
+            # 解析PDO Name
+            name_elem = txpdo_elem.find('Name')
+            if name_elem is not None:
+                pdo_info['name'] = name_elem.text.strip() if name_elem.text else ""
+
+            # 解析所有Entry
+            entries = []
+            for entry_elem in txpdo_elem.findall('Entry'):
+                entry_info = self.parse_pdo_entry(entry_elem)
+                entries.append(entry_info)
+
+            pdo_info['entries'] = entries
+            process_data['tx_pdos'].append(pdo_info)
+
+        # 解析同步管理器配置
+        sm2_elem = process_elem.find('Sm2')
+        if sm2_elem is not None:
+            sm_info = {
+                'index': 2,
+                'direction': 'EC_DIR_OUTPUT',
+                'type': sm2_elem.find('Type').text if sm2_elem.find('Type') is not None else 'Outputs'
+            }
+            process_data['syncs'].append(sm_info)
+
+        sm3_elem = process_elem.find('Sm3')
+        if sm3_elem is not None:
+            sm_info = {
+                'index': 3,
+                'direction': 'EC_DIR_INPUT',
+                'type': sm3_elem.find('Type').text if sm3_elem.find('Type') is not None else 'Inputs'
+            }
+            process_data['syncs'].append(sm_info)
+
+        return process_data
+
+    def parse_eni(self, eni_file: str) -> bool:
+        """解析ENI文件"""
+        try:
+            tree = ET.parse(eni_file)
+            root = tree.getroot()
+
+            # 解析从站配置
+            for slave_elem in root.findall('.//Slave'):
+                slave_info = self.parse_slave_info(slave_elem)
+                process_data = self.parse_process_data(slave_elem)
+
+                slave_config = {
+                    'info': slave_info,
+                    'process_data': process_data
+                }
+
+                self.slaves.append(slave_config)
+
+            return True
+
+        except Exception as e:
+            print(f"Error parsing ENI file: {e}")
+            import traceback
+            traceback.print_exc()
+            return False
+
+    def generate_slave_name(self, slave_info):
+        """生成从站名称标识符"""
+        name = slave_info.get('name', 'slave')
+        # 清理名称,只保留字母数字和下划线
+        clean_name = ''.join(c if c.isalnum() or c == '_' else '_' for c in name.lower())
+        clean_name = clean_name.replace('__', '_').strip('_')
+
+        # 根据产品代码生成后缀
+        product_code = slave_info.get('product_code', 0)
+        return f'eni_{product_code:04x}'
+
+    def generate_c_code(self) -> str:
+        """生成C代码"""
+        lines = [
+            "/*",
+            " * Generated CherryECAT PDO configuration from ENI file",
+            " * Auto-generated - do not modify manually",
+            " */",
+            "",
+            "#include \"ec_master.h\"",
+            ""
+        ]
+
+        for slave_idx, slave in enumerate(self.slaves):
+            slave_info = slave['info']
+            process_data = slave['process_data']
+
+            slave_name = self.generate_slave_name(slave_info)
+
+            lines.append(f"// Slave {slave_idx + 1}: {slave_info.get('name', 'Unknown')}")
+            lines.append(f"// Vendor ID: 0x{slave_info.get('vendor_id', 0):08X}")
+            lines.append(f"// Product Code: 0x{slave_info.get('product_code', 0):08X}")
+            lines.append("")
+
+            # 生成RxPDO entries (输出)
+            rx_entries_generated = set()
+            for pdo in process_data['rx_pdos']:
+                pdo_index = pdo.get('index', 0)
+                pdo_hex = f"{pdo_index:04x}"
+                entries_name = f"{slave_name}_{pdo_hex}"
+
+                if entries_name not in rx_entries_generated:
+                    lines.append(f"static ec_pdo_entry_info_t {entries_name}[] = {{")
+
+                    # 生成每个entry
+                    for entry in pdo.get('entries', []):
+                        comment = entry.get('name', 'Padding')
+                        lines.append(f"    {{ 0x{entry['index']:04x}, 0x{entry['subindex']:02x}, 0x{entry['bit_length']:02x} }},  // {comment}")
+
+                    lines.append("};")
+                    lines.append("")
+                    rx_entries_generated.add(entries_name)
+
+            # 生成TxPDO entries (输入)
+            tx_entries_generated = set()
+            for pdo in process_data['tx_pdos']:
+                pdo_index = pdo.get('index', 0)
+                pdo_hex = f"{pdo_index:04x}"
+                entries_name = f"{slave_name}_{pdo_hex}"
+
+                if entries_name not in tx_entries_generated:
+                    lines.append(f"static ec_pdo_entry_info_t {entries_name}[] = {{")
+
+                    # 生成每个entry
+                    for entry in pdo.get('entries', []):
+                        comment = entry.get('name', 'Padding')
+                        lines.append(f"    {{ 0x{entry['index']:04x}, 0x{entry['subindex']:02x}, 0x{entry['bit_length']:02x} }},  // {comment}")
+
+                    lines.append("};")
+                    lines.append("")
+                    tx_entries_generated.add(entries_name)
+
+            # 生成RxPDO info
+            if process_data['rx_pdos']:
+                lines.append(f"static ec_pdo_info_t {slave_name}_rxpdos[] = {{")
+                for pdo in process_data['rx_pdos']:
+                    pdo_index = pdo.get('index', 0)
+                    pdo_hex = f"{pdo_index:04x}"
+                    entries_name = f"{slave_name}_{pdo_hex}"
+                    entry_count = len(pdo.get('entries', []))
+                    lines.append(f"    {{ 0x{pdo_index:04x}, {entry_count}, &{entries_name}[0] }},")
+                lines.append("};")
+                lines.append("")
+
+            # 生成TxPDO info
+            if process_data['tx_pdos']:
+                lines.append(f"static ec_pdo_info_t {slave_name}_txpdos[] = {{")
+                for pdo in process_data['tx_pdos']:
+                    pdo_index = pdo.get('index', 0)
+                    pdo_hex = f"{pdo_index:04x}"
+                    entries_name = f"{slave_name}_{pdo_hex}"
+                    entry_count = len(pdo.get('entries', []))
+                    lines.append(f"    {{ 0x{pdo_index:04x}, {entry_count}, &{entries_name}[0] }},")
+                lines.append("};")
+                lines.append("")
+
+            # 生成同步管理器配置
+            lines.append(f"static ec_sync_info_t {slave_name}_syncs[] = {{")
+
+            # 添加SM2 (输出)
+            if process_data['rx_pdos']:
+                lines.append(f"    {{ 2, EC_DIR_OUTPUT, {len(process_data['rx_pdos'])}, {slave_name}_rxpdos }},")
+
+            # 添加SM3 (输入)
+            if process_data['tx_pdos']:
+                lines.append(f"    {{ 3, EC_DIR_INPUT, {len(process_data['tx_pdos'])}, {slave_name}_txpdos }},")
+
+            lines.append("};")
+            lines.append("")
+
+        return "\n".join(lines)
+
+def main():
+    if len(sys.argv) != 3:
+        print("Usage: python eni_parser.py <input.xml> <output.h>")
+        print("  input.xml  - ENI XML file")
+        print("  output.h   - Output C header file")
+        sys.exit(1)
+
+    input_file = sys.argv[1]
+    output_file = sys.argv[2]
+
+    if not os.path.exists(input_file):
+        print(f"Error: Input file '{input_file}' not found")
+        sys.exit(1)
+
+    # 创建解析器
+    parser = ENIParser()
+
+    # 解析ENI文件
+    print(f"Parsing ENI file: {input_file}")
+    if not parser.parse_eni(input_file):
+        print("Failed to parse ENI file")
+        sys.exit(1)
+
+    # 生成C代码
+    print("Generating C code...")
+    c_code = parser.generate_c_code()
+
+    # 写入输出文件
+    try:
+        with open(output_file, 'w') as f:
+            f.write(c_code)
+
+        print(f"✓ Successfully converted '{input_file}' to '{output_file}'")
+        print(f"✓ Generated C code for {len(parser.slaves)} slave(s)")
+
+        # 显示生成的PDO映射信息
+        for slave_idx, slave in enumerate(parser.slaves):
+            process_data = slave['process_data']
+            print(f"✓ Slave {slave_idx + 1}:")
+            for pdo in process_data['rx_pdos']:
+                print(f"  - RxPDO 0x{pdo.get('index', 0):04X}: {len(pdo.get('entries', []))} entries")
+            for pdo in process_data['tx_pdos']:
+                print(f"  - TxPDO 0x{pdo.get('index', 0):04X}: {len(pdo.get('entries', []))} entries")
+
+    except Exception as e:
+        print(f"Error writing output file: {e}")
+        sys.exit(1)
+
+if __name__ == "__main__":
+    main()

+ 510 - 0
scripts/esi_parser.py

@@ -0,0 +1,510 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+"""
+ESI(EtherCAT Slave Information) to EEPROM Binary Converter
+
+Copyright (c) 2025, sakumisu
+
+SPDX-License-Identifier: Apache-2.0
+
+"""
+
+import xml.etree.ElementTree as ET
+import struct
+import sys
+import os
+from typing import Dict, List, Tuple, Optional
+
+class EtherCATXMLParser:
+    def __init__(self):
+        # 设备基本信息
+        self.vendor_id = 0x00000000  # 默认厂商ID
+        self.product_code = 0x00000000  # 默认产品代码
+        self.revision_no = 0x00000000  # 默认版本号
+        self.serial_number = 0x00000000  # 序列号
+        self.device_name = ""
+        self.device_type = ""
+
+        # 邮箱配置
+        self.mailbox_protocols = 0x0
+        self.boot_rx_mailbox = {}
+        self.boot_tx_mailbox = {}
+        self.std_rx_mailbox = {}
+        self.std_tx_mailbox = {}
+
+        # 字符串表
+        self.strings = []
+
+        # 类别数据
+        self.categories = []
+
+    def parse_hex_value(self, hex_str: str) -> int:
+        """解析十六进制字符串"""
+        if not hex_str:
+            return 0
+        hex_str = hex_str.strip()
+        if hex_str.startswith('#x'):
+            return int(hex_str[2:], 16)
+        elif hex_str.startswith('0x'):
+            return int(hex_str[2:], 16)
+        else:
+            try:
+                return int(hex_str, 16)
+            except:
+                return int(hex_str, 10)
+
+    def parse_device_info(self, device_elem):
+        """解析设备基本信息"""
+        # 获取产品代码和版本号
+        type_elem = device_elem.find('Type')
+        if type_elem is not None:
+            product_code = type_elem.get('ProductCode')
+            if product_code:
+                self.product_code = self.parse_hex_value(product_code)
+
+            revision_no = type_elem.get('RevisionNo')
+            if revision_no:
+                self.revision_no = self.parse_hex_value(revision_no)
+
+        # 获取设备名称
+        name_elem = device_elem.find('Name')
+        if name_elem is not None and name_elem.text:
+            self.device_name = name_elem.text.strip()
+
+        # 获取设备类型
+        type_name = device_elem.find('Type/Name')
+        if type_name is not None and type_name.text:
+            self.device_type = type_name.text.strip()
+
+    def parse_vendor_info(self, vendor_elem):
+        """解析厂商信息"""
+        vendor_id_elem = vendor_elem.find('Id')
+        if vendor_id_elem is not None and vendor_id_elem.text:
+            self.vendor_id = self.parse_hex_value(vendor_id_elem.text)
+
+    def parse_mailbox_info(self, device_elem):
+        """解析邮箱信息"""
+        mailbox_elem = device_elem.find('.//Mailbox')
+        if mailbox_elem is not None:
+            # 检查支持的协议
+            self.mailbox_protocols = 0
+
+            if mailbox_elem.find('CoE') is not None:
+                self.mailbox_protocols |= 0x04  # CoE
+            if mailbox_elem.find('FoE') is not None:
+                self.mailbox_protocols |= 0x08  # FoE
+            if mailbox_elem.find('EoE') is not None:
+                self.mailbox_protocols |= 0x10  # EoE
+            if mailbox_elem.find('SoE') is not None:
+                self.mailbox_protocols |= 0x20  # SoE
+
+        # 从SM配置中获取邮箱地址和大小
+        sm_elems = device_elem.findall('.//Sm')
+        for i, sm_elem in enumerate(sm_elems):
+            start_addr = self.parse_hex_value(sm_elem.get('StartAddress', '0'))
+            size = self.parse_hex_value(sm_elem.get('DefaultSize', '0'))
+
+            if i == 0:  # MBoxOut (接收)
+                self.boot_rx_mailbox = {"offset": start_addr, "size": size}
+                self.std_rx_mailbox = {"offset": start_addr, "size": size}
+            elif i == 1:  # MBoxIn (发送)
+                self.boot_tx_mailbox = {"offset": start_addr, "size": size}
+                self.std_tx_mailbox = {"offset": start_addr, "size": size}
+
+    def add_string(self, text: str) -> int:
+        """添加字符串到字符串表,返回索引"""
+        if not text:
+            return 0
+
+        # 检查是否已存在
+        for i, existing in enumerate(self.strings):
+            if existing == text:
+                return i + 1
+
+        # 添加新字符串
+        self.strings.append(text)
+        return len(self.strings)
+
+    def create_strings_category(self) -> bytes:
+        """创建字符串类别(Category 10)"""
+        if not self.strings:
+            return b''
+
+        data = bytearray()
+
+        # 字符串数量
+        data.append(len(self.strings))
+
+        # 每个字符串: 长度 + 内容
+        for string in self.strings:
+            string_bytes = string.encode('ascii', errors='replace')
+            data.append(len(string_bytes))
+            data.extend(string_bytes)
+
+        # 填充到偶数长度
+        if len(data) % 2:
+            data.append(0)
+
+        return bytes(data)
+
+    def create_general_category(self) -> bytes:
+        """创建通用类别(Category 30)"""
+        data = bytearray()
+
+        # Group Type String Index (2 bytes)
+        group_idx = self.add_string("ECAT_Device")
+        data.extend(struct.pack('<H', group_idx))
+
+        # Image Name String Index (2 bytes)
+        image_idx = self.add_string("ECAT_CIA402")
+        data.extend(struct.pack('<H', image_idx))
+
+        # Order Number String Index (2 bytes)
+        order_idx = self.add_string("")
+        data.extend(struct.pack('<H', order_idx))
+
+        # Device Name String Index (2 bytes)
+        name_idx = self.add_string(self.device_name)
+        data.extend(struct.pack('<H', name_idx))
+
+        # CoE Details (2 bytes) - 支持SDO, PDO配置
+        coe_details = 0x0027  # Enable SDO, SDO Info, PDO Assign, PDO Config
+        data.extend(struct.pack('<H', coe_details))
+
+        # FoE Details (2 bytes)
+        foe_details = 0x0000
+        data.extend(struct.pack('<H', foe_details))
+
+        # EoE Details (2 bytes)
+        eoe_details = 0x0000
+        data.extend(struct.pack('<H', eoe_details))
+
+        # SoE Channels (1 byte)
+        soe_channels = 0x00
+        data.append(soe_channels)
+
+        # DS402 Channels (1 byte)
+        ds402_channels = 0x01
+        data.append(ds402_channels)
+
+        # SysmanClass (1 byte)
+        sysman_class = 0x00
+        data.append(sysman_class)
+
+        # Flags (1 byte)
+        flags = 0x01  # Enable SafeOp
+        data.append(flags)
+
+        # Current Consumption (2 bytes)
+        current = 0x0000
+        data.extend(struct.pack('<H', current))
+
+        # Group Type and Image Name for 2nd device (if any)
+        data.extend(struct.pack('<H', 0x0000))  # Group Type 2
+        data.extend(struct.pack('<H', 0x0000))  # Image Name 2
+
+        # Physical Memory Address (2 bytes)
+        phys_addr = 0x0000
+        data.extend(struct.pack('<H', phys_addr))
+
+        # 填充到偶数长度
+        if len(data) % 2:
+            data.append(0)
+
+        return bytes(data)
+
+    def create_fmmu_category(self) -> bytes:
+        """创建FMMU类别(Category 40)"""
+        data = bytearray()
+
+        # FMMU配置 - 8个FMMU
+        fmmu_configs = [
+            0x01,  # FMMU0: Outputs
+            0x02,  # FMMU1: Inputs
+            0x03,  # FMMU2: MBox State
+            0x00,  # FMMU3: Unused
+            0x00,  # FMMU4: Unused
+            0x00,  # FMMU5: Unused
+            0x00,  # FMMU6: Unused
+            0x00,  # FMMU7: Unused
+        ]
+
+        for config in fmmu_configs:
+            data.append(config)
+
+        return bytes(data)
+
+    def create_sm_category(self) -> bytes:
+        """创建同步管理器类别(Category 41)"""
+        data = bytearray()
+
+        # SM配置数据结构: StartAddr(2) + Length(2) + ControlByte(1) + Enable(1)
+        sm_configs = [
+            # SM0: MBoxOut (接收邮箱)
+            (self.boot_rx_mailbox["offset"], self.boot_rx_mailbox["size"], 0x26, 0x01),
+            # SM1: MBoxIn (发送邮箱)
+            (self.boot_tx_mailbox["offset"], self.boot_tx_mailbox["size"], 0x22, 0x01),
+            # SM2: Process Data Output
+            (0x1100, 0x0000, 0x64, 0x00),  # 长度为0表示未配置
+            # SM3: Process Data Input
+            (0x1400, 0x0000, 0x20, 0x00),  # 长度为0表示未配置
+            # SM4-7: 未使用
+            (0x0000, 0x0000, 0x00, 0x00),
+            (0x0000, 0x0000, 0x00, 0x00),
+            (0x0000, 0x0000, 0x00, 0x00),
+            (0x0000, 0x0000, 0x00, 0x00),
+        ]
+
+        for start_addr, length, control, enable in sm_configs:
+            data.extend(struct.pack('<H', start_addr))  # Start Address
+            data.extend(struct.pack('<H', length))      # Length
+            data.append(control)                        # Control Byte
+            data.append(enable)                         # Enable
+
+        return bytes(data)
+
+    def create_category(self, category_type: int, data: bytes) -> bytes:
+        """创建类别头部+数据"""
+        header = bytearray()
+
+        # Category Type (2 bytes)
+        header.extend(struct.pack('<H', category_type))
+
+        # Category Size in words (2 bytes)
+        size_words = (len(data) + 1) // 2
+        header.extend(struct.pack('<H', size_words))
+
+        return bytes(header) + data
+
+    def generate_eeprom(self) -> bytes:
+        """生成完整的EEPROM数据,参考eeprom.h的格式"""
+        eeprom_data = bytearray()
+
+        # === EEPROM Header (固定128字节) ===
+
+        # PDI Control (2 bytes) - 0x800C (Digital I/O + SII EEPROM)
+        eeprom_data.extend(struct.pack('<H', 0x800C))
+
+        # PDI Configuration (2 bytes) - 0x6681
+        eeprom_data.extend(struct.pack('<H', 0x6681))
+
+        # Sync Impulse Length (2 bytes)
+        eeprom_data.extend(struct.pack('<H', 0x0000))
+
+        # PDI Configuration 2 (2 bytes)
+        eeprom_data.extend(struct.pack('<H', 0x0000))
+
+        # Station Alias (2 bytes)
+        eeprom_data.extend(struct.pack('<H', 0x3412))
+
+        # Reserved (2 bytes)
+        eeprom_data.extend(struct.pack('<H', 0x0000))
+
+        # Checksum (2 bytes) - 稍后计算
+        checksum_pos = len(eeprom_data)
+        eeprom_data.extend(struct.pack('<H', 0x0077))  # 临时值
+
+        # Vendor ID (4 bytes)
+        eeprom_data.extend(struct.pack('<L', self.vendor_id))
+
+        # Product Code (4 bytes)
+        eeprom_data.extend(struct.pack('<L', self.product_code))
+
+        # Revision Number (4 bytes)
+        eeprom_data.extend(struct.pack('<L', self.revision_no))
+
+        # Serial Number (4 bytes)
+        eeprom_data.extend(struct.pack('<L', self.serial_number))
+
+        # Bootstrap Mailbox Receive Offset (2 bytes)
+        eeprom_data.extend(struct.pack('<H', self.boot_rx_mailbox["offset"]))
+
+        # Bootstrap Mailbox Receive Size (2 bytes)
+        eeprom_data.extend(struct.pack('<H', self.boot_rx_mailbox["size"]))
+
+        # Bootstrap Mailbox Send Offset (2 bytes)
+        eeprom_data.extend(struct.pack('<H', self.boot_tx_mailbox["offset"]))
+
+        # Bootstrap Mailbox Send Size (2 bytes)
+        eeprom_data.extend(struct.pack('<H', self.boot_tx_mailbox["size"]))
+
+        # Standard Mailbox Receive Offset (2 bytes)
+        eeprom_data.extend(struct.pack('<H', self.std_rx_mailbox["offset"]))
+
+        # Standard Mailbox Receive Size (2 bytes)
+        eeprom_data.extend(struct.pack('<H', self.std_rx_mailbox["size"]))
+
+        # Standard Mailbox Send Offset (2 bytes)
+        eeprom_data.extend(struct.pack('<H', self.std_tx_mailbox["offset"]))
+
+        # Standard Mailbox Send Size (2 bytes)
+        eeprom_data.extend(struct.pack('<H', self.std_tx_mailbox["size"]))
+
+        # Mailbox Protocol (2 bytes)
+        eeprom_data.extend(struct.pack('<H', self.mailbox_protocols))
+
+        # Reserved bytes to reach 128 bytes header
+        current_size = len(eeprom_data)
+        header_size = 128
+        if current_size < header_size:
+            eeprom_data.extend(b'\x00' * (header_size - current_size))
+
+        # === Categories Section ===
+
+        # Category 10: Strings
+        strings_data = self.create_strings_category()
+        if strings_data:
+            eeprom_data.extend(self.create_category(10, strings_data))
+
+        # Category 30: General
+        general_data = self.create_general_category()
+        eeprom_data.extend(self.create_category(30, general_data))
+
+        # Category 40: FMMU
+        fmmu_data = self.create_fmmu_category()
+        eeprom_data.extend(self.create_category(40, fmmu_data))
+
+        # Category 41: SyncM
+        sm_data = self.create_sm_category()
+        eeprom_data.extend(self.create_category(41, sm_data))
+
+        # End of Categories marker
+        eeprom_data.extend(struct.pack('<H', 0xFFFF))
+        eeprom_data.extend(struct.pack('<H', 0x0000))
+
+        # 填充到合适的大小 (通常是2KB)
+        target_size = 2048
+        if len(eeprom_data) < target_size:
+            eeprom_data.extend(b'\xFF' * (target_size - len(eeprom_data)))
+
+        # 重新计算校验和 (SII头部校验和)
+        checksum = 0
+        # 计算前14字节的校验和,跳过校验和字段本身
+        for i in range(0, 14, 2):
+            if i != 12:  # 跳过校验和位置
+                word = struct.unpack('<H', eeprom_data[i:i+2])[0]
+                checksum += word
+
+        checksum = (~checksum + 1) & 0xFFFF  # 2's complement
+
+        # 更新校验和
+        struct.pack_into('<H', eeprom_data, checksum_pos, checksum)
+
+        return bytes(eeprom_data)
+
+    def parse_xml(self, xml_file: str) -> bool:
+        """解析XML文件"""
+        try:
+            tree = ET.parse(xml_file)
+            root = tree.getroot()
+
+            # 查找并解析厂商信息
+            vendor_elem = root.find('.//Vendor')
+            if vendor_elem is not None:
+                self.parse_vendor_info(vendor_elem)
+
+            # 查找并解析设备信息
+            device_elem = root.find('.//Device')
+            if device_elem is not None:
+                self.parse_device_info(device_elem)
+                self.parse_mailbox_info(device_elem)
+
+            print(f"Parsed XML: Vendor=0x{self.vendor_id:08X}, Product=0x{self.product_code:08X}")
+            print(f"Device Name: {self.device_name}")
+            print(f"Mailbox RX: 0x{self.std_rx_mailbox['offset']:04X}({self.std_rx_mailbox['size']})")
+            print(f"Mailbox TX: 0x{self.std_tx_mailbox['offset']:04X}({self.std_tx_mailbox['size']})")
+
+            return True
+
+        except Exception as e:
+            print(f"Error parsing XML file: {e}")
+            import traceback
+            traceback.print_exc()
+            return False
+
+    def generate_c_header(self, array_name: str = "cherryecat_eepromdata") -> str:
+        """生成C语言头文件格式的数组"""
+        eeprom_data = self.generate_eeprom()
+
+        lines = [
+            "/*",
+            f"The EEPROM data is created based on EtherCAT Slave Information (ESI) XML file.",
+            f"Generated {len(eeprom_data)} bytes of EEPROM data",
+            f"Vendor ID: 0x{self.vendor_id:08X}",
+            f"Product Code: 0x{self.product_code:08X}",
+            f"Revision: 0x{self.revision_no:08X}",
+            f"Device Name: {self.device_name}",
+            "*/",
+            f"unsigned char {array_name}[] = {{",
+        ]
+
+        # 按16字节一行格式化数据
+        for i in range(0, len(eeprom_data), 16):
+            chunk = eeprom_data[i:i+16]
+            hex_values = [f"0x{b:02X}" for b in chunk]
+            line = ",".join(hex_values)
+            if i + 16 < len(eeprom_data):
+                line += ","
+            lines.append(line)
+
+        lines.append("};")
+
+        return "\n".join(lines)
+
+def main():
+    if len(sys.argv) < 3:
+        print("Usage: python esi_parse.py <input.xml> <output.bin> [output.h]")
+        print("  input.xml  - EtherCAT ESI XML file")
+        print("  output.bin - Output binary EEPROM file")
+        print("  output.h   - Optional C header file output")
+        sys.exit(1)
+
+    input_file = sys.argv[1]
+    output_file = sys.argv[2]
+    header_file = sys.argv[3] if len(sys.argv) > 3 else None
+
+    if not os.path.exists(input_file):
+        print(f"Error: Input file '{input_file}' not found")
+        sys.exit(1)
+
+    # 创建解析器
+    parser = EtherCATXMLParser()
+
+    # 解析XML
+    print(f"Parsing XML file: {input_file}")
+    if not parser.parse_xml(input_file):
+        print("Failed to parse XML file")
+        sys.exit(1)
+
+    # 生成EEPROM数据
+    print("Generating EEPROM data...")
+    eeprom_data = parser.generate_eeprom()
+
+    # 写入二进制文件
+    try:
+        with open(output_file, 'wb') as f:
+            f.write(eeprom_data)
+
+        print(f"✓ Successfully converted '{input_file}' to '{output_file}'")
+        print(f"✓ Generated {len(eeprom_data)} bytes of EEPROM data")
+        print(f"✓ Vendor ID: 0x{parser.vendor_id:08X}")
+        print(f"✓ Product Code: 0x{parser.product_code:08X}")
+        print(f"✓ Revision: 0x{parser.revision_no:08X}")
+        print(f"✓ Device Name: {parser.device_name}")
+
+    except Exception as e:
+        print(f"Error writing binary file: {e}")
+        sys.exit(1)
+
+    # 生成C头文件(可选)
+    if header_file:
+        try:
+            header_content = parser.generate_c_header()
+            with open(header_file, 'w') as f:
+                f.write(header_content)
+            print(f"✓ Generated C header file: {header_file}")
+        except Exception as e:
+            print(f"Error writing header file: {e}")
+
+if __name__ == "__main__":
+    main()

+ 19 - 0
src/ec_cmd.c

@@ -833,6 +833,25 @@ int ethercat(int argc, const char **argv)
         ec_hexdump(global_cmd_master->slaves[slave_idx].sii_image,
                    global_cmd_master->slaves[slave_idx].sii_nwords * 2);
 
+        return 0;
+    } else if (argc >= 5 && strcmp(argv[1], "sii_write") == 0) {
+        // ethercat sii_write -p [slave_idx]
+        uint32_t slave_idx = atoi(argv[3]);
+        if (slave_idx >= global_cmd_master->slave_count) {
+            EC_LOG_RAW("No slaves found\n");
+            return -1;
+        }
+        static ec_datagram_t datagram;
+
+        ec_datagram_init(&datagram, 4096);
+
+        extern unsigned char cherryecat_eepromdata[2048];
+
+        ec_osal_mutex_take(global_cmd_master->scan_lock);
+        ec_sii_write(&global_cmd_master->slaves[slave_idx], &datagram, 0x0000, (const uint16_t *)cherryecat_eepromdata, sizeof(cherryecat_eepromdata));
+        ec_osal_mutex_give(global_cmd_master->scan_lock);
+
+        ec_datagram_clear(&datagram);
         return 0;
     } else if (argc >= 2 && strcmp(argv[1], "pdo_read") == 0) {
         // ethercat pdo_read

+ 1 - 1
src/ec_sii.c

@@ -138,7 +138,7 @@ int ec_sii_read(ec_slave_t *slave, ec_datagram_t *datagram, uint16_t woffset, ui
     return esc_sii_assign_pdi(slave, datagram);
 }
 
-int esc_sii_write(ec_slave_t *slave, ec_datagram_t *datagram, uint16_t woffset, const uint16_t *buf, uint32_t len)
+int ec_sii_write(ec_slave_t *slave, ec_datagram_t *datagram, uint16_t woffset, const uint16_t *buf, uint32_t len)
 {
     int ret;